pytorch的数据都要使用叫tensor的类型,这个类型的数据应该是为pytorch量身打造的,为后面能够自动微分打下基础,所有的数据类型都应该转化为tensor这个类型
自动微分是为了解决机器学习的反馈问题,非常方便,自动微分要配合损失函数和优化器使用
定义需要的网络模型结构,要继承,要定义forward函数
import torch
from torch import nn
from torch.autograd import Variable
import numpy as np
import matplotlib.pyplot as plt
#设定种子 保证随机数的产生在程序每次执行时都一样
torch.manual_seed(1)
#---------------- 定义一个RNN 网络模型 --------------------
class My_RNN(nn.Module):
def __init__(self):
super(My_RNN,self).__init__()
# 建立一个基础的RNN网络层
self.rnn = nn.RNN(
input_size= 1, # 输入向量的特征维数
hidden_size=8, # 中间隐藏层节点数
num_layers= 1, # 隐藏层数
nonlinearity= 'relu', # 非线性激活函数
bias= True, # 是否有偏置项
batch_first= True, # 输入数据的格式 (batch_size,step_size,feature_dimension)
dropout= 0.1, # 随机丢失系数 ,防止过拟合
bidirectional= False #
)
# 建立输出层
self.out = nn.Linear(self.rnn.hidden_size,1) #输出层把RNN层的32维输出转化为一维输出
# 前向传递函数,这个函数必须写
def forward(self,x,state):
"""
:param x: (batch, time_step, input_size)
:param state: (n_layers, batch, hidden_size)
:return: (batch, time_step, output_size)
"""
out,state = self.rnn(x,state) #中间层运算
out = self.out(out) #输出层运算
return out, state
def train_rnn(self,data_input, data_output, epochs=1, step_size=1, state=None):
"""
:param data_input: 输入数据一个numpy数组序列
:param data_output: 输出数据一个numpy数组序列
:param epochs: 训练数据上跑的遍数
:param step_size: 时间步长
:param state: RNN神经网络的中间状态
:return:
"""
# ------- 产生一个优化器对象 -------------------
optimizer = torch.optim.Adam(rnn.parameters(), lr=0.02)
# ---------产生一个损失函数对象 ------------------
loss_func = nn.MSELoss()
for epoch in range(epochs):
steps = np.int(np.floor(data_input.shape[0] / step_size))
for step in range(np.int(steps)):
train_data_in = data_input[step * step_size:(step + 1) * step_size].reshape(1, step_size, 1) #训练数据必须满足(batch_size,Step_size,featur_num)格式
train_data_in = Variable(torch.from_numpy(train_data_in)) # 包装训练数据
train_data_out = data_output[step * step_size:(step + 1) * step_size]
# 前向计算网络输出
prediction, state = self.forward(train_data_in, state)
state = Variable(state.data) # 包装state,下一次循环接着用
# 计算误差,做负反馈
prediction = prediction.reshape(step_size, )
train_data_out = torch.from_numpy(train_data_out).reshape(step_size, )
loss = loss_func(prediction, train_data_out) # 计算误差
optimizer.zero_grad() # clear gradients for this training step
loss.backward() # backpropagation, compute gradients
optimizer.step() # apply gradients 更新参数
# -------------绘图--------------------
if step == 1: # 每个epoch绘制一次,每个epoch的第一次step绘制
plt.plot(np.linspace(0, step_size, step_size, dtype=int), train_data_out.flatten(), 'r-')
plt.plot(np.linspace(0, step_size, step_size, dtype=int), prediction.data.numpy().flatten(), 'b-')
plt.show()
# -------------------产生训练数据---------------
steps = np.linspace(0*np.pi,50*np.pi,500,dtype=np.float32)
A = np.linspace(2000,0,500,dtype=np.float32)
data_input = np.sin(steps) * A + np.cos(2*steps) * (0.5 * A)
data_output = np.cos(steps) * A + np.sin(5*steps) * (0.5 * A)
#
# #-------------------产生测试数据,从训练数据里面选 --------------------
#
test_steps = np.linspace(0*np.pi,5*np.pi,100,dtype=np.float32)
data_input_test = data_input[100:200].reshape(1,100,1)
data_input_test = torch.from_numpy(data_input_test)
data_output_test = data_output[100:200]
# ------- 产生一个RNN模型的对象 -----------------
rnn = My_RNN()
print(rnn)
# -------------开始训练 --------------------
rnn.train_rnn(data_input,data_output,20,10)
# -----------利用训练模型产生预测结果------------
state = None #中间隐藏层状态 可以初始化为None
Pre,state = rnn(data_input_test,state)
#把预测结果画出来
plt.plot(test_steps,data_input_test.flatten(),'g') #输入数据
plt.plot(test_steps,data_output_test.flatten(),'r-') #输出真实数据
plt.plot(test_steps,Pre.data.numpy().flatten(),'b-') #输出预测数据
plt.show()
RNN的输入是一个三维的数据,第一维和第二维可以互换,分别表示计算批次大小batch_size或者时间步长step_size,第三维必须是数据的特征维,另外RNN的输入除了这种方式之外,也可以是一种打包好的数据格式,利用pytorch函数
torch.nn.utils.rnn.pack_padded_sequence(input, lengths, batch_first=False, enforce_sorted=True)
这个函数跑一下就就理解了,它是针对输入的step_size大小不一样而作的计算优化
tensor_in = torch.FloatTensor([[1,2,3],[1,0,0]]).resize_(2,3,1)
tensor_in = Variable(tensor_in)
print(tensor_in)
print(tensor_in.shape)
seq_lengths = [3, 3]
pack = nn_utils.rnn.pack_padded_sequence(tensor_in,seq_lengths,batch_first=True)
print(pack)
a = torch.randn((30,1)).reshape(2,5,3)
print(a)
网络层数影响很大
节点数影响也较大
简单的回归问题,网络层数不要太高,节点数也不要太多