通俗易懂!使用Excel和TF实现Transformer

图片

本文旨在通过最通俗易懂的过程来详解Transformer的每个步骤!

假设我们在做一个从中文翻译到英文的过程,我们的词表很简单如下:

中文词表:[机、器、学、习] 英文词表[deep、machine、learning、chinese]

先来看一下Transformer的整个过程:

图片

接下来,我们将按顺序来讲解Transformer的过程,并配有配套的excel计算过程和tensorflow代码。

先说明一下,本文的tensorflow代码中使用两条训练数据(因为实际场景中输入都是batch的),但excel计算只以第一条数据的处理过程为例。

1、Encoder输入

Encoder输入过程如下图所示:

图片

首先输入数据会转换为对应的embedding,然后会加上位置偏置,得到最终的输入。

这里,为了结果的准确计算,我们使用常量来代表embedding,假设中文词表对应的embedding值分别是:

图片

位置偏置position embedding使用下面的式子计算得出,注意这里位置偏置是包含两个维度的,不仅仅是encoder的第几个输入,同时embedding中的每一个维度都会加入位置偏置信息:

图片

不过为了计算方便,我们仍然使用固定值代替:

图片

假设我们有两条训练数据(Excel大都只以第一条数据为例):

[机、器、学、习] -> [ machine、learning]
[学、习、机、器] -> [learning、machine]

encoder的输入在转换成id后变为[[0,1,2,3],[2,3,0,1]]。

接下来,通过查找中文的embedding表,转换为embedding为:

图片

对输入加入位置偏置,注意这里是两个向量的对位相加:

图片

上面的过程是这样的,接下来咱们用代码来表示一下:

import tensorflow as tfchinese_embedding = tf.constant([[0.11,0.21,0.31,0.41],[0.21,0.31,0.41,0.51],[0.31,0.41,0.51,0.61],[0.41,0.51,0.61,0.71]],dtype=tf.float32)english_embedding = tf.constant([[0.51,0.61,0.71,0.81],[0.52,0.62,0.72,0.82],[0.53,0.63,0.73,0.83],[0.54,0.64,0.74,0.84]],dtype=tf.float32)position_encoding = tf.constant([[0.01,0.01,0.01,0.01],[0.02,0.02,0.02,0.02],[0.03,0.03,0.03,0.03],[0.04,0.04,0.04,0.04]],dtype=tf.float32)encoder_input = tf.constant([[0,1,2,3],[2,3,0,1]],dtype=tf.int32)with tf.variable_scope("encoder_input"):encoder_embedding_input = tf.nn.embedding_lookup(chinese_embedding,encoder_input)encoder_embedding_input = encoder_embedding_input + position_encodingwith tf.Session() as sess:sess.run(tf.global_variables_initializer())print(sess.run([encoder_embedding_input]))

结果为:

图片

跟刚才的结果保持一致。

2、Encoder Block

一个Encoder的Block过程如下:

图片

分为4步,分别是multi-head self attention、Add & Normalize、Feed Forward Network、Add & Normalize。

咱们主要来讲multi-head self attention。在讲multi-head self attention的时候,先讲讲Scaled Dot-Product Attention,我有时候也称为single-head self attention。

2.1 Attention机制简单回顾

Attention其实就是计算一种相关程度,看下面的例子:

图片

Attention通常可以进行如下描述,表示为将query(Q)和key-value pairs映射到输出上,其中query、每个key、每个value都是向量,输出是V中所有values的加权,其中权重是由Query和每个key计算出来的,计算方法分为三步:

1)计算比较Q和K的相似度,用f来表示:

图片

2)将得到的相似度进行softmax归一化:

图片

3)针对计算出来的权重,对所有的values进行加权求和,得到Attention向量:

图片

计算相似度的方法有以下4种:

图片

在本文中,我们计算相似度的方式是第一种。

2.2 Scaled Dot-Product Attention

咱们先说说Q、K、V。比如我们想要计算上图中machine和机、器、学、习四个字的attention,并加权得到一个输出,那么Query由machine对应的embedding计算得到,K和V分别由机、器、学、习四个字对应的embedding得到。

在encoder的self-attention中,由于是计算自身和自身的相似度,所以Q、K、V都是由输入的embedding得到的,不过我们还是加以区分。

这里, Q、K、V分别通过一层全连接神经网络得到,同样,我们把对应的参数矩阵都写作常量。

