目錄
1、ResNet50的mxnet實現
具體網絡結構可參見https://blog.csdn.net/qq_21046135/article/details/81674605
和 https://blog.csdn.net/seven_year_promise/article/details/69360488
from mxnet.gluon import nn
from mxnet import nd, init, gluon, autograd
import mxnet as mx
import gluonbook as gb
from mxnet.gluon.data.vision import transforms
lr = 0.1
num_epochs = 100
batch_size = 128
ctx = mx.gpu()
tansformer = transforms.Compose([
transforms.ToTensor()
])
# 加載數據
train_data = gluon.data.vision.ImageFolderDataset("/home/user/cf/st/train")
test_data = gluon.data.vision.ImageFolderDataset("/home/user/cf/st/test")
train_iter = gluon.data.DataLoader(train_data.transform_first(tansformer), shuffle=True, batch_size=batch_size)
test_iter = gluon.data.DataLoader(test_data.transform_first(tansformer),shuffle=True, batch_size=batch_size)
class Residual(nn.Block):
def __init__(self, num_channels, use_1x1conv=False, strides=1, **kwargs):
super(Residual, self).__init__(**kwargs)
self.conv1 = nn.Conv2D(num_channels, kernel_size=1, strides=strides)
self.conv2 = nn.Conv2D(num_channels, kernel_size=3, strides=1, padding=1)
self.conv3 = nn.Conv2D(num_channels*4, kernel_size=1, strides=1)
if use_1x1conv:
self.conv4 = nn.Conv2D(num_channels*4, kernel_size=1, strides=strides)
self.bn4 = nn.BatchNorm()
else:
self.conv4 = None
self.bn4 = None
self.bn1 = nn.BatchNorm()
self.bn2 = nn.BatchNorm()
self.bn3 = nn.BatchNorm()
def forward(self, x):
y = nd.relu(self.bn1(self.conv1(x)))
y = nd.relu(self.bn2(self.conv2(y)))
y = self.bn3(self.conv3(y))
if self.conv4:
x = self.bn4(self.conv4(x))
return nd.relu(x+y)
def resnet_block(num_channels, num_residuals, stride=1):
blk = nn.Sequential()
for i in range(num_residuals):
if i==0 :
blk.add(Residual(num_channels, use_1x1conv=True, strides=stride))
else:
blk.add(Residual(num_channels))
return blk
net = nn.Sequential()
net.add(
nn.Conv2D(64, kernel_size=7, strides=2, padding=3),
nn.BatchNorm(),
nn.Activation('relu'),
nn.MaxPool2D(pool_size=3, strides=2)
)
net.add(
resnet_block(64, 3, stride=1),
resnet_block(128, 4, stride=2),
resnet_block(256, 6, stride=2),
resnet_block(512, 3, stride=2)
)
# 平均池化
net.add(nn.GlobalAvgPool2D(),
nn.Dense(2))
net.initialize(init=init.Xavier(), force_reinit=True, ctx=ctx)
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate':lr})
loss = gluon.loss.SoftmaxCrossEntropyLoss()
gb.train_ch5(net, train_iter, test_iter, batch_size, trainer, ctx, num_epochs)
當self.bn4定義在self.bn3的後面時,會出現錯誤:mxnet.gluon.parameter.DeferredInitializationError: Parameter 'batchnorm8_gamma' has not been initialized yet because initialization was deferred. Actual initialization happens during the first forward pass. Please pass one batch of data through the network before accessing Parameters. You can also avoid deferred initialization by specifying in_units, num_features, etc., for network layers.
這是因爲定義在後面的bn4,當條件判斷爲false的時候,不會使用到self.bn4,會出現DeferredInitializationError的錯誤,所以需要同時定義兩種情況下的self.bn4
2、ResNet的keras實現
from keras.layers import Conv2D, BatchNormalization, MaxPooling2D, Activation, ZeroPadding2D, Input, Add,AveragePooling2D, Flatten, Dense
from keras.models import Model
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import LearningRateScheduler
from keras.callbacks import ModelCheckpoint
from keras.utils import multi_gpu_model
from keras.optimizers import Adam
import keras.backend as K
def Bottleneck(x, filters, stage, block, s, short_cut):
conv_name_base = 'res'+str(stage)+block+'_branch'
bn_name_base = 'bn'+str(stage)+block+'_branch'
residual = x #shortcut
x = Conv2D(filters=filters, kernel_size=(1,1), strides=(1,1), padding='valid', name=conv_name_base+'2a')(x)
x = BatchNormalization(axis=3, name=bn_name_base+'2a')(x)
x = Activation('relu')(x)
x = Conv2D(filters=filters, kernel_size=(3,3), strides=(s,s), padding='same', name=conv_name_base+'2b')(x)
x = BatchNormalization(axis=3, name=bn_name_base+'2b')(x)
x = Activation('relu')(x)
x = Conv2D(filters=filters*4, kernel_size=(1,1), strides=(1,1), padding='valid', name=conv_name_base+'2c')(x)
x = BatchNormalization(axis=3, name=bn_name_base+'2c')(x)
if short_cut:
residual = Conv2D(filters=filters*4, kernel_size=(1,1), strides=(s,s), name=conv_name_base+'1')(residual)
residual = BatchNormalization(axis=3, name=bn_name_base+'1')(residual)
out = Add()([x, residual])
out = Activation('relu')(out)
return out
def ResNet50(input_shape, classes):
x_input = Input(input_shape)
x = ZeroPadding2D((3,3))(x_input)
x = Conv2D(64, kernel_size=(7,7), strides=(2,2), name='conv1', use_bias=True, kernel_initializer='glorot_uniform')(x)
x = BatchNormalization(axis=3, name='bn_conv1')(x)
x = Activation('relu')(x)
x = ZeroPadding2D((1,1))(x)
x = MaxPooling2D(pool_size=(3,3), strides=(2,2), padding='same')(x)
# layer1 *3
x = Bottleneck(x, 64, stage=2, block='a', s=1, short_cut=True)
x = Bottleneck(x, 64, stage=2, block='b', s=1, short_cut=False)
x = Bottleneck(x, 64, stage=2, block='c', s=1, short_cut=False)
# layer2 *4
x = Bottleneck(x, 128, stage=3, block='a', s=2, short_cut=True)
x = Bottleneck(x, 128, stage=3, block='b', s=1, short_cut=False)
x = Bottleneck(x, 128, stage=3, block='c', s=1, short_cut=False)
x = Bottleneck(x, 128, stage=3, block='d', s=1, short_cut=False)
# layer3 *6
x = Bottleneck(x, 256, stage=4, block='a', s=2, short_cut=True)
x = Bottleneck(x, 256, stage=4, block='b', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='c', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='d', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='e', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='f', s=1, short_cut=False)
# layer4 *3
x = Bottleneck(x, 512, stage=5, block='a', s=2, short_cut=True)
x = Bottleneck(x, 512, stage=5, block='b', s=1, short_cut=False)
x = Bottleneck(x, 512, stage=5, block='c', s=1, short_cut=False)
x = AveragePooling2D((2,2), name='avg_pool')(x)
x = Flatten()(x)
x = Dense(classes, activation='softmax', name='fc'+str(classes))(x)
model = Model(inputs=x_input, outputs=x, name='ResNet50')
return model
def ResNet101(input_shape, classes):
x_input = Input(input_shape)
x = ZeroPadding2D((3,3))(x_input)
x = Conv2D(64, kernel_size=(7,7), strides=(2,2), name='conv1', use_bias=True, kernel_initializer='glorot_uniform')(x)
x = BatchNormalization(axis=3, name='bn_conv1')(x)
x = Activation('relu')(x)
x = ZeroPadding2D((1,1))(x)
x = MaxPooling2D(pool_size=(3,3), strides=(2,2), padding='same')(x)
# layer1 *3
x = Bottleneck(x, 64, stage=2, block='a', s=1, short_cut=True)
x = Bottleneck(x, 64, stage=2, block='b', s=1, short_cut=False)
x = Bottleneck(x, 64, stage=2, block='c', s=1, short_cut=False)
# layer2 *4
x = Bottleneck(x, 128, stage=3, block='a', s=2, short_cut=True)
x = Bottleneck(x, 128, stage=3, block='b', s=1, short_cut=False)
x = Bottleneck(x, 128, stage=3, block='c', s=1, short_cut=False)
x = Bottleneck(x, 128, stage=3, block='d', s=1, short_cut=False)
# layer3 *23
x = Bottleneck(x, 256, stage=4, block='a', s=2, short_cut=True)
x = Bottleneck(x, 256, stage=4, block='b', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='c', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='d', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='e', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='f', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='a_2', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='b_2', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='c_2', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='d_2', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='e_2', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='f_2', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='a_3', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='b_3', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='c_3', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='d_3', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='e_3', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='f_3', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='a_4', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='b_4', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='c_4', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='d_4', s=1, short_cut=False)
x = Bottleneck(x, 256, stage=4, block='e_4', s=1, short_cut=False)
# layer4 *3
x = Bottleneck(x, 512, stage=5, block='a', s=2, short_cut=True)
x = Bottleneck(x, 512, stage=5, block='b', s=1, short_cut=False)
x = Bottleneck(x, 512, stage=5, block='c', s=1, short_cut=False)
x = AveragePooling2D((2,2), name='avg_pool')(x)
x = Flatten()(x)
x = Dense(classes, activation='softmax', name='fc'+str(classes))(x)
model = Model(inputs=x_input, outputs=x, name='ResNet101')
return model
def ResNet152(input_shape, classes):
x_input = Input(input_shape)
x = ZeroPadding2D((3,3))(x_input)
x = Conv2D(64, kernel_size=(7,7), strides=(2,2), name='conv1', use_bias=True, kernel_initializer='glorot_uniform')(x)
x = BatchNormalization(axis=3, name='bn_conv1')(x)
x = Activation('relu')(x)
x = ZeroPadding2D((1,1))(x)
x = MaxPooling2D(pool_size=(3,3), strides=(2,2), padding='same')(x)
# layer1 * 3
x = Bottleneck(x, filters=64, stage=2, block='a', s=1, short_cut=True)
x = Bottleneck(x, filters=64, stage=2, block='b', s=1, short_cut=False)
x = Bottleneck(x, filters=64, stage=2, block='c', s=1, short_cut=False)
# layer2 *8
x = Bottleneck(x, filters=128, stage=3, block='a', s=2, short_cut=True)
x = Bottleneck(x, filters=128, stage=3, block='b', s=1, short_cut=False)
x = Bottleneck(x, filters=128, stage=3, block='c', s=1, short_cut=False)
x = Bottleneck(x, filters=128, stage=3, block='d', s=1, short_cut=False)
x = Bottleneck(x, filters=128, stage=3, block='e', s=1, short_cut=False)
x = Bottleneck(x, filters=128, stage=3, block='f', s=1, short_cut=False)
x = Bottleneck(x, filters=128, stage=3, block='g', s=1, short_cut=False)
x = Bottleneck(x, filters=128, stage=3, block='h', s=1, short_cut=False)
# layer3 * 36
x = Bottleneck(x, filters=256, stage=4, block='a', s=2, short_cut=True)
x = Bottleneck(x, filters=256, stage=4, block='b', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='c', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='d', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='e', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='f', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='a_2', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='b_2', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='c_2', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='d_2', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='e_2', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='f_2', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='a_3', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='b_3', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='c_3', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='d_3', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='e_3', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='f_3', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='a_4', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='b_4', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='c_4', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='d_4', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='e_4', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='f_4', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='a_5', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='b_5', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='c_5', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='d_5', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='e_5', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='f_5', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='a_6', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='b_6', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='c_6', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='d_6', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='e_6', s=1, short_cut=False)
x = Bottleneck(x, filters=256, stage=4, block='f_6', s=1, short_cut=False)
# layer4 * 3
x = Bottleneck(x, filters=512, stage=5, block='a', s=2, short_cut=True)
x = Bottleneck(x, filters=512, stage=5, block='b', s=1, short_cut=False)
x = Bottleneck(x, filters=512, stage=5, block='c', s=1, short_cut=False)
x = AveragePooling2D((2,2), name='avg_pool')(x)
x = Flatten()(x)
x = Dense(classes, activation='softmax', name='fc'+str(classes))(x)
model = Model(inputs=x_input, outputs=x, name='ResNet152')
return model
查看網絡結構可以通過model = ResNet152(input_shape=(224, 224, 3), classes=1000) print(model)
ResNet網絡很有規律性,conv2_x、conv3_x、conv4_x、conv5_x每個模塊無論重複多少遍,模塊內第一次調用Bottleneck,shortcut都是要通過downsample後再add,並且步長是2
3、ResNet的pytorch實現
import torch.nn as nn
import math
import torch.utils.model_zoo as model_zoo
__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152']
model_urls = {
'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
}
def conv3x3(in_planes, out_planes, stride=1):
"""3x3 convolution with padding"""
return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
padding=1, bias=False)
class BasicBlock(nn.Module):
# Figure5(左) Block
expansion = 1
def __init__(self, inplanes, planes, stride=1, downsample=None):
super(BasicBlock, self).__init__()
self.conv1 = conv3x3(inplanes, planes, stride)
self.bn1 = nn.BatchNorm2d(planes)
self.relu = nn.ReLU(inplace=True)
self.conv2 = conv3x3(planes, planes)
self.bn2 = nn.BatchNorm2d(planes)
self.downsample = downsample
self.stride = stride
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
if self.downsample is not None:
residual = self.downsample(x)
out += residual
out = self.relu(out)
return out
class Bottleneck(nn.Module):
# Figure5(右) Block
expansion = 4
def __init__(self, inplanes, planes, stride=1, downsample=None):
super(Bottleneck, self).__init__()
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
self.bn1 = nn.BatchNorm2d(planes)
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,
padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(planes)
self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)
self.bn3 = nn.BatchNorm2d(planes * self.expansion)
self.relu = nn.ReLU(inplace=True)
self.downsample = downsample
self.stride = stride
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.bn3(out)
if self.downsample is not None:
residual = self.downsample(x)
out += residual
out = self.relu(out)
return out
class ResNet(nn.Module):
def __init__(self, block, layers, num_classes=1000):
self.inplanes = 64
super(ResNet, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,
bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.relu = nn.ReLU(inplace=True)
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
self.avgpool = nn.AvgPool2d(7, stride=1)
self.fc = nn.Linear(512 * block.expansion, num_classes)
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
elif isinstance(m, nn.BatchNorm2d):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
def _make_layer(self, block, planes, blocks, stride=1):
downsample = None
if stride != 1 or self.inplanes != planes * block.expansion:
downsample = nn.Sequential(
nn.Conv2d(self.inplanes, planes * block.expansion,
kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(planes * block.expansion),
)
layers = []
layers.append(block(self.inplanes, planes, stride, downsample))
self.inplanes = planes * block.expansion
for i in range(1, blocks):
layers.append(block(self.inplanes, planes))
return nn.Sequential(*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.view(x.size(0), -1)
x = self.fc(x)
return x
def resnet18(pretrained=False, **kwargs):
"""Constructs a ResNet-18 model.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
"""
model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))
return model
def resnet34(pretrained=False, **kwargs):
"""Constructs a ResNet-34 model.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
"""
model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['resnet34']))
return model
def resnet50(pretrained=False, **kwargs):
"""Constructs a ResNet-50 model.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
"""
model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
return model
def resnet101(pretrained=False, **kwargs):
"""Constructs a ResNet-101 model.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
"""
model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))
return model
def resnet152(pretrained=False, **kwargs):
"""Constructs a ResNet-152 model.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
"""
model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))
return model