使用Modules和Models快速搭建自定义模型

modulesmodels 用于构建 fastNLP 所需的神经网络模型,它可以和 torch.nn 中的模型一起使用。 下面我们会分三节介绍编写构建模型的具体方法。

使用 models 中的模型

fastNLP 在 models 模块中内置了如 CNNTextSeqLabeling 等完整的模型,以供用户直接使用。 以文本分类的任务为例,我们从 models 中导入 CNNText 模型,用它进行训练。

from fastNLP.models import CNNText

model_cnn = CNNText((len(vocab),100), num_classes=2, dropout=0.1)

trainer = Trainer(train_data=train_data, dev_data=dev_data, metrics=metric,
                  loss=loss, device=device, model=model_cnn)
trainer.train()

在 iPython 环境输入 model_cnn ,我们可以看到 model_cnn 的网络结构

CNNText(
  (embed): Embedding(
    (embed): Embedding(16292, 100)
    (dropout): Dropout(p=0.0, inplace=False)
  )
  (conv_pool): ConvMaxpool(
    (convs): ModuleList(
      (0): Conv1d(100, 30, kernel_size=(1,), stride=(1,), bias=False)
      (1): Conv1d(100, 40, kernel_size=(3,), stride=(1,), padding=(1,), bias=False)
      (2): Conv1d(100, 50, kernel_size=(5,), stride=(1,), padding=(2,), bias=False)
    )
  )
  (dropout): Dropout(p=0.1, inplace=False)
  (fc): Linear(in_features=120, out_features=2, bias=True)
)

FastNLP 中内置的 models 如下表所示,您可以点击具体的名称查看详细的 API:

名称 介绍
CNNText 使用 CNN 进行文本分类的模型
SeqLabeling 简单的序列标注模型
AdvSeqLabel 更大网络结构的序列标注模型
ESIM ESIM 模型的实现
StarTransEnc 带 word-embedding的Star-Transformer模 型
STSeqLabel 用于序列标注的 Star-Transformer 模型
STNLICls 用于自然语言推断 (NLI) 的 Star-Transformer 模型
STSeqCls 用于分类任务的 Star-Transformer 模型
BiaffineParser Biaffine 依存句法分析网络的实现
BiLSTMCRF 使用BiLSTM与CRF进行序列标注

使用 nn.torch 编写模型

FastNLP 完全支持使用 pyTorch 编写的模型,但与 pyTorch 中编写模型的常见方法不同, 用于 fastNLP 的模型中 forward 函数需要返回一个字典,字典中至少需要包含 pred 这个字段。

下面是使用 pyTorch 中的 torch.nn 模块编写的文本分类,注意观察代码中标注的向量维度。 由于 pyTorch 使用了约定俗成的维度设置,使得 forward 中需要多次处理维度顺序

import torch
import torch.nn as nn

class LSTMText(nn.Module):
    def __init__(self, vocab_size, embedding_dim, output_dim, hidden_dim=64, num_layers=2, dropout=0.5):
        super().__init__()

        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers, bidirectional=True, dropout=dropout)
        self.fc = nn.Linear(hidden_dim * 2, output_dim)
        self.dropout = nn.Dropout(dropout)

    def forward(self, words):
        # (input) words : (batch_size, seq_len)
        words = words.permute(1,0)
        # words : (seq_len, batch_size)

        embedded = self.dropout(self.embedding(words))
        # embedded : (seq_len, batch_size, embedding_dim)
        output, (hidden, cell) = self.lstm(embedded)
        # output: (seq_len, batch_size, hidden_dim * 2)
        # hidden: (num_layers * 2, batch_size, hidden_dim)
        # cell: (num_layers * 2, batch_size, hidden_dim)

        hidden = torch.cat((hidden[-2, :, :], hidden[-1, :, :]), dim=1)
        hidden = self.dropout(hidden)
        # hidden: (batch_size, hidden_dim * 2)

        pred = self.fc(hidden.squeeze(0))
        # result: (batch_size, output_dim)
        return {"pred":pred}

我们同样可以在 iPython 环境中查看这个模型的网络结构

LSTMText(
  (embedding): Embedding(16292, 100)
  (lstm): LSTM(100, 64, num_layers=2, dropout=0.5, bidirectional=True)
  (fc): Linear(in_features=128, out_features=2, bias=True)
  (dropout): Dropout(p=0.5, inplace=False)
)

使用 modules 编写模型

下面我们使用 fastNLP.modules 中的组件来构建同样的网络。由于 fastNLP 统一把 batch_size 放在第一维, 在编写代码的过程中会有一定的便利。

from fastNLP.modules import Embedding, LSTM, MLP

class MyText(nn.Module):
    def __init__(self, vocab_size, embedding_dim, output_dim, hidden_dim=64, num_layers=2, dropout=0.5):
        super().__init__()

        self.embedding = Embedding((vocab_size, embedding_dim))
        self.lstm = LSTM(embedding_dim, hidden_dim, num_layers=num_layers, bidirectional=True)
        self.mlp = MLP([hidden_dim*2,output_dim], dropout=dropout)

    def forward(self, words):
        embedded = self.embedding(words)
        _,(hidden,_) = self.lstm(embedded)
        pred = self.mlp(torch.cat((hidden[-1],hidden[-2]),dim=1))
        return {"pred":pred}

我们自己编写模型的网络结构如下

MyText(
  (embedding): Embedding(
    (embed): Embedding(16292, 100)
    (dropout): Dropout(p=0.0, inplace=False)
  )
  (lstm): LSTM(
    (lstm): LSTM(100, 64, num_layers=2, batch_first=True, bidirectional=True)
  )
  (mlp): MLP(
    (hiddens): ModuleList()
    (output): Linear(in_features=128, out_features=2, bias=True)
    (dropout): Dropout(p=0.5, inplace=False)
  )
)

FastNLP 中包含的各种模块如下表,您可以点击具体的名称查看详细的 API,也可以通过 fastNLP.modules 进行了解。

名称 介绍  
ConvolutionCharEncoder char级别的卷积 encoder  
LSTMCharEncoder char级别基于LSTM的 encoder  
ConvMaxpool 结合了Convolution和Max-Pooling于一体的模块  
LSTM LSTM模块 轻量封装了PyTorch的LSTM
StarTransformer Star-Transformer 的encoder部分  
TransformerEncoder Transformer的encoder模块,不包含embedding层  
VarRNN Variational Dropout RNN 模块  
VarLSTM Variational Dropout LSTM 模块  
VarGRU Variational Dropout GRU 模块  
MaxPool Max-pooling模块  
MaxPoolWithMask 带mask矩阵的max pooling。在做 max-pooling的时候不会考虑mask值为0的位置。  
AvgPool Average-pooling模块  
AvgPoolWithMask 带mask矩阵的average pooling。在做 average-pooling的时候不会考虑mask值为0的位置。  
MultiHeadAttention MultiHead Attention 模块  
MLP 简单的多层感知器模块  
ConditionalRandomField 条件随机场模块  
viterbi_decode 给定一个特征矩阵以及转移分数矩阵,计算出最佳的路径以及对应的分数 (与 ConditionalRandomField 配合使用)  
allowed_transitions 给定一个id到label的映射表,返回所有可以跳转的列表(与 ConditionalRandomField 配合使用)  
TimestepDropout 简单包装过的Dropout 组件