Datawhale AI 夏令营 Task02 学习笔记

Datawhale AI 夏令营 Task02 学习笔记

part1 什么是深度学习

神经元模型是神经网络的基本单元,用于模拟生物神经元的功能。最常用的神经元模型是感知机(Perceptron)和其改进版(如多层感知机,MLP)。以下是神经元模型的详细描述:

感知机模型

感知机是最简单的神经元模型,主要用于二分类问题。其基本结构包括输入、加权求和、激活函数和输出。

  1. 输入(Input):感知机接收多个输入信号,这些信号可以是特征向量的元素,记作 ( x_1, x_2, ..., x_n )。

  2. 权重(Weights):每个输入信号都有一个相应的权重,记作 ( w_1, w_2, ..., w_n )。这些权重决定了输入信号对输出结果的影响。

  3. 加权求和(Weighted Sum):输入信号和权重相乘后求和,再加上一个偏置(bias)项 ( b )。公式如下:

    \[z = \sum_{i=1}^n w_i x_i + b \]

  4. 激活函数(Activation Function):将加权求和的结果 ( z ) 通过激活函数进行非线性变换,得到输出结果 ( y )。常见的激活函数包括:

    • 阶跃函数(Step Function):二分类问题中常用

      \[y = \begin{cases} 1 & \text{if } z \geq 0 \\ 0 & \text{if } z < 0 \end{cases} \]

    • Sigmoid 函数:常用于二分类问题

      \[\sigma(z) = \frac{1}{1 + e^{-z}} \]

    • ReLU(Rectified Linear Unit):常用于深层神经网络

      \[\text{ReLU}(z) = \max(0, z) \]

多层感知机(MLP)

感知机模型的改进版是多层感知机,它包含一个或多个隐藏层,每层包含多个神经元。多层感知机可以处理更复杂的任务。

  1. 输入层(Input Layer):接收特征向量的元素。

  2. 隐藏层(Hidden Layers):包含多个神经元,每个神经元都像一个感知机,接收前一层的输出作为输入,进行加权求和和激活函数的变换。隐藏层的数量和每层神经元的数量可以根据具体任务进行调整。

  3. 输出层(Output Layer):最后一层,输出最终的预测结果。输出层的神经元数量取决于具体的任务,比如二分类问题中输出层通常只有一个神经元,多分类问题中输出层的神经元数量等于类别的数量。

深层神经网络(DNN)

深层神经网络是包含多个隐藏层的多层感知机,通过更多的层次来学习数据的复杂特征。常见的深层神经网络包括:

  • 卷积神经网络(CNN):用于图像处理,包含卷积层、池化层和全连接层。
  • 递归神经网络(RNN):用于序列数据处理,包含循环结构。
  • 生成对抗网络(GAN):包含生成器和判别器,通过对抗训练生成高质量数据。
  • Transformer 模型:通过注意力机制处理序列数据,广泛应用于自然语言处理。

训练过程

神经元模型通过训练来优化权重和偏置,使网络在特定任务上的性能达到最优。训练过程包括以下几个步骤:

  1. 前向传播(Forward Propagation):输入数据通过网络层层传递,计算输出结果。

  2. 损失函数(Loss Function):计算预测结果与真实标签之间的差距,常用的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。

  3. 反向传播(Backward Propagation):通过梯度下降算法计算损失函数对权重的梯度,更新权重和偏置,以减小损失函数的值。

  4. 迭代训练:通过多次迭代(Epochs)不断优化网络参数,直到损失函数收敛或达到预定的训练次数。

综上所述,神经元模型是深度学习的基础,通过层层堆叠和复杂的训练过程,神经网络可以解决各种复杂的任务,如图像识别、语音识别和自然语言处理等。

Part2 深度学习是如何训练的?

深度学习网络的训练过程主要通过梯度下降算法来实现。梯度下降是一种优化算法,用于最小化损失函数,调整模型的权重和偏置。以下是训练过程的详细步骤以及相应的 PyTorch 代码示例:

训练过程步骤

  1. 前向传播(Forward Propagation)

    • 输入数据通过神经网络层层传递,计算每一层的输出,直到得到最终的预测结果。
  2. 计算损失(Compute Loss)

    • 使用损失函数计算预测结果与真实标签之间的差距。常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。
  3. 反向传播(Backward Propagation)

    • 通过链式法则(Chain Rule)计算损失函数对每个参数的梯度。PyTorch 提供了自动求导功能,无需手动计算梯度。
  4. 参数更新(Parameter Update)

    • 使用梯度下降算法根据计算出的梯度更新网络的权重和偏置。常见的梯度下降变种包括随机梯度下降(SGD)、动量梯度下降(Momentum)、Adam 等。

PyTorch 代码示例

下面是一个简单的 PyTorch 代码示例,演示如何使用梯度下降算法训练一个深度学习网络。

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import DataLoader, TensorDataset

# 生成一些简单的示例数据
x = torch.randn(100, 10)  # 100个样本,每个样本10个特征
y = torch.randint(0, 2, (100,))  # 100个样本的标签,二分类问题

# 创建数据集和数据加载器
dataset = TensorDataset(x, y)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

# 定义一个简单的神经网络
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(10, 50)
        self.fc2 = nn.Linear(50, 20)
        self.fc3 = nn.Linear(20, 2)
    
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 实例化神经网络、损失函数和优化器
model = SimpleNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练过程
num_epochs = 20
for epoch in range(num_epochs):
    for batch_x, batch_y in dataloader:
        # 前向传播
        outputs = model(batch_x)
        loss = criterion(outputs, batch_y)
        
        # 反向传播和优化
        optimizer.zero_grad()  # 清除前一次的梯度
        loss.backward()  # 计算梯度
        optimizer.step()  # 更新参数
        
    print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

print("Training Finished!")

代码说明

  1. 数据准备

    • 使用 torch.randn 生成随机输入数据,使用 torch.randint 生成随机标签。
    • 使用 TensorDatasetDataLoader 创建数据集和数据加载器。
  2. 定义神经网络

    • 创建一个简单的全连接神经网络 SimpleNN,包含三个线性层和 ReLU 激活函数。
  3. 实例化模型、损失函数和优化器

    • 使用 nn.CrossEntropyLoss 作为损失函数,适用于二分类问题。
    • 使用 optim.SGD 作为优化器,并设置学习率。
  4. 训练过程

    • 迭代进行多个训练周期(epochs)。
    • 在每个周期内,通过数据加载器遍历数据集。
    • 对每个批次数据进行前向传播、计算损失、反向传播和参数更新。
    • 使用 optimizer.zero_grad() 清除前一次的梯度,使用 loss.backward() 计算当前梯度,使用 optimizer.step() 更新参数。

通过上述过程,模型的参数将逐渐优化,使得损失函数的值最小化,从而提高模型在训练数据上的性能。

Part3 深度学习与迁移学习

深度学习

深度学习(Deep Learning)是机器学习的一个子领域,基于人工神经网络,特别是深层神经网络(DNN)的研究和应用。其主要特点和优势包括:

  1. 层次结构:深度学习模型通过多层神经元的堆叠,逐层抽象和提取数据的特征,从而能够处理复杂的模式识别和表示学习问题。

  2. 自动特征提取:深度学习模型能够自动从数据中学习特征,减少了对手工特征工程的依赖。这使得模型能够处理原始数据(如图像、音频、文本)并从中提取有用的信息。

  3. 大数据和强计算能力:深度学习模型通常需要大量的训练数据和强大的计算资源来实现良好的性能。这得益于近年来数据的爆炸式增长和计算资源的进步(如GPU和TPU)。

  4. 应用领域广泛:深度学习在图像识别、语音识别、自然语言处理、自动驾驶、医疗诊断等多个领域取得了显著成果。

迁移学习

迁移学习(Transfer Learning)是一种机器学习方法,利用在一个任务上训练好的模型在另一个相关任务上进行再训练或微调。迁移学习的优势在于能够充分利用已有的知识,减少对新任务的训练数据和计算资源的需求。迁移学习的常见方法包括:

  1. 特征提取(Feature Extraction):使用预训练模型的某些层作为特征提取器,将输入数据转换为高层次的特征表示,然后在这些特征上训练新的模型。

  2. 微调(Fine-Tuning):在预训练模型的基础上,对部分或全部层进行再训练,使其适应新的任务。通常只需要对最后几层进行微调,而保留前几层的预训练权重。

