【深度学习进阶】基于CNN的猫狗图片分类项目

介绍

基于卷积神经网络(CNN)的猫狗图片分类项目是机器学习领域中的一种常见任务,它涉及图像处理和深度学习技术。以下是该项目的技术点和流程介绍:

技术点

  • 卷积神经网络 (CNN): CNN 是一种专门用于处理具有类似网格结构的数据的神经网络模型,比如时间序列数据或二维的图像数据。CNN 的核心组件包括卷积层、池化层和全连接层。
  • 卷积层: 卷积层使用滤波器(或称内核)在输入图像上滑动,并计算局部加权和来检测图像中的特征,如边缘、纹理等。
  • 激活函数: 激活函数(如ReLU, Sigmoid等)引入非线性因素,使得网络可以学习到更复杂的模式。
  • 池化层: 通常采用最大池化或平均池化操作,用于减少空间尺寸,降低参数数量,同时保留最重要的信息。
  • 全连接层: 在最后几层,CNN 会将多维的特征图展平为一维向量,并通过全连接层进行分类预测。
  • 损失函数与优化算法: 使用交叉熵作为损失函数,通过反向传播和梯度下降等优化算法来更新网络权重。
  • 正则化技术: 包括L2正则化、Dropout等,以防止过拟合。
  • 数据增强: 通过对原始图像进行旋转、翻转、缩放等变换生成更多的训练样本,增加模型的泛化能力。
  • 预训练模型: 可以利用已经在大规模数据集上训练好的模型(如VGG16, ResNet等),并在此基础上进行迁移学习。

流程

  • 数据收集: 收集大量标注好的猫和狗的图片作为训练集和测试集。
  • 数据预处理: 对图像进行标准化(如调整大小、归一化像素值)以及可能的数据增强。
  • 构建模型: 设计CNN架构,选择合适的层数、滤波器大小和其他超参数。
  • 训练模型: 使用训练数据集对CNN进行训练,调整模型参数以最小化损失函数。
  • 评估模型: 在验证集或独立的测试集上评估模型性能,检查准确率、召回率等指标。
  • 调优模型: 根据评估结果调整模型架构或超参数,重复训练和评估过程直至满意。
  • 部署模型: 将最终训练好的模型部署到生产环境中,实现对新图像的实时分类。
  • 持续改进: 随着时间推移,可能会有新的数据加入,或者发现模型表现不佳的地方,这时就需要不断迭代和改进模型。

猫狗图片分类

猫狗图片分类模型是一个使用机器学习技术来辨别猫和狗图片的模型。该模型可以通过对输入的图片进行分析和比对,从而自动识别出图片中的是猫还是狗。

猫狗图片分类模型通常是基于卷积神经网络(Convolutional Neural Network,CNN)构建的。CNN是一种专门用于图像识别和处理的神经网络模型,其特点是能够自动学习图像特征并进行分类。

训练猫狗图片分类模型需要大量的带有标签的猫和狗图片作为训练数据。模型通过训练数据不断调整神经网络中的权重和参数,以提高判断猫和狗的准确性。

一旦训练完成,猫狗图片分类模型就可以用于对新的未知图片进行分类。用户只需输入一张图片,模型会自动输出猫或狗的分类结果。

猫狗图片分类模型可以应用于各种场景,比如社交媒体上的猫狗图片分享、电子商务平台上的宠物产品推荐等。该模型的准确性和性能取决于训练数据的质量和模型的设计。因此,对于更高准确性的要求,需要更多的训练数据和更复杂的模型设计。

导包

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
import os

加载数据

base_dir = './data/cats_and_dogs'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')

# 训练集
train_cats_dir = os.path.join(train_dir, 'cats')
train_dogs_dir = os.path.join(train_dir, 'dogs')

# 验证集
validation_cats_dir = os.path.join(validation_dir, 'cats')
validation_dogs_dir = os.path.join(validation_dir, 'dogs')

数据处理

from tensorflow.keras.preprocessing.image import ImageDataGenerator
# ImageDataGenerator 图片生成器, 会自动的帮我们从指定目录中读取图片. 
train_datagen = ImageDataGenerator(rescale=1./255)
valid_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
    train_dir, # 文件夹路径
    target_size=(64, 64),  # 指定图片缩放之后的大小
    batch_size=20,
    # 默认是categorical,表示多分类, 二分类用binary
    class_mode='binary')

