项目已上传至 GitHub —— sin_pre
数据生成
因为标准的循环神经网络模型预测的是离散的数值,所以需要将连续的 sin 函数曲线离散化
所谓离散化就是在一个给定的区间 [0,MAX] 内,通过有限个采样点模拟一个连续的曲线,即间隔相同距离取点
采样用的是 numpy.linspace() 函数,它可以创建一个等差序列,常用的参数有三个
- start:起始值
- stop:终止值,不包含在内
- num:数列长度,默认为 50
然后使用一个 generate_data() 函数生成输入和输出,序列的第 i 项和后面的 TIMESTEPS-1 项合在一起作为输入,第 i + TIMESTEPS 项作为输出
TFLearn使用
TFlearn 对训练模型进行了一些封装,使 TensorFlow 更便于使用,如下示范了 TFLearn 的使用方法
from tensorflow.contrib.learn.python.learn.estimators.estimator import SKCompat
learn = tf.contrib.learn
# 建立深层循环网络模型
regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir='model/'))
# 调用fit函数训练模型
regressor.fit(train_x, train_y, batch_size=BATCH_SIZE, steps=TRAINGING_STEPS)
# 使用训练好的模型对测试集进行预测
predicted = [[pred] for pred in regressor.predict(test_x)]
完整代码
整个代码的结构如下
- lstm_model() 类用于创建 LSTM 网络并返回一些结果
- LstmCell() 函数用于创建单层 LSTM 结构,防止 LSTM 参数名称一样
- generate_data() 函数用于创建数据集
由于原书中的代码是基于 1.0,而我用的是 1.5,所以出现了很多错误,我将所遇到的错误的解决方法都记录在了文末
import numpy as np
import tensorflow as tf
import matplotlib as mpl
from matplotlib import pyplot as plt
from tensorflow.contrib.learn.python.learn.estimators.estimator import SKCompat
# TensorFlow的高层封装TFLearn
learn = tf.contrib.learn
# 神经网络参数
HIDDEN_SIZE = 30 # LSTM隐藏节点个数
NUM_LAYERS = 2 # LSTM层数
TIMESTEPS = 10 # 循环神经网络截断长度
BATCH_SIZE = 32 # batch大小
# 数据参数
TRAINING_STEPS = 3000 # 训练轮数
TRAINING_EXAMPLES = 10000 # 训练数据个数
TESTING_EXAMPLES = 1000 # 测试数据个数
SAMPLE_GAP = 0.01 # 采样间隔
def generate_data(seq):
# 序列的第i项和后面的TIMESTEPS-1项合在一起作为输入,第i+TIMESTEPS项作为输出
X = []
y = []
for i in range(len(seq) - TIMESTEPS - 1):
X.append([seq[i:i + TIMESTEPS]])
y.append([seq[i + TIMESTEPS]])
return np.array(X, dtype=np.float32), np.array(y, dtype=np.float32)
# LSTM结构单元
def LstmCell():
lstm_cell = tf.contrib.rnn.BasicLSTMCell(HIDDEN_SIZE)
return lstm_cell
def lstm_model(X, y):
# 使用多层LSTM,不能用lstm_cell*NUM_LAYERS的方法,会导致LSTM的tensor名字都一样
cell = tf.contrib.rnn.MultiRNNCell([LstmCell() for _ in range(NUM_LAYERS)])
# 将多层LSTM结构连接成RNN网络并计算前向传播结果
output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)
output = tf.reshape(output, [-1, HIDDEN_SIZE])
# 通过无激活函数的全联接层计算线性回归,并将数据压缩成一维数组的结构
predictions = tf.contrib.layers.fully_connected(output, 1, None)
# 将predictions和labels调整为统一的shape
y = tf.reshape(y, [-1])
predictions = tf.reshape(predictions, [-1])
# 计算损失值
loss = tf.losses.mean_squared_error(predictions, y)
# 创建模型优化器并得到优化步骤
train_op = tf.contrib.layers.optimize_loss(
loss,
tf.train.get_global_step(),
optimizer='Adagrad',
learning_rate=0.1)
return predictions, loss, train_op
# 用sin生成训练和测试数据集
test_start = TRAINING_EXAMPLES * SAMPLE_GAP
test_end = (TRAINING_EXAMPLES + TESTING_EXAMPLES) * SAMPLE_GAP
train_X, train_y = generate_data(
np.sin(np.linspace(0, test_start, TRAINING_EXAMPLES, dtype=np.float32)))
test_X, test_y = generate_data(
np.sin(
np.linspace(test_start, test_end, TESTING_EXAMPLES, dtype=np.float32)))
# 建立深层循环网络模型
regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir='model/'))
# 调用fit函数训练模型
regressor.fit(train_X, train_y, batch_size=BATCH_SIZE, steps=TRAINING_STEPS)
# 使用训练好的模型对测试集进行预测
predicted = [[pred] for pred in regressor.predict(test_X)]
# 计算rmse作为评价指标
rmse = np.sqrt(((predicted - test_y)**2).mean(axis=0))
print('Mean Square Error is: %f' % (rmse[0]))
# 对预测曲线绘图,并存储到sin.jpg
fig = plt.figure()
plot_predicted, = plt.plot(predicted, label='predicted')
plot_test, = plt.plot(test_y, label='real_sin')
plt.legend([plot_predicted, plot_test], ['predicted', 'real_sin'])
plt.show()
运行结果如下
$ python train.py
Mean Square Error is: 0.001638
可以看到曲线重合得非常好,所以用 LSTM 预测具有时间序列的数据非常合适
错误总结
1. 没有 unpack
出现如下错误
AttributeError: module 'tensorflow' has no attribute 'unpack'
原因是 tf.unpack 改为了 tf.unstack
# 原代码
x_ = tf.unpack(x, axis=1)
# 修改为
x_ = tf.unstack(x, axis=1)
2. 没有 rnn_cell
出现如下错误
AttributeError: module 'tensorflow.python.ops.nn' has no attribute 'rnn_cell'
原因是 tf.nn.rnn_cell 改为了 tf.contrib.rnn
# 原代码
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(HIDDEN_SIZE)
cell = tf.nn.rnn_cell.MultiRNNCell([lstm_cell] * NUM_LAYERS)
# 修改为
lstm_cell = tf.contrib.rnn.BasicLSTMCell(HIDDEN_SIZE)
cell = tf.contrib.rnn.MultiRNNCell([lstm_cell] * NUM_LAYERS)
3. rnn 不可调用
出现如下错误
TypeError: 'module' object is not callable
原因是 tf.nn.rnn 现在改为了几个方法
tf.contrib.rnn.static_rnn
tf.contrib.rnn.static_state_saving_rnn
tf.contrib.rnn.static_bidirectional_rnn
tf.contrib.rnn.stack_bidirectional_dynamic_rnn
而我们需要的是 tf.nn.dynamic_rnn() 方法
# 原代码
output, _ = tf.nn.rnn(cell, X, dtype=tf.float32)
# 修改为
output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)
4. 不能调用 Estimator.fit
出现如下警告
WARNING:tensorflow:From train.py:71: calling BaseEstimator.fit (from tensorflow.contrib.learn.python.learn.estimators.estimator) with y is deprecated and will be removed after 2016-12-01.
该警告下面给出了解决方法
Instructions for updating:
Estimator is decoupled from Scikit Learn interface by moving into
separate class SKCompat. Arguments x, y and batch_size are only
available in the SKCompat class, Estimator will only accept input_fn.
Example conversion:
est = Estimator(...) -> est = SKCompat(Estimator(...))
按照给出的方法修改代码
# 原代码
regressor = learn.Estimator(model_fn=lstm_model)
# 修改为
from tensorflow.contrib.learn.python.learn.estimators.estimator import SKCompat
regressor = SKCompat(learn.Estimator(model_fn=lstm_model))
5. 临时文件夹
出现如下警告
WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmp01x9hws6
原因是现在的 Estimator 需要提供 model_dir
# 原代码
regressor = SKCompat(learn.Estimator(model_fn=lstm_model))
# 修改为
regressor = SKCompat(
learn.Estimator(model_fn=lstm_model, model_dir='model/'))
6. 尺寸必须一致
出现如下错误
ValueError: Dimensions must be equal, but are 60 and 40
for 'rnn/rnn/multi_rnn_cell/cell_0/basic_lstm_cell/MatMul_1'
(op: 'MatMul') with input shapes: [?,60], [40,120].
原因我不太清楚,可能是因为 TensorFlow 的调整导致生成的数据在形状上与老版本不一致,也可能是因为使用 lstm_cell*NUM_LAYERS 的方法创建深层循环网络模型导致每层 LSTM 的 tensor 名称都一样
只能在网上搜了其他的类似的博客后照着修改了代码,下面给出了修改的关键地方,详细的部分在完整代码中
# LSTM结构单元
def LstmCell():
lstm_cell = tf.contrib.rnn.BasicLSTMCell(HIDDEN_SIZE)
return lstm_cell
def lstm_model(X, y):
# 使用多层LSTM,不能用lstm_cell*NUM_LAYERS的方法,会导致LSTM的tensor名字都一样
cell = tf.contrib.rnn.MultiRNNCell([LstmCell() for _ in range(NUM_LAYERS)])
# 将多层LSTM结构连接成RNN网络并计算前向传播结果
output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)
......
7. Legend 不支持
出现如下错误
UserWarning: Legend does not support [<matplotlib.lines.Line2D object at 0x7feb52d58c18>] instances.
A proxy artist may be used instead.
原因是因为需要在调用 plt.plot 时参数解包
# 原代码
plot_predicted = plt.plot(predicted, label='predicted')
plot_test = plt.plot(test_y, label='real_sin')
# 修改为(加逗号)
plot_predicted, = plt.plot(predicted, label='predicted')
plot_test, = plt.plot(test_y, label='real_sin')
8. 使用 plt.show() 不显示图片
在代码中使用 plt.show() 运行之后没有图片显示,原因是原代码中使用了 mpl.use(‘Agg’),而 Agg 是不会画图的,所以直接把这一行删掉
9. get_global_step 不建议使用
出现如下警告
WARNING:tensorflow:From train.py:60: get_global_step
(from tensorflow.contrib.framework.python.ops.variables)
is deprecated and will be removed in a future version.
警告下面给出了解决方法
Instructions for updating:
Please switch to tf.train.get_global_step
按照解决方法修改代码
# 原代码
train_op = tf.contrib.layers.optimize_loss(
loss,
tf.contrib.framework.get_global_step(),
optimizer='Adagrad',
learning_rate=0.1)
# 修改为
train_op = tf.contrib.layers.optimize_loss(
loss,
tf.train.get_global_step(),
optimizer='Adagrad',
learning_rate=0.1)