标签 神经网络 下的文章

在过去的几周里,我花了很多时间用 PyTorch 实现了一个 char-rnn 的版本。我以前从未训练过神经网络,所以这可能是一个有趣的开始。

这个想法(来自 循环神经网络的不合理效应)可以让你在文本上训练一个基于字符的 循环神经网络 recurrent neural network (RNN),并得到一些出乎意料好的结果。

不过,虽然没有得到我想要的结果,但是我还是想分享一些示例代码和结果,希望对其他开始尝试使用 PyTorch 和 RNN 的人有帮助。

这是 Jupyter 笔记本格式的代码:char-rnn in PyTorch.ipynb。你可以点击这个网页最上面那个按钮 “Open in Colab”,就可以在 Google 的 Colab 服务中打开,并使用免费的 GPU 进行训练。所有的东西加起来大概有 75 行代码,我将在这篇博文中尽可能地详细解释。

第一步:准备数据

首先,我们要下载数据。我使用的是 古登堡项目 Project Gutenberg 中的这个数据:Hans Christian Anderson’s fairy tales

!wget -O fairy-tales.txt

这个是准备数据的代码。我使用 fastai 库中的 Vocab 类进行数据处理,它能将一堆字母转换成“词表”,然后用这个“词表”把字母变成数字。

之后我们就得到了一个大的数字数组(training_set),我们可以用于训练我们的模型。

from fastai.text import *
text = unidecode.unidecode(open('fairy-tales.txt').read())
v = Vocab.create((x for x in text), max_vocab=400, min_freq=1)
training_set = torch.Tensor(v.numericalize([x for x in text])).type(torch.LongTensor).cuda()
num_letters = len(v.itos)

第二步:定义模型

这个是 PyTorch 中 LSTM 类的封装。除了封装 LSTM 类以外,它还做了三件事:

  1. 对输入向量进行 one-hot 编码,使得它们具有正确的维度。
  2. LSTM 层后一层添加一个线性变换,因为 LSTM 输出的是一个长度为 hidden_size 的向量,我们需要的是一个长度为 input_size 的向量这样才能把它变成一个字符。
  3. LSTM 隐藏层的输出向量(实际上有 2 个向量)保存成实例变量,然后在每轮运行结束后执行 .detach() 函数。(我很难解释清 .detach() 的作用,但我的理解是,它在某种程度上“结束”了模型的求导计算)(LCTT 译注:detach() 函数是将该张量的 requires_grad 参数设置为 False,即反向传播到该张量就结束。)
class MyLSTM(nn.Module):
    def __init__(self, input_size, hidden_size):
        super().__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)
        self.h2o = nn.Linear(hidden_size, input_size)
        self.input_size=input_size
        self.hidden = None

    def forward(self, input):
        input = torch.nn.functional.one_hot(input, num_classes=self.input_size).type(torch.FloatTensor).cuda().unsqueeze(0)
        if self.hidden is None:
            l_output, self.hidden = self.lstm(input)
        else:
            l_output, self.hidden = self.lstm(input, self.hidden)
        self.hidden = (self.hidden[0].detach(), self.hidden[1].detach())

        return self.h2o(l_output)

这个代码还做了一些比较神奇但是不太明显的功能。如果你的输入是一个向量(比如 [1,2,3,4,5,6]),对应六个字母,那么我的理解是 nn.LSTM 会在内部使用沿时间反向传播更新隐藏向量 6 次。

第三步:编写训练代码

模型不会自己训练的!

我最开始的时候尝试用 fastai 库中的一个辅助类(也是 PyTorch 中的封装)。我有点疑惑因为我不知道它在做什么,所以最后我自己编写了模型训练代码。

