首页 > 其他分享 >Pytorch框架与经典卷积神经网络学习Day4|VGG原理与实战

Pytorch框架与经典卷积神经网络学习Day4|VGG原理与实战

时间:2025-01-16 19:28:45浏览次数:3  
标签:loss val nn Day4 VGG Pytorch train model data

目录

跟学视频

1.原理

1.1VGG网络诞生背景 

1.2VGG网络结构 

1.3VGG总结

2.实战

2.1model.py

2.2model_train.py

2.3model_test.py

跟学视频

炮哥带你学_Pytorch框架与经典卷积神经网络与实战

1.原理

VGG(Visual Geometry Group)是一个深度卷积神经网络架构,广泛应用于计算机视觉领域。VGG网络的主要特点是深度较大,使用较小的卷积核(3x3)来构建深度网络结构。VGG模型在很多应用中都得到了广泛使用,尤其是在以下几个领域:

  1. 图像分类:VGG模型是图像分类任务中常用的深度神经网络之一。它可以应用于从简单物体识别到复杂的多类图像分类任务中。例如,VGG16和VGG19是标准的图像分类模型。

  2. 物体检测:VGG常作为物体检测框架的基础网络之一。例如,在基于卷积神经网络的物体检测算法中,VGG可以作为特征提取网络来提取图像的高级特征,进一步用于检测、定位物体。

  3. 图像分割:VGG也常用于图像分割任务。通过将VGG作为特征提取部分,与解码器结合,能够进行像素级的图像分割。例如,U-Net和FCN等网络结构中都可以使用VGG作为骨干网络。

  4. 迁移学习:VGG模型因其深度和性能,广泛用于迁移学习。当训练数据有限时,可以通过预训练的VGG模型进行迁移学习,应用于医学影像分析、人脸识别等任务。

  5. 人脸识别:VGG也被用于一些面向人脸识别的任务,如人脸验证和人脸表情识别,主要通过对大规模人脸数据集的训练来获取有效的特征表示。

  6. 风格迁移与图像生成:VGG也常被应用于风格迁移任务,利用VGG的特征提取能力来提取图像的内容和风格,进行图像风格转换。

尽管VGG在一些任务中表现优异,但其计算量较大,尤其是VGG16和VGG19,由于参数较多,训练和推理的效率相对较低。因此,很多现代的网络架构(如ResNet、Inception等)在某些任务中逐渐取代了VGG。不过,由于其结构简单,VGG依然在很多学术研究和实际应用中有着较高的使用率。

VGG在目标检测中使用较多,因为结构简洁,可移植性较强。 

CNN——特征提取,提取特征图,再进行如分类、目标检测、实例分割、文字识别等操作。

2014年网络挑战赛,GoogLeNet冠军,VGG亚军。

相对应用来说,VGG用的较多,因为VGG可移植性较强与GoogLeNet。

在深度学习中,网络骨架(或叫网络架构骨架)指的是一个神经网络的基本结构或框架,定义了网络层的类型、层次结构和连接方式。网络骨架通常是指网络的高层设计,专注于网络的整体结构,具体的实现可以使用不同的神经网络组件和技术。

常见的网络骨架架构

  • VGGResNetGoogLeNet等都是深度学习中常见的网络骨架,它们定义了如何搭建卷积神经网络(CNN)来处理视觉任务。

1.1VGG网络诞生背景 

1.2VGG网络结构 

VGG参数多,1.38亿

 

 

 全局的kernel_size=3,使参数少,防止过拟合。

步幅越大,下采样越多。

下采样(Downsampling) 是指在数据处理中降低数据的分辨率或尺寸的过程,通常用于减少计算量、加速处理和提取高级特征。在深度学习中,下采样通常指的是通过卷积、池化等操作降低特征图的空间分辨率。

 

 每个卷积之后都有ReLU激活函数。

后面的RestNet解决神经网络够深,但效果不好的问题。

1.3VGG总结

(1)3*3效果也不错

(2)块状结构

(3)网络更深,效果也更好,参数也更多(后续不一定越深效果越好)

2.实战

