【PyTorch】现代卷积神经网络

文章目录

  • 1. 理论介绍
    • 1.1. 深度卷积神经网络(AlexNet)
      • 1.1.1. 概述
      • 1.1.2. 模型设计
    • 1.2. 使用块的网络(VGG)
    • 1.3. 网络中的网络(NiN)
    • 1.4. 含并行连结的网络(GoogLeNet)
  • 2. 实例解析
    • 2.1. 实例描述
    • 2.2. 代码实现
      • 2.2.1. 在FashionMNIST数据集上训练AlexNet
        • 2.2.1.1. 主要代码
        • 2.2.1.2. 完整代码
        • 2.2.1.3. 输出结果
      • 2.2.2. 在FashionMNIST数据集上训练VGG-11
        • 2.2.2.1. 主要代码
        • 2.2.2.2. 完整代码
        • 2.2.2.3. 输出结果
      • 2.2.3. 在FashionMNIST数据集上训练NiN
        • 2.2.3.1. 主要代码
        • 2.2.3.2. 完整代码
        • 2.2.3.3. 输出结果
      • 2.2.4. 在FashionMNIST数据集上训练GoogLeNet
        • 2.2.4.1. 主要代码
        • 2.2.4.2. 完整代码
        • 2.2.4.3. 输出结果

1. 理论介绍

1.1. 深度卷积神经网络(AlexNet)

1.1.1. 概述

  • 特征本身应该被学习,而且在合理地复杂性前提下,特征应该由多个共同学习的神经网络层组成,每个层都有可学习的参数。在机器视觉中,最底层可能检测边缘、颜色和纹理,更高层建立在这些底层表示的基础上,以表示更大的特征。
  • 包含许多特征的深度模型需要大量的有标签数据,才能显著优于基于凸优化的传统方法(如线性方法和核方法)。ImageNet挑战赛为研究人员提高超大规模的数据集。
  • 深度学习对计算资源要求很高,训练可能需要数百个迭代轮数,每次迭代都需要通过代价高昂的许多线性代数层传递数据。用GPU训练神经网络大大提高了训练速度,相比于CPU,GPU由100~1000个小的处理单元(核心)组成,庞大的核心数量使GPU比CPU快几个数量级;GPU核心更简单,功耗更低;GPU拥有更高的内存带宽;卷积和矩阵乘法,都是可以在GPU上并行化的操作。
  • AlexNet首次证明了学习到的特征可以超越手工设计的特征。

1.1.2. 模型设计

模型设计

  • AlexNet使用ReLU而不是sigmoid作为其激活函数。
  • 在最后一个卷积层后有两个全连接层,分别有4096个输出。 这两个巨大的全连接层拥有将近1GB的模型参数。 由于早期GPU显存有限,原版的AlexNet采用了双数据流设计,使得每个GPU只负责存储和计算模型的一半参数。
  • AlexNet通过暂退法控制全连接层的模型复杂度。
  • 为了进一步扩充数据,AlexNet在训练时增加了大量的图像增强数据,如翻转、裁切和变色。 这使得模型更健壮,更大的样本量有效地减少了过拟合。

1.2. 使用块的网络(VGG)

  • 经典卷积神经网络的基本组成部分
    • 带填充以保持分辨率的卷积层
    • 非线性激活函数
    • 池化层
  • VGG块由一系列卷积层组成,后面再加上用于空间下采样的最大池化层。深层且窄的卷积(即 3 × 3 3\times3 3×3)比较浅层且宽的卷积更有效。不同的VGG模型可通过每个VGG块中卷积层数量和输出通道数量的差异来定义。
  • VGG网络由几个VGG块和全连接层组成。超参数变量conv_arch指定了每个VGG块里卷积层个数和输出通道数。全连接模块则与AlexNet中的相同。
  • VGG-11有5个VGG块,其中前两个块各有一个卷积层,后三个块各包含两个卷积层,共8个卷积层。 第一个模块有64个输出通道,每个后续模块将输出通道数量翻倍,直到该数字达到512。

