[1]提到,所谓的"门"就是那个乘法单元

[2]总的图如下:

#-------------------------------------------------------------------------------
那么神经网络中,LSTM上方到底接什么呢?
根据[10]可以是:

可以接Mean pooling
也可以根据<Python深度学习>
直接在上方接个Dense(1)完事:
model.add(layers.Dense(1))
#-------------------------------------------------------------------------------

图上的标示解释如下:

标记 含义
乘以一个因子
两路进行计算
其中一路的数据
两路做点积运算+偏置
把相同的结果传给两路

#-------------------------------------------------------------------------------
什么是门?
根据[3]定义:
Gates are a way to optionally let information through. They are composed out of a sigmoid neural net layer and a pointwise multiplication operation.

常说的三个门如下(红色圈圈内部):

#-------------------------------------------------------------------------------
上图以及本文的公式其实来自[3]
LSTM是复杂版本的RNN
内部对应的公式如下:

ft=σ(Wf⋅[ht−1,xt]+bf)f_t=\sigma(W_f·[h_{t-1},x_t]+b_f)ft=σ(Wf[ht1,xt]+bf)(遗忘门)
it=σ(Wi⋅[ht−1,xt]+bi)i_t=\sigma(W_i·[h_{t-1},x_t]+b_i)it=σ(Wi[ht1,xt]+bi)(输入门/写门)
Ct~=tanh⁡(WC⋅[ht−1,xt]+bC)\widetilde{C_t}=\tanh(W_C·[h_{t-1},x_t]+b_C)Ct

=tanh(WC[ht1,xt]+bC)
Ct=ft∗Ct−1+it∗Ct~C_t=f_t*C_{t-1}+i_t*\widetilde{C_t}Ct=ftCt1+itCt


ot=σ(Wo[ht−1,xt]+bo)o_t=\sigma(W_o[h_{t-1},x_t]+b_o)ot=σ(Wo[ht1,xt]+bo)(输出门/读门)
ht=ot∗tanh(Ct)h_t=o_t*tanh(C_t)ht=ottanh(Ct)
在英文文献中,CtC_tCt叫做carry track
把这些式子一个个对上面的图中对应就行了
上面的对门的定义来自[5]
其中σ\sigmaσ是sigmoid函数。
门的本质是什么?
[8]本质其实是单层神经网络,所以LSTM被训练的时候,门也是被训练对象,所以上图中其实有四个被训练的神经网络。训练LSTM其实训练的是西面的红色部分(WfW_fWf,WiW_iWi,WCW_CWC,WoW_oWo)

根据最新研究[9]显示:
除了遗忘门,其他两个门可以删除,效果更好。
所以别尴尬地去理解门有啥用了。
#-------------------------------------------------------------------------------
什么是state,什么是output?在图中的哪里?
根据[6]:
state是CtC_tCt
output是hth_tht
#-------------------------------------------------------------------------------
用到的tanh和sigmoid函数的区别

激活函数 表达式 区间 函数曲线
tanh(x) ex−e−xex+e−x\frac{e^x-e^{-x}}{e^x+e^{-x}}ex+exexex (-1,1)
sigmoid(x) 11+e−x\frac{1}{1+e^{-x}}1+ex1 (0,1)

#-------------------------------------------------------------------------------
何时决定遗忘,何时决定保留信息?

#-------------------------------------------------------------------------------
LSTM源码解读,来自[11]:

RNN 关键代码:
@tf_export("nn.rnn_cell.BasicRNNCell")
class BasicRNNCell(LayerRNNCell):"""The most basic RNN cell.Args:num_units: int, The number of units in the RNN cell.activation: Nonlinearity to use.  Default: `tanh`.reuse: (optional) Python boolean describing whether to reuse variablesin an existing scope.  If not `True`, and the existing scope already hasthe given variables, an error is raised.name: String, the name of the layer. Layers with the same name willshare weights, but to avoid mistakes we require reuse=True in suchcases.dtype: Default dtype of the layer (default of `None` means use the typeof the first input). Required when `build` is called before `call`."""def __init__(self,num_units,activation=None,reuse=None,name=None,dtype=None):super(BasicRNNCell, self).__init__(_reuse=reuse, name=name, dtype=dtype)# Inputs must be 2-dimensional.self.input_spec = base_layer.InputSpec(ndim=2)self._num_units = num_unitsself._activation = activation or math_ops.tanh@propertydef state_size(self):return self._num_units@propertydef output_size(self):return self._num_unitsdef build(self, inputs_shape):if inputs_shape[1].value is None:raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s"% inputs_shape)input_depth = inputs_shape[1].value# 初始化生成 W 和 B,shape 大小为# W: [input_size + Hidden_size, Hidden_size)# B: [Hidden_size]self._kernel = self.add_variable(_WEIGHTS_VARIABLE_NAME,shape=[input_depth + self._num_units, self._num_units])self._bias = self.add_variable(_BIAS_VARIABLE_NAME,shape=[self._num_units],initializer=init_ops.zeros_initializer(dtype=self.dtype))self.built = True# 循环该函数 num_step(句子长度) 次,则该层计算完;def call(self, inputs, state):"""Most basic RNN: output = new_state = act(W * input + U * state + B)."""# output = Ht = tanh([x,Ht-1]*W + B)# 如果是第 0 时刻,那么当前的 state(即上一时刻的输出H0)的值全部为0;# input 的 shape为: [batch_size,emb_size]# state 的 shape为:[batch_zize,Hidden_size]# matmul : 矩阵相乘# array_ops.concat: 两个矩阵连接,连接后的 shape 为 [batch_size,input_size + Hidden_size],实际就是[Xt,Ht-1]# 此时计算: [input,state] * [W,U] == [Xt,Ht-1] * W,得到的shape为:[batch_size,Hidden_size]gate_inputs = math_ops.matmul(array_ops.concat([inputs, state], 1), self._kernel)# B 的shape 为:【Hidden_size】,[Xt,Ht-1] * W 计算后的shape为:[batch_size,Hidden_size]# nn_ops.bias_add,这个函数的计算方法是,让每个 batch 得到的值,都加上这个 B;# 这一步,加上B后:Ht = tanh([Xt,Ht-1] * W + B),得到的 shape 还是: [batch_size,Hidden_size]# 那么这个 Ht 将作为下一时刻的输入和下一层的输入;gate_inputs = nn_ops.bias_add(gate_inputs, self._bias)output = self._activation(gate_inputs)#此时return的维度为:[batch_size,Hidden_size]# 一个output作为下一时刻的输入Ht,另一个作为下一层的输入 Htreturn output, outputLSTM 关键代码:@tf_export("nn.rnn_cell.BasicLSTMCell")
class BasicLSTMCell(LayerRNNCell):"""Basic LSTM recurrent network cell.The implementation is based on: http://arxiv.org/abs/1409.2329.We add forget_bias (default: 1) to the biases of the forget gate in order toreduce the scale of forgetting in the beginning of the training.It does not allow cell clipping, a projection layer, and does notuse peep-hole connections: it is the basic baseline.For advanced models, please use the full @{tf.nn.rnn_cell.LSTMCell}that follows."""def __init__(self,num_units,forget_bias=1.0,state_is_tuple=True,activation=None,reuse=None,name=None,dtype=None):"""Initialize the basic LSTM cell.Args:num_units: int, The number of units in the LSTM cell.forget_bias: float, The bias added to forget gates (see above).Must set to `0.0` manually when restoring from CudnnLSTM-trainedcheckpoints.state_is_tuple: If True, accepted and returned states are 2-tuples ofthe `c_state` and `m_state`.  If False, they are concatenatedalong the column axis.  The latter behavior will soon be deprecated.activation: Activation function of the inner states.  Default: `tanh`.reuse: (optional) Python boolean describing whether to reuse variablesin an existing scope.  If not `True`, and the existing scope already hasthe given variables, an error is raised.name: String, the name of the layer. Layers with the same name willshare weights, but to avoid mistakes we require reuse=True in suchcases.dtype: Default dtype of the layer (default of `None` means use the typeof the first input). Required when `build` is called before `call`.When restoring from CudnnLSTM-trained checkpoints, must use`CudnnCompatibleLSTMCell` instead."""super(BasicLSTMCell, self).__init__(_reuse=reuse, name=name, dtype=dtype)if not state_is_tuple:logging.warn("%s: Using a concatenated state is slower and will soon be ""deprecated.  Use state_is_tuple=True.", self)# Inputs must be 2-dimensional.self.input_spec = base_layer.InputSpec(ndim=2)self._num_units = num_unitsself._forget_bias = forget_biasself._state_is_tuple = state_is_tupleself._activation = activation or math_ops.tanh@propertydef state_size(self):# 隐藏层的 size:return (LSTMStateTuple(self._num_units, self._num_units)if self._state_is_tuple else 2 * self._num_units)@propertydef output_size(self):# 输出层的size:Hidden_sizereturn self._num_unitsdef build(self, inputs_shape):if inputs_shape[1].value is None:raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s"% inputs_shape)#inputs的维度为:[batch_size,input_size]#如果是第一层每个时刻词语的输入,则这个input_size 就是 embedding_size,就等于词向量的维度;# 所以 此时 input_depth,就是input_sizeinput_depth = inputs_shape[1].value# h_depth 就是 Hidden_size,隐藏层的维度h_depth = self._num_units# self._kernel == W;则此时 W的维度 为【input_size + Hidden_size,4* Hidden_size】# 此处定义四个 W 和 B,是为了,一次就把 i,j,f,o 计算出来;相当于图中的 ft,it,ct‘,otself._kernel = self.add_variable(_WEIGHTS_VARIABLE_NAME,shape=[input_depth + h_depth, 4 * self._num_units])# 此时的B的维度为【4 * Hidden_size】self._bias = self.add_variable(_BIAS_VARIABLE_NAME,shape=[4 * self._num_units],initializer=init_ops.zeros_initializer(dtype=self.dtype))self.built = Truedef call(self, inputs, state):"""Long short-term memory cell (LSTM).Args:inputs: `2-D` tensor with shape `[batch_size, input_size]`.state: An `LSTMStateTuple` of state tensors, each shaped`[batch_size, num_units]`, if `state_is_tuple` has been set to`True`.  Otherwise, a `Tensor` shaped`[batch_size, 2 * num_units]`.Returns:A pair containing the new hidden state, and the new state (either a`LSTMStateTuple` or a concatenated state, depending on`state_is_tuple`)."""sigmoid = math_ops.sigmoidone = constant_op.constant(1, dtype=dtypes.int32)# Parameters of gates are concatenated into one multiply for efficiency.# 每一层的第0时刻的 c 和 h,元素全部初始化为0;if self._state_is_tuple:c, h = stateelse:c, h = array_ops.split(value=state, num_or_size_splits=2, axis=one)# 此时刻的 input:Xt 和 上一时刻的输出:Ht-1,进行结合;# inputs shape : [batch_size,input_size],第一层的时候,input_size,就相当于 embedding_size# 结合后的维度为【batch_size,input_size + Hidden_size】,W的维度为【input_size + Hidden_size,4*hidden_size】# 两者进行矩阵相乘后的维度为:【batch_size,4*hidden_size】gate_inputs = math_ops.matmul(array_ops.concat([inputs, h], 1), self._kernel)# B 的shape 为:【4 * Hidden_size】,[Xt,Ht-1] * W 计算后的shape为:[batch_size, 4 * Hidden_size]# nn_ops.bias_add,这个函数的计算方法是,让每个 batch 得到的值,都加上这个 B;# 这一步,加上B后,得到的是,i,j,f,o 的结合, [Xt,Ht-1] * W + B,得到的 shape 还是: [batch_size, 4 * Hidden_size]#  加上偏置B后的维度为:【batch_size,4 * Hidden_size】gate_inputs = nn_ops.bias_add(gate_inputs, self._bias)# i = input_gate, j = new_input, f = forget_gate, o = output_gate# 从以上的矩阵相乘后,分割出来四部分,就是 i,j,f,o的值;# 每个的维度为【batch_size,Hidden_size】i, j, f, o = array_ops.split(value=gate_inputs, num_or_size_splits=4, axis=one)forget_bias_tensor = constant_op.constant(self._forget_bias, dtype=f.dtype)# Note that using `add` and `multiply` instead of `+` and `*` gives a# performance improvement. So using those at the cost of readability.add = math_ops.add# 此处加上遗忘的 bias,选择遗忘元素;# 以下计算是:对应元素相乘:因为四个参数的维度都是【batch_size,hidden_size】,计算后维度不变;# new_c = c*sigmoid(f+bias) + sigmoid(i)*tanh(o)# 计算后的维度为【batch_size,hidden_size】multiply = math_ops.multiplynew_c = add(multiply(c, sigmoid(add(f, forget_bias_tensor))),multiply(sigmoid(i), self._activation(j)))# 以下计算是:对应元素相乘:因为2个参数的维度都是【batch_size,hidden_size】,计算后维度不变;#new_h = sigmoid(o) * tanh(new_c)new_h = multiply(self._activation(new_c), sigmoid(o))# 计算后的维度是(值不相等):new_c == new_h == 【batch_size,hidden_size】if self._state_is_tuple:new_state = LSTMStateTuple(new_c, new_h)else:new_state = array_ops.concat([new_c, new_h], 1)# new_h:最后一个时刻的H,new_state:最后一个时刻的 H和C;循环执行该函数,执行 num_step次(即 最大的步长),则该层计算完全;# 此时的 new_c 和 new_h,作为下一时刻的输入,new_h 和下一时刻的,Xt+1 进行连接,连接后的维度为,【batch_size,input_size + Hidden_size】# 如果还有下一层的话,那么此刻的 new_h,变身为下一时刻的 Xtreturn new_h, new_state

