文本分类TextRNN_Att模型(pytorch实现)

TextRNN-Att简介

TextRNN前面已经介绍过了,主体结构就是一个双向/单向的LSTM层,由于LSTM获得每个时间点的输出信息之间的“影响程度”都是一样的,而在关系分类中,为了能够突出部分输出结果对分类的重要性,引入加权的思想。而本篇模型在LSTM层之后引入了attention层,其实就是对lstm每刻的隐层进行加权平均。

在这里插入图片描述

模型结构:
  • 输入层:输入是一个一个的句子,通过对它进行划分batch,sentence,然后进行编码

  • 词嵌入层:将文本中的离散词汇表示(如单词或者字符)转换为连续的实值向量表示,也称为词嵌入(Word Embedding)。这些实值向量具有语义信息,能够捕捉词汇之间的语义关系,从而提供更丰富的特征表示。

  • LSTM层:双向LSTM是RNN的一种改进,其主要包括前后向传播,每个时间点包含一个LSTM单元用来选择性的记忆、遗忘和输出信息。模型的输出包括前后向两个结果,通过拼接作为最终的Bi-LSTM输出。公式如下:

  • 注意力层:对lstm每刻的隐层进行加权平均,将词级别的特征合并到句子级别的特征。

M = tanh ⁡ ( H ) M=\tanh \left(H \right) M=tanh(H)

α = s o f t max ⁡ ( W T M ) \alpha =soft\max \left(W^TM \right) α=softmax(WTM)

r = H α T r=H\alpha ^T r=HαT

  • 输出层:将句子层级的特征用于关系分类。
pytorch代码实现:
  1. 模型输入: [batch_size, seq_len]
  2. 经过embedding层:加载预训练词向量或者随机初始化, 词向量维度为embed_size: [batch_size, seq_len, embed_size]
  3. 双向LSTM:隐层大小为hidden_size,得到所有时刻的隐层状态(前向隐层和后向隐层拼接) [batch_size, seq_len, hidden_size * 2]
  4. 初始化一个可学习的权重矩阵w=[hidden_size * 2, 1]
  5. 对LSTM的输出进行非线性激活后与w进行矩阵相乘,将其映射为一个标量值。这个标量值可以看作是对 M 的加权求和,用于表示每个位置的重要程度或注意力权重。由[batch_size, seq_len,word_embedding]变为[batch_size, seq_len],即表示了一个句子当中每个词在这个句子当中的重要程度。接着,通过 Softmax 函数对 M 与 self.w 的点积进行归一化操作。这一步是为了将各个位置的权重转换为概率值,使得它们都落在 [0, 1] 的范围内,并且所有权重的总和为 1。这样可以确保每个位置的注意力权重都在合理的范围内,并且相对于其他位置的权重是有意义的。最后是维度扩展,这样做是为了方便后续的加权求和操作,因为 alpha 中的每个权重需要与 H 中对应位置的隐藏状态进行加权求和,所以它们的维度需要匹配。
  6. 将LSTM的每一时刻的隐层状态乘对应的分值后求和,得到加权平均后的终极隐层值[batch_size, hidden_size * 2]
  7. 对终极隐层值进行非线性激活后送入两个连续的全连接层[batch_size, num_class]
  8. 预测:softmax归一化,将num_class个数中最大的数对应的类作为最终预测[batch_size, 1]
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np


class Config(object):
    """配置参数"""

    def __init__(self):
        self.model_name = 'TextRNN_Att'
        self.dropout = 0.5  # 随机失活
        self.require_improvement = 1000  # 若超过1000batch效果还没提升,则提前结束训练
        self.num_classes = 10 # 类别数
        self.n_vocab = 10000  # 词表大小,在运行时赋值
        self.num_epochs = 10  # epoch数
        self.batch_size = 128  # mini-batch大小
        self.pad_size = 32  # 每句话处理成的长度(短填长切)
        self.learning_rate = 1e-3  # 学习率
        self.embed =  300  # 字向量维度, 若使用了预训练词向量,则维度统一
        self.hidden_size = 128  # lstm隐藏层
        self.num_layers = 2  # lstm层数
        self.hidden_size2 = 64

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
        self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers,
                            bidirectional=True, batch_first=True, dropout=config.dropout)
        self.tanh1 = nn.Tanh()
        self.w = nn.Parameter(torch.zeros(config.hidden_size * 2))
        self.tanh2 = nn.Tanh()
        self.fc1 = nn.Linear(config.hidden_size * 2, config.hidden_size2)
        self.fc = nn.Linear(config.hidden_size2, config.num_classes)

    def forward(self, x):
        x, _ = x
        # 词嵌入层
        emb = self.embedding(x)  # [batch_size, seq_len, embeding]=[128, 32, 300]
        # LSTM层
        H, _ = self.lstm(emb)  # [batch_size, seq_len, hidden_size * num_direction]=[128, 32, 256]
        # 注意力层
        M = self.tanh1(H)  # [128, 32, 256]
        alpha = F.softmax(torch.matmul(M, self.w), dim=1).unsqueeze(-1)  # [128, 32, 1]
        out = H * alpha  # [128, 32, 256]
        #输出层
        out = torch.sum(out, 1)  # [128, 256]
        out = F.relu(out)  # [128, 256]
        out = self.fc1(out)  # [128, 64]
        out = self.fc(out)  # [128, 10]
        return out

config=Config()
model=Model(config)
print(model)

输出:

Model(
  (embedding): Embedding(10000, 300, padding_idx=9999)
  (lstm): LSTM(300, 128, num_layers=2, batch_first=True, dropout=0.5, bidirectional=True)
  (tanh1): Tanh()
  (tanh2): Tanh()
  (fc1): Linear(in_features=256, out_features=64, bias=True)
  (fc): Linear(in_features=64, out_features=10, bias=True)
)
  • 28
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值