问题
PyTorch实现CNN卷积网络的时候,使用数组的方式创建层是一种十分常见的方式,如下所示:
= []
classifier.append(nn.Linear(64, 512)) # in_cha
classifier.append(nn.Linear(512, 2))
self.classifier = nn.Sequential(*classifier)
然而,什么情况下应该使用这种方式呢?
方法
本文将通过案例详细阐述。
方法1
import torch
from torch import nn
class Net(nn.Module):
def __init__(self) -> None:
super().__init__()
# 这种情况下,使用数组来构建层毫无意义
layers = []
layers.append(nn.Conv2d(3, 32, 3, padding=1))
layers.append(nn.AdaptiveAvgPool2d(1))
layers.append(nn.Flatten())
layers.append(nn.Linear(32, 2))
self.classifier = nn.Sequential(*layers)
def forward(self, x):
return self.classifier(x)
if __name__ == '__main__':
x = torch.rand(size=(1, 3, 224, 224))
net = Net()
print(net(x).shape)
方法2
import torch
from torch import nn
class Net(nn.Module):
def __init__(self) -> None:
super().__init__()
self.classifier = nn.Sequential(
nn.Conv2d(3, 32, 3, padding=1),
nn.AdaptiveAvgPool2d(1),
nn.Flatten(),
nn.Linear(32, 2)
)
def forward(self, x):
return self.classifier(x)
if __name__ == '__main__':
x = torch.rand(size=(1, 3, 224, 224))
net = Net()
print(net(x).shape)
方法3
方法1和方法2相比,没有使用数组的方法2更加简洁、清晰。
假如构建10个卷积层,卷积层的输入通道数每次增加5个,应该如何实现呢?
import torch
from torch import nn
class Net(nn.Module):
def __init__(self) -> None:
super().__init__()
in_channels = 3
grow = 5
layers = []
for i in range(10):
# 每次增加grow个通道,并保持特征图大小不改变
layers.append(nn.Conv2d(in_channels, in_channels+grow, 3, padding=1))
in_channels += grow
self.block = nn.Sequential(*layers)
self.classifier = nn.Sequential(
nn.AdaptiveAvgPool2d(1),
nn.Flatten(),
nn.Linear(in_channels, 2)
)
def forward(self, x):
x = self.block(x)
return self.classifier(x)
if __name__ == '__main__':
from torchsummary import summary
device = 'cuda' if torch.cuda.is_available() else 'cpu'
x = torch.rand(size=(1, 3, 224, 224)).to(device)
net = Net().to(device)
print(net(x).shape)
summary(net, (3, 224, 224))
网络输出结果:
结语
当网络层的输入通道数呈现某种规律性的变化时,使用数组创建层的方式将会变得简单,而通常情况下,则无需使用数组,使用Sequential的方式创建会使代码变得更加清晰、易懂。