下面这些代码(epoch() 方法)就是有关于一轮训练过程的基本信息。基本上就是重复做下面这几件事情:

  1. 往 RNN 模型中传入一个字符串,比如 and they ought not to teas。(要以数字向量的形式传入)
  2. 得到下一个字母的预测结果
  3. 计算 RNN 模型预测结果和真实的下一个字母之间的损失函数(e,因为 tease 这个单词是以 e 结尾的)
  4. 计算梯度(用 loss.backward() 函数)
  5. 沿着梯度下降的方向修改模型中参数的权重(用 self.optimizer.step() 函数)
class Trainer():
  def __init__(self):
      self.rnn = MyLSTM(input_size, hidden_size).cuda()
      self.optimizer = torch.optim.Adam(self.rnn.parameters(), amsgrad=True, lr=lr)
  def epoch(self):
      i = 0
      while i < len(training_set) - 40:
        seq_len = random.randint(10, 40)
        input, target = training_set[i:i+seq_len],training_set[i+1:i+1+seq_len]
        i += seq_len
        # forward pass
        output = self.rnn(input)
        loss = F.cross_entropy(output.squeeze()[-1:], target[-1:])
        # compute gradients and take optimizer step
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

使用 nn.LSTM 沿着时间反向传播,不要自己写代码

开始的时候我自己写代码每次传一个字母到 LSTM 层中,之后定期计算导数,就像下面这样:

for i in range(20):
    input, target = next(iter)
    output, hidden = self.lstm(input, hidden)
loss = F.cross_entropy(output, target)
hidden = hidden.detach()
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()

这段代码每次传入 20 个字母,每次一个,并且在最后训练了一次。这个步骤就被称为沿时间反向传播,Karpathy 在他的博客中就是用这种方法。

这个方法有些用处,我编写的损失函数开始能够下降一段时间,但之后就会出现峰值。我不知道为什么会出现这种现象,但之后我改为一次传入 20 个字符到 LSTM 之后(按 seq_len 维度),再进行反向传播,情况就变好了。

第四步:训练模型!

我在同样的数据上重复执行了这个训练代码大概 300 次,直到模型开始输出一些看起来像英文的文本。差不多花了一个多小时吧。

这种情况下我也不关注模型是不是过拟合了,但是如果你在真实场景中训练模型,应该要在验证集上验证你的模型。

第五步:生成输出!

最后一件要做的事就是用这个模型生成一些输出。我写了一个辅助方法从这个训练好的模型中生成文本(make_predsnext_pred)。这里主要是把向量的维度对齐,重要的一点是:

output = rnn(input)
prediction_vector = F.softmax(output/temperature)
letter = v.textify(torch.multinomial(prediction_vector, 1).flatten(), sep='').replace('_', ' ')

基本上做的事情就是这些:

  1. RNN 层为字母表中的每一个字母或者符号输出一个数值向量(output)。
  2. 这个 output 向量并不是一个概率向量,所以需要 F.softmax(output/temperature) 操作,将其转换为概率值(也就是所有数值加起来和为 1)。temperature 某种程度上控制了对更高概率的权重,在限制范围内,如果设置 temperature=0.0000001,它将始终选择概率最高的字母。
  3. torch.multinomial(prediction_vector) 用于获取概率向量,并使用这些概率在向量中选择一个索引(如 12)。
  4. v.textify12 转换为字母。

如果我们想要处理的文本长度为 300,那么只需要重复这个过程 300 次就可以了。

结果!

我把预测函数中的参数设置为 temperature = 1 得到了下面的这些由模型生成的结果。看起来有点像英语,这个结果已经很不错了,因为这个模型要从头开始“学习”英语,并且是在字符序列的级别上进行学习的。

虽然这些话没有什么含义,但我们也不知道到底想要得到什么输出。

“An who was you colotal said that have to have been a little crimantable and beamed home the beetle. “I shall be in the head of the green for the sound of the wood. The pastor. “I child hand through the emperor’s sorthes, where the mother was a great deal down the conscious, which are all the gleam of the wood they saw the last great of the emperor’s forments, the house of a large gone there was nothing of the wonded the sound of which she saw in the converse of the beetle. “I shall know happy to him. This stories herself and the sound of the young mons feathery in the green safe.”

