资讯 文档
技术能力
语音技术
文字识别
人脸与人体
图像技术
语言与知识
视频技术

6.Model

简介

在文心中,我们把深度学习任务中对神经网络的基本操作进行了统一封装,称为Model。一个Model实例中定义的操作包括前向传播网络(forward)、优化策略(optimizer)、指标评估(get_metrics)等部分,这些部分除了可以直接使用文心预置的方法之外,均可实现自定义。

基本结构

每一个Model实例中,都需要实现3个基本功能:搭建前向传播网络、选定优化策略、确定指标评估的方式。这里以一个CNN分类任务来举例说明:

  • 搭建前向传播网络:核心内容是模型的前向计算的组网部分(使用飞桨的接口进行组网)和损失函数的计算。输出即为对输入数据执行变换计算后的结果。
点击查看代码块
    def forward(self, fields_dict, phase):
        """前向计算组网部分包括loss值的计算,必须由子类实现
        :param: fields_dict: 序列化好的id
        :param: phase: 当前调用的阶段,如训练、预测,不同的阶段组网可以不一样
        :return: 一个dict数据,存放TARGET_FEED_NAMES, TARGET_PREDICTS, PREDICT_RESULT,LABEL,LOSS等所有你希望获取的数据
        """
      
        ## 从入参的dict中解析出由Reader构造出来的tensor数据。
        fields_dict = self.fields_process(fields_dict, phase)
        instance_text_a = fields_dict["text_a"]
        record_id_text_a = instance_text_a[InstanceName.RECORD_ID]
        text_a = record_id_text_a[InstanceName.SRC_IDS]
        text_a_lens = record_id_text_a[InstanceName.SEQ_LENS]

        instance_label = fields_dict["label"]
        record_id_label = instance_label[InstanceName.RECORD_ID]
        label = record_id_label[InstanceName.SRC_IDS]

        dict_dim = self.model_params.get('vocab_size', 33261)
        emb_dim = self.model_params.get('emb_dim', 128)
        hid_dim = self.model_params.get('hid_dim', 128)
        hid_dim2 = self.model_params.get('hid_dim2', 96)
        win_size = self.model_params.get('win_size', 3)
        num_labels = self.model_params.get('num_labels', 2)

        unpad_data = fluid.layers.sequence_unpad(text_a, length=text_a_lens)
        
        ## 对样本数据构造embedding(语义表示)向量
        emb = fluid.layers.embedding(input=unpad_data, size=[dict_dim, emb_dim])

        ## 构造好的embedding接入CNN结构层。
        conv = fluid.nets.sequence_conv_pool(
            input=emb,
            num_filters=hid_dim,
            filter_size=win_size,
            act="tanh",
            pool_type="max")

        ## 接入全连接层,进行降维
        fc_1 = fluid.layers.fc(input=[conv], size=hid_dim2)

         ## 接入全连接层,降维到与训练集中的label数目相同的维度,并采用softmax进行概率映射。
        predictions = fluid.layers.fc(input=[fc_1], size=num_labels, act="softmax")
        
        if phase == InstanceName.SAVE_INFERENCE:
            """保存模型时需要的入参:表示模型预测时需要输入的变量名称和顺序"""
            target_feed_name_list = [text_a.name, text_a_lens.name]
            """保存模型时需要的入参:表示预测时最终输出的结果"""
            target_predict_list = [predictions]
            forward_return_dict = collections.OrderedDict()
            forward_return_dict[InstanceName.TARGET_FEED_NAMES] = target_feed_name_list
            forward_return_dict[InstanceName.TARGET_PREDICTS] = target_predict_list
            return forward_return_dict

        ## 损失函数采用交叉熵计算
        cost = fluid.layers.cross_entropy(input=predictions, label=label)
        avg_cost = fluid.layers.mean(x=cost)
        
        """PREDICT_RESULT,LABEL,LOSS 是关键字,必须要赋值并返回"""
        forward_return_dict = collections.OrderedDict()
        forward_return_dict[InstanceName.PREDICT_RESULT] = predictions
        forward_return_dict[InstanceName.LABEL] = label
        forward_return_dict[InstanceName.LOSS] = avg_cost

        return forward_return_dict
  • 选定优化策略:设置优化器,如Adam,Adagrad,SGD等,优化器部分详见Optimizer
