You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
426 lines
14 KiB
Python
426 lines
14 KiB
Python
#https://blog.csdn.net/weixin_35757704/article/details/115910672
|
|
#https://www.bilibili.com/video/BV1hE411t7RN?p=27
|
|
#https://www.zhihu.com/question/39792141
|
|
import numpy as np
|
|
from typing import Union
|
|
import pandas as pd
|
|
from itertools import product
|
|
import torch
|
|
from torch import nn
|
|
from torch.utils.data import DataLoader
|
|
import torchvision
|
|
from sklearn.model_selection import train_test_split
|
|
from sklearn.utils.validation import check_X_y
|
|
import joblib
|
|
from catboost import CatBoostRegressor
|
|
from lightgbm import LGBMRegressor
|
|
from xgboost import XGBRegressor
|
|
from sklearn.metrics import r2_score
|
|
from CNN_architecture import CNN_architecture
|
|
from sklearn.utils import shuffle
|
|
|
|
def get_state_vect_cols(prefix=''):
|
|
if prefix:
|
|
prefix += '_'
|
|
vectors = ['r', 'v']
|
|
components = ['x', 'y', 'z']
|
|
col_names = [f'{prefix}{v}_{c}' for v, c in product(vectors, components)]
|
|
return col_names
|
|
|
|
pd.set_option('display.max_rows', None)
|
|
pd.set_option('display.max_columns', None)
|
|
pd.set_option('display.width', 1000)
|
|
# %%
|
|
df = pd.read_parquet("traindata/physics_preds.parquet")
|
|
test_set = df[df['aso_id'] == "05277"]
|
|
|
|
train_set = df.groupby('aso_id').apply(lambda x: x.head(x.count()[0] - 3))
|
|
print(df.count()[0], train_set.count()[0], test_set.count()[0])
|
|
data_count = df.count()[0]
|
|
|
|
# print(train_set)
|
|
|
|
# %%
|
|
feature_cols = [
|
|
'elapsed_seconds'
|
|
] + get_state_vect_cols('physics_pred') + get_state_vect_cols('start')
|
|
print(feature_cols)
|
|
# The target values are the errors between the physical model predictions
|
|
# and the ground truth observations
|
|
target_cols = get_state_vect_cols('physics_err')
|
|
print(target_cols)
|
|
|
|
print("样本统一归一化处理")
|
|
all_cols = feature_cols + target_cols
|
|
df = df[all_cols]
|
|
df = shuffle(df)
|
|
df = (df - df.mean(axis=0)) / df.std(axis=0)
|
|
# Create feature and target matrices
|
|
feature_cols = ['physics_err_v_x'] + feature_cols
|
|
X = df[feature_cols]
|
|
y = df[target_cols]
|
|
# data_keys = ['X_train', 'X_test', 'y_train', 'y_test']
|
|
# data_vals = train_test_split(X, y, test_size=0.2)
|
|
# train_test_data = dict(zip(data_keys, data_vals))
|
|
# train_test_data['X_test'] = test_set[feature_cols]
|
|
# train_test_data['y_test'] = test_set[target_cols]
|
|
# train_test_data = {
|
|
# 'X_train': train_set[feature_cols],
|
|
# 'y_train': train_set[target_cols],
|
|
# 'X_test': test_set[feature_cols],
|
|
# 'y_test': test_set[target_cols],
|
|
# }
|
|
|
|
# %%
|
|
|
|
import numpy as np
|
|
import torch
|
|
from torch import nn
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
"""
|
|
Github: Yonv1943 Zen4 Jia1 hao2
|
|
https://github.com/Yonv1943/DL_RL_Zoo/blob/master/RNN
|
|
|
|
The source of training data
|
|
https://github.com/L1aoXingyu/
|
|
code-of-learn-deep-learning-with-pytorch/blob/master/
|
|
chapter5_RNN/time-series/lstm-time-series.ipynb
|
|
"""
|
|
|
|
import os
|
|
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
|
|
|
|
def run_train_lstm(X):
|
|
|
|
inp_dim = 14
|
|
out_dim = 1
|
|
mid_dim = 15
|
|
mid_layers = 2
|
|
batch_size = 12 * 4
|
|
mod_dir = '.'
|
|
|
|
'''load data'''
|
|
data = X.values
|
|
pd.set_option('display.max_rows', None)
|
|
pd.set_option('display.max_columns', None)
|
|
pd.set_option('display.width', 1000)
|
|
# np.set_printoptions(threshold='nan')
|
|
# print(data)
|
|
data_x = data[:-1, :]
|
|
data_y = data[+1:, 0]
|
|
# print(data_y)
|
|
assert data_x.shape[1] == inp_dim
|
|
train_size = int(data_count * 0.80)
|
|
|
|
train_x = data_x[:train_size]
|
|
train_y = data_y[:train_size]
|
|
train_x = train_x.reshape((train_size, inp_dim))
|
|
train_y = train_y.reshape((train_size, out_dim))
|
|
|
|
# print(train_y)
|
|
|
|
# X, ys = train_test_data['X_train'], train_test_data['y_train']
|
|
#
|
|
# check_X_y(X, ys, multi_output=True)
|
|
#
|
|
# train_x = X.values
|
|
# train_y = ys['physics_err_r_x'].values
|
|
# train_y = ys.reshape(ys.shape[0], 1)
|
|
|
|
'''build model'''
|
|
# device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
device = torch.device("cuda")
|
|
net = RegLSTM(inp_dim, out_dim, mid_dim, mid_layers).to(device)
|
|
criterion = nn.MSELoss()
|
|
optimizer = torch.optim.Adam(net.parameters(), lr=1e-2)
|
|
|
|
'''train'''
|
|
var_x = torch.tensor(train_x, dtype=torch.float32, device=device)
|
|
var_y = torch.tensor(train_y, dtype=torch.float32, device=device)
|
|
|
|
batch_var_x = list()
|
|
batch_var_y = list()
|
|
|
|
for i in range(batch_size):
|
|
j = batch_size - i
|
|
batch_var_x.append(var_x[j:])
|
|
batch_var_y.append(var_y[j:])
|
|
|
|
from torch.nn.utils.rnn import pad_sequence
|
|
batch_var_x = pad_sequence(batch_var_x)
|
|
batch_var_y = pad_sequence(batch_var_y)
|
|
|
|
with torch.no_grad():
|
|
weights = np.tanh(np.arange(len(train_y)) * (np.e / len(train_y)))
|
|
weights = torch.tensor(weights, dtype=torch.float32, device=device)
|
|
|
|
print("Training Start")
|
|
for e in range(10):
|
|
out = net(batch_var_x)
|
|
|
|
# loss = criterion(out, batch_var_y)
|
|
loss = (out - batch_var_y) ** 2 * weights
|
|
loss = loss.mean()
|
|
|
|
optimizer.zero_grad()
|
|
loss.backward()
|
|
optimizer.step()
|
|
|
|
if e % 64 == 0:
|
|
print('Epoch: {:4}, Loss: {:.5f}'.format(e, loss.item()))
|
|
torch.save(net.state_dict(), '{}/net.pth'.format(mod_dir))
|
|
print("Save in:", '{}/net.pth'.format(mod_dir))
|
|
|
|
'''eval'''
|
|
net.load_state_dict(torch.load('{}/net.pth'.format(mod_dir), map_location=lambda storage, loc: storage))
|
|
net = net.eval()
|
|
|
|
# X1, ys1 = train_test_data['X_test'], train_test_data['y_test']
|
|
# check_X_y(X1, ys1, multi_output=True)
|
|
# test_x = X1.values
|
|
# test_y = ys1['physics_err_r_x'].values
|
|
# test_y = ys1.reshape(ys.shape[0], 1)
|
|
# test_x =
|
|
|
|
|
|
test_x = data_x.copy()
|
|
test_x[train_size:, 0] = 0
|
|
# print(test_x)
|
|
test_x = test_x[:, np.newaxis, :]
|
|
test_x = torch.tensor(test_x, dtype=torch.float32, device=device)
|
|
|
|
'''simple way but no elegant'''
|
|
for i in range(train_size, len(data) - 2):
|
|
test_y = net(test_x[:i])
|
|
test_x[i, 0, 0] = test_y[-1]
|
|
|
|
'''elegant way but slightly complicated'''
|
|
# eval_size = 1
|
|
# zero_ten = torch.zeros((mid_layers, eval_size, mid_dim), dtype=torch.float32, device=device)
|
|
# test_y, hc = net.output_y_hc(test_x[:train_size], (zero_ten, zero_ten))
|
|
# test_x[train_size + 1, 0, 0] = test_y[-1]
|
|
# for i in range(train_size + 1, len(data) - 2):
|
|
# test_y, hc = net.output_y_hc(test_x[i:i + 1], hc)
|
|
# test_x[i + 1, 0, 0] = test_y[-1]
|
|
|
|
pred_y = test_x[1:, 0, 0]
|
|
pred_y = pred_y.cpu().data.numpy()
|
|
print("`````````````````````````")
|
|
print(pred_y.shape)
|
|
diff_y = pred_y[train_size:] - data_y[train_size:-1]
|
|
print("------")
|
|
# print(pred_y[train_size:])
|
|
print("------")
|
|
# print(data_y[train_size:-1])
|
|
r2 = r2_score(data_y[train_size:-1], pred_y[train_size:], multioutput= 'uniform_average')
|
|
evals = []
|
|
eval_dict = {'Error': 'physics_err_v_x', 'R^2': r2}
|
|
evals.append(eval_dict)
|
|
print(pd.DataFrame(evals))
|
|
|
|
l1_loss = np.mean(np.abs(diff_y))
|
|
l2_loss = np.mean(diff_y ** 2)
|
|
print("L1: {:.3f} L2: {:.3f}".format(l1_loss, l2_loss))
|
|
|
|
plt.plot(pred_y, 'r', label='pred')
|
|
plt.plot(data_y, 'b', label='real', alpha=0.3)
|
|
plt.plot([train_size, train_size], [-1, 2], color='k', label='train | pred')
|
|
plt.legend(loc='best')
|
|
plt.savefig('lstm_reg.png')
|
|
plt.pause(4)
|
|
|
|
|
|
def run_origin():
|
|
inp_dim = 2
|
|
out_dim = 1
|
|
mod_dir = '.'
|
|
|
|
'''load data'''
|
|
data = load_data() # axis1: number, year, month
|
|
data_x = np.concatenate((data[:-2, 0:1], data[+1:-1, 0:1]), axis=1)
|
|
data_y = data[2:, 0]
|
|
|
|
train_size = int(len(data_x) * 0.75)
|
|
train_x = data_x[:train_size]
|
|
train_y = data_y[:train_size]
|
|
|
|
train_x = train_x.reshape((-1, 1, inp_dim))
|
|
train_y = train_y.reshape((-1, 1, out_dim))
|
|
|
|
'''build model'''
|
|
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
net = RegLSTM(inp_dim, out_dim, mid_dim=4, mid_layers=2).to(device)
|
|
criterion = nn.SmoothL1Loss()
|
|
optimizer = torch.optim.Adam(net.parameters(), lr=1e-2)
|
|
|
|
'''train'''
|
|
var_x = torch.tensor(train_x, dtype=torch.float32, device=device)
|
|
var_y = torch.tensor(train_y, dtype=torch.float32, device=device)
|
|
print('var_x.size():', var_x.size())
|
|
print('var_y.size():', var_y.size())
|
|
|
|
for e in range(512):
|
|
out = net(var_x)
|
|
loss = criterion(out, var_y)
|
|
|
|
optimizer.zero_grad()
|
|
loss.backward()
|
|
optimizer.step()
|
|
|
|
if (e + 1) % 100 == 0: # 每 100 次输出结果
|
|
print('Epoch: {}, Loss: {:.5f}'.format(e + 1, loss.item()))
|
|
|
|
torch.save(net.state_dict(), '{}/net.pth'.format(mod_dir))
|
|
|
|
'''eval'''
|
|
# net.load_state_dict(torch.load('{}/net.pth'.format(mod_dir), map_location=lambda storage, loc: storage))
|
|
net = net.eval() # 转换成测试模式
|
|
|
|
"""
|
|
inappropriate way of seq prediction:
|
|
use all real data to predict the number of next month
|
|
"""
|
|
test_x = data_x.reshape((-1, 1, inp_dim))
|
|
var_data = torch.tensor(test_x, dtype=torch.float32, device=device)
|
|
eval_y = net(var_data) # 测试集的预测结果
|
|
pred_y = eval_y.view(-1).cpu().data.numpy()
|
|
|
|
plt.plot(pred_y[1:], 'r', label='pred inappr', alpha=0.3)
|
|
plt.plot(data_y, 'b', label='real', alpha=0.3)
|
|
plt.plot([train_size, train_size], [-1, 2], label='train | pred')
|
|
|
|
"""
|
|
appropriate way of seq prediction:
|
|
use real+pred data to predict the number of next 3 years.
|
|
"""
|
|
test_x = data_x.reshape((-1, 1, inp_dim))
|
|
test_x[train_size:] = 0 # delete the data of next 3 years.
|
|
test_x = torch.tensor(test_x, dtype=torch.float32, device=device)
|
|
for i in range(train_size, len(data) - 2):
|
|
test_y = net(test_x[:i])
|
|
test_x[i, 0, 0] = test_x[i - 1, 0, 1]
|
|
test_x[i, 0, 1] = test_y[-1, 0]
|
|
pred_y = test_x.cpu().data.numpy()
|
|
pred_y = pred_y[:, 0, 0]
|
|
plt.plot(pred_y[2:], 'g', label='pred appr')
|
|
|
|
plt.legend(loc='best')
|
|
plt.savefig('lstm_origin.png')
|
|
plt.pause(4)
|
|
|
|
|
|
class RegLSTM(nn.Module):
|
|
def __init__(self, inp_dim, out_dim, mid_dim, mid_layers):
|
|
super(RegLSTM, self).__init__()
|
|
|
|
self.rnn = nn.LSTM(inp_dim, mid_dim, mid_layers) # rnn
|
|
self.reg = nn.Sequential(
|
|
nn.Linear(mid_dim, mid_dim),
|
|
nn.Tanh(),
|
|
nn.Linear(mid_dim, out_dim),
|
|
) # regression
|
|
|
|
def forward(self, x):
|
|
y = self.rnn(x)[0] # y, (h, c) = self.rnn(x)
|
|
|
|
seq_len, batch_size, hid_dim = y.shape
|
|
y = y.view(-1, hid_dim)
|
|
y = self.reg(y)
|
|
y = y.view(seq_len, batch_size, -1)
|
|
return y
|
|
|
|
"""
|
|
PyCharm Crtl+click nn.LSTM() jump to code of PyTorch:
|
|
Examples::
|
|
>>> rnn = nn.LSTM(10, 20, 2)
|
|
>>> input = torch.randn(5, 3, 10)
|
|
>>> h0 = torch.randn(2, 3, 20)
|
|
>>> c0 = torch.randn(2, 3, 20)
|
|
>>> output, (hn, cn) = rnn(input, (h0, c0))
|
|
"""
|
|
|
|
def output_y_hc(self, x, hc):
|
|
y, hc = self.rnn(x, hc) # y, (h, c) = self.rnn(x)
|
|
|
|
seq_len, batch_size, hid_dim = y.size()
|
|
y = y.view(-1, hid_dim)
|
|
y = self.reg(y)
|
|
y = y.view(seq_len, batch_size, -1)
|
|
return y, hc
|
|
|
|
|
|
class RegGRU(nn.Module):
|
|
def __init__(self, inp_dim, out_dim, mod_dim, mid_layers):
|
|
super(RegGRU, self).__init__()
|
|
|
|
self.rnn = nn.GRU(inp_dim, mod_dim, mid_layers)
|
|
self.reg = nn.Linear(mod_dim, out_dim)
|
|
|
|
def forward(self, x):
|
|
x, h = self.rnn(x) # (seq, batch, hidden)
|
|
|
|
seq_len, batch_size, hid_dim = x.shape
|
|
x = x.view(-1, hid_dim)
|
|
x = self.reg(x)
|
|
x = x.view(seq_len, batch_size, -1)
|
|
return x
|
|
|
|
def output_y_h(self, x, h):
|
|
y, h = self.rnn(x, h)
|
|
|
|
seq_len, batch_size, hid_dim = y.size()
|
|
y = y.view(-1, hid_dim)
|
|
y = self.reg(y)
|
|
y = y.view(seq_len, batch_size, -1)
|
|
return y, h
|
|
|
|
|
|
def load_data():
|
|
# passengers number of international airline , 1949-01 ~ 1960-12 per month
|
|
seq_number = np.array(
|
|
[112., 118., 132., 129., 121., 135., 148., 148., 136., 119., 104.,
|
|
118., 115., 126., 141., 135., 125., 149., 170., 170., 158., 133.,
|
|
114., 140., 145., 150., 178., 163., 172., 178., 199., 199., 184.,
|
|
162., 146., 166., 171., 180., 193., 181., 183., 218., 230., 242.,
|
|
209., 191., 172., 194., 196., 196., 236., 235., 229., 243., 264.,
|
|
272., 237., 211., 180., 201., 204., 188., 235., 227., 234., 264.,
|
|
302., 293., 259., 229., 203., 229., 242., 233., 267., 269., 270.,
|
|
315., 364., 347., 312., 274., 237., 278., 284., 277., 317., 313.,
|
|
318., 374., 413., 405., 355., 306., 271., 306., 315., 301., 356.,
|
|
348., 355., 422., 465., 467., 404., 347., 305., 336., 340., 318.,
|
|
362., 348., 363., 435., 491., 505., 404., 359., 310., 337., 360.,
|
|
342., 406., 396., 420., 472., 548., 559., 463., 407., 362., 405.,
|
|
417., 391., 419., 461., 472., 535., 622., 606., 508., 461., 390.,
|
|
432.], dtype=np.float32)
|
|
# assert seq_number.shape == (144, )
|
|
# plt.plot(seq_number)
|
|
# plt.ion()
|
|
# plt.pause(1)
|
|
seq_number = seq_number[:, np.newaxis]
|
|
|
|
# print(repr(seq))
|
|
# 1949~1960, 12 years, 12*12==144 month
|
|
seq_year = np.arange(12)
|
|
seq_month = np.arange(12)
|
|
seq_year_month = np.transpose(
|
|
[np.repeat(seq_year, len(seq_month)),
|
|
np.tile(seq_month, len(seq_year))],
|
|
) # Cartesian Product
|
|
|
|
seq = np.concatenate((seq_number, seq_year_month), axis=1)
|
|
|
|
# normalization
|
|
seq = (seq - seq.mean(axis=0)) / seq.std(axis=0)
|
|
return seq
|
|
|
|
|
|
if __name__ == '__main__':
|
|
run_train_lstm(X)
|
|
# run_train_gru()
|
|
# run_origin()
|
|
|
|
|
|
|