“That was the pastor. The some and hand on the water sound of the beauty be and home to have been consider and tree and the face. The some to the froghesses and stringing to the sea, and the yellow was too intention, he was not a warm to the pastor. The pastor which are the faten to go and the world from the bell, why really the laborer’s back of most handsome that she was a caperven and the confectioned and thoughts were seated to have great made

下面这些结果是当 temperature=0.1 时生成的,它选择字符的方式更接近于“每次都选择出现概率最高的字符”。这就使得输出结果有很多是重复的。

ole the sound of the beauty of the beetle. “She was a great emperor of the sea, and the sun was so warm to the confectioned the beetle. “I shall be so many for the beetle. “I shall be so many for the beetle. “I shall be so standen for the world, and the sun was so warm to the sea, and the sun was so warm to the sea, and the sound of the world from the bell, where the beetle was the sea, and the sound of the world from the bell, where the beetle was the sea, and the sound of the wood flowers and the sound of the wood, and the sound of the world from the bell, where the world from the wood, and the sound of the

这段输出对这几个单词 beetlesconfectionerssunsea 有着奇怪的执念。

总结!

至此,我的结果远不及 Karpathy 的好,可能有一下几个原因:

  1. 没有足够多的训练数据。
  2. 训练了一个小时之后我就没有耐心去查看 Colab 笔记本上的信息。
  3. Karpathy 使用了两层LSTM,包含了更多的参数,而我只使用了一层。
  4. 完全是另一回事。

但我得到了一些大致说得过去的结果!还不错!


via: https://jvns.ca/blog/2020/11/30/implement-char-rnn-in-pytorch/

作者:Julia Evans 选题:lujun9972 译者:zhangxiangping 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

TensorFlow 是用于机器学习任务的开源软件。它的创建者 Google 希望提供一个强大的工具以帮助开发者探索和建立基于机器学习的应用,所以他们在去年作为开源项目发布了它。TensorFlow 是一个非常强大的工具,专注于一种称为 深层神经网络 deep neural network (DNN)的神经网络。

深层神经网络被用来执行复杂的机器学习任务,例如图像识别、手写识别、自然语言处理、聊天机器人等等。这些神经网络被训练学习其所要执行的任务。由于训练所需的计算是非常巨大的,在大多数情况下需要 GPU 支持,这时 TensorFlow 就派上用场了。启用了 GPU 并安装了支持 GPU 的软件,那么训练所需的时间就可以大大减少。

本教程可以帮助你安装只支持 CPU 的和同时支持 GPU 的 TensorFlow。要使用带有 GPU 支持的 TensorFLow,你必须要有一块支持 CUDA 的 Nvidia GPU。CUDA 和 CuDNN(Nvidia 的计算库)的安装有点棘手,本指南会提供在实际安装 TensorFlow 之前一步步安装它们的方法。

Nvidia CUDA 是一个 GPU 加速库,它已经为标准神经网络中用到的标准例程调优过。CuDNN 是一个用于 GPU 的调优库,它负责 GPU 性能的自动调整。TensorFlow 同时依赖这两者用于训练并运行深层神经网络,因此它们必须在 TensorFlow 之前安装。

需要指出的是,那些不希望安装支持 GPU 的 TensorFlow 的人,你可以跳过以下所有的步骤并直接跳到:“步骤 5:安装只支持 CPU 的 TensorFlow”。

关于 TensorFlow 的介绍可以在这里找到。

1、 安装 CUDA

首先,在这里下载用于 Ubuntu 16.04 的 CUDA 库。此文件非常大(2GB),因此也许会花费一些时间下载。

下载的文件是 “.deb” 包。要安装它,运行下面的命令:

sudo dpkg -i cuda-repo-ubuntu1604-8-0-local_8.0.44-1_amd64.deb

