pytorch深度学习和自然语言处理入门

之前也提过,pytorch之于tensorflow,优雅不是一星半点。

pytorch学习是轻松愉快了。本期文章写pytorch在nlp上的应用。(paul allen的allennlp也由tensorflow迁移到了pytorch平台,可见一斑)

导入模块:

import torch

import torch.autograd as autograd

import torch.nn as nn

import torch.optim as optim

torch.manual_seed(1)

一、线性模块,这里需要注意是y = xw+b。不是我们数学上习惯的y=wx+b(矩阵是不满足乘法交换率的)

定义一个全连接层,也就是线性仿射变换。W=(5,3),b=(3)

lin = nn.Linear(5,3)

这里需要特别注意,输入变量是n*5,输出为n*3

data = autograd.Variable(torch.randn(2,5))

lin(data)

运算得到结果如下:

Variable containing:-0.2889 0.3574 0.6554-0.9682 0.0289 0.4426[torch.FloatTensor of size 2x3]

二、非线性激活函数

常用的Relu和tanh。sigmoid因为梯度消失的问题,反而不常用。从理论上讲,非线性的激活函数可以无穷多,为什么选这两个?这是工程上的问题,因为它们的导数形式便于计算

我们用随机正态分布,初始化2*2的矩阵。

data = autograd.Variable(torch.randn(2,2))

Variable containing:-0.6331 0.8795-0.6842 0.4533[torch.FloatTensor of size 2x2]

把变量经由relu计算(Rectified Linear Unit,修正线性单元),relu的公式很简单=max(0,x),就是如果x>0,就取x,否则取0,就是把负的信号给屏蔽了。

F.relu(data)

Variable containing: 0.0000 0.8795 0.0000 0.4533[torch.FloatTensor of size 2x2]

下图的蓝线是relu

对比sigmoid类函数主要变化是:

1)单侧抑制

2)相对宽阔的兴奋边界

3)稀疏激活性。

这与人的神经皮层的工作原理接近。

另外一个很重要的激活函数就是softmax。

data = autograd.Variable(torch.randn(2,2))

Variable containing:-0.3968 -0.6571-1.6428 0.9803[torch.FloatTensor of size 2x2]

F.softmax(data,dim=0),dim=0,按第0维softmax,就是概率化。这个函数在输出层很有用,比如mnist要分成10类,那softmax就是这10类对应的概率。概率最大者就是对应的分类。(概率思维也在这里体现了)

Variable containing: 0.7766 0.1628 0.2234 0.8372[torch.FloatTensor of size 2x2]

还有一个类似的函数F.log_softmax()也是工程上的考虑,因为最小二乘损失函数求导要会带来计算量的问题,所以考虑交叉熵损失。与之配合的就是这个对数softmax

三、目标函数。也就是反身传播要优化的目标。也称为成本函数或损失函数。

四,词袋模型(Bag-Of-Words=BOW),应该算最简单的语言模型,不考虑词的位置,就是数数。比如词汇表如果就两个词,hello,world。那么"hello hello hello hello" = [4,0],'hello world hello world'=[2,2],即所谓语言模型,就是对一个字符串,或文章内容,如何进行编码,转为计算机和pytorch可以处理的向量或矩阵类型。这里的数字就是表达词的出现次数

用这个最简单的BOW,来对西班牙语和英语做分类。

先定义最简单的训练语料和测试语料。

data=[("me gusta comer en la cafeteria".split(),"SPANISH"),("Give it to me".split(),"ENGLISH"),("No creo que sea una buena idea".split(),"SPANISH"),("No it is not a good idea to get lost at sea".split(),"ENGLISH")]

test_data=[("Yo creo que si".split(),"SPANISH"),("it is lost on me".split(),"ENGLISH")]

把词下标化,计算机其实不会真的去管这个词是什么东西,有什么语义。现代统计语言模型或深度学习,确实没有管单词本身具有什么意思,而是“统计”它们出现的位置,频率,前后关系等。就已经解决了很多问题。(语义的环境,应该得交由知识图谱)

首选把词汇表单词下标算出来。

word_2_idx = {}

for sent,_ in data + test_data:

print(sent)

for word in sent:

if word not in word_2_idx:

#这里用的是这个word首次出现的位置,比如me就是第1个出现的,下标为0

word_2_idx[word] = len(word_2_idx)

有了词汇表,就可以算词汇表的长度,以及我们需要把句子分成两类。

VOCAB_SIZE = len(word_2_idx)

NUM_LABELS = 2

神经网络模型:

class BoWClassifier(nn.Module): # 从nn.Module继承bow分类器

def __init__(self, num_labels, vocab_size):

#父类初始化

super(BoWClassifier, self).__init__()

self.linear = nn.Linear(vocab_size, num_labels)

def forward(self, bow_vec):

#bow_vec是词的bow向量

return F.log_softmax(self.linear(bow_vec))

把句子变成向量:

就是用句子里的词,去词汇表里查下标,在向量对应的位置加1

def make_bow_vector(sentence, word_to_ix):

vec = torch.zeros(len(word_to_ix))

for word in sentence:

vec[word_to_ix[word]] += 1

#vec本来是个向量,变形成1*N的矩阵

return vec.view(1, -1)

make_bow_vector("Give it to me".split(),word_2_idx)

在用户手动定义Variable时,参数requires_grad默认值是False。而在Module中的层在定义时,相关Variable的requires_grad参数默认是True。

在计算图中,如果有一个输入的requires_grad是True,那么输出的requires_grad也是True。只有在所有输入的requires_grad都为False时,输出的requires_grad才为False。

关于作者:魏佳斌,互联网产品/技术总监,北京大学光华管理学院(MBA),特许金融分析师(CFA),资深产品经理/码农。偏爱python,深度关注互联网趋势,人工智能,AI金融量化。致力于使用最前沿的认知技术去理解这个复杂的世界。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180313G0PX3E00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券