深度学习基础案例3--构建CNN卷积神经网络实现对不同天气的识别(测试集准确率百分之90+)

news2024/11/14 21:40:20
  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊

基础阶段目标目标

  • 熟悉CNN、RNN神经网络,了解yolo、transfomer等模型
  • 熟练使用Pytorch框架,了解tensorflow

本次目标

  • 了解CNN神经网络构建思路
  • 熟悉pytroch框架

本次案例:

  • 测试集准确率达到了百分之90+,整体预测效果不错
  • 不足: 没有测试集准确率没有达到百分之95,对神经网络的优化和修改能力欠缺

环境:

  • python:3.8.19
  • gpu:cuda
  • torch:2.4.0
  • torchvision:0.19.0
  • 编译器:vscode、jupyter

文章目录

  • 1、前期准备
    • 1、导入库和检查GPU设备
    • 2、导入数据
      • 显示图像
        • API介绍
        • API介绍
      • 加载所有图像
        • datasets.ImageFolder()函数解释
        • transforms.Compose函数解释
    • 3、划分数据集与加载数据
      • 划分数据
        • torch.utils.data.random_split()方法总结
      • 动态加载数据
        • torch.utils.data.DataLoader()简介
  • 2、构建CNN模型
    • torch.nn.Linear()解释
    • 模型的构建
    • 将模型转到GPU
  • 3、模型训练
    • 设置超参数
    • 训练函数
    • 编写测试函数
  • 4、正式训练
    • model.train()
    • model.eval()
    • 模型训练
  • 5、结果显示
  • 6、总结
    • 1、学习总结
    • 2、API总结

1、前期准备

1、导入库和检查GPU设备

import torch 
import torch.nn as nn 
import torchvision 
import torchvision.transforms as transforms  # 这个库种包含了大量的图像处理函数,可以对图像数据进行缩放、裁剪、颜色增强、转置、归一化等
from torchvision import transforms, datasets  # 可以省略 .torchvision 前缀,datasets里卖弄包含了大量的数据

import os,PIL,pathlib,random 
# os:提供了与操作系统交互的接口,包含了一系列处理路径、文件、目录、环境变量的功能
# PIL:处理图像,包括打开、编辑、保存多种格式的图片
# pathlib:处理文件,包括创建、检查、删除
# random:随机数

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(torch.__version__)
print(torchvision.__version__)
print(device)

结果:

2.4.0
0.19.0
cuda

2、导入数据

显示图像

文件目录:data(有四类天气图片的目录)

data_dir = './data/'
data_dir = pathlib.Path(data_dir)  # 转化为 pathlib 对象

data_paths =  list(data_dir.glob('*'))  # 查找 该目录 下的所有 文件路径,如:WindowsPath('data/cloudy')
classNames = [str(name).split("\\")[1] for name in data_paths]    # .split 返回的是一个数组
classNames  # 输出该目录下四类天气文件名字

结果:

['cloudy', 'rain', 'shine', 'sunrise']
API介绍
  • pathlib.Path(): 将文件转化成 pathlib 对象
  • data_dir.glob(‘*’):显示 data_dir 目录下所有的文件
  • [str(name).split(“\”)[1] for name in data_paths] 列表推导式
# 显示一部分图片
import matplotlib.pyplot as plt 
from PIL import Image   # PIL 下的图像处理中的 Image库

# 指定图片路径
image_dir = './data/cloudy/'

# 遍历所有文件
image_files = [f for f in os.listdir(image_dir) if f.endswith((".jpg", ".png", ".jpeg"))]

# 创建子图
fig, axes = plt.subplots(3, 8, figsize=(16, 6))   #fig 是子图对象 ,axes 相当于一个子图框, 

# 加载数据和现实图像
for ax, img_file in zip(axes.flat, image_files):
    img_path = os.path.join(image_dir, img_file)  # 拼接
    img = Image.open(img_path)
    ax.imshow(img)     # ax 一个子图框
    ax.axis('off') 

# 显示
plt.show()


在这里插入图片描述

API介绍
  • os.listdir():遍历该目录的所有文件
  • zip():结合成对象,例如:
# 输入
names = ['Alice', 'Bob', 'Charlie']
ages = [24, 30, 35]

# 结果
[('Alice', 24), ('Bob', 30), ('Charlie', 35)]
  • os.path.join():拼接路径
  • Image.open(): 打开图片文件