1.3. 网络中的网络(NiN)

  • 网络中的网络(NiN)在每个像素的通道上分别使用多层感知机
  • NiN块以一个普通卷积层开始,后面是两个 1 × 1 1\times1 1×1的卷积层。这两个 1 × 1 1\times1 1×1卷积层充当带有ReLU激活函数的逐像素全连接层。
  • NiN网络使用窗口形状为 11 × 11 11\times11 11×11 5 × 5 5\times5 5×5 3 × 3 3\times3 3×3的卷积层,输出通道数量与AlexNet中的相同。 每个NiN块后有一个最大池化层,池化窗口形状为 3 × 3 3\times3 3×3,步幅为2。 NiN和AlexNet之间的一个显著区别是NiN完全取消了全连接层。NiN使用一个NiN块,其输出通道数等于标签类别的数量。最后放一个全局平均池化层,生成一个对数几率 (logits)。
  • 移除全连接层可减少过拟合,同时显著减少NiN的参数。

1.4. 含并行连结的网络(GoogLeNet)

  • 使用不同大小的卷积核组合是有利的,因为可以有效地识别不同范围的图像细节。
  • Inception块由四条并行路径组成。四条路径都使用合适的填充来使输入与输出的高和宽一致。超参数是每层输出通道数
    Inception
  • GoogLeNet一共使用9个Inception块和全局平均汇聚层的堆叠来生成其估计值。Inception块之间的最大汇聚层可降低维度。
    GoogLeNet

2. 实例解析

2.1. 实例描述

  • 在FashionMNIST数据集上训练AlexNet。注:输入图像调整到 224 × 224 224\times224 224×224,不使用跨GPU分解模型。
  • 在FashionMNIST数据集上训练VGG-11。注:输入图像调整到 224 × 224 224\times224 224×224,可以按比例缩小通道数以减少参数量,学习率可以设置得略高。
  • 在FashionMNIST数据集上训练NiN。注:输入图像调整到 224 × 224 224\times224 224×224
  • 在FashionMNIST数据集上训练GoogLeNet。注:输入图像调整到 96 × 96 96\times96 96×96

2.2. 代码实现

2.2.1. 在FashionMNIST数据集上训练AlexNet

2.2.1.1. 主要代码
AlexNet = nn.Sequential(
        nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
        nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
        nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nn.Flatten(),
        nn.Linear(6400, 4096), nn.ReLU(),
        nn.Dropout(p=0.5),
        nn.Linear(4096, 4096), nn.ReLU(),
        nn.Dropout(p=0.5),
        nn.Linear(4096, 10)
).to(device, non_blocking=True)
2.2.1.2. 完整代码
import os, torch
from tensorboardX import SummaryWriter
from rich.progress import track
from torchvision.datasets import FashionMNIST
from torchvision.transforms import Compose, ToTensor, Resize
from torch.utils.data import DataLoader
from torch import nn, optim

def load_dataset():
    """加载数据集"""
    root = "./dataset"
    transform = Compose([Resize(224), ToTensor()])
    mnist_train = FashionMNIST(root, True, transform, download=True)
    mnist_test = FashionMNIST(root, False, transform, download=True)

    dataloader_train = DataLoader(mnist_train, batch_size, shuffle=True, 
        num_workers=num_workers, pin_memory=True,
    )
    dataloader_test = DataLoader(mnist_test, batch_size, shuffle=False,
        num_workers=num_workers, pin_memory=True,
    )
    return dataloader_train, dataloader_test


