【Bert】自然语言(Language Model)入门之---Bert
every blog every motto: Although the world is full of suffering, it is full also of the overcoming of it
0. 前言
对bert进行梳理
论文: BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
时间: 2018.10.11
作者: Jacob Devlin, Ming-Wei Chang, Kenton Lee, Kristina Toutanova
1. 正文
1.1 整体理解
Transformer的第一版时2017.6.12
bert(用到Transformer的Encoder)的第一版arxiv上的文章时间时2018.10.11
GPT1(用到Transformer的Decoder)在arxiv上没找到对应的文章,但是第一版的bert中就有把GPT1作为参考,所以GPT1的时间应该是在2018.10.11之前
动作不得不说快阿!!!

下图展示了三种模型的不同
bert: 双向(Transformer Encoder)
GPT1:从左到右单向(Transformer Decoder)
ELMo:单独训练从左到右和从右到左,再结合(bert双向也是借鉴于此,ELMo基础单元是LSTM,这是一个比较早的东东了)

具体来说,bert使用Transformer的encoder部分作为基础单元进行堆叠,而GPT使用decoder部分作为基础单元进行堆叠。

Bert有两个版本,一个是base (12层),一个是large(24层),base的参数量是110M,large的参数量是340M。
base的作用是为了和GPT1作对比。
base:
L:12; H:768; A:12
large:
L:24; H:1024; A:16
说明: 编码器层数L,注意力头数A,隐藏层数H.

1.2 和GPT1的对比
和GPT1相比的话,主要有两点不同,一个是bert是双向,另一个是预训练。
其中GPT1预训练,是预测一个句子的下一个词是什么(这个在NLP中我们也称作Language Modeling(LM)),如下:

而bert的预训练是以下两个:
1.2.1 任务一:“完型填空”
不同于常规思路预测下一词。
上面说了bert是双向的,如果预测下一个词,那将是没有意义。所以对输入的词进行mask,即遮住,然后让模型去预测遮住的词是什么。(是不是和我们做的完形填空一样!!!),论文中将这个称为:“masked LM” (MLM)
如下,将hairy进行Mask以后去预测:
my dog is hairy → my dog is [MASK]
然后对网络的输出结果相应位置进行softmax,得到每个词的概率分布,然后取概率最大的词作为预测结果。如下图:

但是存在一个问题,mask15%比例比较高,这会造成某些词在微调(fine-tuning)时候没有见过,此外,微调的时候是没有mask的,为了让预训练和微调匹配,做了一些调整。
每一个句子会预测15%token,在这其中,
- 80%的token被替换成
[MASK],my dog is hairy → my dog is [MASK] - 10%的token被替换成随机词,
my dog is hairy → my dog is apple - 10%的token保持不变,
my dog is hairy → my dog is hairy

1.2.2 任务二:预测下一个句子
在NLP中的某些任务当中,需要将两个句子作为输入(如,问答系统),所以bert中的预训练添加了一个的新的训练方式----Next Sentence Prediction,下一个句子预测。
具体的是一次输入两个句子,最后有一个输入,判断是否相似。如下图:
其中, 50%的输入数据B是A的下一个句子,50%的数据B是从语料库中随机选取的。

1.2.3 小结
现在我们看下面这个图应该比较好理解了。
在pre-training阶段,输出的第一位是用于判断是否是下一个句子(NSP,任务二,二分类)后续输出是做
完型填空(MLM,任务一,多分类)。

关于输入,需要注意的是,输入的是一个序列(sequence),一个sequence可能是一个句子(sentence)也可能是两个句子(sentence,为了适应下游的问题任务)。
而一个句子setence,更准确是一段连续的文本,不是我们常规的“句子”。

1.3 小结
除了论文中提到的base和large,github上还有其他版本。
- BERT-tiny, L = 2 , H = 128 L=2,H=128L=2,H=128
- BERT-mini, L = 4 , H = 256 L=4,H=256L=4,H=256
- BERT-small, L = 4 , H = 512 L=4,H=512L=4,H=512
- BERT-medium, L = 8 , H = 512 L=8,H=512L=8,H=512