加载所有图像

# 加载所有的图片
total_dir = './data/'

# 使用 trainsfroms.Compose 函数
train_transforms = transforms.Compose([
    transforms.Resize([224, 224]),    # 统一图片大小
    transforms.ToTensor(),            # 将PIL、Image、numpy转化成 Tensor
    transforms.Normalize(              # 数据标准化处理---> 转化为 标准状态分布,使模型更容易收敛
        mean=[0.485, 0.456, 0.406],  # rgb,均值
        std=[0.229, 0.224, 0.225]    # rgb,标准差,这两个从数据集中随机抽样得到的
    )
])

total_data = datasets.ImageFolder(total_dir, transform=train_transforms)
total_data

结果:

Dataset ImageFolder
    Number of datapoints: 1125
    Root location: ./data/
    StandardTransform
Transform: Compose(
               Resize(size=[224, 224], interpolation=bilinear, max_size=None, antialias=True)
               ToTensor()
               Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
           )
datasets.ImageFolder()函数解释

torchvision.datasets.ImageFolder 是 PyTorch 中一个非常有用的类,用于从磁盘上的文件夹结构中加载图像数据集。它假设你的数据集是按照类别组织的,每个类别有一个独立的文件夹,文件夹的名称通常代表该类别的标签。

参数:

  • root (string): 指定包含类别文件夹的根目录。
  • transform (callable, optional): 一个可选的函数/变换,它将被应用于每个加载的样本,通常用于数据预处理。
  • target_transform (callable, optional): 一个可选的函数/变换,它将被应用于目标/标签,例如将标签转换为 one-hot 编码。
  • loader (callable, optional): 一个可选的函数,用于从给定的文件路径加载一个样本。默认情况下,它使用 default_loader,这是一个简单的函数,使用 PIL 来加载图像。
transforms.Compose函数解释

transforms:里面含有常见的图片变换操作,如旋转、剪裁等。
详细请看:https://blog.csdn.net/qq_38251616/article/details/124878863

3、划分数据集与加载数据

划分数据

# 训练集 0.8,测试集 0.2
train_size = int(len(total_data) * 0.8)    # 注意要转换成 int 类型,默认是 float类型
test_size = len(total_data) - train_size
train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])
print(train_dataset)
print(test_dataset)
# 结果:
<torch.utils.data.dataset.Subset object at 0x000001DC5B727D00>
<torch.utils.data.dataset.Subset object at 0x000001DC572722B0>
torch.utils.data.random_split()方法总结

这个函数作用是随机划分数据,将总体大小划分为[train_size, test_size]的大小

动态加载数据

batch_size = 32   # 自定义:每一批加载 32 个数据

train_dl = torch.utils.data.DataLoader(train_dataset,
                                       batch_size=batch_size,
                                       shuffle=True,
                                       num_workers=1)

test_dl = torch.utils.data.DataLoader(test_dataset,
                                      batch_size=batch_size,
                                      shuffle=True,
                                      num_workers=1)

# 查看数据大小
imgs, labels = next(iter(test_dl))
print("Shape of imgs [N, C, H, W]: ", imgs.shape)
print("Shape of labels: ", labels.shape, labels.dtype)
labels   # labels 是一维张量,大小同N,代表分类的信息,如下:0为一类,3为1类,2为一类,在datasets.ImageFolder加载数据中分好类了
# 结果:
Shape of imgs [N, C, H, W]:  torch.Size([32, 3, 224, 224])
Shape of labels:  torch.Size([32]) torch.int64
tensor([2, 3, 1, 1, 3, 0, 2, 0, 3, 2, 0, 1, 3, 3, 3, 3, 2, 3, 3, 0, 2, 0, 0, 2,
        2, 1, 3, 3, 2, 0, 3, 1])
torch.utils.data.DataLoader()简介

