Компьютерное зрение, Исследования
ResNeXt: с нуля
ResNeXt следует простой концепции «разделяй и властвуй». ResNeXt часто называют расширенной версией ResNet. Некоторые из его важных приложений находятся в области отдела биомедицинской инженерии и особенно в отделе биоимиджинга. Здесь я собираюсь исследовать «создание ResNeXt: с нуля».
Модули: PyTorch, CUDA (необязательно)
Если вы не уверены в том, как установить PyTorch в вашей системе, вы можете проверить эту ссылку здесь. Это вам поможет! Движение вперед…
ResNeXt
Архитектура ResNeXt очень похожа на архитектуру ResNet. Если вы хотите узнать об архитектуре ResNet, то направляйтесь в это направление. Это алгоритм, основанный на глубоком обучении, основная задача которого - глубже понять особенности изображения. С чего же тогда начать?…
import torch import torch.nn as nn
Это начальный блок кода, который инициализирует библиотеку PyTorch в среде Python. Это довольно мощные архитектуры и, следовательно, требуют большого количества вычислений. По умолчанию архитектура ожидает, что система будет иметь хорошие характеристики (с точки зрения мощности ЦП и графического процессора), чтобы иметь возможность выполнить свою задачу в срок и с максимальной точностью.
Теперь, если вы новичок в Python и хотите понять основы этих больших архитектур CNN, тогда это может быть непродуктивно для вас из-за того, что в этом определении ResNeXt было определено множество экземпляров наследования и классов. что сложно даже опытным программистам. Это может показаться поразительным для новичков, поэтому я прошу вас сначала изучить основы ООП.
Достаточно ли комфортно с ООП? Вперед…
class resnext_block(nn.Module): def __init__(self, in_channels, cardinality, bwidth, idt_downsample=None, stride=1): super(resnext_block, self).__init__() self.expansion = 2 out_channels = cardinality * bwidth self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0) self.bn1 = nn.BatchNorm2d(out_channels) self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, groups=cardinality, stride=stride, padding=1) self.bn2 = nn.BatchNorm2d(out_channels) self.conv3 = nn.Conv2d(out_channels, out_channels*self.expansion, kernel_size=1, stride=1, padding=0) self.bn3 = nn.BatchNorm2d(out_channels*self.expansion) self.relu = nn.ReLU() self.identity_downsample = idt_downsample
Начиная с определения блока слоев, в первом блоке мы определили последующие компоненты, которые потребуются для продвижения вперед со структурой. Это всего лишь фаза инициализации. Каждый раз, когда мы вызываем класс, первое, что он делает, - это инициализирует эти модули вместе с их определенными спецификациями.
Одна из вещей, которые вы могли бы связать, если вы изучали ResNet и исследовательскую работу по ResNeXt, - это то, что у нас есть мощность и базовая ширина групп, определенных в предыдущей функции. Мы не определили это в ResNet, потому что теперь мы разделяем всю структуру и складываем их бок о бок, а затем все анализируем. Таким образом, мощность будет определять группы в общей архитектуре, а ширина базы будет полностью определять выходные каналы в архитектуре.
Что делать дальше?…
def forward(self, x): identity = x x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.conv2(x) x = self.bn2(x) x = self.relu(x) x = self.conv3(x) x = self.bn3(x) if self.identity_downsample is not None: identity = self.identity_downsample(identity) x += identity x = self.relu(x) return x
Функция вперед будет вызываться сразу после инициализации. Он будет содержать все методы в упорядоченном виде, как описано в исследовательской статье. Подобие функции вперед вы можете найти в блоге ResNet.
Представляем вам архитектуру ResNeXt…
class ResNeXt(nn.Module): def __init__(self, resnet_block, layers, cardinality, bwidth, img_channels, num_classes): super(ResNeXt, self).__init__() self.in_channels = 64 self.conv1 = nn.Conv2d(img_channels, 64, kernel_size=7, stride=2, padding=3) self.bn1 = nn.BatchNorm2d(64) self.relu = nn.ReLU() self.cardinality = cardinality self.bwidth = bwidth self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) # ResNeXt Layers self.layer1 = self._layers(resnext_block, layers[0], stride=1) self.layer2 = self._layers(resnext_block, layers[1], stride=2) self.layer3 = self._layers(resnext_block, layers[2], stride=2) self.layer4 = self._layers(resnext_block, layers[3], stride=2) self.avgpool = nn.AdaptiveAvgPool2d((1,1)) self.fc = nn.Linear(self.cardinality * self.bwidth, num_classes)
Мы подошли к формальному определению архитектуры «ResNeXt». Опять же, это этап инициализации. Можно заметить, что существует инициализация некоторого метода «_layers», но при этом не существует каких-либо экземпляров того же самого определенного значения. Это будет определено, когда мы пройдем следующие шаги ...
def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.avgpool(x) x = x.reshape(x.shape[0], -1) x = self.fc(x) return x
А вот и функция «вперед». Официально определена наша функция ResNeXt. Мы структурируем функцию «вперед», как это было определено в статье. Использование начальных этапов слоев Conv, а затем настройка всего слоя в зависимости от требований.
def _layers(self, resnext_block, no_residual_blocks, stride): identity_downsample = None out_channels = self.cardinality * self.bwidth layers = [] if stride != 1 or self.in_channels != out_channels * 2: identity_downsample = nn.Sequential(nn.Conv2d(self.in_channels, out_channels*2, kernel_size=1, stride=stride), nn.BatchNorm2d(out_channels*2)) layers.append(resnext_block(self.in_channels, self.cardinality, self.bwidth, identity_downsample, stride)) self.in_channels = out_channels * 2 for i in range(no_residual_blocks - 1): layers.append(resnext_block(self.in_channels, self.cardinality, self.bwidth)) self.bwidth *= 2 return nn.Sequential(*layers)
Итак, мы все определили, и нам пора определить, верны наши предположения или нет. Мы можем реализовать приведенный ниже блок кода для тестирования архитектуры.
def ResNeXt50(img_channels=3, num_classes=1000, cardinality=32, bwidth=4): return ResNeXt(resnext_block, [3,4,6,3], cardinality, bwidth, img_channels, num_classes)
И готово! Это была тяжелая работа. Спасибо, что придерживались последнего. Это важная архитектура в сфере CNN, и понять ее действительно сложно! Если вам нужна дополнительная помощь, см. Разделы ниже…
Помощь уже в пути!
Если вы все еще чувствуете, что вам нужен весь код, перейдите по этой ссылке здесь.
использованная литература
Пожалуйста, ознакомьтесь с оригинальными работами исследователей.