12.3深度学习_感受野、案例

6.感受野

6.1 理解感受野

字面意思是感受的视野范围

​ 如果堆叠3个3 x 3的卷积层,并且保持滑动窗口步长为1,其感受野就是7×7的了, 这跟一个使用7x7卷积核的结果是一样的,那为什么非要堆叠3个小卷积呢?

6.2 感受野的作用

​ 假设输入大小都是h × w × C,并且都使用C个卷积核(得到C个特征图),可以来计算 一下其各自所需参数

​ 很明显,堆叠小的卷积核所需的参数更少一些,并且卷积过程越多,特征提取也会越细致,加入的非线性变换也随着增多,还不会增大权重参数个数,这就是感受野的基本出发点,用小的卷积核来完成体特征提取操作。

8.卷积神经网络案例

8.1 模型结构

网络结构如下:

  1. 输入形状: 32x32
  2. 第一个卷积层输入 3 个 Channel, 输出 6 个 Channel, Kernel Size 为: 3x3
  3. 第一个池化层输入 30x30, 输出 15x15, Kernel Size 为: 2x2, Stride 为: 2
  4. 第二个卷积层输入 6 个 Channel, 输出 16 个 Channel, Kernel Size 为 3x3
  5. 第二个池化层输入 13x13, 输出 6x6, Kernel Size 为: 2x2, Stride 为: 2
  6. 第一个全连接层输入 576 维, 输出 120 维
  7. 第二个全连接层输入 120 维, 输出 84 维
  8. 最后的输出层输入 84 维, 输出 10 维

我们在每个卷积计算之后应用 relu 激活函数来给网络增加非线性因素。

8.2 网络模型定义

.\model\image_classification.py

python 复制代码
import torch
import torch.nn as nn


class ImageClassification(nn.Module):
    def __init__(self):
        super(ImageClassification, self).__init__()
        # 这是一层卷积层
        self.layer1 = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Dropout(0.25),
        )

        self.layer2 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=128, kernel_size=3, stride=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Dropout(0.25),
        )

        self.linear1 = nn.Sequential(
            nn.Linear(128 * 6 * 6, 2048), nn.ReLU(), nn.Dropout(0.5)
        )

        self.linear2 = nn.Sequential(nn.Linear(2048, 1024), nn.ReLU(), nn.Dropout(0.5))

        self.out = nn.Linear(1024, 10)

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = x.reshape(x.size(0), -1)
        x = self.linear1(x)
        x = self.linear2(x)
        return self.out(x)

8.3 用到的模块

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision.datasets import CIFAR10
from torchvision.transforms import Compose, ToTensor
from torch.utils.data import DataLoader
import os
import time

# 从modele目录导入模型
from model.image_classification import ImageClassification

8.4 CIFAR10数据源

python 复制代码
def test001():
    dir = os.path.dirname(__file__)
    # 加载数据集
    train = CIFAR10(
        root=os.path.join(dir, "data"),
        train=True,
        download=True,
        transform=Compose([ToTensor()]),
    )

    vaild = CIFAR10(
        root=os.path.join(dir, "data"),
        train=False,
        download=True,
        transform=Compose([ToTensor()]),
    )

    # 观察一下数据集信息
    print("训练数据集数量:", train.__len__())
    # 观察一下数据集分类情况
    print("训练数据集分类情况:", train.class_to_idx)

    train_loader = DataLoader(train, batch_size=128, shuffle=True)
    vaild_loader = DataLoader(vaild, batch_size=128, shuffle=True)
    for i, (x, y) in enumerate(train_loader):
        print(i, x.shape, y.shape)

8.5 模型训练及保存

python 复制代码
def train():
    dir = os.path.dirname(__file__)
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    # 加载数据集
    train = CIFAR10(
        root=os.path.join(dir, "data"),
        train=True,
        download=True,
        transform=transform,
    )
    # 导入模型
    model = ImageClassification()
    model.to(device)
    # 定义i模型训练的超参数
    epochs = 80
    lr = 1e-3
    batch_size = 256
    loss_history = []
    # 构建训练用的损失函数及优化器
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=lr)
    for i, epoch in enumerate(range(epochs)):
        # 构建训练数据批次
        train_loader = DataLoader(train, batch_size=batch_size, shuffle=True)
        # 记录样本数量
        train_num = 0
        # 记录总的损失值:用于计算平均损失
        total_loss = 0.0
        # 记录正确记录数
        correct = 0
        # 记录训练开始时间
        start = time.time()
        # 开始使用批次数据进行训练
        for x, y in train_loader:
            # 更改模型训练设备
            x = x.to(device)
            y = y.to(device)
            # 送入模型
            output = model(x)
            # 计算损失
            loss = criterion(output, y)
            # 梯度清零
            optimizer.zero_grad()
            # 反向传播
            loss.backward()
            # 更新参数
            optimizer.step()
            # 更新训练过程的数据
            train_num += len(y)
            total_loss += loss.item() * len(y)
            correct += output.argmax(1).eq(y).sum().item()

        print(
            "epoc:%d  loss:%.3f accuracy:%.3f time:%.3f"
            % (i + 1, total_loss / train_num, correct / train_num, time.time() - start)
        )
        loss_history.append(total_loss / train_num)
        # 更新图形
        update_plot(loss_history)
        # 训练完成之后,保存模型
        torch.save(model.state_dict(), os.path.join(dir, "model.pth"))
        print("模型保存成功:", i)