validation_generator = valid_datagen.flow_from_directory(
    validation_dir, # 文件夹路径
    target_size=(64, 64),  # 指定图片缩放之后的大小
    batch_size=20,
    # 默认是categorical,表示多分类, 二分类用binary
    class_mode='binary')
Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.

构建CNN网络

网络结构

  1. Sequential模型:
  • 使用tf.keras.models.Sequential()创建一个线性堆叠的模型,意味着每一层都有一个输入张量和一个输出张量,并且这些层是顺序连接的。
  1. 第一组卷积层与池化层:
  • 第一个Conv2D层使用32个3x3的滤波器进行卷积操作,padding='same’保证了输出特征图与输入图像大小一致,激活函数采用ReLU。
  • 输入形状被指定为(64, 64, 3),表示输入图片尺寸为64x64像素,具有3个颜色通道(RGB)。
  • 第二个Conv2D层继续应用32个3x3的滤波器,进一步提取特征。
  • MaxPool2D层通过2x2窗口的最大值池化减少特征图的空间维度,从而降低计算复杂度并控制过拟合。
  1. 第二组卷积层与池化层:
  • 接下来增加了两个Conv2D层,每个都使用64个3x3的滤波器,这有助于捕捉更复杂的模式。
  • 再次应用MaxPool2D以减小空间维度。
  1. 第三组卷积层与池化层:
  • 类似地,这一部分包含两个Conv2D层,这次是128个3x3的滤波器,用于捕捉更加抽象的特征。
  • 最后一个MaxPool2D再次缩小特征图。
  1. 全连接层(密集层):
  • Flatten()将三维的特征图转换成一维向量,以便于后续的全连接层处理。
  • 第一个Dense层有512个神经元,并使用ReLU作为激活函数,提供非线性的映射能力。
  • 第二个Dense层有256个神经元,同样使用ReLU激活。
  1. 输出层:
    最后一层是一个具有单个神经元的Dense层,其激活函数为sigmoid。这是因为这是一个二分类问题,sigmoid函数可以将输出压缩到[0, 1]区间内,表示预测属于某一类的概率。
# 搭建卷积神经网络
model = tf.keras.models.Sequential()
# 2次卷积一次池化, 3层, 2层全连接. 
model.add(tf.keras.layers.Conv2D(filters=32, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu',
                                 input_shape=(64, 64, 3)))
model.add(tf.keras.layers.Conv2D(filters=32, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=2))

model.add(tf.keras.layers.Conv2D(filters=64, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.Conv2D(filters=64, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=2))

model.add(tf.keras.layers.Conv2D(filters=128, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.Conv2D(filters=128, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=2))

model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(512, activation='relu'))
model.add(tf.keras.layers.Dense(256, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
model.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_6 (Conv2D)            (None, 64, 64, 32)        896       
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 64, 64, 32)        9248      
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 32, 32, 32)        0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 32, 32, 64)        18496     
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 32, 32, 64)        36928     
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 16, 16, 64)        0         
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 16, 16, 128)       73856     
_________________________________________________________________
conv2d_11 (Conv2D)           (None, 16, 16, 128)       147584    
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 8, 8, 128)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 8192)              0         
_________________________________________________________________
dense (Dense)                (None, 512)               4194816   
_________________________________________________________________
dense_1 (Dense)              (None, 256)               131328    
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 257       
=================================================================
Total params: 4,613,409
Trainable params: 4,613,409
Non-trainable params: 0
_________________________________________________________________
model.compile(loss='binary_crossentropy',
             optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),
             metrics=['acc'])

模型训练

history = model.fit(train_generator, 
                    steps_per_epoch=100, # 2000 images : = batch_size * steps
                    epochs=20,
                    validation_data=validation_generator,
                    validation_steps=50, # 1000 images = batch_size * steps
                   )