作用:动态加载和管理数据,并且支持并行化

  1. dataset(必需参数):这是你的数据集对象,通常是 torch.utils.data.Dataset 的子类,它包含了你的数据样本。
  2. batch_size(可选参数):指定每个小批次中包含的样本数。默认值为 1。
  3. shuffle(可选参数):如果设置为 True,则在每个 epoch 开始时对数据进行洗牌,以随机打乱样本的顺序。这对于训练数据的随机性很重要,以避免模型学习到数据的顺序性。默认值为 False。
  4. num_workers(可选参数):用于数据加载的子进程数量。通常,将其设置为大于 0 的值可以加快数据加载速度,特别是当数据集很大时。默认值为 0,表示在主进程中加载数据。
  5. pin_memory(可选参数):如果设置为 True,则数据加载到 GPU 时会将数据存储在 CUDA 的锁页内存中,这可以加速数据传输到 GPU。默认值为 False。
  6. drop_last(可选参数):如果设置为 True,则在最后一个小批次可能包含样本数小于 batch_size 时,丢弃该小批次。这在某些情况下很有用,以确保所有小批次具有相同的大小。默认值为 False。
  7. timeout(可选参数):如果设置为正整数,它定义了每个子进程在等待数据加载器传递数据时的超时时间(以秒为单位)。这可以用于避免子进程卡住的情况。默认值为 0,表示没有超时限制。
  8. worker_init_fn(可选参数):一个可选的函数,用于初始化每个子进程的状态。这对于设置每个子进程的随机种子或其他初始化操作很有用。

2、构建CNN模型

torch.nn.Linear()解释

全连接层作用,进行线性和非线性变换,起到降维作用,输出想要的维度,即类别
函数原型:
torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)

关键参数说明:

  • in_features:每个输入样本的大小
  • out_features:每个输出样本的大小

注意: 卷积层和池化层API、原理讲解,参考:CIRFAR10才是图片识别

模型的构建

本文构建的模型中,有四层卷积层,两层池化层,最后一层全连接层,模型原理和计算流程如下:
模型原理图:

在这里插入图片描述

计算:
输入数据:[3, 224, 224]–> 卷积层1:[12, 220, 220]–> 卷积层2:[12, 216, 216]–> 池化层1:[12, 108, 108]–> 卷积层3:[24, 104, 104]–> 卷积层4:[24, 100, 100]–> 池化层2:[24, 50, 50]–> 全连接层展开降维: 24 * 50 * 50–> num_classes(4)

import torch.nn.functional as F  # 激活函数

class Network_bn(nn.Module):  # nn.Module 继承父类
    def __init__(self):
        super(Network_bn, self).__init__()
        
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=5, stride=1, padding=0)
        self.bn1 = nn.BatchNorm2d(12)  # 对二维特征进行归一化,提高稳定性,12是输入通道数
        self.conv2 = nn.Conv2d(in_channels=12, out_channels=12, kernel_size=5, stride=1, padding=0)
        self.bn2 = nn.BatchNorm2d(12)      
        self.pool1 = nn.MaxPool2d(2, 2)
        self.conv3 = nn.Conv2d(in_channels=12, out_channels=24, kernel_size=5, stride=1, padding=0)
        self.bn3 = nn.BatchNorm2d(24)
        self.conv4 = nn.Conv2d(in_channels=24, out_channels=24, kernel_size=5, stride=1, padding=0)
        self.bn4 = nn.BatchNorm2d(24)
        self.pool2 = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(24 * 50 * 50, len(classNames))
        
    # 构建神经网络
    def forward(self, x):
        x = F.relu(self.bn1(self.conv1(x)))
        x = F.relu(self.bn2(self.conv2(x)))
        x = self.pool1(x)
        x = F.relu(self.bn3(self.conv3(x)))
        x = F.relu(self.bn4(self.conv4(x)))
        x = self.pool2(x)
        x = x.view(-1, 24 * 50 * 50)  # 用 torch.flatten 也行
        x = self.fc1(x)
        
        return x

将模型转到GPU

model = Network_bn().to(device)
model

结果(模型的结构和参数):

Network_bn(
  (conv1): Conv2d(3, 12, kernel_size=(5, 5), stride=(1, 1))
  (bn1): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (conv2): Conv2d(12, 12, kernel_size=(5, 5), stride=(1, 1))
  (bn2): BatchNorm2d(12, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv3): Conv2d(12, 24, kernel_size=(5, 5), stride=(1, 1))
  (bn3): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (conv4): Conv2d(24, 24, kernel_size=(5, 5), stride=(1, 1))
  (bn4): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (fc1): Linear(in_features=60000, out_features=4, bias=True)
)

3、模型训练

设置超参数

loss_fn = nn.CrossEntropyLoss()  # 创建损失函数
learn_rate = 1e-4  # 学习率
opt = torch.optim.SGD(model.parameters(), lr=learn_rate)  # 优化的参数和学习率

训练函数