if __name__ == "__main__":
    # 全局参数设置
    num_epochs = 10
    batch_size = 128
    num_workers = 3
    lr = 0.01
    device = torch.device('cuda')

    # 创建记录器
    def log_dir():
        root = "runs"
        if not os.path.exists(root):
            os.mkdir(root)
        order = len(os.listdir(root)) + 1
        return f'{root}/exp{order}'
    writer = SummaryWriter(log_dir=log_dir())

    # 数据集配置
    dataloader_train, dataloader_test = load_dataset()

    # 模型配置
    AlexNet = nn.Sequential(
        nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
        nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
        nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nn.Flatten(),
        nn.Linear(6400, 4096), nn.ReLU(),
        nn.Dropout(p=0.5),
        nn.Linear(4096, 4096), nn.ReLU(),
        nn.Dropout(p=0.5),
        nn.Linear(4096, 10)
    ).to(device, non_blocking=True)
    criterion = nn.CrossEntropyLoss(reduction='none')
    optimizer = optim.SGD(AlexNet.parameters(), lr=lr)

    # 训练循环
    metrics_train = torch.zeros(3, device=device)  # 训练损失、训练准确度、样本数
    metrics_test = torch.zeros(2, device=device)   # 测试准确度、样本数
    for epoch in track(range(num_epochs), description='AlexNet'):
        AlexNet.train()
        for X, y in dataloader_train:
            X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
            loss = criterion(AlexNet(X), y)
            optimizer.zero_grad()
            loss.mean().backward()
            optimizer.step()

        AlexNet.eval()
        with torch.no_grad():
            metrics_train.zero_()
            for X, y in dataloader_train:
                X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                y_hat = AlexNet(X)
                loss = criterion(y_hat, y)
                metrics_train[0] += loss.sum()
                metrics_train[1] += (y_hat.argmax(dim=1) == y).sum()
                metrics_train[2] += y.numel()
            metrics_train[0] /= metrics_train[2]
            metrics_train[1] /= metrics_train[2]

            metrics_test.zero_()
            for X, y in dataloader_test:
                X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                y_hat = AlexNet(X)
                metrics_test[0] += (y_hat.argmax(dim=1) == y).sum()
                metrics_test[1] += y.numel()
            metrics_test[0] /= metrics_test[1]

            _metrics_train = metrics_train.cpu().numpy()
            _metrics_test = metrics_test.cpu().numpy()
            writer.add_scalars('metrics', {
                'train_loss': _metrics_train[0],
                'train_acc': _metrics_train[1],
                'test_acc': _metrics_test[0]
            }, epoch)

    writer.close()
2.2.1.3. 输出结果

AlexNet

2.2.2. 在FashionMNIST数据集上训练VGG-11

2.2.2.1. 主要代码
def vgg_block(num_convs, in_channels, out_channels):
        """定义VGG块"""
        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)

def vgg(conv_arch):
    """定义VGG网络"""
    vgg_blocks = []
    in_channels = 1
    out_channels = 0

    for num_convs, out_channels in conv_arch:
        vgg_blocks.append(vgg_block(num_convs, in_channels, out_channels))
        in_channels = out_channels

    return nn.Sequential(
        *vgg_blocks, 
        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),
    )
2.2.2.2. 完整代码
import os
from tensorboardX import SummaryWriter
from rich.progress import track
import torch
from torch import nn, optim
from torch.utils.data import DataLoader
from torchvision.transforms import Compose, Resize, ToTensor
from torchvision.datasets import FashionMNIST

def load_dataset():
    """加载数据集"""
    root = "./dataset"
    transform = Compose([Resize(224), ToTensor()])
    mnist_train = FashionMNIST(root, True, transform, download=True)
    mnist_test = FashionMNIST(root, False, transform, download=True)

    dataloader_train = DataLoader(mnist_train, batch_size, shuffle=True, 
        num_workers=num_workers, pin_memory=True,
    )
    dataloader_test = DataLoader(mnist_test, batch_size, shuffle=False,
        num_workers=num_workers, pin_memory=True,
    )
    return dataloader_train, dataloader_test

def vgg_block(num_convs, in_channels, out_channels):
        """定义VGG块"""
        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)

def vgg(conv_arch):
    """定义VGG网络"""
    vgg_blocks = []
    in_channels = 1
    out_channels = 0

    for num_convs, out_channels in conv_arch:
        vgg_blocks.append(vgg_block(num_convs, in_channels, out_channels))
        in_channels = out_channels

    return nn.Sequential(
        *vgg_blocks, 
        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),
    )


