深度之眼Paper带读笔记NLP.12:层次化attention网络.Baseline.09

2023-11-12

前言

本课程来自深度之眼deepshare.net,部分截图来自课程视频。
文章标题:Hierarchical Attention Network for Document Classification
原标题翻译:用于文本分类的层次注意力网络
作者:zichao Yang,Diyi Yang,Chris Dyer,Xiaodong He, Alex Smola,Eduard Hovy
单位:卡耐基梅隆大学,微软研究院
Carnegie Mellon University, Microsoft Research, Redmond
论文来源:NAACL 2016
在线LaTeX公式编辑器
在这里插入图片描述
在这里插入图片描述

第一课 论文导读

文本分类

文本挖掘

文本挖掘:是一个以半结构或者无结构的自然语言文本为对象的数据挖掘,是从大规模文本数据集中发现隐藏的、重要的、新颖的、潜在的、有用的规律的过程。
·文本分类是文本挖掘的一个常见任务。

数据类型

非结构化数据:没有固定结构的数据,直接整体进行存储,一般存储为二进制的数据格式。
半结构化数据:结构化数据的一种形式,它并不符合关系型数据库等形式关联起来的数据模型结构,但包含相关标记,用来分割语义元素以及对记录和字段进行分层。
结构化数据:能够用数据或统一的结构加以表示,如数字、符号。通常的形式是二维表。

文本分类

文本分类是自然语言处理的基本任务。目标是将非结构化文档(例如,评论,电子邮件,帖子,网站内容等)分配给一个或多个类。
文本分类流程:
文本数据获取
文本预处理
文本的向量表示
构造分类器
模型评估
常见的文本分类应用:
主题标记
·产品营销
·产品评论
·内容标记
情感分析:情感分析预测了基于文本分类的特定特征的情绪。

相关技术

信息检索(lR)所有文本分类问题的基础。IR基本算法:
词袋模型:按照词出现的频率表示文本
TF-IDF算法:按比率设置词频和逆向文件频率,通过出现的词的相关性来表示文本
N-gram模型:计算一组共同出现的词
其他早期无监督方法:
在这里插入图片描述
(半)监督方法
在这里插入图片描述
在这里插入图片描述

基于深度学习的文本分类 baseline涉及的三篇TC的论文

深度之眼Paper带读笔记NLP.8:TextCNN.Baseline.04https://blog.csdn.net/oldmao_2001/article/details/101170988
在这里插入图片描述
深度之眼Paper带读笔记NLP.9:基于CNN的词级别的文本分类.Baseline.05.https://blog.csdn.net/oldmao_2001/article/details/101275082
在这里插入图片描述
深度之眼Paper带读笔记NLP.11:FASTTEXT.Baseline.06 https://blog.csdn.net/oldmao_2001/article/details/101615439
在这里插入图片描述
优点:
• 效果特别好,基本都是sota的结果。
• 不需要做特征工程。
忽视的问题:
• 文档中不同句子对于分类的重要性不同。(未考虑句子的重要性红色部分)
• 句子中不同单词对于分类的重要性也有所不同。(未考虑词的重要性蓝色部分)
在这里插入图片描述
因此,需要分层注意网络来解决这两个问题。下面稍微介绍一下,后面详细讲。

分层注意网络

信息重要度:并非句子中的每个单词和文档中的每个句子对于理解文档的主要信息同样重要。
上下文语境:单词的含义需要根据不同的上下文做出不同的判断。
例如:pretty
·The bouquet of flowers is pretty.
·The food is pretty bad.
在这里插入图片描述
结论:并非文档中的所有部分都能从中获得同等重要的本质信息

前期知识储备

文本分类:了解文本分类任务的基本概念和应用种类,以及任务流程。
概率论:了解基本的概率论知识,掌握条件概率的概念和公式。
注意力机制:了解注意力机制的概念和种类,掌握注意力机制的计算方法。
循环神经网络:了解循环神经网络的结构,掌握它的基本工作原理。

第二课论文精读

本小节首先介绍了论文的整体框架,这部分我们根据论文结构和摘要理清作者的写研究和写作思路;然后讲解了层次注意力网络模型HAN,这部分我们讲解层次注意力网络的构成和计算方式。之后讲解了论文实验中的一些设置和并且分析了实验结果。最后我们进行了论文的讨论和总结,并展望该领域未来的发展方向。

论文背景

  1. 文本分类是自然语言处理的基础任务之一,近期的研究者逐渐开始使用基于深度学习的文本分类模型。
  2. 虽然基于深度学习的文本分类模型取得了非常好的效果,但是它们没有注意到文档的结构,并且没有注意到文档中不同部分对于分类的影响程度不一样。
  3. 为了解决这一问题,我们提出了一种层次注意力网络来学习文档的层次结构,并且使用两种注意力机制学习基于上下文的结构重要性。
  4. 我们的工作和前人工作的主要区别是我们使用上下文来区分句子或者单词的重要性,而不是仅仅使用单个句子或者单个的词。

Text classification is one of the fundamental task in Natural Language Processing. The goal is to assign labels to text. It has broad applications including topic labeling (Wang and Manning, 2012), sentiment classification (Maas et al., 2011; Pang and Lee, 2008), and spam detection (Sahami et al., 1998). Traditional approaches of text classification represent documents with sparse lexical features, such as n-grams, and then use a linear model or kernel methods on this representation (Wang and Manning, 2012; Joachims, 1998). More recent approaches used deep learning, such as convolutional neural networks (Blunsom et al., 2014) and recurrent neural networks based on long short-term memory (LSTM) (Hochreiter and Schmidhuber, 1997) to learn text representations.

