当前位置: 首页 > news >正文

第J3周:DenseNet算法实战与解析

文章目录

  • 一、前期准备
    • 1.设置GPU
    • 2.导入数据
    • 3.查看数据
  • 二、数据预处理
    • 1.加载数据
    • 2.可视化数据
    • 3.再次检查数据
    • 4.配置数据集
  • 三、模型复现
    • 1.DenseLayer
    • 2.Transition
    • 3.实现DenseNet网络
  • 四、训练模型
  • 五、结果可视化
  • 总结

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊

一、前期准备

1.设置GPU

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")

2.导入数据

import matplotlib.pyplot as plt
# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False   # 用来正常显示负号

import os,PIL,pathlib
import numpy as np

from tensorflow import keras 
from tensorflow.keras import layers, models
data_dir = "8/bird_photos"

data_dir = pathlib.Path(data_dir)

3.查看数据

image_count = len(list(data_dir.glob('*/*')))

print("图片总数为:", image_count)

图片总数为: 565

二、数据预处理

1.加载数据

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_split=0.2,
    subset="training",
    seed=123,
    image_size=(img_height, img_width),
    batch_size=batch_size)

Found 565 files belonging to 4 classes.
Using 452 files for training.

"""
关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
"""
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="validation",
    seed=123,
    image_size=(img_height, img_width),
    batch_size=batch_size)

Found 565 files belonging to 4 classes.
Using 113 files for validation.

class_names = train_ds.class_names
print(class_names)

[‘Bananaquit’, ‘Black Skimmer’, ‘Black Throated Bushtiti’, ‘Cockatoo’]

2.可视化数据

plt.figure(figsize=(10, 5))  # 图形的宽为10高为5

for images, labels in train_ds.take(1):
    for i in range(8):
        
        ax = plt.subplot(2, 4, i + 1)  

        plt.imshow(images[i].numpy().astype("uint8"))
        plt.title(class_names[labels[i]])
        
        plt.axis("off")

2025-02-21 10:53:06.021196: I tensorflow/core/common_runtime/executor.cc:1197] [/device:CPU:0] (DEBUG INFO) Executor start aborting (this does not indicate an error and you can ignore this message): INVALID_ARGUMENT: You must feed a value for placeholder tensor 'Placeholder/_4' with dtype int32 and shape [452]
	 [[{{node Placeholder/_4}}]]
2025-02-21 10:53:06.021478: I tensorflow/core/common_runtime/executor.cc:1197] [/device:CPU:0] (DEBUG INFO) Executor start aborting (this does not indicate an error and you can ignore this message): INVALID_ARGUMENT: You must feed a value for placeholder tensor 'Placeholder/_0' with dtype string and shape [452]
	 [[{{node Placeholder/_0}}]]
2025-02-21 10:53:06.027975: W tensorflow/tsl/platform/profile_utils/cpu_utils.cc:128] 

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=output_14_1.png&pos_id=img-GMoW51Gv-1740138320577)

在这里插入图片描述

plt.imshow(images[1].numpy().astype("uint8"))

<matplotlib.image.AxesImage at 0x175a9e920>
在这里插入图片描述

3.再次检查数据

for image_batch, labels_batch in train_ds:
    print(image_batch.shape)
    print(labels_batch.shape)
    break

(8, 224, 224, 3)
(8,)

2025-02-21 10:53:07.684073: I tensorflow/core/common_runtime/executor.cc:1197] [/device:CPU:0] (DEBUG INFO) Executor start aborting (this does not indicate an error and you can ignore this message): INVALID_ARGUMENT: You must feed a value for placeholder tensor ‘Placeholder/_4’ with dtype int32 and shape [452]
[[{{node Placeholder/_4}}]]
2025-02-21 10:53:07.684953: I tensorflow/core/common_runtime/executor.cc:1197] [/device:CPU:0] (DEBUG INFO) Executor start aborting (this does not indicate an error and you can ignore this message): INVALID_ARGUMENT: You must feed a value for placeholder tensor ‘Placeholder/_4’ with dtype int32 and shape [452]
[[{{node Placeholder/_4}}]]

