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

如何为TensorFlow Datasets编写每类保留5张图的少样本过滤器?

问题:如何用tfds.Dataset.filter实现每类保留5张图像?

我尝试创建带计数属性的对象来跟踪各类样本数量,filter()能接收输入并执行代码,但无法正确统计各类样本数。代码示例如下:

import tensorflow_datasets as tfds

class few_shot_filter:
    def __init__(self):
        self.count = {}

    def filter(self, x):
        y = x["label"]
        if not y in self.count:
            self.count[y] = 0
        self.count[y] = self.count[y] + 1
        return self.count[y] <= 5

ds = tfds.load("cifar10", supervised=False)
fs_filter=few_shot_filter()
print([y["label"] for y in ds.filter(fs_filter.filter).as_numpy_iterator()])

有趣的是,传递对象并访问其属性本身似乎没有问题,如下方代码可正常运行:

import tensorflow_datasets as tfds

class class_filter:
    def __init__(self):
        self.target_class = 5

    def filter(self, x):
        y = x["label"]
        return y == self.target_class

ds = tfds.load("cifar10", supervised=False)
cl_filter=class_filter()
print([y["label"] for y in ds.filter(cl_filter.filter).as_numpy_iterator()])

是不是filter是并行执行的,类似数组索引的方式?


原因分析

没错,tf.data的操作默认是并行执行的(多线程读取/处理样本)。你的第一个示例中,每个工作线程都会复制few_shot_filter实例,每个线程拥有独立的self.count字典,导致计数被多份副本分散统计,最终结果错误。

而第二个示例中的target_class是固定值,不需要修改,每个线程的副本都能正确判断标签是否匹配,因此可以正常运行。

解决方案

推荐使用按标签分组后取前N个样本的方式,这种方法更可靠,避免并行计数的问题:

import tensorflow_datasets as tfds
from collections import Counter

# 加载cifar10训练集
ds = tfds.load("cifar10", split="train", supervised=False)

# 定义每组保留前5个样本的函数
def keep_top_n_samples(ds):
    return ds.take(5)

# 按标签分组,对每组应用保留函数
ds_few_shot = ds.group_by_window(
    key_func=lambda x: x["label"],  # 分组依据:样本标签
    reduce_func=lambda key, ds: keep_top_n_samples(ds),
    window_size=10000  # 窗口值设为大于每类样本数,确保覆盖所有同标签样本
)

# 验证结果
labels = [y["label"] for y in ds_few_shot.as_numpy_iterator()]
print(Counter(labels))  # 输出:Counter({0:5, 1:5, ..., 9:5})

备选方案:使用tf.Variable共享计数(不推荐,存在并行风险)

如果一定要用filter实现,可以用tf.Variable存储计数(图中共享变量),并通过原子操作更新计数,但仍可能因并行执行顺序问题导致结果偏差:

import tensorflow as tf
import tensorflow_datasets as tfds
from collections import Counter

class FewShotFilter:
    def __init__(self, num_classes=10):
        # 用tf.Variable存储每类计数,确保在图中共享
        self.count = tf.Variable(tf.zeros(num_classes, dtype=tf.int32))
    
    @tf.autograph.experimental.do_not_convert
    def filter_fn(self, x):
        label = x["label"]
        # 原子更新计数:获取当前值→加1→更新变量
        current_count = tf.gather(self.count, label)
        new_count = current_count + 1
        self.count.assign(tf.tensor_scatter_nd_update(
            self.count,
            indices=[[label]],
            updates=[new_count]
        ))
        return new_count <= 5

ds = tfds.load("cifar10", split="train", supervised=False)
fs_filter = FewShotFilter()
ds_few_shot = ds.filter(fs_filter.filter_fn)

# 验证
labels = [y["label"] for y in ds_few_shot.as_numpy_iterator()]
print(Counter(labels))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 21:33:17