当前位置: 首页 > news >正文

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

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 nnclass 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 nnclass 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 pltimport 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 = 15def train(model, trainloader, criterion, optimizer, device):model.train()running_loss = 0.0correct = 0total = 0for 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 / totalreturn epoch_loss, epoch_accif __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.0correct = 0total = 0with 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 / totalreturn epoch_loss, epoch_accif __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}%')

相关文章:

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

Pytorch | 从零构建GoogleNet对CIFAR10进行分类 CIFAR10数据集GoogleNet网络结构特点网络整体架构应用与影响Inceptionv1到Inceptionv2 GoogleNet结构代码详解结构代码代码详解Inception 类初始化方法前向传播 forward GoogleNet 类初始化方法前向传播 forward 训练过程和测试结…...

蓝桥杯刷题——day9

蓝桥杯刷题——day9 题目一题干解题思路一代码解题思路二代码 题目二题干解题思路代码 题目一 题干 小蓝最近在研究一种浮点数的表示方法:R格式。对于一个大于0的浮点数d,可以用R格式的整数来表示。给定一个转换参数n,将浮点数转换为R格式整…...

ffmpeg翻页转场动效的安装及使用

文章目录 前言一、背景二、选型分析2.1 ffmpeg自带的xfade滤镜2.2 ffmpeg使用GL Transition库2.3 xfade-easing项目三、安装3.1、安装依赖([参考](https://trac.ffmpeg.org/wiki/CompilationGuide/macOS#InstallingdependencieswithHomebrew))3.2、获取ffmpeg源码3.3、融合xf…...

分布式刚度编织,让可穿戴触觉更出色 ——Haptiknit

大家好!今天来了解一项非常有趣的科技成果 ——“Haptiknit:用于可穿戴触觉的分布式刚度编织”——《Haptiknit: Distributed stiffness knitting for wearable haptics》发表于《SCIENCE ROBOTICS》。在现代科技发展中,可穿戴触觉设备越来越…...

Elasticsearch:什么是查询语言?

查询语言定义 查询语言包括数据库查询语言 (database query language - DQL),是一种用于查询和从数据库检索信息的专用计算机语言。它充当用户和数据库之间的接口,使用户能够管理来自数据库管理系统 (database management system - DBMS) 的数据。 最广…...

PyQt介绍

**PyQt 和 PySide (Qt for Python) 简介** **PyQt** 和 **PySide** 是 Python 中用于开发图形用户界面 (GUI) 应用程序的两个主要框架,它们都是基于 Qt 库的绑定。Qt 是一个跨平台的应用程序开发框架,广泛用于创建图形用户界面、应用程序开发以及嵌入式…...

Oracle 数据库函数的用法(一)

Oracle数据库提供了大量的内置函数,可以用于完成各种操作,如字符串操作,数学计算,日期时间处理,条件判断,序列生成,聚合统计等。以下是一些常用的Oracle数据库函数: 一、oracle 使用…...

labelme标签批量转换数据集json_to_dataset

文章目录 labelme标签批量转换数据集json_to_dataset转换原理单张图片转换多张图片批量转换bat脚本循环法 标注图片提取标注图片转单通道 labelme标签批量转换数据集json_to_dataset 转自labelme批量制作数据集教程。 转换原理 在安装了labelme的虚拟环境中有一个labelme_js…...

《QT 5.14.1 搭建 opencv 环境全攻略》

《QT 5.14.1 搭建 opencv 环境全攻略》 一、引言二、准备工作(一)软件下载(二)系统环境确认 三、安装 QT 5.14.1(一)安装包下载与运行(二)环境变量配置 四、OpenCV 安装与配置&#…...

Sentry日志管理thinkphp8 tp8 sentry9 sentry8 php8.x配置步骤, tp8自定义异常处理类使用方法

tp8的默认使用的就是composer来管理第三方包, 所以直接使用 composer 来安装 sentry9 即可. 同时tp8和tp5的配置方式不太一样, 这里我们直接使用自定义异常类来处理Sentry的异常. 1. 安装 sentry9 包 # 安装 sentry9 包 composer require "tekintian/sentry9-php" …...

MySQL 基础:开启数据库之旅

MySQL 基础:开启数据库之旅 在当今数字化的时代,数据扮演着至关重要的角色,而数据库管理系统则是存储、管理和操作这些数据的强大工具。MySQL 作为一款广受欢迎的开源关系型数据库管理系统,被广泛应用于各类网站、应用程序以及企业…...

OpenTK 中帧缓存的深度解析与应用实践

摘要: 本文深入探讨了 OpenTK 中帧缓存的使用。首先介绍了帧缓存的基本概念与在图形渲染管线中的关键地位,包括其与颜色缓存、深度缓存、模板缓存等各类缓存的关联。接着详细阐述了帧缓存对象(FBO)的创建、绑定与解绑等操作,深入分析了纹理附件、渲染缓冲区附件在 FBO 中的…...

stm32制作CAN适配器5--WinUsb上位机编写

上次我们要stm32制作了一个基于winusb有canfd适配器,今天我们来制作一个上位机程序来进行报文收发。 上位机还是用以前写好的,只是更改下dll文件。 项目链接器,输入,附加依赖项中增加winusb.lib winusb初始化:#incl…...

【时间之外】IT人求职和创业应知【71】-专利费

目录 2025 ICT产业趋势年会召开,2024年度ICT十大新闻重磅揭晓 海纳致远数字科技申请定制化插件驱动的数据分析专利 阿波罗智联取得语音数据的处理方法、装置、设备和存储介质专利 心勿贪,贵知足。 感谢所有打开这个页面的朋友。人生不如意&#xff0…...

springboot vue 会员营销系统

springboot vue 会员营销系统介绍 演示地址: 开源版本:http://8.146.211.120:8083/ 完整版本:http://8.146.211.120:8086/ 移动端 http://8.146.211.120:8087/ 简介 欢迎使用springboot vue会员营销系统。本项目包含会员储值卡、套餐卡、计…...

Kafka快速扫描

Architecture 系统间解耦,异步通信,削峰填谷 Topic 消息主题,用于存储消息 Partition 分区,通过扩大分区,可以提高存储量 Broker 部署Kafka服务的设备 Leader kafka主分区 Follwer kafka从分区 高性能之道&#xff1a…...

scala基础学习(数据类型)-字符串

文章目录 scala中的字符串引号单引号双引号三引号 常用内置函数length 获取字符串长度charAt 字符串元素访问substring 获取字串indexOf 获取字串位置replace 字符串替换toLowerCase,toUpperCase 字符串大小写转换trim 去除首位空白符split 字符串切割以及查看startsWith,endsW…...

网络架构与IP技术:4K/IP演播室制作的关键支撑

随着科技的不断发展,广播电视行业也在不断迭代更新,其中4K/IP演播室技术的应用成了一个引人注目的焦点。4K超高清技术和IP网络技术的结合,不仅提升了节目制作的画质和效果,还为节目制作带来了更高的效率和灵活性。那么4K超高清技术…...

如何优雅的关闭GoWeb服务器

以下内容均为Let’s Go Further内容节选以及作者本人理解。 这里创建了一个后台进程用于捕获关闭信号,在后台进程中,主要内容为: 创建一个缓冲通道 quit使用signal.Notify函数监听并捕获关机信号SIGINT,SIGTERM,在捕获关机信号后…...

Python爬虫(5) --爬取网页视频

文章目录 爬虫爬取视频指定url发送请求UA伪装请求页面 获取想要的数据解析定位定位音视频位置 存放视频完整代码实现总结 爬虫 Python 爬虫是一种自动化工具,用于从互联网上抓取网页数据并提取有用的信息。Python 因其简洁的语法和丰富的库支持(如 requ…...

simulink离散传递函数得到差分方程并用C语言实现

一. 创建连续时间的传递函数 G ( s ) s 2 217 s s 2 384 s 8989 G(s) \frac{s^2217s}{s^2384s8989} G(s)s2384s8989s2217s​ 二. 离散连续时间的传递函数G(s) 2.1 在matlab中用c2d函数双线性变换法离散G(s), 下面是matlab脚本代码 % 创建连续时间传递函数 …...

第十七届山东省职业院校技能大赛 中职组“网络安全”赛项任务书正式赛题

第十七届山东省职业院校技能大赛 中职组“网络安全”赛项任务书-A 目录 一、竞赛阶段 二、竞赛任务书内容 (一)拓扑图 (二)模块A 基础设施设置与安全加固(200分) (三)B模块安全事件响应/网络安全数据取证/…...

Redis内存碎片详解

什么是内存碎片? 你可以将内存碎片简单地理解为那些不可用的空闲内存。 举个例子:操作系统为你分配了 32 字节的连续内存空间,而你存储数据实际只需要使用 24 字节内存空间,那这多余出来的 8 字节内存空间如果后续没办法再被分配存储其他数…...

Python球球大作战

系列文章 序号直达链接表白系列1Python制作一个无法拒绝的表白界面2Python满屏飘字表白代码3Python无限弹窗满屏表白代码4Python李峋同款可写字版跳动的爱心5Python流星雨代码6Python漂浮爱心代码7Python爱心光波代码8Python普通的玫瑰花代码9Python炫酷的玫瑰花代码10Python多…...

机器学习(Machine Learning)的安全问题

最近看论文,看到了”对抗样本“的一些内容,然后又研究了一下其背后的东西,发现还有”机器学习的安全“这一问题,然后找了几篇博客看了一下,发现了篇2019年的比较有意思的文章,这里整理一下,方编…...

ROS1安装教程

一、环境准备 操作系统:Ubuntu 20.04 LTS 注:为保证系统干净,本文使用Docker进行 演示,如已安装相应的Ubuntu系统请忽略。 Docker安装Ubuntu系统步骤如下: # 拉取镜像 docker pull ubuntu:20.04# 创建容器 docker ru…...

大腾智能CAD:国产云原生三维设计新选择

在快速发展的工业设计领域,CAD软件已成为不可或缺的核心工具。它通过强大的建模、分析、优化等功能,不仅显著提升了设计效率与精度,还促进了设计思维的创新与拓展,为产品从概念构想到实体制造的全过程提供了强有力的技术支持。然而…...

Docker 入门:如何使用 Docker 容器化 AI 项目(一)

引言 在人工智能(AI)项目的开发和部署过程中,环境配置和依赖管理往往是开发者遇到的挑战之一。开发者通常需要在不同的机器上运行同样的代码,确保每个人使用的环境一致,才能避免 “在我的机器上可以运行”的尴尬问题。…...

【04-数据库面试】

如何创建一个新的数据库 数据库是现代信息技术中不可或缺的一部分,它为存储、检索和管理数据提供了强大的工具。无论是企业还是个人,都可能需要创建自己的数据库以满足特定的需求。本文将详细介绍创建一个新数据库的步骤,包括规划、选择数据…...

单元测试使用记录

什么是单元测试 简单来说就是对一个类中的方法进行测试,对输出的结果检查判断是否符合预期结果 但是在多年的工作中,从来没有哪个项目中真正系统的用到了单元测试,因此对它还是很陌生的,也就造成更加不会在项目中区使用它。 如何…...

《深入浅出 Servlet:Java Web 开发的基石》(二)

ServletConfig(熟练) ServletConfig对象对应web.xml文件中的<servlet>元素。例如你想获取当前Servlet在web.xml文件中的配置名&#xff0c;那么可以使用servletConfig.getServletName()方法获取&#xff01; 你不能自己去创建ServletConfig对象&#xff0c;Servlet的in…...

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

Pytorch | 从零构建MobileNet对CIFAR10进行分类 CIFAR10数据集MobileNet设计理念网络结构技术优势应用领域 MobileNet结构代码详解结构代码代码详解DepthwiseSeparableConv 类初始化方法前向传播 forward 方法 MobileNet 类初始化方法前向传播 forward 方法 训练过程和测试结果…...

冯诺依曼架构与哈佛架构的对比与应用

冯诺依曼架构&#xff08;Von Neumann Architecture&#xff09;&#xff0c;也称为 冯诺依曼模型&#xff0c;是由著名数学家和计算机科学家约翰冯诺依曼&#xff08;John von Neumann&#xff09;在1945年提出的。冯诺依曼架构为现代计算机奠定了基础&#xff0c;几乎所有现代…...

【Java基础面试题032】Java中的字节码是什么?

回答重点 Java字节码是Java编译器将Java源代码编译后生成的 位于Java源代码与JVM执行的执行的机器码之间。 Java字节码由JVM解释或即时编译&#xff08;JIT&#xff09;为机器码执行 扩展知识 Java字节码的关键点 1&#xff09;字节码结构&#xff1a; Java字节码是与平…...

K8s ConfigMap的基础功能介绍

在 Kubernetes 中&#xff0c;ConfigMap 是一种用于管理配置信息的资源对象&#xff0c;它允许你将 配置信息与代码解耦&#xff0c;方便管理和更新应用配置&#xff0c;而无需重新构建镜像或重启服务。 ConfigMap 的功能 存储配置信息&#xff1a; 可以以 键值对 的形式存储配…...

stm32制作CAN适配器4--WinUsb的使用

前面使用STM32G474芯片的USB模块做了一个CANFD程序&#xff0c;当时用的是HID模式&#xff0c;在实际使用时发现HID模块的通讯速率太慢了&#xff0c;只能1ms传输一帧&#xff0c;就会造成有些掉帧现象。 现在就把HID模块改为在Window下同样免驱的WinUsb来实现CANFD数据的传输。…...

深入理解 Java 中的 ArrayList 和 List:泛型与动态数组

深入理解 Java 中的 ArrayList 和 List&#xff1a;泛型与动态数组 在 Java 编程中&#xff0c;ArrayList 和 List 是最常用的集合类之一。它们帮助我们管理动态数据&#xff0c;支持按索引访问、增加、删除元素等操作。尤其在使用泛型时&#xff0c;理解它们之间的关系及应用…...

[react 3种方法] 获取ant组件ref用ts如何定义?

获取ant的轮播图组件, 我用ts如何定义? Strongly Type useRef with ElementRef | Total TypeScript import React, { ElementRef } from react; const lunboRef useRef<ElementRef<typeof Carousel>>(null); <Carousel autoplay ref{lunboRef}> 这样就…...

VS Code Copilot 与 Cursor 对比

选手简介 VS Code Copilot&#xff1a;算是“老牌”编程助手了&#xff0c;虽然Copilot在别的编辑器上也有扩展&#xff0c;不过体验最好的还是VS Code&#xff0c;毕竟都是微软家的所以功能集成更好一些&#xff1b;主要提供的是Complete和Chat能力&#xff0c;也就是代码补全…...

华为IPD流程6大阶段370个流程活动详解_第一阶段:概念阶段 — 81个活动

华为IPD流程涵盖了产品从概念到上市的完整过程,各阶段活动明确且相互衔接。在概念启动阶段,产品经理和项目经理分析可行性,PAC评审后成立PDT。概念阶段则包括产品描述、市场定位、投资期望等内容的确定,同时组建PDT核心组并准备项目环境。团队培训涵盖团队建设、流程、业务…...

Vue3组件封装技巧与心得

摘要&#xff1a; 日常开发中&#xff0c;用Vue组件进行业务拆分&#xff0c;代码解耦是一个很好的选择&#xff1b; 今天就来分享一下我在使用Vue3进行组件封装的一些技巧和心得&#xff0c;希望能够帮助到大家&#xff1b; 1. 组件特性&#xff1a; 在Vue中组件是一个独立的…...

15.初识接口1 C#

这是一个用于实验接口的代码 适合初认识接口的人 【CSDN开头介绍】&#xff08;文心一言AI生成&#xff09; 在C#编程世界中&#xff0c;接口&#xff08;Interface&#xff09;扮演着至关重要的角色&#xff0c;它定义了一组方法&#xff0c;但不提供这些方法的实现。它要求所…...

渗透测试-前端加密分析之RSA加密登录(密钥来源本地)

本文是高级前端加解密与验签实战的第5篇文章&#xff0c;本系列文章实验靶场为Yakit里自带的Vulinbox靶场&#xff0c;本文讲述的是绕过前端RSA加密来爆破登录。 分析 generateKey函数用来生成随机的RSA公私钥 加密的格式如下&#xff1a; {"username":"admin…...

题海拾贝:力扣 86.分隔链表

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 1、题…...

《Mycat核心技术》第06章:Mycat问题处理总结

作者&#xff1a;冰河 星球&#xff1a;http://m6z.cn/6aeFbs 博客&#xff1a;https://binghe.gitcode.host 文章汇总&#xff1a;https://binghe.gitcode.host/md/all/all.html 星球项目地址&#xff1a;https://binghe.gitcode.host/md/zsxq/introduce.html 沉淀&#xff0c…...

前端实现图片压缩

前端实现图片压缩的主要方法有&#xff1a; 使用 HTML5 的 API 利用 canvas 将图片绘制到画布上&#xff0c;然后通过 toDataURL 方法获取压缩后的图片数据。 使用第三方库 借助 compressorjs、browser-image-compression 等开源库&#xff0c;快速实现高质量的图片压缩功能。…...

Python OCR 文字识别

一.引言 文字识别&#xff0c;也称为光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;是一种将不同形式的文档&#xff08;如扫描的纸质文档、PDF文件或数字相机拍摄的图片&#xff09;中的文字转换成可编辑和可搜索的数据的技术。随着技…...

怿星科技联合赛力斯举办workshop活动,进一步推动双方合作

12月18日&#xff0c;由怿星科技与赛力斯汽车联合举办的workshop活动在赛力斯五云湖总部展开&#xff0c;双方嘉宾围绕智能汽车发展趋势、行业前沿技术、汽车电子网络与功能测试等核心议题展开了深度对话与交流&#xff0c;并现场参观演示了多套前沿产品。怿星科技CEO潘凯、汽车…...

Vue.js前端框架教程1:Vue应用启动和Vue组件

文章目录 Vue 应用Vue 应用的主要组成部分:启动 Vue 应用:Vue组件基础组件组件注册父子组件组件插槽(Slots)动态组件和 `keep-alive`Vue 应用 Vue 应用由几个主要部分组成,每个部分都有其特定的角色和职责。以下是 Vue 应用的主要组成部分以及如何启动一个 Vue 应用的介绍…...

LabVIEW深海气密采水器测控系统

LabVIEW的深海气密采水器测控系统通过高性价比的硬件选择与自主开发的软件&#xff0c;实现了高精度的温度、盐度和深度测量&#xff0c;并在实际海上试验中得到了有效验证。 项目背景 深海气密采水器是进行海底科学研究的关键工具&#xff0c;用LabVIEW开发了一套测控系统&am…...