基于DenseNet网络实现Cifar-10数据集分类

news2024/11/27 19:55:39

目录

  • 1.作者介绍
  • 2.Cifar-10数据集介绍
  • 3.Densenet网络模型
    • 3.1网络背景
    • 3.2网络结构
      • 3.2.1Dense Block
      • 3.2.2Bottleneck层
      • 3.2.3Transition层
      • 3.2.4压缩
  • 4.代码实现
    • 4.1数据加载
    • 4.2建立 DenseNet 网络模型
    • 4.3模型训练
    • 4.4训练代码
    • 4.5测试代码
  • 参考链接

1.作者介绍

吴思雨,女,西安工程大学电子信息学院,2023级研究生
研究方向:机器视觉与人工智能
电子邮件:2879944563@qq.com
陈梦丹,女,西安工程大学电子信息学院,2022级研究生
研究方向:机器视觉与人工智能
电子邮件:1169738496@qq.com

2.Cifar-10数据集介绍

Cifar-10数据集由10个类别的60000张32x32彩色图像组成,每个类别有6000张图像。有50000个训练图像和10000个测试图像。
数据集分为五个训练批次和一个测试批次,每个批次有10000张图像。测试批次恰好包含从每个类别中随机选择的1000幅图像。训练批包含按随机顺序排列的剩余图像,但某些训练批可能包含来自一个类的图像多于另一类的图像。在它们之间,训练批次恰好包含每个类的5000个图像。
以下是数据集中的类,以及每个类的10张随机图像:
在这里插入图片描述
这些类是完全不同的。汽车和卡车之间没有重叠。“汽车”包括轿车,SUV,诸如此类的东西。“卡车”只包括大卡车。两者都不包括皮卡。
Cifar-10官网下载链接:http://www.cs.toronto.edu/~kriz/cifar.html
Cifar-10数据集有三个版本,本文采用的是第一个版本:Cifar-10 python version。
在这里插入图片描述

3.Densenet网络模型

3.1网络背景

DenseNet(《Densely connected convolutional networks》) 斩获CVPR 2017的最佳论文奖,它的基本思路与ResNet一致,但是在参数和计算成本更少的情形下实现了比ResNet更优的性能,它建立的是前面所有层与后面层的密集连接(即相加变连结),它的名称也是由此而来。
DenseNet的另一大特色是通过特征在通道上的连接来实现特征重用。这些特点让DenseNet的参数量和计算成本都变得更少了,效果也更好了。ResNet解决了深层网络梯度消失问题,它是从深度方向研究的。宽度方向是GoogleNet的Inception。而DenseNet是从feature入手,通过对feature的极致利用能达到更好的效果和减少参数。

3.2网络结构

在这里插入图片描述
上图是一个包含5layer的Dense Block。可以看出Dense Block互相连接所有的层,具体来说就是每一层的输入都来自于它前面所有层的特征图,每一层的输出均会直接连接到它后面所有层的输入。所以对于一个L层的DenseBlock,共包含
L*(L+1)/2 个连接,如果是ResNet的话则为(L-1)2+1。从这里可以看出:相比ResNet,Dense Block采用密集连接。而且Dense Block是直接concat来自不同层的特征图,这可以实现特征重用,提升效率,这一特点是DenseNet与ResNet最主要的区别。
Dense Net的网络结构主要由
Dense Block和Transition*组成;如下图所示。一个DenseNet中有3个或4个DenseBlock。而一个DenseBlock中也会有多个Bottleneck layers。最后的DenseBlock之后是一个global AvgPooling层,然后送入一个softmax分类器,得到每个类别所属分数。
在这里插入图片描述

3.2.1Dense Block

1.Dense connective
为了进一步改善层之间的信息流,提出了一种不同的连接模式:引入了从任何层到所有后续层的直接连接。因此,第l层接收所有先前层的特征图:X0,X1,…Xl-1作为输入:在这里插入图片描述