#-------------------------------------------------------------------------------
LSTM的维度如何理解?来自[11]:

#-------------------------------------------------------------------------------
梯度问题可以参考[13]
#-------------------------------------------------------------------------------
当前最好的RNN单元单元是什么呢?
根据[12],是transformer
#-------------------------------------------------------------------------------

Reference:

[1]学界|神奇!只有遗忘门的LSTM性能优于标准LSTM
[2]LSTM入门总结
[3]Understanding LSTM Networks
[4]How is the LSTM RNN forget gate calculated?
[5]How the LSTM decides when to store long information, short information or reset information?
[6]What is the difference between states and outputs in LSTM?
[7]LSTM的参数问题?
[8]LSTM 如何决定「遗忘」?
[9]The unreasonable effectiveness of the forget gate
[10]LSTM源码分析
[11]tensorflow 笔记8:RNN、Lstm源码,训练代码输入输出,维度分析
[12]LSTM与GRU
[13]How LSTM networks solve the problem of vanishing gradients

LSTM原理解读汇总相关推荐

  1. SDM原理解读与工程实践

    SDM原理解读与工程实践 本文主要介绍的是阿里在召回阶段使用的深度召回模型SDM,paper名称为<SDM: Sequential Deep Matching Model for Online ...

  2. 约2万字-Vue源码解读汇总篇(续更)

    约2万字-Vue源码解读汇总篇(续更) 一.前言 1.系列汇总 未完待续... Vue源码解读:06Vue3探索篇 Vue源码解读:05生命周期篇 Vue源码解读:04模板编译篇 Vue源码解读:03 ...

  3. ORB算法原理解读【不错】

    ORB算法原理解读        这篇写得很好 ORB特征提取.匹配及位置估计   里面对匹配的讲解比较好 两个不同二进制之间的汉明距离指的是两个二进制串不同位的个数.两个二进制不同位的个数是越少越好 ...

  4. mysql引擎层存储层_MySQL存储底层技术:InnoDB底层原理解读

    原标题:MySQL存储底层技术:InnoDB底层原理解读 存储引擎 很多文章都是直接开始介绍有哪些存储引擎,并没有去介绍存储引擎本身.那么究竟什么是存储引擎?不知道大家有没有想过,MySQL是如何存储 ...

  5. Asp.Net Core EndPoint 终结点路由工作原理解读

    Asp.Net Core EndPoint 终点路由工作原理解读 一.背景 在本打算写一篇关于Identityserver4 的文章时候,却发现自己对EndPoint -终结点路由还不是很了解,故暂时 ...

  6. lstm原理及实现_LSTM原理

    引自LSTM原理与实践,原来如此简单 一.介绍 1.1 LSTM介绍 LSTM全称Long Short-Term Memory,是1997年就被发明出来的算法. 经过这么多年的发展,基本上没有什么理论 ...

  7. 计算机顶会论文多少钱,计算机视觉顶会文章的解读汇总(CVPR/ECCV/ICCV/NIPS)

    计算机视觉顶会文章的解读汇总(CVPR/ECCV/ICCV/NIPS) 分享计算机视觉顶会优质论文解读集锦,不断更新中,欢迎大家补充~ 2019 CVPR 2019 论文解读集锦 http://bbs ...

  8. 第14节:lstm原理及numpy

    文章目录 lstm原理 rnn lstm实例 lstm原理 文本相关.主要应用于自然语言处理(NLP).对话系统.情感分析.机器翻译等等领域,Google翻译用的就是一个7-8层的LSTM模型. 时序 ...

  9. 【TUM公开数据集RGBD-Benchmark工具evaluate_rpe.py参数用法原理解读】

    「零基础从零开始写VO视觉里程计」统计学.概率论.最小二乘.图优化(7-4) [TUM公开数据集RGBD-Benchmark工具associate.py参数用法原理解读] [TUM公开数据集RGBD- ...

最新文章

  1. 深度学习新星:GANs的基本原理、应用和走向
  2. jQuery针对多个元素的相同点击事件
  3. 使用Spring提供Quartz来实现定时任务
  4. java孙膑和庞涓问题_庞涓与孙膑的故事
  5. 不懂算法的程序员不是好工程师!
  6. mysql事务总结_mysql事务特点总结
  7. android遍历文件夹里的文件,Android 遍历文件夹中所有文件
  8. 【第8题】求 s=a+aa+aaa+aaaa+aa...a 的值
  9. 2006中秋节短信,最新中秋节祝福短信
  10. 黑苹果(Hackintosh)简单步骤教程
  11. css的侧重点(2021.7.11)
  12. 安卓版旅行青蛙三叶草修改教程
  13. php球半径为2的圆面积,某竖直平面内有一半径为R的光滑固定圆环,斜边长2R、短边长R的匀质直角三角板放在环内,试求三角板在其平衡位...
  14. Python 提示 ModuleNotFoundError: No module named ‘common‘
  15. 主流浏览器有哪些?这些浏览器的内核分别是什么?
  16. 一篇搞懂OOA/OOD/OOP的区别
  17. iOS App完整项目
  18. IC卡读卡器调用php,IC卡读卡器如何进行IC卡的读卡?
  19. 离散数学·代数结构【正规子群、商群、群的同态和同构、环与域、格、布尔代数】
  20. 蓝桥杯单片机常用模块(自用)

热门文章

  1. code1167 树网的核
  2. for(;;)和 while(1) 有什么区别吗?for()和while()的使用情景。
  3. postgresql如何实现group_concat功能
  4. windows phone 中反序列化json时出现的问题
  5. 某CTF比赛部分wp
  6. 前端模块规范AMD/UMD/CommonJs
  7. linux 命令博客,Linux命令(一)
  8. 电容式传感器位移性能试验报告_圆柱形电容式接近开关可以分3类?
  9. linux宏命令编辑,linux-vim宏定义(三)
  10. 三维重建面试0:*SLAM滤波方法的串联综述