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)
相关推荐
yy_xzz16 小时前
【OpenCV + VS】C++实现动态下雪特效
c++·人工智能·opencv
木头左16 小时前
自适应门控循环单元GRU-O与标准LSTM在量化交易策略中的性能对比实验
深度学习·gru·lstm
扬道财经16 小时前
从百度分析师到GEO理论奠基人,罗小军探索AI搜索营销新路径
人工智能·百度·dubbo
哥布林学者17 小时前
吴恩达深度学习课程二: 改善深层神经网络 第三周:超参数调整,批量标准化和编程框架(三)多值预测与多分类
深度学习·ai
xuehaisj17 小时前
菠萝蜜果实目标检测_yolo11-C3k2-ConvFormer改进
人工智能·目标检测·目标跟踪
月下倩影时17 小时前
视觉学习篇——模型推理部署:从“炼丹”到“上桌”
人工智能·深度学习·学习
夕小瑶17 小时前
从无形IP到AI万象,安谋科技Arm China“周易”X3 NPU 发布!
人工智能·科技·tcp/ip
陈天伟教授17 小时前
人工智能技术-人工智能与科学-03 预测分子性能
人工智能
【建模先锋】17 小时前
基于密集连接的DenseNet故障诊断模型:实现高鲁棒性的深度故障诊断
人工智能·cnn·信号处理·故障诊断·轴承故障诊断·西储大学数据集
余俊晖17 小时前
英伟达开源多模态视觉语言模型-Nemotron Nano V2 VL模型架构、训练方法、训练数据
人工智能·算法·语言模型·自然语言处理·多模态