• 利用nn.BatchNorm构建带BN的神经网络


    目录

    网络构建:

    用写好的fit函数进行模型训练

    综合调参:

    Bach Normalization与Batch_size综合调参


    网络构建:

    在构建网络中,我们会定义好一些选择哪种激活函数和是否需要进行BatchNorm以及是在激活函数之前进行BatchNorm还是之后进行,其它为正常网络构建过程:

    1. import torch.nn as nn
    2. import torch
    3. class net_class1(nn.Module):
    4. def __init__(self,act_fun=torch.relu,in_features=2,n_hidden=4,out_features=1,bias=True,BN_model=None,momentum=0.1):
    5. super(net_class1, self).__init__()
    6. self.linear1 = nn.Linear(in_features,n_hidden,bias=bias)
    7. self.bn1 = nn.BatchNorm1d(n_hidden,momentum=momentum)
    8. self.linear2 = nn.Linear(n_hidden,out_features,bias=bias)
    9. self.act_fun = act_fun
    10. self.BN_model = BN_model
    11. def forward(self,x):
    12. if self.BN_model == 'pre':
    13. z1 = self.bn1(self.linear1(x))
    14. f1 = self.act_fun(z1)
    15. out = self.linear2(f1)
    16. elif self.BN_model == 'post':
    17. z1 = self.linear1(x)
    18. f1 = self.act_fun(z1)
    19. out = self.linear2(self.bn1(f1))
    20. else:
    21. z1 = self.linear1(x)
    22. f1 = self.act_fun(z1)
    23. out = self.linear2(f1)
    24. return out
    25. """"""

    无论bn层在隐藏层之前还是之后,对实际结果不会有影响

    用写好的fit函数进行模型训练

    1. from MyPython.test.study.MyTorchUtils import MyTorchUtils
    2. """fit model"""
    3. utils = MyTorchUtils()
    4. torch.manual_seed(420)
    5. # create data
    6. features,labls = utils.tensorDataGenRe(bag=2,w=[2,-1],bias=False)
    7. # split data
    8. train_loader,test_loader = utils.split_loader(features,labls)
    9. # instantiation nn , enter training mode
    10. relu_model1_norm = net_class1(BN_model='pre')
    11. relu_model1_norm.train()
    12. lr = 0.3
    13. utils.fit(net=relu_model1_norm,
    14. criterion=nn.MSELoss(),
    15. optimizer=optim.SGD(relu_model1_norm.parameters(),lr=lr),
    16. batchdata=train_loader,
    17. epochs=20,
    18. cla=False)
    19. print([*relu_model1_norm.modules()][2].weight)
    20. print([*relu_model1_norm.modules()][2].bias)
    21. print([*relu_model1_norm.modules()][2].running_mean)
    22. print([*relu_model1_norm.modules()][2].running_var)
    23. # enter testing mdoe
    24. relu_model1_norm.eval()
    25. print(utils.mse_cla(train_loader, relu_model1_norm))
    26. print(utils.mse_cla(test_loader, relu_model1_norm))
    27. print([*relu_model1_norm.modules()][2].weight)
    28. print([*relu_model1_norm.modules()][2].bias)
    29. print([*relu_model1_norm.modules()][2].running_mean)
    30. print([*relu_model1_norm.modules()][2].running_var)

    注意的是,单独无脑的加入BN层并不一定会提升模型的效果,这里加入一段对比代码:

    1. def bn_sigmoid():
    2. torch.manual_seed(929)
    3. sigmoid_model1 = net_class1(act_fun=torch.sigmoid)
    4. sigmoid_model_norm = net_class1(act_fun=torch.sigmoid,BN_model='pre')
    5. model_1 = [sigmoid_model1,sigmoid_model_norm]
    6. name_1 = ['simoid_model1','sigmoid_model1_norm']
    7. lr = 0.03
    8. num_epochs = 40
    9. train_1,test_1 = utils.model_comparison(model_1=model_1,
    10. name_1=name_1,
    11. train_data=train_loader,
    12. test_data=test_loader,
    13. num_epochs=num_epochs,
    14. criterion=nn.MSELoss(),
    15. optimizer=optim.SGD,
    16. lr=lr,
    17. cla=False,
    18. eva=utils.mse_cla)
    19. for i,name in enumerate(name_1):
    20. plt.plot(list(range(num_epochs)),train_1[i],label=name)
    21. plt.legend(loc=1)
    22. plt.show()

    在上面模型中加入bn层,模型效果反而会变差,此时需要和别的参数进行联合调参,结果:

     

    综合调参:

    Bach Normalization与Batch_size综合调参

    我们首先要明白的一点是,要让模型得到最好的效果其实就是bn层计算出的均值和方差越接近真实的均值和方差,而当面对的数据量(也就是Batch_size)太少的时候,我们用小批数据去估计大的整体就会出现较大的偏差,影响模型准确率。

    调大数据数量来对比:

    1. def bn_sigmoid2():
    2. utils = MyTorchUtils()
    3. torch.manual_seed(420)
    4. features,labls = utils.tensorDataGenRe(bag=2,w=[2,-1],bias=False)
    5. train_loader,test_loader = utils.split_loader(features,labls,batch_size=50)
    6. sigmoid_model1 = net_class1(act_fun=torch.sigmoid)
    7. sigmoid_model_norm = net_class1(act_fun=torch.sigmoid,BN_model='pre')
    8. model_1 = [sigmoid_model1,sigmoid_model_norm]
    9. name_1 = ['simoid_model1','sigmoid_model1_norm']
    10. lr = 0.03
    11. num_epochs = 40
    12. train_1, test_1 = utils.model_comparison(model_1=model_1,
    13. name_1=name_1,
    14. train_data=train_loader,
    15. test_data=test_loader,
    16. num_epochs=num_epochs,
    17. criterion=nn.MSELoss(),
    18. optimizer=optim.SGD,
    19. lr=lr,
    20. cla=False,
    21. eva=utils.mse_cla)
    22. for i,name in enumerate(name_1):
    23. plt.plot(list(range(num_epochs)),train_1[i],label=name)
    24. plt.legend(loc=1)
    25. plt.show()

    对比上段代码,更改了batch_size,结果如下:

     对比可以发现,调整batch_size后,带bn层的有更快的收敛速度和效果

    这里相同的原理,除了提高batch_size外,还可以通过降低momentum参数来实现

    复杂模型上Batch_normalization的表现

    bn主要的优化手段是通过调整线性层的梯度,使整个模型的梯度达到平稳的状态,来获得更好的效果,所以,在一定范围内,bn方法对于复杂模型和复杂数据会更加有效,很多简单模型可以不用(会增加计算量,所以上述中我们的简单模型优化效果可能不是很明显.

  • 相关阅读:
    html5期末大作业——HTML+CSS公益关爱残疾人( 6个页面)
    GPT的全面历史和演变:从GPT-1到GPT-4
    第61章 Jquery JSON Table EntityFrameworkCore自动生成数据库
    [附源码]计算机毕业设计JAVA课后作业提交系统关键技术研究与系统实现
    【UniApp】-uni-app概述
    【微信小程序】博客小程序,静态版本(二)引入 lin-ui 组件、设计和开发文章页
    Mybiosource丨Mybiosource重组表皮葡萄球菌磷酸结合蛋白 pstS
    用R对Twitter用户的编程语言语义分析
    西安博物院重现1000年前唐三彩,竟然是3D打印!
    花生壳微信公众号开发配置
  • 原文地址:https://blog.csdn.net/a_Loki/article/details/126854398