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

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

  • CIFAR10数据集
  • Vgg
    • 网络结构
    • 特点
    • 性能
    • 应用
    • 影响
  • Vgg结构代码详解
    • 结构代码
    • 代码详解
      • 特征提取层 _make_layers
      • 前向传播 forward
  • 训练过程和测试结果
  • 代码汇总
    • vgg.py
    • train.py
    • test.py

前面文章我们构建了AlexNet对CIFAR10进行分类:
Pytorch | 从零构建AlexNet对CIFAR10进行分类
这篇文章我们来构建Vgg.

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个不同的类别,这些类别都是现实世界中常见的物体,具有一定的代表性。

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

Vgg

VGG网络是由牛津大学视觉几何组(Visual Geometry Group)提出的一种深度卷积神经网络,在2014年的ILSVRC竞赛中获得了亚军。以下是对其详细介绍:

网络结构

  • 卷积层:VGG网络由多个卷积层组成,其卷积核大小通常为3×3。采用小卷积核的好处是可以在减少参数数量的同时,增加网络的深度,从而提高网络的表达能力。
  • 池化层:在卷积层之间穿插着池化层,通常采用最大池化,池化核大小为2×2,步长为2。池化操作可以降低特征图的分辨率,减少计算量,同时也可以提取出更具代表性的特征。
  • 全连接层:经过多个卷积和池化层后,网络将得到的特征图展开并连接到全连接层。全连接层用于对特征进行分类或回归等操作。
    在这里插入图片描述
    上图即为Vgg论文中提出的六种不同的架构,本文的 vgg.py 代码中均进行了实现.

特点

  • 结构简洁:VGG网络的结构相对简单且规整,主要由一系列的3×3卷积核和2×2池化核堆叠而成,这种简洁的结构易于理解和实现,也方便进行修改和扩展。
  • 深度较深:VGG网络通常有16或19层,是当时比较深的神经网络之一。通过增加网络的深度,能够学习到更高级的特征表示,从而提高了图像分类的准确率。
  • 小卷积核:使用3×3的小卷积核替代了传统的大卷积核,减少了参数数量,降低了计算量,同时也有助于提高网络的泛化能力。

性能

  • 在图像分类任务上表现出色:在ILSVRC竞赛等图像分类基准测试中取得了很好的成绩,证明了其在图像特征提取和分类方面的有效性。
  • 模型泛化能力较好:由于其深度和小卷积核的设计,VGG网络能够学习到具有较强泛化能力的特征,对不同的图像数据集和任务具有一定的适应性。

应用

  • 图像分类:广泛应用于各种图像分类任务,如人脸识别、物体识别、场景分类等。可以对输入图像进行分类,确定其所属的类别。
  • 目标检测:在目标检测任务中,VGG网络可以作为特征提取器,提取图像中的特征,为后续的目标定位和分类提供基础。
  • 图像分割:也可用于图像分割任务,通过对图像进行像素级的分类,将图像分割成不同的区域或物体。

影响

  • 推动了卷积神经网络的发展:VGG网络的成功激发了更多研究者对深度卷积神经网络的兴趣,推动了该领域的快速发展。
  • 为后续网络设计提供了参考:其简洁的结构和小卷积核的设计理念为后续许多卷积神经网络的设计提供了重要的参考,如ResNet等网络在一定程度上借鉴了VGG的思想。

Vgg结构代码详解

结构代码

import torch
import torch.nn as nn


cfg = {
    'A': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'A-LRN' : [64, 'LRN', 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'B': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], 
    'C': [64, 64, 'M', 128, 128, 'M', 256, 256, 'conv1-256', 'M', 512, 512, 'conv1-512', 'M', 512, 512, 'conv1-512', 'M'], 
    'D': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'], 
    'E': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M']
}

class Vgg(nn.Module):
    def __init__(self, cfg_vgg, num_classes):
        super(Vgg, self).__init__()
        self.features = self._make_layers(cfg_vgg)
        self.classifier = nn.Sequential(
            nn.Linear(512, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, num_classes)
        )

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)

        return x

    def _make_layers(self, cfg_vgg):
        layers = []
        in_channels = 3
        for i in cfg[cfg_vgg]:
            if i == 'M':
                layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
            elif i == 'LRN':
                layers += [nn.LocalResponseNorm(size=5, alpha=1e-4, beta=0.7, k=2)]
            elif i == 'conv1-256':
                conv2d = nn.Conv2d(in_channels, 256, kernel_size=1)
                layers += [conv2d, nn.ReLU(inplace=True)]
                in_channels = 256
            else:
                conv2d = nn.Conv2d(in_channels, i, kernel_size=3, padding=1)
                layers += [conv2d, nn.ReLU(inplace=True)]
                in_channels = i
        
        return nn.Sequential(*layers)

