FiftyOne은 컴퓨터 비전 분야의 데이터셋을 효과적으로 관리하고 분석할 수 있도록 돕는 오픈소스 툴이다.
해당 툴을 사용하면 이미지 및 비디오 기반 데이터셋을 시각화하고 모델 예측 결과를 평가하며 잘못된 라벨을 쉽게 탐지할 수 있다.
1. FiftyOne 설치
- fiftyOne 설치
apt install libcurl4 openssl
apt install libcurl4-openssl-dev
pip install fiftyone
pip install fiftyone-db-ubuntu2204
- quickstart
import fiftyone as fo
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart")
print(dataset)
sample = dataset.first()
print(sample.predictions.detections[0])
session = fo.launch_app(dataset)
session.show()
-> 주피터 노트북에서는 iframe이 뜨지 않아 port 번호를 연결해 web ui를 띄워야 한다.
-> fiftyone은 default port로 5151을 사용 중이다.
print(session.url)
-> localhost:5151 로 출력 될 것이다.
-> 해당 url을 접속하거나 컨테이너 생성 시 5151로 포트 포워딩을 해 주면 컨테이너 생성한 서버 ip:5151로 web ui가 뜨게 된다.

2. 주요 기능
1) 다양한 데이터셋 포맷 지원
COCO, YOLO, Pascal VOC, ImageDirectory, VideoDirectory 등 다양한 포맷의 데이터셋을 fo.Dataset.from_dir() 한 줄로 쉽게 로드 가능하다.
import fiftyone as fo
import fiftyone.utils.yolo as fouy
# A name for the dataset
name = "test"
# The directory containing the dataset to import
dataset_dir = "/workspace/DATA/yolo_dataset/"
dataset = fo.Dataset.from_dir(
dataset_type=fo.types.YOLOv5Dataset, # YOLOv8도 YOLOv5 포맷과 동일함
dataset_dir=dataset_dir,
split="test", # 또는 "val", "test" 등 사용 가능
label_field="gt", # 라벨 필드 이름 (원하는 대로 변경 가능)
)
session = fo.launch_app(dataset)
print(session.url)
-> dataset_dir 경로 내에 dataset.yaml 파일이 무조건 있어야 한다.
2) 모델 결과 시각화 및 평가
모델 예측 결과를 시각화 하고 gt와 비교해 정답 여부를 확인할 수 있다.
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.core.labels as fol
from ultralytics import YOLO
# A name for the dataset
name = "test"
# The directory containing the dataset to import
dataset_dir = "/DATA/yolo_dataset/"
dataset = fo.Dataset.from_dir(
dataset_type=fo.types.YOLOv5Dataset, # YOLOv8도 YOLOv5 포맷과 동일함
dataset_dir=dataset_dir,
split="test", # 또는 "val", "test" 등 사용 가능
label_field="gt", # 라벨 필드 이름 (원하는 대로 변경 가능)
)
# Index images by similarity
fob.compute_similarity(
dataset,
model="clip-vit-base32-torch",
brain_key="img_sim",
)
# 모델 로드
model = YOLO("/DATA_HARD/yolov8n.pt")
filepaths = dataset.values("filepath")
for sample in dataset:
results = model(sample.filepath)[0] # YOLOv8은 리스트 반환
detections = []
for box in results.boxes:
label = results.names[int(box.cls)]
bbox = box.xywhn[0].tolist() # [x_center, y_center, w, h] normalized
confidence = float(box.conf)
detection = fol.Detection(label=label, bounding_box=bbox, confidence=confidence)
detections.append(detection)
# predictions 필드에 추가
sample["predictions"] = fol.Detections(detections=detections)
sample.save()
session = fo.launch_app(dataset)
session.wait()
compute_mistakenness() 함수를 사용해서 어떤 gt가 예측이 안되었고 예측 결과 중 어떤 게 잘못 되었는지 정량적으로 평가가능하다.
import fiftyone as fo
import fiftyone.brain as fob
from fiftyone import ViewField as F
from collections import Counter
# A name for the dataset
name = "test"
# The directory containing the dataset to import
dataset_dir = "/DATA/yolo_dataset/"
# 기존 데이터셋 삭제
if fo.dataset_exists(name):
fo.delete_dataset(name)
# gt format이 yolo format일 때
dataset = fo.Dataset.from_dir(
name=name,
dataset_type=fo.types.YOLOv5Dataset, # YOLOv8도 YOLOv5 포맷과 동일함
dataset_dir=dataset_dir,
split="test", # 또는 "val", "test" 등 사용 가능
label_field="gt", # 라벨 필드 이름 (원하는 대로 변경 가능)
)
dataset_pred = fo.Dataset.from_dir(
dataset_type=fo.types.YOLOv5Dataset,
dataset_dir="/DATA/predict_yolo",
split="test",
label_field="predictions"
)
for sample, pred_sample in zip(dataset, dataset_pred):
sample["predictions"] = pred_sample["predictions"]
sample.save()
fob.compute_mistakenness(dataset, "predictions", label_field="gt")
mistake_view = dataset.sort_by("mistakenness", reverse=True)
session = fo.launch_app(dataset)
session.view = mistake_view
session.wait()

