Feature Extraction
Transformers
Safetensors
PyTorch
phorensics
computer-vision
media-forensics
deepfake-detection
physics-based-vision
signal-processing
custom_code
Instructions to use Anuran66/Phorensics-Engine with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Anuran66/Phorensics-Engine with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="Anuran66/Phorensics-Engine", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Anuran66/Phorensics-Engine", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download phorensics_model.py from Anuran66/Phorensics-Engine: direct link, hf CLI and curl.
- Browser
- Download file 5.01 kB
-
https://huggingface.co/Anuran66/Phorensics-Engine/resolve/main/phorensics_model.py
- Command line
-
hf download hf://Anuran66/Phorensics-Engine/phorensics_model.py
-
curl -L -o phorensics_model.py https://huggingface.co/Anuran66/Phorensics-Engine/resolve/main/phorensics_model.py
5.01 kB
| import cv2 | |
| import torch | |
| import torch.nn.functional as F | |
| import numpy as np | |
| from transformers import PreTrainedModel, PretrainedConfig | |
| # ========================================== | |
| # 1. Hugging Face Configuration | |
| # ========================================== | |
| class PhorensicsConfig(PretrainedConfig): | |
| model_type = "phorensics" | |
| def __init__(self, max_dim=600, patch_size=128, stride=64, **kwargs): | |
| self.max_dim = max_dim | |
| self.patch_size = patch_size | |
| self.stride = stride | |
| super().__init__(**kwargs) | |
| # ========================================== | |
| # 2. Native PyTorch Physics Engine | |
| # ========================================== | |
| class PhorensicsModel(PreTrainedModel): | |
| config_class = PhorensicsConfig | |
| def __init__(self, config): | |
| super().__init__(config) | |
| self.patch_size = config.patch_size | |
| self.stride = config.stride | |
| # THE FIX: Hugging Face requires at least one parameter to determine model dtype. | |
| # This dummy parameter satisfies the push_to_hub internal checks. | |
| self.dummy_param = torch.nn.Parameter(torch.empty(0, dtype=torch.float32)) | |
| # STRUCTURAL TENSORS: Stored permanently in the .safetensors file. | |
| laplacian_kernel = torch.tensor([[[[0., 1., 0.], [1., -4., 1.], [0., 1., 0.]]]], dtype=torch.float32) | |
| self.register_buffer("noise_kernel", laplacian_kernel) | |
| self.register_buffer("safe_z_threshold", torch.tensor(2.5, dtype=torch.float32)) | |
| def _extract_patches(self, tensor): | |
| """Hardware-accelerated tensor unfolding (PyTorch native sliding window)""" | |
| c, h, w = tensor.shape | |
| pad_h = max(0, self.patch_size - h) if h < self.patch_size else 0 | |
| pad_w = max(0, self.patch_size - w) if w < self.patch_size else 0 | |
| if pad_h > 0 or pad_w > 0: | |
| tensor = F.pad(tensor, (0, pad_w, 0, pad_h), mode='reflect') | |
| patches = tensor.unfold(1, self.patch_size, self.stride).unfold(2, self.patch_size, self.stride) | |
| return patches.contiguous().view(c, -1, self.patch_size, self.patch_size).permute(1, 0, 2, 3) | |
| def forward(self, image_path): | |
| """ | |
| The native inference pass. Automatically handles CPU/CUDA routing. | |
| """ | |
| # 1. Load and Standardize Image | |
| img_bgr = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) | |
| if img_bgr is None: | |
| raise ValueError(f"Failed to load image: {image_path}") | |
| h, w = img_bgr.shape[:2] | |
| if max(h, w) > self.config.max_dim: | |
| scale = self.config.max_dim / max(h, w) | |
| img_bgr = cv2.resize(img_bgr, (int(w * scale), int(h * scale)), interpolation=cv2.INTER_AREA) | |
| # 2. TENSOR CONVERSION & GPU ACCELERATION | |
| gray_np = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY) | |
| # Move the image tensor to whatever device the model is currently on (CPU/CUDA) | |
| t_gray = torch.from_numpy(gray_np).to(self.device).float().unsqueeze(0).unsqueeze(0) | |
| # 3. SPATIAL TENSOR CONVOLUTION (PRNU Noise Validation) | |
| # Apply the .safetensors kernel across the image | |
| noise_map = F.conv2d(t_gray, self.noise_kernel, padding=1).squeeze(0) | |
| p_noise = self._extract_patches(noise_map) | |
| # Calculate robust Z-Score using pure vectorized PyTorch math | |
| patch_variances = torch.var(p_noise.view(p_noise.shape[0], -1), dim=1) | |
| median_var = torch.median(patch_variances) | |
| mad = torch.median(torch.abs(patch_variances - median_var)) + 1e-3 | |
| z_scores = 0.6745 * torch.abs(patch_variances - median_var) / mad | |
| max_noise_z = torch.quantile(z_scores, 0.98).item() | |
| # 4. FAST FOURIER TRANSFORM (Global Spectral Decay) | |
| f = np.fft.fft2(gray_np) | |
| power = np.abs(np.fft.fftshift(f))**2 | |
| h_fft, w_fft = power.shape | |
| cy, cx = h_fft // 2, w_fft // 2 | |
| y, x = np.indices((h_fft, w_fft)) | |
| r = np.sqrt((x - cx)**2 + (y - cy)**2).astype(int) | |
| radial_profile = np.bincount(r.ravel(), power.ravel()) / np.maximum(np.bincount(r.ravel()), 1) | |
| r_vals = np.arange(1, len(radial_profile)) | |
| p_vals = radial_profile[1:] | |
| slope, _ = np.polyfit(np.log10(r_vals), np.log10(p_vals + 1e-10), 1) | |
| alpha = (-slope) * 0.70 | |
| # 5. ENGINE FUSION | |
| threshold = self.safe_z_threshold.item() | |
| noise_threat = max(0.0, min(((max_noise_z - threshold) / 1.5) * 100.0, 100.0)) | |
| fft_threat = 99.9 if (2.0 <= alpha <= 3.5) else max(((alpha - 1.0) / 1.0) * 49.9, 0.0) | |
| final_prob = (noise_threat * 0.40) + (fft_threat * 0.60) | |
| return { | |
| "is_fake": final_prob >= 50.0, | |
| "threat_probability": round(min(final_prob, 99.9), 2), | |
| "max_noise_z": round(max_noise_z, 2), | |
| "fft_alpha_value": round(alpha, 3) | |
| } |