Epoch 1/20
100/100 [==============================] - 4s 30ms/step - loss: 0.6933 - acc: 0.5003 - val_loss: 0.6881 - val_acc: 0.5060
Epoch 2/20
100/100 [==============================] - 3s 28ms/step - loss: 0.6768 - acc: 0.5654 - val_loss: 0.6393 - val_acc: 0.6350
Epoch 3/20
100/100 [==============================] - 3s 27ms/step - loss: 0.6194 - acc: 0.6684 - val_loss: 0.6204 - val_acc: 0.6710
Epoch 4/20
100/100 [==============================] - 3s 28ms/step - loss: 0.5548 - acc: 0.7294 - val_loss: 0.6026 - val_acc: 0.6830
Epoch 5/20
100/100 [==============================] - 3s 27ms/step - loss: 0.5452 - acc: 0.7311 - val_loss: 0.5963 - val_acc: 0.6780
Epoch 6/20
100/100 [==============================] - 3s 27ms/step - loss: 0.5030 - acc: 0.7309 - val_loss: 0.5598 - val_acc: 0.7350
Epoch 7/20
100/100 [==============================] - 3s 28ms/step - loss: 0.4529 - acc: 0.7920 - val_loss: 0.5633 - val_acc: 0.7250
Epoch 8/20
100/100 [==============================] - 3s 27ms/step - loss: 0.4246 - acc: 0.8073 - val_loss: 0.5689 - val_acc: 0.7230
Epoch 9/20
100/100 [==============================] - 3s 27ms/step - loss: 0.4018 - acc: 0.8248 - val_loss: 0.5549 - val_acc: 0.7270
Epoch 10/20
100/100 [==============================] - 3s 27ms/step - loss: 0.3472 - acc: 0.8424 - val_loss: 0.5491 - val_acc: 0.7370
Epoch 11/20
100/100 [==============================] - 3s 28ms/step - loss: 0.3243 - acc: 0.8573 - val_loss: 0.5775 - val_acc: 0.7280
Epoch 12/20
100/100 [==============================] - 3s 28ms/step - loss: 0.2770 - acc: 0.8870 - val_loss: 0.6722 - val_acc: 0.7200
Epoch 13/20
100/100 [==============================] - 3s 27ms/step - loss: 0.2264 - acc: 0.9046 - val_loss: 0.6584 - val_acc: 0.7470
Epoch 14/20
100/100 [==============================] - 3s 27ms/step - loss: 0.1956 - acc: 0.9247 - val_loss: 0.6828 - val_acc: 0.7400
Epoch 15/20
100/100 [==============================] - 3s 27ms/step - loss: 0.1288 - acc: 0.9508 - val_loss: 0.7735 - val_acc: 0.7290
Epoch 16/20
100/100 [==============================] - 3s 28ms/step - loss: 0.1085 - acc: 0.9670 - val_loss: 0.7551 - val_acc: 0.7400
Epoch 17/20
100/100 [==============================] - 3s 27ms/step - loss: 0.1228 - acc: 0.9540 - val_loss: 0.9157 - val_acc: 0.7300
Epoch 18/20
100/100 [==============================] - 3s 27ms/step - loss: 0.0789 - acc: 0.9710 - val_loss: 0.9311 - val_acc: 0.7560
Epoch 19/20
100/100 [==============================] - 3s 28ms/step - loss: 0.0217 - acc: 0.9979 - val_loss: 0.9941 - val_acc: 0.7270
Epoch 20/20
100/100 [==============================] - 3s 27ms/step - loss: 0.0207 - acc: 0.9946 - val_loss: 1.0781 - val_acc: 0.7470

可视化

pd.DataFrame(history.history).plot(figsize=(8, 5))
plt.grid()
plt.gca().set_ylim(0, 1)
plt.show()

在这里插入图片描述

数据增强

ImageDataGenerator 提供了一种简单的方法来应用各种图像变换,以扩充训练数据集,从而提高模型的泛化能力。对于猫狗分类这样的二分类任务,适当的图像变换可以帮助模型学习到更多不变性特征。

  • rescale=1./255: 将所有像素值从0-255缩放到0-1之间,这是为了标准化输入数据,使得梯度下降更稳定。
  • rotation_range=40: 随机旋转图片的角度范围(单位是度),这里设置为40度,意味着图片可能会被随机旋转最多正负40度。
  • width_shift_range=0.2 和 height_shift_range=0.2: 宽度和高度方向上的随机平移范围,这里的值表示相对于总宽度或高度的比例,即图像可能在水平或垂直方向上移动最多20%。
  • shear_range=0.2: 斜切变换的程度,可以模拟一些透视效果。
  • zoom_range=0.2: 随机缩放范围,这里的值也表示比例,即图像可能会被放大或缩小最多20%。
  • horizontal_flip=True: 随机水平翻转图像,这对于左右对称的对象(如猫和狗)特别有用。
  • fill_mode=‘nearest’: 当应用上述变换时,如果图像超出原始边界,则用最邻近填充模式填补新产生的空白区域。

