Pytorch LSTM 词性判断
首先,我们定义好一个LSTM网络,然后给出一个句子,每个句子都有很多个词构成,每个词可以用一个词向量表示,这样一句话就可以形成一个序列,我们将这个序列依次传入LSTM,然后就可以得到与序列等长的输出,每个输出都表示的是一种词性,比如名词,动词之类的,还是一种分类问题,每个单词都属于几种词性中的一种。
我们可以思考一下为什么LSTM在这个问题里面起着重要的作用。如果我们完全孤立的对一个词做词性的判断这样我们需要特别高维的词向量,但是对于LSTM,它有着一个记忆的特性,这样我们就能够通过这个单词前面记忆的一些词语来对其做一个判断,比如前面如果是my,那么他紧跟的词有很大可能就是一个名词,这样就能够充分的利用上文来做这个问题。
同时我们还可以通过引入字符来增强表达,什么意思呢?也就是说一个单词有一些前缀和后缀,比如-ly这种后缀很大可能是一个副词,这样我们就能够在字符水平得到一个词性判断的更好结果。
具体怎么做呢?还是用LSTM。每个单词有不同的字母组成,比如 apple 由a p p l e构成,我们同样给这些字符词向量,这样形成了一个长度为5的序列,然后传入另外一个LSTM网络,只取最后输出的状态层作为它的一种字符表达,我们并不需要关心到底提取出来的字符表达是什么样的,在learning的过程中这些都是会被更新的参数,使得最终我们能够正确预测。
- import torch
- import torch.nn.functional as F
- from torch import nn, optim
- from torch.autograd import Variable
- training_data = [("The dog ate the apple".split(),
- ["DET", "NN", "V", "DET", "NN"]),
- ("Everybody read that book".split(), ["NN", "V", "DET",
- "NN"])]
- # 每个单词就用一个数字表示,每种词性也用一个数字表示
- word_to_idx = {}
- tag_to_idx = {}
- for context, tag in training_data:
- for word in context:
- if word not in word_to_idx:
- # 对词进行编码
- word_to_idx[word] = len(word_to_idx)
- for label in tag:
- if label not in tag_to_idx:
- # 对词性编码
- tag_to_idx[label] = len(tag_to_idx)
- alphabet = 'abcdefghijklmnopqrstuvwxyz'
- character_to_idx = {}
- for i in range(len(alphabet)):
- # 对字母编码
- character_to_idx[alphabet[i]] = i
- # 字符LSTM
- class CharLSTM(nn.Module):
- def __init__(self, n_char, char_dim, char_hidden):
- super(CharLSTM, self).__init__()
- self.char_embedding = nn.Embedding(n_char, char_dim)
- self.char_lstm = nn.LSTM(char_dim, char_hidden, batch_first=True)
- def forward(self, x):
- x = self.char_embedding(x)
- _, h = self.char_lstm(x)
- # 取隐层
- return h[0]
- class LSTMTagger(nn.Module):
- def __init__(self, n_word, n_char, char_dim, n_dim, char_hidden, n_hidden,
- n_tag):
- super(LSTMTagger, self).__init__()
- self.word_embedding = nn.Embedding(n_word, n_dim)
- self.char_lstm = CharLSTM(n_char, char_dim, char_hidden)
- self.lstm = nn.LSTM(n_dim + char_hidden, n_hidden, batch_first=True)
- self.linear1 = nn.Linear(n_hidden, n_tag)
- def forward(self, x, word):
- char = torch.FloatTensor()
- for each in word:
- char_list = []
- for letter in each:
- # 对词进行字母编码
- char_list.append(character_to_idx[letter.lower()])
- char_list = torch.LongTensor(char_list)
- char_list = char_list.unsqueeze(0)
- if torch.cuda.is_available():
- tempchar = self.char_lstm(Variable(char_list).cuda())
- else:
- tempchar = self.char_lstm(Variable(char_list))
- tempchar = tempchar.squeeze(0)
- char = torch.cat((char, tempchar.cpu().data), 0)
- if torch.cuda.is_available():
- char = char.cuda()
- char = Variable(char)
- x = self.word_embedding(x)
- x = torch.cat((x, char), 1) # char编码与word编码cat
- x = x.unsqueeze(0)
- # 取输出层 句长*n_hidden
- x, _ = self.lstm(x)
- x = x.squeeze(0)
- x = self.linear1(x)
- y = F.log_softmax(x)
- return y
- model = LSTMTagger(
- len(word_to_idx), len(character_to_idx), 10, 100, 50, 128, len(tag_to_idx))
- if torch.cuda.is_available():
- model = model.cuda()
- criterion = nn.CrossEntropyLoss()
- optimizer = optim.SGD(model.parameters(), lr=1e-2)
- def make_sequence(x, dic):
- idx = [dic[i] for i in x]
- idx = Variable(torch.LongTensor(idx))
- return idx
- for epoch in range(300):
- print('*' * 10)
- print('epoch {}'.format(epoch + 1))
- running_loss = 0
- for data in training_data:
- word, tag = data
- word_list = make_sequence(word, word_to_idx)
- tag = make_sequence(tag, tag_to_idx)
- if torch.cuda.is_available():
- word_list = word_list.cuda()
- tag = tag.cuda()
- # forward
- out = model(word_list, word)
- loss = criterion(out, tag)
- running_loss += loss.data[0]
- # backward 三步常规操作
- optimizer.zero_grad()
- loss.backward()
- optimizer.step()
- print('Loss: {}'.format(running_loss / len(data)))
- print()
- input = make_sequence("Everybody ate the apple".split(), word_to_idx)
- if torch.cuda.is_available():
- input = input.cuda()
- model.eval() #对dropout和batch normalization的操作在训练和测试的时候是不一样
- out = model(input, "Everybody ate the apple".split())
- print(out)
首先n_word 和 n_dim来定义单词的词向量维度,n_char和char_dim来定义字符的词向量维度,char_hidden表示CharLSTM输出的维度,n_hidden表示每个单词作为序列输入的LSTM输出维度,最后n_tag表示输出的词性的种类。
接着开始前向传播,不仅要传入一个编码之后的句子,同时还需要传入原本的单词,因为需要对字符做一个LSTM,所以传入的参数多了一个word_data表示一个句子的所有单词。
然后就是将每个单词传入CharLSTM,得到的结果和单词的词向量拼在一起形成一个新的输入,将输入传入LSTM里面,得到输出,最后接一个全连接层,将输出维数定义为label的数目。
特别要注意里面有一些unsqueeze(增维)和squeeze(降维)是因为LSTM的输入要求要带上batch_size(这里是1),torch.cat里面0和1分别表示沿着行和列来拼接。
预测一下 Everybody ate the apple 这句话每个词的词性,一共有3种词性,DET,NN,V。最后得到的结果为:
一共有4行,每行里面取最大的,那么第一个词的词性就是NN,第二个词是V,第三个词是DET,第四个词是NN。这个是相符的。
参考自:https://sherlockliao.github.io/2017/06/05/lstm%20language/
Pytorch LSTM 词性判断的更多相关文章
- pytorch lstm crf 代码理解 重点
好久没有写博客了,这一次就将最近看的pytorch 教程中的lstm+crf的一些心得与困惑记录下来. 原文 PyTorch Tutorials 参考了很多其他大神的博客,https://blog.c ...
- pytorch lstm crf 代码理解
好久没有写博客了,这一次就将最近看的pytorch 教程中的lstm+crf的一些心得与困惑记录下来. 原文 PyTorch Tutorials 参考了很多其他大神的博客,https://blog.c ...
- pytorch, LSTM介绍
本文中的RNN泛指LSTM,GRU等等 CNN中和RNN中batchSize的默认位置是不同的. CNN中:batchsize的位置是position 0. RNN中:batchsize的位置是pos ...
- pytorch LSTM情感分类全部代码
先运行main.py进行文本序列化,再train.py模型训练 dataset.py from torch.utils.data import DataLoader,Dataset import to ...
- Python中利用LSTM模型进行时间序列预测分析
时间序列模型 时间序列预测分析就是利用过去一段时间内某事件时间的特征来预测未来一段时间内该事件的特征.这是一类相对比较复杂的预测建模问题,和回归分析模型的预测不同,时间序列模型是依赖于事件发生的先后顺 ...
- 神经网络与数字货币量化交易系列(1)——LSTM预测比特币价格
首发地址:https://www.fmz.com/digest-topic/4035 1.简单介绍 深度神经网络这些年越来越热门,在很多领域解决了过去无法解决的难题,体现了强大的能力.在时间序列的预测 ...
- 预训练语言模型的前世今生 - 从Word Embedding到BERT
预训练语言模型的前世今生 - 从Word Embedding到BERT 本篇文章共 24619 个词,一个字一个字手码的不容易,转载请标明出处:预训练语言模型的前世今生 - 从Word Embeddi ...
- 大话循环神经网络(RNN)
在上一篇文章中,介绍了 卷积神经网络(CNN)的算法原理,CNN在图像识别中有着强大.广泛的应用,但有一些场景用CNN却无法得到有效地解决,例如: 语音识别,要按顺序处理每一帧的声音信息,有些结果 ...
- AI 智能写情诗、藏头诗
一.AI 智能情诗.藏头诗展示 最近使用PyTorch的LSTM训练一个写情诗(七言)的模型,可以随机生成情诗.也可以生成藏头情诗. 在特殊的日子用AI生成一首这样的诗,是不是很酷!下面分享下AI 智 ...
随机推荐
- 一个漂亮的php验证码类
一个漂亮的php验证码类(分享) 作者: 字体:[增加 减小] 类型:转载 下面小编就为大家分享一个漂亮的php验证码类.需要的朋友可以过来参考下 直接上代码: 复制代码 代码如下: //验证 ...
- aix装python
网址是:http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html 在AIX下安装python Python是个 ...
- 转-CSRF&OWASP CSRFGuard
一. 什么是CSRF?CSRF(Cross-Site Request Forgery)直译的话就是跨站点请求伪造也就是说在用户会话下对某个需要验证的网络应用发送GET/POST请求——而这些请求是未经 ...
- makefile 中添加依赖的库文件
当库文件中包含多个头文件和c源文件时,需要执行如下步骤: 1) makefile中添加 库文件依赖, -L 后面跟库文件的路径, -l(小写)后面跟库的名字 2)将库文件中的头文件添加到工程中去,使 ...
- javascript for循环 日期 select
2016年12月28日 20:01:54 星期三 html: <a href="aaaa">AAAA</a> <a href="bbbb&q ...
- UniversalImageLoader(异步加载大量图片)
UniversalImageLoader是用于加载图片的一个开源项目,UniversalImageLoader是实现异步加载大量图片的源码和例子,包括缓存.硬盘缓存.容错机制等技术.在其项目介绍中是这 ...
- 自动化工具 Sikuli-Script 使用
Sikuli-IDE用起来方便,但是用到实际项目中还是有局限性的,Sikuli提供了Sikuli-Script的jar包,在Sikuli-X的安装目录下,这样就可以在 eclipse中使用JAVA编写 ...
- 生产环境优雅的重启基于Nginx、Tornado的Web服务进程
Nginx是一个高效的Web服务器及代理服务器,Tornado是一个基于epoll的异步Web开发框架,通常使用Nginx做为Web服务器时,都会以FastCGI模式,而我们从开发.调试.运维的角度考 ...
- Guideline 5.2.1 - Legal - Intellectual Property 解决方案
最近在上架公司公司项目的时候遇到这个问题什么5.2.1 然后去了解发现最近不少人都遇到了这个问题.先说一下 我上架的APP是一个医疗的APP然后说需要什么医疗资质,估计是账号的公司资质不够吧.后面和苹 ...
- python魔法函数之__getattr__与__getattribute__
getattr 在访问对象的属性不存在时,调用__getattr__,如果没有定义该魔法函数会报错 class Test: def __init__(self, name, age): self.na ...