Глубокие нейронные сети становятся все более популярными в последние годы и демонстрируют мощные возможности для решения проблем, которые не могли быть решены в прошлом, во многих областях. В прогнозировании временных последовательностей часто используется цена RNN, поскольку RNN имеет не только текущий ввод данных, но и ввод исторических данных. Конечно, когда мы говорим о прогнозировании цен RNN, мы часто говорим о RNN: LSTM. Это руководство предоставлено FMZ, разработчиком цифровой валюты.www.fmz.comВ этом году мы получили более 10 миллионов долларов США, и мы хотим поделиться своими мыслями.
Пример предсказания цены:https://yq.aliyun.com/articles/538484Подробная информация о модели RNN:https://zhuanlan.zhihu.com/p/27485750Понимание ввода и вывода RNN:https://www.zhihu.com/question/41949741/answer/318771336Официальные документы:https://pytorch.org/docsЕсли вы хотите узнать больше, поищите сами. Кроме того, для чтения этой статьи требуется предварительные знания, такие как панды / рептилии / обработка данных, но это не имеет значения.
Параметры LSTM:
Когда я впервые увидел эти сжатые параметры в документах, я сказал:Если читать медленнее, то, наверное, все будет понятно.
input_size
: величина характеристики ввода вектора x, если предсказывать ценой закрытия, то input_size=1; если предсказывать ценой закрытия с высоким открытием и низким закрытием, то input_size=4hidden_size
Размеры скрытых слоев:num_layers
Число слоев RNN:batch_first
: Если для True первым параметром, вводимым для измерения, является batch_size, этот параметр также может быть запутанным, и будет подробно описан ниже.
Параметры ввода данных:
input
: конкретный ввод данных, трехмерный тензор, конкретная форма: ((seq_len, batch, input_size)); в том числе длина последовательности последовательности seq_len, то есть LSTM необходимо учитывать, как долго исторические данные, обратите внимание, что это относится только к формату данных, а не к структуре внутри LSTM, одна и та же модель LSTM может вводить различные данные seq_len, которые могут дать прогнозируемые результаты; batch указывает на размер batch, который представляет собой несколько различных групп данных; input_size является предыдущим input_size.h_0
: первоначальное состояние hidden, с формой ((num_layers * num_directions, batch, hidden_size), если в то время двусторонняя сеть num_directions=2c_0
: начальное состояние клетки, одинаковая форма, не может быть указана.
Выходные параметры:
output
: форма вывода (seq_len, batch, num_directions * hidden_size), внимание и параметры модели batch_firsth_n
: t = состояние h в момент seq_len, с одинаковой формой h_0c_n
: t = состояние c в момент seq_len, с одинаковой формой c_0
Сначала импортируйте необходимые пакеты.
import pandas as pd
import numpy as np
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
Определение модели LSTM
LSTM = nn.LSTM(input_size=5, hidden_size=10, num_layers=2, batch_first=True)
Подготовка к вводу
x = torch.randn(3,4,5)
# x的值为:
tensor([[[ 0.4657, 1.4398, -0.3479, 0.2685, 1.6903],
[ 1.0738, 0.6283, -1.3682, -0.1002, -1.7200],
[ 0.2836, 0.3013, -0.3373, -0.3271, 0.0375],
[-0.8852, 1.8098, -1.7099, -0.5992, -0.1143]],
[[ 0.6970, 0.6124, -0.1679, 0.8537, -0.1116],
[ 0.1997, -0.1041, -0.4871, 0.8724, 1.2750],
[ 1.9647, -0.3489, 0.7340, 1.3713, 0.3762],
[ 0.4603, -1.6203, -0.6294, -0.1459, -0.0317]],
[[-0.5309, 0.1540, -0.4613, -0.6425, -0.1957],
[-1.9796, -0.1186, -0.2930, -0.2619, -0.4039],
[-0.4453, 0.1987, -1.0775, 1.3212, 1.3577],
[-0.5488, 0.6669, -0.2151, 0.9337, -1.1805]]])
И это означает, что x имеет форму ((3, 4, 5)), как мы уже определили.batch_first=True
, тогда размер batch_size будет 3, sqe_len будет 4, input_size будет 5; x[0] будет представлять первую партию.
Если batch_first не определено, то по умолчанию False, то представление данных в этом случае совершенно другое, batch size 4, sqe_len 3, input_size 5; в этом случае x[0] представляет все batch при t=0 данных, соответственно.batch_first=True
.
Поскольку они не имеют возможности передавать данные, они могут использовать их в своих целях.x.permute(1,0,2)
Ввод и вывод
Форма ввода и вывода LSTM может быть легко запутана.
Источник:https://www.zhihu.com/question/41949741/answer/318771336
x = torch.randn(3,4,5)
h0 = torch.randn(2, 3, 10)
c0 = torch.randn(2, 3, 10)
output, (hn, cn) = LSTM(x, (h0, c0))
print(output.size()) #在这里思考一下,如果batch_first=False输出的大小会是多少?
print(hn.size())
print(cn.size())
#结果
torch.Size([3, 4, 10])
torch.Size([2, 3, 10])
torch.Size([2, 3, 10])
Результаты наблюдения совпадают с объяснением предыдущих параметров. Обратите внимание, что второе значение дляhn.size (()) является 3, и размер batch_size совпадает, что указывает на то, что вhn не сохраняется промежуточное состояние, сохраняется только последний шаг. Поскольку наша сеть LSTM состоит из двух уровней, фактически, последний уровень hn выводит значение вывода, который имеет форму [3, 4, 10] и хранит результаты t = 0, 1, 2, 3 во все моменты, так что:
hn[-1][0] == output[0][-1] #第一个batch在hn最后一层的输出等于第一个batch在t=3时output的结果
hn[-1][1] == output[1][-1]
hn[-1][2] == output[2][-1]
Понимание ввода и вывода в LSTM очень важно, иначе легко ошибиться, потому что благодаря мощным возможностям LSTM на временных последовательностях, даже если модель ошибочна, в конечном итоге можно получить хорошие результаты.
Получение данных
Данные, используемые на рынке, относятся к торговым парам BTC_USD на бирже Bitfinex.
import requests
import json
resp = requests.get('https://q.fmz.com/chart/history?symbol=bitfinex.btc_usd&resolution=15&from=0&to=0&from=1525622626&to=1562658565')
data = resp.json()
df = pd.DataFrame(data,columns = ['t','o','h','l','c','v'])
print(df.head(5))
Формат данных следующий:
Преобразование данных
df.index = df['t'] # index设为时间戳
df = (df-df.mean())/df.std() # 数据的标准化,否则模型的Loss会非常大,不利于收敛
df['n'] = df['c'].shift(-1) # n为下一个周期的收盘价,是我们预测的目标
df = df.dropna()
df = df.astype(np.float32) # 改变下数据格式适应pytorch
Методы стандартизации данных очень грубые, и могут возникнуть некоторые проблемы, только демонстрация, которая может использоваться для стандартизации данных, таких как доходность.
Подготовка к тренировке
seq_len = 10 # 输入10个周期的数据
train_size = 800 # 训练集batch_size
def create_dataset(data, seq_len):
dataX, dataY=[], []
for i in range(0,len(data)-seq_len, seq_len):
dataX.append(data[['o','h','l','c','v']][i:i+seq_len].values)
dataY.append(data['n'][i:i+seq_len].values)
return np.array(dataX), np.array(dataY)
data_X, data_Y = create_dataset(df, seq_len)
train_x = torch.from_numpy(data_X[:train_size].reshape(-1,seq_len,5)) #变化形状,-1代表的值会自动计算
train_y = torch.from_numpy(data_Y[:train_size].reshape(-1,seq_len,1))
Формы конечных train_x и train_y: torch.Size (([800, 10, 5]), torch.Size (([800, 10, 1]) ; поскольку наша модель предсказывает цену закрытия следующего цикла на основе данных из 10 циклов, теоретически 800 партий, если только 800 прогнозируемых цены закрытия будут правильными. Но train_y имеет 10 данных в каждой партии, и фактически промежуточные результаты прогнозов каждой партии сохраняются, а не только последний. При расчете конечных потерь все 10 прогнозов могут быть учтены и сравниты с реальными значениями в train_y.
Обратите внимание, что при подготовке тренировочных данных перемещение окна происходит в скользящем режиме, данные, которые уже использовались, больше не используются, и, конечно же, окна могут перемещаться по отдельности, что дает большую сумму тренировочных сборов.
В итоге была построена следующая модель, включающая в себя два слоя LSTM и один LINEAR.
class LSTM(nn.Module):
def __init__(self, input_size, hidden_size, output_size=1, num_layers=2):
super(LSTM, self).__init__()
self.rnn = nn.LSTM(input_size,hidden_size,num_layers,batch_first=True)
self.reg = nn.Linear(hidden_size,output_size) # 线性层,把LSTM的结果输出成一个值
def forward(self, x):
x, _ = self.rnn(x) # 如果不理解前向传播中数据维度的变化,可单独调试
x = self.reg(x)
return x
net = LSTM(5, 10) # input_size为5,代表了高开低收和交易量. 隐含层为10.
Наконец-то началась тренировка, и код был такой:
criterion = nn.MSELoss() # 使用了简单的均方差损失函数
optimizer = torch.optim.Adam(net.parameters(),lr=0.01) # 优化函数,lr可调
for epoch in range(600): # 由于速度很快,这里的epoch多一些
out = net(train_x) # 由于数据量很小, 直接拿全量数据计算
loss = criterion(out, train_y)
optimizer.zero_grad()
loss.backward() # 反向传播损失
optimizer.step() # 更新参数
print('Epoch: {:<3}, Loss:{:.6f}'.format(epoch+1, loss.item()))
Результаты обучения:
Прогноз модели:
p = net(torch.from_numpy(data_X))[:,-1,0] # 这里只取最后一个预测值作为比较
plt.figure(figsize=(12,8))
plt.plot(p.data.numpy(), label= 'predict')
plt.plot(data_Y[:,-1], label = 'real')
plt.legend()
plt.show()
На графике можно увидеть, что совпадение данных о тренировках (до 800) очень высокое, но впоследствии цена на биткоин выросла до тех пор, пока модель не увидела эти данные, и прогноз не сработал. Это также указывает на проблемы при стандартизации данных в прошлом.
Хотя прогнозируемые цены не всегда являются точными, какая же точность прогнозируемого падения?
r = data_Y[:,-1][800:1000]
y = p.data.numpy()[800:1000]
r_change = np.array([1 if i > 0 else 0 for i in r[1:200] - r[:199]])
y_change = np.array([1 if i > 0 else 0 for i in y[1:200] - r[:199]])
print((r_change == y_change).sum()/float(len(r_change)))
В результате прогноз падения составил 81.4%, что намного больше, чем я ожидал.
Конечно, эта модель не имеет никакой реальной ценности, но она проста и понятна, и это только начало для многих других курсов, посвященных квантованию цифровых валют.
ДжекмаКак вы думаете, какие же данные мы получили?
a838899Что это значит, не совсем понятно, используя данные за 800 дней, прогнозируя следующий день или следующие 800 дней.
Орион 1708Почему мы говорим, что эта модель не имеет реальной ценности?