创建数据生成器

flow_from_directory 方法可以从文件夹中读取图像,并自动根据子文件夹的名字给图像打上标签。它会生成批量的图像数据,可以直接用于模型训练。

  • train_dir 和 validation_dir: 分别指定了训练集和验证集所在的目录路径。每个目录应该包含两个子目录,一个用于“猫”的图片,另一个用于“狗”的图片。
  • target_size=(64, 64): 所有加载的图片将被调整大小到64x64像素。这应该与CNN模型输入层定义的input_shape相匹配。
  • batch_size=20: 每次迭代返回的图片数量。在这个例子中,每次会生成20张图片作为一批。
  • class_mode=‘binary’: 因为这是一个二分类问题,所以这里指定为二元分类模式。如果是多分类问题,则应设置为’categorical’。

通过这种方式,你可以确保训练过程中不断有新的、经过变换的图像提供给模型,有助于提升模型的表现,特别是当可用的原始图像数量有限时。同时,验证集仅进行了简单的归一化处理,而没有进行其他变换,以保证评估结果的真实性。

# 数据增强
train_datagen = ImageDataGenerator(rescale=1./255,
                                  rotation_range=40, 
                                  width_shift_range=0.2,
                                  height_shift_range=0.2,
                                  shear_range=0.2,
                                  zoom_range=0.2,
                                  horizontal_flip=True,
                                  fill_mode='nearest')
valid_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
    train_dir, # 文件夹路径
    target_size=(64, 64),  # 指定图片缩放之后的大小
    batch_size=20,
    # 默认是categorical,表示多分类, 二分类用binary
    class_mode='binary')

validation_generator = valid_datagen.flow_from_directory(
    validation_dir, # 文件夹路径
    target_size=(64, 64),  # 指定图片缩放之后的大小
    batch_size=20,
    # 默认是categorical,表示多分类, 二分类用binary
    class_mode='binary')

Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.

再次训练

# 搭建卷积神经网络
model = tf.keras.models.Sequential()
# 2次卷积一次池化, 3层, 2层全连接. 
model.add(tf.keras.layers.Conv2D(filters=32, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu',
                                 input_shape=(64, 64, 3)))
model.add(tf.keras.layers.Conv2D(filters=32, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=2))

model.add(tf.keras.layers.Conv2D(filters=64, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.Conv2D(filters=64, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=2))

model.add(tf.keras.layers.Conv2D(filters=128, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.Conv2D(filters=128, 
                                 kernel_size=3,
                                 padding='same',
                                 activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=2))

model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(512, activation='relu'))
model.add(tf.keras.layers.Dense(256, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))

model.compile(loss='binary_crossentropy',
             optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),
             metrics=['acc'])

history = model.fit(train_generator, 
                    steps_per_epoch=100, # 2000 images : = batch_size * steps
                    epochs=20,
                    validation_data=validation_generator,
                    validation_steps=50, # 1000 images = batch_size * steps
                   )
