PixelCNN:Pixel Recurrent Neural Networks
借助 NLP 循环输入预测下一字词的特点,通过定义掩码卷积,使用以前的像素预测下一像素
第一个像素 -> 完整图片,随机图片
什么是 PixelCNN ?
- 借助 NLP 循环输入预测下一字词的特点,使用以前的像素预测下一像素,如图中 3 x 3 的像素,首先向网络输入第一个像素,网络输出第二个像素,下一步是输入第一、第二个像素,输出第三个像素,以此类推
- PixelCNN 使用的是一种 "自回归" 的计算方式,利用极大似然驱动网络学习
PixelCNN 的网络结构?
- 使用 Mask CNN 模块构建残差模块 residual block,然后基于残差块搭建 PixelCNN
- PixelCNN 的所有卷积层都是 padding=same 模式,最后模型的输出和原始图像大小一致,分别预测各个位置的 pixel
PixelCNN 的 Mask CNN 结构?
- PixelCNN 使用了两类掩码卷积,我们把两类掩码卷积分别称为「A 类」和「B 类」。二者都是对卷积操作的卷积核做了掩码处理,使得卷积核的右下部分不产生贡献。A 类和 B 类的唯一区别在于卷积核的中心像素是否产生贡献
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26class MaskedConv2d(nn.Conv2d):
"""
Implements a conv2d with mask applied on its weights.
Args:
mask_type (str): the mask type, 'A' or 'B'.
in_channels (int) – Number of channels in the input image.
out_channels (int) – Number of channels produced by the convolution.
kernel_size (int or tuple) – Size of the convolving kernel
"""
def __init__(self, mask_type, in_channels, out_channels, kernel_size, **kwargs):
super().__init__(in_channels, out_channels, kernel_size, **kwargs)
self.mask_type = mask_type
if isinstance(kernel_size, int):
kernel_size = (kernel_size, kernel_size)
mask = torch.zeros(kernel_size)
# 垂直方向卷积核中心以上不屏蔽
mask[:kernel_size[0]//2, :] = 1.0
# 卷积核中心所在行,左边不屏蔽
mask[kernel_size[0]//2, :kernel_size[1]//2] = 1.0
# 如何是B类,卷积核中心不屏蔽
if self.mask_type == "B":
mask[kernel_size[0]//2, kernel_size[1]//2] = 1.0
self.register_buffer('mask', mask[None, None])
def forward(self, x):
self.weight.data *= self.mask # mask weights
return super().forward(x)
Mask CNN 如何实现屏蔽后续像素信息的功能?
- CNN 的第一个的卷积层使用 A 类掩码卷积,之后每一层的都使用 B 类掩码卷积。上图显示连续 3 次使用 A 类型 Mask 卷积和先使用一次 A,再使用两次 B 的效果,可以看出后一种方法接收更多以前像素的信息
PixelCNN 的损失函数?
- 视最终输出而定,如何输出是二值图,则使用二值化交差熵,如果输出 256 颜色的 RGB 图,则使用 256 个输出的交差熵计算
PixelCNN 如何训练与预测?
- 训练:利用掩码卷积的特点,一次前向推理计算所有 pixel 的输出,然后使用已知像素监督网络训练
- 推理:生成过程(推理过程)是序列处理的,此时需要逐个 pixel 进行预测,共需要 次前向预测
参考: