Pytorch | 从零构建GoogleNet对CIFAR10进行分类

news2024/12/22 14:36:20

Pytorch | 从零构建GoogleNet对CIFAR10进行分类

  • CIFAR10数据集
  • GoogleNet
    • 网络结构特点
    • 网络整体架构
    • 应用与影响
    • Inceptionv1到Inceptionv2
  • GoogleNet结构代码详解
    • 结构代码
    • 代码详解
      • Inception 类
        • 初始化方法
        • 前向传播 forward
      • GoogleNet 类
        • 初始化方法
        • 前向传播 forward
  • 训练过程和测试结果
  • 代码汇总
    • googlenet.py
    • train.py
    • test.py

前面文章我们构建了AlexNet、Vgg对CIFAR10进行分类:
Pytorch | 从零构建AlexNet对CIFAR10进行分类
Pytorch | 从零构建Vgg对CIFAR10进行分类
这篇文章我们来构建GoogleNet(或称GoogleNet-BN, Inception v2).

CIFAR10数据集

CIFAR-10数据集是由加拿大高级研究所(CIFAR)收集整理的用于图像识别研究的常用数据集,基本信息如下:

  • 数据规模:该数据集包含60,000张彩色图像,分为10个不同的类别,每个类别有6,000张图像。通常将其中50,000张作为训练集,用于模型的训练;10,000张作为测试集,用于评估模型的性能。
  • 图像尺寸:所有图像的尺寸均为32×32像素,这相对较小的尺寸使得模型在处理该数据集时能够相对快速地进行训练和推理,但也增加了图像分类的难度。
  • 类别内容:涵盖了飞机(plane)、汽车(car)、鸟(bird)、猫(cat)、鹿(deer)、狗(dog)、青蛙(frog)、马(horse)、船(ship)、卡车(truck)这10个不同的类别,这些类别都是现实世界中常见的物体,具有一定的代表性。

下面是一些示例样本:
在这里插入图片描述

GoogleNet

GoogleNet是由Google团队在2014年提出的一种深度卷积神经网络架构,以下是对它的详细介绍:

网络结构特点

  • Inception模块:这是GoogleNet的核心创新点。Inception模块通过并行使用不同大小的卷积核(如1×1、3×3、5×5)和池化操作,然后将它们的结果在通道维度上进行拼接,从而可以同时提取不同尺度的特征。例如,1×1卷积核可以用于在不改变特征图尺寸的情况下进行降维或升维,减少计算量;3×3和5×5卷积核则可以捕捉不同感受野的特征。
  • 深度和宽度:GoogleNet网络很深,共有22层,但它的参数量却比同层次的一些网络少很多,这得益于Inception模块的高效设计。同时,网络的宽度也较大,能够学习到丰富的特征表示。
  • 辅助分类器:为了缓解梯度消失问题,GoogleNet在网络中间层添加了两个辅助分类器。这些辅助分类器在训练过程中与主分类器一起进行反向传播,帮助梯度更好地传播到浅层网络,加快训练速度并提高模型的泛化能力。在测试时,辅助分类器的结果会被加权融合到主分类器的结果中。

网络整体架构

  • 输入层:接收大小为 H × W × 3 H×W×3 H×W×3的图像数据,其中 H H H W W W表示图像的高度和宽度,3表示图像的RGB通道数。

  • 卷积层和池化层:网络的前面几层主要由卷积层和池化层组成,用于提取图像的基本特征。这些层逐渐降低图像的分辨率,同时增加特征图的通道数。

  • Inception模块组:网络的主体部分由多个Inception模块组构成,每个模块组包含多个Inception模块。随着网络的深入,Inception模块的输出通道数逐渐增加,以学习更高级的特征。
    在这里插入图片描述

  • 池化层和全连接层:在Inception模块组之后,网络通过一个平均池化层将特征图的尺寸缩小到1×1,然后将其展平并连接到一个全连接层,最后通过一个Softmax层输出分类结果。

应用与影响

  • 图像分类:GoogleNet在图像分类任务上取得了非常好的效果,在ILSVRC 2014图像分类竞赛中获得了冠军。它能够准确地识别各种自然图像中的物体类别,如猫、狗、汽车、飞机等。
  • 目标检测:GoogleNet也可以应用于目标检测任务,通过在网络中添加一些额外的检测层和算法,可以实现对图像中物体的定位和检测。
  • 后续研究基础:GoogleNet的成功推动了深度学习领域的发展,其Inception模块的设计思想为后来的许多网络架构提供了灵感,如Inception系列的后续版本以及其他一些基于多分支结构的网络。