论文整体框架

摘要

  1. 本文提出了一种层次注意力网络来做文档分类,它有两个特点。
    We propose a hierarchical attention network for document classification. (文章的主要工作)Our model has two distinctive characteristics:
  2. 第一个特点是这种层次结构对应着文档的层次结构。
    (i) it has a hierarchical structure that mirrors the hierarchical structure of documents;
  3. 第二个特点是它具有词级别和句子级别两种注意力机制,这使得网络能够区分文档中重要的部分,从而更好地生成文档表示。
    (ii) it has two levels of attention mechanisms applied at the wordand sentence-level, enabling it to attend differentially to more and less important content when constructing the document representation. (层次注意力模型的特点)
  4. 我们在六个大型数据集上的实验结果表明,我们的模型能够大幅度提高文档分类效果,并且可视化发现我们确实能够选择出文档中重要的句子和单词。
    experiments conducted on six large scale text classification tasks demonstrate that the proposed architecture outperform previous methods by a substantial margin. (模型在文本分类上的表现)
    Visualization of the attention layers illustrates that the model selects qualitatively informative words and sentences.(通过可视化,该模型可以选择出丰富语义的词和句子。)

论文标题

  1. Introduction
  2. Hierarchical Attention Networks
    2.1GPU-based sequence encoder
    2.2 Hierarchical Attention2.3Document Classification
  3. Experiments
    3.1Data sets
    3.2 Baselines
    3.2.1Linear methods
    3.2.2SVMs
    3.2.3 Neural Network methods
    3.3 Model configuration and training
    3.4 Results and analysis
    3.5 Context dependent attention weights
    3.6Visualization of attention
  4. Related Work
  5. Conclusion

层次注意力网络

在这里插入图片描述
网络组成结构:
·word encoder:单词序列编码器
·word attention:单词注意力机制
·sentence encoder:句子编码器
·sentence attention:句子注意力机制

基于GRU的词序列编码器:

·RNN的一个变种,使用门机制来记录序列当前的状态。
·隐藏层状态的计算公式: h t = ( 1 − z t ) ⊙ h t − 1 + z t ⊙ h ~ t h_t=(1-z_t)\odot h_{t-1}+z_t\odot \tilde h_t ht=(1zt)ht1+zth~t(这个公式表示新的状态保留多少,旧的状态保留多少。)
·更新门: z t = σ ( W z x t + U z h t − 1 + b z ) z_t=\sigma(W_zx_t+U_zh_{t-1}+b_z) zt=σ(Wzxt+Uzht1+bz)
·候选状态: h ~ t = t a n h ( W h x t + r t ⊙ ( U h h t − 1 ) + b h ) \tilde h_t=tanh(W_hx_t+r_t\odot(U_hh_{t-1})+b_h) h~t=tanh(Whxt+rt(Uhht1)+bh)
·重置(遗忘)门: r t = σ ( W r x t + U r h t − 1 + b r ) r_t=\sigma(W_rx_t+U_rh_{t-1}+b_r) rt=σ(Wrxt+Urht1+br)
GRU比LSTM少一个cell,用于记忆之前的信息
在这里插入图片描述

单词序列编码器:双向GRU

· x i t x_{it} xit:单词的词向量
· h i t h_{it} hit:隐层状态
x i t = W e w i t , t ∈ [ 1 , T ] , (1) x_{it}=W_ew_{it}, t \in [1, T],\tag1 xit=Wewit,t[1,T],(1)
W e W_e We是词向量矩阵, w i t w_{it} wit是独热编码,两个相乘得到是词向量,t是时间步或者说第几个词,i代表当前第几个句子
h i t → = G R U → ( x i t ) , t ∈ [ 1 , T ] , (2) \overrightarrow{h_{it}}=\overrightarrow{GRU}(x_{it}), t \in [1, T],\tag2 hit =GRU (xit),t[1,T],(2)
上面是前向GRU
h i t ← = G R U ← ( x i t ) , t ∈ [ 1 , T ] , (3) \overleftarrow{h_{it}}=\overleftarrow{GRU}(x_{it}), t \in [1, T],\tag3 hit =GRU (xit),t[1,T],(3)
上面是反向GRU
h i t = [ h i t → , h i t ← ] (4) h_{it}=[\overrightarrow{h_{it}},\overleftarrow{h_{it}}]\tag4 hit=[hit ,hit ](4)
上面是前向和反向GRU的concat
在这里插入图片描述
首先假设一个文档有L个句子,每个句子 S i S_i Si包含有 t i t_i ti个单词,句子的总长度为T
整个网络输入 W i t W_{it} Wit表示第i个句子中的第t个单词(就是上图画红线部分)。然后利用矩阵 W e W_e We和独热编码 w i t w_{it} wit把单词embedding到向量中,得到单词的词向量 x i t x_{it} xit(具体公式是上面第一个。)
然后通过双向GRU,可以将正向和反向的上下文信息结合起来获得隐藏层的输出。(具体公式是上面第2-4个)

单词注意力机制

