define_task_example.md 3.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
# 如何修改Task中的模型网络

在应用中,用户需要更换迁移网络结构以调整模型在数据集上的性能。根据[如何自定义Task](./how_to_define_task.md),本教程展示如何修改Task中的默认网络。
以序列标注任务为例,本教程展示如何修改默认网络结构。SequenceLabelTask提供了两种网络选择,一种是FC网络,一种是FC+CRF网络。

此时如果想在这基础之上,添加LSTM网络,组成BiLSTM+CRF的一种序列标注任务常用网络结构。
此时,需要定义一个Task,继承自SequenceLabelTask,并改写其中build_net()方法。


下方代码示例写了一个BiLSTM+CRF的网络。代码如下:

```python
class SequenceLabelTask_BiLSTMCRF(SequenceLabelTask):
    def _build_net(self):
        """
        自定义序列标注迁移网络结构BiLSTM+CRF
        """
        self.seq_len = fluid.layers.data(
            name="seq_len", shape=[1], dtype='int64', lod_level=0)

        if version_compare(paddle.__version__, "1.6"):
            self.seq_len_used = fluid.layers.squeeze(self.seq_len, axes=[1])
        else:
            self.seq_len_used = self.seq_len

        if self.add_crf:
            # 迁移网络为BiLSTM+CRF

            # 去padding
            unpad_feature = fluid.layers.sequence_unpad(
                self.feature, length=self.seq_len_used)

            # bilstm层
            hid_dim = 128
            fc0 = fluid.layers.fc(input=unpad_feature, size=hid_dim * 4)
            rfc0 = fluid.layers.fc(input=unpad_feature, size=hid_dim * 4)
            lstm_h, c = fluid.layers.dynamic_lstm(
                input=fc0, size=hid_dim * 4, is_reverse=False)
            rlstm_h, c = fluid.layers.dynamic_lstm(
                input=rfc0, size=hid_dim * 4, is_reverse=True)
            # 拼接lstm
            lstm_concat = fluid.layers.concat(input=[lstm_h, rlstm_h], axis=1)

            self.emission = fluid.layers.fc(
                size=self.num_classes,
                input=lstm_concat,
                param_attr=fluid.ParamAttr(
                    initializer=fluid.initializer.Uniform(low=-0.1, high=0.1),
                    regularizer=fluid.regularizer.L2DecayRegularizer(
                        regularization_coeff=1e-4)))
            size = self.emission.shape[1]
            fluid.layers.create_parameter(
                shape=[size + 2, size], dtype=self.emission.dtype, name='crfw')
            # CRF层
            self.ret_infers = fluid.layers.crf_decoding(
                input=self.emission, param_attr=fluid.ParamAttr(name='crfw'))
            ret_infers = fluid.layers.assign(self.ret_infers)
            # 返回预测值,list类型
            return [ret_infers]
        else:
            # 迁移网络为FC
            self.logits = fluid.layers.fc(
                input=self.feature,
                size=self.num_classes,
                num_flatten_dims=2,
                param_attr=fluid.ParamAttr(
                    name="cls_seq_label_out_w",
                    initializer=fluid.initializer.TruncatedNormal(scale=0.02)),
                bias_attr=fluid.ParamAttr(
                    name="cls_seq_label_out_b",
                    initializer=fluid.initializer.Constant(0.)))

            self.ret_infers = fluid.layers.reshape(
                x=fluid.layers.argmax(self.logits, axis=2), shape=[-1, 1])

            logits = self.logits
            logits = fluid.layers.flatten(logits, axis=2)
            logits = fluid.layers.softmax(logits)
            self.num_labels = logits.shape[1]
            # 返回预测值,list类型
            return [logits]
```

以上代码通过继承PaddleHub已经内置的Task,改写其中_build_net方法即可实现自定义迁移网络结构。