Inceptionv1到Inceptionv2

上面所提到的 Inception 模块组,我们称之为 Inception v1,而后谷歌又对其进行优化,体现在本文的代码中的即:

  • 引入了Batch Normalization (BN)层:Inception v1 没有 BN 层,而 Inception v2 在每个卷积层之后引入了 BN 层。这有助于解决深层网络中的梯度消失问题,使每一层的输入更加稳定,从而加快训练过程并提高模型的收敛速度.
  • 优化卷积核组合Inception v1 中使用 1x1、3x3、5x5 的卷积核和 3x3 的池化操作并行组合。Inception v2 学习 VGG 网络的做法,用两个 3x3 的卷积核替代 Inception 模块中的 5x5 卷积核,减少了参数数量,同时增加了网络的非线性表达能力

GoogleNet结构代码详解

结构代码

import torch
import torch.nn as nn


class Inception(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3reduc, ch3x3, ch5x5reduc, ch5x5, pool_proj):
        super().__init__()
        self.branch1x1 = nn.Sequential(
            nn.Conv2d(in_channels, ch1x1, kernel_size=1),
            nn.BatchNorm2d(ch1x1),
            nn.ReLU(inplace=True)
        )

        self.branch3x3 = nn.Sequential(
            nn.Conv2d(in_channels, ch3x3reduc, kernel_size=1),
            nn.BatchNorm2d(ch3x3reduc),
            nn.ReLU(inplace=True),
            nn.Conv2d(ch3x3reduc, ch3x3, kernel_size=3, padding=1),
            nn.ReLU(inplace=True)
        )

        self.branch5x5 = nn.Sequential(
            nn.Conv2d(in_channels, ch5x5reduc, kernel_size=1),
            nn.BatchNorm2d(ch5x5reduc),
            nn.ReLU(inplace=True),
            nn.Conv2d(ch5x5reduc, ch5x5, kernel_size=3, padding=1),
            nn.BatchNorm2d(ch5x5),
            nn.ReLU(inplace=True),
            nn.Conv2d(ch5x5, ch5x5, kernel_size=3, padding=1),
            nn.BatchNorm2d(ch5x5),
            nn.ReLU(inplace=True)
        )

        self.branch_pool = nn.Sequential(
            nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
            nn.Conv2d(in_channels, pool_proj, kernel_size=1),
            nn.BatchNorm2d(pool_proj),
            nn.ReLU(inplace=True)
        )

    def forward(self, x):
        branch1x1 = self.branch1x1(x)
        branch3x3 = self.branch3x3(x)
        branch5x5 = self.branch5x5(x)
        branch_pool = self.branch_pool(x)

        return torch.cat([branch1x1, branch3x3, branch5x5, branch_pool], 1)


class GoogleNet(nn.Module):
    def __init__(self, num_classes):
        super(GoogleNet, self).__init__()
        self.prelayers = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 192, kernel_size=3, padding=1),
            nn.BatchNorm2d(192),
            nn.ReLU(inplace=True)
        )
        self.maxpool2 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        
        self.inception3a = Inception(192, 64, 96, 128, 16, 32, 32)
        self.inception3b = Inception(256, 128, 128, 192, 32, 96, 64)
        self.maxpool3 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        self.inception4a = Inception(480, 192, 96, 208, 16, 48, 64)
        self.inception4b = Inception(512, 160, 112, 224, 24, 64, 64)
        self.inception4c = Inception(512, 128, 128, 256, 24, 64, 64)
        self.inception4d = Inception(512, 112, 144, 288, 32, 64, 64)
        self.inception4e = Inception(528, 256, 160, 320, 32, 128, 128)
        self.maxpool4 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        self.inception5a = Inception(832, 256, 160, 320, 32, 128, 128)
        self.inception5b = Inception(832, 384, 192, 384, 48, 128, 128)

        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.dropout = nn.Dropout(0.4)
        self.fc = nn.Linear(1024, num_classes)

    def forward(self, x):
        x = self.prelayers(x)
        x = self.maxpool2(x)

        x = self.inception3a(x)
        x = self.inception3b(x)
        x = self.maxpool3(x)

        x = self.inception4a(x)
        x = self.inception4b(x)
        x = self.inception4c(x)
        x = self.inception4d(x)
        x = self.inception4e(x)
        x = self.maxpool4(x)

        x = self.inception5a(x)
        x = self.inception5b(x)

        x = self.avgpool(x)
        x = self.dropout(x)
        x = x.view(x.size()[0], -1)
        x = self.fc(x)

        return x

