深度学习课程--理解残差神经网路ResNet如何运作

这文章是理解ResNet神经网络,并且使用简单使用python实战ResNet的残差块以及其他部分。

ResNet残差神经网络

正如之前文章所提到,普通的神经网络,如果超过很多层,比如超过25层之后,模型的accuracy将会下降,按理说,神经网络越深,模型的效果应该越好,但是现实却是相反的情况。这可能是因为梯度消失问题所导致的。 于是有人提出残差块,在某一层中间插入多个残差块,便可以训练超过2000层的神经网络,而且效果越来越好。ResNet网络的提出,使得我们可以训练很深的神经网络,并取得不错的效果。

2015年,ResNet首次被提出,把经过卷积之后的features map和input相加得到新的部分。便是残差块。左图是首次提出的残差块图。2015年的残差块的x是先跟weights相乘之后,再做BN归一化和relu激活。2016年 微软提出新的残差块,对输入input-x提前处理,经过BN归一化和relu 激活之后,再跟weight相乘。
在这里插入图片描述
现在大多人都用微软proposed后的残差块(pre-trained activation),即右图。我们的实战也会是用右图的残差块。

使用python实现残差块

def Unit(x,filters):
	‘’‘
	param x - 输入
	param filters - 特征数量
	’‘’
	res = x
	#第一层
    out = BatchNormalization()(x)  #先对x做BN归一化处理
    out = Activation("relu")(out)  #再激活x,然后做卷积
    out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding="same")(out)  
	#第二层,跟第一层同理处理
    out = BatchNormalization()(out)  
    out = Activation("relu")(out)
    out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding="same")(out)
	#最后跟res-即原来的input x相加
	out = keras.layers.add([res,out])
    return out
但如果我们想加入pooling,那么经过pool之后的x和res的维度就不一样,无法相加。所以我们需要对res也做维度处理。使得两者维度相同。

加载packages

import keras
from keras.datasets import cifar10
from keras.layers import Dense,Conv2D,MaxPooling2D,Flatten,AveragePooling2D,Dropout,BatchNormalization,Activation
from keras.models import Model,Input
from keras.optimizers import Adam
from keras.callbacks import LearningRateScheduler
from keras.callbacks import ModelCheckpoint
from math import ceil
import os
from keras.preprocessing.image import ImageDataGenerator
def Unit(x,filters,pool=False):
	‘’‘
	param x - 输入
	param filters - 特征数量
	param pool - False or True 表示是否要pooling
	’‘’
    res = x
    if pool:
        x = MaxPooling2D(pool_size=(2, 2))(x)
        #困惑点-尽管padding = ‘same’,由于strides是(2,2),所以出来的宽度和长度是 W/strides
        res = Conv2D(filters=filters,kernel_size=[1,1],strides=(2,2),padding="same")(res)   
        #由于strides=2 所以形状缩小了一倍
    out = BatchNormalization()(x)
    out = Activation("relu")(out)
    out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding="same")(out)

    out = BatchNormalization()(out)
    out = Activation("relu")(out)
    out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding="same")(out)

    out = keras.layers.add([res,out])
    
    return out
现在把完善好的残差块组合入模型里面

手写一个小模型

def MiniModel(input_shape):
	‘’‘
	param input_shape: 输入的shape
	’‘’
	images = Input(input_shape)  #表示接受的image的shape将会是input_shape
	#<tf.Tensor 'input_2:0' shape=(None, 32, 32, 3) dtype=float32>
	
	#开始带入网络
	#第一层卷积
	net = Conv2D(filters=32, kernel_size=[3, 3], strides=[1, 1], padding="same")(images)
	#然后放入残差块,stacking堆积三次
	net = Unit(net,32)   #32代表filters数量
	net = Unit(net,32)
	net = Unit(net,32)
	#再次堆积 但输入和输出的维度将会减少一倍when pool = True
	net = Unit(net,64,pool=True)
	net = Unit(net,64)
	net = Unit(net,64)
	#再次堆积
	net = Unit(net,128,pool=True)
	net = Unit(net,128)
	net = Unit(net,128)
	#再次堆积
	net = Unit(net, 256,pool=True)
	net = Unit(net, 256)
	net = Unit(net, 256)
	############# 残差块 堆积结束
	
	#下一层进行BN处理
	net = BatchNormalization()(net)
	#激活
	net = Activation("relu")(net)
	#随机丢掉25%的神经元
	net = Dropout(0.25)(net)
	#进行average pooling 把形状缩小为原来1/4
	net = AveragePooling2D(pool_size=(4,4))(net)
	############# 卷积结束
	#现在开始铺平,并开始预测y 
	#铺平卷积网络
	net = Flatten()(net)
	#用softmax预测 数量为10 
	net = Dense(units=10,activation="softmax")(net)
	############# 预测结束,把网络放入tf的Model里面
	model = Model(inputs=images,outputs=net)
	return model
模型我们已经手写好了,现在开始我们要准备数据,然后开始进行训练。

数据准备 – 使用cifar10数据集

#(1)加载 cifar10 dataset
(train_x, train_y) , (test_x, test_y) = cifar10.load_data()
#(2)数据normalize化,并把数据类型改为float32
train_x = train_x.astype('float32') / 255
test_x = test_x.astype('float32') / 255
#(3)减去平均值
train_x = train_x - train_x.mean()
test_x = test_x - test_x.mean()
#(4)除 std值 
train_x = train_x / train_x.std(axis=0)
test_x = test_x / test_x.std(axis=0)
#(5)ImageDataGenerator()是keras.preprocessing.image模块中的图片生成器,
#同时也可以在batch中对数据进行增强,扩充数据集大小,这里我们是对data进行了水平翻转和角度转移
datagen = ImageDataGenerator(rotation_range=10,
                             width_shift_range=5. / 32,
                             height_shift_range=5. / 32,
                             horizontal_flip=True)
#把train data放入图片生成器 ,只对train data进行生成更多的图片,对 test data 不做处理
datagen.fit(train_x)  
#########################对x的处理结束
#现在对Y做处理,把Y变成vector形式
#Encode the labels to vectors
train_y = keras.utils.to_categorical(train_y,10)
test_y = keras.utils.to_categorical(test_y,10)
#即Y变成了N个[0., 0., 0., 0., 0., 0., 1., 0., 0., 0.]形式的vector               

开始训练模型

input_shape = (32,32,3)
model = MiniModel(input_shape)
#compile模型
model.compile(optimizer=Adam(0.001),loss="categorical_crossentropy",metrics=["accuracy"])

#batch_size确定每个小批次中的样品数量。它的最大值是所有样本的数量
epochs = 50   #参数epoch决定网络中所有图像的训练次数
steps_per_epoch = ceil(50000/128)  #由样本数量/batch size

#放入训练过程的模型中
model.fit_generator(datagen.flow(train_x, train_y, batch_size=128),
                    validation_data=[test_x,test_y],
                    epochs=epochs,steps_per_epoch=steps_per_epoch, verbose=1, workers=4)
训练结束

用test data评估

accuracy = model.evaluate(x=test_x,y=test_y,batch_size=128)
model.save("cifar10model.h5")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jianafeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值