Install CUDA

下面的的命令会安装所有的依赖,并最后安装 cuda 工具包:

sudo apt install -f
sudo apt update
sudo apt install cuda

如果成功安装,你会看到一条消息说:“successfully installed”。如果已经安装了,接着你可以看到类似下面的输出:

Install CUDA with apt

2、安装 CuDNN 库

CuDNN 下载需要花费一些功夫。Nvidia 没有直接提供下载文件(虽然它是免费的)。通过下面的步骤获取 CuDNN。

  1. 点击此处进入 Nvidia 的注册页面并创建一个帐户。第一页要求你输入你的个人资料,第二页会要求你回答几个调查问题。如果你不知道所有答案也没问题,你可以随便选择一个选项。
  2. 通过前面的步骤,Nvidia 会向你的邮箱发送一个激活链接。在你激活之后,直接进入这里的 CuDNN 下载链接。
  3. 登录之后,你需要填写另外一份类似的调查。随机勾选复选框,然后点击调查底部的 “proceed to Download”,在下一页我们点击同意使用条款。
  4. 最后,在下拉中点击 “Download cuDNN v5.1 (Jan 20, 2017), for CUDA 8.0”,最后,你需要下载这两个文件:

注意:即使上面说的是用于 Ubuntu 14.04 的库。它也适用于 16.04。

现在你已经同时有 CuDNN 的两个文件了,是时候安装它们了!在包含这些文件的文件夹内运行下面的命令:

sudo dpkg -i libcudnn5_5.1.5-1+cuda8.0_amd64.deb
sudo dpkg -i libcudnn5-dev_5.1.5-1+cuda8.0_amd64.deb

下面的图片展示了这些命令的输出:

Install the CuDNN library

3、 在 bashrc 中添加安装位置

安装位置应该被添加到 bashrc 文件中,以便系统下一次知道如何找到这些用于 CUDA 的文件。使用下面的命令打开 bashrc 文件:

sudo gedit ~/.bashrc

文件打开后,添加下面两行到文件的末尾:

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/cuda/lib64:/usr/local/cuda/extras/CUPTI/lib64"
export CUDA_HOME=/usr/local/cuda

4、 安装带有 GPU 支持的 TensorFlow

这步我们将安装带有 GPU 支持的 TensorFlow。如果你使用的是 Python 2.7,运行下面的命令:

pip install TensorFlow-gpu

如果安装了 Python 3.x,使用下面的命令:

pip3 install TensorFlow-gpu

安装完后,你会看到一条 “successfully installed” 的消息。现在,剩下要测试的是是否已经正确安装。打开终端并输入下面的命令测试:

python
import TensorFlow as tf

你应该会看到类似下面图片的输出。在图片中你可以观察到 CUDA 库已经成功打开了。如果有任何错误,消息会提示说无法打开 CUDA 甚至无法找到模块。为防你或许遗漏了上面的某步,仔细重做教程的每一步就行了。

Install TensorFlow with GPU support

5、 安装只支持 CPU 的 TensorFlow

注意:这步是对那些没有 GPU 或者没有 Nvidia GPU 的人而言的。其他人请忽略这步!!

安装只支持 CPU 的 TensorFlow 非常简单。使用下面两个命令:

pip install TensorFlow

如果你有 python 3.x,使用下面的命令:

pip3 install TensorFlow

是的,就是这么简单!

安装指南至此结束,你现在可以开始构建深度学习应用了。如果你刚刚起步,你可以在这里看下适合初学者的官方教程。如果你正在寻找更多的高级教程,你可以在这里学习了解如何设置可以高精度识别上千个物体的图片识别系统/工具。

(题图:Pixabay,CC0)


via: https://www.howtoforge.com/tutorial/installing-tensorflow-neural-network-software-for-cpu-and-gpu-on-ubuntu-16-04/

作者:Akshay Pai 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出