代码详解

特征提取层 _make_layers

def _make_layers(self, cfg_vgg):
    layers = []
    in_channels = 3
    for i in cfg[cfg_vgg]:
        if i == 'M':
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        elif i == 'LRN':
            layers += [nn.LocalResponseNorm(size=5, alpha=1e-4, beta=0.7, k=2)]
        elif i == 'conv1-256':
            conv2d = nn.Conv2d(in_channels, 256, kernel_size=1)
            layers += [conv2d, nn.ReLU(inplace=True)]
            in_channels = 256
        else:
            conv2d = nn.Conv2d(in_channels, i, kernel_size=3, padding=1)
            layers += [conv2d, nn.ReLU(inplace=True)]
            in_channels = i
    
    return nn.Sequential(*layers)
  • 初始化:首先创建一个空列表 layers,用于存储构建网络过程中依次添加的各个层,同时将初始输入通道数 in_channels 设置为3,对应RGB图像的三个通道。
  • 循环构建各层及尺寸变化分析
    • 卷积层(一般情况)
      当遇到不是 'M''LRN''conv1-256' 这些特殊标识的数字 i 时,意味着要构建一个卷积层。例如 conv2d = nn.Conv2d(in_channels, i, kernel_size=3, padding=1),这里创建了一个卷积核大小为3×3、填充为1的卷积层,输入通道数是 in_channels,输出通道数为 i
      假设输入图像尺寸为 (batch_size, 3, H, W)H 表示高度,W 表示宽度),对于3×3卷积核且填充为1的卷积操作,根据卷积运算的尺寸计算公式(输出特征图高度/宽度 = (输入特征图高度/宽度 + 2 * 填充 - 卷积核大小) / 步长 + 1),步长默认为1,经过这样的卷积层后,特征图的尺寸变化为 (batch_size, i, H, W)(因为高度和宽度在这种3×3卷积且填充为1的情况下保持不变),然后再添加 nn.ReLU(inplace=True) 激活函数层,特征图尺寸依然是 (batch_size, i, H, W),同时更新 in_channels 的值为 i,用于下一层卷积操作时确定输入通道数。
    • 1×1卷积层(conv1-256 情况)
      当遇到 'conv1-256' 时,创建一个1×1卷积层 conv2d = nn.Conv2d(in_channels, 256, kernel_size=1),它主要用于在不改变特征图尺寸的情况下改变通道数,输入通道数是当前的 in_channels,输出通道数变为256。经过这个1×1卷积层和后面的 ReLU 激活函数后,特征图尺寸仍然保持之前的大小(假设之前是 (batch_size, some_channels, H, W),现在就是 (batch_size, 256, H, W)),同时 in_channels 更新为256。
    • 池化层(M 情况)
      当遇到 'M' 标识时,添加一个最大池化层 nn.MaxPool2d(kernel_size=2, stride=2)。最大池化层的作用是对特征图进行下采样,其池化核大小为2×2,步长为2。根据池化运算的尺寸计算公式(输出特征图高度/宽度 = (输入特征图高度/宽度 - 池化核大小) / 步长 + 1),经过这样的池化操作后,特征图的尺寸在高度和宽度方向上都会减半,例如输入特征图尺寸为 (batch_size, channels, H, W),经过池化后变为 (batch_size, channels, H // 2, W // 2)
    • 局部响应归一化层(LRN 情况)
      当遇到 'LRN' 时,添加 nn.LocalResponseNorm(size=5, alpha=1e-4, beta=0.7, k=2) 层,局部响应归一化层主要用于对局部的神经元活动进行归一化处理,它不会改变特征图的尺寸大小,输入特征图尺寸是多少,输出的还是同样尺寸的特征图,只是对特征图中的数值进行了归一化操作。

最后,通过 nn.Sequential(*layers) 将构建好的所有层组合成一个顺序的网络模块并返回,这个模块就构成了VGG网络的特征提取部分,按照配置的不同,特征图在经过这一系列的卷积、池化等操作后,尺寸会逐步发生变化,最终输出的特征图将被展平后输入到全连接层进行分类处理。

前向传播 forward

def forward(self, x):
    x = self.features(x)
    x = x.view(x.size()[0], -1)
    x = self.classifier(x)
  • 特征提取:首先将输入 x 传入 self.features,也就是前面构建的特征提取层,让其经过一系列的卷积、池化等操作,提取出图像的特征表示。
  • 维度调整:经过特征提取层后,输出的 x 的维度形式为 (batch_size, channels, height, width),为了能够输入到全连接层中,需要将其维度进行调整,x.view(x.size()[0], -1) 这一步操作会将特征图展平成二维张量,第一维是 batch_size(批次大小),第二维是所有特征元素的数量(等于 channels * height * width)。
  • 分类预测:将展平后的特征张量 x 传入 self.classifier 全连接层部分,进行分类预测,最终返回预测的类别结果,其维度为 (batch_size, num_classes)

训练过程和测试结果

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

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

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

代码汇总

项目github地址
项目结构:

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

vgg.py

import torch
import torch.nn as nn


cfg = {
    'A': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'A-LRN' : [64, 'LRN', 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'B': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], 
    'C': [64, 64, 'M', 128, 128, 'M', 256, 256, 'conv1-256', 'M', 512, 512, 'conv1-512', 'M', 512, 512, 'conv1-512', 'M'], 
    'D': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'], 
    'E': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M']
}

class Vgg(nn.Module):
    def __init__(self, cfg_vgg, num_classes):
        super(Vgg, self).__init__()
        self.features = self._make_layers(cfg_vgg)
        self.classifier = nn.Sequential(
            nn.Linear(512, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, num_classes)
        )

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)

        return x

    def _make_layers(self, cfg_vgg):
        layers = []
        in_channels = 3
        for i in cfg[cfg_vgg]:
            if i == 'M':
                layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
            elif i == 'LRN':
                layers += [nn.LocalResponseNorm(size=5, alpha=1e-4, beta=0.7, k=2)]
            elif i == 'conv1-256':
                conv2d = nn.Conv2d(in_channels, 256, kernel_size=1)
                layers += [conv2d, nn.ReLU(inplace=True)]
                in_channels = 256
            else:
                conv2d = nn.Conv2d(in_channels, i, kernel_size=3, padding=1)
                layers += [conv2d, nn.ReLU(inplace=True)]
                in_channels = i
        
        return nn.Sequential(*layers)

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 = 'Vgg_A'
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)

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 = 'Vgg_A'
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)
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}%')

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

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

