(三)fastai 2019 lesson10 Wrapping up our CNN 重构CNN

lesson10 Wrapping up our CNN 重构CNN

目前很困难的部分是软件工程师的部分,如果没有做过软件工程的,在一开始可能会觉得课程很难。

我们要在软件工程的基础上重构大部分pytorch的功能。

  •  05a_foundations.ipynb
    • 用回调函数callback做按钮交互和消息响应:两个参数、*args、**kwargs
    • __dunder__ 双下划线函数:类似于重载操作符
    • 方差variance对异常值过于敏感;平均绝对偏差,也许更好。
    • softmax的局限性:总要输出一个类别;会放大原来的差距;——更好的解决办法是:exp() / ( 1+exp() )
  • 05b_early_stopping.ipynb 
    • lr finder:会提前终止训练,重构Runner和Callback,加入Exception
      • 重构Runner,将原来的call写入了callback;加入Exception,实现cancel batch、cancel epoch、cancel train三个级别中的任何一个stop
      • 在fit中加入了exception,有了Exception才能真正的停止
      • 实现lr finder中,lr在[min_lr, max_lr]中,是log线性增长,而不是线性。是看随着lr的变化,我们的loss的变化情况,来寻找最好的learning rate。
    • Cuda:把数据data和模型model都放在cuda上面。
    • Hooks:重构pytorch的hooks,同时实现删除/析构函数,用于管理内存。
      • ① 没有很好初始化的网络,激活元会不断的尖峰、掉落、再尖峰、掉落。如此往复。模型学习不到任何东西。且几乎大部分的激活元都处于无用状态。
      • 使用kaiming_normal初始化,可怕的震荡消失了但是并不是所有的激活元都在好好工作,虽然std的曲线图还不错,但是激活元直方图表明大部分的激活元90%处于非激活状态。此时虽然使用了kaiming_normal,但是lr=0.9,还是在前部分震荡的很凶的。
      • ③ 所以建立了新的relu类,然后初始化使用了a=0.1 kaiming_normal;对relu的微小改进,以及kaiming_normal 1=0.1,使得激活元全部都活跃起来了。
        最后的效果是,前面可怕的震荡减少了很多了,只有很少的尖峰了!!!
  • 07_batchnorm.ipynb  如何更好的初始化来得到好的结果,这部分我们已经达到了极限。为了更进一步,我们使用归一化方法。
    • Batch Normalization

目前还差几个模块:

  • ① 


  •  使用了一个类来作为cb,cb有init,有call。
def slow_calculation(cb=None):
    res = 0
    for i in range(5):
        res += i*i
        sleep(1)
        if cb: cb(i)
    return res

class ProgressShowingCallback():
    def __init__(self, exclamation="Awesome"): self.exclamation = exclamation
    def __call__(self, epoch): print(f"{self.exclamation}! We've finished epoch {epoch}!")

cb = ProgressShowingCallback("Just super")

slow_calculation(cb)

Just super! We've finished epoch 0!
Just super! We've finished epoch 1!
Just super! We've finished epoch 2!
Just super! We've finished epoch 3!
Just super! We've finished epoch 4!
  • 0.1 `*args`和`**kwargs`两个参数

    • **kwargs 用的太多,虽然对开发人员很方便,但是对于用户来说很烦人。

  •  0.2 __dunder__ 双下划线函数:类似于C++重载操作符

    • __add__ 是操作符 + 的实现方法。
    • __getitem__是[]运算符
    • __init__ 是构造函数
    • __del__ 是析构函数
    • __repr__ 是str() 表示函数
    • __len__ 是长度
  • 0.3 Variance

    • 1,2,4,18 四个数的标准差为std=6.89, var=std^2=47.1875;
    • 但mean=6.25,(|1-6.25|+|2-6.25|+|4--6.25|+|18--6.25|)/ 4 = 5.87
    • abs(X-u).mean 对异常值18不敏感,而方差variance对异常值很敏感。——只要有一个异常值,方差就变得很离谱。
    • 在机器学习中,经常使用平均绝对偏差。但是平均绝对偏差没有得到充分的使用,实际上它是一个非常好用的方法。
      • 异常值18在,pow(2)方差公式中会被放大。
      • Jeremy注意到,在很多地方将 variance用 abs_mean替换,通常后者的效果会更好。
      • 虽然有一种假设:我们应该总是使用方差variance,但实际上不是这样的。
    • (t-m).pow(2).mean().sqrt()
      tensor(6.8693)
      
      (t-m).abs().mean()
      tensor(5.8750)

      协方差:当x和y具有较大的量级差异时,数值容易受绝对数值的影响, 无法衡量二者的相对相似性。

  •  1. Softmax

    • 什么应该是使用softmax?什么时候不该使用softmax?
    • Image1和Image2的输出概率不应该是一样的,所以这里存在一些问题。
    • 由于output中fish的值略高于其它的类别,经过exp()放大之后,其概率推高的更多了

 

  • 不应该增加missing类,或者背景类。——因为non object类,根本不会起作用。

  •  2. LrFinder

    • 重构Runner,使得Runner可以在需要的时候停止回调。