if __name__ == '__main__':
    # 全局参数配置
    num_epochs = 10
    batch_size = 128
    num_workers = 3
    lr = 0.05
    device = torch.device('cuda')

    # 记录器配置
    def log_dir():
        root = "runs"
        if not os.path.exists(root):
            os.mkdir(root)
        order = len(os.listdir(root)) + 1
        return f'{root}/exp{order}'
    writer = SummaryWriter(log_dir=log_dir())

    # 数据集配置
    dataloader_train, dataloader_test = load_dataset()

    # 模型配置
    ratio = 4
    conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
    small_conv_arch =  [(pair[0], pair[1] // ratio) for pair in conv_arch]
    net = vgg(small_conv_arch).to(device, non_blocking=True)
    criterion = nn.CrossEntropyLoss(reduction='none')
    optimizer = optim.SGD(net.parameters(), lr=lr)

    # 训练循环
    metrics_train = torch.zeros(3, device=device)  # 训练损失、训练准确度、样本数
    metrics_test = torch.zeros(2, device=device)   # 测试准确度、样本数
    for epoch in track(range(num_epochs), description='VGG'):
        net.train()
        for X, y in dataloader_train:
            X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
            loss = criterion(net(X), y)
            optimizer.zero_grad()
            loss.mean().backward()
            optimizer.step()
    
        net.eval()
        with torch.no_grad():
            metrics_train.zero_()
            for X, y in dataloader_train:
                X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                y_hat = net(X)
                loss = criterion(y_hat, y)
                metrics_train[0] += loss.sum()
                metrics_train[1] += (y_hat.argmax(dim=1) == y).sum()
                metrics_train[2] += y.numel()
            metrics_train[0] /= metrics_train[2]
            metrics_train[1] /= metrics_train[2]
    
            metrics_test.zero_()
            for X, y in dataloader_test:
                X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                y_hat = net(X)
                metrics_test[0] += (y_hat.argmax(dim=1) == y).sum()
                metrics_test[1] += y.numel()
            metrics_test[0] /= metrics_test[1]
    
            _metrics_train = metrics_train.cpu().numpy()
            _metrics_test = metrics_test.cpu().numpy()
            writer.add_scalars('metrics', {
                'train_loss': _metrics_train[0],
                'train_acc': _metrics_train[1],
                'test_acc': _metrics_test[0]
            }, epoch)
    
    writer.close()
2.2.2.3. 输出结果

VGG

2.2.3. 在FashionMNIST数据集上训练NiN

2.2.3.1. 主要代码
def nin_block(in_channels, out_channels, kernel_size, strides, padding):
    """定义NiN块"""
    return nn.Sequential(
        nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding), nn.ReLU(),
        nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(),
        nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU()
    )
net = nn.Sequential(
    nin_block(1, 96, kernel_size=11, strides=4, padding=0),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nin_block(96, 256, kernel_size=5, strides=1, padding=2),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nin_block(256, 384, kernel_size=3, strides=1, padding=1),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Dropout(0.5),
    nin_block(384, 10, kernel_size=3, strides=1, padding=1),
    nn.AdaptiveAvgPool2d((1, 1)),
    nn.Flatten()
).to(device, non_blocking=True)
2.2.3.2. 完整代码
import os
from tensorboardX import SummaryWriter
from alive_progress import alive_bar
import torch
from torch import nn, optim
from torch.utils.data import DataLoader
from torchvision.transforms import Compose, ToTensor, Resize
from torchvision.datasets import FashionMNIST

def load_dataset():
    """加载数据集"""
    root = "./dataset"
    transform = Compose([Resize(224), ToTensor()])
    mnist_train = FashionMNIST(root, True, transform, download=True)
    mnist_test = FashionMNIST(root, False, transform, download=True)

    dataloader_train = DataLoader(mnist_train, batch_size, shuffle=True, 
        num_workers=num_workers, pin_memory=True,
    )
    dataloader_test = DataLoader(mnist_test, batch_size, shuffle=False,
        num_workers=num_workers, pin_memory=True,
    )
    return dataloader_train, dataloader_test

def train_on_FashionMNIST(title):
    """在FashionMNIST数据集上训练指定模型"""
    # 创建记录器
    def log_dir():
        root = "runs"
        if not os.path.exists(root):
            os.mkdir(root)
        order = len(os.listdir(root)) + 1
        return f'{root}/exp{order}'
    writer = SummaryWriter(log_dir=log_dir())

    # 数据集配置
    dataloader_train, dataloader_test = load_dataset()

    # 模型配置
    criterion = nn.CrossEntropyLoss(reduction='none')
    optimizer = optim.SGD(net.parameters(), lr=lr)

    # 训练循环
    metrics_train = torch.zeros(3, device=device)  # 训练损失、训练准确度、样本数
    metrics_test = torch.zeros(2, device=device)   # 测试准确度、样本数
    with alive_bar(num_epochs, theme='classic', title=title) as bar:
        for epoch in range(num_epochs):
            net.train()
            for X, y in dataloader_train:
                X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                loss = criterion(net(X), y)
                optimizer.zero_grad()
                loss.mean().backward()
                optimizer.step()
        
            net.eval()
            with torch.no_grad():
                metrics_train.zero_()
                for X, y in dataloader_train:
                    X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                    y_hat = net(X)
                    loss = criterion(y_hat, y)
                    metrics_train[0] += loss.sum()
                    metrics_train[1] += (y_hat.argmax(dim=1) == y).sum()
                    metrics_train[2] += y.numel()
                metrics_train[0] /= metrics_train[2]
                metrics_train[1] /= metrics_train[2]
        
                metrics_test.zero_()
                for X, y in dataloader_test:
                    X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                    y_hat = net(X)
                    metrics_test[0] += (y_hat.argmax(dim=1) == y).sum()
                    metrics_test[1] += y.numel()
                metrics_test[0] /= metrics_test[1]
        
                _metrics_train = metrics_train.cpu().numpy()
                _metrics_test = metrics_test.cpu().numpy()
                writer.add_scalars('metrics', {
                    'train_loss': _metrics_train[0],
                    'train_acc': _metrics_train[1],
                    'test_acc': _metrics_test[0]
                }, epoch)
            bar()
    
    writer.close()

if __name__ == '__main__':
    # 全局参数配置
    num_epochs = 10
    batch_size = 128
    num_workers = 3
    lr = 0.1
    device = torch.device('cuda')

    # 模型配置
    def nin_block(in_channels, out_channels, kernel_size, strides, padding):
        """定义NiN块"""
        return nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding), nn.ReLU(),
            nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(),
            nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU()
        )
    net = nn.Sequential(
        nin_block(1, 96, kernel_size=11, strides=4, padding=0),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nin_block(96, 256, kernel_size=5, strides=1, padding=2),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nin_block(256, 384, kernel_size=3, strides=1, padding=1),
        nn.MaxPool2d(kernel_size=3, stride=2),
        nn.Dropout(0.5),
        nin_block(384, 10, kernel_size=3, strides=1, padding=1),
        nn.AdaptiveAvgPool2d((1, 1)),
        nn.Flatten()
    ).to(device, non_blocking=True)
    def init_weights(m):
        if type(m) in [nn.Linear, nn.Conv2d]:
            nn.init.xavier_uniform_(m.weight)
            nn.init.zeros_(m.bias)
    net.apply(init_weights)
    
    # 在FashionMNIST数据集上训练模型
    train_on_FashionMNIST('NiN')
