Python y el aprendizaje profundo (11): CNN y perros y gatos

1. Descripción

Este artículo es otro ejemplo de CNN, la guerra del gato y el perro, es un ejemplo de un conjunto de datos hecho a sí mismo. Todos los ejemplos anteriores están incluidos en la biblioteca de python, pero esta vez el ejemplo es recopilar el conjunto de datos usted mismo, organizarlo como se muestra en la figura a continuación y el enlace del conjunto de datos se colocará en el área de comentarios.
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

2. Gato contra perro

2.1 Importar bibliotecas relacionadas

Las siguientes bibliotecas de terceros son bibliotecas específicas de Python para el aprendizaje profundo

from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten, Dropout, BatchNormalization
from keras.optimizers import RMSprop, Adam
from keras.preprocessing.image import ImageDataGenerator
import sys, os  # 目录结构
from keras.layers import MaxPool2D
import matplotlib.pyplot as plt
import pandas
from keras.callbacks import EarlyStopping, ReduceLROnPlateau

2.2 Construcción de modelos

Esta es otra forma de escribir el modelo.
Se agregaron una capa convolucional de tres capas, una capa de agrupación de tres capas y luego una capa de aplanamiento (enderezando el mapa de características bidimensional en la capa completamente conectada), luego una capa completamente conectada de tres capas y una capa de exclusión.

"1.模型建立"
# 1.卷积层,输入图片大小(150, 150, 3), 卷积核个数16,卷积核大小(5, 5), 激活函数'relu'
conv_layer1 = Conv2D(input_shape=(150, 150, 3), filters=16, kernel_size=(5, 5), activation='relu')
# 2.最大池化层,池化层大小(2, 2), 步长为2
max_pool1 = MaxPool2D(pool_size=(2, 2), strides=2)
# 3.卷积层,卷积核个数32,卷积核大小(5, 5), 激活函数'relu'
conv_layer2 = Conv2D(filters=32, kernel_size=(5, 5), activation='relu')
# 4.最大池化层,池化层大小(2, 2), 步长为2
max_pool2 = MaxPool2D(pool_size=(2, 2), strides=2)
# 5.卷积层,卷积核个数64,卷积核大小(5, 5), 激活函数'relu'
conv_layer3 = Conv2D(filters=64, kernel_size=(5, 5), activation='relu')
# 6.最大池化层,池化层大小(2, 2), 步长为2
max_pool3 = MaxPool2D(pool_size=(2, 2), strides=2)
# 7.卷积层,卷积核个数128,卷积核大小(5, 5), 激活函数'relu'
conv_layer4 = Conv2D(filters=128, kernel_size=(5, 5), activation='relu')
# 8.最大池化层,池化层大小(2, 2), 步长为2
max_pool4 = MaxPool2D(pool_size=(2, 2), strides=2)
# 9.展平层
flatten_layer = Flatten()
# 10.Dropout层, Dropout(0.2)
third_dropout = Dropout(0.2)
# 11.全连接层/隐藏层1,240个节点, 激活函数'relu'
hidden_layer1 = Dense(240, activation='relu')
# 12.全连接层/隐藏层2,84个节点, 激活函数'relu'
hidden_layer3 = Dense(84, activation='relu')
# 13.Dropout层, Dropout(0.2)
fif_dropout = Dropout(0.5)
# 14.输出层,输出节点个数1, 激活函数'sigmoid'
output_layer = Dense(1, activation='sigmoid')
model = Sequential([conv_layer1, max_pool1, conv_layer2, max_pool2,
                    conv_layer3, max_pool3, conv_layer4, max_pool4,
                    flatten_layer, third_dropout, hidden_layer1,
                    hidden_layer3, fif_dropout, output_layer])

2.3 Compilación del modelo

El optimizador del modelo es Adam, la tasa de aprendizaje es 0.01,
la función de pérdida es binary_crossentropy, binary entropy cross,
el índice de rendimiento es precisión
y se agrega un mecanismo de devolución de llamada.
El mecanismo de devolución de llamada simplemente se entiende como la tasa de precisión del conjunto de entrenamiento continúa aumentando, mientras que la tasa de precisión del conjunto de validación básicamente no cambia. En este momento, se ha producido un sobreajuste y la tasa de aprendizaje debe ajustarse para aumentar la tasa de precisión. del conjunto de validación.

"2.模型编译"
# 模型编译,2分类:binary_crossentropy
model.compile(optimizer=Adam(lr=0.0001),  # 优化器选择Adam,初始学习率设置为0.0001
              loss='binary_crossentropy',  # 代价函数选择 binary_crossentropy
              metrics=['accuracy'])  # 设置指标为准确率
model.summary()  # 模型统计

# 回调机制 动态调整学习率
reduce = ReduceLROnPlateau(monitor='val_accuracy',  # 设置监测的值为val_accuracy
                               patience=2,  # 设置耐心容忍次数为2
                               verbose=1,  #
                               factor=0.5,  # 缩放学习率的值为0.5,学习率将以lr = lr*factor的形式被减少
                               min_lr=0.000001  # 学习率最小值0.000001
                               )   # 监控val_accuracy增加趋势

2.4 Generador de datos

Cargue el conjunto de datos creado por usted mismo
y use el generador de datos para mejorar los datos, es decir, la imagen de entrada para cada entrenamiento será el volteo, la traducción, la rotación y el escalado de la imagen original, para reducir el impacto del sobreajuste.
Luego cargue los datos a través del iterador, el tamaño de la imagen de destino es 150 150 3, configure la cantidad de imágenes cargadas en la red de entrenamiento cada vez, configure el modelo de clasificación (codificación one-hot predeterminada) y los datos se codifican.

"3.数据生成器"
# 生成器对象1:  归一化
gen = ImageDataGenerator(rescale=1 / 255.0)
# 生成器对象2:  归一化 + 数据加强
gen1 = ImageDataGenerator(
    rescale=1 / 255.0,
    rotation_range=5,  # 图片随机旋转的角度5度
    width_shift_range=0.1,
    height_shift_range=0.1,  # 水平和竖直方向随机移动0.1
    shear_range=0.1,  # 剪切变换的程度0.1
    zoom_range=0.1,  # 随机放大的程度0.1
    fill_mode='nearest')  # 当需要进行像素填充时选择最近的像素进行填充
# 拼接训练和验证的两个路径
train_path = os.path.join(sys.path[0], 'dog-cats', 'train')
val_path = os.path.join(sys.path[0], 'dog-cats', 'val')
print('训练数据路径: ', train_path)
print('验证数据路径: ', val_path)
# 训练和验证的两个迭代器
train_iter = gen1.flow_from_directory(train_path,  # 训练train目录路径
                                      target_size=(150, 150),  # 目标图像大小统一尺寸150
                                      batch_size=8,  # 设置每次加载到内存的图像大小
                                      class_mode='binary',  # 设置分类模型(默认one-hot编码)
                                      shuffle=True)  # 是否打乱
val_iter = gen.flow_from_directory(val_path,  # 测试val目录路径
                                   target_size=(150, 150),  # 目标图像大小统一尺寸150
                                   batch_size=8,  # 设置每次加载到内存的图像大小
                                   class_mode='binary',  # 设置分类模型(默认one-hot编码)
                                   shuffle=True)  # 是否打乱

2.5 Entrenamiento modelo

El número de modelos de entrenamiento es 20 y la prueba se realiza cada 1 ciclo.

"4.模型训练"
# 模型的训练, model.fit
result = model.fit(train_iter,  # 设置训练数据的迭代器
                   epochs=20,  # 循环次数20次
                   validation_data=val_iter,  # 验证数据的迭代器
                   callbacks=[reduce],  # 回调机制设置为reduce
                   verbose=1)

2.6 Modelo de ahorro

Guarde el modelo en formato de archivo .h5

"5.模型保存"
# 保存训练好的模型
model.save('my_cnn_cat_dog.h5')

2.7 Visualización de los resultados del entrenamiento del modelo

Visualice los resultados de entrenamiento del modelo y los resultados visualizados se muestran en forma de gráficos

