基于映射鉴别器的CGAN
模型中,判别器(Discriminator)不是通过将条件信息简单地与特征向量拼接(concatenate)来使用条件信息,而是采用一种基于投影的方式,这种方式更加尊重条件信息在底层概率模型中的作用。
判别器的构建是受到概率模型假设的启发,其中条件变量 y 给定 x 的分布是离散的或单峰连续分布。这种模型假设在许多实际应用中很常见,包括类条件图像生成和超分辨率。通过这种假设,可以形成一个需要在嵌入的条件向量 y 和特征向量之间进行内积的判别器结构。
代码实现
class DiscriminatorPCGAN(nn.Module):
def __init__(self, x_dim, c_dim, dim=96, norm='none', weight_norm='spectral_norm'):
super(DiscriminatorPCGAN, self).__init__()
norm_fn = _get_norm_fn_2d(norm)
weight_norm_fn = _get_weight_norm_fn(weight_norm)
def conv_norm_lrelu(in_dim, out_dim, kernel_size=3, stride=1, padding=1):
return nn.Sequential(
weight_norm_fn(nn.Conv2d(in_dim, out_dim, kernel_size, stride, padding)),
norm_fn(out_dim),
nn.LeakyReLU(0.2)
)
self.ls = nn.Sequential( # (N, x_dim, 32, 32)
conv_norm_lrelu(x_dim, dim),
conv_norm_lrelu(dim, dim),
conv_norm_lrelu(dim, dim, stride=2), # (N, dim , 16, 16)
conv_norm_lrelu(dim, dim * 2),
conv_norm_lrelu(dim * 2, dim * 2),
conv_norm_lrelu(dim * 2, dim * 2, stride=2), # (N, dim*2, 8, 8)
conv_norm_lrelu(dim * 2, dim * 2, kernel_size=3, stride=1, padding=0),
conv_norm_lrelu(dim * 2, dim * 2, kernel_size=1, stride=1, padding=0),
conv_norm_lrelu(dim * 2, dim * 2, kernel_size=1, stride=1, padding=0), # (N, dim*2, 6, 6)
nn.AvgPool2d(kernel_size=6), # (N, dim*2, 1, 1)
torchlib.Reshape(-1, dim * 2), # (N, dim*2)
)
self.l_logit = weight_norm_fn(nn.Linear(dim * 2, 1)) # (N, 1)
self.l_projection = weight_norm_fn(nn.Linear(dim * 2, c_dim)) # (N, c_dim)
def forward(self, x, c):
# x: (N, x_dim, 32, 32), c: (N, c_dim)
feat = self.ls(x)
logit = self.l_logit(feat)
# 做一个线性编码
embed = (self.l_projection(feat) * c).mean(1, keepdim=True)
logit += embed
return logit
CGAN参考文章