Open In Colab

Training object detection model resultbook#

此 colab 程式碼負責訓練模型。訓練好的模型可以在 Project_Nanshang or Predicting_mask_for_tifimage.ipynb 來建構地圖遮罩的 shp 檔。 另外,本程式碼是從 Roboflow train-yolo-nas-on-custom-dataset.ipynb 而來,更多細節可以參考 Roboflow 的教程

⚡ Before you start#

Let’s make sure that we have access to GPU. We can use nvidia-smi command to do that. In case of any problems navigate to Edit -> Notebook settings -> Hardware accelerator, set it to GPU, and then click Save.

!nvidia-smi

NOTE: To make it easier for us to manage datasets, images and models we create a HOME constant.

import os
HOME = os.getcwd()
print(HOME)

Install YOLO-NAS#

!pip install -q super-gradients==3.1.3
!pip install -q roboflow
!pip install -q supervision

🚨 Restart the runtime

After installation is complete, you’ll need to restart the runtime after installation completes. Navigate to Runtime -> Restart runtime and confirm by clicking Yes when you see the popup.

After that, carry on with the notebook starting from the cell below

import torch

DEVICE = 'cuda' if torch.cuda.is_available() else "cpu"
MODEL_ARCH = 'yolo_nas_l'
from super_gradients.training import models

model = models.get(MODEL_ARCH, pretrained_weights="coco").to(DEVICE)

Login and Specify your dataset in Roboflow,#

In this project, we will also use roboflow’s tool to store our data. make sure you are already have a project on roboflow

Roboflow Universe

請登入 roboflow 並寫上您的資料集名稱 和 版本


%cd {HOME}

import roboflow
from roboflow import Roboflow

roboflow.login()

rf = Roboflow()

Project_name = "nanshang_tomb"  # 請登入 roboflow 並寫上您的資料集名稱 和 版本
Version = 10

project = rf.workspace().project(Project_name)
dataset = project.version(Version).download("yolov5")
LOCATION = dataset.location
print("location:", LOCATION)
CLASSES = sorted(project.classes.keys())
print("classes:", CLASSES)

Fine-tune on custom dataset#

ckpt_root_dir - this is the directory where results from all your experiments will be saved

experiment_name - all checkpoints, logs, and tensorboards will be saved in a directory with the name you specify here.

settings#

MODEL_ARCH = 'yolo_nas_l'
BATCH_SIZE = 10
MAX_EPOCHS = 40
SCORE_THRSHOLD = 0.6
CHECKPOINT_DIR = f'{HOME}/checkpoints'
EXPERIMENT_NAME = project.name.lower().replace(" ", "_")
from super_gradients.training import Trainer

trainer = Trainer(experiment_name=EXPERIMENT_NAME, ckpt_root_dir=CHECKPOINT_DIR)
dataset_params = {
    'data_dir': LOCATION,
    'train_images_dir':'train/images',
    'train_labels_dir':'train/labels',
    'val_images_dir':'valid/images',
    'val_labels_dir':'valid/labels',
    'test_images_dir':'test/images',
    'test_labels_dir':'test/labels',
    'classes': CLASSES
}
from super_gradients.training.dataloaders.dataloaders import (
    coco_detection_yolo_format_train, coco_detection_yolo_format_val)

train_data = coco_detection_yolo_format_train(
    dataset_params={
        'data_dir': dataset_params['data_dir'],
        'images_dir': dataset_params['train_images_dir'],
        'labels_dir': dataset_params['train_labels_dir'],
        'classes': dataset_params['classes']
    },
    dataloader_params={
        'batch_size': BATCH_SIZE,
        'num_workers': 2
    }
)

val_data = coco_detection_yolo_format_val(
    dataset_params={
        'data_dir': dataset_params['data_dir'],
        'images_dir': dataset_params['val_images_dir'],
        'labels_dir': dataset_params['val_labels_dir'],
        'classes': dataset_params['classes']
    },
    dataloader_params={
        'batch_size': BATCH_SIZE,
        'num_workers': 2
    }
)

test_data = coco_detection_yolo_format_val(
    dataset_params={
        'data_dir': dataset_params['data_dir'],
        'images_dir': dataset_params['test_images_dir'],
        'labels_dir': dataset_params['test_labels_dir'],
        'classes': dataset_params['classes']
    },
    dataloader_params={
        'batch_size': BATCH_SIZE,
        'num_workers': 2
    }
)

Instantiate the model#

from super_gradients.training import models

model = models.get(
    MODEL_ARCH,
    num_classes=len(dataset_params['classes']),
    pretrained_weights="coco"
)

Define metrics and training parameters#

from super_gradients.training.losses import PPYoloELoss
from super_gradients.training.metrics import DetectionMetrics_050
from super_gradients.training.models.detection_models.pp_yolo_e import PPYoloEPostPredictionCallback