-> mistakenness : 예측한 결과가 오탐일 가능성이 얼마난 높은지 나타내는 최댓값이다.
→ 즉, gt가 모델에 의해 얼마나 혼동되었는지를 의미한다.
- 각 GT 객체(바운딩 박스) 에 대해 모델이 예측한 결과와 매칭 여부 확인
- 매칭이 안 되거나, 예측 confidence가 낮거나, IoU가 낮으면 → 이 GT는 놓칠 가능성 높다고 판단
- 이런 위험도를 수치화해서 각 gt 마다 mistakenness score (0~1) 부여
- 마지막으로 각 샘플(이미지) 에 대해 → gt 중 가장 높은 score를 mistakenness로 설정
→ possible_spurious(FP) : 모델은 예측 결과 중 gt와 매칭이 되지 않는 bbox 개수(라벨 누락 or 오탐지)
→ possible_missing(FN) : 모델이 예측하지 못한 gt 개수
3) 비디오 데이터셋 지원
프레임 단위 분석이 가능하며 프레임 별 예측 결과를 시각화 할 수 있다.
import fiftyone as fo
import fiftyone.core.labels as fol
import cv2
import os
from ultralytics import YOLO
# 비디오 파일 경로
video_path = "/DATA_HARD/sample.mp4"
# YOLOv8 모델 로드
model = YOLO("/DATA_HARD/yolov8n.pt")
# OpenCV로 비디오 로드
cap = cv2.VideoCapture(video_path)
frame_rate = cap.get(cv2.CAP_PROP_FPS)
frame_number = 1
frames = {}
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 프레임 RGB로 변환
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# YOLO 추론
results = model(rgb_frame)[0]
detections = []
for box in results.boxes:
xc, yc, w, h = box.xywhn[0].tolist()
bbox = [xc - w/2, yc - h/2, w, h]
label = results.names[int(box.cls)]
confidence = float(box.conf)
detections.append(
fol.Detection(label=label, bounding_box=bbox, confidence=confidence)
)
# 프레임 번호에 따라 저장
frames[frame_number] = fol.Detections(detections=detections)
frame_number += 1
cap.release()
# Dataset 생성
dataset = fo.Dataset(name="video-yolo")
# VideoSample 생성
sample = fo.Sample(filepath=video_path)
# Dataset에 먼저 추가 (프레임 액세스 위해)
dataset.add_sample(sample)
# 프레임별 prediction 할당
for frame_number, detections in frames.items():
sample.frames[frame_number] = fo.Frame(predictions=detections)
# 저장
sample.save()
# UI 실행
session = fo.launch_app(dataset)
session.wait()
이렇게 gt 없는 비디오 하나만 web ui에서 시각화가 가능하지만 여러 개의 video가 저장 되어 있는 데이터셋도 web ui에서 시각화가 가능함.
import fiftyone as fo
import fiftyone.brain as fob
import os
# Dataset 이름
name = "videos"
# 비디오가 저장 되어 있는 디렉터리
dataset_dir = "/DATA_HARD/videos/"
# 기존 데이터셋 삭제
if fo.dataset_exists(name):
fo.delete_dataset(name)
# FiftyOne Dataset 생성
dataset = fo.Dataset(name)
# .mp4 파일 전부 가져오기
video_paths = [
os.path.join(dataset_dir, f)
for f in os.listdir(dataset_dir)
if f.endswith(".mp4")
]
# Sample 객체로 변환해서 Dataset에 추가
samples = [fo.Sample(filepath=vp) for vp in video_paths]
dataset.add_samples(samples)
frames_view = dataset.to_frames(sample_frames=True) # framea_rate : 샘플링 할 간격(ex. frame_rate=1.0이면 1초당 1 frame 샘플링 한다는 것)
# 프레임별 유사도 계산
fob.compute_similarity(
frames_view,
model="clip-vit-base32-torch",
brain_key="frame_sim",
)
session = fo.launch_app(dataset) # 비디오를 시각화 하기 위함
# session = fo.launch_app(frames_view) # 비디오의 프레임을 시각화 하기 위함
session.wait()
-> compute_similarity 해당 함수를 사용하여 프레임 간 유사도를 계산할 수 있다.
-> 유사한 프레임들만 시각화 할 수 있다.
이외에도 이미지의 고유성을 계산 해 주거나 임베딩을 시각화 하여 데이터셋을 분석할 수도 있다.
이외의 기능은 공식 문서에서 참고 가능하다.
FiftyOne — FiftyOne 1.4.1 documentation
Contents
docs.voxel51.com
FiftyOne은 컴퓨터 비전 분야의 데이터셋을 효과적으로 관리하고 분석할 수 있도록 돕는 오픈소스 툴이다.
해당 툴을 사용하면 이미지 및 비디오 기반 데이터셋을 시각화하고 모델 예측 결과를 평가하며 잘못된 라벨을 쉽게 탐지할 수 있다.
1. FiftyOne 설치
- fiftyOne 설치
apt install libcurl4 openssl
apt install libcurl4-openssl-dev
pip install fiftyone
pip install fiftyone-db-ubuntu2204
- quickstart
import fiftyone as fo
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart")
print(dataset)
sample = dataset.first()
print(sample.predictions.detections[0])
session = fo.launch_app(dataset)
session.show()
-> 주피터 노트북에서는 iframe이 뜨지 않아 port 번호를 연결해 web ui를 띄워야 한다.
-> fiftyone은 default port로 5151을 사용 중이다.
print(session.url)
-> localhost:5151 로 출력 될 것이다.
-> 해당 url을 접속하거나 컨테이너 생성 시 5151로 포트 포워딩을 해 주면 컨테이너 생성한 서버 ip:5151로 web ui가 뜨게 된다.

