1.1 文章组织

本文简要介绍了BiLSTM的基本原理,并以句子级情感分类任务为例介绍为什么需要使用LSTM或BiLSTM进行建模。在文章的最后,我们给出在PyTorch下BiLSTM的实现代码,供读者参考。

1.2 情感分类任务

自然语言处理中情感分类任务是对给定文本进行情感倾向分类的任务,粗略来看可以认为其是分类任务中的一类。对于情感分类任务,目前通常的做法是先对词或者短语进行表示,再通过某种组合方式把句子中词的表示组合成句子的表示。最后,利用句子的表示对句子进行情感分类。

举一个对句子进行褒贬二分类的例子。

句子:我爱赛尔

情感标签:褒义

1.3 什么是LSTM和BiLSTM?

LSTM的全称是Long Short-Term Memory,它是RNN(Recurrent Neural Network)的一种。LSTM由于其设计的特点,非常适合用于对时序数据的建模,如文本数据。BiLSTM是Bi-directional Long Short-Term Memory的缩写,是由前向LSTM与后向LSTM组合而成。两者在自然语言处理任务中都常被用来建模上下文信息。

1.4 为什么使用LSTM与BiLSTM?

将词的表示组合成句子的表示,可以采用相加的方法,即将所有词的表示进行加和,或者取平均等方法,但是这些方法没有考虑到词语在句子中前后顺序。如句子“我不觉得他好”。“不”字是对后面“好”的否定,即该句子的情感极性是贬义。使用LSTM模型可以更好的捕捉到较长距离的依赖关系。因为LSTM通过训练过程可以学到记忆哪些信息和遗忘哪些信息。

但是利用LSTM对句子进行建模还存在一个问题:无法编码从后到前的信息。在更细粒度的分类时,如对于强程度的褒义、弱程度的褒义、中性、弱程度的贬义、强程度的贬义的五分类任务需要注意情感词、程度词、否定词之间的交互。举一个例子,“这个餐厅脏得不行,没有隔壁好”,这里的“不行”是对“脏”的程度的一种修饰,通过BiLSTM可以更好的捕捉双向的语义依赖。

二、BiLSTM原理简介

2.1 LSTM介绍

2.1.1 总体框架

总体框架如图

2.1.2 详细介绍计算过程

计算遗忘门,选择要遗忘的信息。

计算记忆门,选择要记忆的信息。

计算当前时刻细胞状态

计算输出门和当前时刻隐层状态

最终,我们可以得到与句子长度相同的隐层状态序列

2.2 BiLSTM介绍

前向的LSTM与后向的LSTM结合成BiLSTM。比如,我们对“我爱中国”这句话进行编码,模型如图6所示。

对于情感分类任务来说,我们采用的句子的表示往往是 。因为其包含了前向与后向的所有信息,如图

三、BiLSTM代码实现样例
3.1 模型搭建

使用PyTorch搭建BiLSTM样例代码。代码地址为

