深度学习 Day12——P1实现mnist手写数字识别

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊 | 接辅导、项目定制

文章目录

  • 前言
  • 1 我的环境
  • 2 代码实现与执行结果
    • 2.1 前期准备
      • 2.1.1 引入库
      • 2.1.2 设置GPU(如果设备上支持GPU就使用GPU,否则使用CPU)
      • 2.1.3 导入数据
      • 2.1.4 查看数据
      • 2.1.5.数据可视化
    • 2.2 构建CNN网络模型
    • 2.3 训练模型
      • 2.3.1 训练模型
      • 2.3.2 编写训练函数
      • 2.3.3 编写测试函数
      • 2.3.4 正式训练
    • 2.4 结果可视化
  • 3 知识点详解
    • 3.1 MNIST手写数字数据集介绍
    • 3.2 Torch.NN简介
      • 3.2.1nn.Module模块概述
      • 3.2.2 Sequential类的概述
    • 3.3【Pytorch】model.train() 和 model.eval() 原理与用法
      • 3.3.1 两种模式
      • 3.3.2功能
      • 3.3.3 总结与对比
  • 总结


前言

本文将采用pytorch框架创建CNN网络,实现简单实现mnist手写数字识别。讲述实现代码与执行结果,并浅谈涉及知识点。
关键字:MNIST手写数字数据集介绍,Torch.NN简介,Pytorch】model.train() 和 model.eval() 原理与用法。

1 我的环境

  • 电脑系统:Windows 11
  • 语言环境:python 3.8.6
  • 编译器:pycharm2020.2.3
  • 深度学习环境:
    torch == 1.9.1+cu111
    torchvision == 0.10.1+cu111
  • 显卡:NVIDIA GeForce RTX 4070

2 代码实现与执行结果

2.1 前期准备

2.1.1 引入库

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
plt.rcParams['figure.dpi'] = 100  # 分辨率
import torchvision
import numpy as np
from torchinfo import summary
import torch.nn.functional as F
import warnings

warnings.filterwarnings('ignore')  # 忽略一些warning内容,无需打印

2.1.2 设置GPU(如果设备上支持GPU就使用GPU,否则使用CPU)

"""前期准备-设置GPU-"""
# 如果设备上支持GPU就使用GPU,否则使用CPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

输出

cuda

2.1.3 导入数据

'''前期工作-导入数据'''
train_ds = torchvision.datasets.MNIST('data', 
                                      train=True, 
                                      transform=torchvision.transforms.ToTensor(), # 将数据类型转化为Tensor
                                      download=True)

test_ds  = torchvision.datasets.MNIST('data', 
                                      train=False, 
                                      transform=torchvision.transforms.ToTensor(), # 将数据类型转化为Tensor
                                      download=True)
batch_size = 32

train_dl = torch.utils.data.DataLoader(train_ds, 
                                       batch_size=batch_size, 
                                       shuffle=True)

test_dl  = torch.utils.data.DataLoader(test_ds, 
                                       batch_size=batch_size)

2.1.4 查看数据

'''前期工作-查看数据'''                                       
# 取一个批次查看数据格式
# 数据的shape为:[batch_size, channel, height, weight]
# 其中batch_size为自己设定,channel,height和weight分别是图片的通道数,高度和宽度。
imgs, labels = next(iter(train_dl))  # 通过 iter(train_dl) 创建一个数据迭代器,然后使用 next(train_dl) 从训练数据加载一个批次的图像和对应的标签。
# images包含了一批图像,labels 包含了这些图像的类别标签。
print(imgs.shape)

输出

torch.Size([32, 1, 28, 28])

2.1.5.数据可视化

'''前期工作-数据可视化'''
# 指定图片大小,图像大小为20宽、5高的绘图(单位为英寸inch)
plt.figure(figsize=(20, 5))
for i, img in enumerate(imgs[:20]):
    # 维度缩减,去除所有维度为1的维度
    npimg = np.squeeze(img.numpy())
    # 将整个figure分成2行10列,绘制第i+1个子图。
    plt.subplot(2, 10, i + 1)
    plt.imshow(npimg, cmap=plt.cm.binary)  # 使用matlablib库cm子库中的binary颜色映射,讲图像渲染维黑白色
    plt.axis('off')  # 取消坐标轴显示
plt.show()  # 如果你使用的是Pycharm编译器,请加上这行代码

在这里插入图片描述

2.2 构建CNN网络模型

在这里插入图片描述

"""构建CNN网络"""
num_classes = 10  # 图片的类别数


