Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
cxnt committed Nov 6, 2024
1 parent 2590a67 commit 125503e
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 454 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -175,5 +175,6 @@ temp/
/imgaug.json
imgaug.json
supervisely_integration/train/data
supervisely_integration/train/output
supervisely
app_data
10 changes: 10 additions & 0 deletions rtdetr_pytorch/src/solver/det_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from src.data import CocoEvaluator
from src.misc import MetricLogger, SmoothedValue, reduce_dict
from src.misc.sly_logger import LOGS

from supervisely.app.widgets import Progress


Expand Down Expand Up @@ -105,6 +106,15 @@ def train_one_epoch(
metric_logger.update(loss=loss_value, **loss_dict_reduced)
metric_logger.update(lr=optimizer.param_groups[0]["lr"])

# import wandb

# from supervisely.train import train_logger

# # wandb.log({
# # "Train/loss":
# # })
# train_logger.log({"Train/loss": loss_value.item()})

# Update supervisely logs
LOGS.loss = loss_value.item()
LOGS.grad_norm = grad_norm.item() if grad_norm is not None else None
Expand Down
86 changes: 0 additions & 86 deletions supervisely_integration/train/aaa.json

This file was deleted.

34 changes: 0 additions & 34 deletions supervisely_integration/train/hyperparameters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,37 +31,3 @@ optimizer:
remap_mscoco_category: false
save_ema: false
save_optimizer: false
# general:
# num_epochs: 20 # Total number of training epochs

# data: # Section for data-related parameters
# input_size: [640, 640] # Input image size (width, height)
# train_batch_size: 2 # Batch size for training
# val_batch_size: 1 # Batch size for validation
# val_interval: 1 # Interval for running validation

# checkpoint:
# interval: 1 # Interval for saving checkpoints
# keep_checkpoints: true # Whether to keep saved checkpoints
# max_checkpoints: 3 # Maximum number of checkpoints to retain
# save_last: true # Save the last checkpoint after training
# save_best: true # Save the best-performing checkpoint based on validation
# save_optimizer_state: false # Save the optimizer state in checkpoints

# optimizer:
# frozen_stages_override: false # Override frozen stages if applicable
# type: "AdamW" # Type of optimizer to use
# learning_rate: 0.0001 # Initial learning rate
# weight_decay: 0.0001 # Weight decay (L2 regularization factor)
# clip_grad_norm: true # Enable gradient clipping
# grad_norm_value: 0.1 # Maximum norm for gradient clipping

# lr_scheduler:
# type: null # Type of learning rate scheduler
# by_epoch: true # Schedule learning rate by epochs rather than steps
# warmup:
# enabled: true # Enable warmup phase for learning rate
# steps: 1 # Number of warmup steps
# ratio: 0.001 # Starting learning rate ratio for warmup
# start_factor: 0.001 # Starting learning rate factor for warmup
# end_factor: 1.0 # Ending learning rate factor for warmup
175 changes: 165 additions & 10 deletions supervisely_integration/train/main.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import json
import os
import shutil
import sys
from typing import List

import yaml
from pycocotools.coco import COCO

from supervisely.io.fs import get_file_name, get_file_name_with_ext

cwd = os.getcwd()

rtdetr_pytorch_path = os.path.join(cwd, "rtdetr_pytorch")
sys.path.insert(0, rtdetr_pytorch_path)
from dotenv import load_dotenv
from models import get_models

import supervisely as sly
import supervisely_integration.train.utils as utils
from models import get_models
from supervisely.nn.training.train_app import TrainApp

load_dotenv(os.path.expanduser("~/supervisely.env"))
Expand Down Expand Up @@ -48,7 +56,7 @@
"save_to_file": True, # Save logs to file
"metrics": [ # Metrics to log
"accuracy",
"loss",
"Train/loss",
"mAP",
"AP",
"AR",
Expand All @@ -74,10 +82,17 @@


current_file_dir = os.path.dirname(os.path.abspath(__file__))
output_dir = os.path.join(current_file_dir, "output")
train = TrainApp(models_path, hyperparameters_path, app_options, output_dir)
work_dir = os.path.join(current_file_dir, "output")
train = TrainApp(models_path, hyperparameters_path, app_options, work_dir)

train
# train.init_logger(logger="supervisely")

# from src.serve import RTDETR
# train.register_inference_class(RTDETR) # optional
# def init_logger(self, logger):
# from sly.train import train_logger
#
# train_logger.init(self)


@train.start
Expand All @@ -91,16 +106,156 @@ def start_training():
# Step 2. prepare config.yml (hyperparameters + custom config)
# Step 3. train

# in TrainApp
# Step 4. Add logger

# Step 5. Automatically do model benchmark

import rtdetr_pytorch.train as train_cli

custom_config_path = os.path.join(config_paths_dir, "custom.yml")
hyperparameters = train.hyperparameters
utils.read_parameters(hyperparameters, custom_config_path)
# Step 1. Convert and prepare Project
converted_project_dir = os.path.join(train.work_dir, "converted_project")
convert2yolov8(train.sly_project, converted_project_dir, train.classes)

# Step 2. Prepare config and read hyperparameters
custom_config_path = prepare_config(train, converted_project_dir)

# Step 3. Train
finetune = True
cfg = train_cli.train(
finetune, custom_config_path, train.progress_bar_epochs, train.progress_bar_iters
)
utils.save_config(cfg)

# upload_model in preprocess?
return


def convert2yolov8(project: sly.Project, converted_project_dir: str, selected_classes: List[str]):
sly.logger.info("Converting project to COCO format")
for dataset in project.datasets:
dataset: sly.Dataset
coco_anno = {"images": [], "categories": [], "annotations": []}
cat2id = {name: i for i, name in enumerate(selected_classes)}
img_id = 1
ann_id = 1
for name in dataset.get_items_names():
ann = dataset.get_ann(name, project.meta)
img_dict = {
"id": img_id,
"height": ann.img_size[0],
"width": ann.img_size[1],
"file_name": name,
}
coco_anno["images"].append(img_dict)

for label in ann.labels:
if isinstance(label.geometry, (sly.Bitmap, sly.Polygon)):
rect = label.geometry.to_bbox()
elif isinstance(label.geometry, sly.Rectangle):
rect = label.geometry
else:
continue
class_name = label.obj_class.name
if class_name not in selected_classes:
continue
x, y, x2, y2 = rect.left, rect.top, rect.right, rect.bottom
ann_dict = {
"id": ann_id,
"image_id": img_id,
"category_id": cat2id[class_name],
"bbox": [x, y, x2 - x, y2 - y],
"area": (x2 - x) * (y2 - y),
"iscrowd": 0,
}
coco_anno["annotations"].append(ann_dict)
ann_id += 1

img_id += 1

coco_anno["categories"] = [{"id": i, "name": name} for name, i in cat2id.items()]

# Test:
coco_api = COCO()
coco_api.dataset = coco_anno
coco_api.createIndex()

if dataset.name == "train":
converted_ds_dir = os.path.join(converted_project_dir, "train")
elif dataset.name == "val":
converted_ds_dir = os.path.join(converted_project_dir, "val")

converted_img_dir = os.path.join(converted_ds_dir, "img")
converted_ann_dir = os.path.join(converted_ds_dir, "ann")
converted_ann_path = os.path.join(converted_ann_dir, "coco_anno.json")
os.makedirs(converted_img_dir, exist_ok=True)
os.makedirs(converted_ann_dir, exist_ok=True)
sly.json.dump_json_file(coco_anno, converted_ann_path)

# Move items
for image_name, image_path, _ in dataset.items():
shutil.move(image_path, os.path.join(converted_img_dir, image_name))
sly.logger.info(f"Dataset: '{dataset.name}' converted to COCO format")


def prepare_config(train: TrainApp, converted_project_dir: str):

# Train / Val paths
train_ds_dir = os.path.join(converted_project_dir, "train")
train_img_dir = os.path.join(train_ds_dir, "img")
train_ann_path = os.path.join(train_ds_dir, "ann", "coco_anno.json")

val_ds_dir = os.path.join(converted_project_dir, "val")
val_img_dir = os.path.join(val_ds_dir, "img")
val_ann_path = os.path.join(val_ds_dir, "ann", "coco_anno.json")

# Detect config from model parameters
model_parameters = train.model_parameters
if train.model_source == "Pretrained models":
selected_model_name = model_parameters["Model"]
arch = selected_model_name.split("_coco")[0]
config_name = f"{arch}_6x_coco"
custom_config_path = os.path.join(config_paths_dir, f"{config_name}.yml")
else:
selected_model_name = model_parameters.get("checkpoint_name")
config_name = get_file_name(model_parameters.get("config_url"))
custom_config_path = train.model_config_path

# Read custom config
with open(custom_config_path, "r") as f:
custom_config = yaml.safe_load(f)

# Fill custom config
custom_config["__include__"] = [f"{config_name}.yml"]
custom_config["remap_mscoco_category"] = False
custom_config["num_classes"] = train.num_classes
if "train_dataloader" not in custom_config:
custom_config["train_dataloader"] = {
"dataset": {
"img_folder": train_img_dir,
"ann_file": train_ann_path,
}
}
else:
custom_config["train_dataloader"]["dataset"]["img_folder"] = train_img_dir
custom_config["train_dataloader"]["dataset"]["ann_file"] = train_ann_path
if "val_dataloader" not in custom_config:
custom_config["val_dataloader"] = {
"dataset": {
"img_folder": val_img_dir,
"ann_file": val_ann_path,
}
}
else:
custom_config["val_dataloader"]["dataset"]["img_folder"] = val_img_dir
custom_config["val_dataloader"]["dataset"]["ann_file"] = val_ann_path

# Merge with hyperparameters
hyperparameters = train.hyperparameters
custom_config.update(hyperparameters)

custom_config_path = os.path.join(config_paths_dir, "custom.yml")
with open(custom_config_path, "w") as f:
yaml.safe_dump(custom_config, f)

# Copy to output dir also

return custom_config_path
Loading

0 comments on commit 125503e

Please sign in to comment.