图片

接下来,我们得到的到Q、K、V,我们以第一条输入为例:

图片

既然是一层全连接嘛,所以相当于一次矩阵相乘,excel里面的矩阵相乘如下:

图片

在Mac中,一定要先选中对应大小的区域,输入公式,然后使用command + shift + enter才能一次性得到全部的输出,如下图:

图片

接下来,我们要去计算Q和K的相关性大小了,这里使用内积的方式,相当于QKT:

图片

(上图应该是K,不影响整个过程理解)同样,excel中的转置,也要选择相应的区域后,使用transpose函数,然后按住command + shift + enter一次性得到全部输出。

我们来看看结果代表什么含义:

图片

也就是说,机和机自身的相关性是2.37(未进行归一化处理),机和器的相关性是3.26,依次类推。我们可以称上述的结果为raw attention map。对于raw attention map,我们需要进行两步处理,首先是除以一个规范化因子,然后进行softmax操作,这里的规范化因子选择除以8,然后每行进行一个softmax归一化操作(按行做归一化是因为attention的初衷是计算每个Query和所有的Keys之间的相关性):

图片

最后就是得到每个输入embedding 对应的输出embedding,也就是基于attention map对V进行加权求和,以“机”这个输入为例,最后的输出应该是V对应的四个向量的加权求和:

图片

如果用矩阵表示,那么最终的结果是规范化后的attention map和V矩阵相乘,因此最终结果是:

图片

至此,我们的Scaled Dot-Product Attention的过程就全部计算完了,来看看代码吧:

with tf.variable_scope("encoder_scaled_dot_product_attention"):encoder_Q = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_Q)encoder_K = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_K)encoder_V = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_V)encoder_Q = tf.reshape(encoder_Q,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))encoder_K = tf.reshape(encoder_K,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))encoder_V = tf.reshape(encoder_V,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))attention_map = tf.matmul(encoder_Q,tf.transpose(encoder_K,[0,2,1]))attention_map = attention_map / 8attention_map = tf.nn.softmax(attention_map)with tf.Session() as sess:sess.run(tf.global_variables_initializer())print(sess.run(attention_map))print(sess.run(encoder_first_sa_output))

第一条数据的attention map为:

图片

第一条数据的输出为:

在这里插入图片描述

可以看到,跟我们通过excel计算得到的输出也是保持一致的。

咱们再通过图片来回顾下Scaled Dot-Product Attention的过程:

图片

图片

2.3 multi-head self attention

Multi-Head Attention就是把Scaled Dot-Product Attention的过程做H次,然后把输出Z合起来。

图片

整个过程图示如下:

图片

这里,我们还是先用excel的过程计算一遍。假设我们刚才计算得到的Q、K、V从中间切分,分别作为两个Head的输入:

图片

重复上面的Scaled Dot-Product Attention过程,我们分别得到两个Head的输出:

图片

接下来,我们需要通过一个权重矩阵,来得到最终输出。

为了我们能够进行后面的Add的操作,我们需要把输出的长度和输入保持一致,即每个单词得到的输出embedding长度保持为4。

同样,我们这里把转换矩阵W设置为常数:

图片

最终,每个单词在经过multi-head attention之后,得到的输出为:

图片

好了,开始写代码吧:

w_Z = tf.constant([[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4]],dtype=tf.float32)with tf.variable_scope("encoder_input"):encoder_embedding_input = tf.nn.embedding_lookup(chinese_embedding,encoder_input)encoder_embedding_input = encoder_embedding_input + position_encodingwith tf.variable_scope("encoder_multi_head_product_attention"):encoder_Q = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_Q)encoder_K = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_K)encoder_V = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_V)encoder_Q = tf.reshape(encoder_Q,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))encoder_K = tf.reshape(encoder_K,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))encoder_V = tf.reshape(encoder_V,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))encoder_Q_split = tf.split(encoder_Q,2,axis=2)encoder_K_split = tf.split(encoder_K,2,axis=2)encoder_V_split = tf.split(encoder_V,2,axis=2)encoder_Q_concat = tf.concat(encoder_Q_split,axis=0)encoder_K_concat = tf.concat(encoder_K_split,axis=0)encoder_V_concat = tf.concat(encoder_V_split,axis=0)attention_map = tf.matmul(encoder_Q_concat,tf.transpose(encoder_K_concat,[0,2,1]))attention_map = attention_map / 8attention_map = tf.nn.softmax(attention_map)weightedSumV = tf.matmul(attention_map,encoder_V_concat)outputs_z = tf.concat(tf.split(weightedSumV,2,axis=0),axis=2)outputs = tf.matmul(tf.reshape(outputs_z,(-1,tf.shape(outputs_z)[2])),w_Z)outputs = tf.reshape(outputs,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))import numpy as np
with tf.Session() as sess:
#     print(sess.run(encoder_Q))
#     print(sess.run(encoder_Q_split))#print(sess.run(weightedSumV))#print(sess.run(outputs_z))print(sess.run(outputs))

