本文为365天深度学习训练营中的学习记录博客原作者K同学啊一、前期工作1.设置GPU使用CPU因此跳过import tensorflow as tf gpus tf.config.list_physical_devices(GPU) if gpus: tf.config.experimental.set_memory_growth(gpus[0], True) #设置GPU显存用量按需使用 tf.config.set_visible_devices([gpus[0]],GPU) # 打印显卡信息确认GPU可用 print(gpus)2.导入数据import numpy as np import matplotlib.pyplot as plt # 支持中文 plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号 import os,PIL,pathlib #隐藏警告 import warnings warnings.filterwarnings(ignore) data_dir ./365-9-data data_dir pathlib.Path(data_dir) image_count len(list(data_dir.glob(*/*))) print(图片总数为,image_count)二、数据预处理1.加载数据batch_size 64 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) break3.配置数据集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)三、构建VGG-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])五、训练模型import numpy as np from tqdm import tqdm import tensorflow as tf from tensorflow.keras.optimizers import Adam # 1. 超参数设置 epochs 10 lr 1e-4 # 2. 模型编译 # 【修复点】使用 sparse_categorical_crossentropy 处理整数型标签 (64,) model.compile( optimizerAdam(learning_ratelr), losssparse_categorical_crossentropy, metrics[accuracy] ) # 3. 训练记录器 history_train_loss [] history_train_accuracy [] history_val_loss [] history_val_accuracy [] # 4. 核心训练循环 for epoch in range(epochs): train_total len(train_ds) val_total len(val_ds) # 【修复点】使用 assign 动态更新学习率适配最新版 TF/Keras model.optimizer.learning_rate.assign(lr) # ------------------ 训练阶段 ------------------ with tqdm(totaltrain_total, descfEpoch {epoch 1}/{epochs}, mininterval1, ncols100) as pbar: train_loss [] train_accuracy [] for image, label in train_ds: history model.train_on_batch(image, label) train_loss.append(history[0]) train_accuracy.append(history[1]) # 【修复点】直接格式化输出当前的 lr 变量 pbar.set_postfix({ train_loss: %.4f % history[0], train_acc: %.4f % history[1], lr: %.6f % lr }) pbar.update(1) history_train_loss.append(np.mean(train_loss)) history_train_accuracy.append(np.mean(train_accuracy)) # ------------------ 验证阶段 ------------------ print(开始验证) with tqdm(totalval_total, descfEpoch {epoch 1}/{epochs} (Val), mininterval0.3, ncols100) as pbar: val_loss [] val_accuracy [] for image, label in val_ds: history model.test_on_batch(image, label) val_loss.append(history[0]) val_accuracy.append(history[1]) pbar.set_postfix({ val_loss: %.4f % history[0], val_acc: %.4f % history[1] }) pbar.update(1) history_val_loss.append(np.mean(val_loss)) history_val_accuracy.append(np.mean(val_accuracy)) print(结束验证) print(验证loss为%.4f % np.mean(val_loss)) print(验证准确率为%.4f % np.mean(val_accuracy)) print(- * 60) # 5. 学习率衰减 # 当前 epoch 结束后衰减学习率 lr lr * 0.92六、模型评估from datetime import datetime current_time datetime.now() # 获取当前时间 epochs_range range(epochs) plt.figure(figsize(14, 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()七、预测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)八、个人总结1.数据预处理与管道优化 (tf.data)在构建深度学习数据管道时合理使用 tf.data API 能大幅提升训练效率快捷加载使用 image_dataset_from_directory 可以直接从本地目录按文件夹名称标签自动构建带有批次 (Batch) 的图像数据集。指南此 API 在 TensorFlow 2.3.0 及以上版本才移入正式库。低版本会报错需升级 TF 版本。性能优化cache()将预处理后的数据集缓存到内存中避免在每个 Epoch 重复读取磁盘大幅加速训练。shuffle()打乱数据顺序打破数据的原有排列规律提升模型泛化能力。prefetch()预取数据。让模型在执行当前步训练的同时后台自动准备下一步的数据实现 CPU (数据准备) 和 GPU (模型计算) 的并行工作。指南配置 AUTOTUNE 时若遇到属性报错说明版本较老需改为 tf.data.experimental.AUTOTUNE。2.VGG-16 神经网络架构核心VGG 是一种经典的卷积神经网络其核心设计理念和优缺点非常鲜明网络结构总共包含 16个隐藏层由 13个卷积层 (Conv) 3个全连接层 (FC) 组成池化层不计入权重层数。包含 5个最大池化层 用于特征降维。核心优势 (Pros)结构极简且统一整个网络全部采用相同尺寸的 3x3 卷积核 和 2x2 最大池化核。通过堆叠小卷积核来替代大卷积核既保证了感受野又减少了参数量。致命劣势 (Cons)参数量与体积巨大全连接层占据了极其庞大的参数量导致模型权重文件高达 500MB 以上非常不利于在移动端或嵌入式设备上部署。训练成本高收敛较慢训练时间长调参难度相对较大。3.模型编译 (Compile)在模型训练前必须配置好三大核心组件损失函数 (Loss)模型优化的“指南针”用于计算当前预测值与真实标签之间的差距。优化器 (Optimizer)模型的“引擎”决定了模型如何利用计算出的误差(Loss)去更新网络中的权重例如 Adam, SGD 等。评价指标 (Metrics)用于直观监控模型表现的指标最常用的是准确率 (Accuracy)即分类正确的样本比例。4.模型预测 (Predict)在进行单张图片推理预测时有一个非常容易被忽略的张量维度问题升维处理Keras 模型在设计时默认输入的是批次 (Batch) 数据即输入张量的形状应当是 (batch_size, height, width, channels)。代码实现当我们只输入一张图片 (224, 224, 3) 时必须使用 tf.expand_dims(image, 0) 在第0个位置增加一个维度将其形状转换为 (1, 224, 224, 3) 才能送入 model.predict()。解析结果模型输出的通常是各个类别的概率分布需要结合 np.argmax(predictions) 提取出概率最大的那个索引进而映射回真实的标签名称 (class_names)。5.数据增强提高准确率可以在模型构建前加入数据增强 (Data Augmentation) 层。在 TensorFlow 中可以使用 tf.keras.layers.RandomFlip (随机翻转)、RandomRotation (随机旋转) 或 RandomZoom (随机缩放) 等操作人为增加训练样本的多样性这通常能有效缓解 VGG 模型的过拟合问题。
第T9周:猫狗识别2
本文为365天深度学习训练营中的学习记录博客原作者K同学啊一、前期工作1.设置GPU使用CPU因此跳过import tensorflow as tf gpus tf.config.list_physical_devices(GPU) if gpus: tf.config.experimental.set_memory_growth(gpus[0], True) #设置GPU显存用量按需使用 tf.config.set_visible_devices([gpus[0]],GPU) # 打印显卡信息确认GPU可用 print(gpus)2.导入数据import numpy as np import matplotlib.pyplot as plt # 支持中文 plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号 import os,PIL,pathlib #隐藏警告 import warnings warnings.filterwarnings(ignore) data_dir ./365-9-data data_dir pathlib.Path(data_dir) image_count len(list(data_dir.glob(*/*))) print(图片总数为,image_count)二、数据预处理1.加载数据batch_size 64 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) break3.配置数据集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)三、构建VGG-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])五、训练模型import numpy as np from tqdm import tqdm import tensorflow as tf from tensorflow.keras.optimizers import Adam # 1. 超参数设置 epochs 10 lr 1e-4 # 2. 模型编译 # 【修复点】使用 sparse_categorical_crossentropy 处理整数型标签 (64,) model.compile( optimizerAdam(learning_ratelr), losssparse_categorical_crossentropy, metrics[accuracy] ) # 3. 训练记录器 history_train_loss [] history_train_accuracy [] history_val_loss [] history_val_accuracy [] # 4. 核心训练循环 for epoch in range(epochs): train_total len(train_ds) val_total len(val_ds) # 【修复点】使用 assign 动态更新学习率适配最新版 TF/Keras model.optimizer.learning_rate.assign(lr) # ------------------ 训练阶段 ------------------ with tqdm(totaltrain_total, descfEpoch {epoch 1}/{epochs}, mininterval1, ncols100) as pbar: train_loss [] train_accuracy [] for image, label in train_ds: history model.train_on_batch(image, label) train_loss.append(history[0]) train_accuracy.append(history[1]) # 【修复点】直接格式化输出当前的 lr 变量 pbar.set_postfix({ train_loss: %.4f % history[0], train_acc: %.4f % history[1], lr: %.6f % lr }) pbar.update(1) history_train_loss.append(np.mean(train_loss)) history_train_accuracy.append(np.mean(train_accuracy)) # ------------------ 验证阶段 ------------------ print(开始验证) with tqdm(totalval_total, descfEpoch {epoch 1}/{epochs} (Val), mininterval0.3, ncols100) as pbar: val_loss [] val_accuracy [] for image, label in val_ds: history model.test_on_batch(image, label) val_loss.append(history[0]) val_accuracy.append(history[1]) pbar.set_postfix({ val_loss: %.4f % history[0], val_acc: %.4f % history[1] }) pbar.update(1) history_val_loss.append(np.mean(val_loss)) history_val_accuracy.append(np.mean(val_accuracy)) print(结束验证) print(验证loss为%.4f % np.mean(val_loss)) print(验证准确率为%.4f % np.mean(val_accuracy)) print(- * 60) # 5. 学习率衰减 # 当前 epoch 结束后衰减学习率 lr lr * 0.92六、模型评估from datetime import datetime current_time datetime.now() # 获取当前时间 epochs_range range(epochs) plt.figure(figsize(14, 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()七、预测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)八、个人总结1.数据预处理与管道优化 (tf.data)在构建深度学习数据管道时合理使用 tf.data API 能大幅提升训练效率快捷加载使用 image_dataset_from_directory 可以直接从本地目录按文件夹名称标签自动构建带有批次 (Batch) 的图像数据集。指南此 API 在 TensorFlow 2.3.0 及以上版本才移入正式库。低版本会报错需升级 TF 版本。性能优化cache()将预处理后的数据集缓存到内存中避免在每个 Epoch 重复读取磁盘大幅加速训练。shuffle()打乱数据顺序打破数据的原有排列规律提升模型泛化能力。prefetch()预取数据。让模型在执行当前步训练的同时后台自动准备下一步的数据实现 CPU (数据准备) 和 GPU (模型计算) 的并行工作。指南配置 AUTOTUNE 时若遇到属性报错说明版本较老需改为 tf.data.experimental.AUTOTUNE。2.VGG-16 神经网络架构核心VGG 是一种经典的卷积神经网络其核心设计理念和优缺点非常鲜明网络结构总共包含 16个隐藏层由 13个卷积层 (Conv) 3个全连接层 (FC) 组成池化层不计入权重层数。包含 5个最大池化层 用于特征降维。核心优势 (Pros)结构极简且统一整个网络全部采用相同尺寸的 3x3 卷积核 和 2x2 最大池化核。通过堆叠小卷积核来替代大卷积核既保证了感受野又减少了参数量。致命劣势 (Cons)参数量与体积巨大全连接层占据了极其庞大的参数量导致模型权重文件高达 500MB 以上非常不利于在移动端或嵌入式设备上部署。训练成本高收敛较慢训练时间长调参难度相对较大。3.模型编译 (Compile)在模型训练前必须配置好三大核心组件损失函数 (Loss)模型优化的“指南针”用于计算当前预测值与真实标签之间的差距。优化器 (Optimizer)模型的“引擎”决定了模型如何利用计算出的误差(Loss)去更新网络中的权重例如 Adam, SGD 等。评价指标 (Metrics)用于直观监控模型表现的指标最常用的是准确率 (Accuracy)即分类正确的样本比例。4.模型预测 (Predict)在进行单张图片推理预测时有一个非常容易被忽略的张量维度问题升维处理Keras 模型在设计时默认输入的是批次 (Batch) 数据即输入张量的形状应当是 (batch_size, height, width, channels)。代码实现当我们只输入一张图片 (224, 224, 3) 时必须使用 tf.expand_dims(image, 0) 在第0个位置增加一个维度将其形状转换为 (1, 224, 224, 3) 才能送入 model.predict()。解析结果模型输出的通常是各个类别的概率分布需要结合 np.argmax(predictions) 提取出概率最大的那个索引进而映射回真实的标签名称 (class_names)。5.数据增强提高准确率可以在模型构建前加入数据增强 (Data Augmentation) 层。在 TensorFlow 中可以使用 tf.keras.layers.RandomFlip (随机翻转)、RandomRotation (随机旋转) 或 RandomZoom (随机缩放) 等操作人为增加训练样本的多样性这通常能有效缓解 VGG 模型的过拟合问题。