距离我上一篇文章已经有一段时间了。在这次讨论中,我将指出我在设计神经网络时犯的一些错误,以及我在重新设计时注意到的一些错误。
- 在最后的嵌入层使用ReLU
我犯的错误之一是在 最后的 嵌入层使用ReLU激活函数。这是一个常见的错误,我也看到其他作者犯了这个错误,一些代码库(如CVPR的代码库)就是证明:
class Feature_Embedder_ResNet18(nn.Module): def __init__(self): super(Feature_Embedder_ResNet18, self).__init__() model_resnet = resnet18(pretrained=False) self.layer4 = model_resnet.layer4 self.avgpool = nn.AdaptiveAvgPool2d(output_size=1) self.bottleneck_layer_fc = nn.Linear(512, 512) self.bottleneck_layer_fc.weight.data.normal_(0, 0.005) self.bottleneck_layer_fc.bias.data.fill_(0.1) self.bottleneck_layer = nn.Sequential( self.bottleneck_layer_fc, nn.ReLU(), nn.Dropout(0.5) ) def forward(self, input, norm_flag): feature = self.layer4(input) feature = self.avgpool(feature) feature = feature.view(feature.size(0), -1) feature = self.bottleneck_layer(feature) if (norm_flag): feature_norm = torch.norm(feature, p=2, dim=1, keepdim=True).clamp(min=1e-12) ** 0.5 * (2) ** 0.5 feature = torch.div(feature, feature_norm) return feature
在最终嵌入层使用ReLU激活可以导致非负向量,这可以大大降低嵌入空间的维度。这可能会导致模型的性能下降,因为可用来嵌入样本的选项较少。
想象一下,你的嵌入是一个二维笛卡尔坐标系。在嵌入层应用ReLU激活函数将导致一个更小的空间来区分不同的类别。
当应用ReLU层时,模型没有很多选择。
2 .对测试数据应用不同的归一化处理
有时,你可能会发现你的模型的性能并不像你预期的那样好。一个简单的解决方案可以是对你的输入数据使用归一化。例如,ResNet提供了如下的默认归一化参数:
normalization = transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
不同的网络可能有不同的规范化参数。为了简化这个问题,你可以使用nn.Sequential() ,将归一化转换作为你的网络中的一个层添加:
network = nn.Sequential(normalization, network)
现在,你只需要使用PIL.Image 读取输入图像,并应用其他转换,而不必担心归一化的问题"。