Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
fc4c378
Add transformer decoder head to create dino object detector with unit…
mohamedamrfaroukebrahim Dec 20, 2025
0cc567f
Add utility functions for position encoding and proposal generation i…
mohamedamrfaroukebrahim Dec 20, 2025
1a1bf92
Implement Segmentation Head and MLP Block for Object Detection
mohamedamrfaroukebrahim Dec 20, 2025
90c90b2
Add Keras implementation of projector layers and corresponding tests
mohamedamrfaroukebrahim Dec 20, 2025
dcf61f9
Implement DINO (LW-DETR) object detection architecture in Keras 3
mohamedamrfaroukebrahim Jan 20, 2026
198f58a
Add README files for DINO object detection model components and utili…
mohamedamrfaroukebrahim Jan 20, 2026
fbc945b
create new RFDETR (dino_v2_object_detector) from scratch to overcome …
mohamedamrfaroukebrahim Feb 24, 2026
0a6b1ce
change the dino_v2_object_detection path to be in paz\models\detectio…
mohamedamrfaroukebrahim Feb 24, 2026
d8ce651
Refactor parameter handling and logging in model utilities
mohamedamrfaroukebrahim Mar 3, 2026
abe0820
Enhance TrainConfig with additional parameters and update weight load…
mohamedamrfaroukebrahim Mar 3, 2026
1cf7781
Add training functionality and early stopping to RFDETR model
mohamedamrfaroukebrahim Mar 3, 2026
e2414d7
Add projector module imports to the backbone configuration
mohamedamrfaroukebrahim Mar 4, 2026
cd88c45
Rebuild detection head to support dynamic class updates in LWDETR model
mohamedamrfaroukebrahim Mar 4, 2026
316a99a
Integrate JAX compatibility into training loop with two-phase strateg…
mohamedamrfaroukebrahim Mar 4, 2026
2a4fce2
Update ModelEma tests to assert model_weights by variable path
mohamedamrfaroukebrahim Mar 4, 2026
3a099e6
Synchronize model_config after reinitializing detection head to ensur…
mohamedamrfaroukebrahim Mar 4, 2026
70a6c4f
Enhance weight comparison tests in LWDETR and add backbone parity che…
mohamedamrfaroukebrahim Mar 4, 2026
e6b5e15
Enhance documentation and improve code clarity across various utility…
mohamedamrfaroukebrahim Mar 10, 2026
30a743b
Remove unused debug scripts for RFDETR model inspection and shape tra…
mohamedamrfaroukebrahim Mar 10, 2026
3b4a2b0
Refactor matcher utility functions and improve test coverage
mohamedamrfaroukebrahim Mar 10, 2026
008a507
Enhance documentation and code clarity across RFDETR backbone (DINOv2…
mohamedamrfaroukebrahim Mar 10, 2026
f6339c4
Refactor transformer weight transfer utilities for improved clarity a…
mohamedamrfaroukebrahim Mar 10, 2026
a9ccfa9
Refactor weight transfer utilities and tests for SegmentationHead
mohamedamrfaroukebrahim Mar 10, 2026
ea924c3
Refactor LWDETR and its tests with detailed docstrings
mohamedamrfaroukebrahim Mar 10, 2026
a46b577
Refactor and enhance documentation across detection module
mohamedamrfaroukebrahim Mar 10, 2026
afaa6ca
Remove extensive docstrings from configuration, engine, and main modu…
mohamedamrfaroukebrahim Mar 10, 2026
904cb5f
Add RFDETR Backbone (Dinov2) configuration json files
mohamedamrfaroukebrahim Mar 10, 2026
8f4eba7
Add DeepFish dataset adapter for RFDETR training
mohamedamrfaroukebrahim Mar 10, 2026
cc7ed70
Add MetricsTracker class for tracking and visualizing training metrics
mohamedamrfaroukebrahim Mar 10, 2026
a0d8aa2
Add distributed training utilities for JAX support
mohamedamrfaroukebrahim Apr 19, 2026
b50a24f
Add LoRA and DoRA implementation for Dense layers in Keras
mohamedamrfaroukebrahim Apr 19, 2026
bca2793
Add CocoEvaluator class for COCO metrics computation and evaluation
mohamedamrfaroukebrahim Apr 19, 2026
437a8d0
Add dropout and export functionality to LWDETR model
mohamedamrfaroukebrahim Apr 19, 2026
02bf111
Refine loss function tests for LWDETR
mohamedamrfaroukebrahim Apr 19, 2026
2afa79a
Add data augmentation transforms for object detection
mohamedamrfaroukebrahim Apr 19, 2026
2bbd024
add dropout and drop path scheduling, enhance training loop
mohamedamrfaroukebrahim Apr 19, 2026
5eaa6d3
Update parity test thresholds for improved precision and add COCO dat…
mohamedamrfaroukebrahim Apr 19, 2026
447ea76
Set model training flag to True during eager forward pass in training…
mohamedamrfaroukebrahim Apr 23, 2026
7390450
Merge branch 'oarriaga:paz-jax' into paz-jax
mohamedamrfaroukebrahim May 6, 2026
5b6b5f6
training code and training experiments for testing the model behaviou…
mohamedamrfaroukebrahim May 6, 2026
32abe17
Merge branch 'oarriaga:paz-jax' into paz-jax
mohamedamrfaroukebrahim May 10, 2026
c14e7e9
Refactor attention layer and add unit tests for attention functions
mohamedamrfaroukebrahim May 10, 2026
1cd5c55
Refactor MLP implementation and add comprehensive unit tests
mohamedamrfaroukebrahim May 10, 2026
9da6729
Refactor DropPath and LayerScale implementations; add unit tests for …
mohamedamrfaroukebrahim May 12, 2026
a5c9c1d
Refactor PatchEmbed implementation; add unit tests for patch embeddin…
mohamedamrfaroukebrahim May 12, 2026
a851e40
Refactor SwiGLU feed-forward network implementation; add unit tests f…
mohamedamrfaroukebrahim May 12, 2026
722486d
get back to before refactoring
mohamedamrfaroukebrahim May 13, 2026
8497ef5
Refactor Dinov2 layers and models with adding unit tests
mohamedamrfaroukebrahim Jun 11, 2026
566a16f
Merge branch 'oarriaga:paz-jax' into paz-jax
mohamedamrfaroukebrahim Jun 11, 2026
d3ff9bb
Merge branch 'paz-jax' of https://github.com/mohamedamrfaroukebrahim/…
mohamedamrfaroukebrahim Jun 11, 2026
9abc333
update dinov2 init file
mohamedamrfaroukebrahim Jun 16, 2026
6d130b7
refactor windowed vision transformer and move it to dinov2 and update…
mohamedamrfaroukebrahim Jun 25, 2026
c1eb53e
Merge branch 'oarriaga:paz-jax' into paz-jax
mohamedamrfaroukebrahim Jun 25, 2026
753db63
Merge branch 'paz-jax' of https://github.com/mohamedamrfaroukebrahim/…
mohamedamrfaroukebrahim Jun 25, 2026
ae7a898
Merge branch 'oarriaga:paz-jax' into paz-jax
mohamedamrfaroukebrahim Jun 27, 2026
dea767f
modify requested modification
mohamedamrfaroukebrahim Jun 30, 2026
c64750a
refactor the whole dino_v2_object_detection
mohamedamrfaroukebrahim Aug 3, 2026
09eadf5
Merge remote-tracking branch 'upstream/paz-jax' into paz-jax
mohamedamrfaroukebrahim Aug 4, 2026
466f900
fix imports after upstream moved dinov2 to dinov2_legacy
mohamedamrfaroukebrahim Aug 4, 2026
7da1f7b
skip parity tests when the RF-DETR reference is unavailable
mohamedamrfaroukebrahim Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
190 changes: 190 additions & 0 deletions examples/fish_detection_using_rfdetr_dinov2_detector/dataset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
"""Dataset adapter for RFDETR / LWDETR training — DeepFish."""
import os
import glob
from collections import defaultdict

import numpy as np
from PIL import Image


# ---------------------------------------------------------------------------
# Class names
# ---------------------------------------------------------------------------

DEEPFISH_CLASS_NAMES = ["Fish"]


def _build_class_to_id(class_names):
return {name: idx for idx, name in enumerate(class_names)}


# ---------------------------------------------------------------------------
# Dataset
# ---------------------------------------------------------------------------


class DeepFishDataset:
"""Dataset that serves (image, target) for DeepFish training.

Reads YOLO-format ``.txt`` annotations that sit alongside ``.jpg``
images inside ``Deepfish/{video_id}/{train,valid}/`` sub-directories.

Parameters
----------
root : str or None
Root directory of the extracted DeepFish dataset.
If ``None``, defaults to ``~/.keras/paz/datasets/Deepfish``.
resolution : int or None
If given, resize all images to ``(resolution, resolution)``.
subset : int or None
If given, limit the dataset to the first *subset* images.
"""

def __init__(
self,
root=None,
resolution=None,
subset=None,
):
if root is None:
root = os.path.expanduser("~/.keras/paz/datasets/Deepfish")
self.root = root
self.resolution = resolution
self.class_names = list(DEEPFISH_CLASS_NAMES)
self._class_to_id = _build_class_to_id(self.class_names)

# -- discover images + annotations across all video sub-dirs -----
# Structure: Deepfish/{video_id}/{train,valid}/*.{jpg,txt}
image_paths = sorted(glob.glob(os.path.join(root, "*", "*", "*.jpg")))

self._img_ids = [] # list[str] – unique ID per image
self._img_paths = {} # img_id -> abs path
self._annotations = defaultdict(list) # img_id -> list[row-dict]

for img_path in image_paths:
img_id = os.path.splitext(os.path.basename(img_path))[0]
self._img_ids.append(img_id)
self._img_paths[img_id] = img_path

# Matching annotation file
txt_path = os.path.splitext(img_path)[0] + ".txt"
if os.path.isfile(txt_path):
with open(txt_path, "r") as fh:
for line in fh:
parts = line.strip().split()
if len(parts) < 5:
continue
# YOLO format: class_id cx cy w h (normalised)
cls_id = int(float(parts[0]))
cx_n, cy_n, w_n, h_n = (
float(parts[1]),
float(parts[2]),
float(parts[3]),
float(parts[4]),
)
# We store normalised coords; will convert to
# absolute when needed (in _build_target and
# prepare_coco_dataset). Use dummy 1×1 so that
# the absolute coords equal the normalised ones.
x_min_n = cx_n - w_n / 2.0
x_max_n = cx_n + w_n / 2.0
y_min_n = cy_n - h_n / 2.0
y_max_n = cy_n + h_n / 2.0
label_str = self.class_names[min(cls_id, len(self.class_names) - 1)]
self._annotations[img_id].append({
"label_l1": label_str,
"x_min_norm": x_min_n,
"x_max_norm": x_max_n,
"y_min_norm": y_min_n,
"y_max_norm": y_max_n,
})

# -- subset --------------------------------------------------------
if subset is not None:
self._img_ids = self._img_ids[:min(subset, len(self._img_ids))]

# ------------------------------------------------------------------
# Public API
# ------------------------------------------------------------------

def __len__(self):
return len(self._img_ids)

def get_image_path(self, img_id):
"""Return the absolute path of the image file for *img_id*."""
return self._img_paths.get(img_id)

def __getitem__(self, idx):
img_id = self._img_ids[idx]
image = self._load_image(img_id)
target = self._build_target(img_id)

# Resize
if self.resolution is not None:
image = np.array(
Image.fromarray(
(image * 255).astype(np.uint8)
).resize(
(self.resolution, self.resolution), Image.BILINEAR
)
).astype(np.float32) / 255.0

return image, target

@property
def num_classes(self):
return len(self.class_names)

# ------------------------------------------------------------------
# Internal helpers
# ------------------------------------------------------------------

def _load_image(self, img_id):
"""Load and return an HWC float32 [0, 1] image."""
path = self._img_paths[img_id]
img = Image.open(path).convert("RGB")
return np.asarray(img, dtype=np.float32) / 255.0

def _build_target(self, img_id):
"""Convert annotations into target dict.

Boxes are already in normalised cxcywh from the YOLO format.
"""
rows = self._annotations.get(img_id, [])
boxes = []
labels = []
for row in rows:
x_min_n = row["x_min_norm"]
x_max_n = row["x_max_norm"]
y_min_n = row["y_min_norm"]
y_max_n = row["y_max_norm"]
label_str = row["label_l1"].strip()

if label_str not in self._class_to_id:
continue

# Clamp
x_min_n = max(0.0, min(x_min_n, 1.0))
x_max_n = max(0.0, min(x_max_n, 1.0))
y_min_n = max(0.0, min(y_min_n, 1.0))
y_max_n = max(0.0, min(y_max_n, 1.0))

if x_max_n <= x_min_n or y_max_n <= y_min_n:
continue

cx = (x_min_n + x_max_n) / 2.0
cy = (y_min_n + y_max_n) / 2.0
w = x_max_n - x_min_n
h = y_max_n - y_min_n

boxes.append([cx, cy, w, h])
labels.append(self._class_to_id[label_str])

if len(boxes) == 0:
boxes_arr = np.zeros((0, 4), dtype=np.float32)
labels_arr = np.zeros((0,), dtype=np.int64)
else:
boxes_arr = np.array(boxes, dtype=np.float32)
labels_arr = np.array(labels, dtype=np.int64)

return {"boxes": boxes_arr, "labels": labels_arr}
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#!/bin/bash
###############################################################################
# experiment_1.sh — Full-dataset head-only training: RF-DETR Nano + DINOv2
#
# Trains only the detection head (class_embed + bbox_embed MLPs and query
# embeddings) while freezing the DINOv2 backbone and transformer decoder.
#
# Model: RFDETRNano (DINOv2-small backbone, 384×384, 2 decoder layers)
# Dataset: DeepFish — 6,517 images, 1 class ("Fish"), ~3.7 annotations/image
# 80/20 split → ~5,214 train / ~1,303 val
#
# Augmentation is configurable via the AUGMENTATION environment variable:
# AUGMENTATION=pipeline2 (default — horizontal flip + color jitter)
# AUGMENTATION=rf_detr (reserved for future RF-DETR native augmentations)
#
# Usage:
# sbatch experiment_1.sh # defaults
# AUGMENTATION=rf_detr sbatch experiment_1.sh # override augmentation
# EPOCHS=100 sbatch experiment_1.sh # override epochs
# RESUME=1 sbatch experiment_1.sh # resume from checkpoint
#
###############################################################################

#SBATCH --job-name=rfdetr_exp1_head
#SBATCH --partition=gpu_ampere
#SBATCH --account=deepl
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8
#SBATCH --gres=gpu:a100:1
#SBATCH --mem=64G
#SBATCH --time=3-00:00:00
#SBATCH --chdir=/mnt/beegfs/home/mebrahim/projects/fish_detector_using_rfdetr/paz/examples/fish_detection_using_rfdetr_dinov2_detector
#SBATCH --output=/mnt/beegfs/home/mebrahim/projects/fish_detector_using_rfdetr/paz/examples/fish_detection_using_rfdetr_dinov2_detector/experiments/experiment_1/slurm_%j.out
#SBATCH --error=/mnt/beegfs/home/mebrahim/projects/fish_detector_using_rfdetr/paz/examples/fish_detection_using_rfdetr_dinov2_detector/experiments/experiment_1/slurm_%j.err

set -euo pipefail

###############################################################################
# Pre-create experiment directory (MUST exist before SLURM writes logs)
###############################################################################
EXP_BASE="/mnt/beegfs/home/mebrahim/projects/fish_detector_using_rfdetr/paz/examples/fish_detection_using_rfdetr_dinov2_detector/experiments/experiment_1"
mkdir -p "${EXP_BASE}/checkpoints" "${EXP_BASE}/plots"

###############################################################################
# XLA / cuDNN flags (Ampere safe-mode — avoid autotuner hangs)
###############################################################################
export XLA_FLAGS="${XLA_FLAGS:-} --xla_gpu_strict_conv_algorithm_picker=false --xla_gpu_autotune_level=0 --xla_gpu_enable_triton_gemm=false"

###############################################################################
# Configurable parameters (override via environment before sbatch)
###############################################################################
AUGMENTATION="${AUGMENTATION:-pipeline2}" # pipeline2 | rf_detr
EPOCHS="${EPOCHS:-150}"
BATCH_SIZE="${BATCH_SIZE:-16}"
LR="${LR:-1e-4}"
WEIGHT_DECAY="${WEIGHT_DECAY:-1e-4}"
WARMUP_EPOCHS="${WARMUP_EPOCHS:-1.0}"
CLIP_MAX_NORM="${CLIP_MAX_NORM:-1.0}"
EARLY_STOPPING_PATIENCE="${EARLY_STOPPING_PATIENCE:-20}"
CONFIDENCE_THRESHOLD="${CONFIDENCE_THRESHOLD:-0.1}"
NUM_WORKERS="${NUM_WORKERS:-4}"
PREFETCH_SIZE="${PREFETCH_SIZE:-8}"
SEED="${SEED:-42}"

# Resume flag
RESUME_FLAG=""
if [[ "${RESUME:-0}" == "1" ]]; then
RESUME_FLAG="--resume"
fi

###############################################################################
# Paths
###############################################################################
CONDA_ENV="/mnt/beegfs/home/mebrahim/miniconda3/envs/paz_jax_dev_environment"
PYTHON="${CONDA_ENV}/bin/python"
SCRIPT_DIR="/mnt/beegfs/home/mebrahim/projects/fish_detector_using_rfdetr/paz/examples/fish_detection_using_rfdetr_dinov2_detector"
TRAIN_SCRIPT="${SCRIPT_DIR}/src/train.py"
EXPERIMENTS_ROOT="${SCRIPT_DIR}/experiments"
EXP_DIR="${EXPERIMENTS_ROOT}/experiment_1"

# (directories already created at top of script)

###############################################################################
# Log experiment configuration
###############################################################################
echo "============================================================"
echo " EXPERIMENT 1: Full-dataset head-only — RF-DETR Nano"
echo "============================================================"
echo " Date : $(date)"
echo " Node : $(hostname)"
echo " GPU : ${CUDA_VISIBLE_DEVICES:-none}"
echo " Job ID : ${SLURM_JOB_ID:-local}"
echo " Partition : ${SLURM_JOB_PARTITION:-interactive}"
echo "------------------------------------------------------------"
echo " Variant : RFDETRNano"
echo " Train mode : head_only"
echo " Augmentation : ${AUGMENTATION}"
echo " Epochs : ${EPOCHS}"
echo " Batch size : ${BATCH_SIZE}"
echo " Learning rate : ${LR}"
echo " Weight decay : ${WEIGHT_DECAY}"
echo " Warmup epochs : ${WARMUP_EPOCHS}"
echo " Clip max norm : ${CLIP_MAX_NORM}"
echo " Conf. threshold: ${CONFIDENCE_THRESHOLD}"
echo " Early stop pat.: ${EARLY_STOPPING_PATIENCE}"
echo " Num workers : ${NUM_WORKERS}"
echo " Prefetch size : ${PREFETCH_SIZE}"
echo " Seed : ${SEED}"
echo " Resume : ${RESUME:-0}"
echo " Output dir : ${EXP_DIR}"
echo "============================================================"

# Save config to JSON for reproducibility
cat > "${EXP_DIR}/experiment_config.json" <<EOF
{
"experiment": "experiment_1",
"description": "Full-dataset head-only training: RF-DETR Nano + DINOv2",
"variant": "RFDETRNano",
"train_mode": "head_only",
"augmentation": "${AUGMENTATION}",
"epochs": ${EPOCHS},
"batch_size": ${BATCH_SIZE},
"lr": ${LR},
"weight_decay": ${WEIGHT_DECAY},
"warmup_epochs": ${WARMUP_EPOCHS},
"clip_max_norm": ${CLIP_MAX_NORM},
"confidence_threshold": ${CONFIDENCE_THRESHOLD},
"early_stopping_patience": ${EARLY_STOPPING_PATIENCE},
"num_workers": ${NUM_WORKERS},
"prefetch_size": ${PREFETCH_SIZE},
"seed": ${SEED},
"lr_scheduler": "cosine",
"lr_min_factor": 0.01,
"ema_decay": 0.9997,
"ema_tau": 2000.0,
"val_split": 0.2,
"iou_threshold": 0.5,
"dataset": "DeepFish (6517 images, 1 class)",
"date": "$(date -Iseconds)",
"node": "$(hostname)",
"job_id": "${SLURM_JOB_ID:-local}"
}
EOF

###############################################################################
# Launch training
###############################################################################
${PYTHON} ${TRAIN_SCRIPT} \
--experiment-name "experiment_1" \
--experiments-root "${EXPERIMENTS_ROOT}" \
--variant RFDETRNano \
--train-mode head_only \
--augmentation "${AUGMENTATION}" \
--epochs "${EPOCHS}" \
--batch-size "${BATCH_SIZE}" \
--lr "${LR}" \
--lr-encoder 0.0 \
--lr-component-decay 0.0 \
--warmup-epochs "${WARMUP_EPOCHS}" \
--lr-scheduler cosine \
--lr-min-factor 0.01 \
--weight-decay "${WEIGHT_DECAY}" \
--clip-max-norm "${CLIP_MAX_NORM}" \
--early-stopping \
--early-stopping-patience "${EARLY_STOPPING_PATIENCE}" \
--early-stopping-min-delta 1e-4 \
--checkpoint-mode best_keep \
--plot-interval 1 \
--seed "${SEED}" \
--val-split 0.2 \
--confidence-threshold "${CONFIDENCE_THRESHOLD}" \
--iou-threshold 0.5 \
--group-detr 13 \
--print-freq 10 \
--num-workers "${NUM_WORKERS}" \
--prefetch-size "${PREFETCH_SIZE}" \
--ema-decay 0.9997 \
--ema-tau 2000.0 \
--use-ema \
--validate \
${RESUME_FLAG}

EXIT_CODE=$?

###############################################################################
# Post-training summary
###############################################################################
echo ""
echo "============================================================"
echo " EXPERIMENT 1 COMPLETE — exit code: ${EXIT_CODE}"
echo " Date : $(date)"
echo " Checkpoints : ${EXP_DIR}/checkpoints/"
echo " Plots : ${EXP_DIR}/plots/"
echo " Metrics log : ${EXP_DIR}/metrics_log.json"
echo " Config : ${EXP_DIR}/experiment_config.json"
echo "============================================================"

exit ${EXIT_CODE}
Loading