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

news2024/11/24 21:07:02
  • 🍨 本文为🔗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.coloradmin.cn/o/1304231.html

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

相关文章

【计算机网络】URL概念及组成

目录 一、什么是URL 二、URL格式 示例: 1. Scheme(协议): 2. Host(主机): 3. Port(端口): 4. Path(路径): 5. Quer…

容器化升级对服务有哪些影响?

容器技术是近几年计算机领域的热门技术,特别是随着各种云服务的发展,越来越多的服务运行在以 Docker 为代表的容器之内。 本文我们就来分享一下容器化技术相关的知识。 容器化技术简介 相比传统虚拟化技术,容器技术是一种更加轻量级的操作…

如何使用玻璃材质制作3D钻石模型

在线工具推荐: 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 当谈到游戏角色的3D模型风格时,有几种不同的风格&#xf…

Python数值类型(整形、浮点型和复数)及其用法

数值类型是计算机程序最常用的一种类型,既可用于记录各种游戏的分数、游戏角色的生命值、伤害值等,也可记录各种物品的价格、数量等,Python 提供了对各种数值类型的支持,如支持整型、浮点型和复数。 Python整型 Python 3 的整型…

Python入门第6篇(FastApi、uvicorn)

前言 FastApi用来开发webapi,可以定义路由、定义get、post方法等 但是要让浏览器可以访问webapi,还需要用到uvicorn,即web服务器,类似Tomcat、iis这种的 pip安装相关包 FastApi uvicorn 注意:可能一次安装不成功…

二叉树--基础OJ

1.对称二叉树 题目链接:101. 对称二叉树 - 力扣(LeetCode) 题解: 我们可以用递归的方法去做: 如果两个树互为镜像(1.根节点的值相同,2.左子树的值与右子树的值对称)则为对称二叉树&a…

win中查看MD5、Linux中查看MD5

win中的MD5计算 1、用GitBash Git Bash Here md5sum.exe 我记得-孙燕姿.mp32、win自带命令 certutil -hashfile 我记得-孙燕姿.mp3 MD5Linux中MD5计算 md5sum 我记得-孙燕姿.mp3

使用paddleocr识别图片文本的一种方案

pdf文本分为两种,一种是标准的pdf格式的文本,这种无需利用ocr识别,另外一种就是图片文本,这种需要进行ocr的识别。 OCR 识别文本和文本区域 ppstructure是paddleocr里面的一个子库,可以识别文档的页眉页脚、正文、标…

多线程 - 学习笔记

前置知识 什么是线程和进程? 进程: 是程序的一次执行,一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。 线程: 进程中的一个执行流&#xff0…

我的软考拿证之路

我的软考拿证之路 前言2021年上半年2022年下半年2023年上半年2023年下半年 前言 在2020年8月份,准备参加软考高级项目管理师考试,经历了疫情三年,停考3次,经历了教材更新,经历了考试形式由纸考换机考,共参…

实现TensorBoard可视化网络的参数

前言 最近在做神经网络相关的实验,为了方便神经网络参数是否变化,学习一下TensorBoard可视化网络的参数的方法,这里使用pytorch实现。 实现 当使用PyTorch训练一个简单的神经网络时,可以使用TensorBoardX来可视化网络的参数。以…

机器学习---KNN最近邻算法

1、KNN最近邻算法 K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一,有监督算法。该方法的思路是:如果一个样本在特征空间中的k个最相似的样本中的大多数属于某一个…

小米耳机定制音效选项灰色无法开启使用_开启定制音效_音效模式设置

使用环境:Redmi K50 Ultra +MIUI 14.0.11+定制音效选项是灰色的无法开启及音效模式无法选择 定制音效无法开启 音效模式无法选择(需下载小米耳机APP才能设置),根据提示解决问题即可 解决方法:关…

ICC2:low power与pg strategy(pg_mesh)

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 用pg_strategy创建power stripe,示例如下: set pd_list {{DEFAULT_VA VDD_DIG VDD_DIG VSS} {PD_DSP VDD_DIG VDD_DSP VSS} } ;#两个电源域,DEFAULT_VA和PD_DSP是对应voltage area名字,其中D…

硬件开发笔记(十六):RK3568底板电路mipi摄像头接口原理图分析、mipi摄像头详解

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134922307 红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

【神行百里】pandas查询加速之行索引篇

最近进行大数据处理的时候,发现我以前常用的pandas查询方法太慢了,太慢了,真是太慢了,查阅资料,遂发现了一种新的加速方法,能助力我飞上天,和太阳肩并肩,所以记录下来。 1. 场景说明…

章鱼网络进展月报 | 2023.11.1-11.30

章鱼网络大事摘要 1、2023年12月,Octopus 2.0 将会正式启动。 2、隐私协议 Secret Network 宣布使用 Octopus Network 构建的 NEAR-IBC 连接 NEAR 生态。 3、Louis 受邀作为嘉宾,在 NEARCON2023 的多链网络主题沙龙中发言:我们依然处于区…

Emacs之Plantuml用于复杂UML类图(Markdown用于简单类图)(一百三十二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

FTP、U盘等传统数据安全摆渡方法的6个弊端

数据安全摆渡,即数据在不同的网络之间,进行安全流转。做网间隔离的初衷,就是为了保护数据安全,但是在数据摆渡时,除了安全,企业还是需要考虑其他的要素,比如可靠性、易用性、兼容性等等。而传统…

解决:TypeError: write() argument must be str, not Tag

解决:TypeError: write() argument must be str, not Tag 文章目录 解决:TypeError: write() argument must be str, not Tag背景报错问题报错翻译报错位置代码报错原因解决方法今天的分享就到此结束了 背景 在使用之前的代码时,报错&#xf…