代码:github
modulation
调制,主要是用于控制生成器中的卷积层的权重。
在普通的卷积计算中,权重通常是按照一定方法(随机)初始化,然后在训练过程中反向传播来更新权重。
在stylegan2中,卷积层的权重是由style动态地调整。
具体来说,就是一个随机tensor,经过mapping network后,生成风格向量style(latent)。style再经过EqualLinear变换,与缩放因子scale相乘,从而实现了对权重的动态调整。这样,生成器的每个卷积层的权重都会受到style的影响,从而能够更精细地控制生成图像的样式。从代码中可以看到,weight初始化后,还是可以在训练过程中反向传播来更新权重。
demodulate
解调,为了避免生成的图像出现过于明显的条纹或者模式重复(这些问题通常源于不同特征图之间的相关),需要对特征(通道)解耦,去除特征之间的相关性。
解调的过程,就是权重向量除以L2范数,对权重向量进行了缩放,确保每个权重向量的L2范数为1。这样一来,即使在调整权重后,每个通道的权重仍然保持相同的强度,从而减少了通道间的依赖性,提高了生成图像的质量。
#调制
self.modulation = EqualLinear(style_dim, in_channel, bias_init=1)
self.weight = nn.Parameter(
torch.randn(1, out_channel, in_channel, kernel_size, kernel_size)
)
style = self.modulation(style).view(batch, 1, in_channel, 1, 1) #(1,1,512,1,1)
weight = self.scale * self.weight * style #(1,512,512,3,3)
#解调
if self.demodulate:
demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + 1e-8) #(1,512)
weight = weight * demod.view(batch, self.out_channel, 1, 1, 1) #(1,512,512,3,3)
#
weight = weight.view(batch * self.out_channel, in_channel, self.kernel_size, self.kernel_size)
#(512,512,3,3)
input = input.view(1, batch * in_channel, height, width) #(1,512,4,4) => (1,512,4,4)
out = conv2d_gradfix.conv2d(
input, weight, padding=self.padding, groups=batch #(1,512,4,4)
)
_, _, height, width = out.shape
out = out.view(batch, self.out_channel, height, width) #(1,512,4,4)
Generator
class Generator(nn.Module):
def __init__(
self,
size,
style_dim,
n_mlp,
channel_multiplier=