python生成lmdb格式文件及读取

目录

 

一.lmdb介绍

1.LMDB 的基本函数

二.图片数据示例

参考

一.lmdb介绍

LMDB全称Lightning Memory-Mapped Database,是内存映射型数据库,这意味着它返回指向键和值的内存地址的指针,而不需要像大多数其他数据库那样复制内存中的任何内容,使用内存映射文件,可以提供更好的输入/输出性能,对于神经网络的的大型数据集可以将其存储到LMDB中

LMDB属于key-value数据库,而不是关系型数据库( 比如 MySQL ),LMDB提供 key-value 存储,其中每个键值对都是我们数据集中的一个样本。LMDB的主要作用是提供数据管理,可以将各种各样的原始数据转换为统一的key-value存储。

LMDB不仅可以用来存放训练和测试用的数据集,还可以存放神经网络提取出的特征数据。如果数据的结构很简单,就是大量的矩阵和向量,而且数据之间没有什么关联,数据内没有复杂的对象结构,那么就可以选择LMDB这个简单的数据库来存放数据。

用LMDB数据库来存放图像数据,而不是直接读取原始图像数据的原因:

  • 数据类型多种多样,比如:二进制文件、文本文件、编码后的图像文件jpeg、png等,不可能用一套代码实现所有类型的输入数据读取,因此通过LMDB数据库,转换为统一数据格式可以简化数据读取层的实现。
  • lmdb具有极高的存取速度,大大减少了系统访问大量小文件时的磁盘IO的时间开销。LMDB将整个数据集都放在一个文件里,避免了文件系统寻址的开销,你的存储介质有多快,就能访问多快,不会因为文件多而导致时间长。LMDB使用了内存映射的方式访问文件,这使得文件内寻址的开销大幅度降低。

1.LMDB 的基本函数

  • env = lmdb.open():创建 lmdb 环境
  • txn = env.begin():建立事务
  • txn.put(key, value):进行插入和修改
  • txn.delete(key):进行删除
  • txn.get(key):通过查询value
  • txn.cursor():整个db进行遍历
  • txn.commit():提交更改

创建一个 lmdb 环境:

# 安装:pip install lmdb
import lmdb
env = lmdb.open(lmdb_path, map_size=1099511627776)  

lmdb_path 指定存放生成的lmdb数据库的文件夹路径,如果没有该文件夹则自动创建。

map_size 指定创建的新数据库所需磁盘空间的最小值,1099511627776B=1T。可以在这里进行 存储单位换算

会在指定路径下创建 data.mdb 和 lock.mdb 两个文件,一是个数据文件,一个是锁文件。

修改数据库内容:

txn = env.begin(write=True)

# insert/modify
txn.put(str(1).encode(), "Alice".encode())
txn.put(str(2).encode(), "Bob".encode())

# delete
txn.delete(str(1).encode())

txn.commit()

先创建一个事务(transaction) 对象 txn,所有的操作都必须经过这个事务对象。因为我们要对数据库进行写入操作,所以将 write 参数置为 True,默认其为 False

使用 .put(key, value) 对数据库进行插入和修改操作,传入的参数为键值对。

值得注意的是,需要在键值字符串后加 .encode() 改变其编码格式,将 str 转换为 bytes 格式,否则会报该错误:TypeError: Won't implicitly convert Unicode to bytes; use .encode()。在后面使用 .decode() 对其进行解码得到原数据。

使用 .delete(key) 删除指定键值对。

对LMDB的读写操作在事务中执行,需要使用 commit 方法提交待处理的事务,如果不提交存在数据保存不成功的情况。

查询数据库内容:

txn = env.begin()

print(txn.get(str(2).encode()))

for key, value in txn.cursor():
    print(key, value)

env.close()

每次 commit() 之后都要用 env.begin() 更新 txn(得到最新的lmdb数据库)。

使用 .get(key) 查询数据库中的单条记录。

使用 .cursor() 遍历数据库中的所有记录,其返回一个可迭代对象,相当于关系数据库中的游标,每读取一次,游标下移一位。

也可以想文件一样使用 with 语法:

