先说几个常用的可以下载数据集的地方
- 平台:kaggle(https://www.kaggle.com/datasets)
和鲸社区(https://www.heywhale.com/home)
阿里天池(https://tianchi.aliyun.com/)
- 其他:海量公开数据集汇总-CSDN博客
下面使用的数据集来源与计算股票数据集 | Kaggle
普通神经网络处理序列数据
我们尝试一下用普通神经网络处理序列数据,下面是一个股票相关的序列数据
import pandas as pd
import os,math
from sklearn.preprocessing import MinMaxScaler
from sklearn import metrics
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('SH600519.csv')
data
我们取其中一列作为预测的 y 值,图像大概如下所示
dataset = data.iloc[:, 2:3].values
plt.plot(dataset)
下面对数据进行预处理
max_value = np.max(dataset)
min_value = np.min(dataset)
scalar = max_value - min_value #也可以直接用MinMaxScaler(feature_range=(0, 1))
dataset = list(map(lambda x: x / scalar, dataset))
def create_dataset(dataset, look_back=5):
dataX, dataY = [], []
for i in range(len(dataset) - look_back):
a = dataset[i:(i + look_back)]
dataX.append(a)
dataY.append(dataset[i + look_back])
return np.array(dataX), np.array(dataY)
# 创建好输入输出
data_X, data_Y = create_dataset(dataset)
data_X =data_X.reshape(-1,5)
# 划分训练集和测试集,70% 作为训练集
train_size = int(len(data_X) * 0.7)
test_size = len(data_X) - train_size
train_X = data_X[:train_size]
train_Y = data_Y[:train_size]
test_X = data_X[train_size:]
test_Y = data_Y[train_size:]
look_back = 5
train_x = torch.from_numpy(train_X)
train_y = torch.from_numpy(train_Y)
test_x = torch.from_numpy(test_X)
构建普通神经网络
class FullyConnected(nn.Module):
def __init__(self, x_size, hidden_size, output_size=1):
super(FullyConnected, self).__init__()
self.hidden_size = hidden_size
self.linear_with_tanh = nn.Sequential(
nn.Linear(x_size, self.hidden_size), # 线性层1
nn.Tanh(), # 激活函数
nn.Linear(self.hidden_size, self.hidden_size), #线性层2
nn.Tanh(), #激活函数
nn.Linear(self.hidden_size, output_size) #线性层
)
def forward(self, x):
yhat = self.linear_with_tanh(x)
return yhat
开始训练
fc_model = FullyConnected(x_size=5, hidden_size = 3)
criterion = nn.MSELoss() #损失函数类型:多分类(CrossEntropyLoss),均方误差(MSELoss),二分类(BCELoss)
optimizer = torch.optim.Adam(fc_model.parameters(), lr=1e-2)
## 开始训练
for e in range(1000):
# 前向传播
for i in range(len(train_x)):
x_train = train_x[i]
y_train = train_y[i]
out = fc_model(x_train)
loss = criterion(out, y_train)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (e + 1) % 100 == 0: # 每 100 次输出结果
print('Epoch: {}, Loss: {:.5f}'.format(e + 1, loss.item()))
fc_model = fc_model.eval() # 转换成测试模式
data_X = torch.from_numpy(data_X)
var_data = Variable(data_X)
pred_test = fc_model(var_data) # 测试集的预测结果
# 改变输出的格式
pred_test = pred_test.view(-1).data.numpy()
# 画出实际结果和预测的结果
plt.plot(pred_test, 'r', label='prediction')
plt.plot(dataset, 'b', label='real')
plt.legend(loc='best')
这里插播一下之前讲过的梯度下降方法,其实只需要改成下面代码就够了【从0到1搞懂大模型】神经网络长什么样子?参数又是如何变化的?(2)-CSDN博客
- 普通梯度下降:torch.optim.SGD
- adagrad:torch.optim.Adagrad
- RMSprop:torch.optim.RMSprop
- Adam:torch.optim.Adam
最终得到的曲线如下
我们可以发现,普通神经网络对于这样一个小小的序列数据预测效果还是很差的,那怎么办呢?下面引出我们的循环神经网络——RNN
RNN
在实际应用中,我们会遇到很多序列数据 如:
- 自然语言处理问题。x1可以看做是第一个单词,x2可以看做是第二个单词,依次类推。
- 语音处理。此时,x1、x2、x3……是每帧的声音信号。
- 时间序列问题。例如每天的股票价格等等。
序列形的数据不太好用原始的神经网络处理了。
为了建模序列问题,RNN引入了隐状态h(hidden state)的概念,h可以对序列形的数据提取特征,接着再转换为输出。
先从h1的计算开始看:
其实整体来说就是每次处理新数据时,它会结合当前的输入和之前的“记忆”(即隐藏状态)。
接下来我们用 RNN 再对刚才的数据集做预测
import pandas as pd
import os,math
from sklearn.preprocessing import MinMaxScaler
from sklearn import metrics
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('SH600519.csv')
dataset = data.iloc[:, 2:3].values
plt.plot(dataset)
dataset = dataset.astype('float32')
max_value = np.max(dataset)
min_value = np.min(dataset)
scalar = max_value - min_value
dataset = list(map(lambda x: x / scalar, dataset))
def create_dataset(dataset, look_back=5):
dataX, dataY = [], []
for i in range(len(dataset) - look_back):
a = dataset[i:(i + look_back)]
dataX.append(a)
dataY.append(dataset[i + look_back])
return np.array(dataX), np.array(dataY)
data_X, data_Y = create_dataset(dataset)
# 划分训练集和测试集,70% 作为训练集
train_size = int(len(data_X) * 0.7)
test_size = len(data_X) - train_size
train_X = data_X[:train_size]
train_Y = data_Y[:train_size]
test_X = data_X[train_size:]
test_Y = data_Y[train_size:]
train_X = train_X.reshape(-1, 1, 5)
train_Y = train_Y.reshape(-1, 1, 1)
test_X = test_X.reshape(-1, 1, 5)
train_x = torch.from_numpy(train_X) #如果是把torch转为numpy则用array = torch_data.numpy()
train_y = torch.from_numpy(train_Y)
test_x = torch.from_numpy(test_X)
# 定义模型
class rnn_reg(nn.Module):
def __init__(self, input_size, hidden_size, output_size=1, num_layers=2):
super(rnn_reg, self).__init__()
self.rnn = nn.RNN(input_size, hidden_size, num_layers) # rnn
self.reg = nn.Linear(hidden_size, output_size) # 线性层
def forward(self, x):
x, _ = self.rnn(x) # (seq, batch, hidden)
s, b, h = x.shape
x = x.view(s*b, h) # 转换成线性层的输入格式
x = self.reg(x)
x = x.view(s, b, -1)
return x
net = rnn_reg(5, 3)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=1e-2)
for e in range(1000):
# 前向传播
out = net(train_x)
loss = criterion(out, train_y)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (e + 1) % 100 == 0: # 每 100 次输出结果
print('Epoch: {}, Loss: {:.5f}'.format(e + 1, loss.item()))
net = net.eval() # 转换成测试模式
data_X = data_X.reshape(-1, 1, 5)
data_X = torch.from_numpy(data_X)
var_data = Variable(data_X)
pred_test = net(var_data) # 测试集的预测结果
# 改变输出的格式
pred_test = pred_test.view(-1).data.numpy()
# 画出实际结果和预测的结果
plt.plot(pred_test, 'r', label='prediction')
plt.plot(dataset, 'b', label='real')
plt.legend(loc='best')
这次用了 RNN,预测结果如下
可以看到对于序列数据,RNN 效果比普通神经网络好很多!
具体来说,RNN有三个核心特点:
-
自带记忆功能
每次处理新数据时,它会结合当前的输入和之前的“记忆”(即隐藏状态)。比如分析“我想吃北京烤鸭”这句话,读到“吃”时,RNN会记住前面有个“我”,从而推测后面大概率是食物名词 -
适合序列任务
像语言翻译、股票预测这类需要联系前后信息的任务,传统神经网络处理不好,而RNN能捕捉时间或顺序的关联性。比如预测明天的气温,它会把今天、昨天的温度变化趋势都考虑进去 -
结构简单但有局限
虽然基础版RNN结构不复杂(输入层+循环隐藏层+输出层),但它容易“记不住太久远的事”。比如分析长篇文章时,可能只记得最近几段的内容,早期的信息会被淡化
举个生活中的例子:就像你背古诗,背到第五句时可能记不清第二句,但能根据第四句推测第五句的内容。RNN也是这样——短期记忆强,但对特别长的序列处理效果会打折扣(后来人们发明了LSTM等改进版解决了这个问题),下次我们就讲一下 LSTM~