PAI官方提供了NLP模型压缩镜像,助力您快捷地进行文本类模型的训练和优化。本文介绍如何在PAI-DSW和PAI-DLC中,使用该镜像训练并优化文本分类模型。此外,针对获得的PyTorch和TensorFlow文本分类模型,介绍进行模型推理的具体方法。

背景信息

NLP模型压缩镜像采用PAI-Compression框架,主要应用于文本类任务,目前仅支持文本分类任务。该镜像预装了常用的开源框架(Huggingface和EasyTransfer),并集成了模型优化和系统优化的相关技术。使用该镜像进行训练时,您只需要通过一行命令或几行代码即可方便快捷地完成模型训练和优化操作,从而获得针对特定数据集的优化模型。您无需对该模型进行任何优化,即可直接部署。

使用限制

使用NLP模型压缩镜像进行模型训练和优化时,必须满足以下要求:
  • 如果您通过PAI-DSW进行模型训练,仅支持实例资源GPU的PAI-DSW实例。
  • 如果您通过PAI-DLC进行模型训练,仅支持公共资源组的工作集群。

准备数据

NLP模型压缩镜像支持CSV和JSON两种格式的输入数据:
  • CSV数据格式
    label,sentence
    0,xxxx
    1,xxxxx
    2,xxxxxx
    其中第一行表示每列数据的属性,取值为固定值label,sentencelabel表示第一列数据为文本的对应类别,sentence表示第二列数据为具体的文本信息。其他的每一行均表示一条数据,包含数据的类别和文本。
  • JSON数据格式
    {'label':0, 'sentence':xxxxx}
    {'label':1, 'sentence':xxxxxx}
    {'label':2, 'sentence':xxxxxxx}
    其中每一行表示一条数据,每条数据包含两个属性的KV对。label对应的value表示文本对应的类别,sentence对应的value表示具体的文本信息。

步骤一:获取NLP模型压缩镜像的地址

  1. 进入镜像管理列表页面。
    1. 登录PAI控制台
    2. 在左侧导航栏,选择AI资产管理 > 镜像管理
  2. 查看目标镜像的地址。
    1. 镜像管理列表PAI官方公共镜像页签,搜索nlp-compression
    2. 单击目标镜像操作列下的ACR镜像地址
    3. 在镜像详情页面,查看镜像的公网地址
    4. 使用半角冒号(:)将公网地址与模型最终部署的平台类型(GPU或CPU)进行拼接,即得镜像地址。
      例如,公网地址registry.cn-hangzhou.aliyuncs.com/pai-compression/nlp,最终的优化模型部署在GPU平台,则镜像地址为registry.cn-hangzhou.aliyuncs.com/pai-compression/nlp:gpu
      说明 如果最终的优化模型部署在GPU平台,则必须选择GPU版本的镜像。如果最终的优化模型部署在CPU平台,则选择CPU版本的镜像。

步骤二:训练并优化模型

镜像里已经预装了所有依赖的环境和库,您可以在PAI-DSW或PAI-DLC中,使用该镜像训练并优化模型:

在PAI-DSW,使用该镜像训练并优化模型的具体方法如下。

  1. 创建PAI-DSW实例,您需要将如下参数配置为特定值。关于如何创建PAI-DSW实例,请参见创建实例
    您需要将PAI-DSW实例的如下参数配置为特定值:
    • 配置实例资源GPU
    • 配置实例镜像自定义镜像,并在下方的文本框中输入上一步获取的镜像地址。
  2. 交互式建模(DSW)页面,单击目标实例操作列下的打开,进入PAI-DSW开发环境。
  3. 在顶部菜单栏,选择File > New > Notebook,创建Notebook建模文件。
  4. 您可以根据自己的需求编写业务代码,在模型训练时,调用如下训练代码。
    from bert_training.training import train 
    
    train(task_type='text-classification',    # 任务类型,目前仅支持文本分类。
          train_file_path="xxx",              # 训练数据的存储位置。
          val_file_path="xxx",                # 测试数据的存储位置。
          compression_ratio=0.5,              # [0, 1):压缩率,越接近1,输出的模型越小。
          model_type='pytorch',               # {'pytorch', 'tensorflow'}, 训练完成后,输出的模型类型。
          language='chinese',                 # {'chinese'}, 数据语言。
          device_type='gpu',                  # {'gpu', 'x86_cpu', 'arm_cpu'},最终部署的硬件平台。
          train_load_config=None,             # 训练参数。
          save_dir="./",                      # 输出路径,默认为当前路径。
          enable_blade=True,                  # 是否开启PAI-Blade敏捷版优化。
    ) 
    您需要根据实际需要修改如下参数值。
    参数 是否必选 描述 类型 默认值
    task_type 任务类型。目前仅支持文本分类,因此为固定值'text-classification' STRING
    train_file_path 训练数据的存储位置。 STRING
    val_file_path 测试数据的存储位置。 STRING
    compression_ratio 压缩率,取值越接近1,输出的模型越小。该参数取值范围为[0, 1) FLOAT 0
    model_type 训练完成后,输出的模型类型。该参数的取值包括:
    • 'pytorch'
    • 'tensorflow'
    STRING 'pytorch'
    language 数据语言。 STRING 'chinese'
    device_type 模型最终部署的平台,取值包括:
    • 'gpu'
    • 'x86_cpu'
    STRING 'gpu'
    train_load_config 训练参数。使用PAI-DSW进行模型训练时,是通过Python Library进行调用,因此该参数为一个DICT。 DICT 具体参数请参见表 1
    save_dir 输出路径,默认为当前路径。 STRING 当前路径
    enable_blade 是否开启PAI-Blade敏捷版优化,取值包括:
    • True:开启PAI-Blade敏捷版优化。
    • False:关闭PAI-Blade敏捷版优化。
    说明 如果开启PAI-Blade敏捷版优化,则需要保证训练服务器和实际部署服务器的GPU/CPU型号一致。
    BOOL True
  5. 运行编写好的训练代码。

在PAI-DLC,使用该镜像训练并优化模型的具体方法如下。

  1. 进入PAI-DLC Dashboard。
    1. 登录PAI控制台
    2. 在左侧导航栏,选择模型开发和训练 > 云原生深度学习训练(DLC)
    3. 在PAI-DLC管理控制台页面,找到类型公共资源组的工作集群,单击操作列下的集群控制台
  2. 创建任务,配置节点镜像自定义镜像,并在下方的文本框中输入上一步获取的镜像地址。配置执行命令为如下类似命令。关于如何创建任务,请参见创建任务
    python3 /scripts/train_model.py \
            --train_file_path /root/data/train.csv \
            --val_file_path /root/data/val.csv \
            --model_type pytorch \
            --compression_ratio 0.5 \
            --save_dir /root/data/bert_training 
    其中/scripts/train_model.py为预置的训练脚本,无需修改。您只需要根据实际需要修改如下参数值。
    参数 是否必选 描述 类型 默认值
    train_file_path 训练数据集的存储路径,通常为CSV或JSON格式的文件。 STRING
    val_file_path 测试数据集的存储路径,通常为CSV或JSON格式的文件。 STRING
    task_type 任务类型,仅支持文本分类。 STRING 'text-classification'
    compression_ratio 模型压缩率,取值越接近1,输出的模型越小。该参数取值范围为[0, 1) FLOAT 0
    model_type 训练完成后,输出的模型类型。该参数取值范围包括:
    • 'pytorch'
    • 'tensorflow'
    STRING 'pytorch'
    language 文本语言,仅支持中文。 STRING 'chinese'
    device_type 模型最终部署的硬件平台,取值包括:
    • 'gpu'
    • 'x86_cpu'
    STRING 'gpu'
    train_load_config 训练参数。使用PAI-DLC进行模型训练时是通过命令行调用脚本,因此该参数为配置好训练参数的JSON文件路径。 STRING 具体参数请参见表 1
    save_dir 训练相关信息和优化模型保存的位置。模型训练和优化完成后,会在save_dir下生成如下两个文件夹:
    • experiments保存训练中记录的内容。
    • outputs保存最终输出结果。
    STRING 当前路径
    enable_blade 是否开启PAI-Blade敏捷版优化,取值包括:
    • True:开启PAI-Blade敏捷版优化。
    • False:关闭PAI-Blade敏捷版优化。
    说明 如果开启PAI-Blade敏捷版优化,则需要保证训练服务器和实际部署服务器的GPU/CPU型号一致。
    BOOL True
    表 1. train_load_config(训练的具体参数)
    参数 描述 类型 默认值
    learning_rate 学习率,建议取值范围为{1e-4, 5e-5, 3e-5, 1e-5} FLOAT 3e-5
    train_batch_size 训练的Batch Size。 INT 32
    eval_batch_size 测试的Batch Size。 INT 32
    max_seq_length 输入单条文本数据的最大长度。如果数据长度大于该参数值,则会被截断。 INT 128
    epochs 训练的Epoch数量。 INT 3
    kd_lambda 知识蒸馏损失函数的权重参数。 FLOAT 1.0
    width_mult 网络宽度(Channel数量)的搜索空间,取值越大,训练时间越长。 LIST [1.0, 0.75, 0.5, 0.25]
    depth_mult 网络深度(层数)的搜索空间,取值越大,训练时间越长。 LIST [1.0, 0.75, 0.5, 0.25]

