热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CodeBERT理解

1.动机大型的预训练模型,比如ELMo、GPT、Bert等提高了NLP任务的最新技术。这些预训练模型在NLP的成功驱动了多模态预训练模型,比如ViBE




1.动机

大型的预训练模型,比如ELMo、GPT、Bert等提高了NLP任务的最新技术。这些预训练模型在NLP的成功驱动了多模态预训练模型,比如ViBERT、VideoBERT(他们从双模式数据,比如语言-图像对中进行自监督学习)

CodeBERT,是一种用于编程语言(PL)和自然语言(NL)的bimodal预训练模型。CodeBERT捕获自然语言和编程语言的语义连接,生成能广泛支持NL-PL理解任务(自然语言代码搜索)和生成任务(代码文档生成)的通用表示形式。

为了利用NL-PL pairs bimodal 实例和大量可用的uni-modal 代码,训练CodeBERT时用一个混合目标函数(包含标准掩码语言模型和 replaced token detection)


replaced token detection

在BERT中,句子内15%的token被选中,其中80%被[MASK]替换,10%被随机替换,10%保持不变,随后将替换后的句子输入到BERT中用于预测那些被替换的token。

论文作者认为BERT只学习这15%的token有点浪费算力,还存在[MASK]不会在实际任务中出现的问题。于是,文章提出了一个新的预训练任务:replaced token detection,即首先使用一个生成器预测句中被mask掉的token,接下来使用预测的token替代句中的[MASK]标记,然后使用一个判别器区分句中的每个token是原始的还是替换后的。
在这里插入图片描述
在预训练后,将判别器用于用于下游任务。作者认为replaced token detection任务让模型(判别器)可以在所有的token上学习,而不是那些仅仅被mask掉的token,这使得计算效率更高。


2.1模型架构

遵循 BERT 和 RoBERTa ,并使用了多层双向 Transformer 作为 CodeBERT 的模型架构。通过使用与Roberta-Base完全相同的模型架构来开发Codebert。模型参数的总数为125M。

RoBERTa:
与BERT相比主要有以下几点改进:


  • 更大的模型参数量(论文提供的训练时间来看,模型使用 1024 块 V100 GPU 训练了 1 天的时间)
  • 更大bacth size。RoBERTa 在训练过程中使用了更大的bacth size。尝试过从 256 到 8000 不等的bacth size。
  • 更多的训练数据(包括:CC-NEWS 等在内的 160GB 纯文本。而最初的BERT使用16GB
    BookCorpus数据集和英语维基百科进行训练)

另外,RoBERTa在训练方法上有以下改进:


  • 去掉下一句预测(NSP)任务
  • 动态掩码。BERT 依赖随机掩码和预测 token。原版的 BERT 实现在数据预处理期间执行一次掩码,得到一个静态掩码。 而 RoBERTa 使用了动态掩码:每次向模型输入一个序列时都会生成新的掩码模式。这样,在大量数据不断输入的过程中,模型会逐渐适应不同的掩码策略,学习不同的语言表征。
  • 文本编码。Byte-Pair Encoding(BPE)是字符级和词级别表征的混合,支持处理自然语言语料库中的众多常见词汇。原版的 BERT 实现使用字符级别的 BPE 词汇,大小为 30K,是在利用启发式分词规则对输入进行预处理之后学得的。Facebook 研究者没有采用这种方式,而是考虑用更大的 byte 级别 BPE 词汇表来训练 BERT,这一词汇表包含 50K 的 subword 单元,且没有对输入作任何额外的预处理或分词。

2.2输入/输出表示

在预训练阶段,将输入设置为两个序列与特殊token的串联




[


C


L


S


]


,



w


1



,



w


1



,



w


2



,


.


.


.


,



w


n



,


[


S


E


P


]


,



c


1



,



c


2



,


.


.


.


,



c


m



,


[


E


O


S


]



[CLS] ,w_{1},w_{1},w_{2},...,w_{n},[SEP],c_{1},c_{2},...,c_{m},[EOS]


[CLS],w1,w1,w2,...,wn,[SEP],c1,c2,...,cm,[EOS]
,其中一个序列是自然语言文本,另一个是编程语言。




[


C


L


S


]



[CLS]


[CLS]
是两个部分前面的特殊token,其最终隐藏代表被视为分类或排名的汇总序列表示形式。

按照transformers中处理文本的标准方式,将自然语言文本看作一系列单词,把它分为WordPiece。把一块代码视为一系列tokens。
输出包括:


  1. 对于自然语言和代码的每个token的上下文向量表示
  2. [CLS]的表示,该表示充当汇总序列表示

2.3训练数据

训练CodeBERT模型并行使用单峰数据和双峰数据,双峰数据就是NL-PL对,单峰数据就是单一的自然语言文本,或者是单一的代码。
数据来自公开可用的开源非fork github存储库,并用一组约束和规则过滤。


  1. 每个项目至少被另一个项目使用过
  2. 每个文档都被截断为第一段
  3. 少于三个token的文档被删除
  4. 少于三行的函数被删除
  5. 函数名带有test的函数被删除

2.4预训练CodeBERT

