You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何构建多类别边界框回归的TensorFlow数据集输入管道

问题根因

你遇到的ValueError: y argument is not supported when using dataset as input核心原因是:当model.fit接收tf.data.Dataset类型输入时,框架不支持将输入样本、标签拆分为多个独立Dataset分别传入,必须把图像、类别标签、边界框打包为单个Dataset对象,每个迭代元素符合(单样本张量, 标签字典/元组)的结构。
除此之外你现有代码还存在几个会引发后续报错的问题:

  • DICOM读取返回类型错误,读取后的图像数组不应返回tf.string类型
  • 标签编码器在build_dataset内单独拟合,会导致训练/测试集类别编码规则不一致
  • 边界框未做归一化处理,不同尺寸原图的坐标值范围差异会导致模型回归难以收敛
  • 140GB规模的数据集必须采用流式读取逻辑,所有IO、预处理操作要放在Dataset pipeline中按需执行,不能提前加载全量数据到内存

正确实现方案

前置依赖与工具函数

首先全局初始化标签编码器(避免训练/测试集编码不一致),实现DICOM读取、边界框解析的工具函数:

import tensorflow as tf
import pydicom
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split

# 全局拟合标签编码器,必须传入全量数据集的类别字段,不要在build_dataset内单独拟合
lb = LabelBinarizer()
lb.fit(df["Class"].unique())
NUM_CLASSES = len(lb.classes_)
# 统一模型输入图像尺寸,根据你自己的模型要求调整
TARGET_IMG_SIZE = (256, 256)

def read_dcm_as_array(path):
    """读取单张DICOM文件,返回归一化、resize后的float32格式数组"""
    path = path.numpy().decode("utf-8")
    dcm = pydicom.dcmread(path)
    img = dcm.pixel_array.astype(np.float32)
    # 像素值归一化到0-1区间
    img = (img - img.min()) / (img.max() - img.min() + 1e-8)
    # 灰度图增加单通道维度
    img = np.expand_dims(img, axis=-1)
    # resize到模型要求的统一输入尺寸
    img = tf.image.resize(img, TARGET_IMG_SIZE)
    return img

def parse_bbox(bbox_str, orig_h, orig_w):
    """解析边界框字符串,坐标归一化到0-1区间,输出格式为[xmin, ymin, xmax, ymax]"""
    coords = list(map(int, bbox_str.replace(",", "-").split("-")))
    xmin, ymin, xmax, ymax = coords
    # 按原图尺寸做坐标归一化,消除不同图像尺寸差异
    xmin = xmin / orig_w
    ymin = ymin / orig_h
    xmax = xmax / orig_w
    ymax = ymax / orig_h
    return np.array([xmin, ymin, xmax, ymax], dtype=np.float32)

实现build_dataset管道函数

所有预处理逻辑放在map流程中流式执行,最终返回单个结构化Dataset对象,直接适配model.fit输入要求:

def build_dataset(dataframe, batch_size=32, shuffle=False, cache=False):
    # 仅将元数据转为张量切片,不加载实际图像数据
    ds = tf.data.Dataset.from_tensor_slices({
        "filepath": dataframe["FilePath"].values,
        "class_name": dataframe["Class"].values,
        "bbox_str": dataframe["BBox"].values,
        "orig_h": dataframe["ImageHeight"].values,
        "orig_w": dataframe["ImageWidth"].values
    })

    def parse_sample(sample):
        """逐样本解析逻辑,训练时按需调用,不会全量加载到内存"""
        # 读取并预处理DICOM图像
        img = tf.py_function(
            func=read_dcm_as_array,
            inp=[sample["filepath"]],
            Tout=tf.float32
        )
        img.set_shape((*TARGET_IMG_SIZE, 1)) # 固定张量静态形状,避免形状未知报错

        # 编码类别标签
        class_label = tf.py_function(
            func=lambda x: lb.transform([x.numpy().decode("utf-8")])[0],
            inp=[sample["class_name"]],
            Tout=tf.float32
        )
        class_label.set_shape((NUM_CLASSES,))

        # 解析归一化边界框
        bbox = tf.py_function(
            func=parse_bbox,
            inp=[sample["bbox_str"], sample["orig_h"], sample["orig_w"]],
            Tout=tf.float32
        )
        bbox.set_shape((4,)) # 边界框固定4个坐标值

        # 返回格式直接适配model.fit输入要求:(输入样本, 标签字典)
        return img, {
            "class_label": class_label,
            "bounding_box": bbox
        }

    # 构建高性能数据管道
    ds = ds.map(parse_sample, num_parallel_calls=tf.data.AUTOTUNE)
    if shuffle:
        ds = ds.shuffle(buffer_size=1024) # 缓冲区大小根据剩余内存调整,不要设置过大
    if cache:
        ds = ds.cache() # 内存不足时不要开启,或传入磁盘路径做磁盘缓存
    ds = ds.batch(batch_size)
    ds = ds.prefetch(tf.data.AUTOTUNE) # 开启预取,让CPU预处理和GPU计算并行,消除数据等待瓶颈
    return ds

训练代码调整

不需要手动拆分图像、标签、边界框再拼接字典,直接使用build_dataset返回的Dataset即可:

# 拆分训练/测试集
train_df, test_df = train_test_split(df, test_size=0.2, random_state=42)

# 生成训练和验证数据集
train_ds = build_dataset(train_df, batch_size=32, shuffle=True)
test_ds = build_dataset(test_df, batch_size=32, shuffle=False)

# 直接传入模型训练
history = model.fit(
    train_ds,
    validation_data=test_ds,
    epochs=20
)

注意事项
  • 如果需要做DICOM窗宽窗位调整、数据增强等操作,直接在parse_sample函数中添加对应逻辑即可,不影响管道结构
  • 如果训练时出现GPU利用率低的情况,可以适当调大shuffle的缓冲区大小、开启缓存,进一步提升数据加载速度
  • 多分类任务如果是二分类场景,需要调整LabelBinarizer输出维度匹配模型最后一层的输出节点数

内容的提问来源于stack exchange,提问作者osbm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:51:32