Hi, I’ve just started learning to hailo model zoo.
Now, I stucked one problem.
I made a model based on yolov8s by retraining with docker, and tried to evaluate it.
I’ll show commands that I excuted below.
What I did is shown below.
- made tfrecord from my own datasets based on yolo format.
- excuted command hailomz eval --har --target emulator --data-path
- I got this logs
Processed: 536images [00:35, 15.09images/s]
creating index...
index created!
Loading and preparing results...
Converting ndarray to lists...
(53600, 7)
0/53600
DONE (t=0.07s)
creating index...
index created!
Running per image evaluation...
Evaluate annotation type *bbox*
DONE (t=0.02s).
Accumulating evaluation results...
Please run evaluate() first
DONE (t=0.00s).
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = -1.000
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = -1.000
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = -1.000
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.000
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = -1.000
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = -1.000
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = -1.000
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = -1.000
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = -1.000
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = -1.000
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = -1.000
<Hailo Model Zoo INFO> Done 536 images AP=-100.000 AP50=-100.000
I think it cause parsing tfrecord or setting yaml.
parse tfrecord script
yolo to coco
#!/usr/bin/env python
import argparse
import json
import os
from pathlib import Path
from PIL import Image
def yolo_to_coco(img_dir, label_dir, output_json, class_names):
image_id = 0
annotation_id = 0
images = []
annotations = []
categories = []
# カテゴリ定義
for i, name in enumerate(class_names):
categories.append({
"id": i,
"name": name,
"supercategory": "object"
})
for img_file in sorted(Path(img_dir).glob("*.[jp][pn]g")):
label_file = Path(label_dir) / (img_file.stem + ".txt")
if not label_file.exists():
continue
with Image.open(img_file) as img:
width, height = img.size
images.append({
"id": image_id,
"file_name": img_file.name,
"width": width,
"height": height
})
with open(label_file, "r") as f:
for line in f:
parts = line.strip().split()
if len(parts) != 5:
continue
class_id, x_center, y_center, w, h = map(float, parts)
bbox_width = w * width
bbox_height = h * height
x = (x_center * width) - bbox_width / 2
y = (y_center * height) - bbox_height / 2
annotations.append({
"id": annotation_id,
"image_id": image_id,
"category_id": int(class_id),
"bbox": [x, y, bbox_width, bbox_height],
"area": bbox_width * bbox_height,
"iscrowd": 0
})
annotation_id += 1
image_id += 1
coco_format = {
"images": images,
"annotations": annotations,
"categories": categories
}
with open(output_json, "w") as f:
json.dump(coco_format, f, indent=2)
print(f"Converted {image_id} images and {annotation_id} annotations to COCO format.")
print(f"Output saved to: {output_json}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Convert YOLO annotations to COCO format.")
parser.add_argument("--img", required=True, help="Path to directory with images")
parser.add_argument("--label", required=True, help="Path to directory with YOLO .txt annotations")
parser.add_argument("--output", default="output.json", help="Output COCO JSON file")
parser.add_argument("--names", required=True, help="Path to .names file (one class per line)")
args = parser.parse_args()
with open(args.names, "r") as f:
class_names = [line.strip() for line in f if line.strip()]
yolo_to_coco(args.img, args.label, args.output, class_names)
coco to tfrecord
#!/usr/bin/env python
import argparse
import collections
import json
import os
import random
from pathlib import Path
import numpy as np
import tensorflow as tf
from PIL import Image
from tqdm import tqdm
# TFRecord feature helpers
def _int64_feature(values):
if not isinstance(values, (tuple, list)):
values = [values]
return tf.train.Feature(int64_list=tf.train.Int64List(value=values))
def _bytes_feature(value):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def _float_list_feature(value):
return tf.train.Feature(float_list=tf.train.FloatList(value=value))
def _create_tfrecord(img_label_pairs, imgs_name2id, tfrecord_path, name):
with tf.io.TFRecordWriter(str(tfrecord_path)) as writer:
progress_bar = tqdm(img_label_pairs, desc=f"Creating {name}")
for i, (img_path, annotations) in enumerate(progress_bar):
progress_bar.set_description(f"{name} #{i+1}: {img_path}")
# Load image
with open(img_path, "rb") as f:
img_jpeg = f.read()
img = np.array(Image.open(img_path))
height, width = img.shape[:2]
# Bounding box info
xmin, xmax, ymin, ymax = [], [], [], []
category_id, is_crowd, area = [], [], []
for ann in annotations:
x, y, w, h = ann["bbox"]
if w <= 0 or h <= 0 or x + w > width or y + h > height:
continue
xmin.append(x / width)
xmax.append((x + w) / width)
ymin.append(y / height)
ymax.append((y + h) / height)
category_id.append(int(ann["category_id"]))
is_crowd.append(ann["iscrowd"])
area.append(ann["area"])
img_id = ann["image_id"] if annotations else imgs_name2id[os.path.basename(img_path)]
example = tf.train.Example(features=tf.train.Features(feature={
"height": _int64_feature(height),
"width": _int64_feature(width),
"num_boxes": _int64_feature(len(annotations)),
"image_id": _int64_feature(img_id),
"xmin": _float_list_feature(xmin),
"xmax": _float_list_feature(xmax),
"ymin": _float_list_feature(ymin),
"ymax": _float_list_feature(ymax),
"area": _float_list_feature(area),
"category_id": _int64_feature(category_id),
"is_crowd": _int64_feature(is_crowd),
"image_name": _bytes_feature(os.path.basename(img_path).encode()),
"image_jpeg": _bytes_feature(img_jpeg),
}))
writer.write(example.SerializeToString())
return i + 1
def get_img_labels_list(dataset_dir, annotation_file):
with tf.io.gfile.GFile(str(annotation_file), "r") as fid:
annotations = json.load(fid)
imgs_name2id = {img["file_name"]: img["id"] for img in annotations["images"]}
img_to_annotations = collections.defaultdict(list)
for ann in annotations["annotations"]:
img_name = f'{ann["image_id"]:012d}.jpg'
img_to_annotations[img_name].append(ann)
no_anns_count = 0
img_label_pairs = []
for img_file in sorted(dataset_dir.iterdir()):
img_name = img_file.name
anns = img_to_annotations.get(img_name, [])
if not anns:
no_anns_count += 1
img_label_pairs.append((str(img_file), anns))
print(f"{no_anns_count} / {len(img_label_pairs)} images have no annotations")
random.seed(0)
random.shuffle(img_label_pairs)
return img_label_pairs, imgs_name2id
def run(img_dir, annotation_path):
if not img_dir or not annotation_path:
if img_dir or annotation_path:
raise ValueError("Both --img and --det must be specified together.")
else:
raise ValueError("Please specify --img and --det arguments.")
dataset_dir = Path(img_dir)
annotation_file = Path(annotation_path)
img_label_pairs, imgs_name2id = get_img_labels_list(dataset_dir, annotation_file)
tfrecord_output_path = dataset_dir.parent / "output.tfrecord"
num_images = _create_tfrecord(img_label_pairs, imgs_name2id, tfrecord_output_path, "TFRecord")
print(f"\nDone converting {num_images} images. Output saved to: {tfrecord_output_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Convert image and annotation dataset to TFRecord.")
parser.add_argument("--img", "-img", help="Path to image directory", type=str, required=True)
parser.add_argument("--det", "-det", help="Path to COCO-format annotation JSON", type=str, required=True)
args = parser.parse_args()
run(args.img, args.det)
yaml
base:
- base/yolov8.yaml
postprocessing:
device_pre_post_layers:
nms: true
hpp: true
network:
network_name: yolov8s
paths:
network_path:
- /local/workspace/hailo/2025-04/shared_with_docker/20250428_yolov8s/weights/20250428_yolov8s.onnx
alls_script: yolov8s.alls