第i个句子第t个词的输出为:
u i t = tanh ( W w h i t + b w ) u_{it}=\text{tanh}(W_wh_{it}+b_w) uit=tanh(Wwhit+bw)
α i t = exp ( u i t ⊤ u w ) ∑ t exp ( u i t ⊤ u w ) ) \alpha_{it}=\frac{\text{exp}(u_{it}^{\top}u_w)}{\sum_t\text{exp}(u_{it}^{\top}u_w))} αit=texp(uituw))exp(uituw)
s i = ∑ t α i t h i t s_i=\sum_t\alpha_{it}h_{it} si=tαithit
u i t u_{it} uit:隐层表示,对应的是上图中中间绿色正方形框框
α i t \alpha_{it} αit:注意力分数(权重),用随机初始化(在训练过程中也是不断更新的)的 u w u_w uw和隐层表示 u i t u_{it} uit求相似度后进行softmax分类得到该权重。这里的 u w u_w uw是作者自己创建的注意力机制中的Query(随机初始化,并在梯度下降中进行优化),然后 u i t u_{it} uit是Key,代表第i句话的所有词的集合。
s i s_i si:句子向量表示
不是所有的词对句子表示都很重要,因此使用注意力机制来实现提取词语对句子含义重要程度的信息,并将该信息汇总形成句子向量。

句子编码器

在这里插入图片描述
s i s_i si:句子向量
h i h_i hi:隐层向量
h i → = G R U → ( s i ) , i ∈ [ 1 , L ] \overrightarrow{h_{i}}=\overrightarrow{GRU}(s_{i}),i\in[1,L] hi =GRU (si),i[1,L]
h i ← = G R U ← ( s i ) , i ∈ [ 1 , L ] \overleftarrow{h_{i}}=\overleftarrow{GRU}(s_{i}),i\in[1,L] hi =GRU (si),i[1,L]
h i = [ h i → , h i ← ] h_{i}=[\overrightarrow{h_{i}},\overleftarrow{h_{i}}] hi=[hi ,hi ]
由句子向量到文档向量和上面的流程一样

句子注意力机制

u i = t a n h ( W s h i + b s ) u_{i}=tanh(W_sh_{i}+b_s) ui=tanh(Wshi+bs)
α i = e x p ( u i ⊤ u s ) ∑ t e x p ( u i ⊤ u s ) ) \alpha_{i}=\frac{exp(u_{i}^{\top}u_s)}{\sum_texp(u_{i}^{\top}u_s))} αi=texp(uius))exp(uius)
v = ∑ i α i h i v=\sum_i\alpha_{i}h_{i} v=iαihi
u i u_{i} ui:隐层表示
α i t \alpha_{it} αit:注意力分数(权重),
v v v:文档向量

文档分类

·文档向量v是文档的高级表示,可用作文档分类的功能:
p = s o f t m a x ( W c v + b c ) p=softmax(W_cv+b_c) p=softmax(Wcv+bc)
·损失函数:负对数似然
L = − ∑ d l o g p d j L=-\sum_dlogp_{dj} L=dlogpdj

应用:

  1. 注意力机制在文本分类,以及其他分类和句子表示上大规模应用。
  2. 推动了注意力机制在非Seq2Seq场景下的应用。
  3. 层次结构对于文档级别数据的应用。

实验和结果

介绍论文中模型的实验设置和运行结果
论文中使用了六个数据集,Yelp reviews2013,2014,2015;IMDB reviews;Yahoo Answers;Amazon reviews
每个数据集合中80%的数据用作训练集合,10%的数据用作验证集合,剩余10%的集合用作测试集合
在这里插入图片描述

实验设置

实验任务:六个数据集上的文本分类
对比模型:
·线性模型
·SVM
·word-based CNN(基于词的CNN)
·Character-based CNN(基于字符集的CNN Character-level Convolutional Networks for Text Classification)
在这里插入图片描述

·ConV/LSTM-GRNN:Document Modeling with Gated Recurrent Neural Network for Sentiment Classification
在这里插入图片描述

实验结果

·HN-AVE使用平均来处理向量融合。
·HN-MAX使用求最大值处理向量融合。
·HN-ATT使用注意力机制处理向量融合。
·在各个数据集上均取得最优的结果。
模型参数:批次大小:64;动量值:0.9
在这里插入图片描述
无论数据集大小,结果都是最好。

可视化分析

单词“good”的权重分布情况,a是总体情况,b-f是good这个单词在好评度从差评过度到好评(1,2,3,4,5分)的不同分类中权重变化的情况,在f中很明显,good在好评中的权重很大。
在这里插入图片描述
单词“bad”的权重分布情况
在这里插入图片描述
注意力机制可视化分析,红色是句子注意力,蓝色是词注意力。这里每句话进行了处理,句子不重要就不显示该句话中的重要的词。
在这里插入图片描述

总结

A)提出一种用于文本分类的层次注意力网络
B)该网路首先构建句子的表示然后将它们聚合成文档表示
C)该网络在单词和句子级别应用了两个级别的注意机制
关键点
·之前的基于深度学习的文本分类没有关注到文档不同部分的信息重要性的不同。
·通过注意力机制可以学习到文档中各个部分对于分类的重要度。
·HAN Attention模型。
创新点
·提出了一种新的文本分类模型—HAN Attention模型
·HAN Attention模型通过两种级别的注意力机制同时学习文档中重要的句子和单词。
·在六个文本分类数据集上取得sota的结果。
启发点
·我们模型背后的直觉是文档不同部分对于问题的重要性不同,而且这些部分的重要性还取决于内部的
单词,而不仅仅是对这部分单独确定重要性。
The intuition underlying our model is that not all parts of a document are equally relevant for answering a query and that determining the relevant sections involves modeling the interactions of the words,not just their presence in isolation(Introduction P2)
·此外,单词和句子的重要性是上下文相关的,同样的词或者句子在不同的上下文情景下重要性也不同。
Moreover,the importance of words and sentences are highly context dependent,i.e.the same word or sentence may be differentially important in different context.(Introduction P3)

推荐文献

Tianyang Zhang et al.2018.Learning Structured Representation for Text Classification via Reinforcement Learning (清华团队出品)
Joulin et al.2017.Bag of Tricks for Efficient Text Classification (这个有带读笔记)
Johnson et al.2017.Deep Pyramid Convolutional Neural Networks for Text Categorization (DPCNN用于捕捉全局语义表示)
JacobDevlin et al.2019.BERT:Pre-training of Deep Bidirectional Transformers for Language Understanding(BERT)

复现

在这里插入图片描述
代码结构:
在这里插入图片描述
数据集下载
数据集: http://ir.hit.edu.cn/~dytang/paper/emnlp2015/emnlp-2015-data.7z
其他数据集可以看之前baseline里面有。
本次用的是影评数据imdb,前面两列估计是编号和外键,数字是类别,后面是评论。
在这里插入图片描述

01层次文档分类数据处理

层次文档分类的数据处理

# coding:utf-8
from torch.utils import data
import os
import torch
import nltk
import numpy as np
from gensim.models import KeyedVectors
import nltk


# 数据集加载
# 根据长度排序,这个之前讲过,按长度进行排序后,句子长度相近,就可以使得pad的效率比较高
# 创建word2id
# 分句
# 将数据转化成id
class IMDB_Data(data.DataLoader):
    def __init__(self, data_name, min_count, word2id=None, max_sentence_length=100, batch_size=64, is_pretrain=False):
        self.path = os.path.abspath(".")
        if "data" not in self.path:
            self.path += "/data"
        self.data_name = "/imdb/" + data_name
        self.min_count = min_count
        self.word2id = word2id
        self.max_sentence_length = max_sentence_length
        self.batch_size = batch_size
        self.datas, self.labels = self.load_data()
        if is_pretrain:
            self.get_word2vec()
        else:
            self.weight = None
        for i in range(len(self.datas)):
            self.datas[i] = np.array(self.datas[i])

    def load_data(self):
        datas = open(self.path + self.data_name, encoding="utf-8").read().splitlines()
        # -1代表最后一个字段就是文章列,2是label列,把两个东西放在一起,按句子长度排序,这样不会丢失句子和label的对应关系。
        datas = [data.split("		")[-1].split() + [data.split("		")[2]] for data in datas]
        # 按句子长度排序reverse=True代表从大到小,这样可以防止显存分配不足
        datas = sorted(datas, key=lambda x: len(x), reverse=True)
        # 获取label
        labels = [int(data[-1]) - 1 for data in datas]
        # 剥离label
        datas = [data[0:-1] for data in datas]
        if self.word2id == None:
            self.get_word2id(datas)
        # 分句
        for i, data in enumerate(datas):
            #数据集中是用<sssss>来进行分句的
            datas[i] = " ".join(data).split("<sssss>")
            for j, sentence in enumerate(datas[i]):
                datas[i][j] = sentence.split()
        datas = self.convert_data2id(datas)
        return datas, labels

    def get_word2id(self, datas):
        word_freq = {}
        for data in datas:
            for word in data:
                word_freq[word] = word_freq.get(word, 0) + 1
        word2id = {"<pad>": 0, "<unk>": 1}
        for word in word_freq:
            # 小于min_count设置为UNK词
            if word_freq[word] < self.min_count:
                continue
            else:
                word2id[word] = len(word2id)
        self.word2id = word2id

    # max_sentence_length 句子必须是一样长。
    # batch_size 代表每个batch_size,每个文档的句子一样多。
    def convert_data2id(self, datas):
        for i, document in enumerate(datas):
            if i % 10000 == 0:
                print(i, len(datas))
            for j, sentence in enumerate(document):
                for k, word in enumerate(sentence):
                    datas[i][j][k] = self.word2id.get(word, self.word2id["<unk>"])
                # 超长截断,过短pad补齐
                datas[i][j] = datas[i][j][0:self.max_sentence_length] + \
                              [self.word2id["<pad>"]] * (self.max_sentence_length - len(datas[i][j]))
        for i in range(0, len(datas), self.batch_size):
            max_data_length = max([len(x) for x in datas[i:i + self.batch_size]])
            for j in range(i, min(i + self.batch_size, len(datas))):
                datas[j] = datas[j] + [[self.word2id["<pad>"]] * self.max_sentence_length] * (
                            max_data_length - len(datas[j]))
                datas[j] = datas[j]
        return datas

    def get_word2vec(self):
        '''
        生成word2vec词向量
        :return: 根据词表生成的词向量
        '''
        print("Reading word2vec Embedding...")
        wvmodel = KeyedVectors.load_word2vec_format(self.path + "/imdb.model", binary=True)
        tmp = []
        for word, index in self.word2id.items():
            try:
                tmp.append(wvmodel.get_vector(word))
            except:
                pass
        mean = np.mean(np.array(tmp))
        std = np.std(np.array(tmp))
        print(mean, std)
        vocab_size = len(self.word2id)
        embed_size = 200
        np.random.seed(2)
        embedding_weights = np.random.normal(mean, std, [vocab_size, embed_size])  # 正太分布初始化方法
        for word, index in self.word2id.items():
            try:
                embedding_weights[index, :] = wvmodel.get_vector(word)
            except:
                pass
        self.weight = torch.from_numpy(embedding_weights).float()

    def __getitem__(self, idx):
        return self.datas[idx], self.labels[idx]

    def __len__(self):
        return len(self.labels)