class Model(nn.Module):
    def __init__(self):
        super().__init__()
        # 特征提取网络
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3)  # 第一层卷积,卷积核大小为3*3
        self.pool1 = nn.MaxPool2d(2)  # 设置池化层,池化核大小为2*2
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3)  # 第二层卷积,卷积核大小为3*3
        self.pool2 = nn.MaxPool2d(2)

        # 分类网络
        self.fc1 = nn.Linear(1600, 64)
        self.fc2 = nn.Linear(64, num_classes)

    # 前向传播
    def forward(self, x):
        x = self.pool1(F.relu(self.conv1(x)))
        x = self.pool2(F.relu(self.conv2(x)))

        x = torch.flatten(x, start_dim=1)

        x = F.relu(self.fc1(x))
        x = self.fc2(x)

        return x


# 将模型转移到GPU中(我们模型运行均在GPU中进行)
model = Model().to(device)
summary(model)

输出

=================================================================
Layer (type:depth-idx)                   Param #
=================================================================
Model                                    --
├─Conv2d: 1-1                            320
├─MaxPool2d: 1-2                         --
├─Conv2d: 1-3                            18,496
├─MaxPool2d: 1-4                         --
├─Linear: 1-5                            102,464
├─Linear: 1-6                            650
=================================================================
Total params: 121,930
Trainable params: 121,930
Non-trainable params: 0
=================================================================

2.3 训练模型

2.3.1 训练模型

"""训练模型--设置超参数"""
loss_fn = nn.CrossEntropyLoss()  # 创建损失函数,计算实际输出和真实相差多少,交叉熵损失函数,事实上,它就是做图片分类任务时常用的损失函数
learn_rate = 1e-2  # 学习率
opt = torch.optim.SGD(model.parameters(), lr=learn_rate)  # 作用是定义优化器,用来训练时候优化模型参数;其中,SGD表示随机梯度下降,用于控制实际输出y与真实y之间的相差有多大

2.3.2 编写训练函数

"""训练模型--编写训练函数"""
# 训练循环
def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)  # 训练集的大小,一共60000张图片
    num_batches = len(dataloader)  # 批次数目,1875(60000/32)

    train_loss, train_acc = 0, 0  # 初始化训练损失和正确率

    for X, y in dataloader:  # 加载数据加载器,得到里面的 X(图片数据)和 y(真实标签)
        X, y = X.to(device), y.to(device) # 用于将数据存到显卡

        # 计算预测误差
        pred = model(X)  # 网络输出
        loss = loss_fn(pred, y)  # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失

        # 反向传播
        optimizer.zero_grad()  # 清空过往梯度
        loss.backward()  # 反向传播,计算当前梯度
        optimizer.step()  # 根据梯度更新网络参数

        # 记录acc与loss
        train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
        train_loss += loss.item()

    train_acc /= size
    train_loss /= num_batches

    return train_acc, train_loss

2.3.3 编写测试函数

"""训练模型--编写测试函数"""
# 测试函数和训练函数大致相同,但是由于不进行梯度下降对网络权重进行更新,所以不需要传入优化器
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)  # 测试集的大小,一共10000张图片
    num_batches = len(dataloader)  # 批次数目,313(10000/32=312.5,向上取整)
    test_loss, test_acc = 0, 0

    # 当不进行训练时,停止梯度更新,节省计算内存消耗
    with torch.no_grad(): # 测试时模型参数不用更新,所以 no_grad,整个模型参数正向推就ok,不反向更新参数
        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_loss += loss.item()
            test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()#统计预测正确的个数

    test_acc /= size
    test_loss /= num_batches

    return test_acc, test_loss

2.3.4 正式训练

"""训练模型--正式训练"""
epochs = 5
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    model.train()
    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:79.5%, Train_loss:0.709, Test_acc:92.7%,Test_loss:0.243
Epoch: 2, Train_acc:94.3%, Train_loss:0.188, Test_acc:96.2%,Test_loss:0.125
Epoch: 3, Train_acc:96.4%, Train_loss:0.121, Test_acc:97.3%,Test_loss:0.088
Epoch: 4, Train_acc:97.2%, Train_loss:0.093, Test_acc:97.6%,Test_loss:0.077
Epoch: 5, Train_acc:97.6%, Train_loss:0.078, Test_acc:98.0%,Test_loss:0.064
Done

2.4 结果可视化

"""训练模型--结果可视化"""
epochs_range = range(epochs)

plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)

plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

在这里插入图片描述

3 知识点详解

