中文文本分类,基本模型的pytoch实现

news2024/11/18 22:53:43

学习说明:最近发现了一个宝藏仓库,将常见的文本分类方法做了一个介绍、及封装。现在将学习这仓库的一些笔记记录如下

参照资料

649453932/Chinese-Text-Classification-Pytorch: 中文文本分类,TextCNN,TextRNN,FastText,TextRCNN,BiLSTM_Attention,DPCNN,Transformer,基于pytorch,开箱即用。 (github.com)

中文文本分类 pytorch实现 - 知乎 (zhihu.com)

文章目录

      • 参照资料
      • TextRNN
      • TextRNN + Attention
      • TextCNN
      • TextRCNN
      • DPCNN
      • FastText
      • Transformers

TextRNN

  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. 拿出最后时刻的隐层值:[batch_size,hidden_size * 2]
  5. 全连接:num_class是预测的类别数。[batch_size,num_class]
  6. 预测:sotfmax归一化,将num_class个数中概率最大的数对应的类作为最终预测。[batch_size,1]

分析:LSTM能比较好的捕捉长距离语义关系,但由于其递归结构,不能并行计算,速度慢

代码如下:

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            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.fc = nn.Linear(config.hidden_size * 2, config.num_classes)

    def forward(self, x): # x:{[batch_size,seq_len],batch_size}
        x, _ = x # x:[batch_size,seq_len]
        out = self.embedding(x)  # out:[batch_size, seq_len, embeding]
        out, _ = self.lstm(out) # out:[batch_size,seq_len,hidden_size * 2]
        out = self.fc(out[:, -1, :])  # out:[batch_size,class_nums]
        return out

TextRNN + Attention

  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。w = [hidden_size * 2,1]
  5. 对LSTM的输出进行非线性激活后与w进行矩阵相乘,并经softmax归一化,得到每时刻的分值。[batch_size,seq_len,1]
  6. 将LSTM的每一时刻的隐层状态乘对应的分值求和,得到加权平均后的终极隐层值。[batch_size,hidden_size * 2]
  7. 对终极隐层值进行非线性激活后送入两个连续的全连接层。[batch_size,num_class]
  8. 预测:sotfmax归一化,将num_class个数中概率最大的数对应的类作为最终预测。[batch_size,1]

分析:其中4~6步是attention机制计算过程,其实就是对lstm每刻的隐层进行加权平均。比如句长为4,首先算出4个时刻的归一化分值:[0.1, 0.3, 0.4, 0.2],然后
h 终极 = 0.1 h 1 + 0.3 h 2 + 0.4 h 3 + 0.2 h 4 h_{终极}=0.1h_1 + 0.3h_2 + 0.4h_3 + 0.2 h_4 h终极=0.1h1+0.3h2+0.4h3+0.2h4
代码如下

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            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.u = nn.Parameter(torch.Tensor(config.hidden_size * 2, config.hidden_size * 2))
        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:{[batch_size,seq_len],[batch_size]}
        x, _ = x # x:[batch_size,seq_len]
        emb = self.embedding(x) # emb:[batch_size,seq_len,embedding]
        H, _ = self.lstm(emb) # H:[batch_size,seq_len,hidden_size * 2]

        M = self.tanh1(H)  # M:[batch_size,seq_len,hidden_size * 2]
        # M = torch.tanh(torch.matmul(H, self.u))
        alpha = F.softmax(torch.matmul(M, self.w), dim=1).unsqueeze(-1) # alpha:[batch_size,seq_len,1]
        out = H * alpha # out:[batch_size,seq_len,hidden_size * 2]
        out = torch.sum(out, 1) # out:[batch_size,hidden_size * 2]
        out = F.relu(out) # out:[batch_size,hidden_size * 2]
        out = self.fc1(out) # out:[batch_size,hidden_size2]
        out = self.fc(out)  # out:[batch_size,num_classes]
        return out