2.1model.py

import torch
from torch import nn
from torchsummary import summary

class VGG16(nn.Module):
    def __init__(self):
        super(VGG16, self).__init__()
        self.block1 = nn.Sequential(   # Sequential功能是将网络的层组合到一起
            nn.Conv2d(in_channels=1, out_channels=64, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )
        self.block2 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )
        self.block3 = nn.Sequential(
            nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )
        self.block4 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )
        self.block5 = nn.Sequential(
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )
        self.block6 = nn.Sequential(
            nn.Flatten(),
            nn.Linear(7*7*512, 4096),
            nn.ReLU(),
            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Linear(4096, 10)
        )
        # 初始化
        for m in self.modules():  # 遍历模型的所有子模块
            if isinstance(m, nn.Conv2d):  # 如果当前模块是二维卷积层
                # 使用 Kaiming 正态分布初始化权重,适用于 ReLU 激活函数
                nn.init.kaiming_normal_(m.weight, nonlinearity='relu')
                if m.bias is not None:  # 如果该卷积层有偏置项
                    # 将偏置初始化为常数 0
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):  # 如果当前模块是全连接层
                # 使用正态分布初始化权重,均值为 0,标准差为 0.01
                nn.init.normal_(m.weight, 0, 0.01)
                if m.bias is not None:  # 如果该全连接层有偏置项
                    # 将偏置初始化为常数 0
                    nn.init.constant_(m.bias, 0)

    def forward(self, x):
        x = self.block1(x)
        x = self.block2(x)
        x = self.block3(x)
        x = self.block4(x)
        x = self.block5(x)
        x = self.block6(x)
        return x


if __name__ == '__main__':
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    model = VGG16().to(device)
    print(summary(model,(1, 224, 224)))

初始化 

# 初始化
        for m in self.modules():  # 遍历模型的所有子模块
            if isinstance(m, nn.Conv2d):  # 如果当前模块是二维卷积层
                # 使用 Kaiming 正态分布初始化权重,适用于 ReLU 激活函数
                nn.init.kaiming_normal_(m.weight, nonlinearity='relu')
                if m.bias is not None:  # 如果该卷积层有偏置项
                    # 将偏置初始化为常数 0
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):  # 如果当前模块是全连接层
                # 使用正态分布初始化权重,均值为 0,标准差为 0.01
                nn.init.normal_(m.weight, 0, 0.01)
                if m.bias is not None:  # 如果该全连接层有偏置项
                    # 将偏置初始化为常数 0
                    nn.init.constant_(m.bias, 0)

为什么这样初始化?

  • 卷积层:
    使用 Kaiming 初始化是为了避免深层网络中梯度的爆炸或消失,尤其适合 ReLU 激活函数。

  • 全连接层:
    使用小范围的正态分布初始化权重,确保网络在训练初期不会产生过大的激活值。

  • 偏置初始化为 0:
    偏置项为 0 是一种常见的策略,它不影响权重的梯度流,简化了模型的初始化过程。

2.2model_train.py

import copy
import time

import torch
from torchvision.datasets import FashionMNIST   # torchvision.datasets提供了多种常用的数据集接口,特别是用于图像处理和计算机视觉任务的数据集。
from torchvision import transforms  # torchvision.transforms提供了一般的图像转换操作类。
import torch.utils.data as Data  # torch.utils.data模块提供了用于加载和处理数据的工具。
import numpy as np
import matplotlib.pyplot as plt  # matplotlib.pyplot提供了类似MATLAB的绘图API。
from model import VGG16  # 从model.py中导入VGG16模型
import torch.nn as nn
import pandas as pd

