一、Attention的介绍


在普通的RNN结构中,Encoder需要把一个句子转化为一个向量,然后在Decoder中使用,这就要求Encoder把源句子中所有的信息都包含进去,但是当句子长度过长的时候,这个要求就很难达到,或者说会产生瓶颈(比如,输入一篇文章等场长内容),当然我们可以使用更深的RNN和大多的单元来解决这个问题,但是这样的代价也很大。那么有没有什么方法能够优化现有的RNN结构呢?

为此,Bahdanau等人在2015年提出了Attenion机制,Attention翻译成为中文叫做注意力,把这种模型称为Attention based model。就像我们自己看到一副画,我们能够很快的说出画的主要内容,而忽略画中的背景,因为我们注意的,更关注的往往是其中的主要内容。

通过这种方式,在我们的RNN中,我们有通过LSTM或者是GRU得到的所有信息,那么这些信息中只去关注重点,而不需要在Decoder的每个time step使用全部的encoder的信息,这样就可以解决第一段所说的问题了

二、Attention的实现机制


假设我们现在有一个文本翻译的需求,即机器学习翻译为machine learning。那么这个过程通过前面所学习的Seq2Seq就可以实现

上图的左边是Encoder,能够得到hidden_state在右边使用

Deocder中蓝色方框中的内容,是为了提高模型的训练速度而使用teacher forcing手段,否则的话会把前一次的输出作为下一次的输入(但是在Attention模型中不再是这样了

那么整个过程中如果使用Attention应该怎么做呢?

在之前我们把encoder的最后一个输出,作为decoder的初始的隐藏状态,现在我们不再这样做

1、Attention的实现过程

  • 初始化一个Decoder的隐藏z_0z\_0z_0

  • 这个z_oz\_oz_o会和encoder第一个time step的output进行match操作(或者是socre操作),得到α_01\alpha\_0^1α_01 ,这里的match可以使很多中操作,比如:

    • z和h的余弦值
    • 是一个神经网络,输入为z和h
    • 或者α=hTWz\alpha = h^T W zα=hTWz

  • encoder中的每个output都和z_0z\_0z_0进行计算之后,得到的结果进行softmax,让他们的和为1(可以理解为权重)

之后把所有的softmax之后的结果和原来encoder的输出h_ih\_ih_i进行相加求和得到c0c^0c0 即:c0=∑α^i0hi

  • 得到c0c^0c0之后,把它作为decoder的input,同和传入初始化的z0z^0z0,得到第一个time step的输出和hidden_state(Z1Z^1Z1

  • Z_1Z\_1Z_1再和所有的encoder的output进行match操作,得到的结果进行softmax之后作为权重和encoder的每个timestep的结果相乘求和得到c1c^1c1

  • 再把c1c^1c1作为decoder的input,和Z1Z^1Z1作为输入得到下一个输出,如此循环,只到最终decoder的output为终止符

  • 整个过程写成数学公式如下:

  1. 先计算attention权重
  2. 在计算上下文向量,图中的cic^ici
  3. 最后计算结果,往往会把当前的output([batch_size,1,hidden_size])和上下文向量进行拼接然后使用

2、不同Attention的介绍

在上述过程中,使用decoder的状态和encoder的状态的计算后的结果作为权重,乘上encoder每个时间步的输出,这需要我们去训练一个合适的match函数,得到的结果就能够在不同的时间步上使用不同的encoder的相关信息,从而达到只关注某一个局部的效果,也就是注意力的效果

  • Soft-Attention 和 Hard-Attention

最开始Bahdanau等人提出的Attention机制通常被称为soft-attention,所谓的soft-attention指的是encoder中输入的每个词语都会计算得到一个注意力的概率。

在进行图像捕捉的时候,提出了一种hard-attenion的方法,希望直接从input中找到一个和输出的某个词对应的那一个词。但是由于NLP中词语和词语之间往往存在联系,不会只关注某一个词语,所以都会使用soft-attention,所以这里的就不多介绍hard-attention

  • Global-Attention 和Local Attention

    Bahdanau等人提出的Bahdanau Attention 被称为local attention,后来Luong等人提出的Luong Attention是一种全局的attenion。

    所谓全局的attenion指的是:使用的全部的encoder端的输入的attenion的权重

    local-attenion就是使用了部分的encoder端的输入的权重(当前时间步上的encoder的hidden state),这样可以减少计算量,特别是当句子的长度比较长的时候。

三、Attention的代码实现


通过attention的代码,需要实现计算的是attention weight

通过前面的学习,我们知道attention_weight = f(hidden,encoder_outputs),主要就是实现Luong attention中的三种操作

class Attention(nn.Module):
def __init__(self,method,batch_size,hidden_size):
super(Attention,self).__init__()
self.method = method
self.hidden_size = hidden_size
assert self.method in ["dot","general","concat"],"method 只能是 dot,general,concat,当前是{}".format(self.method)
if self.method == "dot":
pass
elif self.method == "general":
self.Wa = nn.Linear(hidden_size,hidden_size,bias=False)
elif self.method == "concat":
self.Wa = nn.Linear(hidden_size*2,hidden_size,bias=False)
self.Va = nn.Parameter(torch.FloatTensor(batch_size,hidden_size))
def forward(self, hidden,encoder_outputs):
"""
:param hidden:[1,batch_size,hidden_size]
:param encoder_outputs: [batch_size,seq_len,hidden_size]
:return:
"""
batch_size,seq_len,hidden_size = encoder_outputs.size()
hidden = hidden.squeeze(0) #[batch_size,hidden_size]
if self.method == "dot":
return self.dot_score(hidden,encoder_outputs)
elif self.method == "general":
return self.general_score(hidden,encoder_outputs)
elif self.method == "concat":
return self.concat_score(hidden,encoder_outputs)
def _score(self,batch_size,seq_len,hidden,encoder_outputs):
# 速度太慢
# [batch_size,seql_len]
attn_energies = torch.zeros(batch_size,seq_len).to(config.device)
for b in range(batch_size):
for i in range(seq_len):
#encoder_output : [batch_size,seq_len,hidden_size]
#deocder_hidden :[batch_size,hidden_size]
#torch.Size([256, 128]) torch.Size([128]) torch.Size([256, 24, 128]) torch.Size([128])
# print("attn size:",hidden.size(),hidden[b,:].size(),encoder_output.size(),encoder_output[b,i].size())
attn_energies[b,i] = hidden[b,:].dot(encoder_outputs[b,i]) #dot score
return F.softmax(attn_energies).unsqueeze(1)  # [batch_size,1,seq_len]
def dot_score(self,hidden,encoder_outputs):
"""
dot attention
:param hidden:[batch_size,hidden_size] --->[batch_size,hidden_size,1]
:param encoder_outputs: [batch_size,seq_len,hidden_size]
:return:
"""
#hiiden :[hidden_size] -->[hidden_size,1] ,encoder_output:[seq_len,hidden_size]
hidden = hidden.unsqueeze(-1)
attn_energies = torch.bmm(encoder_outputs, hidden)
attn_energies = attn_energies.squeeze(-1) #[batch_size,seq_len,1] ==>[batch_size,seq_len]
return F.softmax(attn_energies).unsqueeze(1)  # [batch_size,1,seq_len]
def general_score(self,hidden,encoder_outputs):
"""
general attenion
:param batch_size:int
:param hidden: [batch_size,hidden_size]
:param encoder_outputs: [batch_size,seq_len,hidden_size]
:return:
"""
x = self.Wa(hidden) #[batch_size,hidden_size]
x = x.unsqueeze(-1) #[batch_size,hidden_size,1]
attn_energies = torch.bmm(encoder_outputs,x).squeeze(-1) #[batch_size,seq_len,1]
return F.softmax(attn_energies,dim=-1).unsqueeze(1)      # [batch_size,1,seq_len]
def concat_score(self,hidden,encoder_outputs):
"""
concat attention
:param batch_size:int
:param hidden: [batch_size,hidden_size]
:param encoder_outputs: [batch_size,seq_len,hidden_size]
:return:
"""
#需要先进行repeat操作,变成和encoder_outputs相同的形状,让每个batch有seq_len个hidden_size
x = hidden.repeat(1,encoder_outputs.size(1),1) ##[batch_size,seq_len,hidden_size]
x = torch.tanh(self.Wa(torch.cat([x,encoder_outputs],dim=-1))) #[batch_size,seq_len,hidden_size*2] --> [batch_size,seq_len,hidden_size]
#va [batch_size,hidden_size] ---> [batch_size,hidden_size,1]
attn_energis = torch.bmm(x,self.Va.unsqueeze(2))  #[batch_size,seq_len,1]
attn_energis = attn_energis.squeeze(-1)
# print("concat attention:",attn_energis.size(),encoder_outputs.size())
return F.softmax(attn_energis,dim=-1).unsqueeze(1) #[batch_size,1,seq_len]

完成了attention weight的计算之后,需要再对代码中forward_step的内容进行修改

def forward_step(self,decoder_input,decoder_hidden,encoder_outputs):
"""
:param decoder_input:[batch_size,1]
:param decoder_hidden: [1,batch_size,hidden_size]
:param encoder_outputs: encoder中所有的输出,[batch_size,seq_len,hidden_size]
:return: out:[batch_size,vocab_size],decoder_hidden:[1,batch_size,didden_size]
"""
embeded = self.embedding(decoder_input)  #embeded: [batch_size,1 , embedding_dim]
#TODO 可以把embeded的结果和前一次的context(初始值为全0tensor) concate之后作为结果
#rnn_input = torch.cat((embeded, last_context.unsqueeze(0)), 2)
# gru_out:[256,1, 128]  decoder_hidden: [1, batch_size, hidden_size]
gru_out,decoder_hidden = self.gru(embeded,decoder_hidden)
gru_out = gru_out.squeeze(1)
#TODO 注意:如果是单层,这里使用decoder_hidden没问题(output和hidden相同)
# 如果是多层,可以使用GRU的output作为attention的输入
#开始使用attention
attn_weights = self.attn(decoder_hidden,encoder_outputs)
# attn_weights [batch_size,1,seq_len] * [batch_size,seq_len,hidden_size]
context = attn_weights.bmm(encoder_outputs) #[batch_size,1,hidden_size]
gru_out = gru_out.squeeze(0)  # [batch_size,hidden_size]
context = context.squeeze(1)  # [batch_size,hidden_size]
#把output和attention的结果合并到一起
concat_input = torch.cat((gru_out, context), 1) #[batch_size,hidden_size*2]
concat_output = torch.tanh(self.concat(concat_input)) #[batch_size,hidden_size]
output = F.log_softmax(self.fc(concat_output),dim=-1) #[batch_Size, vocab_size]
# out = out.squeeze(1)
return output,decoder_hidden,attn_weights

四、如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

这份完整版的大模型 AI 学习和面试资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
在这里插入图片描述

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈

• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