TextCNN

  1. 模型输入:[batch_size,seq_len]
  2. 经过embedding层:加载预训练词向量或随机初始化,词向量维度为embed_size。[batch_size,seq_len,embed_size]
  3. 卷积层:NLP中卷积核宽度与embed-size相同,相当于一维卷积。3个尺寸的filter_sizes卷积核(2,3,4),每个尺寸的卷积核num_filters有256个,卷积后得到三个特征图[batch_size,num_filters,seq_len - filter_sizes + 1]
    • [batch_size,num_filters,seq_len-1]
    • [batch_size,num_filters,seq_len-2]
    • [batch_size,num_filters,seq_len-3]
  4. 池化层:对三个特征图做最大池化
    • [batch_size,num_filters]
    • [batch_size,num_filters]
    • [batch_size,num_filters]
  5. 拼接:[batch_size,num_filters * 3]
  6. 全连接:num_class是预测的类别数。[batch_size,num_class]
  7. 预测:sotfmax归一化,将num_class个数中概率最大的数对应的类作为最终预测。[batch_size,1]

分析:卷积操作相当于提取了句中的2-gram,3-gram,4-gram信息,多个卷积是为了提取多种特征,最大池化将提取到最重要的信息保留

代码如下:

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
        self.convs = nn.ModuleList(
            [nn.Conv2d(1, config.num_filters, (k, config.embed)) for k in config.filter_sizes])
        self.dropout = nn.Dropout(config.dropout)
        self.fc = nn.Linear(config.num_filters * len(config.filter_sizes), config.num_classes)

    def conv_and_pool(self, x, conv): # x:[batch_size,1,seq_len,embedding],conv:Conv2d(1,num_filters,kernerl_size=(filter_sizes,embedding),stride=(1,1))
        x = F.relu(conv(x)).squeeze(3) # x:[batch_size,num_filters,seq_len - filter_sizes + 1]
        x = F.max_pool1d(x, x.size(2)).squeeze(2) # x:[batch_size,num_filters]
        return x

    def forward(self, x): # x:{[batch_size,seq_len],[batch_size,]}
        x, _ = x # x:[batch_size,seq_len]
        out = self.embedding(x)  # out:[batch_size, seq_len, embedding]
        out = out.unsqueeze(1) # out:[bacth_size,1,seq_len,embedding]
        out = torch.cat([self.conv_and_pool(out, conv) for conv in self.convs], 1) # out:[batch_size,num_filters * len(filter_sizes)]
        out = self.dropout(out) # out:[batch_size,num_filters * len(filter_sizes)]
        out = self.fc(out) # out:[batch_size,num_classes]
        return out

TextRCNN

  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. 将embedding层与LSTM输出拼接,进行非线性激活。[batch_size, seq_len, hidden_size * 2 + embed_size]
  5. 池化层:seq_len个特征中取最大的。[batch_size, hidden_size * 2 + embed_size]
  6. 全连接:num_class是预测的类别数。[batch_size,num_class]
  7. 预测:sotfmax归一化,将num_class个数中概率最大的数对应的类作为最终预测。[batch_size,1]

分析:

双向LSTM每一时刻的隐层值(前向+后向)都可以表示当前词的前向和后向语义信息,将隐藏值与embedding值拼接来表示一个词;然后用最大池化层来筛选出有用的特征信息。就做了一个池化,所以被称之为RCNN

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            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.maxpool = nn.MaxPool1d(config.pad_size)
        self.fc = nn.Linear(config.hidden_size * 2 + config.embed, config.num_classes)

    def forward(self, x): # x:{[batch_size,seq_len],batch_size}
        x, _ = x # x:[batch_size,seq_len]
        emb = self.embedding(x) # emb:[batch_size, seq_len, embedding]
        out, _ = self.lstm(emb) # out:[batch_size,seq_len,hidden_size * 2]
        out = torch.cat((emb, out), 2) # out:[batch_size,seq_len,hidden_size * 2 + embedding]
        out = F.relu(out) # out:[batch_size,seq_len,hidden_size * 2 + embedding]
        out = out.permute(0, 2, 1) # out:[batch_size,hidden_size * 2 + embedding,seq_len]
        out = self.maxpool(out).squeeze() # out:[batch_size,hidden_size * 2 + embedding]
        out = self.fc(out) # out:[batch_size,num_classes]
        return out

