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

目录

  • 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

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

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

相关文章

【python】tkinter GUI开发: Button和Entry的应用实战探索

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

2024年计算机、信息工程与大数据应用国际会议(CIEBDA 2024)

2024 International Conference on Computer, Information Engineering, and Big Data Applications 【1】大会信息 会议简称&#xff1a;CIEBDA 2024 大会地点&#xff1a;中国青岛 审稿通知&#xff1a;投稿后2-3日内通知 投稿邮箱&#xff1a;ciebdasub-paper.com 【2】会…

【three.js】设置three.js全屏展示,并解决大小动态变化

目录 一、设置全屏 二、canvas画布宽高度动态变化 一、设置全屏 这个很简单,直接用代码读取当前全屏需要的长宽即可。 const width = window.innerWidth; //窗口文档显示区的宽度作为画布宽度 const height = window.innerHeight; //窗口文档显示区的高度作为画布高度 二、…

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

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

三:SpringBoot的helloworld和使用Springboot的优点以及快速创建Springboot应用

三&#xff1a;SpringBoot的helloworld和使用Springboot的优点以及快速创建Springboot应用 一&#xff1a;HelloWorld [我们创建的是maven项目或者直接创建一个Spring] 1.1&#xff1a;创建一个maven 项目&#xff08;1】&#xff1a;需要自己手动写一个SpringBoot 的启动类同…

EVA-CLIP实战

摘要 EVA-CLIP,这是一种基于对比语言图像预训练(CLIP)技术改进的模型,通过引入新的表示学习、优化和增强技术,显著提高了CLIP的训练效率和效果。EVA-CLIP系列模型在保持较低训练成本的同时,实现了与先前具有相似参数数量的CLIP模型相比更高的性能。特别地,文中提到的EV…

Flink的简单学习五

一 动态表与连续查询 1.1 动态表 1.是flink的支持流数据Table API 和SQL的核心概念。动态表随时间的变化而变化 2.在流上面定义的表在内部是没有数据的 1.2 连续查询 1.永远不会停止&#xff0c;结果是一张动态表 二 Flink SQL 2.1 sql行 1.先启动启动flink集群 yarn-see…

TOGAF架构介绍

框架组件 软件开发过程中通用能力的集合。 一个完整的框架包括&#xff1a;异常处理组件&#xff0c;数据访问组件&#xff0c;日志组件&#xff0c;错误码组件。

面向对象三大特征之:封装

文章目录 什么是封装&#xff1f;封装的设计规范 什么是封装&#xff1f; 就是用类设计对象处理某一个事物的数据时&#xff0c;应该把要处理的数据&#xff0c;以及处理这些书记的方法设计到一个对象中去。 封装的设计规范 合理隐藏&#xff0c;合理暴露 public就是都能访问…

搭建自己的多平台镜像站

# 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…

LeetCode | 66.加一

这道题有多个思路&#xff0c;可以依次取数组的每一位&#xff0c;乘10后加下一位&#xff0c;直到最后一位&#xff0c;就得到我们数组所表示的数字&#xff0c;然后加一&#xff0c;然后把新得到的数字再转化为对应的数组&#xff0c;我的做法是直接取数组的最后一位&#xf…

快速上手 GreatSQL 8.0.32-25 with openEuler 24.03 LTS

5 月底&#xff0c;openEuler 24.03 LTS 发布&#xff0c;详情戳&#xff1a; 恭喜&#xff01;openEuler 24.03 LTS 版本发布&#xff1a;首个AI原生开源操作系统 在诸多亮点特性中&#xff0c;有一条值得注意&#xff1a; 集成 GreatSQL 数据库&#xff0c;适用于金融级应用场…

小程序 js+Canvas 绘制半圆环虚线进度条

效果图&#xff1a; 思路&#xff1a;过程分为三步&#xff0c;第1步&#xff0c;先画虚线底部背景&#xff0c;第2步&#xff0c;画动态的虚线&#xff08;已选虚线蓝颜色&#xff09;&#xff0c;第3步&#xff0c;画动态的外标&#xff08;已选虚线外位置的标&#xff09;&a…

面向对象编程

文章目录 面向对象编程是怎么回事&#xff1a;面向对象编程的好处是&#xff1a;对象是啥&#xff0c;如何得到&#xff1f;运行原理代码举例注意事项&#xff1a;空指针异常 黑马学习笔记 面向对象编程是怎么回事&#xff1a; 祖师爷 詹姆斯高斯林 认为万物皆对象&#xff0c…

[next.js] svgr/webpack

nextjs如何配置svg文件&#xff0c;使其像react组件一样导入? 当前next.js 开发环境我使用了--turbo 来开启turbopack加速文件构建&#xff0c;所以之前的一些webpack loader之类的无法正常工作。通过搜索发现一般都是使用svgr/webpack来处理svg&#xff0c;打开svgr官网发现…

Stable Diffusion: ControlNet 插件安装

前面介绍了一些通过代码实现ControlNet进行控制的案例。现在通过Stable Diffusion体验一下更便捷的操作。 Stable Diffusion插件安装办法大致相同。启动Stable Diffusion后&#xff0c;点击最右边的“扩展”&#xff0c;点击“可下载”&#xff0c;点击“加载扩展列表”。 视网…

Linux服务器安装Jupyter,并设置公网访问详细教程

本章教程,主要介绍如何在Linux服务器上安装jupyter,并可以通过公网地址进行访问。 一、安装jupyter pip install jupyter二、生成jupyter配置文件 jupyter notebook --generate-config三、编辑这个配置文件 找到配置文件并修改以下配置项: # 允许所有 IP 地址访问 c.Noteb…

【Java面试】十九、并发篇(下):线程池

文章目录 1、为什么要使用线程池2、线程池的执行原理2.1 七个核心参数2.2 线程池的执行原理 3、线程池用到的常见的阻塞队列有哪些4、如何确定核心线程数开多少个&#xff1f;5、线程池的种类有哪些&#xff1f;6、为什么不建议用Executors封装好的静态方法创建线程池7、线程池…

【C++ | 左值、右值】一文了解C++的左值、右值、左值引用()、右值引用()

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-06-12 1…

鸿蒙轻内核A核源码分析系列五 虚实映射(5)虚实映射解除

虚实映射解除函数LOS_ArchMmuUnmap解除进程空间虚拟地址区间与物理地址区间的映射关系&#xff0c;其中参数包含MMU结构体、解除映射的虚拟地址和解除映射的数量count,数量的单位是内存页数。 ⑴处函数OsGetPte1用于获取指定虚拟地址对应的L1页表项数据。⑵处计算需要解除的无效…