Epoch 1/20
100/100 [==============================] - 5s 47ms/step - loss: 0.6934 - acc: 0.4989 - val_loss: 0.6905 - val_acc: 0.5040
Epoch 2/20
100/100 [==============================] - 5s 47ms/step - loss: 0.6930 - acc: 0.5108 - val_loss: 0.6845 - val_acc: 0.5280
Epoch 3/20
100/100 [==============================] - 4s 44ms/step - loss: 0.6867 - acc: 0.5560 - val_loss: 0.6446 - val_acc: 0.6200
Epoch 4/20
100/100 [==============================] - 4s 45ms/step - loss: 0.6524 - acc: 0.6232 - val_loss: 0.6780 - val_acc: 0.5750
Epoch 5/20
100/100 [==============================] - 4s 44ms/step - loss: 0.6736 - acc: 0.5856 - val_loss: 0.6043 - val_acc: 0.6770
Epoch 6/20
100/100 [==============================] - 4s 44ms/step - loss: 0.6133 - acc: 0.6503 - val_loss: 0.5926 - val_acc: 0.6860
Epoch 7/20
100/100 [==============================] - 4s 44ms/step - loss: 0.6189 - acc: 0.6653 - val_loss: 0.6047 - val_acc: 0.6670
Epoch 8/20
100/100 [==============================] - 5s 46ms/step - loss: 0.6108 - acc: 0.6662 - val_loss: 0.5849 - val_acc: 0.6740
Epoch 9/20
100/100 [==============================] - 5s 46ms/step - loss: 0.5685 - acc: 0.6985 - val_loss: 0.5654 - val_acc: 0.7070
Epoch 10/20
100/100 [==============================] - 5s 45ms/step - loss: 0.5980 - acc: 0.6622 - val_loss: 0.5646 - val_acc: 0.6970
Epoch 11/20
100/100 [==============================] - 5s 46ms/step - loss: 0.5759 - acc: 0.6879 - val_loss: 0.5836 - val_acc: 0.6910
Epoch 12/20
100/100 [==============================] - 5s 45ms/step - loss: 0.5805 - acc: 0.6865 - val_loss: 0.5640 - val_acc: 0.7060
Epoch 13/20
100/100 [==============================] - 5s 45ms/step - loss: 0.5733 - acc: 0.6967 - val_loss: 0.5808 - val_acc: 0.6820
Epoch 14/20
100/100 [==============================] - 5s 45ms/step - loss: 0.5779 - acc: 0.6857 - val_loss: 0.6307 - val_acc: 0.6680
Epoch 15/20
100/100 [==============================] - 4s 45ms/step - loss: 0.5498 - acc: 0.7178 - val_loss: 0.5564 - val_acc: 0.7050
Epoch 16/20
100/100 [==============================] - 5s 45ms/step - loss: 0.5561 - acc: 0.7016 - val_loss: 0.6625 - val_acc: 0.6450
Epoch 17/20
100/100 [==============================] - 4s 45ms/step - loss: 0.5513 - acc: 0.7060 - val_loss: 0.5414 - val_acc: 0.7160
Epoch 18/20
100/100 [==============================] - 4s 45ms/step - loss: 0.5293 - acc: 0.7339 - val_loss: 0.5329 - val_acc: 0.7300
Epoch 19/20
100/100 [==============================] - 5s 45ms/step - loss: 0.5344 - acc: 0.7272 - val_loss: 0.5141 - val_acc: 0.7410
Epoch 20/20
100/100 [==============================] - 5s 48ms/step - loss: 0.5257 - acc: 0.7146 - val_loss: 0.5461 - val_acc: 0.7240

调参

history = model.fit(train_generator, 
                    steps_per_epoch=100, # 2000 images : = batch_size * steps
                    epochs=20,
                    validation_data=validation_generator,
                    validation_steps=50, # 1000 images = batch_size * steps
                   )
Epoch 1/20
100/100 [==============================] - 5s 47ms/step - loss: 0.5291 - acc: 0.7345 - val_loss: 0.5312 - val_acc: 0.7310
Epoch 2/20
100/100 [==============================] - 5s 45ms/step - loss: 0.5126 - acc: 0.7400 - val_loss: 0.5147 - val_acc: 0.7490
Epoch 3/20
100/100 [==============================] - 4s 45ms/step - loss: 0.5192 - acc: 0.7385 - val_loss: 0.4972 - val_acc: 0.7420
Epoch 4/20
100/100 [==============================] - 5s 45ms/step - loss: 0.5124 - acc: 0.7465 - val_loss: 0.5264 - val_acc: 0.7170
Epoch 5/20
100/100 [==============================] - 4s 45ms/step - loss: 0.5141 - acc: 0.7485 - val_loss: 0.4969 - val_acc: 0.7450
Epoch 6/20
100/100 [==============================] - 5s 46ms/step - loss: 0.5048 - acc: 0.7400 - val_loss: 0.5044 - val_acc: 0.7460
Epoch 7/20
100/100 [==============================] - 5s 46ms/step - loss: 0.4905 - acc: 0.7610 - val_loss: 0.5057 - val_acc: 0.7400
Epoch 8/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4864 - acc: 0.7620 - val_loss: 0.4977 - val_acc: 0.7380
Epoch 9/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4972 - acc: 0.7585 - val_loss: 0.5027 - val_acc: 0.7530
Epoch 10/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4959 - acc: 0.7660 - val_loss: 0.4850 - val_acc: 0.7570
Epoch 11/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4816 - acc: 0.7655 - val_loss: 0.4954 - val_acc: 0.7440
Epoch 12/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4731 - acc: 0.7750 - val_loss: 0.5530 - val_acc: 0.7060
Epoch 13/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4826 - acc: 0.7625 - val_loss: 0.4668 - val_acc: 0.7700
Epoch 14/20
100/100 [==============================] - 4s 45ms/step - loss: 0.4625 - acc: 0.7865 - val_loss: 0.4852 - val_acc: 0.7580
Epoch 15/20
100/100 [==============================] - 4s 45ms/step - loss: 0.4678 - acc: 0.7830 - val_loss: 0.4709 - val_acc: 0.7690
Epoch 16/20
100/100 [==============================] - 5s 46ms/step - loss: 0.4590 - acc: 0.7835 - val_loss: 0.4554 - val_acc: 0.7730
Epoch 17/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4528 - acc: 0.7985 - val_loss: 0.4717 - val_acc: 0.7680
Epoch 18/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4524 - acc: 0.7755 - val_loss: 0.4518 - val_acc: 0.7750
Epoch 19/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4543 - acc: 0.7825 - val_loss: 0.4612 - val_acc: 0.7780
Epoch 20/20
100/100 [==============================] - 5s 45ms/step - loss: 0.4376 - acc: 0.8035 - val_loss: 0.5148 - val_acc: 0.7710

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947470.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uni-app 页面生命周期及组件生命周期汇总(Vue2、Vue3)

