提交 b9f4f47d 编写于 作者: hyl-ocean's avatar hyl-ocean

校对章节 NLP From Scratch: 使用char-RNN对姓氏进行分类

上级 18d1fed4
......@@ -6,13 +6,13 @@
单击此处的[下载完整的示例代码](#sphx-glr-download-intermediate-char-rnn-classification-tutorial-py)
**作者**[Sean Robertson](https://github.com/spro/practical-pytorch)
**译者**[haiyang](https://github.com/hyl11)
我们将构建和训练基本的字符级 RNN 对单词进行分类。 本教程与以下两个教程一起,展示了如何“从头开始”进行 NLP 建模的预处理数据,特别是不使用 <cite>torchtext</cite> 的许多便利功能,因此您可以了解如何进行 NLP 建模的预处理 在低水平上工作
本篇我们将构建并训练基本的字符级 RNN 来对单词进行分类。 本教程,以及后续两个教程,展示了如何“从头开始”针对 NLP 建模过程中所需的数据进行预处理,抛开*torchtext*的许多便利功能进行编码,能够让您了解在底层针对 NLP 建模所需的数据是如何预进行处理的
字符级 RNN 将单词作为一系列字符读取-在每个步骤输出预测和“隐藏状态”,将其先前的隐藏状态输入到每个下一步。 我们将最终的预测作为输出,即单词属于哪个类别。
字符级 RNN 将单词看做字符序列进行读取并在每个步骤输出预测结果和“隐藏状态”,然后将其先前的隐藏状态输入到下一步。 我们将最终的预测结果作为输出,即该单词属于哪个类别。
具体来说,我们将训练来自 18 种起源语言的数千种姓氏,并根据拼写方式预测名称的来源
具体来说,我们将训练来自 18 种语言的数千种姓氏,并根据拼写方式预测该名称属于哪种语言,如下示例
```
$ python predict.py Hinton
......@@ -29,17 +29,17 @@ $ python predict.py Schmidhuber
**推荐读物:**
我假设您至少已经安装了 PyTorch,了解 Python 和了解 Tensors:
本篇教程假设您至少已经安装了 PyTorch,了解 Python 和 Tensors:
* [https://pytorch.org/](https://pytorch.org/) 有关安装说明
* [使用 PyTorch 进行深度学习:60 分钟的闪电战](../beginner/deep_learning_60min_blitz.html)通常开始使用 PyTorch
* [使用示例](../beginner/pytorch_with_examples.html)学习 PyTorch 进行广泛而深入的概述
* [使用 PyTorch 进行深度学习:60 分钟的闪电战](../beginner/deep_learning_60min_blitz.html)如何快速开始使用 PyTorch
* [根据示例学习Pytorch](../beginner/pytorch_with_examples.html)对 Pytorch 进行更广泛深入的了解
* [PyTorch(以前的 Torch 用户)](../beginner/former_torchies_tutorial.html)(如果您以前是 Lua Torch 用户)
了解 RNN 及其工作方式也将很有用
了解 RNN 及其工作方式也很重要
* [循环神经网络的不合理效果](https://karpathy.github.io/2015/05/21/rnn-effectiveness/)显示了许多现实生活中的例子
* [了解 LSTM 网络](https://colah.github.io/posts/2015-08-Understanding-LSTMs/)特别是关于 LSTM 的,但总体上也关于 RNN 的
* [循环神经网络的超常效果](https://karpathy.github.io/2015/05/21/rnn-effectiveness/)显示了许多现实生活中的例子
* [了解 LSTM 网络](https://colah.github.io/posts/2015-08-Understanding-LSTMs/)主要是关于 LSTM 的,但总体上也是有关 RNN 的
## 准备数据
......@@ -47,9 +47,9 @@ Note
-[这里](https://download.pytorch.org/tutorial/data.zip)下载数据,并将其提取到当前目录。
`data/names`目录中包含 18 个文本文件,名为“ [Language] .txt”。 每个文件包含一堆名称,每行一个名称,大多数都是罗马化的(但我们仍然需要从 Unicode 转换为 ASCII)。
`data/names`目录中包含 18 个文本文件,名为“ [Language] .txt”。 每个文件包含多行,每行一个姓氏,大多数都是罗马字符(但谨慎起见我们仍然需要从 Unicode 编码转换为 ASCII 编码)。
我们将得到一个字典,列出每种语言的名称列表`{language: [names ...]}`。 通用变量“类别”和“行”(在本例中为语言和名称)用于以后的扩展
处理之后我们得到一个字典,字典包含每种语言的姓氏列表`{language: [names ...]}`。 通用变量`category``line`(在本例中分别为语言和姓氏)在后续还会使用
```
from __future__ import unicode_literals, print_function, division
......@@ -104,7 +104,7 @@ Slusarski
```
现在我们有了`category_lines`,这是一个字典,将每个类别(语言)映射到行(名称)列表。 我们还跟踪了`all_categories`(只是语言列表)和`n_categories`,以供以后参考
经过上述处理,我们获得了变量`category_lines`,这是一个字典,字典索引为每个类别(语言)值为一个列表,列表包含多个行(姓氏)。 我们还保存了`all_categories`(类别(语言)列表)和`n_categories`(语言类别数量),以供后续使用
```
print(category_lines['Italian'][:5])
......@@ -120,13 +120,13 @@ Out:
### 将名称转换为张量
现在我们已经组织了所有名称,我们需要将它们转换为张量以使用它们
获取所有姓氏之后,我们需要将它们转换为张量
为了表示单个字母,我们使用大小为`<1 x n_letters>`的“ one-hot vector”。 一个热门向量用 0 填充,但当前字母的索引处的数字为 1,例如 `"b" = <0 1 0 0 0 ...>`
为了表示单个字母,我们使用大小为`<1 x n_letters>`的“ one-hot vector”。 一个“one hot”向量是当前字母的索引处为 1,其余部分为 0 的向量,例如 `"b" = <0 1 0 0 0 ...>`
为了制造一个单词,我们将其中的一些连接成 2D 矩阵`<line_length x 1 x n_letters>`
我们将每行的所有字母的“one hot”向量连接成 2D 矩阵`<line_length x 1 x n_letters>`来表示一个单词(姓氏)
额外的 1 维是因为 PyTorch 假设所有内容都是批量的-我们在这里只使用 1 的批量大小
额外的 1 维是因为 PyTorch 假设所有内容都是批量的-我们这里批量大小为 1
```
import torch
......@@ -168,9 +168,9 @@ torch.Size([5, 1, 57])
## 建立网络
进行自动分级之前,在 Torch 中创建一个循环神经网络需要在多个时间步上克隆图层的参数。 图层保留了隐藏状态和渐变,这些图层现在完全由图形本身处理。 这意味着您可以以非常“纯粹”的方式实现 RNN,作为常规的前馈层
Torch 中创建一个循环神经网络需要在多个时间步上克隆神经层的参数。 现在不同的时间步骤下网络层所保存的隐藏状态和梯度均由计算图自身处理,编程者无需关心,因此您可以向构建常见的前馈网络一样在Torch中简便的构建循环神经网络
这个 RNN 模块(主要从 PyTorch for Torch 用户教程的[复制)仅是 2 个线性层,它们在输入和隐藏状态下运行,输出之后是 LogSoftmax 层。](https://pytorch.org/tutorials/beginner/former_torchies/nn_tutorial.html#example-2-recurrent-net)
下图的 RNN 模块(主要从 [ the PyTorch for Torch users tutorial](https://pytorch.org/tutorials/beginner/former_torchies/nn_tutorial.html#example-2-recurrent-net) 复制)仅是 2 个线性层,它们读取输入和隐藏状态,并将其进行线性映射后,在讲输出结果通过 LogSoftmax 层作为本层输出。
![](https://i.imgur.com/Z2xbySO.png)
......@@ -202,7 +202,7 @@ rnn = RNN(n_letters, n_hidden, n_categories)
```
运行此网络的步骤,我们需要传递输入(在本例中为当前字母的张量)和先前的隐藏状态(首先将其初始化为零)。 我们将返回输出(每种语言的概率)和下一个隐藏状态(我们将其保留用于下一步)。
对该网络进行单步运行,我们需要传递输入(在本例中为当前字母的张量)和上一步的隐藏状态(首先将其初始化为零)。 该网络将返回输出(每种语言的概率)和下一个隐藏状态(我们将其保留用于下一步)。
```
input = letterToTensor('A')
......@@ -212,7 +212,7 @@ output, next_hidden = rnn(input, hidden)
```
为了提高效率,我们不想为每个步骤创建一个新的 Tensor,因此我们将使用`lineToTensor`而不是`letterToTensor`并使用切片。 这可以通过预先计算一批张量来进一步优化。
为了提高效率,我们不想为每个步骤创建一个新的 Tensor,因此我们将使用`lineToTensor`生成向量再进行切片,而不是多次使用`letterToTensor`。 这可以通过预先计算一批张量来进一步优化。
```
input = lineToTensor('Albert')
......@@ -232,13 +232,13 @@ tensor([[-2.9504, -2.8402, -2.9195, -2.9136, -2.9799, -2.8207, -2.8258, -2.8399,
```
您所见,输出为`<1 x n_categories>`张量,其中每个项目都是该类别的可能性(更高的可能性更大)。
上,输出为`<1 x n_categories>`张量,其中每项对应于该类别的可能性(数值更高的可能性更大)。
## 训练
### 准备训练
接受训练之前,我们应该做一些辅助功能。 首先是解释网络的输出,我们知道这是每个类别的可能性。 我们可以使用`Tensor.topk`来获得最大值的索引:
训练之前,我们需要设置一些辅助函数。 首先我们需要针对网络的输出(每个类别的可能性)进行处理,以输出其最可能的类别。 我们可以使用`Tensor.topk`来获得最大值的索引:
```
def categoryFromOutput(output):
......@@ -257,7 +257,7 @@ Out:
```
我们还将需要一种快速的方法来获取训练示例(名称及其语言):
我们还将需要一个快速获取训练示例的函数(姓氏及其语言):
```
import random
......@@ -296,9 +296,9 @@ category = Dutch / line = Robert
### 训练网络
现在,训练该网络所需要做的就是向它展示大量示例,进行猜测,并告诉它是否错误。
现在,训练该网络所需要做的就是向它输入大量示例,让网络进行猜测,并告诉它该猜测是否错误。
对于损失函数,`nn.NLLLoss`是适当的,因为 RNN 的最后一层是`nn.LogSoftmax`
`nn.NLLLoss`是比较合适的损失函数,因为 RNN 的最后一层是`nn.LogSoftmax`
```
criterion = nn.NLLLoss()
......@@ -309,9 +309,9 @@ criterion = nn.NLLLoss()
* 创建输入和目标张量
* 创建归零的初始隐藏状态
* 阅读和中的每个字母
*持下一个字母的隐藏状态
* 比较最终输出与目标
* 读入每个字母
*存隐藏状态用于下个字母
* 比较最终输出与目标张量的差距
* 反向传播
* 返回输出和损失
......@@ -337,7 +337,7 @@ def train(category_tensor, line_tensor):
```
现在,我们只需要运行大量示例。 由于`train`函数同时返回输出和损失,因此我们可以打印其猜测并跟踪绘制损失。 因为有 1000 个示例,所以我们仅打印每个`print_every`示例,并对损失进行平均
现在,我们只需要使用大量示例来运行该网络即可。 由于`train`函数同时返回输出和损失,因此我们可以打印其猜测结果并跟踪绘制损失变化。 因为有 1000 个示例,所以我们每隔`print_every`个示例打印一次,并平均这段时间内的损失然后保存下来
```
import time
......@@ -406,7 +406,7 @@ Out:
### 绘制结果
`all_losses`绘制历史损失可显示网络学习情况:
`all_losses`绘制损失的变化情况可以显示网络学习情况:
```
import matplotlib.pyplot as plt
......@@ -421,7 +421,7 @@ plt.plot(all_losses)
## 评估结果
为了查看网络在不同类别上的表现如何,我们将创建一个混淆矩阵,为每种实际语言(行)指示网络猜测(列)哪种语言。 为了计算混淆矩阵,使用`evaluate()`通过网络运行一堆样本,该样本等于`train()`减去反向传播器
为了查看网络在不同类别上的表现如何,我们将创建一个混淆矩阵,行对应于每种语言,列对应于网络猜测的语言。为了计算混淆矩阵,使用`evaluate()`函数通过训练好的网络运行一批样本,这一步类似于训练函数`train`,但是没有反向传播过程
```
# Keep track of correct guesses in a confusion matrix
......@@ -470,7 +470,7 @@ plt.show()
![../_images/sphx_glr_char_rnn_classification_tutorial_002.png](img/029a9d26725997aae97e9e3f6f10067f.jpg)
您可以从主轴上挑出一些亮点,以显示它猜错了哪些语言,例如 中文(朝鲜语)和西班牙语(意大利语)。 它似乎与希腊语搭配得很好,与英语搭配得很差(可能是因为与其他语言重叠)。
主轴上的一些亮点代表神经网络容易猜错哪些语言,例如 中文和朝鲜语,西班牙语和意大利语。 神经网络在希腊语上表现很好,在英语上表现得很差(可能是因为与其他语言重叠较多)。
### 在用户输入上运行
......@@ -516,17 +516,17 @@ Out:
```
实际 PyTorch 存储库中的脚本[的最终版本将上述代码分成几个文件:](https://github.com/spro/practical-pytorch/tree/master/char-rnn-classification)
实际 [PyTorch 存储库](https://github.com/spro/practical-pytorch/tree/master/char-rnn-classification)中的脚本将上述代码分成几个文件:
* `data.py`(加载文件)
* `model.py`(定义 RNN)
* `train.py`(进行训练)
* `predict.py`(使用命令行参数运行`predict()`
* `server.py`(通过 bottle.py 将预测用作 JSON API)
* `server.py` (通过bottle.py将预测用作 JSON API)
运行`train.py`训练并保存网络。
使用名称运行`predict.py`以查看预测
将姓氏作为输入运行`predict.py`来查看预测结果
```
$ python predict.py Hazaki
......@@ -536,7 +536,7 @@ $ python predict.py Hazaki
```
运行`server.py`并访问[http://localhost:5533/您的名字](http://localhost:5533/Yourname)以获取预测的 JSON 输出。
运行`server.py`并访问[http://localhost:5533/您的名字](http://localhost:5533/Yourname)以获取预测的 JSON 格式输出。
## 练习题
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册