from_tensor_slices()适用于小规模内存数据(如NumPy数组),按第一维切片并配对特征与标签;不适用于大文件或流式数据,否则易OOM。

GPU 等着数据,不是模型等着收敛——tf.data 管道调不好,90% 的训练时间都花在空转上。
tf.data.Dataset.from_tensor_slices() 适合什么场景
只适用于小数据集(比如 numpy 数组能一次性全塞进内存),例如 MNIST、Iris 或调试用的 toy 数据。它把第一维当样本维度切片,自动配对特征和标签:
import tensorflow as tf import numpy as np <p>x = np.random.rand(1000, 224, 224, 3).astype(np.float32) y = np.random.randint(0, 10, (1000,))</p><p>dataset = tf.data.Dataset.from_tensor_slices((x, y)) # 每次 yield (x[i], y[i])</p>
别用它读大文件或流式数据:会直接 OOM。也不要用它加载 TFRecord 或图像路径列表——那是 TFRecordDataset 和 list_files 的活。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
map() 不加 num_parallel_calls 就是单线程堵点
图像解码、归一化、随机裁剪这些操作默认串行执行,哪怕你有 32 核 CPU,map() 也只占 1 个核,GPU 显存利用率常掉到 30% 以下。
- 必须显式设
num_parallel_calls=tf.data.AUTOTUNE(推荐,跨环境自适应) - 手动控制时,设
num_parallel_calls=4或略高于物理核心数;超过 8 通常无收益,还可能因线程竞争反拖慢 - 函数体内不能含
cv2.VideoCapture、全局变量、print()、tf.py_function—— 后者会退回到 Python GIL,性能断崖下跌
shuffle(buffer_size) 设太小或太大都出问题
shuffle() 不是真打乱整个数据集,而是维护一个大小为 buffer_size 的滑动缓冲池:每次从中随机取一个样本,再用新样本补位。
- 训练集 8 万样本,
buffer_size=1000→ 前 1000 个样本高频出现,后期样本几乎不会进入前几个 epoch,loss 抖动剧烈 -
buffer_size=len(dataset)→ TFRecord 流式读取时根本不知道总长,强行估算易 OOM;即使能算准,也极易挤占系统内存 - 经验起点:
buffer_size=10000;已知总量时,设为样本数的 1–3 倍(如 8 万 →buffer_size=240000) - 必须在
repeat()之前调用shuffle(),否则每个 epoch 都从同一顺序开始,shuffle 形同虚设
prefetch(tf.data.AUTOTUNE) 必须放在 pipeline 最末端
prefetch() 的作用是让“数据预处理”和“GPU 训练 step”重叠执行,但它只对后续操作生效——放错位置等于没开。
- 正确顺序:
dataset.map(...).shuffle(...).batch(...).prefetch(tf.data.AUTOTUNE) - 错误写法:
dataset.prefetch(...).map(...).batch(...)→ 此时 prefetch 的是原始字节流,还没解码,毫无意义 - 别写
prefetch(1)或prefetch(2):硬编码值在不同 GPU 显存、batch_size、CPU 核心数下极易失配 - 即使用了
tf.distribute.MirroredStrategy,AUTOTUNE依然有效,无需额外修改
最容易被忽略的一点:如果你的数据管道里混用了 cache(),它只能用于小数据集,且必须放在 shuffle() 前——放错位置反而增加内存压力,尤其在 TFRecord 场景下。

















