尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

T8周:猫狗识别

T8周:猫狗识别 本文为365天深度学习训练营中的学习记录博客原作者K同学啊学习目的 要求了解model.train_on_batch()并运用了解tqdm并使用tqdm实现可视化进度条 拔高可选本文代码中存在一个严重的BUG请找出它并配以文字说明 探索难度有点大修改代码处理BUG一、 前期准备关于环境语言环境Python3.6编译器vsCode深度学习环境TensorFlow 2.6.21.数据导入import tensorflow as tf import os,PIL,pathlib import matplotlib.pyplot as plt import numpy as np from tensorflow import keras from tensorflow.keras import layers,modelsdata_dir C:/Users/hsq/Desktop/train/D7/ data_dir pathlib.Path(data_dir)image_count len(list(data_dir.glob(*/*.jpg))) print(图片总数为,image_count)代码运行结果二、数据预处理1.加载数据使用image_dataset_from_directory方法将磁盘中的数据加载到tf.data.Dataset中batch_size 8 img_height 224 img_width 224 关于image_dataset_from_directory()的详细介绍可以参考文章https://mtyjkh.blog.csdn.net/article/details/117018789 train_ds tf.keras.preprocessing.image_dataset_from_directory( data_dir, validation_split0.2, subsettraining, seed12, image_size(img_height, img_width), batch_sizebatch_size)代码运行结果 关于image_dataset_from_directory()的详细介绍可以参考文章https://mtyjkh.blog.csdn.net/article/details/117018789 val_ds tf.keras.preprocessing.image_dataset_from_directory( data_dir, validation_split0.2, subsetvalidation, seed12, image_size(img_height, img_width), batch_sizebatch_size)代码运行结果class_names train_ds.class_names print(class_names)代码运行结果2. 再次检查数据for image_batch, labels_batch in train_ds: print(image_batch.shape) print(labels_batch.shape) break代码运行结果Image_batch是形状的张量8,224,224,3。这是一批形状224x224x3的8张图片Label_batch是形状8的张量这些标签对应8张图片3. 配置数据集AUTOTUNE tf.data.AUTOTUNE def preprocess_image(image,label): return (image/255.0,label) # 归一化处理 train_ds train_ds.map(preprocess_image, num_parallel_callsAUTOTUNE) val_ds val_ds.map(preprocess_image, num_parallel_callsAUTOTUNE) train_ds train_ds.cache().shuffle(1000).prefetch(buffer_sizeAUTOTUNE) val_ds val_ds.cache().prefetch(buffer_sizeAUTOTUNE)4.可视化数据plt.figure(figsize(15, 10)) # 图形的宽为15高为10 for images, labels in train_ds.take(1): for i in range(8): ax plt.subplot(5, 8, i 1) plt.imshow(images[i]) plt.title(class_names[labels[i]]) plt.axis(off)代码运行结果三、构建VG-16网络from tensorflow.keras import layers, models, Input from tensorflow.keras.models import Model from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten, Dropout def VGG16(nb_classes, input_shape): input_tensor Input(shapeinput_shape) # 1st block x Conv2D(64, (3,3), activationrelu, paddingsame,nameblock1_conv1)(input_tensor) x Conv2D(64, (3,3), activationrelu, paddingsame,nameblock1_conv2)(x) x MaxPooling2D((2,2), strides(2,2), name block1_pool)(x) # 2nd block x Conv2D(128, (3,3), activationrelu, paddingsame,nameblock2_conv1)(x) x Conv2D(128, (3,3), activationrelu, paddingsame,nameblock2_conv2)(x) x MaxPooling2D((2,2), strides(2,2), name block2_pool)(x) # 3rd block x Conv2D(256, (3,3), activationrelu, paddingsame,nameblock3_conv1)(x) x Conv2D(256, (3,3), activationrelu, paddingsame,nameblock3_conv2)(x) x Conv2D(256, (3,3), activationrelu, paddingsame,nameblock3_conv3)(x) x MaxPooling2D((2,2), strides(2,2), name block3_pool)(x) # 4th block x Conv2D(512, (3,3), activationrelu, paddingsame,nameblock4_conv1)(x) x Conv2D(512, (3,3), activationrelu, paddingsame,nameblock4_conv2)(x) x Conv2D(512, (3,3), activationrelu, paddingsame,nameblock4_conv3)(x) x MaxPooling2D((2,2), strides(2,2), name block4_pool)(x) # 5th block x Conv2D(512, (3,3), activationrelu, paddingsame,nameblock5_conv1)(x) x Conv2D(512, (3,3), activationrelu, paddingsame,nameblock5_conv2)(x) x Conv2D(512, (3,3), activationrelu, paddingsame,nameblock5_conv3)(x) x MaxPooling2D((2,2), strides(2,2), name block5_pool)(x) # full connection x Flatten()(x) x Dense(4096, activationrelu, namefc1)(x) x Dense(4096, activationrelu, namefc2)(x) output_tensor Dense(nb_classes, activationsoftmax, namepredictions)(x) model Model(input_tensor, output_tensor) return model modelVGG16(1000, (img_width, img_height, 3)) model.summary()代码运行结果四、编译model.compile(optimizeradam, loss sparse_categorical_crossentropy, metrics [accuracy])五、训练模型from tqdm import tqdm import tensorflow.keras.backend as K epochs 10 lr 1e-4 # 记录训练数据方便后面的分析 history_train_loss [] history_train_accuracy [] history_val_loss [] history_val_accuracy [] for epoch in range(epochs): train_total len(train_ds) val_total len(val_ds) total预期的迭代数目 ncols控制进度条宽度 mininterval进度更新最小间隔以秒为单位默认值0.1 with tqdm(totaltrain_total, descfEpoch {epoch 1}/{epochs},mininterval1,ncols100) as pbar: lr lr*0.92 K.set_value(model.optimizer.lr, lr) for image,label in train_ds: 训练模型简单理解train_on_batch就是它是比model.fit()更高级的一个用法 想详细了解 train_on_batch 的同学 可以看看我的这篇文章https://www.yuque.com/mingtian-fkmxf/hv4lcq/ztt4gy history model.train_on_batch(image,label) train_loss history[0] train_accuracy history[1] pbar.set_postfix({loss: %.4f%train_loss, accuracy:%.4f%train_accuracy, lr: K.get_value(model.optimizer.lr)}) pbar.update(1) history_train_loss.append(train_loss) history_train_accuracy.append(train_accuracy) print(开始验证) with tqdm(totalval_total, descfEpoch {epoch 1}/{epochs},mininterval0.3,ncols100) as pbar: for image,label in val_ds: history model.test_on_batch(image,label) val_loss history[0] val_accuracy history[1] pbar.set_postfix({loss: %.4f%val_loss, accuracy:%.4f%val_accuracy}) pbar.update(1) history_val_loss.append(val_loss) history_val_accuracy.append(val_accuracy) print(结束验证) print(验证loss为%.4f%val_loss) print(验证准确率为%.4f%val_accuracy)lr从 1e-4 开始每轮乘以 0.92代码运行结果在代码运行过程中使用了“tqdm这个库tqdm是一个显示Python运行进度条的库可以在Python长循环中添加一个进度提示信息用户只需要封装任意的迭代器tqdm(iterator)。它可以帮助我们监测程序运行的进度估计运行的时长甚至可以协助debug。对于在长时间运行的任务中显示进度很有用因为它可以让用户知道任务正在进行。model.train_on_batch()特性model.fit()model.train_on_batch()抽象层级高层 API封装完整训练流程低层 API单步训练输入完整数据集Dataset、NumPy 数组等单个 batch 的输入和标签功能自动遍历 epoch、batch自动打乱、验证、回调、进度条、指标累积平均、学习率调度等只对当前 batch 做一次前向传播、反向传播和参数更新返回值History对象包含每个 epoch 的 loss 和 metrics当前 batch 的 loss 和 metrics 列表如[loss, accuracy]指标记录自动累积并计算整个 epoch 的平均指标只返回当前 batch 的指标不会自动累积验证可通过validation_data自动验证并计算整体指标需手动遍历验证集并自行累加计算平均适用场景常规训练、快速实验需要精细控制训练过程如 GAN、自定义梯度、强化学习等model.fit()是“全自动”适合大多数标准训练train_on_batch()是“手动挡”适合需要自定义训练逻辑的场景。但使用train_on_batch()时所有 epoch 循环、指标统计、验证评估、学习率调整等都需要自己正确实现。六、模型评估from datetime import datetime current_time datetime.now() # 获取当前时间 epochs_range range(epochs) plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(epochs_range, history_train_accuracy, labelTraining Accuracy) plt.plot(epochs_range, history_val_accuracy, labelValidation Accuracy) plt.legend(loclower right) plt.title(Training and Validation Accuracy) plt.xlabel(current_time) # 打卡请带上时间戳否则代码截图无效 plt.subplot(1, 2, 2) plt.plot(epochs_range, history_train_loss, labelTraining Loss) plt.plot(epochs_range, history_val_loss, labelValidation Loss) plt.legend(locupper right) plt.title(Training and Validation Loss) plt.show()代码运行结果验证集准确率从第2轮开始保持在100%查看模型构建发现标签数为1000这是原始模型的标签数在迁移学习后要改成数据集对应的标签数这里改成2再次尝试验证集准确率始终保持在同一水平依然存在问题model.train_on_batch()这个做法学习后可以发现原代码对损失率和准确率的记录并不是整个 epoch 的平均指标而是每个 epoch 最后一个 batch 的瞬时指标。因此应该需要在每个 batch 循环内累加 loss 和 accuracy最后除以 batch 数量得到 epoch 平均值from tqdm import tqdm import tensorflow.keras.backend as K epochs 10 lr 1e-4 # 记录训练数据方便后面的分析 history_train_loss [] history_train_accuracy [] history_val_loss [] history_val_accuracy [] for epoch in range(epochs): train_total len(train_ds) val_total len(val_ds) lr lr * 0.92 K.set_value(model.optimizer.lr, lr) # 训练 train_loss_sum 0.0 train_accuracy_sum 0.0 train_batches 0 with tqdm(totaltrain_total, descfEpoch {epoch 1}/{epochs}, mininterval1, ncols100) as pbar: for image, label in train_ds: history model.train_on_batch(image, label) train_loss history[0] train_accuracy history[1] train_loss_sum train_loss train_accuracy_sum train_accuracy train_batches 1 pbar.set_postfix({loss: %.4f % train_loss, accuracy: %.4f % train_accuracy, lr: K.get_value(model.optimizer.lr)}) pbar.update(1) train_loss_avg train_loss_sum / train_batches train_accuracy_avg train_accuracy_sum / train_batches history_train_loss.append(train_loss_avg) history_train_accuracy.append(train_accuracy_avg) print(开始验证) # 验证 val_loss_sum 0.0 val_accuracy_sum 0.0 val_batches 0 with tqdm(totalval_total, descfEpoch {epoch 1}/{epochs}, mininterval0.3, ncols100) as pbar: for image, label in val_ds: history model.test_on_batch(image, label) val_loss history[0] val_accuracy history[1] val_loss_sum val_loss val_accuracy_sum val_accuracy val_batches 1 pbar.set_postfix({loss: %.4f % val_loss, accuracy: %.4f % val_accuracy}) pbar.update(1) val_loss_avg val_loss_sum / val_batches val_accuracy_avg val_accuracy_sum / val_batches history_val_loss.append(val_loss_avg) history_val_accuracy.append(val_accuracy_avg) print(结束验证) print(验证loss为%.4f % val_loss_avg) print(验证准确率为%.4f % val_accuracy_avg)代码运行结果七、预测import numpy as np # 采用加载的模型new_model来看预测结果 plt.figure(figsize(18, 3)) # 图形的宽为18高为5 plt.suptitle(预测结果展示) for images, labels in val_ds.take(1): for i in range(8): ax plt.subplot(1,8, i 1) # 显示图片 plt.imshow(images[i].numpy()) # 需要给图片增加一个维度 img_array tf.expand_dims(images[i], 0) # 使用模型预测图片中的人物 predictions model.predict(img_array) plt.title(class_names[np.argmax(predictions)]) plt.axis(off)代码运行结果八、感想本周只要学习的是使用model.train_on_batch()对每一个 batch执行一次完整的训练步骤然后获得所有Batch训练获得的均值结果。这个其实是模型训练的底层代码model.fit()其实就是自动挡的model.train_on_batch()。model.fit()内部其实就是在循环调用train_on_batch()。此外对bug修改后准确率始终维持在0.49对于一个二分类模型来说这个训练结果说明模型并没有学习到东西是在乱猜。考虑的原因主要是数据量太小模型参数太大学习率在每个epoch都在衰减在这些情况下导致模型学习失败。可以考虑对数据进行增强、模型模块冻结、增大学习率等措施尝试改善学习情况。
返回列表