DCGAN生成器自定义权重初始化报错:'ConvTr'无'weight'属性
PyTorch DCGAN生成器权重初始化报错解决
问题描述
在PyTorch中搭建DCGAN生成器时,封装了整合转置卷积、BatchNorm2d和ReLU的ConvTr模块,使用自定义weights_init函数初始化权重时,触发错误:
AttributeError: 'ConvTr' object has no attribute 'weight'
相关代码
官方教程生成器代码
# Generator Code class Generator(nn.Module): def __init__(self, ngpu): super(Generator, self).__init__() self.ngpu = ngpu self.main = nn.Sequential( # input is Z, going into a convolution nn.ConvTranspose2d( nz, ngf * 8, 4, 1, 0, bias=False), nn.BatchNorm2d(ngf * 8), nn.ReLU(True), # state size. (ngf*8) x 4 x 4 nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 4), nn.ReLU(True), # state size. (ngf*4) x 8 x 8 nn.ConvTranspose2d( ngf * 4, ngf * 2, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf * 2), nn.ReLU(True), # state size. (ngf*2) x 16 x 16 nn.ConvTranspose2d( ngf * 2, ngf, 4, 2, 1, bias=False), nn.BatchNorm2d(ngf), nn.ReLU(True), # state size. (ngf) x 32 x 32 nn.ConvTranspose2d( ngf, nc, 4, 2, 1, bias=False), nn.Tanh() # state size. (nc) x 64 x 64 ) def forward(self, input): return self.main(input)
自定义生成器代码
class ConvTr(nn.Module): def __init__(self, input_channels, output_channels, k_size, stride, pad, b = False): super().__init__() self.conv = nn.ConvTranspose2d(in_channels=input_channels, out_channels=output_channels, kernel_size=k_size, stride=stride, padding=pad, bias=b) self.batch_norm = nn.BatchNorm2d(input_channels) self.activation = nn.ReLU() def forward(self, x): x = self.conv(x) x = self.activation(x) x = self.batch_norm(x) return x class Generator(nn.Module): def __init__(self, inputNoise=100): super().__init__() self.conv1 = ConvTr(input_channels = inputNoise, output_channels = 128, k_size = 4, stride = 2, pad = 0) self.conv2 = ConvTr(input_channels = 128, output_channels = 64, k_size = 3, stride = 2, pad = 1) self.conv3 = ConvTr(input_channels = 64, output_channels = 32, k_size = 4, stride = 2, pad = 1) self.conv4 = ConvTranspose2d(in_channels=32, out_channels=1, kernel_size=4, stride=2, padding=1) self.tanh = Tanh() def forward(self, x): x = self.conv1(x) x = self.conv2(x) x = self.conv3(x) x = self.conv4(x) output = self.tanh(x) return output
权重初始化函数
def weights_init(model): # get the class name classname = model.__class__.__name__ # check if the classname contains the word "conv" if classname.find("Conv") != -1: # intialize the weights from normal distribution nn.init.normal_(model.weight.data, 0.0, 0.02) # otherwise, check if the name contains the word "BatcnNorm" elif classname.find("BatcnNorm") != -1: # intialize the weights from normal distribution and set the # bias to 0 nn.init.normal_(model.weight.data, 1.0, 0.02) nn.init.constant_(model.bias.data, 0)
错误信息
raise AttributeError("'{}' object has no attribute '{}'".format( AttributeError: 'ConvTr' object has no attribute 'weight'
错误原因
- 初始化逻辑误判模块类型:
weights_init通过类名含"Conv"就认为是卷积层,但ConvTr是你自定义的容器模块,本身没有weight属性,真正的卷积层是它内部的self.conv成员。调用generator.apply(weights_init)时,函数会递归遍历所有子模块,包括ConvTr,此时访问model.weight必然报错。 - BatchNorm参数错误:
ConvTr中的BatchNorm2d传入了输入通道数,但转置卷积后的输出通道是output_channels,这里参数应该改为output_channels。 - 拼写错误:初始化函数里的
BatcnNorm是笔误,正确应为BatchNorm。
解决方案
方案1:修改初始化函数,精准匹配目标模块
让初始化函数只对PyTorch原生的卷积层和BatchNorm层生效,跳过自定义的ConvTr容器:
def weights_init(model): # 遍历所有子模块 for m in model.modules(): classname = m.__class__.__name__ # 只处理原生Conv层,跳过自定义ConvTr if classname.find('Conv') != -1 and not isinstance(m, ConvTr): nn.init.normal_(m.weight.data, 0.0, 0.02) elif classname.find('BatchNorm') != -1: nn.init.normal_(m.weight.data, 1.0, 0.02) nn.init.constant_(m.bias.data, 0)
使用时正常调用:
generator = Generator() generator.apply(weights_init)
方案2:在ConvTr模块内部完成初始化
直接在ConvTr的初始化方法里完成内部卷积和BatchNorm的权重初始化,外部无需额外处理:
class ConvTr(nn.Module): def __init__(self, input_channels, output_channels, k_size, stride, pad, b = False): super().__init__() self.conv = nn.ConvTranspose2d(in_channels=input_channels, out_channels=output_channels, kernel_size=k_size, stride=stride, padding=pad, bias=b) # 修正BatchNorm的输入参数为输出通道数 self.batch_norm = nn.BatchNorm2d(output_channels) self.activation = nn.ReLU() # 初始化当前模块内的卷积和BatchNorm nn.init.normal_(self.conv.weight.data, 0.0, 0.02) nn.init.normal_(self.batch_norm.weight.data, 1.0, 0.02) nn.init.constant_(self.batch_norm.bias.data, 0) def forward(self, x): x = self.conv(x) x = self.activation(x) x = self.batch_norm(x) return x
同时注意修正Generator中conv4和tanh的导入问题(需从torch.nn导入:from torch.nn import ConvTranspose2d, Tanh)。
内容的提问来源于stack exchange,提问作者Nafees
相关产品推荐
相关产品推荐