代码详解

以下是对上述代码的详细解释,这段Python代码使用PyTorch库构建了经典的GoogleNet(Inception v1)网络结构,用于图像分类任务,以下从不同部分展开介绍:

Inception 类

这个类定义了GoogleNet中的Inception模块,它的作用是通过不同尺寸的卷积核等操作来并行提取特征,然后将这些特征在通道维度上进行拼接。

初始化方法
  • 参数说明
    • in_channels:输入特征图的通道数,即输入数据的深度维度。
    • ch1x1ch3x3reducch3x3ch5x5reducch5x5pool_proj:分别对应不同分支中卷积操作涉及的通道数等参数,用于配置每个分支的结构。
  • 网络结构构建
    • self.branch1x1:构建了一个包含1×1卷积、批归一化(BatchNorm)和ReLU激活函数的顺序结构。1×1卷积用于在不改变特征图尺寸的情况下调整通道数,批归一化有助于加速训练和提高模型稳定性,ReLU激活函数引入非线性变换。
    • self.branch3x3:先是一个1×1卷积进行通道数的降维(减少计算量),接着经过批归一化和ReLU激活,然后是一个3×3卷积(通过padding=1保证特征图尺寸不变),最后再接ReLU激活。
    • self.branch5x5:结构相对更复杂些,先是1×1卷积和批归一化、ReLU激活,然后连续两个3×3卷积(都通过合适的padding保证尺寸不变),中间穿插批归一化和ReLU激活,用于提取更复杂的特征。
    • self.branch_pool:先进行最大池化(MaxPool2d,通过特定参数设置保证尺寸基本不变),然后接1×1卷积来调整通道数,再进行批归一化和ReLU激活。
前向传播 forward
  • 接收输入张量x,分别将其传入上述四个分支结构中,得到四个分支的输出branch1x1branch3x3branch5x5branch_pool
  • 最后通过torch.cat函数沿着通道维度(维度1,即参数中的1)将这四个分支的输出特征图拼接在一起,作为整个Inception模块的输出。

GoogleNet 类

这是整个网络的主体类,将多个Inception模块以及其他必要的层组合起来构建完整的GoogleNet架构。

初始化方法
  • 参数说明
    • num_classes:表示分类任务的类别数量,用于最终全连接层输出对应数量的类别预测结果。
  • 网络结构构建
    • self.prelayers:由一系列的卷积、批归一化和ReLU激活函数组成的顺序结构,用于对输入图像进行初步的特征提取,逐步将输入的3通道(对应RGB图像)特征图转换为192通道的特征图。
    • self.maxpool2:一个最大池化层,用于下采样,减小特征图尺寸,同时增大感受野,步长为2,按一定的padding设置来控制输出尺寸。
    • 接下来依次定义了多个Inception模块,如self.inception3aself.inception3b等,它们的输入通道数和各分支的配置参数不同,随着网络的深入逐渐提取更高级、更复杂的特征,并且中间穿插了几个最大池化层(self.maxpool3self.maxpool4等)进行下采样操作。
    • self.avgpool:自适应平均池化层,将不同尺寸的特征图转换为固定大小(这里是1×1)的特征图,方便后续的全连接层处理。
    • self.dropout:引入Dropout层,概率设置为0.4,在训练过程中随机丢弃部分神经元连接,防止过拟合。
    • self.fc:全连接层,将经过前面处理后的特征映射到指定的num_classes个类别上,用于最终的分类预测。
前向传播 forward
  • 首先将输入x传入self.prelayers进行初步特征提取,然后经过self.maxpool2下采样。
  • 接着依次将特征图传入各个Inception模块,并穿插经过最大池化层进行下采样,不断提取和整合特征。
  • 经过最后的Inception模块后,特征图通过self.avgpool进行平均池化,再经过self.dropout进行随机失活处理,然后通过x.view函数将特征图展平成一维向量(方便全连接层处理),最后传入self.fc全连接层得到最终的分类预测结果并返回。