4.配置数据集

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

三、模型复现

1.DenseLayer

import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras.models import Model

class DenseLayer(tf.keras.Model):
    """Basic unit of DenseBlock (using bottleneck layer)"""
    def __init__(self, num_input_features, growth_rate, bn_size, drop_rate):
        super(DenseLayer, self).__init__()
        
        # BatchNorm + ReLU + 1x1 Conv (Bottleneck layer)
        self.norm1 = layers.BatchNormalization()
        self.relu1 = layers.ReLU()
        self.conv1 = layers.Conv2D(filters=bn_size * growth_rate, kernel_size=1, 
                                   strides=1, use_bias=False, padding="valid")
        
        # BatchNorm + ReLU + 3x3 Conv (Feature Extraction)
        self.norm2 = layers.BatchNormalization()
        self.relu2 = layers.ReLU()
        self.conv2 = layers.Conv2D(filters=growth_rate, kernel_size=3, 
                                   strides=1, padding="same", use_bias=False)
        
        self.drop_rate = drop_rate

    def call(self, x, training=False):
        """Forward pass"""
        out = self.conv1(self.relu1(self.norm1(x, training=training)))
        out = self.conv2(self.relu2(self.norm2(out, training=training)))
        
        # Dropout if drop_rate > 0
        if self.drop_rate > 0:
            out = layers.Dropout(self.drop_rate)(out, training=training)
        
        # Concatenate input and new features
        return tf.concat([x, out], axis=-1)  # TensorFlow uses `axis=-1` for channels
class DenseBlock(tf.keras.Model):
    """Dense Block for DenseNet"""
    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate):
        super(DenseBlock, self).__init__()
        self.layers_list = []

        # 逐层添加 DenseLayer
        for i in range(num_layers):
            layer = DenseLayer(num_input_features + i * growth_rate, growth_rate, bn_size, drop_rate)
            self.layers_list.append(layer)

    def call(self, x, training=False):
        """Forward pass"""
        for layer in self.layers_list:
            x = layer(x, training=training)  # 依次通过每个 DenseLayer,并进行拼接
        return x

2.Transition

class TransitionLayer(tf.keras.Model):
    """Transition layer between two adjacent DenseBlock"""
    def __init__(self, num_input_features, num_output_features):
        super(TransitionLayer, self).__init__()

        # Batch Normalization + ReLU
        self.norm = layers.BatchNormalization()
        self.relu = layers.ReLU()

        # 1x1 Convolution to reduce feature maps
        self.conv = layers.Conv2D(filters=num_output_features, kernel_size=1, 
                                  strides=1, use_bias=False, padding="valid")

        # 2x2 Average Pooling (stride=2)
        self.pool = layers.AveragePooling2D(pool_size=2, strides=2)

    def call(self, x, training=False):
        """Forward pass"""
        x = self.conv(self.relu(self.norm(x, training=training)))
        x = self.pool(x)  # Reduce spatial dimensions
        return x

3.实现DenseNet网络