https://github.com/albertwy/BiLSTM/
#!/usr/bin/env python
# coding:utf8import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variabletorch.manual_seed(123456)class BLSTM(nn.Module):"""Implementation of BLSTM Concatenation for sentiment classification task"""def __init__(self, embeddings, input_dim, hidden_dim, num_layers, output_dim, max_len=40, dropout=0.5):super(BLSTM, self).__init__()self.emb = nn.Embedding(num_embeddings=embeddings.size(0),embedding_dim=embeddings.size(1),padding_idx=0)self.emb.weight = nn.Parameter(embeddings)self.input_dim = input_dimself.hidden_dim = hidden_dimself.output_dim = output_dim# sen encoderself.sen_len = max_lenself.sen_rnn = nn.LSTM(input_size=input_dim,hidden_size=hidden_dim,num_layers=num_layers,dropout=dropout,batch_first=True,bidirectional=True)self.output = nn.Linear(2 * self.hidden_dim, output_dim)def bi_fetch(self, rnn_outs, seq_lengths, batch_size, max_len):rnn_outs = rnn_outs.view(batch_size, max_len, 2, -1)# (batch_size, max_len, 1, -1)fw_out = torch.index_select(rnn_outs, 2, Variable(torch.LongTensor([0])).cuda())fw_out = fw_out.view(batch_size * max_len, -1)bw_out = torch.index_select(rnn_outs, 2, Variable(torch.LongTensor([1])).cuda())bw_out = bw_out.view(batch_size * max_len, -1)batch_range = Variable(torch.LongTensor(range(batch_size))).cuda() * max_lenbatch_zeros = Variable(torch.zeros(batch_size).long()).cuda()fw_index = batch_range + seq_lengths.view(batch_size) - 1fw_out = torch.index_select(fw_out, 0, fw_index)  # (batch_size, hid)bw_index = batch_range + batch_zerosbw_out = torch.index_select(bw_out, 0, bw_index)outs = torch.cat([fw_out, bw_out], dim=1)return outsdef forward(self, sen_batch, sen_lengths, sen_mask_matrix):""":param sen_batch: (batch, sen_length), tensor for sentence sequence:param sen_lengths::param sen_mask_matrix::return:"""''' Embedding Layer | Padding | Sequence_length 40'''sen_batch = self.emb(sen_batch)batch_size = len(sen_batch)''' Bi-LSTM Computation '''sen_outs, _ = self.sen_rnn(sen_batch.view(batch_size, -1, self.input_dim))sen_rnn = sen_outs.contiguous().view(batch_size, -1, 2 * self.hidden_dim)  # (batch, sen_len, 2*hid)''' Fetch the truly last hidden layer of both sides'''sentence_batch = self.bi_fetch(sen_rnn, sen_lengths, batch_size, self.sen_len)  # (batch_size, 2*hid)representation = sentence_batchout = self.output(representation)out_prob = F.softmax(out.view(batch_size, -1))return out_prob

__init__()函数中对网络进行初始化,设定词向量维度,前向/后向LSTM中隐层向量的维度,还有要分类的类别数等。

bi_fetch()函数的作用是将  与  拼接起来并返回拼接后的向量。由于使用了batch,所以需要使用句子长度用来定位开始padding时前一个时刻的输出的隐层向量。

forward()函数里进行前向计算,得到各个类别的概率值。

3.2 模型训练

def train(model, training_data, args, optimizer, criterion):model.train()batch_size = args.batch_sizesentences, sentences_seqlen, sentences_mask, labels = training_data# print batch_size, len(sentences), len(labels)assert batch_size == len(sentences) == len(labels)''' Prepare data and prediction'''sentences_, sentences_seqlen_, sentences_mask_ = \var_batch(args, batch_size, sentences, sentences_seqlen, sentences_mask)labels_ = Variable(torch.LongTensor(labels))if args.cuda:labels_ = labels_.cuda()assert len(sentences) == len(labels)model.zero_grad()probs = model(sentences_, sentences_seqlen_, sentences_mask_)loss = criterion(probs.view(len(labels_), -1), labels_)loss.backward()optimizer.step()

代码中training_data是一个batch的数据,其中包括输入的句子sentences(句子中每个词以词下标表示),输入句子的长度sentences_seqlen,输入的句子对应的情感类别labels。 训练模型前,先清空遗留的梯度值,再根据该batch数据计算出来的梯度进行更新模型。

    model.zero_grad()probs = model(sentences_, sentences_seqlen_, sentences_mask_)loss = criterion(probs.view(len(labels_), -1), labels_)loss.backward()optimizer.step()

3.3 模型测试

以下是进行模型测试的代码。