点击查看代码块
    def optimizer(self, loss, is_fleet=False):
        """
        :param loss: 前向计算得到的损失值
        :param is_fleet: 是否采用了飞桨的fleet模式
        :return: OrderedDict: 该dict中放的是需要在运行过程中fetch出来的tensor
        """
        opt_param = self.model_params.get('optimization', None)
        if opt_param:
            lr = opt_param.get('learning_rate', 2e-5)
        else:
            lr = 2e-5
        
        ## 调用飞桨提供的优化器相关的API。
        optimizer = fluid.optimizer.Adam(learning_rate=lr)
        if is_fleet:
            optimizer = fleet.distributed_optimizer(optimizer)
        optimizer.minimize(loss)

        optimizer_output_dict = collections.OrderedDict()
        return optimizer_output_dict
  • 确定指标评估的方式:训练过程中某一时刻模型的指标评估部分的动态计算和打印。
点击查看代码块
    def get_metrics(self, forward_return_dict, meta_info, phase):
        """指标评估部分的动态计算和打印
        :param forward_return_dict: executor.run过程中fetch出来的forward中定义的tensor
        :param meta_info:常用的meta信息,如step, used_time, gpu_id等
        :param phase: 当前调用的阶段,包含训练和评估
        :return:
        """
        predictions = forward_return_dict[InstanceName.PREDICT_RESULT]
        label = forward_return_dict[InstanceName.LABEL]
        ## acc计算
        metrics_acc = metrics.Acc()
        acc = metrics_acc.eval([predictions, label])
        
        ## precision计算
        metrics_pres = metrics.Precision()
        precision = metrics_pres.eval([predictions, label])

        if phase == InstanceName.TRAINING:
            step = meta_info[InstanceName.STEP]
            time_cost = meta_info[InstanceName.TIME_COST]
            logging.debug("phase = {0} acc = {1} precision = {2} step = {3} time_cost = {4}".format(
                phase, round(acc, 3), round(precision, 3), step, time_cost))
        if phase == InstanceName.EVALUATE or phase == InstanceName.TEST:
            time_cost = meta_info[InstanceName.TIME_COST]
            logging.debug("phase = {0} acc = {1} precision = {2} time_cost = {3}".format(
                phase, round(acc, 3), round(precision, 3), time_cost))

        metrics_return_dict = collections.OrderedDict()
        metrics_return_dict["acc"] = acc
        metrics_return_dict["precision"] = precision
        return metrics_return_dict

文心中的预置Model

文心提供了丰富的预置Model,支持常见的NLP领域的经典任务,包括文本分类、文本匹配、序列标注、信息抽取等,所有的预置Model文件位于./wenxin/models/目录下,部分Model如下所示:

.
├── __init__.py
├── model.py                                 ## 所有model的基类
├── cnn_classification.py                    ## 基于CNN的单分类网络
├── ernie_cnn_classification.py              ## 在ERNIE基础上进行微调的CNN的单分类网络
├── ....
├── cnn_matching_pairwise.py                 ## 基于CNN的pairwise匹配网络
├── cnn_matching_pointwise.py                ## 基于CNN的pointwise匹配网络
├── ernie_matching_fc_pointwise.py           ## 在ERNIE基础上进行微调的pointwise匹配网络
├── ernie_matching_siamese_pairwise.py       ## 在ERNIE基础上进行微调的pairwise匹配网络
├── ....
├── crf_sequence_label.py                    ## 基于crf结构的序列标注网络
├── ernie_crf_sequence_label.py              ## 在ERNIE基础上进行微调的基于crf结构的序列标注网络
├── ernie_fc_sequence_label.py               ## 在ERNIE基础上进行微调的最简单的序列标注网络
├── ....
├── ernie_one_sent_classification.py         ## 在ERNIE基础上进行微调的单句分类网络
├── ernie_mrc.py                             ## 在ERNIE基础上进行微调的阅读理解任务的网络
├── ernie_hierar_label_classification.py     ## 在ERNIE基础上进行微调的层次化分类网络
├── ernie_multi_label_classification.py      ## 在ERNIE基础上进行微调的多标签分类网络
├── textcnn_hierar_label_classification.py   ## 基于TextCNN结构的层次化分类网络
├── ernie_two_sent_classification.py         ## 在ERNIE基础上进行微调的句对分类网络
└── ....

进阶使用

文心中提供了NLP领域比较通用的经典网络,如果用户需要针对自己的业务场景进行自定义优化使用的话,请参考详细的接口设计与自定义核心接口Model设计

上一篇
5.Reader
下一篇
7. Metrics