如何从Caffe训练集LMDB文件拆分生成验证集LMDB?
从训练集LMDB拆分生成验证集LMDB的方法
没问题!完全可以把训练集LMDB里的一部分数据拆出来做成独立的验证集LMDB,我给你一步步讲清楚怎么做:
1. 先搞定依赖库
首先确保你装了必要的工具包,用pip安装就行:
pip install lmdb opencv-python # opencv是用来处理图像的,如果你的LMDB存的不是图像,可以只装lmdb
2. 用Python脚本拆分数据
LMDB本质是键值对数据库,我们可以读取原训练集的所有键值对,随机打乱后按比例拆分,再分别写入新的训练集和验证集LMDB。下面是现成的脚本,你直接改路径和拆分比例就能用:
import lmdb import cv2 import numpy as np import random def split_lmdb(source_lmdb_path, train_lmdb_path, val_lmdb_path, split_ratio=0.9): # 打开源训练集LMDB source_env = lmdb.open(source_lmdb_path, readonly=True, lock=False) with source_env.begin(write=False) as txn: # 获取所有数据的键 keys = [key.decode('utf-8') for key in txn.cursor().iternext(keys=True, values=False)] # 随机打乱键的顺序,避免验证集是连续的子集 random.shuffle(keys) # 计算拆分点,比如9:1的话,90%留作训练,10%作为验证 split_idx = int(len(keys) * split_ratio) train_keys = keys[:split_idx] val_keys = keys[split_idx:] # 写入新的训练集LMDB(建议保留原训练集,所以用新路径) train_env = lmdb.open(train_lmdb_path, map_size=1099511627776) # map_size设成1TB足够大部分数据集 with train_env.begin(write=True) as txn: with source_env.begin(write=False) as source_txn: for key in train_keys: value = source_txn.get(key.encode('utf-8')) txn.put(key.encode('utf-8'), value) train_env.close() # 写入验证集LMDB,也就是你需要的val_lmdb val_env = lmdb.open(val_lmdb_path, map_size=1099511627776) with val_env.begin(write=True) as txn: with source_env.begin(write=False) as source_txn: for key in val_keys: value = source_txn.get(key.encode('utf-8')) txn.put(key.encode('utf-8'), value) val_env.close() source_env.close() if __name__ == '__main__': # 替换成你自己的路径 source_path = 'train_lmdb' # 原训练集LMDB路径 new_train_path = 'new_train_lmdb' # 拆分后的新训练集路径(不想改原训练集就用这个) val_path = 'val_lmdb' # 要生成的验证集路径 split_lmdb(source_path, new_train_path, val_path, split_ratio=0.9) # 这里可以改拆分比例
3. 几个要注意的点
- map_size别太小:
map_size是LMDB的最大存储空间,一定要设得比你的数据集总大小大,我上面设的1TB(1099511627776)基本能覆盖大部分图像数据集,如果你的数据特别大,可以再调大。 - 一定要打乱顺序:别直接拿最后10%当验证集,这样分布可能和训练集不一致,验证结果不准,随机打乱才靠谱。
- 保留原数据:建议不要直接覆盖原训练集LMDB,生成新的训练集和验证集,原数据留着备用总没错。
- 非图像数据也能用:如果你的LMDB存的不是图像,把脚本里和
cv2相关的代码删掉就行,直接处理键值对就OK。
4. 验证拆分结果
拆分完可以用下面的小脚本检查一下两个LMDB的内容是否正常:
def check_lmdb(lmdb_path): env = lmdb.open(lmdb_path, readonly=True, lock=False) with env.begin(write=False) as txn: count = txn.stat()['entries'] print(f"{lmdb_path} 里有 {count} 条数据") # 读第一条数据看看 cursor = txn.cursor() cursor.first() key, value = cursor.item() print(f"第一条数据的键:{key.decode('utf-8')}") # 如果是图像的话,解码看看形状 img = cv2.imdecode(np.frombuffer(value, np.uint8), cv2.IMREAD_COLOR) if img is not None: print(f"图像形状:{img.shape}") env.close() check_lmdb('new_train_lmdb') check_lmdb('val_lmdb')
跑完脚本后,你要的val_lmdb/data.mdb和val_lmdb/lock.mdb就生成好了~
内容的提问来源于stack exchange,提问作者8-Bit Borges