文章目录 一、前言🍃二、页面生命周期三、Vue2 页面及组件生命周期流程图四、Vue3 页面及组件生命周期流程图4.1 页面加载时序介绍4.2 页面加载常见问题4.3 onShow 和 onHide4.4 onInit4.5 onLoad4.6 onReachBottom4.7 onPageScroll4.8 onBackPress4.9 onTabItemTap…

缓存淘汰算法:次数除以时间差

记录缓存中的每一项的访问次数、最后访问时间,获取当前时间,可算出时间差,然后,用次数除以时间差,取最小的淘汰。 这一算法比较慢,需配合多级缓存。一级缓存不很大,使用此算法。二级缓存可以大…

uniapp 微信小程序开发使用高德地图、腾讯地图

一、高德地图 1.注册高德地图开放平台账号 (1)创建应用 这个key 第3步骤,配置到项目中locationGps.js 2.下载高德地图微信小程序插件 (1)下载地址 高德地图API | 微信小程序插件 (2)引入项目…

Mac iTerm2集成DeepSeek AI

1. 去deepseek官网申请api key,DeepSeek 2. 安装iTerm2 AI Plugin插件,https://iterm2.com/ai-plugin.html,插件解压后直接放到和iTerms相同的位置,默认就在/Applications 下 3. 配置iTerm2 4. 重启iTerm2,使用快捷键呼出AI对话…

树莓派 Pico RP2040 教程点灯 双核编程案例

双核点亮不同的 LED 示例,引脚分别是GP0跟GP1。 #include "pico/stdlib.h" #include "pico/multicore.h"#define LED1 0 // 核心 0 控制的 LED 引脚 #define LED2 1 // 核心 1 控制的 LED 引脚// the setup function runs once when you press …

简单使用linux

1.1 Linux的组成 Linux 内核:内核是系统的核心,是运行程序和管理 像磁盘和打印机等硬件设备的核心程序。 文件系统 : 文件存放在磁盘等存储设备上的组织方法。 Linux 能支持多种目前浒的文件系统,如 ext4 、 FAT 、 VFAT 、 ISO9660 、 NF…

ACM算法模板

ACM算法模板 起手式基础算法前缀和与差分二分查找三分查找求极值分治法:归并排序 动态规划基本线性 d p dp dp最长上升子序列I O ( n 2 ) O(n ^ 2) O(n2)最长上升子序列II O ( n l o g n ) O(nlogn) O(nlogn) 贪心二分最长公共子序列 背包背包求组合种类背包求排列…

《Vue3实战教程》19:Vue3组件 v-model

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 组件 v-model​ 基本用法​ v-model 可以在组件上使用以实现双向绑定。 从 Vue 3.4 开始&#xff0c;推荐的实现方式是使用 defineModel() 宏&#xff1a; vue <!-- Child.vue --> <script setup> co…

Docker 环境中搭建 Redis 哨兵模式集群的步骤与问题解决

在 Docker 环境中搭建 Redis 哨兵模式集群的步骤与问题解决 在 Redis 高可用架构中&#xff0c;哨兵模式&#xff08;Sentinel&#xff09;是确保 Redis 集群在出现故障时自动切换主节点的一种机制。通过使用 Redis 哨兵&#xff0c;我们可以实现 Redis 集群的监控、故障检测和…

