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

深度学习(12)--Mnist分类任务

一.Mnist分类任务流程详解

1.1.引入数据集

Mnist数据集是官方的数据集,比较特殊,可以直接通过%matplotlib inline自动下载,博主此处已经完成下载,从本地文件中引入数据集。

设置数据路径

from pathlib import Path# 设置数据路径
# PATH = Path("data/minst")
DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"# PATH.mkdir(parents=True, exist_ok=True)  # 父目录不存在时创建父目录'''
parents:如果父目录不存在,是否创建父目录。
exist_ok:只有在目录不存在时创建目录,目录已存在时不会抛出异常。
'''

读取数据

import pickle
import gzip# 读取数据
'''
gzip.open的作用是解压gzip文件
with gzip.open(PATH.as_posix(), "rb") as f:((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")
'''
# rb表示以二进制格式打开一个文件用于只读
# 打开PATH路径的文件用以接下来的操作
# 保存数据的文件类型为pickle,所以用pickle.load打开文件,文件此处设置的别名为f
with open(PATH.as_posix(), "rb") as f:((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")'''
as.posix()的作用:
#返回使用斜杠(/)分割路径的字符串
#将所有连续的正斜杠、反斜杠,统一修改为单个正斜杠
#相对路径 './' 替换为空,'../' 则保持不变。
'''

测试引入数据集是否成功

from matplotlib import pyplot
import numpy as np# 测试数据集是否导入成功
pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")
print(x_train.shape)

1.2.数据类型转换

数据需要转换成tensor类型才能参与后续建模训练

import torch# 通过map映射,将x_train等数据全都转为torch.tensor类型。tensor类型才能参与后续建模训练
x_train, y_train, x_valid, y_valid = map(torch.tensor, (x_train, y_train, x_valid, y_valid)
)

测试数据类型是否转换成功

n, c = x_train.shape
x_train, x_train.shape, y_train.min(), y_train.max()
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())

数据均为tensor类型,转换成功

1.3.设置损失函数

import torch.nn.functional as F# 设置损失函数,此处使用的损失函数为交叉熵
loss_func = F.cross_entropy 

测试损失函数

手动设置初始权重和偏置值进行测试,真实情况下系统会自动帮我们初始化

bs = 64
xb = x_train[0:bs]  # a mini-batch from x ,xb是x_train中0~64项的数
yb = y_train[0:bs]# 实际操作中模型会自动定义权重参数,不用我们手动设置
# 因为输入数据是784x1个像素点,而最后得到的是十个类别,所以权重矩阵的大小为784x10。
weights = torch.randn([784, 10], dtype = torch.float,  requires_grad = True) 
bs = 64
# bias矩阵的大小取决于最后的类别数量,此处的bias矩阵为10x1
bias = torch.zeros(10, requires_grad=True)def model(xb):return xb.mm(weights) + bias  # .mm()是矩阵相乘 .mul()则是对应位相乘# 损失函数是用来度量模型的预测值f(x)与真实值Y的差异程度的运算函数,此处model(xb)得到的是经过权重计算的预测值,yb是真实值。给损失函数传入的参数即为预测值和真实值。
print(loss_func(model(xb), yb))

1.4.神经网络构造 

此处所选用的是传统神经网络完成Minist分类任务

from torch import nn# 创建一个模型类,注意一定要继承于nn.Module(取决于你要创建的网络类型)
class Mnist_NN(nn.Module):def __init__(self):# 调用父类的构造函数super().__init__()# 创建两个隐层 由784->128->256->10self.hidden1 = nn.Linear(784, 128)self.hidden2 = nn.Linear(128, 256)# 创建输出层,由256->10,即最后输出十个类别self.out  = nn.Linear(256, 10)self.dropout = nn.Dropout(0.5)# torch框架需要自己定义前向传播,反向传播由框架自己实现# 传入的x是一个batch x 特征值def forward(self, x):# x经过第一个隐层x = F.relu(self.hidden1(x))# x经过dropout层x = self.dropout(x)# x经过第二个隐藏x = F.relu(self.hidden2(x))# x经过dropout层x = self.dropout(x)# x经过输出层x = self.out(x)return x

测试构造的神经网络

net = Mnist_NN()
print(net)

查看网络中构建好的权重和偏置项 

for name, parameter in net.named_parameters():print(name, parameter,parameter.size())
 

1.5.使用TensorDataset和DataLoader简化数据 

from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader# TensorDataset获取数据,再由DataLoader打包数据传给GPU(包的大小位batch_size)
# 训练集一般打乱顺序,验证集不打乱顺序
train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)def get_data(train_ds, valid_ds, bs):return (DataLoader(train_ds, batch_size=bs, shuffle=True),DataLoader(valid_ds, batch_size=bs * 2),)

1.6.模型训练

优化器设置

from torch import optim
def get_model():model = Mnist_NN() # 使用先前创建的类构造一个网络return model, optim.SGD(model.parameters(), lr=0.001) # 返回值为模型和优化器# 优化器的设置,optim.SGD(),参数分别为:要优化的参数、学习率def loss_batch(model, loss_func, xb, yb, opt=None):# 计算损失,参数为预测值和真实值loss = loss_func(model.forward(xb), yb)  # 预测值由定义的前向传播过程计算处# 如果存在优化器if opt is not None: loss.backward()  # 反向传播,算出更新的权重参数opt.step()  # 执行backward()计算出的权重参数的更新opt.zero_grad()  # torch会进行迭代的累加,通过zero_grad()将之前的梯度清空(不同的迭代之间应当是没有关系的)return loss.item(), len(xb)

常用优化器:

  • 随机梯度下降(SGD, stochastic gradient descent)
  • SGDM(加入了一阶动量)
  • AdaGrad(加入了二阶动量)
  • RMSProp
  • Adam

模型训练

import numpy as np#epoch和batch的关系,
#eg:有10000个数据,batch=100,则一个1epoch需要训练100个batch(1一个epoch就是训练整个数据一次)
# 定义训练函数,传入的参数分别为:迭代的次数、模型、损失函数、优化器、训练集、验证集
def fit(steps, model, loss_func, opt, train_dl, valid_dl):for step in range(steps):# 训练模式:model.train()  for xb, yb in train_dl:loss_batch(model, loss_func, xb, yb, opt)  # 得到由loss_batch更新的权重值# 验证模式:model.eval()   with torch.no_grad():  # 没有梯度,即不更新权重参数# zip将两个矩阵配对,例如两个一维矩阵配对成一个二维矩阵,下述情况中即为一个losses对应一个nums -> [(losses,nums)]。zip*是解包操作,即将二维矩阵又拆分成一维矩阵,并返回拆分得到的一维矩阵。losses, nums = zip(*[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl])val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)  # 计算平均损失:对应的损失值和样本数相乘的总和 / 总样本数print('当前step:'+str(step), '验证集损失:'+str(val_loss))

二.完整代码 

from pathlib import Path
import pickle
import gzipfrom matplotlib import pyplot
import numpy as npimport torchimport torch.nn.functional as Ffrom torch import nnfrom torch.utils.data import TensorDataset
from torch.utils.data import DataLoaderfrom torch import optimimport numpy as np# 设置数据路径
DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist.pkl"# PATH.mkdir(parents=True, exist_ok=True)'''
parents:如果父目录不存在,是否创建父目录。
exist_ok:只有在目录不存在时创建目录,目录已存在时不会抛出异常。
'''# 读取数据
'''
gzip.open的作用是解压gzip文件
with gzip.open(PATH.as_posix(), "rb") as f:((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")
'''
# rb表示以二进制格式打开一个文件用于只读
# 打开PATH路径的文件用以接下来的操作
# 保存数据的文件类型为pickle,所以用pickle.load打开文件,文件此处设置的别名为f
with open(PATH.as_posix(), "rb") as f:((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")'''
as.posix()的作用:
#返回使用斜杠(/)分割路径的字符串
#将所有连续的正斜杠、反斜杠,统一修改为单个正斜杠
#相对路径 './' 替换为空,'../' 则保持不变。
''''''
# 测试数据集是否导入成功
pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")
print(x_train.shape)
'''# 数据类型转换为torch# 通过map映射,将x_train等数据全都转为torch.tensor类型。tensor类型才能参与后续建模训练
x_train, y_train, x_valid, y_valid = map(torch.tensor, (x_train, y_train, x_valid, y_valid)
)# 测试数据类型是否转换成功
'''
n, c = x_train.shape
x_train, x_train.shape, y_train.min(), y_train.max()
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())
'''# 设置损失函数
loss_func = F.cross_entropybs = 64
xb = x_train[0:bs]  # a mini-batch from x ,xb是x_train中0~64项的数
yb = y_train[0:bs]''' 
# 手动初始化进行测试# 实际操作中模型会自动定义权重参数,不用我们手动设置
# 因为输入数据是784x1个像素点,而最后得到的是十个类别,所以权重矩阵的大小为784x10。
weights = torch.randn([784, 10], dtype = torch.float,  requires_grad = True)
bs = 64
# bias矩阵的大小取决于最后的类别数量,此处的bias矩阵为10x1
bias = torch.zeros(10, requires_grad=True)def model(xb):return xb.mm(weights) + bias  # .mm()是矩阵相乘 .mul()则是对应位相乘# 损失函数是用来度量模型的预测值f(x)与真实值Y的差异程度的运算函数,此处model(xb)得到的是经过权重计算的预测值,yb是真实值。给损失函数传入的参数即为预测值和真实值。
print(loss_func(model(xb), yb))
'''# 创建一个模型类,注意一定要继承于nn.Module(取决于你要创建的网络类型)
class Mnist_NN(nn.Module):def __init__(self):# 调用父类的构造函数super().__init__()# 创建两个隐层 由784->128->256->10self.hidden1 = nn.Linear(784, 128)self.hidden2 = nn.Linear(128, 256)# 创建输出层,由256->10,即最后输出十个类别self.out = nn.Linear(256, 10)self.dropout = nn.Dropout(0.5)# torch框架需要自己定义前向传播,反向传播由框架自己实现# 传入的x是一个batch x 特征值def forward(self, x):# x经过第一个隐层x = F.relu(self.hidden1(x))# x经过dropout层x = self.dropout(x)# x经过第二个隐藏x = F.relu(self.hidden2(x))# x经过dropout层x = self.dropout(x)# x经过输出层x = self.out(x)return x'''
# 测试构造的网络模型
net = Mnist_NN()
print(net)打印权重和偏置项
for name, parameter in net.named_parameters():print(name, parameter,parameter.size())
'''# TensorDataset获取数据,再由DataLoader打包数据传给GPU
# 训练集一般打乱顺序,验证集不打乱顺序
train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)def get_data(train_ds, valid_ds, bs):return (DataLoader(train_ds, batch_size=bs, shuffle=True),DataLoader(valid_ds, batch_size=bs * 2),)# 优化器设置
def get_model():model = Mnist_NN()return model, optim.SGD(model.parameters(), lr=0.001)# 优化器的设置,optim.SGD(),参数分别为:要优化的参数、学习率def loss_batch(model, loss_func, xb, yb, opt=None):# 计算损失,参数为预测值和真实值loss = loss_func(model.forward(xb), yb)  # 预测值由定义的前向传播过程计算处# 如果存在优化器if opt is not None:loss.backward()  # 反向传播,算出更新的权重参数opt.step()  # 执行backward()计算出的权重参数的更新opt.zero_grad()  # torch会进行迭代的累加,通过zero_grad()将之前的梯度清空(不同的迭代之间应当是没有关系的)return loss.item(), len(xb)# 模型训练
# epoch和batch的关系,
# eg:有10000个数据,batch=100,则一个1epoch需要训练100个batch(1一个epoch就是训练整个数据一次)
# 定义训练函数,传入的参数分别为:迭代的次数、模型、损失函数、优化器、训练集、验证集
def fit(steps, model, loss_func, opt, train_dl, valid_dl):for step in range(steps):# 训练模式:model.train()for xb, yb in train_dl:loss_batch(model, loss_func, xb, yb, opt)  # 得到由loss_batch更新的权重值# 验证模式:model.eval()with torch.no_grad():  # 没有梯度,即不更新权重参数# zip将两个矩阵配对,例如两个一维矩阵配对成一个二维矩阵,下述情况中即为一个losses对应一个nums -> [(losses,nums)]。zip*是解包操作,即将二维矩阵又拆分成一维矩阵,并返回拆分得到的一维矩阵。losses, nums = zip(*[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl])val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)  # 计算平均损失:对应的损失值和样本数相乘的总和 / 总样本数print('当前step:'+str(step), '验证集损失:'+str(val_loss))# 输出
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(25, model, loss_func, opt, train_dl, valid_dl)# 准确率的计算
correct = 0
total = 0
for xb,yb in valid_dl:outputs = model(xb)_, predicted = torch.max(outputs.data,1)  # 返回最大的值和对应的列索引(列索引在此处就是对应的类别)    (, 0)则返回行索引total += yb.size(0)  # yb的样本数correct += (predicted == yb).sum().item( ) # .sum()返回验证正确了的样本数,item()从tensor数据类型中取值,方便后续的画图等(tensor数据类型不好画图)print('Accuracy of the network on the 10000 test image: %d %%' %(100*correct/total))

三.输出结果

相关文章:

深度学习(12)--Mnist分类任务

一.Mnist分类任务流程详解 1.1.引入数据集 Mnist数据集是官方的数据集,比较特殊,可以直接通过%matplotlib inline自动下载,博主此处已经完成下载,从本地文件中引入数据集。 设置数据路径 from pathlib import Path# 设置数据路…...

AI工具【OCR 01】Java可使用的OCR工具Tess4J使用举例(身份证信息识别核心代码及信息提取方法分享)

Java可使用的OCR工具Tess4J使用举例 1.简介1.1 简单介绍1.2 官方说明 2.使用举例2.1 依赖及语言数据包2.2 核心代码2.3 识别身份证信息2.3.1 核心代码2.3.2 截取指定字符2.3.3 去掉字符串里的非中文字符2.3.4 提取出生日期(待优化)2.3.5 实测 3.总结 1.简…...

【MySQL复制】半同步复制

介绍 除了内置的异步复制之外,MySQL 5.7 还支持通过插件实现的半同步复制接口。本节讨论半同步复制的概念及其工作原理。接下来的部分将涵盖与半同步复制相关的管理界面,以及如何安装、配置和监控它。 异步复制 MySQL 复制默认是异步的。源服务器将事…...

PHP面试知识点--echo、print、print_r、var_dump区别

echo、print、print_r、var_dump 区别 echo 输出单个或多个字符,多个使用逗号分隔无返回值 echo "String 1", "String 2";print 只可以输出单个字符返回1,因此可用于表达式 print "Hello"; if ($expr && pri…...

centos 7 部署若依前后端分离项目

目录 一、新建数据库 二、修改需求配置 1.修改数据库连接 2.修改Redis连接信息 3.文件路径 4.日志存储路径调整 三、编译后端项目 四、编译前端项目 1.上传项目 2.安装依赖 3.构建生产环境 五、项目部署 1.创建目录 2.后端文件上传 3. 前端文件上传 六、服务启…...

RFID手持终端_智能pda手持终端设备定制方案

手持终端是一款多功能、适用范围广泛的安卓产品,具有高性能、大容量存储、高端扫描头和全网通数据连接能力。它能够快速平稳地运行,并提供稳定的连接表现和快速的响应时,适用于医院、物流运输、零售配送、资产盘点等苛刻的环境。通过快速采集…...

51单片机学习——矩阵按键

目录 gitee链接 小程吃饭饭 (xiaocheng-has-a-meal) - Gitee.comhttps://gitee.com/xiaocheng-has-a-meal 1.图~突突突突突 矩阵键盘原理图 矩阵键盘的实物图 2.矩阵键盘 引入~啦啦啦啦啦 原理~沥沥沥沥沥 代码~嗷嗷嗷嗷嗷 【1】延时函数 【2】 LCD1602 【3】检测按…...

重写Sylar基于协程的服务器(1、日志模块的架构)

重写Sylar基于协程的服务器(1、日志模块的架构) 重写Sylar基于协程的服务器系列: 重写Sylar基于协程的服务器(0、搭建开发环境以及项目框架 || 下载编译简化版Sylar) 重写Sylar基于协程的服务器(1、日志模…...

ElementUI Form:Radio 单选框

ElementUI安装与使用指南 Radio 单选框 点击下载learnelementuispringboot项目源码 效果图 el-radio.vue &#xff08;Radio 单选框&#xff09;页面效果图 项目里el-radio.vue代码 <script> export default {name: el_radio,data() {return {radio: 1,radio2: 2,ra…...

react-activation实现缓存,且部分页面刷新缓存,清除缓存

1.安装依赖 npm i -S react-activation2.使用AliveScope 包裹根组件 import { AliveScope } from "react-activation" <AliveScope><Router><Switch><Route exact path"/" render{() > <Redirect to"/login" push …...

idea 中 tomcat 乱码问题修复

之前是修改 Tomcat 目录下 conf/logging.properties 的配置&#xff0c;将 UTF-8 修改为 GBK&#xff0c;现在发现不用这样修改了。只需要修改 IDEA 中 Tomcat 的配置就可以了。 修改IDEA中Tomcat的配置&#xff1a;添加-Dfile.encodingUTF-8 本文结束...

Modbus协议学习第七篇之libmodbus库API介绍(modbus_write_bits等)

写在前面 在第六篇中我们介绍了基于libmodbus库的演示代码&#xff0c;那本篇博客就详细介绍一下第六篇的代码中使用的基于该库的API函数。另各位读者&#xff0c;Modbus相关知识受众较少&#xff0c;如果觉得我的专栏文章有帮助&#xff0c;请一定点个赞&#xff0c;在此跪谢&…...

第九节HarmonyOS 常用基础组件13-TimePicker

1、描述 时间选择组件&#xff0c;根据指定参数创建选择器&#xff0c;支持选择小时以及分钟。默认以24小时的时间区间创建滑动选择器。 2、接口 TimePicker(options?: {selected?: Date}) 3、参数 selected - Date - 设置选中项的时间。默认是系统当前的时间。 4、属性…...

力扣刷题-55.跳跃游戏

给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 class Solution { publ…...

Ruby安装演示教程

安装 Ruby 的过程会根据您的操作系统&#xff08;如 Windows、MacOS、Linux&#xff09;而有所不同。以下是在这些主要平台上安装 Ruby 的基本指南。 在 Windows 上安装 Ruby 下载 Ruby Installer&#xff1a;访问 RubyInstaller 官方网站下载适合您系统的 Ruby Installer 版…...

前端使用vue-simple-uploader进行分片上传

目录 一、安装vue-simple-uploader 二、在vue中使用 一、安装vue-simple-uploader npm install vue-simple-uploader --save main.js初始化vue-simple-uploader import uploader from vue-simple-uploaderVue.use(uploader) common/config文件 export const ACCEPT_CONF…...

Java 源代码中常见的数据类型

在Java源代码中&#xff0c;常见的数据类型包括基本数据类型&#xff08;Primitive Data Types&#xff09;和引用数据类型&#xff08;Reference Data Types&#xff09;。这些数据类型在Java中用于存储不同种类的数据&#xff0c;如整数、小数、字符、布尔值以及对象等。 1.…...

Web3行业研究逐步加强,“链上数据”缘何成为关注焦点?

据中国电子报报道&#xff0c;近日&#xff0c;由中关村区块链产业联盟指导&#xff0c;中国信息通信研究院牵头&#xff0c;欧科云链控股有限公司参与编写的《全球Web3产业全景与发展趋势研究报告&#xff08;2023年&#xff09;》正式发布。研究报告通过全面追踪国内外Web3产…...

逸学区块链【solidity】真随机数

参考Get a Random Number | Chainlink Documentation 但是很贵&#xff0c;价格 Gas Price&#xff1a;当前gas价格&#xff0c;根据网络状况而波动。Callback gas &#xff1a;返回您所请求的随机值时&#xff0c;回调请求消耗的gas 量。验证gas &#xff1a;量gas 用于验证…...

【WPF.NET开发】优化性能:对象行为

本文内容 不删除对象的事件处理程序可能会使对象保持活动状态依赖属性和对象Freezable 对象用户界面虚拟化 了解 WPF 对象的内部行为有助于在功能和性能之间做出适当的取舍。 1、不删除对象的事件处理程序可能会使对象保持活动状态 对象传递给其事件的委托是对该对象的有效…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

Device Mapper 机制

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

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...