结果的输出为:

图片

这里的结果其实和excel是一致的,细小的差异源于excel在复制粘贴过程中,小数点的精度有所损失。

这里我们主要来看下两个函数,分别是split和concat,理解这两个函数的过程对明白上述代码至关重要。

split函数主要有三个参数,第一个是要split的tensor,第二个是分割成几个tensor,第三个是在哪一维进行切分。也就是说, encoder_Q_split = tf.split(encoder_Q,2,axis=2),执行这段代码的话,encoder_Q这个tensor会按照axis=2切分成两个同样大的tensor,这两个tensor的axis=0和axis=1维度的长度是不变的,但axis=2的长度变为了一半,我们在后面通过图示的方式来解释。

从代码可以看到,共有两次split和concat的过程,第一次是将Q、K、V切分为不同的Head:

图片

也就是说,原先每条数据的所对应的各Head的Q并非相连的,而是交替出现的,即 [Head1-Q11,Head1-Q21,Head2-Q12,Head2-Q22]

第二次是最后计算完每个Head的输出Z之后,通过split和concat进行还原,过程如下:

图片

上面的图示咱们将三维矩阵操作抽象成了二维,我加入了axis的说明帮助你理解。如果不懂的话,单步执行下代码就会懂啦。

2.4 Add & Normalize & FFN

后面的过程其实很多简单了,我们继续用excel来表示一下,这里,我们忽略BN的操作(大家可以加上,这里主要是比较麻烦哈哈)

第一次Add & Normalize

图片

接下来是一个FFN,我们仍然假设是固定的参数,那么output是:

图片

第二次Add & Normalize

图片

我们终于在经过一个Encoder的Block后得到了每个输入对应的输出,分别为:

图片

让我们把这段代码补充上去吧:

with tf.variable_scope("encoder_block"):encoder_Q = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_Q)encoder_K = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_K)encoder_V = tf.matmul(tf.reshape(encoder_embedding_input,(-1,tf.shape(encoder_embedding_input)[2])),w_V)encoder_Q = tf.reshape(encoder_Q,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))encoder_K = tf.reshape(encoder_K,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))encoder_V = tf.reshape(encoder_V,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))encoder_Q_split = tf.split(encoder_Q,2,axis=2)encoder_K_split = tf.split(encoder_K,2,axis=2)encoder_V_split = tf.split(encoder_V,2,axis=2)encoder_Q_concat = tf.concat(encoder_Q_split,axis=0)encoder_K_concat = tf.concat(encoder_K_split,axis=0)encoder_V_concat = tf.concat(encoder_V_split,axis=0)attention_map = tf.matmul(encoder_Q_concat,tf.transpose(encoder_K_concat,[0,2,1]))attention_map = attention_map / 8attention_map = tf.nn.softmax(attention_map)weightedSumV = tf.matmul(attention_map,encoder_V_concat)outputs_z = tf.concat(tf.split(weightedSumV,2,axis=0),axis=2)sa_outputs = tf.matmul(tf.reshape(outputs_z,(-1,tf.shape(outputs_z)[2])),w_Z)sa_outputs = tf.reshape(sa_outputs,(tf.shape(encoder_embedding_input)[0],tf.shape(encoder_embedding_input)[1],-1))sa_outputs = sa_outputs + encoder_embedding_input# todo :add BNW_f = tf.constant([[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4]])ffn_outputs = tf.matmul(tf.reshape(sa_outputs,(-1,tf.shape(sa_outputs)[2])),W_f)ffn_outputs = tf.reshape(ffn_outputs,(tf.shape(sa_outputs)[0],tf.shape(sa_outputs)[1],-1))encoder_outputs = ffn_outputs + sa_outputs# todo :add BNimport numpy as np
with tf.Session() as sess:
#     print(sess.run(encoder_Q))
#     print(sess.run(encoder_Q_split))#print(sess.run(weightedSumV))#print(sess.run(outputs_z))#print(sess.run(sa_outputs))#print(sess.run(ffn_outputs))print(sess.run(encoder_outputs))

