如何使用tensorflow获得每个类具有相同数量图像的验证集



我现在使用CIFAR-100数据集来训练模型。我想使用10%的列车数据作为验证数据。我一开始使用了下面的代码。

(train_images, train_labels), (test_images, test_labels) = datasets.cifar100.load_data()
train_images, val_images, train_labels, val_labels = train_test_split(train_images, train_labels, test_size=0.1)
train_db = tf.data.Dataset.from_tensor_slices((train_images, train_labels))
train_db = train_db.map(train_prep).shuffle(5000).repeat().batch(128).prefetch(-1)
val_db = tf.data.Dataset.from_tensor_slices((val_images, val_labels))
val_db = val_db.map(valid_prep).batch(512).prefetch(-1)

它在某些型号中效果良好。但在其他一些模型中,验证精度可能远高于测试精度。我认为原因可能是使用train_test_split不能保证验证集每个类都有相同数量的图像。所以我尝试"手动"获取验证集。我的代码如下所示。

(train_images, train_labels), (test_images, test_labels) = datasets.cifar100.load_data()
def get_index(y):
index = [[] for i in range(100)]
for i in range(len(y)):
for j in range(100):
if y[i][0] == j:
index[j].append(i)
return index
index = get_index(train_labels)
index_train = []
index_val = []
for i in range(100):
index1, index2 = train_test_split(index[i], test_size=0.1)
index_train.extend(index1)
index_val.extend(index2)
val_images = train_images[index_val]
train_images_1 = train_images[index_train]
val_labels = train_labels[index_val]
train_labels_1 = train_labels[index_train]
train_db = tf.data.Dataset.from_tensor_slices((train_images_1, train_labels_1))
train_db = train_db.map(train_prep).shuffle(5000).repeat().batch(128).prefetch(-1)
val_db = tf.data.Dataset.from_tensor_slices((val_images, val_labels))
val_db = val_db.map(valid_prep).batch(512).prefetch(-1)

但当我使用这个训练集和验证集来训练我的模型时,准确性相当低。因此,这种分裂方法一定存在一些问题。但我不知道问题出在哪里。如果有人能帮我解决这个问题,我将不胜感激。

train_testrongplit有一个名为layery的参数,它可能会对您有所帮助。在下面的示例中,假设数据帧df具有2列。其中一个称为文件路径,其中列的每一行都包含图像文件的完整路径。第二列称为标签。列中的每一行都包含标识该行中图像的类别的文本;狗;或";猫";。假设80%的图像是猫的,20%是狗的。分割数据集时,可以确保分割完成,从而使生成的数据帧分别具有80%的猫图像和20%的狗图像。代码是

train_split=.8 # % of images to use for training
validation_split=.1 # % of images to use for validation
dsplit=validation_split/(1-train_split)
train_ds, dummy_df=train_test_split(df, train_size=train_split, shuffle=True, random_state=123, stratify=df['labels'])
valid_df, test_df=train_test_split(dummy_df, train_size=dsplit, shuffle=True, random_state=123, stratify=df['labels'])

结果得到三个数据集traindf、testdf和validdf。每个数据集将具有与原始数据帧df相同的cat和dog类标签比例。现在,为了获得一个平衡的数据集,其中50%的标签是猫的,50%的标签也是狗的,你需要进行欠采样、图像增强或两者结合。

我也遇到了类似的问题。我想为每个类平均分配数据,但要保持输入中数据的顺序。换句话说:所以我做了一个函数来做这件事。
请注意,数据在拆分之前不是shuffle,而是在拆分之后。

def unison_shuffled_copies(a, b):
assert len(a) == len(b)
p = np.random.permutation(len(a))
return a[p], b[p]
def split_dataset(X, y, size=0.5, shuffle_a = True):
ax = []
bx = []
ay = []
by = []
# Iterate over the labels
for label in np.unique(y):
count = 0
# Calculate the maximum number of values to include
max_count = len(y[y == label]) * size
for i in range(0,len(y)):
if y[i] == label: # Make sure we treat only a specific label
if (count < max_count):
ax.append(X[i])
ay.append(y[i])
else:
bx.append(X[i])
by.append(y[i])
count += 1

if shuffle_a:
ax, ay = unison_shuffled_copies(np.array(ax), np.array(ay))
else:
ax, ay = (np.array(ax), np.array(ay))
bx, by = unison_shuffled_copies(np.array(bx), np.array(by))
return ax, bx, ay, by

如果你不想要一个比例,而是一个特定的数字,那么你可以直接替换:

max_count = len(y[y == label]) * size

通过

max_count = size

或者添加max_count参数。

注意,与tensorflow函数相比,大小百分比是相反的,它表示A的大小,而不是B的大小。

免责声明

有更好的方法可以实现此拆分功能。如果您复制它,那么就让它用于测试目的或具有很少类别的数据集。如果您想提高性能,请创建以标签为键、计数和最大计数值的dict,而不是每个标签运行一次循环,然后只运行一次。

最新更新