两个训练目标:


  • 掩码语言模型(MLM),应用于NL-PL pairs的双峰数据
  • 替换token检测(RTD),应用于单峰数据

MLM

给定NL-PL pair(




X


=



w


,


c




X = {w,c}


X=w,c
)的数据点作为输入,其中




w



w


w
是NL单​​词的序列,




c



c


c
是PL tokens的序列,我们首先选择NL和PL的随机位置集要掩盖(分别为





m


w




m^{w}


mw






m


c




m^{c}


mc
),然后用特殊的[MASK] token替换所选位置。其中x中15%的token被mask掉。然后预测被mask掉的原始token。


RTD

在我们的情况下对其进行调整,并在训练中同时使用双峰和单峰数据。具体而言,有两个数据生成器,一个NL,一个PL,均用于为一组随机掩盖的位置生成合理的替代方案。

判别器被训练检测一个单词是否是原始的单词,这是一个二分类问题。值得注意的是,RTD适用于输入的每个位置,如果生成器生成的单词恰好是原来真实的单词,则标签为 real 而不是 fake

在这里插入图片描述
NL和Code生成器都是语言模型,它们基于周围的上下文环境生成了被掩盖位置的合理的token,NL-Code Discriminator是目标的预训练模型,该模型通过检测从NL和PL生成器采样的合理的可替代方案来训练。NL-Code 判别器用于在微调阶段产生通用的表示。NL和Code生成器在微调阶段被抛出。


2.5微调CodeBERT

有不同的设置可以在下游NL-PL任务中使用Codebert。例如,在自然语言代码搜索中,我们将输入与预训练阶段相同,并使用[CLS]的表示来测量代码和自然语言查询之间的语义相关性,而在代码到文本中生成,我们使用编码 - 解码器框架,并使用Codebert初始化生成模型的编码器。


3源码分析

从头开始预训练RoBERTa模型的步骤:


  1. 利用Tokenizer对语料分词
  2. 配置RoBERTa模型
  3. 训练任务的代码
  4. 数据输入模型进行训练

3.1对语料进行分词——RobertaTokenizer

核心代码在\transformers\models\roberta\tokenization_roberta.py


3.2配置RoBERTa模型

核心代码在\transformers\models\roberta\modeling_roberta.py


3.3训练任务的代码

MLM任务:

class RobertaLMHead(nn.Module):
"""Roberta Head for masked language modeling."""
def __init__(self, config):
super().__init__()
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
self.layer_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
self.decoder = nn.Linear(config.hidden_size, config.vocab_size)
self.bias = nn.Parameter(torch.zeros(config.vocab_size))
self.decoder.bias = self.bias
def forward(self, features, **kwargs):
x = self.dense(features)
x = gelu(x)
x = self.layer_norm(x)
# project back to size of vocabulary with bias
x = self.decoder(x)
return x

  • 对输入的embedding进行线性变换、激活和层归一化
  • 输出形状为[batch_size, seq_length, vocab_size],即预测每个句子每个词是什么类别的概率值

3.4数据输入模型进行训练

class RobertaForMaskedLM(RobertaPreTrainedModel):
_keys_to_ignore_on_save = [r"lm_head.decoder.weight", r"lm_head.decoder.bias"]
_keys_to_ignore_on_load_missing = [r"position_ids", r"lm_head.decoder.weight", r"lm_head.decoder.bias"]
_keys_to_ignore_on_load_unexpected = [r"pooler"]
def __init__(self, config):
super().__init__(config)
if config.is_decoder:
logger.warning(
"If you want to use `RobertaForMaskedLM` make sure `config.is_decoder=False` for "
"bi-directional self-attention."
)
self.roberta = RobertaModel(config, add_pooling_layer=False)
self.lm_head = RobertaLMHead(config)
# The LM head weights require special treatment only when they are tied with the word embeddings
self.update_keys_to_ignore(config, ["lm_head.decoder.weight"])
# Initialize weights and apply final processing
self.post_init()
def get_output_embeddings(self):
return self.lm_head.decoder
def set_output_embeddings(self, new_embeddings):
self.lm_head.decoder = new_embeddings
@add_start_docstrings_to_model_forward(ROBERTA_INPUTS_DOCSTRING.format("batch_size, sequence_length"))
@add_code_sample_docstrings(
processor_class=_TOKENIZER_FOR_DOC,
checkpoint=_CHECKPOINT_FOR_DOC,
output_type=MaskedLMOutput,
config_class=_CONFIG_FOR_DOC,
mask="",
expected_output="' Paris'",
expected_loss=0.1,
)
def forward(
self,
input_ids: Optional[torch.LongTensor] = None,
attention_mask: Optional[torch.FloatTensor] = None,
token_type_ids: Optional[torch.LongTensor] = None,
position_ids: Optional[torch.LongTensor] = None,
head_mask: Optional[torch.FloatTensor] = None,
inputs_embeds: Optional[torch.FloatTensor] = None,
encoder_hidden_states: Optional[torch.FloatTensor] = None,
encoder_attention_mask: Optional[torch.FloatTensor] = None,
labels: Optional[torch.LongTensor] = None,
output_attentions: Optional[bool] = None,
output_hidden_states: Optional[bool] = None,
return_dict: Optional[bool] = None,
) -> Union[Tuple[torch.Tensor], MaskedLMOutput]:
r"""
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
Labels for computing the masked language modeling loss. Indices should be in `[-100, 0, ...,
config.vocab_size]` (see `input_ids` docstring) Tokens with indices set to `-100` are ignored (masked), the
loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`
kwargs (`Dict[str, any]`, optional, defaults to *{}*):
Used to hide legacy arguments that have been deprecated.
"""