2.2.3.3. 输出结果

NiN

2.2.4. 在FashionMNIST数据集上训练GoogLeNet

2.2.4.1. 主要代码
class Inception(nn.Module):
    # c1--c4是每条路径的输出通道数
    def __init__(self, in_channels, c1, c2, c3, c4, **kwargs):
        super(Inception, self).__init__(**kwargs)
        # 线路1,单1x1卷积层
        self.p1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)
        # 线路2,1x1卷积层后接3x3卷积层
        self.p2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)
        self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)
        # 线路3,1x1卷积层后接5x5卷积层
        self.p3_1 = nn.Conv2d(in_channels, c3[0], kernel_size=1)
        self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)
        # 线路4,3x3最大汇聚层后接1x1卷积层
        self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
        self.p4_2 = nn.Conv2d(in_channels, c4, kernel_size=1)

    def forward(self, x):
        p1 = F.relu(self.p1_1(x))
        p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))
        p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
        p4 = F.relu(self.p4_2(self.p4_1(x)))
        # 在通道维度上连结输出
        return torch.cat((p1, p2, p3, p4), dim=1)
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
               nn.ReLU(),
               nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1),
               nn.ReLU(),
               nn.Conv2d(64, 192, kernel_size=3, padding=1),
               nn.ReLU(),
               nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b3 = nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32),
               Inception(256, 128, (128, 192), (32, 96), 64),
               nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b4 = nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64),
               Inception(512, 160, (112, 224), (24, 64), 64),
               Inception(512, 128, (128, 256), (24, 64), 64),
               Inception(512, 112, (144, 288), (32, 64), 64),
               Inception(528, 256, (160, 320), (32, 128), 128),
               nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b5 = nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128),
               Inception(832, 384, (192, 384), (48, 128), 128),
               nn.AdaptiveAvgPool2d((1,1)),
               nn.Flatten())

