hidden_size: int. Hidden size of the Transformer.
num_hidden_layers: int. Number of layers (blocks) in the Transformer.
num_attention_heads: int. Number of attention heads in the Transformer.
中间层大小 , 中间层的激活函数,隐藏层的丢弃比例,注意力概率层的丢弃比例
intermediate_size: int. The size of the "intermediate" (a.k.a., feed
forward) layer.
intermediate_act_fn: function. The non-linear activation function to apply
to the output of the intermediate/feed-forward layer.
hidden_dropout_prob: float. Dropout probability for the hidden layers.
attention_probs_dropout_prob: float. Dropout probability of the attention
probabilities.
截断的标准正太分布的标准差,
也就是权重参数初始化的数值范围(超出该范围的会被截断)
initializer_range: float. Range of the initializer (stddev of truncated
normal).
是否要求返回所有的层,还是返回最后一层
do_return_all_layers: Whether to also return all layers or just the final
layer.
Returns: 返回值,一个张量 , Transformer模型中的最后一个隐藏层
float Tensor of shape [batch_size, seq_length, hidden_size], the final
hidden layer of the Transformer.
Raises: 异常 无效的形状或参数值
ValueError: A Tensor shape or parameter is invalid.
"""
if hidden_size % num_attention_heads != 0:
如果隐藏的大小不能整除注意力头数,就触发异常
raise ValueError(
"The hidden size (%d) is not a multiple of the number of attention "
"heads (%d)" % (hidden_size, num_attention_heads))
attention_head_size = int(hidden_size / num_attention_heads)
input_shape = get_shape_list(input_tensor, expected_rank=3)
batch_size = input_shape[0]
seq_length = input_shape[1]
input_width = input_shape[2]
Transformer 需要对残差进行求和计算 , 所以 所需的参数和隐藏层相同
# The Transformer performs sum residuals on all layers so the input needs
# to be the same as the hidden size.
if input_width != hidden_size: 参数尺寸不一致,就报错
raise ValueError("The width of the input tensor (%d) != hidden size (%d)" %
(input_width, hidden_size))
我们始终使用2D张量 , 避免来回的变形;
矩阵变形对于GPU和CPU是很简单的,但是对于TPU就有点麻烦了,
所以要减少这么不必要的转换带来的计算量,从而提高模型效率;
# We keep the representation as a 2D tensor to avoid re-shaping it back and
# forth from a 3D tensor to a 2D tensor. Re-shapes are normally free on
# the GPU/CPU but may not be free on the TPU, so we want to minimize them to
# help the optimizer.
将输入的张量转换为2D矩阵
prev_output = reshape_to_matrix(input_tensor)
all_layer_outputs = [] 定义所有的输出层
variable_scope()是作用域,和tf.get_variable()搭配使用
variable_scope也是个作为上下文管理器的角色,
下文管理器:意思就是 , 在这个管理器下做的事情,会被这个管理器管着 。
variable_scope 主要是因为 变量共享 的需求 。
for layer_idx in range(num_hidden_layers): 遍历所有的层
with tf.variable_scope("layer_%d" % layer_idx):
layer_input = prev_output 输入就是原先的输出
with tf.variable_scope("attention"):
attention_heads = [] 定义注意力头的集合
with tf.variable_scope("self"):
attention_head = attention_layer( 每个注意力头就是一个注意力层
from_tensor=layer_input, 源矩阵和目标矩阵相同 , 也就是自己注意自己
to_tensor=layer_input,
attention_mask=attention_mask, 注意力掩码
num_attention_heads=num_attention_heads, 头数
size_per_head=attention_head_size, 每头的大小
attention_probs_dropout_prob=attention_probs_dropout_prob, 注意力数据丢弃比例
initializer_range=initializer_range, 数据初始化范围,也就是标准差
do_return_2d_tensor=True, 是否要求返回2D张量
batch_size=batch_size, 批处理量
from_seq_length=seq_length, 源序列长度
to_seq_length=seq_length) 目标序列长度
attention_heads.append(attention_head) 将生成的头【矩阵】添加到集合中
attention_output = None
if len(attention_heads) == 1: 如果只有一头,则输出就是这一头
attention_output = attention_heads[0]
else: 如果有好多头
有多头的情况下,我们将他们连接起来,然后再投影;
推荐阅读
- 【lwip】11-UDP协议&源码分析
- 硬核剖析Java锁底层AQS源码,深入理解底层架构设计
- SpringCloudAlibaba 微服务组件 Nacos 之配置中心源码深度解析
- Seata 1.5.2 源码学习
- MindStudio模型训练场景精度比对全流程和结果分析
- .NET 源码学习 [数据结构-线性表1.2] 链表与 LinkedList<T>
- Redisson源码解读-公平锁
- OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py
- 【深入浅出 Yarn 架构与实现】1-2 搭建 Hadoop 源码阅读环境
- JVM学习笔记——内存模型篇