相关文章

将4G太阳能无线监控的视频接入电子监控大屏,要考虑哪些方面?

随着科技的飞速发展,4G太阳能无线监控系统以其独特的优势在远程监控领域脱颖而出。这种系统结合了太阳能供电的环保特性和4G无线传输的便捷性,为各种环境尤其是无电或电网不稳定的地区提供了一种高效、可靠的视频监控解决方案。将这些视频流接入大屏显示…

ASP.NET |日常开发中连接Mysql数据库增删改查详解

ASP.NET |日常开发中连接Mysql数据库增删改查详解 前言一、连接 MySQL 数据库1.1 安装和引用相关库1.2 建立数据库连接 二、数据库增删改查操作2.1 插入数据(Insert)2.2 查询数据(Select)2.3 更新数据(Upda…

Go框架比较:goframe、beego、iris和gin

由于工作需要,这些年来也接触了不少的开发框架,Golang的开发框架比较多,不过基本都是Web"框架"为主。这里稍微打了个引号,因为大部分"框架"从设计和功能定位上来讲,充其量都只能算是一个组件&…

LLaMA-Factory 单卡3080*2 deepspeed zero3 微调Qwen2.5-7B-Instruct

环境安装 git clone https://gitcode.com/gh_mirrors/ll/LLaMA-Factory.git 下载模型 pip install modelscope modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct 微调 llamafactory-cli train \--st…

华为ensp--BGP路径选择-AS_Path

学习新思想,争做新青年,今天学习的是BGP路径选择-AS_Path 实验目的: 理解AS_Path属性的概念 理解通过AS_Path属性进行选路的机制 掌握修改AS_Path属性的方法 实验内容: 本实验模拟了一个运营商网络场景,所有路由器都运行BGP协议&#xff…

泛微OA定时任务的设置

泛微OA定时任务 背景 在日常流程开发中,是需要和别的系统进行连接的,比如OA和SAP之间的数据传输。 SAP涉及到的业务数据在生成之后,需要在OA生成对应的流程进行信息的审核,但是毕竟是两个不同的系统,所以数据同步是需…

【Harmony Next】多个图文配合解释DevEco Studio工程中,如何配置App相关内容,一次解决多个问题?

解决App配置相关问题列表 1、Harmony Next如何配置图标? 2、Harmony Next如何配置App名称? 3、Harmony Next如何配置版本号? 4、Harmony Next如何配置Bundle ID? 5、Harmony Next如何配置build号? 6、Harmony Next多语言配置在哪…

如何从0构建一个flask项目,直接上实操!!!

项目结构 首先,创建一个项目目录,结构如下: flask_app/ │ ├── app.py # Flask 应用代码 ├── static/ # 存放静态文件(如CSS、JS、图片等) │ └── style.css # 示例…

计算机网络B重修班-期末复习

[TOC] (计算机网络B重修班-期末复习) 一、单选 (20题,1分/题,共20分) 二、判断 (10题,1分/题,共10分) 三、填空 (10题,1分/题,共10…

js日期时区问题

东八区与0时区 东八区 我们所在地域使用的是 东八区 时区,所以平常使用的电脑设置的多是东八时区 js获取的时间格式 0时区 0时区 也叫 协调世界时 js获取的时间格式 数据库读取时间数据 平常从数据读取的时间默认是0时区的,成以下格式: 2024…

Ubantu22系统安装Miniconda3

1、Anaconda和Miniconda异同 清华源镜像的Miniconda3和Anaconda都是用于管理Python环境和软件包的工具,但它们之间存在一些关键的不同之处。下面将分别介绍它们的特点以及使用清华源镜像的差异。 相同点: (1)功能相似&#xff1a…

锂电池SOH预测 | 基于BiGRU双向门控循环单元的锂电池SOH预测,附锂电池最新文章汇集

锂电池SOH预测 | 基于BiGRU双向门控循环单元的锂电池SOH预测,附锂电池最新文章汇集 目录 锂电池SOH预测 | 基于BiGRU双向门控循环单元的锂电池SOH预测,附锂电池最新文章汇集预测效果基本描述程序设计参考资料 预测效果 基本描述 锂电池SOH预测 | 基于Bi…

安装opnet14.5遇到的问题

安装opnet遇到的问题 我是按照这个教程来安装的。 然后遇到了两个问题&#xff1a; 1、“mod_dirs”目录问题 Can’t enable ETS scripting support due to missing files。 This is likely because:<opnet_release_dir>\sys\lib is notinclude in the “mod_dirs” pre…

以腾讯混元模型为例,在管理平台上集成一个智能助手

背景 前几天&#xff0c;公司的同事们一起吃了个饭&#xff0c;餐桌上大家聊到大模型的落地场景。我个人在去年已经利用百度千帆平台写过案例&#xff0c;并发过博客&#xff08;传送门&#x1f449;&#xff1a;利用文心千帆打造一个属于自己的小师爷&#xff09;&#xff0c…

软件实验室认可|实验室比对的形式与方法

实验室比对是软件测试实验室在申请软件实验室认可必须要做的一类质量控制活动。实验室比对包括实验室间比对&#xff0c;和实验室内比对。实验室间比对指的是按照预先规定的条件&#xff0c;由两个或多个实验室对相同或类似的物品进行测量或检测的组织、实施和评价。实验室内比…

酷克数据携手江西移动入选“星河(Galaxy)”数据库潜力案例

2024 年 12 月 18 - 19 日&#xff0c;为推动打造行业交流平台&#xff0c;驱动产业创新共荣&#xff0c;大数据技术标准推进委员会以“数据重塑价值 智能链接未来”为主题&#xff0c;在北京召开为期两天的“2024 数据资产管理大会”。 在会上&#xff0c;第八届大数据“星河&…

【Verilog】UDP用户原语

User-defined primitives 概述基本语法组合逻辑的UDP时序逻辑的UDPUDP 符号表 Verilog HDL&#xff08;简称 Verilog &#xff09;是一种硬件描述语言&#xff0c;用于数字电路的系统设计。可对算法级、门级、开关级等多种抽象设计层次进行建模。 Verilog 不仅定义了语法&…

《Java核心技术I》Swing中滚动窗格

滚动窗格 Swing中文本区没有滚动条&#xff0c;如需要&#xff0c;可以将文本区放在 滚动窗格(scrollpane)中。 textArea new JTextArea(8,40); var scrollPane new JScrollPane(textArea); 添加到滚动窗格不是文本区特有的&#xff0c;所有组件都可以。 注释&#xff1a;JTe…

Node.js day-01

01.Node.js 讲解 什么是 Node.js&#xff0c;有什么用&#xff0c;为何能独立执行 JS 代码&#xff0c;演示安装和执行 JS 文件内代码 Node.js 是一个独立的 JavaScript 运行环境&#xff0c;能独立执行 JS 代码&#xff0c;因为这个特点&#xff0c;它可以用来编写服务器后端…

排序算法(7):堆排序

问题 排序 [30, 24, 5, 58, 18, 36, 12, 42, 39] 堆排序 堆排序是一种基于堆数据结构的排序算法。堆是一个近似完全二叉树的结构&#xff0c;即除了最后一层外&#xff0c;每一层都必须填满&#xff0c;且最后一层从左往右填充。 堆可以分为大根堆和小根堆。在大根堆中&…