# 注意:optimizer只负责通过梯度下降进行优化,而不负责产生梯度,梯度是tensor.backward()方法产生的。
def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)  # 训练集大小 
    num_batches = len(dataloader)   # 批次
    
    train_loss, trian_acc = 0, 0   # 记录损失率
    
    for X, y in dataloader:
        X, y = X.to(device), y.to(device)  # 转入GPU
        
        # 预测
        pred = model(X)
        # 计算误差
        loss = loss_fn(pred, y)
        
        # 反向传播
        optimizer.zero_grad()  # 梯度归 0
        loss.backward()     # 反向传播
        optimizer.step()     # 自动跟新权重
        
        # 记录acc和loss
        trian_acc += (pred.argmax(1) == y).type(torch.float64).sum().item()
        train_loss += loss.item()   # .item() 为转化成标准类型项
    
    # 计算acc和loss
    trian_acc /= size           # 总体准确率
    train_loss /= num_batches   # 得到的是平均损失,每一批次的loss
    
    return trian_acc, train_loss 

pred.argmax(1) == y:pred 是模型对一批次数据的预测输出,通常是一个二维张量,其中每一行代表一个样本,每一列代表该样本属于不同类别的预测得分。.argmax(1) 函数会找到每一行(即每个样本)中最大值的索引,这通常代表模型预测的类别标签。y 是这批数据的实际标签。

编写测试函数

测试函数和训练函数大概相同,但是由于不进行梯度下降对网络权重进行更新,故不需要优化器

def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)  # 测试集大小,10000张
    num_batches = len(dataloader)   # 测试集批次, 313, 每一批 32 张
    
    test_acc, test_loss = 0, 0
    
    # 不进行反向传播了
    with torch.no_grad():
        for imgs, target in dataloader:
            imgs, target = imgs.to(device), target.to(device)
            
            # 计算loss
            target_pred = model(imgs)
            loss = loss_fn(target_pred, target)   # 注意:顺序有要求
            
            test_acc += (target_pred.argmax(1) == target).type(torch.float64).sum().item()
            test_loss += loss.item()
            
    
    test_acc /= size  # 整体
    test_loss /= num_batches  # 平均损失
    
    return test_acc, test_loss

4、正式训练

model.train()

model.train()的作用是启用 Batch Normalization 和 Dropout。

如果模型中有BN层(Batch Normalization)和Dropout,需要在训练时添加model.train()。model.train()是保证BN层能够用到每一批数据的均值和方差。对于Dropout,model.train()是随机取一部分网络连接来训练更新参数。

model.eval()

model.eval()的作用是不启用 Batch Normalization 和 Dropout。

如果模型中有BN层(Batch Normalization)和Dropout,在测试时添加model.eval()。model.eval()是保证BN层能够用全部训练数据的均值和方差,即测试过程中要保证BN层的均值和方差不变。对于Dropout,model.eval()是利用到了所有网络连接,即不进行随机舍弃神经元。

模型训练

epochs = 30
train_acc = []
train_loss = []
test_acc = []
test_loss = []

for epoch in range(epochs):
    model.train()   # 有bn层设置
    epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)
    
    model.eval()  # 训练用的,保证全程均值和方差一样
    epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
    
    train_acc.append(epoch_train_acc)
    train_loss.append(epoch_train_loss)
    test_acc.append(epoch_test_acc)
    test_loss.append(epoch_test_loss)
    
    template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}')
    print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss))
    
