相较于dropout,可以理解为dropout的升级版,将一个区域的神经元或通道整体失活,dropout是随机点失活,作者认为dropout随机点失活,对于一个区域的影响不大,不是最优的神经网络的集成学习方案;
dropout在训练时,随机失活一定比例的神经元个数(Linear层),通道个数(卷积层conv);
在测试时,不会进行失活,所有神经元或通道数都进行连接;最后将隐层结果乘以比例因子,相当于做了一次模型集成;
下面是dropblock的pytorch实现方式
# -*- coding:utf8 -*-
import torch
import torch.nn.functional as F
from torch import nn
class Drop(nn.Module):
def __init__(self, drop_prob=0.1, block_size=7):
super(Drop, self).__init__()
self.drop_prob = drop_prob
self.block_size = block_size
def forward(self, x):
if self.drop_prob == 0:
return x
# 设置gamma,比gamma小的设置为1,大于gamma的为0,对应第五步
# 这样计算可以得到丢弃的比率的随机点个数
gamma = self.drop_prob / (self.block_size**2)
mask = (torch.rand(x.shape[0], *x.shape[2:]) < gamma).float()
mask = mask.to(x.device)
# compute block mask
block_mask = self._compute_block_mask(mask)
# apply block mask,为算法图的第六步
out = x * block_mask[:, None, :, :]
# Normalize the features,对应第七步
out = out * block_mask.numel() / block_mask.sum()
return out
def _compute_block_mask(self, mask):
# 取最大值,这样就能够取出一个block的块大小的1作为drop,当然需要翻转大小,使得1为0,0为1
block_mask = F.max_pool2d(input=mask[:, None, :, :],
kernel_size=(self.block_size,
self.block_size),
stride=(1, 1),
padding=self.block_size // 2)
if self.block_size % 2 == 0:
# 如果block大小是2的话,会边界会多出1,要去掉才能输出与原图一样大小.
block_mask = block_mask[:, :, :-1, :-1]
block_mask = 1 - block_mask.squeeze(1)
return block_mask