"6.模型训练时的可视化"
# 显示训练集和验证集的acc和loss曲线
acc = result.history['accuracy']  # 获取模型训练中的accuracy
val_acc = result.history['val_accuracy']  # 获取模型训练中的val_accuracy
loss = result.history['loss']  # 获取模型训练中的loss
val_loss = result.history['val_loss']  # 获取模型训练中的val_loss
# 绘值acc曲线
plt.figure(1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.savefig('cat_dog_acc.png', dpi=600)
# 绘制loss曲线
plt.figure(2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.savefig('cat_dog_loss.png', dpi=600)
plt.show()  # 将结果显示出来

3. Resultados de la visualización del modelo CNN de la guerra de gatos y perros

Epoch 1/20
250/250 [==============================] - 59s 231ms/step - loss: 0.6940 - accuracy: 0.4925 - val_loss: 0.6899 - val_accuracy: 0.5050 - lr: 1.0000e-04
Epoch 2/20
250/250 [==============================] - 55s 219ms/step - loss: 0.6891 - accuracy: 0.5125 - val_loss: 0.6787 - val_accuracy: 0.5880 - lr: 1.0000e-04
Epoch 3/20
250/250 [==============================] - 54s 216ms/step - loss: 0.6791 - accuracy: 0.5840 - val_loss: 0.6655 - val_accuracy: 0.6080 - lr: 1.0000e-04
Epoch 4/20
250/250 [==============================] - 60s 238ms/step - loss: 0.6628 - accuracy: 0.6040 - val_loss: 0.6501 - val_accuracy: 0.6300 - lr: 1.0000e-04
Epoch 5/20
250/250 [==============================] - 57s 226ms/step - loss: 0.6480 - accuracy: 0.6400 - val_loss: 0.6281 - val_accuracy: 0.6590 - lr: 1.0000e-04
Epoch 6/20
250/250 [==============================] - 67s 268ms/step - loss: 0.6275 - accuracy: 0.6565 - val_loss: 0.6160 - val_accuracy: 0.6690 - lr: 1.0000e-04
Epoch 7/20
250/250 [==============================] - 62s 247ms/step - loss: 0.6252 - accuracy: 0.6570 - val_loss: 0.6026 - val_accuracy: 0.6790 - lr: 1.0000e-04
Epoch 8/20
250/250 [==============================] - 63s 251ms/step - loss: 0.5915 - accuracy: 0.6770 - val_loss: 0.5770 - val_accuracy: 0.6960 - lr: 1.0000e-04
Epoch 9/20
250/250 [==============================] - 57s 228ms/step - loss: 0.5778 - accuracy: 0.6930 - val_loss: 0.5769 - val_accuracy: 0.6880 - lr: 1.0000e-04
Epoch 10/20
250/250 [==============================] - 55s 219ms/step - loss: 0.5532 - accuracy: 0.7085 - val_loss: 0.5601 - val_accuracy: 0.6970 - lr: 1.0000e-04
Epoch 11/20
250/250 [==============================] - 55s 221ms/step - loss: 0.5408 - accuracy: 0.7370 - val_loss: 0.6002 - val_accuracy: 0.6810 - lr: 1.0000e-04
Epoch 12/20
250/250 [==============================] - ETA: 0s - loss: 0.5285 - accuracy: 0.7350
Epoch 12: ReduceLROnPlateau reducing learning rate to 4.999999873689376e-05.
250/250 [==============================] - 56s 226ms/step - loss: 0.5285 - accuracy: 0.7350 - val_loss: 0.5735 - val_accuracy: 0.6960 - lr: 1.0000e-04
Epoch 13/20
250/250 [==============================] - 70s 280ms/step - loss: 0.4969 - accuracy: 0.7595 - val_loss: 0.5212 - val_accuracy: 0.7410 - lr: 5.0000e-05
Epoch 14/20
250/250 [==============================] - 73s 292ms/step - loss: 0.4776 - accuracy: 0.7740 - val_loss: 0.5146 - val_accuracy: 0.7470 - lr: 5.0000e-05
Epoch 15/20
250/250 [==============================] - 71s 285ms/step - loss: 0.4605 - accuracy: 0.7930 - val_loss: 0.5180 - val_accuracy: 0.7530 - lr: 5.0000e-05
Epoch 16/20
250/250 [==============================] - 74s 298ms/step - loss: 0.4619 - accuracy: 0.7825 - val_loss: 0.5100 - val_accuracy: 0.7510 - lr: 5.0000e-05
Epoch 17/20
250/250 [==============================] - 72s 289ms/step - loss: 0.4558 - accuracy: 0.7885 - val_loss: 0.4991 - val_accuracy: 0.7630 - lr: 5.0000e-05
Epoch 18/20
250/250 [==============================] - 75s 300ms/step - loss: 0.4498 - accuracy: 0.7900 - val_loss: 0.4966 - val_accuracy: 0.7580 - lr: 5.0000e-05
Epoch 19/20
250/250 [==============================] - 61s 243ms/step - loss: 0.4269 - accuracy: 0.8060 - val_loss: 0.5000 - val_accuracy: 0.7690 - lr: 5.0000e-05
Epoch 20/20
250/250 [==============================] - 56s 224ms/step - loss: 0.4202 - accuracy: 0.8090 - val_loss: 0.4845 - val_accuracy: 0.7700 - lr: 5.0000e-05

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
De los resultados anteriores, se puede ver que la tasa de precisión del modelo alcanzó el 77%. Se puede encontrar que no es muy alto, por lo que se adopta el siguiente aprendizaje de transferencia.

4. Código completo

from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten, Dropout, BatchNormalization
from keras.optimizers import RMSprop, Adam
from keras.preprocessing.image import ImageDataGenerator
import sys, os  # 目录结构
from keras.layers import MaxPool2D
import matplotlib.pyplot as plt
import pandas
from keras.callbacks import EarlyStopping, ReduceLROnPlateau

"1.模型建立"
# 1.卷积层,输入图片大小(150, 150, 3), 卷积核个数16,卷积核大小(5, 5), 激活函数'relu'
conv_layer1 = Conv2D(input_shape=(150, 150, 3), filters=16, kernel_size=(5, 5), activation='relu')
# 2.最大池化层,池化层大小(2, 2), 步长为2
max_pool1 = MaxPool2D(pool_size=(2, 2), strides=2)
# 3.卷积层,卷积核个数32,卷积核大小(5, 5), 激活函数'relu'
conv_layer2 = Conv2D(filters=32, kernel_size=(5, 5), activation='relu')
# 4.最大池化层,池化层大小(2, 2), 步长为2
max_pool2 = MaxPool2D(pool_size=(2, 2), strides=2)
# 5.卷积层,卷积核个数64,卷积核大小(5, 5), 激活函数'relu'
conv_layer3 = Conv2D(filters=64, kernel_size=(5, 5), activation='relu')
# 6.最大池化层,池化层大小(2, 2), 步长为2
max_pool3 = MaxPool2D(pool_size=(2, 2), strides=2)
# 7.卷积层,卷积核个数128,卷积核大小(5, 5), 激活函数'relu'
conv_layer4 = Conv2D(filters=128, kernel_size=(5, 5), activation='relu')
# 8.最大池化层,池化层大小(2, 2), 步长为2
max_pool4 = MaxPool2D(pool_size=(2, 2), strides=2)
# 9.展平层
flatten_layer = Flatten()
# 10.Dropout层, Dropout(0.2)
third_dropout = Dropout(0.2)
# 11.全连接层/隐藏层1,240个节点, 激活函数'relu'
hidden_layer1 = Dense(240, activation='relu')
# 12.全连接层/隐藏层2,84个节点, 激活函数'relu'
hidden_layer3 = Dense(84, activation='relu')
# 13.Dropout层, Dropout(0.2)
fif_dropout = Dropout(0.5)
# 14.输出层,输出节点个数1, 激活函数'sigmoid'
output_layer = Dense(1, activation='sigmoid')
model = Sequential([conv_layer1, max_pool1, conv_layer2, max_pool2,
                    conv_layer3, max_pool3, conv_layer4, max_pool4,
                    flatten_layer, third_dropout, hidden_layer1,
                    hidden_layer3, fif_dropout, output_layer])
"2.模型编译"
# 模型编译,2分类:binary_crossentropy
model.compile(optimizer=Adam(lr=0.0001),  # 优化器选择Adam,初始学习率设置为0.0001
              loss='binary_crossentropy',  # 代价函数选择 binary_crossentropy
              metrics=['accuracy'])  # 设置指标为准确率
model.summary()  # 模型统计

# 回调机制 动态调整学习率
reduce = ReduceLROnPlateau(monitor='val_accuracy',  # 设置监测的值为val_accuracy
                               patience=2,  # 设置耐心容忍次数为2
                               verbose=1,  #
                               factor=0.5,  # 缩放学习率的值为0.5,学习率将以lr = lr*factor的形式被减少
                               min_lr=0.000001  # 学习率最小值0.000001
                               )   # 监控val_accuracy增加趋势
"3.数据生成器"
# 生成器对象1:  归一化
gen = ImageDataGenerator(rescale=1 / 255.0)
# 生成器对象2:  归一化 + 数据加强
gen1 = ImageDataGenerator(
    rescale=1 / 255.0,
    rotation_range=5,  # 图片随机旋转的角度5度
    width_shift_range=0.1,
    height_shift_range=0.1,  # 水平和竖直方向随机移动0.1
    shear_range=0.1,  # 剪切变换的程度0.1
    zoom_range=0.1,  # 随机放大的程度0.1
    fill_mode='nearest')  # 当需要进行像素填充时选择最近的像素进行填充
# 拼接训练和验证的两个路径
train_path = os.path.join(sys.path[0], 'dog-cats', 'train')
val_path = os.path.join(sys.path[0], 'dog-cats', 'val')
print('训练数据路径: ', train_path)
print('验证数据路径: ', val_path)
# 训练和验证的两个迭代器
train_iter = gen1.flow_from_directory(train_path,  # 训练train目录路径
                                      target_size=(150, 150),  # 目标图像大小统一尺寸150
                                      batch_size=8,  # 设置每次加载到内存的图像大小
                                      class_mode='binary',  # 设置分类模型(默认one-hot编码)
                                      shuffle=True)  # 是否打乱
val_iter = gen.flow_from_directory(val_path,  # 测试val目录路径
                                   target_size=(150, 150),  # 目标图像大小统一尺寸150
                                   batch_size=8,  # 设置每次加载到内存的图像大小
                                   class_mode='binary',  # 设置分类模型(默认one-hot编码)
                                   shuffle=True)  # 是否打乱
"4.模型训练"
# 模型的训练, model.fit
result = model.fit(train_iter,  # 设置训练数据的迭代器
                   epochs=20,  # 循环次数20次
                   validation_data=val_iter,  # 验证数据的迭代器
                   callbacks=[reduce],  # 回调机制设置为reduce
                   verbose=1)

"5.模型保存"
# 保存训练好的模型
model.save('my_cnn_cat_dog.h5')

"6.模型训练时的可视化"
# 显示训练集和验证集的acc和loss曲线
acc = result.history['accuracy']  # 获取模型训练中的accuracy
val_acc = result.history['val_accuracy']  # 获取模型训练中的val_accuracy
loss = result.history['loss']  # 获取模型训练中的loss
val_loss = result.history['val_loss']  # 获取模型训练中的val_loss
# 绘值acc曲线
plt.figure(1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.savefig('cat_dog_acc.png', dpi=600)
# 绘制loss曲线
plt.figure(2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.savefig('cat_dog_loss.png', dpi=600)
plt.show()  # 将结果显示出来


5. Transferencia de aprendizaje para perros y gatos

Transferir el aprendizaje es simplemente usar el modelo que otros han entrenado para su propio uso.

from keras.applications import DenseNet121
from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten, Dropout, BatchNormalization
from keras.optimizers import RMSprop, Adam
from keras.preprocessing.image import ImageDataGenerator
import sys, os  # 目录结构
from keras.layers import MaxPool2D
import matplotlib.pyplot as plt
import pandas
from keras.callbacks import EarlyStopping, ReduceLROnPlateau

"1.模型建立"
# 加载DenseNet网络模型,并去掉最后一层全连接层,最后一个池化层设置为max pooling
net = DenseNet121(weights='imagenet', include_top=False, pooling='max')
# 设计为不参与优化,即MobileNet这部分参数固定不动
net.trainable = False
newnet = Sequential([
    net,  # 去掉最后一层的DenseNet121
    Dense(1024, activation='relu'),  # 追加全连接层
    BatchNormalization(),  # 追加BN层
    Dropout(rate=0.5),  # 追加Dropout层,防止过拟合
    Dense(1,activation='sigmoid') # 根据宝可梦数据的任务,设置最后一层输出节点数为5
])
newnet.build(input_shape=(None, 150, 150, 3))

"2.模型编译"
newnet.compile(optimizer=Adam(lr=0.0001), loss="binary_crossentropy", metrics=["accuracy"])
newnet.summary()

# 回调机制 动态调整学习率
reduce = ReduceLROnPlateau(monitor='val_accuracy',  # 设置监测的值为val_accuracy
                               patience=2,  # 设置耐心容忍次数为2
                               verbose=1,  #
                               factor=0.5,  # 缩放学习率的值为0.5,学习率将以lr = lr*factor的形式被减少
                               min_lr=0.000001  # 学习率最小值0.000001
                               )   # 监控val_accuracy增加趋势

"3.数据生成器"
# 生成器对象1:  归一化
gen = ImageDataGenerator(rescale=1 / 255.0)
# 生成器对象2:  归一化 + 数据加强
gen1 = ImageDataGenerator(
    rescale=1 / 255.0,
    rotation_range=5,  # 图片随机旋转的角度5度
    width_shift_range=0.1,
    height_shift_range=0.1,  # 水平和竖直方向随机移动0.1
    shear_range=0.1,  # 剪切变换的程度0.1
    zoom_range=0.1,  # 随机放大的程度0.1
    fill_mode='nearest')  # 当需要进行像素填充时选择最近的像素进行填充
# 拼接训练和验证的两个路径
train_path = os.path.join(sys.path[0], 'dog-cats', 'train')
val_path = os.path.join(sys.path[0], 'dog-cats', 'val')
print('训练数据路径: ', train_path)
print('验证数据路径: ', val_path)
# 训练和验证的两个迭代器
train_iter = gen1.flow_from_directory(train_path,  # 训练train目录路径
                                      target_size=(150, 150),  # 目标图像大小统一尺寸150
                                      batch_size=10,  # 设置每次加载到内存的图像大小
                                      class_mode='binary',  # 设置分类模型(默认one-hot编码)
                                      shuffle=True)  # 是否打乱
val_iter = gen.flow_from_directory(val_path,  # 测试val目录路径
                                   target_size=(150, 150),  # 目标图像大小统一尺寸150
                                   batch_size=10,  # 设置每次加载到内存的图像大小
                                   class_mode='binary',  # 设置分类模型(默认one-hot编码)
                                   shuffle=True)  # 是否打乱
"4.模型训练"
# 模型的训练, newnet.fit
result = newnet.fit(train_iter,  # 设置训练数据的迭代器
                    epochs=20,  # 循环次数20次
                    validation_data=val_iter,  # 验证数据的迭代器
                    callbacks=[reduce],  # 回调机制设置为reduce
                    verbose=1)

"5.模型保存"
# 保存训练好的模型
newnet.save('my_cnn_cat_dog_3.h5')

"6.模型训练时的可视化"
# 显示训练集和验证集的acc和loss曲线
acc = result.history['accuracy']  # 获取模型训练中的accuracy
val_acc = result.history['val_accuracy']  # 获取模型训练中的val_accuracy
loss = result.history['loss']  # 获取模型训练中的loss
val_loss = result.history['val_loss']  # 获取模型训练中的val_loss
# 绘值acc曲线
plt.figure(1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.savefig('cat_dog_acc_3.png', dpi=600)
# 绘制loss曲线
plt.figure(2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.savefig('cat_dog_loss_3.png', dpi=600)
plt.show()  # 将结果显示出来


inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Se puede encontrar que la tasa de precisión del modelo después del aprendizaje de transferencia ha alcanzado el 96%.

Supongo que te gusta

Origin blog.csdn.net/qq_47598782/article/details/132011996
Recomendado
Clasificación