Jaringan syaraf dalam telah menjadi semakin populer dalam beberapa tahun terakhir. Jaringan ini telah memecahkan masalah yang tidak dapat diselesaikan di masa lalu di banyak bidang dan telah menunjukkan kemampuannya yang kuat. Dalam prediksi deret waktu, harga jaringan syaraf yang umum digunakan adalah RNN, karena tidak hanya memiliki input data saat ini, tetapi juga input data historis. Tentu saja, ketika kita berbicara tentang prediksi harga RNN, kita sering berbicara tentang salah satu RNN: LSTM. Makalah ini akan membangun model untuk memprediksi harga Bitcoin berdasarkan PyTorch. Meskipun ada banyak informasi yang relevan di Internet, itu masih tidak cukup menyeluruh, dan masih ada relatif sedikit orang yang menggunakan PyTorch. Masih perlu menulis artikel. Hasil akhir adalah menggunakan harga pembukaan, harga penutupan, harga perdagangan tertinggi, harga terendah, dan volume penutupan Bitcoin berikutnya. Tutorial ini diproduksi oleh platform FMZ Quant Trading (www.fmz.comSelamat datang untuk bergabung dengan kelompok QQ: 863946592 untuk komunikasi.
Data harga Bitcoin berasal dari platform FMZ Quant Trading:https://www.quantinfo.com/Tools/View/4.htmlAku tidak tahu. Contoh yang terkait dengan prediksi harga:https://yq.aliyun.com/articles/538484Aku tidak tahu. Pendahuluan rinci tentang model RNN:https://zhuanlan.zhihu.com/p/27485750Aku tidak tahu. Memahami input dan output RNN:https://www.zhihu.com/question/41949741/answer/318771336Aku tidak tahu. Tentang pytorch: dokumentasi resmi:https://pytorch.org/docsUntuk informasi lain, Anda dapat mencari sendiri. Selain itu, Anda membutuhkan beberapa pengetahuan sebelumnya untuk membaca artikel ini, seperti panda / python / pemrosesan data, tetapi tidak masalah jika Anda tidak.
Parameter LSTM:
Pertama kali saya melihat parameter padat ini pada dokumen, reaksi saya adalah: apa ini?
Seiring saya membaca perlahan, akhirnya saya mengerti.
input_size
: Masukkan ukuran karakteristik vektor x. Jika harga penutupan diprediksi oleh harga penutupan, maka input_size=1; Jika harga penutupan diprediksi oleh pembukaan tinggi dan penutupan rendah, maka input_size=4.hidden_size
: Ukuran lapisan implisitnum_layers
: Jumlah lapisan RNN.batch_first
: Jika benar, dimensi input pertama adalah batch_size, yang juga sangat membingungkan, dan akan dijelaskan secara rinci di bawah ini.
Masukkan parameter data:
input
: Data input spesifik adalah tensor tiga dimensi, dan bentuk spesifiknya adalah: (seq_len, batch, input_size). Di mana, seq_len mengacu pada panjang urutan, yaitu berapa lama LSTM perlu mempertimbangkan data historis. Perhatikan bahwa ini mengacu pada format data saja, bukan struktur internal LSTM. Model LSTM yang sama dapat memasukkan data seqs_lenh_0
: Keadaan tersembunyi awal, bentuknya seperti (num_layers * num_directions, batch, hidden_size), jika jaringan dua arah, num_directions=2.c_0
: Keadaan sel awal, bentuk seperti di atas, dapat tidak ditentukan.
Parameter output:
output
: Bentuk output (seq_len, batch, num_directions * hidden_size), perhatikan bahwa hal ini terkait dengan model batch_first parameter.h_n
: Negara h pada saat t = seq_len, bentuk yang sama dengan h_0.c_n
: Negara c pada saat t = seq_len, bentuk yang sama dengan c_0.
Mengimpor paket yang diperlukan terlebih dahulu
import pandas as pd
import numpy as np
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
Mendefinisikan model LSTM
LSTM = nn.LSTM(input_size=5, hidden_size=10, num_layers=2, batch_first=True)
Siapkan data masukan
x = torch.randn(3,4,5)
# The value of x is:
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]]])
Bentuk x adalah (3,4,5), karena kita mendefinisikanbatch_first=True
sebelumnya, ukuran batch_size pada saat ini adalah 3, sqe_len adalah 4, input_size adalah 5. X [0] mewakili batch pertama.
Jika batch_first tidak didefinisikan, nilai default adalah False, maka representasi data benar-benar berbeda pada saat ini. ukuran batch adalah 4, sqe_len adalah 3, input_size adalah 5. Pada saat ini, x [0] mewakili data dari semua batch ketika t = 0, dan seterusnya. Saya merasa bahwa pengaturan ini tidak intuitif, jadi saya menambahkan parameterbatch_first=True
.
Konversi data antara keduanya juga sangat nyaman:x.permute (1,0,2)
Input dan output
Bentuk input dan output LSTM sangat membingungkan, dan gambar berikut dapat membantu kita memahami:
Dari: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()) # Thinking about it, what would be the size of the output if batch_first=False?
print(hn.size())
print(cn.size())
# result
torch.Size([3, 4, 10])
torch.Size([2, 3, 10])
torch.Size([2, 3, 10])
Perhatikan hasil output, yang konsisten dengan interpretasi parameter sebelumnya. Perhatikan bahwa nilai kedua hn.size() adalah 3, yang konsisten dengan ukuran batch_size, yang berarti bahwa keadaan perantara tidak disimpan di hn, hanya langkah terakhir yang disimpan. Karena jaringan LSTM kami memiliki dua lapisan, sebenarnya output dari lapisan terakhir hn adalah nilai output. bentuk output adalah [3, 4, 10], yang menyimpan hasil pada semua waktu t = 0,1,2,3, jadi:
hn[-1][0] == output[0][-1] # The output of the first batch at the last level of hn is equal to the output of the first batch at t=3.
hn[-1][1] == output[1][-1]
hn[-1][2] == output[2][-1]
Hal ini sangat penting untuk memahami input dan output LSTM. Jika tidak, mudah untuk membuat kesalahan dengan secara acak mengekstrak beberapa kode dari Internet. Karena kemampuan kuat LSTM dalam deret waktu, bahkan jika modelnya salah, hasil yang baik dapat diperoleh pada akhirnya.
Pengumpulan data
Data pasar dari pasangan perdagangan BTC_USD di Bitfinex Exchange digunakan.
import requests
import json
resp = requests.get('https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1562658565')
data = resp.json()
df = pd.DataFrame(data,columns = ['t','o','h','l','c','v'])
print(df.head(5))
Format data adalah sebagai berikut:
Pemrosesan pra data
df.index = df['t'] # index is set to timestamp
df = (df-df.mean())/df.std() # The standardization of the data, otherwise the loss of the model will be very large, which is not conducive to convergence.
df['n'] = df['c'].shift(-1) # n is the closing price of the next period, which is our forecast target.
df = df.dropna()
df = df.astype(np.float32) # Change the data format to fit pytorch.
Metode standardisasi data sangat kasar, dan akan ada beberapa masalah. hanya untuk demonstrasi, Anda dapat menggunakan standardisasi data seperti tingkat pengembalian.
Siapkan data pelatihan
seq_len = 10 # Input 10 periods of data
train_size = 800 # Training set 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)) # The change in shape, -1 represents the value that will be calculated automatically.
train_y = torch.from_numpy(data_Y[:train_size].reshape(-1,seq_len,1))
Bentuk akhir dari train_x dan train_y adalah: torch.Size ([800, 10, 5]), torch.Size ([800, 10, 1]). Karena model kami memprediksi harga penutupan periode berikutnya berdasarkan data 10 periode, ada 800 batch secara teori, selama ada 800 harga penutupan yang diprediksi. Tetapi train_y dalam setiap batch memiliki 10 data. Sebenarnya, hasil perantara dari setiap prediksi batch disimpan. Saat menghitung kerugian akhir, semua 10 hasil prediksi dapat dipertimbangkan dan dibandingkan dengan nilai aktual di train_y. Secara teoritis, kita hanya dapat menghitung kerugian dari hasil prediksi terakhir. Karena model LSTM tidak mengandung parameter seq_lenful sebenarnya, sehingga model dapat diterapkan pada berbagai panjang, dan hasil prediksi di tengah juga berarti, jadi saya lebih memilih untuk menggabungkan dan menghitung kerugian.
Perhatikan bahwa ketika menyiapkan data pelatihan, gerakan jendela melompat, dan data yang sudah digunakan tidak lagi digunakan. Tentu saja, jendela juga dapat dipindahkan satu per satu, sehingga set pelatihan yang diperoleh jauh lebih besar. Namun, saya merasa bahwa data batch yang berdekatan terlalu berulang, jadi saya mengadopsi metode saat ini.
Model akhir dibangun sebagai berikut, yang berisi LSTM dua lapisan dan lapisan linier.
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) # Linear layer, output the result of LSTM into a value.
def forward(self, x):
x, _ = self.rnn(x) # If you don't understand the change of data dimension in forward propagation, you can debug it separately.
x = self.reg(x)
return x
net = LSTM(5, 10) # input_size is 5, which represents the high opening and low closing and trading volume. The implicit layer is 10.
Akhirnya kita mulai pelatihan, kode adalah sebagai berikut:
criterion = nn.MSELoss() # A simple mean square error loss function is used.
optimizer = torch.optim.Adam(net.parameters(),lr=0.01) # Optimize function, lr is adjustable.
for epoch in range(600): # Because of the speed, there are more epochs here.
out = net(train_x) # Due to the small amount of data, the full amount of data is directly used for calculation.
loss = criterion(out, train_y)
optimizer.zero_grad()
loss.backward() # Reverse propagation losses
optimizer.step() # Update parameters
print('Epoch: {:<3}, Loss:{:.6f}'.format(epoch+1, loss.item()))
Hasil pelatihan adalah sebagai berikut:
Nilai yang diprediksi dari model:
p = net(torch.from_numpy(data_X))[:,-1,0] # Only the last predicted value is taken here for comparison.
plt.figure(figsize=(12,8))
plt.plot(p.data.numpy(), label= 'predict')
plt.plot(data_Y[:,-1], label = 'real')
plt.legend()
plt.show()
Dari grafik dapat dilihat bahwa data pelatihan (sebelum 800) sangat konsisten, tetapi harga Bitcoin telah naik di periode berikutnya. Model tidak melihat data ini, sehingga prediksi tidak memadai. Ini juga menunjukkan bahwa ada masalah dalam standarisasi data. Meskipun harga yang diprediksi mungkin tidak akurat, berapa akurasi prediksi kenaikan dan penurunan?
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)))
Hasilnya, tingkat akurasi dalam memprediksi kenaikan dan penurunan mencapai 81,4%, yang masih melebihi harapan saya.
Tentu saja, model ini tidak berlaku untuk bot nyata, tapi itu sederhana dan mudah dipahami. hanya mulai dengan itu. selanjutnya, akan ada lebih banyak kursus pengantar aplikasi jaringan saraf dalam kuantifikasi mata uang digital.