数据结构:时间复杂度和空间复杂度

我们知道代码和代码之间算法的不同&#xff0c;一定影响了代码的执行效率&#xff0c;那么我们该如何评判算法的好坏呢&#xff1f;这就涉及到了我们算法效率的分析了。 &#x1f4d6;一、算法效率 所谓算法效率的分析分为两种&#xff1a;第一种时间效率&#xff0c;又称时间…

《Vue3实战教程》39:Vue3无障碍访问

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 无障碍访问​ Web 无障碍访问 (也称为 a11y) 是指创建可供任何人使用的网站的做法——无论是身患某种障碍、通过慢速的网络连接访问、使用老旧或损坏的硬件&#xff0c;还是仅处于某种不方便的环境。例如&#xff0c;…

GESP2024年6月认证C++五级( 第三部分编程题(1)黑白格)

参考程序&#xff08;二维前缀和&#xff09; #include <iostream> #include <vector> #include <algorithm> using namespace std;int main() {int n, m, k;cin >> n >> m >> k;// 输入网格图vector<vector<int>> grid(n, v…

二、SQL语言,《数据库系统概念》,原书第7版

文章目录 一、概览SQL语言1.1 SQL 语言概述1.1.1 SQL语言的提出和发展1.1.2 SQL 语言的功能概述 1.2 利用SQL语言建立数据库1.2.1 示例1.2.2 SQL-DDL1.2.2.1 CREATE DATABASE1.2.2.2 CREATE TABLE 1.2.3 SQL-DML1.2.3.1 INSERT INTO 1.3 用SQL 语言进行简单查询1.3.1 单表查询 …

js按日期按数量进行倒序排序,然后再新增一个字段,给这个字段赋值 10 到1

效果如下图&#xff1a; 实现思路&#xff1a; 汇总数据&#xff1a;使用 reduce 方法遍历原始数据数组&#xff0c;将相同日期的数据进行合并&#xff0c;并计算每个日期的总和。创建日期映射&#xff1a;创建一个映射 dateMap&#xff0c;存储每个日期的对象列表。排序并添加…

用uniapp写一个播放视频首页页面代码

效果如下图所示 首页有导航栏&#xff0c;搜索框&#xff0c;和视频列表&#xff0c; 导航栏如下图 搜索框如下图 视频列表如下图 文件目录 视频首页页面代码如下 <template> <view class"video-home"> <!-- 搜索栏 --> <view class…

【three.js】光源

光源 光源特点 当使用MeshLambertMaterial材质时&#xff0c;会受到光线的影响&#xff0c; 我们代码里面如果没有设置光线&#xff0c;则使用MeshLambertMaterial材质修饰的模型不可见&#xff0c;这个时候&#xff0c;我们添加光线后&#xff0c;便可以看见。 环境光 定义&a…

U8G2库使用案例(stm32)

U8G2官网&#xff1a; 自己移植的U8g2库&#xff0c;OLED库超好用&#xff0c;自己封装了用户层不需要再去查资料使用&#xff0c;注释写的很多很详细&#xff0c;有示例上手就会&#xff0c;初始化也很简单 个人移植的U8g2库&#xff1a; 超简单的stm32 U8g2移植 大家可以自…

Linux 上安装 PostgreSQL

文章目录 前言一、安装PostgreSQL二、修改数据库默认数据存储目录 1.自定义数据存放目录2.修改自定义服务3.初始化数据库4.运行数据库 三、配置数据库信息 四、权限 异常处理 前言 提示&#xff1a;本次博客是centos7.9安装PostgreSQL12版本 名称 版本 Centos 7.9 postg…

HTML——56.表单发送

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>表单发送</title></head><body><!--注意&#xff1a;1.表单接收程序&#xff0c;放在服务器环境中(也就是这里的www文件目录中)2.表单发送地址&#x…

logback之pattern详解以及源码分析

目录 &#xff08;一&#xff09;pattern关键字介绍 &#xff08;二&#xff09;源码分析 &#xff08;一&#xff09;pattern关键字介绍 %d或%date&#xff1a;表示日期&#xff0c;可配置格式化%d{yyyy-MM-dd HH:mm:ss} %r或%relative&#xff1a;也是日期&#xff0c;不过…