主要贡献:
- 引入了Masked LM,使用双向LM做模型预训练。
- 为预训练引入了新目标NSP,它可以学习句子与句子间的关系。
- 进一步验证了更大的模型效果更好: 12 --> 24 层。
- 为下游任务引入了很通用的求解框架,不再为任务做模型定制。
- 刷新了多项NLP任务的记录,引爆了NLP无监督预训练技术。
1.4 关于输入
bert的是输入是一个序列(sequence,包含多个句子(sentence)),而网络的最小处理单元是一个词,就是token。关于bert中具体的分词方式我们暂时按下不表。
我们先看一个例子。 若我们一个序列是:
Sentence A: Paris is a beautiful city.
Sentence B: I love Paris.
1.4.1 token
先将句子进行分词,转换成一个个token以后,如下:
[CLS] Paris is a beautiful city . [SEP] I love Paris . [SEP]
其中,
- [CLS]放在序列第一个位置,用于分类(NSP,下一个句子预测)
- [SEP]放在每个句子(sentence)结尾,用于区分句子和句子。

1.4.2 segment
由于我们一次会输入两个句子(sentence),所以需要区分是句子A还是句子B,所以bert中引入了segment,用于区分句子A和句子B。
- 句子A的segment id为0
- 句子B的segment id为1

1.4.3 position
由于bert的输入是一个序列,而序列的长度是有限的,所以需要将序列进行截断,而截断以后,我们无法知道每个词在句子中的位置,所以bert中引入了position,用于表示每个词在句子中的位置。

1.4.4 最终的输入
最终的输入是将上面的token、segment和position相加