8.6 模型加载及验证

python 复制代码
# 测试集评估
def vaild():
    dir = os.path.dirname(__file__)
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    # 定义超参数
    batch_size = 100
    # 定义测试记录数据
    vaild_num = 0
    total_correct = 0

    vaild_data = CIFAR10(
        root=os.path.join(dir, "data"),
        train=False,
        download=False,
        transform=transform,
    )
    # 构建测评数据集批次
    vaild_loader = DataLoader(vaild_data, batch_size=batch_size, shuffle=False)
    model = ImageClassification()
    # 加载模型参数
    model.load_state_dict(torch.load(os.path.join(dir, "model.pth")))
    # 切换为验证模式
    model.to(device)
    model.eval()
    for x, y in vaild_loader:
        x = x.to(device)
        y = y.to(device)
        output = model(x)
        total_correct += output.argmax(1).eq(y).sum().item()
        vaild_num += len(y)

    print("测试集正确率:%.3f" % (total_correct / vaild_num))

我们可以从以下几个方面来调整网络:

  1. 增加卷积核输出通道数
  2. 增加全连接层的参数量
  3. 调整学习率
  4. 调整优化方法
  5. 修改激活函数
  6. 进行数据增强,等等

8.7 数据增强

python 复制代码
data_transforms = {
    'train': transforms.Compose([transforms.RandomRotation(45),#随机旋转,-45到45度之间随机选
        transforms.CenterCrop(224),#从中心开始裁剪
        transforms.RandomHorizontalFlip(p=0.5),#随机水平翻转 选择一个概率概率
        transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转
        transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
        transforms.RandomGrayscale(p=0.025),#概率转换成灰度率,3通道就是R=G=B
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#均值,标准差
    ]),
    'valid': transforms.Compose([transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}
python 复制代码
from torchvision import transforms
from PIL import Image

# 定义图像预处理步骤
preprocess = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

# 打开图像
img = Image.open("path_to_image.jpg")

# 应用预处理步骤
img_tensor = preprocess(img)

8.8 实时渲染训练效果

python 复制代码
# 更新图形的函数
def update_plot(loss_history):
    plt.cla()  # 清除之前的图形
    plt.plot(loss_history, marker="o", color="green", linestyle="-")  # 绘制损失率曲线
    plt.xlabel("Epoch")
    plt.ylabel("Loss")
    plt.title("Training Loss")
    plt.grid(True)
    plt.pause(0.001)  # 暂停一段时间以便更新图形

	# 开始训练模型并动态显示损失率变化
    plt.ion()  # 打开交互模式
    train()
    plt.ioff()  # 关闭交互模式
    plt.show()
    
#在训练的时候实时更新数据
loss_history = []
loss_history.append(total_loss / train_num)
# 更新图形
update_plot(loss_history)
相关推荐
audyxiao0013 分钟前
AI一周重要会议和活动概览
人工智能·计算机视觉·数据挖掘·多模态
Jeremy_lf21 分钟前
【生成模型之三】ControlNet & Latent Diffusion Models论文详解
人工智能·深度学习·stable diffusion·aigc·扩散模型
桃花键神1 小时前
AI可信论坛亮点:合合信息分享视觉内容安全技术前沿
人工智能
野蛮的大西瓜1 小时前
开源呼叫中心中,如何将ASR与IVR菜单结合,实现动态的IVR交互
人工智能·机器人·自动化·音视频·信息与通信
CountingStars6192 小时前
目标检测常用评估指标(metrics)
人工智能·目标检测·目标跟踪
tangjunjun-owen2 小时前
第四节:GLM-4v-9b模型的tokenizer源码解读
人工智能·glm-4v-9b·多模态大模型教程
冰蓝蓝2 小时前
深度学习中的注意力机制:解锁智能模型的新视角
人工智能·深度学习
橙子小哥的代码世界2 小时前
【计算机视觉基础CV-图像分类】01- 从历史源头到深度时代:一文读懂计算机视觉的进化脉络、核心任务与产业蓝图
人工智能·计算机视觉
新加坡内哥谈技术3 小时前
苏黎世联邦理工学院与加州大学伯克利分校推出MaxInfoRL:平衡内在与外在探索的全新强化学习框架
大数据·人工智能·语言模型
fanstuck3 小时前
Prompt提示工程上手指南(七)Prompt编写实战-基于智能客服问答系统下的Prompt编写
人工智能·数据挖掘·openai