if __name__ == "__main__":
    imdb_data = IMDB_Data(data_name="imdb-train.txt.ss", min_count=5, is_pretrain=True)
    training_iter = torch.utils.data.DataLoader(dataset=imdb_data,
                                                batch_size=64,
                                                shuffle=False,
                                                num_workers=0)
    for data, label in training_iter:
        print(np.array(data).shape)

02使用Pytorch实现HAN Attention模型

基于Pytorch的文本分类注意力机制实现以及HAN Attention模型实现

# -*- coding: utf-8 -*-
import torch
import torch.nn as nn
import numpy as np
from torch.nn import functional as F
from torch.autograd import Variable


class HAN_Model(nn.Module):
    def __init__(self, vocab_size, embedding_size, gru_size, class_num, is_pretrain=False, weights=None):
        super(HAN_Model, self).__init__()
        # 判断是否词向量是否预训练,不是预训练效果会差一点
        if is_pretrain:
            self.embedding = nn.Embedding.from_pretrained(weights, freeze=False)
        else:
            self.embedding = nn.Embedding(vocab_size, embedding_size)
        # 词的双向gru
        self.word_gru = nn.GRU(input_size=embedding_size, hidden_size=gru_size, num_layers=1,
                               bidirectional=True, batch_first=True)
        # 词attention的Query
        self.word_context = nn.Parameter(torch.Tensor(2 * gru_size, 1), requires_grad=True)
        self.word_dense = nn.Linear(2 * gru_size, 2 * gru_size)
        # 句子的双向gru,这里的输入shape是上一句的输出2*gru_size,
        self.sentence_gru = nn.GRU(input_size=2 * gru_size, hidden_size=gru_size, num_layers=1,
                                   bidirectional=True, batch_first=True)
        # 句attention的Query
        self.sentence_context = nn.Parameter(torch.Tensor(2 * gru_size, 1), requires_grad=True)
        self.sentence_dense = nn.Linear(2 * gru_size, 2 * gru_size)
        # class_num是最后文本分类的类别数量
        self.fc = nn.Linear(2 * gru_size, class_num)

    def forward(self, x, gpu=False):
        # 句子个数
        sentence_num = x.shape[1]
        # 句子长度
        sentence_length = x.shape[2]
        # x原来维度是bs*sentence_num*sentence_length,经过下面变化成二维的:(bs*sentence_num)*sentence_length
        x = x.view([-1, sentence_length])
        # 加了embedding维度:(bs*sentence_num)*sentence_length*embedding_size
        x_embedding = self.embedding(x)
        # word_outputs.shape:(bs*sentence_num)*sentence_length*(2*gru_size),这里因为是双向gru所以是2*gru_size
        word_outputs, word_hidden = self.word_gru(x_embedding)
        # attention_word_outputs.shape:(bs*sentence_num)*sentence_length*(2*gru_size),这里对应原文公式5
        attention_word_outputs = torch.tanh(self.word_dense(word_outputs))
        # weights.shape:(bs*sentence_num)*sentence_length*1,,这里和下面一句对应原文公式6
        weights = torch.matmul(attention_word_outputs, self.word_context)
        # weights.shape: (bs * sentence_num) * sentence_length * 1
        weights = F.softmax(weights, dim=1)
        # 这里对x加一个维度:(bs*sentence_num)*sentence_length*1
        x = x.unsqueeze(2)
        # 对x加的这个维度进行判断,如果这个维度上为0,表示这个地方是pad出来的,没有必要进行计算。
        # 如果为1,则按weight进行计算比例
        if gpu:
            weights = torch.where(x != 0, weights, torch.full_like(x, 0, dtype=torch.float).cuda())
        else:
            weights = torch.where(x != 0, weights, torch.full_like(x, 0, dtype=torch.float))

        # 这里由于忽略掉了pad为0的部分,所以要按维度重新计算分布
        weights = weights / (torch.sum(weights, dim=1).unsqueeze(1) + 1e-4)
        # bs*sentence_num*(2*gru_size)
        sentence_vector = torch.sum(word_outputs * weights, dim=1).view([-1, sentence_num, word_outputs.shape[-1]])
        # sentence_outputs.shape:bs*sentence_num*(2*gru_size)
        sentence_outputs, sentence_hidden = self.sentence_gru(sentence_vector)
        # 对应原文公式8:bs*sentence_num*(2*gru_size)
        attention_sentence_outputs = torch.tanh(self.sentence_dense(sentence_outputs))
        # bs*sentence_num*1
        weights = torch.matmul(attention_sentence_outputs, self.sentence_context)
        # bs*sentence_num*1
        weights = F.softmax(weights, dim=1)
        # bs * sentence_num * sentence_length
        x = x.view(-1, sentence_num, x.shape[1])
        # bs * sentence_num * 1
        x = torch.sum(x, dim=2).unsqueeze(2)
        if gpu:
            # bs * sentence_num * 1
            weights = torch.where(x != 0, weights, torch.full_like(x, 0, dtype=torch.float).cuda())
        else:
            weights = torch.where(x != 0, weights, torch.full_like(x, 0, dtype=torch.float))
        # bs * sentence_num * 1,对未计算的pad进行缩放
        weights = weights / (torch.sum(weights, dim=1).unsqueeze(1) + 1e-4)
        # bs *(2*gru)
        document_vector = torch.sum(sentence_outputs * weights, dim=1)
        # bs * class_num
        output = self.fc(document_vector)
        return output


