文章目录
-
- 一、文件主要结构
- 二、lib.utlis 函数 `load_graphdata_channel1`
- 三、lib.utlis函数`get_adjacency_matrix`
- 四、函数`train_main`
- 五、函数`predict_main`
- 六、lib.metrics中的函数`masked_mae`
- 七、lib.utlis函数`compute_val_loss_mstgcn`
- 八、lib.utils函数`predict_and_save_results_mstgcn`
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import os
from time import time
import shutil
import argparse
import configparser
from model.ASTGCN_r import make_model
from lib.utils import load_graphdata_channel1, get_adjacency_matrix, compute_val_loss_mstgcn, predict_and_save_results_mstgcn
from tensorboardX import SummaryWriter
在这里主要讲解训练的主函数以及在主函数中引用的函数。
一、文件主要结构
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
parser = argparse.ArgumentParser()
parser.add_argument("--config", default='configurations/PEMS04_astgcn.conf', type=str,
help="configuration file path")
args = parser.parse_args()
config = configparser.ConfigParser()
print('Read configuration file: %s' % (args.config))
config.read(args.config)
data_config = config['Data']
training_config = config['Training']
adj_filename = data_config['adj_filename']
graph_signal_matrix_filename = data_config['graph_signal_matrix_filename']
if config.has_option('Data', 'id_filename'):
id_filename = data_config['id_filename']
else:
id_filename = None
num_of_vertices = int(data_config['num_of_vertices'])
points_per_hour = int(data_config['points_per_hour'])
num_for_predict = int(data_config['num_for_predict'])
len_input = int(data_config['len_input'])
dataset_name = data_config['dataset_name']
model_name = training_config['model_name']
''' ctx = mx.gpu(int(ctx[ctx.index('-') + 0:])) '''
ctx = training_config['ctx']
os.environ["CUDA_VISIBLE_DEVICES"] = ctx
USE_CUDA = torch.cuda.is_available()
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("CUDA:", USE_CUDA, DEVICE)
learning_rate = float(training_config['learning_rate'])
epochs = int(training_config['epochs'])
start_epoch = int(training_config['start_epoch'])
batch_size = int(training_config['batch_size'])
num_of_weeks = int(training_config['num_of_weeks'])
num_of_days = int(training_config['num_of_days'])
num_of_hours = int(training_config['num_of_hours'])
time_strides = num_of_hours
nb_chev_filter = int(training_config['nb_chev_filter'])
nb_time_filter = int(training_config['nb_time_filter'])
in_channels = int(training_config['in_channels'])
nb_block = int(training_config['nb_block'])
K = int(training_config['K'])
loss_function = training_config['loss_function']
metric_method = training_config['metric_method']
missing_value = float(training_config['missing_value'])
folder_dir = '%s_h%dd%dw%d_channel%d_%e' % (model_name, num_of_hours, num_of_days, num_of_weeks, in_channels, learning_rate)
print('folder_dir:', folder_dir)
params_path = os.path.join('experiments', dataset_name, folder_dir)
print('params_path:', params_path)
train_loader, train_target_tensor, val_loader, val_target_tensor, test_loader, test_target_tensor, _mean, _std \
= load_graphdata_channel1(graph_signal_matrix_filename, num_of_hours,num_of_days, num_of_weeks, device, batch_size)
adj_mx, distance_mx = get_adjacency_matrix(adj_filename, num_of_vertices, id_filename)
if __name__ == "__main__":
train_main()
二、lib.utlis 函数 load_graphdata_channel1
变量名称 |
类型 |
举例 |
graph_signal_matrix_filename |
str |
./data/PEMS04/PEMS04.npz |
num_of_weeks |
int |
0 |
num_of_days |
int |
0 |
num_of_hours |
int |
1 |
DEVICE |
|
CPU |
batch_size |
int |
32 |
1. 文件路径的拼接结果: ./data/PEMS04\PEMS04_r1_d0_w0_astcgn.npz
2. 数据读取为file_data
3. 获得'特征数据'及'标签数据',特征中为F=3,现选择第一个特征[0:1]。
4. shape如下(seq,N,F,T)
* train: [10181, 307, 1, 12] train_target: [10181, 307, 12]
* val: [3394, 307, 1, 12] val_target: [3394, 307, 12]
* test: [3394, 307, 1, 12] test_target: [3394, 307, 12]
5. 获得关于F这一轴的均值和标准差
* PEMS04Mean: (1, 1, 1, 1)
* PEMS04Std: (1, 1, 1, 1)
6. train_loader的数据生成:
生成Tensor:train_x_tensor和train_target_tensor
函数TensorDataset生成相同格式的迭代器:train_dataset,
该迭代器介绍:
for tx,ty in train_dataset:共循环B=10181次
tx.shape=(N,F,T)=(307,1,12)
ty.shape=(N,F,T) =(307,1,12)
7. test_loader的数据生成:
生成Tensor:test_x_tensor和test_target_tensor
函数TensorDataset生成相同格式的迭代器:test_dataset,
该迭代器介绍:
for tx,ty in train_dataset:共循环B=3394次
tx.shape=(N,F,T)=(307,1,12)
ty.shape=(N,F,T) =(307,1,12)
8. val_loader的数据生成
生成Tensor:val_x_tensor和val_target_tensor
函数TensorDataset生成相同格式的迭代器:val_dataset,
该迭代器介绍:
for tx,ty in train_dataset:共循环B=3394次
tx.shape=(N,F,T)=(307,1,12)
ty.shape=(N,F,T) =(307,1,12)
变量名称 |
类型 |
shape |
用途 |
train_loader |
迭代器 |
len=319 |
每个迭代含dx,dy;dx和dy的shape都为(32,307,1,12) |
train_target_tensor |
Tensor |
[10181, 307, 12] |
训练部分的标签 |
val_loader |
迭代器 |
len=107 |
每个迭代含dx,dy;dx和dy的shape都为(32,307,1,12) |
val_target_tensor |
Tensor |
[3394, 307, 12] |
验证部分的标签 |
test_loader |
迭代器 |
len=107 |
每个迭代含dx,dy;dx和dy的shape都为(32,307,1,12) |
test_target_tensor |
Tensor |
[3394, 307, 12] |
测试部分的标签 |
mean |
Tensor |
[1,1,1,] |
整个数据集关于F[0:1]的均值 |
std |
Tensor |
[1,1,1,1] |
整个数据集关于F[0:1]的标准差 |
def load_graphdata_channel1(graph_signal_matrix_filename, num_of_hours, num_of_days, num_of_weeks, DEVICE, batch_size, shuffle=True):
'''
这个是为PEMS的数据准备的函数
将x,y都处理成归一化到[-1,1]之前的数据;
每个样本同时包含所有监测点的数据,所以本函数构造的数据输入时空序列预测模型;
该函数会把hour, day, week的时间串起来;
注: 从文件读入的数据,x是最大最小归一化的,但是y是真实值
这个函数转为mstgcn,astgcn设计,返回的数据x都是通过减均值除方差进行归一化的,y都是真实值
:return:
three DataLoaders, each dataloader contains:
test_x_tensor: (B, N_nodes, in_feature, T_input)
test_decoder_input_tensor: (B, N_nodes, T_output)
test_target_tensor: (B, N_nodes, T_output)
'''
file = os.path.basename(graph_signal_matrix_filename).split('.')[0]
dirpath = os.path.dirname(graph_signal_matrix_filename)
filename = os.path.join(dirpath,
file + '_r' + str(num_of_hours) + '_d' + str(num_of_days) + '_w' + str(num_of_weeks)) +'_astcgn'
print('load file:', filename)
file_data = np.load(filename + '.npz')
train_x = file_data['train_x']
train_x = train_x[:, :, 0:1, :]
train_target = file_data['train_target']
val_x = file_data['val_x']
val_x = val_x[:, :, 0:1, :]
val_target = file_data['val_target']
test_x = file_data['test_x']
test_x = test_x[:, :, 0:1, :]
test_target = file_data['test_target']
mean = file_data['mean'][:, :, 0:1, :]
std = file_data['std'][:, :, 0:1, :]
train_x_tensor = torch.from_numpy(train_x).type(torch.FloatTensor).to(DEVICE)
train_target_tensor = torch.from_numpy(train_target).type(torch.FloatTensor).to(DEVICE)
train_dataset = torch.utils.data.TensorDataset(train_x_tensor, train_target_tensor)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=shuffle)
val_x_tensor = torch.from_numpy(val_x).type(torch.FloatTensor).to(DEVICE)
val_target_tensor = torch.from_numpy(val_target).type(torch.FloatTensor).to(DEVICE)
val_dataset = torch.utils.data.TensorDataset(val_x_tensor, val_target_tensor)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=False)
test_x_tensor = torch.from_numpy(test_x).type(torch.FloatTensor).to(DEVICE)
test_target_tensor = torch.from_numpy(test_target).type(torch.FloatTensor).to(DEVICE)
test_dataset = torch.utils.data.TensorDataset(test_x_tensor, test_target_tensor)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
print('train:', train_x_tensor.size(), train_target_tensor.size())
print('val:', val_x_tensor.size(), val_target_tensor.size())
print('test:', test_x_tensor.size(), test_target_tensor.size())
return train_loader, train_target_tensor, val_loader, val_target_tensor, test_loader, test_target_tensor, mean, std
注释:
- PyTorch之torch.utils.data.DataLoader详解
DataLoader(dataset,batch_size=32,shuttle=True,drop_last=True):批次为32,在每次迭代训练时将数据洗牌,并丢弃最后一批数据,因为最后一批数据可能要
疑问❓,这里的最后一批的数据集的batch_size ≠ 32 \neq 32 =32,为什么不通过drop_last=True
丢掉呢??
三、lib.utlis函数get_adjacency_matrix
变量 |
类型 |
举例 |
distance_df_filename |
str |
./data/PEMS04/distance.csv |
num_of_vertices |
int |
307 |
id_filename |
|
None |
1. 如果是.npy格式邻接矩阵直接np.load读取并返回A,None
2. 否则读取.csv格式的数据
3. 根据顶点个数创建全0的array数组A, distanceA
4. 如果id_filename有内容的话,。。。。,然会A,distanceA
5. 否则的话,用csv打开distance_df_filename,数据填充进A和distanceA并返回
* A 是无权的邻接矩阵(0-1)
* distanceA是加权的邻接矩阵
def get_adjacency_matrix(distance_df_filename, num_of_vertices, id_filename=None):
'''
Returns
----------
A: np.ndarray, adjacency matrix
'''
if 'npy' in distance_df_filename:
adj_mx = np.load(distance_df_filename)
return adj_mx, None
else:
import csv
A = np.zeros((int(num_of_vertices), int(num_of_vertices)),dtype=np.float32)
distaneA = np.zeros((int(num_of_vertices), int(num_of_vertices)),dtype=np.float32)
if id_filename:
with open(id_filename, 'r') as f:
id_dict = {int(i): idx for idx, i in enumerate(f.read().strip().split('\n'))}
with open(distance_df_filename, 'r') as f:
f.readline()
reader = csv.reader(f)
for row in reader:
if len(row) != 3:
continue
i, j, distance = int(row[0]), int(row[1]), float(row[2])
A[id_dict[i], id_dict[j]] = 1
distaneA[id_dict[i], id_dict[j]] = distance
return A, distaneA
else:
with open(distance_df_filename, 'r') as f:
f.readline()
reader = csv.reader(f)
for row in reader:
if len(row) != 3:
continue
i, j, distance = int(row[0]), int(row[1]), float(row[2])
A[i, j] = 1
distaneA[i, j] = distance
return A, distaneA
四、函数train_main
变量 |
类型 |
举例 |
用途 |
start_epoch |
int |
0 |
模型训练开始的轮次 |
params_path |
str |
experiments\PEMS04\astgcn_r_h1d0w0_channel1_1.000000e-03 |
参数保存的路径 |
masked_flag |
int |
0或1 |
用来选择控制损失函数 |
global_step |
int |
init 0 |
全局变量,记录当前训练轮次 |
best_epoch |
int |
init 0 |
记录验证模型最好的轮次 |
best_val_loss |
float |
init 无穷大 |
记录验证最好的结果 |
#######准备工作#######
1. 通过start_epoch和params_path组合来保证参数保存的路径的正确性和可靠性
2. 打印相关参数
3. masked_flag和loss_function控制2个损失函数criterion和criterion_masked
4. 使用Adam方法初始化优化器optimizer
5. 初始化SummaryWriter以将信息写入日志目录
6. 打印net模型、net's state_dict、Optimizer's state_dict
7. 如果不是从0开始训练,则获得参数文件,net加载参数
8. 设置初始全局变量:global_step = 0 best_epoch = 0,best_val_loss为无穷大
#####模型训练#######
for epoch in range(start_epoch, epochs)
a. 参数文件路径的获取部分
b. 模型验证部分
c. 模型训练部分
net.train()
for ...train_loader:
获取数据inputs,label
梯度设置为0
outputs=net(inputs)
根据masked_flag获得损失值loss
loss.backward()向后函数
optimizer.step()优化
training_loss = loss.item()损失值剥离
global_step += 1训练次数+1
sw.add_scalar 写入日志
#####获取最优net####
打印best_val_loss和best_epoch
并根据获得最优的net
使用 predict_main函数预测最优结果
def train_main():
if (start_epoch == 0) and (not os.path.exists(params_path)):
os.makedirs(params_path)
print('create params directory %s' % (params_path))
elif (start_epoch == 0) and (os.path.exists(params_path)):
shutil.rmtree(params_path)
os.makedirs(params_path)
print('delete the old one and create params directory %s' % (params_path))
elif (start_epoch > 0) and (os.path.exists(params_path)):
print('train from params directory %s' % (params_path))
else:
raise SystemExit('Wrong type of model!')
print('param list:')
print('CUDA\t', device)
print('in_channels\t', in_channels)
print('nb_block\t', nb_block)
print('nb_chev_filter\t', nb_chev_filter)
print('nb_time_filter\t', nb_time_filter)
print('time_strides\t', time_strides)
print('batch_size\t', batch_size)
print('graph_signal_matrix_filename\t', graph_signal_matrix_filename)
print('start_epoch\t', start_epoch)
print('epochs\t', epochs)
masked_flag=0
criterion = nn.L1Loss().to(device)
criterion_masked = masked_mae
if loss_function=='masked_mse':
criterion_masked = masked_mse
masked_flag=1
elif loss_function=='masked_mae':
criterion_masked = masked_mae
masked_flag = 1
elif loss_function == 'mae':
criterion = nn.L1Loss().to(device)
masked_flag = 0
elif loss_function == 'rmse':
criterion = nn.MSELoss().to(device)
masked_flag= 0
optimizer = optim.Adam(net.parameters(), lr=learning_rate)
sw = SummaryWriter(logdir=params_path, flush_secs=5)
print(net)
print('Net\'s state_dict:')
total_param = 0
for param_tensor in net.state_dict():
print(param_tensor, '\t', net.state_dict()[param_tensor].size())
total_param += np.prod(net.state_dict()[param_tensor].size())
print('Net\'s total params:', total_param)
print('Optimizer\'s state_dict:')
for var_name in optimizer.state_dict():
print(var_name, '\t', optimizer.state_dict()[var_name])
global_step = 0
best_epoch = 0
best_val_loss = np.inf
start_time = time()
if start_epoch > 0:
params_filename = os.path.join(params_path, 'epoch_%s.params' % start_epoch)
net.load_state_dict(torch.load(params_filename))
print('start epoch:', start_epoch)
print('load weight from: ', params_filename)
for epoch in range(start_epoch, epochs):
params_filename = os.path.join(params_path, 'epoch_%s.params' % epoch)
if masked_flag:
val_loss = compute_val_loss_mstgcn(net, val_loader, criterion_masked, masked_flag,missing_value,sw, epoch)
else:
val_loss = compute_val_loss_mstgcn(net, val_loader, criterion, masked_flag, missing_value, sw, epoch)
if val_loss < best_val_loss:
best_val_loss = val_loss
best_epoch = epoch
torch.save(net.state_dict(), params_filename)
print('save parameters to file: %s' % params_filename)
net.train()
for batch_index, batch_data in enumerate(train_loader):
encoder_inputs, labels = batch_data
optimizer.zero_grad()
outputs = net(encoder_inputs)
if masked_flag:
loss = criterion_masked(outputs, labels,missing_value)
else :
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
training_loss = loss.item()
global_step += 1
sw.add_scalar('training_loss', training_loss, global_step)
if global_step % 1000 == 0:
print('global step: %s, training loss: %.2f, time: %.2fs' % (global_step, training_loss, time() - start_time))
print('best epoch:', best_epoch)
predict_main(best_epoch, test_loader, test_target_tensor,metric_method ,_mean, _std, 'test')
五、函数predict_main
变量 |
类型 |
举例 |
用途 |
global_step |
int |
>=0 |
训练轮次 |
data_loader |
迭代器 |
test_loader |
用于预测的测试数据 |
data_target_tensor |
Tensor |
test_target_tensor |
测试的标签数据 |
metric_method |
str |
unmask |
|
_mean |
(1,1,1,1) |
load_graphdata_channel1中而来 |
均值 |
_std |
(1,1,1,1) |
load_graphdata_channel1中而来 |
标准差 |
type |
str |
test |
表明哪个数据样本 |
1. 参数路径的拼接获取
2. net加载参数路径
3. predict_and_save_results_mstgcn函数获得预测结果
def predict_main(global_step, data_loader, data_target_tensor,metric_method, _mean, _std, type):
params_filename = os.path.join(params_path, 'epoch_%s.params' % global_step)
print('load weight from:', params_filename)
net.load_state_dict(torch.load(params_filename))
predict_and_save_results_mstgcn(net, data_loader, data_target_tensor, global_step, metric_method,_mean, _std, params_path, type)
六、lib.metrics中的函数masked_mae
def masked_mae(preds, labels, null_val=np.nan):
if np.isnan(null_val):
mask = ~torch.isnan(labels)
else:
mask = (labels != null_val)
mask = mask.float()
mask /= torch.mean((mask))
mask = torch.where(torch.isnan(mask), torch.zeros_like(mask), mask)
loss = torch.abs(preds - labels)
loss = loss * mask
loss = torch.where(torch.isnan(loss), torch.zeros_like(loss), loss)
return torch.mean(loss)
七、lib.utlis函数compute_val_loss_mstgcn
变量 |
类型 |
举例 |
用途 |
net |
nn.Module |
|
模型 |
val_loader |
迭代器 |
|
验证集数据 |
criterion |
fun |
nn.MSELoss |
损失函数 |
masked_flag |
int |
0或1 |
用于配合损失函数 |
sw |
tensorboardX.SummaryWriter |
|
训练日志 |
epoch |
int |
>=0 |
第几轮训练 |
1. net.train(False)去点dropout机制
2. 模型静态0梯度:
tmp=[ ] 存储loss结果
for enumerate(val_loader):
outputs=net(输入)
用masked_flag选择损失函数返回损失loss
validation_loss是多轮次的平均损失值
将epoch和validation_loss写入日志sw
return validation_loss
《Dropout理解-原理,实现,优缺点》
def compute_val_loss_mstgcn(net, val_loader, criterion, masked_flag,missing_value,sw, epoch, limit=None):
net.train(False)
with torch.no_grad():
val_loader_length = len(val_loader)
tmp = []
for batch_index, batch_data in enumerate(val_loader):
encoder_inputs, labels = batch_data
outputs = net(encoder_inputs)
if masked_flag:
loss = criterion(outputs, labels, missing_value)
else:
loss = criterion(outputs, labels)
tmp.append(loss.item())
if batch_index % 100 == 0:
print('validation batch %s / %s, loss: %.2f' % (batch_index + 1, val_loader_length, loss.item()))
if (limit is not None) and batch_index >= limit:
break
validation_loss = sum(tmp) / len(tmp)
sw.add_scalar('validation_loss', validation_loss, epoch)
return validation_loss
八、lib.utils函数predict_and_save_results_mstgcn
注意到:该函数多次用到type
,input
等原本具有函数意义的变量。不建议如此使用。
变量 |
类型 |
举例 |
用途 |
net |
nn.Module |
|
|
data_loader |
迭代器 |
test_loader |
测试数据用于预测 |
data_target_tensor |
Tensor |
test_target_tensor |
测试数据的label |
global_step |
int |
>=0 |
用于选择第几轮次模型参数 |
metric_method |
str |
unmask |
|
_mean |
Tensor |
(1,1,1,1) |
均值 |
_std |
Tensor |
(1,1,1,1) |
标准差 |
params_path |
str |
|
文件路径 |
type |
str |
“test” |
说明数据类型的 |
A. net.train(False) # 去掉dropout机制
B. with torch.no_grad() 以下均在此环境中进行
1. prediction=[]用于存储net结果;input=[]用于存储输入数据
2. 注意到所有与net相关的数据转换:detach().cpu().numpy()
3. for ... enumerate(data_loader):
outputs=net(encoder_inputs)
输入和输出数据分别放入input和prediction
4. 对input数据按照axis=0进行合并,再利用_mean和_std进行反归一化
5. 对prediction数据按照axis=0进行合并
6. 打印input,prediction,data_target_tensor的shape
7. excel_list=[]用于存储误差
8. for i in range(prediction.shape[2]):
确保 data_target_tensor和prediction的shape一致
对数据data_target_tensor[:, :, i]和prediction[:, :, i]求误差
if metric_method == 'mask':
计算mae,rmse,mape并打印结果
if metric_method == 'unmask'
计算mae,rmse,mape并打印结果
[mae,rmse,mape]放入excel_list
9. if metric_method == 'mask':
对数据data_target_tensor.reshape(-1, 1),和prediction.reshape(-1, 1)求误差
计算mae,rmse,mape
10. if metric_method == 'ummask':
对数据data_target_tensor.reshape(-1, 1),和prediction.reshape(-1, 1)求误差
计算mae,rmse,mape
11. 打印mae,rmse,mape这个总结果,并放入excel_list中
def predict_and_save_results_mstgcn(net, data_loader, data_target_tensor, global_step, metric_method,_mean, _std, params_path, type):
net.train(False)
with torch.no_grad():
data_target_tensor = data_target_tensor.cpu().numpy()
loader_length = len(data_loader)
prediction = []
input = []
for batch_index, batch_data in enumerate(data_loader):
encoder_inputs, labels = batch_data
input.append(encoder_inputs[:, :, 0:1].cpu().numpy())
outputs = net(encoder_inputs)
prediction.append(outputs.detach().cpu().numpy())
if batch_index % 100 == 0:
print('predicting data set batch %s / %s' % (batch_index + 1, loader_length))
input = np.concatenate(input, 0)
input = re_normalization(input, _mean, _std)
prediction = np.concatenate(prediction, 0)
print('input:', input.shape)
print('prediction:', prediction.shape)
print('data_target_tensor:', data_target_tensor.shape)
output_filename = os.path.join(params_path, 'output_epoch_%s_%s' % (global_step, type))
np.savez(output_filename, input=input, prediction=prediction, data_target_tensor=data_target_tensor)
excel_list = []
prediction_length = prediction.shape[2]
for i in range(prediction_length):
assert data_target_tensor.shape[0] == prediction.shape[0]
print('current epoch: %s, predict %s points' % (global_step, i))
if metric_method == 'mask':
mae = masked_mae_test(data_target_tensor[:, :, i], prediction[:, :, i],0.0)
rmse = masked_rmse_test(data_target_tensor[:, :, i], prediction[:, :, i],0.0)
mape = masked_mape_np(data_target_tensor[:, :, i], prediction[:, :, i], 0)
else :
mae = mean_absolute_error(data_target_tensor[:, :, i], prediction[:, :, i])
rmse = mean_squared_error(data_target_tensor[:, :, i], prediction[:, :, i]) ** 0.5
mape = masked_mape_np(data_target_tensor[:, :, i], prediction[:, :, i], 0)
print('MAE: %.2f' % (mae))
print('RMSE: %.2f' % (rmse))
print('MAPE: %.2f' % (mape))
excel_list.extend([mae, rmse, mape])
if metric_method == 'mask':
mae = masked_mae_test(data_target_tensor.reshape(-1, 1), prediction.reshape(-1, 1), 0.0)
rmse = masked_rmse_test(data_target_tensor.reshape(-1, 1), prediction.reshape(-1, 1), 0.0)
mape = masked_mape_np(data_target_tensor.reshape(-1, 1), prediction.reshape(-1, 1), 0)
else :
mae = mean_absolute_error(data_target_tensor.reshape(-1, 1), prediction.reshape(-1, 1))
rmse = mean_squared_error(data_target_tensor.reshape(-1, 1), prediction.reshape(-1, 1)) ** 0.5
mape = masked_mape_np(data_target_tensor.reshape(-1, 1), prediction.reshape(-1, 1), 0)
print('all MAE: %.2f' % (mae))
print('all RMSE: %.2f' % (rmse))
print('all MAPE: %.2f' % (mape))
excel_list.extend([mae, rmse, mape])
print(excel_list)