动手学深度学习V2每日笔记(使用块的网络VGG)

news2025/1/24 4:51:39

本文主要参考沐神的视频教程
https://www.bilibili.com/video/BV1Ao4y117Pd/spm_id_from=autoNext&vd_source=c7bfc6ce0ea0cbe43aa288ba2713e56d
文档教程 https://zh-v2.d2l.ai/

本文的主要内容对沐神提供的代码中个人不太理解的内容进行笔记记录,内容不会特别严谨仅供参考。

1.函数目录

1.1 python

python位置
可变参数解包3.1

2. VGG

  • AleNet比LeNet更深更大来得到更好的精度
  • 能不能更深和更大呢?
  • 选项
    • 更多的全连接层(太贵)
    • 更多的卷积层
    • 将卷积层组合成块

2.1 VGG块

  • 深VS宽?
    • 5x5卷积
    • 3x3卷积
    • 深但窄效果更好
  • VGG块
    • 3x3卷积(填充为1)(n层,m通道)
    • 2x2最大池化层(步幅2)
      在这里插入图片描述

2.2 VGG架构

  • 多个VGG块后面接全连接层
  • 不同次数的重复块得到不同的架构VGG-16、VGG-19
    在这里插入图片描述
    从AlexNet到VGG,它们本质上都是块设计。

3 代码实现

3.1 VGG块

3.1.1 可变参数解包

  1. 函数定义时使用 *
    当在函数定义中使用 * 时,表示函数可以接受任意数量的位置参数,并将这些参数存储为一个元组。例如:
def foo(*args):
    for arg in args:
        print(arg)

foo(1, 2, 3)  # Output: 1 2 3
  1. 函数调用时使用 *
    在函数调用时使用 * 可以将一个可迭代对象解包为单独的参数传递给函数。例如:
def foo(a, b, c):
    print(a, b, c)

values = (1, 2, 3)
foo(*values)  # Output: 1 2 3
values = [1, 2, 3]
foo(*values)  # Output: 1 2 3

*values 将列表 values 解包为三个单独的参数传递给函数 foo。

def vgg_block(num_convs, in_channels, out_channels):
    layers = []
    for _ in range(num_convs):
        layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3,padding=1))
        layers.append(nn.ReLU())
        in_channels = out_channels
    layers.append(nn.MaxPool2d(kernel_size=2, stride=2))
    return nn.Sequential(*layers)

3.2 VGG网络

原始VGG网络有5个卷积块,其中前两个块各有一个卷积层,后三个块各包含两个卷积层。 第一个模块有64个输出通道,每个后续模块将输出通道数量翻倍,直到该数字达到512。由于该网络使用8个卷积层和3个全连接层,因此它通常被称为VGG-11。

import torch
from torch import nn

def vgg_block(num_convs, in_channels, out_channels):
    layers = []
    for _ in range(num_convs):
        layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3,padding=1))
        layers.append(nn.ReLU())
        in_channels = out_channels
    layers.append(nn.MaxPool2d(kernel_size=2, stride=2))
    return nn.Sequential(*layers)

conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
def vgg(conv_arch):
    conv_blks = []
    in_channels = 1
    for (num_convs, out_channels) in conv_arch:
        conv_blks.append(vgg_block(num_convs, in_channels, out_channels))
        in_channels = out_channels

    return nn.Sequential(
        *conv_blks, nn.Flatten(),
        nn.Linear(out_channels*7*7, 4096), nn.ReLU(), nn.Dropout(p=0.5),
        nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(p=0.5),
        nn.Linear(4096, 10)
    )

# net = vgg(conv_arch)
# X = torch.rand((1,1,224,224), dtype=torch.float32)
# for layer in net:
#     X = layer(X)
#     print(layer.__class__.__name__, 'output shape:\t',X.shape)

3.3 训练

import torch
from torch import nn

import model
import tools
from model import vgg
from d2l import torch as d2l
import pandas as pd
from tools import *