net = nn.Sequential(b1, b2, b3, b4, b5, nn.Linear(1024, 10)).to(device, non_blocking=True)
2.2.4.2. 完整代码
import os
from tensorboardX import SummaryWriter
from alive_progress import alive_bar
import torch
from torch import nn, optim
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision.transforms import Compose, ToTensor, Resize
from torchvision.datasets import FashionMNIST

def load_dataset():
    """加载数据集"""
    root = "./dataset"
    transform = Compose([Resize(96), ToTensor()])
    mnist_train = FashionMNIST(root, True, transform, download=True)
    mnist_test = FashionMNIST(root, False, transform, download=True)

    dataloader_train = DataLoader(mnist_train, batch_size, shuffle=True, 
        num_workers=num_workers, pin_memory=True,
    )
    dataloader_test = DataLoader(mnist_test, batch_size, shuffle=False,
        num_workers=num_workers, pin_memory=True,
    )
    return dataloader_train, dataloader_test

def train_on_FashionMNIST(title):
    """在FashionMNIST数据集上训练指定模型"""
    # 创建记录器
    def log_dir():
        root = "runs"
        if not os.path.exists(root):
            os.mkdir(root)
        order = len(os.listdir(root)) + 1
        return f'{root}/exp{order}'
    writer = SummaryWriter(log_dir=log_dir())

    # 数据集配置
    dataloader_train, dataloader_test = load_dataset()

    # 模型配置
    criterion = nn.CrossEntropyLoss(reduction='none')
    optimizer = optim.SGD(net.parameters(), lr=lr)

    # 训练循环
    metrics_train = torch.zeros(3, device=device)  # 训练损失、训练准确度、样本数
    metrics_test = torch.zeros(2, device=device)   # 测试准确度、样本数
    with alive_bar(num_epochs, theme='classic', title=title) as bar:
        for epoch in range(num_epochs):
            net.train()
            for X, y in dataloader_train:
                X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                loss = criterion(net(X), y)
                optimizer.zero_grad()
                loss.mean().backward()
                optimizer.step()
        
            net.eval()
            with torch.no_grad():
                metrics_train.zero_()
                for X, y in dataloader_train:
                    X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                    y_hat = net(X)
                    loss = criterion(y_hat, y)
                    metrics_train[0] += loss.sum()
                    metrics_train[1] += (y_hat.argmax(dim=1) == y).sum()
                    metrics_train[2] += y.numel()
                metrics_train[0] /= metrics_train[2]
                metrics_train[1] /= metrics_train[2]
        
                metrics_test.zero_()
                for X, y in dataloader_test:
                    X, y = X.to(device, non_blocking=True), y.to(device, non_blocking=True)
                    y_hat = net(X)
                    metrics_test[0] += (y_hat.argmax(dim=1) == y).sum()
                    metrics_test[1] += y.numel()
                metrics_test[0] /= metrics_test[1]
        
                _metrics_train = metrics_train.cpu().numpy()
                _metrics_test = metrics_test.cpu().numpy()
                writer.add_scalars('metrics', {
                    'train_loss': _metrics_train[0],
                    'train_acc': _metrics_train[1],
                    'test_acc': _metrics_test[0]
                }, epoch)
            bar()
    
    writer.close()

