注意一点就是: sigmoid函数和tanh函数有所区别:
sigmoid将一个实数输入映射到[0,1]范围内 tanh函数将一个实数输入映射到[-1,1]范围内
不过两者都有所优劣,Relu激活函数可以极大地加快收敛速度,相比tanh函数,收敛速度可以加快6倍
# 从零实现 LSTM,其实与 RNN、GRU 的主要区别在于有门的设计
# 确定哪些是需要初始化模型参数:
# 核心公式就是以下六个
# It=σ(XtWxi+Ht−1Whi+bi), Ft=σ(XtWxf+Ht−1Whf+bf), Ot=σ(XtWxo+Ht−1Who+bo), C~t=tanh(XtWxc+Ht−1Whc+bc),
# Ct=Ft⊙Ct−1+It⊙C~t,Ht=Ot⊙tanh(Ct)
# 初始化参数有:Ht-1 的维度
vocab_size = 1027
num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size
class LSTM(object):
def __init__(self, hiden_dim, params=None):
"""
初始化待训练的参数 variabel
params = (Wxr, Whr, br, Wxz, Whz, bz, Wxh, Whh, bh)
"""
# 是否加载预训练参数
if params:
self.Wxi, self.Whi, self.bi, self.Wxf, self.Whf, self.bf, self.Wxo, self.Who, self.bo, self.wxc, \
self.whc, self.bc = params
else:
# 定义变量
self.Wxi = self._ones(shape=(vocab_size, num_hiddens))
self.Whi = self._ones(shape=(num_hiddens, num_hiddens))
self.Wxf = self._ones(shape=(vocab_size, num_hiddens))
self.Whf = self._ones(shape=(num_hiddens, num_hiddens))
self.Wxo = self._ones(shape=(vocab_size, num_hiddens))
self.Who = self._ones(shape=(num_hiddens, num_hiddens))
self.Wxc = self._ones(shape=(vocab_size, num_hiddens))
self.Whc = self._ones(shape=(num_hiddens, num_hiddens))
# 偏置项
self.bi = tf.Variable(tf.zeros([1,num_hiddens]), dtype=tf.float32)
self.bf = tf.Variable(tf.zeros([1,num_hiddens]), dtype=tf.float32)
self.bo = tf.Variable(tf.zeros([1,num_hiddens]), dtype=tf.float32)
self.bc = tf.Variable(tf.zeros([1,num_hiddens]), dtype=tf.float32)
# 输出层参数
self.Whq = self._ones(shape=(num_hiddens, vocab_size))
self.bq = tf.Variable(tf.zeros([1,vocab_size]), dtype=tf.float32)
def _ones(self,shape):
return tf.Variable(tf.random.normal(shape=shape,stddev=0.01,mean=0,dtype=tf.float32))
def net(self, inputs, Ht, Ct):
# 展开做循环计算
outputs = []
for X in inputs:
x = tf.reshape(X,(-1, vocab_size))
# Rt=σ(XtWxr+Ht−1Whr+br)
It = tf.sigmoid(x@self.Wxi + Ht@self.Whi + self.bi)
Ft = tf.sigmoid(x@self.Wxf + Ht@self.Whf + self.bf)
Ot = tf.sigmoid(x@self.Wxo + Ht@self.Who + self.bo)
C_hat = tf.tanh(x@self.Wxc + Ht@self.Whc + self.bc)
C_t = Ft * Ct + It * C_hat
Ht = Ot * tf.tanh(Ct)
Y = tf.matmul(Ht, self.Whq) + self.bq
outputs.append(Y)
return outputs, Ht, Ct
注意:‘for X in inputs’此类写法其实有些问题,容易造成误解在 batch_size 维度上做循环,实则是在 time_step 上做得拆解,建议使用:¶
for x in tf.unstack(inputs, axis=1)
在时间维度上做循环更加合理,不过此处不做更改了