Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >广告行业中那些趣事系列57:从理论到实战一网打尽Transformer中的位置编码

广告行业中那些趣事系列57:从理论到实战一网打尽Transformer中的位置编码

作者头像
数据拾光者
发布于 2022-12-20 08:08:13
发布于 2022-12-20 08:08:13
3K00
代码可运行
举报
文章被收录于专栏:数据拾光者数据拾光者
运行总次数:0
代码可运行

导读:本文是“数据拾光者”专栏的第五十七篇文章,这个系列将介绍在广告行业中自然语言处理推荐系统实践。本篇从理论到实践介绍了Transformer中的位置编码,包括训练式位置编码、三角函数式位置编码和相对位置编码,同时基于开源项目bert4keras源码实践了各种位置编码。 欢迎转载,转载请注明出处以及链接,更多关于自然语言处理、推荐系统优质内容请关注如下频道。 知乎专栏:数据拾光者 公众号:数据拾光者

摘要:本篇从理论到实践介绍了Transformer中的位置编码。首先介绍了位置编码的作用以及主要实现方式;然后重点介绍了主流的位置编码方式,包括训练式位置编码、三角函数式位置编码和相对位置编码,同时基于开源项目bert4keras源码实践了各种位置编码。对Transformer中位置编码的知识和源码实践感兴趣的小伙伴可以多交流。

下面主要按照如下思维导图进行学习分享:

01

位置编码背景介绍

1.1 为什么需要位置编码

BERT作为NLP领域中里程碑式的模型,不仅效果好而且应用范围广,最重要的原因是使用Transformer作为特征抽取器。Transformer相比于传统的CNN和RNN来说,整个网络主要由Attention机制组成,同时具有可并行化计算和捕捉长距离特征的优点,是目前公认效果最好的特征抽取器之一。对于Transformer来说位置编码是非常重要的,主要原因有以下两个:

  • 词在语句中的位置非常重要。使用同样的词语,排列位置不同,语义可能不同,比如:“我喜欢刘亦菲”和“刘亦菲喜欢我”表达的语义差别很大;
  • Transformer主要核心是attention注意力机制,attention机制可以计算当前词对其他词的注意力得分,但无法捕捉词顺序,类似一个升级版的“词袋”模型。

1.2 更通俗的理解位置编码

因为Transformer模型不具备RNN学习词序的能力,所以需要将词序信息提供给模型。原来输入到模型中的是词信息,现在需要将词信息和位置信息融合之后输入到模型中,所以位置编码可以看成是利用词的位置信息对语句中的词进行二次表示的方法,通过位置编码使得Transformer模型具备了学习词序的能力

1.3 实现位置编码的主要方式

想让Transformer具备学习词序信息的能力,一般有两种做法:第一种是将位置信息融合到模型输入,这种主要是绝对位置编码,主要代表是BERT和GPT等模型;第二种是微调Attention结构使其获得识别词序信息的能力,这种主要是相对位置编码。

02

训练式位置编码

训练式位置编码的典型代表就是BERT、GPT等模型,将位置编码添加到输入中,比如下面的BERT模型输入,会将文本序列转化成三层embedding作为Transformer模型的输入,第一层embedding是词信息token embedding,第二层是segment embedding,第三层则是位置编码信息position embedding。下面是将文本转化成三层embedding作为BERT模型输入介绍图:

图1 文本转化成三层embedding作为BERT模型输入

将位置编码和词token一样作为可以训练的参数,比如最大长度设置为512,向量维度设置为768,那么一条语句就会得到512X768的矩阵作为初始向量,并随着训练进行更新。训练式位置编码的优点是简单容易实现,缺点则是没有外推性。比如原生BERT最长只能处理512长度的语句,如果任务中文本大于512则会进行截断操作。最近调研到苏神通过层次分解可以让BERT处理足够长的文本,并且效果还不错,感兴趣的小伙伴可以查看参考资料1。

