tensorflow2实现resnet50并用来分类猫狗

一、首先实现resnet50

具体可以参考这篇文章

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)


二、准备数据

如下面的图所示,将数据分成traintest文件夹,每个文件夹里面分成dogcat

tensorflow2实现resnet50并用来分类猫狗_第1张图片

三、写训练文件

细节都写在注释里了,有不懂的地方可以留言

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 查看训练情况:

tensorflow2实现resnet50并用来分类猫狗_第2张图片

 

四、写预测文件

训练好的权重文件会保存在logs文件夹里面:

tensorflow2实现resnet50并用来分类猫狗_第3张图片 

一般挑最后一个进行预测。其中注意要将传入预测的图片进行和训练时一样的预处理,具体包括:①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张猫和狗的图片进行测试:

tensorflow2实现resnet50并用来分类猫狗_第4张图片

最后将预测结果通过画图显示出来,以预测结果作为图像的title:

tensorflow2实现resnet50并用来分类猫狗_第5张图片

 这样,我们就走完了图像分类的所有流程了,如果对您有帮助,就点个赞吧,谢谢!

你可能感兴趣的:(tensorflow2,深度学习,深度学习)