当前位置: 首页 > news >正文

【机器学习】PyTorch-MNIST-手写字识别

文章目录

  • 前言
  • 完成效果
  • 一、下载数据集
    • 手动下载
    • 代码下载MNIST数据集:
  • 二、 展示图片
  • 三、DataLoader数据加载器
  • 四、搭建神经网络
  • 五、 训练和测试
    • 第一次运行:
  • 六、优化模型
    • 第二次优化后运行:
  • 七、完整代码
  • 八、手写板实现输入识别功能

前言

注意:本代码需要安装PyTorch未安装请看之前的文章https://blog.csdn.net/qq_39583774/article/details/132070870
MNIST(Modified National Institute of Standards and Technology)是一个常用于机器学习和计算机视觉领域的数据集,用于手写数字识别。它包含了一系列28x28像素大小的灰度图像,每个图像都表示了一个手写的数字(0到9之间)。MNIST数据集共有60,000个训练样本和10,000个测试样本,可用于训练和测试各种图像分类算法。
通过使用MNIST数据集,研究人员和开发者可以测试和验证各种机器学习模型和算法的性能,特别是在图像分类领域。这个数据集成为了计算机视觉领域中的基准,许多研究论文和教程都使用它来演示各种图像处理和机器学习技术的效果。

完成效果

准确率有待提高,可能是因为测试数据集和训练数据集的数据是国外,写法有点不一样,如果你能提高这个模型的成功率可以分享给我,感谢。
在这里插入图片描述

一、下载数据集

下载可以使用代码也可以使用手动方式下载:
数据集网站:http://yann.lecun.com/exdb/mnist/

手动下载

在这里插入图片描述

代码下载MNIST数据集:

#MNIST--手写字识别
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor#创建一个MNIST数据集的实例,其中包括训练图像和标签
training_data = datasets.MNIST(root="data", #下载的跟目录train=True, #加载训练数据集download=True,#如果数据集不存在,将自动下载transform=ToTensor(), #将图像数据转换为Tensor格式的数据(张量),pytorch使用tensor数据流所以这里要转换
)
print(len(training_data))

在这里插入图片描述
运行:
在这里插入图片描述

打印训练数量:

在这里插入图片描述
读取测试数据集:

代码下载工作原理:按住ctrl建跳转源代码
在这里插入图片描述
从上面看是通过爬虫方式下载,和我们的手动下载方式差不多
在这里插入图片描述
可以看到我们下载好的数据集:

在这里插入图片描述
前言中我们有训练数据和测试数据上面是读取训练数据下面我们读取测试数据集:

test_data = datasets.MNIST(root="data", #下载的跟目录train=False, #加载测试数据集download=True,#如果数据集不存在,将自动下载transform=ToTensor(), #将图像数据转换为Tensor格式的数据(张量),pytorch使用tensor数据流所以这里要转换
)
print(len(test_data))

运行一下:
在这里插入图片描述

二、 展示图片

#展示训练数据集图片和标签
from matplotlib import pyplot as plt #导入matplotlib库中的pyplot模块,用于绘制图像
figure = plt.figure() #创建一个新的图像画布
for i in range(12):#遍历前12张图片0-12img, label = training_data[i]figure.add_subplot(3, 4, i+1)plt.title(label)plt.axis("off")plt.imshow(img.squeeze(), cmap="gray")#使用imshow函数显示图像,其中img.squeeze()将图像的通道维度去除,cmap="gray"表示使用灰度颜色映射
plt.show()

在这里插入图片描述

三、DataLoader数据加载器

为什么要做这一步:因为数据集有6万个数据集,通过打包方式将64个为一组,打包起来一起传入,内存这样可以大大加快处理的速度,不然就是6万多个数据集一个一个传入导致速度变慢。

train_dataloader = DataLoader(training_data, batch_size=64)#创建一个训练数据加载器,将training_data(训练数据集)分成64张图像一组的批次
test_dataloader = DataLoader(test_data, batch_size=64)#创建一个测试数据加载器,将test_data(测试数据集)分成64张图像一组的批次。
for X, y in test_dataloader:#X是表示打包好的每一个数据包#打印当前批次图像数据X的形状,其中N表示批次大小,C表示通道数,H和W表示图像的高度和宽度print(f"Shape of X [N, C, H, W]: {X.shape}")#打印当前批次标签数据y的形状和数据类型print(f"Shape of y: {y.shape} {y.dtype}")break#这里测试一下第一个组中的形状
'''
此代码段的作用是检查当前系统是否支持CUDA(GPU计算),
如果支持,则使用CUDA设备;如果不支持CUDA,它还会检查是否支持多进程模式(MPS),
如果支持,则使用MPS设备;最后,如果都不支持,则使用CPU设备。然后,它会打印出所选择的设备类型。'''device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")

第一组中中有64张图像,大小为28*28,使用GPU计算

在这里插入图片描述

四、搭建神经网络

构造示意图:输出层为固定参数十个,因为数字数字0-9一共就十个
在这里插入图片描述

class NeuralNetwork(nn.Module):def __init__(self):super().__init__()self.flatten = nn.Flatten()  # 将图像展平self.hidden1 = nn.Linear(28*28, 128)  # 第一个隐藏层,输入维度为28*28,输出维度为128self.hidden2 = nn.Linear(128, 256)    # 第二个隐藏层,输入维度为128,输出维度为256self.out = nn.Linear(256, 10)         # 输出层,输入维度为256,输出维度为10(对应10个数字类别)def forward(self, x):x = self.flatten(x)        # 将输入图像展平x = self.hidden1(x)        # 第一个隐藏层的线性变换x = torch.sigmoid(x)       # 使用Sigmoid激活函数x = self.hidden2(x)        # 第二个隐藏层的线性变换x = torch.sigmoid(x)       # 使用Sigmoid激活函数x = self.out(x)            # 输出层的线性变换(未经激活函数)return x                   # 返回模型的输出
model = NeuralNetwork().to(device)#传入对应设备,根据上面识别的设备进行传入,这里传入GPU
print(model)

从分类中也可以看出分类:
在这里插入图片描述
运行代码:
在这里插入图片描述

五、 训练和测试

#训练数据
def train(dataloader, model, loss_fn, optimizer):model.train()
#pytorch提供2种方式来切换训练和测试的模式,分别是:model.train() 和 model.eval()。
# 一般用法是:在训练开始之前写上model.trian(),在测试时写上 model.eval() 。batch_size_num = 1for X, y in dataloader:                 #其中batch为每一个数据的编号X, y = X.to(device), y.to(device)   #把训练数据集和标签传入cpu或GPUpred = model.forward(X)             #自动初始化 w权值loss = loss_fn(pred, y)             #通过交叉熵损失函数计算损失值loss# Backpropagation 进来一个batch的数据,计算一次梯度,更新一次网络optimizer.zero_grad()               #梯度值清零loss.backward()                     #反向传播计算得到每个参数的梯度值optimizer.step()                    #根据梯度更新网络参数loss = loss.item()                  #获取损失值print(f"loss: {loss:>7f}  [number:{batch_size_num}]")batch_size_num += 1
#测试数据
def test(dataloader, model, loss_fn):size = len(dataloader.dataset)num_batches = len(dataloader)model.eval()    #梯度管理test_loss, correct = 0, 0with torch.no_grad():   #一个上下文管理器,关闭梯度计算。当你确认不会调用Tensor.backward()的时候。这可以减少计算所用内存消耗。for X, y in dataloader:X, y = X.to(device), y.to(device)pred = model.forward(X)test_loss += loss_fn(pred, y).item() #correct += (pred.argmax(1) == y).type(torch.float).sum().item()a = (pred.argmax(1) == y)  #dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号b = (pred.argmax(1) == y).type(torch.float)test_loss /= num_batches#计算正确率correct /= size#计算损失print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}")
# 多分类使用交叉熵损失函数
loss_fn = nn.CrossEntropyLoss() #创建交叉熵损失函数对象,因为手写字识别中一共有10个数字,输出会有10个结果
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)#创建一个优化器,SGD为随机梯度下降算法??
#params:要训练的参数,一般我们传入的都是model.parameters()。
#lr:learning_rate学习率,也就是步长。

调用函数训练:

#训练模型
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)

多次训练:

epochs = 5 #
for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train(train_dataloader, model, loss_fn, optimizer)# test(test_dataloader, model, loss_fn)
print("Done!")
test(test_dataloader, model, loss_fn)

第一次运行:

成功率只有可怜的16,loss高达2.2
在这里插入图片描述

六、优化模型

使用Adam(自适应矩估计):
修改代码118行:

# 多分类使用交叉熵损失函数
loss_fn = nn.CrossEntropyLoss() #创建交叉熵损失函数对象,因为手写字识别中一共有10个数字,输出会有10个结果
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)#创建一个优化器

防止梯度爆炸和梯度消失使用relu函数替换:

class NeuralNetwork(nn.Module):def __init__(self):super().__init__()self.flatten = nn.Flatten()  # 将图像展平self.hidden1 = nn.Linear(28*28, 128)  # 第一个隐藏层,输入维度为28*28,输出维度为128self.hidden2 = nn.Linear(128, 256)    # 第二个隐藏层,输入维度为128,输出维度为256self.out = nn.Linear(256, 10)         # 输出层,输入维度为256,输出维度为10(对应10个数字类别)def forward(self, x):x = self.flatten(x)        # 将输入图像展平x = self.hidden1(x)        # 第一个隐藏层的线性变换x = torch.relu(x)       # 使用Sigmoid激活函数/修改为relux = self.hidden2(x)        # 第二个隐藏层的线性变换x = torch.relu(x)       # 使用Sigmoid激活函数/修改为relux = self.out(x)            # 输出层的线性变换(未经激活函数)return x                   # 返回模型的输出#传入GPU
model = NeuralNetwork().to(device)#传入对应设备,根据上面识别的设备进行传入
print(model)

增加训练次数:

epochs = 15 #
for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train(train_dataloader, model, loss_fn, optimizer)# test(test_dataloader, model, loss_fn)
print("Done!")
test(test_dataloader, model, loss_fn)

第二次优化后运行:

成功率大大提高:
Accuracy: 97.67%, Avg loss: 0.12269500801303047
在这里插入图片描述

七、完整代码

#MNIST--手写字识别import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor#创建一个MNIST数据集的实例,其中包括训练图像和标签
training_data = datasets.MNIST(root="data", #下载的跟目录train=True, #加载训练数据集download=True,#如果数据集不存在,将自动下载transform=ToTensor(), #将图像数据转换为Tensor格式的数据(张量)
)
print(len(training_data))#创建一个MNIST数据集的实例,其中包括训练图像和标签
test_data = datasets.MNIST(root="data", #下载的跟目录train=False, #加载测试数据集download=True,#如果数据集不存在,将自动下载transform=ToTensor(), #将图像数据转换为Tensor格式的数据(张量),pytorch使用tensor数据流所以这里要转换
)
print(len(test_data))#展示训练数据集图片和标签
from matplotlib import pyplot as plt #导入matplotlib库中的pyplot模块,用于绘制图像
figure = plt.figure() #创建一个新的图像画布
for i in range(12):#遍历前12张图片img, label = training_data[i]figure.add_subplot(3, 4, i+1)plt.title(label)plt.axis("off")plt.imshow(img.squeeze(), cmap="gray")#使用imshow函数显示图像,其中img.squeeze()将图像的通道维度去除,cmap="gray"表示使用灰度颜色映射
plt.show()#DataLoader数据加载器
train_dataloader = DataLoader(training_data, batch_size=64)#创建一个训练数据加载器,将training_data(训练数据集)分成64张图像一组的批次
test_dataloader = DataLoader(test_data, batch_size=64)#创建一个测试数据加载器,将test_data(测试数据集)分成64张图像一组的批次。
for X, y in test_dataloader:#X是表示打包好的每一个数据包#打印当前批次图像数据X的形状,其中N表示批次大小,C表示通道数,H和W表示图像的高度和宽度print(f"Shape of X [N, C, H, W]: {X.shape}")#打印当前批次标签数据y的形状和数据类型print(f"Shape of y: {y.shape} {y.dtype}")break'''
此代码段的作用是检查当前系统是否支持CUDA(GPU计算),
如果支持,则使用CUDA设备;如果不支持CUDA,它还会检查是否支持多进程模式(MPS),
如果支持,则使用MPS设备;最后,如果都不支持,则使用CPU设备。然后,它会打印出所选择的设备类型。'''device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")class NeuralNetwork(nn.Module):def __init__(self):super().__init__()self.flatten = nn.Flatten()  # 将图像展平self.hidden1 = nn.Linear(28*28, 128)  # 第一个隐藏层,输入维度为28*28,输出维度为128self.hidden2 = nn.Linear(128, 256)    # 第二个隐藏层,输入维度为128,输出维度为256self.out = nn.Linear(256, 10)         # 输出层,输入维度为256,输出维度为10(对应10个数字类别)def forward(self, x):x = self.flatten(x)        # 将输入图像展平x = self.hidden1(x)        # 第一个隐藏层的线性变换x = torch.relu(x)       # 使用Sigmoid激活函数/修改为relux = self.hidden2(x)        # 第二个隐藏层的线性变换x = torch.relu(x)       # 使用Sigmoid激活函数/修改为relux = self.out(x)            # 输出层的线性变换(未经激活函数)return x                   # 返回模型的输出#传入GPU
model = NeuralNetwork().to(device)#传入对应设备,根据上面识别的设备进行传入
print(model)#训练数据
def train(dataloader, model, loss_fn, optimizer):model.train()
#pytorch提供2种方式来切换训练和测试的模式,分别是:model.train() 和 model.eval()。
# 一般用法是:在训练开始之前写上model.trian(),在测试时写上 model.eval() 。batch_size_num = 1for X, y in dataloader:                 #其中batch为每一个数据的编号X, y = X.to(device), y.to(device)   #把训练数据集和标签传入cpu或GPUpred = model.forward(X)             #自动初始化 w权值loss = loss_fn(pred, y)             #通过交叉熵损失函数计算损失值loss# Backpropagation 进来一个batch的数据,计算一次梯度,更新一次网络optimizer.zero_grad()               #梯度值清零loss.backward()                     #反向传播计算得到每个参数的梯度值optimizer.step()                    #根据梯度更新网络参数loss = loss.item()                  #获取损失值print(f"loss: {loss:>7f}  [number:{batch_size_num}]")batch_size_num += 1
#测试数据
def test(dataloader, model, loss_fn):size = len(dataloader.dataset)num_batches = len(dataloader)model.eval()    #梯度管理test_loss, correct = 0, 0with torch.no_grad():   #一个上下文管理器,关闭梯度计算。当你确认不会调用Tensor.backward()的时候。这可以减少计算所用内存消耗。for X, y in dataloader:X, y = X.to(device), y.to(device)pred = model.forward(X)test_loss += loss_fn(pred, y).item() #correct += (pred.argmax(1) == y).type(torch.float).sum().item()a = (pred.argmax(1) == y)  #dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号b = (pred.argmax(1) == y).type(torch.float)test_loss /= num_batches#计算正确率correct /= size#计算损失print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}")# 多分类使用交叉熵损失函数
loss_fn = nn.CrossEntropyLoss() #创建交叉熵损失函数对象,因为手写字识别中一共有10个数字,输出会有10个结果
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)#创建一个优化器
#params:要训练的参数,一般我们传入的都是model.parameters()。
#lr:learning_rate学习率,也就是步长。#训练模型
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)epochs = 15 #
for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train(train_dataloader, model, loss_fn, optimizer)# test(test_dataloader, model, loss_fn)
print("Done!")
test(test_dataloader, model, loss_fn)

八、手写板实现输入识别功能

在原来的基础上实现,手写数字然后识别,训练完成后使用pygame做一个手写版实现手写,保存图片,然后将图片的大小修改为模型可以识别的大小,然后传入模型识别:

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor
from PIL import Image
import torchvision.transforms as transforms
import pygame
import sys ;sys.setrecursionlimit(sys.getrecursionlimit() * 5)
from pygame.locals import *# 创建一个MNIST数据集的实例
training_data = datasets.MNIST(root="data",train=True,download=True,transform=ToTensor(),
)test_data = datasets.MNIST(root="data",train=False,download=True,transform=ToTensor(),
)# 创建一个神经网络模型
class NeuralNetwork(nn.Module):def __init__(self):super().__init__()self.flatten = nn.Flatten()self.hidden1 = nn.Linear(28 * 28, 128)self.hidden2 = nn.Linear(128, 256)self.out = nn.Linear(256, 10)def forward(self, x):x = self.flatten(x)x = self.hidden1(x)x = torch.relu(x)x = self.hidden2(x)x = torch.relu(x)x = self.out(x)return x# 训练模型和测试模型的函数
def train(dataloader, model, loss_fn, optimizer):model.train()for X, y in dataloader:X, y = X.to(device), y.to(device)pred = model.forward(X)loss = loss_fn(pred, y)optimizer.zero_grad()loss.backward()optimizer.step()loss = loss.item()print(f"loss: {loss:>7f}")def test(dataloader, model, loss_fn):size = len(dataloader.dataset)num_batches = len(dataloader)model.eval()test_loss, correct = 0, 0with torch.no_grad():for X, y in dataloader:X, y = X.to(device), y.to(device)pred = model.forward(X)test_loss += loss_fn(pred, y).item()correct += (pred.argmax(1) == y).type(torch.float).sum().item()test_loss /= num_batchescorrect /= sizeprint(f"Test result: \n Accuracy: {(100 * correct)}%, Avg loss: {test_loss}")# 定义一个函数来识别手写数字
def recognize_handwritten_digit(image_path, model):image = Image.open(image_path).convert('L')preprocess = transforms.Compose([transforms.Resize((28, 28)),transforms.ToTensor(),])input_tensor = preprocess(image)input_batch = input_tensor.unsqueeze(0)input_batch = input_batch.to(device)with torch.no_grad():output = model(input_batch)_, predicted_class = torch.max(output, 1)return predicted_class.item()# 检查是否支持CUDA,然后选择设备
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")# 创建数据加载器
train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)# 创建模型并传入设备
model = NeuralNetwork().to(device)# 定义损失函数和优化器
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)# 训练模型
for epoch in range(20):#训练次数print(f"Epoch {epoch + 1}\n-------------------------------")train(train_dataloader, model, loss_fn, optimizer)test(test_dataloader, model, loss_fn)# 识别手写数字
def get_handwritten_input():pygame.init()# 设置窗口window = pygame.display.set_mode((280, 280))pygame.display.set_caption('Handwritten Input')window.fill((0, 0, 0))  # 设置背景为黑色drawing = Falselast_pos = Nonewhile True:for event in pygame.event.get():if event.type == QUIT:pygame.quit()sys.exit()elif event.type == MOUSEBUTTONDOWN:drawing = Trueelif event.type == MOUSEMOTION:if drawing:mouse_x, mouse_y = pygame.mouse.get_pos()if last_pos:pygame.draw.line(window, (255, 255, 255), last_pos, (mouse_x, mouse_y), 15)  # 设置绘画颜色为白色last_pos = (mouse_x, mouse_y)elif event.type == MOUSEBUTTONUP:drawing = Falselast_pos = Nonepygame.display.update()if event.type == KEYDOWN and event.key == K_RETURN:pygame.image.save(window, 'handwritten_input.png')return 'handwritten_input.png'def main():while True:  # 死循环保证程序一直运行,直到关闭image_path = get_handwritten_input()predicted_digit = recognize_handwritten_digit(image_path, model)print(f"The predicted digit is: {predicted_digit}")if __name__ == "__main__":main()

在这里插入图片描述

相关文章:

【机器学习】PyTorch-MNIST-手写字识别

文章目录 前言完成效果一、下载数据集手动下载代码下载MNIST数据集: 二、 展示图片三、DataLoader数据加载器四、搭建神经网络五、 训练和测试第一次运行: 六、优化模型第二次优化后运行: 七、完整代码八、手写板实现输入识别功能 前言 注意…...

玩转代码| Vue 中 JSX 的特性,这一篇讲的明明白白

目录 什么时候使用JSX JSX在Vue2中的基本使用 配置 文本插值 条件与循环渲染 属性绑定 事件绑定 v-show与v-model 插槽 使用自定义组件 在method里返回JSX JSX是一种Javascript的语法扩展,即具备了Javascript的全部功能,同时又兼具html的语义…...

(vue)el-descriptions 描述列表无效

(vue)el-descriptions 描述列表无效 原因:element 的版本不够 解决:运行下面两个命令 npm uninstall element-ui //卸载之前安装的版本 npm i element-ui -S //重新安装解决参考:https://blog.csdn.net/weixin_59769148/article/details/1…...

ios 苹果手机日期格式问题

目录 问题解决其他 问题 ios 无法识别的时间戳格式:2023-10-17 11:10:49 可识别的: 2023/10/17 11:10:49 解决 const startTime 2023/10/17 11:10:49 startTime.replace(/-/g, /)// 获取时间差值 export const useDateDiff (startTime , endTime …...

学习嵌入式系统的推荐步骤:

学习嵌入式系统的推荐步骤: 00001. 选择一款Linux发行版作为主要操作系统,如RedHat、Ubuntu、Fedora等。进入Linux后,使用终端进行任务操作。建议不要使用虚拟机,如有需要可考虑双系统安装。 00002. 00003. 学习C语言、数…...

勒索病毒LockBit2.0 数据库(mysql与sqlsever)解锁恢复思路分享

0.前言 今天公司服务器中招LockBit2.0勒索病毒,损失惨重,全体加班了一天基本解决了部分问题,首先是丢失的文件数据就没法恢复了,这一块没有理睬,主要恢复的是两个数据库,一个是16GB大小的SQLserver数据库&…...

超简单小白攻略:如何利用黑群晖虚拟机和内网穿透实现公网访问

文章目录 前言本教程解决的问题是:按照本教程方法操作后,达到的效果是前排提醒: 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机:1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…...

Ubuntu 16.04 LTS third maintenance update release

Ubuntu 16.04 LTS (Xenial Xerus)今天迎来的第三个维护版本更新中,已经基于Linux Kernel 4.10内核,而且Mesa图形栈已经升级至17.0版本。Adam Conrad表示:“像此前LTS系列相似,16.04.3对那些使用更新硬件的用户带来了硬件优化。该版…...

Java学习_day01_hello java

构成 JDK JDK是java开发者工具,由JRE和一些开发工具组成。JRE JRE是java运行环境,由JVM和java核心类库组成。JVM JVM是java虚拟机,主要用来运行字节码。 执行过程 由IDE或文本编辑器,编写源代码,并将文件保存为*.ja…...

UnitTesting 单元测试

1. 测试分为两种及详细介绍测试书籍: 1.1 Unit Test : 单元测试 - test the business logic in your app : 测试应用中的业务逻辑 1.2 UI Test : 界面测试 - test the UI of your app : 测试应用中的界面 1.3 测试书籍网址:《Testing Swift》 https://www.hackingwithswift.c…...

C++内存管理:其五、指针类型转换与嵌入式指针

一、内存池的缺陷 作者在上一版本里面介绍了链表实现内存池,其中有一个小缺陷:虽然较少了cookie的内存损耗,但是加入了一个额外的指针,仍然需要占用内存。我们仔细看内存池的设计思想,可以发现一个关键点:…...

常见锁的分类

入职体验: 今天运维岗位刚入职,但是目前还没有办理入职手续,但是领导发了一堆资料!看了一下,非常多的新东西,只能说努力一把!!! 一、锁的分类 1.1 可重入锁、不可重入锁…...

vue 鼠标划入划出多传一个参数

// item可以传递弹窗显示数据, $event相关参数可以用来做弹窗定位用 mouseover"handleMouseOver($event, item)" mouseleave"handleMouseLeave($event, item)"举个栗子: 做一个hover提示弹窗组件(用的vue3框架 less插件) 可以将组件…...

svn项目同步到gitLab

安装git 确保安装了git 新建一个文件夹svn-git 在文件夹中新建userinfo.txt文件&#xff0c;映射svn用户,这个文件主要是用于将SVN用户映射为Git用户&#xff08;昵称及其邮箱&#xff09;。 userinfo.txt具体格式如下&#xff1a; admin admin <admin163.com> lis…...

图解Dubbo,Dubbo 服务治理详解

目录 一、介绍1、介绍 Dubbo 服务治理的基本概念和重要性2、阐述 Dubbo 服务治理的实现方式和应用场景 二、Dubbo 服务治理的原理1、Dubbo 服务治理的架构设计2、Dubbo 服务治理的注册与发现机制3、Dubbo 服务治理的负载均衡算法 三、Dubbo 服务治理的实现方式1、基于 Docker 容…...

Css 如何取消a链接点击时的背景颜色

要取消 <a> 链接点击时的背景颜色&#xff0c;可以使用 CSS 的伪类 :active。你可以通过为 a:active 应用 background-color 属性设置为 transparent 或者 none&#xff0c;来取消点击时的背景色。下面是一个示例&#xff1a; a:active {background-color: transparent;…...

1.16.C++项目:仿muduo库实现并发服务器之HttpContext以及HttpServer模块的设计

文章目录 一、HttpContext模块二、HttpServer模块三、HttpContext模块实现思想&#xff08;一&#xff09;功能&#xff08;二&#xff09;意义&#xff08;三&#xff09;接口 四、HttpServer模块实现思想&#xff08;一&#xff09;功能&#xff08;二&#xff09;意义&#…...

ABAP 新增PO计划行时 新增行交货日期默认当前最大交期

ABAP 新增PO计划行时 新增行交货日期默认当前最大交期 DATA: ls_poitem TYPE mepoitem. DATA: ls_jhh TYPE meposchedule. DATA: ls_poitemc TYPE REF TO if_purchase_order_item_mm. DATA: is_persistent TYPE mmpur_bool. DATA: lt_eket TYPE TABLE OF eket. DATA: ls_e…...

VSCode怎么创建Java项目

首先安装好Java的开发环境&#xff1a;JDK在VSCode中安装适用于Java开发的插件。打开VSCode&#xff0c;点击左侧的扩展图标&#xff0c;搜索并安装Java Extension Pack插件。等待安装完成后&#xff0c;重启VSCode生效。创建一个新的Java项目&#xff0c;按下Ctrl Shift P&a…...

软件工程与计算(十四)详细设计中面向对象方法下的模块化

一.面向对象中的模块 1.类 模块化是消除软件复杂度的一个重要方法&#xff0c;每个代码片段相互独立&#xff0c;这样能够提高可维护性。在面向对象方法中&#xff0c;代码片段最重要的类&#xff0c;整个类的所有代码联合起来构成独立的代码片段。 模块化希望代码片段由两部…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释

以Module Federation 插件详为例&#xff0c;Webpack.config.js它可能的配置和含义如下&#xff1a; 前言 Module Federation 的Webpack.config.js核心配置包括&#xff1a; name filename&#xff08;定义应用标识&#xff09; remotes&#xff08;引用远程模块&#xff0…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...