我可以不吃啊 发表于 2024-7-23 03:43:00

神经网络中如何优化模子和超参数调优(案例为tensor的预测)

总结:

初级:简单修改一下超参数,结果一般般但是够用,偶然候乃至直接不敷用
中级:optuna得出最好的超参数之后,再多一些epoch让train和testloss团体下降,然后结果就很不错。
高级:在中级的底子上,更换更适合的损失函数之后,在train的时间backward反向传播这个loss,optuna也更改这个loss标准,现在结果有质的改变。

问题:

迩来在做cfd领域,需要流场进行预测,然后流场提取出来再深度学习就是一个多维度tensor,而神经网络的目的就是通过模子预测让预测的tensor与实际的tensor的结果尽大概的靠近,具体来说就是让每个值之间的毛病尽大概小。
目前环境:现在模子大概以及确定,但是结果一般般,这时间就需要进行下面的调优方法。
优化方法:

一、初级优化:

简单修改一下超参数,结果一般般但是够用,偶然候乃至直接不敷用
https://i-blog.csdnimg.cn/direct/b68723ad6ff746a091f25c5793006940.png
二、中级优化:optuna调参,然后epoch加多

optuna得出最好的超参数之后,再多一些epoch让train和testloss团体下降,然后结果就很不错。
https://i-blog.csdnimg.cn/direct/67c7173e10df4fc69682b96c446451d5.png

三、高级优化:

在中级的底子上,现在更换更适合的损失函数之后,在train的时间backward反向传播这个loss,optuna也更改这个loss标准,现在结果有质的改变。

也就是下面这三行代码
smooth_l1 = F.smooth_l1_loss(out.view(shape1, shape2), y.view(shape1, shape2))#!!!!!!!!!!!!!
smooth_l1.backward() #用这个smooth_l1_loss反向传播#!!!!!!!!!!!!!!!!!!!!!!!!!
return test_smooth_l1#test中的最后一个epoch的test_smooth_l1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
https://i-blog.csdnimg.cn/direct/70aef3d356f14488b0e22f277ca7750d.png
https://i-blog.csdnimg.cn/direct/8c37ee97b98c4887bd89cf0c04dc2eb9.png
通过上面预测的数据和实际的数据进行的对比,可以发现预测的每个结果与实际的结果的毛病在大约0.01范围之内(实际数据在[-4,4]之间)。

确定损失函数:

要让两个矩阵的值尽大概靠近,选择符合的损失函数(loss function)是关键。常见的用于这种目的的损失函数包罗以下几种:

[*] 均方毛病(Mean Squared Error, MSE):对预测值与真实值之间的平方毛病求均匀。MSE对大毛病比力敏感,能够明显惩罚偏离较大的预测值。
import torch.nn.functional as F loss = F.mse_loss(predicted, target)
[*] 均匀绝对毛病(Mean Absolute Error, MAE):对预测值与真实值之间的绝对毛病求均匀。MAE对异常值不如MSE敏感,适用于数据中存在异常值的环境。
import torch loss = torch.mean(torch.abs(predicted - target))
[*] 平滑L1损失(Smooth L1 Loss):又称Huber Loss,当毛病较小时,平滑L1损失类似于L1损失,当毛病较大时,类似于L2损失。适合在有噪声的数据集上使用。
import torch.nn.functional as F loss = F.smooth_l1_loss(predicted, target) 总结如下:


[*]     MSE:适用于需要明显惩罚大毛病的环境。
[*]     MAE:适用于数据中存在异常值,并且你渴望对异常值不那么敏感的环境。
[*]     Smooth L1 Loss:适用于既有肯定抗噪声能力又能对大毛病适当惩罚的环境。
      这里根据任务选择Smooth L1 Loss。

具体做法:

目前这个经过optuna调优,然后先下面处置惩罚(思想是将loss的反向传播和optuna优化标准全换为更适合这个任务的smooth_l1_loss函数)


[*]1.  loss将mse更换为smooth_l1_loss,
[*]2.  l2.backward()更换为smooth_l1.backward(),
[*]3.  return test_l2更改为return test_smooth_l1  
结果:point_data看着值很靠近,每个值毛病0.01范围内。阐明用这个上面这个方法是对的。试了一下图也有优化。并step_loss现在极低。


下面代码中加感叹号的行都是上面思路修改我的项目中对应的代码行,重要!!!
import optuna
import time
import torch.optim as optim
# 求解loss的两个参数
shape1 =-1   
shape2 = data.shape* 3