训练过程和测试结果

训练过程损失函数变化曲线:
在这里插入图片描述

训练过程准确率变化曲线:
在这里插入图片描述

测试结果:
在这里插入图片描述

代码汇总

项目github地址
项目结构:

|--data
|--models
	|--__init__.py
	|--googlenet.py
	|--...
|--results
|--weights
|--train.py
|--test.py

googlenet.py

import torch
import torch.nn as nn


class Inception(nn.Module):
    def __init__(self, in_channels, ch1x1, ch3x3reduc, ch3x3, ch5x5reduc, ch5x5, pool_proj):
        super().__init__()
        self.branch1x1 = nn.Sequential(
            nn.Conv2d(in_channels, ch1x1, kernel_size=1),
            nn.BatchNorm2d(ch1x1),
            nn.ReLU(inplace=True)
        )

        self.branch3x3 = nn.Sequential(
            nn.Conv2d(in_channels, ch3x3reduc, kernel_size=1),
            nn.BatchNorm2d(ch3x3reduc),
            nn.ReLU(inplace=True),
            nn.Conv2d(ch3x3reduc, ch3x3, kernel_size=3, padding=1),
            nn.ReLU(inplace=True)
        )

        self.branch5x5 = nn.Sequential(
            nn.Conv2d(in_channels, ch5x5reduc, kernel_size=1),
            nn.BatchNorm2d(ch5x5reduc),
            nn.ReLU(inplace=True),
            nn.Conv2d(ch5x5reduc, ch5x5, kernel_size=3, padding=1),
            nn.BatchNorm2d(ch5x5),
            nn.ReLU(inplace=True),
            nn.Conv2d(ch5x5, ch5x5, kernel_size=3, padding=1),
            nn.BatchNorm2d(ch5x5),
            nn.ReLU(inplace=True)
        )

        self.branch_pool = nn.Sequential(
            nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
            nn.Conv2d(in_channels, pool_proj, kernel_size=1),
            nn.BatchNorm2d(pool_proj),
            nn.ReLU(inplace=True)
        )

    def forward(self, x):
        branch1x1 = self.branch1x1(x)
        branch3x3 = self.branch3x3(x)
        branch5x5 = self.branch5x5(x)
        branch_pool = self.branch_pool(x)

        return torch.cat([branch1x1, branch3x3, branch5x5, branch_pool], 1)


class GoogleNet(nn.Module):
    def __init__(self, num_classes):
        super(GoogleNet, self).__init__()
        self.prelayers = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 192, kernel_size=3, padding=1),
            nn.BatchNorm2d(192),
            nn.ReLU(inplace=True)
        )
        self.maxpool2 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        
        self.inception3a = Inception(192, 64, 96, 128, 16, 32, 32)
        self.inception3b = Inception(256, 128, 128, 192, 32, 96, 64)
        self.maxpool3 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        self.inception4a = Inception(480, 192, 96, 208, 16, 48, 64)
        self.inception4b = Inception(512, 160, 112, 224, 24, 64, 64)
        self.inception4c = Inception(512, 128, 128, 256, 24, 64, 64)
        self.inception4d = Inception(512, 112, 144, 288, 32, 64, 64)
        self.inception4e = Inception(528, 256, 160, 320, 32, 128, 128)
        self.maxpool4 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        self.inception5a = Inception(832, 256, 160, 320, 32, 128, 128)
        self.inception5b = Inception(832, 384, 192, 384, 48, 128, 128)

        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.dropout = nn.Dropout(0.4)
        self.fc = nn.Linear(1024, num_classes)

    def forward(self, x):
        x = self.prelayers(x)
        x = self.maxpool2(x)

        x = self.inception3a(x)
        x = self.inception3b(x)
        x = self.maxpool3(x)

        x = self.inception4a(x)
        x = self.inception4b(x)
        x = self.inception4c(x)
        x = self.inception4d(x)
        x = self.inception4e(x)
        x = self.maxpool4(x)

        x = self.inception5a(x)
        x = self.inception5b(x)

        x = self.avgpool(x)
        x = self.dropout(x)
        x = x.view(x.size()[0], -1)
        x = self.fc(x)

        return x

