resnet网络是一种使用了残差网络的结构,相较于普通的神经网络在达到一定accuracy后会出现一定的下降,resnet解决了这个问题
对于初学cnn的人来说,这是一个非常好的上手模型,它的结构不复杂,实现起来也非常的容易,然而,为了搞清如何使用tensorflow2实现resnet,
我百度了各种使用tensorflow2.0实现resnet的方法,虽然也搜到了几个使用tensorflow2.0实现resnet网络,但要么只有resnet18,要么使用tensorflow1实现的,并且由于我本身对于tensorflow2.0的不太熟悉,看了半天才勉强看懂,自己重写却总是出现各种错误,
于是我又花了好长时间从官网学习tensorflow2,终于我码出来了resnet18和50的代码,我自认为实现的代码数量以及精简程度比其他人写的稍微少一点,当然,这并不是说代码的质量有多好,而是为了对新手更友好点,
我希望将其分享出来,以备那些初学cnn以及对于tensorflow还不是特别熟悉的人,可以借鉴下我实现模型的写法,希望新人们不会像我一样卡在实现resnet模型的结点上,
这两个模型我已经在我的数据集(一个4分类的1600张118*118的关于上下左右箭头分类的图片上)试验过了,均可以达到100%的accuracy,因此,模型应该是没有问题的
好了,话不多说,代码奉上
resnet18:
import tensorflow as tf
import numpy as np
import os
from tensorflow import keras
from tensorflow.keras import layers,Sequentialclass prepare(layers.Layer):
def __init__(self):
super(prepare, self).__init__()
self.conv1=layers.Conv2D(64,(3,3),strides=1,padding="same")
self.bn=layers.BatchNormalization()
self.Relu=layers.Activation('relu')
self.mp=layers.MaxPool2D(pool_size=(2,2),strides=2)
def call(self,inputs):
x=self.conv1(inputs)
x=self.bn(x)
x=self.Relu(x)
x=self.mp(x)
return x
class BasicBlock(layers.Layer):
def __init__(self,filter_num,stride=1):
super(BasicBlock, self).__init__()
self.conv1=layers.Conv2D(filter_num,(3,3),strides=stride,padding='same')
self.bn1=layers.BatchNormalization()
self.relu=layers.Activation('relu')
self.conv2=layers.Conv2D(filter_num,(3,3),strides=1,padding='same')
self.bn2 = layers.BatchNormalization()if stride!=1:
self.downsample=Sequential()
self.downsample.add(layers.Conv2D(filter_num,(1,1),strides=stride))
else:
self.downsample=lambda x:x
def call(self,input,training=None):
out=self.conv1(input)
out=self.bn1(out)
out=self.relu(out)out=self.conv2(out)
out=self.bn2(out)identity=self.downsample(input)
output=layers.add([out,identity])
output=tf.nn.relu(output)
return output
def get_model(num_classes):
input_image = layers.Input(shape=(112, 112, 3), dtype="float32")
output=prepare()(input_image)
output=BasicBlock(64)(output)
output=BasicBlock(64)(output)
output=BasicBlock(128,2)(output)
output=BasicBlock(128)(output)
output=BasicBlock(256,2)(output)
output=BasicBlock(256)(output)
output=BasicBlock(512,2)(output)
output=BasicBlock(512)(output)
output=layers.GlobalAveragePooling2D()(output)
output=layers.Dense(num_classes)(output)
output-layers.Activation('relu')(output)
return keras.Model(inputs=input_image, outputs=output)
resnet50:
import tensorflow as tf
import numpy as np
import os
from tensorflow import keras
from tensorflow.keras import layers,Sequentialclass prepare(layers.Layer):
def __init__(self):
super(prepare, self).__init__()
self.conv1=layers.Conv2D(64,(3,3),strides=1,padding="same")
self.bn=layers.BatchNormalization()
self.Relu=layers.Activation('relu')
self.mp=layers.MaxPool2D(pool_size=(2,2),strides=2)
def call(self,inputs):
x=self.conv1(inputs)
x=self.bn(x)
x=self.Relu(x)
x=self.mp(x)
return x
class block(layers.Layer):
def __init__(self,filter_num,stride=1,is_first=False):
super(block,self).__init__()
self.conv1=layers.Conv2D(filter_num,(1,1),strides=1)
self.bn1=layers.BatchNormalization()
self.conv2=layers.Conv2D(filter_num,(3,3),strides=stride,padding='same')
self.bn2=layers.BatchNormalization()
self.conv3=layers.Conv2D(filter_num*4,(1,1),strides=1)
self.bn3=layers.BatchNormalization()
self.relu=layers.Activation('relu')
if stride!=1 or is_first==True:
self.downsample=Sequential()
self.downsample.add(layers.Conv2D(filter_num*4,(1,1),strides=stride))
else:
self.downsample=lambda x:x
def call(self,inputs):
x=self.conv1(inputs)
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)
identity=self.downsample(inputs)
output=layers.add([x,identity])
output=tf.nn.relu(output)
return output
def get_model(num_classes):
input_image = layers.Input(shape=(112, 112, 3), dtype="float32")
out=prepare()(input_image)
out=block(64,is_first=True)(out)
out=block(64)(out)
out=block(64)(out)
out=block(128,stride=2)(out)
out=block(128)(out)
out=block(128)(out)
out=block(256,stride=2)(out)
out=block(256)(out)
out=block(256)(out)
out=block(512,stride=2)(out)
out=block(512)(out)
out=block(512)(out)
out=layers.GlobalAveragePooling2D()(out)
out=layers.Dense(num_classes)(out)
out-layers.Activation('relu')(out)
return keras.Model(inputs=input_image, outputs=out)
需要注意的是,prepare类是对数据的预处理,论文是先使用7x7的过滤器的,我这里使用的是3x3,因为我输入的图片是
112*112大小的,如果需要改的话改prepare就行了
以上就是resnet的tensorflow1实现,代码是不是可以接受呢,是不是能看懂呢,
只要输入model=get_model(num_classes)就能得到模型拉,num_calsses是你分类的数量
之后定义好损失函数,使用fit训练就可以了,
同时,因为大多数数据集要么是量大,要么是分类的数量大,普通的笔记本基本是训练不了的,
必须得专门的gpu训练才可,我这里从别人那里得到了一份1600张的4分类上下左右箭头的图片,如果需要的话私聊我哦
最后,附上一张resnet结构图,