DPCNN

  1. 模型输入:[batch_size,seq_len]
  2. 经过embedding层:加载预训练的词向量或随机初始化,词向量维度为embed_size。[batch_size,seq_len,embed_size]
  3. 进行卷积:尺寸为3的卷积核num_filters为250,论文中称这层为region embedding。[batch_size, num_filters, seq_len - 3 + 1]
  4. 接两层卷积(+relu),每层都是num_filters为250,尺寸为3的卷积核(等长卷积,先padding再卷积,保证卷积前后序列的长度不变)。[batch_size,num_filters,seq-len-3+1]
  5. 接下来进行上图中小框的操作
    • 进行大小为3,步长为2的最大池化,将序列长度压缩为原来的1/2(进行采样)
    • 接两层等长卷积(+relu),每层都是num_filters为250,尺寸为3的卷积核
    • 上述两结果相加,残差连接
    • 重复以上步骤,直至序列长度等于1。[batch_size,num_filters,1,1]
  6. 全连接:num_class是预测的类别数。[batch_size,num_class]
  7. 预测:sotfmax归一化,将num_class个数中概率最大的数对应的类作为最终预测。[batch_size,1]

分析:TextCNN的过程类似于提取N-Gram信息,而且只有一层,难以捕捉长距离特征。反观DPCNN,可以看出它的region embedding就是一个去掉池化层的TextCNN,再将卷积层叠加

每层序列长度都减半,可以这么理解:相当于再N-Gram上在再做N-Gram。越往后的层,每个位置融合的信息越多,最后一层提取的就是整个序列的语义信息

代码如下:

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
        self.conv_region = nn.Conv2d(1, config.num_filters, (3, config.embed), stride=1)
        self.conv = nn.Conv2d(config.num_filters, config.num_filters, (3, 1), stride=1)
        self.max_pool = nn.MaxPool2d(kernel_size=(3, 1), stride=2)
        self.padding1 = nn.ZeroPad2d((0, 0, 1, 1))  # top bottom
        self.padding2 = nn.ZeroPad2d((0, 0, 0, 1))  # bottom
        self.relu = nn.ReLU()
        self.fc = nn.Linear(config.num_filters, config.num_classes)

    def forward(self, x): # x:{[batch_size,seq_len],[batch_size,]}
        x, _ = x # x:[batch_size,seq_len]
        x = self.embedding(x) # x:[batch_size,seq_len,embedding]
        x = x.unsqueeze(1)  # x:[batch_size,1,seq_len,embedding]
        x = self.conv_region(x)  # x:[batch_size, num_filters, seq_len-3+1, 1]

        x = self.padding1(x)  # x:[batch_size, num_filters, seq_len, 1]
        x = self.relu(x)  # x:[batch_size, num_filters, seq_len, 1]
        x = self.conv(x)  # x:[batch_size, num_filters, seq_len-3+1, 1]
        x = self.padding1(x)  # x:[batch_size, num_filters, seq_len, 1]
        x = self.relu(x)  # x:[batch_size, num_filters, seq_len, 1]
        x = self.conv(x)  # x:[batch_size, num_filters, seq_len-3+1, 1]
        while x.size()[2] > 2:
            x = self._block(x) # x:[batch_size,num_filters,1,1]
        x = x.squeeze()  # x:[batch_size,num_filters]
        x = self.fc(x) # x:[batch_size,num_class]
        return x

    def _block(self, x): # x:[batch_size, num_filters, seq_len-3+1, 1]
        x = self.padding2(x)
        px = self.max_pool(x)

        x = self.padding1(px)
        x = F.relu(x)
        x = self.conv(x)

        x = self.padding1(x)
        x = F.relu(x)
        x = self.conv(x)

        # Short Cut
        x = x + px
        return x

