从零开始学习NLP
在这个由三部分组成的系列中,你将构建并训练一个基本的字符级循环神经网络 (RNN) 来对单词进行分类。
你将学习
- 如何从零开始构建循环神经网络
- NLP 的基本数据处理技术
- 如何训练 RNN 以识别单词的语言来源。
从零开始学自然语言处理:使用字符级 RNN 对名字进行分类
我们将构建并训练一个基本的字符级循环神经网络 (RNN) 来对单词进行分类。展示了如何预处理数据以建模 NLP。特别是,这些教程展示了如何以低层次处理数据来建模 NLP。
字符级 RNN 将单词读取为一系列字符 - 在每个步骤输出一个预测和“隐藏状态”,并将其先前的隐藏状态馈送到下一个步骤中。我们将最终预测作为输出,即单词所属的类别。
具体来说,我们将训练数据集包含来自 18 种语言的数千个姓氏,并根据拼写预测名字来自哪种语言。
准备 Torch
设置 torch,使其默认使用正确的设备,并根据您的硬件(CPU 或 CUDA)使用 GPU 加速。
import torch# Check if CUDA is available
device = torch.device('cpu')
if torch.cuda.is_available():device = torch.device('cuda')torch.set_default_device(device)
print(f"Using device = {torch.get_default_device()}")
输出:
Using device = cuda:0
准备数据
从此处下载数据并将其解压到当前目录。
data/names
目录中包含 18 个文本文件,文件名格式为 [Language].txt
。每个文件包含许多名字,每行一个,大部分已罗马化(但我们仍然需要从 Unicode 转换为 ASCII)。
第一步是定义和清理我们的数据。首先,我们需要将 Unicode 转换为纯 ASCII 以限制 RNN 输入层。这通过将 Unicode 字符串转换为 ASCII 并只允许一小部分允许的字符来实现。
import string
import unicodedata# We can use "_" to represent an out-of-vocabulary character, that is, any character we are not handling in our model
allowed_characters = string.ascii_letters + " .,;'" + "_"
n_letters = len(allowed_characters)# Turn a Unicode string to plain ASCII, thanks to https://stackoverflow.com/a/518232/2809427
def unicodeToAscii(s):return ''.join(c for c in unicodedata.normalize('NFD', s)if unicodedata.category(c) != 'Mn'and c in allowed_characters)
这是一个将 Unicode 字母名字转换为纯 ASCII 的示例。这简化了输入层
print (f"converting 'Ślusàrski' to {unicodeToAscii('Ślusàrski')}")
输出:
converting 'Ślusàrski' to Slusarski
将名字转换为张量(Tensors)
现在我们已经组织好所有名字,我们需要将它们转换为张量才能使用它们。
为了表示单个字母,我们使用大小为 <1 x n_letters>
的“one-hot 向量”。one-hot 向量除了当前字母索引处为 1 外,其余均为 0,例如 "b" = <0 1 0 0 0 ...>
。
为了构成一个单词,我们将这些向量连接成一个 2D 矩阵 <line_length x 1 x n_letters>
。
额外的维度 1 是因为 PyTorch 假定所有内容都是批量的 - 我们这里仅使用批量大小为 1。
# Find letter index from all_letters, e.g. "a" = 0
def letterToIndex(letter):# return our out-of-vocabulary character if we encounter a letter unknown to our modelif letter not in allowed_characters:return allowed_characters.find("_")else:return allowed_characters.find(letter)# Turn a line into a <line_length x 1 x n_letters>,
# or an array of one-hot letter vectors
def lineToTensor(line):tensor = torch.zeros(len(line), 1, n_letters)for li, letter in enumerate(line):tensor[li][0][letterToIndex(letter)] = 1return tensor
这里有一些如何对单个字符或多个字符字符串使用 lineToTensor()
的示例。
print (f"The letter 'a' becomes {lineToTensor('a')}") #notice that the first position in the tensor = 1
print (f"The name 'Ahn' becomes {lineToTensor('Ahn')}") #notice '