ahsanMah commited on
Commit
be66f33
·
1 Parent(s): 72232c2

init commit of files

Browse files
Files changed (3) hide show
  1. .gitignore +1 -0
  2. app.py +38 -0
  3. scorer.py +153 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ **/__pycache__/*
app.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pickle import load
2
+
3
+ import gradio as gr
4
+ import numpy as np
5
+ import torch
6
+
7
+ from scorer import build_model
8
+
9
+
10
+ def compute_gmm_likelihood(x_score, gmmdir='models'):
11
+ with open(f"{gmmdir}/gmm.pkl", "rb") as f:
12
+ clf = load(f)
13
+ nll = -clf.score(x_score)
14
+
15
+ with np.load(f"{gmmdir}/refscores.npz", "wb") as f:
16
+ ref_nll = f["arr_0"]
17
+ percentile = (ref_nll < nll).mean() * 100
18
+
19
+ return nll, percentile
20
+
21
+ def run_inference(img):
22
+ img = torch.from_numpy(img).permute(2,0,1).unsqueeze(0)
23
+ img = torch.nn.functional.interpolate(img, size=64, mode='bilinear')
24
+ model = build_model(device='cuda')
25
+ x = model(img.cuda())
26
+ x = x.square().sum(dim=(2, 3, 4)) ** 0.5
27
+ nll, pct = compute_gmm_likelihood(x.cpu())
28
+
29
+ return f"Image of shape: {img.shape} -> {nll:.3f}@{pct:.2f}"
30
+
31
+
32
+ demo = gr.Interface(
33
+ fn=run_inference,
34
+ inputs=["image"],
35
+ outputs=["text"],
36
+ )
37
+
38
+ demo.launch()
scorer.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pickle
3
+ from pickle import dump, load
4
+
5
+ import numpy as np
6
+ import PIL.Image
7
+ import torch
8
+ from sklearn.mixture import GaussianMixture
9
+ from sklearn.pipeline import Pipeline
10
+ from sklearn.preprocessing import StandardScaler
11
+ from tqdm import tqdm
12
+
13
+ import dnnlib
14
+
15
+
16
+ class EDMScorer(torch.nn.Module):
17
+ def __init__(
18
+ self,
19
+ net,
20
+ stop_ratio=0.8, # Maximum ratio of noise levels to compute
21
+ num_steps=10, # Number of noise levels to evaluate.
22
+ use_fp16=False, # Execute the underlying model at FP16 precision?
23
+ sigma_min=0.002, # Minimum supported noise level.
24
+ sigma_max=80, # Maximum supported noise level.
25
+ sigma_data=0.5, # Expected standard deviation of the training data.
26
+ rho=7, # Time step discretization.
27
+ device=torch.device("cpu"), # Device to use.
28
+ ):
29
+ super().__init__()
30
+ self.use_fp16 = use_fp16
31
+ self.sigma_min = sigma_min
32
+ self.sigma_max = sigma_max
33
+ self.sigma_data = sigma_data
34
+ self.net = net.eval()
35
+
36
+ # Adjust noise levels based on how far we want to accumulate
37
+ self.sigma_min = sigma_min
38
+ self.sigma_max = sigma_max * stop_ratio
39
+
40
+ step_indices = torch.arange(num_steps, dtype=torch.float64, device=device)
41
+ t_steps = (
42
+ sigma_max ** (1 / rho)
43
+ + step_indices
44
+ / (num_steps - 1)
45
+ * (sigma_min ** (1 / rho) - sigma_max ** (1 / rho))
46
+ ) ** rho
47
+ print("Using steps:", t_steps)
48
+
49
+ self.register_buffer("sigma_steps", t_steps.to(torch.float64))
50
+
51
+ @torch.inference_mode()
52
+ def forward(
53
+ self,
54
+ x,
55
+ force_fp32=False,
56
+ ):
57
+ x = x.to(torch.float32)
58
+
59
+ batch_scores = []
60
+ for sigma in self.sigma_steps:
61
+ xhat = self.net(x, sigma, force_fp32=force_fp32)
62
+ c_skip = self.net.sigma_data**2 / (sigma**2 + self.net.sigma_data**2)
63
+ score = xhat - (c_skip * x)
64
+
65
+ # score_norms = score.mean(1)
66
+ # score_norms = score.square().sum(dim=(1, 2, 3)) ** 0.5
67
+ batch_scores.append(score)
68
+ batch_scores = torch.stack(batch_scores, axis=1)
69
+
70
+ return batch_scores
71
+
72
+
73
+ def build_model(netpath=f"edm2-img64-s-1073741-0.075.pkl", device="cpu"):
74
+ model_root = "https://nvlabs-fi-cdn.nvidia.com/edm2/posthoc-reconstructions"
75
+ netpath = f"{model_root}/{netpath}"
76
+ with dnnlib.util.open_url(netpath, verbose=1) as f:
77
+ data = pickle.load(f)
78
+ net = data["ema"]
79
+ model = EDMScorer(net, num_steps=20).to(device)
80
+ return model
81
+
82
+
83
+ def train_gmm(score_path, outdir="out/msma/"):
84
+ X = torch.load(score_path)
85
+
86
+ gm = GaussianMixture(n_components=5, random_state=42)
87
+ clf = Pipeline([("scaler", StandardScaler()), ("GMM", gm)])
88
+ clf.fit(X)
89
+ inlier_nll = -clf.score_samples(X)
90
+
91
+ with open(f"{outdir}/refscores.npz", "wb") as f:
92
+ np.savez_compressed(f, inlier_nll)
93
+
94
+ with open(f"{outdir}/gmm.pkl", "wb") as f:
95
+ dump(clf, f, protocol=5)
96
+
97
+
98
+ def compute_gmm_likelihood(x_score, gmmdir):
99
+ with open(f"{gmmdir}/gmm.pkl", "rb") as f:
100
+ clf = load(f)
101
+ nll = -clf.score_samples(x_score)
102
+
103
+ with np.load(f"{gmmdir}/refscores.npz", "wb") as f:
104
+ ref_nll = f["arr_0"]
105
+ percentile = (ref_nll < nll).mean()
106
+
107
+ return nll, percentile
108
+
109
+
110
+ def test_runner(device="cpu"):
111
+ f = "goldfish.JPEG"
112
+ image = (PIL.Image.open(f)).resize((64, 64), PIL.Image.Resampling.LANCZOS)
113
+ image = np.array(image)
114
+ image = image.reshape(*image.shape[:2], -1).transpose(2, 0, 1)
115
+ x = torch.from_numpy(image).unsqueeze(0).to(device)
116
+ model = build_model(device=device)
117
+ scores = model(x)
118
+ return scores
119
+
120
+
121
+ def runner(dataset_path, device="cpu"):
122
+ dsobj = ImageFolderDataset(path=dataset_path, resolution=64)
123
+ refimg, reflabel = dsobj[0]
124
+ print(refimg.shape, refimg.dtype, reflabel)
125
+ dsloader = torch.utils.data.DataLoader(
126
+ dsobj, batch_size=48, num_workers=4, prefetch_factor=2
127
+ )
128
+
129
+ model = build_model(device=device)
130
+ score_norms = []
131
+
132
+ for x, _ in tqdm(dsloader):
133
+ s = model(x.to(device))
134
+ s = s.square().sum(dim=(2, 3, 4)) ** 0.5
135
+ score_norms.append(s.cpu())
136
+
137
+ score_norms = torch.cat(score_norms, dim=0)
138
+
139
+ os.makedirs("out/msma", exist_ok=True)
140
+ with open("out/msma/imagenette64_score_norms.pt", "wb") as f:
141
+ torch.save(score_norms, f)
142
+
143
+ print(f"Computed score norms for {score_norms.shape[0]} samples")
144
+
145
+
146
+ if __name__ == "__main__":
147
+ # runner("/GROND_STOR/amahmood/datasets/img64/", device="cuda")
148
+ train_gmm("out/msma/imagenette64_score_norms.pt")
149
+ s = test_runner(device="cuda")
150
+ s = s.square().sum(dim=(2, 3, 4)) ** 0.5
151
+ s = s.to("cpu").numpy()
152
+ nll, pct = compute_gmm_likelihood(s, gmmdir="out/msma/")
153
+ print(f"Anomaly score for image: {nll[0]:.3f} @ {pct*100:.2f} percentile")