print('Done')
Epoch: 1, Train_acc:94.6%, Train_loss:0.211, Test_acc:90.2%, Test_loss:0.244
Epoch: 2, Train_acc:95.9%, Train_loss:0.182, Test_acc:88.9%, Test_loss:0.261
Epoch: 3, Train_acc:95.0%, Train_loss:0.210, Test_acc:90.2%, Test_loss:0.257
Epoch: 4, Train_acc:95.6%, Train_loss:0.206, Test_acc:84.9%, Test_loss:0.335
Epoch: 5, Train_acc:95.8%, Train_loss:0.167, Test_acc:90.7%, Test_loss:0.241
Epoch: 6, Train_acc:96.3%, Train_loss:0.190, Test_acc:88.4%, Test_loss:0.306
Epoch: 7, Train_acc:96.8%, Train_loss:0.173, Test_acc:88.0%, Test_loss:0.748
Epoch: 8, Train_acc:96.2%, Train_loss:0.155, Test_acc:91.1%, Test_loss:0.327
Epoch: 9, Train_acc:96.7%, Train_loss:0.140, Test_acc:90.2%, Test_loss:0.223
Epoch:10, Train_acc:96.9%, Train_loss:0.140, Test_acc:91.6%, Test_loss:0.243
Epoch:11, Train_acc:97.1%, Train_loss:0.140, Test_acc:90.2%, Test_loss:0.299
Epoch:12, Train_acc:97.3%, Train_loss:0.160, Test_acc:90.2%, Test_loss:0.251
Epoch:13, Train_acc:97.2%, Train_loss:0.165, Test_acc:91.1%, Test_loss:0.247
Epoch:14, Train_acc:97.6%, Train_loss:0.150, Test_acc:88.0%, Test_loss:0.301
Epoch:15, Train_acc:97.1%, Train_loss:0.170, Test_acc:87.1%, Test_loss:0.268
Epoch:16, Train_acc:97.3%, Train_loss:0.132, Test_acc:91.1%, Test_loss:0.265
Epoch:17, Train_acc:97.8%, Train_loss:0.136, Test_acc:91.1%, Test_loss:0.253
Epoch:18, Train_acc:97.3%, Train_loss:0.117, Test_acc:89.8%, Test_loss:0.220
Epoch:19, Train_acc:97.7%, Train_loss:0.142, Test_acc:91.6%, Test_loss:0.421
Epoch:20, Train_acc:96.9%, Train_loss:0.159, Test_acc:90.7%, Test_loss:0.261
Epoch:21, Train_acc:97.9%, Train_loss:0.102, Test_acc:90.2%, Test_loss:0.229
Epoch:22, Train_acc:98.4%, Train_loss:0.093, Test_acc:90.7%, Test_loss:0.210
Epoch:23, Train_acc:98.3%, Train_loss:0.110, Test_acc:89.3%, Test_loss:0.244
Epoch:24, Train_acc:98.4%, Train_loss:0.144, Test_acc:91.1%, Test_loss:0.245
Epoch:25, Train_acc:97.4%, Train_loss:0.114, Test_acc:91.1%, Test_loss:0.227
Epoch:26, Train_acc:97.9%, Train_loss:0.161, Test_acc:88.4%, Test_loss:0.307
Epoch:27, Train_acc:97.4%, Train_loss:0.108, Test_acc:91.1%, Test_loss:0.238
Epoch:28, Train_acc:98.6%, Train_loss:0.092, Test_acc:91.6%, Test_loss:0.268
Epoch:29, Train_acc:99.2%, Train_loss:0.080, Test_acc:91.1%, Test_loss:0.206
Epoch:30, Train_acc:99.0%, Train_loss:0.086, Test_acc:91.6%, Test_loss:0.287
Done

5、结果显示

import matplotlib.pyplot as plt 

#隐藏警告和显示中文
import warnings
warnings.filterwarnings("ignore")               #忽略警告信息
plt.rcParams['font.sans-serif']    = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False      # 用来正常显示负号
plt.rcParams['figure.dpi']         = 100        #分辨率

x = range(epochs)
# 创建画板
plt.figure(figsize=(12, 3))
# 子图一
plt.subplot(1, 2, 1)
plt.plot(x, train_acc, label='Train Accurary')
plt.plot(x, test_acc, label='Test Accurary')
plt.legend(loc='lower right')
plt.title("Train and test Accurary")
# 子图二
plt.subplot(1, 2, 2)
plt.plot(x, train_loss, label='Train loss')
plt.plot(x, test_loss, label='Test loss')
plt.legend(loc='upper right')
plt.title("Train and test Loss")

plt.show()


在这里插入图片描述

Accurary:

  • 训练集准确率逐步提升均在百分之90以上
  • 测试集也均在85% - 90%
    Loss:
  • 训练集均在0.2一下
  • 测试集后面稳定在0.3一下

总体效果不错

6、总结

1、学习总结

  • 进一步熟悉了pytorch的使用
  • 进一步深入了解了cnn神经网络:卷积层、池化层、全连接层的作用,以及自动微分、清理梯度、自动跟新权重的步骤
  • 进一步了解了准确率(Accurary)和损失率(Loss)的意义,以及API是如何计算的,计算场景是怎么样子的
  • 了解了Python如何处理图像文件方法
  • 不足:无法自己修改神经网络结构,不怎么如何做优化