def test(model, dataset, args, data_part="test"):""":param model::param args::param dataset::param data_part::return:"""tvt_set = dataset[data_part]tvt_set = yutils.YDataset(tvt_set["xIndexes"],tvt_set["yLabels"],to_pad=True, max_len=args.sen_max_len)test_set = tvt_setsentences, sentences_seqlen, sentences_mask, labels = test_set.next_batch(len(test_set))assert len(test_set) == len(sentences) == len(labels)tic = time.time()model.eval()''' Prepare data and prediction'''batch_size = len(sentences)sentences_, sentences_seqlen_, sentences_mask_ = \var_batch(args, batch_size, sentences, sentences_seqlen, sentences_mask)probs = model(sentences_, sentences_seqlen_, sentences_mask_)_, pred = torch.max(probs, dim=1)if args.cuda:pred = pred.view(-1).cpu().data.numpy()else:pred = pred.view(-1).data.numpy()tit = time.time() - ticprint "  Predicting {:d} examples using {:5.4f} seconds".format(len(test_set), tit)labels = numpy.asarray(labels)''' log and return prf scores '''accuracy = test_prf(pred, labels)return accuracydef cal_prf(pred, right, gold, formation=True, metric_type=""):""":param pred: predicted labels:param right: predicting right labels:param gold: gold labels:param formation: whether format the float to 6 digits:param metric_type::return: prf for each label"""''' Pred: [0, 2905, 0]  Right: [0, 2083, 0]  Gold: [370, 2083, 452] '''num_class = len(pred)precision = [0.0] * num_classrecall = [0.0] * num_classf1_score = [0.0] * num_classfor i in xrange(num_class):''' cal precision for each class: right / predict '''precision[i] = 0 if pred[i] == 0 else 1.0 * right[i] / pred[i]''' cal recall for each class: right / gold '''recall[i] = 0 if gold[i] == 0 else 1.0 * right[i] / gold[i]''' cal recall for each class: 2 pr / (p+r) '''f1_score[i] = 0 if precision[i] == 0 or recall[i] == 0 \else 2.0 * (precision[i] * recall[i]) / (precision[i] + recall[i])if formation:precision[i] = precision[i].__format__(".6f")recall[i] = recall[i].__format__(".6f")f1_score[i] = f1_score[i].__format__(".6f")''' PRF for each label or PRF for all labels '''if metric_type == "macro":precision = sum(precision) / len(precision)recall = sum(recall) / len(recall)f1_score = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0elif metric_type == "micro":precision = 1.0 * sum(right) / sum(pred) if sum(pred) > 0 else 0recall = 1.0 * sum(right) / sum(gold) if sum(recall) > 0 else 0f1_score = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0return precision, recall, f1_score

四、总结

本文中,我们结合情感分类任务介绍了LSTM以及BiLSTM的基本原理,并给出一个BiLSTM样例代码。除了情感分类任务,LSTM与BiLSTM在自然语言处理领域的其它任务上也得到了广泛应用,如机器翻译任务中使用其进行源语言的编码和目标语言的解码,机器阅读理解任务中使用其对文章和问题的编码等。

五、参考资料

http://colah.github.io/posts/2015-08-Understanding-LSTMs/