2. 주요 기능
1) 다양한 데이터셋 포맷 지원
COCO, YOLO, Pascal VOC, ImageDirectory, VideoDirectory 등 다양한 포맷의 데이터셋을 fo.Dataset.from_dir() 한 줄로 쉽게 로드 가능하다.
import fiftyone as fo
import fiftyone.utils.yolo as fouy
# A name for the dataset
name = "test"
# The directory containing the dataset to import
dataset_dir = "/workspace/DATA/yolo_dataset/"
dataset = fo.Dataset.from_dir(
dataset_type=fo.types.YOLOv5Dataset, # YOLOv8도 YOLOv5 포맷과 동일함
dataset_dir=dataset_dir,
split="test", # 또는 "val", "test" 등 사용 가능
label_field="gt", # 라벨 필드 이름 (원하는 대로 변경 가능)
)
session = fo.launch_app(dataset)
print(session.url)
-> dataset_dir 경로 내에 dataset.yaml 파일이 무조건 있어야 한다.
2) 모델 결과 시각화 및 평가
모델 예측 결과를 시각화 하고 gt와 비교해 정답 여부를 확인할 수 있다.
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.core.labels as fol
from ultralytics import YOLO
# A name for the dataset
name = "test"
# The directory containing the dataset to import
dataset_dir = "/DATA/yolo_dataset/"
dataset = fo.Dataset.from_dir(
dataset_type=fo.types.YOLOv5Dataset, # YOLOv8도 YOLOv5 포맷과 동일함
dataset_dir=dataset_dir,
split="test", # 또는 "val", "test" 등 사용 가능
label_field="gt", # 라벨 필드 이름 (원하는 대로 변경 가능)
)
# Index images by similarity
fob.compute_similarity(
dataset,
model="clip-vit-base32-torch",
brain_key="img_sim",
)
# 모델 로드
model = YOLO("/DATA_HARD/yolov8n.pt")
filepaths = dataset.values("filepath")
for sample in dataset:
results = model(sample.filepath)[0] # YOLOv8은 리스트 반환
detections = []
for box in results.boxes:
label = results.names[int(box.cls)]
bbox = box.xywhn[0].tolist() # [x_center, y_center, w, h] normalized
confidence = float(box.conf)
detection = fol.Detection(label=label, bounding_box=bbox, confidence=confidence)
detections.append(detection)
# predictions 필드에 추가
sample["predictions"] = fol.Detections(detections=detections)
sample.save()
session = fo.launch_app(dataset)
session.wait()
compute_mistakenness() 함수를 사용해서 어떤 gt가 예측이 안되었고 예측 결과 중 어떤 게 잘못 되었는지 정량적으로 평가가능하다.
import fiftyone as fo
import fiftyone.brain as fob
from fiftyone import ViewField as F
from collections import Counter
# A name for the dataset
name = "test"
# The directory containing the dataset to import
dataset_dir = "/DATA/yolo_dataset/"
# 기존 데이터셋 삭제
if fo.dataset_exists(name):
fo.delete_dataset(name)
# gt format이 yolo format일 때
dataset = fo.Dataset.from_dir(
name=name,
dataset_type=fo.types.YOLOv5Dataset, # YOLOv8도 YOLOv5 포맷과 동일함
dataset_dir=dataset_dir,
split="test", # 또는 "val", "test" 등 사용 가능
label_field="gt", # 라벨 필드 이름 (원하는 대로 변경 가능)
)
dataset_pred = fo.Dataset.from_dir(
dataset_type=fo.types.YOLOv5Dataset,
dataset_dir="/DATA/predict_yolo",
split="test",
label_field="predictions"
)
for sample, pred_sample in zip(dataset, dataset_pred):
sample["predictions"] = pred_sample["predictions"]
sample.save()
fob.compute_mistakenness(dataset, "predictions", label_field="gt")
mistake_view = dataset.sort_by("mistakenness", reverse=True)
session = fo.launch_app(dataset)
session.view = mistake_view
session.wait()