run.fit(3, learn)
  • __call__写在Callback类中更有意义。
    • 原来的Callback始终会return True,没有False。导致Exception无法真正的stop。
    • 把call写在callback类中,可以raise Exception
    • 原来的Runner的fit()等函数中,没有Exception的代码,所以不会真正的stop
    • 超级巧妙的方式:没有stack track,没有error,只有Exception作为control flow,也不是error处理技术。
      • 我们可以用callback实现cancel batch、cancel epoch、cancel train三个级别中的任何一个stop

 

 左侧为新的Runner类的设计,新Runner中的Call函数也不一样了。

 

  • 实现lr finder

    • min \times (\frac{max}{min})^{\frac{i}{n}},i为当前的迭代batch,n为总共有多少个batch。 这个是当前batch应该设置的学习率lr。
    • 为什么[min_lr, max_lr]中间,是靠上面的公式实现的?lr曲线是一个递增曲线,前面的lr是小,后半部分的lr很大。
    • log(min\times (\frac{max}{min})^{\frac{i}{n}})=log min + \frac{i}{n}(log max - log min) = a + \frac{i}{n}(b-a) \in [a, b],所以其实是[logmin, log max]的一个区间。
      本来是一个线性增长,结果是exp(线性增长),所以超过了1后,指数增长的过快。在lr∈[1e-6,1]之前,都是exp(线性),增长率较慢的。

 

  •  3. CUDA

    • 把parameters(weights)放在GPU上。还有activations需要放在GPU上。
    • self.model把模型放在cuda中,tensor放在GPU上。
    • self.run.xb,self.run.yb把数据放在GPU上。

  •  4. Refactor model 重构模型

    • ① 把conv2d和relu结合起来,构成一个新的模块。
    • ② 增加一个callback,实现每一个batch数据都能transform为【28,28】的格式,方便做卷积层的输入。这部分做一个BatchTransformXCallback,order=2.
    • ③ 第一层的kernel=5,而不是3。原因在于要避免无效的运算。

  •  5. Hooks——自定义的Hook,与pytorch的Hook对照,重构pytorch的Hook

    • 我们想要知道模型里面是不是训练的很稳定?如何能让训练更快更好?我们想要看模型里面到底发生了什么?怎样能看到每层的activations激活元是怎样的状态呢?
    • 我们已经知道不同的初始化方式会改变不同层的方差,我们如何能找出某一层的激活元是不是已经饱和了?如果饱和了会发生什么?
    • 如果我们用自己的序列模型替换掉nn.Sequential会怎么样?
      • 第一层的3×3的卷积核,有点浪费信息。因为你在为相同的信息占用更多的空间!
      • 神经网络的全部意义在于提取一些有趣的特征,所以希望拥有较少的激活元。
      • 所以在同一层增加同样意义的激活元是没有意义的;只有增加激活元的层数才能产生更多的多样性。增加同一层的冗余基函数是没有意义的!浪费激活元、浪费内存、也浪费了大量的计算!

 Pytorch的Hooks是如何实现的呢?

增加一个hook类来对hook进行管理!

 

  • 此处对Hooks加入了迭代器等的管理。

 Hook类有enter和exit方法,有了这两个方法后,就可以使用上下文管理器,即with块。确保进入with块后,可以使用enter方法;退出with块后,可以使用exit方法来remove所有的hook,这样就不会污染我们的内存了。免得内存管理混乱。

 

 

 

 

 

6. BatchNormalization 小批量归一化

 2023年3月16日10:03:39 update

在BatchNorm的加持下,训练出的每一层的权重的分布直方图如下图所示。①希望均值为0,方差在1附近;②但又不能全为0,权重为0的比例要小,dead activations。

从下面可以看出来:加了GeneralReLU后,分布更广;加了BactchNorm后,得到了很大的改变。

 

 从下面可以看出来:加了GeneralReLU+BactchNorm后,得到了很大的改变。直方图发生了较大的改变,同时分布也发生了变化。BN的效果是显著的。 


 

加入了1cycle,lr退火,得到了8个epoch的acc==98%,所以batch_normalization非常棒。

More norms

  1. Layer Norm:
    Batchnorm在大多数情况下运行良好。但是不能应用于在线学习任务,或者batch比较小的超大型分布式模型上也不能使用。
    1. online learning,比如机器人。在运行的同时训练。
    2. BatchNorm不适合于小批量batch。BN也不适合于RNN。
    3. 如果batch=1, 方差就是Inf。
如果我们正在做一个分割任务,其中我们只能有 2 或 4 的批量大小,我们在第一部分中已经看到很多次。这将是一个问题,因为在我们所有的层中,当然我们所有的训练都在 batch size = 2 在某些时候这两个值将成为相同或几乎相同,所以我们然后除以大约为 0 的方差 我们有无穷大,所以我们遇到了这个问题,无论何时当你有一个小批量时,你会得到
稳定或不可能的训练 ,它也会是对我们自己的目的来说真的很难。

因为Batch Normalization会有一个除以方差的操作;如果batch太小的话,方差为Inf,BN层就没有意义了!!!!! 

所有的输入x除以一个Inf,整个层的激活元就变得没有意义了!!! 训练就会不稳定,或者完全不可能训练了!! 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值