我正在寻找一种拆分对象检测数据(内部带有标记对象的图像)的智能方法,同时考虑对象本身的分布而不仅仅是图像。
我有一个由许多图像组成的数据集。这些图像中的每一个内部都有一个或多个对象,这些对象被标记。为了训练对象检测模型,我需要执行传统的训练/评估拆分(在这种情况下,我不需要测试集)。但是,对于每组中应该包含哪些标签,我有非常具体的要求。
具体来说,我想确保每个标签的最小样本量最终出现在训练和评估集中。例如,如果我知道我只有 5 辆汽车样本,我想确保这些汽车中至少有 3 辆在火车集中。因此,图像的简单随机分割(例如 80/20)并不理想,因为它没有考虑每个图像中的对象,因此无法强制执行我的约束。例如,如果只有两张图片有汽车,一张有三辆,一张有两辆,没有什么能阻止这两张图片出现在火车集合中,因此我可能没有任何汽车可供评估!
自然,这些约束可能是不可能实现的(如果所有汽车都是单一图像,那么 train 和 eval 中就不可能有汽车),这是算法应该管理的。(即尽可能给出符合要求的最佳解决方案)。
其他一些并发症:
- 每个图像可以有任意数量的对象属于任意数量的标签,因此将图像添加到任一集合都会影响它包含的所有标签的分布。
- 作为前一点的结果,在一组中强制执行一个约束可能会使另一组中的另一个无效(对于相同的标签,甚至对于不同的标签)。
你以前遇到过这个问题吗?有什么建议?
如果需要更多详细信息,请告诉我,我会相应地更新帖子。提前致谢。
编辑 1:添加整数编程方法状态
这是 Python 中当前整数解决方案的一个工作示例,使用cvxpy:
需要的库:
import numpy as np
import cvxpy
示例数据:
# rows -> classes, columns -> images
L = np.array([[2, 0, 0, 0, 3, 0, 8, 0, 0],
[0, 3, 0, 2, 0, 0, 0, 8, 0],
[0, 0, 2, 0, 0, 3, 0, 0, 8]])
big_L = np.vstack((np.hstack((L, np.zeros_like(L))),
np.hstack((np.zeros_like(L), L))))
# minimum examples per class for each set
left_min = [2, 2, 2]
right_min = [2, 2, 2]
# maximum examples per class for each set
left_max = [9, 9, 9]
right_max = [2, 2, 2]
# number of frames and classes
nc, n = L.shape
定义约束所需的一些变量:
w = np.hstack((np.array(left_min), np.array(right_min))).T
max_w = np.hstack((np.array(left_max), np.array(right_max))).T
s = cvxpy.Variable(2*n, boolean=True)
big_s = np.vstack((np.hstack((np.zeros((n, n)), np.eye(n))),
np.hstack((np.eye(n), np.zeros((n, n))))))
约束:
# constraints
# only one frame can be selected for each set
output_constraint_0 = (big_s @ s) + s <= np.ones((2*n))
# only one frame can be selected for each set
output_constraint_01 = (big_s @ s) + s >= np.zeros((2*n))
# all frames must be selected for either set
output_constraint_1 = cvxpy.sum(s) == cvxpy.Variable(n, integer=True)
# result vector must be binary, only zeros or ones (and in between?)
output_constraint_2 = np.eye(2*n) @ s <= np.ones(2*n)
output_constraint_3 = - np.eye(2*n) @ s <= np.zeros(2*n)
# sets have at least required quantities of examples per class
output_constraint_4 = big_L @ s - w >= np.zeros((2*nc))
# check that train has required (for now, we ignore eval numbers)
output_constraint_5 = big_L @ s - max_w >= np.zeros((2*nc))
constraints = [output_constraint_0, output_constraint_01,
output_constraint_1, output_constraint_2,
output_constraint_3, output_constraint_4,
output_constraint_5]
# Objective function
objective = cvxpy.norm((big_s @ s) + s - np.ones((2*n)))
定义问题并解决:
split_problem = cvxpy.Problem(cvxpy.Minimize(objective), constraints)
split_problem.solve()
获取每个集合的图像索引并断言结果符合预期:
result = s.value.reshape((2, n))
l = np.array([int(x) for x in np.round(s.value[:n])], dtype=np.int)
r = np.array([int(x) for x in np.round(s.value[n:])], dtype=np.int)
assert all(L @ l >= left_min) and all(L @ l >= left_max)
assert all(L @ r >= right_min) and all(L @ r >= right_max)
虽然此解决方案适用于简单的案例,例如上面展示的示例数据集,但它不适用于具有更复杂类分布的真实数据集。问题主要在于不可行的“最大示例数”约束,可以通过迭代不同的训练/评估分数(例如 0.2、0.3、0.4,...)并解决每个问题来解决,最终可以达到一个解决方案(在最坏的情况下,eval 分数将为 1)。在这里,我们假设如果 eval_fraction 为 x 时问题不可行,则存在一个大于 x 的 eval_fraction y,可以使问题可解决。
另一个复杂因素是我们正在使用的当前求解器,即“ECOS_BB”(更多信息here和here),对于大型数据集来说太慢了,这使得它在实际使用中完全不切实际。此外,cvxpy 仅使用单个 CPU 内核,这意味着缺乏处理速度。
因此,下一步是找到一个合适的解决方案,该解决方案可以在合理的时间内利用所有可用的硬件来处理大型、非常异构的数据集。