train_params = {
    'silent_mode': False,
    "average_best_models":True,
    "warmup_mode": "linear_epoch_step",
    "warmup_initial_lr": 1e-6,
    "lr_warmup_epochs": 3,
    "initial_lr": 5e-4,
    "lr_mode": "cosine",
    "cosine_final_lr_ratio": 0.1,
    "optimizer": "Adam",
    "optimizer_params": {"weight_decay": 0.0001},
    "zero_weight_decay_on_bias_and_bn": True,
    "ema": True,
    "ema_params": {"decay": 0.9, "decay_type": "threshold"},
    "max_epochs": MAX_EPOCHS,
    "mixed_precision": True,
    "loss": PPYoloELoss(
        use_static_assigner=False,
        num_classes=len(dataset_params['classes']),
        reg_max=16
    ),
    "valid_metrics_list": [
        DetectionMetrics_050(
            score_thres=SCORE_THRSHOLD,
            top_k_predictions=300,
            num_cls=len(dataset_params['classes']),
            normalize_targets=True,
            post_prediction_callback=PPYoloEPostPredictionCallback(
                score_threshold=0.01,
                nms_top_k=1000,
                max_predictions=300,
                nms_threshold=0.7
            )
        )
    ],
    "metric_to_watch": 'mAP@0.50'
}

Train the model#

trainer.train(
    model=model,
    training_params=train_params,
    train_loader=train_data,
    valid_loader=val_data
)

Analyze training metrics#

%load_ext tensorboard
%tensorboard --logdir {CHECKPOINT_DIR}/{EXPERIMENT_NAME}

Zip and download fine-tuned model#

# if you experience 'NotImplementedError: A UTF-8 locale is required. Got ANSI_X3.4-1968' error, run code below 👇

import locale
locale.getpreferredencoding = lambda: "UTF-8"
!zip -r yolo_nas.zip {CHECKPOINT_DIR}/{EXPERIMENT_NAME}

可以使用以下程式碼將資料轉移至自己的 google 雲端 ( address 要修改就是了 )

import locale
locale.getpreferredencoding = lambda: "UTF-8"
%cp "/content/checkpoints/nanshang_tomb/average_model.pth" "/content/drive/MyDrive/project_NanShang/resources/average_modelv10.pth"

記得將 checkpoints/nanshang_tomb 資料夾中的 average_model.pth 文件下載下來,此文件將在後續的物件偵測中被使用到。#

其本上 fine-tune 模型就到這裡就完成了。接下來可以到 Predicting_mask_for_tifimage.ipynb 來產生 shp 檔

Testing on testing dataset and Visualize them#

想要檢查 model 辨識能力的人請繼續閱讀,以下會在 testing dataset 中呈現預測的遮罩檔

Evaluate trained model#

trainer.test(
    model=model,
    test_loader=test_data,
    test_metrics_list=DetectionMetrics_050(
        score_thres=SCORE_THRSHOLD,
        top_k_predictions=300,
        num_cls=len(dataset_params['classes']),
        normalize_targets=True,
        post_prediction_callback=PPYoloEPostPredictionCallback(
            score_threshold=0.01,
            nms_top_k=1000,
            max_predictions=300,
            nms_threshold=0.7
        )
    )
)

Inference with trained model#


import supervision as sv

ds = sv.DetectionDataset.from_yolo(
    images_directory_path=f"{dataset.location}/test/images",
    annotations_directory_path=f"{dataset.location}/test/labels",
    data_yaml_path=f"{dataset.location}/data.yaml",
    force_masks=False
)

import supervision as sv

CONFIDENCE_TRESHOLD = 0.60

predictions = {}

for image_name, image in ds.images.items():
    result = list(model.predict(image, conf=CONFIDENCE_TRESHOLD))[0]
    detections = sv.Detections(
        xyxy=result.prediction.bboxes_xyxy,
        confidence=result.prediction.confidence,
        class_id=result.prediction.labels.astype(int)
    )
    predictions[image_name] = detections

Visualize inference results#

請調整 Seed 值以查看不同圖片的預測結果

import random

Seed = 14   # 可以調整 Seed 值以查看不同圖片的預測結果
random.seed(Seed)
import supervision as sv

MAX_IMAGE_COUNT = 5

n = min(MAX_IMAGE_COUNT, len(ds.images))

keys = list(ds.images.keys())
keys = random.sample(keys, n)

box_annotator = sv.BoxAnnotator()

images = []
titles = []

for key in keys:
    frame_with_annotations = box_annotator.annotate(
        scene=ds.images[key].copy(),
        detections=ds.annotations[key],
        skip_label=True
    )
    images.append(frame_with_annotations)
    titles.append('annotations')
    frame_with_predictions = box_annotator.annotate(
        scene=ds.images[key].copy(),
        detections=predictions[key],
        skip_label=True
    )
    images.append(frame_with_predictions)
    titles.append('predictions')

%matplotlib inline
sv.plot_images_grid(images=images, titles=titles, grid_size=(n, 2), size=(2 * 4, n * 4))

恭喜您完成訓練,如果您對模型呈現結果滿意,可以到下一個 workbook 來製作 shp 檔