with env.begin() as txn:
    print(txn.get(str(2).encode()))

    for key, value in txn.cursor():
        print(key, value)

完整的demo如下:

import lmdb
import os, sys

def initialize():
    env = lmdb.open("lmdb_dir")
    return env

def insert(env, sid, name):
    txn = env.begin(write=True)
    txn.put(str(sid).encode(), name.encode())
    txn.commit()

def delete(env, sid):
    txn = env.begin(write=True)
    txn.delete(str(sid).encode())
    txn.commit()

def update(env, sid, name):
    txn = env.begin(write=True)
    txn.put(str(sid).encode(), name.encode())
    txn.commit()

def search(env, sid):
    txn = env.begin()
    name = txn.get(str(sid).encode())
    return name

def display(env):
    txn = env.begin()
    cur = txn.cursor()
    for key, value in cur:
        print(key, value)


env = initialize()

print("Insert 3 records.")
insert(env, 1, "Alice")
insert(env, 2, "Bob")
insert(env, 3, "Peter")
display(env)

print("Delete the record where sid = 1.")
delete(env, 1)
display(env)

print("Update the record where sid = 3.")
update(env, 3, "Mark")
display(env)

print("Get the name of student whose sid = 3.")
name = search(env, 3)
print(name)

# 最后需要关闭关闭lmdb数据库
env.close()

# 执行系统命令
os.system("rm -r lmdb_dir")

二.图片数据示例

在图像深度学习训练中我们一般都会把大量原始数据集转化为lmdb格式以方便后续的网络训练。因此我们也需要对该数据集进行lmdb格式转化。

将图片和对应的文本标签存放到lmdb数据库:

import lmdb

image_path = './cat.jpg'
label = 'cat'

env = lmdb.open('lmdb_dir')
cache = {}  # 存储键值对

with open(image_path, 'rb') as f:
    # 读取图像文件的二进制格式数据
    image_bin = f.read()

# 用两个键值对表示一个数据样本
cache['image_000'] = image_bin
cache['label_000'] = label

txn = env.begin(write=True)
for k, v in cache.items():
    if isinstance(v, bytes):
       # 图片类型为bytes
        txn.put(k.encode(), v)
    else:
        # 标签类型为str, 转为bytes
        txn.put(k.encode(), v.encode())  # 编码
txn.commit()
env.close()

这里需要获取图像文件的二进制格式数据,然后用两个键值对保存一个数据样本,即分开保存图片和其标签。

然后分别将图像和标签写入到lmdb数据库中,和上面例子一样都需要将键值转换为 bytes 格式。因为此处读取的图片格式本身就为 bytes,所以不需要转换,标签格式为 str,写入数据库之前需要先进行编码将其转换为 bytes

从lmdb数据库中读取图片数据:

import cv2
import lmdb
import numpy as np

env = lmdb.open('lmdb_dir')

with env.begin(write=False) as txn:
    # 获取图像数据
    image_bin = txn.get('image_000'.encode())
    label = txn.get('label_000'.encode()).decode()  # 解码

    # 将二进制文件转为十进制文件(一维数组)
    image_buf = np.frombuffer(image_bin, dtype=np.uint8)
    # 将数据转换(解码)成图像格式
    # cv2.IMREAD_GRAYSCALE为灰度图,cv2.IMREAD_COLOR为彩色图
    img = cv2.imdecode(image_buf, cv2.IMREAD_COLOR)
    cv2.imshow('image', img)
    cv2.waitKey(0)

先通过 lmdb.open() 获取之前创建的lmdb数据库。

这里通过键得到图片和其标签,因为写入数据库之前进行了编码,所以这里需要先解码。

  • 标签通过 .decode() 进行解码重新得到字符串格式。
  • 读取到的图片数据为二进制格式,所以先使用 np.frombuffer() 将其转换为十进制格式的文件,这是一维数组。然后可以使用 cv2.imdecode() 将其转换为灰度图(二维数组)或者彩色图(三维数组)。

个人感觉和字典的有些相似之处

三.参考

https://zhuanlan.zhihu.com/p/70359311

https://lmdb.readthedocs.io/en/release/#environment-class

  • 13
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值