当前位置:   article > 正文

使用TensorFlow和Keras对以ResNet50模型进行微调

使用TensorFlow和Keras对以ResNet50模型进行微调

以下是使用ResNet50进行微调以识别特定的新东西的代码演示。将使用TensorFlow和Keras进行这个任务。

数据集下载地址,解压到工程里面去:

https://www.kaggle.com/datasets/marquis03/cats-and-dogs
  • 1

原始代码:

​ ```

from keras.applications import ResNet50
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Model
from keras import models
from keras.layers import Dense, GlobalAveragePooling2D, Dropout
from keras.optimizers import Adam
import os

# 加载ResNet50模型,并去掉顶层
base_model = ResNet50(weights='imagenet', include_top=False)

# 添加自定义顶层
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
x = Dropout(0.5)(x)  # 添加Dropout层以防止过拟合
predictions = Dense(2, activation='softmax')(x)  # 用于二分类任务,输出层有两个神经元

model = Model(inputs=base_model.input, outputs=predictions)

# 冻结大部分卷积层,只训练顶层
for layer in base_model.layers:
    layer.trainable = False

# 编译模型
model.compile(optimizer=Adam(learning_rate=0.01),  # 调整学习率
              loss='categorical_crossentropy',  # 使用categorical_crossentropy损失函数
              metrics=['accuracy'])

# 假设数据存储在train_data_dir和validation_data_dir中,并且每个类有一个文件夹
train_data_dir = 'D:\\py\\tvr_search_py\\robot\\test\\catanddog\\train'  # 替换为实际路径
validation_data_dir = 'D:\\py\\tvr_search_py\\robot\\test\\catanddog\\val'  # 替换为实际路径
img_height, img_width = 224, 224
batch_size = 32

# 检查目录是否存在
if not os.path.exists(train_data_dir):
    raise ValueError(f"训练数据目录不存在: {train_data_dir}")
if not os.path.exists(validation_data_dir):
    raise ValueError(f"验证数据目录不存在: {validation_data_dir}")

train_datagen = ImageDataGenerator(rescale=1. / 255,
                                   shear_range=0.2,
                                   zoom_range=0.2,
                                   horizontal_flip=True)

test_datagen = ImageDataGenerator(rescale=1. / 255)

train_generator = train_datagen.flow_from_directory(train_data_dir,
                                                    target_size=(img_height, img_width),
                                                    batch_size=batch_size,
                                                    class_mode='categorical')  # 用于二分类任务

validation_generator = test_datagen.flow_from_directory(validation_data_dir,
                                                        target_size=(img_height, img_width),
                                                        batch_size=batch_size,
                                                        class_mode='categorical')  # 用于二分类任务

# 确保steps_per_epoch和validation_steps不为零
if train_generator.samples == 0:
    raise ValueError(f"训练数据目录中没有找到图像: {train_data_dir}")
if validation_generator.samples == 0:
    raise ValueError(f"验证数据目录中没有找到图像: {validation_data_dir}")

steps_per_epoch = max(1, train_generator.samples // batch_size)
validation_steps = max(1, validation_generator.samples // batch_size)

epochs = 10  # 增加训练轮数

model.fit(train_generator,
          steps_per_epoch=steps_per_epoch,
          validation_data=validation_generator,
          validation_steps=validation_steps,
          epochs=epochs)

# model.summary()
# model.save('D:\\py\\tvr_search_py\\robot\\test\\model\\resnet50_model.keras')

# 解冻部分或全部的卷积层并继续训练
# 
for layer in base_model.layers[:]:
    layer.trainable = True
#
model.compile(optimizer=Adam(learning_rate=0.0001),  # 用较低的学习率
              loss='categorical_crossentropy',
              metrics=['accuracy'])
#
model.fit(train_generator,
          steps_per_epoch=train_generator.samples // batch_size,
          validation_data=validation_generator,
          validation_steps=validation_generator.samples // batch_size,
          epochs=20)

# # 再次保存模型
model.save('D:\\py\\tvr_search_py\\robot\\test\\model\\resnet50_finetuned_model.keras')
#
# # 加载模型
loaded_model = models.load_model('D:\\py\\tvr_search_py\\robot\\test\\model\\resnet50_finetuned_model.keras')
#
# # 打印模型结构
loaded_model.summary()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

解析

  1. 安装必要的库

    pip3 install tensorflow keras
    
    • 1
  2. 导入库

    import tensorflow as tf
    from tensorflow.keras.applications import ResNet50
    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    from tensorflow.keras.models import Model
    from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
    from tensorflow.keras.optimizers import Adam
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  3. 加载ResNet50模型,并去掉顶层

    base_model = ResNet50(weights='imagenet', include_top=False)
    
    • 1
  4. 添加自定义顶层

    x = base_model.output
    x = GlobalAveragePooling2D()(x)
    x = Dense(1024, activation='relu')(x)
    predictions = Dense(num_classes, activation='softmax')(x)  # `num_classes`是新数据集的类别数
    
    model = Model(inputs=base_model.input, outputs=predictions)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  5. 冻结base_model的所有卷积层

    for layer in base_model.layers:
        layer.trainable = False
    
    • 1
    • 2
  6. 编译模型

    model.compile(optimizer=Adam(learning_rate=0.001),
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    
    • 1
    • 2
    • 3
  7. 准备数据
    假设数据存储在train_data_dirvalidation_data_dir中,并且每个类有一个文件夹。

    train_data_dir = 'path_to_train_data'
    validation_data_dir = 'path_to_validation_data'
    img_height, img_width = 224, 224
    batch_size = 32
    
    train_datagen = ImageDataGenerator(rescale=1./255, 
                                       shear_range=0.2, 
                                       zoom_range=0.2, 
                                       horizontal_flip=True)
    
    test_datagen = ImageDataGenerator(rescale=1./255)
    
    train_generator = train_datagen.flow_from_directory(train_data_dir,
                                                        target_size=(img_height, img_width),
                                                        batch_size=batch_size,
                                                        class_mode='categorical')
    
    validation_generator = test_datagen.flow_from_directory(validation_data_dir,
                                                            target_size=(img_height, img_width),
                                                            batch_size=batch_size,
                                                            class_mode='categorical')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  8. 训练模型

    epochs = 10
    
    model.fit(train_generator,
              steps_per_epoch=train_generator.samples // batch_size,
              validation_data=validation_generator,
              validation_steps=validation_generator.samples // batch_size,
              epochs=epochs)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  9. 解冻部分或全部的卷积层并继续训练

    for layer in base_model.layers[:]:
        layer.trainable = True
    
    model.compile(optimizer=Adam(learning_rate=0.0001),  # 用较低的学习率
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    
    model.fit(train_generator,
              steps_per_epoch=train_generator.samples // batch_size,
              validation_data=validation_generator,
              validation_steps=validation_generator.samples // batch_size,
              epochs=10)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

在这段代码中,“添加自定义顶层”是指在预训练的ResNet50模型的基础上,增加一些新的层,这些层专门用于处理分类任务。ResNet50模型预先在ImageNet数据集上进行了训练,但它的输出层是针对ImageNet的1000个类别的。在微调过程中,希望将它应用到一个新的数据集,这个数据集的类别数可能不同,因此需要添加新的顶层来适应这个新的任务。

以下是这个过程的详细解释:

  1. 去掉顶层:首先,加载预训练的ResNet50模型,并去掉它的顶层(include_top=False)。这样做的目的是只保留模型的卷积层部分,这些层已经在大量图像上学习到了很有用的特征。

    base_model = ResNet50(weights='imagenet', include_top=False)
    
    • 1
  2. 添加新的全局平均池化层:在base_model的输出之后,添加一个全局平均池化层(GlobalAveragePooling2D)。这个层将把卷积层的输出转换成一个扁平的特征向量。

    x = base_model.output
    x = GlobalAveragePooling2D()(x)
    
    • 1
    • 2
  3. 添加一个全连接层:接下来,添加一个全连接层(Dense层),用于进一步处理特征向量。这个例子中,使用了一个具有1024个神经元和ReLU激活函数的全连接层。

    x = Dense(1024, activation='relu')(x)
    
    • 1
  4. 添加输出层:最后,添加一个输出层,这个层的神经元数目等于新数据集的类别数(num_classes),并使用softmax激活函数来输出每个类别的概率。

    predictions = Dense(num_classes, activation='softmax')(x)
    
    • 1

    num_classes 是指在新的数据集中需要分类的类别数。它决定了最终输出层的神经元数量,每个神经元对应一个类别,并通过softmax激活函数输出每个类别的概率。以下是一个详细的解释和代码注释,帮助更好地理解这个概念:

    Detailed Explanation

    In a classification task, the neural network aims to assign input images to one of several predefined categories. The number of these categories is called num_classes. For example, if we are building a model to classify images of cats, dogs, and birds, then num_classes would be 3.

    在ResNet50的原始结构中,输出层的num_classes是1000,因为它是在ImageNet数据集上预训练的,而ImageNet数据集包含1000个类别。

    如果希望用ResNet50模型来处理二分类任务(即只有两个类别),则需要将输出层的num_classes改为1。但是,需要注意的是,在二分类任务中,通常会使用sigmoid激活函数而不是softmax激活函数。

    以下是将输出层改为适用于二分类任务的代码示例:

    import tensorflow as tf
    from tensorflow.keras.applications import ResNet50
    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    from tensorflow.keras.models import Model
    from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
    from tensorflow.keras.optimizers import Adam
    
    # 加载ResNet50模型,并去掉顶层
    base_model = ResNet50(weights='imagenet', include_top=False)
    
    # 添加自定义顶层
    x = base_model.output
    x = GlobalAveragePooling2D()(x)
    x = Dense(1024, activation='relu')(x)
    predictions = Dense(1, activation='sigmoid')(x)  # 用于二分类任务
    
    model = Model(inputs=base_model.input, outputs=predictions)
    
    # 冻结base_model的所有卷积层
    for layer in base_model.layers:
        layer.trainable = False
    
    # 编译模型
    model.compile(optimizer=Adam(learning_rate=0.001),
                  loss='binary_crossentropy',  # 使用binary_crossentropy损失函数
                  metrics=['accuracy'])
    
    # 假设数据存储在train_data_dir和validation_data_dir中,并且每个类有一个文件夹
    train_data_dir = 'path_to_train_data'  # 替换为实际路径
    validation_data_dir = 'path_to_validation_data'  # 替换为实际路径
    img_height, img_width = 224, 224
    batch_size = 32
    
    train_datagen = ImageDataGenerator(rescale=1./255, 
                                       shear_range=0.2, 
                                       zoom_range=0.2, 
                                       horizontal_flip=True)
    
    test_datagen = ImageDataGenerator(rescale=1./255)
    
    train_generator = train_datagen.flow_from_directory(train_data_dir,
                                                        target_size=(img_height, img_width),
                                                        batch_size=batch_size,
                                                        class_mode='binary')  # 用于二分类任务
    
    validation_generator = test_datagen.flow_from_directory(validation_data_dir,
                                                            target_size=(img_height, img_width),
                                                            batch_size=batch_size,
                                                            class_mode='binary')  # 用于二分类任务
    
    # 训练模型
    epochs = 10
    
    model.fit(train_generator,
              steps_per_epoch=train_generator.samples // batch_size,
              validation_data=validation_generator,
              validation_steps=validation_generator.samples // batch_size,
              epochs=epochs)
    
    # 解冻部分或全部的卷积层并继续训练
    for layer in base_model.layers[:]:
        layer.trainable = True
    
    model.compile(optimizer=Adam(learning_rate=0.0001),  # 用较低的学习率
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    
    model.fit(train_generator,
              steps_per_epoch=train_generator.samples // batch_size,
              validation_data=validation_generator,
              validation_steps=validation_generator.samples // batch_size,
              epochs=10)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    代码解释:

    1. 修改输出层:将输出层改为只有一个神经元,并使用sigmoid激活函数。

      predictions = Dense(1, activation='sigmoid')(x)  # 用于二分类任务
      
      • 1
    2. 使用二分类损失函数:编译模型时,将损失函数设为binary_crossentropy

      model.compile(optimizer=Adam(learning_rate=0.001),
                    loss='binary_crossentropy',
                    metrics=['accuracy'])
      
      • 1
      • 2
      • 3
    3. 设置数据生成器的模式:将class_mode设置为binary,以适应二分类任务。

      train_generator = train_datagen.flow_from_directory(train_data_dir,
                                                          target_size=(img_height, img_width),
                                                          batch_size=batch_size,
                                                          class_mode='binary')
      
      validation_generator = test_datagen.flow_from_directory(validation_data_dir,
                                                              target_size=(img_height, img_width),
                                                              batch_size=batch_size,
                                                              class_mode='binary')
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
  5. 创建新的模型:将新的顶层与base_model连接起来,创建一个新的完整模型。

    model = Model(inputs=base_model.input, outputs=predictions)
    
    • 1
  6. model.compile是Keras中用于配置模型的编译方法。它指定了优化器、损失函数和评估指标。具体解释如下:

    model.compile(optimizer=Adam(learning_rate=0.001),
                  loss='binary_crossentropy',  # 使用binary_crossentropy损失函数
                  metrics=['accuracy'])
    
    • 1
    • 2
    • 3

    参数解释

    1. optimizer=Adam(learning_rate=0.001)

      • optimizer: 指定用于训练模型的优化器。在这里使用的是Adam优化器,它是一种常用的、适合处理稀疏梯度的优化算法。
      • learning_rate=0.001: 指定优化器的学习率,控制每次更新的步长大小。学习率是一个非常重要的超参数,它影响到模型收敛的速度和稳定性。
    2. loss='binary_crossentropy'

      • loss: 指定用于计算模型误差的损失函数。损失函数衡量模型预测值与真实值之间的差异,是模型训练的关键部分。
      • binary_crossentropy: 二分类交叉熵损失函数,适用于二分类任务。该损失函数通过衡量实际标签和预测概率之间的交叉熵来计算误差。
    3. metrics=['accuracy']

      • metrics: 指定评估模型性能的指标。在训练和评估过程中,这些指标将被计算并显示,以帮助评估模型的表现。
      • accuracy: 准确率指标,表示模型预测正确的样本数占总样本数的比例。对于二分类任务,准确率是一个常用的评估指标。
  7. 具体的数据集应该具有以下结构:

    1. 训练数据目录 (train_data_dir):

      • 该目录包含用于训练模型的图像数据,每个类别有一个单独的文件夹。

      • 文件夹名称是类别标签。

      • note: train_data_dir = “…/to/path_to_train_data”

      • 目录结构如下:

        path_to_train_data/
        ├── class1/
        │   ├── image1.jpg
        │   ├── image2.jpg
        │   └── ...
        └── class2/
            ├── image1.jpg
            ├── image2.jpg
            └── ...
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
    2. 验证数据目录 (validation_data_dir):

      • 该目录包含用于验证模型的图像数据,每个类别有一个单独的文件夹。

      • 文件夹名称是类别标签。

      • note: train_data_dir = “…/to/path_to_validation_data”

      • 目录结构如下:

        path_to_validation_data/
        ├── class1/
        │   ├── image1.jpg
        │   ├── image2.jpg
        │   └── ...
        └── class2/
            ├── image1.jpg
            ├── image2.jpg
            └── ...
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9

    假设有一个包含猫和狗图像的数据集,训练和验证数据目录的结构可能如下:

    训练数据目录 (path_to_train_data)
    path_to_train_data/
    ├── cats/
    │   ├── cat1.jpg
    │   ├── cat2.jpg
    │   └── ...
    └── dogs/
        ├── dog1.jpg
        ├── dog2.jpg
        └── ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    验证数据目录 (path_to_validation_data)
    path_to_validation_data/
    ├── cats/
    │   ├── cat1.jpg
    │   ├── cat2.jpg
    │   └── ...
    └── dogs/
        ├── dog1.jpg
        ├── dog2.jpg
        └── ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在上述目录结构中:

    • cats文件夹包含所有猫的图像。
    • dogs文件夹包含所有狗的图像。
    • 图像文件可以是任意名称,但通常使用.jpg、.png等常见图像格式。
  8. 代码解释

    1. 数据增强和预处理

      train_datagen = ImageDataGenerator(rescale=1./255, 
                                         shear_range=0.2, 
                                         zoom_range=0.2, 
                                         horizontal_flip=True)
      
      test_datagen = ImageDataGenerator(rescale=1./255)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • ImageDataGenerator:用于生成批次的图像数据,提供实时数据增强功能。它在训练时对图像进行随机变换,以增强模型的泛化能力。
      • rescale=1./255:将图像的像素值缩放到0到1之间。原始像素值是0到255,缩放后有助于加速模型训练并提高准确率。
      • shear_range=0.2:应用随机剪切变换,范围为0.2。这是一种几何变换,可以增加数据的多样性。
      • zoom_range=0.2:应用随机缩放变换,范围为0.2。
      • horizontal_flip=True:随机水平翻转图像。
    2. 训练和验证数据生成器

      train_generator = train_datagen.flow_from_directory(train_data_dir,
                                                          target_size=(img_height, img_width),
                                                          batch_size=batch_size,
                                                          class_mode='binary')
      
      validation_generator = test_datagen.flow_from_directory(validation_data_dir,
                                                              target_size=(img_height, img_width),
                                                              batch_size=batch_size,
                                                              class_mode='binary')
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • flow_from_directory:从目录中读取图像数据,并生成批次。这个方法会根据目录结构自动为图像分配标签。
      • target_size=(img_height, img_width):将所有图像调整为指定的目标大小。在这个例子中,图像大小被调整为224x224像素。
      • batch_size=batch_size:每个批次包含的图像数量。在这个例子中,批次大小为32。
      • class_mode='binary':指定标签模式为二分类。对于二分类任务,标签是0或1。
  9. 代码解释

    model.fit(train_generator,
              steps_per_epoch=train_generator.samples // batch_size,
              validation_data=validation_generator,
              validation_steps=validation_generator.samples // batch_size,
              epochs=epochs)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    参数解释

    1. train_generator

      • 这是之前定义的训练数据生成器,它从训练数据目录中批量生成增强后的图像数据和对应的标签。
    2. steps_per_epoch=train_generator.samples // batch_size

      • steps_per_epoch:定义每个epoch需要执行的训练步骤数。在每个epoch中,模型会处理完所有训练数据一次。
      • train_generator.samples:训练数据集中图像的总数。
      • batch_size:每个批次包含的图像数量。
      • train_generator.samples // batch_size:计算每个epoch中包含的批次数。这里使用整除操作,确保每个epoch处理完整的批次数。
    3. validation_data=validation_generator

      • 这是之前定义的验证数据生成器,它从验证数据目录中批量生成预处理后的图像数据和对应的标签,用于在训练过程中评估模型性能。
    4. validation_steps=validation_generator.samples // batch_size

      • validation_steps:定义在每个epoch结束时需要执行的验证步骤数。
      • validation_generator.samples:验证数据集中图像的总数。
      • batch_size:每个批次包含的图像数量。
      • validation_generator.samples // batch_size:计算每个epoch中包含的验证批次数,确保验证数据在每个epoch结束时得到充分评估。
    5. epochs=epochs

      • epochs:训练的轮数,表示整个训练数据集将被处理的次数。
  10. 代码解释

    for layer in base_model.layers[:]:
        layer.trainable = True
    
    model.compile(optimizer=Adam(learning_rate=0.0001),  # 用较低的学习率
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    参数解释

    1. for layer in base_model.layers[:]:

      • 这个循环遍历 base_model 的所有层。
    2. layer.trainable = True

      • 将每一层的 trainable 属性设置为 True,表示这些层在训练过程中将被更新。
      • 这种操作通常用于迁移学习的最后阶段,即在预训练模型的基础上进行微调。
    3. model.compile

      • optimizer=Adam(learning_rate=0.0001)

        • 使用Adam优化器进行梯度下降优化。
        • learning_rate=0.0001:设置学习率为0.0001,较低的学习率通常用于微调,以防止模型参数过大变化,导致模型性能下降。
      • loss='binary_crossentropy'

        • 损失函数使用二分类交叉熵损失,这在二分类任务中是常见的选择。
        • 二分类交叉熵衡量模型预测的概率分布与实际标签之间的差异。
      • metrics=['accuracy']

        • 使用准确率作为评价指标,表示模型在验证数据上的预测准确性。
  11. model.compile 的参数详细解释

    model.compile(optimizer=Adam(learning_rate=0.0001),  # 用较低的学习率
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    
    • 1
    • 2
    • 3
    1. optimizer
    • Adam(learning_rate=0.0001):
      • Adam: 一种自适应学习率优化算法,全称是Adaptive Moment Estimation。Adam结合了Momentum和RMSProp的优点,能更快地收敛并且更稳定。
      • learning_rate=0.0001: 学习率,控制每次参数更新的步伐。0.0001 是一个较低的学习率,通常用于微调模型,以防止模型参数的剧烈变化,保持训练的稳定性。
    1. loss
    • binary_crossentropy:

      • 二分类交叉熵损失函数,常用于二分类问题。它度量的是预测的概率分布与实际标签之间的差异。公式如下:
        Loss = − 1 N ∑ i = 1 N [ y i log ⁡ ( p i ) + ( 1 − y i ) log ⁡ ( 1 − p i ) ] \text{Loss} = -\frac{1}{N} \sum_{i=1}^{N} [y_i \log(p_i) + (1 - y_i) \log(1 - p_i)] Loss=N1i=1N[yilog(pi)+(1yi)log(1pi)]

      • 其中,( y_i ) 是实际标签,( p_i ) 是预测概率,( N ) 是样本数。

    1. metrics
    • accuracy:

      • accuracy: 准确率,是最常用的评价指标之一。它表示预测正确的样本数占总样本数的比例。公式如下:
        Accuracy = Number of correct predictions Total number of predictions \text{Accuracy} = \frac{\text{Number of correct predictions}}{\text{Total number of predictions}} Accuracy=Total number of predictionsNumber of correct predictions
  12. 顶层(Top Layer)是什么

    在深度学习模型,特别是卷积神经网络(CNN)中,顶层(Top Layer)指的是网络的最后几层,通常包括全连接层和输出层。这些层负责将前面卷积层提取到的特征映射到最终的分类结果或其他任务的输出。

    示例

    以VGG16模型为例,其顶层通常包括几个全连接层和一个输出层:

    1. 全连接层(Fully Connected Layer)

      • 这些层接收来自卷积层的特征图,并通过全连接操作将这些特征映射到一个固定大小的向量。
    2. 输出层(Output Layer)

      • 最后一层通常是一个全连接层,输出单元数目等于分类类别数。对于二分类问题,这一层的输出单元数为1,并使用Sigmoid激活函数。

    在Keras中,include_top=False 意味着不包括这些顶层,只保留卷积层部分,这通常用于迁移学习,允许用户根据具体任务添加自定义的顶层结构。

    顶层的作用

    1. 特征变换

      • 将卷积层提取到的特征进行进一步处理和变换,以适应具体任务(如分类任务)。
    2. 输出预测

      • 最后一层输出预测结果,具体形式取决于任务类型(分类、回归等)。
  13. 全连接层(Fully Connected Layer)是什么

    全连接层(Fully Connected Layer),也称作密集层(Dense Layer),是神经网络中一种基本的层类型。它的特点是每个神经元与上一层的所有神经元相连接。这种层通常用于卷积神经网络(CNN)中的最后几层,用于综合卷积层提取到的特征并进行最终的分类或回归任务。

    全连接层的特征

    1. 连接方式

      • 全连接层中的每个神经元与上一层的所有神经元都有连接,这意味着这一层的每个输出单元都是前一层所有输入单元的加权求和。
    2. 权重和偏置

      • 每个连接都有一个权重,同时每个神经元还有一个偏置。通过训练,这些权重和偏置被不断调整,以最小化损失函数。
    3. 激活函数

      • 全连接层通常与激活函数一起使用,如ReLU、Sigmoid、Tanh等,以引入非线性,使模型能够拟合复杂的函数。

    全连接层的作用

    1. 特征综合

      • 在卷积神经网络中,全连接层位于网络的末端,用于综合卷积层和池化层提取到的特征。
    2. 输出预测

      • 全连接层的最后一层通常是输出层,输出的单元数等于分类问题的类别数或者回归问题的目标数。
    例子

    下面是一个包含全连接层的简单神经网络结构:

    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Dense, Flatten
    
    model = Sequential([
        # 输入层,假设输入是一个28x28的图像
        Flatten(input_shape=(28, 28)),
        # 第一个全连接层,128个神经元,使用ReLU激活函数
        Dense(128, activation='relu'),
        # 输出层,10个神经元,对应10个类别,使用Softmax激活函数
        Dense(10, activation='softmax')
    ])
    
    # 编译模型
    model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
    
    # 打印模型结构
    model.summary()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这个例子中:

    1. Flatten

      • 将输入的28x28的图像展平成784个单位的向量,方便后续的全连接层处理。
    2. 第一个Dense

      • 包含128个神经元,每个神经元与输入向量的所有单位相连接。使用ReLU激活函数引入非线性。
    3. 输出Dense

      • 包含10个神经元,对应10个类别。使用Softmax激活函数将输出转换为概率分布,适用于多分类任务。
  14. model = Model(inputs=base_model.input, outputs=predictions) 中的 inputs

    在深度学习中,使用 Keras 或 TensorFlow 框架定义和构建模型时,inputs 参数指的是模型的输入张量。这个张量描述了模型预期接收的数据的形状和类型。

    具体解释

    model = Model(inputs=base_model.input, outputs=predictions)
    
    • 1

    在这段代码中:

    1. inputs=base_model.input

      • base_model: 这是一个预训练的模型实例,例如 VGG16、ResNet 等。
      • base_model.input: 这是 base_model 模型的输入张量。它定义了模型期望接收的输入数据的形状。例如,如果 base_model 是 VGG16,那么 base_model.input 的形状通常是 (None, 224, 224, 3),表示输入是形状为 (224, 224, 3) 的 RGB 图像,None 表示批量大小可以是任意的。
    2. outputs=predictions

      • predictions:这是在预训练模型基础上添加的自定义输出张量。它代表模型的最终输出,例如分类结果。

    inputs` 的作用

    • 定义输入形状:通过 inputs 参数,明确告诉模型输入数据的形状和类型。这对于确保数据能够正确地通过模型的各层处理非常重要。
    • 连接模型层次:在构建模型时,inputsoutputs 将模型的所有层次连接起来,从输入层到输出层。
  15. 模型的保存和加载

    保存模型

    1. 保存整个模型
      这种方法保存了模型的结构、权重和训练配置(优化器、损失函数等)。可以直接加载并继续训练或进行推理。

      model.save('model_path.keras')
      
      • 1
    2. 保存模型的权重
      如果只需要保存模型的权重,可以使用 save_weights 方法。这种方法适合在模型架构不变的情况下进行权重的保存和加载。

      model.save_weights('model_weights.keras')
      
      • 1

    加载模型

    1. 加载整个模型
      可以使用 load_model 方法来加载之前保存的整个模型。

      from keras.models import load_model
      
      # 加载模型
      model = load_model('model_path.keras')
      
      • 1
      • 2
      • 3
      • 4
    2. 加载模型的权重
      如果只保存了模型的权重,需要先构建与保存时相同的模型架构,然后再加载权重。

      from tensorflow.keras.applications import ResNet50
      from tensorflow.keras.models import Model
      from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
      
      # 重新创建模型结构
      base_model = ResNet50(weights=None, include_top=False, input_shape=(224, 224, 3))
      x = base_model.output
      x = GlobalAveragePooling2D()(x)
      x = Dense(1024, activation='relu')(x)
      predictions = Dense(1, activation='sigmoid')(x)
      model = Model(inputs=base_model.input, outputs=predictions)
      
      # 加载权重
      model.load_weights('model_weights.keras')
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
  16. 在 TensorFlow Keras 中,加载模型的过程通常涉及两种不同的方法:加载本地保存的模型和从预训练模型库中下载模型。

    #####加载本地保存的模型

    当使用 model.save 方法将模型保存到本地文件系统时,可以在后续的操作中从本地加载该模型。这种方式不需要每次都从网上下载。示例如下:

    #####保存模型

    # 保存模型到本地文件系统
    model.save('local_model_path.keras')
    
    • 1
    • 2

    #####加载模型

    from tensorflow.keras.models import load_model
    
    # 从本地文件系统加载模型
    model = load_model('local_model_path.keras')
    
    • 1
    • 2
    • 3
    • 4

    #####从预训练模型库中下载模型

    当使用预训练模型,例如 ResNet50,并且指定 weights='imagenet' 时,Keras 会从网上下载预训练的权重文件并缓存到本地目录(通常是 ~/.keras/models/)。一旦下载完成并缓存,就不需要每次重新下载。示例如下:

    加载预训练模型
    from keras.applications import ResNet50
    
    # 加载预训练的 ResNet50 模型
    base_model = ResNet50(weights='imagenet', include_top=False)
    
    • 1
    • 2
    • 3
    • 4
    缓存机制

    Keras 使用的缓存机制会将下载的模型文件存储在本地用户目录下,以避免每次都重新下载。具体位置如下:

    • Linux 和 MacOS: ~/.keras/models/
    • Windows: C:\Users\<username>\.keras\models\

    在加载预训练模型时,如果缓存目录中已经存在所需的文件,Keras 会直接使用本地缓存文件。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/707444
推荐阅读
相关标签
  

闽ICP备14008679号