3.1 MNIST手写数字数据集介绍

MNIST手写数字数据集来源于是美国国家标准与技术研究所,是著名的公开数据集之一。数据集中的数字图片是由250个不同职业的人纯手写绘制,数据集获取的网址为:http://yann.lecun.com/exdb/mnist/(下载后需解压)。我们一般会采用(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()这行代码直接调用,这样就比较简单MNIST手写数字数据集中包含了70000张图片,其中60000张为训练数据,10000为测试数据,70000张图片均是2828,如果我们把每一张图片中的像素转换为向量,则得到长度为2828=784的向量。因此我们可以把训练集看成是一个[60000,784]的张量,第一个维度表示图片的索引,第二个维度表示每张图片中的像素点。而图片里的每个像素点的值介于0-1之间。
在pytorch下可以直接调用torchvision.datasets里面的MNIST数据集(这是官方写好的数据集类)

train = torchvision.datasets.MNIST(root='./data/',train=True, transform= transforms.ToTensor())

作用
从 torchvision 中加载 MNIST 数据集的训练集
参数

  • root=‘./data’: 数据集将被下载并保存在当前工作目录下的 ‘data’ 子目录中
  • train=True: 加载训练集
  • download=True: 如果数据集不存在,则下载数据集
  • transform=transforms.ToTensor(): #接收PIL图片并返回转换后版本图片的转换函数,这里为将图像转换为 PyTorch 的 Tensor 格式
    返回值为一个元组(train_data,train_target)(这个类使用的时候也有坑,必须用train[i]索引才能使用 transform功能),一般是与torch.utils.data.DataLoader配合使用
dataloader = DataLoader(train, batch_size=50,shuffle=True, num_workers=4)
for step, (x, y) in enumerate(dataloader):
 b_x = x.shape
 b_y = y.shape
 print 'Step: ', step, '| train_data的维度' ,b_x,'| train_target的维度',b_y

作用
创建一个 DataLoader 对象,用于对数据进行批量加载和处理
参数

  • trainset: 要加载的数据集
  • batch_size=4: 每个批次包含的图像样本数量
  • shuffle=True: 打乱数据,以便在每个 epoch 中随机访问样本
  • num_workers=4:并行处理数

3.2 Torch.NN简介

