【TensorFlow】LSTM(使用TFLearn预测正弦sin函数)

项目已上传至 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)]

完整代码


该代码实现自《TensorFlow:实战Google深度学习框架》

整个代码的结构如下

  • 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

【TensorFlow】LSTM(使用TFLearn预测正弦sin函数)_第1张图片

可以看到曲线重合得非常好,所以用 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 [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)

你可能感兴趣的:(深度学习,TensorFlow实践)