365天深度学习训练营-第T8周:猫狗识别

 我的环境:

  • 语言环境:Python3.11.2
  • 编译器:PyCharm Community Edition 2022.3
  • 深度学习环境:TensorFlow2 

 一、跑通代码

1.1 导入数据构建网络

        导入并配置数据数据,构建VGG16神经网络

import matplotlib.pyplot as plt
import pathlib,PIL,warnings
import tensorflow as tf
from tensorflow.keras import layers,models,Input
from tensorflow.keras.layers import Conv2D,MaxPooling2D,Dense,Flatten,Dropout
from tensorflow.keras.models import Model
import numpy as np
from tqdm import tqdm
import tensorflow.keras.backend as k
#用来设置中文字体,此处为黑体
plt.rcParams['font.sans-serif'] = ['SimHei']
#用来显示负号
plt.rcParams['axes.unicode_minus'] = False
#隐藏警告
warnings.filterwarnings('ignore')

#导入数据
path = 'F:/365-7-data'
data = pathlib.Path(path)

#显示数据
count = len(list(data.glob('*/*')))
print(count)
PIL.Image.open(str(list(data.glob('cat/*'))[0])).show()

#配置数据
batch_size=8
img_height = 224
img_width = 224

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data,
    validation_split=0.2,
    subset='training',
    seed=123,
    image_size=(img_height,img_width),
    batch_size=batch_size
)
vali_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data,
    validation_split=0.2,
    subset='validation',
    seed=123,
    image_size=(img_height,img_width),
    batch_size=batch_size
)
class_names = train_ds.class_names
print(class_names)

#查看数据
for img,labels in train_ds.take(1):
    print(img.shape)
    print(labels.shape)
    break

#配置数据集
AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
vali_ds = vali_ds.cache().prefetch(buffer_size=AUTOTUNE)

normalization_layer = layers.experimental.preprocessing.Rescaling(1./255)
train_ds = train_ds.map(lambda x,y:(normalization_layer(x),y))
vali_ds = vali_ds.map(lambda x,y:(normalization_layer(x),y))

image_batch ,labels_batch = next(iter(train_ds))
print(np.min(image_batch[0]),np.max(image_batch[0]))

#构建VGG16
def VGG16(nb_classes, input_shape):
    input_tensor = Input(shape=input_shape)
    x = Conv2D(64,(3,3),activation='relu',padding='same',name='block1_conv1')(input_tensor)
    y = Conv2D(64,(3,3),activation='relu',padding='same',name='block1_conv2')(x)
    z = MaxPooling2D((2,2),strides=(2,2),name='block1_pool')(y)
    q = Conv2D(128,(3,3),activation='relu',padding='same',name='block2_conv1')(z)
    w = Conv2D(128,(3,3),activation='relu',padding='same',name='block2_conv2')(q)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(w)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
    x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
    x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
    x = Flatten()(x)
    x = Dense(4096,activation='relu',name='fc1')(x)
    x = Dense(4096, activation='relu', name='fc2')(x)
    output_tensor = Dense(nb_classes,activation='softmax',name='predictions')(x)
    print(output_tensor)
    print(type(output_tensor))
    model = Model(input_tensor,output_tensor)
    return model
model = VGG16(1000,(224,224,3))
model.summary()
model.compile(
    optimizer='adam',
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=['accuracy']
)

        使用了plt的rcParams模块,其是一个全局的参数配置字典,可以用来设置图形的各种属性。font.sans-serif用于设置图形中的字体,它是一个列表,其中的元素是字体名称。axes.unicode_minus用于设置图形中的负号显示方式。

        使用了VGG16神经网络进行图片分类。该网络层结构简洁,但因为其较深的网络结构会导致训练时间过长,调参难度大。除此之外该模型需要的容量大,不利于部署。

1.2 模型训练

        本次使用train_on_batch进行模型训练,配合tqdm显示进度条

epochs = 10
lr = 1e-4
trloss = []
tracc = []
valoss = []
vaacc = []

