学习笔记CB012: LSTM 简单实现、完整实现、torch、小说训练word2vec lstm机器人

本文详细介绍了LSTM(长短期记忆网络)的工作原理,并提供了原始Python代码实现了一个简单的二进制加法器。LSTM适用于自然语言处理任务,如word2vec和聊天机器人,解决传统统计方法无法捕捉长距离依赖的问题。文章还涵盖了完整的LSTM实现,以及在Torch框架下的应用,并给出使用LSTM进行小说训练的词向量模型示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

真正掌握一种算法,最实际的方法,完全手写出来。

LSTM(Long Short Tem Memory)特殊递归神经网络,神经元保存历史记忆,解决自然语言处理统计方法只能考虑最近n个词语而忽略更久前词语的问题。用途:word representation(embedding)(词语向量)、sequence to sequence learning(输入句子预测句子)、机器翻译、语音识别等。

100多行原始python代码实现基于LSTM二进制加法器。https://iamtrask.github.io/2015/11/15/anyone-can-code-lstm/ ,翻译http://blog.youkuaiyun.com/zzukun/article/details/49968129

import copy, numpy as np
np.random.seed(0)

最开始引入numpy库,矩阵操作。

def sigmoid(x):
    output = 1/(1+np.exp(-x))
    return output

声明sigmoid激活函数,神经网络基础内容,常用激活函数sigmoid、tan、relu等,sigmoid取值范围[0, 1],tan取值范围[-1,1],x是向量,返回output是向量。

def sigmoid_output_to_derivative(output):
    return output*(1-output)

声明sigmoid求导函数。
加法器思路:二进制加法是二进制位相加,记录满二进一进位,训练时随机c=a+b样本,输入a、b输出c是整个lstm预测过程,训练由a、b二进制向c各种转换矩阵和权重,神经网络。

int2binary = {}

声明词典,由整型数字转成二进制,存起来不用随时计算,提前存好读取更快。

binary_dim = 8

largest_number = pow(2,binary_dim)
声明二进制数字维度,8,二进制能表达最大整数2^8=256,largest_number。

binary = np.unpackbits(
                       np.array([range(largest_number)],dtype=np.uint8).T,axis=1)
for i in range(largest_number):
    int2binary[i] = binary[i]

预先把整数到二进制转换词典存起来。

alpha = 0.1
input_dim = 2
hidden_dim = 16
output_dim = 1

设置参数,alpha是学习速度,input_dim是输入层向量维度,输入a、b两个数,是2,hidden_dim是隐藏层向量维度,隐藏层神经元个数,output_dim是输出层向量维度,输出一个c,是1维。从输入层到隐藏层权重矩阵是2*16维,从隐藏层到输出层权重矩阵是16*1维,隐藏层到隐藏层权重矩阵是16*16维:

synapse_0 = 2*np.random.random((input_dim,hidden_dim)) - 1
synapse_1 = 2*np.random.random((hidden_dim,output_dim)) - 1
synapse_h = 2*np.random.random((hidden_dim,hidden_dim)) - 1

2x-1,np.random.random生成从0到1之间随机浮点数,2x-1使其取值范围在[-1, 1]。

synapse_0_update = np.zeros_like(synapse_0)
synapse_1_update = np.zeros_like(synapse_1)
synapse_h_update = np.zeros_like(synapse_h)

声明三个矩阵更新,Delta。

for j in range(10000):

进行10000次迭代。

a_int = np.random.randint(largest_number/2)
a = int2binary[a_int]
b_int = np.random.randint(largest_number/2)
b = int2binary[b_int]
c_int = a_int + b_int
c = int2binary[c_int]

随机生成样本,包含二进制a、b、c,c=a+b,a_int、b_int、c_int分别是a、b、c对应整数格式。

d = np.zeros_like(c)

d存模型对c预测值。

overallError = 0

全局误差,观察模型效果。
layer_2_deltas = list()
存储第二层(输出层)残差,输出层残差计算公式推导公式http://deeplearning.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95

