文章目录
- 背景
- 代码
- 报错
- 原因
- 解决
-
- 网络结构(修改前)
- 网络结构(修改后)
- 类似的错误
- 参考
背景
人脸40个属性预测,原网络为Arcface,最后一层输出512维特征,修改后的网络输出为40个属性的二分类特征输出。
代码
loss.append(criterion(output, target, ))
报错
RuntimeError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
原因
出现这个问题不一定是 这里 所说的,第一维输入的是0/1不是概率值,也有可能是第一和第二两个维度的shape不匹配,或者说长度不一样导致的。也就是网络的输出和ground truth target的size不匹配。
如果强制修改网络结构的最后一层输出shape使之匹配之后还是有这个问题,可能是网络结构有问题。
解决
- 通过检查output和target的内容,发现不是概率和标签的问题。
- 通过查看output和target的length发现确实前者的长度为batch_size 128,而后者的长度为512,是Arcface的最后一层输出特征size。两者不匹配。
- 解决方法:不能强制将Arcface最后一层输出维度调整为128(这样做之后即使能运行也可能不满足背景需求),更好的做法是调整网络结构(增加一层,使网络输出匹配target,并且满足背景要求:40个属性的二分类),使预测输出和ground truth标签的shape匹配之后解决。
网络结构(修改前)
class Backbone(Module):def __init__(self, num_layers, drop_ratio, mode='ir'):super(Backbone, self).__init__()assert num_layers in [50, 100, 152], 'num_layers should be 50,100, or 152'assert mode in ['ir', 'ir_se'], 'mode should be ir or ir_se'blocks = get_blocks(num_layers)if mode == 'ir':unit_module = bottleneck_IRelif mode == 'ir_se':unit_module = bottleneck_IR_SEself.input_layer = Sequential(Conv2d(3, 64, (3, 3), 1, 1 ,bias=False), BatchNorm2d(64), PReLU(64))self.output_layer = Sequential(BatchNorm2d(512), Dropout(drop_ratio),Flatten(),Linear(512 * 7 * 7, 512),BatchNorm1d(512))modules = []for block in blocks:for bottleneck in block:modules.append(unit_module(bottleneck.in_channel,bottleneck.depth,bottleneck.stride))self.body = Sequential(*modules)def forward(self,x):x = self.input_layer(x)x = self.body(x)x = self.output_layer(x)return l2_norm(x)
网络结构(修改后)
# add fc block
class fc_block(nn.Module):def __init__(self, inplanes, planes, drop_rate=0.15):super(fc_block, self).__init__()self.fc = nn.Linear(inplanes, planes)self.bn = nn.BatchNorm1d(planes)if drop_rate > 0:self.dropout = nn.Dropout(drop_rate)self.relu = nn.ReLU(inplace=True)self.drop_rate = drop_ratedef forward(self, x):x = self.fc(x)x = self.bn(x)if self.drop_rate > 0:x = self.dropout(x)x = self.relu(x)return xclass Backbone(Module):def __init__(self, num_layers, drop_ratio, mode='ir'):super(Backbone, self).__init__()assert num_layers in [50, 100, 152], 'num_layers should be 50,100, or 152'assert mode in ['ir', 'ir_se'], 'mode should be ir or ir_se'blocks = get_blocks(num_layers)if mode == 'ir':unit_module = bottleneck_IRelif mode == 'ir_se':unit_module = bottleneck_IR_SEself.input_layer = Sequential(Conv2d(3, 64, (3, 3), 1, 1 ,bias=False), BatchNorm2d(64), PReLU(64))self.output_layer = Sequential(BatchNorm2d(512), Dropout(drop_ratio),Flatten(),Linear(512 * 7 * 7, 512),BatchNorm1d(512))modules = []for block in blocks:for bottleneck in block:modules.append(unit_module(bottleneck.in_channel,bottleneck.depth,bottleneck.stride))self.body = Sequential(*modules)######################## add 1 more layer #################################num_attributes = 40for i in range(num_attributes):setattr(self, 'classifier' + str(i).zfill(2), nn.Sequential(fc_block(512, 256), nn.Linear(256, 2)))self.num_attributes = num_attributesfor m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')elif isinstance(m, nn.BatchNorm2d):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)################################################################def forward(self,x):x = self.input_layer(x)x = self.body(x)x = self.output_layer(x)######################## add 1 more layer ######################y = []for i in range(self.num_attributes):classifier = getattr(self, 'classifier' + str(i).zfill(2))y.append(classifier(x))return y#################################################################
类似的错误
IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
参考
[1] Pytorch Arcface:https://github.com/TreB1eN/InsightFace_Pytorch
[2] ResNet for facial attributes estimation: https://github.com/Light–/face-attribute-prediction