使用Python将数据写入LMDB非常慢

时间:2015-07-27 09:16:20

标签: python caffe lmdb

使用Caffe创建用于培训的数据集我都尝试使用HDF5和LMDB。但是,创建LMDB非常慢,甚至比HDF5慢。我正在尝试写出~20,000张图片。

我做错了什么吗?有什么我不知道的吗?

这是我创建LMDB的代码:

DB_KEY_FORMAT = "{:0>10d}"
db = lmdb.open(path, map_size=int(1e12))
    curr_idx = 0
    commit_size = 1000
    for curr_commit_idx in range(0, num_data, commit_size):
        with in_db_data.begin(write=True) as in_txn:
            for i in range(curr_commit_idx, min(curr_commit_idx + commit_size, num_data)):
                d, l = data[i], labels[i]
                im_dat = caffe.io.array_to_datum(d.astype(float), label=int(l))
                key = DB_KEY_FORMAT.format(curr_idx)
                in_txn.put(key, im_dat.SerializeToString())
                curr_idx += 1
    db.close()

正如您所看到的,我正在为每1000个图像创建一个事务,因为我认为为每个图像创建一个事务会产生开销,但似乎这不会对性能产生太大影响。

4 个答案:

答案 0 :(得分:6)

根据我的经验,我已经 50-100毫秒写入来自Python的LMDB 在Ubuntu上的ext4硬盘上写入Caffe数据。 这就是为什么我使用tmpfs (Linux中内置的 RAM磁盘功能)并在 0.07 ms 附近完成这些写操作。您可以在ramdisk上创建较小的数据库并将它们复制到硬盘上,然后再对所有数据库进行训练。我正在制作大约20-40GB的内存,因为我有64 GB的内存。

一些代码可以帮助您动态创建,填充和移动LMDB到存储。随意编辑它以适合您的情况。它可以节省你一些时间来了解LMDB和文件操作如何在Python中工作。

import shutil
import lmdb
import random


def move_db():
    global image_db
    image_db.close();
    rnd = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5))
    shutil.move( fold + 'ram/train_images',  '/storage/lmdb/'+rnd)
    open_db()


def open_db():
    global image_db
    image_db    = lmdb.open(os.path.join(fold, 'ram/train_images'),
            map_async=True,
            max_dbs=0)

def write_to_lmdb(db, key, value):
    """
    Write (key,value) to db
    """
    success = False
    while not success:
        txn = db.begin(write=True)
        try:
            txn.put(key, value)
            txn.commit()
            success = True
        except lmdb.MapFullError:
            txn.abort()
            # double the map_size
            curr_limit = db.info()['map_size']
            new_limit = curr_limit*2
            print '>>> Doubling LMDB map size to %sMB ...' % (new_limit>>20,)
            db.set_mapsize(new_limit) # double it

...

image_datum                 = caffe.io.array_to_datum( transformed_image, label )
write_to_lmdb(image_db, str(itr), image_datum.SerializeToString())

答案 1 :(得分:3)

试试这个:

DB_KEY_FORMAT = "{:0>10d}"
db = lmdb.open(path, map_size=int(1e12))
    curr_idx = 0
    commit_size = 1000
    with in_db_data.begin(write=True) as in_txn:
        for curr_commit_idx in range(0, num_data, commit_size):
            for i in range(curr_commit_idx, min(curr_commit_idx + commit_size, num_data)):
                d, l = data[i], labels[i]
                im_dat = caffe.io.array_to_datum(d.astype(float), label=int(l))
                key = DB_KEY_FORMAT.format(curr_idx)
                in_txn.put(key, im_dat.SerializeToString())
                curr_idx += 1
    db.close()

代码

with in_db_data.begin(write=True) as in_txn:

需要很长时间。

答案 2 :(得分:0)

LMDB写入对命令非常敏感 - 如果您可以在插入速度显着提高之前对数据进行排序

答案 3 :(得分:0)

我做了一个小的基准测试来说明Ophir的观点:

机器:

RasPi 4B-超频至1.75 GHz,4GB,RasperryPi OS,SSD上的操作系统

代码:

def insert_lmdb(fsobj, transaction):
    transaction.put(key=str(fsobj).encode("utf-8", "ignore"), value=generate_hash_from_file(fsobj).hexdigest().encode("utf-8", "ignore"))
list_f = list_files(FOLDER)

print(f"\n> Insert results in lmdb <")
list_f = Directory(path=DIR_ECTORY, use_hash=False, hash_from_content=False).lists["files"]

# list_f = sorted(list_f) # Run only in the 'sorted' case.

st = timeit.default_timer()

env = lmdb.open(path=DB_NAME)

with env.begin(write=True) as txn:
    for i in list_f:
        insert_lmdb(i, transaction=txn)
average = (timeit.default_timer() - st)*1000000/records

print(f"Test repeated {TIMES} times.\nNumber of files: {records}\nAverage time: {round(average, 3)} us or {round(1000000/average/1000, 3)}k inserts/sec")

结果:

不进行排序:

> Insert results in lmdb <
Test repeated 50000 times.
Number of files: 363
Average time: 84 us or 12k inserts/sec

具有排序功能:

> Insert results in lmdb <
Test repeated 50000 times.
Number of files: 363
Average time: 18.5 us or 54k inserts/sec

排序使写入速度提高了4.5倍,对于仅多一行代码就可以了:)。