如何基于文件夹结构创建CNTK自定义图像数据集并生成所需文件?
解决CNTK自定义图像数据集的map.txt、mean.xml生成与序列化问题
我之前也碰到过和你一样的困惑——CNTK官方教程大多用现成的MNIST这类数据集,对从正负样本文件夹生成所需的标签/特征文件这块讲得不够细。下面我就一步步教你怎么搞定这些文件:
1. 生成map.txt(标签-图像路径映射文件)
map.txt的作用是告诉CNTK每张图像对应的标签,格式是**图像路径 标签值**,每行对应一个样本。假设你的数据集结构是这样的:
dataset_root/ ├─ positive/ # 正样本,标签设为1 │ ├─ img_001.jpg │ ├─ img_002.jpg │ └─ ... └─ negative/ # 负样本,标签设为0 ├─ img_001.jpg ├─ img_002.jpg └─ ...
你可以用Python写个简单的脚本来遍历文件夹生成map.txt:
import os # 数据集根目录,替换成你的路径 dataset_root = "./dataset_root" # 输出map.txt的路径 output_map = "./map.txt" with open(output_map, "w") as f: # 处理正样本 pos_dir = os.path.join(dataset_root, "positive") for img_name in os.listdir(pos_dir): img_path = os.path.join(pos_dir, img_name) # 确保是图像文件(可以根据你的格式调整后缀) if img_name.lower().endswith((".jpg", ".png", ".bmp")): f.write(f"{img_path} 1\n") # 处理负样本 neg_dir = os.path.join(dataset_root, "negative") for img_name in os.listdir(neg_dir): img_path = os.path.join(neg_dir, img_name) if img_name.lower().endswith((".jpg", ".png", ".bmp")): f.write(f"{img_path} 0\n")
运行这个脚本后,你就能得到符合要求的map.txt了。
2. 生成mean.xml(数据集均值文件)
mean.xml用来存储数据集所有图像的像素均值,训练时用来做图像归一化。同样用Python脚本计算并生成:
import os import cv2 import numpy as np from xml.etree.ElementTree import Element, SubElement, tostring from xml.dom.minidom import parseString # 数据集根目录 dataset_root = "./dataset_root" # 输出mean.xml的路径 output_mean = "./mean.xml" # 初始化均值统计 total_pixels = 0 mean_b = 0.0 mean_g = 0.0 mean_r = 0.0 # 遍历所有图像 for root, _, files in os.walk(dataset_root): for file in files: if file.lower().endswith((".jpg", ".png", ".bmp")): img_path = os.path.join(root, file) # 读取图像(OpenCV默认是BGR格式) img = cv2.imread(img_path) if img is None: print(f"跳过无效图像: {img_path}") continue # 计算当前图像的像素均值 b, g, r = cv2.mean(img)[:3] # 累加统计 pixel_count = img.shape[0] * img.shape[1] mean_b += b * pixel_count mean_g += g * pixel_count mean_r += r * pixel_count total_pixels += pixel_count # 计算全局均值 mean_b /= total_pixels mean_g /= total_pixels mean_r /= total_pixels # 生成CNTK格式的XML root = Element("opencv_storage") mean_elem = SubElement(root, "mean") SubElement(mean_elem, "channels").text = "3" SubElement(mean_elem, "height").text = str(img.shape[0]) # 假设所有图像尺寸一致,若不一致可以统一resize后再计算 SubElement(mean_elem, "width").text = str(img.shape[1]) SubElement(mean_elem, "meanMat", type_id="opencv-matrix").text = f"{mean_b} {mean_g} {mean_r}" # 格式化XML并保存 xml_str = parseString(tostring(root)).toprettyxml() with open(output_mean, "w") as f: f.write(xml_str)
注意:如果你的图像尺寸不一致,建议先统一resize到相同尺寸再计算均值,否则生成的mean.xml可能无法正常使用。
3. 图像序列化(可选,提升训练速度)
如果你的数据集很大,直接用map.txt配合CNTKTextFormatReader读取可能速度较慢,这时可以把图像序列化成CNTK的二进制格式(.cntk)。不过更简单的方式是在训练脚本中直接使用map.txt,通过ImageDeserializer来加载,示例代码片段:
from cntk.io import MinibatchSource, ImageDeserializer, StreamDef, StreamDefs # 定义输入流(根据你的图像尺寸调整shape参数) image_stream = StreamDef(field='image', shape=(3, 224, 224), is_sparse=False) label_stream = StreamDef(field='label', shape=1, is_sparse=False) # 创建MinibatchSource minibatch_source = MinibatchSource( ImageDeserializer(map_file="./map.txt", streams=StreamDefs(image=image_stream, label=label_stream)), randomize=True, max_samples=10000)
这样CNTK会自动读取图像并处理,不需要提前序列化,适合大多数场景。
内容的提问来源于stack exchange,提问作者Mordred
相关产品推荐
相关产品推荐