class DenseNet(Model):
    """DenseNet-BC Model"""
    def __init__(self, growth_rate=32, block_config=(6, 12, 24, 16), num_init_features=64,
                 bn_size=4, compression_rate=0.5, drop_rate=0, num_classes=1000):
        """
        :param growth_rate: (int) number of filters used in DenseLayer, `k` in the paper
        :param block_config: (list of 4 ints) number of layers in each DenseBlock
        :param num_init_features: (int) number of filters in the first Conv2d
        :param bn_size: (int) the factor using in the bottleneck layer
        :param compression_rate: (float) the compression rate used in Transition Layer
        :param drop_rate: (float) the drop rate after each DenseLayer
        :param num_classes: (int) number of classes for classification
        """
        super(DenseNet, self).__init__()

        # First Convolutional Layer (Conv2d + BN + ReLU + MaxPool)
        self.conv0 = layers.Conv2D(filters=num_init_features, kernel_size=7, strides=2,
                                   padding="same", use_bias=False)
        self.norm0 = layers.BatchNormalization()
        self.relu0 = layers.ReLU()
        self.pool0 = layers.MaxPooling2D(pool_size=3, strides=2, padding="same")

        # Dense Blocks
        self.blocks = []
        num_features = num_init_features
        for i, num_layers in enumerate(block_config):
            block = DenseBlock(num_layers, num_features, bn_size, growth_rate, drop_rate)
            self.blocks.append(block)
            num_features += num_layers * growth_rate

            # Transition Layer
            if i != len(block_config) - 1:
                num_output_features = int(num_features * compression_rate)
                transition = TransitionLayer(num_features, num_output_features)
                self.blocks.append(transition)
                num_features = num_output_features

        # Final BN + ReLU
        self.norm5 = layers.BatchNormalization()
        self.relu5 = layers.ReLU()

        # Global Average Pooling + Fully Connected Layer (Classifier)
        self.global_avg_pool = layers.GlobalAveragePooling2D()
        self.classifier = layers.Dense(num_classes)

        # Weight Initialization
        self._init_weights()

    def _init_weights(self):
        """Initialize weights similar to PyTorch's kaiming_normal_"""
        for layer in self.layers:
            if isinstance(layer, layers.Conv2D):
                layer.kernel_initializer = tf.keras.initializers.HeNormal()
            elif isinstance(layer, layers.BatchNormalization):
                layer.beta_initializer = tf.keras.initializers.Zeros()
                layer.gamma_initializer = tf.keras.initializers.Ones()
            elif isinstance(layer, layers.Dense):
                layer.bias_initializer = tf.keras.initializers.Zeros()

    def call(self, x, training=False):
        """Forward pass"""
        x = self.conv0(x)
        x = self.relu0(self.norm0(x, training=training))
        x = self.pool0(x)

        for block in self.blocks:
            x = block(x, training=training)  # Pass through DenseBlocks and TransitionLayers

        x = self.relu5(self.norm5(x, training=training))
        x = self.global_avg_pool(x)
        x = self.classifier(x)

        return x
def densenet121(pretrained=False, weights_path=None, **kwargs):
    """DenseNet121 in TensorFlow"""
    model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 24, 16),
                     **kwargs)

    if pretrained and weights_path:
        model.load_weights(weights_path)
        print(f"Loaded pretrained weights from {weights_path}")

    return model
model = densenet121(pretrained=False, num_classes=4) 
model.compile(optimizer="adam",
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

四、训练模型

epochs = 10

history = model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=epochs
)

Epoch 1/10

2025-02-21 10:54:10.969427: I tensorflow/core/common_runtime/executor.cc:1197] [/device:CPU:0] (DEBUG INFO) Executor start aborting (this does not indicate an error and you can ignore this message): INVALID_ARGUMENT: You must feed a value for placeholder tensor ‘Placeholder/_0’ with dtype string and shape [452]
[[{{node Placeholder/_0}}]]
2025-02-21 10:54:10.969780: I tensorflow/core/common_runtime/executor.cc:1197] [/device:CPU:0] (DEBUG INFO) Executor start aborting (this does not indicate an error and you can ignore this message): INVALID_ARGUMENT: You must feed a value for placeholder tensor ‘Placeholder/_4’ with dtype int32 and shape [452]
[[{{node Placeholder/_4}}]]

57/57 [==============================] - ETA: 0s - loss: 5.5120 - accuracy: 0.3230

2025-02-21 10:54:53.306479: I tensorflow/core/common_runtime/executor.cc:1197] [/device:CPU:0] (DEBUG INFO) Executor start aborting (this does not indicate an error and you can ignore this message): INVALID_ARGUMENT: You must feed a value for placeholder tensor ‘Placeholder/_4’ with dtype int32 and shape [113]
[[{{node Placeholder/_4}}]]
2025-02-21 10:54:53.306614: I tensorflow/core/common_runtime/executor.cc:1197] [/device:CPU:0] (DEBUG INFO) Executor start aborting (this does not indicate an error and you can ignore this message): INVALID_ARGUMENT: You must feed a value for placeholder tensor ‘Placeholder/_0’ with dtype string and shape [113]
[[{{node Placeholder/_0}}]]

57/57 [] - 45s 737ms/step - loss: 5.5120 - accuracy: 0.3230 - val_loss: 1.3863 - val_accuracy: 0.2655
Epoch 2/10
57/57 [
] - 43s 750ms/step - loss: 3.0714 - accuracy: 0.4292 - val_loss: 1.3863 - val_accuracy: 0.3186
Epoch 3/10
57/57 [] - 41s 718ms/step - loss: 1.3863 - accuracy: 0.4646 - val_loss: 1.3863 - val_accuracy: 0.3186
Epoch 4/10
57/57 [
] - 41s 717ms/step - loss: 1.3863 - accuracy: 0.4447 - val_loss: 1.3863 - val_accuracy: 0.4336
Epoch 5/10
57/57 [] - 41s 716ms/step - loss: 1.3863 - accuracy: 0.4447 - val_loss: 1.3863 - val_accuracy: 0.4425
Epoch 6/10
57/57 [
] - 41s 716ms/step - loss: 1.3863 - accuracy: 0.4447 - val_loss: 1.3863 - val_accuracy: 0.5310
Epoch 7/10
57/57 [] - 41s 716ms/step - loss: 1.3863 - accuracy: 0.4447 - val_loss: 1.3863 - val_accuracy: 0.5398
Epoch 8/10
57/57 [
] - 41s 717ms/step - loss: 1.3863 - accuracy: 0.4447 - val_loss: 1.3863 - val_accuracy: 0.5310
Epoch 9/10
57/57 [] - 41s 719ms/step - loss: 1.3863 - accuracy: 0.4447 - val_loss: 1.3863 - val_accuracy: 0.5221
Epoch 10/10
57/57 [
] - 41s 716ms/step - loss: 1.3863 - accuracy: 0.4447 - val_loss: 1.3863 - val_accuracy: 0.5398

五、结果可视化

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)

plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

在这里插入图片描述

总结

本周主要学习了DenseNet,特别了解了DenseNet的结构,其中最主要的是DenseNet的密集连接机制。使用了上周的数据集进行复现实验,更加深入地了解到了DenseNet的结构以及应用。

相关文章:

  • 深度优化方法汇总
  • MyBatis是什么
  • 【Python项目】基于Python的语音数据及标注核对审核系统
  • Javascript数组排序
  • Golang深度学习
  • WPF的页面设计和实用功能实现
  • C#调用126邮箱发送邮件及注意事项,(完整源代码)下载
  • 每日一题——字符串变形
  • 如何生成美观且内容稳定的PDF文档:从基础到进阶的全方案解析
  • Datawhale Ollama教程笔记5
  • Rust编程语言入门教程 (七)函数与控制流
  • 什么是LoRA微调
  • SpringBoot详解
  • 使用爬虫按关键字搜索亚马逊商品:实战指南
  • AWS-SAA中文版题库
  • 【c语言初阶】函数_递归和迭代
  • 计算机专业知识【深入理解 IP 地址与子网掩码:从 /27 到不同 CIDR 表示】
  • PyTorch 源码学习:Dispatch Autograd Operators
  • 《炒股养家心法.pdf》 kimi总结
  • 京东cfe滑块 分析
  • 闽清网站建设/常用的seo工具
  • 域名购买之后怎么做网站/广东百度推广的代理商
  • 做网站服务器 自己电脑还是租/seo引擎搜索网站
  • 甘肃省住房和建设厅网站首页/靠谱seo整站优化外包
  • 做网站客户给不了素材/站长工具关键词
  • 怎么做网站主/谷歌应用商店