torch.nn 是 PyTorch 中用于构建神经网络的模块。它提供了一组类和函数,用于定义、训练和评估神经网络模型。
torch.nn 模块的核心是 nn.Module 类,它是所有神经网络模型的基类。在Containers中通过继承 nn.Module 类,您可以创建自己的神经网络模型,并定义模型的结构和操作。
以下是 torch.nn 模块中常用的一些类和函数:

  • nn.Linear: 线性层,用于定义全连接层,可以起到特征提取器的作用,最后一层的全连接层也可以认为是输出层,传入参数为输入特征数和输出特征数(输入特征数由特征提取网络计算得到,如果不会计算可以直接运行网络,报错中会提示输入特征数的大小,下方网络中第一个全连接层的输入特征数为1600。
  • nn.Conv2d: 二维卷积层,用于处理图像数据。
  • nn.ReLU: ReLU 激活函数。
  • nn.Sigmoid: Sigmoid 激活函数。
  • nn.Dropout: Dropout 层,用于正则化和防止过拟合。
  • nn.CrossEntropyLoss: 交叉熵损失函数,通常用于多类别分类问题。
  • nn.MSELoss: 均方误差损失函数,通常用于回归问题。
  • nn.Sequential: 顺序容器,用于按顺序组合多个层,在初始化阶段就设定好网络结构,不需要在前向传播中重新写一遍。
    使用 torch.nn 模块,您可以创建自定义的神经网络模型,并使用 PyTorch 提供的优化器(如 torch.optim)和损失函数来训练和优化模型。

3.2.1nn.Module模块概述

nn.Module类的基本定义
在定义自已的网络的时候,需要继承nn.Module类,并重新实现构造函数__init__()和forward这两个方法。在构造函数__init__()中使用super(Model, self).init()来调用父类的构造函数,forward方法是必须要重写的,它是实现模型的功能,实现各个层之间的连接关系的核心。
1.一般把网络中具有可学习参数的层(如全连接层、卷积层)放在构造函数__init__()中。
2.一般把不具有可学习参数的层(如ReLU、dropout)可放在构造函数中,也可不放在构造函数中(在forward中使用nn.functional来调用)。
示例1:将具有可学习参数层和不具有可学习参数层均放在构造函数中

import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()   # 调用父类的构造函数
        self.con2v = nn.Conv2d(1, 3, 3, 1)
        self.relu = nn.ReLU()
        self.max_pooling = nn.MaxPool2d(2, 1)
    def forward(self, x):
        x = self.con2v(x)
        x = self.relu(x)
        x = self.max_pooling(x)
        return x
model = Model()
print(model)
'''  可看到输出的模型结构
Model(
  (con2v): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
  (relu): ReLU()
  (max_pooling): MaxPool2d(kernel_size=2, stride=1, padding=0, dilation=1, ceil_mode=False)
)
'''

示例2:把不具有可学习参数的层不放在构造函数中(在forward中使用nn.functional调用)

import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()   # 调用父类的构造函数
        self.con2v = nn.Conv2d(1, 3, 3, 1)
        self.max_pooling = nn.MaxPool2d(2, 1)
    def forward(self, x):
        x = self.con2v(x)
        x = F.relu(x)
        x = self.max_pooling(x)
        return x
model = Model()
print(model)
''' 可看到输出的模型结构
Model(
  (con2v): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
  (max_pooling): MaxPool2d(kernel_size=2, stride=1, padding=0, dilation=1, ceil_mode=False)
)
'''

由此可看出不具有可学习参数层没有放在构造函数里面,那么这些层就不会出现在model中。
也就是在构造函数__init__()中只是定义了模型的结构,而在forward方法中实现了模型中的所有层的连接。
3.只要在nn.Module中定义了forward函数,backward函数就会被自动实现(利用Autograd)。而且一般不是显式的调用forward(layer.forward), 而是layer(input), 会自执行forward()。

3.2.2 Sequential类的概述

nn.Sequential的定义:一个有顺序容器,神经网络模块将按照构造函数中传递的顺序添加到该容器中。此外,也可以传入一个有序的模块字典。

Sequenrial类实现了整数索引,每一个层是没有名称的,默认是以0、1、2…这样的index来命名,可以使用model[index]这样的方式获取一个层,并不能够通过名称(如model[“Conv2d”])来获取层。
示例如下:

import torch.nn as nn
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()   # 调用父类的构造函数
        self.model1= nn.Sequential(
            nn.Conv2d(1, 3, 3, 1),
            nn.ReLU(),
            nn.Conv2d(3, 9, 3, 1),
            nn.MaxPool2d(2, 1)
        )
    def forward(self, x):
        x = self.struct(x)
        return x
model = Model()
print(model)
print(model.model1[2])  # 通过索引获取第几个层

'''  输出结果
Model(
  (model1): Sequential(
    (0): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
    (1): ReLU()
    (2): Conv2d(3, 9, kernel_size=(3, 3), stride=(1, 1))
    (3): MaxPool2d(kernel_size=2, stride=1, padding=0, dilation=1, ceil_mode=False)
  )
)
Conv2d(3, 9, kernel_size=(3, 3), stride=(1, 1))
'''

Sequential的三种包装方式
示例如下:

import torch.nn as nn
from collections import OrderedDict
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()   # 调用父类的构造函数
        self.model1 = nn.Sequential(    # 方式一
            nn.Conv2d(1, 3, 3, 1),
            nn.ReLU()
        )
        self.model2 = nn.Sequential(   # 方式二
            OrderedDict([
                ('conv1', nn.Conv2d(1, 3, 3, 1)),
                ('relu1', nn.ReLU())
            ])
        )
        self.model3 = nn.Sequential()  # 方式三
        self.model3.add_module('conv1', nn.Conv2d(1, 3, 3, 1)),
        self.model3.add_module('relu1', nn.ReLU())
    def forward(self, x):
        x = self.model1(x)
        x = self.model2(x)
        x = self.model3(x)
        return x
model = Model()
print(model)

'''  输出结果
Model(
  (model1): Sequential(
    (0): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
    (1): ReLU()
  )
  (model2): Sequential(
    (conv1): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
    (relu1): ReLU()
  )
  (model3): Sequential(
    (conv1): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
    (relu1): ReLU()
  )
)
'''

参考链接:
nn.Module模块概述
神经网络的基本框架的搭建-nn.Module

3.3【Pytorch】model.train() 和 model.eval() 原理与用法

3.3.1 两种模式

pytorch可以给我们提供两种方式来切换训练和评估(推断)的模式,分别是:model.train() 和 model.eval()。
一般用法是:在训练开始之前写上 model.trian() ,在测试时写上 model.eval() 。

3.3.2功能

1. model.train()
在使用 pytorch 构建神经网络的时候,训练过程中会在程序上方添加一句model.train(),作用是 启用 batch normalization 和 dropout 。
如果模型中有BN层(Batch Normalization)和 Dropout ,需要在 训练时 添加 model.train()。
model.train() 是保证 BN 层能够用到 每一批数据 的均值和方差。对于 Dropout,model.train() 是 随机取一部分 网络连接来训练更新参数。

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

为什么测试时要用 model.eval() ?
训练完 train 样本后,生成的模型 model 要用来测试样本了。在 model(test) 之前,需要加上model.eval(),否则的话,有输入数据,即使不训练,它也会改变权值。这是 model 中含有 BN 层和 Dropout 所带来的的性质。

eval() 时,pytorch 会自动把 BN 和 DropOut 固定住,不会取平均,而是用训练好的值。
不然的话,一旦 test 的 batch_size 过小,很容易就会被 BN 层导致生成图片颜色失真极大。
eval() 在非训练的时候是需要加的,没有这句代码,一些网络层的值会发生变动,不会固定,你神经网络每一次生成的结果也是不固定的,生成质量可能好也可能不好。

也就是说,测试过程中使用model.eval(),这时神经网络会 沿用 batch normalization 的值,而并不使用 dropout。

3.3.3 总结与对比

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

参考链接:【Pytorch】model.train() 和 model.eval() 原理与用法

总结

通过本文的学习,了解了pytorch网络模型如何创建、训练与测试。

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

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

相关文章

伪原创API,一文快速了解伪原创API

伪原创API,听起来可能对许多人来说是一个陌生的术语。然而,在当今数字化时代,尤其是在内容创作和网络营销领域,伪原创API正逐渐崭露头角。在本文中,我将向您深入介绍伪原创API是什么,以及它如何在实际应用中…

LED透镜粘接UV胶是一种特殊的UV固化胶

LED透镜粘接UV胶是一种特殊的UV固化胶,用于固定和粘合LED透镜。 它具有以下特点: 1. 高透明度:LED透镜粘接UV胶具有高透明度,可以确保光线的透过性,不影响LED的亮度和效果。 2. 快速固化:经过UV紫外线照射…

c语言二维数组之浮点型数组

介绍: 本篇文章讲解c语言二维数组之浮点型数组 其实和小编上一篇文章 c语言二维数组之整型数组 差不多 只不过就是数组里存储的数的类型不一样了 所以这里 仅仅提供代码和执行结果就不多说了 OK 下面进入正文 代码和执行结果: 大家放心好了 这次的…

带你玩转 Vite + Vue3 高低版本常用玩法

一、首先来个 Vite 的通用简介 Vite 是一种新型前端构建工具,在我们保险前端项目中已经推动并应用很久了,Vite 能够显著降低构建时间,提升前端开发效率。 它主要由两部分组成: 一个开发服务器,它基于 原生 ES 模块 提供了 丰富的内建功能,如速度快到惊人的 模块热更新(…

靠谱的车- 华为OD统一考试(C卷)

靠谱的车- 华为OD统一考试(C卷) OD统一考试(C卷) 分值: 100分 题解: Java / Python / C++ 题目描述 程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。 出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇…

微信小程序:模态框(弹窗)的实现

效果 wxml <!--新增&#xff08;点击按钮&#xff09;--> <image classimg src"{{add}}" bindtapadd_mode></image> <!-- 弹窗 --> <view class"modal" wx:if"{{showModal}}"><view class"modal-conten…

深入Docker命令行:探索常用命令和实用技巧

Docker命令行界面是每个容器开发者的得力工具。在这篇文章中&#xff0c;将深入探讨一系列常用的Docker命令&#xff0c;以及一些实用技巧&#xff0c;通过更丰富的示例代码&#xff0c;帮助大家更全面地理解和运用Docker命令行工具。 1. Docker基本命令 1.1 镜像操作 深入了…

【打印机如何设置只打印黑色】

目录 1. Window X 打开&#xff0c;选择“设置” 2. 选择“打印机和扫描仪” 3. 选择对应的“打印机” 4. 选择“打印首选项” 5. 选择“页设置”&#xff0c;并选择“打印选项” 6. 用于打印的墨水&#xff0c;改为“仅黑色” 7. 点击“确定”&#xff0c;关闭即可 1. Wi…

visual studio 2022 IDE对C++代码反汇编

敲一段代码&#xff0c;在windows电脑儿上&#xff0c;忽然想用visual studio瞧瞧这段代码的汇编长什么样&#xff0c;怎么做呢&#xff1f; 代码有了 #include <stdio.h> void sort(int*,int);int main(){int array[] { 977,1,32,3,99,8,7,5,23,6 };int length int(…

RocketMQ Connect详解

一、概览 RocketMQ Connect是RocketMQ数据集成重要组件&#xff0c;可将各种系统中的数据通过高效&#xff0c;可靠&#xff0c;流的方式&#xff0c;流入流出到RocketMQ&#xff0c;它是独立于RocketMQ的&#xff0c;一个单独的分布式、可扩展、可容错系统&#xff0c; 它具备…

解密:为何YouTube 5秒广告‘秒’过,国内视频平台坚持15秒?

大家好&#xff0c;我是小米&#xff01;今天我们来聊一个热门的话题&#xff1a;为什么YouTube可以在5秒后跳过广告&#xff0c;而国内视频平台却坚持15秒呢&#xff1f;这可不是简单的数字差异&#xff0c;而是一个关乎用户体验、商业模式以及产品策略的大问题。作为一个热衷…

IBM DMC运行在RedHat 9的FIPS模式

文章目录 环境步骤打开RedHat的FIPS模式安装DMCnssdbpk12util和certutil导入certificate导入Liberty的SSL key导入Java的certificate查看nssdb&#xff08;可选&#xff09; 配置jvm.options配置server.xml配置java.security配置dswebserver_override.properties重启DMC验证 常…

解读 | 为什么有很多名人让人们警惕人工智能

大家好&#xff0c;我是极智视界&#xff0c;欢迎关注我的公众号&#xff0c;获取我的更多前沿科技分享 邀您加入我的知识星球「极智视界」&#xff0c;星球内有超多好玩的项目实战源码和资源下载&#xff0c;链接&#xff1a;https://t.zsxq.com/0aiNxERDq 这个话题总能引起很…

Firewalld 防火墙配置

文章目录 Firewalld 防火墙配置1. Firewalld 概述2. 区域名称及策略规则3. Firewalld 配置方法4. Firewalld 参数和命令5. Firewalld 两种模式6. Firewalld 使用 Firewalld 防火墙配置 1. Firewalld 概述 firewalld 是一个动态防火墙管理器&#xff0c;作为 Systemd 管理的防…

串口通信(1)-硬件知识

本文讲解串口通信的硬件知识。让读者快速了解硬件知识&#xff0c;为下一步编写代码做基础。 目录 一、概述 二、串口通信分类 2.1信息的传送方向进行分类 2.2同步通信和异步通信 三、串口协议 3.1 RS232 3.1.1 电气特性 3.1.2 连接器的机械特性 3.1.3 连接类型 3.1…

算法:买卖股票的最佳时机(快慢指针和动态规划)

快慢指针 时间复杂度 O(n) 空间复杂度 O(1) /*** param {number[]} prices* return {number}*/ var maxProfit function (prices) {let l 0let r 1let temp 0while (r < prices.length - 1) {// 如果当前左值大于右值说明当前不是最佳买入时机// 所以将右指针赋值给左指…

痤疮分割 实验心路历程

数据集的制作 将labelme生成的标注文件记普通的json文件转成coco数据集格式的json文件 图像分辨率过大 如果不做任何调整&#xff1a; 会出现“killed”的报错&#xff0c;表示图片像素过大&#xff0c;显卡内存不够&#xff0c;无法支撑训练 显卡 换成更高性能的显卡&am…

视频剪辑:视频创意制作,背景图片融合视频制作画中画效果

随着社交媒体的兴起&#xff0c;视频制作不再仅仅是专业人士的专利。每个人都可以通过一些技巧&#xff0c;创作出独特而富有吸引力的视频内容。视频剪辑是一种非常重要的技术&#xff0c;它能让视频从平淡无奇变为生动有趣。背景图片融合视频制作画中画效果&#xff0c;也能增…

APD--传感器

#1 Current temperature coeffiency Hamamastu Si APD S8664, with same bias, **low temperature**, **higher gain**, it means that **higher current output**. #2, PD

市场全局复盘 20231211

昨日回顾&#xff1a; SELECT TOP 10000 CODE,成交额排名,净流入排名,代码,名称,DDE大单金额,涨幅,所属行业,主力净额,DDE大单净量,CONVERT(DATETIME, 最后涨停时间, 120) AS 最后涨停时间 FROM dbo.全部&#xff21;股20231208_ALL WHERE 连板天 > 1AND DDE大单净量 > …