데이터 추가 및 준비
업로드 전에 로컬에서 데이터셋을 검사하고, 동영상을 계획적으로 샘플링하여, 첫 시도에 플랫폼 데이터셋을 준비 완료 상태로 만드세요.
업로드 전에 발견하는 데이터셋 버그가 가장 저렴한 버그입니다. Pascal VOC 레이블은 아무런 알림 없이 건너뛰고, 28픽셀보다 작은 이미지는 거부되며, 30분짜리 동영상에서는 프레임 100개만 추출되는데 대부분 빈 장면입니다. 이 강의에서는 업로드 전 2분 점검을 수행하고, 동영상을 목적에 맞게 샘플링하며, 플랫폼의 처리 상태 신호를 확인해 학습 데이터를 온전히 준비합니다.
실습형
데이터셋 만들기#

사이드바에서 Annotate을 열고 New Dataset을 클릭합니다. 대화상자에서 소스, 이름, 작업 유형, 선택적 라이선스, 얼굴 흐리게 처리 여부, 공개 범위를 지정합니다:

| 소스 | 사용할 상황 | 계획 |
|---|---|---|
| 업로드 | 파일이 로컬 컴퓨터에 있는 경우: 이미지, 동영상, 아카이브 또는 NDJSON 내보내기 파일 | 전체 |
| URL | 공개 .zip, .tar, .tar.gz, .tgz 또는 .ndjson 링크가 있으며, 플랫폼이 서버 측에서 다운로드하는 경우 | 전체 |
| 클라우드 | 데이터가 이미 Google Cloud Storage, Amazon S3 또는 Azure Blob Storage에 있으며 해당 위치에 그대로 두어야 하는 경우 | Pro, Enterprise |
| 온프레미스 | 픽셀 데이터를 절대 로컬 컴퓨터 밖으로 내보내면 안 되는 경우 | Enterprise |
결정 원칙: 이 과정에서는 복사본을 업로드하세요. 클라우드 및 온프레미스 데이터셋은 픽셀 데이터를 플랫폼 외부에 보관하므로 스마트 주석, 클러스터링, 복제, 버전 스냅샷을 사용할 수 없습니다.
작업 유형에 따라 표시되는 도구와 모델이 결정됩니다. 플랫폼은 Ultralytics YOLO의 7가지 작업을 모두 지원합니다:
| 작업 | 레이블 지정 방법 |
|---|---|
| 탐지 | 직사각형 또는 SAM 및 YOLO 스마트 주석 |
| 분할 | 다각형 또는 SAM 및 YOLO 스마트 주석 |
| 의미론적 분할 | 다각형 또는 SAM 및 YOLO 스마트 주석, PNG 마스크 직접 가져오기 |
| 자세 추정 | 기본 제공 또는 사용자 지정 스켈레톤의 키포인트, 스마트 주석용 YOLO 포즈 모델 |
| OBB | 회전 바운딩 박스 또는 SAM 및 YOLO 스마트 주석 |
| 분류 | 사이드바의 클래스 선택기 |
| 깊이 | 그리기 없음: 쌍을 이루는 깊이 맵이 있는 이미지를 업로드하세요(업로드 또는 URL만 가능). |
실습 예제: 업로드 전에 데이터셋 확인하기#
Platform은 최대 50 MB이며 짧은 변의 길이가 28 px 이상인 JPEG, PNG, WebP, BMP, TIFF, HEIC, AVIF, JP2, DNG, MPO 이미지를 지원하고 YOLO, COCO, LabelMe, Ultralytics 또는 Labelbox NDJSON, 시맨틱 PNG 마스크 레이블을 읽습니다. Pascal VOC XML은 감지되지만 가져오지는 않습니다. 이 스크립트는 로컬 YOLO 데이터셋이 해당 규칙을 따르는지 확인합니다. 여기서는 공개 의료용 알약 데이터셋을 사용합니다.
from collections import Counter
from pathlib import Path
from PIL import Image
from ultralytics.data.utils import check_det_dataset
ACCEPTED = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tif", ".tiff", ".heic", ".avif", ".jp2", ".dng", ".mpo"}
data = check_det_dataset("medical-pills.yaml") # your local dataset YAML
root = Path(data["path"])
problems = Counter()
for split in ("train", "val", "test"):
if not data.get(split):
continue
files = [p for p in Path(data[split]).rglob("*") if p.is_file()]
images = [p for p in files if p.suffix.lower() in ACCEPTED]
labeled = 0
for img in images:
label = Path(str(img).replace("images", "labels")).with_suffix(".txt")
labeled += label.exists() and label.stat().st_size > 0
if min(Image.open(img).size) < 28:
problems["under 28 px (rejected)"] += 1
if img.stat().st_size > 50 * 1024**2:
problems["over 50 MB (rejected)"] += 1
problems["unsupported files (skipped)"] += len(files) - len(images)
print(f"{split:<5} {len(images):>4} images, {labeled:>4} labeled, {len(images) - labeled:>3} background")
problems["Pascal VOC .xml labels (not imported)"] += len(list(root.rglob("*.xml")))
print("classes:", data["names"])
print("problems:", {k: v for k, v in problems.items() if v} or "none")train 92 images, 92 labeled, 0 background
val 23 images, 23 labeled, 0 background
classes: {0: 'pill'}
problems: none출력 내용:
- 분할별 개수.
train/,val/,test/폴더에 있는 이미지는 업로드 시 해당 분할에 유지되므로, 이 수치가 Platform에 표시됩니다.val행이 없다면 Platform에서 임의의 검증 분할을 만들어 줍니다(아래 주의 사항 참조). - 배경 이미지(레이블 파일이 없는 이미지)는 적당한 수라면 괜찮습니다. 모델이 "아무것도 없음"이 어떤 모습인지 학습하는 데 도움이 됩니다. 수백 장에 달한다면 대개 레이블 내보내기에 실패한 것입니다.
problems: none은 모든 이미지가 처리된다는 뜻입니다. 여기에 표시되는 개수만큼의 파일은Errors탭으로 이동하거나 아예 도착하지 않습니다.
데이터셋 폴더와 그 안의 data.yaml을 함께 압축한 다음, 아카이브를 갤러리로 끌어다 놓으세요. Platform은 형식을 자동으로 감지하고 동일한 이미지는 한 번만 저장합니다. 또한 업로드한 이미지가 데이터셋의 기존 이미지와 충돌하면 건너뛰기, 둘 다 유지, 바꾸기 중에서 선택하라는 메시지를 표시합니다.
실습 예제: Platform이 처리하기 전에 동영상 샘플링하기#
Platform은 각 동영상에서 초당 1프레임을 샘플링하고 최대 100프레임을 유지합니다. 100초보다 긴 클립은 간격을 넓힙니다.
| 클립 길이 | 유지되는 프레임 | 간격 |
|---|---|---|
| 60초 | 60 | 1초 |
| 100초 | 100 | 1초 |
| 30분(30 fps에서 54,000프레임) | 100 | 18초 |
빠르게 살펴보기에는 적합하지만 대부분의 실제 프로젝트에는 부족합니다. 30분 동안 촬영한 교대 근무 영상이 100프레임으로 줄어들고, 대부분은 텅 빈 통로일 것입니다. 긴 영상을 직접 샘플링하고 프레임을 업로드하세요.
균일하게 샘플링하려면 FFmpeg로 충분합니다.
mkdir -p frames
ffmpeg -i source.mp4 -vf fps=1 frames/%06d.jpg이벤트 기반 샘플링을 하려면 사전 학습된 Ultralytics YOLO 모델을 사용하여 대상 객체가 포함된 프레임만 유지하세요.
from pathlib import Path
import cv2
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # or your latest fine-tune
out = Path("frames")
out.mkdir(exist_ok=True)
source = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
seen = kept = 0
for i, result in enumerate(model.predict(source, stream=True, vid_stride=5, classes=[0], conf=0.5, verbose=False)):
seen += 1
if len(result.boxes): # keep only frames where a person was detected
cv2.imwrite(str(out / f"frame_{i:05d}.jpg"), result.orig_img)
kept += 1
print(f"Kept {kept} of {seen} sampled frames")Kept 12 of 12 sampled framesvid_stride=5은 5프레임마다 확인하고, classes=[0]은 사람만 탐지하며, conf=0.5는 신뢰도가 낮은 예측을 무시합니다. 이 분주한 데모 클립에는 샘플링된 모든 프레임에 사람이 있습니다. 대부분 비어 있는 장면을 촬영한 영상에서는 유지되는 프레임의 비율이 급격히 낮아지고, 레이블링 비용도 줄어듭니다. 인접한 유지 프레임이 더 이상 비슷해 보이지 않을 때까지 vid_stride을 높이세요.
Platform의 처리 신호 읽기#
업로드 후 Platform은 검증, 정규화(4,096 px를 초과하는 이미지는 크기 조정), 썸네일 생성, 레이블 파싱, 통계 계산을 수행합니다. 다음 세 곳을 확인하세요.