下面是开源工程bert4keras训练式位置编码的源码实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class PositionEmbedding(Layer):
    """定义可训练的位置Embedding
    """
    def __init__(
        self,
        input_dim,
        output_dim,
        merge_mode='add',
        hierarchical=None,
        embeddings_initializer='zeros',
        custom_position_ids=False,
        **kwargs
    ):
        super(PositionEmbedding, self).__init__(**kwargs)
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.merge_mode = merge_mode
        self.hierarchical = hierarchical
        self.embeddings_initializer = initializers.get(embeddings_initializer)
        self.custom_position_ids = custom_position_ids

    def build(self, input_shape):
        super(PositionEmbedding, self).build(input_shape)
        self.embeddings = self.add_weight(
            name='embeddings',
            shape=(self.input_dim, self.output_dim),
            initializer=self.embeddings_initializer
        )

    def call(self, inputs):
        """如果custom_position_ids,那么第二个输入为自定义的位置id
        """
        if self.custom_position_ids:
            inputs, position_ids = inputs
            if 'int' not in K.dtype(position_ids):
                position_ids = K.cast(position_ids, 'int32')
        else:
            input_shape = K.shape(inputs)
            batch_size, seq_len = input_shape[0], input_shape[1]
            position_ids = K.arange(0, seq_len, dtype='int32')[None]

        if self.hierarchical:
            alpha = 0.4 if self.hierarchical is True else self.hierarchical
            embeddings = self.embeddings - alpha * self.embeddings[:1]
            embeddings = embeddings / (1 - alpha)
            embeddings_x = K.gather(embeddings, position_ids // self.input_dim)
            embeddings_y = K.gather(embeddings, position_ids % self.input_dim)
            embeddings = alpha * embeddings_x + (1 - alpha) * embeddings_y
        else:
            if self.custom_position_ids:
                embeddings = K.gather(self.embeddings, position_ids)
            else:
                embeddings = self.embeddings[None, :seq_len]

        if self.merge_mode == 'add':
            return inputs + embeddings
        elif self.merge_mode == 'mul':
            return inputs * (embeddings + 1.0)
        elif self.merge_mode == 'zero':
            return embeddings
        else:
            if not self.custom_position_ids:
                embeddings = K.tile(embeddings, [batch_size, 1, 1])
            return K.concatenate([inputs, embeddings])

    def compute_output_shape(self, input_shape):
        if self.custom_position_ids:
            input_shape = input_shape[0]

        if self.merge_mode in ['add', 'mul', 'zero']:
            return input_shape[:2] + (self.output_dim,)
        else:
            return input_shape[:2] + (input_shape[2] + self.output_dim,)

    def get_config(self):
        config = {
            'input_dim': self.input_dim,
            'output_dim': self.output_dim,
            'merge_mode': self.merge_mode,
            'hierarchical': self.hierarchical,
            'embeddings_initializer':
                initializers.serialize(self.embeddings_initializer),
            'custom_position_ids': self.custom_position_ids,
        }
        base_config = super(PositionEmbedding, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

03

三角函数式位置编码

三角函数式位置编码是谷歌在论文《Attention is All You Need》所提出来的一个显式解。训练式位置编码的做法是线性分配一个数值给每个时间步,比如语句中第一个词分配的初始位置编码为1,第二个词分配为2,以此类推,直到最后一个词分配为语句长度N。这种位置编码会存在一定的问题,一方面当序列很长时会使分配的数值非常大;另一方面模型可能会遇到和训练中长度不同的语句,这里可能是更长或者更短的样本,会严重影响模型的泛化能力。

为了解决训练式位置编码存在的问题,Transformer的作者提出了一种简单但是创新的位置编码-三角函数式位置编码。三角函数式位置编码满足以下四个特点:

  • 语句中每个词的位置编码是唯一的;
  • 不同长度的句子中任意相邻两个词的距离是一致的;
  • 模型可以很容易处理更长的语句,并且值有界;
  • 位置编码是确定性的。

三角函数式位置编码不是一个单一的数值,而是一个类似词向量的d维向量,通过注入词的顺序信息来增强模型输入。下面通过公式理解三角函数式位置编码,给定一个长度n的语句,t表示词在语句中的位置,Pt则表示位置t对应的位置向量,d代表向量的维度。Pt公式定义如下:

图2 三角函数式位置编码公式

其中频率Wk定义如下:

从公式中可以看出位置编码Pt是一个包含各频率的正弦和余弦对,展开表示如下:

图3 位置编码Pt展开表示

位置t对应的三角函数位置编码是d维向量,其中d是双数。这里有个问题,为什么要通过sin和cos函数来表示位置编码?如果通过one-hot编码来表示位置,则如下图所示:

图4 one-hot表示位置编码

One-hot编码存在高维稀疏问题,为了节约空间使用sin-cos函数。假如有50个词,每个词的位置编码有128维,三角函数的值域空间是【-1,1】,值从小到大颜色从红色到蓝色,下面是每行代表每个词的位置编码cos/sin函数图:

图5 每个词的位置编码cos/sin函数图

下面是开源工程bert4keras三角函数式位置编码的源码实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class SinusoidalPositionEmbedding(Layer):
    """定义Sin-Cos位置Embedding
    """
    def __init__(
        self,
        output_dim,
        merge_mode='add',
        custom_position_ids=False,
        **kwargs
    ):
        super(SinusoidalPositionEmbedding, self).__init__(**kwargs)
        self.output_dim = output_dim
        self.merge_mode = merge_mode
        self.custom_position_ids = custom_position_ids

    def call(self, inputs):
        """如果custom_position_ids,那么第二个输入为自定义的位置id
        """
        if self.custom_position_ids:
            seq_len = K.shape(inputs)[1]
            inputs, position_ids = inputs
            if 'float' not in K.dtype(position_ids):
                position_ids = K.cast(position_ids, K.floatx())
        else:
            input_shape = K.shape(inputs)
            batch_size, seq_len = input_shape[0], input_shape[1]
            position_ids = K.arange(0, seq_len, dtype=K.floatx())[None]

        indices = K.arange(0, self.output_dim // 2, dtype=K.floatx())
        indices = K.pow(10000.0, -2 * indices / self.output_dim)
        embeddings = tf.einsum('bn,d->bnd', position_ids, indices)
        embeddings = K.stack([K.sin(embeddings), K.cos(embeddings)], axis=-1)
        embeddings = K.reshape(embeddings, (-1, seq_len, self.output_dim))

        if self.merge_mode == 'add':
            return inputs + embeddings
        elif self.merge_mode == 'mul':
            return inputs * (embeddings + 1.0)
        elif self.merge_mode == 'zero':
            return embeddings
        else:
            if not self.custom_position_ids:
                embeddings = K.tile(embeddings, [batch_size, 1, 1])
            return K.concatenate([inputs, embeddings])

    def compute_output_shape(self, input_shape):
        if self.custom_position_ids:
            input_shape = input_shape[0]

        if self.merge_mode in ['add', 'mul', 'zero']:
            return input_shape[:2] + (self.output_dim,)
        else:
            return input_shape[:2] + (input_shape[2] + self.output_dim,)

    def get_config(self):
        config = {
            'output_dim': self.output_dim,
            'merge_mode': self.merge_mode,
            'custom_position_ids': self.custom_position_ids,
        }
        base_config = super(SinusoidalPositionEmbedding, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

04

相对位置编码

相对位置编码是谷歌的论文《Self-Attention with Relative Position Representations》中提出来的,典型代表是华为开源的NEZHA模型。因为语句中词与词之间相对位置非常重要,所以相对位置编码在自然语言处理任务中也有不错的表现。

相对位置编码由绝对位置编码启发得到,下面是相对位置编码的推导公式:

图6 相对位置编码推导公式

上图中左上角是self-attention的计算公式,将qikjT展开,为了引入相对位置,把piWQ去掉,把pjWk转换为二元位置向量RijK,同时将pjWv替换成二元位置向量RijV。通过这种转换,将原来依赖二元坐标(i,j)的向量RijK和RijV改成只依赖于相对位置i-j。同时为了适应任意不同的距离,会进行截断操作,也就是如下公式:

因为进行了截断操作,只需要有限个位置编码,就可以表达出任意长度的相对位置,所以可以处理任意长度的文本数据。

下面是开源工程bert4keras相对位置编码的源码实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class RelativePositionEmbedding(Layer):
    """相对位置编码
    来自论文:https://arxiv.org/abs/1803.02155
    """
    def __init__(
        self, input_dim, output_dim, embeddings_initializer='zeros', **kwargs
    ):
        super(RelativePositionEmbedding, self).__init__(**kwargs)
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.embeddings_initializer = initializers.get(embeddings_initializer)

    def build(self, input_shape):
        super(RelativePositionEmbedding, self).build(input_shape)
        self.embeddings = self.add_weight(
            name='embeddings',
            shape=(self.input_dim, self.output_dim),
            initializer=self.embeddings_initializer,
        )

    def call(self, inputs):
        pos_ids = self.compute_position_ids(inputs)
        return K.gather(self.embeddings, pos_ids)

    def compute_position_ids(self, inputs):
        q, v = inputs
        # 计算位置差
        q_idxs = K.arange(0, K.shape(q)[1], dtype='int32')
        q_idxs = K.expand_dims(q_idxs, 1)
        v_idxs = K.arange(0, K.shape(v)[1], dtype='int32')
        v_idxs = K.expand_dims(v_idxs, 0)
        pos_ids = v_idxs - q_idxs
        # 后处理操作
        max_position = (self.input_dim - 1) // 2
        pos_ids = K.clip(pos_ids, -max_position, max_position)
        pos_ids = pos_ids + max_position
        return pos_ids

    def compute_output_shape(self, input_shape):
        return (None, None, self.output_dim)

    def compute_mask(self, inputs, mask):
        return mask[0]

    def get_config(self):
        config = {
            'input_dim': self.input_dim,
            'output_dim': self.output_dim,
            'embeddings_initializer':
                initializers.serialize(self.embeddings_initializer),
        }
        base_config = super(RelativePositionEmbedding, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

05

总结及反思

本篇从理论到实践介绍了Transformer中的位置编码。首先介绍了位置编码的作用以及主要实现方式;然后重点介绍了主流的位置编码方式,包括训练式位置编码、三角函数式位置编码和相对位置编码,同时基于开源项目bert4keras源码实践了各种位置编码。对Transformer中位置编码的知识和源码实践感兴趣的小伙伴可以多交流。

06

参考文献

【1】苏剑林. (Dec. 04, 2020). 《层次分解位置编码,让BERT可以处理超长文本 》[Blog post]. Retrieved from https://www.kexue.fm/archives/7947

【2】Transformer Architecture: The Positional Encoding, https://kazemnejad.com/blog/transformer_architecture_positional_encoding/

【3】苏剑林. (Feb. 03, 2021). 《让研究人员绞尽脑汁的Transformer位置编码 》[Blog post]. Retrieved from https://www.kexue.fm/archives/8130

最新最全的文章请关注我的微信公众号或者知乎专栏:数据拾光者。

码字不易,欢迎小伙伴们点赞和分享。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据拾光者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
位置编码
在transformer中使用了位置编码,为什么需要位置编码。因为对于transformer中的注意力机制而言,交换两个单词,并不会影响注意力的计算,也就是说这里的注意力是对单词位置不敏感的,而单词之间的位置信息往往是很重要的,因此考虑使用位置编码。
西西嘛呦
2022/05/10
2.6K0
ACL2022 | 序列标注的小样本NER:融合标签语义的双塔BERT模型
每天给你送来NLP技术干货! ---- 作者 | SinGaln 来自 | PaperWeekly 这是一篇来自于 ACL 2022 的文章,总体思想就是在 meta-learning 的基础上,采用双塔 BERT 模型分别来对文本字符和对应的label进行编码,并且将二者进行 Dot Product(点乘)得到的输出做一个分类的事情。文章总体也不复杂,涉及到的公式也很少,比较容易理解作者的思路。对于采用序列标注的方式做 NER 是个不错的思路。 论文标题: Label Semantics for Few
zenRRan
2022/07/12
8540
ACL2022 | 序列标注的小样本NER:融合标签语义的双塔BERT模型
Llama深入浅出
前方干货预警:这可能是你能够找到的最容易懂的最具实操性的学习开源LLM模型源码的教程。
lyhue1991
2023/09/05
2.4K1
Llama深入浅出
为什么 BERT 不采用原始 Transformer 中的正弦-余弦位置编码?
笔者在学习 BERT 架构技术时,看到书中提到了 BERT 没有采用原始 Transformer 中的正弦-余弦位置编码,但是没讲原因。
编程小妖女
2025/01/05
2770
为什么 BERT 不采用原始 Transformer 中的正弦-余弦位置编码?
[Keras实战教程]·使用Transfromer模型做文本分类(NLP分类最佳模型)
谷歌大脑在论文《Attention Is All You Need》中提出了一个完全基于注意力机制的编解码器模型 Transformer ,它完全抛弃了之前其它模型引入注意力机制后仍然保留的循环与卷积结构,然后在任务表现、并行能力和易于训练性方面都有大幅的提高。Transformer 从此也成为了机器翻译和其它许多文本理解任务中的重要基准模型。
小宋是呢
2019/06/27
1.4K0
用带注意力机制的模型分析评论者是否满意
本内容取之电子工业出版社出版、李金洪编著的《深度学习之TensorFlow工程化项目实战》一书的实例36。
代码医生工作室
2019/08/27
7720
【Pre-Training】Transformers 源码阅读和实践
本文主要针对HuggingFace开源的 transformers,以BERT为例介绍其源码并进行一些实践。主要以pytorch为例 (tf 2.0 代码风格几乎和pytorch一致),介绍BERT使用的Transformer Encoder,Pre-training Tasks和Fine-tuning Tasks。最后,针对预训练好的BERT进行简单的实践,例如产出语句embeddings,预测目标词以及进行抽取式问答。本文主要面向BERT新手,在阅读本文章前,假设读者已经阅读过BERT原论文。
阿泽 Crz
2020/11/25
2.6K0
机器如何读懂人心:Keras实现Self-Attention文本分类
了解了模型大致原理,我们可以详细的看一下究竟Self-Attention结构是怎样的。其基本结构如下
AI科技大本营
2019/07/03
2.7K0
机器如何读懂人心:Keras实现Self-Attention文本分类
nlp-with-transformers系列-03_剖析transformers模型
在第2章中,我们看到了微调和评估一个Transformer所需要的东西。 现在让我们来看看它们在引擎盖下是如何工作的。 在本章中,我们将探讨Transformer模型的主要组件以及如何使用PyTorch实现它们。 我们还将提供关于如何在TensorFlow中做同样事情的指导。 我们将首先专注于建立注意力机制,然后添加必要组件,使Transformer编码器工作。 我们还将简单了解一下编码器和解码器模块之间的结构差异。 在本章结束时,你将能够自己实现一个简单的Transformer模型!
致Great
2023/08/25
3480
nlp-with-transformers系列-03_剖析transformers模型
[深度应用]·Keras实现Self-Attention文本分类(机器如何读懂人心)
笔者在[深度概念]·Attention机制概念学习笔记博文中,讲解了Attention机制的概念与技术细节,本篇内容配合讲解,使用Keras实现Self-Attention文本分类,来让大家更加深入理解Attention机制。
小宋是呢
2019/06/27
2.5K0
[深度应用]·Keras实现Self-Attention文本分类(机器如何读懂人心)
keras实战系列之推荐系统FM(Factorization Machine)算法
博主在之前的文章中介绍过使用keras搭建一个基于矩阵分解的推荐系统,而那篇文章所介绍的方法可能只是一个庞大推荐系统中的一小环节。而对于工业级别的推荐系统,面对极其庞大的产品种类数量,一步就输出符合用户心意的产品可能够呛,最好的方式应该是从巨大的产品类别之中粗筛出一些靠谱的待推荐产品,然后再从粗筛的产品中精挑细选出要推荐给用户的最终产品。
润森
2022/09/22
1.1K0
keras实战系列之推荐系统FM(Factorization Machine)算法
Transformers 4.37 中文文档(八十四)
中文 CLIP 模型是由 An Yang、Junshu Pan、Junyang Lin、Rui Men、Yichang Zhang、Jingren Zhou、Chang Zhou 在中文 CLIP:中文对比视觉-语言预训练中提出的。中文 CLIP 是在大规模中文图像-文本对数据集上实现的 CLIP(Radford 等,2021)的一个实现。它能够执行跨模态检索,并且还可以作为视觉任务的视觉骨干,如零样本图像分类、开放域目标检测等。原始的中文 CLIP 代码在此链接上发布。
ApacheCN_飞龙
2024/06/26
1.2K0
Transformers 4.37 中文文档(八十二)
XLS-R 模型由 Arun Babu、Changhan Wang、Andros Tjandra、Kushal Lakhotia、Qiantong Xu、Naman Goyal、Kritika Singh、Patrick von Platen、Yatharth Saraf、Juan Pino、Alexei Baevski、Alexis Conneau、Michael Auli 在XLS-R: Self-supervised Cross-lingual Speech Representation Learning at Scale中提出。
ApacheCN_飞龙
2024/06/26
3110
Transformers 4.37 中文文档(八十二)
深度解析BERT:从理论到Pytorch实战
在信息爆炸的时代,自然语言处理(NLP)成为了一门极其重要的学科。它不仅应用于搜索引擎、推荐系统,还广泛应用于语音识别、情感分析等多个领域。然而,理解和生成自然语言一直是机器学习面临的巨大挑战。接下来,我们将深入探讨自然语言处理的一些传统方法,以及它们在处理语言模型时所面临的各种挑战。
TechLead
2023/10/21
5.1K0
深度解析BERT:从理论到Pytorch实战
BERT源码分析PART I
BERT模型也出来很久了, 之前有看过论文和一些博客对其做了解读:NLP大杀器BERT模型解读,但是一直没有细致地去看源码具体实现。最近有用到就抽时间来仔细看看记录下来,和大家一起讨论。
AINLP
2019/07/17
1.6K0
BERT源码分析PART I
【论文复现】时序预测:多头注意力+宽度学习
Liyun Su, Lang Xiong和Jialing Yang在2024年发表了题为“Multi-Attn BLS: Multi-head attention mechanism with broad learning system for chaotic time series prediction”的论文,发表在《Applied Soft Computing》杂志上(CiteScore14.3,影响因子8.7)。这篇论文针对混沌时间序列数据的高复杂性和非线性提出了一种新的范式,即将宽度学习模型与多头自注意力机制相结合。在此之前,将这两种高度非线性映射算法融合的主要方法是使用堆叠的多头自注意力来提取特征,然后使用宽度学习模型进行分类预测。这篇论文提出了一种直接将多头注意力模块集成到宽度学习中的方法,从而实现了端到端的预测模型。
Eternity._
2024/11/28
3180
【论文复现】时序预测:多头注意力+宽度学习
Transformers 4.37 中文文档(八十五)
CLIPSeg 模型是由 Timo Lüddecke 和 Alexander Ecker 在使用文本和图像提示进行图像分割中提出的。CLIPSeg 在冻结的 CLIP 模型之上添加了一个最小的解码器,用于零样本和一样本图像分割。
ApacheCN_飞龙
2024/06/26
3570
Transformers 4.37 中文文档(八十五)
Transformers 4.37 中文文档(九十六)
VipLlava 模型是由 Mu Cai、Haotian Liu、Siva Karthik Mustikovela、Gregory P. Meyer、Yuning Chai、Dennis Park、Yong Jae Lee 在《Making Large Multimodal Models Understand Arbitrary Visual Prompts》中提出的。
ApacheCN_飞龙
2024/06/26
5260
聊聊ChatGLM-6B源码分析(二)
GLM模型中位置编码是2D的,有两层的位置表示,分别是序列的位置表示和mask block的位置表示。由get_position_ids函数处理。position_ids对应GLM论文中的postion 1,block_position_ids对应GLM论文中的position 2。
Ryan_OVO
2024/01/13
4510
聊聊ChatGLM-6B源码分析(二)
[预训练语言模型专题] Huggingface简介及BERT代码浅析
感谢清华大学自然语言处理实验室对预训练语言模型架构的梳理,我们将沿此脉络前行,探索预训练语言模型的前沿技术,红色框为已介绍的文章。本期的内容是结合Huggingface的Transformers代码,
朴素人工智能
2020/04/21
3.9K0
[预训练语言模型专题] Huggingface简介及BERT代码浅析
相关推荐
位置编码
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验