背景
ModelScope目前已集成数百个业内顶尖的模型,并且其中大部分模型都支持pipeline推理和finetune。
此文档以一个文本分类任务为例,记录了从数据集创建到最终完成模型训练的完整端到端流程,旨在帮助第一次使用ModelScope的用户减少开发周期。
流程
基于ModelScope从模型库中选择模型并在自己的数据上finetune的整体流程其实非常清晰。简单来说用户只需要3个步骤:环境安装、数据集上传和开始训练。下面依次介绍这三个步骤所需的操作,以及可能会遇到的问题。
环境安装
- 若用户在ModelScope提供的在线Notebook中开发可跳过该步骤。若在本地环境,用户需要运行以下3行代码即可完成环境安装(此处只安装了ModelScope中NLP相关的功能,更多的选择参考相关文档):
# 安装pytorch pip3 install torch torchvision torchaudio # 安装Tensorflow pip install --upgrade tensorflow # 安装ModelScope library pip install "modelscope[nlp]" -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html
- 安装完成后运行这行代码,若成功分词则说明完成环境安装。
python -c "from modelscope.pipelines import pipeline;print(pipeline('word-segmentation')('今天天气不错,适合 出去游玩'))"
数据集上传
用户可以通过SDK或者WEB端的方式上传数据集,通过ModelScope或者公开Host托管。这里介绍基于WEB端可视化界面,将数据集托管到ModelScope的方式,这种方法对用户而言操作更友好。具体流程如下:
- 用户在ModelScope平台注册后,依次点击右上角头像图标中的个人中心 -我的数据集-创建数据集-填写基本信息。会进入这样一个页面:
- 如上图所示得到一个空的数据仓库test。可以看到左侧有元数据和数据文件两个选择:
- 元数据对应的文件格式是CSV,用于描述数据结构或直接存储数据。如涉及音频/视频/图片等形态文件,CSV文件存储数据相对路径;如是文本,那么CSV文件可以直接存文本信息。
- 数据文件对应的文件格式是ZIP(使用SDK的话也可以上传文件夹),用于存放视觉、语音任务中的一些具体数据。
- 由于我们是文本分类任务,所以可以直接将数据按照下面的方式组织。点击右侧添加元数据文件上传组织好的训练集、测试集和验证集即可。
# text为文本,label为标签(可以是中文或者数字,若是中文后面还需要mapping) text,label xxxxx,1 xxxxx,0 ...
- 上传完成后,我们还未指定整个库里有几个子数据集,并且哪个csv文件是训练集,哪个是验证集。这个操作我们通过编辑上图中的JSON文件完成。这个文件说明了整个数据仓库中共有几个子数据集,每个子数据集的各split对应哪个CSV文件,且可以随时修改。默认初始化了一个default子数据集,我们只需要为其中的train、test、validation指定对应的CSV文件(不可重复,可为空),再点击保存即可。
- 使用MsDataset验证数据集是否可加载,能正常返回样本即可:
from modelscope.msdatasets import MsDataset # dataset_id为数据集名,这里是test;namesapce为个人账号名;subset_name为指定的子数据集名;split指定加载的是训练or测试or验证集 train_dataset = MsDataset.load(dataset_id, namespace='xxx',subset_name='default', split='train') print(next(iter(train_dataset)))
注意若设置了数据集为非公开模式,还需要额外登陆。或者在设置中点击“设为公开数据集”即可无需登陆加载。登陆代码如下:
from modelscope.hub.api import HubApi api = HubApi() api.login(YOUR_ACCESS_TOKEN) # 备注:YOUR_ACCESS_TOKEN需要登录modelscope.cn,进入 个人中心->访问令牌->新建SDK令牌,登录状态默认保持30天
开始训练
完成数据集部分后,我们就可以通过MsDataset类去加载我们上传的数据集了。接下来就是训练部分:
- 首先从模型库选择一个backbone模型,我们这里由于是在自己的数据集上finetune文本分类任务,那么我建议是从ModelScope的模型库上下载StructBert预训练模型-中文-base。直接本地运行下面的代码即可完成下载:
git clone http://www.modelscope.cn/damo/nlp_structbert_backbone_base_std.git
- 下载完成后进入文件夹,其中注config.json参数是底层模型相关参数,configuration.json是配置文件相关参数。由于ModelScope已经帮开发者封装了完善的API接口,因此我们主要需要做的就是通过修改配置参数去实现不同的训练需求。这里着重说明几个比较重要的参数,其他的参数在代码里进行注释(可以参考configuration.json进行修改):
- WORK_DIR :训练log、模型保存的工作目录
- cfg.task:指定任务,文本分类目前指定Tasks.sentiment_classification(也可以直接传字符串'sentiment-classification')
- cfg.preprocessor.type:指定预处理方式,文本分类目前指定sen-cls-tokenizer
- cfg.train.lr_scheduler.type:指定学习率策略。注意若为LinearLR,torch版本需>1.12
- cfg.evaluation.metrics:指定评估指标,文本分类目前指定Metrics.seq_cls_metric,最终默认返回acc准确率指标。若想修改为f1,可在modelscope/metrics/sequence_classification_metric.py中把SequenceClassificationMetric这个类的evaluate修改为:
... from sklearn import metrics ... def evaluate(self): preds = np.concatenate(self.preds, axis=0) labels = np.concatenate(self.labels, axis=0) preds = np.argmax(preds, axis=1) macro_f1 = metrics.f1_score(labels, preds,average='macro') _,_,f_classes,_ = metrics.precision_recall_fscore_support(labels, preds, labels=[0, 1, 2, 3], average=None) return { MetricKeys.F1: [macro_f1,f_classes] } ...
完整代码
import os.path as osp from modelscope.trainers import build_trainer from modelscope.msdatasets import MsDataset from modelscope.utils.hub import read_config from modelscope.metainfo import Metrics from modelscope.utils.constant import Tasks from modelscope.metainfo import Trainers # 登陆 from modelscope.hub.api import HubApi api = HubApi() api.login(YOUR_KEY) # 加载数据集 model_id = 'damo/nlp_structbert_backbone_base_std' dataset_id = YOUR_DATASET_NAME train_dataset = MsDataset.load(dataset_id, namespace=YOUR_NAMESPACE, subset_name='default', split='train').to_hf_dataset() eval_dataset = MsDataset.load(dataset_id, namespace=YOUR_NAMESPACE, subset_name='default', split='validation').to_hf_dataset() # 过滤训练文本或标签为空的样本 train_dataset = train_dataset.filter(lambda x: x["label"] != None and x["order"] != None) eval_dataset = eval_dataset.filter(lambda x: x["label"] != None and x["order"] != None) # 训练log、模型保存的工作目录 WORK_DIR = 'workspace' #修改配置文件 def cfg_modify_fn(cfg): cfg.task = Tasks.sentiment_classification cfg['preprocessor'] = {'type': 'sen-cls-tokenizer'} cfg['dataset'] = { 'train': { # 数据集中labels的值 'labels': ['0', '1', '2','3'], # csv文件中,训练文本的列名为'order' 'first_sequence': 'order', # csv文件中,标签列名为'label' 'label': 'label', } } # batch_size cfg.train.dataloader.batch_size_per_gpu =32 cfg.evaluation.dataloader.batch_size_per_gpu =32 # epoch cfg.train.max_epochs = 5 # 学习率相关配置,可参考torch自带的学习率及对应的参数字段 cfg.train.lr_scheduler={'type':'StepLR', 'step_size':2, 'options':{'warmup':{'type':'LinearWarmup','warmup_iters':2}}} # hook cfg.train.hooks = cfg.train.hooks = [ # 多少轮打一次log { 'type': 'TextLoggerHook', 'interval': 100 }, # 多少轮跑一次验证集,'by_epoch': True表示每一个epoch跑一次 { 'type': 'EvaluationHook', 'by_epoch': True }, # 多少轮保存一次checkpoint { 'type':'CheckpointHook', 'by_epoch': True }] # 初始学习率 cfg.train.optimizer.lr = 2e-6 # 指定评测方法,Metrics.seq_cls_metric为文本分类的acc cfg.evaluation.metrics = [Metrics.seq_cls_metric] cfg.evaluation.dataloader.shuffle = True return cfg # 构建trainer参数 kwargs = dict( model=model_id, train_dataset=train_dataset, eval_dataset=eval_dataset, work_dir=WORK_DIR, cfg_modify_fn=cfg_modify_fn, ) # build_trainer trainer = build_trainer(name='nlp-base-trainer', default_args=kwargs) # 开始训练 print('===============================================================') print('pre-trained model loaded, training started:') print('===============================================================') trainer.train() print('===============================================================') print('train success.') print('===============================================================') for i in range(max_epochs): eval_results = trainer.evaluate(f'{WORK_DIR}/epoch_{i+1}.pth') print(f'epoch {i} evaluation result:') print(eval_results) print('===============================================================') print('evaluate success') print('===============================================================')
使用感想
作为一名首次接触ModelScope的用户,可以感受到ModelScope的功能架构比较完整,能较好地支持在自己的数据集上finetune模型的流程。同时模型库拥有大量基于中文数据集训练的预训练模型,方便用户进行中文下游任务的处理。在首次跑通流程后,后续的开发比较顺畅,基本无感额外的操作开销。
期待ModelScope在文档建设上更加完善,进一步补充各任务全流程、各模型参数配置的文档描述,甚至可以直接基于模型能一键发布服务,降低用户的使用门槛,非常期待ModelScope在后续的更新!