train.py

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
from models import *
import matplotlib.pyplot as plt

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

# 定义数据预处理操作
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.491, 0.482, 0.446), (0.247, 0.243, 0.261))])

# 加载CIFAR10训练集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=False, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128,
                                          shuffle=True, num_workers=2)

# 定义设备(GPU优先,若可用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 实例化模型
model_name = 'GoogleNet'
if model_name == 'AlexNet':
    model = AlexNet(num_classes=10).to(device)
elif model_name == 'Vgg_A':
    model = Vgg(cfg_vgg='A', num_classes=10).to(device)
elif model_name == 'Vgg_A-LRN':
    model = Vgg(cfg_vgg='A-LRN', num_classes=10).to(device)
elif model_name == 'Vgg_B':
    model = Vgg(cfg_vgg='B', num_classes=10).to(device)
elif model_name == 'Vgg_C':
    model = Vgg(cfg_vgg='C', num_classes=10).to(device)
elif model_name == 'Vgg_D':
    model = Vgg(cfg_vgg='D', num_classes=10).to(device)
elif model_name == 'Vgg_E':
    model = Vgg(cfg_vgg='E', num_classes=10).to(device)
elif model_name == 'GoogleNet':
    model = GoogleNet(num_classes=10).to(device)

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练轮次
epochs = 15

def train(model, trainloader, criterion, optimizer, device):
    model.train()
    running_loss = 0.0
    correct = 0
    total = 0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data[0].to(device), data[1].to(device)

        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        _, predicted = outputs.max(1)
        total += labels.size(0)
        correct += predicted.eq(labels).sum().item()

    epoch_loss = running_loss / len(trainloader)
    epoch_acc = 100. * correct / total
    return epoch_loss, epoch_acc

if __name__ == "__main__":
    loss_history, acc_history = [], []
    for epoch in range(epochs):
        train_loss, train_acc = train(model, trainloader, criterion, optimizer, device)
        print(f'Epoch {epoch + 1}: Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.2f}%')
        loss_history.append(train_loss)
        acc_history.append(train_acc)
        # 保存模型权重,每5轮次保存到weights文件夹下
        if (epoch + 1) % 5 == 0:
            torch.save(model.state_dict(), f'weights/{model_name}_epoch_{epoch + 1}.pth')
    
    # 绘制损失曲线
    plt.plot(range(1, epochs+1), loss_history, label='Loss', marker='o')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.title('Training Loss Curve')
    plt.legend()
    plt.savefig(f'results\\{model_name}_train_loss_curve.png')
    plt.close()

    # 绘制准确率曲线
    plt.plot(range(1, epochs+1), acc_history, label='Accuracy', marker='o')
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy (%)')
    plt.title('Training Accuracy Curve')
    plt.legend()
    plt.savefig(f'results\\{model_name}_train_acc_curve.png')
    plt.close()

test.py

import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from models import *

import ssl
ssl._create_default_https_context = ssl._create_unverified_context
# 定义数据预处理操作
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.491, 0.482, 0.446), (0.247, 0.243, 0.261))])

# 加载CIFAR10测试集
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=128,
                                         shuffle=False, num_workers=2)

# 定义设备(GPU优先,若可用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 实例化模型
model_name = 'GoogleNet'
if model_name == 'AlexNet':
    model = AlexNet(num_classes=10).to(device)
elif model_name == 'Vgg_A':
    model = Vgg(cfg_vgg='A', num_classes=10).to(device)
elif model_name == 'Vgg_A-LRN':
    model = Vgg(cfg_vgg='A-LRN', num_classes=10).to(device)
elif model_name == 'Vgg_B':
    model = Vgg(cfg_vgg='B', num_classes=10).to(device)
elif model_name == 'Vgg_C':
    model = Vgg(cfg_vgg='C', num_classes=10).to(device)
elif model_name == 'Vgg_D':
    model = Vgg(cfg_vgg='D', num_classes=10).to(device)
elif model_name == 'Vgg_E':
    model = Vgg(cfg_vgg='E', num_classes=10).to(device)
elif model_name == 'GoogleNet':
    model = GoogleNet(num_classes=10).to(device)

criterion = nn.CrossEntropyLoss()