2、API总结

  • pathlib.Path(): 将文件转化成 pathlib 对象

  • data_dir.glob('*'):显示 data_dir 目录下所有的文件

  • [str(name).split("\\")[1] for name in data_paths] : 列表推导式

  • os.listdir():遍历该目录的所有文件

  • zip():结合成对象

  • datasets.ImageFolder():pytorch在文件中加载图片

  • transforms.Compose:torchvision中处理图片的API,可以统一图片大小,旋转、分割等作用

  • torch.utils.data.random_split():按照比例随机划分数据

  • torch.nn.Linear():全连接层,本质定义线性和非线性函数,可以将多维展开然后降维输出特征

  • model.train(): model.train()是保证BN层能够用到每一批数据的均值和方差。

  • model.eval(): model.eval()是不启用BN层(不对数据进行进一步归一化,稳定性处理),全过程用到的均值和方差是全部test集的

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

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

相关文章

使用ToDesk云电脑3个月,这5个功能点越用越爽!

在过去的三个月里&#xff0c;小埋 有幸 深度 体验了ToDesk云电脑这一创新科技产品&#xff0c;它不仅彻底改变了我的工作方式&#xff0c;还让我在日常学习和娱乐中享受到了前所未有的便捷与高效。 下面就跟着小埋&#xff0c;一起来看看 ToDesk云电脑使用体验极佳的五大功能特…

解决银河麒麟V10登录循环的方法

解决银河麒麟V10登录循环的方法 一&#xff1a;进入命令行二&#xff1a;删除.Xauthority文件三&#xff1a;重启系统 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在使用银河麒麟桌面操作系统V10时&#xff0c;有时可能会遇到一个令人头…

JavaScript - 对象

Array 数组 定义 var 变量名 new Array(元素列表)&#xff1b;//方式一 var 变量名 [ 元素列表 ]&#xff1b;//方式二 访问 arr[ 索引] 值&#xff1b; 属性 length : 设置或返回数组中元素的数量 方法 forEach() : 遍历数组中每个有值的元素&…

Spring cloud alibaba(一)nacos

一、注册中心 作用&#xff1a;解决微服务之间复杂的调用关系&#xff1b; 实现思路&#xff1a; 服务注册&#xff1a;就是将提供某个服务的模块信息注册到一个公共组件上去 服务发现&#xff1a;就是新注册这个服务模块能够及时的呗其它调用者发现&#xff0c;不管是服务新增…

前端开发中的大屏布局方案:使用 rem 单位与动态设置 html 的 font-size

使用 rem 单位与动态设置 html 的 font-size 前言 随着设备尺寸的多样化&#xff0c;网页需要能够在不同大小的屏幕上提供良好的用户体验。传统的布局方式&#xff08;如使用 px&#xff09;在不同分辨率下可能会导致布局失真。为了解决这个问题&#xff0c;我们可以通过动态…

微分方程(Blanchard Differential Equations 4th)中文版Section3.3

具有实特征值的线性系统的相图 在前面的部分,我们看到直线解在求解某些线性微分方程系统的通解中起着主导作用。为了求解这样的系统,我们首先使用代数方法计算系数矩阵的特征值和特征向量。当我们找到一个实特征值和一个相关的特征向量时,就可以写出对应的直线解。此外,在…

Element-02.组件-Table表格

一.常见组件-表格 二.具体操作 <template><el-table:data"tableData"borderstyle"width: 100%"><el-table-columnprop"date"label"日期"width"180"></el-table-column><el-table-columnprop&q…

使用Apache POI和POI-OOXML实现word模板文档自动填充功能

最近接到一个新的需求&#xff0c;用户创建好模板文件保存到模板库&#xff0c;然后使用在线文档编辑器打开模板时&#xff0c;将系统数据填充到模板文件并生成新的word文件&#xff0c;然后在线编辑&#xff0c;研究使用Apache POI和POI-OOXML实现了这个功能。 Maven依赖 <…

AI提效实例-借助AI高效生成Markdown格式的超链接

我在学习谷粒商城的过程中&#xff0c;每集都写一篇博客笔记&#xff0c;为了方便查找&#xff0c;把所有博客都汇总到一起谷粒商城笔记汇总&#xff0c;如下。 现在一共有142篇笔记。 之前每发表一篇就把地址记录下来&#xff0c;虽然麻烦&#xff0c;还可忍受。 后来有点懈…

