动手学深度学习V2每日笔记(深度卷积神经网络AlexNet)

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

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

1.函数目录

2. 深度卷积神经网络AlexNet

  • AlexNet赢了2012年lmageNet 竞赛·
  • 更深更大的 LeNet·
  • 主要改进:
    • 丢弃法
    • ReLu
    • MaxPooling
  • 计算机视觉方法论的改变
    在这里插入图片描述
LeNet操作输出形状AlexNet操作输出形状
输入层\1x28x28输入层\3x224x224
卷积层kernel=5、padding=2、stride=1、output_channel=66x28x28卷积层kernel=11、stride=4、output_channel=9696x54x54
平均池化层kernel=2、padding=0、stride=26x14x14最大池化层kernel=3、stride=296x26x26
卷积层kernel=5、padding=0、stride=1、output_channel=1616x10x10卷积层kernel=5、padding=2、output_channel=256256x26x26
平均池化层kernel=2、padding=0、stride=216x5x5最大池化层kernel=3、stride=2256x12x12
全连接层480->120120卷积层kernel=3、padding=1、output_channel=384384x12x12
全连接层120->8484卷积层kernel=3、padding=1、output_channel=384384x12x12
全连接层84->1010卷积层kernel=3、padding=1、output_channel=256256x12x12
\\\最大池化层kernel=3、stride=2256x5x5
\\\全连接层256x5x5->40964096
\\\全连接层4096->40964096
\\\全连接层4096->10001000

在这里插入图片描述
从LeNet(左)到AlexNet(右)
更多细节

  • 激活函数从sigmoid变成了Relu(减缓梯度消失)
  • 隐藏全连接层后加入了丢弃层
  • 数据增强

3 代码实现

3.1 模型

import torch
from torch import nn

class Reshape(torch.nn.Module):
    def forward(self, x):
        return x.view(-1, 1, 28, 28)

net = nn.Sequential(
    nn.Conv2d(in_channels=1, out_channels=96, kernel_size=11, stride=4, padding=1),nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Conv2d(in_channels=96, out_channels=256, kernel_size=5, padding=2),nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Conv2d(in_channels=256, out_channels=384, kernel_size=3, padding=1),nn.ReLU(),
    nn.Conv2d(in_channels=384, out_channels=384, kernel_size=3, padding=1),nn.ReLU(),
    nn.Conv2d(in_channels=384, out_channels=256, kernel_size=3, padding=1),nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Flatten(),
    nn.Linear(256*5*5, 4096), nn.ReLU(),nn.Dropout(p=0.5),
    nn.Linear(4096, 4096), nn.ReLU(),nn.Dropout(p=0.5),
    nn.Linear(4096,10)
)

# 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.2 训练

import torch
from torch import nn

import model
import tools
from model import net
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)
    AlexNet = model.net
    train_process = train_ch6(AlexNet,train_iter,test_iter,10,0.01,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

问题1:老师,ImageNet数据集是怎么构建的,现在看是不是要成为历史了?
ImageNet数据集仍然还是一个很重要的数据集。在多数卷积神经网络中还是使用该数据集验证模型性能。

问题2:为什么2000年的时候,神经网络被核方法代替?是因为神经网络运算量太大,数据多,硬件跟不上吗?
主要是核方法有很好理论,同时在2000年的时候深度神经网络计算不动。

问题3:nlp领域,cnn也代替了人工特征工程吗?如何看待nlp领域transformer、bert、deepfm这些方法和cv领域cnn方法的区别?
nlp与cnn在设计思路上是没有区别的。

问题4:alexNet让机器自己寻找特征,这些找到的特征都符合人类的逻辑吗?如果不复合的话,要怎么解释?
AlexNet寻找的特征通常是不符合人类的逻辑。其优化的目标是让机器模型可以更好的分类,再此过程中并没有考虑人的因素。因此深度学习神经网络解释性较差。

问题7:从发展视角来看,CNN完爆MLP吗?未来MLP是否有可能由于某些技术成为主流?
CNN就是一个特殊的MLP,MLP可以做更多的结构化设计。Transformer你也可以认为是MLP加一起其他东西的设计。

问题11:我们在一个识别细胞的程序里做了颜色+几何变换的增强后效果反倒比只做几何变化的增强效果差。这个可能是因为什么?
这个现象属于正常现象。数据增强加多变差不是一个很奇怪的事情。

问题13:没太明白为什么leNet不属于深度卷积神经网络?
对于好的研究成果也要学会包装和营销。取一个好的名字很重要。突出自己工作内容的创新。

问题16:作为一个行外汉,感觉现在新的CV领域模型也越来越少,大家都在搞demo。老师如何看待这件事呢?
这是技术发展的必然过程。这是一个好的现象。大家搞demo可以将技术落地,搞出产品。现在去做CNN的设计比较难。

问题17:网络要求输入的size是固定的,实际使用的时候图片不一定是要求的size,如果强行resize成网络要求的size,会不会最后的效果要差?
当图片过大的时候,通常会将短边压缩到要求的宽度然后再冲里面随机扣除符合要求的图片去做训练或者测试。

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《动手深度学习 v2》是一本介绍深度学习的教材,通过动手实践的方式帮助读者深入理解深度学习的理论和实践。这本书由李沐等人共同编写,内容包含了深度学习的基本概念、算法原理以及实际应用等方面。 这本书的优点之一是注重实践,通过大量的案例和代码实现,读者可以亲自动手搭建深度学习模型,并通过实际操作来理解算法的工作原理。此外,书中还涵盖了一些最新的深度学习技术和应用,帮助读者跟上深度学习领域的最新发展。 《动手深度学习 v2》也具有一定的难度,对于初者来说需要一定的数和编程基础才能更好地理解和实践。但是,书中的难点都有详细的解答和说明,读者可以在遇到困难时查看相关解析,提升习效果。 总的来说,《动手深度学习 v2》是一本非常实用的深度学习教材,适合有一定基础的读者习和实践。通过阅读这本书,读者可以系统地深度学习的基本概念和算法,掌握如何应用深度学习解决实际问题,进而在深度学习领域有更深入的理解和应用。 ### 回答2: 《动手深度学习 v2》pdf是一本深度学习入门的教程,适合初深度学习的理论和实践。这本教程由作者李沐、阿斯顿·张剑锋等人合作撰写,涵盖了深度学习的基本概念、神经网络的构建、常见深度学习模型、计算机视觉、自然语言处理等领域的应用。 这本教程的特点是注重实践,每个章节都提供了大量的代码示例和实验指导,让读者可以动手实践,巩固所知识。同时,教程还配有相应的代码库和数据集,读者可以下载使用。 教程通过讲解深度学习的基本概念和原理,帮助读者建立起对深度学习的整体认识。然后,通过实例演示和实践,教会读者如何使用深度学习框架搭建神经网络,并进行训练和优化。 另外,这本教程也介绍了一些常见的应用领域,如计算机视觉和自然语言处理。读者可以习到如何使用深度学习来解决图像分类、目标检测、文本生成等问题。 最后,这本教程还提供了一些深度学习的进阶内容,如深度生成模型和强化习等,供读者深入习和拓展。 总的来说,《动手深度学习 v2》pdf是一本很好的深度学习入门教程,通过动手实践和实例演示,帮助读者快速入门和掌握深度学习的基本知识和应用技巧。对于想要深度学习的初者来说,是一本非常有价值的教材。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值