# 加载模型权重
weights_path = f"weights/{model_name}_epoch_15.pth"  
model.load_state_dict(torch.load(weights_path, map_location=device))

def test(model, testloader, criterion, device):
    model.eval()
    running_loss = 0.0
    correct = 0
    total = 0
    with torch.no_grad():
        for data in testloader:
            inputs, labels = data[0].to(device), data[1].to(device)
            outputs = model(inputs)
            loss = criterion(outputs, labels)

            running_loss += loss.item()
            _, predicted = outputs.max(1)
            total += labels.size(0)
            correct += predicted.eq(labels).sum().item()

    epoch_loss = running_loss / len(testloader)
    epoch_acc = 100. * correct / total
    return epoch_loss, epoch_acc

if __name__ == "__main__":
    test_loss, test_acc = test(model, testloader, criterion, device)
    print(f"================{model_name} Test================")
    print(f"Load Model Weights From: {weights_path}")
    print(f'Test Loss: {test_loss:.4f}, Test Acc: {test_acc:.2f}%')

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

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

相关文章

PCIe_Host驱动分析_地址映射

往期内容 本文章相关专栏往期内容,PCI/PCIe子系统专栏: 嵌入式系统的内存访问和总线通信机制解析、PCI/PCIe引入 深入解析非桥PCI设备的访问和配置方法 PCI桥设备的访问方法、软件角度讲解PCIe设备的硬件结构 深入解析PCIe设备事务层与配置过程 PCIe的三…

jenkins 出现 Jenkins: 403 No valid crumb was included in the request

文章目录 前言解决方式:1.跨站请求为找保护勾选"代理兼容"2.全局变量或者节点上添加环境变量3.(可选)下载插件 the strict Crumb Issuer plugin4.重启 前言 jenkins运行时间长了,经常出现点了好几次才能构建,然后报了Je…

CentOS 7 安装、测试和部署FastDFS

目录 FastDFS环境搭建 安装 libfastcommon 库 安装FastDFS 查看编译后的文件 FastDFS配置 FastDFS启动 启动tracker服务 启动storage服务 查看storage是否已经注册到了tracker下 查看存储文件的目录 FastDFS重启 FastDFS关闭 使用fdfs_test进行测试 修改client.co…

【WRF教程第3.1期】预处理系统 WPS 详解:以4.5版本为例

预处理系统 WPS 详解:以4.5版本为例 每个 WPS 程序的功能程序1:geogrid程序2:ungrib程序3:metgrid WPS运行(Running the WPS)步骤1:Define model domains with geogrid步骤2:Extract…

Flutter组件————FloatingActionButton

FloatingActionButton 是Flutter中的一个组件,通常用于显示一个圆形的按钮,它悬浮在内容之上,旨在吸引用户的注意力,并代表屏幕上的主要动作。这种按钮是Material Design的一部分,通常放置在页面的右下角,但…

在Windows11上编译C#的实现Mono的步骤

在Windows11上编译Mono的步骤 1、 在win11打开开发者模式,在更新和安全选项里,如下图: 2、下载并安装64位的cygwin, 下载网站:www.cygwin.com 3、 安装 Visual Studio 2015 or later 的社区版本。 4、 下载Mono的windows最新版本。 5、 在cmd.exe里运行下面的命令来安…

[HNCTF 2022 Week1]你想学密码吗?

下载附件用记事本打开 把这些代码放在pytho中 # encode utf-8 # python3 # pycryptodemo 3.12.0import Crypto.PublicKey as pk from hashlib import md5 from functools import reducea sum([len(str(i)) for i in pk.__dict__]) funcs list(pk.__dict__.keys()) b reduc…

【记录50】uniapp安装uview插件,样式引入失败分析及解决

SassError: Undefined variable: "$u-border-color". 表示样式变量$u-border-color没定义&#xff0c;实际是定义的 首先确保安装了scss/sass 其次&#xff0c;根目录下 app.vue中是否全局引入 <style lang"scss">import /uni_modules/uview-ui/in…

如何写申请essay

俗话说&#xff1a;万事开头难。英国留学申请essay也是如此。申请essay怎么写呢&#xff1f;一篇essay的开头是否精彩直接关系到导师能否被你的文字吸引。一把而言&#xff0c;招生官每天阅读的essay在200封以上&#xff0c;每篇阅读在12分钟以内&#xff0c;所以你的essay开头…