输出为:

图片

与excel计算结果基本一致。

当然,encoder的各层是可以堆叠的,但我们这里只以单层的为例,重点是理解整个过程。

3、Decoder Block

一个Decoder的Block过程如下:

相比Encoder,这里的过程分为6步,分别是 masked multi-head self attention、Add & Normalize、encoder-decoder attention、Add & Normalize、Feed Forward Network、Add & Normalize。

咱们还是重点来讲masked multi-head self attention和encoder-decoder attention。

3.1 Decoder输入

这里,在excel中,咱们还是以第一条输入为例,来展示整个过程:

[机、器、学、习] -> [ machine、learning]

图片

因此,Decoder阶段的输入是:

图片

对应的代码如下:

english_embedding = tf.constant([[0.51,0.61,0.71,0.81],[0.61,0.71,0.81,0.91],[0.71,0.81,0.91,1.01],[0.81,0.91,1.01,1.11]],dtype=tf.float32)position_encoding = tf.constant([[0.01,0.01,0.01,0.01],[0.02,0.02,0.02,0.02],[0.03,0.03,0.03,0.03],[0.04,0.04,0.04,0.04]],dtype=tf.float32)decoder_input = tf.constant([[1,2],[2,1]],dtype=tf.int32)with tf.variable_scope("decoder_input"):decoder_embedding_input = tf.nn.embedding_lookup(english_embedding,decoder_input)decoder_embedding_input = decoder_embedding_input + position_encoding[0:tf.shape(decoder_embedding_input)[1]]

3.2 masked multi-head self attention

这个过程和multi-head self attention基本一致,只不过对于decoder来说,得到每个阶段的输出时,我们是看不到后面的信息的。举个例子,我们的第一条输入是:[机、器、学、习] -> [ machine、learning] ,decoder阶段两次的输入分别是machine和learning,在输入machine时,我们是看不到learning的信息的,因此在计算attention的权重的时候,machine和learning的权重是没有的。我们还是先通过excel来演示一下,再通过代码来理解:

计算Attention的权重矩阵是:

图片

仍然以两个Head为例,计算Q、K、V:

图片

分别计算两个Head的attention map

图片

咱们先来实现这部分的代码,masked attention map的计算过程:

先定义下权重矩阵,同encoder一样,定义成常数:

w_Q_decoder_sa = tf.constant([[0.15,0.25,0.35,0.45,0.55,0.65],[0.25,0.35,0.45,0.55,0.65,0.75],[0.35,0.45,0.55,0.65,0.75,0.85],[0.45,0.55,0.65,0.75,0.85,0.95]],dtype=tf.float32)w_K_decoder_sa = tf.constant([[0.13,0.23,0.33,0.43,0.53,0.63],[0.23,0.33,0.43,0.53,0.63,0.73],[0.33,0.43,0.53,0.63,0.73,0.83],[0.43,0.53,0.63,0.73,0.83,0.93]],dtype=tf.float32)w_V_decoder_sa = tf.constant([[0.17,0.27,0.37,0.47,0.57,0.67],[0.27,0.37,0.47,0.57,0.67,0.77],[0.37,0.47,0.57,0.67,0.77,0.87],[0.47,0.57,0.67,0.77,0.87,0.97]],dtype=tf.float32)

随后,计算添加mask之前的attention map:

with tf.variable_scope("decoder_sa_block"):decoder_Q = tf.matmul(tf.reshape(decoder_embedding_input,(-1,tf.shape(decoder_embedding_input)[2])),w_Q_decoder_sa)decoder_K = tf.matmul(tf.reshape(decoder_embedding_input,(-1,tf.shape(decoder_embedding_input)[2])),w_K_decoder_sa)decoder_V = tf.matmul(tf.reshape(decoder_embedding_input,(-1,tf.shape(decoder_embedding_input)[2])),w_V_decoder_sa)decoder_Q = tf.reshape(decoder_Q,(tf.shape(decoder_embedding_input)[0],tf.shape(decoder_embedding_input)[1],-1))decoder_K = tf.reshape(decoder_K,(tf.shape(decoder_embedding_input)[0],tf.shape(decoder_embedding_input)[1],-1))decoder_V = tf.reshape(decoder_V,(tf.shape(decoder_embedding_input)[0],tf.shape(decoder_embedding_input)[1],-1))decoder_Q_split = tf.split(decoder_Q,2,axis=2)decoder_K_split = tf.split(decoder_K,2,axis=2)decoder_V_split = tf.split(decoder_V,2,axis=2)decoder_Q_concat = tf.concat(decoder_Q_split,axis=0)decoder_K_concat = tf.concat(decoder_K_split,axis=0)decoder_V_concat = tf.concat(decoder_V_split,axis=0)decoder_sa_attention_map_raw = tf.matmul(decoder_Q_concat,tf.transpose(decoder_K_concat,[0,2,1]))decoder_sa_attention_map = decoder_sa_attention_map_raw / 8

随后,对attention map添加mask:

diag_vals = tf.ones_like(decoder_sa_attention_map[0,:,:])
tril = tf.contrib.linalg.LinearOperatorTriL(diag_vals).to_dense()
masks = tf.tile(tf.expand_dims(tril,0),[tf.shape(decoder_sa_attention_map)[0],1,1])
paddings = tf.ones_like(masks) * (-2 ** 32 + 1)
decoder_sa_attention_map = tf.where(tf.equal(masks,0),paddings,decoder_sa_attention_map)
decoder_sa_attention_map = tf.nn.softmax(decoder_sa_attention_map)

这里我们首先构造一个全1的矩阵diag_vals,这个矩阵的大小同attention map。随后通过tf.contrib.linalg.LinearOperatorTriL方法把上三角部分变为0,该函数的示意如下:

图片

基于这个函数生成的矩阵tril,我们便可以构造对应的mask了。不过需要注意的是,对于我们要加mask的地方,不能赋值为0,而是需要赋值一个很小的数,这里为-2^32 + 1。因为我们后面要做softmax,e^0=1,是一个很大的数啦。

运行上面的代码:

import numpy as np
with tf.Session() as sess:print(sess.run(decoder_sa_attention_map))

观察第一条数据对应的结果如下:

图片

与我们excel计算结果相吻合。

后面的过程我们就不详细介绍了,我们直接给出经过masked multi-head self attention的对应结果:

图片

对应的代码如下:

weightedSumV = tf.matmul(decoder_sa_attention_map,decoder_V_concat)decoder_outputs_z = tf.concat(tf.split(weightedSumV,2,axis=0),axis=2)decoder_sa_outputs = tf.matmul(tf.reshape(decoder_outputs_z,(-1,tf.shape(decoder_outputs_z)[2])),w_Z_decoder_sa)decoder_sa_outputs = tf.reshape(decoder_sa_outputs,(tf.shape(decoder_embedding_input)[0],tf.shape(decoder_embedding_input)[1],-1))with tf.Session() as sess:print(sess.run(decoder_sa_outputs))

输出为:

图片

与excel保持一致!

3.3 encoder-decoder attention

在encoder-decoder attention之间,还有一个Add & Normalize的过程,同样,我们忽略 Normalize,只做Add操作:

图片

接下来,就是encoder-decoder了,这里跟multi-head attention相同,但是需要注意的一点是,我们这里想要做的是,计算decoder的每个阶段的输入和encoder阶段所有输出的attention,所以Q的计算通过decoder对应的embedding计算,而K和V通过encoder阶段输出的embedding来计算:

图片

接下来,计算Attention Map,注意,这里attention map的大小为2 * 4的,每一行代表一个decoder的输入,与所有encoder输出之间的attention score。同时,我们不需要添加mask,因为decoder的输入是可以看到所有encoder的输出信息的。得到的attention map结果如下:

图片

哈哈,这里数是我瞎写的,结果不太好,不过不影响对整个过程的理解。

接下来,我们得到整个encoder-decoder阶段的输出为:

图片

接下来,还有Add & Normalize、Feed Forward Network、Add & Normalize过程,咱们这里就省略了。直接上代码吧:

w_Q_decoder_sa2 = tf.constant([[0.2,0.3,0.4,0.5,0.6,0.7],[0.3,0.4,0.5,0.6,0.7,0.8],[0.4,0.5,0.6,0.7,0.8,0.9],[0.5,0.6,0.7,0.8,0.9,1]],dtype=tf.float32)w_K_decoder_sa2 = tf.constant([[0.18,0.28,0.38,0.48,0.58,0.68],[0.28,0.38,0.48,0.58,0.68,0.78],[0.38,0.48,0.58,0.68,0.78,0.88],[0.48,0.58,0.68,0.78,0.88,0.98]],dtype=tf.float32)w_V_decoder_sa2 = tf.constant([[0.22,0.32,0.42,0.52,0.62,0.72],[0.32,0.42,0.52,0.62,0.72,0.82],[0.42,0.52,0.62,0.72,0.82,0.92],[0.52,0.62,0.72,0.82,0.92,1.02]],dtype=tf.float32)w_Z_decoder_sa2 = tf.constant([[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4],[0.1,0.2,0.3,0.4]],dtype=tf.float32)with tf.variable_scope("decoder_encoder_attention_block"):decoder_sa_outputs = decoder_sa_outputs + decoder_embedding_inputencoder_decoder_Q = tf.matmul(tf.reshape(decoder_sa_outputs,(-1,tf.shape(decoder_sa_outputs)[2])),w_Q_decoder_sa2)encoder_decoder_K = tf.matmul(tf.reshape(encoder_outputs,(-1,tf.shape(encoder_outputs)[2])),w_K_decoder_sa2)encoder_decoder_V = tf.matmul(tf.reshape(encoder_outputs,(-1,tf.shape(encoder_outputs)[2])),w_V_decoder_sa2)encoder_decoder_Q = tf.reshape(encoder_decoder_Q,(tf.shape(decoder_embedding_input)[0],tf.shape(decoder_embedding_input)[1],-1))encoder_decoder_K = tf.reshape(encoder_decoder_K,(tf.shape(encoder_outputs)[0],tf.shape(encoder_outputs)[1],-1))encoder_decoder_V = tf.reshape(encoder_decoder_V,(tf.shape(encoder_outputs)[0],tf.shape(encoder_outputs)[1],-1))encoder_decoder_Q_split = tf.split(encoder_decoder_Q,2,axis=2)encoder_decoder_K_split = tf.split(encoder_decoder_K,2,axis=2)encoder_decoder_V_split = tf.split(encoder_decoder_V,2,axis=2)encoder_decoder_Q_concat = tf.concat(encoder_decoder_Q_split,axis=0)encoder_decoder_K_concat = tf.concat(encoder_decoder_K_split,axis=0)encoder_decoder_V_concat = tf.concat(encoder_decoder_V_split,axis=0)encoder_decoder_attention_map_raw = tf.matmul(encoder_decoder_Q_concat,tf.transpose(encoder_decoder_K_concat,[0,2,1]))encoder_decoder_attention_map = encoder_decoder_attention_map_raw / 8encoder_decoder_attention_map = tf.nn.softmax(encoder_decoder_attention_map)weightedSumV = tf.matmul(encoder_decoder_attention_map,encoder_decoder_V_concat)encoder_decoder_outputs_z = tf.concat(tf.split(weightedSumV,2,axis=0),axis=2)encoder_decoder_outputs = tf.matmul(tf.reshape(encoder_decoder_outputs_z,(-1,tf.shape(encoder_decoder_outputs_z)[2])),w_Z_decoder_sa2)encoder_decoder_attention_outputs = tf.reshape(encoder_decoder_outputs,(tf.shape(decoder_embedding_input)[0],tf.shape(decoder_embedding_input)[1],-1))encoder_decoder_attention_outputs = encoder_decoder_attention_outputs + decoder_sa_outputs# todo :add BNW_f = tf.constant([[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4]])decoder_ffn_outputs = tf.matmul(tf.reshape(encoder_decoder_attention_outputs,(-1,tf.shape(encoder_decoder_attention_outputs)[2])),W_f)decoder_ffn_outputs = tf.reshape(decoder_ffn_outputs,(tf.shape(encoder_decoder_attention_outputs)[0],tf.shape(encoder_decoder_attention_outputs)[1],-1))decoder_outputs = decoder_ffn_outputs + encoder_decoder_attention_outputs# todo :add BNwith tf.Session() as sess:print(sess.run(decoder_outputs))

4、全连接层及最终输出

