您当前的位置:首页 > 生活 > 内容

哪里可以学一些ml技巧(如何进行MLM训练)

哪里可以学一些ml技巧(如何进行MLM训练)

1.作为伯特的两大任务之一的前期培训,MLM和NSP应该是大家熟悉的。其中,NSP任务在随后的一些预训练任务中经常被拒绝,比如罗伯塔直接放弃NSP任务,艾伯特用句序预测代替NSP。

这主要是因为NSP作为分类任务过于简单,对模型学习没有帮助,而MLM则被大部分预训练模型所保留。罗伯塔实验结果也可以证明伯特的主要能力应该来自MLM任务的训练。

以Bert为代表的训练前语言模型,是在大规模语料库的基础上,通过训练获得的基础学习能力。但是,在实际应用中,我们面对的语料可能具有一定的特殊性,这就需要对MLM进行重新训练。

1.2如何训练MLM 1.2.1什么是MLMMLM训练?在不同的前期培养模式中其实是不一样的。今天的介绍以最基础的Bert为例。

伯特 MLM是静态掩码,但在随后的其他预训练模型中,这种策略通常被动态掩码所取代。另外还有全字掩码的模型,不在今天的讨论范围之内的讨论。

所谓屏蔽语言模型的任务,一般来说就是替换一个句子中的部分标记,然后根据句子的其余部分,尝试还原这部分被屏蔽的标记。

1.2.2如何蒙版蒙版比例一般为15%,这也是大部分后续机型所继承的。然而,在最初的伯特的论文中,没有对这个比率的定义进行具体的解释。印象中好像知道T5型号也是Google在论文中提出来的,解释了一下这个,实验了一下mask的比例,最后得出15%的比例最合理(如果我说错了请指正)。

在选择了15%的标记之后,并不是所有的标记都被替换为[mask]标记。实际操作是:

从15%中选择80%的部分替换为[mask];10%换成随机代币;剩下的10%保留原代币。这可以提高模型的稳健性。这个比例也可以自己控制。

讲到这里,有些同学可能要问了。既然其中的10%不变,为什么不干脆选择15%*90%=13.5%的token呢?如果你看了下面的代码,你会清楚地理解这个问题。

让先说结论:因为MLM的任务是预测所有被选中的15%令牌,不管这个令牌是否被替换为[mask],也就是说,即使保持原样,它仍然需要被预测。

2.Code Part 2.1在介绍完基本内容之后,我将介绍如何基于transformers模块训练mask语言模型。

其实变形金刚模块本身就提供了MLM训练任务,模型都是写好的,你只需要调用它内置的trainer和datasets模块。感兴趣的同学可以去huggingface s官网搜索相关教程。

不过我觉得datasets每次调用都要写dataset的py文件。如果不熟悉arrow的数据格式,很容易出错。况且trainer也不是很好用,任何小的修改都是相当费力的(就是它自以为写的很好,考虑到了用户的所有需求,其实还有一些多余的部分)。

所以我参考它的实现,反汇编它的代码,用自己的方式重新组织。

2.2准备首先,做好写核心代码前的准备工作。导入所有必需的模块:

import OS import JSON import copy from tqdm . notebook import tqdm import torch from torch . optim import Adam from torch . utils . data import data loader,Dataset from transformers import bertformaskedlm,berttokenizerfast然后编写一个config类来收集所有参数:

