Upload agents/model_agent.py with huggingface_hub
Browse files- agents/model_agent.py +108 -2
agents/model_agent.py
CHANGED
|
@@ -213,13 +213,119 @@ def analyze_model_fingerprint(img: Image.Image) -> Dict[str, Any]:
|
|
| 213 |
}
|
| 214 |
|
| 215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
# βββ Main Agent Entry Point βββββββββββββββββββββββββββββββββββββββββ
|
| 217 |
def run_model_agent(img: Image.Image) -> AgentEvidence:
|
| 218 |
"""Run all generative model detection tests."""
|
| 219 |
findings = []
|
| 220 |
scores = []
|
| 221 |
|
| 222 |
-
for fn in [analyze_frequency_grid, analyze_diffusion_residuals, analyze_model_fingerprint
|
|
|
|
| 223 |
try:
|
| 224 |
result = fn(img)
|
| 225 |
findings.append(result)
|
|
@@ -248,7 +354,7 @@ def run_model_agent(img: Image.Image) -> AgentEvidence:
|
|
| 248 |
agent_name="Generative Model Agent",
|
| 249 |
violation_score=np.clip(avg_score, -1, 1),
|
| 250 |
confidence=confidence,
|
| 251 |
-
failure_prob=max(0.0, 1.0 - len(scores) /
|
| 252 |
rationale=rationale,
|
| 253 |
sub_findings=findings,
|
| 254 |
)
|
|
|
|
| 213 |
}
|
| 214 |
|
| 215 |
|
| 216 |
+
# βββ GAN Upsampling Checkerboard βββββββββββββββββββββββββββββββββββββ
|
| 217 |
+
def analyze_upsampling_checkerboard(img: Image.Image) -> Dict[str, Any]:
|
| 218 |
+
"""
|
| 219 |
+
Transposed convolutions in GANs create checkerboard patterns.
|
| 220 |
+
Detected via pixel-level autocorrelation at lag=2.
|
| 221 |
+
"""
|
| 222 |
+
gray = np.array(img.convert("L")).astype(np.float64)
|
| 223 |
+
h, w = gray.shape
|
| 224 |
+
|
| 225 |
+
# Compute autocorrelation at lag 2 (checkerboard period)
|
| 226 |
+
if h < 10 or w < 10:
|
| 227 |
+
return {"test": "Upsampling Checkerboard", "score": 0.0, "note": "Image too small"}
|
| 228 |
+
|
| 229 |
+
# Horizontal lag-2 autocorrelation
|
| 230 |
+
h_auto = float(np.corrcoef(gray[:, :-2].ravel(), gray[:, 2:].ravel())[0, 1])
|
| 231 |
+
# Vertical lag-2
|
| 232 |
+
v_auto = float(np.corrcoef(gray[:-2, :].ravel(), gray[2:, :].ravel())[0, 1])
|
| 233 |
+
|
| 234 |
+
# Compare lag-1 vs lag-2 (checkerboard: lag-2 > lag-1)
|
| 235 |
+
h_auto1 = float(np.corrcoef(gray[:, :-1].ravel(), gray[:, 1:].ravel())[0, 1])
|
| 236 |
+
v_auto1 = float(np.corrcoef(gray[:-1, :].ravel(), gray[1:, :].ravel())[0, 1])
|
| 237 |
+
|
| 238 |
+
# Checkerboard signature: lag-2 corr noticeably higher than lag-1
|
| 239 |
+
h_checker = h_auto - h_auto1
|
| 240 |
+
v_checker = v_auto - v_auto1
|
| 241 |
+
checker_score = (h_checker + v_checker) / 2
|
| 242 |
+
|
| 243 |
+
if checker_score > 0.02:
|
| 244 |
+
score = 0.5
|
| 245 |
+
note = f"Checkerboard pattern detected (Ξcorr={checker_score:.4f}, GAN upsampling artifact)"
|
| 246 |
+
elif checker_score > 0.005:
|
| 247 |
+
score = 0.2
|
| 248 |
+
note = f"Mild checkerboard tendency (Ξcorr={checker_score:.4f})"
|
| 249 |
+
else:
|
| 250 |
+
score = -0.1
|
| 251 |
+
note = f"No checkerboard pattern (Ξcorr={checker_score:.4f})"
|
| 252 |
+
|
| 253 |
+
return {
|
| 254 |
+
"test": "Upsampling Checkerboard",
|
| 255 |
+
"checker_delta": round(checker_score, 6),
|
| 256 |
+
"h_lag2": round(h_auto, 4),
|
| 257 |
+
"v_lag2": round(v_auto, 4),
|
| 258 |
+
"score": score,
|
| 259 |
+
"note": note,
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
# βββ VAE Boundary Artifacts βββββββββββββββββββββββββββββββββββββββββ
|
| 264 |
+
def analyze_vae_boundaries(img: Image.Image) -> Dict[str, Any]:
|
| 265 |
+
"""
|
| 266 |
+
VAE-based generators (Stable Diffusion) process in latent patches.
|
| 267 |
+
This can create subtle boundary artifacts at 64x64 or 32x32 grid.
|
| 268 |
+
"""
|
| 269 |
+
gray = np.array(img.convert("L")).astype(np.float64)
|
| 270 |
+
h, w = gray.shape
|
| 271 |
+
|
| 272 |
+
# Check for grid artifacts at common VAE patch sizes
|
| 273 |
+
best_score = 0.0
|
| 274 |
+
best_size = 0
|
| 275 |
+
best_ratio = 1.0
|
| 276 |
+
|
| 277 |
+
for patch_size in [32, 64, 128]:
|
| 278 |
+
if h < patch_size * 2 or w < patch_size * 2:
|
| 279 |
+
continue
|
| 280 |
+
|
| 281 |
+
h_crop = (h // patch_size) * patch_size
|
| 282 |
+
w_crop = (w // patch_size) * patch_size
|
| 283 |
+
g = gray[:h_crop, :w_crop]
|
| 284 |
+
|
| 285 |
+
# Measure intensity discontinuity at patch boundaries
|
| 286 |
+
boundary_diffs = []
|
| 287 |
+
interior_diffs = []
|
| 288 |
+
|
| 289 |
+
for i in range(1, h_crop):
|
| 290 |
+
row_diff = np.abs(g[i, :] - g[i - 1, :])
|
| 291 |
+
if i % patch_size == 0:
|
| 292 |
+
boundary_diffs.append(float(np.mean(row_diff)))
|
| 293 |
+
elif i % patch_size != 1:
|
| 294 |
+
interior_diffs.append(float(np.mean(row_diff)))
|
| 295 |
+
|
| 296 |
+
if boundary_diffs and interior_diffs:
|
| 297 |
+
ratio = float(np.mean(boundary_diffs)) / (float(np.mean(interior_diffs)) + 1e-9)
|
| 298 |
+
if ratio > best_ratio:
|
| 299 |
+
best_ratio = ratio
|
| 300 |
+
best_size = patch_size
|
| 301 |
+
|
| 302 |
+
if best_ratio > 1.3:
|
| 303 |
+
score = 0.4
|
| 304 |
+
note = f"VAE boundary artifacts at {best_size}px grid (ratio={best_ratio:.3f})"
|
| 305 |
+
elif best_ratio > 1.1:
|
| 306 |
+
score = 0.2
|
| 307 |
+
note = f"Weak boundary artifacts at {best_size}px (ratio={best_ratio:.3f})"
|
| 308 |
+
else:
|
| 309 |
+
score = -0.1
|
| 310 |
+
note = f"No VAE boundary artifacts (max ratio={best_ratio:.3f})"
|
| 311 |
+
|
| 312 |
+
return {
|
| 313 |
+
"test": "VAE Boundary Artifacts",
|
| 314 |
+
"best_boundary_ratio": round(best_ratio, 4),
|
| 315 |
+
"best_patch_size": best_size,
|
| 316 |
+
"score": score,
|
| 317 |
+
"note": note,
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
|
| 321 |
# βββ Main Agent Entry Point βββββββββββββββββββββββββββββββββββββββββ
|
| 322 |
def run_model_agent(img: Image.Image) -> AgentEvidence:
|
| 323 |
"""Run all generative model detection tests."""
|
| 324 |
findings = []
|
| 325 |
scores = []
|
| 326 |
|
| 327 |
+
for fn in [analyze_frequency_grid, analyze_diffusion_residuals, analyze_model_fingerprint,
|
| 328 |
+
analyze_upsampling_checkerboard, analyze_vae_boundaries]:
|
| 329 |
try:
|
| 330 |
result = fn(img)
|
| 331 |
findings.append(result)
|
|
|
|
| 354 |
agent_name="Generative Model Agent",
|
| 355 |
violation_score=np.clip(avg_score, -1, 1),
|
| 356 |
confidence=confidence,
|
| 357 |
+
failure_prob=max(0.0, 1.0 - len(scores) / 5),
|
| 358 |
rationale=rationale,
|
| 359 |
sub_findings=findings,
|
| 360 |
)
|