具体可以参考这篇文章
import warnings
warnings.filterwarnings("ignore")
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
from tensorflow.keras.layers import (Conv2D,MaxPool2D,Input,ZeroPadding2D,
Add,AveragePooling2D,Dense,Flatten,BatchNormalization,
)
from tensorflow.keras.models import Model
def conv_block(inputs,block_id:str,filter_num,stride=1):
""" 从conv3_x开始,第1个1*1卷积需要下采样 """
if (block_id[0]!='1' and block_id[2]=='1'):
stride = 2
bottle_conv1 = Conv2D(filter_num,1,stride,activation='relu',name="block"+block_id+"_conv1")(inputs)
bottle_conv1 = BatchNormalization()(bottle_conv1)
bottle_conv2 = Conv2D(filter_num,3,1,activation='relu',name="block"+block_id+"_conv2")(bottle_conv1)
bottle_conv2 = BatchNormalization()(bottle_conv2)
bottle_conv3 = Conv2D(filter_num*4,1,1,activation='relu',name="block"+block_id+"_conv3")(bottle_conv2)
bottle_conv3 = BatchNormalization()(bottle_conv3)
bottle_conv3_pad = ZeroPadding2D((1,1),name="block"+block_id+"_conv3Pad")(bottle_conv3)
""" 从conv3_x开始,第1个1*1卷积需要下采样与输出进行堆叠 """
inputs_conv = Conv2D(filter_num*4,1,stride,activation='relu',name='block'+block_id+"_conv4")(inputs)
inputs_conv = BatchNormalization()(inputs_conv)
# print(block_id,bottle_conv3.shape,inputs_conv.shape)
bottle_out = Add()([bottle_conv3_pad,inputs_conv])
return bottle_out
def RESNET50(input_shape=(224,224,3),num_classes=1000):
inputs = Input(shape=input_shape)
inputsPad = ZeroPadding2D((3,3))(inputs) # 多出
conv1 = Conv2D(64,7,2,activation='relu',name='conv1')(inputsPad)
conv1 = BatchNormalization()(conv1)
conv2_x_1 = MaxPool2D((3,3),2,padding='same',name='conv2_x_maxpooling')(conv1) # 注意padding
print('conv2_x start...')
filter_nums0 = 64
BLOCK1_out = conv2_x_1
for i in range(1,4):
BLOCK1_out = conv_block(BLOCK1_out,f"1_{i}",filter_nums0)
print('conv2_x done!')
print(BLOCK1_out.shape)
print('conv3_x start...')
filter_nums1 = 128
# remind downsampling
BLOCK2_out = BLOCK1_out
for i in range(1,5):
BLOCK2_out = conv_block(BLOCK2_out,f"2_{i}",filter_nums1)
print('conv3_x done!')
print(BLOCK2_out.shape)
print('conv4_x start...')
filter_num2 = 256
# remind downsampling
BLOCK3_out = BLOCK2_out
for i in range(1,7):
BLOCK3_out = conv_block(BLOCK3_out,f"3_{i}",filter_num2)
print('conv4_x done!')
print(BLOCK3_out.shape)
print('conv5_x start...')
filter_num3 = 512
# remind downsampling
BLOCK4_out = BLOCK3_out
for i in range(1,4):
BLOCK4_out = conv_block(BLOCK4_out,f"4_{i}",filter_num3)
print('conv5_x done!')
print(BLOCK4_out.shape)
avgPooling = AveragePooling2D(BLOCK4_out.shape[1],name='average_pool')(BLOCK4_out)
x = Flatten()(avgPooling)
outlayer = Dense(num_classes,activation='softmax',name='out_layer')(x)
print('out shape:',outlayer.shape)
model = Model(inputs=inputs,outputs=outlayer,name='resnet50-tf2')
# model.load_weights("resnet50_weights_tf_dim_ordering_tf_kernels.h5")
return model
# model = RESNET50(num_classes=2)
# model.summary()
# print(f"layer's length={len(model.layers)}")
# for i,layer in enumerate(model.layers):
# print(i,layer.name)
如下面的图所示,将数据分成和文件夹,每个文件夹里面分成和
细节都写在注释里了,有不懂的地方可以留言
from resnet50 import RESNET50
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import (ModelCheckpoint,TensorBoard)
import tensorflow as tf
import os
from tensorflow.keras.optimizers.schedules import ExponentialDecay
from tensorflow.keras.preprocessing.image import ImageDataGenerator
if __name__ == '__main__':
print('这条线以下是输出'.center(62,'-'))
model = RESNET50(num_classes=2) # cat,dog
INIT_LEARNING_RATE = 0.001
# 学习率指数衰减
learningRateDecay = ExponentialDecay(initial_learning_rate=INIT_LEARNING_RATE,
decay_steps=2000,decay_rate=0.96)
adam = Adam(learning_rate=learningRateDecay)
model.compile(optimizer=adam,loss='categorical_crossentropy',metrics=['acc'])
# model.load_weights("logs/EP058_acc0.022-vac0.490.h5") 这个可以从断点处继续训练
""" 数据 """
bs = 30
train_dir = "datasets/train/"
val_dir = "datasets/test/"
train_datagen = ImageDataGenerator(rescale=1.0/255.0)
val_datagen = ImageDataGenerator(rescale=1.0/255.0)
train_generator = train_datagen.flow_from_directory(train_dir,batch_size=bs,
class_mode='categorical',
target_size=(224,224))
val_generator = val_datagen.flow_from_directory(val_dir,batch_size=bs,
class_mode='categorical',
target_size=(224,224))
# 设置checkpoint
logdir = 'logs/'
if not os.path.exists(logdir):
os.mkdir(logdir)
checkpoint_path = logdir + "EP{epoch:03d}_loss{loss:.3f}-valoss{val_loss:.3f}.h5"
checkpoint_dir = os.path.dirname(checkpoint_path)
cp_callback = ModelCheckpoint(filepath=checkpoint_path,
save_weights_only=True,verbose=1)
# 设置tensorboard
tensorboard_callback = TensorBoard(log_dir=logdir, histogram_freq=1)
# 训练
epochs = 100
model.fit(train_generator,
validation_data=val_generator,
epochs=epochs,
callbacks=[cp_callback,tensorboard_callback])
print('输出完毕'.center(66,'-'))
可以通过 tensorboard --logdir=logs --host=localhost 查看训练情况:
训练好的权重文件会保存在logs文件夹里面:
一般挑最后一个进行预测。其中注意要将传入预测的图片进行和训练时一样的预处理,具体包括:①reshape,②expand_dims,③归一化
from resnet50 import RESNET50
import cv2
import numpy as np
import time
import matplotlib.pyplot as plt
if __name__ == '__main__':
print('这条线以下是输出'.center(62,'-'))
classes_name = ['cat',"dog"]
input_shape = (224,224)
print('predict start...'.center(66,'-'))
model = RESNET50(num_classes=len(classes_name))
model.load_weights("logs/EP039_loss0.019-valoss0.295.h5")
print(f'load weights successfully!')
figure = plt.figure(figsize=(6,4),dpi=200)
for i,filename in enumerate(['testCat1.jpg','testCat2.jpg',
'testDog.jpg','testDog2.jpg']):
start = time.time()
inputs = cv2.imread(filename)
inputs = cv2.resize(inputs,input_shape).astype(np.float32)
inputs0 = np.array(inputs, dtype="float") / 255.0
inputs = np.expand_dims(inputs0,axis=0)
# print(inputs.shape)
# print(inputs)
outputs = model.predict(inputs)
print(outputs)
result_index = np.argmax(outputs)
result = classes_name[result_index]
print(f"图片是{result}")
print(f'花费时间{time.time()-start:.2f}s')
plt.subplot(2,2,i+1)
plt.title(result)
plt.axis('off')
plt.imshow(inputs0[...,::-1])
plt.show()
print('输出完毕'.center(66,'-'))
我到网上下了2张猫和狗的图片进行测试:
最后将预测结果通过画图显示出来,以预测结果作为图像的title: