GoogLeNet 是一种深度学习卷积神经网络(CNN)架构,最初由 Google 团队于 2014 年提出,并在 ImageNet 挑战中赢得了第一名。它标志着深度学习技术在计算机视觉领域的重要发展,展现了更加复杂的网络结构的潜力。以下是对 GoogLeNet 的概述,包括其设计理念、结构特点和主要贡献。

1. 设计理念

        GoogLeNet 的设计理念是通过引入 Inception 模块 来提高模型的效率和表现。这个模块允许网络在同一层中并行处理多种尺度的信息,通过不同大小的卷积核和池化层捕捉不同的特征。

2. 网络结构

        GoogLeNet 是一个深而宽的卷积神经网络(CNN),其架构在设计上旨在充分利用深层特征提取的能力,同时控制参数量,提升计算效率。以下是 GooggleNet 的主要结构特征:

2.1 Inception 模块

        概述: Inception 模块是 GoogLeNet 最核心的构件。它通过结合多个卷积核的输出,允许网络在一个层级处理多种不同尺度的特征。

结构:
        每个 Inception 模块包含多条分支:
        1x1 卷积: 用于特征图降维,减少计算负担,并增加非线性。
        3x3 卷积: 提取中等尺寸特征。
        5x5 卷积: 提取更大尺寸的特征。
        3x3 最大池化: 提供空间不变性,同时通过 1x1 卷积增加非线性。

        连接方式: 所有分支的输出在通道维度上连接,形成最终的输出特征图。这使得网络不仅能同时使用多种卷积核捕获多层累积特征,还能保持计算的高效性,而不至于引入过多的参数。

2.2 1x1 卷积

功能: 
         1x1 卷积在 Inception 模块中起到了重要的作用。虽然其卷积核尺寸较小,但它可以实现以下功能:
        降维:在不同的卷积层之前使用 1x1 卷积来减少特征图的深度,有效地控制参数的数量。
        增加非线性:与非线性激活函数(如 ReLU)结合使用,从而增加网络的表达能力。
        弥补大卷积核的计算复杂度,使得整个网络可以在保持高性能的同时降低计算负担。

2.3 全局平均池化

        设计决策: 在 GoogLeNet 的最后,采用全局平均池化层代替传统的全连接层进行分类

        优势:
        减少参数量: 通过将每个特征图的平均值作为输出,一个具有很小参数量的层可以替代可能因全连接层带来的大量参数。
        改善特征表示:全局平均池化使得模型在每个类别的特征图上进行汇聚,有效避免了复杂的过拟合问题,并增强了模型的泛化能力。
        输出形式简洁: 这种方式直接输出类别概率,简化了模型结构。

2.4 深度结构

        层数: GoogLeNet 通常被称为“22 层”网络,虽然其实现方式使得实际的参数量和计算量相较于深度更小和不够高效的网络(如 AlexNet)大幅减少。

        架构优势:
        更深的网络: 通过更深的模型,GoogLeNet 能够学习到更加丰富和复杂的特征。
        参数控制: 在拥有如此深度的同时,较少的参数量使得训练更加高效,适应大规模数据集。

2.5 GoogLeNet模型图

2.6 GoogLeNet模型模块划分图

3. GoogLeNet 的实例代码

3.1 GoogLeNet(Inception V1)

以下是使用 TensorFlow 和 Keras 实现 GoogLeNet(Inception V1)网络的代码示例

3.1.1 导入必要的库
import tensorflow as tf  
from tensorflow.keras import layers, models
3.1.2 定义 Inception 模块

首先,我们需要定义一个 Inception 模块,这是 GoogLeNet 的基本构建块。

方法1:

def inception_module(x, filters):  
    # 1x1 卷积分支  
    branch1x1 = layers.Conv2D(filters[0], (1, 1), padding='same', activation='relu')(x)  

    # 1x1 卷积 + 3x3 卷积分支  
    branch3x3 = layers.Conv2D(filters[1], (1, 1), padding='same', activation='relu')(x)  
    branch3x3 = layers.Conv2D(filters[2], (3, 3), padding='same', activation='relu')(branch3x3)  

    # 1x1 卷积 + 5x5 卷积分支  
    branch5x5 = layers.Conv2D(filters[3], (1, 1), padding='same', activation='relu')(x)  
    branch5x5 = layers.Conv2D(filters[4], (5, 5), padding='same', activation='relu')(branch5x5)  

    # 3x3 池化 + 1x1 卷积分支  
    branch_pool = layers.MaxPooling2D((3, 3), strides=(1, 1), padding='same')(x)  
    branch_pool = layers.Conv2D(filters[5], (1, 1), padding='same', activation='relu')(branch_pool)  

    # 将所有分支连接在一起  
    outputs = layers.concatenate([branch1x1, branch3x3, branch5x5, branch_pool], axis=-1)  
    return outputs

 方法2:

# 定义Inception模块
class Inception(tf.keras.layers.Layer):
    # 输⼊参数为各个卷积的卷积核个数
    def __init__(self,c1,c2,c3,c4):
        super().__init__()
        # 线路1:1 x 1卷积层,激活函数是RELU,padding是same 
        self.p1_1 = tf.keras.layers.Conv2D(c1,kernel_size=1,activation='relu',padding='same')
        # 线路2,1 x 1卷积层后接3 x 3卷积层,激活函数是RELU,padding是same 
        self.p2_1 = tf.keras.layers.Conv2D(c2[0],kernel_size=1,activation='relu',padding='same')
        self.p2_2 = tf.keras.layers.Conv2D(c2[1],kernel_size=3,activation='relu',padding='same')
        # 线路3,1 x 1卷积层后接5 x 5卷积层,激活函数是RELU,padding是same 
        self.p3_1 = tf.keras.layers.Conv2D(c3[0],kernel_size=1,activation='relu',padding='same')
        self.p3_2 = tf.keras.layers.Conv2D(c3[1],kernel_size=3,activation='relu',padding='same')
        # 线路4,3 x 3最⼤池化层后接1 x 1卷积层,激活函数是RELU,padding是same 
        self.p4_1 = tf.keras.layers.MaxPool2D(pool_size=3,padding='same',strides=1)
        self.p4_2 = tf.keras.layers.Conv2D(c4,kernel_size=1,activation='relu',padding='same')
    
    # 完成前向传播过程
    def call(self,x):
        # 线路1 
        p1 = self.p1_1(x)
        # 线路2 
        p2 = self.p2_2(self.p2_1(x))
        # 线路3 
        p3 = self.p3_2(self.p3_1(x))
        # 线路4 
        p4 = self.p4_2(self.p4_1(x))
        # 在通道维上concat输出 
        outputs = tf.concat([p1,p2,p3,p4],axis=-1)
        return outputs
3.1.3 定义 GoogLeNet 模型

接下来,我们将定义 GoogLeNet 整体结构,利用上面定义的 Inception 模块。

方法1:

def create_googlenet_model(input_shape=(224, 224, 3), num_classes=1000):  
    inputs = layers.Input(shape=input_shape)  

    # 卷积层  
    x = layers.Conv2D(64, (7, 7), strides=(2, 2), padding='same', activation='relu')(inputs)  
    x = layers.MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)  
    x = layers.Conv2D(64, (1, 1), padding='same', activation='relu')(x)  
    x = layers.Conv2D(192, (3, 3), padding='same', activation='relu')(x)  
    x = layers.MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)  

    # Inception 模块  
    x = inception_module(x, filters=[64, 128, 128, 32, 32, 32])  
    x = inception_module(x, filters=[128, 192, 192, 96, 96, 64])  
    x = layers.MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)  

    x = inception_module(x, filters=[192, 208, 192, 48, 64, 64])  
    x = inception_module(x, filters=[160, 224, 224, 64, 64, 64])  
    x = inception_module(x, filters=[128, 256, 256, 64, 64, 64])  
    x = layers.MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)  

    x = inception_module(x, filters=[256, 256, 256, 64, 64, 64])  
    x = inception_module(x, filters=[384, 384, 384, 64, 64, 64])  

    # 上采样和分类  
    x = layers.AveragePooling2D((7, 7))(x)  
    x = layers.Flatten()(x)  
    x = layers.Dense(num_classes, activation='softmax')(x)  

    model = models.Model(inputs=inputs, outputs=x)  
    return model

方法2:

# 辅助分类器
def aux_classifier(x,filter_size):
    #x:输⼊数据,filter_size:卷积层卷积核个数,全连接层神经元个数
    # 池化层
    x = tf.keras.layers.AveragePooling2D(pool_size=5,strides=3,padding='same')(x)
    # 1x1 卷积层
    x = tf.keras.layers.Conv2D(filters=filter_size[0],kernel_size=1,strides=1,padding='valid',activation='relu')(x)
    # 展平
    x = tf.keras.layers.Flatten()(x)
    # 全连接层1
    x = tf.keras.layers.Dense(units=filter_size[1],activation='relu')(x)
    # softmax输出层
    x = tf.keras.layers.Dense(units=10,activation='relu')(x)
    return x

## GoogLeNet 构建¶
# 定义模型的输⼊ 
inputs = tf.keras.Input(shape=(224,223,1),name='input')
# b1 模块
# 卷积层7*7的卷积核,步⻓为2,pad是same,激活函数RELU
x = tf.keras.layers.Conv2D(64,kernel_size=7,strides=2,padding='same',activation='relu')(inputs)
# 最⼤池化:窗⼝⼤⼩为3*3,步⻓为2,pad是same 
x = tf.keras.layers.MaxPool2D(pool_size=3,strides=2,padding='same')(x)

# b2 模块
# 卷积层1*1的卷积核,步⻓为2,pad是same,激活函数RELU 
x = tf.keras.layers.Conv2D(64,kernel_size=1,strides=1,padding='same',activation='relu')(x)
# 卷积层3*3的卷积核,步⻓为2,pad是same,激活函数RELU 
x = tf.keras.layers.Conv2D(192,kernel_size=3,strides=1,padding='same',activation='relu')(x)
# 最⼤池化:窗⼝⼤⼩为3*3,步⻓为2,pad是same 
x = tf.keras.layers.MaxPool2D(pool_size=3,strides=2,padding='same')(x)

# b3 模块
# Inception 
x = Inception(64,(96,128),(16,32),32)(x)
x = Inception(128,(128,192),(32,96),64)(x)
# 最⼤池化:窗⼝⼤⼩为3*3,步⻓为2,pad是same
x = tf.keras.layers.MaxPool2D(pool_size=3,strides=2,padding='same')(x)

# b4 模块
# Inception
x = Inception(192,(96,208),(16,48),64)(x)
# 辅助输出1 
aux_output1 = aux_classifier(x,[128,1024])
x = Inception(160,(112,224),(24,64),64)(x)
x = Inception(128,(128,256),(24,64),64)(x)
x = Inception(112,(144,228),(32,64),64)(x)
# 辅助输出1 
aux_output2 = aux_classifier(x,[128,1024])
x = Inception(256,(160,320),(32,128),128)(x)
x = tf.keras.layers.MaxPool2D(pool_size=3,strides=2,padding='same')(x)

# b5 模块
x = Inception(256,(160,320),(32,128),128)(x)
x = Inception(384,(192,384),(48,128),128)(x)
# GAP 
x = tf.keras.layers.GlobalAvgPool2D()(x)
# 输出层
output = tf.keras.layers.Dense(10,activation='softmax')(x)

# 使⽤Model来创建模型,指明输⼊和输出
model = tf.keras.Model(inputs=inputs,outputs=[output,aux_output1,aux_output2])
3.1.4 加载数据集

与其他神经网络类似,我们使用 `tf.keras.preprocessing.image_dataset_from_directory` 加载训练和验证数据集:

train_dataset = tf.keras.preprocessing.image_dataset_from_directory(  
    'dataset/train',  
    image_size=(224, 224),  
    batch_size=32  
)  

val_dataset = tf.keras.preprocessing.image_dataset_from_directory(  
    'dataset/val',  
    image_size=(224, 224),  
    batch_size=32  
)
3.1.5 创建并编译 GoogLeNet 模型
# 创建 GoogLeNet 模型  
googlenet_model = create_googlenet_model(num_classes=1000)  

# 编译模型  
googlenet_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])  

# 打印模型摘要  
googlenet_model.summary()
3.1.6 训练模型
# 训练模型  
history = googlenet_model.fit(train_dataset, validation_data=val_dataset, epochs=10)
3.1.7 评估模型
# 评估模型  
loss, accuracy = googlenet_model.evaluate(val_dataset)  
print(f"Validation accuracy: {accuracy * 100:.2f}%")
3.1.8 可视化训练过程(可选)`
import matplotlib.pyplot as plt  

# 绘制训练和验证的准确率和损失  
plt.figure(figsize=(12, 4))  

# 准确率  
plt.subplot(1, 2, 1)  
plt.plot(history.history['accuracy'], label='Train Accuracy')  
plt.plot(history.history['val_accuracy'], label='Val Accuracy')  
plt.title('Accuracy')  
plt.xlabel('Epoch')  
plt.ylabel('Accuracy')  
plt.legend()  

# 损失  
plt.subplot(1, 2, 2)  
plt.plot(history.history['loss'], label='Train Loss')  
plt.plot(history.history['val_loss'], label='Val Loss')  
plt.title('Loss')  
plt.xlabel('Epoch')  
plt.ylabel('Loss')  
plt.legend()  

plt.show()

        以上代码展示了如何在 TensorFlow 中实现和训练 GoogLeNet 模型。在这里,我们定义了 Inception 模块并将其用于构建整合的 GoogLeNet 架构。如果希望使用预训练的 GoogLeNet 模型,请考虑使用更现代的 Inception 版本,如 InceptionV3。

3.2  GoogLeNet(Inception V3)

        以下是完整的代码示例,展示如何使用 `tensorflow.keras.applications.InceptionV3` 进行图像分类任务。该示例将包括数据准备、模型构建、训练以及评估步骤。

import tensorflow as tf  
from tensorflow.keras.applications import InceptionV3  
from tensorflow.keras.preprocessing.image import ImageDataGenerator  
from tensorflow.keras import layers, models  

# 设定超参数  
img_height, img_width = 299, 299  
batch_size = 32  
num_classes = 10  # 替换为你的分类数量  
epochs = 10  

# 加载 InceptionV3 模型,不包含顶层(即全连接层)  
base_model = InceptionV3(weights='imagenet', include_top=False, input_shape=(img_height, img_width, 3))  

# 冻结基础模型的层  
for layer in base_model.layers:  
    layer.trainable = False  

# 添加自定义分类头  
model = models.Sequential()  
model.add(base_model)  
model.add(layers.GlobalAveragePooling2D())  
model.add(layers.Dense(256, activation='relu'))  
model.add(layers.Dropout(0.5))  # 添加 Dropout 防止过拟合  
model.add(layers.Dense(num_classes, activation='softmax'))  # num_classes 是你的分类数  

# 编译模型  
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])  

# 数据准备  
train_datagen = ImageDataGenerator(  
    rescale=1.0/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'  
)  

# 替换为你的训练数据目录  
train_generator = train_datagen.flow_from_directory(  
    'path_to_train_directory',  # 确保此目录包含子文件夹,每个子文件夹代表一个类别  
    target_size=(img_height, img_width),  
    batch_size=batch_size,  
    class_mode='categorical'  
)  

# 训练模型  
model.fit(train_generator, epochs=epochs)  

# 表示可以使用验证数据集来评估模型  
# 如果有验证集,可以使用类似下面的代码进行评估  

# 评估模型  
val_datagen = ImageDataGenerator(rescale=1.0/255)  
val_generator = val_datagen.flow_from_directory(  
    'path_to_validation_directory',  # 替换为你的验证数据目录  
    target_size=(img_height, img_width),  
    batch_size=batch_size,  
    class_mode='categorical'  
)  

# 评估  
loss, accuracy = model.evaluate(val_generator)  
print(f"Validation accuracy: {accuracy * 100:.2f}%")

说明

        导入库: 引入所需的 TensorFlow 和 Keras 模块。
        超参数设定: 设置图像高度和宽度、批量大小和训练轮数等超参数。
        加载模型: 加载预训练的 InceptionV3 模型,并去掉顶部的全连接层。
        模型构建: 在基础模型上添加自定义的全局平均池化层、两个 Dense 层和一个 Dropout 层,以适应特定的分类任务。
        编译模型: 使用 Adam 优化器和 categorical_crossentropy 损失函数编译模型。
        数据准备: 使用 `ImageDataGenerator` 创建训练和验证数据生成器,进行数据预处理和增强。
        训练模型: 通过调用 `fit` 方法以训练模型。
        评估模型: 使用验证数据集评估模型的准确率。

4. 主要贡献

        参数高效:通过 Inception 模块进行并行特征学习,使得 GoogLeNet 能够在大规模数据集上达到较高的性能,而不需要大量的参数。

        创新的网络设计:GoogLeNet 引入了模块化的设计理念,为后续网络架构(如 Inception V2、Inception V3 和 GoogLeNet V2 等)奠定了基础。

        准确性:在 ImageNet 图像分类任务中,GoogLeNet 取得了较高的准确性,标志着深度学习领域的一项重要突破。

5. 应用

        GoogLeNet 被广泛应用于图像分类、目标检测、图像分割等计算机视觉任务中。它的设计理念也启发了其他深度学习模型的研发。

6. 总结

        GoogLeNet 是一款具有里程碑意义的深度学习卷积神经网络,通过创新的 Inception 模块提升了模型在图像分类中的性能。其设计思想和结构在深度学习的发展过程中产生了深远的影响,促进了神经网络在计算机视觉任务中的应用和普及。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