anofit 0.1.0.dev0__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- anofit/__init__.py +32 -0
- anofit/__main__.py +6 -0
- anofit/_ed25519.cp313-win_amd64.pyd +0 -0
- anofit/_vendor/__init__.py +0 -0
- anofit/_vendor/csad_onnx.py +251 -0
- anofit/_vendor/logical.py +115 -0
- anofit/_vendor/model.py +191 -0
- anofit/_vendor/models/__init__.py +1 -0
- anofit/_vendor/models/segmentation/__init__.py +1 -0
- anofit/_vendor/models/segmentation/model.py +209 -0
- anofit/_vendor/seg_model.py +209 -0
- anofit/_vendor/structural.py +51 -0
- anofit/bundle.py +140 -0
- anofit/bundleio.py +233 -0
- anofit/cli.py +413 -0
- anofit/config.py +248 -0
- anofit/draw.py +59 -0
- anofit/engine/__init__.py +21 -0
- anofit/engine/compat.py +203 -0
- anofit/engine/determinism.py +134 -0
- anofit/fetch.py +362 -0
- anofit/fetch_manifest.json +82 -0
- anofit/jobs.py +252 -0
- anofit/licensing.cp313-win_amd64.pyd +0 -0
- anofit/modes.py +159 -0
- anofit/paths.py +94 -0
- anofit/preprocess.py +42 -0
- anofit/profile.py +226 -0
- anofit/profiles/_default.yaml +72 -0
- anofit/profiles/breakfast_box.yaml +70 -0
- anofit/profiles/juice_bottle.yaml +76 -0
- anofit/profiles/pushpins.yaml +86 -0
- anofit/profiles/screw_bag.yaml +101 -0
- anofit/profiles/splicing_connectors.yaml +70 -0
- anofit/quality.py +256 -0
- anofit/scoring.py +84 -0
- anofit/server.py +816 -0
- anofit/state.py +77 -0
- anofit/static/index.html +972 -0
- anofit/train/__init__.py +7 -0
- anofit/train/_boot.py +65 -0
- anofit/train/entry.py +669 -0
- anofit/train/ledger.py +84 -0
- anofit/train/logic/CSAD.py +590 -0
- anofit/train/logic/_ram/__init__.py +2 -0
- anofit/train/logic/_ram/configs/med_config.json +21 -0
- anofit/train/logic/_ram/configs/q2l_config.json +22 -0
- anofit/train/logic/_ram/configs/swin/config_swinB_224.json +9 -0
- anofit/train/logic/_ram/configs/swin/config_swinB_384.json +9 -0
- anofit/train/logic/_ram/configs/swin/config_swinL_224.json +9 -0
- anofit/train/logic/_ram/configs/swin/config_swinL_384.json +9 -0
- anofit/train/logic/_ram/data/__init__.py +71 -0
- anofit/train/logic/_ram/data/dataset.py +112 -0
- anofit/train/logic/_ram/data/ram_tag_list.txt +4585 -0
- anofit/train/logic/_ram/data/ram_tag_list_chinese.txt +4585 -0
- anofit/train/logic/_ram/data/ram_tag_list_threshold.txt +4585 -0
- anofit/train/logic/_ram/data/randaugment.py +340 -0
- anofit/train/logic/_ram/data/tag2text_ori_tag_list.txt +3429 -0
- anofit/train/logic/_ram/data/tag_list.txt +3429 -0
- anofit/train/logic/_ram/data/utils.py +112 -0
- anofit/train/logic/_ram/inference.py +46 -0
- anofit/train/logic/_ram/models/__init__.py +3 -0
- anofit/train/logic/_ram/models/bert.py +1088 -0
- anofit/train/logic/_ram/models/ram.py +409 -0
- anofit/train/logic/_ram/models/ram_plus.py +413 -0
- anofit/train/logic/_ram/models/swin_transformer.py +654 -0
- anofit/train/logic/_ram/models/tag2text.py +385 -0
- anofit/train/logic/_ram/models/utils.py +332 -0
- anofit/train/logic/_ram/models/vit.py +319 -0
- anofit/train/logic/_ram/transform.py +13 -0
- anofit/train/logic/_ram/utils/__init__.py +2 -0
- anofit/train/logic/_ram/utils/metrics.py +102 -0
- anofit/train/logic/_ram/utils/openset_utils.py +372 -0
- anofit/train/logic/_transformers_compat.py +171 -0
- anofit/train/logic/configs/class_histogram/breakfast_box.yaml +35 -0
- anofit/train/logic/configs/class_histogram/juice_bottle.yaml +34 -0
- anofit/train/logic/configs/class_histogram/pushpins.yaml +34 -0
- anofit/train/logic/configs/class_histogram/screw_bag.yaml +33 -0
- anofit/train/logic/configs/class_histogram/splicing_connectors.yaml +33 -0
- anofit/train/logic/configs/mvtecloco_train.yaml +27 -0
- anofit/train/logic/configs/segmentor/breakfast_box.yaml +29 -0
- anofit/train/logic/configs/segmentor/juice_bottle.yaml +29 -0
- anofit/train/logic/configs/segmentor/pushpins.yaml +29 -0
- anofit/train/logic/configs/segmentor/screw_bag.yaml +29 -0
- anofit/train/logic/configs/segmentor/splicing_connectors.yaml +29 -0
- anofit/train/logic/data_loader.py +191 -0
- anofit/train/logic/export_model.py +608 -0
- anofit/train/logic/extract_prompt.py +163 -0
- anofit/train/logic/grounded_sam.py +236 -0
- anofit/train/logic/groundingdino/__init__.py +0 -0
- anofit/train/logic/groundingdino/config/GroundingDINO_SwinB.py +43 -0
- anofit/train/logic/groundingdino/config/GroundingDINO_SwinT_OGC.py +43 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/__init__.py +15 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/backbone/__init__.py +1 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/backbone/backbone.py +221 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/backbone/position_encoding.py +186 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/backbone/swin_transformer.py +802 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/bertwarper.py +296 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/fuse_modules.py +297 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/groundingdino.py +395 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/ms_deform_attn.py +413 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/transformer.py +959 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/transformer_vanilla.py +123 -0
- anofit/train/logic/groundingdino/models/GroundingDINO/utils.py +268 -0
- anofit/train/logic/groundingdino/models/__init__.py +18 -0
- anofit/train/logic/groundingdino/models/registry.py +66 -0
- anofit/train/logic/groundingdino/util/__init__.py +1 -0
- anofit/train/logic/groundingdino/util/box_ops.py +140 -0
- anofit/train/logic/groundingdino/util/get_tokenlizer.py +26 -0
- anofit/train/logic/groundingdino/util/inference.py +257 -0
- anofit/train/logic/groundingdino/util/logger.py +93 -0
- anofit/train/logic/groundingdino/util/misc.py +717 -0
- anofit/train/logic/groundingdino/util/slconfig.py +427 -0
- anofit/train/logic/groundingdino/util/slio.py +177 -0
- anofit/train/logic/groundingdino/util/time_counter.py +62 -0
- anofit/train/logic/groundingdino/util/utils.py +608 -0
- anofit/train/logic/groundingdino/util/visualizer.py +318 -0
- anofit/train/logic/groundingdino/util/vl_utils.py +100 -0
- anofit/train/logic/groundingdino/version.py +1 -0
- anofit/train/logic/models/component_feature_extractor.py +227 -0
- anofit/train/logic/models/model.py +190 -0
- anofit/train/logic/models/onnx_model.py +220 -0
- anofit/train/logic/models/segmentation/dataloader.py +295 -0
- anofit/train/logic/models/segmentation/loss.py +248 -0
- anofit/train/logic/models/segmentation/lsa.py +273 -0
- anofit/train/logic/models/segmentation/model.py +208 -0
- anofit/train/logic/models/segmentation/patch_histogram.py +177 -0
- anofit/train/logic/models/segmentation/segmentor.py +416 -0
- anofit/train/logic/models/tflite_model.py +289 -0
- anofit/train/logic/preview_segmentation.py +200 -0
- anofit/train/logic/pseudo_label.py +1348 -0
- anofit/train/logic/ram_prompt.py +136 -0
- anofit/train/logic/segment_anything/__init__.py +22 -0
- anofit/train/logic/segment_anything/automatic_mask_generator.py +372 -0
- anofit/train/logic/segment_anything/build_sam.py +107 -0
- anofit/train/logic/segment_anything/build_sam_hq.py +114 -0
- anofit/train/logic/segment_anything/modeling/__init__.py +12 -0
- anofit/train/logic/segment_anything/modeling/common.py +43 -0
- anofit/train/logic/segment_anything/modeling/image_encoder.py +398 -0
- anofit/train/logic/segment_anything/modeling/mask_decoder.py +178 -0
- anofit/train/logic/segment_anything/modeling/mask_decoder_hq.py +232 -0
- anofit/train/logic/segment_anything/modeling/prompt_encoder.py +214 -0
- anofit/train/logic/segment_anything/modeling/sam.py +174 -0
- anofit/train/logic/segment_anything/modeling/transformer.py +240 -0
- anofit/train/logic/segment_anything/predictor.py +276 -0
- anofit/train/logic/segment_anything/utils/__init__.py +5 -0
- anofit/train/logic/segment_anything/utils/amg.py +346 -0
- anofit/train/logic/segment_anything/utils/onnx.py +144 -0
- anofit/train/logic/segment_anything/utils/transforms.py +102 -0
- anofit/train/logic/train_full.py +226 -0
- anofit/train/logic/train_light.py +606 -0
- anofit/train/logic/train_segmentor.py +151 -0
- anofit/train/preflight.py +188 -0
- anofit/train/select.py +212 -0
- anofit/train/split.py +118 -0
- anofit/train/struct/_numpy_compat.py +48 -0
- anofit/train/struct/ae.py +215 -0
- anofit/train/struct/argparser.py +18 -0
- anofit/train/struct/composition_map_creation/dataset.py +283 -0
- anofit/train/struct/composition_map_creation/dino/utils.py +693 -0
- anofit/train/struct/composition_map_creation/dino/vision_transformer.py +432 -0
- anofit/train/struct/composition_map_creation/modules.py +55 -0
- anofit/train/struct/composition_map_creation/pseudo_label_dataset.py +51 -0
- anofit/train/struct/composition_map_creation/unet.py +293 -0
- anofit/train/struct/create_fg_masks.py +102 -0
- anofit/train/struct/create_pseudo_labels.py +299 -0
- anofit/train/struct/dice_loss.py +58 -0
- anofit/train/struct/effad_networks.py +102 -0
- anofit/train/struct/eval_salad_plus.py +103 -0
- anofit/train/struct/logger.py +15 -0
- anofit/train/struct/salad_dataset.py +339 -0
- anofit/train/struct/salad_infer.py +291 -0
- anofit/train/struct/test_count.py +155 -0
- anofit/train/struct/test_salad.py +119 -0
- anofit/train/struct/train_composition_segmentation_model.py +185 -0
- anofit/train/struct/train_entry.py +335 -0
- anofit/train/struct/train_salad.py +781 -0
- anofit/train/struct/unet.py +348 -0
- anofit/train/struct/visualization_utils.py +35 -0
- anofit/train/tune.py +310 -0
- anofit-0.1.0.dev0.dist-info/METADATA +170 -0
- anofit-0.1.0.dev0.dist-info/RECORD +189 -0
- anofit-0.1.0.dev0.dist-info/WHEEL +5 -0
- anofit-0.1.0.dev0.dist-info/entry_points.txt +2 -0
- anofit-0.1.0.dev0.dist-info/licenses/LICENSE +53 -0
- anofit-0.1.0.dev0.dist-info/licenses/THIRD_PARTY_NOTICES.md +185 -0
- anofit-0.1.0.dev0.dist-info/licenses/licenses/Apache-2.0.txt +201 -0
- anofit-0.1.0.dev0.dist-info/licenses/licenses/MIT-SALAD.txt +21 -0
- anofit-0.1.0.dev0.dist-info/top_level.txt +1 -0
anofit/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""anofit — SCHAD 이상탐지 엔진 (구조부 + 논리부, 모드 선택).
|
|
2
|
+
|
|
3
|
+
geofit(찾기) · gaugefit(재기) 형제. 이쪽은 **가려내기**다.
|
|
4
|
+
|
|
5
|
+
import anofit
|
|
6
|
+
b = anofit.load("juice", mode="struct") # 학습된 분기의 부분집합만 허용
|
|
7
|
+
s, amap, parts = anofit.score(b, image_bgr)
|
|
8
|
+
|
|
9
|
+
알고리즘 이름은 계속 SCHAD 다 — `anofit` 은 그것을 담아 파는 제품의 이름이다.
|
|
10
|
+
"""
|
|
11
|
+
# ⚠ **torch/transformers 임포트 전에** 캐시 경로를 심는다. 라이브러리가 임포트 시점에
|
|
12
|
+
# 경로를 굳히므로 나중에 바꿔도 늦다. 아래 임포트들은 torch 를 지연 임포트하지만,
|
|
13
|
+
# 순서를 지키는 것이 규약이다.
|
|
14
|
+
from . import config as _config
|
|
15
|
+
|
|
16
|
+
_config.apply_cache_env()
|
|
17
|
+
|
|
18
|
+
from .bundle import BundleError, describe, evict, load
|
|
19
|
+
from .modes import BRANCHES, MODES, Mode, ModeError, available, resolve
|
|
20
|
+
from .scoring import fuse_from_raw, score, score_many, score_raw
|
|
21
|
+
from .quality import drift, mode_table, operating, roi_mismatch
|
|
22
|
+
from .state import ModelState, threshold_report
|
|
23
|
+
|
|
24
|
+
__version__ = "0.1.0.dev0"
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"load", "describe", "evict", "BundleError",
|
|
28
|
+
"score", "score_raw", "score_many", "fuse_from_raw",
|
|
29
|
+
"MODES", "Mode", "ModeError", "BRANCHES", "resolve", "available",
|
|
30
|
+
"ModelState", "threshold_report", "__version__",
|
|
31
|
+
"mode_table", "operating", "drift", "roi_mismatch",
|
|
32
|
+
]
|
anofit/__main__.py
ADDED
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file contains the ONNX/Pytorch model for CSAD.
|
|
3
|
+
"""
|
|
4
|
+
import timm
|
|
5
|
+
import torch
|
|
6
|
+
import torch.nn as nn
|
|
7
|
+
import torch.nn.functional as F
|
|
8
|
+
import torch.onnx
|
|
9
|
+
|
|
10
|
+
from .model import AutoEncoder, LocalStudent
|
|
11
|
+
from .seg_model import Segmentor
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FixedPatchClassDetector(nn.Module):
|
|
15
|
+
"""
|
|
16
|
+
Optimized version of patch histogram detector for fast speed
|
|
17
|
+
and support batched input.
|
|
18
|
+
(Predefined patch sizes and overlap ratios)
|
|
19
|
+
(not using EMPatches to extract patches)
|
|
20
|
+
"""
|
|
21
|
+
def __init__(self,num_classes=5,segmap_size=256,use_nahalanobis=True):
|
|
22
|
+
super().__init__()
|
|
23
|
+
self.num_classes = num_classes
|
|
24
|
+
self.segmap_size = segmap_size
|
|
25
|
+
|
|
26
|
+
self.use_nahalanobis = use_nahalanobis
|
|
27
|
+
|
|
28
|
+
self.hist_mean = torch.nn.Parameter(data=torch.randn((self.num_classes,1)),requires_grad=False)
|
|
29
|
+
self.hist_invcov = torch.nn.Parameter(data=torch.randn((self.num_classes,self.num_classes)),requires_grad=False)
|
|
30
|
+
self.patch_hist_mean = torch.nn.Parameter(data=torch.randn((self.num_classes*4,1)),requires_grad=False)
|
|
31
|
+
self.patch_hist_invcov = torch.nn.Parameter(data=torch.randn((self.num_classes*4,self.num_classes*4)),requires_grad=False)
|
|
32
|
+
self.hist_val_mean = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
33
|
+
self.hist_val_std = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
34
|
+
self.patch_hist_val_mean = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
35
|
+
self.patch_hist_val_std = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def set_params(self,params):
|
|
39
|
+
self.hist_mean = torch.nn.Parameter(data=params['hist_mean'].unsqueeze(1),requires_grad=False)
|
|
40
|
+
self.hist_invcov = torch.nn.Parameter(data=params['hist_invcov'],requires_grad=False)
|
|
41
|
+
self.patch_hist_mean = torch.nn.Parameter(data=params['patch_hist_mean'].unsqueeze(1),requires_grad=False)
|
|
42
|
+
self.patch_hist_invcov = torch.nn.Parameter(data=params['patch_hist_invcov'],requires_grad=False)
|
|
43
|
+
self.hist_val_mean = torch.nn.Parameter(data=params['hist_val_mean'],requires_grad=False)
|
|
44
|
+
self.hist_val_std = torch.nn.Parameter(data=params['hist_val_std'],requires_grad=False)
|
|
45
|
+
self.patch_hist_val_mean = torch.nn.Parameter(data=params['patch_hist_val_mean'],requires_grad=False)
|
|
46
|
+
self.patch_hist_val_std = torch.nn.Parameter(data=params['patch_hist_val_std'],requires_grad=False)
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def mahalanobis(u, v, invcov):
|
|
50
|
+
delta = u - v
|
|
51
|
+
m = torch.matmul(delta.T, torch.matmul(invcov, delta)).squeeze()
|
|
52
|
+
return torch.sqrt(m)
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def histogram(seg_map):
|
|
56
|
+
_, max_indices = torch.max(seg_map, dim=1)
|
|
57
|
+
# Create a tensor of zeros with the same shape as the input tensor
|
|
58
|
+
out = torch.zeros_like(seg_map)
|
|
59
|
+
# Set the max values to 1 by using advanced indexing
|
|
60
|
+
out.scatter_(1, max_indices.unsqueeze(1), 1)
|
|
61
|
+
hist = torch.mean(out,dim=[2,3])
|
|
62
|
+
hist = hist.unsqueeze(2)
|
|
63
|
+
return hist
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def patch_histogram(seg_map):
|
|
67
|
+
# patch_size = 128
|
|
68
|
+
a = seg_map[:,:,:128,:128]
|
|
69
|
+
b = seg_map[:,:,128:,:128]
|
|
70
|
+
c = seg_map[:,:,:128,128:]
|
|
71
|
+
d = seg_map[:,:,128:,128:]
|
|
72
|
+
return torch.concat([
|
|
73
|
+
FixedPatchClassDetector.histogram(a),
|
|
74
|
+
FixedPatchClassDetector.histogram(b),
|
|
75
|
+
FixedPatchClassDetector.histogram(c),
|
|
76
|
+
FixedPatchClassDetector.histogram(d)]
|
|
77
|
+
,dim=1)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def forward(self,segmap):
|
|
82
|
+
hist = FixedPatchClassDetector.histogram(segmap)
|
|
83
|
+
patch_hist = FixedPatchClassDetector.patch_histogram(segmap)
|
|
84
|
+
|
|
85
|
+
diff_hists = []
|
|
86
|
+
diff_patchhists = []
|
|
87
|
+
for i in range(segmap.shape[0]):
|
|
88
|
+
if self.use_nahalanobis:
|
|
89
|
+
diff_hist = FixedPatchClassDetector.mahalanobis(hist[i],self.hist_mean,self.hist_invcov)
|
|
90
|
+
diff_patchhist = FixedPatchClassDetector.mahalanobis(patch_hist[i],self.patch_hist_mean,self.patch_hist_invcov)
|
|
91
|
+
else:
|
|
92
|
+
diff_hist = ((hist[i]-self.hist_mean)**2).sum()**0.5
|
|
93
|
+
diff_patchhist = ((patch_hist[i]-self.patch_hist_mean)**2).sum()**0.5
|
|
94
|
+
diff_hists.append(diff_hist)
|
|
95
|
+
diff_patchhists.append(diff_patchhist)
|
|
96
|
+
diff_hist = torch.stack(diff_hists)
|
|
97
|
+
diff_patchhist = torch.stack(diff_patchhists)
|
|
98
|
+
|
|
99
|
+
diff_hist = (diff_hist-self.hist_val_mean)/self.hist_val_std
|
|
100
|
+
diff_patchhist = (diff_patchhist-self.patch_hist_val_mean)/self.patch_hist_val_std
|
|
101
|
+
|
|
102
|
+
out_score = diff_hist + diff_patchhist
|
|
103
|
+
return out_score
|
|
104
|
+
|
|
105
|
+
# without encoder
|
|
106
|
+
class ResNetTeacher(nn.Module):
|
|
107
|
+
def __init__(self,out_dim=512,feat_size=64):
|
|
108
|
+
super().__init__()
|
|
109
|
+
self.out_dim = out_dim
|
|
110
|
+
self.feat_size = feat_size
|
|
111
|
+
self.proj = nn.Conv2d(1024+512, self.out_dim, kernel_size=1, stride=1, padding=0)
|
|
112
|
+
self.proj.requires_grad_(False)
|
|
113
|
+
|
|
114
|
+
def forward(self, x):
|
|
115
|
+
x = [x[1],x[2]]
|
|
116
|
+
concat_feat = []
|
|
117
|
+
for i in range(len(x)):
|
|
118
|
+
feat = x[i]
|
|
119
|
+
feat = F.interpolate(feat, size=self.feat_size, mode='bilinear',align_corners=False)
|
|
120
|
+
concat_feat.append(feat)
|
|
121
|
+
concat_feat = torch.cat(concat_feat,dim=1)
|
|
122
|
+
concat_feat = nn.AvgPool2d(kernel_size=3, stride=1, padding=1)(concat_feat)
|
|
123
|
+
proj_feat = self.proj(concat_feat)
|
|
124
|
+
return proj_feat
|
|
125
|
+
|
|
126
|
+
class CSAD_ONNX(nn.Module):
|
|
127
|
+
def __init__(self,dim=512,num_classes=5):
|
|
128
|
+
super().__init__()
|
|
129
|
+
self.teacher_mean = torch.nn.Parameter(data=torch.randn((1,dim,1,1)),requires_grad=False)
|
|
130
|
+
self.teacher_std = torch.nn.Parameter(data=torch.randn((1,dim,1,1)),requires_grad=False)
|
|
131
|
+
|
|
132
|
+
self.q_st_start = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
133
|
+
self.q_st_end = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
134
|
+
self.q_ae_start = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
135
|
+
self.q_ae_end = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
136
|
+
|
|
137
|
+
self.lgst_mean = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
138
|
+
self.lgst_std = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
139
|
+
|
|
140
|
+
self.patch_hist_mean = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
141
|
+
self.patch_hist_std = torch.nn.Parameter(data=torch.randn(1)[0],requires_grad=False)
|
|
142
|
+
|
|
143
|
+
self.encoder = timm.create_model('hf_hub:timm/wide_resnet50_2.tv2_in1k'
|
|
144
|
+
,pretrained=True,
|
|
145
|
+
features_only=True,
|
|
146
|
+
out_indices=[1,2,3])
|
|
147
|
+
self.teacher = ResNetTeacher(out_dim=512,feat_size=64)
|
|
148
|
+
self.local_st = LocalStudent(out_dim=512,feat_size=64,padding=True)
|
|
149
|
+
self.autoencoder = AutoEncoder(out_dim=512,out_size=64)
|
|
150
|
+
self.segmentor = Segmentor(num_classes=num_classes)
|
|
151
|
+
self.patch_hist_detector = FixedPatchClassDetector(
|
|
152
|
+
num_classes=num_classes
|
|
153
|
+
,segmap_size=256,
|
|
154
|
+
use_nahalanobis=True
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def load_model_params(self,models,params):
|
|
158
|
+
self.teacher_mean = torch.nn.Parameter(data=params['teacher_mean'],requires_grad=False)
|
|
159
|
+
self.teacher_std = torch.nn.Parameter(data=params['teacher_std'],requires_grad=False)
|
|
160
|
+
|
|
161
|
+
self.q_st_start = torch.nn.Parameter(data=params['q_st_start'],requires_grad=False)
|
|
162
|
+
self.q_st_end = torch.nn.Parameter(data=params['q_st_end'],requires_grad=False)
|
|
163
|
+
self.q_ae_start = torch.nn.Parameter(data=params['q_ae_start'],requires_grad=False)
|
|
164
|
+
self.q_ae_end = torch.nn.Parameter(data=params['q_ae_end'],requires_grad=False)
|
|
165
|
+
|
|
166
|
+
self.lgst_mean = torch.nn.Parameter(data=params['lgst_mean'],requires_grad=False)
|
|
167
|
+
self.lgst_std = torch.nn.Parameter(data=params['lgst_std'],requires_grad=False)
|
|
168
|
+
if self.lgst_std < 1e-3:
|
|
169
|
+
self.lgst_std = torch.nn.Parameter(data=torch.tensor([1])[0],requires_grad=False)
|
|
170
|
+
|
|
171
|
+
self.patch_hist_mean = torch.nn.Parameter(data=params['patchhist_mean'],requires_grad=False)
|
|
172
|
+
self.patch_hist_std = torch.nn.Parameter(data=params['patchhist_std'],requires_grad=False)
|
|
173
|
+
if self.patch_hist_std < 1e-3:
|
|
174
|
+
self.patch_hist_std = torch.nn.Parameter(data=torch.tensor([1])[0],requires_grad=False)
|
|
175
|
+
|
|
176
|
+
self.encoder = models['encoder']
|
|
177
|
+
self.teacher = models['teacher']
|
|
178
|
+
self.local_st = models['local_st']
|
|
179
|
+
self.autoencoder = models['autoencoder']
|
|
180
|
+
self.segmentor = models['segmentor']
|
|
181
|
+
self.patch_hist_detector = models['patch_hist_detector']
|
|
182
|
+
return self
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@classmethod
|
|
186
|
+
def from_pretrained(cls,models,params):
|
|
187
|
+
num_classes = models['segmentor'].fc2.conv3.out_channels
|
|
188
|
+
return cls(num_classes=num_classes).load_model_params(models,params)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def forward(self, image):
|
|
192
|
+
# shape: (B,3,256,256)
|
|
193
|
+
feat = self.encoder(image)
|
|
194
|
+
|
|
195
|
+
# Patch Histogram branch
|
|
196
|
+
segmap = self.segmentor(feat)
|
|
197
|
+
# segmap = torch.argmax(segmap,dim=1)
|
|
198
|
+
patch_hist_score = self.patch_hist_detector(segmap)
|
|
199
|
+
|
|
200
|
+
# LGST branch
|
|
201
|
+
teacher_feat = self.teacher(feat)
|
|
202
|
+
teacher_feat = (teacher_feat-self.teacher_mean)/self.teacher_std
|
|
203
|
+
local_feat,global_feat = self.local_st(image)
|
|
204
|
+
ae_global_feat = self.autoencoder(image)
|
|
205
|
+
|
|
206
|
+
diff_local = torch.pow(teacher_feat-local_feat,2).mean(1)
|
|
207
|
+
diff_global = torch.pow(global_feat-ae_global_feat,2).mean(1)
|
|
208
|
+
|
|
209
|
+
# map normalization
|
|
210
|
+
diff_local = 0.1 * (diff_local - self.q_st_start) / (self.q_st_end - self.q_st_start)
|
|
211
|
+
diff_global = 0.1 * (diff_global - self.q_ae_start) / (self.q_ae_end - self.q_ae_start)
|
|
212
|
+
|
|
213
|
+
LGST_score = torch.amax(diff_local+diff_global,dim=(1,2))
|
|
214
|
+
|
|
215
|
+
# score fusion
|
|
216
|
+
LGST_score = (LGST_score-self.lgst_mean)/self.lgst_std
|
|
217
|
+
patch_hist_score = (patch_hist_score-self.patch_hist_mean)/self.patch_hist_std
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
return LGST_score+patch_hist_score
|
|
222
|
+
|
|
223
|
+
def forward_maps(self, image):
|
|
224
|
+
"""forward 와 동일 점수 + 오버레이용 2D 이상맵(LGST 공간맵, (B,64,64)) 반환.
|
|
225
|
+
|
|
226
|
+
patch-histogram(논리) 브랜치는 히스토그램 기반이라 자연스러운 공간맵이 없어,
|
|
227
|
+
오버레이는 LGST(구조) 공간맵으로 위치를 표시하고, 최종 점수에는 둘 다 반영된다.
|
|
228
|
+
"""
|
|
229
|
+
feat = self.encoder(image)
|
|
230
|
+
|
|
231
|
+
segmap = self.segmentor(feat)
|
|
232
|
+
patch_hist_score = self.patch_hist_detector(segmap)
|
|
233
|
+
|
|
234
|
+
teacher_feat = self.teacher(feat)
|
|
235
|
+
teacher_feat = (teacher_feat - self.teacher_mean) / self.teacher_std
|
|
236
|
+
local_feat, global_feat = self.local_st(image)
|
|
237
|
+
ae_global_feat = self.autoencoder(image)
|
|
238
|
+
|
|
239
|
+
diff_local = torch.pow(teacher_feat - local_feat, 2).mean(1)
|
|
240
|
+
diff_global = torch.pow(global_feat - ae_global_feat, 2).mean(1)
|
|
241
|
+
diff_local = 0.1 * (diff_local - self.q_st_start) / (self.q_st_end - self.q_st_start)
|
|
242
|
+
diff_global = 0.1 * (diff_global - self.q_ae_start) / (self.q_ae_end - self.q_ae_start)
|
|
243
|
+
|
|
244
|
+
lgst_map = diff_local + diff_global # (B,64,64)
|
|
245
|
+
LGST_score = torch.amax(lgst_map, dim=(1, 2))
|
|
246
|
+
|
|
247
|
+
LGST_score = (LGST_score - self.lgst_mean) / self.lgst_std
|
|
248
|
+
patch_hist_score = (patch_hist_score - self.patch_hist_mean) / self.patch_hist_std
|
|
249
|
+
|
|
250
|
+
score = LGST_score + patch_hist_score
|
|
251
|
+
return score, lgst_map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""SCHAD 논리부(patch-hist) — 벤더링된 CSAD LightCSAD 추론 코드.
|
|
2
|
+
|
|
3
|
+
원본: modules/csad/runner.py 의 LightCSAD/_light_segmentor/_preprocess/_get_transform.
|
|
4
|
+
schad 자립(standalone)을 위해 csad 모듈 의존 없이 _vendor 안으로 흡수한다.
|
|
5
|
+
encoder(timm wide_resnet50_2.tv2_in1k)·전처리(PIL BILINEAR)는 원본과 동일해야 점수가 재현된다.
|
|
6
|
+
|
|
7
|
+
오프라인 배포(CLAUDE.md §13-6): 인코더 가중치는 **프로젝트 내** weights/ 에 둔다.
|
|
8
|
+
과거엔 timm 이 `hf_hub:` 로 HuggingFace 를 직접 쳤고, 그러면 가중치가 프로젝트가 아니라
|
|
9
|
+
사용자 캐시(~/.cache/huggingface)에 떨어진다 — 프로젝트를 통째로 복사해도 인터넷 없는
|
|
10
|
+
현장 PC 에서 첫 로드가 실패한다(다른 모듈은 이미 weights/ 로 오프라인화돼 있었는데 여기만 누락).
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger("anofit.logical")
|
|
19
|
+
|
|
20
|
+
# 학습 때 쓴 인코더와 동일해야 한다 — 바꾸면 segmentor 가 학습한 특징과 어긋나 점수가 재현되지 않는다.
|
|
21
|
+
_ENCODER_MODEL = "wide_resnet50_2.tv2_in1k"
|
|
22
|
+
_ENCODER_KW = dict(features_only=True, out_indices=[1, 2, 3])
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _encoder_weight_path():
|
|
26
|
+
"""인코더 가중치 로컬 보관 경로(weights/timm__{모델}/encoder.pth)."""
|
|
27
|
+
from ..config import find_weight
|
|
28
|
+
|
|
29
|
+
return find_weight(f"timm__{_ENCODER_MODEL}/encoder.pth")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _build_encoder():
|
|
33
|
+
"""논리부 인코더 로드 — 오프라인 우선.
|
|
34
|
+
|
|
35
|
+
weights/ 에 받아둔 게 있으면 인터넷 없이 그것으로, 없으면 이때만 내려받아 weights/ 에
|
|
36
|
+
영속화한다(다음부터 오프라인 가능). patchcore/backbone.py 와 같은 방식.
|
|
37
|
+
"""
|
|
38
|
+
import timm
|
|
39
|
+
import torch
|
|
40
|
+
|
|
41
|
+
local = _encoder_weight_path()
|
|
42
|
+
if local.exists():
|
|
43
|
+
enc = timm.create_model(_ENCODER_MODEL, pretrained=False, **_ENCODER_KW)
|
|
44
|
+
enc.load_state_dict(torch.load(str(local), map_location="cpu"))
|
|
45
|
+
logger.info("논리부 인코더 로컬 로드: %s", local)
|
|
46
|
+
return enc
|
|
47
|
+
|
|
48
|
+
logger.info("논리부 인코더 다운로드: %s → %s", _ENCODER_MODEL, local)
|
|
49
|
+
try:
|
|
50
|
+
enc = timm.create_model(f"hf_hub:timm/{_ENCODER_MODEL}", pretrained=True, **_ENCODER_KW)
|
|
51
|
+
except Exception as exc:
|
|
52
|
+
from ..config import weights_root
|
|
53
|
+
|
|
54
|
+
raise RuntimeError(
|
|
55
|
+
f"논리부 인코더 로드 실패({_ENCODER_MODEL}): {exc}. "
|
|
56
|
+
f"오프라인 현장이면 인터넷 PC 에서 한 번 받아 '{weights_root()}' 폴더를 "
|
|
57
|
+
"현장 PC 로 복사하세요."
|
|
58
|
+
) from exc
|
|
59
|
+
try:
|
|
60
|
+
local.parent.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
torch.save(enc.state_dict(), str(local))
|
|
62
|
+
logger.info("논리부 인코더 영속화 완료: %s", local)
|
|
63
|
+
except OSError as exc:
|
|
64
|
+
logger.warning("인코더 로컬 저장 실패(%s): %s — 이번 세션은 그대로 동작", local, exc)
|
|
65
|
+
return enc
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _light_segmentor(num_classes, in_dim, state_dict):
|
|
69
|
+
"""벤더링된 Segmentor 재구성(추론 전용)."""
|
|
70
|
+
from .models.segmentation.model import Segmentor # 벤더 상대 import
|
|
71
|
+
|
|
72
|
+
seg = Segmentor(num_classes=num_classes, in_dim=in_dim, in_size=256)
|
|
73
|
+
seg.load_state_dict(state_dict)
|
|
74
|
+
return seg.eval()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def LightCSAD(bundle):
|
|
78
|
+
import torch
|
|
79
|
+
import torch.nn as nn
|
|
80
|
+
|
|
81
|
+
from .csad_onnx import FixedPatchClassDetector
|
|
82
|
+
|
|
83
|
+
nc = int(bundle["num_classes"])
|
|
84
|
+
p = bundle["patchhist_params"]
|
|
85
|
+
|
|
86
|
+
class _LightCSAD(nn.Module):
|
|
87
|
+
def __init__(self):
|
|
88
|
+
super().__init__()
|
|
89
|
+
# 학습 때와 동일 encoder (segmentor 가 이 특징으로 학습됨) — weights/ 오프라인 우선
|
|
90
|
+
self.encoder = _build_encoder()
|
|
91
|
+
for q in self.encoder.parameters():
|
|
92
|
+
q.requires_grad = False
|
|
93
|
+
self.segmentor = _light_segmentor(nc, bundle.get("in_dim", [256, 1024]),
|
|
94
|
+
bundle["segmentor_state"])
|
|
95
|
+
self.patch_hist_detector = FixedPatchClassDetector(num_classes=nc, segmap_size=256, use_nahalanobis=True)
|
|
96
|
+
t = lambda x: torch.tensor(np.asarray(x), dtype=torch.float32)
|
|
97
|
+
self.patch_hist_detector.set_params({
|
|
98
|
+
"hist_mean": t(p["hist_mean"]), "hist_invcov": t(p["hist_invcov"]),
|
|
99
|
+
"patch_hist_mean": t(p["patch_hist_mean"]), "patch_hist_invcov": t(p["patch_hist_invcov"]),
|
|
100
|
+
"hist_val_mean": t(p["hist_val_mean"]), "hist_val_std": t(p["hist_val_std"]),
|
|
101
|
+
"patch_hist_val_mean": t(p["patch_hist_val_mean"]), "patch_hist_val_std": t(p["patch_hist_val_std"]),
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
def forward(self, image):
|
|
105
|
+
return self.patch_hist_detector(self.segmentor(self.encoder(image)))
|
|
106
|
+
|
|
107
|
+
def forward_maps(self, image):
|
|
108
|
+
# 경량(patch-hist)은 히스토그램 기반이라 공간 이상맵이 없음 → 오버레이 None
|
|
109
|
+
return self.forward(image), None
|
|
110
|
+
|
|
111
|
+
return _LightCSAD()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# 전처리(_get_transform/_preprocess)는 anofit/preprocess.py 로 옮겼다 (기획서 §3.4-2).
|
|
115
|
+
# 구조부 전용 경로가 논리부 모듈을 import 하지 않게 하려는 것이 목적이다.
|
anofit/_vendor/model.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
|
|
2
|
+
import timm
|
|
3
|
+
import torch
|
|
4
|
+
import torch.nn as nn
|
|
5
|
+
import torch.nn.functional as F
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PDN_M(nn.Module):
|
|
9
|
+
def __init__(self, out_dim=512,feat_size=64,padding=False):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.out_dim = out_dim
|
|
12
|
+
self.st_size = feat_size
|
|
13
|
+
self.ae_size = feat_size
|
|
14
|
+
self.padding = 1 if padding else 0
|
|
15
|
+
self.conv1 = nn.Conv2d(3, 256, kernel_size=4, stride=1, padding=3*self.padding)
|
|
16
|
+
self.conv2 = nn.Conv2d(256, 512, kernel_size=4, stride=1, padding=3*self.padding)
|
|
17
|
+
self.conv3 = nn.Conv2d(512, 512, kernel_size=1, stride=1, padding=0)
|
|
18
|
+
self.conv4 = nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1*self.padding)
|
|
19
|
+
self.conv5 = nn.Conv2d(512, self.out_dim*2, kernel_size=4, stride=1, padding=0)
|
|
20
|
+
self.conv6 = nn.Conv2d(self.out_dim*2, self.out_dim*2, kernel_size=1, stride=1, padding=0)
|
|
21
|
+
self.avgpool1 = nn.AvgPool2d(kernel_size=2, stride=2, padding=1*self.padding)
|
|
22
|
+
self.avgpool2 = nn.AvgPool2d(kernel_size=2, stride=2, padding=1*self.padding)
|
|
23
|
+
|
|
24
|
+
def forward(self, x):
|
|
25
|
+
x = self.conv1(x)
|
|
26
|
+
x = F.relu(x)
|
|
27
|
+
x = self.avgpool1(x)
|
|
28
|
+
x = self.conv2(x)
|
|
29
|
+
x = F.relu(x)
|
|
30
|
+
x = self.avgpool2(x)
|
|
31
|
+
x = self.conv3(x)
|
|
32
|
+
x = F.relu(x)
|
|
33
|
+
x = self.conv4(x)
|
|
34
|
+
x = F.relu(x)
|
|
35
|
+
x = self.conv5(x)
|
|
36
|
+
x = F.relu(x)
|
|
37
|
+
x = self.conv6(x)
|
|
38
|
+
# x = F.relu(x)
|
|
39
|
+
x = F.interpolate(x, size=self.st_size, mode='bilinear', align_corners=False)
|
|
40
|
+
st = x[:,:self.out_dim]
|
|
41
|
+
ae = x[:,self.out_dim:]
|
|
42
|
+
return st,ae
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class LocalStudent(nn.Module):
|
|
46
|
+
|
|
47
|
+
def __init__(self, out_dim=512,feat_size=64,padding=False):
|
|
48
|
+
super().__init__()
|
|
49
|
+
self.out_dim = out_dim
|
|
50
|
+
self.feat_size = feat_size
|
|
51
|
+
self.padding = 1 if padding else 0
|
|
52
|
+
self.conv1 = nn.Conv2d(3, 256, kernel_size=4, stride=1, padding=3*self.padding)
|
|
53
|
+
self.conv2 = nn.Conv2d(256, 512, kernel_size=4, stride=1, padding=3*self.padding)
|
|
54
|
+
self.conv3 = nn.Conv2d(512, 512, kernel_size=1, stride=1, padding=0)
|
|
55
|
+
self.conv4 = nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1*self.padding)
|
|
56
|
+
self.conv5 = nn.Conv2d(512, self.out_dim, kernel_size=4, stride=1, padding=0)
|
|
57
|
+
# self.conv6 = nn.Conv2d(self.out_dim, self.out_dim, kernel_size=1, stride=1, padding=0)
|
|
58
|
+
|
|
59
|
+
self.avgpool1 = nn.AvgPool2d(kernel_size=2, stride=2, padding=1*self.padding)
|
|
60
|
+
self.avgpool2 = nn.AvgPool2d(kernel_size=2, stride=2, padding=1*self.padding)
|
|
61
|
+
|
|
62
|
+
self.conv_st = nn.Conv2d(self.out_dim, self.out_dim, kernel_size=1, stride=1, padding=0)
|
|
63
|
+
self.conv_ae = nn.Conv2d(self.out_dim, self.out_dim, kernel_size=1, stride=1, padding=0)
|
|
64
|
+
|
|
65
|
+
def forward(self, x):
|
|
66
|
+
x = self.conv1(x)
|
|
67
|
+
x = F.relu(x)
|
|
68
|
+
x = self.avgpool1(x)
|
|
69
|
+
x = self.conv2(x)
|
|
70
|
+
x = F.relu(x)
|
|
71
|
+
x = self.avgpool2(x)
|
|
72
|
+
x = self.conv3(x)
|
|
73
|
+
x = F.relu(x)
|
|
74
|
+
x = self.conv4(x)
|
|
75
|
+
x = F.relu(x)
|
|
76
|
+
x = self.conv5(x)
|
|
77
|
+
x = F.relu(x)
|
|
78
|
+
x = F.interpolate(x, size=self.feat_size, mode='bilinear', align_corners=False)
|
|
79
|
+
st = self.conv_st(x)
|
|
80
|
+
ae = self.conv_ae(x)
|
|
81
|
+
return st,ae
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class AutoEncoder(nn.Module):
|
|
86
|
+
def __init__(self, out_size=64,out_dim=512,base_dim=64):
|
|
87
|
+
super().__init__()
|
|
88
|
+
self.out_dim = out_dim
|
|
89
|
+
self.base_dim = base_dim
|
|
90
|
+
self.out_size = out_size
|
|
91
|
+
|
|
92
|
+
self.enconv1 = nn.Conv2d(3, self.base_dim//2, kernel_size=4, stride=2, padding=1)
|
|
93
|
+
self.enconv2 = nn.Conv2d(self.base_dim//2, self.base_dim//2, kernel_size=4, stride=2, padding=1)
|
|
94
|
+
self.enconv3 = nn.Conv2d(self.base_dim//2, self.base_dim, kernel_size=4, stride=2, padding=1)
|
|
95
|
+
self.enconv4 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=4, stride=2, padding=1)
|
|
96
|
+
self.enconv5 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=4, stride=2, padding=1)
|
|
97
|
+
self.enconv6 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=8, stride=1, padding=0)
|
|
98
|
+
|
|
99
|
+
self.deconv1 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=4, stride=1, padding=2)
|
|
100
|
+
self.deconv2 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=4, stride=1, padding=2)
|
|
101
|
+
self.deconv3 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=4, stride=1, padding=2)
|
|
102
|
+
self.deconv4 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=4, stride=1, padding=2)
|
|
103
|
+
self.deconv5 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=4, stride=1, padding=2)
|
|
104
|
+
self.deconv6 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=4, stride=1, padding=2)
|
|
105
|
+
self.deconv7 = nn.Conv2d(self.base_dim, self.base_dim, kernel_size=3, stride=1, padding=1)
|
|
106
|
+
self.deconv8 = nn.Conv2d(self.base_dim, self.out_dim, kernel_size=3, stride=1, padding=1)
|
|
107
|
+
self.dropout1 = nn.Dropout(p=0.2)
|
|
108
|
+
self.dropout2 = nn.Dropout(p=0.2)
|
|
109
|
+
self.dropout3 = nn.Dropout(p=0.2)
|
|
110
|
+
self.dropout4 = nn.Dropout(p=0.2)
|
|
111
|
+
self.dropout5 = nn.Dropout(p=0.2)
|
|
112
|
+
self.dropout6 = nn.Dropout(p=0.2)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def forward(self, x):
|
|
116
|
+
x1 = F.relu(self.enconv1(x))
|
|
117
|
+
x2 = F.relu(self.enconv2(x1))
|
|
118
|
+
x3 = F.relu(self.enconv3(x2))
|
|
119
|
+
x4 = F.relu(self.enconv4(x3))
|
|
120
|
+
x5 = F.relu(self.enconv5(x4))
|
|
121
|
+
x6 = self.enconv6(x5)
|
|
122
|
+
|
|
123
|
+
x = F.interpolate(x6, size=3, mode='bilinear')
|
|
124
|
+
x = F.relu(self.deconv1(x))
|
|
125
|
+
x = self.dropout1(x)
|
|
126
|
+
x = F.interpolate(x, size=8, mode='bilinear')
|
|
127
|
+
x = F.relu(self.deconv2(x))
|
|
128
|
+
x = self.dropout2(x)
|
|
129
|
+
x = F.interpolate(x, size=15, mode='bilinear')
|
|
130
|
+
x = F.relu(self.deconv3(x))
|
|
131
|
+
x = self.dropout3(x)
|
|
132
|
+
x = F.interpolate(x, size=32, mode='bilinear')
|
|
133
|
+
x = F.relu(self.deconv4(x))
|
|
134
|
+
x = self.dropout4(x)
|
|
135
|
+
x = F.interpolate(x, size=63, mode='bilinear')
|
|
136
|
+
x = F.relu(self.deconv5(x))
|
|
137
|
+
x = self.dropout5(x)
|
|
138
|
+
x = F.interpolate(x, size=127, mode='bilinear')
|
|
139
|
+
x = F.relu(self.deconv6(x))
|
|
140
|
+
x = self.dropout6(x)
|
|
141
|
+
x = F.interpolate(x, size=self.out_size, mode='bilinear')
|
|
142
|
+
x = F.relu(self.deconv7(x))
|
|
143
|
+
x = self.deconv8(x)
|
|
144
|
+
return x
|
|
145
|
+
|
|
146
|
+
class ResNetTeacher(nn.Module):
|
|
147
|
+
def __init__(self,out_dim=512,feat_size=64):
|
|
148
|
+
super().__init__()
|
|
149
|
+
# hf_hub:timm/wide_resnet50_2.tv2_in1k
|
|
150
|
+
# hf_hub:timm/wide_resnet50_2.racm_in1k
|
|
151
|
+
self.encoder = timm.create_model('hf_hub:timm/wide_resnet50_2.tv2_in1k'
|
|
152
|
+
,pretrained=True,
|
|
153
|
+
features_only=True,
|
|
154
|
+
out_indices=[2,3])
|
|
155
|
+
for param in self.encoder.parameters():
|
|
156
|
+
param.requires_grad = False
|
|
157
|
+
self.encoder.eval()
|
|
158
|
+
self.out_dim = out_dim
|
|
159
|
+
self.feat_size = feat_size
|
|
160
|
+
self.proj = nn.Conv2d(1024+512, self.out_dim, kernel_size=1, stride=1, padding=0)
|
|
161
|
+
self.proj.requires_grad_(False)
|
|
162
|
+
|
|
163
|
+
def forward(self, x):
|
|
164
|
+
x = self.encoder(x)
|
|
165
|
+
concat_feat = []
|
|
166
|
+
for i in range(len(x)):
|
|
167
|
+
feat = x[i]
|
|
168
|
+
feat = F.interpolate(feat, size=self.feat_size, mode='bilinear',align_corners=False)
|
|
169
|
+
concat_feat.append(feat)
|
|
170
|
+
concat_feat = torch.cat(concat_feat,dim=1)
|
|
171
|
+
concat_feat = nn.AvgPool2d(kernel_size=3, stride=1, padding=1)(concat_feat)
|
|
172
|
+
proj_feat = self.proj(concat_feat)
|
|
173
|
+
return proj_feat
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
if __name__ == '__main__':
|
|
179
|
+
|
|
180
|
+
import torch
|
|
181
|
+
import torchsummary
|
|
182
|
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
|
183
|
+
|
|
184
|
+
model = AutoEncoder(
|
|
185
|
+
out_size=64,
|
|
186
|
+
out_dim=512,
|
|
187
|
+
base_dim=64,
|
|
188
|
+
input_size=256
|
|
189
|
+
).cuda()
|
|
190
|
+
torchsummary.summary(model, (3, 256, 256))
|
|
191
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""벤더링된 CSAD 논리부(patch-hist) — schad 자립용. 원본: modules/csad."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""벤더링된 CSAD segmentation 모델(Segmentor) — schad 논리부용."""
|