if __name__ == "__main__":
    han_model = HAN_Model(vocab_size=30000, embedding_size=200, gru_size=50, class_num=4)
    x = torch.Tensor(np.zeros([64, 50, 100])).long()
    x[0][0][0:10] = 1
    output = han_model(x)
    print(output.shape)

03HAN Attention模型的训练和测试

基于Pytorch的HAN Attention模型的训练和测试

# -*- coding: utf-8 -*-
import torch
import torch.autograd as autograd
import torch.nn as nn
import torch.optim as optim
from model import HAN_Model
from data import IMDB_Data
import numpy as np
from tqdm import tqdm
import config as argumentparser

config = argumentparser.ArgumentParser()
torch.manual_seed(config.seed)

if config.cuda and torch.cuda.is_available():
    torch.cuda.set_device(config.gpu)


def get_test_result(data_iter, data_set):
    # 生成测试结果
    model.eval()
    true_sample_num = 0
    for data, label in data_iter:
        if config.cuda and torch.cuda.is_available():
            data = data.cuda()
            label = label.cuda()
        else:
            data = torch.autograd.Variable(data).long()
        if config.cuda and torch.cuda.is_available():
            out = model(data, gpu=True)
        else:
            out = model(data)
        true_sample_num += np.sum((torch.argmax(out, 1) == label).cpu().numpy())
    acc = true_sample_num / data_set.__len__()
    return acc

# 导入训练集,shuffle=False,不能是true,因为是按句子长度排序的
training_set = IMDB_Data("imdb-train.txt.ss", min_count=config.min_count,
                         max_sentence_length=config.max_sentence_length, batch_size=config.batch_size, is_pretrain=True)
training_iter = torch.utils.data.DataLoader(dataset=training_set,
                                            batch_size=config.batch_size,
                                            shuffle=False,
                                            num_workers=0)
test_set = IMDB_Data("imdb-test.txt.ss", min_count=config.min_count, word2id=training_set.word2id,
                     max_sentence_length=config.max_sentence_length, batch_size=config.batch_size)
test_iter = torch.utils.data.DataLoader(dataset=test_set,
                                        batch_size=config.batch_size,
                                        shuffle=False,
                                        num_workers=0)
if config.cuda and torch.cuda.is_available():
    training_set.weight = training_set.weight.cuda()
model = HAN_Model(vocab_size=len(training_set.word2id),
                  embedding_size=config.embedding_size,
                  gru_size=config.gru_size, class_num=config.class_num, weights=training_set.weight, is_pretrain=True)
if config.cuda and torch.cuda.is_available():
    model.cuda()
# CrossEntropyLoss自带softmax效果,无需额外做softmax
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=config.learning_rate)
loss = -1
for epoch in range(config.epoch):
    model.train()
    process_bar = tqdm(training_iter)
    for data, label in process_bar:
        if config.cuda and torch.cuda.is_available():
            data = data.cuda()
            label = label.cuda()
        else:
            data = torch.autograd.Variable(data).long()
        label = torch.autograd.Variable(label).squeeze()
        if config.cuda and torch.cuda.is_available():
            out = model(data, gpu=True)
        else:
            out = model(data)
        loss_now = criterion(out, autograd.Variable(label.long()))
        if loss == -1:
            loss = loss_now.data.item()
        else:
            loss = 0.95 * loss + 0.05 * loss_now.data.item()# 平滑处理
        process_bar.set_postfix(loss=loss_now.data.item())
        process_bar.update()
        optimizer.zero_grad()
        loss_now.backward()
        optimizer.step()
    test_acc = get_test_result(test_iter, test_set)
    print("The test acc is: %.5f" % test_acc)

04总结