模型推理

优化完成的模型默认输出在save_diroutputs文件夹,您可以使用该模型进行模型推理。本文分别介绍使用PyTorch和TensorFlow的文本分类模型进行模型推理,示例如下:
  • 文本分类(PyTorch)
    输出的模型为PyTorch类型时,outputs文件夹下包含如下三个文件:
    • model.pt:优化的模型。
    • config.json:模型的配置文件。
    • token:数据词表信息。
    如果启用PAI-Blade敏捷版优化,则使用命令import blade runtime导入库,且需要获取Token并进行鉴权。如何获取PAI-Blade敏捷版Token,请参见获取Token。如何鉴权并使用模型,请参见使用SDK部署PyTorch模型推理。如果模型部署在PAI-EAS,则调用方式请参见公网地址调用
    from transformers import AutoConfig, AutoTokenizer
    import torch
    
    # 根据outputs文件夹下输出的优化结果进行修改。
    model_path = 'outputs/xxx/model.pt'
    config_path = 'outputs/xxx/config.json'
    token_path = 'outputs/xxx/token'
    input_str = '需要进行分类的文本'
    
    # 数据预处理准备。
    config = AutoConfig.from_pretrained(config_path, num_labels=类别数量)
    tokenizer = AutoTokenizer.from_pretrained(token_path, config=config)
    
    # 数据预处理。
    input_tensor = tokenizer(input_str)
    input_tensors = [torch.LongTensor(input_tensor['input_ids']).unsqueeze(0)\
                    .cuda(), torch.LongTensor(input_tensor['attention_mask'])\
                    .unsqueeze(0).cuda(), \
            torch.LongTensor(input_tensor['token_type_ids']).unsqueeze(0).cuda()]
    seq_len = len(input_tensor['input_ids'])
    
    # -------------------- 模型部署在本地 --------------------
    # 如果启用PAI-Blade敏捷版优化,则需要import blade runtime,且需要鉴权。
    import blade.runtime.torch
    
    model = torch.jit.load(model_path)
    model = model.cuda()
    output = model(*input_tensors)
    # ------------------------------------------------------
    
    # -------------------- 模型部署在EAS --------------------
    from eas_prediction import PredictClient
    from eas_prediction import TorchRequest
    
    client = PredictClient('公网调用的访问地址','任务名')
    client.set_token('公网地址调用信息中获取的token')
    client.init()
    
    request = TorchRequest()
    request.add_feed(0, [1, seq_len], TorchRequest.DT_INT64, input_tensors[0])
    request.add_feed(1, [1, seq_len], TorchRequest.DT_INT64, input_tensors[1])
    request.add_feed(2, [1, seq_len], TorchRequest.DT_INT64, input_tensors[2])
    resp = client.predict(request)
    output = resp.get_values(0)
    # ------------------------------------------------------
    
    # 输出的output中的元素数量为num_labels,每个元素分别表示待分类本文属于每个类别的概率,取值越大,属于该类别的可能性越高。
    label = torch.argmax(output)
  • 文本分类(TensorFlow)
    输出的模型为TensorFlow类型时,outputs文件夹下包含如下三个文件:
    • model.pb:优化的模型。
    • config.json:模型的配置文件。
    • vocab.txt:数据词表信息。
    如果启用PAI-Blade敏捷版优化,则使用命令import blade runtime导入库,且需要获取Token并进行鉴权。如何获取PAI-Blade敏捷版Token,请参见获取Token。如何鉴权并使用模型,请参见使用SDK部署TensorFlow模型推理。如果模型部署在PAI-EAS,则调用方式请参见公网地址调用
    from easytransfer import preprocessors, Config
    import tensorflow as tf
    import numpy as np
    import json
    
    # 根据outputs文件夹下输出的优化结果进行修改。
    model_path = 'outputs/xxx/model.pb'
    config_path = 'outputs/xxx/config.json'
    token_path = 'outputs/xxx/vocab.txt'
    input_str = '需要进行分类的文本'
    
    with tf.Session() as sess:
        # 数据预处理准备。
        with open(config_path, 'r') as f:
            config_json = json.loads(f.read())
        
        config = Config(mode='preprocess', config_json=config_json)
        preprocessor = preprocessors.get_preprocessor(model_path, user_defined_config=config, token=token_path)
        input_str_ph = tf.placeholder(name="input_str_pb", dtype=tf.string)
        input_ids, input_mask, segment_ids, label_ids = preprocessor({'sentence':[input_str_ph]})
        
        # 数据预处理。
        input_data = sess.run([input_ids, input_mask, segment_ids], feed_dict={input_str_ph:input_str})
        seq_len = input_data[0].shape[1]
        
        # -------------------- 模型部署在本地 --------------------
        # 如果启用PAI-Blade敏捷版优化,则需要import blade runtime,且需要鉴权。
        import blade.runtime.tensorflow
        with tf.gfile.FastGFile(model_path,'rb') as f:
              graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        sess.graph.as_default()
        tf.import_graph_def(graph_def, name='')
        output_tensor = sess.graph.get_tensor_by_name("output:0")
        output = sess.run(output_tensor, feed_dict={'input_ids:0':input_data[0],\
                     'input_mask:0':input_data[1], 'segment_ids:0':input_data[2]})
        # -----------------------------------------------------
        
        # -------------------- 模型部署在PAI-EAS --------------------
        from eas_prediction import PredictClient
        from eas_prediction import TFRequest
    
        client = PredictClient('公网调用的访问地址','任务名')
        client.set_token('公网地址调用信息中获取的token')
        client.init()
        
        request = TFRequest('') 
        request.add_feed('input_ids', [1, seq_len], TFRequest.DT_INT32, input_data[0].flatten())
        request.add_feed('input_mask', [1, seq_len], TFRequest.DT_INT32, input_data[1].flatten())
        request.add_feed('segment_ids', [1, seq_len], TFRequest.DT_INT32, input_data[2].flatten())
        request.add_fetch('output')
        resp = client.predict(request)
        output = resp.get_values('output')
        # ------------------------------------------------------
        
        # 输出的output中的元素数量为num_labels,每个元素分别表示待分类本文属于每个类别的概率,取值越大,属于该类别的可能性越高。
        label = np.argmax(output)