一个很赞NLP入门代码练习库(含Pytorch和Tensorflow版本)
Posted 机器学习算法与自然语言处理
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个很赞NLP入门代码练习库(含Pytorch和Tensorflow版本)相关的知识,希望对你有一定的参考价值。
重磅干货,第一时间送达
github:https://github.com/graykode/nlp-tutorial
该仓库中绝大部分内容代码不超过100行代码,包括了NLP中比较全面的基础内容:
如基本的 Embedding 模型
经典的CNN,RNN的模型实现:
Attention,transformer,以及目前火热的bert相关实现。代码量以及相关实现任务可参考如下:
笔者点开NNLM这个库,打开Torch版本:
# code by Tae Hwan Jung @graykode
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
dtype = torch.FloatTensor
sentences = [ "i like dog", "i love coffee", "i hate milk"]
word_list = " ".join(sentences).split()
word_list = list(set(word_list))
word_dict = {w: i for i, w in enumerate(word_list)}
number_dict = {i: w for i, w in enumerate(word_list)}
n_class = len(word_dict) # number of Vocabulary
# NNLM Parameter
n_step = 2 # n-1 in paper
n_hidden = 2 # h in paper
m = 2 # m in paper
def make_batch(sentences):
input_batch = []
target_batch = []
for sen in sentences:
word = sen.split()
input = [word_dict[n] for n in word[:-1]]
target = word_dict[word[-1]]
input_batch.append(input)
target_batch.append(target)
return input_batch, target_batch
# Model
class NNLM(nn.Module):
def __init__(self):
super(NNLM, self).__init__()
self.C = nn.Embedding(n_class, m)
self.H = nn.Parameter(torch.randn(n_step * m, n_hidden).type(dtype))
self.W = nn.Parameter(torch.randn(n_step * m, n_class).type(dtype))
self.d = nn.Parameter(torch.randn(n_hidden).type(dtype))
self.U = nn.Parameter(torch.randn(n_hidden, n_class).type(dtype))
self.b = nn.Parameter(torch.randn(n_class).type(dtype))
def forward(self, X):
X = self.C(X)
X = X.view(-1, n_step * m) # [batch_size, n_step * n_class]
tanh = torch.tanh(self.d + torch.mm(X, self.H)) # [batch_size, n_hidden]
output = self.b + torch.mm(X, self.W) + torch.mm(tanh, self.U) # [batch_size, n_class]
return output
model = NNLM()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
input_batch, target_batch = make_batch(sentences)
input_batch = Variable(torch.LongTensor(input_batch))
target_batch = Variable(torch.LongTensor(target_batch))
# Training
for epoch in range(5000):
optimizer.zero_grad()
output = model(input_batch)
# output : [batch_size, n_class], target_batch : [batch_size] (LongTensor, not one-hot)
loss = criterion(output, target_batch)
if (epoch + 1)%1000 == 0:
print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))
loss.backward()
optimizer.step()
# Predict
predict = model(input_batch).data.max(1, keepdim=True)[1]
# Test
print([sen.split()[:2] for sen in sentences], '->', [number_dict[n.item()] for n in predict.squeeze()])
亲测有效,代码也非常简洁,作为入门学习已经足矣,虽说小有瑕疵是pytorch版本不是最新版本,但不妨碍我们利用该代码学习夯实相关知识点。
最近也在带着几个大二的新手,让他们学习该代码,给代码做了一些注释和知识讲解,如下:
# code by Tae Hwan Jung @graykode
import numpy as np
import torch
import torch.nn as nn # torch的神经网络库,里面有很多基本的神经网络基础代码,比如Conv2d,ReLU等
import torch.optim as optim # optimizer的简称,是实现各种优化算法的包,比如梯度下降,比如Adam
# 这个库中提供了类和函数用来对任意标量函数进行求导,引入Variable可以实现自动求导
from torch.autograd import Variable
# 在pyTorch中,基本的数据结构是Torch,包含了多维张量,可以就把它看作是n维矩阵的一个表示
dtype = torch.FloatTensor # 创建一个浮点tensor,还没有对其赋值和规定其维度大小
# 本次将要训练的句子集,也就是输入
sentences = [ "i like dog", "i love coffee", "i hate milk"]
# 以下两行代码是将上面sentences列表中的单词提取出来
word_list = " ".join(sentences).split() # 每句首先使用空格分割形成一个单词列表
word_list = list(set(word_list)) # 用一个小技巧,先让list变成set,然后再变回去,这样就提取出了单词列表
# 以下两行是建立单词对应序号的索引字典word_dict和序号对应单词的索引number_dict
# 使用了enumerate函数,使得在遍历的同时可以追踪到序号,i, w是元组,其实可以写成(i, w)
word_dict = {w: i for i, w in enumerate(word_list)} # w: i 单词对应序号键值对
number_dict = {i: w for i, w in enumerate(word_list)} # i: w 序号对应单词键值对
n_class = len(word_dict) # number of Vocabulary
# NNLM Parameter
n_step = 2 # n-1 in paper 根据前两个单词预测第三个单词
n_hidden = 2 # h in paper 隐藏层神经元个数
m = 2 # m in paper 词向量维数
# make_batch是将输入sentences中的前面的单词和最后一个单词分开
def make_batch(sentences):
input_batch = [] # 用于存放输入的单词
target_batch = [] # 用于存放最后一个单词,模拟预测的结果
for sen in sentences: # 对sentences中的每个句子
word = sen.split() # 默认空格分割
input = [word_dict[n] for n in word[:-1]] # 注意这里的切片不能切反了,[:-1]是刚好最后一个不要
target = word_dict[word[-1]] # 最后一个单词
# 将分离好的输入结果放到列表中存好
input_batch.append(input)
target_batch.append(target)
return input_batch, target_batch
# Model NNLM模型部分
class NNLM(nn.Module): # 定义网络时一般是继承torch.nn.Module创建新的子类
def __init__(self): # 构造函数
super(NNLM, self).__init__() # 子类构造函数强制调用父类构造函数
# 参数都是论文中的数学表示
# 以下是设置神经网络中的各项参数
# 一个嵌入字典,第一个参数是嵌入字典的大小,第二个参数是每个嵌入向量的大小
# C词向量C(w)存在于矩阵C(|V|*m)中,矩阵C的行数表示词汇表的大小;列数表示词向量C(w)的维度。矩阵C的某一行对应一个单词的词向量表示
self.C = nn.Embedding(n_class, m)
# Parameter类是Variable的子类,常用于模块参数,作为属性时会被自动加入到参数列表中
# 隐藏层的权重(h*(n-1)m)
self.H = nn.Parameter(torch.randn(n_step * m, n_hidden).type(dtype))
# 输入层到输出层权重(|V|*(n-1)m)
self.W = nn.Parameter(torch.randn(n_step * m, n_class).type(dtype))
# 隐藏层偏置bias(h)
self.d = nn.Parameter(torch.randn(n_hidden).type(dtype))
# 隐藏层到输出层的权重(|V|*h)
self.U = nn.Parameter(torch.randn(n_hidden, n_class).type(dtype))
# 输出层的偏置bias(|V|)
self.b = nn.Parameter(torch.randn(n_class).type(dtype))
# 前向传播过程,如paper中描述
def forward(self, X):
X = self.C(X)
X = X.view(-1, n_step * m) # [batch_size, n_step * n_class]
tanh = torch.tanh(self.d + torch.mm(X, self.H)) # [batch_size, n_hidden]
output = self.b + torch.mm(X, self.W) + torch.mm(tanh, self.U) # [batch_size, n_class]
return output
model = NNLM() # 初始化模型
# 损失函数定义为交叉熵损失函数
criterion = nn.CrossEntropyLoss()
# 采用Adam优化算法,学习率0.001
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 以下三行将输入进行torch包装,用Variable可以实现自动求导
input_batch, target_batch = make_batch(sentences)
input_batch = Variable(torch.LongTensor(input_batch))
target_batch = Variable(torch.LongTensor(target_batch))
# Training 训练过程,5000轮
for epoch in range(5000):
optimizer.zero_grad() # 初始化
output = model(input_batch)
# output : [batch_size, n_class], target_batch : [batch_size] (LongTensor, not one-hot)
loss = criterion(output, target_batch)
if (epoch + 1)%1000 == 0: # 每1000轮查看一次损失函数变化
print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))
# 自动求导反向传播,使用step()来更新参数
loss.backward()
optimizer.step()
# Predict 预测值
predict = model(input_batch).data.max(1, keepdim=True)[1]
# Test 测试
print([sen.split()[:2] for sen in sentences], '->', [number_dict[n.item()] for n in predict.squeeze()])
```
后续也会慢慢放出学习笔记,最后希望大家有所收获。
推荐阅读:
以上是关于一个很赞NLP入门代码练习库(含Pytorch和Tensorflow版本)的主要内容,如果未能解决你的问题,请参考以下文章
Pytorch入门练习-kaggle手写字识别神经网络(SNN)实现
Github 3.5K 星PyTorch资源列表:450个NLP/CV/SP论文实现库教程&示例
Github2.2K星PyTorch资源列表:450个NLP/CV/SP论文实现教程示例
最强 NLP 预训练模型库 PyTorch-Transformers 正式开源:支持 6 个预训练框架,27 个预训练模型