【发布时间】: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] 在每张图像上,同样的问题。
-
我尝试调试日志记录,但它只打印迭代/损失。
- 有什么我缺少的想法吗?
- 我可以在某处调试它吗?我不确定标签在 API 中的哪个位置加载。
【问题讨论】:
-
我已经阅读了创建
tf_example的函数,我也找不到任何问题,但我相信问题存在于 tfrecrod 文件中,因为您尝试了其他 tfrecord 并且工作正常。这是提取地面实况框以进行可视化的链接。 github.com/tensorflow/models/blob/…。在同一个函数中,它会调用 vis_utils.VisualizeSingleFrameDetections,然后绘制两个子图像,左边是检测,右边是 groundtruth 框。 -
经过大量的摆弄(在我的数据集和宠物之间交换图像、交换标签等)后,我的课程文本字段中出现了流氓换行符。
标签: python tensorflow