Errors탭은 파일이 처리되지 않을 때만 표시됩니다. 손상된 파일, 지원되지 않는 형식, 28 px 미만의 이미지, CMYK 및 인덱스 색상 모드가 여기에 해당하며 각각 해결 방법이 안내됩니다. 해당 파일을 다시 내보내거나 업로드하세요.Charts탭에는 분할 분포, 상위 클래스, 이미지 크기, 파일 크기, 어노테이션 위치, 박스 크기, 이미지당 객체 수가 표시됩니다. 거의 나타나지 않는 클래스, 지나치게 작은 이미지, 한쪽 구석에 몰린 박스가 있는지 살펴보세요.- 데이터셋 헤더의 배지는 처리가 완료되고 데이터셋에
train이미지 1개 이상,val또는test이미지 1개 이상, 레이블이 지정된 이미지 1개 이상이 있으면Ready으로 표시됩니다.Not Ready를 클릭하면 충족되지 않은 조건을 확인할 수 있습니다.

공개 데이터셋에서 시작하기#

아직 데이터가 없으신가요? 탐색 페이지에서 공식 데이터셋과 커뮤니티 데이터셋을 확인할 수 있습니다. 데이터셋 복제는 이미지, 어노테이션, 클래스를 작업 공간에 복사하며 저장 공간을 차지합니다. 기본적으로 원본의 공개 여부도 유지하므로, 민감한 데이터를 추가하려면 대화상자의 스위치를 전환하세요.
주의할 점#
증상: 업로드는 성공하지만 모든 이미지에 레이블이 없는 상태로 들어옵니다. 해결 방법: Platform은 Pascal VOC XML을 감지하지만 가져오지는 않습니다. 먼저 YOLO .txt 레이블 또는 COCO JSON으로 변환합니다. 업로드 전 검사는 .xml 파일 수를 집계하므로 업로드 전에 이 문제를 파악할 수 있습니다.
증상: 검증 mAP는 매우 높지만 배포된 모델의 성능은 그렇지 않습니다. 해결 방법: 분할을 선택하지 않은 업로드로 val이 비어 있으면 Platform은 학습 이미지의 약 20%를 무작위로 val로 옮깁니다. 비디오 프레임에서는 서로 거의 동일한 이웃 프레임이 두 분할에 들어갑니다. 대신 train/ 및 val/ 폴더로 업로드하고, 비디오 또는 카메라별로 분할합니다(강의 4).
증상: 다각형 도구나 키포인트를 찾을 수 없습니다. 해결 방법: 작업 유형에 따라 도구가 결정됩니다. 데이터셋 헤더에서 작업 유형을 변경하세요. 각 이미지는 모든 작업의 레이블을 저장하므로 작업 유형을 전환해도 다른 작업의 레이블이 삭제되지 않고 숨겨집니다.
정답 보기
의료용 알약 데이터셋과 4분 길이의 라인 카메라 동영상을 사용한 정답 예시입니다. 업로드 전 확인 결과: train 이미지 92개, val 이미지 23개이며 모두 레이블이 있고 문제는 없습니다. 동영상은 240초로 100초를 초과하므로 간격이 ceil(240 / 100) = 3초로 늘어나고 Platform은 80프레임을 유지합니다(0초, 3초, …, 237초에 하나씩). 예상 갤러리 이미지 수: 92 + 23 + 80 = 195개입니다. 동영상 프레임에는 레이블이 지정되지 않은 채 갤러리 필터에서 선택한 분할로 들어오므로, val에 포함되지 않도록 동영상을 놓기 전에 Train을 선택하세요. train, val, 레이블이 지정된 이미지가 모두 있으므로 배지에는 Ready이 표시됩니다. 동영상만 업로드했다면 레이블이 지정된 이미지가 아직 없으므로 배지에 Not Ready이 표시됩니다.