Pcie学习笔记(24)

Ordering and Receive Buffer Flow Control 流量控制(FC)用于防止接收端缓冲区溢出&#xff0c;并使其符合定义的排序规则。请注意&#xff0c;请求者使用流量控制机制来跟踪代理中可用的队列/缓冲区空间&#xff0c;如图2-48所示。也就是说&#xff0c;流控制是点对点的(跨一…

模型优化之剪枝

文章目录 什么是神经网络剪枝剪枝的好处不同粒度的剪枝剪枝的分类非结构化剪枝结构化剪枝 哪些层的参数更容易被剪掉剪枝效果 什么是神经网络剪枝 神经网络剪枝 在训练期间删除连接密集张量将变得稀疏&#xff08;用零填充&#xff09;可以通过结构化块&#xff08; n m nm nm&…

【无标题】playbook的基本使用

1、使用ansible安装并启动ftp服务 [root1 ~]# vim /etc/ansible/hosts s0 ansible_ssh_host10.0.0.12 ansible_ssh_port22 ansible_ssh_userroot ansible_ssh_pass1 s1 ansible_ssh_host10.0.0.13 ansible_ssh_port22 ansible_ssh_userroot ansible_ssh_pass1 s2 ansible_s…

Android 12系统源码_屏幕设备(二)DisplayAdapter和DisplayDevice的创建

前言 在Android 12系统源码_屏幕设备&#xff08;一&#xff09;DisplayManagerService的启动这篇文章中我们具体分析了DisplayManagerService 的启动流程&#xff0c;本篇文章我们将在这个的基础上具体来分析下设备屏幕适配器的创建过程。 一、注册屏幕适配器 系统是在Disp…

43.x86游戏实战-DXX寻找吸怪坐标

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

Xshell中弹出“ssh服务器拒绝了密码请再试一次”时,如何解决

在使用Xshell连接Ubuntu系统时&#xff0c;可能会弹出这个错误 可能原因如下​ 密码输入错误Ubantu系统默认禁止root用户登录ssh。 解决方法&#xff1a; 1. 先用root登录 (由于我买的是云服务器&#xff0c;所以拿这个来举例&#xff09; 注&#xff1a;要在本地shell中登录…

基于jqury和canvas画板技术五子棋游戏设计与实现(论文+源码)_kaic

摘 要 网络五子棋游戏如今面临着一些新的挑战和机遇。一方面&#xff0c;网络游戏需要考虑到网络延迟和带宽等因素&#xff0c;保证游戏的实时性和稳定性。另一方面&#xff0c;网络游戏需要考虑到游戏的可玩性和趣味性&#xff0c;以吸引更多的玩家参与。本文基于HTML5和Canv…

银河麒麟V10忘记Root密码怎么办?

银河麒麟V10忘记Root密码怎么办&#xff1f; 一&#xff1a;进入GRUB模式二&#xff1a;输入GRUB账号密码三&#xff1a;修改启动参数四&#xff1a;修改root密码五&#xff1a;重启系统六&#xff1a;验证root密码 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

就想刷题过?新手必看的华为认证题库最强背题经验技巧

华为认证作为网络和IT领域的重要资格认证&#xff0c;其难度不容小觑。许多考生为了顺利通过考试&#xff0c;选择背题库作为备考策略。 &#xff08;重点说一下啊&#xff0c;不提倡刷题&#xff0c;能学知识&#xff0c;把技术学透&#xff0c;肯定是最佳的。&#xff09; …

Java基于数据库、乐观锁、悲观锁、Redis、Zookeeper分布式锁的简单案例实现(保姆级教程)

1. 分布式锁的定义 分布式锁是一种在分布式系统中用来协调多个进程或线程对共享资源进行访问的机制。它确保在分布式环境下&#xff0c;多个节点&#xff08;如不同的服务器或进程&#xff09;不会同时访问同一个共享资源&#xff0c;从而避免数据不一致、资源竞争等问题。 2…

简单记录:两台服务器如何超快速互传文件/文件夹

在服务器间传输文件和文件夹是一个常见的任务&#xff0c;尤其是在需要同步数据或进行备份时。以下是使用 scp 命令在两台服务器之间进行文件传输的基本步骤。 服务器A 至 服务器B&#xff1a;文件传输指南 前提条件 确保服务器A和服务器B之间网络互通。确认您有权限访问目标…