if __name__ == '__main__':
    # 全局参数配置
    num_epochs = 10
    batch_size = 128
    num_workers = 3
    lr = 0.1
    device = torch.device('cuda')

    # 模型配置
    class Inception(nn.Module):
        # c1--c4是每条路径的输出通道数
        def __init__(self, in_channels, c1, c2, c3, c4, **kwargs):
            super(Inception, self).__init__(**kwargs)
            # 线路1,单1x1卷积层
            self.p1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)
            # 线路2,1x1卷积层后接3x3卷积层
            self.p2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)
            self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)
            # 线路3,1x1卷积层后接5x5卷积层
            self.p3_1 = nn.Conv2d(in_channels, c3[0], kernel_size=1)
            self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)
            # 线路4,3x3最大汇聚层后接1x1卷积层
            self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
            self.p4_2 = nn.Conv2d(in_channels, c4, kernel_size=1)

        def forward(self, x):
            p1 = F.relu(self.p1_1(x))
            p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))
            p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
            p4 = F.relu(self.p4_2(self.p4_1(x)))
            # 在通道维度上连结输出
            return torch.cat((p1, p2, p3, p4), dim=1)
    b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
                   nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
    b2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1),
                   nn.ReLU(),
                   nn.Conv2d(64, 192, kernel_size=3, padding=1),
                   nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
    b3 = nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32),
                   Inception(256, 128, (128, 192), (32, 96), 64),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
    b4 = nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64),
                   Inception(512, 160, (112, 224), (24, 64), 64),
                   Inception(512, 128, (128, 256), (24, 64), 64),
                   Inception(512, 112, (144, 288), (32, 64), 64),
                   Inception(528, 256, (160, 320), (32, 128), 128),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
    b5 = nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128),
                   Inception(832, 384, (192, 384), (48, 128), 128),
                   nn.AdaptiveAvgPool2d((1,1)),
                   nn.Flatten())

    net = nn.Sequential(b1, b2, b3, b4, b5, nn.Linear(1024, 10)).to(device, non_blocking=True)
    def init_weights(m):
        if type(m) in [nn.Linear, nn.Conv2d]:
            nn.init.xavier_uniform_(m.weight)
            nn.init.zeros_(m.bias)
    net.apply(init_weights)

    # 在FashionMNIST数据集上训练模型
    train_on_FashionMNIST('GoogLeNet')
2.2.4.3. 输出结果

GoogLeNet

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

连连看游戏

连通块记忆性递归的综合运用 这里x,y的设置反我平常的习惯,搞得我有点晕 实际上可以一输入就交换x,y的数据的 如果设置y1为全局变量的话会warning: warning: built-in function y1 declared as non-function 所以我改成p和q了…

Python---综合案例

一、系统需求分析 1、需求分析 使用面向对象编程思想完成学员管理系统的开发,具体如下: ① 系统要求:学员数据存储在文件中 ② 系统功能:添加学员、删除学员、修改学员信息、查询学员信息、显示所有学员信息、保存学员信息及退…

Kotlin基础——基础内容

文章目录 1 函数和变量1.1 基本程序1.2 函数1.3 变量1.3.1 变量的类型推导1.3.2 可变变量和不可变量1.3.3 变量使用规则 1.4 字符串模板 2 类和属性2.1 属性2.2 自定义访问器2.3 目录和包2.3.1 同包访问2.3.2 不同包导入2.3.3 包名类名定义规则 3 枚举和“when”3.1 声明枚举类…

软件测试之压力测试详解

一、什么是压力测试 软件测试中:压力测试(Stress Test),也称为强度测试、负载测试。压力测试是模拟实际应用的软硬件环境及用户使用过程的系统负荷,长时间或超大负荷地运行测试软件,来测试被测系统的性能、…

leetcode-19-删除链表的倒数第N个节点

题目: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5]示例 2: 输入:head [1], n 1 输出:[]示…