layer_1_values = list()
layer_1_values.append(np.zeros(hidden_dim))

存储第一层(隐藏层)输出值,赋0值作为上一个时间值。

for position in range(binary_dim):

遍历二进制每一位。

X = np.array([[a[binary_dim - position - 1],b[binary_dim - position - 1]]])
y = np.array([[c[binary_dim - position - 1]]]).T

X和y分别是样本输入和输出二进制值第position位,X对于每个样本有两个值,分别是a和b对应第position位。把样本拆成每个二进制位用于训练,二进制加法存在进位标记正好适合利用LSTM长短期记忆训练,每个样本8个二进制位是一个时间序列。

layer_1 = sigmoid(np.dot(X,synapse_0) + np.dot(layer_1_values[-1],synapse_h))

公式Ct = sigma(W0·Xt + Wh·Ct-1)

layer_2 = sigmoid(np.dot(layer_1,synapse_1))

这里使用的公式是C2 = sigma(W1·C1),

layer_2_error = y - layer_2

计算预测值和真实值误差。

layer_2_deltas.append((layer_2_error)*sigmoid_output_to_derivative(layer_2))

反向传导,计算delta,添加到数组layer_2_deltas

overallError += np.abs(layer_2_error[0])

计算累加总误差,用于展示和观察。

d[binary_dim - position - 1] = np.round(layer_2[0][0])

存储预测position位输出值。

layer_1_values.append(copy.deepcopy(layer_1))

存储中间过程生成隐藏层值。

future_layer_1_delta = np.zeros(hidden_dim)

存储下一个时间周期隐藏层历史记忆值,先赋一个空值。

for position in range(binary_dim):

遍历二进制每一位。

X = np.array([[a[position],b[position]]])

取出X值,从大位开始更新,反向传导按时序逆着一级一级更新。

layer_1 = layer_1_values[-position-1]

取出位对应隐藏层输出。

prev_layer_1 = layer_1_values[-position-2]

取出位对应隐藏层上一时序输出。

layer_2_delta = layer_2_deltas[-position-1]

取出位对应输出层delta。

layer_1_delta = (future_layer_1_delta.dot(synapse_h.T) + layer_2_delta.dot(synapse_1.T)) * sigmoid_output_to_derivative(layer_1)

神经网络反向传导公式,加上隐藏层?值。

synapse_1_update += np.atleast_2d(layer_1).T.dot(layer_2_delta)

累加权重矩阵更新,对权重(权重矩阵)偏导等于本层输出与下一层delta点乘。

synapse_h_update += np.atleast_2d(prev_layer_1).T.dot(layer_1_delta)

前一时序隐藏层权重矩阵更新,前一时序隐藏层输出与本时序delta点乘。

synapse_0_update += X.T.dot(layer_1_delta)

输入层权重矩阵更新。

future_layer_1_delta = layer_1_delta

记录本时序隐藏层delta。

synapse_0 += synapse_0_update * alpha
synapse_1 += synapse_1_update * alpha
synapse_h += synapse_h_update * alpha

权重矩阵更新。

synapse_0_update *= 0
synapse_1_update *= 0
synapse_h_update *= 0

更新变量归零。

if(j % 1000 == 0):
        print "Error:" + str(overallError)
        print "Pred:" + str(d)
        print "True:" + str(c)
        out = 0
        for index,x in enumerate(reversed(d)):
            out += x*pow(2,index)
        print str(a_int) + " + " + str(b_int) + " = " + str(out)
        print "------------"

每训练1000个样本输出总误差信息,运行时看收敛过程。
LSTM最简单实现,没有考虑偏置变量,只有两个神经元。

完整LSTM python实现。完全参照论文great intro paper实现,代码来源https://github.com/nicodjimenez/lstm ,作者解释http://nicodjimenez.github.io/2014/08/08/lstm.html ,具体过程参考http://colah.github.io/posts/2015-08-Understanding-LSTMs/ 图。

import random
import numpy as np
imp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值