def objective1(trial):
    batch_size = trial.suggest_categorical('batch_size', )
    learning_rate = trial.suggest_float('learning_rate', 1e-6, 1e-2,log=True)
    layers = trial.suggest_categorical('layers', )
    width = trial.suggest_categorical('width', )#新加的
    weight_decay = trial.suggest_float('weight_decay', 1e-6, 1e-2,log=True)#新加的
   
    #再加个优化器
    optimizer_name = trial.suggest_categorical('optimizer', ['Adam', 'SGD', 'RMSprop'])
    # loss_function_name = trial.suggest_categorical('loss_function', ['LpLoss', 'MSELoss'])
   
   
    """ Read data """
    # data是,而data_cp是为归一化的
    train_a = data#data:torch.Size:50:, 80, 40, 30。train50对应的是predict50+9+1
    train_u = data_cp#torch.Size()#data_cp是未归一化的,第11个对应的是data的第data的第1个,两者差10
    # print(train_a.shape)
    # print(train_u.shape)
   
    test_a = data[:ntest,:,:]#选取最后200个当测试集
    test_u = data_cp
    # print(test_a.shape)
    # print(test_u.shape)#torch.Size()
    train_loader = torch.utils.data.DataLoader(torch.utils.data.TensorDataset(train_a, train_u),
                                             batch_size=batch_size, shuffle=True)
    test_loader = torch.utils.data.DataLoader(torch.utils.data.TensorDataset(test_a, test_u),
                                              batch_size=batch_size, shuffle=False)
    #没有随机的train_loader,用于后面预测可视化
    data_loader_noshuffle = torch.utils.data.DataLoader(torch.utils.data.TensorDataset(data[:,:,:], data_cp),
                                             batch_size=batch_size, shuffle=False)
   
   
    # %%
    """ The model definition """
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    model = WNO1d(width=width, level=level, layers=layers, size=h, wavelet=wavelet,
                  in_channel=in_channel, grid_range=grid_range).to(device)
    # print(count_params(model))
   
    # optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=1e-6)
      #调参数用,优化器选择
    if optimizer_name == 'Adam':
      optimizer = optim.Adam(model.parameters(), lr=learning_rate, weight_decay=weight_decay)
    elif optimizer_name == 'SGD':
      optimizer = optim.SGD(model.parameters(), lr=learning_rate, weight_decay=weight_decay, momentum=0.9)
    else:# RMSprop
      optimizer = optim.RMSprop(model.parameters(), lr=learning_rate, weight_decay=weight_decay)
      
    scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=step_size, gamma=gamma)
   
    train_loss = torch.zeros(epochs)
    test_loss = torch.zeros(epochs)
    myloss = LpLoss(size_average=False)
   



    """ Training and testing """
    for ep in range(epochs):
      model.train()
      t1 = default_timer()
      train_mse = 0
      train_l2 = 0
      for x, y in train_loader:
            x, y = x.to(device), y.to(device)
   
            optimizer.zero_grad()
            out = model(x)
   
            mse = F.mse_loss(out.view(shape1, shape2), y.view(shape1, shape2))
            # # 训练时使用 Smooth L1 Loss
            smooth_l1 = F.smooth_l1_loss(out.view(shape1, shape2), y.view(shape1, shape2))#!!!!!!!!!!!!!

            l2 = myloss(out.view(shape1, shape2), y.view(shape1, shape2))
            # l2.backward()
            smooth_l1.backward() #用这个smooth_l1_loss反向传播#!!!!!!!!!!!!!!!!!!!!!!!!!

            optimizer.step()
            train_mse += mse.item()
            train_l2 += l2.item()
   
      scheduler.step()
      model.eval()
      test_l2 = 0.0
      test_smooth_l1 =0
      with torch.no_grad():
            for x, y in test_loader:
                x, y = x.to(device), y.to(device)
   
                out = model(x)
                test_l2 += myloss(out.view(shape1, shape2), y.view(shape1, shape2)).item()
                test_smooth_l1+=F.smooth_l1_loss(out.view(shape1, shape2), y.view(shape1, shape2)).item()#!!!!!!!!!!!!!!!!!!
      train_mse /= ntrain#len(train_loader)
      train_l2 /= ntrain
      test_l2 /= ntest
      test_smooth_l1 /= ntest#!!!!!!!!!!!!!!!!!!!
      
      train_loss = train_l2
      test_loss = test_l2
   
      t2 = default_timer()
      print('Epoch-{}, Time-{:0.4f}, -> Train-MSE-{:0.4f},test_smooth_l1-{:0.4f} Train-L2-{:0.4f}, Test-L2-{:0.4f}'
            .format(ep, t2-t1, train_mse,test_smooth_l1, train_l2, test_l2))#!!!!!!!!!!!!!!!!1
   

    if trial.should_prune():
      raise optuna.exceptions.TrialPruned()

    """防止打印信息错位"""
    print(f"Trial {trial.number} finished with value: {test_l2}")

    return test_smooth_l1#test中的最后一个epoch的test_smooth_l1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   
    """ For saving the trained model and prediction data """


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 神经网络中如何优化模子和超参数调优(案例为tensor的预测)