• 批量规范化+代码+Q&A


    1.批量归一化

    在作者的论文中,还解释了其原理:通过减少内部协变量偏移(internal covariate shift)。 据推测,作者所说的“内部协变量转移”类似于上述的投机直觉,即变量值的分布在训练过程中会发生变化。 然而,这种解释有两个问题: 1、这种偏移与严格定义的协变量偏移(covariate shift)非常不同,所以这个名字用词不当。 2、这种解释只提供了一种不明确的直觉,但留下了一个有待后续挖掘的问题:为什么这项技术如此有效?

    但事实上我们不需要纠结这么多,因为学术界现在没有得出到底他为什么这么有效。事实上我们现在普遍认为是一个正则项。让中间输出的值变得稳定。

    需要记住的是BN再全连接和卷积使用方式不同。

    批量规范化层和暂退层一样,在训练模式和预测模式下计算不同。

    批量规范化有许多有益的副作用,主要是正则化。另一方面,”减少内部协变量偏移“的原始动机似乎不是一个有效的解释。

    2.代码部分

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. # 输入,两个学习的参数,moving_mean全局的均值,moving_var全局的方差,在推理的时候用
    5. #也就是所有批次的方差和均值、eps为了避免除0的东西,momentum更新全局的方差和均值的
    6. def batch_norm(X, gamma, beta, moving_mean, moving_var, eps, momentum):
    7. #is_grad_enabled判断当前是训练还是预测模式
    8. if not torch.is_grad_enabled():
    9. #如果是预测模式 ,直接传入平均的均值和方差
    10. X_hat = (X-moving_mean) / torch.sqrt(moving_var + eps)
    11. else:#这里就是要么是全连接层 要么是卷积层
    12. assert len(X.shape) in (2, 4)
    13. if len(X.shape) == 2 :
    14. #按行求均值
    15. mean = X.mean(dim=0)
    16. var = ((X - mean)**2).mean(dim=0)
    17. else:
    18. #2d卷积的情况 0是批量大小,1是通道数,2,3,是高和宽
    19. #1*n*1*1的
    20. mean = X.mean(dim=(0, 2, 3), keepdim=True)
    21. var = ((X - mean)**2).mean(dim=(0 , 2, 3), keepdim=True)
    22. #训练中的小批量的mean和var
    23. X_hat = (X - mean) / torch.sqrt(var + eps)
    24. #全局的更新
    25. moving_mean = momentum * moving_mean + (1.0 - momentum) * mean
    26. moving_var = momentum * moving_var + (1.0 - momentum) * var
    27. Y = gamma * X_hat + beta
    28. return Y,moving_mean.data, moving_var.data
    29. #创建一个batchNorm的层
    30. #层中需要的是你的输入的数。和你是什么层 2?4? 全连接或卷积
    31. class BatchNorm(nn.Module):
    32. # num_features:完全连接层的输出数量或卷积层的输出通道数。
    33. # num_dims:2表示完全连接层,4表示卷积层
    34. def __init__(self, num_features, num_dims):
    35. super().__init__()
    36. if num_dims == 2:
    37. #1*n的
    38. shape = (1, num_features)
    39. else:
    40. #1*n*1*1的
    41. shape = (1, num_features, 1, 1)
    42. # 参与求梯度和迭代的拉伸和偏移参数,分别初始化成1和0
    43. self.gamma = nn.Parameter(torch.ones(shape))
    44. self.beta = nn.Parameter(torch.zeros(shape))
    45. # 非模型参数的变量初始化为0和1
    46. self.moving_mean = torch.zeros(shape)
    47. self.moving_var = torch.ones(shape)
    48. def forward(self, X):
    49. if self.moving_mean.device != X.device:
    50. self.moving_mean = self.moving_mean.to(X.device)
    51. self.moving_var = self.moving_var.to(X.device)
    52. Y, self.moving_mean, self.moving_var = batch_norm(
    53. X, self.gamma, self.beta, self.moving_mean, self.moving_var,
    54. eps=1e-5, momentum=0.9)
    55. return Y
    56. net = nn.Sequential(
    57. nn.Conv2d(1, 6, kernel_size=5), BatchNorm(6, num_dims=4), nn.Sigmoid(),
    58. nn.AvgPool2d(kernel_size=2, stride=2),
    59. nn.Conv2d(6, 16, kernel_size=5), BatchNorm(16, num_dims=4), nn.Sigmoid(),
    60. nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),
    61. nn.Linear(16*4*4, 120), BatchNorm(120, num_dims=2), nn.Sigmoid(),
    62. nn.Linear(120, 84), BatchNorm(84, num_dims=2), nn.Sigmoid(),
    63. nn.Linear(84, 10))
    64. lr, num_epochs, batch_size = 1.0, 10, 1
    65. train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
    66. d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

    简明实现: 

    1. #我们可以使用深度学习框架中定义的BN
    2. net = nn.Sequential(
    3. nn.Conv2d(1, 6, kernel_size=5), nn.BatchNorm2d(6), nn.Sigmoid(),
    4. nn.AvgPool2d(kernel_size=2, stride=2),
    5. nn.Conv2d(6, 16, kernel_size=5), nn.BatchNorm2d(16), nn.Sigmoid(),
    6. nn.AvgPool2d(kernel_size=2, stride=2), nn.Flatten(),
    7. nn.Linear(256, 120), nn.BatchNorm1d(120), nn.Sigmoid(),
    8. nn.Linear(120, 84), nn.BatchNorm1d(84), nn.Sigmoid(),
    9. nn.Linear(84, 10))
    10. d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

    3.练习

    1. 在使用批量规范化之前,我们是否可以从全连接层或卷积层中删除偏置参数?为什么?
      可以,因为不改变方差和均值。

    2. 比较LeNet在使用和不使用批量规范化情况下的学习率。
      自己动手与试验一下

      1. 绘制训练和测试准确度的提高。

      2. 你的学习率有多高?

         用1.3好一点

         

    3. 我们是否需要在每个层中进行批量规范化?尝试一下?
      全连接没必要

    4. 你可以通过批量规范化来替换暂退法吗?行为会如何改变?
      都相当于正则化 应该是可以的。但是深度的神经网络,BN效果应该好一点

    5. 确定参数betagamma,并观察和分析结果。

    6. 查看高级API中有关BatchNorm的在线文档,以查看其他批量规范化的应用。

    7. 研究思路:想想你可以应用的其他“规范化”转换?你可以应用概率积分变换吗?全秩协方差估计可以么?

    4.Q&A

    有一个评论很有意思

           1.请注意,如果我们尝试使用大小为 1 的小批量应用批量归一化,我们将无法学到任何东西。 这是因为在减去均值之后,每个隐藏单元将为 0。 所以,只有使用足够大的小批量,批量归一化这种方法才是有效且稳定的。 请注意,在应用批量归一化时,批量大小的选择可能比没有批量归一化时更重要”,请问怎么理解呢?这里的批量请问是网络训练的batch吗?

     

     指batch_size,notebook上设置为256。如果batch_size为1,那么这个小批量的均值就是这个样本值本身,则样本值减去均值就为0了,也即文中所说的”每个隐藏单元将为 0“,所以batch_size要足够大,但也不要太大

     1.BN到底干嘛?

    防止极端数据出现,在整个模型中,强行的让你保持到几乎一样的层次。对深度的网络比较好哦,

    2.为什么加了BN后,收敛时间变短了?

    BN本身会让梯度变大一点,每个层的梯度都差不多,这样就可以使用更大的Lr。

  • 相关阅读:
    一文搞懂JavaScript中的typeof用法
    逆置链表(原地逆置链表)
    Git保姆级使用教程
    vue学习笔记——简单入门总结(一)
    C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子)
    【报名指南】2024年第九届数维杯数学建模挑战赛报名全流程图解
    es(Elasticsearch)客户端Kibana安装使用(03Kibana安装篇)
    FreeBSD通过CBSD管理低资源容器jail来安装Ubuntu子系统实践
    【无标题】
    从新手到高手:Scala函数式编程完全指南,Scala 数据类型(4)
  • 原文地址:https://blog.csdn.net/qq_60567866/article/details/125608162