keras LSTM 前向计算实例

LSTM前向计算

在keras里训练完成一个模型后保存到本地,然后读取模型参数做前向计算,为C++移植做准备

关于LSTM的原理网上很多,被引用最多的应该就是这篇博客了Understanding LSTM Networks,它的译文也是遍布网上各个角落

使用LSTM分类mnist数据集的数字,数字图片大小 2828 28 ∗ 28 ,每一步输入一行数据,总共28步输入图片的所有行,即lstm的timesteps为28,LSTM在最后一步输出结果,
模型训练完成后,model.summery()如下:

model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
lstm_1 (LSTM)                (None, 128)               80384     
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1290      
=================================================================
Total params: 81,674
Trainable params: 81,674
Non-trainable params: 0
_________________________________________________________________
model.input_shape
Out[4]: (None, 28, 28)

贴几张经典图片介绍一下,图片出自博客Understanding LSTM Networks
这里写图片描述
LSTM每一步有图中红色标记1、2、3、4的四个控制门,这四个门都分别是一个全连接网络,例如这个例子中的LSTM单元数为128,则这四个门就都是有128个单元的MLP。每一个绿色框表示一个cell,这三个cell表示同一个cell在不同的时刻,那一个LSTM的参数个数有多少呢,以这个mnist例子来算一下,

LSTM units = 128,则 ht1 h t − 1 维度也为128
每一步输入 xt x t 维度为28
这四个门的输入都是 xt x t ht1 h t − 1 的拼接,则四个门的输入维度为 128+28=156 ( 128 + 28 ) = 156
前面说到四个门都是有units个单元的MLP,那每个门的参数就是 (28+128)128 ( 28 + 128 ) ∗ 128 ,四个门就乘以4再加上各自的bias,就是 (28+128)1284+1284=80384 ( 28 + 128 ) ∗ 128 ∗ 4 + 128 ∗ 4 = 80384
翻上去一看,答案跟model.summary()的结果一样!

检查完了参数个数,那就开始前向计算了,其实就是四个门的更新公式,程序按照公式写就可以了
先看看keras保存的weights长什么样,

weights = model.get_weights()
weights[0].shape
Out[6]: (28, 512)
weights[1].shape
Out[7]: (128, 512)
weights[2].shape
Out[8]: (512,)

可以看到weight[0]、weights[1]就是前面分析的(28+128)*128*4这项,weights[2]就是bias的128*4这项了,分析了这个,程序就简单了,weights中是把四个门的系数放到一个矩阵里了,那计算的时候我们取这个矩阵中的相应部分就行了,例如bias取法如下

bias_i = weights[2][:128]
bias_f = weights[2][128:256]
bias_C = weights[2][256:384]
bias_o = weights[2][384:]

先将 xtht1 x t 和 h t − 1 与四个门的系数矩阵相乘再拼接

    input_xt =  np.dot(x0[:,i,:],weights[0])
    input_ht_1 = np.dot(ht_1,weights[1])
    input = input_xt+input_ht_1

LSTM层计算步骤如下
forget gate
这里写图片描述

ft = sigmoid(input[:,128:256]+bias_f)

input gate:
这里写图片描述

it = sigmoid(input[:, :128] + bias_i)

计算cell状态:

Ct = tanh(input[:,256:384]+bias_C)

更新cell状态
这里写图片描述

Ct = ft*C_t_1+it*Ct

output gate
这里写图片描述

    ot = sigmoid(input[:,384:]+bias_o)
    ht = ot*tanh(Ct)

最后,更新一下 ht1 h t − 1 Ct1 C t − 1 以便进入下一次递归

    ht_1 = ht
    C_t_1 = Ct

其实,前向计算就是按照公式写,没什么难度,需要注意的问题有以下两点(也是我踩过的坑)

  1. keras模型里参数矩阵与这四个门对应的先后顺序
  2. keras里activation与recurrent activation的关系,recurrent activation用在了 ifo i 、 f 、 o 的计算中(keras里默认是hard_sigmoid),activation用在了 Ct C t ht h t 的计算中(keras里默认是tanh)

关于这两个问题,可以参考博客Keras之LSTM源码阅读笔记,别人分析的更深入

参考资料:

  1. Understanding LSTM Networks
  2. [译] 理解 LSTM 网络
  3. 零基础入门深度学习(6) - 长短时记忆网络(LSTM)
  4. Keras之LSTM源码阅读笔记

附上测试本地模型的代码

import keras
import numpy as np
from keras.models import load_model
model = load_model('lstm-model.h5')
weights = model.get_weights()
weights = np.array(weights)
x0 = np.load('x0.npy')
y0 = model.predict(x0,1)

def sigmoid(x):
    y = 1/(1+np.exp(-1*x))
    return y
def tanh(x):
    y = 2*sigmoid(2*x)-1
    # y = (np.exp(x)-np.exp(-1*x))/(np.exp(x)+np.exp(-1*x))
    return y
def softmax(x):
    y = np.exp(x)/np.sum(np.exp(x))
    return y


ht_1 = np.zeros([1,128]).astype('float32')
# ht_1.dtype = 'float32'
C_t_1 = np.zeros([1,128]).astype('float32')
bias_i = weights[2][:128]
bias_f = weights[2][128:256]
bias_C = weights[2][256:384]
bias_o = weights[2][384:]
for i in range(x0.shape[1]):
    input_xt =  np.dot(x0[:,i,:],weights[0])
    input_ht_1 = np.dot(ht_1,weights[1])
    input = input_xt+input_ht_1

    it = sigmoid(input[:, :128] + bias_i)

    ft = sigmoid(input[:,128:256]+bias_f)

    Ct = tanh(input[:,256:384]+bias_C)
    Ct = ft*C_t_1+it*Ct

    ot = sigmoid(input[:,384:]+bias_o)
    ht = ot*tanh(Ct)

    ht_1 = ht
    C_t_1 = Ct

output = softmax(np.dot(ht,weights[3])+weights[4])

print('haha')
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值