1
0
mirror of https://github.com/microsoft/qlib.git synced 2026-07-16 17:12:20 +08:00

Add ALSTM config

This commit is contained in:
Jactus
2020-11-25 19:29:30 +08:00
parent 05599d1de8
commit a99db6a1dc
10 changed files with 139 additions and 53 deletions

View File

@@ -196,10 +196,12 @@ Here is a list of models built on `Qlib`.
- [MLP based on pytorch](qlib/contrib/model/pytorch_nn.py) - [MLP based on pytorch](qlib/contrib/model/pytorch_nn.py)
- [GRU based on pytorch](qlib/contrib/model/pytorch_gru.py) - [GRU based on pytorch](qlib/contrib/model/pytorch_gru.py)
- [LSTM based on pytorcn](qlib/contrib/model/pytorch_lstm.py) - [LSTM based on pytorcn](qlib/contrib/model/pytorch_lstm.py)
- [ALSTM based on pytorcn](qlib/contrib/model/pytorch_alstm.py)
- [GATs based on pytorch](qlib/contrib/model/pytorch_gats.py) - [GATs based on pytorch](qlib/contrib/model/pytorch_gats.py)
- [TabNet based on pytorch](qlib/contrib/model/tabnet.py) - [TabNet based on pytorch](qlib/contrib/model/tabnet.py)
- [SFM based on pytorch](qlib/contrib/model/pytorch_sfm.py) - [SFM based on pytorch](qlib/contrib/model/pytorch_sfm.py)
<!-- - [TFT based on tensorflow](examples/benchmarks/TFT/tft.py) --> - [HATs based on pytorch](qlib/contrib/model/pytorch_hats.py)
- [TFT based on tensorflow](examples/benchmarks/TFT/tft.py)
Your PR of new Quant models is highly welcomed. Your PR of new Quant models is highly welcomed.

View File

@@ -0,0 +1,4 @@
numpy==1.17.4
pandas==1.1.2
scikit_learn==0.23.2
torch==1.7.0

View File

@@ -0,0 +1,69 @@
provider_uri: "~/.qlib/qlib_data/cn_data"
region: cn
market: &market csi300
benchmark: &benchmark SH000300
data_handler_config: &data_handler_config
start_time: 2008-01-01
end_time: 2020-08-01
fit_start_time: 2008-01-01
fit_end_time: 2014-12-31
instruments: *market
port_analysis_config: &port_analysis_config
strategy:
class: TopkDropoutStrategy
module_path: qlib.contrib.strategy.strategy
kwargs:
topk: 50
n_drop: 5
backtest:
verbose: False
limit_threshold: 0.095
account: 100000000
benchmark: *benchmark
deal_price: close
open_cost: 0.0005
close_cost: 0.0015
min_cost: 5
task:
model:
class: ALSTM
module_path: qlib.contrib.model.pytorch_alstm
kwargs:
d_feat: 6
hidden_size: 64
num_layers: 2
dropout: 0.0
n_epochs: 200
lr: 1e-3
early_stop: 20
batch_size: 800
metric: IC
loss: mse
seed: 0
GPU: 0
rnn_type: GRU
dataset:
class: DatasetH
module_path: qlib.data.dataset
kwargs:
handler:
class: ALPHA360_Denoise
module_path: qlib.contrib.data.handler
kwargs: *data_handler_config
segments:
train: [2008-01-01, 2014-12-31]
valid: [2015-01-01, 2016-12-31]
test: [2017-01-01, 2020-08-01]
record:
- class: SignalRecord
module_path: qlib.workflow.record_temp
kwargs: {}
- class: SigAnaRecord
module_path: qlib.workflow.record_temp
kwargs:
ana_long_short: False
ann_scaler: 252
- class: PortAnaRecord
module_path: qlib.workflow.record_temp
kwargs:
config: *port_analysis_config

View File

