当前位置:   article > 正文

RNN之seq2seq模型_rnn seq2seq

rnn seq2seq

1.RNN模型概述

RNN大致可以分为4种,输出和输入序列不同数量rnn可以有多种不同的结构,不同结构自然就有不同的引用场合。

如下图所示:

one to one 结构: 仅仅只是简单的给一个输入得到一个输出,此处并未体现序列的特征,例如图像分类场景。
one to many 结构:给一个输入得到一系列输出,这种结构可用于生产图片描述的场景。
many to one 结构: 给一系列输入得到一个输出,这种结构可用于文本情感分析,对一些列的文本输入进行分类,看是消极还是积 极情感。
many to many 结构: 给一些列输入得到一系列输出,这种结构可用于翻译或聊天对话场景,对输入的文本转换成另外一些列文本。
同步 many to many 结构: 它是经典的rnn结构,前一输入的状态会带到下一个状态中,而且每个输入都会对应一个输出,我们最熟悉的就是用于字符预测了,同样也可以用于视频分类,对视频的帧打标签。

2.seq2seq 简介

     seq2seq是一个重要的RNN变种,属于many to many。同时这种结构又叫Encoder-Decoder模型。原始的N vs N RNN要求序列等长,然而我们遇到的大部分问题序列都是不等长的,如机器翻译中,源语言和目标语言的句子往往并没有相同的长度。

    为此,我们先用Encoder 将输入编码映射到语义空间(下图左侧部分),得到一个个固定维数的向量(下图C),这个向量就表示输入的语义。然后我们使用Decoder进行解码,便获得所需的输出。

  它的特点很明显,就是不限制输入输出,故有很广泛的应用。如机器翻译,智能对话等。

 

 

3. seq2seq预测股票