14-zookeeper环境搭建

0、环境 java&#xff1a;1.8zookeeper&#xff1a;3.5.6 1、下载 zookeeper下载点击这里。 2、安装 下载完成后解压&#xff0c;放到你想放的目录里。先看一下zookeeper的目录结构&#xff0c;如下图&#xff1a; 进入conf目录&#xff0c;复制zoo_sample.cfg&#xff0…

【UE5】pmx导入UE5,套动作。(防止“气球人”现象。

参考视频&#xff1a;UE5Animation 16: MMD模型與動作導入 (繁中自動字幕) 问题所在&#xff1a; 做法记录&#xff08;自用&#xff09; 1.导入pmx&#xff0c;删除这两个。 2.转换给blender&#xff0c;清理节点。 3.导出时&#xff0c;内嵌贴图&#xff0c;选“复制”。 …

yolo 视频流播放并进行目标识别

根据视频流&#xff0c;实时的进行目标识别 一、下载 [lal](https://github.com/q191201771/lal/releases/tag/v0.37.4)二、安装 [FFmpeg](https://ffmpeg.org/)三、完整代码演示 需要前置了解YOLO的完整操作 使用labelImg标注&#xff0c;YOLO进行目标训练 一、下载 lal 下载…

分类模型的预测概率解读:3D概率分布可视化的直观呈现

背景 在分类模型中&#xff0c;预测概率不仅是结果&#xff0c;更是模型决策的关键依据。为了更直观地理解这些概率分布&#xff0c;3D可视化提供了一种生动的展示方式&#xff0c;本文通过3D概率分布图&#xff0c;直观展示分类模型的预测概率 代码实现 基于时间序列的3D分…

【Spring】获取Bean对象需要哪些注解

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;Service&#xff08;服务存储&#xff09; 1&#xff1a;存储bean的代码 2&#xff1…

【C++】哈希表实现

目录 一、哈希概念 1.1 直接定址法 1.2 哈希冲突 1.3 负载因子 1.4 将关键字转为整数 二、哈希函数 2.1 除法散列法/除留余数法 2.2 乘法散列图&#xff08;了解即可&#xff09; 2.3 全域散列法&#xff08;了解即可&#xff09; ​编辑 三、处理哈希冲突 3.1 开放…

Android-相对布局RelativeLayout

相对布局在摆放子视图位置时&#xff0c;按照指定的参考系来摆放子视图的位置&#xff0c;默认以屏幕左上角(0,0)位置作为参考系摆放位置 了解一下接下来都会以代码的方式可视化出来 属性 可选值 说明 layout_alignParentTop true/false 是否让控件相对于父容器顶部对齐 …

Intellij配置scala运行环境

文章目录 Intellij配置scala运行环境下载地址安装插件设置sdk与scala scala项目创建安装可能出现的错误 Intellij配置scala运行环境 下载地址 在centos7上安装intellij https://www.jetbrains.com/idea/download/other.html解压后进入文件夹启动打开ide ./idea-IC-232.1033…

【批量生成WORD和PDF文件】根据表格内容和模板文件批量创建word文件,一次性生成多个word文档和批量创建PDF文件

如何按照Word模板和表格的数据快速制作5000个word文档 &#xff1f; 在与客户的合作的中需要创建大量的合同&#xff0c;这些合同的模板大概都是一致的&#xff0c;是不是每次我们都需要填充不一样的数据来完成&#xff1f; 今天用表格数据完成合同模板的填充&#xff0c;批量…

深度网络结构中的梯度消失与爆炸原理分析

原理 梯度消失的定义 在深度神经网络中&#xff0c;梯度消失是指在误差反向传播过程中&#xff0c;接近输入层的层次上梯度趋近于零的现象。这导致网络权重的更新非常缓慢&#xff0c;甚至停止&#xff0c;使得训练过程变得极其困难。主要发生在使用Sigmoid或Tanh等饱和激活函…

请求go web后端接口 java安卓端播放视频

前端代码 添加gradle依赖 implementation com.squareup.retrofit2:retrofit:2.9.0 implementation com.squareup.retrofit2:converter-gson:2.9.0 添加访问网络权限 <uses-permission android:name"android.permission.INTERNET" />允许http 请求请求 andro…