1.5 分词:WordPiece
bert中的分词采用的是WorPiece,是Google在2016年提出的,它将词拆分成更小的子词,比如,将“unhappiness”拆分成“un”和“-happy”,这样就可以避免OOV问题。
具体做法:检查单词是否在词表(vocabulary)中,如果在则标记;否则,拆分成子词,
对子词继续重复前面的过程(然后检查子词是否在词表中,如果在则标记;否则,继续拆分,直到拆分出来的子词在词表中。)
Bert的词表有30k标记。
比如:
"Let us start pretraining the model."
其中pretraining不在词表中,所以会被拆分成pre、##train和##ing。
前面的#表示这个单词为一个子词,并且它前面有其他单词。现在我们检查子词##train和##ing是否出现在词表中。因为它们正好在词表中,所以我们不需要继续拆分。
所以上述句子会被拆分成:
tokens = [let, us, start, pre, ##train, ##ing, the, model]
增加[CLS]和[SEP]后是:
tokens = [ [CLS], let, us, start, pre, ##train, ##ing, the model, [SEP] ]
1.6 预处理代码
我们的原始数据是文本,而所谓的神经网络训练本质是对数字进行数学运算。
所以我们需要将文本转换为数字,而转换的过程就是预处理。下面我们看下代码
1.6.1 步骤
本次使用的是抱脸的transformers库
pip install transformers
1. 导入库
导入库,加载预训练的模型和分词器。
from transformers import BertModel, BertTokenizer
import torch
model = BertModel.from_pretrained('bert-base-uncased')
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
离线情况下
model_path = './model_path'
bert = BertModel.from_pretrained(pretrained_model_name_or_path=model_path)
将下图中需要的文件下载到本地即可

2. 分词
sentence = 'I love Paris'
tokens = tokenizer.tokenize(sentence)
print(tokens)

3. 添加CLS、SEP
tokens = ['[CLS]'] + tokens + ['[SEP]']
print(tokens)

4. 添加pad
正常的bert的输入是个固定长度,如果长度超过这个固定长度进行截断,小于该固定长度添加pad。
假设固定长度是7,现在我们的tokens长度位5,所以需要添加pad
tokens = tokens + ['[PAD]'] + ['[PAD]']
tokens

5. mask
bert中的encoder内部是注意力机制,我们需要传入一个mask,用于区分正常词和pad。
attention_mask = [1 if i!= '[PAD]' else 0 for i in tokens]
attention_mask

6. 转为id
不管是中文还是英文句子都是字符,而神经网络是对数字进行训练。所以需要将字符转化为数字。
不管是中文还是英文句子都是字符,而神经网络是对数字进行训练。所以需要将字符转化为数字。
不管是中文还是英文句子都是字符,而神经网络是对数字进行训练。所以需要将字符转化为数字。
token_ids = tokenizer.convert_tokens_to_ids(tokens)
token_ids

本质是从一个大的字典里面找到每次词对应的id。

7. 转为tensor
import torch
token_ids = torch.tensor(token_ids).unsqueeze(0)
attention_mask = torch.tensor(attention_mask).unsqueeze(0)print(token_ids.shape)
print(token_ids)
我们输入是一个句子,每个句子的长度是7。

8. 输入模型
hidden_rep, cls_head = bert(token_ids, attention_mask=attention_mask,return_dict=False)print(hidden_rep.shape,cls_head.shape)
hidden_rep : 是bert中最后一个encoder的输出,维度是[1,7,768]
cls_head : 是cls的输出,维度是[1,768]
对于hidden_rep,1表示一个1个句子,7表示句子的长度,768表示每个词的向量维度 (一个词用一个长度为768的向量表示)。

1.6.2 小结
我们处理的是句子,而所谓的神经网络训练本质是对数字进行加减乘除运算。所以实际输入网络的是数字。
原始的是文本,输入网络的是经过字典映射的数字。

1.7 关于embedding
如果看论文,会发现bert的输入是embedding,而我们上面的预处理最终的结果好像是token_ids(只是索引而已),这二者有什么关系呢?

在说embedding之前,我们先看下one-hot编码。
1.7.1 one-hot编码
one-hot编码是机器学习中最常用的编码方式,对于每个词,我们用长度为n的向量表示,其中n是词表的大小,向量中只有一个1,其余都是0。
比如中文有5000个词,为了方便我们简化一下,现在词典里面有5个词。[‘我’,‘是’,‘中’,‘国’,‘人’]。
'我们人’可以用如下向量表示:
我:[1 0 0 0 0 ]
是:[0 1 0 0 0 ]
人:[0 0 0 0 1 ]
看起来也比较直观,但是别忘了我们这里词典大小是5,如果5000呢?那么我这个词的向量就是5000维的,如果50000呢?50000维的向量,是不是有点太大了?
这会导致我们的结果非常的稀疏!
其次,one-hot编码之间的向量是正交的,词和词之间没有关系,比如’我’和’是’之间没有关系,'中’和’国’之间也没有关系,这显然是不合理的。
所以就出现了embedding
1.7.2 embedding
embedding是一个词典,更通俗的说一个二维向量。
我们的embedding现在是(5000,768),5000表示词表大小,768表示每个词的向量维度。
啥意思?就是我们的词表里面有5000个词,每个词用一个长度为768的向量表示。
现在我们要表示我,只需要根据我这个词对应的索引,在5000个词中找到对应的向量即可。而这个向量是一个长度为768的向量。
768相比之前的5000小了不少。同时词和词和词之间也有有关系的。
1.7.3 代码示例
构建一个含有10个词的词表,每个词用一个长度为3的向量表示。
import torch
import torch.nn as nn# 创建 Embedding 层
num_embeddings = 10 # 词汇表大小
embedding_dim = 3 # 嵌入向量的维度
embedding_layer = nn.Embedding(num_embeddings, embedding_dim)
embedding_layer

我们看下词表里面的值是个啥
embedding_layer.weight

现在我们有词索引如下:
# 示例输入
input_indices = torch.LongTensor([1, 2, 3, 4])
print('input.shape: ',input_indices.shape)
print("Input indices:", input_indices)

现在我们根据对应的词到词表中查找我们的词对应的向量。
# 获取嵌入向量
output_vectors = embedding_layer(input_indices)
print('output.shape: ',output_vectors.shape)
print("Output vectors:", output_vectors)

这个值是从词表中来的。

1.7.4 bert官方部分代码

1.7.5 小结
embedding正式表述是词表,或是或是词典。更本质来说是一个二维向量。
通过“查表”我们获得了每一个词的向量表示。这样的表示相比one-hot编码更稠密。同时,也能表达词和词之间的关系。
开始是我们的embedding参数是随机的,通过不断的训练,含义更加准确。
1.8 小结
bert 借鉴了GPT1和ELMo,使用Transformer的encoder部分进行堆叠。
两种预训练(MLM和NSP)能够更有效的获取语义信息。
参考
- https://cloud.tencent.com/developer/article/2058413
- https://blog.csdn.net/jiaowoshouzi/article/details/89073944
- https://blog.csdn.net/yjw123456/article/details/120211601
- https://blog.csdn.net/weixin_42029738/article/details/139578563
- https://helloai.blog.csdn.net/article/details/120211601
- https://www.cnblogs.com/JuggyZhan/p/18249075
- https://cloud.tencent.com/developer/article/2348457
- https://cloud.tencent.com/developer/article/2336439
- https://blog.csdn.net/magicyangjay111/article/details/132665098
- https://www.cnblogs.com/zackstang/p/15387549.html
- https://blog.csdn.net/yjw123456/article/details/120232707
- https://people.ee.duke.edu/~lcarin/Dixin2.22.2019.pdf
相关文章:
【Bert】自然语言(Language Model)入门之---Bert
every blog every motto: Although the world is full of suffering, it is full also of the overcoming of it 0. 前言 对bert进行梳理 论文: BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding 时间:…...
实时股票行情接口与WebSocket行情接口的应用
实时股票行情接口与WebSocket行情接口的应用 实时股票行情接口是量化交易和投资决策的核心工具之一,行情接口的种类和功能也在不断扩展。介绍几种常见的行情接口,包括实时股票行情接口、Level2行情接口、WebSocket行情接口以及量化行情接口,…...
.NET版PDF处理控件Aspose.PDF教程:在 C# 中将 TIFF 文件转换为 PDF
将TIFF文件转换为PDF文档在各个行业中都是必不可少的。许多企业需要将文档转换为存档、共享或打印。TIFF 文件通常用于图像,而 PDF 是文档共享的标准。将 TIFF 文件转换为 PDF 可确保跨不同平台的兼容性和易用性。在这篇博文中,我们将探讨如何使用 Aspos…...
本地搭建小型 DeepSeek 并进行微调
本文将指导您在本地搭建一个小型的 DeepSeek 模型,并进行微调,以处理您的特定数据。 1. 环境准备 Python 3.7 或更高版本 PyTorch 1.8 或更高版本 CUDA (可选,用于 GPU 加速) Git 2. 克隆 DeepSeek 仓库 bash 复制 git clone https://github.com/deepseek-ai/deepseek.g…...
备战蓝桥杯 Day4 差分
差分(修改区间后查询) 1.要点 a[0]0; for(int i1;i<n;i){diff[i]a[i]-a[i-1];//构建差分数组 } //原数组a区间[l,r]全部加上x diff[l]x;//还原a数组[l,n]全部加上x diff[r1]-x;//还原a数组[r1,n]全部减去x for(int i1;i<n;i){a[i]a[i-1]diff[i]; }实现多次修改完后多次…...
解决华硕主板的Boot界面无法设置M.2的系统启动盘问题
一、问题描述 当我们的华硕主板电脑开机后,发现电脑无法正常进入Windows系统界面,直接显示PXE网络网络信息;且知道我们进入到BIOS界面也无法找到选择系统盘,界面只显示【UEFI:PXE IP4 Intel(R) Ethernet】、【UEFI:PXE IP6 Intel(…...
【Arxiv 大模型最新进展】PEAR: 零额外推理开销,提升RAG性能!(★AI最前线★)
【Arxiv 大模型最新进展】PEAR: 零额外推理开销,提升RAG性能!(★AI最前线★) 🌟 嗨,你好,我是 青松 ! 🌈 自小刺头深草里,而今渐觉出蓬蒿。 NLP Github 项目…...
硬件学习笔记--46 电能表影响量试验梳理
目录 1.电流和电压电路中的谐波影响试验 1)电流和电压电路中谐波——第5次谐波试验 2)电流和电压电路中谐波——方顶波波形试验 3)电流和电压电路中谐波——尖顶波波形试验 4)电流和电压电路中谐…...
Linux-C/C++《C/9、信号:基础》(基本概念、信号分类、信号传递等)
本章将讨论信号,虽然信号的基本概念比较简单,但是其所涉及到的细节内容比较多,所以本章篇幅也会相对比较长。事实上,在很多应用程序当中,都会存在处理异步事件这种需求,而信号提供了一种处理异步事件的方法…...
【工具插件类教学】实现运行时2D物体交互的利器Runtime2DTransformInteractor
目录 编辑 1. 插件核心功能 1.1 基础变换操作 1.2 高级特性 2. 安装与配置 2.1 导入插件 2.2 配置控制器参数 2.3 为物体添加交互功能 3. 使用示例 3.1 基础操作演示 3.2 多选与批量操作 3.3 自定义光标与外观 4. 高级配置技巧 4.1 动态调整包围框控件尺寸 4.…...
OpenCV形态学操作
1.1. 形态学操作介绍 初识: 形态学操作是一种基于图像形状的处理方法,主要用于分析和处理图像中的几何结构。其核心是通过结构元素(卷积核)对图像进行扫描和操作,从而改变图像的形状和特征。例如: 腐蚀&…...
【Ubuntu】GPU显存被占用,但显示没有使用GPU的进程
文章目录 一、问题描述二、解决方案2.1 寻找问题进程2.2 尝试杀死相关进程2.3 投放核弹,一键全杀2.4 再次查看GPU使用情况 参考资料 一、问题描述 今天使用服务器的时候发现gpu被占了很多内存,但是使用 nvidia-smi 命令并没有发现占这么多显存的进程&am…...
什么是pytest.ini及如何在Pytest中应用以提升配置效率
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 当通过控制台运行Pytest测试时你必须记住记录输出、运行时环境变量、设置超时时间、…...
通义灵码AI程序员
通义灵码是阿里云与通义实验室联合打造的智能编码辅助工具,基于通义大模型技术,为开发者提供多种编程辅助功能。它支持多种编程语言,包括 Java、Python、Go、TypeScript、JavaScript、C/C、PHP、C#、Ruby 等 200 多种编码语言。 通义灵码 AI…...
以ChatGPT为例解析大模型背后的技术
目录 1、大模型分类 2、为什么自然语言处理可计算? 2.1、One-hot分类编码(传统词表示方法) 2.2、词向量 3、Transformer架构 3.1、何为注意力机制? 3.2、注意力机制在 Transformer 模型中有何意义? 3.3、位置编…...
Git中revert和reset区别?
git revert 和 git reset 都用于撤销 Git 中的提交,但它们的作用和使用场景不同: git revert: 作用:创建一个新的提交,撤销指定的提交内容。使用场景:用于“回滚”已推送到远程仓库的提交。这种方法不会改变提交历史&a…...
使用docker部署NextChat,使用阿里云、硅机流动、deepseek的apikey
1、首先使用安装好了docker的服务器拉取NextChat项目 [rootxx docker]# docker pull yidadaa/chatgpt-next-web 2、启动docker容器,基于不同平台 以下的OPENAI_API_KEY参数替换成自己的就行,启动后访问地址:http://[服务器ip]:3000/ # 硅机…...
Redis-缓存过期和内存淘汰
缓存过期&&内存淘汰 过期删除如何设置过期时间判断key是否过期过期删除策略有哪些定时删除惰性删除定期删除Redis过期删除策略 内存淘汰策略如何设置Redis最大运行内存Redis内存淘汰策略有哪些不进行数据淘汰进行数据淘汰的策略设置了过期时间的数据中进行淘汰所有数据…...
测试 FreeSWITCH 的 sip_invite_route_uri
bgapi originate sofia/external/123461.132.230.73:5161 &echo 得到的是: 172.17.129.123:5088 -> 61.132.230.73:5161 INVITE sip:123461.132.230.73:5161 SIP/2.0 Via: SIP/2.0/UDP 8.141.11.8:5088;rport;branchz9hG4bKcagQFyUgF21NS Max-Forwards: 70 …...
七星棋牌全开源修复版源码解析:6端兼容,200种玩法全面支持
本篇文章将详细讲解 七星棋牌修复版源码 的 技术架构、功能实现、二次开发思路、搭建教程 等内容,助您快速掌握该棋牌系统的开发技巧。 1. 七星棋牌源码概述 七星棋牌修复版源码是一款高度自由的 开源棋牌项目,该版本修复了原版中的多个 系统漏洞&#…...
第六届计算机信息和大数据应用国际学术会议(CIBDA 2025)
重要信息 大会官网:www.ic-cibda.org(了解会议,投稿等) 大会时间:2025年3月14-16日 大会地点:中国-武汉 简介 第六届计算机信息和大数据应用(CIBDA 2025)将于2025年3月14-16日在中国…...
在 Vue 3 中使用 Lottie 动画:实现一个加载动画
在现代前端开发中,动画是提升用户体验的重要元素之一。Lottie 是一个流行的动画库,它允许我们使用 JSON 文件来渲染高质量的动画。本文将介绍如何在 Vue 3 项目中集成 Lottie 动画,并实现一个加载动画效果。 如果对你有帮助请帮忙点个&#x…...
PyTorch 深度学习框架中 torch.cuda.empty_cache() 的妙用与注意事项
🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 在使用 PyTorch 进行深度学习模型训练与调优过程中,torch.cuda.empty_cache() 方法作为一种高效工具被广泛采用;但其正确应用要求充分理解该方法的功能及最佳实践。下文将对该方…...
快速入门——Vue框架快速上手
学习自哔哩哔哩上的“刘老师教编程”,具体学习的网站为:8.Vue框架快速上手_哔哩哔哩_bilibili,以下是看课后做的笔记,仅供参考。 第一节:前端环境准备 编码工具VSCode【www.code.visualstudio.com】/WebStorm也可&am…...
【Leetcode 每日一题】2595. 奇偶位数
问题背景 给你一个 正 整数 n n n。 用 e v e n even even 表示在 n n n 的二进制形式(下标从 0 0 0 开始)中值为 1 1 1 的偶数下标的个数。 用 o d d odd odd 表示在 n n n 的二进制形式(下标从 0 0 0 开始)中值为 1 1…...
zookeeper集群配置
配置 一、配置myid文件 # 进入解压好的文件夹下面 touch myid vim myid # master节点写0,slave1节点写1,slave2节点写2二、配置zoo.cfg文件 1.在master节点编辑zookeeper配置文件 # 进入解压好的文件夹下面 cd conf/ cp zoo_sample.cfg zoo.cfg vim …...
掌握.NET Core后端发布流程,如何部署后端应用?
无论你是刚接触.NET Core的新手还是已有经验的开发者,在这篇文章中你将会学习到一系列实用的发布技巧与最佳实践,帮助你高效顺利地将.NET Core后端应用部署到生产环境中 目录 程序发布操作 Docker容器注册表 文件夹发布 导入配置文件 网站运行操作 …...
华为昇腾920b服务器部署DeepSeek翻车现场
最近到祸一台HUAWEI Kunpeng 920 5250,先看看配置。之前是部署的讯飞大模型,发现资源利用率太低了。把5台减少到3台,就出了他 硬件配置信息 基本硬件信息 按照惯例先来看看配置。一共3块盘,500G的系统盘, 2块3T固态…...
java基础语知识(8)
类之间的关系 在类之间,最常见的关系有: 依赖(“uses-a”);聚合(“has-a”);继承(“is-a”)。 依赖:一种使用关系,即一个类的实现需要另一个类的协助&#x…...
使用Python添加、读取和删除Word文档属性
在Python中处理Word文档时,对文档属性进行操作是一项重要的任务。文档属性主要分为内置属性(如标题、作者等)和自定义属性(用户根据自身需求定义的属性)。合理地管理这些属性,能够提升文档管理效率、优化信…...