最后的全连接层很简单了,对于decoder阶段的输出,通过全连接层和softmax之后,最终得到选择每个单词的概率,并计算交叉熵损失:

图片

这里,我们直接给出代码:

W_final = tf.constant([[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4],[0.2,0.3,0.5,0.4]])logits = tf.matmul(tf.reshape(decoder_outputs,(-1,tf.shape(decoder_outputs)[2])),W_final)
logits = tf.reshape(logits,(tf.shape(decoder_outputs)[0],tf.shape(decoder_outputs)[1],-1))logits = tf.nn.softmax(logits)y = tf.one_hot(decoder_input,depth=4)loss = tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=y)train_op = tf.train.AdamOptimizer(learning_rate=0.0001).minimize(loss)

整个文章下来,咱们不仅通过excel实现了一遍transorform的正向传播过程,还通过tf代码实现了一遍。放两张excel的抽象图,就知道是多么浩大的工程了:

图片

图片

好了,文章最后,咱们再来回顾一下整个Transformer的结构:

图片

希望通过本文,你能够对Transformer的整体结构有个更清晰的认识!

如何学习AI大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

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

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/65268.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智慧楼盘二维、三维组件融合 720三维全景可视化

本系统通过数字孪生技术,实现小区楼盘系统的可视化展示,整合楼盘内各个系统的数据源,将楼盘模型与房间模型、720三维全景图相结合,实现了从楼盘周边到室内布局的全方位展示,为购房者提供全方位的可视化信息。 整个项目…

QT QCombox QSS样式问题

/*combobox 样式*/ QComboBox#FileterComboBox,QComboBox#DateRangeComboBox{background-color: #262626; /* 背景颜色 */color: #e0e0e0; /* 文本颜色 */border-radius:16px;font-family: "Microsoft YaHei"; /* 文本字体族 */font-size: 18px; /* 文…

Unittest02|TestSuite、TestRunner、HTMLTestRunner、处理excel表数据、邮件接收测试结果

目录 八、测试套件TestSuite和测试运行器TestRunner 1、基本概念 2、创建和使用测试套件 3、 自动发现测试用例、创建测试套件、运行测试 4、生成html的测试报告:HTMLTestRunner 1️⃣导入HTMLTestRunner模块 2️⃣运行测试用例并生成html文件 九、unittest…

NIPS2014 | GAN: 生成对抗网络

Generative Adversarial Nets 摘要-Abstract引言-Introduction相关工作-Related Work对抗网络-Adversarial Nets理论结果-Theoretical Results实验-Experiments优势和不足-Advantages and disadvantages缺点优点 结论及未来工作-Conclusions and future work研究总结未来研究方…

【已解决】pyinstaller打包ico图片报错:OSError: [WinError 225] 无法成功完成操作,因为文件包含病毒或潜在的垃圾软件。

起因: pyinstaller加上 --icon 参数打包时报错。 命令如下: 解决: 关闭 Windows 的病毒防护即可,步骤如下。 点屏幕右下角通知栏,进入“病毒和威胁防护”: 打开: 关闭实时保护&#xff08…

011-spring-整合三方框架的命名空间原理(重要)

根据context标签来学习了解 <context:property-placeholder location"jdbc.properties"/> <bean id"dataSource" class"com.alibaba.druid.pool.DruidDataSource"><property name"driver" value"${db.driver}&quo…

No.29 笔记 | CTF 学习干货

大家好呀&#xff01;我刚参加了美国线上CTF比赛&#xff0c;收获超多&#xff0c;特别感谢老师教我的干货知识。今天就和大家分享我的学习笔记。CTF像刺激冒险&#xff0c;有挑战有惊喜。 学习中我懂了很多知识技能&#xff0c;像密码学、Web安全、Misc题型等&#xff0c;它们…

sonarqube 安装及使用

一、官网参考地址 相关版本下载地址 配置全局变量 .bash_profileexport SONAR_HOME=/Users/jd/soft/sonar-scanner-6.2.1.4610 export PATH=$PATH:$SONAR_HOME/bin export SQ_HOST=http://127.0.0.1:9000/ export SQ_TOKEN=squ_dbb1913e095a92a727a918a9ba6b1af94b007748二、…

使用ArcGIS/ArcGIS pro绘制六边形/三角形/菱形渔网图