总结HAN Attention模型以及实现
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深度之眼Paper带读笔记NLP.12:层次化attention网络.Baseline.09 的相关文章

  • Windows terminal + WSL 美化教程的笔记——解决遇到的问题

    文章目录 前言 问题1 如何打开Windows Terminal 的设置 修改配置文件 问题2 打开windows terminal有更新提示怎么办 问题3 打开windows terminal报错怎么办 参考文献 前言 学习过程中突感字体
  • vaultwarden密码库 搭建流程

    系统工程 建设篇 第二章 vaultwarden密码库 搭建流程 系统工程 建设篇 系列文章回顾 前言 前置条件 实施步骤 注意事项 浏览器插件下载链接 部署 vaultwarden密码库 宝塔面板配置docker 开启docker服务 从
  • python连接clickhouse使用方法

    前沿 clickhouse现在作为分布式存储成熟的解决方案 在python开发中经常会用到clickhouse的连接方案 下面所列一个简单的连接clickhouse的写法 正文 from clickhouse driver import C
  • 焉建伟:3.31黄金走势看涨看跌?黄金原油今日如何操作? 实时策略

    消息面 美东时间周二 美国媒体援引两名知情人士的话报道 拜登周三预计将在匹兹堡宣布2 25万亿美元的一揽子基础设施和就业支持计划 具体而言 大约6500亿美元会被用于重建美国基础设施 如道路 桥梁 高速公路和港口 4000亿美元用于老年人和
  • 蓝桥杯单片机前言(经验分享)

    本人在今年省赛的获得了省一等奖 这是战利品hhh 国赛由于没有好好准备 所以没有取得好名次 已经后悔了555 个人经历 当时是寒假开始学习蓝桥杯单片机开发板的 本人情况是有模电 电路理论基础 c语言基础 当时差不多忘记完了 没有51和模电基
  • 六轴融合算法

    先说什么叫六轴融合 在3Dof姿态追踪功能中 最主要的传感器就是陀螺仪 Gyroscope 它可以提供3个轴的角加速度 对时间进行积分 就可以得出物体旋转的方向角度 但是因为硬件精度等各方面原因 会产生误差 随着时间的累积 计算得到的角度误
  • 活动回顾|解锁 AIGC 密码,探寻企业发展新商机

    5月24日 Google Cloud 与 Cloud Ace 联合主办的线下活动顺利落下帷幕 本次活动 有近 40 位企业精英到场支持 三位 Google Cloud 演讲嘉宾就本次活动主题 为大家带来了比较深度的演讲内容 干货满满 以下的
  • Lua中的协同程序 coroutine

    int running 1 int lua finish lua State L running 0 printf lua finish called n return 0 int lua sleep lua State L printf
  • 装X指南之Xposed安装与配置

    一 前言 Xposed 能干嘛 我可以告诉你 Root Xposed 真的可以为所欲为 而 Android 开源 为 搞机 带了更多的乐趣的同时 当然也引入安全性问题 部分流氓软件在 Root 下 会盗取用户私密信息 例如 号码 照片 短信
  • 惊为天人,普林斯顿博士NumPy手写全部主流机器学习模型,代码超3万行

    点击上方 高级农民工 选择 星标 公众号 第一时间速享重磅干货 本文转自 机器之心 禁止二次转载 用 NumPy 手写所有主流 ML 模型 普林斯顿博士后 David Bourgin 最近开源了一个非常剽悍的项目 超过 3 万行代码 30
  • Golang 字符串(string)与字节数组([]byte)一行代码互转

    Golang 字符串 string 与字节数组 byte 一行代码互转 Golang轻松学习 文章目录 Golang 字符串 string 与字节数组 byte 一行代码互转 一 字符串与字节数组 二 详细代码 1 简单的方式字节转字符串
  • 【Redis】《Redis 开发与运维》笔记-汇总

    一 初识Redis 1 Redis提供了两种持久化方式 RDB和AOF 即可以用这两种策略将内存的数据保存到硬盘中 2 复制功能是分布式Redis的基础 3 一般推荐使用的安装方式 源码的方式进行安装 下面以3 0 7版本为例 只需6步 w
  • xshell传输文件到服务器(ubuntu)(上传下载)

    一 利用xshell上传下载内容 点击xftp按钮 绿色按钮 出现一个对话框 对话框左边是本地的文件预览 对话框右边是服务器当前路径的文件预览 上传下载文件 直接拖拉内容 二 其他方式 1 xshell连接服务器 本地虚拟机 2 首先在服务
  • python变量进阶(可变不可变,局部变量和全局变量)

    变量进阶 理解 目标 变量的引用 可变和不可变类型 局部变量和全局变量 01 变量的引用 变量 和 数据 都是保存在 内存 中的 在 Python 中 函数 的 参数传递 以及 返回值 都是靠 引用 传递的 1 1 引用的概念 在 Pyth
  • Mongodb常用语句总结

    1 查询所有用户信息 db system users find pretty 2 查询mongo启动进程 ps ef grep mongo 3 mongo常用操作命令 1 打开数据库 mongo 10 1 1 30 20000 admin
  • C++中promise和future详解

    Promise和Future 原理 C 11中promise和future机制是用于并发编程的一种解决方案 用于在不同线程完成数据传递 异步操作 传统方式通过回调函数处理异步返回的结果 导致代码逻辑分散且难以维护 Promise和Futur
  • js如何截取某个字符串前面或者后面的内容

    截取某个字符串后面的内容 var str http abc def ghi com var index str lastIndexOf str str substring index 1 str length 返回最后一个 后面的内容 截取

