|
| 1 | +import numpy as np |
| 2 | +import pickle |
| 3 | +import pca |
| 4 | +import tensorflow as tf |
| 5 | +from tensorflow.contrib import rnn |
| 6 | +import matplotlib.pyplot as plt |
| 7 | + |
| 8 | + |
| 9 | +def lstm(layer_num, hidden_size, batch_size, output_size, lstm_x, keep_prob): |
| 10 | + def multi_cells(cell_num): |
| 11 | + # 多cell的lstm必须多次建立cell保存在一个list当中 |
| 12 | + multi_cell = [] |
| 13 | + for _ in range(cell_num): |
| 14 | + # **步骤2:定义LSTM_cell,只需要说明 hidden_size, 它会自动匹配输入的 X 的维度 |
| 15 | + lstm_cell = rnn.BasicLSTMCell(num_units=hidden_size, forget_bias=1.0, state_is_tuple=True) |
| 16 | + |
| 17 | + # **步骤3:添加 dropout layer, 一般只设置 output_keep_prob |
| 18 | + lstm_cell = rnn.DropoutWrapper(cell=lstm_cell, input_keep_prob=1.0, output_keep_prob=keep_prob) |
| 19 | + multi_cell.append(lstm_cell) |
| 20 | + return multi_cell |
| 21 | + |
| 22 | + # **步骤4:调用 MultiRNNCell 来实现多层 LSTM |
| 23 | + mlstm_cell = rnn.MultiRNNCell(multi_cells(layer_num), state_is_tuple=True) |
| 24 | + |
| 25 | + # **步骤5:用全零来初始化state |
| 26 | + init_state = mlstm_cell.zero_state(batch_size, dtype=tf.float32) |
| 27 | + |
| 28 | + # **步骤6:调用 dynamic_rnn() 来让我们构建好的网络运行起来 |
| 29 | + # ** 当 time_major==False 时, outputs.shape = [batch_size, time_step_size, hidden_size] |
| 30 | + # ** 所以,可以取 h_state = outputs[:, -1, :] 作为最后输出 |
| 31 | + # ** state.shape = [layer_num, 2, batch_size, hidden_size](中间的‘2’指的是每个cell中有两层分别是c和h), |
| 32 | + # ** 或者,可以取 h_state = state[-1][1] 作为最后输出 |
| 33 | + # ** 最后输出维度是 [batch_size, hidden_size] |
| 34 | + outputs, state = tf.nn.dynamic_rnn(mlstm_cell, inputs=lstm_x, initial_state=init_state, time_major=False) |
| 35 | + h_state = outputs[:, -1, :] # 或者 h_state = state[-1][1] |
| 36 | + |
| 37 | + # 输出层 |
| 38 | + # W_o = tf.Variable(tf.truncated_normal([hidden_size, output_size], stddev=0.1), dtype=tf.float32) |
| 39 | + # b_o = tf.Variable(tf.constant(0.1, shape=[output_size]), dtype=tf.float32) |
| 40 | + # y_pre = tf.add(tf.matmul(h_state, W_o), b_o) |
| 41 | + # tf.layers.dense是全连接层,不给激活函数,默认是linear function |
| 42 | + lstm_y_pres = tf.layers.dense(h_state, output_size) |
| 43 | + return lstm_y_pres |
| 44 | + |
| 45 | + |
| 46 | +# 原始的data里面的数据格式是dataframe,arr改成了里面也是list |
| 47 | +def transfer(data): |
| 48 | + vol_col_index = 1 # 找到流量对应的列 |
| 49 | + height = len(data) |
| 50 | + width = data[0].shape[0] |
| 51 | + arr = np.zeros((height, width)) |
| 52 | + for i in range(height): |
| 53 | + for j in range(width): |
| 54 | + arr[i, j] = data[i].iloc[j, vol_col_index] |
| 55 | + return arr |
| 56 | + |
| 57 | + |
| 58 | +def createdataset(data): |
| 59 | + dataset = [] |
| 60 | + for road in data: # 对于某一条路的数据 |
| 61 | + dataset.append(transfer(road)) |
| 62 | + return dataset |
| 63 | + |
| 64 | + |
| 65 | +def myload(): |
| 66 | + filename = 'dump2.txt' |
| 67 | + f = open('data/' + filename, 'rb') |
| 68 | + data = pickle.load(f) |
| 69 | + f.close() |
| 70 | + # print (data) # 路段数 * 每个路段的信息(df的数据结构) |
| 71 | + return data |
| 72 | + |
| 73 | + |
| 74 | +def split_dataset(dataset): |
| 75 | + trainX = [] |
| 76 | + trainY = [] |
| 77 | + trainX_len = 2 # 使用3天预测一天 |
| 78 | + trainY_len = 1 # 使用3天预测一天 |
| 79 | + days = dataset[0].shape[0] |
| 80 | + for road in dataset: |
| 81 | + trainX_per_road = [] |
| 82 | + trainY_pre_road = [] |
| 83 | + for i in range(0, days - (trainX_len + trainY_len - 1)): |
| 84 | + trainX_per_road.append(road[i:i + trainX_len]) |
| 85 | + trainY_pre_road.append(road[i + trainX_len:i + trainX_len + trainY_len]) |
| 86 | + trainX.append(trainX_per_road) |
| 87 | + trainY.append(trainY_pre_road) |
| 88 | + return np.array(trainX), np.array(trainY) |
| 89 | + |
| 90 | + |
| 91 | +def use_pca(dataset): |
| 92 | + dataset_rest = [] |
| 93 | + dataset_main = [] |
| 94 | + for road in dataset: |
| 95 | + pca_obj = pca.PCA(road, 4) |
| 96 | + dataset_rest.append(pca_obj.rest_x) |
| 97 | + dataset_main.append(pca_obj.main_x) |
| 98 | + return dataset_main, dataset_rest |
| 99 | + |
| 100 | + |
| 101 | +if __name__ == "__main__": |
| 102 | + time_step = 2 |
| 103 | + data = myload() # data是一个list,里面是df格式的数据 |
| 104 | + # transfer |
| 105 | + dataset = createdataset(data) # dataset 的格式是 (路段 * 每一天 * 一天内的数据)20 * 7 * 480 |
| 106 | + dataset_main, dataset_rest = use_pca(dataset) # dataset_main = 路段 * 每一个路段里面的主成分 ; dataset_rest = 路段 * 每一个路段里面的偏差 |
| 107 | + days, dnum = dataset_main[0].shape |
| 108 | + y_main = dataset_main[0][time_step:days, :] |
| 109 | + trainX, trainY = split_dataset(dataset_rest) |
| 110 | + train_x_raw = trainX[0] |
| 111 | + train_y_raw = np.reshape(trainY[0], (days - time_step, 480)) |
| 112 | + |
| 113 | + x_max = train_x_raw.max() |
| 114 | + x_min = train_x_raw.min() |
| 115 | + y_max = train_y_raw.max() |
| 116 | + y_min = train_y_raw.min() |
| 117 | + |
| 118 | + train_x = (train_x_raw - x_min) / (x_max - x_min) |
| 119 | + train_y = (train_y_raw - y_min) / (y_max - y_min) |
| 120 | + |
| 121 | + # lstm的hyper-parameter |
| 122 | + |
| 123 | + hidden_size = 400 |
| 124 | + layer_num = 1 |
| 125 | + max_epoch = 5000 |
| 126 | + dropout_keep_rate = 1 |
| 127 | + |
| 128 | + # 根据输入数据来决定,train_num训练集大小,input_size输入维度 |
| 129 | + train_num, time_step_size, input_size = train_x.shape |
| 130 | + # output_size输出的结点个数 |
| 131 | + _, output_size = train_y.shape |
| 132 | + |
| 133 | + # **步骤1:LSTM 的输入shape = (batch_size, time_step_size, input_size),输出shape=(batch_size, output_size) |
| 134 | + x_input = tf.placeholder(tf.float32, [None, time_step_size, input_size]) |
| 135 | + y_real = tf.placeholder(tf.float32, [None, output_size]) |
| 136 | + |
| 137 | + # dropout的留下的神经元的比例 |
| 138 | + keep_prob = tf.placeholder(tf.float32, []) |
| 139 | + |
| 140 | + # 在训练和测试的时候,我们想用不同的 batch_size.所以采用占位符的方式 |
| 141 | + batch_size = tf.placeholder(tf.int32, []) # 注意类型必须为 tf.int32 |
| 142 | + |
| 143 | + pre_layer_hidden_num = 0 |
| 144 | + pre_layer_hidden_size = 0 |
| 145 | + hide_output = x_input |
| 146 | + |
| 147 | + y_pred = lstm(layer_num, hidden_size, batch_size, output_size, hide_output, keep_prob) |
| 148 | + # 损失和评估函数 |
| 149 | + mse = tf.losses.mean_squared_error(y_real, y_pred) |
| 150 | + train_op = tf.train.AdamOptimizer(1e-3).minimize(mse) |
| 151 | + |
| 152 | + config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True) |
| 153 | + # 设置 GPU 按需增长 |
| 154 | + config.gpu_options.allow_growth = True |
| 155 | + sess = tf.Session(config=config) |
| 156 | + # 初始化变量 |
| 157 | + sess.run(tf.global_variables_initializer()) |
| 158 | + |
| 159 | + mre_result = [] |
| 160 | + mae_result = [] |
| 161 | + rmse_result = [] |
| 162 | + |
| 163 | + |
| 164 | + def get_metrics(y, pred_y): |
| 165 | + mre = np.mean(np.abs(y - pred_y) / y) |
| 166 | + mae = np.mean(np.abs(y - pred_y)) |
| 167 | + rmse = np.sqrt(np.mean(np.square(y - pred_y))) |
| 168 | + return mre, mae, rmse |
| 169 | + |
| 170 | + |
| 171 | + def print_to_console(i, train_y_pred): |
| 172 | + train_y_pred_real = train_y_pred * (y_max - y_min) + y_min |
| 173 | + train_y_real = train_y * (y_max - y_min) + y_min |
| 174 | + plt.plot(range(dnum), train_y_real[0], 'b-') |
| 175 | + plt.plot(range(dnum), train_y_pred_real[0], 'r-') |
| 176 | + plt.show() |
| 177 | + train_mre, train_mae, train_rmse = get_metrics(train_y_real, train_y_pred_real) |
| 178 | + print('epoch %d train %.4f %.2f %.2f' % (i, train_mre, train_mae, train_rmse)) |
| 179 | + |
| 180 | + |
| 181 | + for i in range(1, max_epoch + 1): |
| 182 | + feed_dict = {x_input: train_x, y_real: train_y, keep_prob: dropout_keep_rate, batch_size: train_num} |
| 183 | + sess.run(train_op, feed_dict=feed_dict) |
| 184 | + if i % 50 == 0: |
| 185 | + feed_dict = {x_input: train_x, y_real: train_y, keep_prob: 1.0, batch_size: train_num} |
| 186 | + train_y_pred = sess.run(y_pred, feed_dict=feed_dict) |
| 187 | + print_to_console(i, train_y_pred) |
| 188 | + |
| 189 | + y_main = dataset_main[0][time_step:days, :] |
| 190 | + y_pre_real = y_main + train_y_pred * (y_max - y_min) + y_min |
| 191 | + y_raw = y_main + train_y * (y_max - y_min) + y_min |
| 192 | + plt.plot(y_raw[0]) |
| 193 | + plt.plot(y_pre_real[0]) |
| 194 | + plt.show() |
0 commit comments