ImageNet

ImageNet 是一个大型视觉数据库,用于图像识别和计算机视觉研究。其主要特点包括:

  1. 大规模数据集:ImageNet 包含超过1400万张标注好的图像,覆盖了多种类别(如动物、物体、场景等),每个类别包含数百至数千张图像。

  2. ImageNet 挑战赛:ImageNet 大规模视觉识别挑战赛(ILSVRC)是计算机视觉领域的重要赛事,推动了图像识别技术的发展。参赛者需要在ImageNet数据集上训练模型并进行评测,比赛结果常用于衡量模型的性能。

  3. 预训练模型:许多深度学习模型(如VGG、ResNet、Inception、MobileNet等)在ImageNet数据集上进行预训练,这些预训练模型广泛用于迁移学习,通过微调应用于其他视觉任务。

结合深度学习和迁移学习的代码示例

下面是一个使用 PyTorch 实现的迁移学习示例,利用在 ImageNet 上预训练的 ResNet 模型,并在自定义数据集上进行微调:

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, models, transforms
from torch.utils.data import DataLoader

# 数据预处理
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

data_dir = 'data/hymenoptera_data'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
                                          data_transforms[x])
                  for x in ['train', 'val']}
dataloaders = {x: DataLoader(image_datasets[x], batch_size=4,
                             shuffle=True, num_workers=4)
               for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
class_names = image_datasets['train'].classes
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# 加载预训练的 ResNet 模型
model_ft = models.resnet18(pretrained=True)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, 2)  # 修改最后的全连接层以适应新任务(如二分类)

model_ft = model_ft.to(device)

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)