for epoch in range(epochs):
    tr_to = len(train_ds)
    va_to = len(vali_ds)
    with tqdm(total=tr_to,desc=f'Epoch{epoch+1}/{epoch}',mininterval=1,ncols=100) as pdar:
        lr = lr*0.92
        k.set_value(model.optimizer.lr,lr)
        for img,label in train_ds:
            history = model.train_on_batch(img,label)

            tr_loss = history[0]
            tr_acc = history[1]
            pdar.set_postfix({'loss':'%.4f'%tr_loss,
                             'accuracy':'%.4f'%tr_acc,
                              'lr': k.get_value(model.optimizer.lr)}
                             )
            pdar.update(1)
        trloss.append(tr_loss)
        tracc.append(tr_acc)
    print('开始验证!')
    with tqdm(total=va_to, desc=f'Epoch{epoch + 1}/{epoch}', mininterval=0.3, ncols=100) as pdar:
        for img, label in vali_ds:
            history = model.test_on_batch(img, label)

            va_loss = history[0]
            va_acc = history[1]
            pdar.set_postfix({'loss': '%.4f' % va_loss,
                              'accuracy': '%.4f' % va_acc}
                             )
            pdar.update(1)
        valoss.append(va_loss)
        vaacc.append(va_acc)
    print('结束验证')
    print('验证loss为:%.4f'%va_loss)
    print('验证准确率为:%.4f'%va_acc)

        使用了tqdm中的tqdm模块用于在循环或迭代中使用简易的方式显示进度条,其中的参数为total为当次循环的总次数,用于计算百分比;desc是描述进度条的文本;mininterval是每次更新的最小间隔,以秒为单位;nclos用于控制进度条的宽度,默认80。这里将tqdm.tqdm命名为了pdar并在训练集和验证集的循环中使用。

        set_postfix()是tqdm库中的一个方法,用于在进度条后面添加附加信息。而update(1)是用于更新进度条的进度,其中的参数1表示进度条的步长,即每次更新进度条的进度增加的量。

        这里训练模型使用的是model.train_on_batch()方法。它比fit()方法更加灵活。model.train_on_batch()方法是用于手动批量训练模型的方法。它需要手动传入一个批次的训练数据,然后计算损失并更新模型参数。这个方法通常用于需要更细粒度控制训练过程的场景,比如使用自定义的损失函数或者需要手动调整学习率等。而model.fit()方法则是用于自动批量训练模型的方法。它会自动将训练数据分成多个批次,然后进行训练。在每个批次训练完成后,它会自动计算损失并更新模型参数。这个方法通常用于一般的训练场景,比如使用常见的损失函数和优化器进行训练。

        这里使用了tensorflow.keras.backend的set_value()方法修改张量的值。这里修改的为学习率。

1.3 模型评估

        评估准确率及损失率 

epochs_range = range(len(trloss))

plt.figure(figsize=(12,4))
plt.subplot(1,2,1)
plt.plot(epochs_range,tracc,label='Training Accuracy')
plt.plot(epochs_range,vaacc,label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1,2,2)
plt.plot(epochs_range,trloss,label='Training Loss')
plt.plot(epochs_range,valoss,label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

二、bug

        安照教程上的代码运行了该模型没有出现问题,但是拔高中有所含有重大bug,在训练模型时的学习并没有使用到初始的1e-4,而是之间进行了下降,将下降调整到训练循环后即可。

with tqdm(total=tr_to,desc=f'Epoch{epoch+1}/{epoch}',mininterval=1,ncols=100) as pdar:
        for img,label in train_ds:
            history = model.train_on_batch(img,label)

            tr_loss = history[0]
            tr_acc = history[1]
            pdar.set_postfix({'loss':'%.4f'%tr_loss,
                             'accuracy':'%.4f'%tr_acc,
                              'lr': k.get_value(model.optimizer.lr)}
                             )
            pdar.update(1)
        lr = lr*0.92
        k.set_value(model.optimizer.lr,lr)
        trloss.append(tr_loss)
        tracc.append(tr_acc)

 三、总结

        本次使用了新的训练方法训练模型,并为了清晰的看到模型训练状况使用了tqdm库进行进度条的显示。新的训练方式train_on_batch()相比于fit()更加灵活,更适合细致的、需要调参的模型训练。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值