【问题标题】:Tensorflow object detection API AvgNumGroundtruthBoxesPerImage is always zero (no ground truth labels shown)Tensorflow 对象检测 API AvgNumGroundtruthBoxesPerImage 始终为零(未显示地面实况标签)
【发布时间】:2020-05-27 13:01:13
【问题描述】:

根据标题 - 我可以使用对象检测 API 运行训练作业,但是当我查看损失曲线时,它太平滑了。在 1 个 epoch 后的 eval 阶段,ground truth 图像显示在 Tensorboard 中,但没有在其上绘制任何框。我的数据集中没有反例,所以所有图像都应该有标签。

我已经测试了 Oxford Pet 数据集并且效果很好(统计数据看起来不错,并且图像显示在 Tensorboard 中的方框中)。我将我的 TFRecords 与模型存储库提供的 Pet 脚本生成的 TFRecords 进行了比较,没有什么明显的。

我使用以下函数将一组图像和边界框转换为 TFRecords。它采用 Darknet/Yolo 格式标签(框中心 x/y、框宽、框高,以标准化单位表示)。所有图像都是 1 通道 PNG 文件 (640x512),所以我加载它们并将它们转换为 3 通道。

我不确定decode_png 是否会在您选择三个通道时自动执行此操作,但我不想冒险所以我先在 OpenCV 中进行转换。

def create_tf_example(path, names):
    """Creates a tf.Example proto from sample image

    Returns:
    example: The created tf.Example.
    """

    annotations = load_annotation(path)

    if annotations is None:
        return

    if len(annotations) == 0:
        return

    try:
        with tf.gfile.GFile(path, 'rb') as fid:
            image_data = fid.read()

        # Force conversion to 3 channel just to be sure
        image_cv = cv2.imdecode(np.fromstring(image_data, np.uint8), cv2.IMREAD_COLOR)
        res, image_data = cv2.imencode('.png', image_cv)

        image_data = image_data.tostring()

        image_tensor = tf.image.decode_png(
                image_data,
                channels=3,
                name=None
        )

    except:
        print("Failed: ", path)
        return

    classes_text = []
    classes = []
    xmins = []
    xmaxs = []
    ymins = []
    ymaxs = []

    height = 512
    width = 640

    for a in annotations:
        class_id, box_cx, box_cy, box_width, box_height = a

        class_id = int(class_id)

        if class_id < len(names):

            xmin = max(0, float(box_cx - 0.5*box_width))
            assert(xmin >= 0 and xmin <= 1)

            xmax = min(1, float(box_cx + 0.5*box_width))
            assert(xmax >= 0 and xmax <= 1)

            ymin = max(0, float(box_cy - 0.5*box_height))
            assert(ymin >= 0 and ymin <= 1)

            ymax = min(1, float(box_cy + 0.5*box_height))
            assert(ymax >= 0 and ymax <= 1)

            xmins.append(xmin)
            xmaxs.append(xmax)
            ymins.append(ymin)
            ymaxs.append(ymax)
            classes.append(class_id+1)
            classes_text.append(names[class_id].encode('utf8'))

    if len(classes) is None:
        print("Class out of range")
        return

    # Possible we've found annotations with invalid class IDs
    if len(xmins) == 0:
        return

    tf_example = tf.train.Example(features=tf.train.Features(feature={
      'image/height': int64_feature(height),
      'image/width': int64_feature(width),
      'image/filename': bytes_feature(os.path.basename(path).encode('utf8')),
      'image/source_id': bytes_feature(os.path.basename(path).encode('utf8')),
      'image/encoded': bytes_feature(image_data),
      'image/format': bytes_feature('png'.encode('utf8')),
      'image/object/bbox/xmin': float_list_feature(xmins),
      'image/object/bbox/xmax': float_list_feature(xmaxs),
      'image/object/bbox/ymin': float_list_feature(ymins),
      'image/object/bbox/ymax': float_list_feature(ymaxs),
      'image/object/class/text': bytes_list_feature(classes_text),
      'image/object/class/label': int64_list_feature(classes),
    }))

    return tf_example

Darknet 注释文件类似于(因此 class_id 获得 +1):

0 0.251252 0.35801225 0.36322 0.25812092

这是一个示例测试:

raw_image_dataset = tf.data.TFRecordDataset('/home/josh/data/data/test.record-00000-of-00010')