if __name__ == "__main__":
    batch_size = 128
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size,resize=224)
    conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
    ratio = 4
    small_conv_arch = [(pair[0], pair[1]//ratio) for  pair in conv_arch]
    net = vgg(small_conv_arch)
    lr, num_epochs = 0.05, 10
    train_process = train_ch6(net,train_iter,test_iter,num_epochs,lr,tools.try_gpu())
    tools.matplot_acc_loss(train_process)

tools模块

import pandas as pd
import torch
import matplotlib.pyplot as plt
from torch import nn
import time
import numpy as np

class Timer:  #@save
    """记录多次运行时间"""
    def __init__(self):
        self.times = []
        self.start()

    def start(self):
        """启动计时器"""
        self.tik = time.time()

    def stop(self):
        """停止计时器并将时间记录在列表中"""
        self.times.append(time.time() - self.tik)
        return self.times[-1]

    def avg(self):
        """返回平均时间"""
        return sum(self.times) / len(self.times)

    def sum(self):
        """返回时间总和"""
        return sum(self.times)

    def cumsum(self):
        """返回累计时间"""
        return np.array(self.times).cumsum().tolist()


argmax = lambda x, *args, **kwargs: x.argmax(*args, **kwargs) #返回最大值的索引下标
astype = lambda x, *args, **kwargs: x.type(*args, **kwargs)  # 转换数据类型
reduce_sum = lambda x, *args, **kwargs: x.sum(*args, **kwargs)  # 求和

# 对多个变量累加
class Accumulator:
    """For accumulating sums over `n` variables."""

    def __init__(self, n):
        """Defined in :numref:`sec_utils`"""
        self.data = [0.0] * n

    def add(self, *args):
        self.data = [a + float(b) for a, b in zip(self.data, args)]

    def reset(self):
        self.data = [0.0] * len(self.data)

    def __getitem__(self, idx):
        return self.data[idx]

# 计算正确预测的数量
def accuracy(y_hat, y):
    """Compute the number of correct predictions.
    Defined in :numref:`sec_utils`"""
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        y_hat = argmax(y_hat, axis=1)
    cmp = astype(y_hat, y.dtype) == y
    return float(reduce_sum(astype(cmp, y.dtype)))

# 单轮训练
def train_epoch(net, train_iter, loss, trainer):
    if isinstance(net, nn.Module):
        net.train()
    metric_train = Accumulator(3)
    for X, y in train_iter:
        y_hat = net(X)
        l = loss(y_hat, y)
        if isinstance(trainer, torch.optim.Optimizer):
            trainer.zero_grad()
            l.mean().backward()
            trainer.step()
        else:
            l.sum().backward()
            trainer(X.shape[0])
        metric_train.add(float(l.sum()), accuracy(y_hat, y), y.numel())
    #返回训练损失和训练精度
    return metric_train[0]/metric_train[2], metric_train[1]/metric_train[2]

# 单轮训练
def train_epoch_gpu(net, train_iter, loss, trainer,device):
    if isinstance(net, nn.Module):
        net.train()
    metric_train = Accumulator(3)
    for i, (X, y) in enumerate(train_iter):
        X, y = X.to(device), y.to(device)
        y_hat = net(X)
        l = loss(y_hat, y)
        if isinstance(trainer, torch.optim.Optimizer):
            trainer.zero_grad()
            l.backward()
            trainer.step()
        else:
            l.sum().backward()
            trainer(X.shape[0])
        metric_train.add(l * X.shape[0], accuracy(y_hat, y), X.shape[0])
    #返回训练损失和训练精度
    return metric_train[0]/metric_train[2], metric_train[1]/metric_train[2]

# 用于计算验证集上的准确率
def evalution_loss_accuracy(net, data_iter, loss):
    if isinstance(net, torch.nn.Module):
        net.eval()
    meteric = Accumulator(3)
    with torch.no_grad():
        for X, y in data_iter:
            l = loss(net(X), y)
            meteric.add(float(l.sum())*X.shape[0], accuracy(net(X), y), X.shape[0])
    return meteric[0]/meteric[2], meteric[1]/meteric[2]

# 用于计算验证集上的准确率
def evalution_loss_accuracy_gpu(net, data_iter, loss, device='None'):
    if isinstance(net, torch.nn.Module):
        net.eval()
        if not device:
            #将net层的第一个元素拿出来看其在那个设备上
            device = next(iter(net.parameters())).device
    meteric = Accumulator(3)
    with torch.no_grad():
        for X, y in data_iter:
            if isinstance(X, list):
                X = [x.to(device) for x in X]
            else:
                X = X.to(device)  # 赋值给 X,将数据移动到GPU中
            y = y.to(device)  # 赋值给 y,将数据移动到GPU中
            l = loss(net(X), y)
            meteric.add(l * X.shape[0], accuracy(net(X), y), X.shape[0])
            # meteric.add(float(l.sum()), accuracy(net(X), y), y.numel())  # 转为浮点数
    return meteric[0]/meteric[2], meteric[1]/meteric[2]

def matplot_acc_loss(train_process):
    # 显示每一次迭代后的训练集和验证集的损失函数和准确率
    plt.figure(figsize=(12, 4))
    plt.subplot(1, 2, 1)
    plt.plot(train_process['epoch'], train_process.train_loss_all, "ro-", label="Train loss")
    plt.plot(train_process['epoch'], train_process.val_loss_all, "bs-", label="Val loss")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("Loss")
    plt.subplot(1, 2, 2)
    plt.plot(train_process['epoch'], train_process.train_acc_all, "ro-", label="Train acc")
    plt.plot(train_process['epoch'], train_process.val_acc_all, "bs-", label="Val acc")
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.legend()
    plt.show()

def gpu(i=0):
    """Get a GPU device.

    Defined in :numref:`sec_use_gpu`"""
    return torch.device(f'cuda:{i}')

def cpu():
    """Get the CPU device.

    Defined in :numref:`sec_use_gpu`"""
    return torch.device('cpu')
def num_gpus():
    """Get the number of available GPUs.

    Defined in :numref:`sec_use_gpu`"""
    return torch.cuda.device_count()

def try_gpu(i=0):
    """Return gpu(i) if exists, otherwise return cpu().

    Defined in :numref:`sec_use_gpu`"""
    if num_gpus() >= i + 1:
        return gpu(i)
    return cpu()

def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    """用GPU训练模型(在第六章定义)"""
    #模型参数初始化
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
            nn.init.xavier_uniform_(m.weight)
    net.apply(init_weights)
    print("training on", device)
    net.to(device)
    # 定义优化器
    ptimizer = torch.optim.SGD(net.parameters(), lr=lr)
    # 定义损失函数
    loss = nn.CrossEntropyLoss()
    # 训练集损失函数
    # 训练集损失列表
    train_loss_all = []
    train_acc_all = []
    # 验证集损失列表
    val_loss_all = []
    val_acc_all = []
    timer = Timer()
    timer.start()
    for epoch in range(num_epochs):
        train_loss, train_acc = train_epoch_gpu(net, train_iter, loss, ptimizer, device)
        val_loss, val_acc = evalution_loss_accuracy_gpu(net, test_iter, loss, device)
        train_loss_all.append(train_loss)
        train_acc_all.append(train_acc)
        val_loss_all.append(val_loss)
        val_acc_all.append(val_acc)
        print("{} train loss:{:.4f} train acc: {:.4f}".format(epoch, train_loss_all[-1], train_acc_all[-1]))
        print("{} val loss:{:.4f} val acc: {:.4f}".format(epoch, val_loss_all[-1], val_acc_all[-1]))
        print("训练和验证耗费的时间{:.0f}m{:.0f}s".format(timer.stop() // 60, timer.stop() % 60))

    train_process = pd.DataFrame(data={"epoch": range(num_epochs),
                                       "train_loss_all": train_loss_all,
                                       "val_loss_all": val_loss_all,
                                       "train_acc_all": train_acc_all,
                                       "val_acc_all": val_acc_all, })
    return train_process

4 QA

问题20:在视觉领域人工特征的研究还没有进展?研究如何设计更好的特征是不是也还有意义?尤其是提升研究能力方面
目前还是很少的论文去做人工特征的研究,特别是在主流的视觉领域期刊上。

问题23:训练loss一直下降 测试loss 从开始起就一点不降 成水平状 是什么原因呢?
可能原因1:代码写错了
可能原因2:过拟合了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1988854.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

postgregSQL配置vector插件

1.下载vector 下载vector:https://pgxn.org/dist/vector/0.5.1/ 放在:C:\Program Files\PostgreSQL\vector-0.5.1 2.安装Visual Studio 2022 下载:https://visualstudio.microsoft.com/zh-hans/downloads/ 安装Visual Studio是为了C编译环…

JL-杰理芯片-认识TA的SDK的第六天

通过修改代码无法解决的错误解决问题的方法: 从头开始一点点的配置,并运行。(配置的是标准SDK) 将无法修改的错误打印到xshell中,去看看是什么原因,就算不能理解,也要看看他运行了几次。 上电开机和按键开机1T1,2T1,一拖二

Together规则引擎 金融解决方案

目录 1.金融法规和期望正在发生变化,快速跟踪您的金融数字化变革!2.抵押贷款功能集(MFS)3.MFS 示例模型4.MFS 知识特点5.MFS特定功能 1.金融法规和期望正在发生变化,快速跟踪您的金融数字化变革! ogether规则引擎使金融机构能够简…

26.9 Django书籍管理练习

1. 搭建环境 1.1 创建数据库 Django本身不会自动创建数据库服务器或数据库实例, 这一步需要手动完成.可以使用Navicat可视化工具或者命令行创建library数据库, 编码格式为utf8_mp4.# 连接数据库 mysql -h localhost -P 3306 -u root -p123456# 创建library数据库并设置编码 c…

面试题:Java 集合类的遍历方式,如何一边遍历 一边删除?

问题一:你用过 Java 中的哪些集合类? ArrayList, LinkedList, HashMap, HashSet, TreeSet, Stack, Queue, PriorityQueue等 问题二:集合中遍历元素的方式? Collection 接口实现子类 1. List 集合 // list 集合public static …

【Linux】进程间通信(管道通信、共享内存通信)

一.什么是进程间通信 进程间通信这五个字很好理解,就是进程和进程之间通信。 那么为什么要有进程间通信呢? 1.数据传输:一个进程需要将它的数据发送给另一个进程 2.资源共享:多个进程之间共享同样的资源 3.通知事件:一…

如何制作自己的python .whl包(支持entry_points)

目录 代码目录结构如下截图所示:dir_test.py 源码如下:list/dir_list.py 源码如下:setup.py 文件源码生成.whl文件指令: 代码目录结构如下截图所示: dir_test.py 源码如下: import os import sys from pat…

RunAsDate(时间限制工具)

参考链接1 参考链接2 参考链接3 下载地址 ps:64位系统需要下载64的RunAsDate

LAMP架构详解

目录 一、Apache详解 1.1 简介 1.2 Apache功能 1.3 apache特点 1.4 三种工作模式 二、LAMP简介 2.1 LAMP平台概述 2.2 构建LAMP平台顺序 2.3 编译安装的优点 2.4 各组件的主要作用 三、wget命令 四、curl命令 五、压力测试工具 一、Apache详解 1.1 简介 Apache …

vue2,v-for中动态渲染本地的图片

一、描述 如果是正常在img标签的src上使用本地的url地址,是可以正常被渲染的,但是我们通过for的形式,动态渲染的话,就会通过网络请求的方式进行渲染,这个形式反而渲染不出来。 二、效果 这个效果,毋庸置…

LVS负载均衡集群部署之—NAT模式的介绍及搭建步骤

一、环境准备 1.准备三台rhel9服务器 服务器名称 主机名 ip地址备注LVS调度服务器lvs.timinglee.org eth0:172.25.254.100(外网) eth1:192.168.0.100(内网) 关闭selinux和防火墙webserver2网站服务器webserver1.timinglee.orgeth0:192.168.…

为什么高校开设微专业,建议搭建动作捕捉与数字人开发实训室?

随着近年来虚拟现实技术产业与元宇宙产业不断发展,动作捕捉技术成为元宇宙、VR/AR、影视动画、游戏、艺术创作、虚拟偶像等行业相关不可或缺的技术之一。各大院校为了探索新的教学模式,纷纷积极开设“微专业”,相比传统的虚拟仿真实训室来说&…

Linux进程调度与切换

目录 前言 Linux 2.6内核O(1)调度器 调度过程 调度算法 Linux 进程切换 前言 在Linux 2.6版本的内核中,进程调度器引入了O(1)调度器,这个调度器通过优先级队列、活跃队列和过期队列的机制来管理进程调度,虽然在现在已被更好的CFS调度器取代,但对于我…

中仕公考:2024年空军专业技能类文职人员公开招考公告

2024年空军专业技能类文职人员公开招考公告,有关事项公告如下: 一、招考岗位 主要有保管员、司机、炊事员、文印员、汽车修理工兼司机等专业技能三级以下岗位。 二、招考对象 符合岗位资格条件的社会人员(含高校应届毕业生、退役军人)。 根据军队有…

理解栈(Stack)及其在 C++ 中的应用【栈、数据结构】

在这篇博客中,我们将详细介绍栈(Stack)这一重要的数据结构,包括其基本概念、常用操作、C 中的实现,以及一些实际应用。 什么是栈? 栈是一种数据结构,它遵循“后进先出”(LIFO - La…

上海AI Lab 搭台,36个大模型一起角逐长上下文建模能力

现在的大模型论文简直像是在比长度,动不动就上百页!记得前阵子小编瞅见那份90页的Gemini技术报告,顿时脑袋嗡嗡作响。那会儿就幻想着:要是有个AI大脑来啃下这些"学术巨无霸",那岂不是爽歪歪? 没…

SpringDoc:一个用于自动生成API文档的工具

SpringDoc的使用 概述SpringDoc添加依赖配置 Springdoc创建 REST 控制器访问 API 文档添加注释和描述自定义配置常用注解 详细示例创建模型类创建REST控制器查看Swagger UI与OpenAPI 安全策略类型概述HTTPAPIKEYOAUTH2OPENIDCONNECTMUTUALTLS 请求头配置认证token代码实现验证 …

C++:C++11介绍

✨✨✨学习的道路很枯燥,希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一、C11简介 二 统一的列表初始化 2.1 {} 初始化 2.2 std::initializer_list 三 声明 3.1 auto 3.2 decltype 3.3 nullptr 四 范围for循环 五 智能指针 六 STL中一些变化…

瑞_RabbitMQ_初识MQ

文章目录 1 初识MQ1.1 同步调用1.1.1 同步调用的优势1.1.2 同步调用的缺点 1.2 异步调用1.2.1 异步调用的角色1.2.2 异步调用的优势1.2.3 异步调用的缺点1.2.4 异步调用的场景 1.3 MQ技术选型 2 RabbitMQ2.1 安装2.1.1 资源准备2.1.2 安装步骤 2.2 RabbitMQ架构2.3 RabbitMQ管理…

Starrocks解析json数组

json数据 [{"spec": "70g/支","unit": "支","skuId": "1707823848651276346","amount": 6,"weight": 70,"spuName": "伊利 甄稀 苦咖啡味雪糕 流心冰淇淋 70g/支",&quo…