随机推荐

  • JavaScript -- 数组去重

    文章目录 方法一 利用indexOf 去重 思路 代码 方法二 利用splice方法去重 思路 代码实现 方法三 利用ES6的Set去重 思路 代码实现 方法一 利用indexOf 去重 indexOf 方法可返回某个指定的字符串值在字符串
  • REST API URI 设计的七准则

    在了解 REST API URI 设计的规则之前 让我们快速过一下我们将要讨论的一些术语 URI REST API 使用统一资源标识符 URI 来寻址资源 在今天的网站上 URI 设计范围从可以清楚地传达API的资源模型 如 http ap
  • 汇编指令与Intrinsics指令的对应关系汇总

    汇编指令与Intrinsics指令的对应关系汇总 参考网址 https software intel com sites landingpage IntrinsicsGuide 1 赋值指令 movq 使用方法 movq xmm m64 功
  • vs编译与停止调试时卡顿、无响应的问题

    这是由于VS运行太久参数大量的缓存导致 1 单击 开始 选择 运行 或者win r快捷键 2 键入 devenv exe resetuserdata 此命令会运行几分钟时间 Visual Studio 清除设置并将其自身重置到其最初的状态
  • java实现kafka消息发送和接收

    之前写了一篇关于kafka集群搭建的点击打开链接 想了解的可以看下 今天这个实现是和前面集群对应的 使用的是新版的API 属性如果想定制自己的 需要到官方网址上面去查看一下对应的值 推介大家多去看看官方的介绍和demo 网上有些翻译过来的例
  • 这可能是史上最详细的MES介绍

    本文篇幅较长 干货满满 可以先收藏 方便日后再次查看 目录 MES 的定义 MES 的产生背景 MES 的发展历程 MES 的功能介绍 MES 与其他 IT 系统的关系 MES 的业务价值 MES 的定义 MES Manufacturing
  • 关于webconfig 的配置跨域和理解

    今日碰到一个问题 就是在很久以前碰到的跨域问题 需求 页面要显示1个图片 但是因为各种原因 导致图片在服务器2上 但是要展示的程序在服务器1 的上面 这样就造成了在显示的时候出现了跨域的问题 本来的思路为直接写个程序进行后台获得图片的路径
  • DROP DATABASE

    在做迁移时 由于某种原因导致回退 现在准备将备库的数据库删除 然后重新部署dg 但在删除备库的时候遇到一些小问题 在节点一执行 oracle sde1 sqlplus as sysdba SQL Plus Release 11 2 0 3
  • Vmware安装到本地,磁盘不够解决方案

    在使用虚拟机的时候 如果在创建的时候选择错误的盘符 那么在安装虚拟机后这个盘符的空间容量不够的问题 那么如何把虚拟机迁移出来到另外的盘符 1 找到虚拟机安装路径 打开虚拟机点击虚拟机详细信息 查看详细的虚拟机的路径 2 找到虚拟机所有的文件
  • 小程序web-view,h5页监听返回到小程序指定页面

    在h5页面进行监听返回跳转判断 created this pushHistory window addEventListener popstate function e 首页点击返回 直接关闭网页 WeixinJSBridge call c
  • QT定时器与lambda表达式联合使用

    QTimer定时器在程序开发中经常使用 比如网络请求超时检查 定时刷新数据 控制动态图开始停止等功能 一般如果是定时触发某个标志 用专来的槽函数处理会显示有点繁琐 如果用lambda表达式处理就不用专门声明定义槽函数 这样代码会更简洁 下面
  • 在Eclipse中安装JSHint插件

    离线安装 1 下载插件包 http download eclipsesource com rsternberg jshint eclipse 0 9 8 20130728 0004 b94b446 zip 2 解压缩后是一个jshint e
  • Linux 自定义简单命令

    如何让一个脚本文件没有 sh后缀输入文件名即可执行 权限问题 首先当然得让它成为可执行文件 不要出现死亡Permission denine 执行以下命令 chmod x 文件路径 文件名 两种方式 当我们输入一个命令的时候默认是从下面这些路
  • 利用Python中的statsmodels简单建立多元线性回归模型(一)

    利用Python中的statsmodels简单建立多元线性回归模型 一 概念简单介绍 多元线性回归其实是在一元线性回归的基础上增加了若干个自变量个数 数学表达式如下 其中 y y y是因变量 响应变量 0
  • ESOE-IDE v0.3 技术说明书

    ESOE IDE v0 3 技术说明书 Author Feng WeiGuo 冯卫国 Email forxm 21cn com Web http www supertree org Tel 86 0755 81030955 All Righ
  • 如何获取股票预测数据集“上海证券综合指数”(上证综指,Shanghai Composite Index)?

    以下网址可提供较为全面的数据集 涵盖Date Opening price Highest price Lowest price Closing price Volume Turnover Ups and Downs Change指标 即日期
  • 10分钟教你用Python玩转微信之抓取好友个性签名制作词云

    01 前言 展示 各位小伙伴我又来啦 今天带大家玩点好玩的东西 用Python抓取我们的微信好友个性签名 然后制作词云 怎样 有趣吧 好了 下面开始干活 我知道你们还是想先看看效果的 后台登录 词云 02 环境准备 Python版本 3 6
  • Linux基础笔记18

    fdisk 分区工具 fdisk 这个古老的软件并不认识 GPT 所以 fdisk 只支持 MBR 的分区模式 且磁盘小于2T 大于了就不能使用 fdisk 进行分区了 新磁盘的分区 一块新加的磁盘的分区方式 检查系统中需要分区的磁盘 fd
  • Vue:Vue动画效果全解析

    Vue中的CSS动画原理 当使用transition 标签包裹标签时 Vue会自动分析其css样式 从而构建动画流程 下图中的点的开头到结尾即为一个动画流程 当一个动画流程执行时 内部被transition 标签包裹的标签瞬间增加两个fad
  • 深度之眼Paper带读笔记NLP.12:层次化attention网络.Baseline.09

    文章目录 前言 第一课 论文导读 文本分类 文本挖掘 数据类型 文本分类 相关技术 基于深度学习的文本分类 baseline涉及的三篇TC的论文 分层注意网络 前期知识储备 第二课论文精读 论文背景 论文整体框架 论文标题 层次注意力网络