Spaces:
Sleeping
Sleeping
File size: 9,089 Bytes
6396e6b c8f4e3f df1b2ad c8f4e3f 8d28be7 6396e6b df1b2ad c8f4e3f 6396e6b c8f4e3f 6396e6b c8f4e3f 6396e6b c8f4e3f 6396e6b df1b2ad c8f4e3f 6396e6b c8f4e3f 6396e6b 8d28be7 6396e6b c8f4e3f 6396e6b c8f4e3f 6396e6b c8f4e3f df1b2ad c8f4e3f df1b2ad c8f4e3f df1b2ad c8f4e3f df1b2ad c8f4e3f df1b2ad c8f4e3f 6396e6b 4d6298c c8f4e3f 6396e6b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | from pathlib import Path
from typing import Any
import shutil
from .model import FFTCNN # Import the FFT CNN architecture (package-relative)
from config import Config
try:
from huggingface_hub import hf_hub_download
except Exception:
hf_hub_download = None
# NOTE: EfficientNet/nn imports are done lazily when torch is available.
ELAForgeryNet = None # will be constructed dynamically when needed
torch = None
TORCH_AVAILABLE = False
class ModelLoader:
"""A class to load and hold PyTorch models used by this feature.
It loads:
- an FFT-based CNN (downloaded from Hugging Face Hub)
- an ELA-based document forgery detector (local .pth by default)
"""
def __init__(self, model_repo_id: str, model_filename: str, doc_model_path: str = None):
# Try to import torch once and expose module-level variables
global torch, TORCH_AVAILABLE
try:
import torch as _torch
torch = _torch
TORCH_AVAILABLE = True
except Exception:
torch = None
TORCH_AVAILABLE = False
print("[WARN] PyTorch not available; model loading will be skipped until torch is installed.")
if TORCH_AVAILABLE:
self.device = "cuda" if torch.cuda.is_available() else "cpu"
else:
self.device = "cpu"
print(f"Using device: {self.device} (torch available: {TORCH_AVAILABLE})")
# Load FFT CNN from HF Hub
self.fft_model = None
if TORCH_AVAILABLE:
try:
self.fft_model = self._load_fft_model(repo_id=model_repo_id, filename=model_filename)
print("FFT CNN model loaded successfully from Hub.")
except Exception:
# Try local fallback path (if provided in config)
self.fft_model = None
local_path = Path(getattr(Config, 'REAL_FORGED_MODEL_LOCAL_PATH', ''))
if local_path and local_path.exists():
try:
print(f"Attempting to load FFT model from local path: {local_path}")
model = FFTCNN()
state = torch.load(str(local_path), map_location=torch.device(self.device))
state_dict = state.get('state_dict', state) if isinstance(state, dict) else state
model.load_state_dict(state_dict, strict=False)
model.to(self.device)
model.eval()
self.fft_model = model
print("FFT CNN model loaded successfully from local path.")
except Exception as e:
print(f"Failed to load local FFT model: {e}")
else:
print("No local FFT model path configured or file missing; FFT model not loaded.")
else:
print("Skipping FFT model load because PyTorch is not installed.")
# Load document forgery model (ELA CNN), downloading the checkpoint if needed.
self.doc_model = None
if doc_model_path is None:
doc_model_path = Config.DOCUMENT_FORGERY_MODEL_PATH
self.doc_model = None
if TORCH_AVAILABLE:
try:
self.doc_model = self._load_document_forgery_model(Path(doc_model_path))
if self.doc_model is not None:
print("Document forgery (ELA) model loaded successfully.")
except Exception as e:
print(f"Warning: failed to load document forgery model: {e}")
else:
print("Skipping document forgery model load because PyTorch is not installed.")
def _load_fft_model(self, repo_id: str, filename: str):
"""Downloads and loads the FFT CNN model from a Hugging Face Hub repository."""
print(f"Attempting to download FFT CNN model from Hugging Face repo: {repo_id}")
try:
from huggingface_hub import hf_hub_download
except Exception as e:
raise RuntimeError(f"huggingface_hub not available: {e}")
try:
model_path = hf_hub_download(repo_id=repo_id, filename=filename, token=Config.HF_TOKEN)
print(f"Model downloaded to: {model_path}")
model = FFTCNN()
model.load_state_dict(torch.load(model_path, map_location=torch.device(self.device)))
model.to(self.device)
model.eval()
return model
except Exception as e:
print(f"Error downloading or loading FFT model from Hugging Face: {e}")
raise
def _load_document_forgery_model(self, path: Path):
"""Load the ELA-based document forgery model from a local .pth checkpoint.
Returns the model instance or None if the file does not exist.
"""
# If the configured path doesn't exist, try sensible fallbacks in the repo.
if not path.exists():
print(f"Document forgery model file not found at configured path: {path}")
# 1) Try the configured document forgery checkpoint path relative to repo root
repo_root = Path(__file__).resolve().parents[2]
candidate = repo_root / 'features' / 'Model' / 'document_forgery' / path.name
if candidate.exists():
path = candidate
print(f"Found document forgery model at fallback path: {path}")
else:
# 2) Search the repo for any file with the configured checkpoint name
print(f"Searching repository for '{path.name}'...")
matches = list(repo_root.rglob(path.name))
if matches:
path = matches[0]
print(f"Found document forgery model at: {path}")
else:
try:
path = self._download_document_forgery_model(path)
except Exception as exc:
print(f"Document forgery model not found in repository and download failed: {exc}")
return None
print(f"Loading document forgery model from: {path}")
# Build the ELA model architecture lazily (requires torchvision & torch.nn)
try:
import torchvision.models as tv_models
import torch.nn as nn
except Exception as e:
raise RuntimeError(f"Required packages for ELA model not available: {e}")
backbone = tv_models.efficientnet_b0(weights='IMAGENET1K_V1')
in_features = backbone.classifier[1].in_features
backbone.classifier = nn.Sequential(
nn.Dropout(p=0.4),
nn.Linear(in_features, 256),
nn.ReLU(inplace=True),
nn.Dropout(p=0.2),
nn.Linear(256, 2),
)
model = backbone
state = torch.load(str(path), map_location=torch.device(self.device))
# The checkpoint might be either a state_dict or a full checkpoint dict
if isinstance(state, dict) and 'state_dict' in state:
state_dict = state['state_dict']
else:
state_dict = state
# Attempt to load state dict; allow strict=False to be tolerant to minor key name differences
model.load_state_dict(state_dict, strict=False)
model.to(self.device)
model.eval()
return model
def _download_document_forgery_model(self, target_path: Path) -> Path:
"""Download the document forgery checkpoint into the configured local path."""
if hf_hub_download is None:
raise RuntimeError("huggingface_hub not available")
repo_id = getattr(Config, "DOCUMENT_FORGERY_MODEL_REPO_ID", Config.REAL_FORGED_MODEL_REPO_ID)
configured_name = getattr(Config, "DOCUMENT_FORGERY_MODEL_FILENAME", str(target_path))
candidate_filenames = []
for candidate in (configured_name, str(target_path), target_path.name):
if candidate and candidate not in candidate_filenames:
candidate_filenames.append(candidate)
last_error = None
for filename in candidate_filenames:
try:
print(f"Downloading document forgery model from Hugging Face repo: {repo_id} ({filename})")
downloaded_path = hf_hub_download(repo_id=repo_id, filename=filename, token=Config.HF_TOKEN)
target_path.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(downloaded_path, target_path)
print(f"Document forgery model downloaded to: {target_path}")
return target_path
except Exception as exc:
last_error = exc
raise RuntimeError(f"unable to download document forgery model: {last_error}")
# --- Global Model Instance ---
MODEL_REPO_ID = Config.REAL_FORGED_MODEL_REPO_ID
MODEL_FILENAME = Config.REAL_FORGED_MODEL_FILENAME
DOC_MODEL_PATH = Config.DOCUMENT_FORGERY_MODEL_PATH
models = ModelLoader(model_repo_id=MODEL_REPO_ID, model_filename=MODEL_FILENAME, doc_model_path=DOC_MODEL_PATH)
|