digit_eye开发记录(2): Python读取MNIST数据集

在上一篇博客 digit_eye开发记录(1): C++读取MNIST数据集 中解读了 IDX 文件格式,并使用 C++ 语言完成了 MNIST 数据集的解析,第6小节给出的完整代码有146行之多。使用 Python 读取则可以省略70%的代码,只用不到50行代码完成相同功能。

读取 buffer

np.frombuffer(buf, dtype, count, offset)

说明:

  • buf: buffer,从文件读出来的
  • dtype: 从buf读取时,按什么类型读取数据,或者说,读取的基本单位是什么
  • count: 从buf读取时,读取多少个基本单位
  • offset: 从buf读取时,指针首先偏移多少个字节

读取 magic number

magic number 是 mnist 文件的前4个字节。 以二进制形式打开后,读取4字节即可:

import numpy as npwith open(filename, 'rb') as fin:buf = bytearray(fin.read())
magic = np.frombuffer(buf, np.uint8, count=4)
print(magic)

读取维度信息

回忆一下 magic numbers 的构成: 前两个字节是0,第三个字节是类型,第四个字节是维度数量 num_dims。
根据 num_dims 的取值,读取对应数量的字节,得到对应的维度信息。每个维度都是一个 int32 大小。

注意 MSB 到 LSB 的转换,通过 dtype=np.dtype('>u4') 指定, >u4 意思是:以MSB序,读取4个byte.

对于图像数据:

num_dims = magic[3]
dims = np.frombuffer(buf, dtype=np.dtype('>u4'), count=num_dims, offset=4)

对于label数据:

dims = np.frombuffer(buf, dtype=np.dtype('>u4'), count=num_dims, offset=4)
num_labels = dims[0]

读取图像像素

很容易想到使用 OOP 方式,定义 DataSet 类,在成员 self.images 中保存图像;于是乎,很“毛躁”的写出如下糟糕代码:

class DataSet:def __init__(self):self.images = []self.labels = []def load_images(self, filename):...for i in range(num_images):self.images.append(...)

存在的问题:

  • self.images 的类型一定是 list 吗?其实可以是 numpy 数组
  • self.images 的每个元素,和其他元素,一定是独立的吗? 可以是同一个内存上连续的分布
  • self.images 的每个元素,内存可以和读取文件得到的 buffer 复用吗?可以!
class DataSet:def __init__(self):self.images = Noneself.labels = Noneself.buf = Nonedef load_images(self, filename):with open(filename, 'rb') as fin:self.buf = bytearray(fin.read())magic = np.frombuffer(self.buf, np.uint8, count=4)num_dims = magic[3]dims = np.frombuffer(self.buf, dtype=np.dtype('>u4'), count=num_dims, offset=4)num_images, rows, cols = dimsself.images = np.frombuffer(self.buf, dtype=np.uint8, offset=4+4*num_dims).reshape(num_images, rows, cols)...train_set = DataSet()
train_set.load_images('data/train-images.idx3-ubyte')
print("Images and buffer share memory:", np.shares_memory(train_set.images, train_set.buf))

解释:self.buf 的类型,如果直接用 fin.read() 则得到 bytes 类型,是不可变的;转为 bytearray 类型后,是可变的,就可以保持和 self.images( ) 共享。

遗憾的是, self.buf = bytearray(fin.read()) 这句本身就发生了内存拷贝。

改进 - 避免内存拷贝

with open(filename, 'rb') as fin:  self.buf = bytearray(fin.read())  # 当前实现,存在两次内存分配  

改为

with open(filename, 'rb') as fin:  self.buf = fin.read()  # 读取为 bytes  self.buf = memoryview(self.buf)  # 直接使用 memoryview  

就可以避免 bytes 对象的中间拷贝过程。

完整代码

import numpy as np
import cv2class DataSet:def __init__(self):self.images = Noneself.labels = Noneself.buf = Nonedef load_images(self, filename):with open(filename, 'rb') as fin:#self.buf = bytearray(fin.read())self.buf = fin.read()self.buf = memoryview(self.buf)magic = np.frombuffer(self.buf, np.uint8, count=4)num_dims = magic[3]dims = np.frombuffer(self.buf, dtype=np.dtype('>u4'), count=num_dims, offset=4)num_images, rows, cols = dimsself.images = np.frombuffer(self.buf, dtype=np.uint8, offset=4+4*num_dims).reshape(num_images, rows, cols)def load_labels(self, filename):with open(filename, 'rb') as fin:buf = fin.read()magic = np.frombuffer(buf, np.uint8, count=4)num_dims = magic[3]dims = np.frombuffer(buf, dtype=np.dtype('>u4'), count=num_dims, offset=4)num_labels = dims[0]assert num_labels == len(self.images)self.labels = np.frombuffer(buf, dtype=np.uint8, offset=4+4*num_dims)def show_image(self, index):cv2.imshow('image', self.images[index])print('label:', self.labels[index])cv2.waitKey(0)cv2.destroyAllWindows()def main():train_set = DataSet()train_set.load_images('data/train-images.idx3-ubyte')train_set.load_labels('data/train-labels.idx1-ubyte')# train_set.show_image(0)# train_set.show_image(2)# train_set.show_image(5)print("Images and buffer share memory:", np.shares_memory(train_set.images, train_set.buf))if __name__ == '__main__':main()

总结

在前一篇,我们解析了MNIST数据集的IDX格式并用C++做了文件读取的实现,在本篇则切换到 Python 语言,在降低70%代码量的情况下实现了相同功能,并且避免了不必要的内存拷贝。这份工程之美,建立在对 IDX 格式有所了解的前提之下,对于 Python 的熟悉也是必不可少的,对于C++的经验也促使了复用内存这一条件的达成。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

聊聊Flink:这次把Flink的触发器(Trigger)、移除器(Evictor)讲透

一、触发器(Trigger) Trigger 决定了一个窗口(由 window assigner 定义)何时可以被 window function 处理。 每个 WindowAssigner 都有一个默认的 Trigger。 如果默认 trigger 无法满足你的需要,你可以在 trigger(…) 调用中指定自定义的 tr…

docker部署nginx,并配置SSL证书

、拉取nginx镜像 docker pull nginx:latest 在此过程中会遇到网络的问题&#xff0c;导致镜像无法下载&#xff0c;这时候需要在服务器中配置下国内的镜像地址。下面包含近期最新的国内镜像&#xff0c;截至2024年11月27日&#xff1a; "https://<你的阿里云账号ID&…

OceanBase 大数据量导入(obloader)

现需要将源数据库&#xff08;Oracle|MySQL等&#xff09;一些表的海量数据迁移到目标数据库 OceanBase 中&#xff0c;基于常规 jdbc 驱动编码的方式涉及开发工作&#xff0c;性能效率也要看编码的处理机制。 OceanBase 官方提供了的 OceanBase Migration Service (OMS) 数据…

【Spring MVC】如何获取cookie/session以及响应@RestController的理解,Header的设置

前言 &#x1f31f;&#x1f31f;本期讲解关于SpringMVC的编程之参数传递~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废…

【详细介绍及演示】Flink之checkpoint检查点的使用

目录 一、介绍 二、 设置checkpoint检查点演示 1、 代码演示 2、测试代码效果 3、查看快照情况 ​编辑 三、在集群上运行 1、第一次运行 2、第二次运行 四、自定义检查点savePoint 1、提交一个flink job 打成jar包 2、输入一些数据&#xff0c;观察单词对应的数字的…

JAVA篇05 —— 内部类(Local、Anonymous、Member、Static)

欢迎来到我的主页&#xff1a;【一只认真写代码的程序猿】 本篇文章收录于专栏【小小爪哇】 如果这篇文章对你有帮助&#xff0c;希望点赞收藏加关注啦~ 目录 1 内部类Inner Class 1.1 局部内部类 1.2 匿名内部类&#xff08;※※&#xff09; 1.3 匿名类最佳实践&#xf…

Spring Boot 与 Spring Cloud Alibaba 版本兼容对照

版本选择要点 Spring Boot 3.x 与 Spring Cloud Alibaba 2022.0.x Spring Boot 3.x 基于 Jakarta EE&#xff0c;javax.* 更换为 jakarta.*。 需要使用 Spring Cloud 2022.0.x 和 Spring Cloud Alibaba 2022.0.x。 Alibaba 2022.0.x 对 Spring Boot 3.x 的支持在其发行说明中…

jsp的pageContext对象

jsp的pageContext对象 是页面的上下文对象&#xff0c;表示当前页面运行环境&#xff0c;用于获取当前页面jsp页面信息&#xff0c;作用范围为当前的jsp页面 pageContext对象可以访问当前页面的所有jsp内置对象 jsp的四种内置对象 4中作用域&#xff1a;pagecontext,request…

网络安全在数字时代保护库存数据中的作用

如今&#xff0c;通过软件管理库存已成为一种标准做法。企业使用数字工具来跟踪库存水平、管理供应链和规划财务。 然而&#xff0c;技术的便利性也带来了网络威胁的风险。黑客将库存数据视为有价值的目标。保护这些数据不仅重要&#xff0c;而且必不可少。 了解网络安全及其…

Python图像处理:打造平滑液化效果动画

液化动画中的强度变化是通过在每一帧中逐渐调整液化效果的强度参数来实现的。在提供的代码示例中&#xff0c;强度变化是通过一个简单的线性插值方法来控制的&#xff0c;即随着动画帧数的增加&#xff0c;液化效果的强度也逐渐增加。 def liquify_image(image, center, radius…

day2全局注册

全局注册代码&#xff1a; //文件核心作用&#xff1a;导入App.vue,基于App.vue创建结构渲染index.htmlimport Vue from vue import App from ./App.vue //编写导入的代码&#xff0c;往代码的顶部编写&#xff08;规范&#xff09; import HmButton from ./components/Hm-But…

wireshark基础

免责声明&#xff1a; 笔记的只是方便各位师傅学习知识&#xff0c;以下代码、网站只涉及学习内容&#xff0c;其他的都与本人无关&#xff0c;切莫逾越法律红线&#xff0c;否则后果自负。 泷羽sec官网&#xff1a;https://longyusec.com/ 泷羽sec B站地址&#xff1a;https:/…

学习笔记037——Java中【Synchronized锁】

文章目录 1、修饰方法1.1、静态方法&#xff0c;锁定的是类1.2、非静态方法&#xff0c;锁定的是方法的调用者&#xff08;对象&#xff09; 2、修饰代码块&#xff0c;锁定的是传入的对象2.1、没有锁之前&#xff1a;2.2、有锁后&#xff1a; 实现线程同步&#xff0c;让多个线…

⭐️ GitHub Star 数量前十的工作流项目

文章开始前&#xff0c;我们先做个小调查&#xff1a;在日常工作中&#xff0c;你会使用自动化工作流工具吗&#xff1f;&#x1f64b; 事实上&#xff0c;工作流工具已经变成了提升效率的关键。其实在此之前我们已经写过一篇博客&#xff0c;跟大家分享五个好用的工作流工具。…

智能桥梁安全运行监测系统守护桥梁安全卫士

一、方案背景 桥梁作为交通基础设施中不可或缺的重要组成部分&#xff0c;其安全稳定的运行直接关联到广大人民群众的生命财产安全以及整个社会的稳定与和谐。桥梁不仅是连接两地的通道&#xff0c;更是经济发展和社会进步的重要纽带。为了确保桥梁的安全运行&#xff0c;桥梁安…

[创业之路-155] :《领先的密码-BLM方法论全面解读与应用指南》- 综合管理框架

目录 一、BLM&#xff08;业务领先模型&#xff09;综合管理框架 1、BLM模型的起源与发展 2、BLM模型的核心组成 3、BLM模型的战略规划与执行流程 4、BLM模型的应用价值 二、BLM&#xff08;业务领先模型&#xff09;实施案例 1. 华为的实施案例 2. 某知名企业A的实施案…

用Java爬虫“搜刮”工厂数据:一场数据的寻宝之旅

引言&#xff1a;数据的宝藏 在这个数字化的时代&#xff0c;数据就像是隐藏在数字丛林中的宝藏&#xff0c;等待着勇敢的探险家去发掘。而我们&#xff0c;就是那些手持Java魔杖的现代海盗&#xff0c;准备用我们的爬虫船去征服那些数据的海洋。今天&#xff0c;我们将一起踏…

redis 底层数据结构

概述 Redis 6 和 Redis 7 之间对比&#xff1a; Redis6 和 Redis7 最大的区别就在于 Redis7 已经用 listpack 替代了 ziplist. 以下是基于 Redis 7基础分析。 RedisObject Redis是⼀个<k,v>型的数据库&#xff0c;其中key通常都是string类型的字符串对象&#xff0c;⽽…

UE5 实现组合键触发事件的方法

因为工作原因。 需要用大括号{和}来触发事件 但是在蓝图中搜了一下&#xff0c;发现键盘事件里根本就没有{}这两个键。 花费了一下午&#xff0c;终于找到解决的方法了&#xff0c;也就是增强输入的弦操作 首先创建一个项目 纯蓝图或者C都可行 进入到内容浏览器的默认页面 …

使用Github Action将Docker镜像转存到阿里云私有仓库,供国内服务器使用,免费易用

文章目录 一、前言二、 工具准备&#xff1a;三、最终效果示例四、具体步骤第一大部分是配置阿里云1. 首先登录阿里云容器镜像服务 [服务地址](https://cr.console.aliyun.com/cn-hangzhou/instances)2. 选择个人版本3. 创建 命名空间4. 进入访问凭证来查看&#xff0c;用户名字…