李哥AI第七章注意力机制(自然语言处理)加分类bert实战
如何将文字转会为数值:
将文字转成向量,用one-hot进行编码。
但是one-hot有两个问题:
- 维度太高,比如汉字就得用21128维的向量表示
- 无法表示两个汉字是否接近
因此使用线性变化将高维向量转成一维,如下图所示

这样可以用模型提取特征值,完成各种输出任务:

输出是多分类

输出是二分类

输出是序列
如何提取每个字词在整体语境中的特征:


有一种方法是运用记忆单元(传家宝),串行的记录整个句子的特征。如:CNN
但这会带来一些问题:句子相关词相隔太远怎么办?

LSTM可以禁止某些字词修改记忆单元,从而提升效果。
但还有一个更重要的问题:文章太长,串行结构太慢
引入自注意力机制
下图是自注意力机制的总体模型:

什么是注意力:

对于一句话中的一个字,提取其特征值不仅要注意自身,也要将一部分注意力分配给同一句话的其他字。

注意力靠两个部分完成:我怎么注意别人,我怎么让别人注意
在该模型中是分别通过和
两个矩阵乘以自身完成。

上图中的就是
包含全局注意力的特征值。

如上图所示,就提取出了每个输入值归一化后的特征值。
为了确保输入数据和输出数据形状等个方面相匹配还要加上一个

这样就构建了一个完全并行运算的有全局信息的特征值提取方法:

接下来用矩阵方程性质进行描述(注意下图中的矩阵描述方法与线性代数中的矩阵有所不同)

得到每个字的query,key和value向量

query和key相乘得到每个字对于其他字的注意力。

最终会形成一个n*n的矩阵(表示第i个字对第j个字的注意力
然后做一个softmax的处理

最后与value相乘再相加得到全局特征值
有哪些需要训练的参数:

了解内容:

加层数:

位置信息
文字是一段序列,文字相同,顺序不同,内容完全不同

将位置信息也加入到输入数据中:

要经过一个线性变换变成输入数据的长度

这是的输入数据称为一个token

transformer模型的结构:

通过结合迁移训练的方法

如何进行预训练:

字遮罩训练和句子连续标签训练:

bert的结构:
bert来自一个芝麻屋中的角色:

embedding:使用one-hot

注解:Segment Embedding是表明文字属于那一句话;在input中有一些特殊的token,CLS是专门用来做分类的,它会记录全局的信息,从而拥有全局的特征,而SEP表示一个句子的结束
pooling

上图是一些常用的pooling方法,其他方法比如再用一层注意力机制,找到那个注意力最高的做输出

Bert实战
实战bert对文本情感进行分类:
实际上该分类任务只需要在图片分类中做出两个大修改,一个是数据的预处理,一个是替换模型
数据预处理
首先将文字处理为向量:

Input ids为one-hot编码,这里用数字替代,实际实现是用bert模型自带的词表进行的转换。
Mask:遮挡,用于指出每次输入的句子中那部分为填充
Seq_ids:表名输入的短句属于哪一个句子
数据处理代码:
input = self.tokenizer(
text,
return_tensors="pt", #返回张量格式("pt"=PyTorch, "tf"=TensorFlow, "np"=NumPy)
truncation=True, #超过 max_length 时截断文本
padding="max_length", #填充到 max_length 指定长度
max_length=128 #最大序列长度(包括特殊Token如 [CLS]、[SEP])
)
处理后的数据
input_ids = input["input_ids"].to(self.device)
token_type_ids = input['token_type_ids'].to(self.device)
attention_mask = input['attention_mask'].to(self.device)
定义模型
处理完后进行模型输入:
注意这里的输入已经由线性变换统一转成了768维,然后相加。
有两个地方不一样:
- 没有Mask,因为Mask直接乘上了Input ids经过线性变换转换成了TokenEmbeddings
- 多了一个PositionEmbedings,因为位置直接用下标转换即可,并不用特别对数据做处理。
输入模型:
sequence_out, pooler_out = self.bert(input_ids=input_ids,
token_type_ids=token_type_ids,
attention_mask=attention_mask,
return_dict=False) #return_dict
定义模型:
self.bert = BertModel.from_pretrained(bert_path)
# config = BertConfig.from_pretrained(bert_path)
# self.bert = BertModel(config) 只加载了其中的模型部分
self.device = device
self.cls_head = nn.Linear(768, num_class)
self.tokenizer = BertTokenizer.from_pretrained(bert_path)
其他部分大致等于图片分类
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)