def train_val_data_process():
    train_data = FashionMNIST(root='./data',  # 指定数据集下载或保存的路径,这里为当前目录下的 './data'
                              train=True,  # 加载训练集。如果设置为 False,则加载测试集
                              transform=transforms.Compose([  # 进行数据预处理和转换
                                  transforms.Resize(size=224),
                                  transforms.ToTensor()]),  # 将图像转换为 PyTorch 张量
                              download=True)  # 如果指定的目录下没有数据集,下载数据集
    train_data, val_data = Data.random_split(train_data, [round(0.8*len(train_data)), round(0.2*len(train_data))])

    train_dataloader = Data.DataLoader(dataset=train_data,
                                       batch_size=12,
                                       shuffle=True,
                                       num_workers=2)
    val_dataloader = Data.DataLoader(dataset=val_data,
                                       batch_size=12,
                                       shuffle=True,
                                       num_workers=2)

    return train_dataloader, val_dataloader


# 模型训练
def train_model_process(model, train_dataloader, val_dataloader, num_epochs):
    # 设定训练所用到的设备,有GPU则使用GPU,否则使用CPU
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 使用Adam优化器,学习率为0.001
    criterion = nn.CrossEntropyLoss()  # 使用交叉熵损失函数(回归一般使用均方误差损失函数,分类一般使用交叉熵损失函数)
    # 将模型放入到训练设备中
    model = model.to(device)
    # 复制当前模型的参数
    best_model_wts = copy.deepcopy(model.state_dict())

    # 初始化参数
    # 最高准确度
    best_acc = 0.0
    # 训练集损失列表
    train_loss_all = []
    # 验证集损失列表
    val_loss_all = []
    # 训练集准确度列表
    train_acc_all = []
    # 验证集准确度列表
    val_acc_all = []
    # 当前时间
    since = time.time()

    for epoch in range(num_epochs):
        print("Epoch {}/{}".format(epoch, num_epochs - 1))
        print("-"*10)

        # 初始化参数
        # 训练集损失函数
        train_loss = 0.0
        # 训练集准确度
        train_corrects = 0
        # 验证集损失函数
        val_loss = 0.0
        # 验证集准确度
        val_corrects = 0
        # 训练集样本数量
        train_num = 0
        # 验证集样本数量
        val_num = 0

        #对每一个mini-batch训练和计算
        for step, (b_x, b_y) in enumerate(train_dataloader):
            # 将特征放到训练设备中
            b_x = b_x.to(device)
            # 将标签放到训练设备中
            b_y = b_y.to(device)
            # 设置模型为训练模式
            model.train()

            # 前向传播过程,输入为一个batch,输出为一个batch中对应的预测
            output = model(b_x)
            # 查找每一行中最大值对应的行标
            pre_lab = torch.argmax(output, dim=1)
            # 计算每一个batch的损失函数
            loss = criterion(output, b_y)

            # 将梯度初始化为0,每一轮都要初始化,防止梯度累积
            optimizer.zero_grad()
            # 反向传播,计算梯度
            loss.backward()
            # 根据网络反向传播的梯度信息更新网络的参数,以起到降低loss函数计算值的作用
            optimizer.step()
            # 对损失函数进行累加
            train_loss += loss.item() * b_x.size(0)
            # 如果预测正确,则准确值train_corrects加1
            train_corrects += torch.sum(pre_lab == b_y.data)
            # 当前用于训练的样本数量
            train_num += b_x.size(0)
        for step, (b_x, b_y) in enumerate(val_dataloader):
            # 将特征放到验证设备中
            b_x = b_x.to(device)
            # 将标签放到验证设备中
            b_y = b_y.to(device)
            # 设置模型为评估模式
            model.eval()
            # 前向传播过程,输入为一个batch,输出为一个batch中对应的预测
            output = model(b_x)
            # 查找每一行中最大值对应的行标
            pre_lab = torch.argmax(output, dim=1)
            # 计算每一个batch的损失函数
            loss = criterion(output, b_y)

            # 对损失函数进行累加
            val_loss += loss.item() * b_x.size(0)
            # 如果预测正确,则准确值train_corrects加1
            val_corrects += torch.sum(pre_lab == b_y.data)
            # 当前用于验证的样本数量
            val_num += b_x.size(0)


        # 计算并保存每一次迭代的loss值和准确值
        # 计算并保存训练集的loss值
        train_loss_all.append(train_loss / train_num)
        # 计算并保存训练集的准确率
        train_acc_all.append(train_corrects.double().item() / train_num)

        # 计算并保存验证集的loss值
        val_loss_all.append(val_loss / val_num)
        # 计算并保存验证集的准确率
        val_acc_all.append(val_corrects.double().item() / val_num)
        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]))

        # 寻找最高准确度的权重
        if val_acc_all[-1] > best_acc:
            # 保存当前的最高准确度
            best_acc = val_acc_all[-1]
            # 保存当前最高准确度对应的模型参数
            best_model_wts = copy.deepcopy(model.state_dict())
        # 训练耗费时间
        time_use = time.time() - since
        print("训练和验证耗费时间:{:.0f}m {:.0f}s".format(time_use // 60, time_use % 60))


    # 选择最优参数
    # 加载最高准确率下的模型参数
    torch.save(best_model_wts, 'D:/code/pych/pytorch_learning/VGG16/best_model.pth')

    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

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.figure(figsize=(12, 4))
    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.legend()
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.show()


if __name__ == "__main__":
    # 实例化LeNet模型
    VGG16 = VGG16()
    train_dataloader, val_dataloader = train_val_data_process()
    train_process = train_model_process(VGG16, train_dataloader, val_dataloader, 20)
    matplot_acc_loss(train_process)

梯度消失,权重几乎不更新,一直不收敛,所以训练准确度低。

下面通过加上权重初始化,来使训练结果更加满足预期效果。

权重初始化对深度学习模型的训练至关重要。正确的初始化可以加快收敛速度,避免梯度消失或梯度爆炸问题,从而提升模型性能。在使用 VGG16 或类似的深度网络时,以下是几种常见的权重初始化方法及其代码实现。

2.3model_test.py

import torch
import torch.utils.data as Data
from torchvision import transforms
from torchvision.datasets import FashionMNIST
from model import VGG16


def test_data_process():
    test_data = FashionMNIST(root='./data',  # 指定数据集下载或保存的路径,这里为当前目录下的 './data'
                              train=False,  # 加载测试集。如果设置为 False,则加载测试集
                              transform=transforms.Compose([  # 进行数据预处理和转换
                                  transforms.Resize(size=224),
                                  transforms.ToTensor()]),  # 将图像转换为 PyTorch 张量
                              download=True)

    test_dataloader = Data.DataLoader(dataset=test_data,
                                       batch_size=1,
                                       shuffle=True,
                                       num_workers=0)

    return test_dataloader

def test_model_process(model, test_dataloader):
    # 设定训练所用到的设备,有GPU则使用GPU,否则使用CPU
    device = "cuda" if torch.cuda.is_available() else "cpu"
    # 将模型放入到测试设备中
    model = model.to(device)

    # 初始化参数
    test_correct = 0.0
    test_num = 0

    # 只进行前向传播,不进行梯度计算,从而节省内存,加快运行速度
    with torch.no_grad():
        for test_data_x, test_data_y in test_dataloader:
            # 将数据放入到测试设备中
            test_data_x = test_data_x.to(device)
            # 将标签放入到测试设备中
            test_data_y = test_data_y.to(device)
            # 将模型设置为评估模式
            model.eval()
            # 前向传播过程,输入为测试数据集,输出每个样本的预测值
            output = model(test_data_x)
            # 查找每一行中最大值对应的行标
            pre_lab = torch.argmax(output, dim=1)
            # 如果预测正确,则精确度test_correct加1
            test_correct += torch.sum(pre_lab == test_data_y.data)
            # 将所有的测试样本累加
            test_num += test_data_x.size(0)

    # 计算测试集的准确度
    test_acc = test_correct.double().item() / test_num
    print("测试的准确率为:", test_acc)



if __name__ == "__main__":
    # 加载模型
    model = VGG16()
    model.load_state_dict(torch.load("best_model.pth"))
    # 加载测试数据
    test_dataloader = test_data_process()
    # 加载模型测试的函数
    #test_model_process(model, test_dataloader)

    # 设定测试所用到的设备,有GPU则使用GPU,否则使用CPU
    device = "cuda" if torch.cuda.is_available() else "cpu"
    model = model.to(device)


    classes = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
    with torch.no_grad():
        for b_x, b_y in test_dataloader:
            b_x = b_x.to(device)
            b_y = b_y.to(device)
            model.eval()
            output = model(b_x)
            pre_lab = torch.argmax(output, dim=1)
            result = pre_lab.item()
            label = b_y.item()
            print("预测值:", classes[result], "-------", "真实值:", classes[label])

标签:loss,val,nn,Day4,VGG,Pytorch,train,model,data
From: https://blog.csdn.net/weixin_74106693/article/details/145171006

相关文章

  • PyTorch使用教程(3)-Tensor包
    1、张量Tensor张量(Tensor)是PyTorch深度学习框架中的核心数据结构,在PyTorch软件框架中,几乎所有的数据计算和信息流都是以Tensor的形式在表达。官方给出的定义是:一个torch.Tensor是一个包含单个数据类型元素的多维矩阵关键词单个数据类型:在一个张量数据结构内,只会包含......
  • PyTorch使用教程(2)-torch包
    1、简介torch包是PyTorch框架最外层的包,主要是包含了张量的创建和基本操作、随机数生成器、序列化、局部梯度操作的上下文管理器等等,内容很多。我们基础学习的时候,只有关注张量的创建、序列化,随机数、张量的数学数学计算等常用的点即可。2、什么是张量在PyTorch中,张量(Te......
  • Python|【Pytorch】基于小波时频图与SwinTransformer的轴承故障诊断研究
    ......
  • pytorch算子调用过程:以rand算子为例
    通过pytorch的torch.profiler带调用栈采集运行过程可以看到如下信息,通过chrome://tracing查看,图上每个小条条表示一个traceEvent,json中的信息如下图所示,其中cat表示traceEvent的类型,有cpu_op,python_function等,前者表示torch的cpp代码中定义的操作,后者表示pytorch的python代码......
  • 错误修改系列---基于RNN模型的心脏病预测(pytorch实现)
    前言前几天发布了pytorch实现,TensorFlow实现为:基于RNN模型的心脏病预测(tensorflow实现),但是一处繁琐地方+一处错误,这篇文章进行修改,修改效果还是好了不少;源文章为:基于RNN模型的心脏病预测,提供tensorflow和pytorch实现错误一这个也不算是错误,就是之前数据标准化、划分......
  • 从PyTorch入门到项目实战 | 基础知识篇 | 工欲善其事,必先利其器!详解PyTorch安装与环境
    从PyTorch入门到项目实战......
  • pytorch模型的保存失敗しましたが、
    目录简洁: 评估模式后缀区别保存模型(整个模型)加载过程:保存状态字典加载过程:总结把模型训练到一半保存,想下次接着训练,用那种保存方式保存模型和优化器状态字典加载模型和优化器状态字典如果保存整个模型,就不能继续训练吗、保存整个模型加载整个模型并继续训练......
  • PyTorch 微调代码完整示例:从模型训练到评估
    PyTorch微调代码完整示例:从模型训练到评估1.环境准备2.代码实现2.1导入必要的库2.2自定义数据集2.3定义模型2.4初始化模型、损失函数和优化器2.5准备数据2.6训练循环2.7模型评估3.代码说明4.总结在深度学习任务中,微调(Fine-tuning)是一个非常重要的步骤,尤......
  • 【Javascript Day4】三元运算符及循环(while、do while)
    目录三元运算符循环while循环do{ }while()循环案例三元运算符//0:女 1:男     varsex=1;    //编号的转换变量,基于编号的值提供显示文本    vartemp="";    if(sex===0){      temp="女";   ......
  • PyTorch团队为TorchAO引入1-8比特量化,提升ARM平台性能
    在深度学习模型部署和优化领域,计算效率与资源消耗的平衡一直是一个核心挑战。PyTorch团队针对这一问题推出了创新性的技术方案——在其原生低精度计算库TorchAO中引入低位运算符支持。这一技术突破不仅实现了1至8位精度的嵌入层权重量化,还支持了具有8位动态量化激活的线性运算符,为......