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結構圖,