Первоначальный план состоял в том, чтобы рассказать сегодня об EfficientNet PyTorch, но я обнаружил, что EfficientNet опирается на две сетевые структуры SENet и MobileNet, поэтому эта серия предназначена для начинающих «Xiaobai», поэтому в этом уроке сначала объясняется MobileNet, а SENet рассматривается в следующем уроке. , то EfficientNet рассматривается в следующем уроке, и, конечно же, каждый урок реализуется с помощью PyTorch.
1. Предпосылки
Mobile — это концепция мобильных и мобильных телефонов.MobileNet — это облегченная глубокая нейронная сеть, предложенная Google в 2017 году, которая специально используется для мобильных и встроенных устройств с низкой вычислительной мощностью, скоростью и производительностью в реальном времени.
2 инновации
2.1 Разделимая по глубине свертка
Свертка с разделением по глубине в основном применяется для замены традиционной операции свертки, а от слоя объединения отказываются. Разложите стандартную свертка на:
- свертка по глубине
- Точечная свертка.
Преимущество этого в том, чтоЗначительно сократить количество параметров и вычислений.
2.2 Общая сумма расчета свертки
Давайте сначала рассмотрим, что такое общая свертка:Сначала поговорим о теме:Размер карты объектов — H (высота) и W (ширина), размер (длина стороны) — K, M — количество каналов входной карты объектов, а N — количество каналов выходной карты объектов.
Теперь, чтобы упростить задачу, как показано на изображении выше,Входная одноканальная карта объектов, выходная карта объектов также является одноканальной,Мы знаем, что каждый результат свертки является скаляром, и из выходной карты признаков всего выполняется 9 сверток. Каждая свертка вычисляется 9 раз, потому что каждая свертка должна умножать каждое число на ядре свертки на соответствующее число на исходной карте признаков (здесь только умножение не считается сложением). Итак, как показано на рис. 6.18, всего:
еслиВходная карта объектов представляет собой 2-канальный, то это означает, что ядру свертки также требуется 2-канальное ядро свертки, а выходная карта признаков на данный момент все еще одноканальная. Таким образом, сумма расчета становится:
Исходной одноканальной карте признаков нужно было вычислить только 9 умножений на свертку, но теперь, поскольку количество входных каналов становится равным 2, требуется 18 умножений, чтобы получить 1 число на выходе. Теперь предположимВыходная карта объектов предназначена для вывода 3-канальной карты объектов.Затем вам нужно подготовить 3 разных ядра свертки и повторить все вышеперечисленные операции 3 раза, чтобы получить 3 карты функций. Итак, сумма расчета:
Теперь, чтобы решить исходную проблему:Размер карты признаков — H (высота) и W (ширина), ядро свертки — квадратное, размер (длина стороны) — K, M — количество каналов входной карты признаков, а N — количество каналов выходная карта признаков.Тогда расчетная сумма такой свертки:
Это формула для расчета количества свертки.
2.2 Вычисления свертки с разделением по глубине
- Разделимая по глубине свертка (DSC)
Предположим, что в общей свертке входную карту объектов 64 × 7 × 7 необходимо преобразовать в выходную карту объектов 128 × 7 × 7 с помощью ядра свертки 3 × 3. Подсчитайте, сколько вычислений требуется для этого процесса:
еслиИспользование свертки с разделением по глубине состоит в том, чтобы превратить эту свертку в два этапа:
- По глубине: сначала используйте 64 × 7 × 7, чтобы получить карту функций 64 × 7 × 7 через ядро свертки 3 × 3. Внимание пожалуйста! Вот карта признаков 64×7×7 с ядром свертки 3×3, а не ядром свертки 64×3×3! Здесь карта признаков 64 × 7 × 7 рассматривается как 64 изображения 7 × 7, а затем по очереди свертывается с ядром свертки 3 × 3;
- Поточечно: в работе Depthwise нетрудно обнаружить, что такие вычисления вообще не могут интегрировать информацию разных каналов, потому что все каналы разобраны на предыдущем шаге, поэтому на этом шаге ядро свертки 64×1×1 Используется для интеграции информации о разных каналах, и 128 ядер свертки 64 × 1 × 1 используются для создания карты признаков 128 × 7 × 7.
Окончательный расчет:
Объем вычислений был сокращен более чем на 80 процентов.
Схематическая диаграмма процесса разложения выглядит следующим образом:
На рисунке вы можете увидеть:
- (a) представляет собой общий процесс свертки,Ядра свертки — это все M каналов, а затем всего N и ядер свертки, что означает, что входная карта признаков имеет M каналов, а затем выходная карта признаков имеет N каналов.
- (b) представляет глубинный процесс, Всего ядер свертки M. Здесь свертка выполняется на M каналах входной карты признаков, а выходная карта признаков также M каналов;
- (c) представляет поточечный процесс, всего НЯдро свертки используется для интеграции информации из разных каналов, а выходная карта объектов имеет N каналов.
2.3 Структура сети
На рисунке слева показан общий процесс свертки.После свертки следуют слои активации BN и ReLU.Поскольку DBC будет разделен на два процесса свертки, он становится структурой справа на рисунке.Добавлены BN и ReLU после Depthwise. , а затем Bn и ReLU добавляются после Pointwise.
Это видно из всей структуры сети:
- За исключением первого слоя, который представляет собой стандартный сверточный слой, все остальные слои представляют собой свертки, отделяемые по глубине.
- Вся сеть не использует слой пула.
Реализация PyTorch
import torch
import torch.nn as nn
import torch.nn.functional as F
class Block(nn.Module):
'''Depthwise conv + Pointwise conv'''
def __init__(self, in_planes, out_planes, stride=1):
super(Block, self).__init__()
self.conv1 = nn.Conv2d\
(in_planes, in_planes, kernel_size=3, stride=stride,
padding=1, groups=in_planes, bias=False)
self.bn1 = nn.BatchNorm2d(in_planes)
self.conv2 = nn.Conv2d\
(in_planes, out_planes, kernel_size=1,
stride=1, padding=0, bias=False)
self.bn2 = nn.BatchNorm2d(out_planes)
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = F.relu(self.bn2(self.conv2(out)))
return out
class MobileNet(nn.Module):
# (128,2) means conv planes=128, conv stride=2,
# by default conv stride=1
cfg = [64, (128,2), 128, (256,2), 256, (512,2),
512, 512, 512, 512, 512, (1024,2), 1024]
def __init__(self, num_classes=10):
super(MobileNet, self).__init__()
self.conv1 = nn.Conv2d(3, 32, kernel_size=3,
stride=1, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(32)
self.layers = self._make_layers(in_planes=32)
self.linear = nn.Linear(1024, num_classes)
def _make_layers(self, in_planes):
layers = []
for x in self.cfg:
out_planes = x if isinstance(x, int) else x[0]
stride = 1 if isinstance(x, int) else x[1]
layers.append(Block(in_planes, out_planes, stride))
in_planes = out_planes
return nn.Sequential(*layers)
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.layers(out)
out = F.avg_pool2d(out, 2)
out = out.view(out.size(0), -1)
out = self.linear(out)
return out
net = MobileNet()
x = torch.randn(1,3,32,32)
y = net(x)
print(y.size())
> torch.Size([1, 10])
При нормальных обстоятельствах эта модель предварительного обучения будет выводить 1024 линейных узла, а затем здесь я добавляю полносвязный слой 1024->10.
Давайте посмотрим на эту структуру сети:
print(net)
Выходной результат:
Затем в коде:
О настройке части количества каналов модели:
MobileNet почти готов, и следующим уроком будет реализация и подробное объяснение PyTorch от SENet.