Bruno Santos
Published © GPL3+

YOLOv8 custom classification model using Jetson Orin NX

How to use YOLOv8 to train a classification model using a custom dataset on Seeed Studio reComputer J4012

IntermediateFull instructions provided3 hours567
YOLOv8 custom classification model using Jetson Orin NX

Things used in this project

Hardware components

Seeed Studio reComputer J4012
×1

Software apps and online services

VS Code
Microsoft VS Code
Jupyter Notebooks and Python extensions installed

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Code

Jupyter Notebook

Python
This Jupyter Notebook contains all the steps
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We should already have YOLOv8 installed, as well PyTorch - following the instructions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before going into the notebook, some steps should already be done:\n",
    "1- Install some dependencies\n",
    "sudo apt install libopenblas-dev cuda-toolkit libcudnn8 tensorrt python3-libnvinfer nvidia-l4t-dla-compiler\n",
    "\n",
    "2 - create the virtual environment\n",
    "python -m venv birdClassificationModel\n",
    "\n",
    "3 - Active it\n",
    "source birdClassificationModel/bin/activate\n",
    "\n",
    "4 - Enter it\n",
    "cd birdClassificationModel\n",
    "\n",
    "5 - Upgrade PIP\n",
    "pip install -U pip\n",
    "\n",
    "6 - Install some packages from the NVIDIA forums\n",
    "wget https://nvidia.box.com/shared/static/mp164asf3sceb570wvjsrezk1p4ftj8t.whl -O torch-2.3.0-cp310-cp310-linux_aarch64.whl\n",
    "sudo apt-get install python3-pip libopenblas-base libopenmpi-dev libomp-dev\n",
    "pip3 install 'Cython<3'\n",
    "pip install numpy torch-2.3.0-cp310-cp310-linux_aarch64.whl\n",
    "\n",
    "7 - Install torchvision\n",
    "sudo apt-get install libjpeg-dev zlib1g-dev libpython3-dev libopenblas-dev libavcodec-dev libavformat-dev libswscale-dev\n",
    "git clone --branch v0.18.0 https://github.com/pytorch/vision torchvision\n",
    "cd torchvision/\n",
    "export BUILD_VERSION=0.18.0\n",
    "python setup.py install\n",
    "\n",
    "8 - check cuda - should return true\n",
    "python -c \"import torch;print (torch.cuda.is_available())\"\n",
    "\n",
    "9 - Install Yolov8, roboflow and jupyterlab \n",
    "pip install roboflow ultralytics jupyterlab\n",
    "\n",
    "10 - Now we can use this notebook and procced from the next step"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# install some libraries\n",
    "!pip install IPython"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# import libraries\n",
    "import ultralytics\n",
    "from roboflow import Roboflow\n",
    "from IPython.display import Image\n",
    "import matplotlib.pyplot as plt\n",
    "from PIL import Image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# download dataset - replace this code with your model from roboflow\n",
    "\n",
    "#rf = Roboflow(api_key=\"<your_api_here>\")\n",
    "#project = rf.workspace(\"bruno-santos-omqsq\").project(\"bird-classification-19z7c\")\n",
    "#version = project.version(1)\n",
    "#dataset = version.download(\"folder\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Prepare the config file with the classes\n",
    "1: Create a file named birdClassification.yaml in the root of the dataset and place the following text there:\n",
    "train: train/\n",
    "valid: valid/\n",
    "test: test/\n",
    "\n",
    "# number of classes\n",
    "nc: 12\n",
    "\n",
    "# class names\n",
    "names: [\"Barn Swallow\",\"Common Firecrest\",\"Common Nightingale\",\"Eurasian Chaffinch\",\"Eurasian Crag Martin\",\"European Goldfinch\",\"European Greenfinch\",\"European Serin\",\"House Sparrow\",\"Spanish Sparrow\",\"Western House Martin\",\"white Wagtail\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Train the model\n",
    "# because YoloV8 includes a command line interface, let's use it\n",
    "# the data name is the directory where the dataset is\n",
    "!yolo task=classify mode=train model=yolov8l-cls.pt data=Bird-Classification-1 epochs=100 imgsz=640"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After training, here's some metrics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Image ('./runs/classify/train6/confusion_matrix_normalized.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# some results\n",
    "Image ('./runs/classify/train6/results.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# let's validade the model\n",
    "!yolo task=classify mode=val model='./runs/classify/train6/weights/best.pt' data=Bird-Classification-1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Image ('./runs/classify/train6/train_batch19260.jpg')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# who validation labels and predictions\n",
    "img1 = Image.open('./runs/classify/train6/val_batch0_labels.jpg')\n",
    "img2 = Image.open('./runs/classify/train6/val_batch0_pred.jpg')\n",
    "fig, axs = plt.subplots(1, 2, figsize=(20,10))\n",
    "# Display the first image\n",
    "axs[0].imshow(img1)\n",
    "axs[0].axis('off')  # Hide axes for the first image\n",
    "axs[0].set_title('Validation Labels')\n",
    "\n",
    "# Display the second image\n",
    "axs[1].imshow(img2)\n",
    "axs[1].axis('off')  # Hide axes for the second image\n",
    "axs[1].set_title('Validation Predictions')\n",
    "# show\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's test the model\n",
    "!yolo task=classify mode=predict model='./runs/classify/train6/weights/best.pt' source=Bird-Classification-1/test/**/*.jpg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's predict in new photos\n",
    "!yolo task=classify mode=predict model='./runs/classify/train6/weights/best.pt' source=house_sparrow.jpg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!yolo task=classify mode=predict model='./runs/classify/train6/weights/best.pt' source=white_wagtail.jpg"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's run inference using the our model\n",
    "This time, let's use Python Code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# running inference\n",
    "from ultralytics import YOLO\n",
    "\n",
    "# load the  model\n",
    "bird_model = YOLO(\"./runs/classify/train6/weights/best.pt\")\n",
    "\n",
    "#run inference\n",
    "results = bird_model(\"house_sparrow.jpg\")[0]\n",
    "\n",
    "# get class names\n",
    "class_names = results.names\n",
    "\n",
    "\n",
    "# get top class with more probability\n",
    "top1 = results.probs.top1\n",
    "top1conf = results.probs.top1conf\n",
    "print (top1conf)\n",
    "\n",
    "# print the class name with the highest probability\n",
    "print (f\" The detected bird is: {class_names[top1]}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now use a camera\n",
    "Connect a USB camera to your Jetson\n",
    "You need to run this in the desktop, using Python\n",
    "Here's the code for it. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Lets test if we can use a USB camera\n",
    "import cv2\n",
    "\n",
    "cap = cv2.VideoCapture(1)\n",
    "while True:\n",
    "    ret, img = cap.read()\n",
    "    cv2.imshow('Camera', img)\n",
    "    \n",
    "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "        break\n",
    "cap.release()\n",
    "cv2.destroyAllWindows"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# again, save this code in a file a run it from the Jetson desktop\n",
    "# now, let's run inference\n",
    "import cv2\n",
    "from ultralytics import YOLO\n",
    "import time\n",
    "\n",
    "#define confidence level\n",
    "#only equal or above this level we say it's a class of bird\n",
    "confidence = 0.95\n",
    "\n",
    "# time when processed last frame\n",
    "prev_frame = 0\n",
    "\n",
    "# time processed current frame\n",
    "cur_time = 0\n",
    "\n",
    "# load the  model\n",
    "bird_model = YOLO(\"./runs/classify/train6/weights/best.pt\")\n",
    "\n",
    "# cv2 font\n",
    "font = cv2.FONT_HERSHEY_SIMPLEX \n",
    "\n",
    "# open camera\n",
    "cap = cv2.VideoCapture(0)\n",
    "\n",
    "while True:\n",
    "    ret, img = cap.read()\n",
    "        \n",
    "    # to display fps\n",
    "    cur_frame = time.time()\n",
    "    fps = 1 / (cur_frame - prev_frame)\n",
    "    prev_frame = cur_frame\n",
    "    fps = int(fps)\n",
    "    fps = str(fps)\n",
    "\n",
    "    cv2.putText (img, fps, (550,50), font, 1, (124,10,120), 2, cv2.LINE_AA)\n",
    "    #img = cv2.imshow('Camera', img)\n",
    "    # inference current frame\n",
    "    results = bird_model(img, verbose=False)[0]\n",
    "    \n",
    "    # get class names - this is \n",
    "    class_names = results.names\n",
    "\n",
    "    # get top class with more probability\n",
    "    top1 = results.probs.top1\n",
    "    top1conf = results.probs.top1conf.tolist()\n",
    "\n",
    "\n",
    "    # we will only show the class name if the confidence is higher than defined level\n",
    "    # print the class name with the highest probability\n",
    "    if (top1conf >= confidence):\n",
    "        bird_class = class_names[top1]\n",
    "        print (f\" The detected bird is: {class_names[top1]}\")\n",
    "        # color is in BGR\n",
    "        confid = round(top1conf,2)\n",
    "        img = cv2.putText(img, bird_class, (50,50), font, 0.9, (0, 0, 255), 2, cv2.LINE_AA)\n",
    "        img = cv2.putText(img, \"Conf: \" + str(confid), (50,80), font, 0.6, (255, 0, 255), 1, cv2.LINE_AA)\n",
    "        cv2.imshow('Camera', img)\n",
    "    else:\n",
    "        img = cv2.imshow('Camera', img)\n",
    "\n",
    "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "        break\n",
    "cap.release()\n",
    "cv2.destroyAllWindows\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Exporting the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# To ONNX\n",
    "!yolo export model='./runs/classify/train6/weights/best.pt' format=onnx imgsz=640"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# to run a onnx model, we need the onnxruntime-gpu to use CUDA\n",
    "# To install onnxruntime-gpu with JetPack 6.0, we need to download it from the [Jetson Zoo](https://elinux.org/Jetson_Zoo#ONNX_Runtime). \n",
    "!wget https://nvidia.box.com/shared/static/48dtuob7meiw6ebgfsfqakc9vse62sg4.whl -O onnxruntime_gpu-1.18.0-cp310-cp310-linux_aarch64.whl\n",
    "!pip install onnxruntime_gpu-1.18.0-cp310-cp310-linux_aarch64.whl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "birdClassificationModel",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}

Credits

Bruno Santos
7 projects • 6 followers
Linux and Raspberry PI lover! Systems and Network Administrator, programmer, kind of a Nerd!

Comments