实验要求:
1.HKO-07 先居中 取 360*360 然后缩放到128*128(532→222)
2.训练模型 batch=4 迭代10万次, 每2000次验证一次,
以最低B-MSE保存训练模型,最后一次的训练模型也同时保存
3.随机数种子 设置为 12345098
要求一的实现:①在数据加载这里对数据进行处理(valid_batch同理)
原代码: train_batch = torch.from_numpy(train_batch.astype(np.float32)).to(cfg.GLOBAL.DEVICE) / 255.0 train_data = train_batch[:IN_LEN, ...] train_label = train_batch[IN_LEN:IN_LEN + OUT_LEN, ...]
修改后的代码: import torchvision.transforms as transforms import torch.nn.functional as F train_batch = torch.from_numpy(train_batch.astype(np.float32)).to(cfg.GLOBAL.DEVICE) / 255.0 # 裁剪+缩放 b, s, c, h, w = train_batch.shape # 变形为 (b * s, c, h, w) 以适应批处理 train_batch = train_batch.view(-1, c, h, w) # 定义转换操作:先居中裁剪,然后缩放到128x128 transform = transforms.Compose([ transforms.CenterCrop(384), transforms.Resize(128) ]) # 处理所有图像,使用批处理 output_data = transform(train_batch) # 还原到原来的批次和序列形状 train_batch = output_data.view(b, s, c, 128, 128) train_data = train_batch[:IN_LEN, ...] train_label = train_batch[IN_LEN:IN_LEN + OUT_LEN, ...]
②修改网络模型参数
encoder = Encoder(convlstm_encoder_params[0], convlstm_encoder_params[1]).to(cfg.GLOBAL.DEVICE) forecaster = Forecaster(convlstm_forecaster_params[0], convlstm_forecaster_params[1]).to(cfg.GLOBAL.DEVICE)
这两句里面的参数需要修改
具体是在net_params.py文件里面
# build model convlstm_encoder_params = [ [ OrderedDict({'conv1_leaky_1': [1, 8, 7, 5, 1]}), OrderedDict({'conv2_leaky_1': [64, 192, 5, 3, 1]}), OrderedDict({'conv3_leaky_1': [192, 192, 3, 2, 1]}), ], [ ConvLSTM(input_channel=8, num_filter=64, b_h_w=(batch_size, 96, 96), kernel_size=3, stride=1, padding=1), ConvLSTM(input_channel=192, num_filter=192, b_h_w=(batch_size, 32, 32), kernel_size=3, stride=1, padding=1), ConvLSTM(input_channel=192, num_filter=192, b_h_w=(batch_size, 16, 16), kernel_size=3, stride=1, padding=1), ] ] convlstm_forecaster_params = [ [ OrderedDict({'deconv1_leaky_1': [192, 192, 4, 2, 1]}), OrderedDict({'deconv2_leaky_1': [192, 64, 5, 3, 1]}), OrderedDict({ 'deconv3_leaky_1': [64, 8, 7, 5, 1], 'conv3_leaky_2': [8, 8, 3, 1, 1], 'conv3_3': [8, 1, 1, 1, 0] }), ], [ ConvLSTM(input_channel=192, num_filter=192, b_h_w=(batch_size, 16, 16), kernel_size=3, stride=1, padding=1), ConvLSTM(input_channel=192, num_filter=192, b_h_w=(batch_size, 32, 32), kernel_size=3, stride=1, padding=1), ConvLSTM(input_channel=64, num_filter=64, b_h_w=(batch_size, 96, 96), kernel_size=3, stride=1, padding=1), ] ]
其中,'conv1_leaky_1': [1, 8, 7, 5, 1]、'deconv1_leaky_1': [192, 192, 4, 2, 1]的参数依次表示
- 输入通道数(input_channels):输入到该层的特征图的通道数。
- 输出通道数(output_channels):该层卷积核的数量,也就是输出特征图的通道数。
- 卷积核大小(kernel_size):卷积核的高度和宽度。
- 步长(stride):卷积核在输入特征图上移动的步长。
- 填充(padding):在输入特征图的边界上添加零值的大小,以控制输出特征图的大小。
因为原来采样是480→96→32→16,现在是128→64→32→16
所以stride从5、3、2改成2、2、2
kernel_size在卷积层里按公式“output_size=(input_size−kernel_size+2×padding)/stride+1”来推算
在反卷积层里按公式“output_height=(input_height−1)×stride−2×padding+kernel_size”来推算
修改后的代码:
# build model convlstm_encoder_params_222 = [ [ OrderedDict({'conv1_leaky_1': [1, 8, 4, 2, 1]}), OrderedDict({'conv2_leaky_1': [64, 192, 4, 2, 1]}), OrderedDict({'conv3_leaky_1': [192, 192, 4, 2, 1]}), ], [ ConvLSTM(input_channel=8, num_filter=64, b_h_w=(batch_size, 64, 64), kernel_size=3, stride=1, padding=1), ConvLSTM(input_channel=192, num_filter=192, b_h_w=(batch_size, 32, 32), kernel_size=3, stride=1, padding=1), ConvLSTM(input_channel=192, num_filter=192, b_h_w=(batch_size, 16, 16), kernel_size=3, stride=1, padding=1), ] ] convlstm_forecaster_params_222 = [ [ OrderedDict({'deconv1_leaky_1': [192, 192, 4, 2, 1]}), OrderedDict({'deconv2_leaky_1': [192, 64, 4, 2, 1]}), OrderedDict({ 'deconv3_leaky_1': [64, 8, 4, 2, 1], 'conv3_leaky_2': [8, 8, 3, 1, 1], 'conv3_3': [8, 1, 1, 1, 0] }), ], [ ConvLSTM(input_channel=192, num_filter=192, b_h_w=(batch_size, 16, 16), kernel_size=3, stride=1, padding=1), ConvLSTM(input_channel=192, num_filter=192, b_h_w=(batch_size, 32, 32), kernel_size=3, stride=1, padding=1), ConvLSTM(input_channel=64, num_filter=64, b_h_w=(batch_size, 64, 64), kernel_size=3, stride=1, padding=1), ] ]
要求二的实现:修改模型保存逻辑
原代码的模型保存:(和模型测试是相互独立的) if itera % test_and_save_checkpoint_iterations == 0: modelsave_path = osp.join(model_save_dir, 'encoder_forecaster_{}.pth'.format(itera)) print(f'modelsave_path={modelsave_path}') torch.save(encoder_forecaster.state_dict(), modelsave_path)
修改后的代码: # 在没有梯度的情况下进行验证 with torch.no_grad():…… 之后添加模型保存代码 #设置best_valid_mse的值为无限大,方便后续比较大小保存模型 best_valid_mse = float('inf') mean_valid_mse = np.mean(valid_mse)#valid_mse是个数组,所以要取平均值 if mean_valid_mse < best_valid_mse: best_valid_mse = mean_valid_mse print(f'itera={itera}') print(f'best_valid_mse={best_valid_mse}') modelsave_path = osp.join(model_save_dir, 'encoder_forecaster_{}.pth'.format(itera)) print(f'modelsave_path={modelsave_path}') torch.save(encoder_forecaster.state_dict(), modelsave_path)
要求三的实现:
添加一段代码:
def set_seed(seed=12345098): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False
在main函数里,初始化阶段调用
#设置随机数种子 set_seed()
与随机数种子相关的设置
- random.seed(seed):设置 Python 内置随机数生成器的种子。
- np.random.seed(seed):设置 NumPy 随机数生成器的种子。
- torch.manual_seed(seed):设置 PyTorch 随机数生成器的种子。
- torch.cuda.manual_seed(seed):设置当前 CUDA 设备的随机数种子。
- torch.cuda.manual_seed_all(seed):设置所有 CUDA 设备的随机数种子。
- torch.backends.cudnn.deterministic = True:使 PyTorch 使用确定性算法,以确保每次运行时得到相同的结果。
- torch.backends.cudnn.benchmark = False:禁用 PyTorch 的自动优化,以确保结果的一致性。
在设置随机数种子时,可以根据具体的应用场景和需求选择需要使用的语句。通常情况下,使用前述的这些语句可以确保实验结果的可重复性和稳定性。