我们利用seq2seq对股票收盘价进行了预测,关于代码的详细说明,参见注释,需要数据的同学可以加我qq,请备注csdn_seq2seq。

  1. # -*- coding: utf-8 -*-
  2. """
  3. seq2seq stock
  4. """
  5. import tensorflow as tf
  6. import numpy as np
  7. import matplotlib.pyplot as plt
  8. import pandas as pd
  9. '''
  10. 1.样本数据产生
  11. '''
  12. #pandas 链式赋值警告:a=b=c=1,凡事出现链式赋值的情况,
  13. #pandas都是不能够确定到底返回的是一个引用还是一个拷贝。 所以遇到这种情况就干脆报warning
  14. pd.options.mode.chained_assignment = None # default='warn'
  15. def loadstock(window_size):
  16. names = ['date', #日期
  17. 'code', #股票代码
  18. 'name', #名字
  19. 'Close', # 收盘价
  20. 'top_price', #最高价
  21. 'low_price', #最低价
  22. 'opening_price', #开盘价
  23. 'bef_price',
  24. 'floor_price',
  25. 'floor',
  26. 'exchange',
  27. 'Volume',
  28. 'amount',
  29. '总市值',
  30. '流通市值']
  31. data = pd.read_csv('600000.csv', names=names, header=None,encoding = "gbk")
  32. #predictor_names = ["Close",'top_price',"low_price","opening_price"]
  33. predictor_names = ["Close"] #预测收盘价,当然可以用来预测多个
  34. training_features = np.asarray(data[predictor_names], dtype = "float32")#asarray,不占内存等同于array
  35. kept_values = training_features[1000:] #取1000以后的
  36. X = [] ## x ;前window_size天,输入数据
  37. Y = [] #y后window_size天 作为标注结果
  38. for i in range(len(kept_values) - window_size * 2):
  39. X.append(kept_values[i:i + window_size]) #每一组40个
  40. Y.append(kept_values[i + window_size:i + window_size * 2])
  41. X = np.reshape(X,[-1,window_size,len(predictor_names)]) #len(predictor 可能是要预测多个时候有用
  42. Y = np.reshape(Y,[-1,window_size,len(predictor_names)])
  43. print(np.shape(X))
  44. return X, Y
  45. X_train = []
  46. Y_train = []
  47. X_test = []
  48. Y_test = []
  49. def generate_data(isTrain, batch_size):
  50. # 生成40个样本,预测后40个样本
  51. seq_length = 40 #window_size
  52. seq_length_test = 80
  53. global Y_train
  54. global X_train
  55. global X_test
  56. global Y_test
  57. # 训练集
  58. if len(Y_train) == 0:
  59. X, Y= loadstock( window_size=seq_length)
  60. #X, Y = normalizestock(X, Y)
  61. # Split 80-20:
  62. X_train = X[:int(len(X) * 0.8)]
  63. Y_train = Y[:int(len(Y) * 0.8)]
  64. #测试集
  65. if len(Y_test) == 0:
  66. X, Y = loadstock( window_size=seq_length_test) #测试集为什么用80?
  67. #X, Y = normalizestock(X, Y)
  68. X_test = X[int(len(X) * 0.8):]
  69. Y_test = Y[int(len(Y) * 0.8):]
  70. if isTrain:
  71. return do_generate_x_y(X_train, Y_train, batch_size)
  72. else:
  73. return do_generate_x_y(X_test, Y_test, batch_size)
  74. def do_generate_x_y(X, Y, batch_size):
  75. #在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行最崩溃,
  76. #不如在出现错误条件时就崩溃,这时候就需要assert断言的帮助。能起到提前报错的作用
  77. assert X.shape == Y.shape, (X.shape, Y.shape) #如果这里不等于,则直接报错就不执行下去了
  78. idxes = np.random.randint(X.shape[0], size=batch_size) #产生随机整数,不相等的
  79. X_out = np.array(X[idxes]).transpose((1, 0, 2)) #0,1,列互换,输出数据:[batch_size,windows_size,value]
  80. Y_out = np.array(Y[idxes]).transpose((1, 0, 2)) # ------->[windows_size,batch_szie,value ]
  81. return X_out, Y_out #是训练需要吗?
  82. sample_now, sample_f = generate_data(isTrain=True, batch_size=3)
  83. print("training examples : ")
  84. print(sample_now.shape)
  85. print("(seq_length, batch_size, output_dim)")
  86. '''
  87. 2. 定义模型框架
  88. '''
  89. seq_length = sample_now.shape[0]
  90. batch_size = 100
  91. output_dim = input_dim = sample_now.shape[-1] #decoder输出维度,需要预测一个就输出一个就好了,需要预测的就一个
  92. hidden_dim = 12 #每一层有12个gru
  93. layers_num = 2 #两层
  94. #Optmizer:
  95. learning_rate =0.04
  96. nb_iters = 10000
  97. lambda_l2_reg = 0.003 # L2正则化系数
  98. tf.reset_default_graph()
  99. encoder_input = [] #encoder 输入
  100. expected_output = [] #中间,在feed_dict中间输入进去
  101. decode_input =[] #decode输出
  102. #占位符,encoder,middle,decode
  103. for i in range(seq_length):#windows_size个占位符,每个占位符里面是数据
  104. encoder_input.append( tf.placeholder(tf.float32, shape=( None, input_dim))) #[40,bacht_size,1]的占位符
  105. expected_output.append( tf.placeholder(tf.float32, shape=( None, output_dim)) )
  106. decode_input.append( tf.placeholder(tf.float32, shape=( None, input_dim)) )
  107. #定义网络结构 ,seq2seq
  108. tcells = [] #定义了两层循环网络,每层12个GRUcell
  109. for i in range(layers_num):
  110. tcells.append(tf.contrib.rnn.GRUCell(hidden_dim))
  111. #多层RNN实现
  112. Mcell = tf.contrib.rnn.MultiRNNCell(tcells)
  113. dec_outputs, dec_memory = tf.contrib.legacy_seq2seq.basic_rnn_seq2seq(encoder_input,decode_input,Mcell)
  114. #最后结果全连接输出???? 没看太懂
  115. reshaped_outputs = []
  116. for ii in dec_outputs :
  117. reshaped_outputs.append( tf.contrib.layers.fully_connected(ii,output_dim,activation_fn=None))
  118. #损失函数计算,均方差(x-y)^2
  119. output_loss = 0
  120. for _y, _Y in zip(reshaped_outputs, expected_output):
  121. output_loss += tf.reduce_mean( tf.pow(_y - _Y, 2) )
  122. # 正则项,l2正则项
  123. reg_loss = 0
  124. for tf_var in tf.trainable_variables():
  125. if not ("fully_connected" in tf_var.name ):
  126. #print(tf_var.name)
  127. reg_loss += tf.reduce_mean(tf.nn.l2_loss(tf_var))
  128. loss = output_loss + lambda_l2_reg * reg_loss
  129. train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss)
  130. '''
  131. 3.训练模型,可视化loss
  132. '''
  133. #seq_2_seq的输入是一个list,需要构建一个list(encoder_input,except_input,decode_input),
  134. #按照这个时间顺序放入,可以不抢位置
  135. sess = tf.InteractiveSession()
  136. def train_batch(batch_size):
  137. X, Y = generate_data(isTrain=True, batch_size=batch_size) #[40,100.1]
  138. #这里是赋值操作
  139. feed_dict = {encoder_input[t]: X[t] for t in range(len(encoder_input))} # 40 组 每一组长100个
  140. feed_dict.update({expected_output[t]: Y[t] for t in range(len(expected_output))}) #80组
  141. #dict.update(dict2) dict.update(dict) 用法
  142. #decode_input的输入重要说明,将其第一列输入变为零,做为初始输入的标记,接上未来序列。
  143. #Y的最后一列并没有作为decoder的输入
  144. c =np.concatenate(( [np.zeros_like(Y[0])],Y[:-1]),axis = 0)#c [40,100,1]
  145. feed_dict.update({decode_input[t]: c[t] for t in range(len(c))}) #decoder数据喂入 #100组
  146. _, loss_t = sess.run([train_op, loss], feed_dict)
  147. return loss_t
  148. def test_batch(batch_size):
  149. X, Y = generate_data(isTrain=True, batch_size=batch_size)
  150. feed_dict = {encoder_input[t]: X[t] for t in range(len(encoder_input))} #encoder_input
  151. feed_dict.update({expected_output[t]: Y[t] for t in range(len(expected_output))})#实际值
  152. #[np.zeros_like(Y[0])],100个0,其他Y分别往后面移动一位,构成新的c
  153. c =np.concatenate(( [np.zeros_like(Y[0])],Y[:-1]),axis = 0)
  154. feed_dict.update({decode_input[t]: c[t] for t in range(len(c))})
  155. output_lossv,reg_lossv,loss_t = sess.run([output_loss,reg_loss,loss], feed_dict)
  156. print("-----------------")
  157. print(output_lossv,reg_lossv)
  158. return loss_t
  159. # Training
  160. train_losses = []
  161. test_losses = []
  162. sess.run(tf.global_variables_initializer())
  163. for t in range(nb_iters + 1):
  164. train_loss = train_batch(batch_size)
  165. train_losses.append(train_loss)
  166. if t % 200 == 0:
  167. test_loss = test_batch(batch_size)
  168. test_losses.append(test_loss)
  169. print("Step {}/{}, train loss: {}, \tTEST loss: {}".format(t,nb_iters, train_loss, test_loss))
  170. print("Fin. train loss: {}, \tTEST loss: {}".format(train_loss, test_loss)) #最终结果
  171. # 画损失函数
  172. #test 损失
  173. plt.figure(figsize=(12, 6))#画布大小
  174. plt.plot(np.array(range(0, len(test_losses))) /
  175. float(len(test_losses) - 1) * (len(train_losses) - 1),
  176. #应为test_loss并不是每次都进行了计算,整200的计算,故把横坐标映射到那么长去
  177. np.log(test_losses),label="Test loss")
  178. #训练损失,随着时间迭代
  179. plt.plot(np.log(train_losses),label="Train loss")
  180. plt.title("Training errors over time (on a logarithmic scale)")
  181. plt.xlabel('Iteration')#横坐标迭代次数
  182. plt.ylabel('log(Loss)')#纵坐标对数误差
  183. plt.legend(loc='best')
  184. plt.show()
  185. '''
  186. #4.用训练好的模型, 随机选取5次进行预测,并且可视化结果
  187. '''
  188. nb_predictions = 5
  189. print("visualize {} predictions data:".format(nb_predictions))
  190. preout =[]
  191. X, Y = generate_data(isTrain=False, batch_size=nb_predictions)
  192. print(np.shape(X),np.shape(Y))
  193. for tt in range(seq_length):
  194. feed_dict = {encoder_input[t]: X[t+tt] for t in range(seq_length)}
  195. feed_dict.update({expected_output[t]: Y[t+tt] for t in range(len(expected_output))})
  196. c =np.concatenate(( [np.zeros_like(Y[0])],Y[tt:seq_length+tt-1]),axis = 0) #从前15个的最后一个开始预测
  197. feed_dict.update({decode_input[t]: c[t] for t in range(len(c))})
  198. outputs = np.array(sess.run([reshaped_outputs], feed_dict)[0])
  199. preout.append(outputs[-1])
  200. print(np.shape(preout)) #将每个未知预测值收集起来准备显示出来。
  201. preout =np.reshape(preout,[seq_length,nb_predictions,output_dim])
  202. for j in range(nb_predictions):
  203. plt.figure(figsize=(12, 3))
  204. for k in range(output_dim):
  205. past = X[:, j, k]
  206. expected = Y[seq_length-1:, j, k]#对应预测值的打印
  207. pred = preout[:, j, k]
  208. label1 = "past" if k == 0 else "_nolegend_"
  209. label2 = "future" if k == 0 else "_nolegend_"
  210. label3 = "Pred" if k == 0 else "_nolegend_"
  211. plt.plot(range(len(past)), past, "o--b", label=label1)
  212. plt.plot(range(len(past), len(expected) + len(past)),
  213. expected, "x--b", label=label2)
  214. plt.plot(range(len(past), len(pred) + len(past)),
  215. pred, "o--y", label=label3)
  216. plt.legend(loc='best')
  217. plt.title("Predictions vs. future")
  218. plt.show()

4.结果展示

图 一

图1为训练中loss值的变化,当然,在可视化时,我们取了对数。

图二

图二,我们使用训练好的模型,随机抽取了一部分数据,用来它的预测股票收盘价,并了相关对比。发现预测还是相对准确的。

在上面代码中,我们画了5张图,这里只上传了一张。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号