From 52c7076917cbd88bab59b3707285396b71e73a55 Mon Sep 17 00:00:00 2001 From: bxdd Date: Thu, 26 Nov 2020 21:15:21 +0800 Subject: [PATCH 1/4] dnn model opz --- .../benchmarks/DNN/workflow_config_dnn.yaml | 14 ++++++- qlib/contrib/model/pytorch_nn.py | 39 +++++++++++-------- qlib/data/dataset/processor.py | 16 +++++++- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/examples/benchmarks/DNN/workflow_config_dnn.yaml b/examples/benchmarks/DNN/workflow_config_dnn.yaml index 0f9ae7254..bf5bd7c5f 100644 --- a/examples/benchmarks/DNN/workflow_config_dnn.yaml +++ b/examples/benchmarks/DNN/workflow_config_dnn.yaml @@ -1,4 +1,4 @@ -provider_uri: "~/.qlib/qlib_data/cn_data" +provider_uri: "~/.qlib/qlib_data/cn_data_new" region: cn market: &market csi300 benchmark: &benchmark SH000300 @@ -8,6 +8,18 @@ data_handler_config: &data_handler_config fit_start_time: 2008-01-01 fit_end_time: 2014-12-31 instruments: *market + infer_processors: [ + { + "class" : "CSZFillna", + "kwargs":{"fields_group": "feature"} + }, + { + "class" : "Fillna", + "kwargs":{"fields_group": "feature"} + } + ] + learn_processors: ["DropnaLabel", {"class": "CSZScoreNorm", "kwargs": {"fields_group": "label"}}] + port_analysis_config: &port_analysis_config strategy: class: TopkDropoutStrategy diff --git a/qlib/contrib/model/pytorch_nn.py b/qlib/contrib/model/pytorch_nn.py index 9bad755b6..e1b0736e2 100644 --- a/qlib/contrib/model/pytorch_nn.py +++ b/qlib/contrib/model/pytorch_nn.py @@ -49,7 +49,7 @@ class DNNModelPytorch(Model): self, input_dim, output_dim, - layers=(256, 512, 768, 1024, 768, 512, 256, 128, 64), + layers=(256, 512, 768, 512, 256, 128, 64), lr=0.001, max_steps=300, batch_size=2000, @@ -78,7 +78,7 @@ class DNNModelPytorch(Model): self.optimizer = optimizer.lower() self.loss_type = loss self.visible_GPU = GPU - self.use_gpu = torch.cuda.is_available() + self.use_GPU = torch.cuda.is_available() self.logger.info( "DNN parameters setting:" @@ -107,7 +107,7 @@ class DNNModelPytorch(Model): loss, eval_steps, GPU, - self.use_gpu, + self.use_GPU, ) ) @@ -138,7 +138,7 @@ class DNNModelPytorch(Model): ) self._fitted = False - if self.use_gpu: + if self.use_GPU: self.dnn_model.cuda() # set the visible GPU if self.visible_GPU: @@ -157,7 +157,6 @@ class DNNModelPytorch(Model): ) x_train, y_train = df_train["feature"], df_train["label"] x_valid, y_valid = df_valid["feature"], df_valid["label"] - try: wdf_train, wdf_valid = dataset.prepare(["train", "valid"], col_set=["weight"], data_key=DataHandlerLP.DK_L) w_train, w_valid = wdf_train["weight"], wdf_valid["weight"] @@ -181,13 +180,14 @@ class DNNModelPytorch(Model): y_train_values = torch.from_numpy(y_train.values).float() w_train_values = torch.from_numpy(w_train.values).float() train_num = y_train_values.shape[0] - # prepare validation data x_val_auto = torch.from_numpy(x_valid.values).float() y_val_auto = torch.from_numpy(y_valid.values).float() w_val_auto = torch.from_numpy(w_valid.values).float() - - if self.use_gpu: + #print('valiadationx:', x_val_auto) + #print('valiadationy:', y_val_auto) + #print('valiadationw:', w_val_auto) + if self.use_GPU: x_val_auto = x_val_auto.cuda() y_val_auto = y_val_auto.cuda() w_val_auto = w_val_auto.cuda() @@ -206,13 +206,15 @@ class DNNModelPytorch(Model): y_batch_auto = y_train_values[choice] w_batch_auto = w_train_values[choice] - if self.use_gpu: - x_batch_auto = x_batch_auto.float().cuda() - y_batch_auto = y_batch_auto.float().cuda() - w_batch_auto = w_batch_auto.float().cuda() + if self.use_GPU: + x_batch_auto = x_batch_auto.cuda() + y_batch_auto = y_batch_auto.cuda() + w_batch_auto = w_batch_auto.cuda() # forward preds = self.dnn_model(x_batch_auto) + #print('pred_train:', preds.detach().cpu().numpy()) + #print('label_train:', y_batch_auto.cpu().numpy()) cur_loss = self.get_loss(preds, w_batch_auto, y_batch_auto, self.loss_type) cur_loss.backward() self.train_optimizer.step() @@ -230,6 +232,7 @@ class DNNModelPytorch(Model): loss_val = AverageMeter() # forward + preds = self.dnn_model(x_val_auto) cur_loss_val = self.get_loss(preds, w_val_auto, y_val_auto, self.loss_type) loss_val.update(cur_loss_val.item()) @@ -255,7 +258,7 @@ class DNNModelPytorch(Model): # restore the optimal parameters after training ?? self.dnn_model.load_state_dict(torch.load(save_path)) - if self.use_gpu: + if self.use_GPU: torch.cuda.empty_cache() def get_loss(self, pred, w, target, loss_type): @@ -273,16 +276,18 @@ class DNNModelPytorch(Model): if not self._fitted: raise ValueError("model is not fitted yet!") x_test_pd = dataset.prepare("test", col_set="feature") + print(x_test_pd) x_test = torch.from_numpy(x_test_pd.values).float() - if self.use_gpu: + if self.use_GPU: x_test = x_test.cuda() self.dnn_model.eval() with torch.no_grad(): - if self.use_gpu: + if self.use_GPU: preds = self.dnn_model(x_test).detach().cpu().numpy() else: preds = self.dnn_model(x_test).detach().numpy() + print(preds) return pd.Series(np.squeeze(preds), index=x_test_pd.index) def save(self, filename, **kwargs): @@ -331,7 +336,7 @@ class Net(nn.Module): dnn_layers.append(drop_input) for i, (input_dim, hidden_units) in enumerate(zip(layers[:-1], layers[1:])): fc = nn.Linear(input_dim, hidden_units) - activation = nn.ReLU() + activation = nn.LeakyReLU(negative_slope=0.1, inplace=False) bn = nn.BatchNorm1d(hidden_units) seq = nn.Sequential(fc, bn, activation) dnn_layers.append(seq) @@ -354,7 +359,7 @@ class Net(nn.Module): def _weight_init(self): for m in self.modules(): if isinstance(m, nn.Linear): - nn.init.xavier_normal_(m.weight, gain=1) + nn.init.kaiming_normal_(m.weight, a=0.1, mode='fan_in', nonlinearity='leaky_relu') def forward(self, x): cur_output = x diff --git a/qlib/data/dataset/processor.py b/qlib/data/dataset/processor.py index 2201c0891..32b42462f 100755 --- a/qlib/data/dataset/processor.py +++ b/qlib/data/dataset/processor.py @@ -90,6 +90,7 @@ class DropnaLabel(DropnaProcessor): return False + class TanhProcess(Processor): """ Use tanh to process noise data""" @@ -122,7 +123,6 @@ class ProcessInf(Processor): return replace_inf(df) - class Fillna(Processor): """Process NaN""" @@ -202,7 +202,8 @@ class CSZScoreNorm(Processor): def __call__(self, df): # try not modify original dataframe cols = get_group_columns(df, self.fields_group) - df[cols] = df[cols].groupby("datetime").apply(lambda df: (df - df.mean()).div(df.std())) + df[cols] = df[cols].groupby("datetime").apply(lambda x: (x - x.mean()).div(x.std())) + return df @@ -220,3 +221,14 @@ class CSRankNorm(Processor): t *= 3.46 # NOTE: towards unit std df[cols] = t return df + +class CSZFillna(Processor): + """Cross Sectional Fill Nan""" + + def __init__(self, fields_group=None): + self.fields_group = fields_group + + def __call__(self, df): + cols = get_group_columns(df, self.fields_group) + df[cols] = df[cols].groupby("datetime").apply(lambda x: x.fillna(x.mean())) + return df \ No newline at end of file From a144a9c3c6b5c720ad49c214f6e9256f4b742fe1 Mon Sep 17 00:00:00 2001 From: bxdd Date: Fri, 27 Nov 2020 13:00:14 +0800 Subject: [PATCH 2/4] update dnn --- .../benchmarks/DNN/workflow_config_dnn.yaml | 27 ++++++++++++++----- qlib/contrib/data/handler.py | 2 ++ qlib/contrib/model/pytorch_nn.py | 16 +++-------- qlib/data/dataset/processor.py | 10 +++++++ 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/examples/benchmarks/DNN/workflow_config_dnn.yaml b/examples/benchmarks/DNN/workflow_config_dnn.yaml index bf5bd7c5f..023d1cd49 100644 --- a/examples/benchmarks/DNN/workflow_config_dnn.yaml +++ b/examples/benchmarks/DNN/workflow_config_dnn.yaml @@ -10,15 +10,30 @@ data_handler_config: &data_handler_config instruments: *market infer_processors: [ { - "class" : "CSZFillna", - "kwargs":{"fields_group": "feature"} + "class" : "DropCol", + "kwargs":{"col_list": ["VWAP0"]} }, { - "class" : "Fillna", - "kwargs":{"fields_group": "feature"} + "class" : "CSZFillna", + "kwargs":{"fields_group": "feature"} } ] - learn_processors: ["DropnaLabel", {"class": "CSZScoreNorm", "kwargs": {"fields_group": "label"}}] + learn_processors: [ + { + "class" : "DropCol", + "kwargs":{"col_list": ["VWAP0"]} + }, + { + "class" : "DropnaProcessor", + "kwargs":{"fields_group": "feature"} + }, + "DropnaLabel", + { + "class": "CSZScoreNorm", + "kwargs": {"fields_group": "label"} + } + ] + process_type: "independent" port_analysis_config: &port_analysis_config strategy: @@ -42,7 +57,7 @@ task: module_path: qlib.contrib.model.pytorch_nn kwargs: loss: mse - input_dim: 158 + input_dim: 157 output_dim: 1 lr: 0.002 lr_decay: 0.96 diff --git a/qlib/contrib/data/handler.py b/qlib/contrib/data/handler.py index 8cce92907..3668a0cc0 100644 --- a/qlib/contrib/data/handler.py +++ b/qlib/contrib/data/handler.py @@ -171,6 +171,7 @@ class Alpha158(DataHandlerLP): learn_processors=["DropnaLabel", {"class": "CSZScoreNorm", "kwargs": {"fields_group": "label"}}], fit_start_time=None, fit_end_time=None, + process_type=DataHandlerLP.PTYPE_A ): def check_transform_proc(proc_l): new_l = [] @@ -209,6 +210,7 @@ class Alpha158(DataHandlerLP): data_loader=data_loader, infer_processors=infer_processors, learn_processors=learn_processors, + process_type=process_type ) def get_feature_config(self): diff --git a/qlib/contrib/model/pytorch_nn.py b/qlib/contrib/model/pytorch_nn.py index e1b0736e2..47316ebf6 100644 --- a/qlib/contrib/model/pytorch_nn.py +++ b/qlib/contrib/model/pytorch_nn.py @@ -20,7 +20,7 @@ from ...data.dataset import DatasetH from ...data.dataset.handler import DataHandlerLP from ...utils import unpack_archive_with_buffer, save_multiple_parts_file, create_save_path, drop_nan_by_y_index from ...log import get_module_logger, TimeInspector - +from ...workflow import R class DNNModelPytorch(Model): """DNN Model @@ -151,7 +151,6 @@ class DNNModelPytorch(Model): verbose=True, save_path=None, ): - df_train, df_valid = dataset.prepare( ["train", "valid"], col_set=["feature", "label"], data_key=DataHandlerLP.DK_L ) @@ -170,7 +169,6 @@ class DNNModelPytorch(Model): best_loss = np.inf evals_result["train"] = [] evals_result["valid"] = [] - # train self.logger.info("training...") self._fitted = True @@ -184,9 +182,6 @@ class DNNModelPytorch(Model): x_val_auto = torch.from_numpy(x_valid.values).float() y_val_auto = torch.from_numpy(y_valid.values).float() w_val_auto = torch.from_numpy(w_valid.values).float() - #print('valiadationx:', x_val_auto) - #print('valiadationy:', y_val_auto) - #print('valiadationw:', w_val_auto) if self.use_GPU: x_val_auto = x_val_auto.cuda() y_val_auto = y_val_auto.cuda() @@ -200,7 +195,6 @@ class DNNModelPytorch(Model): loss = AverageMeter() self.dnn_model.train() self.train_optimizer.zero_grad() - choice = np.random.choice(train_num, self.batch_size) x_batch_auto = x_train_values[choice] y_batch_auto = y_train_values[choice] @@ -213,16 +207,14 @@ class DNNModelPytorch(Model): # forward preds = self.dnn_model(x_batch_auto) - #print('pred_train:', preds.detach().cpu().numpy()) - #print('label_train:', y_batch_auto.cpu().numpy()) cur_loss = self.get_loss(preds, w_batch_auto, y_batch_auto, self.loss_type) cur_loss.backward() self.train_optimizer.step() loss.update(cur_loss.item()) + R.log_metrics(train_loss=loss.avg, step=step) # validation train_loss += loss.val - # print(loss.val) if step and step % self.eval_steps == 0: stop_steps += 1 train_loss /= self.eval_steps @@ -232,10 +224,10 @@ class DNNModelPytorch(Model): loss_val = AverageMeter() # forward - preds = self.dnn_model(x_val_auto) cur_loss_val = self.get_loss(preds, w_val_auto, y_val_auto, self.loss_type) loss_val.update(cur_loss_val.item()) + R.log_metrics(val_loss=loss_val.val, step=step) if verbose: self.logger.info( "[Epoch {}]: train_loss {:.6f}, valid_loss {:.6f}".format(step, train_loss, loss_val.val) @@ -276,7 +268,6 @@ class DNNModelPytorch(Model): if not self._fitted: raise ValueError("model is not fitted yet!") x_test_pd = dataset.prepare("test", col_set="feature") - print(x_test_pd) x_test = torch.from_numpy(x_test_pd.values).float() if self.use_GPU: x_test = x_test.cuda() @@ -287,7 +278,6 @@ class DNNModelPytorch(Model): preds = self.dnn_model(x_test).detach().cpu().numpy() else: preds = self.dnn_model(x_test).detach().numpy() - print(preds) return pd.Series(np.squeeze(preds), index=x_test_pd.index) def save(self, filename, **kwargs): diff --git a/qlib/data/dataset/processor.py b/qlib/data/dataset/processor.py index 32b42462f..4a2d36e2f 100755 --- a/qlib/data/dataset/processor.py +++ b/qlib/data/dataset/processor.py @@ -90,7 +90,17 @@ class DropnaLabel(DropnaProcessor): return False +class DropCol(Processor): + def __init__(self, col_list=[]): + self.col_list = col_list + def __call__(self, df): + if isinstance(df.columns, pd.MultiIndex): + mask = df.columns.get_level_values(-1).isin(self.col_list) + else: + mask = df.columns.isin(self.col_list) + return df.loc[:, ~mask] + class TanhProcess(Processor): """ Use tanh to process noise data""" From 8b275a60063c9b72c19a24401f827cee866d1a0e Mon Sep 17 00:00:00 2001 From: bxdd Date: Fri, 27 Nov 2020 13:07:18 +0800 Subject: [PATCH 3/4] fix bug --- examples/benchmarks/DNN/workflow_config_dnn.yaml | 2 +- qlib/contrib/data/handler.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/benchmarks/DNN/workflow_config_dnn.yaml b/examples/benchmarks/DNN/workflow_config_dnn.yaml index 023d1cd49..e01c4eb3a 100644 --- a/examples/benchmarks/DNN/workflow_config_dnn.yaml +++ b/examples/benchmarks/DNN/workflow_config_dnn.yaml @@ -1,4 +1,4 @@ -provider_uri: "~/.qlib/qlib_data/cn_data_new" +provider_uri: "~/.qlib/qlib_data/cn_data" region: cn market: &market csi300 benchmark: &benchmark SH000300 diff --git a/qlib/contrib/data/handler.py b/qlib/contrib/data/handler.py index e61d26254..f74c2cebc 100644 --- a/qlib/contrib/data/handler.py +++ b/qlib/contrib/data/handler.py @@ -207,7 +207,7 @@ class Alpha158(DataHandlerLP): learn_processors=_DEFAULT_LEARN_PROCESSORS, fit_start_time=None, fit_end_time=None, - process_type=DataHandlerLP.PTYPE_A + process_type=DataHandlerLP.PTYPE_A, **kwargs, ): infer_processors = check_transform_proc(infer_processors, fit_start_time, fit_end_time) From ae757a4b5198a75c8650548acef52aac9a33f73e Mon Sep 17 00:00:00 2001 From: bxdd Date: Fri, 27 Nov 2020 13:09:40 +0800 Subject: [PATCH 4/4] black format --- qlib/contrib/data/handler.py | 2 +- qlib/contrib/model/pytorch_alstm.py | 1 - qlib/contrib/model/pytorch_nn.py | 3 ++- qlib/data/dataset/processor.py | 7 +++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/qlib/contrib/data/handler.py b/qlib/contrib/data/handler.py index f74c2cebc..e97b00c24 100644 --- a/qlib/contrib/data/handler.py +++ b/qlib/contrib/data/handler.py @@ -226,7 +226,7 @@ class Alpha158(DataHandlerLP): data_loader=data_loader, infer_processors=infer_processors, learn_processors=learn_processors, - process_type=process_type + process_type=process_type, ) def get_feature_config(self): diff --git a/qlib/contrib/model/pytorch_alstm.py b/qlib/contrib/model/pytorch_alstm.py index 8f5ddc486..1b23d2401 100644 --- a/qlib/contrib/model/pytorch_alstm.py +++ b/qlib/contrib/model/pytorch_alstm.py @@ -146,7 +146,6 @@ class ALSTM(Model): raise ValueError("unknown metric `%s`" % self.metric) - def train_epoch(self, x_train, y_train): x_train_values = x_train.values diff --git a/qlib/contrib/model/pytorch_nn.py b/qlib/contrib/model/pytorch_nn.py index 47316ebf6..d324e27aa 100644 --- a/qlib/contrib/model/pytorch_nn.py +++ b/qlib/contrib/model/pytorch_nn.py @@ -22,6 +22,7 @@ from ...utils import unpack_archive_with_buffer, save_multiple_parts_file, creat from ...log import get_module_logger, TimeInspector from ...workflow import R + class DNNModelPytorch(Model): """DNN Model @@ -349,7 +350,7 @@ class Net(nn.Module): def _weight_init(self): for m in self.modules(): if isinstance(m, nn.Linear): - nn.init.kaiming_normal_(m.weight, a=0.1, mode='fan_in', nonlinearity='leaky_relu') + nn.init.kaiming_normal_(m.weight, a=0.1, mode="fan_in", nonlinearity="leaky_relu") def forward(self, x): cur_output = x diff --git a/qlib/data/dataset/processor.py b/qlib/data/dataset/processor.py index fc85ccde9..76cf85c4a 100755 --- a/qlib/data/dataset/processor.py +++ b/qlib/data/dataset/processor.py @@ -100,7 +100,8 @@ class DropCol(Processor): else: mask = df.columns.isin(self.col_list) return df.loc[:, ~mask] - + + class TanhProcess(Processor): """ Use tanh to process noise data""" @@ -133,6 +134,7 @@ class ProcessInf(Processor): return replace_inf(df) + class Fillna(Processor): """Process NaN""" @@ -270,6 +272,7 @@ class CSRankNorm(Processor): df[cols] = t return df + class CSZFillna(Processor): """Cross Sectional Fill Nan""" @@ -279,4 +282,4 @@ class CSZFillna(Processor): def __call__(self, df): cols = get_group_columns(df, self.fields_group) df[cols] = df[cols].groupby("datetime").apply(lambda x: x.fillna(x.mean())) - return df \ No newline at end of file + return df