class Config:def _ _ init _ _(self):pass def MLM _ Config(self,mlm_probability=0.15,special_tokens_mask=None,prob_replace_mask=0.8,prob_replace_rand=0.1,prob_keep_ori=0.1),''参数mlm_probability:被面具的代币总数参数特殊令牌掩码:特殊token :param prob_replace_mask:被替换成[面具]的代币比率:param prob_replace_rand:被随机替换成其他代币比率:参数prob_keep_ori:保留原代币的比率'''assert sum([prob_replace_mask,prob_replace_rand,prob_keep_ori])==1,值错误(问题的总和必须等于1。')自我。MLM概率=MLM概率。特殊令牌掩码=特殊令牌掩码自身。prob _ replace _ mask=prob _ replace _ rand self。prob _ keep _ ori=prob _ keep _ ori def training _ config(self,batch_size,epochs,learning_rate,weight_decay,device,):self。batch _ size=batch _ size自身。纪元=学习_速率自我。重量接着就是设置各种配置:

Config=Config()配置。MLM配置()配置。training _ Config(batch _ size=4,epochs=10,learning_rate=1e-5,weight_decay=0,device=cuda:0 )配置。io _ Config(from _ path=/data/Bert模特/抱脸/中文_ wwm/保存路径=/fine tune _ embedding _ model/MLM/)最后创建伯特模型。注意,这里的标记器就是一个普通的记号赋予器,而伯特模型则是带了下游任务的BertForMaskedLM,它是变形金刚中写好的一个类,

Bert _ token izer=bertokenizerfast。from _预训练(配置。from _ path)Bert _ MLM _ model=bertformaskedlm。from _预训练(配置。从_路径)2.3数据集因为舍弃了数据集这个包,所以我们现在需要自己实现数据的输入了。方案就是使用火炬的资料组类。这个类一般在构建数据加载器的时候,会与一个聚合函数一起使用,以实现对一批的组织。而我这里偷个懒,就没有写聚合函数,批次的组织方法放在资料组中进行。

在这个类中,有一个屏蔽令牌的方法,作用是从数据中选择出所有需要面具的令牌,并且采用三种面具方式中的一个。这个方法是从变形金刚中拿出来的,将其从类方法转为静态方法测试之后,再将其放在自己的这个类中为我们所用。仔细阅读这一段代码,也就可以回答1.2.2 中提出的那个问题了。

取一批的原理很简单,一开始我们将原始数据深层拷贝备份一下,然后每次从中截取一个一批的大小,这个时候的当前数据就少了一个批次,我们定义这个类的长度为当前长度除以批量向下取整,所以当类的长度变为0的时候,就说明这一个世的所有步骤都已经执行结束,要进行下一个世的训练,此时,再将当前数据变为原始数据,就可以实现对世的循环了。

类训练数据集(数据集):""注意:由于没有使用数据_排序器,批处理放在资料组里边做,因而在数据加载器出来的结果会多套一层一批维度,传入模型时注意挤压掉'''def __init__(self,input_texts,tokenizer,config):self。输入文本=输入文本本身。tokenizer=tokenizer self。ori _ inputs=复制。深度复制(input _ texts)def _ _ len _ _(self):return len(self。input _ texts)//self。配置。batch _ size def _ _ getitem _ _(self,idx):batch _ text=self。input _ texts[:self。配置。batch _ size]特征=自身。tokenizer(batch _ text 标签=inputs.clone() #我们对每个序列中的一些令牌进行采样以进行MLM训练(概率为“自我。MLM概率`)概率矩阵=火炬。完整(标签。形状,self.config.mlm_probability)如果自我。配置。特殊_令牌_掩码为None:special _ tokens _ mask=[self。记号赋予器。标签中val的get _ special _ tokens _ mask(val,has _ special _ tokens=True)。to list()]special _ tokens _ mask=torch。张量(special _ tobool()标签[~ masked _ indexes]=-100 #我们只计算屏蔽令牌的损失# 80%的情况下,我们用记号赋予器。MASK _ token([MASK])indexes _ replaced=torch。伯努利(火炬。完整(标签。shape,self.config.prob_replace_mask))替换屏蔽的输入令牌bool()masked _ indexes inputs[indexes _ replaced]=self。记号赋予器。convert _ tokens _ to _ ids(self。记号赋予器。掩码_令牌)# 10%的时候,我们用随机字current_prob=self。配置。prob _ replace _ rand/(1-self。配置。prob _ replace _ mask)indexes _ random=torch。伯努利(火炬。完整(标签。shape,current _ prob).bool()masked _ indexes ~ indexes _ replaced random _ words=torch。randint(len(self。tokenizer),labels.shape,dtype=torch。long)输入[indexes _ random]=random _ words[indexes _ random]#其余时间(10%的时间)我们保持屏蔽的输入令牌不变返回输入、标签然后取一些用于训练的语料,格式很简单,就是把所有文本放在一个目录里边,注意长度不要超过512个令牌,不然多出来的部分就浪费掉了。可以做适当的预处理。