FastText

  1. 用哈希算法将2-gram、3-gram信息分别映射到两张表内
  2. 模型输入:[batch_size,seq_len]
  3. 经过embedding层:加载预训练的词向量或随机初始化,词向量维度为embed_size。[batch_size,seq_len,embed_size],同理:
    • 2-gram:[batch_size, seq_len, embed_size]
    • 3-gram:[batch_size, seq_len, embed_size]
  4. 拼接embedding层:batch_size, seq_len, embed_size * 3]
  5. 求所有seq_len个词的均值:[batch_size, embed_size * 3]
  6. 全连接+非线性激活:隐层大小hidden_size。[batch_size,hidden_size]
  7. 全连接:num_class是预测的类别数。[batch_size,num_class]
  8. 预测:sotfmax归一化,将num_class个数中概率最大的数对应的类作为最终预测。[batch_size,1]

分析:不加N-Gram信息,就是词袋模型。对于N-Gram,我们设定一个词表,这个词表大小自己设定大小,理论上越大效果越好,但N-Gram词表大小太大,机器会承受不了,不同的N-Gram用哈希算法可能会映射到词表同一位置,这是一个弊端,但影响不是很大。对于N-Gram词表大小对效果的影响,可以描述为:一分价钱1分货,十分价钱1.1分货

代码如下:

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
        self.embedding_ngram2 = nn.Embedding(config.n_gram_vocab, config.embed)
        self.embedding_ngram3 = nn.Embedding(config.n_gram_vocab, config.embed)
        self.dropout = nn.Dropout(config.dropout)
        self.fc1 = nn.Linear(config.embed * 3, config.hidden_size)
        # self.dropout2 = nn.Dropout(config.dropout)
        self.fc2 = nn.Linear(config.hidden_size, config.num_classes)

    def forward(self, x): # x:{[batch_size,seq_len],[batch_size,],[batch_size,seq_len],[batch_size,seq_len]}

        out_word = self.embedding(x[0]) # out_word:[batch_size,seq_len,embedding]
        out_bigram = self.embedding_ngram2(x[2]) # out_bigram:[batch_size,seq_len,embedding]
        out_trigram = self.embedding_ngram3(x[3]) # out_trigram:[batch_size,seq_len,embedding]
        out = torch.cat((out_word, out_bigram, out_trigram), -1) # out:[batch_size,seq_len,embedding * 3]

        out = out.mean(dim=1) # out:[batch_size,embedding * 3]
        out = self.dropout(out)
        out = self.fc1(out) # out:[batch_size,hidden_size]
        out = F.relu(out)
        out = self.fc2(out) # out:[batch_size,num_class]
        return out

Transformers

详细说明:(203条消息) Transformer原理以及文本分类实战_五月的echo的博客-CSDN博客_transformer文本分类

代码如下:

class ConfigTrans(object):

    """配置参数"""
    def __init__(self):
        self.model_name = 'Transformer'
        self.dropout = 0.5                              
        self.num_classes = cfg.classes                      # 类别数
        self.num_epochs = 100                # epoch数
        self.batch_size = 128             # mini-batch大小
        self.pad_size = cfg.nV                     # 每句话处理成的长度(短填长切),这个根据自己的数据集而定
        self.learning_rate = 0.001                    # 学习率
        self.embed = 50          # 字向量维度
        self.dim_model = 50      # 需要与embed一样
        self.hidden = 1024 
        self.last_hidden = 512
        self.num_head = 5       # 多头注意力,注意需要整除
        self.num_encoder = 2    # 使用两个Encoder,尝试6个encoder发现存在过拟合,毕竟数据集量比较少(10000左右),可能性能还是比不过LSTM
config = ConfigTrans()
class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        if config.embedding_pretrained is not None:
            self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
        else:
            self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)

        self.postion_embedding = Positional_Encoding(config.embed, config.pad_size, config.dropout, config.device)
        self.encoder = Encoder(config.dim_model, config.num_head, config.hidden, config.dropout)
        self.encoders = nn.ModuleList([
            copy.deepcopy(self.encoder)
            # Encoder(config.dim_model, config.num_head, config.hidden, config.dropout)
            for _ in range(config.num_encoder)])

        self.fc1 = nn.Linear(config.pad_size * config.dim_model, config.num_classes)
        # self.fc2 = nn.Linear(config.last_hidden, config.num_classes)
        # self.fc1 = nn.Linear(config.dim_model, config.num_classes)

    def forward(self, x): # x:{[batch_size,seq_len],[batch_size,]}
        out = self.embedding(x[0]) # out:[batch_size,seq_len,embedding]
        out = self.postion_embedding(out) # out:{batch_size,seq_len,embedding}
        for encoder in self.encoders:
            out = encoder(out) # out:[batch_size,seq_len,dim_model]
        out = out.view(out.size(0), -1) #  out:[batch_size,seq_len * dim_model]
        # out = torch.mean(out, 1)
        out = self.fc1(out) # out:[batch_size,num_class]
        return out