# 训练和评估模型
def train_model(model, criterion, optimizer, num_epochs=25):
    for epoch in range(num_epochs):
        print(f'Epoch {epoch}/{num_epochs - 1}')
        print('-' * 10)
        
        for phase in ['train', 'val']:
            if phase == 'train':
                model.train()
            else:
                model.eval()

            running_loss = 0.0
            running_corrects = 0

            for inputs, labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                optimizer.zero_grad()

                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)

                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)

            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() / dataset_sizes[phase]

            print(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')

        print()

    return model

model_ft = train_model(model_ft, criterion, optimizer_ft, num_epochs=25)
print("Training Finished!")

代码说明

  1. 数据预处理

    • 使用 transforms 对训练和验证数据进行预处理,包括裁剪、归一化等操作。
  2. 数据加载

    • 使用 ImageFolder 加载自定义数据集,创建数据加载器 DataLoader
  3. 加载预训练模型

    • 使用 torchvision.models 加载在 ImageNet 上预训练的 ResNet-18 模型,并修改最后的全连接层以适应新的任务。
  4. 定义损失函数和优化器

    • 使用交叉熵损失函数 nn.CrossEntropyLoss 和随机梯度下降优化器 optim.SGD
  5. 训练和评估模型

    • 定义 train_model 函数,在训练和验证阶段分别进行前向传播、损失计算、反向传播和参数更新。

通过上述过程,可以利用 ImageNet 上预训练的模型快速构建和微调适应特定任务的深度学习模型,从而显著提升模型的训练效率和性能。

Part4 三种常用图像分类模型

AlexNet

AlexNet是由Alex Krizhevsky等人在2012年提出的卷积神经网络,标志着深度学习在计算机视觉领域的重大突破。AlexNet在2012年的ImageNet大规模视觉识别挑战赛(ILSVRC)中取得了显著的成功,其结构特点和贡献包括:

  1. 结构特点

    • 卷积层:包含5个卷积层,使用了ReLU激活函数来增加非线性。
    • 池化层:在卷积层之后,使用最大池化(Max Pooling)来减少特征图的尺寸。
    • 全连接层:包含3个全连接层,用于分类任务的最终输出。
    • Dropout:为了防止过拟合,在全连接层之间使用了Dropout正则化。
  2. 贡献

    • ReLU激活函数:相对于传统的Sigmoid或Tanh激活函数,ReLU加速了收敛速度。
    • GPU并行计算:AlexNet利用两个GPU并行训练,显著提高了计算效率。
    • 数据增强:通过数据增强(如随机裁剪、水平翻转)扩充训练数据,进一步提升模型的泛化能力。

ResNet

ResNet(Residual Network)是由Kaiming He等人在2015年提出的深度卷积神经网络,主要解决深层网络训练中的退化问题。ResNet在ILSVRC 2015中取得了优异成绩,其结构特点和贡献包括:

  1. 结构特点

    • 残差块(Residual Block):引入了跳跃连接(Skip Connections),即通过添加恒等映射(Identity Mapping)来构建残差块,使得梯度能够更容易地传递,缓解了梯度消失和梯度爆炸问题。
    • 层数:ResNet可以构建非常深的网络,最初的ResNet-50、ResNet-101、ResNet-152分别包含50、101、152层。
  2. 贡献

    • 深度模型训练:通过残差块,ResNet成功训练了更深的神经网络,极大地提高了模型的表达能力。
    • 广泛应用:ResNet的残差思想被广泛应用于其他深度学习模型,如目标检测、语义分割等任务。

EfficientNet

EfficientNet是由Mingxing Tan和Quoc V. Le在2019年提出的一种高效卷积神经网络架构,通过联合优化网络宽度、深度和分辨率,取得了优异的性能。其结构特点和贡献包括:

  1. 结构特点

    • 复合缩放(Compound Scaling):通过一个复合系数均衡地缩放网络的宽度、深度和分辨率,实现了更高效的模型设计。
    • 基础网络(EfficientNet-B0):基于神经架构搜索(NAS)找到的基础网络EfficientNet-B0,然后通过复合缩放策略生成一系列EfficientNet模型(如EfficientNet-B1至EfficientNet-B7)。
  2. 贡献

    • 高效性能:EfficientNet在多个图像分类任务上达到了更高的准确率,同时显著降低了计算量和参数量。
    • 模型缩放:提供了一种系统化的方法来扩展和设计高效的卷积神经网络,在各种计算资源和准确率需求下都能表现出色。

比较和总结

  1. AlexNet:作为卷积神经网络发展的里程碑,开启了深度学习在计算机视觉领域的广泛应用,但由于层数较少和较大的参数量,在面对更复杂的任务时存在局限性。

  2. ResNet:通过引入残差块解决了深层网络的训练问题,使得构建超深层网络成为可能,极大地提高了模型的性能和应用广泛性。

  3. EfficientNet:通过复合缩放策略优化了网络的宽度、深度和分辨率,达到了更高的效率和准确率,适应了多种计算资源和应用场景的需求。

PyTorch实现示例

以下是如何使用PyTorch加载和应用预训练的AlexNet、ResNet和EfficientNet模型的示例代码:

import torch
import torchvision.models as models

# 加载预训练的AlexNet
alexnet = models.alexnet(pretrained=True)
print(alexnet)

# 加载预训练的ResNet-50
resnet50 = models.resnet50(pretrained=True)
print(resnet50)

# 加载预训练的EfficientNet-B0
efficientnet_b0 = models.efficientnet_b0(pretrained=True)
print(efficientnet_b0)

# 示例:如何在自定义数据集上进行微调
# 以ResNet-50为例,修改最后的全连接层以适应新的任务(如二分类)

# 获取ResNet-50的输入特征数
num_ftrs = resnet50.fc.in_features

# 修改最后的全连接层,使其输出类别数为2
resnet50.fc = torch.nn.Linear(num_ftrs, 2)

# 将模型移至GPU(如果可用)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
resnet50 = resnet50.to(device)

# 定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(resnet50.parameters(), lr=0.001, momentum=0.9)

# 接下来,可以使用上述代码中的训练过程对模型进行微调

上述代码展示了如何加载预训练模型并修改其结构以适应新的任务。通过迁移学习,可以有效利用这些预训练模型的强大特征提取能力,从而在新的数据集上快速构建高性能模型。

posted @ 2024-07-17 20:53  zfz04  阅读(68)  评论(0)    收藏  举报