#!/usr/bin/env bash # SPDX-License-Identifier: MIT # Copyright (C) Intel Corporation # # Export a community YOLOv26 fire/smoke detector to OpenVINO IR for the # fire-and-smoke-detection use case. The model detects the "fire" and # "smoke" classes. # Usage: ./export_and_quantize.sh [PRECISION] # Example: ./export_and_quantize.sh FP16 set -euo pipefail PRECISION="${1:-FP16}" PRECISION="$(echo "${PRECISION}" | tr '[:lower:]' '[:upper:]')" MODEL_NAME="yolov26_fire" MODEL_URL="https://huggingface.co/SalahALHaismawi/yolov26-fire-detection/resolve/main/best.pt" # CC0 / Pexels-licensed sample video: "Aerial view of wildfire in forested # area" by K (Kelly), free to use via Pexels. VIDEO_URL="https://www.pexels.com/download/video/30937716/" if [[ "${PRECISION}" != "FP32" && "${PRECISION}" != "FP16" && "${PRECISION}" != "INT8" ]]; then echo "ERROR: unsupported precision '${PRECISION}'. Choose FP32, FP16, or INT8." >&2 exit 1 fi echo "--- Installing dependencies ---" if [[ "${PRECISION}" == "INT8" ]]; then pip install -qU openvino nncf ultralytics else pip install -qU openvino ultralytics fi # Ask for approval before downloading models and sample files echo "" echo "This script will download:" echo " - Community YOLOv26 fire/smoke model weights" echo " - A Pexels-licensed sample wildfire video" echo "" read -p "Continue with downloads? (yes/no): " APPROVAL if [[ "${APPROVAL}" != "yes" ]]; then echo "Download cancelled by user." exit 0 fi echo "" echo "--- Downloading fire/smoke model weights ---" if [[ ! -f "${MODEL_NAME}.pt" ]]; then curl -sL -o "${MODEL_NAME}.pt" "${MODEL_URL}" echo "Downloaded: ${MODEL_NAME}.pt" else echo "Already present: ${MODEL_NAME}.pt" fi echo "--- Downloading and transcoding sample test video ---" # Both samples run on an H.264 MP4. A fire/smoke-rich 8-second window is # trimmed, center-cropped to a square (so the fixed 640x640 resize does not # distort the aspect ratio the model is sensitive to), and transcoded with # ffmpeg. if [[ ! -f test_video.mp4 ]]; then if ! command -v ffmpeg >/dev/null 2>&1; then echo "ERROR: ffmpeg is required to transcode the sample video." >&2 echo "Install it (e.g. 'sudo apt-get install ffmpeg') and re-run." >&2 exit 1 fi curl -sL -o fire_source.mp4 "${VIDEO_URL}" ffmpeg -y -loglevel error -ss 2 -t 8 -i fire_source.mp4 \ -vf "crop=ih:ih,scale=736:736,format=yuv420p" \ -c:v libx264 -preset veryfast -an test_video.mp4 rm -f fire_source.mp4 echo "Downloaded and transcoded: test_video.mp4" else echo "Already present: test_video.mp4" fi if [[ "${PRECISION}" == "FP32" ]]; then HALF_FLAG="False" EXPORT_LABEL="FP32" else HALF_FLAG="True" EXPORT_LABEL="FP16" fi echo "--- Exporting ${MODEL_NAME} to OpenVINO IR (${EXPORT_LABEL}) ---" python3 -c " from ultralytics import YOLO model = YOLO('${MODEL_NAME}.pt') model.export(format='openvino', half=${HALF_FLAG}, dynamic=False, imgsz=640) print('Export complete: ${MODEL_NAME}_openvino_model/') " if [[ "${PRECISION}" == "INT8" ]]; then echo "--- Quantizing to INT8 with NNCF ---" python3 -c " import nncf import openvino as ov import numpy as np import cv2 core = ov.Core() model = core.read_model('${MODEL_NAME}_openvino_model/${MODEL_NAME}.xml') cap = cv2.VideoCapture('test_video.mp4') ok, frame = cap.read() cap.release() img = cv2.resize(frame, (640, 640)) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0 img = img.transpose(2, 0, 1)[np.newaxis, ...] def transform_fn(data_item): return img calibration_dataset = nncf.Dataset(list(range(300)), transform_fn) quantized = nncf.quantize( model, calibration_dataset, preset=nncf.QuantizationPreset.MIXED, subset_size=300, ) ov.save_model(quantized, '${MODEL_NAME}_int8.xml') print('Quantization complete: ${MODEL_NAME}_int8.xml') " fi echo "--- Done ---"