共计 2859 个字符,预计需要花费 8 分钟才能阅读完成。
背景痛点
CelebA(CelebFaces Attributes Dataset)是人脸识别领域的经典数据集,包含超过 20 万张名人脸部图像,每张图像有 40 个属性标注。但在实际使用中,开发者常遇到以下问题:

- 下载速度慢:官方源位于国外,国内直连下载速度经常只有几十 KB/s
- 文件校验失败:压缩包损坏导致需要重新下载数十 GB 数据
- 目录结构混乱:原始 zip 包内嵌套多层目录,需手动整理
- 预处理效率低:直接加载数万张 JPEG 图像会导致 IO 瓶颈
技术方案对比
下载渠道选择
- 官方源(香港中文大学)
- 优点:数据最完整,更新及时
-
缺点:国内访问速度极不稳定(实测约 50-300KB/s)
-
国内镜像源(OpenDataLab 等)
- 优点:下载速度可达 10MB/ s 以上
- 缺点:可能存在版本滞后(延迟 1 - 2 个版本)
下载工具性能测试
使用不同工具下载 1.4GB 的img_align_celeba.zip:
- 单线程 wget:平均耗时 45 分钟
- aria2c(16 线程):平均耗时 3 分钟
- IDM(32 线程):平均耗时 2 分 15 秒
核心实现
带校验的下载脚本
import hashlib
import os
from pathlib import Path
import requests
from tqdm import tqdm
def download_file(url: str, target_path: Path, md5: str = None) -> bool:
"""下载文件并验证 MD5"""
try:
resp = requests.get(url, stream=True)
total_size = int(resp.headers.get('content-length', 0))
with open(target_path, 'wb') as f, tqdm(
desc=target_path.name,
total=total_size,
unit='iB',
unit_scale=True
) as bar:
for chunk in resp.iter_content(chunk_size=1024):
size = f.write(chunk)
bar.update(size)
if md5:
file_md5 = hashlib.md5(open(target_path, 'rb').read()).hexdigest()
if file_md5 != md5:
target_path.unlink()
raise ValueError(f'MD5 mismatch: {file_md5} != {md5}')
return True
except Exception as e:
print(f"Download failed: {e}")
if target_path.exists():
target_path.unlink()
return False
# 使用示例
if __name__ == "__main__":
file_info = {
"url": "https://example.com/img_align_celeba.zip",
"path": Path("./data/img_align_celeba.zip"),
"md5": "321d0a30b5e3a79b8d2f765a8ed5e8ba" # 示例 MD5
}
download_file(**file_info)
人脸 ROI 裁剪
import cv2
import numpy as np
from pathlib import Path
def detect_and_crop_face(
image_path: Path,
output_path: Path,
target_size: tuple = (178, 218)
) -> bool:
"""使用 OpenCV 进行人脸检测和裁剪"""
try:
img = cv2.imread(str(image_path))
if img is None:
return False
# CelebA 已经对齐,直接使用固定坐标
# 坐标来自官方标注的 landmark[0]
y1, x1 = 45, 25
y2, x2 = y1 + target_size[1], x1 + target_size[0]
cropped = img[y1:y2, x1:x2]
if cropped.size == 0:
return False
cv2.imwrite(str(output_path), cropped)
return True
except Exception as e:
print(f"Error processing {image_path.name}: {e}")
return False
性能优化
文件格式转换
原生 JPEG 加载的 IO 开销较大,建议转换格式:
- HDF5 格式
- 优点:支持随机访问,适合小规模数据
-
缺点:不支持并行写入
-
TFRecord 格式
- 优点:TensorFlow 原生支持,适合分布式训练
- 缺点:需要额外序列化 / 反序列化
多进程预处理
from multiprocessing import Pool
from functools import partial
def process_images_parallel(
input_dir: Path,
output_dir: Path,
workers: int = 8
):
"""多进程处理图像"""
output_dir.mkdir(exist_ok=True)
image_paths = list(input_dir.glob("*.jpg"))
with Pool(workers) as pool:
processor = partial(detect_and_crop_face, output_dir=output_dir)
results = pool.map(processor, image_paths)
print(f"Success rate: {sum(results)/len(results):.2%}")
避坑指南
标注文件编码问题
原始 list_attr_celeba.txt 使用 UTF- 8 编码但有 BOM 头,建议处理方式:
with open('list_attr_celeba.txt', 'r', encoding='utf-8-sig') as f:
header = f.readline() # 跳过第一行
内存优化技巧
当内存不足时,可采用分块加载:
import pandas as pd
# 分块读取标注文件
chunk_iter = pd.read_csv(
'list_attr_celeba.txt',
delim_whitespace=True,
skiprows=1,
chunksize=10000
)
for chunk in chunk_iter:
process_chunk(chunk) # 自定义处理函数
结语
经过以上优化,我们成功将 CelebA 数据集的下载时间从小时级缩短到分钟级,预处理效率提升 5 - 8 倍。在实际项目中,建议根据硬件条件调整并行度,对于 SSD 存储可以适当增加工作进程数。
如果你有其他预处理优化技巧,欢迎在评论区分享你的实践经验。特别是关于:
– 分布式环境下的数据加载优化
– 自定义数据增强管道的实现
– 超大规模数据集的内存管理技巧
期待看到更多创意解决方案!
正文完
发表至: 未分类
近两天内