@@ -74,7 +74,7 @@ if __name__ == "__main__":
"loss": "mse", "loss": "mse",
"seed": 0, "seed": 0,
"GPU": 0, "GPU": 0,
"rnn_type": "GRU" "rnn_type": "GRU",
}, },
}, },
"dataset": { "dataset": {

View File

@@ -100,7 +100,7 @@ if __name__ == "__main__":
# model = train_model(task) # model = train_model(task)
model = init_instance_by_config(task["model"]) model = init_instance_by_config(task["model"])
dataset = init_instance_by_config(task["dataset"]) dataset = init_instance_by_config(task["dataset"])
model.fit(dataset,save_path='benchmarks/HATS/model_hat.pkl') model.fit(dataset, save_path="benchmarks/HATS/model_hat.pkl")
pred_score = model.predict(dataset) pred_score = model.predict(dataset)

View File

@@ -345,7 +345,6 @@ class GRUModel(nn.Module):
return self.fc_out(out[:, -1, :]).squeeze() return self.fc_out(out[:, -1, :]).squeeze()
class ALSTMModel(nn.Module): class ALSTMModel(nn.Module):
def __init__(self, d_feat=6, hidden_size=64, num_layers=2, dropout=0.0, rnn_type="GRU"): def __init__(self, d_feat=6, hidden_size=64, num_layers=2, dropout=0.0, rnn_type="GRU"):
super().__init__() super().__init__()
@@ -360,23 +359,25 @@ class ALSTMModel(nn.Module):
try: try:
klass = getattr(nn, self.rnn_type.upper()) klass = getattr(nn, self.rnn_type.upper())
except: except:
raise ValueError('unknown rnn_type `%s`' % self.rnn_type) raise ValueError("unknown rnn_type `%s`" % self.rnn_type)
self.net = nn.Sequential() self.net = nn.Sequential()
self.net.add_module('fc_in', nn.Linear(in_features=self.input_size, out_features=self.hid_size)) self.net.add_module("fc_in", nn.Linear(in_features=self.input_size, out_features=self.hid_size))
self.net.add_module('act', nn.Tanh()) self.net.add_module("act", nn.Tanh())
self.rnn = klass(input_size=self.hid_size, self.rnn = klass(
input_size=self.hid_size,
hidden_size=self.hid_size, hidden_size=self.hid_size,
num_layers=self.rnn_layer, num_layers=self.rnn_layer,
batch_first=True, batch_first=True,
dropout=self.dropout) dropout=self.dropout,
)
self.fc_out = nn.Linear(in_features=self.hid_size * 2, out_features=1) self.fc_out = nn.Linear(in_features=self.hid_size * 2, out_features=1)
# self.fc_out = nn.Linear(in_features=self.hid_size, out_features=1) # self.fc_out = nn.Linear(in_features=self.hid_size, out_features=1)
self.att_net = nn.Sequential() self.att_net = nn.Sequential()
self.att_net.add_module('att_fc_in', nn.Linear(in_features=self.hid_size, out_features=int(self.hid_size/2))) self.att_net.add_module("att_fc_in", nn.Linear(in_features=self.hid_size, out_features=int(self.hid_size / 2)))
self.att_net.add_module('att_dropout', torch.nn.Dropout(self.dropout)) self.att_net.add_module("att_dropout", torch.nn.Dropout(self.dropout))
self.att_net.add_module('att_act', nn.Tanh()) self.att_net.add_module("att_act", nn.Tanh())
self.att_net.add_module('att_fc_out', nn.Linear(in_features=int(self.hid_size/2), out_features=1, bias=False)) self.att_net.add_module("att_fc_out", nn.Linear(in_features=int(self.hid_size / 2), out_features=1, bias=False))
self.att_net.add_module('att_softmax', nn.Softmax(dim=1)) self.att_net.add_module("att_softmax", nn.Softmax(dim=1))
def forward(self, inputs): def forward(self, inputs):
# inputs: [batch_size, input_size*input_day] # inputs: [batch_size, input_size*input_day]
@@ -386,7 +387,8 @@ class ALSTMModel(nn.Module):
attention_score = self.att_net(rnn_out) # [batch, seq_len, 1] attention_score = self.att_net(rnn_out) # [batch, seq_len, 1]
out_att = torch.mul(rnn_out, attention_score) out_att = torch.mul(rnn_out, attention_score)
out_att = torch.sum(out_att, dim=1) out_att = torch.sum(out_att, dim=1)
out = self.fc_out(torch.cat((rnn_out[:, -1, :], out_att), dim=1)) # [batch, seq_len, num_directions * hidden_size] -> [batch, 1] out = self.fc_out(
torch.cat((rnn_out[:, -1, :], out_att), dim=1)
) # [batch, seq_len, num_directions * hidden_size] -> [batch, 1]
# out = self.fc_out(rnn_out[:, -1, :] + out_att) # out = self.fc_out(rnn_out[:, -1, :] + out_att)
return out[..., 0] return out[..., 0]

View File

@@ -265,12 +265,14 @@ class GAT(Model):
self.logger.info("Loading pretrained model...") self.logger.info("Loading pretrained model...")
if self.base_model == "LSTM": if self.base_model == "LSTM":
from ...contrib.model.pytorch_lstm import LSTMModel from ...contrib.model.pytorch_lstm import LSTMModel
pretrained_model = LSTMModel() pretrained_model = LSTMModel()
pretrained_model.load_state_dict(torch.load('benchmarks/LSTM/model_lstm_csi300.pkl')) pretrained_model.load_state_dict(torch.load("benchmarks/LSTM/model_lstm_csi300.pkl"))
elif self.base_model == "GRU": elif self.base_model == "GRU":
from ...contrib.model.pytorch_gru import GRUModel from ...contrib.model.pytorch_gru import GRUModel
pretrained_model = GRUModel() pretrained_model = GRUModel()
pretrained_model.load_state_dict(torch.load('benchmarks/GRU/model_gru_csi300.pkl')) pretrained_model.load_state_dict(torch.load("benchmarks/GRU/model_gru_csi300.pkl"))
model_dict = self.GAT_model.state_dict() model_dict = self.GAT_model.state_dict()
pretrained_dict = {k: v for k, v in pretrained_model.state_dict().items() if k in model_dict} pretrained_dict = {k: v for k, v in pretrained_model.state_dict().items() if k in model_dict}
model_dict.update(pretrained_dict) model_dict.update(pretrained_dict)

View File

@@ -265,12 +265,14 @@ class HATS(Model):
self.logger.info("loading pretrained model...") self.logger.info("loading pretrained model...")
if self.base_model == "LSTM": if self.base_model == "LSTM":
from ...contrib.model.pytorch_lstm import LSTMModel from ...contrib.model.pytorch_lstm import LSTMModel
pretrained_model = LSTMModel() pretrained_model = LSTMModel()
pretrained_model.load_state_dict(torch.load('benchmarks/LSTM/model_lstm_csi300.pkl')) pretrained_model.load_state_dict(torch.load("benchmarks/LSTM/model_lstm_csi300.pkl"))
elif self.base_model == "GRU": elif self.base_model == "GRU":
from ...contrib.model.pytorch_gru import GRUModel from ...contrib.model.pytorch_gru import GRUModel
pretrained_model = GRUModel() pretrained_model = GRUModel()
pretrained_model.load_state_dict(torch.load('benchmarks/GRU/model_gru_csi300.pkl')) pretrained_model.load_state_dict(torch.load("benchmarks/GRU/model_gru_csi300.pkl"))
model_dict = self.HATS_model.state_dict() model_dict = self.HATS_model.state_dict()
# filter unnecessary parameters # filter unnecessary parameters
@@ -281,7 +283,6 @@ class HATS(Model):
self.HATS_model.load_state_dict(model_dict) self.HATS_model.load_state_dict(model_dict)
self.logger.info("loading pretrained model Done...") self.logger.info("loading pretrained model Done...")
# train # train
self.logger.info("training...") self.logger.info("training...")
self._fitted = True self._fitted = True
@@ -387,7 +388,9 @@ class HATSModel(nn.Module):
dims = [d_feat] + [d * nh for (d, nh) in zip(hidden_dim, num_head_att[:-1])] + [num_head_att[-1]] dims = [d_feat] + [d * nh for (d, nh) in zip(hidden_dim, num_head_att[:-1])] + [num_head_att[-1]]
in_dims = dims[:-1] in_dims = dims[:-1]
out_dims = [d // nh for (d, nh) in zip(dims[1:], num_head_att)] out_dims = [d // nh for (d, nh) in zip(dims[1:], num_head_att)]
self.attn = nn.ModuleList([GraphAttention(i, o, nh, dropout) for (i, o, nh) in zip(in_dims, out_dims,num_head_att)]) self.attn = nn.ModuleList(
[GraphAttention(i, o, nh, dropout) for (i, o, nh) in zip(in_dims, out_dims, num_head_att)]
)
self.bns = nn.ModuleList([nn.BatchNorm1d(dim) for dim in dims[1:-1]]) self.bns = nn.ModuleList([nn.BatchNorm1d(dim) for dim in dims[1:-1]])
self.dropout = nn.Dropout(dropout) self.dropout = nn.Dropout(dropout)
self.elu = nn.ELU() self.elu = nn.ELU()
@@ -406,9 +409,7 @@ class HATSModel(nn.Module):
return self.fc_out(output).squeeze() return self.fc_out(output).squeeze()
class GraphAttention(nn.Module): class GraphAttention(nn.Module):
def __init__(self, input_dim, output_dim, num_heads, dropout=0.5): def __init__(self, input_dim, output_dim, num_heads, dropout=0.5):
super().__init__() super().__init__()
@@ -466,7 +467,6 @@ class GraphAttention(nn.Module):
mapped_nodes = [mapping[v] for v in nodes] mapped_nodes = [mapping[v] for v in nodes]
indices = torch.LongTensor([[v, c] for (v, row) in zip(mapped_nodes, rows) for c in row]).t() indices = torch.LongTensor([[v, c] for (v, row) in zip(mapped_nodes, rows) for c in row]).t()
out = [] out = []
for k in range(self.num_heads): for k in range(self.num_heads):
h = self.fcs[k](features) h = self.fcs[k](features)
@@ -494,4 +494,11 @@ class GraphAttention(nn.Module):
att = att_x.mm(torch.t(att_y)) att = att_x.mm(torch.t(att_y))
x_att = x.reshape(x.shape[0], 1, x.shape[1]).repeat(1, y.shape[0], 1) x_att = x.reshape(x.shape[0], 1, x.shape[1]).repeat(1, y.shape[0], 1)
y_att = y.reshape(1, y.shape[0], y.shape[1]).repeat(x.shape[0], 1, 1) y_att = y.reshape(1, y.shape[0], y.shape[1]).repeat(x.shape[0], 1, 1)
return torch.mean(x.reshape(x.shape[0], 1, x.shape[1]).repeat(1, y.shape[0], 1)*y.reshape(1, y.shape[0], y.shape[1]).repeat(x.shape[0], 1, 1), dim = 2)-att return (
torch.mean(
x.reshape(x.shape[0], 1, x.shape[1]).repeat(1, y.shape[0], 1)
* y.reshape(1, y.shape[0], y.shape[1]).repeat(x.shape[0], 1, 1),
dim=2,
)
- att
)