return_dict = return_dict if return_dict is not None else self.config.use_return_dict
outputs = self.roberta(
input_ids,
attention_mask=attention_mask,
token_type_ids=token_type_ids,
position_ids=position_ids,
head_mask=head_mask,
inputs_embeds=inputs_embeds,
encoder_hidden_states=encoder_hidden_states,
encoder_attention_mask=encoder_attention_mask,
output_attentions=output_attentions,
output_hidden_states=output_hidden_states,
return_dict=return_dict,
)
sequence_output = outputs[0]
prediction_scores = self.lm_head(sequence_output)
masked_lm_loss = None
if labels is not None:
loss_fct = CrossEntropyLoss()
masked_lm_loss = loss_fct(prediction_scores.view(-1, self.config.vocab_size), labels.view(-1))
if not return_dict:
output = (prediction_scores,) + outputs[2:]
return ((masked_lm_loss,) + output) if masked_lm_loss is not None else output
return MaskedLMOutput(
loss=masked_lm_loss,
logits=prediction_scores,
hidden_states=outputs.hidden_states,
attentions=outputs.attentions,
)






推荐阅读
  • Java中字符串截取方法详解
    本文详细介绍了Java中常用的字符串截取方法及其应用场景,帮助开发者更好地理解和使用这些方法。 ... [详细]
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • 本文详细介绍了如何在 Oracle 数据库中进行筛选备份和恢复操作,包括权限授予、目录管理、数据导出和导入等步骤。 ... [详细]
  • 七大策略降低云上MySQL成本
    在全球经济放缓和通胀压力下,降低云环境中MySQL数据库的运行成本成为企业关注的重点。本文提供了一系列实用技巧,旨在帮助企业有效控制成本,同时保持高效运作。 ... [详细]
  • 为何Compose与Swarm之后仍有Kubernetes的诞生?
    探讨在已有Compose和Swarm的情况下,Kubernetes是如何以其独特的设计理念和技术优势脱颖而出,成为容器编排领域的领航者。 ... [详细]
  • 2023年,Android开发前景如何?25岁还能转行吗?
    近期,关于Android开发行业的讨论在多个平台上热度不减,许多人担忧其未来发展。本文将探讨当前Android开发市场的现状、薪资水平及职业选择建议。 ... [详细]
  • 本文详细介绍了`android.os.Binder.getCallingPid()`方法的功能和应用场景,并提供了多个实际的代码示例。通过这些示例,开发者可以更好地理解如何在不同的开发场景中使用该方法。 ... [详细]
  • 编译原理中的语法分析方法探讨
    本文探讨了在编译原理课程中遇到的复杂文法问题,特别是当使用SLR(1)文法时遇到的多重规约与移进冲突。文章讨论了可能的解决策略,包括递归下降解析、运算符优先级解析等,并提供了相关示例。 ... [详细]
  • Python Requests模块中的身份验证机制
    随着Web服务的发展,身份验证成为了确保数据安全的重要环节。本文将详细介绍如何利用Python的Requests库实现不同类型的HTTP身份验证,包括基本身份验证、摘要式身份验证以及OAuth 1认证等。 ... [详细]
  • 如何处理PHP缺少扩展的问题
    本文将详细介绍如何解决PHP环境中缺少扩展的问题,包括检查当前环境、修改配置文件以及验证修改是否生效的具体步骤,帮助开发者更好地管理和使用PHP扩展。 ... [详细]
  • 在现代Web开发中,HTML5 Canvas常用于图像处理和绘图任务。本文将详细介绍如何将Canvas中的图像导出并上传至服务器,适用于拼图、图片编辑等场景。 ... [详细]
  • 本文详细介绍了 `org.apache.hadoop.hdfs.server.namenode.FSNamesystem.shouldUseDelegationTokens()` 方法的用途和实际应用场景,并提供了多个代码示例以帮助开发者更好地理解和使用该方法。 ... [详细]
  • web页面报表js下载,web报表软件 ... [详细]
  • java解析json转Map前段时间在做json报文处理的时候,写了一个针对不同格式json转map的处理工具方法,总结记录如下:1、单节点单层级、单节点多层级json转mapim ... [详细]
  • SvpplyTable: 实现可扩展和可折叠的菜单动画
    SvpplyTable 是一个示例项目,旨在实现类似 Svpply 应用程序中的可扩展和可折叠的菜单动画效果。该项目托管在 GitHub 上,地址为 https://github.com/liuminqian/SvpplyTable。 ... [详细]
author-avatar
mobiledu2502856013
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有