A pointwise convolution uses a 1 × 1 kernel to transform the channels at each spatial location without using a wider spatial neighborhood. Its main architectural roles are reducing channel dimensionality and aligning feature-map shapes for later computation. section 11.2.2 section 11.2.3
Use pointwise convolutions to:
- Reduce input channels before expensive 3 × 3 or 5 × 5 convolutions, sharply lowering their parameter cost. section 11.2.2
- Project a feature map after pooling so its output channels fit the concatenated Inception representation. section 11.2.2
- Match residual-branch resolution and channel count when a shortcut changes spatial size or doubles features. section 11.2.3
Dimensionality-reduced Inception branch
An Inception branch can apply a 1 × 1 convolution first, then a 3 × 3 or 5 × 5 convolution. The first operation reduces the incoming channel count, making the spatial convolution substantially cheaper while preserving the feature-map resolution. section 11.2.2
Residual shortcut projection
When a residual block halves spatial resolution with stride 2 and doubles the number of features, a 1 × 1 convolution with stride 2 transforms the shortcut so it can be added to the main branch. section 11.2.3
Listing 11.7 PyTorch code for a dimensionality reduced Inception block
class Inceptionv1Module(nn.Module):
def __init__(self, in_channels, num_1x1=64,
reduce_3x3=96, num_3x3=128,
reduce_5x5=16, num_5x5=32,
pool_proj=32):
super(Inceptionv1Module, self).__init__()
self.branch1x1 = torch.nn.Sequential(
nn.Conv2d( #1
in_channels, num_1x1,
kernel_size=1, bias=False),
nn.BatchNorm2d(num_1x1, eps=0.001),
nn.ReLU(inplace=True))
self.branch3x3_1 = torch.nn.Sequential( #2
nn.Conv2d(
in_channels, reduce_3x3,
kernel_size=1, bias=False),
nn.BatchNorm2d(reduce_3x3, eps=0.001),
nn.ReLU(inplace=True))
self.branch3x3_2 = torch.nn.Sequential( #3
nn.Conv2d(
reduce_3x3, num_3x3,
kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(num_3x3, eps=0.001),
nn.ReLU(inplace=True))
self.branch5x5_1 = torch.nn.Sequential( #4
nn.Conv2d(
in_channels, reduce_5x5,
kernel_size=5, padding=2, bias=False),
nn.BatchNorm2d(reduce_5x5, eps=0.001),
nn.ReLU(inplace=True))
self.branch5x5_2 = torch.nn.Sequential( #5
nn.Conv2d(
reduce_5x5, num_5x5,
kernel_size=5, padding=2, bias=False),
nn.BatchNorm2d(num_5x5, eps=0.001),
nn.ReLU(inplace=True))
self.pool = torch.nn.Sequential( #6
torch.nn.MaxPool2d(
kernel_size=3, stride=1, padding=1),
nn.Conv2d(
in_channels, pool_proj,
kernel_size=1, bias=False),
nn.BatchNorm2d(pool_proj, eps=0.001),
nn.ReLU(inplace=True))
def forward(self, x):
conv1x1 = self.branch1x1(x)
conv3x3 = self.branch3x3_2(self.branch3x3_1((x)))
conv5x5 = self.branch5x5_2(self.branch5x5_1((x)))
pool_out = self.pool(x)
out = torch.cat( #7
[conv1x1, conv3x3, conv5x5, pool_out], 1)
return out
Inspect the PyTorch dimensionality-reduced Inception implementation, where 1 × 1 convolutions precede the 3 × 3 and 5 × 5 branches. section 11.2.2