class Encoder(nn.Module):
    def __init__(self, dim_model, num_head, hidden, dropout):
        super(Encoder, self).__init__()
        self.attention = Multi_Head_Attention(dim_model, num_head, dropout)
        self.feed_forward = Position_wise_Feed_Forward(dim_model, hidden, dropout)

    def forward(self, x): # x:[batch_size,seq_len,dim_model]
        out = self.attention(x) # out:[batch_size,seq_len,dim_model]
        out = self.feed_forward(out) # out:[batch_size,seq_len,dim_model]
        return out


class Positional_Encoding(nn.Module):
    def __init__(self, embed, pad_size, dropout, device):
        super(Positional_Encoding, self).__init__()
        self.device = device
        self.pe = torch.tensor([[pos / (10000.0 ** (i // 2 * 2.0 / embed)) for i in range(embed)] for pos in range(pad_size)])
        self.pe[:, 0::2] = np.sin(self.pe[:, 0::2])
        self.pe[:, 1::2] = np.cos(self.pe[:, 1::2])
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        out = x + nn.Parameter(self.pe, requires_grad=False).to(self.device)
        out = self.dropout(out)
        return out


class Scaled_Dot_Product_Attention(nn.Module):
    '''Scaled Dot-Product Attention '''
    def __init__(self):
        super(Scaled_Dot_Product_Attention, self).__init__()

    def forward(self, Q, K, V, scale=None):
        '''
        Args:
            Q: [batch_size, len_Q, dim_Q]
            K: [batch_size, len_K, dim_K]
            V: [batch_size, len_V, dim_V]
            scale: 缩放因子 论文为根号dim_K
        Return:
            self-attention后的张量,以及attention张量
        '''
        attention = torch.matmul(Q, K.permute(0, 2, 1)) # Q*K^T,attention:[batch_size * num_head,seq_len,seq_len]
        if scale:
            attention = attention * scale
        # if mask:  # TODO change this
        #     attention = attention.masked_fill_(mask == 0, -1e9)
        attention = F.softmax(attention, dim=-1) # attention:[batch_size * num_head,seq_len,seq_len]
        context = torch.matmul(attention, V) # context:[batch_size * num_head,seq_len,dim_head]
        return context


class Multi_Head_Attention(nn.Module):
    def __init__(self, dim_model, num_head, dropout=0.0):
        super(Multi_Head_Attention, self).__init__()
        self.num_head = num_head
        assert dim_model % num_head == 0 # head数必须能够整除隐层大小
        self.dim_head = dim_model // self.num_head # 按照head数量进行张量均分
        self.fc_Q = nn.Linear(dim_model, num_head * self.dim_head) # Q,通过Linear实现张量之间的乘法,等同手动定义参数W与之相乘
        self.fc_K = nn.Linear(dim_model, num_head * self.dim_head)
        self.fc_V = nn.Linear(dim_model, num_head * self.dim_head)
        self.attention = Scaled_Dot_Product_Attention()
        self.fc = nn.Linear(num_head * self.dim_head, dim_model)
        self.dropout = nn.Dropout(dropout)
        self.layer_norm = nn.LayerNorm(dim_model)

    def forward(self, x): # x:[batch_size,seq_len,embedding]
        batch_size = x.size(0)
        Q = self.fc_Q(x) # Q:[batch_size,seq_len,dim_model]
        K = self.fc_K(x) # K:[batch_size,seq_len,dim_model]
        V = self.fc_V(x) # V:[batch_size,seq_len,dim_model]
        Q = Q.view(batch_size * self.num_head, -1, self.dim_head) # Q:[batch_size * num_head,seq_len,dim_head] 注意:dim_head = dim_model / num_head
        K = K.view(batch_size * self.num_head, -1, self.dim_head) # K:[batch_size * num_head,seq_len,dim_head]
        V = V.view(batch_size * self.num_head, -1, self.dim_head) # V:[batch_size * num_head,seq_len,dim_head]
        # if mask:  # TODO
        #     mask = mask.repeat(self.num_head, 1, 1)  # TODO change this
        scale = K.size(-1) ** -0.5  # sqrt(1/dim_head),根号dk分之一,对应Scaled操作,缩放因子
        context = self.attention(Q, K, V, scale)# Scaled_Dot_Product_Attention计算,context:[batch_size * num_head,seq_len,dim_head]

        context = context.view(batch_size, -1, self.dim_head * self.num_head) # context:[batch_size,seq_len,num_head * dim_head]
        out = self.fc(context) # out:[batch_size,seq_len,dim_model]
        out = self.dropout(out)
        out = out + x  # 残差连接
        out = self.layer_norm(out)
        return out


class Position_wise_Feed_Forward(nn.Module):
    def __init__(self, dim_model, hidden, dropout=0.0):
        super(Position_wise_Feed_Forward, self).__init__()
        self.fc1 = nn.Linear(dim_model, hidden)
        self.fc2 = nn.Linear(hidden, dim_model)
        self.dropout = nn.Dropout(dropout)
        self.layer_norm = nn.LayerNorm(dim_model)

    def forward(self, x): # x:[batch_size,seq_len,dim_model]
        out = self.fc1(x) # out:[batch_size,seq_len,hidden]
        out = F.relu(out)
        out = self.fc2(out) # out:[batch_size,seq_len,dim_model]
        out = self.dropout(out)
        out = out + x  # 残差连接
        out = self.layer_norm(out)
        return out

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

宣布 .NET MAUI 支持 .NET 7 Release Candidate 2

支持 .NET 7 Release Candidate 2的 .NET 多平台应用程序 UI (MAUI) 现在可在 Windows 和 Mac 上的 Visual Studio 17.4 Preview 4 中使用。RC2 的主要主题是质量和对带有 iOS 16 的 Xcode 14 的 .NET 支持。此版本包含在生产中使用的上线支持许可证。 在相关新闻中&#xff0…

Linux 内存node和zone

文章目录前言一、内存模型二、(N)UMA2.1 简介2.2 节点2.3 UMA节点与Flat Memory Model2.4 zone2.4.1 zone2.4.2 zone_type参考资料前言 一、内存模型 所谓memory model,其实就是从cpu的角度看,其物理内存的分布情况,…

图解操作系统-cpu cache

不同物理器件的访问速度不一:速度快的代价高、容量小;代价低且容量大,速度较慢。 为充分发挥各种器件优点,计算机存储数据的物理器件不会只选择一种,而是以CPU为核心,由内而外地组建一整套存储体系结构。它…

亿可控_第2章_指标数据采集与断连监控

亿可控_第2章_指标数据采集与断连监控 文章目录亿可控_第2章_指标数据采集与断连监控第2章 指标数据采集与断连监控学习目标1. EMQ指标主题订阅1.1 Eclipse paho简介1.2 发送与订阅消息1.2.1 发送消息1.2.2 订阅消息1.3 订阅指标主题1.3.1 需求分析1.3.2 实现思路1.3.3 代码实现…

23模式---单例模式

单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例) 这个也是23设计模型中最…

Python 图像处理OpenCV:几何变换(笔记)

包括图像缩放、图像平移、图像旋转、图像的仿射变换、图像的透射变换及图像金字塔等内容。 图像缩放: 缩放是对图像的大小进行调整,即使图像放大或缩小。cv2.resize(src,dsize,fx0,fy0,interpolationcv2.INTER_LINEAR)src : 输入图像dsize: 绝对尺寸&a…

Linux运维面试题总结—Linux基础、计算机网络基础

文章目录一、三次握手四次挥手二、如何划分vlan三、为什么划分vlanvlan三个模式:vxlan和vlan区别是什么?四、OSI七层模型及对应协议五、Linux中 查找大于10M的文件并删除六、查看cup占用情况,查看内存,查看磁盘IO使用情况&#xf…

图像处理黑科技——弯曲矫正、去摩尔纹、切边增强、PS检测

目录0 前言1 弯曲矫正2 去摩尔纹3 图像切边增强4 PS检测5 总结0 前言 合合信息是行业领先的人工智能及大数据科技企业,专注文字识别领域16年,在智能文字识别及商业大数据等核心领域处于国内领先地位,全球企业和个人用户提供创新的数字化、智…

代码随想录动态规划——一和零

题目 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。 示例 1: 输入:strs [“10…

Oracle Unifier 系统架构简述(安装部署)

关于Oracle Primavera Unifier 的应用架构,其实在我之前的博客已有介绍相关内容 谈谈 Oracle P6 , Unifier 和其他应用系统间的联系https://campin.blog.csdn.net/article/details/104972949 从官方文档方面,其实在《unifier_performance_and_sizing_g…

【C语言】全面解析数据在内存中的存储

文章目录前言类型的基本分类整型浮点数自定义类型整型在内存中的存储原码、反码、补码大端和小端如何判断编译器是大端还是小端浮点数在内存中的存储总结前言 C语言中有char、short、int、long、long long、float和doubole这些数据类型。这些数据类型也叫内置类型。 所占存储空…

JECloud微服务低代码平台重大发布。

JECloud微服务低代码平台【1.0.0】版升级发布,本次发布内容如下: JECloud微服务低代码平台是一款基于元数据领域模型构建的低代码开发平台,其底层采用微服务与微应用构建底层框架,并基于基础框架构建各核心微服务模块来实现低代码…

手撕七大排序 (四)

归并排序归并排序递归写法一. 基本概念二. 图解归并排序递归写法 一. 基本概念 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并…

数据结构与算法——链表(双向链表,顺序表与链表的比较)

🍓个人主页:bit.. 🍒系列专栏:Linux(Ubuntu)入门必看 C语言刷题 数据结构与算法 目录 一.双向链表 二.双向链表的对称性:(设指针p指向某一结点) 1.双向链表的插入 2.双向链表的删除 …

浏览器中的页面循环系统

【】渲染进程中有个主线程处理安排好的任务,为了在线程运行过程中接收并处理新任务,引入了事件循环机制;为了处理其他线程发送来的任务,引入消息队列;为了处理其他进程发送来的任务,渲染进程专门有一个IO线…

【数据结构初阶】二、顺序表的实现

目录 一、线性表 二、顺序表 2.1 顺序表概念及结构 2.2 顺序表接口实现 2.2.1 顺序表初始化 2.2.2 顺序表的销毁 2.2.3 顺序表的打印 2.2.4 顺序表增加数据(插入,头插、尾插) 2.2.5 顺序表删除数据(删除,头删…

Uniapp集成腾讯IM+音视频通话

腾讯IM(包含界面)源码下载相关配置 传送门:https://cloud.tencent.com/document/product/269/36887 传送门:https://github.com/TencentCloud/TIMSDK/tree/master/uni-app vue2 vue3都可 笔者用的vue2 解压文件 拖到编辑器 #项目右键 在命令行窗口打开 …

Promethues原理详解

目录 引言 一、Prometheus概念 1.1、什么是Prometheus 1.2、Zabbix和Prometheus区别 1.3、Prometheus的特点 二、运维监控平台设计思路 三、Prometheus监控体系 3.1、系统层监控(需要监控的数据) 3.2、中间件及基础设施类监控 3.3、应用层监控…

语音合成经典模型结构介绍

(以下内容搬运自 PaddleSpeech) Models introduction TTS system mainly includes three modules: Text Frontend, Acoustic model and Vocoder. We introduce a rule-based Chinese text frontend in cn_text_frontend.md. Here, we will introduce acoustic models and voc…

XDataverse免费的统一数据库管理工具

XDataverse产品简介 XDataverse是一款通用的数据库管理工具,主要管理关系型数据库,同时也支持一些其余类型的数据库,比如Redis。其主要功能有 支持主流关系型数据库的常规操作,比如MySQL,SQLServer,SQlite,SQLCE,Postg…