[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-105400":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":16,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":17,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":32,"readmeContent":33,"aiSummary":10,"trendingCount":15,"starSnapshotCount":15,"syncStatus":34,"lastSyncTime":35,"discoverSource":36},105400,"PatchCore","lee-dro\u002FPatchCore","lee-dro","基于 PatchCore 的工业异常检测项目，研究 layer2\u002Flayer3 分数融合、敏感性引导收缩与风险受控门控，并提供 Streamlit 工程化 Demo。","",null,"Python",121,28,1,0,29,87,77.74,"Apache License 2.0",false,"main",true,[24,25,26,27,28,29,30,31],"anomaly-detection","computer-vision","feature-fusion","industrial-anomaly-detection","mvtec-ad","patchcore","pytorch","semantic-segmentation","2026-11-01 00:15:52","# PatchCore 工业异常检测与工程化 Demo\n\n本仓库基于 Roth 等人提出的 PatchCore，用于工业图像异常检测与缺陷定位：\n\n- 复现 PatchCore 的记忆库、近邻搜索和异常图生成流程；\n- 研究 `layer2` 与 `layer3` 独立分支的图像级\u002F像素级分数融合；\n- 对比固定融合、合成缺陷敏感性收缩和风险受控门控策略；\n- 提供可直接运行的 Streamlit 单图检测 Demo，展示判定、热力图、分支诊断和 JSON 结果。\n\n## 项目亮点\n\n研究部分在 15 个 MVTec AD 类别和多随机种子上分析了检测与定位之间的权衡、类别依赖性、\n随机波动和额外计算成本。当前实验结果显示，门控融合在部分类别上能够带来像素级定位收益，\n但提升并非普适，因此项目将其定位为带固定权重回退的实验策略，而不是无条件优于基线的\n“通用自适应算法”。\n\n工程化 Demo 支持四种明确模式：\n\n1. 原论文 PatchCore（`layer2+layer3` 单记忆库）；\n2. 固定融合基线；\n3. 敏感性收缩融合（实验模式）；\n4. 风险受控门控融合（实验模式）。\n\nDemo 会根据模型目录自动发现类别、检查模型结构、加载兼容的 `fusion.json` 和模式专属阈值，\n用户只需要上传待检测图片，不需要手动上传配置文件。项目同时提供 VS Code 启动配置、\n模型结构校验、页面级测试和跨类别推理验证。\n\n原始 PatchCore 论文与上游预训练模型说明见：Roth et al. (2021),\n\u003Chttps:\u002F\u002Farxiv.org\u002Fabs\u002F2106.08265>。\n\nIt also provides various pretrained models that can achieve up to _99.6%_ image-level anomaly\ndetection AUROC, _98.4%_ pixel-level anomaly localization AUROC and _>95%_ PRO score (although the\nlater metric is not included for license reasons).\n\n![defect_segmentation](images\u002Fpatchcore_defect_segmentation.png)\n\n_For questions & feedback, please reach out to karsten.rh1@gmail.com!_\n\n---\n\n## Quick Guide\n\nFirst, clone this repository and set the `PYTHONPATH` environment variable with `env PYTHONPATH=src python bin\u002Frun_patchcore.py`.\nTo train PatchCore on MVTec AD (as described below), run\n\n```\ndatapath=\u002Fpath_to_mvtec_folder\u002Fmvtec datasets=('bottle' 'cable' 'capsule' 'carpet' 'grid' 'hazelnut'\n'leather' 'metal_nut' 'pill' 'screw' 'tile' 'toothbrush' 'transistor' 'wood' 'zipper')\ndataset_flags=($(for dataset in \"${datasets[@]}\"; do echo '-d '$dataset; done))\n\n\npython bin\u002Frun_patchcore.py --gpu 0 --seed 0 --save_patchcore_model \\\n--log_group IM224_WR50_L2-3_P01_D1024-1024_PS-3_AN-1_S0 --log_project MVTecAD_Results results \\\npatch_core -b wideresnet50 -le layer2 -le layer3 --faiss_on_gpu \\\n--pretrain_embed_dimension 1024  --target_embed_dimension 1024 --anomaly_scorer_num_nn 1 --patchsize 3 \\\nsampler -p 0.1 approx_greedy_coreset dataset --resize 256 --imagesize 224 \"${dataset_flags[@]}\" mvtec $datapath\n```\n\nwhich runs PatchCore on MVTec images of sizes 224x224 using a WideResNet50-backbone pretrained on\nImageNet. For other sample runs with different backbones, larger images or ensembles, see\n`sample_training.sh`.\n\n### 本项目：带固定回退的敏感性引导异常分数融合\n\n本项目基于上游 PatchCore，研究 `layer2` 与 `layer3` 的独立异常响应，\n并比较检测、定位收益与额外计算成本。当前研究主线恢复为**双分支分数融合**，\n不再把单库内的特征加权作为主方案。上方论文成绩属于上游实现，不是本项目改进成绩。\n\n| 方法 | 记忆库 | 图像分数 | 像素异常图 |\n|---|---|---|---|\n| 原论文 PatchCore | layer2+layer3 共用一个库 | 单模型原始分数 | 单模型原始异常图 |\n| 双分支固定分数融合 | 两层分别建库 | 0.9\u002F0.1 | 0.5\u002F0.5 |\n| 敏感性 + 收缩 | 两层分别建库 | 固定 0.9\u002F0.1 | 75% 固定权重 + 25% 敏感性权重 |\n| 可选门控 | 同上 | 不变 | 满足校准规则用收缩，否则回退 0.5\u002F0.5 |\n\n敏感性来自训练集中留出的正常图及其合成小点、划痕、纹理扰动，\n不是从真实测试缺陷标签拟合的权重。门控检查跨合成缺陷组的一致性及分支相对稳定性。\n这是类别\u002F校准集级权重，不是每张测试图的自适应网络，也没有形式化风险保证。\n\nVS Code 当前仅保留一套运行配置：`PatchCore Demo - Streamlit`，用于直接启动工程化 Demo。\n训练和批量实验仍可通过下方命令及 `bin\u002F` 中的脚本执行，避免把训练数据集和实验参数\n硬编码到 Demo 启动配置中。运行生成的模型、阈值和实验结果默认保存在 `results\u002F`，\n其中模型文件和过程目录不会作为源代码同步到 GitHub。\n\n完整用法、数据流、参数与局限见 [方法说明](docs\u002Fadaptive_score_fusion.md)。\n固定分数对照见 [固定融合说明](docs\u002Ffixed_weight_fusion.md)。\nDemo 的 `fusion.json` 绑定规则见 [Demo 融合配置说明](docs\u002Fdemo_fusion_config.md)。\n批量复核与补跑入口为 `bin\u002Fbenchmark_fusion.py`，结果索引见 [实验索引](results\u002FREADME.md)。\n\n### 工程化单图 Demo\n\n仓库现在提供一个独立的 Streamlit 推理 Demo，用于把模型加载、单图推理、\n异常热力图、分支诊断、耗时统计和 JSON 导出串成可演示的闭环。Demo 提供原论文 PatchCore\n单记忆库、固定融合基线、\n敏感性收缩融合和风险受控门控融合四种显式模式；敏感性与门控模式只自动加载与当前模型\n绑定且经过结构校验的 `fusion.json`，不会在上传图片时重新计算或静默回退。用户不需要上传\n`fusion.json`；程序会优先读取当前模型目录，并自动关联 `results\u002Fdemo` 中同类别且分支数量兼容的保存配置。\n\n在 `patchcore` 环境中执行：\n\n```powershell\npip install -r requirements-demo.txt\n$env:PYTHONPATH = \"src\"\nstreamlit run demo\u002Fapp.py\n```\n\n界面支持：\n\n- 上传 JPG、PNG、BMP 或 WEBP 图像；\n- 选择仓库内或外部保存的 PatchCore 模型目录；\n- 查看输入图、融合异常热力图、各分支原始分数与权重；\n- 查看单图推理耗时并下载 JSON 诊断结果。\n- 根据当前模型自动判断四种模式是否可用，并显示配置缺失或分支不匹配原因；\n- 将 `results\u002Fdemo` 中保存的 Demo 模型加入模型选择列表，并自动显示实际加载的 `fusion.json` 来源；\n- 在诊断结果中显示实际加载的变体、权重、门控状态和配置路径。\n\n原论文模式只接受“一个 FAISS 索引 + `layers_to_extract_from=['layer2', 'layer3']`”的单库模型，\n不会把双分支模型设置成 1.0\u002F1.0 后冒充原论文方法。当前仓库内的预训练模型主要是单库\n`layer2+layer3` 模型或多 backbone Ensemble，因此原论文和固定模式通常可直接运行；它们没有\n被伪装成独立 layer2\u002Flayer3 敏感性模型。要启用后两种实验模式，需要使用本项目的独立双分支\n实验流程保存带兼容 `fusion.json` 的模型。\n\n实现说明与边界见 [Demo 文档](demo\u002FREADME.md)。需要注意：单图展示分数使用\n可视化归一化，不等同于跨测试集计算的 AUROC，也不能直接当作生产概率阈值。\n\n#### 已核对的历史结果\n\n15 类 × 5 seed 的历史记录中，相对**双分支固定分数融合**的平均 AUROC 差值：\n\n| 方法 | 图像 AUROC | 全像素 AUROC | 异常图像内像素 AUROC |\n|---|---:|---:|---:|\n| 仅像素敏感性 | 0 | -0.002308 | -0.001736 |\n| λ=0.25 收缩 | 0 | +0.000176 | +0.000311 |\n| legacy 门控 + 收缩 | 0 | +0.000388 | +0.000501 |\n\n这些数字来自已保存表格的重算，不是本次重新训练 15 类。\n门控的全像素 34 胜\u002F29 平\u002F12 负，异常图像像素 35 胜\u002F29 平\u002F11 负。\n按类别均值作双侧配对符号置换，p 分别为 0.0746、0.0516；\n门控也经过先前测试结果探索，不能据此声称显著、普适提升。\npill、cable、transistor 等仍有失败，历史原始运行配置缺失也限制了精确复现。\n\n单库 0.7\u002F0.3 加权的 40 次负结果保留在归档中，属于另一种方法，\n不得与上述分数融合结果混用。下一步应优先评估收益、成本与有效边界，\n而不是持续根据同一测试集重新选择门限。\n\n#### 本次冻结协议补跑（2026-10-22）\n\n本次按同一 `80%` 建库、`20%` 校准、`seed=0..4` 完成 bottle、pill、transistor，\n共 30 次训练命令；四个双分支方案共享同一次预测。相对双分支固定分数融合的类别等权均值为：\n\n| 方法 | 图像 AUROC | 全像素 AUROC | 异常图像像素 AUROC |\n|---|---:|---:|---:|\n| 原始单库 | +0.009161 | -0.004087 | -0.003855 |\n| 仅像素敏感性 | 0 | -0.014347 | -0.014618 |\n| λ=0.25 收缩 | 0 | -0.001866 | -0.002080 |\n| legacy 门控 | 0 | -0.000500 | -0.000537 |\n\n这三类不是新的未见类别，结论只支持“门控能减轻敏感性调权的退化”，\n不支持“门控已带来跨类别提升”。门控启用次数为 bottle 5\u002F5、pill 4\u002F5、transistor 2\u002F5。\n当前 Windows 同环境平均阶段耗时：原始单库 `19.42s`，双分支含校准 `35.07s`；\n保存前墙钟时间约为 `25.78s` 与 `51.85s`。旧记录使用的进程设置不同，不能直接作速度归因。\n\n本次完整表格见 `results\u002Frestoration_20261022\u002Ffusion_restoration_results.xlsx`，\n协议、逐 seed 记录、计时和门控诊断同目录保存。该结果把“效果最好阶段”恢复为\n双分支敏感性方案的可复核版本，但推荐默认仍是固定分数融合，门控只作为有边界的研究选项。\n\nGiven a pretrained PatchCore model (or models for all MVTec AD subdatasets), these can be evaluated using\n\n```shell\ndatapath=\u002Fpath_to_mvtec_folder\u002Fmvtec\nloadpath=\u002Fpath_to_pretrained_patchcores_models\nmodelfolder=IM224_WR50_L2-3_P001_D1024-1024_PS-3_AN-1_S0\nsavefolder=evaluated_results'\u002F'$modelfolder\n\ndatasets=('bottle'  'cable'  'capsule'  'carpet'  'grid'  'hazelnut' 'leather'  'metal_nut'  'pill' 'screw' 'tile' 'toothbrush' 'transistor' 'wood' 'zipper')\ndataset_flags=($(for dataset in \"${datasets[@]}\"; do echo '-d '$dataset; done))\nmodel_flags=($(for dataset in \"${datasets[@]}\"; do echo '-p '$loadpath'\u002F'$modelfolder'\u002Fmodels\u002Fmvtec_'$dataset; done))\n\npython bin\u002Fload_and_evaluate_patchcore.py --gpu 0 --seed 0 $savefolder \\\npatch_core_loader \"${model_flags[@]}\" --faiss_on_gpu \\\ndataset --resize 366 --imagesize 320 \"${dataset_flags[@]}\" mvtec $datapath\n```\n\nA set of pretrained PatchCores are hosted here: __add link__. To use them (and replicate training),\ncheck out `sample_evaluation.sh` and `sample_training.sh`.\n\n---\n\n## In-Depth Description\n\n### Requirements\n\nOur results were computed using Python 3.8, with packages and respective version noted in\n`requirements.txt`. In general, the majority of experiments should not exceed 11GB of GPU memory;\nhowever using significantly large input images will incur higher memory cost.\n\n### Setting up MVTec AD\n\nTo set up the main MVTec AD benchmark, download it from here: \u003Chttps:\u002F\u002Fwww.mvtec.com\u002Fcompany\u002Fresearch\u002Fdatasets\u002Fmvtec-ad>.\nPlace it in some location `datapath`. Make sure that it follows the following data tree:\n\n```shell\nmvtec\n|-- bottle\n|-----|----- ground_truth\n|-----|----- test\n|-----|--------|------ good\n|-----|--------|------ broken_large\n|-----|--------|------ ...\n|-----|----- train\n|-----|--------|------ good\n|-- cable\n|-- ...\n```\n\ncontaining in total 15 subdatasets: `bottle`, `cable`, `capsule`, `carpet`, `grid`, `hazelnut`,\n`leather`, `metal_nut`, `pill`, `screw`, `tile`, `toothbrush`, `transistor`, `wood`, `zipper`.\n\n### \"Training\" PatchCore\n\nPatchCore extracts a (coreset-subsampled) memory of pretrained, locally aggregated training patch features:\n\n![patchcore_architecture](images\u002Farchitecture.png)\n\nTo do so, we have provided `bin\u002Frun_patchcore.py`, which uses `click` to manage and aggregate input\narguments. This looks something like\n\n```shell\npython bin\u002Frun_patchcore.py \\\n--gpu \u003Cgpu_id> --seed \u003Cseed> # Set GPU-id & reproducibility seed.\n--save_patchcore_model # If set, saves the patchcore model(s).\n--log_group IM224_WR50_L2-3_P01_D1024-1024_PS-3_AN-1_S0 --log_project MVTecAD_Results results # Logging details: Name of the run & Name of the overall project folder.\n\npatch_core  # We now pass all PatchCore-related parameters.\n-b wideresnet50  # Which backbone to use.\n-le layer2 -le layer3 # Which layers to extract features from.\n--faiss_on_gpu # If similarity-searches should be performed on GPU.\n--pretrain_embed_dimension 1024  --target_embed_dimension 1024 # Dimensionality of features extracted from backbone layer(s) and final aggregated PatchCore Dimensionality\n--anomaly_scorer_num_nn 1 --patchsize 3 # Num. nearest neighbours to use for anomaly detection & neighbourhoodsize for local aggregation.\n\nsampler # We now pass all the (Coreset-)subsampling parameters.\n-p 0.1 approx_greedy_coreset # Subsampling percentage & exact subsampling method.\n\ndataset # We now pass all the Dataset-relevant parameters.\n--resize 256 --imagesize 224 \"${dataset_flags[@]}\" mvtec $datapath # Initial resizing shape and final imagesize (centercropped) as well as the MVTec subdatasets to use.\n```\n\n`sample_training.sh` contains upstream example training configurations (Bash).\nTheir comments describe upstream results, not measurements from this checkout.\nFor the current Windows experiment use `.vscode\u002Flaunch.json` or `bin\u002Fbenchmark_fusion.py`.\nSaved models can be evaluated with `bin\u002Fload_and_evaluate_patchcore.py`.\n\nDuring (after) training, the following information will be stored:\n\n```shell\n|PatchCore model (if --save_patchcore_model is set)\n|-- models\n|-----|----- mvtec_bottle\n|-----|-----------|------- nnscorer_search_index.faiss\n|-----|-----------|------- patchcore_params.pkl\n|-----|----- mvtec_cable\n|-----|----- ...\n|-- results.csv # Contains performance for each subdataset.\n\n|Sample_segmentations (if --save_segmentation_images is set)\n```\n\nThis checkout records results locally. It does not expose the old online-logging flags.\n\nFinally, due to the effectiveness and efficiency of PatchCore, we also incorporate the option to use\nan ensemble of backbone networks and network featuremaps. For this, provide the list of backbones to\nuse (as listed in `src\u002Fpatchcore\u002Fbackbones.py`) with `-b \u003Cbackbone>` and, given their\nordering, denote the layers to extract with `-le idx.\u003Clayer_name>`. An example with three different\nbackbones would look something like\n\n```shell\npython bin\u002Frun_patchcore.py --gpu \u003Cgpu_id> --seed \u003Cseed> --save_patchcore_model --log_group \u003Clog_name> --log_project \u003Clog_project> results \\\n\npatch_core -b wideresnet101 -b resnext101 -b densenet201 -le 0.layer2 -le 0.layer3 -le 1.layer2 -le 1.layer3 -le 2.features.denseblock2 -le 2.features.denseblock3 --faiss_on_gpu \\\n\n--pretrain_embed_dimension 1024  --target_embed_dimension 384 --anomaly_scorer_num_nn 1 --patchsize 3 sampler -p 0.01 approx_greedy_coreset dataset --resize 256 --imagesize 224 \"${dataset_flags[@]}\" mvtec $datapath\n\n```\n\nWhen using `--save_patchcore_model`, in the case of ensembles, a respective ensemble of PatchCore parameters is stored.\n\n### Evaluating a pretrained PatchCore model\n\nTo evaluate a\u002Four pretrained PatchCore model(s), run\n\n```shell\npython bin\u002Fload_and_evaluate_patchcore.py --gpu \u003Cgpu_id> --seed \u003Cseed> $savefolder \\\npatch_core_loader \"${model_flags[@]}\" --faiss_on_gpu \\\ndataset --resize 366 --imagesize 320 \"${dataset_flags[@]}\" mvtec $datapath\n```\n\nassuming your pretrained model locations to be contained in `model_flags`; one for each subdataset\nin `dataset_flags`. Results will then be stored in `savefolder`. Example model & dataset flags:\n\n```shell\nmodel_flags=('-p', 'path_to_mvtec_bottle_patchcore_model', '-p', 'path_to_mvtec_cable_patchcore_model', ...)\ndataset_flags=('-d', 'bottle', '-d', 'cable', ...)\n```\n\n### Expected performance of pretrained models\n\nWhile there may be minor changes in performance due to software & hardware differences, the provided\npretrained models should achieve the performances provided in their respective `results.csv`-files.\nThe mean performance (particularly for the baseline WR50 as well as the larger Ensemble model)\nshould look something like:\n\n| Model | Mean AUROC | Mean Seg. AUROC | Mean PRO\n|---|---|---|---|\n| WR50-baseline | 99.2% | 98.1% | 94.4%\n| Ensemble | __99.6%__ | __98.2%__ | __94.9%__\n\n### Citing\n\nIf you use the code in this repository, please cite\n\n```\n@misc{roth2021total,\n      title={Towards Total Recall in Industrial Anomaly Detection},\n      author={Karsten Roth and Latha Pemula and Joaquin Zepeda and Bernhard Schölkopf and Thomas Brox and Peter Gehler},\n      year={2021},\n      eprint={2106.08265},\n      archivePrefix={arXiv},\n      primaryClass={cs.CV}\n}\n```\n\n## Security\n\nSee [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.\n\n## License\n\nThis project is licensed under the Apache-2.0 License.\n",2,"2026-10-31 04:26:40","CREATED_QUERY"]