深度学习 Day15——P4猴痘病识别

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU(如果设备上支持GPU就使用GPU,否则使用C…

Swagger快速上手

快速开始&#xff1a; 导入maven包 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.7.0</version> </dependency><dependency><groupId>io.springfox<…

UDS DTC故障码格式

文章目录 DTC的定义DTC 故障码的分类DTC 故障码的组成1、OBD DTC 格式结构2、UDS DTC&#xff08;ISO 14229-1、ISO 15031-6&#xff09;格式结构 参考 DTC的定义 DTC&#xff0c;Diagnostic Trouble Code&#xff0c;诊断故障码&#xff0c;即 故障类型的 ID。 一个完整的DT…

【快速应用开发】看看RedwoodJS

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

CommonJs模块化实现原理ES Module模块化原理

CommonJs模块化实现原理 首先看一个案例 初始化项目 npm init npm i webpack -D目录结构如下&#xff1a; webpack.config.js const path require("path"); module.exports {mode: "development",entry: "./src/index.js",output: {path: p…

VBA信息获取与处理:在EXCEL中随机函数的利用

《VBA信息获取与处理》教程(版权10178984)是我推出第六套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。这部教程给大家讲解的内容有&#xff1a;跨应用程序信息获得、随机信息的利用、电子邮件的发送、VBA互…

助力工业生产质检,基于轻量级yolov5-seg开发构建工业场景下滚珠丝杠传动表面缺陷分割检测系统

AI赋能工业生产是一个强有力的方式&#xff0c;在我们之前的系列博文中也有很多相应的开发实践&#xff0c;感兴趣的胡都可以自行移步阅读&#xff0c;本文的核心思想就是想要基于轻量级的实例分割模型来开发构建工业场景下的滚珠丝杠传动表面缺陷分割检测系统&#xff0c;首先…

Openwrt源码下载出现“The remote end hung up unexpected”

最近项目原因需要下载openwrt21.02版本源码&#xff0c;花费了很多时间&#xff0c;找到正确方法后&#xff0c;发现可以节省很多时间&#xff0c;记录下过程&#xff0c;方便自己&#xff0c;可能方便他人。 一.问题阐述 openwrt21.02下载链接如下&#xff1a; git clone -…

Springboot入门篇

一、概述 Spring是一个开源框架&#xff0c;2003 年兴起的一个轻量级的Java 开发框架&#xff0c;作者Rod Johnson 。Spring是为了解决企业级应用开发的复杂性而创建的&#xff0c;简化开发。 1.1对比 对比一下 Spring 程序和 SpringBoot 程序。如下图 坐标 Spring 程序中的…

【华为数据之道学习笔记】3-11元数据管理

1. 产生元数据 &#xff08;1&#xff09;明确业务元数据、技术元数据和操作元数据之间的关系&#xff0c;定义华为公司元数据模型。 &#xff08;2&#xff09;针对找数据及获取数据难的痛点&#xff0c;明确业务元数据、技术元数据、操作元数据的设计原则。 1&#xff09;业务…

Pytorch-LSTM轴承故障一维信号分类(一)

目录 前言 1 数据集制作与加载 1.1 导入数据 第一步&#xff0c;导入十分类数据 第二步&#xff0c;读取MAT文件驱动端数据 第三步&#xff0c;制作数据集 第四步&#xff0c;制作训练集和标签 1.2 数据加载&#xff0c;训练数据、测试数据分组&#xff0c;数据分batch…

C++之STL算法(1)

STL容器算法主要由、、组成&#xff1b;   algorithm主要有遍历、比较、交换、查找、拷贝、修改等&#xff1b; 1.遍历容器for_each for_each()函数用于完成容器遍历&#xff0c;函数参数如下&#xff1a; for_each(_InIt _First, _InIt _Last, _Fn _Func) 形参&#xff1a…

mybatis多表映射-延迟加载,延迟加载的前提条件是:分步查询

1、建库建表 create database mybatis-example; use mybatis-example; create table t_book (bid varchar(20) primary key,bname varchar(20),stuid varchar(20) ); insert into t_book values(b001,Java,s001); insert into t_book values(b002,Python,s002); insert into …

基于 librosa和soundfile对音频进行重采样 (VITS 必备)

基于 librosa和soundfile对音频进行重采样 一、前言 在玩bert-vits2的时候有对音频进行重采样的需求&#xff0c;故写了一下批量对音频进行重采样的脚本。 优化点&#xff1a; 根据机器自适应线程数为最多&#xff0c;保证充分利用机器资源&#xff0c;提高速度>30%。支持…

UE引擎 LandscapeGrass 实现机制分析(UE5.2)

前言 随着电脑和手机硬件性能越来越高&#xff0c;游戏越来越追求大世界&#xff0c;而大世界非常核心的一环是植被&#xff0c;目前UE5引擎提供给植被生成的主流两种方式为 手刷植被和LandscapeGrass(WeightMap程序化植被)。当然UE5.3推出新一代PCGFramework 节点程序化生成框…