2.Composite function—复合功能
将 Hℓ(⋅)定义为三个连续运算的复合函数:批量归一化(BN),然后是 ReLU 和一个 3×3的卷积(Conv)。
在这里插入图片描述
在这里插入图片描述其中,ℓ表示第几层;将第ℓ 层的输出表示为Xℓ; [X0,X1,…]表示将第0,1…(ℓ-1)层的特征图进行组合。将非线性变换Hℓ(⋅)定义为三个连续操作的符合函数:BN+ReLU+一个3×3的Conv。
3.Growth rate—增长率
k–DenseNet中的growth rate(增长率),这是一个超参数。一般情况下使用较小的k,就可以得到较佳的性能。假定输入层的特征图的通道数为k0,那么L层输入的channel数为 k0+k*(L-1),因此随着层数增加,尽管k设定得较小,DenseBlock中每一层输入依旧会越来越多。

3.2.2Bottleneck层

尽管每一层仅生成k个输出特征图,但通常具有更多输入。可以在每次3×3卷积之前引入1×1卷积作为瓶颈层,以减少输入特征图的数量,从而提高计算效率。并且将具有此类瓶颈层的网络称为DenseNet-B,瓶颈层如下图所示。
在这里插入图片描述

3.2.3Transition层

当特征图的大小改变时,不能直接连接。然而,卷积网络的重要组成部分是降低特征图大小的下采样层。为了便于在体系结构中进行下采样,将网络划分为多个密集连接的密集块。如下图所示,将块之间的层称为过渡层,它们进行卷积和池化。实验中使用的过渡层包括批处理规范化层和1×1卷积层,然后是一个 2×2的平均池化层。
在这里插入图片描述

3.2.4压缩

为了进一步提高模型的紧凑性,可以减少转换层的特征图数量。引入一个压缩因子θ(0 < θ ≤1),当θ=1时转换层的输入和输出特征数不变,也就是经过转换层后特征数不变;当θ <1时,输入特征图数为m时,输出为⌊θm⌋。将θ<1的DenseNet称为DenseNet-C (在实验中设置θ=0.5)。

4.代码实现

4.1数据加载

CIFAR 数据集可以从官网下载后使用,也可以使用 datasets 类自动加载(如果本地路径没有该文件则自动下载)。大型训练数据集不能一次性加载全部样本来训练,可以使用 Dataloader 类自动加载数据。Dataloader 是一个迭代器,基本功能是传入一个 Dataset 对象,根据参数 batch_size 生成一个 batch 的数据。

4.2建立 DenseNet 网络模型

建立一个 DenseNet 网络模型进行训练,包括三个步骤:
1.实例化 DenseNet 模型对象;
2.设置训练的损失函数;
3.设置训练的优化器。

4.3模型训练

在模型训练过程中,可以使用验证集数据评价训练过程中的模型精度,以便控制训练过程。模型验证就是用验证数据进行模型推理,前向计算得到模型输出,但不反向计算模型误差,因此需要设置 torch.no_grad()。

4.4训练代码

# 经典模型: 使用 DenseNet 模型 进行 CIFAR10 图像分类,使用 Torchvision 预定义模型
# 使用 torchvision.models.densenet.DenseNet 类
# Copyright: youcans@qq.com
# Crated: Huang Shan, 2023/05/20

# _*_coding:utf-8_*_
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
from torchvision import transforms, models
from matplotlib import pyplot as plt
import numpy as np


# 优化结果写入数据文件
import pandas as pd
def WriteDataFile(epoch_list, loss_list, accu_list, filepath):
    # print("def WriteDataFile()")
    optRecord = {
        "epoch": epoch_list,
        "train_loss": loss_list,
        "accuracy": accu_list}
    dfRecord = pd.DataFrame(optRecord)
    dfRecord.to_csv(filepath, index=False, encoding="utf_8_sig")
    print("写入数据文件: %s 完成。" % filepath)
    return