# Create a dictionary describing the features.  
image_feature_description = {
    'image/height': tf.FixedLenFeature([], tf.int64),
    'image/width': tf.FixedLenFeature([], tf.int64),
    'image/encoded': tf.FixedLenFeature([],tf.string),
    'image/object/bbox/xmax': tf.VarLenFeature(tf.float32),
    'image/object/bbox/xmin': tf.VarLenFeature(tf.float32),
    'image/object/bbox/ymin': tf.VarLenFeature(tf.float32),
    'image/object/bbox/ymax': tf.VarLenFeature(tf.float32),
    'image/object/class/text': tf.VarLenFeature(tf.string),
    'image/object/class/label': tf.VarLenFeature(tf.int64),
}

def _parse_image_function(example_proto):
  # Parse the input tf.Example proto using the dictionary above.
  return tf.parse_single_example(example_proto, image_feature_description)

parsed_image_dataset = raw_image_dataset.map(_parse_image_function)

for im in parsed_image_dataset:
    print(im['image/object/bbox/xmin'])
    print(im['image/object/bbox/xmax'])
    print(im['image/object/bbox/ymin'])
    print(im['image/object/bbox/ymax'])
    print(im['image/object/class/label'])
    break
SparseTensor(indices=tf.Tensor(
[[0]
 [1]], shape=(2, 1), dtype=int64), values=tf.Tensor([0.390625  0.4687505], shape=(2,), dtype=float32), dense_shape=tf.Tensor([2], shape=(1,), dtype=int64))
SparseTensor(indices=tf.Tensor(
[[0]
 [1]], shape=(2, 1), dtype=int64), values=tf.Tensor([0.446875  0.5093755], shape=(2,), dtype=float32), dense_shape=tf.Tensor([2], shape=(1,), dtype=int64))
SparseTensor(indices=tf.Tensor(
[[0]
 [1]], shape=(2, 1), dtype=int64), values=tf.Tensor([0.3923828 0.4685552], shape=(2,), dtype=float32), dense_shape=tf.Tensor([2], shape=(1,), dtype=int64))
SparseTensor(indices=tf.Tensor(
[[0]
 [1]], shape=(2, 1), dtype=int64), values=tf.Tensor([0.4451172 0.5095708], shape=(2,), dtype=float32), dense_shape=tf.Tensor([2], shape=(1,), dtype=int64))
SparseTensor(indices=tf.Tensor(
[[0]
 [1]], shape=(2, 1), dtype=int64), values=tf.Tensor([1 1], shape=(2,), dtype=int64), dense_shape=tf.Tensor([2], shape=(1,), dtype=int64))

  • stdout/err 中的错误为零,因此无论发生什么,它都是无声的。
  • 图像(我假设)加载正确,否则整个事情会失败(?)
  • 我已将框固定为非零且
  • 很确定我尝试蛮力将边界框设置为例如[0.1, 0.2, 0.3, 0.4] 在每张图像上,同样的问题。
  • 我尝试调试日志记录,但它只打印迭代/损失。

    1. 有什么我缺少的想法吗?
    2. 我可以在某处调试它吗?我不确定标签在 API 中的哪个位置加载。

【问题讨论】:

  • 我已经阅读了创建tf_example 的函数,我也找不到任何问题,但我相信问题存在于 tfrecrod 文件中,因为您尝试了其他 tfrecord 并且工作正常。这是提取地面实况框以进行可视化的链接。 github.com/tensorflow/models/blob/…。在同一个函数中,它会调用 vis_utils.VisualizeSingleFrameDetections,然后绘制两个子图像,左边是检测,右边是 groundtruth 框。
  • 经过大量的摆弄(在我的数据集和宠物之间交换图像、交换标签等)后,我的课程文本字段中出现了流氓换行符。

标签: python tensorflow


【解决方案1】:

原来我在每个 TFRecord 中的类标签最后都有一个换行符。这比我愿意承认的要付出更多的努力!

我有一个正在读取的 .names 文件,例如

cat
dog
horse

除了不是那个,是:

cat\n
dog\n
horse\n

当我使用f.readlines() 打开我的名称文件以获取类标签时,我无意中将换行符存储在记录中。现在,Tensorflow 实际上不应该使用那个文本标签。它有一个标签映射文件并使用模型中的类 ID。我怀疑正在发生的事情是用于解析 TFRecord 的任何内容都遇到了 class/text 字段中的换行符,然后完全忽略了标签。

强烈建议任何这样做的人使用类似的东西:

classes_text.append(names[class_id].rstrip().encode('utf8'))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 2019-02-24
    • 2017-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多