LSTM 与 Bilstm介绍(包含代码实现、Python)相关推荐

  1. BILSTM详细介绍及代码实现

    BILSTM原理介绍:https://blog.csdn.net/sinat_24330297/article/details/102487270 BiLSTM介绍及代码实现:https://www. ...

  2. [Python人工智能] 二十八.Keras深度学习中文文本分类万字总结(CNN、TextCNN、LSTM、BiLSTM、BiLSTM+Attention)

    从本专栏开始,作者正式研究Python深度学习.神经网络及人工智能相关知识.前一篇文章分享了BiLSTM-CRF模型搭建及训练.预测,最终实现医学命名实体识别实验.这篇文章将详细讲解Keras实现经典 ...

  3. DEMATEL-ISM模型的Python实现——方法介绍以及代码复现

    DEMATEL-ISM模型的Python实现--方法介绍以及代码复现 前言 DEMATEL-ISM分析方法 方法简介 步骤 明确系统要素 确定直接影响矩阵 规范影响矩阵 计算综合影响矩阵 计算各个要素 ...

  4. 数据代码分享|PYTHON用NLP自然语言处理LSTM神经网络TWITTER推特灾难文本数据、词云可视化...

    全文下载链接:http://tecdat.cn/?p=28877 作者:Yunfan Zhang Twitter是一家美国社交网络及微博客服务的网站,致力于服务公众对话.迄今为止,Twitter的日活 ...

  5. python简单代码画曲线图教程-Python绘制折线图和散点图的详细方法介绍(代码示例)...

    本篇文章给大家带来的内容是关于Python绘制折线图和散点图的详细方法介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 1.绘制折线图和散点图要用到matplotlib ...

  6. python画折线图代码-Python绘制折线图和散点图的详细方法介绍(代码示例)

    本篇文章给大家带来的内容是关于Python绘制折线图和散点图的详细方法介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 1.绘制折线图和散点图要用到matplotlib ...

  7. 机器学习之MATLAB代码--LSTM和BiLSTM预测对比(十五)

    机器学习之MATLAB代码--LSTM和BiLSTM预测对比(十五) 代码 数据 结果 代码 1. clc; clear; close all; %% 导入数据 load DATA; % 导入60天的 ...

  8. 联邦学习算法介绍-FedAvg详细案例-Python代码获取

    联邦学习算法介绍-FedAvg详细案例-Python代码获取 一.联邦学习系统框架 二.联邦平均算法(FedAvg) 三.联邦随梯度下降算法 (FedSGD) 四.差分隐私随联邦梯度下降算法 (DP- ...

  9. python代码块-python代码块

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. 开发准备cas 的 python sdk 包含了用于访问和操作 cas ...

最新文章

  1. 【推导】【线段树】hdu5929 Basic Data Structure
  2. c语言什么是合法的变量名,在C语言中,下列合法的变量名包括
  3. poj1815最小割
  4. NYOJ 1075 (递推 + 矩阵快速幂)
  5. 【机器学习】机器学习的学习经验总结!
  6. 论文浅尝 | 面向简单知识库问答的模式修正强化策略
  7. myEclipse背景控制插件方案 内附使用说明
  8. 系统最小的服务最小的权限最大的安全。
  9. 一分钟教你学会配置eslint,还在为风格单双引号,对象末位逗号要不要,引用各种报错而烦恼?(建议收藏!详细中文注释)...
  10. 《构建之法》 第5.5 第6 第7章
  11. java使用python爬虫,如何使用 Python 爬虫爬取 Java 题库?
  12. 微信电影影视小程序系统源码
  13. 虚拟现实未来前景无限
  14. 计算机无法装补丁,主编教您win7 sp1补丁安装失败怎么办
  15. 常见十大量化投资策略
  16. 【数据分析day04】美国2012年总统候选人政治献金数据分析
  17. 大规模MIP的精确算法和实现
  18. SLAM的数学基础(3):几种常见的概率分布的实现及验证
  19. bzoj4372 烁烁的游戏
  20. Mysql组复制(MGR)——前提及限制

热门文章

  1. 微生物组-宏基因组分析第8期 (报名直播课免费参加线下课2020.7,最后一周)
  2. Digital Text Animations for Mac - 未来感活力全屏标题动画fcpx插件
  3. 适用于Photoshop的人像美容磨皮ps插件:Beauty Retouch Panel 2021 Mac
  4. 解决mac 系统软件被阻止载入点允许没反应的问题
  5. 解决安装Tuxera NTFS For Mac后依旧无法写入的问题
  6. python儿童入门书_一款儿童编程入门的理想工具——PythonTurtle
  7. P1420 最长连号(python3实现)
  8. P5708 【深基2.习2】三角形面积(python3实现)
  9. 1.3编程基础之算术表达式与顺序执行 19 AXB问题
  10. 第58课 百钱买百鸡(完整) 3.完善程序 (《小学生C++趣味编程》)