if __name__ == '__main__':
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print(device)

    # (1)[0,1]的PILImage 转换为[-1,1]的Tensor
    transform_train = transforms.Compose([
        transforms.RandomHorizontalFlip(),  # 随机水平翻转
        transforms.RandomRotation(10),  # 随机旋转
        transforms.RandomAffine(0, shear=10, scale=(0.8, 1.2)),
        transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),
        transforms.Resize((32, 32)),  # 图像大小调整为 (w,h)=(3232)
        transforms.ToTensor(),  # 将图像转换为张量 Tensor
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))
    ])
    # 测试集不需要进行数据增强
    transform = transforms.Compose([
        transforms.Resize((32, 32)),  # 图像大小调整为 (w,h)=(3232)
        transforms.ToTensor(),  # 将图像转换为张量 Tensor
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))
    ])

    # (2) 加载 CIFAR10 数据集
    batchsize = 128
    # 加载 CIFAR10 数据集, 如果 root 路径加载失败, 则自动在线下载
    # 加载 CIFAR10 训练数据集, 50000张训练图片
    train_set = torchvision.datasets.CIFAR10(root='', train=True,
                                            download=True, transform=transform_train)
    train_loader = torch.utils.data.DataLoader(train_set, batch_size=batchsize)
    # 加载 CIFAR10 验证数据集, 10000张验证图片
    test_set = torchvision.datasets.CIFAR10(root='', train=False,
                                           download=True, transform=transform)
    test_loader = torch.utils.data.DataLoader(test_set, batch_size=1000)
    # 创建生成器,用 next 获取一个批次的数据
    valid_data_iter = iter(test_loader)  # _SingleProcessDataLoaderIter 对象
    valid_images, valid_labels = next(valid_data_iter)  # images: [batch,3,224,224], labels: [batch]
    valid_size = valid_labels.size(0)  # 验证数据集大小,batch
    print(valid_images.shape, valid_labels.shape)

    # 定义类别名称,CIFAR10 数据集的 10个类别
    classes = ('plane', 'car', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck')

    # (3) 从 torchvision.model 加载预定义模型 DenseNet (不加载模型权值)
    model = models.DenseNet(num_init_features=32, num_classes=10)  # 实例化 DenseNet 模型类
    model.to(device)  # 将网络分配到指定的 device中
    # print(model)

    # 定义损失函数和优化器
    criterion = nn.CrossEntropyLoss()  # 定义损失函数 CrossEntropy
    optimizer = torch.optim.SGD(model.parameters(), momentum=0.8, lr=0.01)  # 定义优化器 SGD

    # (4) 训练 DenseNet 网络模型
    epoch_list = []  # 记录训练轮次
    loss_list = []  # 记录训练集的损失值
    accu_list = []  # 记录验证集的准确率
    num_epochs = 99 # 训练轮次
    for epoch in range(num_epochs):  # 训练轮次 epoch
        running_loss = 0.0  # 每个轮次的累加损失值清零
        for step, data in enumerate(train_loader, start=0):  # 迭代器加载数据
            optimizer.zero_grad()  # 损失梯度清零

            inputs, labels = data  # inputs: [batch,3,224,224] labels: [batch]
            outputs = model(inputs.to(device))  # 正向传播
            loss = criterion(outputs, labels.to(device))  # 计算损失函数
            loss.backward()  # 反向传播
            optimizer.step()  # 参数更新

            # 累加训练损失值
            running_loss += loss.item()
            # print("\t epoch {}, step {}: loss = {:.4f}".format(epoch, step, loss.item()))
            if step%100==99:  # 每 100 个 step 打印一次训练信息
                print("\t epoch {}, step {}: loss = {:.4f}".format(epoch, step, loss.item()))

        # 计算每个轮次的验证集准确率
        with torch.no_grad():  # 验证过程, 不计算损失函数梯度
            outputs_valid = model(valid_images.to(device))  # 模型对验证集进行推理, [batch, 10]
        pred_labels = torch.max(outputs_valid, dim=1)[1]  # 预测类别, [batch]
        accuracy = torch.eq(pred_labels, valid_labels.to(device)).sum().item() / valid_size * 100  # 计算准确率
        print("Epoch {}: train loss={:.4f}, accuracy={:.2f}%".format(epoch, running_loss, accuracy))

        # 记录训练过程的统计数据
        epoch_list.append(epoch)  # 记录迭代次数
        loss_list.append(running_loss)  # 记录训练集的损失函数
        accu_list.append(accuracy)  # 记录验证集的准确率

    # 训练结果可视化
    plt.figure(figsize=(11, 5))
    plt.suptitle("DenseNet Model in CIFAR10")
    plt.subplot(121), plt.title("Train loss")
    plt.plot(epoch_list, loss_list)
    plt.xlabel('epoch'), plt.ylabel('loss')
    plt.subplot(122), plt.title("Valid accuracy")
    plt.plot(epoch_list, accu_list)
    plt.xlabel('epoch'), plt.ylabel('accuracy')
    plt.show()
    # 保存图像文件
    plt.savefig('/data/Users/wusy/myProject/efficient_densenet_pytorch-master/images')
    print("Plot saved to /data/Users/wusy/myProject/efficient_densenet_pytorch-master/images")

 
    # (5) 保存 DenseNet 网络模型
    save_path = "/data/Users/wusy/myProject/efficient_densenet_pytorch-master/dir1"
    #model_cpu = model.cpu()  # 将模型移动到 CPU
    model_path = save_path + ".pth"  # 模型文件路径
    torch.save(model.state_dict(), model_path)  # 保存模型权值
    # 优化结果写入数据文件
    result_path = save_path + ".csv"  # 优化结果文件路径
    WriteDataFile(epoch_list, loss_list, accu_list, result_path)

经过 20 轮左右的训练,使用验证集中的 1000 张图片进行验证,模型准确率达到 80%。继续训练可以进一步降低训练损失函数值,经过 100轮左右的训练验证集的准确率保持在 80%左右。
在这里插入图片描述## 4.4测试阶段
使用加载的 DenseNet 模型,输入新的图片进行模型推理,可以由模型输出结果确定输入图片所属的类别。从测试集中提取几张图片,或者读取图像文件,进行模型推理,获得图片的分类类别。在提取图片或读取文件时,要注意对图片格式和图片大小进行适当的转换。
从测试集中提取图片,结果如下:
在这里插入图片描述
读取图像文件,结果如下
在这里插入图片描述

4.5测试代码

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
from torchvision import transforms, models
from matplotlib import pyplot as plt
import numpy as np


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # 检测并指定设备

if __name__ == '__main__':
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print(device)
    
    # (1)[0,1]的PILImage 转换为[-1,1]的Tensor
    transform_train = transforms.Compose([
        transforms.RandomHorizontalFlip(),  # 随机水平翻转
        transforms.RandomRotation(10),  # 随机旋转
        transforms.RandomAffine(0, shear=10, scale=(0.8, 1.2)),
        transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),
        transforms.Resize((32, 32)),  # 图像大小调整为 (w,h)=(3232)
        transforms.ToTensor(),  # 将图像转换为张量 Tensor
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))
    ])
    # 测试集不需要进行数据增强
    transform = transforms.Compose([
        transforms.Resize((32, 32)),  # 图像大小调整为 (w,h)=(3232)
        transforms.ToTensor(),  # 将图像转换为张量 Tensor
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))
    ])
    
    
     # (2) 加载 CIFAR10 数据集
    batchsize = 128
    # 加载 CIFAR10 数据集, 如果 root 路径加载失败, 则自动在线下载
    # 加载 CIFAR10 训练数据集, 50000张训练图片
   # 加载 CIFAR10 验证数据集, 10000张验证图片
    test_set = torchvision.datasets.CIFAR10(root='/cifar-10-python.tar.gz', train=False,download=True, transform=transform)
    test_loader = torch.utils.data.DataLoader(test_set, batch_size=1000)
    # 创建生成器,用 next 获取一个批次的数据
    valid_data_iter = iter(test_loader)  # _SingleProcessDataLoaderIter 对象
    valid_images, valid_labels = next(valid_data_iter)  # images: [batch,3,224,224], labels: [batch]
    valid_size = valid_labels.size(0)  # 验证数据集大小,batch
    print(valid_images.shape, valid_labels.shape)

    # 定义类别名称,CIFAR10 数据集的 10个类别
    classes = ('plane', 'car', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck')

    # (3) 从 torchvision.model 加载预定义模型 DenseNet (不加载模型权值)
    model = models.DenseNet(num_init_features=32, num_classes=10)  # 实例化 DenseNet 模型类
    model.to(device)  # 将网络分配到指定的 device中
    # print(model)

    # 定义损失函数和优化器
    criterion = nn.CrossEntropyLoss()  # 定义损失函数 CrossEntropy
    optimizer = torch.optim.SGD(model.parameters(), momentum=0.8, lr=0.01)  # 定义优化器 SGD
    # 加载 DenseNet 预训练模型
    # model = DenseNet(num_classes=10)  # 实例化 DenseNet 网络模型
    model = models.DenseNet(num_init_features=32, num_classes=10)  # 实例化 DenseNet 模型类
    model.to(device)  # 将网络分配到指定的device中
    model_path = '/dir.pth'
    model.load_state_dict(torch.load(model_path))
    model.eval()  # 模型推理模式

# 模型检测
correct = 0
total = 0
for data in test_loader:  # 迭代器加载测试数据集
    imgs, labels = data  # torch.Size([batch,3,32,32) torch.Size([batch])
    # print(imgs.shape, labels.shape)
    outputs = model(imgs.to(device))  # 正向传播, 模型推理, [batch, 10]
    labels_pred = torch.max(outputs, dim=1)[1]  # 模型预测的类别 [batch]
    # _, labels_pred = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += torch.eq(labels_pred, labels.to(device)).sum().item()
accuracy = 100. * correct / total
print("Test samples: {}".format(total))
print("Test accuracy={:.2f}%".format(accuracy))

# 提取测试集图片进行模型推理
batch = 8  # 批次大小
data_set = torchvision.datasets.CIFAR10(root='/cifar-10-python.tar.gz', train=False, download=True, transform=None)
plt.figure(figsize=(9, 6))
for i in range(batch):
    imgPIL = data_set[i][0]  # 提取 PIL 图片
    label = data_set[i][1]  # 提取 图片标签
    # 预处理/模型推理/后处理
    imgTrans = transform(imgPIL)  # 预处理变换, torch.Size([3,32,32])
    imgBatch = torch.unsqueeze(imgTrans, 0)  # 转为批处理,torch.Size([batch=1,3,32,32])
    outputs = model(imgBatch.to(device))  # 模型推理, 返回 [batch=1, 10]
    indexes = torch.max(outputs, dim=1)[1]  # 注意 [batch=1], device = 'device
    index = indexes[0].item()  # 预测类别,整数
    # 绘制第 i 张图片
    imgNP = np.array(imgPIL)  # PIL -> Numpy
    out_text = "label:{}/model:{}".format(classes[label], classes[index])
    plt.subplot(2, 4, i+1)
    plt.imshow(imgNP)
    plt.title(out_text)
    plt.axis('off')
plt.tight_layout()
plt.show()
plt.savefig('/images1')

# 读取图像文件进行模型推理
from PIL import Image
filePath = ''  # 数据文件的地址和文件名
imgPIL = Image.open(filePath)  # PIL 读取图像文件, <class 'PIL.Image.Image'>

# 预处理/模型推理/后处理
imgTrans = transform(imgPIL)  # 预处理变换, torch.Size([3, 224, 224])
imgBatch = torch.unsqueeze(imgTrans, 0)  # 转为批处理,torch.Size([batch=1, 3, 224, 224])
outputs = model(imgBatch.to(device))  # 模型推理, 返回 [batch=1, 10]
indexes = torch.max(outputs, dim=1)[1]  # 注意 [batch=1], device = 'device
percentages = nn.functional.softmax(outputs, dim=1)[0] * 100
index = indexes[0].item()  # 预测类别,整数
percent = percentages[index].item()  # 预测类别的概率,浮点数

# 绘制第 i 张图片
imgNP = np.array(imgPIL)  # PIL -> Numpy
out_text = "Prediction:{}, {}, {:.2f}%".format(index, classes[index], percent)
print(out_text)
plt.imshow(imgNP)
plt.title(out_text)
plt.axis('off')
plt.tight_layout()
# 保存图像到指定路径
output_image_path = '/prediction_result.jpg'
plt.savefig(output_image_path, bbox_inches='tight', pad_inches=0)
plt.show()

参考链接

[1]DenseNet 模型-CIFAR10图像分类: http://t.csdnimg.cn/InzLt
[2]经典神经网络论文超详细解读: http://t.csdnimg.cn/jVmaw

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

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

相关文章

搭建自己的多平台镜像站

# 1. 拉取代码 $ git clone https://github.com/wzshiming/crproxy.git $ cd crproxy/examples/default# 2. 修改网关域名 使用vim编辑start.sh文件&#xff0c;将第五行的gateway变量值修改为你自己设定的域名。 原&#xff1a;gatewaycr.zsm.io 修改为&#xff1a;gatewayXS…

go语言 | 快速生成数据库表的 model 和 queryset

就是生成 model 目录的 xxx.go 和 xxx_gen.go 文件 使用的工具&#xff1a; 快速生成 model&#xff1a;gentool&#xff1a;https://github.com/go-gorm/gen/tree/master/tools/gentool 根据 model 生成 queryset&#xff1a;go-queryset&#xff1a;https://github.com/jirfa…

layuimini框架实现点击菜单栏回到起始页

在layui页面中&#xff0c;如果使用了 window.location.href""进行了页面跳转&#xff0c;再点击菜单栏是不会显示起始页&#xff0c;而是跳转后的页面&#xff0c; 解决&#xff1a; 在miniTab.js文件中找到&#xff1a;listen方法 将其中修改为&#xff1a; if …

全球首创4090推理!昆仑万维开源Skywork-MoE模型

昆仑万维近期宣布开源了其2千亿参数规模的稀疏大模型Skywork-MoE。这个模型是基于他们之前开源的Skywork-13B模型中间checkpoint扩展而来的&#xff0c;并且宣称是首个完整应用MoE Upcycling技术的开源千亿MoE大模型。此外&#xff0c;它也是首个支持使用单台RTX 4090服务器&am…

MyBatisPlus代码生成器(交互式)快速指南

引言 本片文章是对代码生成器(交互)快速配置使用流程&#xff0c;更多配置方法可查看官方文档&#xff1a; 代码生成器配置官网 如有疑问欢迎评论区交流&#xff01; 文章目录 引言演示效果图引入相关依赖创建代码生成器对象引入Freemarker模板引擎依赖支持的模板引擎 MyBat…

Day 20:2806. 取整购买后的账户余额

Leetcode 2806. 取整购买后的账户余额 一开始&#xff0c;你的银行账户里有 100 块钱。 给你一个整数purchaseAmount &#xff0c;它表示你在一次购买中愿意支出的金额。 在一个商店里&#xff0c;你进行一次购买&#xff0c;实际支出的金额会向 最近 的 10 的 倍数 取整。换句…

【QT5】<总览二> QT信号槽、对象树及常用函数

文章目录 前言 一、QT信号与槽 1. 信号槽连接模型 2. 信号槽介绍 3. 自定义信号槽 二、QT的对象树 三、添加资源文件 四、样式表的使用 五、QSS文件的使用 六、常用函数与宏 前言 承接【QT5】&#xff1c;总览一&#xff1e; QT环境搭建、快捷键及编程规范。若存在版…

Python使用tkinter库设置背景图片、label显示位置和label设置显示图片

tkinter 设置背景图片 label显示位置 label设置显示图片 from tkinter import * import tkinter as tk from PIL import ImageTk from PIL import Imagedef get_img(filename, width, height):im Image.open(filename).resize((width, height))im ImageTk.PhotoImage(im)…

网络仿真方法综述

目录 1. 引言 2.仿真器介绍 2.1 NS-2 2.2 NS-3 2.3 OPNET 2.4 GNS3 3.仿真对比 4.结论 参考文献 1. 引言 网络仿真是指使用计算机模拟网络系统的行为和性能的过程。在网络仿真中&#xff0c;可以建立一个虚拟的网络环境&#xff0c;并通过模拟各种网络设备、协议和应用程…

this关键字,构造函数(构造器)

文章目录 thisthis是什么应用场景 构造器注意事项代码演示 this this是什么 this就是一个变量&#xff0c;可以在方法中&#xff0c;拿到当前对象 应用场景 解决变量名称 冲突问题 构造器 注意事项 必须和类名相同没有返回值只要参数不同&#xff08;个数不同&#xff0…

【C语言】10.操作符详解

一、操作符分类 • 算术操作符&#xff1a; 、- 、* 、/ 、% • 移位操作符: << 、 >> • 位操作符: & 、|、^、 ~ • 赋值操作符: 、 、 - 、 、 / 、% 、<< 、>> 、& 、| 、^ • 单目操作符&#xff1a; &#xff01;、、–、&、、、…

postman教程-20-Newman安装入门

上一小节我们学习了Postman mock测试的方法&#xff0c;本小节我们讲解一下Postman Newman的安装方法。 Newman是Postman团队开发的一个命令行工具&#xff0c;它允许用户通过命令行接口&#xff08;CLI&#xff09;运行Postman集合&#xff08;Collections&#xff09;和环境…

样式的双向绑定的2种方式,实现样式交互效果

与样式标签实现双向绑定 通过布尔值来决定样式是出现还是消失 show代表着布尔值&#xff0c;show的初始值是false所以文本不会有高亮的效果&#xff0c;当用户点击了按钮&#xff0c;就会调用shows这个函数&#xff0c;并将show的相反值true赋值并覆盖给show,此时show的值为tru…

0602 差分式放大电路

差分式放大电路 差分放大电路的基本概念直接耦合放大电路中的零点漂移 6.2.1 差分式放大的基本概念 6.2.2 直接耦合放大电路中的零点漂移 6.2.3 BJT射极耦合差分式放大电路 差分放大电路的基本概念 直接耦合放大电路中的零点漂移

.NET Core 服务注册步骤总结

总结一下 .NET Core 服务注册的步骤&#xff1a; .NET Core Web Api 项目服务注册步骤&#xff1a; 创建一个接口&#xff0c;和实现类 比如&#xff1a;IMyService, CnService 在 Program.cs 的 var app builder.Build(); 语句之前加上&#xff1a; var builder WebApplic…

鸿蒙开发:【线程模型】

线程模型 线程类型 Stage模型下的线程主要有如下三类&#xff1a; 主线程 执行UI绘制。管理主线程的ArkTS引擎实例&#xff0c;使多个UIAbility组件能够运行在其之上。管理其他线程的ArkTS引擎实例&#xff0c;例如使用TaskPool&#xff08;任务池&#xff09;创建任务或取消…

使用 PNPM 从 0 搭建 monorepo,测试并发布

1 目标 通过 PNPM 创建一个 monorepo&#xff08;多个项目在一个代码仓库&#xff09;项目&#xff0c;形成一个通用的仓库模板。 这个仓库既可以用于公司存放和管理所有的项目&#xff0c;也可以用于将个人班余的所有积累整合其中。 2 环境要求 核心是 PNPM 和 Node.js&…

SpringAI调用OpenAI Demo

Spring AI 在maven的setting.xml <mirror> <id>spring-milestones</id> <name>Spring Milestones</name> <mirrorOf>spring-milestones</mirrorOf> <url>https://repo.sprin…

RV32A\CSR\Counters 指令集

RV32A\CSR\Counters指令集 一、RV32A指令集1、Load-Reserved/Store-Conditional InstructionsLR.WSC.W2、Atomic Memory OperationsAMOSWAP.WAMOADD.WAMOAND.WAMOXOR.WAMOOR.W二、CSR(Control and Status Register) 指令集CSRRWCSRRSCSRRCCSRRWICSRRSICSRRCI三、"Zicntr…

uniapp上传头像并裁剪图片

第一步写上uniapp自带的选择图片button按钮 点击之后会弹出选择图片的方式 拍照或从相册选择图片后将会跳到图片裁剪 然后我们裁剪完之后点击确定在上传图片 这里是上传图片的接口 拿到本地图片 上传的话自己想以那种方式上传都可以