在做一些尺度分析时&#xff0c;经常会涉及到对研究区构建不同尺度的渔网进行分析&#xff0c;渔网的形状通常为规则四边形。构建渔网的方法也很简单&#xff0c;使用ArcGIS/ArcGIS Pro工具箱中的【创建渔网/CreateFishnet】工具来构建。但如果想构建其他形状渔网进行相关分析&…

pytorch MoE(专家混合网络)的简单实现。

专家混合&#xff08;Mixture of Experts, MoE&#xff09;是一种深度学习模型架构&#xff0c;通常用于处理大规模数据和复杂任务。它通过将输入分配给多个专家网络&#xff08;即子模型&#xff09;&#xff0c;然后根据门控网络&#xff08;gating network&#xff09;的输出…

NAT 技术如何解决 IP 地址短缺问题?

NAT 技术如何解决 IP 地址短缺问题&#xff1f; 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 随着互联网的普及和发展&#xff0c;IP 地址的需求量迅速增加。尤其是 IPv4 地址&…

华为麦芒5(安卓6)termux记录 使用ddns-go,alist

下载0.119bate1版,不能换源,其他源似乎都用不了,如果root可以直接用面具模块 https://github.com/termux/termux-app/releases/download/v0.119.0-beta.1/termux-app_v0.119.0-beta.1apt-android-5-github-debug_arm64-v8a.apk 安装ssh(非必要) pkg install openssh开启ssh …

FPC在蓝牙耳机中有哪些应用?【新立电子】

随着科技的进步和消费者需求的提升&#xff0c;耳机已经从传统的有线连接转变为现在的无线蓝牙耳机&#xff0c;真正做到了便捷出行与极佳的用户体验。而FPC在蓝牙耳机中的应用主要体现在优化耳机的设计与性能上。 蓝牙耳机&#xff0c;主要使用方式是与手机、电脑等移动设备通…

《计算机组成及汇编语言原理》阅读笔记:p121-p122

《计算机组成及汇编语言原理》学习第 8 天&#xff0c;p121-p122 总结&#xff0c;总计 2 页。 一、技术总结 1.memory优化 (1)cache memory remove blank from “Most computers support two different kinds (levels) of cache: level one (L1) cache is built into the …

ffmpeg: stream_loop报错 Error while filtering: Operation not permitted

问题描述 执行ffmpeg命令的时候&#xff0c;报错&#xff1a;Error while filtering: Operation not permitted 我得命令如下 ffmpeg -framerate 25 -y -i /data/workerspace/mtk/work_home/mtk_202406111543-l9CSU91H1f1b3/tmp/%08d.png -stream_loop -1 -i /data/workerspa…

【微信小程序】1|底部图标 | 我的咖啡店-综合实训

底部图标 引言 在微信小程序开发中&#xff0c;底部导航栏&#xff08;tabBar&#xff09;是用户界面的重要组成部分&#xff0c;它为用户提供了快速切换不同页面的功能。今天&#xff0c;我们将通过一个实际案例——“我的咖啡店”小程序&#xff0c;来详细解析如何配置底部图…

c++编译过程初识

编译过程 预处理&#xff1a;主要是执行一些预处理指令&#xff0c;主要是#开头的代码&#xff0c;如#include 的头文件、#define 定义的宏常量、#ifdef #ifndef #endif等条件编译的代码&#xff0c;具体包括查找头文件、进行宏替换、根据条件编译等操作。 g -E example.cpp -…

Springboot高并发乐观锁

Spring Boot分布式锁的主要缺点包括但不限于以下几点&#xff1a; 性能开销&#xff1a;使用分布式锁通常涉及到网络通信&#xff0c;这会引入额外的延迟和性能开销。例如&#xff0c;当使用Redis或Zookeeper实现分布式锁时&#xff0c;每次获取或释放锁都需要与这些服务进行交…

揭秘 Fluss 架构组件

这是 Fluss 系列的第四篇文章了&#xff0c;我们先回顾一下前面三篇文章主要说了哪些内容。 Fluss 部署&#xff0c;带领大家部署Fluss 环境&#xff0c;体验一下 Fluss 的功能Fluss 整合数据湖的操作&#xff0c;体验Fluss 与数据湖的结合讲解了 Fluss、Kafka、Paimon 之间的…

leetcode82:删除链表中的重复元素II

原题地址&#xff1a;82. 删除排序链表中的重复元素 II - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&…