-> mistakenness : 예측한 결과가 오탐일 가능성이 얼마난 높은지 나타내는 최댓값이다.
→ 즉, gt가 모델에 의해 얼마나 혼동되었는지를 의미한다.
- 각 GT 객체(바운딩 박스) 에 대해 모델이 예측한 결과와 매칭 여부 확인
- 매칭이 안 되거나, 예측 confidence가 낮거나, IoU가 낮으면 → 이 GT는 놓칠 가능성 높다고 판단
- 이런 위험도를 수치화해서 각 gt 마다 mistakenness score (0~1) 부여
- 마지막으로 각 샘플(이미지) 에 대해 → gt 중 가장 높은 score를 mistakenness로 설정
→ possible_spurious(FP) : 모델은 예측 결과 중 gt와 매칭이 되지 않는 bbox 개수(라벨 누락 or 오탐지)
→ possible_missing(FN) : 모델이 예측하지 못한 gt 개수
3) 비디오 데이터셋 지원
프레임 단위 분석이 가능하며 프레임 별 예측 결과를 시각화 할 수 있다.
import fiftyone as fo
import fiftyone.core.labels as fol
import cv2
import os
from ultralytics import YOLO
# 비디오 파일 경로
video_path = "/DATA_HARD/sample.mp4"
# YOLOv8 모델 로드
model = YOLO("/DATA_HARD/yolov8n.pt")
# OpenCV로 비디오 로드
cap = cv2.VideoCapture(video_path)
frame_rate = cap.get(cv2.CAP_PROP_FPS)
frame_number = 1
frames = {}
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 프레임 RGB로 변환
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# YOLO 추론
results = model(rgb_frame)[0]
detections = []
for box in results.boxes:
xc, yc, w, h = box.xywhn[0].tolist()
bbox = [xc - w/2, yc - h/2, w, h]
label = results.names[int(box.cls)]
confidence = float(box.conf)
detections.append(
fol.Detection(label=label, bounding_box=bbox, confidence=confidence)
)
# 프레임 번호에 따라 저장
frames[frame_number] = fol.Detections(detections=detections)
frame_number += 1
cap.release()
# Dataset 생성
dataset = fo.Dataset(name="video-yolo")
# VideoSample 생성
sample = fo.Sample(filepath=video_path)
# Dataset에 먼저 추가 (프레임 액세스 위해)
dataset.add_sample(sample)
# 프레임별 prediction 할당
for frame_number, detections in frames.items():
sample.frames[frame_number] = fo.Frame(predictions=detections)
# 저장
sample.save()
# UI 실행
session = fo.launch_app(dataset)
session.wait()
이렇게 gt 없는 비디오 하나만 web ui에서 시각화가 가능하지만 여러 개의 video가 저장 되어 있는 데이터셋도 web ui에서 시각화가 가능함.
import fiftyone as fo
import fiftyone.brain as fob
import os
# Dataset 이름
name = "videos"
# 비디오가 저장 되어 있는 디렉터리
dataset_dir = "/DATA_HARD/videos/"
# 기존 데이터셋 삭제
if fo.dataset_exists(name):
fo.delete_dataset(name)
# FiftyOne Dataset 생성
dataset = fo.Dataset(name)
# .mp4 파일 전부 가져오기
video_paths = [
os.path.join(dataset_dir, f)
for f in os.listdir(dataset_dir)
if f.endswith(".mp4")
]
# Sample 객체로 변환해서 Dataset에 추가
samples = [fo.Sample(filepath=vp) for vp in video_paths]
dataset.add_samples(samples)
frames_view = dataset.to_frames(sample_frames=True) # framea_rate : 샘플링 할 간격(ex. frame_rate=1.0이면 1초당 1 frame 샘플링 한다는 것)
# 프레임별 유사도 계산
fob.compute_similarity(
frames_view,
model="clip-vit-base32-torch",
brain_key="frame_sim",
)
session = fo.launch_app(dataset) # 비디오를 시각화 하기 위함
# session = fo.launch_app(frames_view) # 비디오의 프레임을 시각화 하기 위함
session.wait()
-> compute_similarity 해당 함수를 사용하여 프레임 간 유사도를 계산할 수 있다.
-> 유사한 프레임들만 시각화 할 수 있다.
이외에도 이미지의 고유성을 계산 해 주거나 임베딩을 시각화 하여 데이터셋을 분석할 수도 있다.
이외의 기능은 공식 문서에서 참고 가능하다.
FiftyOne — FiftyOne 1.4.1 documentation
Contents
docs.voxel51.com