['这是一条文本''这是另一条文本,]然后构建数据加载器:

train _ dataset=train dataset(training _ texts,bert_tokenizer,config)train _ data loader=data loader(train _ dataset)2.4训练构建一个训练方法,输入参数分别是我们实例化好的待训练模型,数据集,还有配置:

定义训练(模型,训练_数据加载器,配置): '''训练:参数型号:nn .模块:param train _ data loader:data loader:param Config:Config-ver:2021-11-08 by:常宏宇'''断言配置。设备。以(cuda )或config.device==cpu ,值错误(无效设备。')设备=火炬。设备(配置设备)型号。to(device)如果不是len(train _ data loader):raise EOFError(空载列车_数据加载器.')param _ optimizer=list(模型。named _ parameters())no _ decay=[偏见'LayerNorm.bias ,'层规范。重量]optimizer _ grouped _ parameters=[{ params :[p for n,p in param _ optimizer if not any(nd in n for nd in no _ decay)],权重_衰减[p for n,p in param _ optimizer if any(nd in n for nd in no _ decay)),权重_衰减0.0 }]optimizer=adaa format(cur _ EPC 1))模型。train()for Step,batch in enumerate(tqdm(train _ data loader,desc=步骤):input _ ids=batch[输入]。挤压(0)。至(设备)标签=批次['标签']。挤压(0)。至(设备)损耗=型号(输入标识=输入标识,标签=标签)。损失优化器。zero _ grad()损失。backward()优化器。step()模型。zero _ grad()Training _ loss=损失。item()打印(培训损失: '培训损失)调用它训练几轮:

训练(模型=bert _ mlm _模型,训练_数据加载器=训练_数据加载器,配置=配置)2.5保存和加载使用过预训练模型的同学应该都了解,普通的伯特有两项输出,分别是:

每一个代币对应的768维编码结果;以及用于表征整个句子的句子特征。其中,这个句子特征是由模型中的一个普尔勒模块对原句池化得来的。可是这个普尔勒的训练,并不是由MLM任务来的,而是由网络服务协议(网络服务协议)任务中来的。

由于没有网络服务协议(网络服务协议)任务,所以无法对普尔勒进行训练,故而没有必要在模型中加入普尔勒。所以在保存的时候需要分别保存把.嵌入和编码器,加载的时候也需要分别读取把.嵌入和编码器,这样训练出来的模型拿不到CLS层的句子表征。如果需要的话,可以手动合用。

火炬。保存(伯特_ MLM _模型。伯特。嵌入。state _ dict(),os.path.join(config.save_path,bert _ mlm _ ep _ { } _ eb.bin 。格式(配置。划时代))火炬。保存(伯特_ MLM _模型。伯特。编码器。state _ dict(),os.path.join(config.save_path,bert _ mlm _ ep _ { } _ ec.bin 。格式(配置时代)))加载的话,也是实例化完伯特模型之后,用伯特的把.嵌入组件和编码器组件分别读取这两个权重文件即可。

到这里,本期内容就全部结束了,希望看完这篇博客的同学,能够对伯特(男子名等于伯特)的基础原理有更深入的了解。

审核编辑:李倩

标签:模型训练数据


声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,谢谢。

上一篇: 机箱电源功率计算器(怎么查看电脑电源输出功率有几W)

下一篇: g210显卡驱动(我是英伟达G210的显卡能下最新显卡驱动301.42版吗)



推荐阅读

网站内容来自网络,如有侵权请联系我们,立即删除! | 软文发布 | 粤ICP备2021106084号