imageO-ViT / src /config.py
iamSubha16's picture
Update src/config.py
7971c9e verified
Raw
History Blame
7.6 kB
"""Application configuration for imageO_v3."""
from __future__ import annotations
import os
from typing import Optional
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
# Cache defaults are set only when they are not already configured.
os.environ.setdefault("XDG_CACHE_HOME", "/app/.cache")
os.environ.setdefault("HF_HOME", "/app/.cache/huggingface")
os.environ.setdefault("NUMBA_DISABLE_CACHE", "1")
class Settings(BaseSettings):
"""Typed settings loaded from environment variables."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore",
)
app_env: str = Field(default="development", description="Runtime environment")
log_level: str = Field(default="INFO", description="Logger minimum level")
model_version: str = Field(default="v3.2.0", description="Service model version")
redis_url: str = Field(default="", description="Redis connection URL")
hf_token: str = Field(default="", description="Hugging Face token for gated model access")
replay_attack_ttl_s: int = Field(default=60, description="HMAC timestamp TTL")
prediction_cache_ttl_s: int = Field(default=300, description="Prediction cache TTL")
max_image_size_mb: int = Field(default=3, description="Maximum upload size in MB")
model_checkpoint_path: str = Field(
default="",
alias="MODEL_CHECKPOINT_PATH",
description="Local path to ABMIL .pt when ABMIL_HF_REPO_ID is unset; ignored when Hub repo id is set",
)
abmil_hf_repo_id: Optional[str] = Field(
default="iamSubha16/milk_adulteration_abmil_prod",
description="Hugging Face Hub repo id (e.g. org/private-repo). If set, ABMIL checkpoint is fetched via hf_hub_download.",
)
abmil_hf_filename: str = Field(
default="production_model_v3.pt",
description=(
"Checkpoint filename inside the Hub repo. This code targets the scale-aware hybrid-LSE "
"ABMIL, so point this at the RETRAINED checkpoint; the old plain-attention _v2 file will "
"not load under strict=True. Override via ABMIL_HF_FILENAME."
),
)
abmil_hf_revision: Optional[str] = Field(
default="main",
description="Optional Hub revision: branch, tag, or commit SHA (pin in production)",
)
abmil_hf_subfolder: Optional[str] = Field(
default="",
description="Optional folder inside the repo containing ABMIL_HF_FILENAME",
)
abmil_hf_local_files_only: bool = Field(
default=False,
description="If true, Hub resolution uses only local HF cache (no network)",
)
dinov3_model_id: str = Field(
default="facebook/dinov3-vits16plus-pretrain-lvd1689m",
description="Hugging Face model id for DINOv3 backbone",
)
embedding_batch_size: int = Field(
default=256,
description="Batch size for tile embedding"
)
embedding_device: Optional[str] = Field(
default="cpu",
description="Optional device override (cpu/cuda)",
)
embedding_dtype: Optional[str] = Field(
default="float32",
description="Optional dtype for DINO model loading (auto/float16/float32/bfloat16)",
)
dinov3_local_files_only: bool = Field(
default=False,
description="If true, do not fetch model files from Hugging Face",
)
# --- Tiling / preprocessing (multi-scale; must match training extraction config) ---
tile_sizes_raw: str = Field(
default="",
alias="TILE_SIZES",
description="Comma-separated or JSON tile sizes, e.g. '128,64'. Empty falls back to TILE_SIZE, then [128, 64].",
)
tile_size_legacy: str = Field(
default="",
alias="TILE_SIZE",
description="Legacy single tile size; used only when TILE_SIZES is unset.",
)
tile_overlap_ratio: float = Field(default=0.25, description="Preprocessing tile overlap ratio")
tile_shrink_factor: float = Field(default=0.85, description="ROI shrink factor")
tile_min_mask_coverage: float = Field(
default=0.8,
ge=0.0,
le=1.0,
description="Minimum fraction of tile pixels inside ROI mask to accept the tile",
)
# ROI Hough-circle detection knobs (defaults match milk_adulteration_mil ROIConfig).
roi_dp: float = Field(default=1.2, description="HoughCircles inverse accumulator resolution")
roi_param1: float = Field(default=60.0, description="HoughCircles Canny high threshold")
roi_param2: float = Field(default=35.0, description="HoughCircles accumulator threshold")
roi_min_radius_frac: float = Field(default=0.25, description="Min circle radius as fraction of min(h, w)")
roi_max_radius_frac: float = Field(default=0.75, description="Max circle radius as fraction of min(h, w)")
roi_median_blur_ksize: int = Field(default=7, description="Median blur kernel size before Hough transform")
roi_fallback_margin_frac: float = Field(
default=0.10,
description="Center-crop margin fraction used when no circle is detected",
)
# Optional tile-quality gates (DISABLED by default to match current training extraction).
tile_variance_gate_enabled: bool = Field(
default=False,
description="If true, reject tiles whose grayscale variance < tile_min_variance",
)
tile_min_variance: float = Field(default=50.0, description="Min grayscale variance when variance gate enabled")
tile_highlight_gate_enabled: bool = Field(
default=False,
description="If true, reject tiles whose specular-highlight fraction > tile_max_highlight_frac",
)
tile_highlight_thresh: int = Field(default=235, description="Grayscale value above which a pixel is a highlight")
tile_max_highlight_frac: float = Field(
default=0.40,
description="Max fraction of highlight pixels when highlight gate enabled",
)
abmil_attn_dim: int = Field(default=256, description="Fallback ABMIL attention dimension")
abmil_classifier_hidden: int = Field(
default=256,
description="Fallback ABMIL classifier hidden size",
)
abmil_attn_hidden: int = Field(default=128, description="Fallback gated attention hidden size")
abmil_dropout: float = Field(default=0.40, description="Fallback ABMIL dropout")
abmil_threshold: float = Field(default=0.35, description="Fallback positive class threshold")
abmil_scale_embed_dim: int = Field(
default=16,
description="Scale-embedding dim for MultiScaleEmbeddingProjector (0 disables); inferred from checkpoint when possible",
)
abmil_num_scales: int = Field(
default=3,
description="Number of tile-scale buckets in the scale-embedding table; inferred from checkpoint when possible",
)
abmil_lse_r: float = Field(
default=5.0,
description="LSE pooling sharpness r; not stored in the checkpoint, so must match the training default",
)
@property
def tile_sizes(self) -> list[int]:
"""Resolved multi-scale tile sizes (TILE_SIZES wins, then legacy TILE_SIZE, then [128, 64])."""
raw = (self.tile_sizes_raw or "").strip()
if raw:
if raw.startswith("["):
import json
return [int(x) for x in json.loads(raw)]
return [int(x.strip()) for x in raw.split(",") if x.strip()]
legacy = (self.tile_size_legacy or "").strip()
if legacy:
return [int(legacy)]
return [128, 64]
settings = Settings()