Spaces:
Runtime error
Runtime error
Fix: Add model with LFS and include source code
Browse files- .gitattributes +1 -0
- .gitignore +208 -0
- app.py +66 -4
- models/multi_smoothing1.2_reducelr_epoch116.pth +3 -0
- requirements.txt +1188 -0
- src/dataset.py +73 -0
- src/densenet.py +58 -0
- src/metrics.py +112 -0
- src/preprocessing.py +62 -0
- src/statistics.py +234 -0
- src/test.py +53 -0
- src/utils.py +119 -0
- src/xdl.py +689 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
models/multi_smoothing1.2_reducelr_epoch116.pth filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# Byte-compiled / optimized / DLL files
|
| 3 |
+
__pycache__/
|
| 4 |
+
*.py[codz]
|
| 5 |
+
*$py.class
|
| 6 |
+
|
| 7 |
+
# C extensions
|
| 8 |
+
*.so
|
| 9 |
+
|
| 10 |
+
# Distribution / packaging
|
| 11 |
+
.Python
|
| 12 |
+
build/
|
| 13 |
+
develop-eggs/
|
| 14 |
+
dist/
|
| 15 |
+
downloads/
|
| 16 |
+
eggs/
|
| 17 |
+
.eggs/
|
| 18 |
+
lib/
|
| 19 |
+
lib64/
|
| 20 |
+
parts/
|
| 21 |
+
sdist/
|
| 22 |
+
var/
|
| 23 |
+
wheels/
|
| 24 |
+
share/python-wheels/
|
| 25 |
+
*.egg-info/
|
| 26 |
+
.installed.cfg
|
| 27 |
+
*.egg
|
| 28 |
+
MANIFEST
|
| 29 |
+
|
| 30 |
+
# PyInstaller
|
| 31 |
+
# Usually these files are written by a python script from a template
|
| 32 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
| 33 |
+
*.manifest
|
| 34 |
+
*.spec
|
| 35 |
+
|
| 36 |
+
# Installer logs
|
| 37 |
+
pip-log.txt
|
| 38 |
+
pip-delete-this-directory.txt
|
| 39 |
+
|
| 40 |
+
# Unit test / coverage reports
|
| 41 |
+
htmlcov/
|
| 42 |
+
.tox/
|
| 43 |
+
.nox/
|
| 44 |
+
.coverage
|
| 45 |
+
.coverage.*
|
| 46 |
+
.cache
|
| 47 |
+
nosetests.xml
|
| 48 |
+
coverage.xml
|
| 49 |
+
*.cover
|
| 50 |
+
*.py.cover
|
| 51 |
+
.hypothesis/
|
| 52 |
+
.pytest_cache/
|
| 53 |
+
cover/
|
| 54 |
+
|
| 55 |
+
# Translations
|
| 56 |
+
*.mo
|
| 57 |
+
*.pot
|
| 58 |
+
|
| 59 |
+
# Django stuff:
|
| 60 |
+
*.log
|
| 61 |
+
local_settings.py
|
| 62 |
+
db.sqlite3
|
| 63 |
+
db.sqlite3-journal
|
| 64 |
+
|
| 65 |
+
# Flask stuff:
|
| 66 |
+
instance/
|
| 67 |
+
.webassets-cache
|
| 68 |
+
|
| 69 |
+
# Scrapy stuff:
|
| 70 |
+
.scrapy
|
| 71 |
+
|
| 72 |
+
# Sphinx documentation
|
| 73 |
+
docs/_build/
|
| 74 |
+
|
| 75 |
+
# PyBuilder
|
| 76 |
+
.pybuilder/
|
| 77 |
+
target/
|
| 78 |
+
|
| 79 |
+
# Jupyter Notebook
|
| 80 |
+
.ipynb_checkpoints
|
| 81 |
+
|
| 82 |
+
# IPython
|
| 83 |
+
profile_default/
|
| 84 |
+
ipython_config.py
|
| 85 |
+
|
| 86 |
+
# pyenv
|
| 87 |
+
# For a library or package, you might want to ignore these files since the code is
|
| 88 |
+
# intended to run in multiple environments; otherwise, check them in:
|
| 89 |
+
# .python-version
|
| 90 |
+
|
| 91 |
+
# pipenv
|
| 92 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
| 93 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
| 94 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
| 95 |
+
# install all needed dependencies.
|
| 96 |
+
#Pipfile.lock
|
| 97 |
+
|
| 98 |
+
# UV
|
| 99 |
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
| 100 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
| 101 |
+
# commonly ignored for libraries.
|
| 102 |
+
#uv.lock
|
| 103 |
+
|
| 104 |
+
# poetry
|
| 105 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
| 106 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
| 107 |
+
# commonly ignored for libraries.
|
| 108 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
| 109 |
+
#poetry.lock
|
| 110 |
+
#poetry.toml
|
| 111 |
+
|
| 112 |
+
# pdm
|
| 113 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
| 114 |
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
| 115 |
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
| 116 |
+
#pdm.lock
|
| 117 |
+
#pdm.toml
|
| 118 |
+
.pdm-python
|
| 119 |
+
.pdm-build/
|
| 120 |
+
|
| 121 |
+
# pixi
|
| 122 |
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
| 123 |
+
#pixi.lock
|
| 124 |
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
| 125 |
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
| 126 |
+
.pixi
|
| 127 |
+
|
| 128 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
| 129 |
+
__pypackages__/
|
| 130 |
+
|
| 131 |
+
# Celery stuff
|
| 132 |
+
celerybeat-schedule
|
| 133 |
+
celerybeat.pid
|
| 134 |
+
|
| 135 |
+
# SageMath parsed files
|
| 136 |
+
*.sage.py
|
| 137 |
+
|
| 138 |
+
# Environments
|
| 139 |
+
.env
|
| 140 |
+
.envrc
|
| 141 |
+
.venv
|
| 142 |
+
env/
|
| 143 |
+
venv/
|
| 144 |
+
ENV/
|
| 145 |
+
env.bak/
|
| 146 |
+
venv.bak/
|
| 147 |
+
|
| 148 |
+
# Spyder project settings
|
| 149 |
+
.spyderproject
|
| 150 |
+
.spyproject
|
| 151 |
+
|
| 152 |
+
# Rope project settings
|
| 153 |
+
.ropeproject
|
| 154 |
+
|
| 155 |
+
# mkdocs documentation
|
| 156 |
+
/site
|
| 157 |
+
|
| 158 |
+
# mypy
|
| 159 |
+
.mypy_cache/
|
| 160 |
+
.dmypy.json
|
| 161 |
+
dmypy.json
|
| 162 |
+
|
| 163 |
+
# Pyre type checker
|
| 164 |
+
.pyre/
|
| 165 |
+
|
| 166 |
+
# pytype static type analyzer
|
| 167 |
+
.pytype/
|
| 168 |
+
|
| 169 |
+
# Cython debug symbols
|
| 170 |
+
cython_debug/
|
| 171 |
+
|
| 172 |
+
# PyCharm
|
| 173 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
| 174 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
| 175 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
| 176 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
| 177 |
+
#.idea/
|
| 178 |
+
|
| 179 |
+
# Abstra
|
| 180 |
+
# Abstra is an AI-powered process automation framework.
|
| 181 |
+
# Ignore directories containing user credentials, local state, and settings.
|
| 182 |
+
# Learn more at https://abstra.io/docs
|
| 183 |
+
.abstra/
|
| 184 |
+
|
| 185 |
+
# Visual Studio Code
|
| 186 |
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
| 187 |
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
| 188 |
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
| 189 |
+
# you could uncomment the following to ignore the entire vscode folder
|
| 190 |
+
# .vscode/
|
| 191 |
+
|
| 192 |
+
# Ruff stuff:
|
| 193 |
+
.ruff_cache/
|
| 194 |
+
|
| 195 |
+
# PyPI configuration file
|
| 196 |
+
.pypirc
|
| 197 |
+
|
| 198 |
+
# Cursor
|
| 199 |
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
| 200 |
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
| 201 |
+
# refer to https://docs.cursor.com/context/ignore-files
|
| 202 |
+
.cursorignore
|
| 203 |
+
.cursorindexingignore
|
| 204 |
+
|
| 205 |
+
# Marimo
|
| 206 |
+
marimo/_static/
|
| 207 |
+
marimo/_lsp/
|
| 208 |
+
__marimo__/
|
app.py
CHANGED
|
@@ -1,7 +1,69 @@
|
|
| 1 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
from torchvision import transforms
|
| 5 |
+
from PIL import Image
|
| 6 |
|
| 7 |
+
# ---------------------------------------------------------
|
| 8 |
+
# 1. CONFIGURATION (Edit these!)
|
| 9 |
+
# ---------------------------------------------------------
|
| 10 |
+
MODEL_PATH = "models/multi_smoothing1.2_reducelr_epoch116.pth" # Your model file name
|
| 11 |
+
# IMPORTANT: These must match the order of folders/classes used during training!
|
| 12 |
+
LABELS = ["uc", "infeksi", "crohn", "tb"] # Example for your Colitis demo
|
| 13 |
|
| 14 |
+
# ---------------------------------------------------------
|
| 15 |
+
# 2. LOAD MODEL
|
| 16 |
+
# ---------------------------------------------------------
|
| 17 |
+
# We load to CPU since Hugging Face basic tier is CPU-only
|
| 18 |
+
from src.densenet import DenseNet121
|
| 19 |
+
model = DenseNet121(num_classes=len(LABELS))
|
| 20 |
+
|
| 21 |
+
try:
|
| 22 |
+
model.load_state_dict(torch.load(MODEL_PATH, map_location=torch.device('cpu')))
|
| 23 |
+
model.eval() # Set to evaluation mode
|
| 24 |
+
except Exception as e:
|
| 25 |
+
print(f"Error loading model: {e}")
|
| 26 |
+
print("Make sure your model file is uploaded and matches MODEL_PATH.")
|
| 27 |
+
# Create a dummy model just so the app doesn't crash immediately for testing
|
| 28 |
+
|
| 29 |
+
# ---------------------------------------------------------
|
| 30 |
+
# 3. PREPROCESSING
|
| 31 |
+
# ---------------------------------------------------------
|
| 32 |
+
# Standard preprocessing. Adjust "Resize" if your model expects 299x299 (Inception) or others.
|
| 33 |
+
from src.preprocessing import preprocess
|
| 34 |
+
|
| 35 |
+
target_input_size = tuple([3, 299, 299])
|
| 36 |
+
|
| 37 |
+
val_transform = preprocess(target_input_size=target_input_size)
|
| 38 |
+
|
| 39 |
+
# ---------------------------------------------------------
|
| 40 |
+
# 4. PREDICTION FUNCTION
|
| 41 |
+
# ---------------------------------------------------------
|
| 42 |
+
def predict(image):
|
| 43 |
+
if model is None:
|
| 44 |
+
return {"Error": 1.0}
|
| 45 |
+
|
| 46 |
+
input_tensor = val_transform(image).unsqueeze(0)
|
| 47 |
+
|
| 48 |
+
with torch.no_grad():
|
| 49 |
+
output = model(input_tensor)
|
| 50 |
+
|
| 51 |
+
probabilities = F.softmax(output[0], dim=0)
|
| 52 |
+
|
| 53 |
+
# 4. Map to labels
|
| 54 |
+
# Returns a dictionary: {"Class A": 0.9, "Class B": 0.1}
|
| 55 |
+
return {LABELS[i]: float(probabilities[i]) for i in range(len(LABELS))}
|
| 56 |
+
|
| 57 |
+
# ---------------------------------------------------------
|
| 58 |
+
# 5. GRADIO INTERFACE
|
| 59 |
+
# ---------------------------------------------------------
|
| 60 |
+
demo = gr.Interface(
|
| 61 |
+
fn=predict,
|
| 62 |
+
inputs=gr.Image(type="pil"),
|
| 63 |
+
outputs=gr.Label(num_top_classes=3),
|
| 64 |
+
title="Medical Image Classification Demo",
|
| 65 |
+
description="Upload a scan to classify it."
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
if __name__ == "__main__":
|
| 69 |
+
demo.launch()
|
models/multi_smoothing1.2_reducelr_epoch116.pth
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5ccc18364e541f77e359530c5fd889c732a3a133efef53ce548b42ca1e258c31
|
| 3 |
+
size 32555962
|
requirements.txt
ADDED
|
@@ -0,0 +1,1188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file was autogenerated by uv via the following command:
|
| 2 |
+
# uv export --format requirements-txt
|
| 3 |
+
aiofiles==24.1.0 \
|
| 4 |
+
--hash=sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c \
|
| 5 |
+
--hash=sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5
|
| 6 |
+
# via gradio
|
| 7 |
+
annotated-doc==0.0.4 \
|
| 8 |
+
--hash=sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320 \
|
| 9 |
+
--hash=sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4
|
| 10 |
+
# via fastapi
|
| 11 |
+
annotated-types==0.7.0 \
|
| 12 |
+
--hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
|
| 13 |
+
--hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
|
| 14 |
+
# via pydantic
|
| 15 |
+
anyio==4.12.1 \
|
| 16 |
+
--hash=sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703 \
|
| 17 |
+
--hash=sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c
|
| 18 |
+
# via
|
| 19 |
+
# gradio
|
| 20 |
+
# httpx
|
| 21 |
+
# starlette
|
| 22 |
+
audioop-lts==0.2.2 ; python_full_version >= '3.13' \
|
| 23 |
+
--hash=sha256:0337d658f9b81f4cd0fdb1f47635070cc084871a3d4646d9de74fdf4e7c3d24a \
|
| 24 |
+
--hash=sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449 \
|
| 25 |
+
--hash=sha256:068aa17a38b4e0e7de771c62c60bbca2455924b67a8814f3b0dee92b5820c0b3 \
|
| 26 |
+
--hash=sha256:088327f00488cdeed296edd9215ca159f3a5a5034741465789cad403fcf4bec0 \
|
| 27 |
+
--hash=sha256:0d9385e96f9f6da847f4d571ce3cb15b5091140edf3db97276872647ce37efd7 \
|
| 28 |
+
--hash=sha256:106753a83a25ee4d6f473f2be6b0966fc1c9af7e0017192f5531a3e7463dce58 \
|
| 29 |
+
--hash=sha256:143fad0311e8209ece30a8dbddab3b65ab419cbe8c0dde6e8828da25999be911 \
|
| 30 |
+
--hash=sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7 \
|
| 31 |
+
--hash=sha256:167d3b62586faef8b6b2275c3218796b12621a60e43f7e9d5845d627b9c9b80e \
|
| 32 |
+
--hash=sha256:2b267b70747d82125f1a021506565bdc5609a2b24bcb4773c16d79d2bb260bbd \
|
| 33 |
+
--hash=sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636 \
|
| 34 |
+
--hash=sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623 \
|
| 35 |
+
--hash=sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b \
|
| 36 |
+
--hash=sha256:48159d96962674eccdca9a3df280e864e8ac75e40a577cc97c5c42667ffabfc5 \
|
| 37 |
+
--hash=sha256:49ee1a41738a23e98d98b937a0638357a2477bc99e61b0f768a8f654f45d9b7a \
|
| 38 |
+
--hash=sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a \
|
| 39 |
+
--hash=sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6 \
|
| 40 |
+
--hash=sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d \
|
| 41 |
+
--hash=sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303 \
|
| 42 |
+
--hash=sha256:58cf54380c3884fb49fdd37dfb7a772632b6701d28edd3e2904743c5e1773602 \
|
| 43 |
+
--hash=sha256:5b00be98ccd0fc123dcfad31d50030d25fcf31488cde9e61692029cd7394733b \
|
| 44 |
+
--hash=sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f \
|
| 45 |
+
--hash=sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0 \
|
| 46 |
+
--hash=sha256:73f80bf4cd5d2ca7814da30a120de1f9408ee0619cc75da87d0641273d202a09 \
|
| 47 |
+
--hash=sha256:752d76472d9804ac60f0078c79cdae8b956f293177acd2316cd1e15149aee132 \
|
| 48 |
+
--hash=sha256:83c381767e2cc10e93e40281a04852facc4cd9334550e0f392f72d1c0a9c5753 \
|
| 49 |
+
--hash=sha256:8fefe5868cd082db1186f2837d64cfbfa78b548ea0d0543e9b28935ccce81ce9 \
|
| 50 |
+
--hash=sha256:9191d68659eda01e448188f60364c7763a7ca6653ed3f87ebb165822153a8547 \
|
| 51 |
+
--hash=sha256:96f19de485a2925314f5020e85911fb447ff5fbef56e8c7c6927851b95533a1c \
|
| 52 |
+
--hash=sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75 \
|
| 53 |
+
--hash=sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e \
|
| 54 |
+
--hash=sha256:a2d4f1513d63c795e82948e1305f31a6d530626e5f9f2605408b300ae6095093 \
|
| 55 |
+
--hash=sha256:a5bf613e96f49712073de86f20dbdd4014ca18efd4d34ed18c75bd808337851b \
|
| 56 |
+
--hash=sha256:a6d2e0f9f7a69403e388894d4ca5ada5c47230716a03f2847cfc7bd1ecb589d6 \
|
| 57 |
+
--hash=sha256:b492c3b040153e68b9fdaff5913305aaaba5bb433d8a7f73d5cf6a64ed3cc1dd \
|
| 58 |
+
--hash=sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8 \
|
| 59 |
+
--hash=sha256:c0022283e9556e0f3643b7c3c03f05063ca72b3063291834cca43234f20c60bb \
|
| 60 |
+
--hash=sha256:c174e322bb5783c099aaf87faeb240c8d210686b04bd61dfd05a8e5a83d88969 \
|
| 61 |
+
--hash=sha256:c9c8e68d8b4a56fda8c025e538e639f8c5953f5073886b596c93ec9b620055e7 \
|
| 62 |
+
--hash=sha256:cfcac6aa6f42397471e4943e0feb2244549db5c5d01efcd02725b96af417f3fe \
|
| 63 |
+
--hash=sha256:d5e73fa573e273e4f2e5ff96f9043858a5e9311e94ffefd88a3186a910c70917 \
|
| 64 |
+
--hash=sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc \
|
| 65 |
+
--hash=sha256:dfbbc74ec68a0fd08cfec1f4b5e8cca3d3cd7de5501b01c4b5d209995033cde9 \
|
| 66 |
+
--hash=sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3 \
|
| 67 |
+
--hash=sha256:e541c3ef484852ef36545f66209444c48b28661e864ccadb29daddb6a4b8e5f5 \
|
| 68 |
+
--hash=sha256:f9b0b8a03ef474f56d1a842af1a2e01398b8f7654009823c6d9e0ecff4d5cfbf \
|
| 69 |
+
--hash=sha256:f9ee9b52f5f857fbaf9d605a360884f034c92c1c23021fb90b2e39b8e64bede6 \
|
| 70 |
+
--hash=sha256:fbdd522624141e40948ab3e8cdae6e04c748d78710e9f0f8d4dae2750831de19 \
|
| 71 |
+
--hash=sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800
|
| 72 |
+
# via gradio
|
| 73 |
+
brotli==1.2.0 \
|
| 74 |
+
--hash=sha256:022426c9e99fd65d9475dce5c195526f04bb8be8907607e27e747893f6ee3e24 \
|
| 75 |
+
--hash=sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f \
|
| 76 |
+
--hash=sha256:0bbd5b5ccd157ae7913750476d48099aaf507a79841c0d04a9db4415b14842de \
|
| 77 |
+
--hash=sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c \
|
| 78 |
+
--hash=sha256:15b33fe93cedc4caaff8a0bd1eb7e3dab1c61bb22a0bf5bdfdfd97cd7da79744 \
|
| 79 |
+
--hash=sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a \
|
| 80 |
+
--hash=sha256:1b557b29782a643420e08d75aea889462a4a8796e9a6cf5621ab05a3f7da8ef2 \
|
| 81 |
+
--hash=sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca \
|
| 82 |
+
--hash=sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6 \
|
| 83 |
+
--hash=sha256:2a7f1d03727130fc875448b65b127a9ec5d06d19d0148e7554384229706f9d1b \
|
| 84 |
+
--hash=sha256:2e1ad3fda65ae0d93fec742a128d72e145c9c7a99ee2fcd667785d99eb25a7fe \
|
| 85 |
+
--hash=sha256:3219bd9e69868e57183316ee19c84e03e8f8b5a1d1f2667e1aa8c2f91cb061ac \
|
| 86 |
+
--hash=sha256:350c8348f0e76fff0a0fd6c26755d2653863279d086d3aa2c290a6a7251135dd \
|
| 87 |
+
--hash=sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84 \
|
| 88 |
+
--hash=sha256:3b90b767916ac44e93a8e28ce6adf8d551e43affb512f2377c732d486ac6514e \
|
| 89 |
+
--hash=sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18 \
|
| 90 |
+
--hash=sha256:3f3c908bcc404c90c77d5a073e55271a0a498f4e0756e48127c35d91cf155947 \
|
| 91 |
+
--hash=sha256:40d918bce2b427a0c4ba189df7a006ac0c7277c180aee4617d99e9ccaaf59e6a \
|
| 92 |
+
--hash=sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48 \
|
| 93 |
+
--hash=sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5 \
|
| 94 |
+
--hash=sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c \
|
| 95 |
+
--hash=sha256:6be67c19e0b0c56365c6a76e393b932fb0e78b3b56b711d180dd7013cb1fd984 \
|
| 96 |
+
--hash=sha256:6c12dad5cd04530323e723787ff762bac749a7b256a5bece32b2243dd5c27b21 \
|
| 97 |
+
--hash=sha256:7547369c4392b47d30a3467fe8c3330b4f2e0f7730e45e3103d7d636678a808b \
|
| 98 |
+
--hash=sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7 \
|
| 99 |
+
--hash=sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b \
|
| 100 |
+
--hash=sha256:81da1b229b1889f25adadc929aeb9dbc4e922bd18561b65b08dd9343cfccca84 \
|
| 101 |
+
--hash=sha256:832c115a020e463c2f67664560449a7bea26b0c1fdd690352addad6d0a08714d \
|
| 102 |
+
--hash=sha256:844a8ceb8483fefafc412f85c14f2aae2fb69567bf2a0de53cdb88b73e7c43ae \
|
| 103 |
+
--hash=sha256:898be2be399c221d2671d29eed26b6b2713a02c2119168ed914e7d00ceadb56f \
|
| 104 |
+
--hash=sha256:9322b9f8656782414b37e6af884146869d46ab85158201d82bab9abbcb971dc7 \
|
| 105 |
+
--hash=sha256:963a08f3bebd8b75ac57661045402da15991468a621f014be54e50f53a58d19e \
|
| 106 |
+
--hash=sha256:9c79f57faa25d97900bfb119480806d783fba83cd09ee0b33c17623935b05fa3 \
|
| 107 |
+
--hash=sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab \
|
| 108 |
+
--hash=sha256:a1778532b978d2536e79c05dac2d8cd857f6c55cd0c95ace5b03740824e0e2f1 \
|
| 109 |
+
--hash=sha256:aa47441fa3026543513139cb8926a92a8e305ee9c71a6209ef7a97d91640ea03 \
|
| 110 |
+
--hash=sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d \
|
| 111 |
+
--hash=sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28 \
|
| 112 |
+
--hash=sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036 \
|
| 113 |
+
--hash=sha256:b232029d100d393ae3c603c8ffd7e3fe6f798c5e28ddca5feabb8e8fdb732997 \
|
| 114 |
+
--hash=sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44 \
|
| 115 |
+
--hash=sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8 \
|
| 116 |
+
--hash=sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f \
|
| 117 |
+
--hash=sha256:cf9cba6f5b78a2071ec6fb1e7bd39acf35071d90a81231d67e92d637776a6a63 \
|
| 118 |
+
--hash=sha256:d2d085ded05278d1c7f65560aae97b3160aeb2ea2c0b3e26204856beccb60888 \
|
| 119 |
+
--hash=sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a \
|
| 120 |
+
--hash=sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3 \
|
| 121 |
+
--hash=sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161 \
|
| 122 |
+
--hash=sha256:ef87b8ab2704da227e83a246356a2b179ef826f550f794b2c52cddb4efbd0196 \
|
| 123 |
+
--hash=sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361 \
|
| 124 |
+
--hash=sha256:ff09cd8c5eec3b9d02d2408db41be150d8891c5566addce57513bf546e3d6c6d
|
| 125 |
+
# via gradio
|
| 126 |
+
certifi==2026.1.4 \
|
| 127 |
+
--hash=sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c \
|
| 128 |
+
--hash=sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120
|
| 129 |
+
# via
|
| 130 |
+
# httpcore
|
| 131 |
+
# httpx
|
| 132 |
+
click==8.3.1 \
|
| 133 |
+
--hash=sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a \
|
| 134 |
+
--hash=sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6
|
| 135 |
+
# via
|
| 136 |
+
# typer
|
| 137 |
+
# typer-slim
|
| 138 |
+
# uvicorn
|
| 139 |
+
colorama==0.4.6 ; sys_platform == 'win32' \
|
| 140 |
+
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
|
| 141 |
+
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
|
| 142 |
+
# via
|
| 143 |
+
# click
|
| 144 |
+
# tqdm
|
| 145 |
+
cuda-bindings==12.9.4 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 146 |
+
--hash=sha256:32bdc5a76906be4c61eb98f546a6786c5773a881f3b166486449b5d141e4a39f \
|
| 147 |
+
--hash=sha256:4d3c842c2a4303b2a580fe955018e31aea30278be19795ae05226235268032e5 \
|
| 148 |
+
--hash=sha256:56e0043c457a99ac473ddc926fe0dc4046694d99caef633e92601ab52cbe17eb \
|
| 149 |
+
--hash=sha256:8b72ee72a9cc1b531db31eebaaee5c69a8ec3500e32c6933f2d3b15297b53686 \
|
| 150 |
+
--hash=sha256:c912a3d9e6b6651853eed8eed96d6800d69c08e94052c292fec3f282c5a817c9 \
|
| 151 |
+
--hash=sha256:d80bffc357df9988dca279734bc9674c3934a654cab10cadeed27ce17d8635ee \
|
| 152 |
+
--hash=sha256:fda147a344e8eaeca0c6ff113d2851ffca8f7dfc0a6c932374ee5c47caa649c8
|
| 153 |
+
# via torch
|
| 154 |
+
cuda-pathfinder==1.3.3 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 155 |
+
--hash=sha256:9984b664e404f7c134954a771be8775dfd6180ea1e1aef4a5a37d4be05d9bbb1
|
| 156 |
+
# via cuda-bindings
|
| 157 |
+
exceptiongroup==1.3.1 ; python_full_version < '3.11' \
|
| 158 |
+
--hash=sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219 \
|
| 159 |
+
--hash=sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598
|
| 160 |
+
# via anyio
|
| 161 |
+
fastapi==0.128.7 \
|
| 162 |
+
--hash=sha256:6bd9bd31cb7047465f2d3fa3ba3f33b0870b17d4eaf7cdb36d1576ab060ad662 \
|
| 163 |
+
--hash=sha256:783c273416995486c155ad2c0e2b45905dedfaf20b9ef8d9f6a9124670639a24
|
| 164 |
+
# via gradio
|
| 165 |
+
ffmpy==1.0.0 \
|
| 166 |
+
--hash=sha256:5640e5f0fd03fb6236d0e119b16ccf6522db1c826fdf35dcb87087b60fd7504f \
|
| 167 |
+
--hash=sha256:b12932e95435c8820f1cd041024402765f821971e4bae753b327fc02a6e12f8b
|
| 168 |
+
# via gradio
|
| 169 |
+
filelock==3.20.3 \
|
| 170 |
+
--hash=sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1 \
|
| 171 |
+
--hash=sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1
|
| 172 |
+
# via
|
| 173 |
+
# huggingface-hub
|
| 174 |
+
# torch
|
| 175 |
+
fsspec==2026.2.0 \
|
| 176 |
+
--hash=sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff \
|
| 177 |
+
--hash=sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437
|
| 178 |
+
# via
|
| 179 |
+
# gradio-client
|
| 180 |
+
# huggingface-hub
|
| 181 |
+
# torch
|
| 182 |
+
gradio==6.5.1 \
|
| 183 |
+
--hash=sha256:31223a1699f15072176dbf48a94f08457228a38263bb4c221a0ccea3a639a595 \
|
| 184 |
+
--hash=sha256:5d49ff9691413ca5411189a694de5cbf1b171e2d49bf9f113952ae8a93c7088d
|
| 185 |
+
# via xdl-colitis-demo
|
| 186 |
+
gradio-client==2.0.3 \
|
| 187 |
+
--hash=sha256:8f1cec02dccaf64ac0285ed60479a2b0db3778dfe74c85a36d7ec9a95daeccc4 \
|
| 188 |
+
--hash=sha256:bcc88da74e3a387bcd41535578abbafe2091bcf4715c9542111804741b9e50b0
|
| 189 |
+
# via gradio
|
| 190 |
+
groovy==0.1.2 \
|
| 191 |
+
--hash=sha256:25c1dc09b3f9d7e292458aa762c6beb96ea037071bf5e917fc81fb78d2231083 \
|
| 192 |
+
--hash=sha256:7f7975bab18c729a257a8b1ae9dcd70b7cafb1720481beae47719af57c35fa64
|
| 193 |
+
# via gradio
|
| 194 |
+
h11==0.16.0 \
|
| 195 |
+
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
|
| 196 |
+
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
|
| 197 |
+
# via
|
| 198 |
+
# httpcore
|
| 199 |
+
# uvicorn
|
| 200 |
+
hf-xet==1.2.0 ; platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' \
|
| 201 |
+
--hash=sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e \
|
| 202 |
+
--hash=sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc \
|
| 203 |
+
--hash=sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4 \
|
| 204 |
+
--hash=sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382 \
|
| 205 |
+
--hash=sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090 \
|
| 206 |
+
--hash=sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8 \
|
| 207 |
+
--hash=sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0 \
|
| 208 |
+
--hash=sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd \
|
| 209 |
+
--hash=sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848 \
|
| 210 |
+
--hash=sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737 \
|
| 211 |
+
--hash=sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a \
|
| 212 |
+
--hash=sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f \
|
| 213 |
+
--hash=sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc \
|
| 214 |
+
--hash=sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f \
|
| 215 |
+
--hash=sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865 \
|
| 216 |
+
--hash=sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f \
|
| 217 |
+
--hash=sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813 \
|
| 218 |
+
--hash=sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5 \
|
| 219 |
+
--hash=sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649 \
|
| 220 |
+
--hash=sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c \
|
| 221 |
+
--hash=sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69 \
|
| 222 |
+
--hash=sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832
|
| 223 |
+
# via huggingface-hub
|
| 224 |
+
httpcore==1.0.9 \
|
| 225 |
+
--hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \
|
| 226 |
+
--hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8
|
| 227 |
+
# via httpx
|
| 228 |
+
httpx==0.28.1 \
|
| 229 |
+
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
|
| 230 |
+
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
|
| 231 |
+
# via
|
| 232 |
+
# gradio
|
| 233 |
+
# gradio-client
|
| 234 |
+
# huggingface-hub
|
| 235 |
+
# safehttpx
|
| 236 |
+
huggingface-hub==1.4.1 \
|
| 237 |
+
--hash=sha256:9931d075fb7a79af5abc487106414ec5fba2c0ae86104c0c62fd6cae38873d18 \
|
| 238 |
+
--hash=sha256:b41131ec35e631e7383ab26d6146b8d8972abc8b6309b963b306fbcca87f5ed5
|
| 239 |
+
# via
|
| 240 |
+
# gradio
|
| 241 |
+
# gradio-client
|
| 242 |
+
idna==3.11 \
|
| 243 |
+
--hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \
|
| 244 |
+
--hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902
|
| 245 |
+
# via
|
| 246 |
+
# anyio
|
| 247 |
+
# httpx
|
| 248 |
+
jinja2==3.1.6 \
|
| 249 |
+
--hash=sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d \
|
| 250 |
+
--hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67
|
| 251 |
+
# via
|
| 252 |
+
# gradio
|
| 253 |
+
# torch
|
| 254 |
+
markdown-it-py==4.0.0 \
|
| 255 |
+
--hash=sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147 \
|
| 256 |
+
--hash=sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3
|
| 257 |
+
# via rich
|
| 258 |
+
markupsafe==3.0.3 \
|
| 259 |
+
--hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \
|
| 260 |
+
--hash=sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a \
|
| 261 |
+
--hash=sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf \
|
| 262 |
+
--hash=sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19 \
|
| 263 |
+
--hash=sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf \
|
| 264 |
+
--hash=sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175 \
|
| 265 |
+
--hash=sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219 \
|
| 266 |
+
--hash=sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb \
|
| 267 |
+
--hash=sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6 \
|
| 268 |
+
--hash=sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab \
|
| 269 |
+
--hash=sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1 \
|
| 270 |
+
--hash=sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce \
|
| 271 |
+
--hash=sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218 \
|
| 272 |
+
--hash=sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634 \
|
| 273 |
+
--hash=sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695 \
|
| 274 |
+
--hash=sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad \
|
| 275 |
+
--hash=sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73 \
|
| 276 |
+
--hash=sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c \
|
| 277 |
+
--hash=sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe \
|
| 278 |
+
--hash=sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa \
|
| 279 |
+
--hash=sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559 \
|
| 280 |
+
--hash=sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa \
|
| 281 |
+
--hash=sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37 \
|
| 282 |
+
--hash=sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f \
|
| 283 |
+
--hash=sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d \
|
| 284 |
+
--hash=sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c \
|
| 285 |
+
--hash=sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97 \
|
| 286 |
+
--hash=sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a \
|
| 287 |
+
--hash=sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19 \
|
| 288 |
+
--hash=sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9 \
|
| 289 |
+
--hash=sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9 \
|
| 290 |
+
--hash=sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc \
|
| 291 |
+
--hash=sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4 \
|
| 292 |
+
--hash=sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354 \
|
| 293 |
+
--hash=sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50 \
|
| 294 |
+
--hash=sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698 \
|
| 295 |
+
--hash=sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9 \
|
| 296 |
+
--hash=sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b \
|
| 297 |
+
--hash=sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc \
|
| 298 |
+
--hash=sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115 \
|
| 299 |
+
--hash=sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485 \
|
| 300 |
+
--hash=sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f \
|
| 301 |
+
--hash=sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12 \
|
| 302 |
+
--hash=sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025 \
|
| 303 |
+
--hash=sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009 \
|
| 304 |
+
--hash=sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d \
|
| 305 |
+
--hash=sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a \
|
| 306 |
+
--hash=sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5 \
|
| 307 |
+
--hash=sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f \
|
| 308 |
+
--hash=sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1 \
|
| 309 |
+
--hash=sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287 \
|
| 310 |
+
--hash=sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6 \
|
| 311 |
+
--hash=sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f \
|
| 312 |
+
--hash=sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581 \
|
| 313 |
+
--hash=sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed \
|
| 314 |
+
--hash=sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b \
|
| 315 |
+
--hash=sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c \
|
| 316 |
+
--hash=sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026 \
|
| 317 |
+
--hash=sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8 \
|
| 318 |
+
--hash=sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676 \
|
| 319 |
+
--hash=sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6 \
|
| 320 |
+
--hash=sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e \
|
| 321 |
+
--hash=sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d \
|
| 322 |
+
--hash=sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d \
|
| 323 |
+
--hash=sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01 \
|
| 324 |
+
--hash=sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419 \
|
| 325 |
+
--hash=sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795 \
|
| 326 |
+
--hash=sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1 \
|
| 327 |
+
--hash=sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5 \
|
| 328 |
+
--hash=sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d \
|
| 329 |
+
--hash=sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe \
|
| 330 |
+
--hash=sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda \
|
| 331 |
+
--hash=sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e \
|
| 332 |
+
--hash=sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737 \
|
| 333 |
+
--hash=sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523 \
|
| 334 |
+
--hash=sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591 \
|
| 335 |
+
--hash=sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a \
|
| 336 |
+
--hash=sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50
|
| 337 |
+
# via
|
| 338 |
+
# gradio
|
| 339 |
+
# jinja2
|
| 340 |
+
mdurl==0.1.2 \
|
| 341 |
+
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
|
| 342 |
+
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
|
| 343 |
+
# via markdown-it-py
|
| 344 |
+
mpmath==1.3.0 \
|
| 345 |
+
--hash=sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f \
|
| 346 |
+
--hash=sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c
|
| 347 |
+
# via sympy
|
| 348 |
+
networkx==3.4.2 ; python_full_version < '3.11' \
|
| 349 |
+
--hash=sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1 \
|
| 350 |
+
--hash=sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f
|
| 351 |
+
# via torch
|
| 352 |
+
networkx==3.6.1 ; python_full_version >= '3.11' \
|
| 353 |
+
--hash=sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509 \
|
| 354 |
+
--hash=sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762
|
| 355 |
+
# via torch
|
| 356 |
+
numpy==2.2.6 ; python_full_version < '3.11' \
|
| 357 |
+
--hash=sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff \
|
| 358 |
+
--hash=sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47 \
|
| 359 |
+
--hash=sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84 \
|
| 360 |
+
--hash=sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d \
|
| 361 |
+
--hash=sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6 \
|
| 362 |
+
--hash=sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f \
|
| 363 |
+
--hash=sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b \
|
| 364 |
+
--hash=sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49 \
|
| 365 |
+
--hash=sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163 \
|
| 366 |
+
--hash=sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571 \
|
| 367 |
+
--hash=sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42 \
|
| 368 |
+
--hash=sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff \
|
| 369 |
+
--hash=sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491 \
|
| 370 |
+
--hash=sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4 \
|
| 371 |
+
--hash=sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566 \
|
| 372 |
+
--hash=sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf \
|
| 373 |
+
--hash=sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40 \
|
| 374 |
+
--hash=sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd \
|
| 375 |
+
--hash=sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06 \
|
| 376 |
+
--hash=sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282 \
|
| 377 |
+
--hash=sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680 \
|
| 378 |
+
--hash=sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db \
|
| 379 |
+
--hash=sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3 \
|
| 380 |
+
--hash=sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90 \
|
| 381 |
+
--hash=sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1 \
|
| 382 |
+
--hash=sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289 \
|
| 383 |
+
--hash=sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab \
|
| 384 |
+
--hash=sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c \
|
| 385 |
+
--hash=sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d \
|
| 386 |
+
--hash=sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb \
|
| 387 |
+
--hash=sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d \
|
| 388 |
+
--hash=sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a \
|
| 389 |
+
--hash=sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf \
|
| 390 |
+
--hash=sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1 \
|
| 391 |
+
--hash=sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2 \
|
| 392 |
+
--hash=sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a \
|
| 393 |
+
--hash=sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543 \
|
| 394 |
+
--hash=sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00 \
|
| 395 |
+
--hash=sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c \
|
| 396 |
+
--hash=sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f \
|
| 397 |
+
--hash=sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd \
|
| 398 |
+
--hash=sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868 \
|
| 399 |
+
--hash=sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303 \
|
| 400 |
+
--hash=sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83 \
|
| 401 |
+
--hash=sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3 \
|
| 402 |
+
--hash=sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d \
|
| 403 |
+
--hash=sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87 \
|
| 404 |
+
--hash=sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa \
|
| 405 |
+
--hash=sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f \
|
| 406 |
+
--hash=sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae \
|
| 407 |
+
--hash=sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda \
|
| 408 |
+
--hash=sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915 \
|
| 409 |
+
--hash=sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249 \
|
| 410 |
+
--hash=sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de \
|
| 411 |
+
--hash=sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8
|
| 412 |
+
# via
|
| 413 |
+
# gradio
|
| 414 |
+
# pandas
|
| 415 |
+
# torchvision
|
| 416 |
+
# xdl-colitis-demo
|
| 417 |
+
numpy==2.4.2 ; python_full_version >= '3.11' \
|
| 418 |
+
--hash=sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82 \
|
| 419 |
+
--hash=sha256:068cdb2d0d644cdb45670810894f6a0600797a69c05f1ac478e8d31670b8ee75 \
|
| 420 |
+
--hash=sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257 \
|
| 421 |
+
--hash=sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71 \
|
| 422 |
+
--hash=sha256:12e26134a0331d8dbd9351620f037ec470b7c75929cb8a1537f6bfe411152a1a \
|
| 423 |
+
--hash=sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413 \
|
| 424 |
+
--hash=sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181 \
|
| 425 |
+
--hash=sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85 \
|
| 426 |
+
--hash=sha256:20abd069b9cda45874498b245c8015b18ace6de8546bf50dfa8cea1696ed06ef \
|
| 427 |
+
--hash=sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a \
|
| 428 |
+
--hash=sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c \
|
| 429 |
+
--hash=sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390 \
|
| 430 |
+
--hash=sha256:2b8f157c8a6f20eb657e240f8985cc135598b2b46985c5bccbde7616dc9c6b1e \
|
| 431 |
+
--hash=sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f \
|
| 432 |
+
--hash=sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1 \
|
| 433 |
+
--hash=sha256:444be170853f1f9d528428eceb55f12918e4fda5d8805480f36a002f1415e09b \
|
| 434 |
+
--hash=sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3 \
|
| 435 |
+
--hash=sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1 \
|
| 436 |
+
--hash=sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657 \
|
| 437 |
+
--hash=sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262 \
|
| 438 |
+
--hash=sha256:5daf6f3914a733336dab21a05cdec343144600e964d2fcdabaac0c0269874b2a \
|
| 439 |
+
--hash=sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b \
|
| 440 |
+
--hash=sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0 \
|
| 441 |
+
--hash=sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae \
|
| 442 |
+
--hash=sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554 \
|
| 443 |
+
--hash=sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548 \
|
| 444 |
+
--hash=sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7 \
|
| 445 |
+
--hash=sha256:6ed0be1ee58eef41231a5c943d7d1375f093142702d5723ca2eb07db9b934b05 \
|
| 446 |
+
--hash=sha256:7cdde6de52fb6664b00b056341265441192d1291c130e99183ec0d4b110ff8b1 \
|
| 447 |
+
--hash=sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622 \
|
| 448 |
+
--hash=sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1 \
|
| 449 |
+
--hash=sha256:7f54844851cdb630ceb623dcec4db3240d1ac13d4990532446761baede94996a \
|
| 450 |
+
--hash=sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27 \
|
| 451 |
+
--hash=sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba \
|
| 452 |
+
--hash=sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082 \
|
| 453 |
+
--hash=sha256:8c50dd1fc8826f5b26a5ee4d77ca55d88a895f4e4819c7ecc2a9f5905047a443 \
|
| 454 |
+
--hash=sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98 \
|
| 455 |
+
--hash=sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110 \
|
| 456 |
+
--hash=sha256:98f16a80e917003a12c0580f97b5f875853ebc33e2eaa4bccfc8201ac6869308 \
|
| 457 |
+
--hash=sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f \
|
| 458 |
+
--hash=sha256:9e4424677ce4b47fe73c8b5556d876571f7c6945d264201180db2dc34f676ab5 \
|
| 459 |
+
--hash=sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460 \
|
| 460 |
+
--hash=sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef \
|
| 461 |
+
--hash=sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab \
|
| 462 |
+
--hash=sha256:b2f0073ed0868db1dcd86e052d37279eef185b9c8db5bf61f30f46adac63c909 \
|
| 463 |
+
--hash=sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e \
|
| 464 |
+
--hash=sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695 \
|
| 465 |
+
--hash=sha256:bba37bc29d4d85761deed3954a1bc62be7cf462b9510b51d367b769a8c8df325 \
|
| 466 |
+
--hash=sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979 \
|
| 467 |
+
--hash=sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0 \
|
| 468 |
+
--hash=sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32 \
|
| 469 |
+
--hash=sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7 \
|
| 470 |
+
--hash=sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7 \
|
| 471 |
+
--hash=sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73 \
|
| 472 |
+
--hash=sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920 \
|
| 473 |
+
--hash=sha256:cda077c2e5b780200b6b3e09d0b42205a3d1c68f30c6dceb90401c13bff8fe74 \
|
| 474 |
+
--hash=sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821 \
|
| 475 |
+
--hash=sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499 \
|
| 476 |
+
--hash=sha256:d1240d50adff70c2a88217698ca844723068533f3f5c5fa6ee2e3220e3bdb000 \
|
| 477 |
+
--hash=sha256:d30291931c915b2ab5717c2974bb95ee891a1cf22ebc16a8006bd59cd210d40a \
|
| 478 |
+
--hash=sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913 \
|
| 479 |
+
--hash=sha256:da6cad4e82cb893db4b69105c604d805e0c3ce11501a55b5e9f9083b47d2ffe8 \
|
| 480 |
+
--hash=sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda \
|
| 481 |
+
--hash=sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb \
|
| 482 |
+
--hash=sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a \
|
| 483 |
+
--hash=sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825 \
|
| 484 |
+
--hash=sha256:e98c97502435b53741540a5717a6749ac2ada901056c7db951d33e11c885cc7d \
|
| 485 |
+
--hash=sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f \
|
| 486 |
+
--hash=sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb \
|
| 487 |
+
--hash=sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa \
|
| 488 |
+
--hash=sha256:fcf92bee92742edd401ba41135185866f7026c502617f422eb432cfeca4fe236 \
|
| 489 |
+
--hash=sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1
|
| 490 |
+
# via
|
| 491 |
+
# gradio
|
| 492 |
+
# pandas
|
| 493 |
+
# torchvision
|
| 494 |
+
# xdl-colitis-demo
|
| 495 |
+
nvidia-cublas-cu12==12.8.4.1 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 496 |
+
--hash=sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142
|
| 497 |
+
# via
|
| 498 |
+
# nvidia-cudnn-cu12
|
| 499 |
+
# nvidia-cusolver-cu12
|
| 500 |
+
# torch
|
| 501 |
+
nvidia-cuda-cupti-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 502 |
+
--hash=sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182
|
| 503 |
+
# via torch
|
| 504 |
+
nvidia-cuda-nvrtc-cu12==12.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 505 |
+
--hash=sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994
|
| 506 |
+
# via torch
|
| 507 |
+
nvidia-cuda-runtime-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 508 |
+
--hash=sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90
|
| 509 |
+
# via torch
|
| 510 |
+
nvidia-cudnn-cu12==9.10.2.21 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 511 |
+
--hash=sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8
|
| 512 |
+
# via torch
|
| 513 |
+
nvidia-cufft-cu12==11.3.3.83 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 514 |
+
--hash=sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74
|
| 515 |
+
# via torch
|
| 516 |
+
nvidia-cufile-cu12==1.13.1.3 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 517 |
+
--hash=sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc
|
| 518 |
+
# via torch
|
| 519 |
+
nvidia-curand-cu12==10.3.9.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 520 |
+
--hash=sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9
|
| 521 |
+
# via torch
|
| 522 |
+
nvidia-cusolver-cu12==11.7.3.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 523 |
+
--hash=sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450
|
| 524 |
+
# via torch
|
| 525 |
+
nvidia-cusparse-cu12==12.5.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 526 |
+
--hash=sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b
|
| 527 |
+
# via
|
| 528 |
+
# nvidia-cusolver-cu12
|
| 529 |
+
# torch
|
| 530 |
+
nvidia-cusparselt-cu12==0.7.1 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 531 |
+
--hash=sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623
|
| 532 |
+
# via torch
|
| 533 |
+
nvidia-nccl-cu12==2.27.5 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 534 |
+
--hash=sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457
|
| 535 |
+
# via torch
|
| 536 |
+
nvidia-nvjitlink-cu12==12.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 537 |
+
--hash=sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88
|
| 538 |
+
# via
|
| 539 |
+
# nvidia-cufft-cu12
|
| 540 |
+
# nvidia-cusolver-cu12
|
| 541 |
+
# nvidia-cusparse-cu12
|
| 542 |
+
# torch
|
| 543 |
+
nvidia-nvshmem-cu12==3.4.5 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 544 |
+
--hash=sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd
|
| 545 |
+
# via torch
|
| 546 |
+
nvidia-nvtx-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 547 |
+
--hash=sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f
|
| 548 |
+
# via torch
|
| 549 |
+
orjson==3.11.7 \
|
| 550 |
+
--hash=sha256:043d3006b7d32c7e233b8cfb1f01c651013ea079e08dcef7189a29abd8befe11 \
|
| 551 |
+
--hash=sha256:0527a4510c300e3b406591b0ba69b5dc50031895b0a93743526a3fc45f59d26e \
|
| 552 |
+
--hash=sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f \
|
| 553 |
+
--hash=sha256:136dcd6a2e796dfd9ffca9fc027d778567b0b7c9968d092842d3c323cef88aa8 \
|
| 554 |
+
--hash=sha256:14f440c7268c8f8633d1b3d443a434bd70cb15686117ea6beff8fdc8f5917a1e \
|
| 555 |
+
--hash=sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733 \
|
| 556 |
+
--hash=sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223 \
|
| 557 |
+
--hash=sha256:1ee5cc7160a821dfe14f130bc8e63e7611051f964b463d9e2a3a573204446a4d \
|
| 558 |
+
--hash=sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650 \
|
| 559 |
+
--hash=sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5 \
|
| 560 |
+
--hash=sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1 \
|
| 561 |
+
--hash=sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8 \
|
| 562 |
+
--hash=sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3 \
|
| 563 |
+
--hash=sha256:3a2479753bbb95b0ebcf7969f562cdb9668e6d12416a35b0dda79febf89cdea2 \
|
| 564 |
+
--hash=sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6 \
|
| 565 |
+
--hash=sha256:411ebaf34d735e25e358a6d9e7978954a9c9d58cfb47bc6683cdc3964cd2f910 \
|
| 566 |
+
--hash=sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2 \
|
| 567 |
+
--hash=sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d \
|
| 568 |
+
--hash=sha256:57036b27ac8a25d81112eb0cc9835cd4833c5b16e1467816adc0015f59e870dc \
|
| 569 |
+
--hash=sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a \
|
| 570 |
+
--hash=sha256:5fdfad2093bdd08245f2e204d977facd5f871c88c4a71230d5bcbd0e43bf6222 \
|
| 571 |
+
--hash=sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5 \
|
| 572 |
+
--hash=sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e \
|
| 573 |
+
--hash=sha256:6543001328aa857187f905308a028935864aefe9968af3848401b6fe80dbb471 \
|
| 574 |
+
--hash=sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892 \
|
| 575 |
+
--hash=sha256:71924496986275a737f38e3f22b4e0878882b3f7a310d2ff4dc96e812789120c \
|
| 576 |
+
--hash=sha256:733ae23ada68b804b222c44affed76b39e30806d38660bf1eb200520d259cc16 \
|
| 577 |
+
--hash=sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3 \
|
| 578 |
+
--hash=sha256:79cacb0b52f6004caf92405a7e1f11e6e2de8bdf9019e4f76b44ba045125cd6b \
|
| 579 |
+
--hash=sha256:7ba61079379b0ae29e117db13bda5f28d939766e410d321ec1624afc6a0b0504 \
|
| 580 |
+
--hash=sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539 \
|
| 581 |
+
--hash=sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785 \
|
| 582 |
+
--hash=sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1 \
|
| 583 |
+
--hash=sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab \
|
| 584 |
+
--hash=sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576 \
|
| 585 |
+
--hash=sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b \
|
| 586 |
+
--hash=sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141 \
|
| 587 |
+
--hash=sha256:91c81ef070c8f3220054115e1ef468b1c9ce8497b4e526cb9f68ab4dc0a7ac62 \
|
| 588 |
+
--hash=sha256:9487abc2c2086e7c8eb9a211d2ce8855bae0e92586279d0d27b341d5ad76c85c \
|
| 589 |
+
--hash=sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2 \
|
| 590 |
+
--hash=sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b \
|
| 591 |
+
--hash=sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49 \
|
| 592 |
+
--hash=sha256:9c0b51672e466fd7e56230ffbae7f1639e18d0ce023351fb75da21b71bc2c960 \
|
| 593 |
+
--hash=sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705 \
|
| 594 |
+
--hash=sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174 \
|
| 595 |
+
--hash=sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace \
|
| 596 |
+
--hash=sha256:a16bcd08ab0bcdfc7e8801d9c4a9cc17e58418e4d48ddc6ded4e9e4b1a94062b \
|
| 597 |
+
--hash=sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1 \
|
| 598 |
+
--hash=sha256:a709e881723c9b18acddcfb8ba357322491ad553e277cf467e1e7e20e2d90561 \
|
| 599 |
+
--hash=sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157 \
|
| 600 |
+
--hash=sha256:ae9e0b37a834cef7ce8f99de6498f8fad4a2c0bf6bfc3d02abd8ed56aa15b2de \
|
| 601 |
+
--hash=sha256:b4a9eefdc70bf8bf9857f0290f973dec534ac84c35cd6a7f4083be43e7170a8f \
|
| 602 |
+
--hash=sha256:b63c6e6738d7c3470ad01601e23376aa511e50e1f3931395b9f9c722406d1a67 \
|
| 603 |
+
--hash=sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10 \
|
| 604 |
+
--hash=sha256:b8d14b71c0b12963fe8a62aac87119f1afdf4cb88a400f61ca5ae581449efcb5 \
|
| 605 |
+
--hash=sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757 \
|
| 606 |
+
--hash=sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d \
|
| 607 |
+
--hash=sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f \
|
| 608 |
+
--hash=sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf \
|
| 609 |
+
--hash=sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183 \
|
| 610 |
+
--hash=sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74 \
|
| 611 |
+
--hash=sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0 \
|
| 612 |
+
--hash=sha256:c2e85fe4698b6a56d5e2ebf7ae87544d668eb6bde1ad1226c13f44663f20ec9e \
|
| 613 |
+
--hash=sha256:c43b8b5bab288b6b90dac410cca7e986a4fa747a2e8f94615aea407da706980d \
|
| 614 |
+
--hash=sha256:cededd6738e1c153530793998e31c05086582b08315db48ab66649768f326baa \
|
| 615 |
+
--hash=sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539 \
|
| 616 |
+
--hash=sha256:d772afdb22555f0c58cfc741bdae44180122b3616faa1ecadb595cd526e4c993 \
|
| 617 |
+
--hash=sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4 \
|
| 618 |
+
--hash=sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0 \
|
| 619 |
+
--hash=sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad \
|
| 620 |
+
--hash=sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa \
|
| 621 |
+
--hash=sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f \
|
| 622 |
+
--hash=sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1 \
|
| 623 |
+
--hash=sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867
|
| 624 |
+
# via gradio
|
| 625 |
+
packaging==26.0 \
|
| 626 |
+
--hash=sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4 \
|
| 627 |
+
--hash=sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529
|
| 628 |
+
# via
|
| 629 |
+
# gradio
|
| 630 |
+
# gradio-client
|
| 631 |
+
# huggingface-hub
|
| 632 |
+
pandas==2.3.3 ; python_full_version < '3.11' \
|
| 633 |
+
--hash=sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7 \
|
| 634 |
+
--hash=sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593 \
|
| 635 |
+
--hash=sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5 \
|
| 636 |
+
--hash=sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791 \
|
| 637 |
+
--hash=sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec \
|
| 638 |
+
--hash=sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4 \
|
| 639 |
+
--hash=sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5 \
|
| 640 |
+
--hash=sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac \
|
| 641 |
+
--hash=sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084 \
|
| 642 |
+
--hash=sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c \
|
| 643 |
+
--hash=sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87 \
|
| 644 |
+
--hash=sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35 \
|
| 645 |
+
--hash=sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250 \
|
| 646 |
+
--hash=sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c \
|
| 647 |
+
--hash=sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826 \
|
| 648 |
+
--hash=sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713 \
|
| 649 |
+
--hash=sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1 \
|
| 650 |
+
--hash=sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523 \
|
| 651 |
+
--hash=sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3 \
|
| 652 |
+
--hash=sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78 \
|
| 653 |
+
--hash=sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53 \
|
| 654 |
+
--hash=sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c \
|
| 655 |
+
--hash=sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21 \
|
| 656 |
+
--hash=sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5 \
|
| 657 |
+
--hash=sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45 \
|
| 658 |
+
--hash=sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110 \
|
| 659 |
+
--hash=sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493 \
|
| 660 |
+
--hash=sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b \
|
| 661 |
+
--hash=sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450 \
|
| 662 |
+
--hash=sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86 \
|
| 663 |
+
--hash=sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98 \
|
| 664 |
+
--hash=sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89 \
|
| 665 |
+
--hash=sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66 \
|
| 666 |
+
--hash=sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b \
|
| 667 |
+
--hash=sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8 \
|
| 668 |
+
--hash=sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6 \
|
| 669 |
+
--hash=sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc \
|
| 670 |
+
--hash=sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788 \
|
| 671 |
+
--hash=sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151 \
|
| 672 |
+
--hash=sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838 \
|
| 673 |
+
--hash=sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b \
|
| 674 |
+
--hash=sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a \
|
| 675 |
+
--hash=sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d \
|
| 676 |
+
--hash=sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908 \
|
| 677 |
+
--hash=sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0 \
|
| 678 |
+
--hash=sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b \
|
| 679 |
+
--hash=sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c \
|
| 680 |
+
--hash=sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee
|
| 681 |
+
# via
|
| 682 |
+
# gradio
|
| 683 |
+
# xdl-colitis-demo
|
| 684 |
+
pandas==3.0.0 ; python_full_version >= '3.11' \
|
| 685 |
+
--hash=sha256:0192fee1f1a8e743b464a6607858ee4b071deb0b118eb143d71c2a1d170996d5 \
|
| 686 |
+
--hash=sha256:083b11415b9970b6e7888800c43c82e81a06cd6b06755d84804444f0007d6bb7 \
|
| 687 |
+
--hash=sha256:0facf7e87d38f721f0af46fe70d97373a37701b1c09f7ed7aeeb292ade5c050f \
|
| 688 |
+
--hash=sha256:113b4cca2614ff7e5b9fee9b6f066618fe73c5a83e99d721ffc41217b2bf57dd \
|
| 689 |
+
--hash=sha256:125eb901e233f155b268bbef9abd9afb5819db74f0e677e89a61b246228c71ac \
|
| 690 |
+
--hash=sha256:14c2a4099cd38a1d18ff108168ea417909b2dea3bd1ebff2ccf28ddb6a74d740 \
|
| 691 |
+
--hash=sha256:15d59f885ee5011daf8335dff47dcb8a912a27b4ad7826dc6cbe809fd145d327 \
|
| 692 |
+
--hash=sha256:177d9df10b3f43b70307a149d7ec49a1229a653f907aa60a48f1877d0e6be3be \
|
| 693 |
+
--hash=sha256:1c39eab3ad38f2d7a249095f0a3d8f8c22cc0f847e98ccf5bbe732b272e2d9fa \
|
| 694 |
+
--hash=sha256:1fbbb5a7288719e36b76b4f18d46ede46e7f916b6c8d9915b756b0a6c3f792b3 \
|
| 695 |
+
--hash=sha256:24e6547fb64d2c92665dd2adbfa4e85fa4fd70a9c070e7cfb03b629a0bbab5eb \
|
| 696 |
+
--hash=sha256:2713810ad3806767b89ad3b7b69ba153e1c6ff6d9c20f9c2140379b2a98b6c98 \
|
| 697 |
+
--hash=sha256:33fd3e6baa72899746b820c31e4b9688c8e1b7864d7aec2de7ab5035c285277a \
|
| 698 |
+
--hash=sha256:3c9a1a149aed3b6c9bf246033ff91e1b02d529546c5d6fb6b74a28fea0cf4c70 \
|
| 699 |
+
--hash=sha256:412d1a89aab46889f3033a386912efcdfa0f1131c5705ff5b668dda88305e986 \
|
| 700 |
+
--hash=sha256:447b2d68ac5edcbf94655fe909113a6dba6ef09ad7f9f60c80477825b6c489fe \
|
| 701 |
+
--hash=sha256:48ee04b90e2505c693d3f8e8f524dab8cb8aaf7ddcab52c92afa535e717c4812 \
|
| 702 |
+
--hash=sha256:4a4a400ca18230976724a5066f20878af785f36c6756e498e94c2a5e5d57779c \
|
| 703 |
+
--hash=sha256:4a66384f017240f3858a4c8a7cf21b0591c3ac885cddb7758a589f0f71e87ebb \
|
| 704 |
+
--hash=sha256:597c08fb9fef0edf1e4fa2f9828dd27f3d78f9b8c9b4a748d435ffc55732310b \
|
| 705 |
+
--hash=sha256:5db1e62cb99e739fa78a28047e861b256d17f88463c76b8dafc7c1338086dca8 \
|
| 706 |
+
--hash=sha256:613e13426069793aa1ec53bdcc3b86e8d32071daea138bbcf4fa959c9cdaa2e2 \
|
| 707 |
+
--hash=sha256:66f72fb172959af42a459e27a8d8d2c7e311ff4c1f7db6deb3b643dbc382ae08 \
|
| 708 |
+
--hash=sha256:69780c98f286076dcafca38d8b8eee1676adf220199c0a39f0ecbf976b68151a \
|
| 709 |
+
--hash=sha256:697b8f7d346c68274b1b93a170a70974cdc7d7354429894d5927c1effdcccd73 \
|
| 710 |
+
--hash=sha256:707a9a877a876c326ae2cb640fbdc4ef63b0a7b9e2ef55c6df9942dcee8e2af9 \
|
| 711 |
+
--hash=sha256:783ac35c4d0fe0effdb0d67161859078618b1b6587a1af15928137525217a721 \
|
| 712 |
+
--hash=sha256:8cb3120f0d9467ed95e77f67a75e030b67545bcfa08964e349252d674171def2 \
|
| 713 |
+
--hash=sha256:8e8b9808590fa364416b49b2a35c1f4cf2785a6c156935879e57f826df22038e \
|
| 714 |
+
--hash=sha256:940eebffe55528074341a5a36515f3e4c5e25e958ebbc764c9502cfc35ba3faa \
|
| 715 |
+
--hash=sha256:95683af6175d884ee89471842acfca29172a85031fccdabc35e50c0984470a0e \
|
| 716 |
+
--hash=sha256:9803b31f5039b3c3b10cc858c5e40054adb4b29b4d81cb2fd789f4121c8efbcd \
|
| 717 |
+
--hash=sha256:98212a38a709feb90ae658cb6227ea3657c22ba8157d4b8f913cd4c950de5e7e \
|
| 718 |
+
--hash=sha256:a453aad8c4f4e9f166436994a33884442ea62aa8b27d007311e87521b97246e1 \
|
| 719 |
+
--hash=sha256:a8942e333dc67ceda1095227ad0febb05a3b36535e520154085db632c40ad084 \
|
| 720 |
+
--hash=sha256:afd0aa3d0b5cda6e0b8ffc10dbcca3b09ef3cbcd3fe2b27364f85fdc04e1989d \
|
| 721 |
+
--hash=sha256:b78d646249b9a2bc191040988c7bb524c92fa8534fb0898a0741d7e6f2ffafa6 \
|
| 722 |
+
--hash=sha256:b86d113b6c109df3ce0ad5abbc259fe86a1bd4adfd4a31a89da42f84f65509bb \
|
| 723 |
+
--hash=sha256:bc9cba7b355cb4162442a88ce495e01cb605f17ac1e27d6596ac963504e0305f \
|
| 724 |
+
--hash=sha256:be8c515c9bc33989d97b89db66ea0cececb0f6e3c2a87fcc8b69443a6923e95f \
|
| 725 |
+
--hash=sha256:c14837eba8e99a8da1527c0280bba29b0eb842f64aa94982c5e21227966e164b \
|
| 726 |
+
--hash=sha256:d257699b9a9960e6125686098d5714ac59d05222bef7a5e6af7a7fd87c650801 \
|
| 727 |
+
--hash=sha256:d64ce01eb9cdca96a15266aa679ae50212ec52757c79204dbc7701a222401850 \
|
| 728 |
+
--hash=sha256:da768007b5a33057f6d9053563d6b74dd6d029c337d93c6d0d22a763a5c2ecc0 \
|
| 729 |
+
--hash=sha256:debb95c77ff3ed3ba0d9aa20c3a2f19165cc7956362f9873fce1ba0a53819d70 \
|
| 730 |
+
--hash=sha256:e979d22316f9350c516479dd3a92252be2937a9531ed3a26ec324198a99cdd49 \
|
| 731 |
+
--hash=sha256:f0b853319dec8d5e0c8b875374c078ef17f2269986a78168d9bd57e49bf650ae \
|
| 732 |
+
--hash=sha256:fedabf175e7cd82b69b74c30adbaa616de301291a5231138d7242596fc296a8d
|
| 733 |
+
# via
|
| 734 |
+
# gradio
|
| 735 |
+
# xdl-colitis-demo
|
| 736 |
+
pillow==12.1.0 \
|
| 737 |
+
--hash=sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d \
|
| 738 |
+
--hash=sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc \
|
| 739 |
+
--hash=sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84 \
|
| 740 |
+
--hash=sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de \
|
| 741 |
+
--hash=sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0 \
|
| 742 |
+
--hash=sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef \
|
| 743 |
+
--hash=sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4 \
|
| 744 |
+
--hash=sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82 \
|
| 745 |
+
--hash=sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9 \
|
| 746 |
+
--hash=sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030 \
|
| 747 |
+
--hash=sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0 \
|
| 748 |
+
--hash=sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18 \
|
| 749 |
+
--hash=sha256:21e686a21078b0f9cb8c8a961d99e6a4ddb88e0fc5ea6e130172ddddc2e5221a \
|
| 750 |
+
--hash=sha256:2415373395a831f53933c23ce051021e79c8cd7979822d8cc478547a3f4da8ef \
|
| 751 |
+
--hash=sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b \
|
| 752 |
+
--hash=sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6 \
|
| 753 |
+
--hash=sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179 \
|
| 754 |
+
--hash=sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e \
|
| 755 |
+
--hash=sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72 \
|
| 756 |
+
--hash=sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64 \
|
| 757 |
+
--hash=sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451 \
|
| 758 |
+
--hash=sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd \
|
| 759 |
+
--hash=sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924 \
|
| 760 |
+
--hash=sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616 \
|
| 761 |
+
--hash=sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a \
|
| 762 |
+
--hash=sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94 \
|
| 763 |
+
--hash=sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc \
|
| 764 |
+
--hash=sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8 \
|
| 765 |
+
--hash=sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9 \
|
| 766 |
+
--hash=sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91 \
|
| 767 |
+
--hash=sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a \
|
| 768 |
+
--hash=sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c \
|
| 769 |
+
--hash=sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670 \
|
| 770 |
+
--hash=sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea \
|
| 771 |
+
--hash=sha256:64efdf00c09e31efd754448a383ea241f55a994fd079866b92d2bbff598aad91 \
|
| 772 |
+
--hash=sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c \
|
| 773 |
+
--hash=sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc \
|
| 774 |
+
--hash=sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0 \
|
| 775 |
+
--hash=sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b \
|
| 776 |
+
--hash=sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65 \
|
| 777 |
+
--hash=sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661 \
|
| 778 |
+
--hash=sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19 \
|
| 779 |
+
--hash=sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1 \
|
| 780 |
+
--hash=sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0 \
|
| 781 |
+
--hash=sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e \
|
| 782 |
+
--hash=sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75 \
|
| 783 |
+
--hash=sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4 \
|
| 784 |
+
--hash=sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8 \
|
| 785 |
+
--hash=sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd \
|
| 786 |
+
--hash=sha256:8637e29d13f478bc4f153d8daa9ffb16455f0a6cb287da1b432fdad2bfbd66c7 \
|
| 787 |
+
--hash=sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61 \
|
| 788 |
+
--hash=sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51 \
|
| 789 |
+
--hash=sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551 \
|
| 790 |
+
--hash=sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45 \
|
| 791 |
+
--hash=sha256:92a7fe4225365c5e3a8e598982269c6d6698d3e783b3b1ae979e7819f9cd55c1 \
|
| 792 |
+
--hash=sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644 \
|
| 793 |
+
--hash=sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796 \
|
| 794 |
+
--hash=sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587 \
|
| 795 |
+
--hash=sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304 \
|
| 796 |
+
--hash=sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b \
|
| 797 |
+
--hash=sha256:a40905599d8079e09f25027423aed94f2823adaf2868940de991e53a449e14a8 \
|
| 798 |
+
--hash=sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17 \
|
| 799 |
+
--hash=sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171 \
|
| 800 |
+
--hash=sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3 \
|
| 801 |
+
--hash=sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7 \
|
| 802 |
+
--hash=sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988 \
|
| 803 |
+
--hash=sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a \
|
| 804 |
+
--hash=sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0 \
|
| 805 |
+
--hash=sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c \
|
| 806 |
+
--hash=sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2 \
|
| 807 |
+
--hash=sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14 \
|
| 808 |
+
--hash=sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5 \
|
| 809 |
+
--hash=sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a \
|
| 810 |
+
--hash=sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377 \
|
| 811 |
+
--hash=sha256:cad302dc10fac357d3467a74a9561c90609768a6f73a1923b0fd851b6486f8b0 \
|
| 812 |
+
--hash=sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5 \
|
| 813 |
+
--hash=sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b \
|
| 814 |
+
--hash=sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d \
|
| 815 |
+
--hash=sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac \
|
| 816 |
+
--hash=sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c \
|
| 817 |
+
--hash=sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554 \
|
| 818 |
+
--hash=sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643 \
|
| 819 |
+
--hash=sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13 \
|
| 820 |
+
--hash=sha256:e75d3dba8fc1ddfec0cd752108f93b83b4f8d6ab40e524a95d35f016b9683b09 \
|
| 821 |
+
--hash=sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208 \
|
| 822 |
+
--hash=sha256:f10c98f49227ed8383d28174ee95155a675c4ed7f85e2e573b04414f7e371bda \
|
| 823 |
+
--hash=sha256:f188028b5af6b8fb2e9a76ac0f841a575bd1bd396e46ef0840d9b88a48fdbcea \
|
| 824 |
+
--hash=sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e \
|
| 825 |
+
--hash=sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0 \
|
| 826 |
+
--hash=sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831 \
|
| 827 |
+
--hash=sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd
|
| 828 |
+
# via
|
| 829 |
+
# gradio
|
| 830 |
+
# torchvision
|
| 831 |
+
pydantic==2.12.5 \
|
| 832 |
+
--hash=sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49 \
|
| 833 |
+
--hash=sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d
|
| 834 |
+
# via
|
| 835 |
+
# fastapi
|
| 836 |
+
# gradio
|
| 837 |
+
pydantic-core==2.41.5 \
|
| 838 |
+
--hash=sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90 \
|
| 839 |
+
--hash=sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740 \
|
| 840 |
+
--hash=sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84 \
|
| 841 |
+
--hash=sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33 \
|
| 842 |
+
--hash=sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c \
|
| 843 |
+
--hash=sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0 \
|
| 844 |
+
--hash=sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e \
|
| 845 |
+
--hash=sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0 \
|
| 846 |
+
--hash=sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a \
|
| 847 |
+
--hash=sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34 \
|
| 848 |
+
--hash=sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2 \
|
| 849 |
+
--hash=sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3 \
|
| 850 |
+
--hash=sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815 \
|
| 851 |
+
--hash=sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14 \
|
| 852 |
+
--hash=sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba \
|
| 853 |
+
--hash=sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375 \
|
| 854 |
+
--hash=sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf \
|
| 855 |
+
--hash=sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963 \
|
| 856 |
+
--hash=sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1 \
|
| 857 |
+
--hash=sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808 \
|
| 858 |
+
--hash=sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553 \
|
| 859 |
+
--hash=sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1 \
|
| 860 |
+
--hash=sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2 \
|
| 861 |
+
--hash=sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470 \
|
| 862 |
+
--hash=sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2 \
|
| 863 |
+
--hash=sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b \
|
| 864 |
+
--hash=sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660 \
|
| 865 |
+
--hash=sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c \
|
| 866 |
+
--hash=sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093 \
|
| 867 |
+
--hash=sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594 \
|
| 868 |
+
--hash=sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008 \
|
| 869 |
+
--hash=sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a \
|
| 870 |
+
--hash=sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a \
|
| 871 |
+
--hash=sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd \
|
| 872 |
+
--hash=sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284 \
|
| 873 |
+
--hash=sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586 \
|
| 874 |
+
--hash=sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869 \
|
| 875 |
+
--hash=sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294 \
|
| 876 |
+
--hash=sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f \
|
| 877 |
+
--hash=sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66 \
|
| 878 |
+
--hash=sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51 \
|
| 879 |
+
--hash=sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc \
|
| 880 |
+
--hash=sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97 \
|
| 881 |
+
--hash=sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a \
|
| 882 |
+
--hash=sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d \
|
| 883 |
+
--hash=sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9 \
|
| 884 |
+
--hash=sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c \
|
| 885 |
+
--hash=sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07 \
|
| 886 |
+
--hash=sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36 \
|
| 887 |
+
--hash=sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e \
|
| 888 |
+
--hash=sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05 \
|
| 889 |
+
--hash=sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e \
|
| 890 |
+
--hash=sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941 \
|
| 891 |
+
--hash=sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612 \
|
| 892 |
+
--hash=sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b \
|
| 893 |
+
--hash=sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe \
|
| 894 |
+
--hash=sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146 \
|
| 895 |
+
--hash=sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11 \
|
| 896 |
+
--hash=sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd \
|
| 897 |
+
--hash=sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b \
|
| 898 |
+
--hash=sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c \
|
| 899 |
+
--hash=sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a \
|
| 900 |
+
--hash=sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1 \
|
| 901 |
+
--hash=sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf \
|
| 902 |
+
--hash=sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858 \
|
| 903 |
+
--hash=sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2 \
|
| 904 |
+
--hash=sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9 \
|
| 905 |
+
--hash=sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2 \
|
| 906 |
+
--hash=sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3 \
|
| 907 |
+
--hash=sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6 \
|
| 908 |
+
--hash=sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770 \
|
| 909 |
+
--hash=sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc \
|
| 910 |
+
--hash=sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23 \
|
| 911 |
+
--hash=sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26 \
|
| 912 |
+
--hash=sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa \
|
| 913 |
+
--hash=sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8 \
|
| 914 |
+
--hash=sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d \
|
| 915 |
+
--hash=sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3 \
|
| 916 |
+
--hash=sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d \
|
| 917 |
+
--hash=sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034 \
|
| 918 |
+
--hash=sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9 \
|
| 919 |
+
--hash=sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1 \
|
| 920 |
+
--hash=sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56 \
|
| 921 |
+
--hash=sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b \
|
| 922 |
+
--hash=sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c \
|
| 923 |
+
--hash=sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a \
|
| 924 |
+
--hash=sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e \
|
| 925 |
+
--hash=sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9 \
|
| 926 |
+
--hash=sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5 \
|
| 927 |
+
--hash=sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a \
|
| 928 |
+
--hash=sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556 \
|
| 929 |
+
--hash=sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e \
|
| 930 |
+
--hash=sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49 \
|
| 931 |
+
--hash=sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2 \
|
| 932 |
+
--hash=sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9 \
|
| 933 |
+
--hash=sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc \
|
| 934 |
+
--hash=sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb \
|
| 935 |
+
--hash=sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0 \
|
| 936 |
+
--hash=sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8 \
|
| 937 |
+
--hash=sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69 \
|
| 938 |
+
--hash=sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b \
|
| 939 |
+
--hash=sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c \
|
| 940 |
+
--hash=sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75 \
|
| 941 |
+
--hash=sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f \
|
| 942 |
+
--hash=sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad \
|
| 943 |
+
--hash=sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b \
|
| 944 |
+
--hash=sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7 \
|
| 945 |
+
--hash=sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52
|
| 946 |
+
# via pydantic
|
| 947 |
+
pydub==0.25.1 \
|
| 948 |
+
--hash=sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6 \
|
| 949 |
+
--hash=sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f
|
| 950 |
+
# via gradio
|
| 951 |
+
pygments==2.19.2 \
|
| 952 |
+
--hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \
|
| 953 |
+
--hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b
|
| 954 |
+
# via rich
|
| 955 |
+
python-dateutil==2.9.0.post0 \
|
| 956 |
+
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
|
| 957 |
+
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
|
| 958 |
+
# via pandas
|
| 959 |
+
python-multipart==0.0.22 \
|
| 960 |
+
--hash=sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155 \
|
| 961 |
+
--hash=sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58
|
| 962 |
+
# via gradio
|
| 963 |
+
pytz==2025.2 \
|
| 964 |
+
--hash=sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3 \
|
| 965 |
+
--hash=sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00
|
| 966 |
+
# via
|
| 967 |
+
# gradio
|
| 968 |
+
# pandas
|
| 969 |
+
pyyaml==6.0.3 \
|
| 970 |
+
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
|
| 971 |
+
--hash=sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3 \
|
| 972 |
+
--hash=sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956 \
|
| 973 |
+
--hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \
|
| 974 |
+
--hash=sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c \
|
| 975 |
+
--hash=sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65 \
|
| 976 |
+
--hash=sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a \
|
| 977 |
+
--hash=sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b \
|
| 978 |
+
--hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \
|
| 979 |
+
--hash=sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e \
|
| 980 |
+
--hash=sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 \
|
| 981 |
+
--hash=sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4 \
|
| 982 |
+
--hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \
|
| 983 |
+
--hash=sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0 \
|
| 984 |
+
--hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \
|
| 985 |
+
--hash=sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac \
|
| 986 |
+
--hash=sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9 \
|
| 987 |
+
--hash=sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7 \
|
| 988 |
+
--hash=sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35 \
|
| 989 |
+
--hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \
|
| 990 |
+
--hash=sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69 \
|
| 991 |
+
--hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \
|
| 992 |
+
--hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \
|
| 993 |
+
--hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \
|
| 994 |
+
--hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \
|
| 995 |
+
--hash=sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198 \
|
| 996 |
+
--hash=sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065 \
|
| 997 |
+
--hash=sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c \
|
| 998 |
+
--hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \
|
| 999 |
+
--hash=sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764 \
|
| 1000 |
+
--hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \
|
| 1001 |
+
--hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b \
|
| 1002 |
+
--hash=sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00 \
|
| 1003 |
+
--hash=sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac \
|
| 1004 |
+
--hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \
|
| 1005 |
+
--hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \
|
| 1006 |
+
--hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \
|
| 1007 |
+
--hash=sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3 \
|
| 1008 |
+
--hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \
|
| 1009 |
+
--hash=sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b \
|
| 1010 |
+
--hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \
|
| 1011 |
+
--hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \
|
| 1012 |
+
--hash=sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702 \
|
| 1013 |
+
--hash=sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8 \
|
| 1014 |
+
--hash=sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788 \
|
| 1015 |
+
--hash=sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d \
|
| 1016 |
+
--hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \
|
| 1017 |
+
--hash=sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c \
|
| 1018 |
+
--hash=sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba \
|
| 1019 |
+
--hash=sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 \
|
| 1020 |
+
--hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \
|
| 1021 |
+
--hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \
|
| 1022 |
+
--hash=sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b \
|
| 1023 |
+
--hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \
|
| 1024 |
+
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
|
| 1025 |
+
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \
|
| 1026 |
+
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
|
| 1027 |
+
# via
|
| 1028 |
+
# gradio
|
| 1029 |
+
# huggingface-hub
|
| 1030 |
+
rich==14.3.2 \
|
| 1031 |
+
--hash=sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69 \
|
| 1032 |
+
--hash=sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8
|
| 1033 |
+
# via typer
|
| 1034 |
+
safehttpx==0.1.7 \
|
| 1035 |
+
--hash=sha256:c4f4a162db6993464d7ca3d7cc4af0ffc6515a606dfd220b9f82c6945d869cde \
|
| 1036 |
+
--hash=sha256:db201c0978c41eddb8bb480f3eee59dd67304fdd91646035e9d9a720049a9d23
|
| 1037 |
+
# via gradio
|
| 1038 |
+
semantic-version==2.10.0 \
|
| 1039 |
+
--hash=sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c \
|
| 1040 |
+
--hash=sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177
|
| 1041 |
+
# via gradio
|
| 1042 |
+
setuptools==82.0.0 ; python_full_version >= '3.12' \
|
| 1043 |
+
--hash=sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb \
|
| 1044 |
+
--hash=sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0
|
| 1045 |
+
# via torch
|
| 1046 |
+
shellingham==1.5.4 \
|
| 1047 |
+
--hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \
|
| 1048 |
+
--hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de
|
| 1049 |
+
# via
|
| 1050 |
+
# huggingface-hub
|
| 1051 |
+
# typer
|
| 1052 |
+
six==1.17.0 \
|
| 1053 |
+
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
|
| 1054 |
+
--hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81
|
| 1055 |
+
# via python-dateutil
|
| 1056 |
+
starlette==0.52.1 \
|
| 1057 |
+
--hash=sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74 \
|
| 1058 |
+
--hash=sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933
|
| 1059 |
+
# via
|
| 1060 |
+
# fastapi
|
| 1061 |
+
# gradio
|
| 1062 |
+
sympy==1.14.0 \
|
| 1063 |
+
--hash=sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517 \
|
| 1064 |
+
--hash=sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5
|
| 1065 |
+
# via torch
|
| 1066 |
+
tomlkit==0.13.3 \
|
| 1067 |
+
--hash=sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1 \
|
| 1068 |
+
--hash=sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0
|
| 1069 |
+
# via gradio
|
| 1070 |
+
torch==2.10.0 \
|
| 1071 |
+
--hash=sha256:233aed0659a2503b831d8a67e9da66a62c996204c0bba4f4c442ccc0c68a3f60 \
|
| 1072 |
+
--hash=sha256:29b7009dba4b7a1c960260fc8ac85022c784250af43af9fb0ebafc9883782ebd \
|
| 1073 |
+
--hash=sha256:2c66c61f44c5f903046cc696d088e21062644cbe541c7f1c4eaae88b2ad23547 \
|
| 1074 |
+
--hash=sha256:3202429f58309b9fa96a614885eace4b7995729f44beb54d3e4a47773649d382 \
|
| 1075 |
+
--hash=sha256:3282d9febd1e4e476630a099692b44fdc214ee9bf8ee5377732d9d9dfe5712e4 \
|
| 1076 |
+
--hash=sha256:35e407430795c8d3edb07a1d711c41cc1f9eaddc8b2f1cc0a165a6767a8fb73d \
|
| 1077 |
+
--hash=sha256:5276fa790a666ee8becaffff8acb711922252521b28fbce5db7db5cf9cb2026d \
|
| 1078 |
+
--hash=sha256:5c4d217b14741e40776dd7074d9006fd28b8a97ef5654db959d8635b2fe5f29b \
|
| 1079 |
+
--hash=sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf \
|
| 1080 |
+
--hash=sha256:6021db85958db2f07ec94e1bc77212721ba4920c12a18dc552d2ae36a3eb163f \
|
| 1081 |
+
--hash=sha256:6528f13d2a8593a1a412ea07a99812495bec07e9224c28b2a25c0a30c7da025c \
|
| 1082 |
+
--hash=sha256:682497e16bdfa6efeec8cde66531bc8d1fbbbb4d8788ec6173c089ed3cc2bfe5 \
|
| 1083 |
+
--hash=sha256:6abb224c2b6e9e27b592a1c0015c33a504b00a0e0938f1499f7f514e9b7bfb5c \
|
| 1084 |
+
--hash=sha256:6b71486353fce0f9714ca0c9ef1c850a2ae766b409808acd58e9678a3edb7738 \
|
| 1085 |
+
--hash=sha256:6d3707a61863d1c4d6ebba7be4ca320f42b869ee657e9b2c21c736bf17000294 \
|
| 1086 |
+
--hash=sha256:71283a373f0ee2c89e0f0d5f446039bdabe8dbc3c9ccf35f0f784908b0acd185 \
|
| 1087 |
+
--hash=sha256:716b01a176c2a5659c98f6b01bf868244abdd896526f1c692712ab36dbaf9b63 \
|
| 1088 |
+
--hash=sha256:7350f6652dfd761f11f9ecb590bfe95b573e2961f7a242eccb3c8e78348d26fe \
|
| 1089 |
+
--hash=sha256:787124e7db3b379d4f1ed54dd12ae7c741c16a4d29b49c0226a89bea50923ffb \
|
| 1090 |
+
--hash=sha256:a2f9edd8dbc99f62bc4dfb78af7bf89499bca3d753423ac1b4e06592e467b763 \
|
| 1091 |
+
--hash=sha256:a4be6a2a190b32ff5c8002a0977a25ea60e64f7ba46b1be37093c141d9c49aeb \
|
| 1092 |
+
--hash=sha256:aae1b29cd68e50a9397f5ee897b9c24742e9e306f88a807a27d617f07adb3bd8 \
|
| 1093 |
+
--hash=sha256:aaf663927bcd490ae971469a624c322202a2a1e68936eb952535ca4cd3b90444 \
|
| 1094 |
+
--hash=sha256:b7bd80f3477b830dd166c707c5b0b82a898e7b16f59a7d9d42778dd058272e8b \
|
| 1095 |
+
--hash=sha256:bf0d9ff448b0218e0433aeb198805192346c4fd659c852370d5cc245f602a06a \
|
| 1096 |
+
--hash=sha256:c2ee399c644dc92ef7bc0d4f7e74b5360c37cdbe7c5ba11318dda49ffac2bc57 \
|
| 1097 |
+
--hash=sha256:c37fc46eedd9175f9c81814cc47308f1b42cfe4987e532d4b423d23852f2bf63 \
|
| 1098 |
+
--hash=sha256:cdf2a523d699b70d613243211ecaac14fe9c5df8a0b0a9c02add60fb2a413e0f \
|
| 1099 |
+
--hash=sha256:d8f5912ba938233f86361e891789595ff35ca4b4e2ac8fe3670895e5976731d6 \
|
| 1100 |
+
--hash=sha256:f5ab4ba32383061be0fb74bda772d470140a12c1c3b58a0cfbf3dae94d164c28 \
|
| 1101 |
+
--hash=sha256:f699f31a236a677b3118bc0a3ef3d89c0c29b5ec0b20f4c4bf0b110378487464 \
|
| 1102 |
+
--hash=sha256:ff43db38af76fda183156153983c9a096fc4c78d0cd1e07b14a2314c7f01c2c8
|
| 1103 |
+
# via
|
| 1104 |
+
# torchvision
|
| 1105 |
+
# xdl-colitis-demo
|
| 1106 |
+
torchvision==0.25.0 \
|
| 1107 |
+
--hash=sha256:0b5e7f50002a8145a98c5694a018e738c50e2972608310c7e88e1bd4c058f6ce \
|
| 1108 |
+
--hash=sha256:0d9a3f925a081dd2ebb0b791249b687c2ef2c2717d027946654607494b9b64b6 \
|
| 1109 |
+
--hash=sha256:146d02c9876858420adf41f3189fe90e3d6a409cbfa65454c09f25fb33bf7266 \
|
| 1110 |
+
--hash=sha256:153c0d2cbc34b7cf2da19d73450f24ba36d2b75ec9211b9962b5022fb9e4ecee \
|
| 1111 |
+
--hash=sha256:24e11199e4d84ba9c5ee7825ebdf1cd37ce8deec225117f10243cae984ced3ec \
|
| 1112 |
+
--hash=sha256:40a122c3cf4d14b651f095e0f672b688dde78632783fc5cd3d4d5e4f6a828563 \
|
| 1113 |
+
--hash=sha256:5e6b449e9fa7d642142c0e27c41e5a43b508d57ed8e79b7c0a0c28652da8678c \
|
| 1114 |
+
--hash=sha256:5f271136d2d2c0b7a24c5671795c6e4fd8da4e0ea98aeb1041f62bc04c4370ef \
|
| 1115 |
+
--hash=sha256:620a236288d594dcec7634c754484542dc0a5c1b0e0b83a34bda5e91e9b7c3a1 \
|
| 1116 |
+
--hash=sha256:632db02300e83793812eee4f61ae6a2686dab10b4cfd628b620dc47747aa9d03 \
|
| 1117 |
+
--hash=sha256:846890161b825b38aa85fc37fb3ba5eea74e7091ff28bab378287111483b6443 \
|
| 1118 |
+
--hash=sha256:855c0dc6d37f462482da7531c6788518baedca1e0847f3df42a911713acdfe52 \
|
| 1119 |
+
--hash=sha256:a8f8061284395ce31bcd460f2169013382ccf411148ceb2ee38e718e9860f5a7 \
|
| 1120 |
+
--hash=sha256:a95c47abb817d4e90ea1a8e57bd0d728e3e6b533b3495ae77d84d883c4d11f56 \
|
| 1121 |
+
--hash=sha256:acc339aba4a858192998c2b91f635827e40d9c469d9cf1455bafdda6e4c28ea4 \
|
| 1122 |
+
--hash=sha256:ad9a8a5877782944d99186e4502a614770fe906626d76e9cd32446a0ac3075f2 \
|
| 1123 |
+
--hash=sha256:b57430fbe9e9b697418a395041bb615124d9c007710a2712fda6e35fb310f264 \
|
| 1124 |
+
--hash=sha256:b75deafa2dfea3e2c2a525559b04783515e3463f6e830cb71de0fb7ea36fe233 \
|
| 1125 |
+
--hash=sha256:c2abe430c90b1d5e552680037d68da4eb80a5852ebb1c811b2b89d299b10573b \
|
| 1126 |
+
--hash=sha256:c4d395cb2c4a2712f6eb93a34476cdf7aae74bb6ea2ea1917f858e96344b00aa \
|
| 1127 |
+
--hash=sha256:cef0196be31be421f6f462d1e9da1101be7332d91984caa6f8022e6c78a5877f \
|
| 1128 |
+
--hash=sha256:d1abd5ed030c708f5dbf4812ad5f6fbe9384b63c40d6bd79f8df41a4a759a917 \
|
| 1129 |
+
--hash=sha256:db74a551946b75d19f9996c419a799ffdf6a223ecf17c656f90da011f1d75b20 \
|
| 1130 |
+
--hash=sha256:ea580ffd6094cc01914ad32f8c8118174f18974629af905cea08cb6d5d48c7b7 \
|
| 1131 |
+
--hash=sha256:f07f01d27375ad89d72aa2b3f2180f07da95dd9d2e4c758e015c0acb2da72977 \
|
| 1132 |
+
--hash=sha256:f25aa9e380865b11ea6e9d99d84df86b9cc959f1a007cd966fc6f1ab2ed0e248 \
|
| 1133 |
+
--hash=sha256:f49964f96644dbac2506dffe1a0a7ec0f2bf8cf7a588c3319fed26e6329ffdf3 \
|
| 1134 |
+
--hash=sha256:f9c55ae8d673ab493325d1267cbd285bb94d56f99626c00ac4644de32a59ede3
|
| 1135 |
+
# via xdl-colitis-demo
|
| 1136 |
+
tqdm==4.67.3 \
|
| 1137 |
+
--hash=sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb \
|
| 1138 |
+
--hash=sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf
|
| 1139 |
+
# via huggingface-hub
|
| 1140 |
+
triton==3.6.0 ; platform_machine == 'x86_64' and sys_platform == 'linux' \
|
| 1141 |
+
--hash=sha256:10c7f76c6e72d2ef08df639e3d0d30729112f47a56b0c81672edc05ee5116ac9 \
|
| 1142 |
+
--hash=sha256:46bd1c1af4b6704e554cad2eeb3b0a6513a980d470ccfa63189737340c7746a7 \
|
| 1143 |
+
--hash=sha256:74caf5e34b66d9f3a429af689c1c7128daba1d8208df60e81106b115c00d6fca \
|
| 1144 |
+
--hash=sha256:a17a5d5985f0ac494ed8a8e54568f092f7057ef60e1b0fa09d3fd1512064e803 \
|
| 1145 |
+
--hash=sha256:a6550fae429e0667e397e5de64b332d1e5695b73650ee75a6146e2e902770bea \
|
| 1146 |
+
--hash=sha256:d002e07d7180fd65e622134fbd980c9a3d4211fb85224b56a0a0efbd422ab72f \
|
| 1147 |
+
--hash=sha256:e8e323d608e3a9bfcc2d9efcc90ceefb764a82b99dea12a86d643c72539ad5d3
|
| 1148 |
+
# via torch
|
| 1149 |
+
typer==0.21.1 \
|
| 1150 |
+
--hash=sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01 \
|
| 1151 |
+
--hash=sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d
|
| 1152 |
+
# via gradio
|
| 1153 |
+
typer-slim==0.21.1 \
|
| 1154 |
+
--hash=sha256:6e6c31047f171ac93cc5a973c9e617dbc5ab2bddc4d0a3135dc161b4e2020e0d \
|
| 1155 |
+
--hash=sha256:73495dd08c2d0940d611c5a8c04e91c2a0a98600cbd4ee19192255a233b6dbfd
|
| 1156 |
+
# via huggingface-hub
|
| 1157 |
+
typing-extensions==4.15.0 \
|
| 1158 |
+
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
|
| 1159 |
+
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
|
| 1160 |
+
# via
|
| 1161 |
+
# anyio
|
| 1162 |
+
# exceptiongroup
|
| 1163 |
+
# fastapi
|
| 1164 |
+
# gradio
|
| 1165 |
+
# gradio-client
|
| 1166 |
+
# huggingface-hub
|
| 1167 |
+
# pydantic
|
| 1168 |
+
# pydantic-core
|
| 1169 |
+
# starlette
|
| 1170 |
+
# torch
|
| 1171 |
+
# typer
|
| 1172 |
+
# typer-slim
|
| 1173 |
+
# typing-inspection
|
| 1174 |
+
# uvicorn
|
| 1175 |
+
typing-inspection==0.4.2 \
|
| 1176 |
+
--hash=sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7 \
|
| 1177 |
+
--hash=sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464
|
| 1178 |
+
# via
|
| 1179 |
+
# fastapi
|
| 1180 |
+
# pydantic
|
| 1181 |
+
tzdata==2025.3 ; python_full_version < '3.11' or sys_platform == 'emscripten' or sys_platform == 'win32' \
|
| 1182 |
+
--hash=sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1 \
|
| 1183 |
+
--hash=sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7
|
| 1184 |
+
# via pandas
|
| 1185 |
+
uvicorn==0.40.0 \
|
| 1186 |
+
--hash=sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea \
|
| 1187 |
+
--hash=sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee
|
| 1188 |
+
# via gradio
|
src/dataset.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import torch
|
| 4 |
+
from torchvision.io import decode_image
|
| 5 |
+
from PIL import Image
|
| 6 |
+
|
| 7 |
+
class Dataset(torch.utils.data.Dataset):
|
| 8 |
+
def __init__(self,
|
| 9 |
+
dataframe: pd.DataFrame,
|
| 10 |
+
categories: list[str],
|
| 11 |
+
transform=None,
|
| 12 |
+
seed: int = 42,
|
| 13 |
+
shuffle: bool = True,
|
| 14 |
+
is_sampling: bool = False,
|
| 15 |
+
sampling_number: int = 50):
|
| 16 |
+
self.transform = transform
|
| 17 |
+
self.seed = seed
|
| 18 |
+
self.is_sampling = is_sampling
|
| 19 |
+
self.sampling_number = sampling_number
|
| 20 |
+
self.categories = categories
|
| 21 |
+
self.num_classes = len(self.categories)
|
| 22 |
+
if is_sampling:
|
| 23 |
+
self.dataframe = dataframe.reset_index(drop=True)[:sampling_number]
|
| 24 |
+
elif shuffle:
|
| 25 |
+
self.dataframe = dataframe.reset_index(drop=True).sample(frac=1, random_state=self.seed).reset_index(drop=True)
|
| 26 |
+
else:
|
| 27 |
+
self.dataframe = dataframe.reset_index(drop=True)
|
| 28 |
+
|
| 29 |
+
def __len__(self):
|
| 30 |
+
return len(self.dataframe)
|
| 31 |
+
|
| 32 |
+
def __getitem__(self, index):
|
| 33 |
+
row = self.dataframe.iloc[index]
|
| 34 |
+
img = Image.open(row["image_path"]).convert("RGB")
|
| 35 |
+
if self.transform:
|
| 36 |
+
img = self.transform(img)
|
| 37 |
+
label = torch.zeros(self.num_classes)
|
| 38 |
+
class_idx = self.categories.index(row["class"])
|
| 39 |
+
label[class_idx] = 1
|
| 40 |
+
assert torch.any(label), "Label tensor is empty"
|
| 41 |
+
return img, label
|
| 42 |
+
|
| 43 |
+
class IterableDataset(torch.utils.data.IterableDataset):
|
| 44 |
+
def __init__(self, dataframe: pd.DataFrame, transform=None, is_sampling: bool = False, sampling_number: int = 50):
|
| 45 |
+
if is_sampling:
|
| 46 |
+
self.dataframe = dataframe.reset_index(drop=True)[:sampling_number]
|
| 47 |
+
else:
|
| 48 |
+
self.dataframe = dataframe.reset_index(drop=True)
|
| 49 |
+
self.transform = transform
|
| 50 |
+
|
| 51 |
+
def __iter__(self):
|
| 52 |
+
worker_info = torch.utils.data.get_worker_info()
|
| 53 |
+
if worker_info is None:
|
| 54 |
+
start, end = 0, len(self.dataframe)
|
| 55 |
+
else:
|
| 56 |
+
per_worker = int(math.ceil(len(self.dataframe) / float(worker_info.num_workers)))
|
| 57 |
+
worker_id = worker_info.id
|
| 58 |
+
start = worker_id * per_worker
|
| 59 |
+
end = min(start + per_worker, len(self.dataframe))
|
| 60 |
+
|
| 61 |
+
for idx in range(start, end):
|
| 62 |
+
row = self.dataframe.iloc[idx]
|
| 63 |
+
img = decode_image(row["image_path"], mode="RGB")
|
| 64 |
+
if self.transform:
|
| 65 |
+
img = self.transform(img)
|
| 66 |
+
label = row["class"]
|
| 67 |
+
yield img, label
|
| 68 |
+
|
| 69 |
+
def __len__(self):
|
| 70 |
+
return len(self.dataframe)
|
| 71 |
+
|
| 72 |
+
def __getitem__(self, index):
|
| 73 |
+
return self.dataframe.iloc[index]
|
src/densenet.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import torch.nn as nn
|
| 3 |
+
from torch.nn import functional as F
|
| 4 |
+
|
| 5 |
+
import torchvision.models as models
|
| 6 |
+
|
| 7 |
+
class DenseNet121(nn.Module):
|
| 8 |
+
def __init__(self, num_classes, dropout_rate=0.25):
|
| 9 |
+
"""
|
| 10 |
+
Initialize DenseNet121 model with custom number of classes
|
| 11 |
+
|
| 12 |
+
Args:
|
| 13 |
+
num_classes (int): Number of output classes for classification
|
| 14 |
+
"""
|
| 15 |
+
super(DenseNet121, self).__init__()
|
| 16 |
+
|
| 17 |
+
self.densenet_model = models.densenet121(weights='IMAGENET1K_V1')
|
| 18 |
+
self.pool = True
|
| 19 |
+
self.dropout = nn.Dropout(p=dropout_rate)
|
| 20 |
+
|
| 21 |
+
if self.pool:
|
| 22 |
+
self.classifier = nn.Linear(1024, num_classes)
|
| 23 |
+
else:
|
| 24 |
+
self.classifier = nn.Linear(82944, num_classes)
|
| 25 |
+
|
| 26 |
+
def forward(self, x):
|
| 27 |
+
"""
|
| 28 |
+
Forward pass of the model
|
| 29 |
+
|
| 30 |
+
Args:
|
| 31 |
+
x (torch.Tensor): Input tensor of shape (batch_size, channels, height, width)
|
| 32 |
+
or (channels, height, width) for single image
|
| 33 |
+
|
| 34 |
+
Returns:
|
| 35 |
+
torch.Tensor: Output tensor of shape (batch_size, num_classes)
|
| 36 |
+
"""
|
| 37 |
+
# Add batch dimension if input is a single image
|
| 38 |
+
if x.dim() == 3:
|
| 39 |
+
x = x.unsqueeze(0)
|
| 40 |
+
|
| 41 |
+
features = self.densenet_model.features(x)
|
| 42 |
+
out = F.gelu(features)
|
| 43 |
+
# out = F.relu(features, inplace=True)
|
| 44 |
+
|
| 45 |
+
if self.pool:
|
| 46 |
+
out = F.adaptive_avg_pool2d(out, (1, 1)) # Global avg pool
|
| 47 |
+
|
| 48 |
+
if self.training:
|
| 49 |
+
# Apply dropout only during training
|
| 50 |
+
out = self.dropout(out)
|
| 51 |
+
|
| 52 |
+
# Flatten the output
|
| 53 |
+
out = torch.flatten(out, 1)
|
| 54 |
+
|
| 55 |
+
# Pass through the classifier
|
| 56 |
+
out = self.classifier(out)
|
| 57 |
+
|
| 58 |
+
return out
|
src/metrics.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from torcheval.metrics.metric import Metric
|
| 3 |
+
from typing import Iterable, TYPE_CHECKING, TypeVar, cast, Union, Optional
|
| 4 |
+
|
| 5 |
+
if TYPE_CHECKING:
|
| 6 |
+
from typing_extensions import Self # Or from typing import Self for Python 3.11+
|
| 7 |
+
|
| 8 |
+
_T = TypeVar("_T", bound="Metric") # TypeVar for merge_state
|
| 9 |
+
class MulticlassMCC(Metric):
|
| 10 |
+
def __init__(self, num_classes, device: Optional[Union[torch.device, str]] = None):
|
| 11 |
+
resolved_device = device if isinstance(device, torch.device) else torch.device(device or 'cpu')
|
| 12 |
+
super().__init__(device=resolved_device)
|
| 13 |
+
self.num_classes = num_classes
|
| 14 |
+
self._add_state("confusion_matrix", torch.zeros(num_classes, num_classes, device=resolved_device))
|
| 15 |
+
|
| 16 |
+
def update(self, y_pred: torch.Tensor, y_true: torch.Tensor) -> "Self":
|
| 17 |
+
y_true_labels = y_true
|
| 18 |
+
y_pred_labels = y_pred
|
| 19 |
+
|
| 20 |
+
if self.confusion_matrix.device != y_true.device:
|
| 21 |
+
self.confusion_matrix = self.confusion_matrix.to(y_true.device)
|
| 22 |
+
|
| 23 |
+
for t, p in zip(y_true_labels, y_pred_labels):
|
| 24 |
+
self.confusion_matrix[t.long(), p.long()] += 1
|
| 25 |
+
|
| 26 |
+
return self
|
| 27 |
+
|
| 28 |
+
def compute(self) -> torch.Tensor:
|
| 29 |
+
cm = self.confusion_matrix
|
| 30 |
+
t = torch.sum(cm, dim=1)
|
| 31 |
+
p = torch.sum(cm, dim=0)
|
| 32 |
+
c = torch.sum(torch.diag(cm))
|
| 33 |
+
s = torch.sum(cm)
|
| 34 |
+
numerator = c * s - torch.dot(t, p)
|
| 35 |
+
denominator = torch.sqrt((s**2 - torch.dot(p, p)) * (s**2 - torch.dot(t, t)))
|
| 36 |
+
return numerator / (denominator + torch.finfo(torch.float32).eps)
|
| 37 |
+
|
| 38 |
+
def reset(self) -> "Self":
|
| 39 |
+
self.confusion_matrix.zero_()
|
| 40 |
+
return self
|
| 41 |
+
|
| 42 |
+
def merge_state(self: _T, metrics: Iterable[_T]) -> _T:
|
| 43 |
+
for metric_obj in metrics:
|
| 44 |
+
if not isinstance(metric_obj, MulticlassMCC):
|
| 45 |
+
raise TypeError(f"Cannot merge_state for MulticlassMCC with metric of type {type(metric_obj).__name__}")
|
| 46 |
+
typed_metric = cast(MulticlassMCC, metric_obj)
|
| 47 |
+
|
| 48 |
+
other_cm_state = typed_metric.confusion_matrix
|
| 49 |
+
if self.confusion_matrix.device != other_cm_state.device:
|
| 50 |
+
other_cm_state = other_cm_state.to(self.confusion_matrix.device)
|
| 51 |
+
self.confusion_matrix += other_cm_state
|
| 52 |
+
return self
|
| 53 |
+
|
| 54 |
+
class MulticlassSpecificity(Metric):
|
| 55 |
+
def __init__(self, num_classes, device: Optional[Union[torch.device, str]] = None, average="macro"):
|
| 56 |
+
resolved_device = device if isinstance(device, torch.device) else torch.device(device or 'cpu')
|
| 57 |
+
super().__init__(device=resolved_device)
|
| 58 |
+
self.num_classes = num_classes
|
| 59 |
+
self.average = average
|
| 60 |
+
self._add_state("confusion_matrix", torch.zeros(num_classes, num_classes, device=resolved_device))
|
| 61 |
+
|
| 62 |
+
def update(self, y_pred: torch.Tensor, y_true: torch.Tensor) -> "Self":
|
| 63 |
+
y_true_labels = y_true
|
| 64 |
+
y_pred_labels = y_pred
|
| 65 |
+
|
| 66 |
+
if self.confusion_matrix.device != y_true.device:
|
| 67 |
+
self.confusion_matrix = self.confusion_matrix.to(y_true.device)
|
| 68 |
+
|
| 69 |
+
for t, p in zip(y_true_labels, y_pred_labels):
|
| 70 |
+
self.confusion_matrix[t.long(), p.long()] += 1
|
| 71 |
+
|
| 72 |
+
return self
|
| 73 |
+
|
| 74 |
+
def compute(self) -> torch.Tensor:
|
| 75 |
+
cm = self.confusion_matrix
|
| 76 |
+
tp = torch.diag(cm)
|
| 77 |
+
fp = torch.sum(cm, dim=0) - tp
|
| 78 |
+
fn = torch.sum(cm, dim=1) - tp
|
| 79 |
+
tn = torch.sum(cm) - (tp + fp + fn)
|
| 80 |
+
|
| 81 |
+
specificity_per_class = tn / (tn + fp + torch.finfo(torch.float32).eps)
|
| 82 |
+
|
| 83 |
+
if self.average == "macro":
|
| 84 |
+
return torch.mean(specificity_per_class)
|
| 85 |
+
elif self.average == "micro":
|
| 86 |
+
total_tn = torch.sum(tn)
|
| 87 |
+
total_fp = torch.sum(fp)
|
| 88 |
+
return total_tn / (total_tn + total_fp + torch.finfo(torch.float32).eps)
|
| 89 |
+
elif self.average == "weighted":
|
| 90 |
+
support = torch.sum(cm, dim=0) - torch.diag(cm) + (torch.sum(cm) - torch.sum(cm, dim=1))
|
| 91 |
+
weights = support / (torch.sum(support) + torch.finfo(torch.float32).eps)
|
| 92 |
+
return torch.sum(specificity_per_class * weights)
|
| 93 |
+
elif self.average == "none":
|
| 94 |
+
return specificity_per_class
|
| 95 |
+
else:
|
| 96 |
+
raise ValueError(f"Unknown average type: {self.average}")
|
| 97 |
+
|
| 98 |
+
def reset(self) -> "Self":
|
| 99 |
+
self.confusion_matrix.zero_()
|
| 100 |
+
return self
|
| 101 |
+
|
| 102 |
+
def merge_state(self: _T, metrics: Iterable[_T]) -> _T:
|
| 103 |
+
for metric_obj in metrics:
|
| 104 |
+
if not isinstance(metric_obj, MulticlassSpecificity):
|
| 105 |
+
raise TypeError(f"Cannot merge_state for MulticlassSpecificity with metric of type {type(metric_obj).__name__}")
|
| 106 |
+
typed_metric = cast(MulticlassSpecificity, metric_obj)
|
| 107 |
+
|
| 108 |
+
other_cm_state = typed_metric.confusion_matrix
|
| 109 |
+
if self.confusion_matrix.device != other_cm_state.device:
|
| 110 |
+
other_cm_state = other_cm_state.to(self.confusion_matrix.device)
|
| 111 |
+
self.confusion_matrix += other_cm_state
|
| 112 |
+
return self
|
src/preprocessing.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torchvision.transforms as transforms
|
| 2 |
+
|
| 3 |
+
def preprocess(target_input_size, # Expected as (C, H, W)
|
| 4 |
+
rotation_range=None,
|
| 5 |
+
width_shift_range=None,
|
| 6 |
+
height_shift_range=None,
|
| 7 |
+
shear_range=None,
|
| 8 |
+
zoom_range=None,
|
| 9 |
+
horizontal_flip=None,
|
| 10 |
+
vertical_flip=None,
|
| 11 |
+
brightness_range=None,
|
| 12 |
+
channel_shift_range=None,
|
| 13 |
+
fill_mode='nearest'):
|
| 14 |
+
|
| 15 |
+
if not (isinstance(target_input_size, (list, tuple)) and len(target_input_size) == 3):
|
| 16 |
+
raise ValueError("target_input_size must be a tuple or list of (C, H, W)")
|
| 17 |
+
|
| 18 |
+
_ , H, W = target_input_size # C is not used for Resize directly
|
| 19 |
+
resize_dims = (H, W)
|
| 20 |
+
|
| 21 |
+
# Create transforms that match TensorFlow's ImageDataGenerator functionality
|
| 22 |
+
transform_list = [
|
| 23 |
+
transforms.Resize(resize_dims), # Added Resize
|
| 24 |
+
transforms.ToTensor(),
|
| 25 |
+
# transforms.Lambda(lambda x: x / 255.0) # User's current normalization
|
| 26 |
+
]
|
| 27 |
+
|
| 28 |
+
if rotation_range is not None:
|
| 29 |
+
transform_list.append(transforms.RandomRotation(rotation_range))
|
| 30 |
+
|
| 31 |
+
if width_shift_range is not None or height_shift_range is not None:
|
| 32 |
+
transform_list.append(
|
| 33 |
+
transforms.RandomAffine(0, translate=(width_shift_range, height_shift_range))
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
if shear_range is not None:
|
| 37 |
+
transform_list.append(transforms.RandomAffine(0, shear=shear_range))
|
| 38 |
+
|
| 39 |
+
if zoom_range is not None:
|
| 40 |
+
transform_list.append(
|
| 41 |
+
transforms.RandomAffine(0, scale=(1-zoom_range, 1+zoom_range))
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
if horizontal_flip is not None:
|
| 45 |
+
transform_list.append(transforms.RandomHorizontalFlip())
|
| 46 |
+
|
| 47 |
+
if vertical_flip is not None:
|
| 48 |
+
transform_list.append(transforms.RandomVerticalFlip())
|
| 49 |
+
|
| 50 |
+
if brightness_range is not None:
|
| 51 |
+
transform_list.append(
|
| 52 |
+
transforms.ColorJitter(brightness=brightness_range[1]-brightness_range[0])
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
if channel_shift_range is not None:
|
| 56 |
+
# Clamp the channel_shift_range to ensure it falls within the acceptable range
|
| 57 |
+
hue_value = max(min(channel_shift_range/255.0, 0.5), -0.5)
|
| 58 |
+
transform_list.append(
|
| 59 |
+
transforms.ColorJitter(hue=hue_value)
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
return transforms.Compose(transform_list)
|
src/statistics.py
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
import numpy as np
|
| 3 |
+
import seaborn as sns
|
| 4 |
+
import matplotlib.pyplot as plt
|
| 5 |
+
from sklearn.calibration import calibration_curve
|
| 6 |
+
import os
|
| 7 |
+
|
| 8 |
+
from sklearn.metrics import accuracy_score, confusion_matrix, f1_score, precision_score, recall_score, roc_auc_score, average_precision_score, matthews_corrcoef
|
| 9 |
+
from imblearn.metrics import specificity_score
|
| 10 |
+
from torch.nn.functional import softmax
|
| 11 |
+
|
| 12 |
+
class Statistics:
|
| 13 |
+
def __init__(self, df: pd.DataFrame, categories: list = None):
|
| 14 |
+
self.data = df
|
| 15 |
+
self.categories = categories
|
| 16 |
+
self.data['is_correct'] = self.data['true_label'] == self.data['predicted_label']
|
| 17 |
+
self.total_samples = len(self.data)
|
| 18 |
+
self.total_correct = self.data['is_correct'].sum()
|
| 19 |
+
self.total_incorrect = self.total_samples - self.total_correct
|
| 20 |
+
|
| 21 |
+
def plot_confidence_distribution(self, save_path: str = None):
|
| 22 |
+
plt.figure(figsize=(10, 6))
|
| 23 |
+
sns.histplot(
|
| 24 |
+
data=self.data,
|
| 25 |
+
x='confidence',
|
| 26 |
+
hue='is_correct',
|
| 27 |
+
# element='step',
|
| 28 |
+
# stat='density',
|
| 29 |
+
common_norm=False,
|
| 30 |
+
palette={True: 'green', False: 'red'},
|
| 31 |
+
alpha=0.3
|
| 32 |
+
)
|
| 33 |
+
plt.title('Confidence Distribution')
|
| 34 |
+
plt.xlabel('Confidence')
|
| 35 |
+
plt.ylabel('Frequency')
|
| 36 |
+
self._save_plot(save_path)
|
| 37 |
+
plt.show()
|
| 38 |
+
|
| 39 |
+
def plot_class_confidence_boxplot(self, by_column='true_label', save_path: str = None):
|
| 40 |
+
"""Plots boxplots of confidence scores for each class."""
|
| 41 |
+
plt.figure(figsize=(14, 8))
|
| 42 |
+
|
| 43 |
+
sns.boxplot(
|
| 44 |
+
data=self.data,
|
| 45 |
+
x=by_column,
|
| 46 |
+
y='confidence',
|
| 47 |
+
hue='is_correct',
|
| 48 |
+
palette={True: 'green', False: 'red'},
|
| 49 |
+
showfliers=True,
|
| 50 |
+
linewidth=1.5
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
plt.title(f'Confidence Spread per Class (Grouped by {by_column})', fontsize=20)
|
| 54 |
+
plt.xlabel('Class Label')
|
| 55 |
+
plt.ylabel('Confidence Score')
|
| 56 |
+
plt.xticks(rotation=45, ha='right')
|
| 57 |
+
plt.legend(title='Prediction Status', loc='lower right', fontsize=13)
|
| 58 |
+
plt.tight_layout()
|
| 59 |
+
self._save_plot(save_path)
|
| 60 |
+
plt.show()
|
| 61 |
+
|
| 62 |
+
def recommend_threshold(self, save_path: str = None, target_accuracy=None, minimum_data_coverage = None, min_coverage=0.0):
|
| 63 |
+
"""
|
| 64 |
+
Scans thresholds from 0.5 to 0.99 to find the optimal cutoff.
|
| 65 |
+
Returns a DataFrame of the trade-offs.
|
| 66 |
+
If target_accuracy is provided, recommends the lowest threshold that meets it.
|
| 67 |
+
If minimum_data_coverage is provided, recommends the highest threshold that meets it.
|
| 68 |
+
"""
|
| 69 |
+
thresholds = np.linspace(0.5, 0.99, 50)
|
| 70 |
+
results = []
|
| 71 |
+
|
| 72 |
+
for t in thresholds:
|
| 73 |
+
passed = self.data[self.data['confidence'] >= t]
|
| 74 |
+
|
| 75 |
+
if len(passed) == 0:
|
| 76 |
+
continue
|
| 77 |
+
|
| 78 |
+
coverage = len(passed) / self.total_samples
|
| 79 |
+
|
| 80 |
+
results.append({
|
| 81 |
+
'threshold': t,
|
| 82 |
+
'filtered_accuracy': self._calc_accuracy(passed),
|
| 83 |
+
'filtered_f1': self._calc_f1(passed),
|
| 84 |
+
'filtered_precision': self._calc_precision(passed),
|
| 85 |
+
'filtered_recall': self._calc_recall(passed),
|
| 86 |
+
'filtered_mcc': self._calc_mcc(passed),
|
| 87 |
+
'filtered_specificity': self._calc_specificity(passed),
|
| 88 |
+
'coverage': coverage
|
| 89 |
+
})
|
| 90 |
+
|
| 91 |
+
results_df = pd.DataFrame(results)
|
| 92 |
+
baseline_accuracy = self.total_correct / self.total_samples
|
| 93 |
+
plt.figure(figsize=(10, 6))
|
| 94 |
+
sns.lineplot(data=results_df, x='threshold', y='filtered_accuracy', label='Accuracy (on retained)', color='blue')
|
| 95 |
+
sns.lineplot(data=results_df, x='threshold', y='coverage', label='Coverage (% data kept)', color='orange', linestyle='--')
|
| 96 |
+
plt.axhline(y=baseline_accuracy, color='red', linestyle=':', label=f'Baseline Accuracy: {baseline_accuracy:.2%}')
|
| 97 |
+
|
| 98 |
+
if target_accuracy is not None:
|
| 99 |
+
candidates = results_df[results_df['filtered_accuracy'] >= target_accuracy]
|
| 100 |
+
if not candidates.empty:
|
| 101 |
+
best = candidates.iloc[0]
|
| 102 |
+
plt.axvline(x=best['threshold'], color='green', linestyle='-.', label=f'Rec. Threshold: {best["threshold"]:.2f} \nat Coverage: {best["coverage"]:.2%}')
|
| 103 |
+
print(f"Recommended Threshold: {best['threshold']:.3f}")
|
| 104 |
+
print(f"Expected Accuracy: {best['filtered_accuracy']:.2%} | Data Retained: {best['coverage']:.2%}")
|
| 105 |
+
else:
|
| 106 |
+
print(f"Cannot achieve {target_accuracy} accuracy even at 99% threshold.")
|
| 107 |
+
|
| 108 |
+
plt.title(f'Accuracy-Coverage Analysis: Accuracy vs Data Retention\nRecommendation based on Target Accuracy ({target_accuracy:.2%})')
|
| 109 |
+
|
| 110 |
+
if minimum_data_coverage is not None:
|
| 111 |
+
candidates = results_df[results_df['coverage'] >= minimum_data_coverage]
|
| 112 |
+
if not candidates.empty:
|
| 113 |
+
# find the highest accuracy among candidates
|
| 114 |
+
best = candidates.loc[candidates['filtered_accuracy'].idxmax()]
|
| 115 |
+
plt.axvline(x=best['threshold'], color='purple', linestyle='-.', label=f'Rec. Threshold: {best["threshold"]:.2f} \nat Accuracy: {best["filtered_accuracy"]:.2%}')
|
| 116 |
+
print(f"Recommended Threshold for min coverage {minimum_data_coverage}: {best['threshold']:.3f}")
|
| 117 |
+
print(f"Expected Accuracy: {best['filtered_accuracy']:.2%} | Data Retained: {best['coverage']:.2%}")
|
| 118 |
+
else:
|
| 119 |
+
print(f"Cannot retain at least {minimum_data_coverage} of data even at 50% threshold.")
|
| 120 |
+
plt.title(f'Accuracy-Coverage Analysis: Accuracy vs Data Retention\nRecommendation based on Minimum Data Coverage ({minimum_data_coverage:.2%})')
|
| 121 |
+
|
| 122 |
+
plt.xlabel('Confidence Threshold')
|
| 123 |
+
plt.ylabel('Accuracy Score')
|
| 124 |
+
plt.legend(fontsize=13)
|
| 125 |
+
plt.grid(True, alpha=0.3)
|
| 126 |
+
self._save_plot(save_path)
|
| 127 |
+
plt.show()
|
| 128 |
+
|
| 129 |
+
self._best_threshold = best['threshold']
|
| 130 |
+
self._threshold_df = results_df
|
| 131 |
+
|
| 132 |
+
return self._threshold_df, self._best_threshold
|
| 133 |
+
|
| 134 |
+
def plot_filtered_threshold_cm(self, threshold=None, save_path=None):
|
| 135 |
+
# Plot confusion matrix using the best threshold
|
| 136 |
+
if not hasattr(self, '_best_threshold'):
|
| 137 |
+
raise ValueError("Best threshold not found. Please run recommend_threshold() first.")
|
| 138 |
+
elif threshold is None:
|
| 139 |
+
threshold = self._best_threshold
|
| 140 |
+
|
| 141 |
+
filtered_data = self.data[self.data['confidence'] >= threshold]
|
| 142 |
+
cm = confusion_matrix(filtered_data['true_label'], filtered_data['predicted_label'])
|
| 143 |
+
plt.figure(figsize=(8, 6))
|
| 144 |
+
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
|
| 145 |
+
xticklabels=self.categories,
|
| 146 |
+
yticklabels=self.categories)
|
| 147 |
+
plt.title(f'Confusion Matrix at Threshold: {threshold:.2f}')
|
| 148 |
+
plt.xlabel('Predicted Label')
|
| 149 |
+
plt.ylabel('True Label')
|
| 150 |
+
self._save_plot(save_path)
|
| 151 |
+
plt.show()
|
| 152 |
+
|
| 153 |
+
def plot_filtered_class_condidence_boxplot(self, threshold=None, save_path=None):
|
| 154 |
+
# Plot boxplot of confidence scores for each class using the best threshold
|
| 155 |
+
if not hasattr(self, '_best_threshold'):
|
| 156 |
+
raise ValueError("Best threshold not found. Please run recommend_threshold() first.")
|
| 157 |
+
elif threshold is None:
|
| 158 |
+
threshold = self._best_threshold
|
| 159 |
+
|
| 160 |
+
filtered_data = self.data[self.data['confidence'] >= threshold]
|
| 161 |
+
plt.figure(figsize=(14, 8))
|
| 162 |
+
|
| 163 |
+
sns.boxplot(
|
| 164 |
+
data=filtered_data,
|
| 165 |
+
x='true_label',
|
| 166 |
+
y='confidence',
|
| 167 |
+
hue='is_correct',
|
| 168 |
+
palette={True: 'green', False: 'red'},
|
| 169 |
+
showfliers=True,
|
| 170 |
+
linewidth=1.5
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
plt.title(f'Confidence Spread per Class at Best Threshold: {threshold:.2f}', fontsize=20)
|
| 174 |
+
plt.xlabel('Class Label')
|
| 175 |
+
plt.ylabel('Confidence Score')
|
| 176 |
+
plt.xticks(rotation=45, ha='right')
|
| 177 |
+
plt.legend(title='Prediction Status', loc='lower right', fontsize=13)
|
| 178 |
+
plt.tight_layout()
|
| 179 |
+
self._save_plot(save_path)
|
| 180 |
+
plt.show()
|
| 181 |
+
|
| 182 |
+
def plot_calibration_curve(self, n_bins=10):
|
| 183 |
+
"""
|
| 184 |
+
Checks if the model is overconfident.
|
| 185 |
+
Perfect calibration means the curve lies on the diagonal (y=x).
|
| 186 |
+
"""
|
| 187 |
+
prob_true, prob_pred = calibration_curve(self.data['is_correct'], self.data['confidence'], n_bins=n_bins)
|
| 188 |
+
|
| 189 |
+
plt.figure(figsize=(8, 8))
|
| 190 |
+
plt.plot(prob_pred, prob_true, marker='o', label='Model Calibration')
|
| 191 |
+
plt.plot([0, 1], [0, 1], linestyle='--', color='gray', label='Perfectly Calibrated')
|
| 192 |
+
|
| 193 |
+
plt.title('Reliability Diagram (Calibration Curve)')
|
| 194 |
+
plt.xlabel('Mean Predicted Confidence')
|
| 195 |
+
plt.ylabel('Fraction of Positives (Actual Accuracy)')
|
| 196 |
+
plt.legend()
|
| 197 |
+
plt.grid(True)
|
| 198 |
+
plt.show()
|
| 199 |
+
|
| 200 |
+
@staticmethod
|
| 201 |
+
def _calc_accuracy(df):
|
| 202 |
+
return accuracy_score(df['true_label'], df['predicted_label'])
|
| 203 |
+
|
| 204 |
+
@staticmethod
|
| 205 |
+
def _calc_precision(df):
|
| 206 |
+
return precision_score(df['true_label'], df['predicted_label'], average='macro')
|
| 207 |
+
|
| 208 |
+
@staticmethod
|
| 209 |
+
def _calc_recall(df):
|
| 210 |
+
return recall_score(df['true_label'], df['predicted_label'], average='macro')
|
| 211 |
+
|
| 212 |
+
@staticmethod
|
| 213 |
+
def _calc_f1(df):
|
| 214 |
+
return f1_score(df['true_label'], df['predicted_label'], average='macro')
|
| 215 |
+
|
| 216 |
+
@staticmethod
|
| 217 |
+
def _calc_specificity(df):
|
| 218 |
+
return specificity_score(df['true_label'], df['predicted_label'], average='macro')
|
| 219 |
+
|
| 220 |
+
@staticmethod
|
| 221 |
+
def _calc_mcc(df):
|
| 222 |
+
return matthews_corrcoef(df['true_label'], df['predicted_label'])
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def _save_plot(self, save_path):
|
| 226 |
+
if save_path:
|
| 227 |
+
directory = os.path.dirname(save_path)
|
| 228 |
+
if directory and not os.path.exists(directory):
|
| 229 |
+
os.makedirs(directory)
|
| 230 |
+
plt.savefig(save_path)
|
| 231 |
+
print(f"Plot saved to {save_path}")
|
| 232 |
+
|
| 233 |
+
def __len__(self):
|
| 234 |
+
return self.total_samples
|
src/test.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import torch
|
| 3 |
+
from tqdm import tqdm
|
| 4 |
+
|
| 5 |
+
def test(model, test_loader, device, verbose=False, print_every=10, metrics=None):
|
| 6 |
+
model.eval()
|
| 7 |
+
raw_predictions = []
|
| 8 |
+
target_indices = []
|
| 9 |
+
predicted_indices = []
|
| 10 |
+
loop = tqdm(test_loader, desc="Testing")
|
| 11 |
+
with torch.no_grad():
|
| 12 |
+
for batch_idx, (data, targets) in enumerate(loop):
|
| 13 |
+
data = data.to(device)
|
| 14 |
+
targets = targets.to(device)
|
| 15 |
+
|
| 16 |
+
model_outputs_raw = model(data)
|
| 17 |
+
raw_predictions.append(model_outputs_raw.detach().cpu())
|
| 18 |
+
# print(model_outputs_raw)
|
| 19 |
+
predicted_indices.append(torch.argmax(model_outputs_raw, dim=1).detach().cpu())
|
| 20 |
+
target_indices.append(torch.argmax(targets, dim=1).detach().cpu())
|
| 21 |
+
|
| 22 |
+
if (batch_idx + 1) % print_every == 0 and verbose:
|
| 23 |
+
print(f"Batch {batch_idx + 1}/{len(test_loader)}")
|
| 24 |
+
|
| 25 |
+
if torch.cuda.is_available():
|
| 26 |
+
torch.cuda.empty_cache()
|
| 27 |
+
|
| 28 |
+
# Concatenate tensors instead of converting to numpy
|
| 29 |
+
raw_predictions_flattened = torch.cat(raw_predictions)
|
| 30 |
+
predicted_indices_flattened = torch.cat(predicted_indices)
|
| 31 |
+
target_indices_flattened = torch.cat(target_indices)
|
| 32 |
+
|
| 33 |
+
if metrics:
|
| 34 |
+
test_metrics = {}
|
| 35 |
+
for metric_name, metric_obj in metrics.items():
|
| 36 |
+
if metric_name in ["auroc", "auprc"]:
|
| 37 |
+
# For binary classification metrics, use the positive class probabilities
|
| 38 |
+
# positive_class_probs = raw_predictions_flattened[:, 1] # Get probabilities for class 1
|
| 39 |
+
metric_obj.update(raw_predictions_flattened, target_indices_flattened)
|
| 40 |
+
# metric_obj.update(positive_class_probs, target_indices_flattened)
|
| 41 |
+
else:
|
| 42 |
+
metric_obj.update(predicted_indices_flattened, target_indices_flattened)
|
| 43 |
+
val = metric_obj.compute().clone().detach().cpu()
|
| 44 |
+
metric_val_to_store = val.item() if val.numel() == 1 else val.numpy()
|
| 45 |
+
test_metrics[metric_name] = metric_val_to_store
|
| 46 |
+
else:
|
| 47 |
+
test_metrics = None
|
| 48 |
+
|
| 49 |
+
# Convert to numpy only at the end for return values
|
| 50 |
+
predicted_indices_flattened = predicted_indices_flattened.numpy()
|
| 51 |
+
target_indices_flattened = target_indices_flattened.numpy()
|
| 52 |
+
|
| 53 |
+
return raw_predictions, predicted_indices_flattened, target_indices_flattened, test_metrics
|
src/utils.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import psutil
|
| 5 |
+
import gc
|
| 6 |
+
import numpy as np
|
| 7 |
+
import random
|
| 8 |
+
import yaml
|
| 9 |
+
from .densenet import DenseNet121
|
| 10 |
+
|
| 11 |
+
def set_seed(seed: int):
|
| 12 |
+
torch.manual_seed(seed)
|
| 13 |
+
torch.cuda.manual_seed(seed)
|
| 14 |
+
torch.cuda.manual_seed_all(seed)
|
| 15 |
+
torch.backends.cudnn.benchmark = False
|
| 16 |
+
torch.backends.cudnn.deterministic = True
|
| 17 |
+
np.random.seed(seed)
|
| 18 |
+
random.seed(seed)
|
| 19 |
+
os.environ['PYTHONHASHSEED'] = str(seed)\
|
| 20 |
+
|
| 21 |
+
def get_filenames(dataset_path):
|
| 22 |
+
# Get the list of file names
|
| 23 |
+
filenames = os.listdir(dataset_path)
|
| 24 |
+
filenames.sort()
|
| 25 |
+
|
| 26 |
+
return filenames
|
| 27 |
+
|
| 28 |
+
def generate_filenames_df(dataset_dir,
|
| 29 |
+
categories,
|
| 30 |
+
shuffle=False,
|
| 31 |
+
seed=42,
|
| 32 |
+
is_sample = False,
|
| 33 |
+
sample_size = 50):
|
| 34 |
+
full_filenames = {"image_path": [], "class": []}
|
| 35 |
+
|
| 36 |
+
for category in categories:
|
| 37 |
+
full_filenames_temp = get_filenames(os.path.join(dataset_dir, category))
|
| 38 |
+
|
| 39 |
+
for i in range(len(full_filenames_temp)):
|
| 40 |
+
full_filenames_temp[i] = os.path.join(dataset_dir, category, full_filenames_temp[i])
|
| 41 |
+
|
| 42 |
+
full_filenames["image_path"].extend(full_filenames_temp)
|
| 43 |
+
full_filenames["class"].extend([category] * len(full_filenames_temp))
|
| 44 |
+
|
| 45 |
+
full_filenames_df = pd.DataFrame.from_dict(full_filenames)
|
| 46 |
+
if shuffle:
|
| 47 |
+
full_filenames_df = full_filenames_df.sample(frac=1, random_state=seed).reset_index(drop=True)
|
| 48 |
+
|
| 49 |
+
if is_sample:
|
| 50 |
+
full_filenames_df = full_filenames_df.sample(n=sample_size, random_state=seed).reset_index(drop=True)
|
| 51 |
+
|
| 52 |
+
return full_filenames_df
|
| 53 |
+
|
| 54 |
+
def get_device():
|
| 55 |
+
if torch.cuda.is_available():
|
| 56 |
+
return torch.device("cuda")
|
| 57 |
+
else:
|
| 58 |
+
return torch.device("cpu")
|
| 59 |
+
|
| 60 |
+
def get_memory_usage():
|
| 61 |
+
"""Get current memory usage"""
|
| 62 |
+
process = psutil.Process(os.getpid())
|
| 63 |
+
cpu_memory = process.memory_info().rss / 1024 / 1024 # in MB
|
| 64 |
+
if torch.cuda.is_available():
|
| 65 |
+
gpu_memory = torch.cuda.memory_allocated() / 1024 / 1024 # in MB
|
| 66 |
+
gpu_memory_reserved = torch.cuda.memory_reserved() / 1024 / 1024 # in MB
|
| 67 |
+
return {
|
| 68 |
+
'cpu_memory': f"{cpu_memory:.2f}MB",
|
| 69 |
+
'gpu_memory_allocated': f"{gpu_memory:.2f}MB",
|
| 70 |
+
'gpu_memory_reserved': f"{gpu_memory_reserved:.2f}MB"
|
| 71 |
+
}
|
| 72 |
+
return {'cpu_memory': f"{cpu_memory:.2f}MB"}
|
| 73 |
+
|
| 74 |
+
def clear_memory():
|
| 75 |
+
"""Clear unused memory"""
|
| 76 |
+
gc.collect()
|
| 77 |
+
if torch.cuda.is_available():
|
| 78 |
+
torch.cuda.empty_cache()
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def is_best_model(current_metric, best_metric, mode="max", monitor_metric="loss"):
|
| 82 |
+
if mode == "max":
|
| 83 |
+
return current_metric > best_metric
|
| 84 |
+
else:
|
| 85 |
+
return current_metric < best_metric
|
| 86 |
+
|
| 87 |
+
def is_scheduler_per_batch(scheduler):
|
| 88 |
+
if scheduler is None:
|
| 89 |
+
return False
|
| 90 |
+
if (isinstance(scheduler, torch.optim.lr_scheduler.CyclicLR)
|
| 91 |
+
or isinstance(scheduler, torch.optim.lr_scheduler.CosineAnnealingWarmRestarts)
|
| 92 |
+
or isinstance(scheduler, torch.optim.lr_scheduler.OneCycleLR)):
|
| 93 |
+
return True
|
| 94 |
+
else:
|
| 95 |
+
return False
|
| 96 |
+
|
| 97 |
+
def load_model(model_path, num_classes=None, dropout_rate=0.25):
|
| 98 |
+
"""
|
| 99 |
+
Load a DenseNet121 model from a saved state dict or create a new one
|
| 100 |
+
|
| 101 |
+
Args:
|
| 102 |
+
model_path (str): Path to the saved model state dict
|
| 103 |
+
num_classes (int, optional): Number of output classes. Required if creating new model
|
| 104 |
+
dropout_rate (float, optional): Dropout rate for the model. Defaults to 0.25
|
| 105 |
+
|
| 106 |
+
Returns:
|
| 107 |
+
DenseNet121: Loaded or newly created model
|
| 108 |
+
"""
|
| 109 |
+
try:
|
| 110 |
+
# Try to load the model state dict
|
| 111 |
+
state_dict = torch.load(model_path)
|
| 112 |
+
model = DenseNet121(num_classes=num_classes, dropout_rate=dropout_rate)
|
| 113 |
+
model.load_state_dict(state_dict)
|
| 114 |
+
return model
|
| 115 |
+
except:
|
| 116 |
+
# If loading fails, create a new model
|
| 117 |
+
if num_classes is None:
|
| 118 |
+
raise ValueError("num_classes must be specified when creating a new model")
|
| 119 |
+
return DenseNet121(num_classes=num_classes, dropout_rate=dropout_rate)
|
src/xdl.py
ADDED
|
@@ -0,0 +1,689 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from typing import List, Tuple, Optional, Any, Union
|
| 3 |
+
|
| 4 |
+
import torch
|
| 5 |
+
import torch.nn as nn
|
| 6 |
+
from torch.utils.data import DataLoader
|
| 7 |
+
from pytorch_grad_cam import GradCAM
|
| 8 |
+
from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget
|
| 9 |
+
from pytorch_grad_cam.utils.image import show_cam_on_image
|
| 10 |
+
|
| 11 |
+
import cv2
|
| 12 |
+
import numpy as np
|
| 13 |
+
import matplotlib.pyplot as plt
|
| 14 |
+
import matplotlib.colors as colors
|
| 15 |
+
|
| 16 |
+
from src.densenet_multilayer import DenseNet121Multilayer
|
| 17 |
+
from src.densenet import DenseNet121
|
| 18 |
+
from src.resnet import ResNet50
|
| 19 |
+
|
| 20 |
+
def _preprocess_image(data_tensor: torch.Tensor) -> Tuple[np.ndarray, np.ndarray]:
|
| 21 |
+
"""
|
| 22 |
+
Convert tensor image to numpy and normalize for visualization.
|
| 23 |
+
|
| 24 |
+
Args:
|
| 25 |
+
data_tensor: input image tensor of shape (C, H, W)
|
| 26 |
+
|
| 27 |
+
Returns:
|
| 28 |
+
Tuple of (normalized_float_image, uint8_image)
|
| 29 |
+
"""
|
| 30 |
+
img = data_tensor.cpu().numpy()
|
| 31 |
+
img = np.transpose(img, (1, 2, 0))
|
| 32 |
+
img = (img - img.min()) / (img.max() - img.min())
|
| 33 |
+
img_uint8 = (img * 255).astype(np.uint8)
|
| 34 |
+
return img, img_uint8
|
| 35 |
+
|
| 36 |
+
def _process_smoothgrad_map(
|
| 37 |
+
smoothgrad_map: np.ndarray,
|
| 38 |
+
img_shape: Tuple[int, int],
|
| 39 |
+
percentile: float,
|
| 40 |
+
colormap: str,
|
| 41 |
+
) -> Tuple[np.ndarray, np.ndarray]:
|
| 42 |
+
"""
|
| 43 |
+
Process raw SmoothGrad map into visualization ready formats.
|
| 44 |
+
|
| 45 |
+
Args:
|
| 46 |
+
smoothgrad_map: Raw SmoothGrad attribution map
|
| 47 |
+
img_shape: Target shape (H, W)
|
| 48 |
+
percentile: Percentile for clipping high values
|
| 49 |
+
colormap: Colormap name ('hot' or 'viridis')
|
| 50 |
+
|
| 51 |
+
Returns:
|
| 52 |
+
Tuple of (normalized_map, heatmap_uint8)
|
| 53 |
+
"""
|
| 54 |
+
smoothgrad_map = np.transpose(smoothgrad_map, (1, 2, 0))
|
| 55 |
+
smoothgrad_map = np.mean(smoothgrad_map, axis=2) # Convert to grayscale
|
| 56 |
+
smoothgrad_map = cv2.resize(smoothgrad_map, (img_shape[1], img_shape[0]))
|
| 57 |
+
|
| 58 |
+
# Increase contrast by clipping at specified percentile and re-normalizing
|
| 59 |
+
p_clip = np.percentile(smoothgrad_map, percentile)
|
| 60 |
+
if p_clip > 0:
|
| 61 |
+
smoothgrad_map = np.clip(smoothgrad_map, 0, p_clip)
|
| 62 |
+
smoothgrad_map = (smoothgrad_map - smoothgrad_map.min()) / (p_clip - smoothgrad_map.min() + 1e-8)
|
| 63 |
+
|
| 64 |
+
# Improve visualization
|
| 65 |
+
smoothgrad_heatmap = (smoothgrad_map * 255).astype(np.uint8)
|
| 66 |
+
heatmap = cv2.applyColorMap(
|
| 67 |
+
smoothgrad_heatmap,
|
| 68 |
+
cv2.COLORMAP_HOT if colormap == 'hot' else cv2.COLORMAP_VIRIDIS
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
return smoothgrad_map, heatmap
|
| 72 |
+
|
| 73 |
+
def _calculate_abnormality_score(heatmap: np.ndarray, threshold: float = 0.5) -> dict:
|
| 74 |
+
"""
|
| 75 |
+
Calculate abnormality score based on heatmap coverage and intensity.
|
| 76 |
+
|
| 77 |
+
Args:
|
| 78 |
+
heatmap: Normalized GradCAM heatmap (0-1).
|
| 79 |
+
threshold: Threshold for considering a pixel as active.
|
| 80 |
+
|
| 81 |
+
Returns:
|
| 82 |
+
Dictionary containing coverage, avg_intensity, and calculate score.
|
| 83 |
+
"""
|
| 84 |
+
active_pixels = heatmap > threshold
|
| 85 |
+
coverage = np.mean(active_pixels)
|
| 86 |
+
|
| 87 |
+
if coverage > 0:
|
| 88 |
+
avg_intensity = np.mean(heatmap[active_pixels])
|
| 89 |
+
else:
|
| 90 |
+
avg_intensity = 0.0
|
| 91 |
+
|
| 92 |
+
# Score definition: weighted combination or simple product
|
| 93 |
+
# Here we define it as Coverage * Average Intensity of active region
|
| 94 |
+
score = coverage * avg_intensity
|
| 95 |
+
|
| 96 |
+
return {
|
| 97 |
+
"coverage": coverage,
|
| 98 |
+
"avg_intensity": avg_intensity,
|
| 99 |
+
"score": score
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
def _get_target_layer(model: nn.Module) -> Any:
|
| 103 |
+
"""Identify the target layer for GradCAM based on model architecture."""
|
| 104 |
+
if isinstance(model, DenseNet121):
|
| 105 |
+
return model.densenet_model.features[-1]
|
| 106 |
+
elif isinstance(model, ResNet50):
|
| 107 |
+
return model.resnet_model.layer4[-1]
|
| 108 |
+
elif isinstance(model, DenseNet121Multilayer):
|
| 109 |
+
return model.model_layer_2.densenet_model.features[-1]
|
| 110 |
+
# Fallback or error handling could go here
|
| 111 |
+
return None
|
| 112 |
+
|
| 113 |
+
def smoothgrad(
|
| 114 |
+
model: nn.Module,
|
| 115 |
+
input_tensor: torch.Tensor,
|
| 116 |
+
target_class: int,
|
| 117 |
+
n_samples: int = 100,
|
| 118 |
+
noise_level: float = 0.05
|
| 119 |
+
) -> np.ndarray:
|
| 120 |
+
"""
|
| 121 |
+
Compute SmoothGrad saliency map.
|
| 122 |
+
|
| 123 |
+
Args:
|
| 124 |
+
model: PyTorch model
|
| 125 |
+
input_tensor: Input tensor of shape (1, C, H, W)
|
| 126 |
+
target_class: Target class index
|
| 127 |
+
n_samples: Number of noisy samples to average (default: 100)
|
| 128 |
+
noise_level: Standard deviation of noise to add as fraction of range (default: 0.05)
|
| 129 |
+
|
| 130 |
+
Returns:
|
| 131 |
+
SmoothGrad saliency map as numpy array
|
| 132 |
+
"""
|
| 133 |
+
model.eval()
|
| 134 |
+
accumulated_gradients = torch.zeros_like(input_tensor)
|
| 135 |
+
input_range = torch.max(input_tensor) - torch.min(input_tensor)
|
| 136 |
+
scaled_noise_level = noise_level * input_range
|
| 137 |
+
|
| 138 |
+
for _ in range(n_samples):
|
| 139 |
+
# Clone and detach input for each sample
|
| 140 |
+
noise = torch.randn_like(input_tensor) * scaled_noise_level
|
| 141 |
+
noisy_input = (input_tensor + noise).clone().detach().requires_grad_(True)
|
| 142 |
+
|
| 143 |
+
output = model(noisy_input)
|
| 144 |
+
if len(output.shape) == 1:
|
| 145 |
+
output = output.unsqueeze(0)
|
| 146 |
+
|
| 147 |
+
model.zero_grad()
|
| 148 |
+
loss = output[0, target_class]
|
| 149 |
+
loss.backward()
|
| 150 |
+
|
| 151 |
+
if noisy_input.grad is not None:
|
| 152 |
+
accumulated_gradients += noisy_input.grad.data
|
| 153 |
+
|
| 154 |
+
smoothgrad_map = accumulated_gradients / n_samples
|
| 155 |
+
smoothgrad_map = torch.abs(smoothgrad_map)
|
| 156 |
+
|
| 157 |
+
# Normalize map
|
| 158 |
+
min_val, max_val = smoothgrad_map.min(), smoothgrad_map.max()
|
| 159 |
+
smoothgrad_map = (smoothgrad_map - min_val) / (max_val - min_val + 1e-8)
|
| 160 |
+
|
| 161 |
+
return smoothgrad_map[0].cpu().numpy()
|
| 162 |
+
|
| 163 |
+
def _get_model_predictions(
|
| 164 |
+
model: nn.Module,
|
| 165 |
+
data: torch.Tensor
|
| 166 |
+
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 167 |
+
"""
|
| 168 |
+
Get raw outputs, predicted indices and probabilities.
|
| 169 |
+
|
| 170 |
+
Returns:
|
| 171 |
+
Tuple of (model_outputs_raw, predicted_indices, probabilities)
|
| 172 |
+
"""
|
| 173 |
+
with torch.no_grad():
|
| 174 |
+
model_outputs_raw = model(data)
|
| 175 |
+
predicted_indices = torch.argmax(model_outputs_raw, dim=1)
|
| 176 |
+
probabilities = torch.nn.functional.softmax(model_outputs_raw, dim=1)
|
| 177 |
+
return model_outputs_raw, predicted_indices, probabilities
|
| 178 |
+
|
| 179 |
+
def plot_XDL_Visualizations(
|
| 180 |
+
model: nn.Module,
|
| 181 |
+
test_loader: DataLoader,
|
| 182 |
+
device: torch.device,
|
| 183 |
+
num_samples: int = 5,
|
| 184 |
+
print_img: bool = False,
|
| 185 |
+
print_every: int = 10,
|
| 186 |
+
save_path: Optional[str] = None,
|
| 187 |
+
smoothgrad_percentile: float = 95,
|
| 188 |
+
smoothgrad_colormap: str = 'hot',
|
| 189 |
+
smoothgrad_overlay_alpha: float = 0.5
|
| 190 |
+
) -> None:
|
| 191 |
+
"""
|
| 192 |
+
Plot visualizations with GradCAM and SmoothGrad.
|
| 193 |
+
|
| 194 |
+
Args:
|
| 195 |
+
model: PyTorch model
|
| 196 |
+
test_loader: DataLoader for test data
|
| 197 |
+
device: Device to run model on
|
| 198 |
+
num_samples: Number of samples to visualize
|
| 199 |
+
print_img: Whether to display images
|
| 200 |
+
print_every: Print progress every N batches
|
| 201 |
+
save_path: Path to save visualizations
|
| 202 |
+
smoothgrad_percentile: Percentile for clipping SmoothGrad values (default: 95)
|
| 203 |
+
smoothgrad_colormap: Colormap for SmoothGrad visualization (default: 'hot')
|
| 204 |
+
smoothgrad_overlay_alpha: Alpha value for SmoothGrad overlay (default: 0.5)
|
| 205 |
+
"""
|
| 206 |
+
model.eval()
|
| 207 |
+
print(f"Using model: {model.__class__.__name__}")
|
| 208 |
+
|
| 209 |
+
target_layer = _get_target_layer(model)
|
| 210 |
+
if target_layer is None:
|
| 211 |
+
print("Warning: Could not determine target layer for GradCAM.")
|
| 212 |
+
|
| 213 |
+
categories = test_loader.dataset.categories
|
| 214 |
+
|
| 215 |
+
# Initialize GradCAM
|
| 216 |
+
cam = GradCAM(
|
| 217 |
+
model=model,
|
| 218 |
+
target_layers=[target_layer] if target_layer else []
|
| 219 |
+
)
|
| 220 |
+
|
| 221 |
+
samples_processed = 0
|
| 222 |
+
samples_processed_per_class = {i: 0 for i in range(len(categories))}
|
| 223 |
+
max_samples_per_class = num_samples // len(categories) if num_samples > len(categories) else num_samples
|
| 224 |
+
|
| 225 |
+
for batch_idx, (data, targets) in enumerate(test_loader):
|
| 226 |
+
if samples_processed >= num_samples:
|
| 227 |
+
break
|
| 228 |
+
|
| 229 |
+
data = data.to(device)
|
| 230 |
+
targets = targets.to(device)
|
| 231 |
+
|
| 232 |
+
model_outputs_raw, predicted_indices, _ = _get_model_predictions(model, data)
|
| 233 |
+
target_indices = torch.argmax(targets, dim=1)
|
| 234 |
+
|
| 235 |
+
if batch_idx % print_every == 0:
|
| 236 |
+
print(f'Processing batch {batch_idx + 1}, samples processed: {samples_processed}')
|
| 237 |
+
|
| 238 |
+
for i in range(min(len(data), num_samples - samples_processed)):
|
| 239 |
+
|
| 240 |
+
if samples_processed >= num_samples:
|
| 241 |
+
break
|
| 242 |
+
|
| 243 |
+
img, img_uint8 = _preprocess_image(data[i])
|
| 244 |
+
pred_idx = predicted_indices[i].item()
|
| 245 |
+
true_idx = target_indices[i].item()
|
| 246 |
+
|
| 247 |
+
print(f'Processing sample {samples_processed + 1}, raw prediction: {model_outputs_raw[i].cpu().numpy()}, predicted index: {pred_idx}, true index: {true_idx}')
|
| 248 |
+
|
| 249 |
+
# Get GradCAM visualization
|
| 250 |
+
grayscale_cam = cam(
|
| 251 |
+
input_tensor=data[i:i+1],
|
| 252 |
+
targets=[ClassifierOutputTarget(pred_idx)]
|
| 253 |
+
)[0, :]
|
| 254 |
+
cam_image = show_cam_on_image(img, grayscale_cam, use_rgb=True)
|
| 255 |
+
|
| 256 |
+
# Get SmoothGrad visualization
|
| 257 |
+
smoothgrad_map_raw = smoothgrad(model, data[i:i+1], pred_idx)
|
| 258 |
+
smoothgrad_map, heatmap = _process_smoothgrad_map(
|
| 259 |
+
smoothgrad_map_raw,
|
| 260 |
+
img_shape=(img.shape[0], img.shape[1]),
|
| 261 |
+
percentile=smoothgrad_percentile,
|
| 262 |
+
colormap=smoothgrad_colormap
|
| 263 |
+
)
|
| 264 |
+
|
| 265 |
+
# Adjust overlay weights for better visibility
|
| 266 |
+
overlay = cv2.addWeighted(img_uint8, 1 - smoothgrad_overlay_alpha, heatmap, smoothgrad_overlay_alpha, 0)
|
| 267 |
+
|
| 268 |
+
# Create visualization
|
| 269 |
+
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(18, 10))
|
| 270 |
+
|
| 271 |
+
# Firs row, First column: original image with label information
|
| 272 |
+
axes[0, 0].imshow(img)
|
| 273 |
+
axes[0, 0].set_title(f'True: {categories[true_idx]}, Pred: {categories[pred_idx]} \nConfidence: {torch.nn.functional.softmax(model_outputs_raw[i], dim=0)[pred_idx]:.4f}')
|
| 274 |
+
axes[0, 0].axis('off')
|
| 275 |
+
|
| 276 |
+
# First row, Second column: GradCAM visualization
|
| 277 |
+
axes[0, 1].imshow(cam_image)
|
| 278 |
+
axes[0, 1].set_title('GradCAM Visualization')
|
| 279 |
+
axes[0, 1].axis('off')
|
| 280 |
+
|
| 281 |
+
# Add colorbar for GradCAM
|
| 282 |
+
norm_cam = colors.Normalize(vmin=grayscale_cam.min(), vmax=grayscale_cam.max())
|
| 283 |
+
sm_cam = plt.cm.ScalarMappable(cmap='jet', norm=norm_cam)
|
| 284 |
+
sm_cam.set_array([])
|
| 285 |
+
fig.colorbar(sm_cam, ax=axes[0, 1], shrink=0.8)
|
| 286 |
+
|
| 287 |
+
# First row, Third column: SmoothGrad visualization
|
| 288 |
+
axes[0, 2].imshow(overlay)
|
| 289 |
+
axes[0, 2].set_title('SmoothGrad Visualization')
|
| 290 |
+
axes[0, 2].axis('off')
|
| 291 |
+
|
| 292 |
+
# Add colorbar for SmoothGrad
|
| 293 |
+
norm_smooth = colors.Normalize(vmin=smoothgrad_map.min(), vmax=smoothgrad_map.max())
|
| 294 |
+
sm_smooth = plt.cm.ScalarMappable(cmap='viridis', norm=norm_smooth)
|
| 295 |
+
sm_smooth.set_array([])
|
| 296 |
+
fig.colorbar(sm_smooth, ax=axes[0, 2], shrink=0.8)
|
| 297 |
+
|
| 298 |
+
# Second row, First column: Filtered Image (SmoothGrad)
|
| 299 |
+
threshold = 0.5
|
| 300 |
+
|
| 301 |
+
# Add channel dimension if needed for masking
|
| 302 |
+
smoothgrad_map_copy = smoothgrad_map.copy()
|
| 303 |
+
if len(smoothgrad_map_copy.shape) == 2:
|
| 304 |
+
smoothgrad_map_copy = np.expand_dims(smoothgrad_map_copy, axis=-1)
|
| 305 |
+
smoothgrad_map_copy = np.repeat(smoothgrad_map_copy, repeats=3, axis=-1)
|
| 306 |
+
|
| 307 |
+
filtered_img = np.where(smoothgrad_map_copy > threshold, img, 1)
|
| 308 |
+
axes[1, 0].imshow(filtered_img)
|
| 309 |
+
axes[1, 0].set_title(f'Filtered Image (SmoothGrad > {threshold})')
|
| 310 |
+
axes[1, 0].axis('off')
|
| 311 |
+
|
| 312 |
+
# Second row, Imshow SmoothGrad heatmap
|
| 313 |
+
axes[1, 2].imshow(smoothgrad_map, cmap='viridis')
|
| 314 |
+
axes[1, 2].set_title('SmoothGrad Heatmap')
|
| 315 |
+
axes[1, 2].axis('off')
|
| 316 |
+
|
| 317 |
+
# Add colorbar for SmoothGrad heatmap
|
| 318 |
+
sm_smooth_heatmap = plt.cm.ScalarMappable(cmap='viridis', norm=colors.Normalize(vmin=smoothgrad_map.min(), vmax=smoothgrad_map.max()))
|
| 319 |
+
sm_smooth_heatmap.set_array([])
|
| 320 |
+
fig.colorbar(sm_smooth_heatmap, ax=axes[1, 2], shrink=0.8)
|
| 321 |
+
|
| 322 |
+
# Second row, Second column: Filtered Image (GradCAM)
|
| 323 |
+
cam_threshold = 0.5
|
| 324 |
+
|
| 325 |
+
# Add channel dimension if needed
|
| 326 |
+
cam_image_copy = grayscale_cam.copy()
|
| 327 |
+
if len(cam_image_copy.shape) == 2:
|
| 328 |
+
cam_image_copy = np.expand_dims(cam_image_copy, axis=-1)
|
| 329 |
+
cam_image_copy = np.repeat(cam_image_copy, repeats=3, axis=-1)
|
| 330 |
+
filtered_cam_img = np.where(cam_image_copy > cam_threshold, img, 1)
|
| 331 |
+
axes[1, 1].imshow(filtered_cam_img)
|
| 332 |
+
axes[1, 1].set_title(f'Filtered Image (GradCAM > {cam_threshold})')
|
| 333 |
+
axes[1, 1].axis('off')
|
| 334 |
+
|
| 335 |
+
# Add invisible colorbar for alignment
|
| 336 |
+
norm_cam_invis = colors.Normalize(vmin=0, vmax=0)
|
| 337 |
+
sm_cam_invis = plt.cm.ScalarMappable(cmap='Greys', norm=norm_cam_invis)
|
| 338 |
+
sm_cam_invis.set_array([])
|
| 339 |
+
fig.colorbar(sm_cam_invis, ax=axes[1, 1], shrink=0.8)
|
| 340 |
+
|
| 341 |
+
plt.tight_layout()
|
| 342 |
+
|
| 343 |
+
if save_path:
|
| 344 |
+
true_label = categories[true_idx]
|
| 345 |
+
pred_label = categories[pred_idx]
|
| 346 |
+
os.makedirs(save_path, exist_ok=True)
|
| 347 |
+
|
| 348 |
+
if pred_label == true_label:
|
| 349 |
+
plt.savefig(os.path.join(save_path, f'{true_label}_{samples_processed}.png'))
|
| 350 |
+
else:
|
| 351 |
+
plt.savefig(os.path.join(save_path, f'wrong_{true_label}_{samples_processed}.png'))
|
| 352 |
+
|
| 353 |
+
if print_img:
|
| 354 |
+
plt.show()
|
| 355 |
+
|
| 356 |
+
plt.close(fig)
|
| 357 |
+
samples_processed += 1
|
| 358 |
+
|
| 359 |
+
if batch_idx % print_every == 0:
|
| 360 |
+
print(f'Processed {samples_processed} samples')
|
| 361 |
+
|
| 362 |
+
def plot_XDL_GradCAM(
|
| 363 |
+
model: nn.Module,
|
| 364 |
+
test_loader: DataLoader,
|
| 365 |
+
device: torch.device,
|
| 366 |
+
fontsize: int = 13,
|
| 367 |
+
num_samples: int = 5,
|
| 368 |
+
print_img: bool = False,
|
| 369 |
+
print_every: int = 10,
|
| 370 |
+
save_path: Optional[str] = None,
|
| 371 |
+
show_abnormality_score: bool = True
|
| 372 |
+
) -> None:
|
| 373 |
+
"""
|
| 374 |
+
Plot simple GradCAM visualizations.
|
| 375 |
+
|
| 376 |
+
Args:
|
| 377 |
+
model: PyTorch model
|
| 378 |
+
test_loader: DataLoader for test data
|
| 379 |
+
device: Device to run model on
|
| 380 |
+
fontsize: Font size for titles
|
| 381 |
+
num_samples: Number of samples to visualize
|
| 382 |
+
print_img: Whether to display images
|
| 383 |
+
print_every: Print progress every N batches
|
| 384 |
+
save_path: Path to save visualizations
|
| 385 |
+
show_abnormality_score: Whether to calculate and show abnormality score (default: True)
|
| 386 |
+
"""
|
| 387 |
+
model.eval()
|
| 388 |
+
|
| 389 |
+
target_layer = _get_target_layer(model)
|
| 390 |
+
if target_layer is None:
|
| 391 |
+
print("Warning: Could not determine target layer for GradCAM.")
|
| 392 |
+
|
| 393 |
+
categories = test_loader.dataset.categories
|
| 394 |
+
|
| 395 |
+
cam = GradCAM(
|
| 396 |
+
model=model,
|
| 397 |
+
target_layers=[target_layer] if target_layer else []
|
| 398 |
+
)
|
| 399 |
+
|
| 400 |
+
samples_processed = 0
|
| 401 |
+
for batch_idx, (data, targets) in enumerate(test_loader):
|
| 402 |
+
if samples_processed >= num_samples:
|
| 403 |
+
break
|
| 404 |
+
|
| 405 |
+
data = data.to(device)
|
| 406 |
+
targets = targets.to(device)
|
| 407 |
+
|
| 408 |
+
_, predicted_indices, raw_probabilities = _get_model_predictions(model, data)
|
| 409 |
+
raw_predictions = raw_probabilities.cpu().numpy()
|
| 410 |
+
target_indices = torch.argmax(targets, dim=1)
|
| 411 |
+
|
| 412 |
+
for i in range(min(len(data), num_samples - samples_processed)):
|
| 413 |
+
if save_path:
|
| 414 |
+
os.makedirs(save_path, exist_ok=True)
|
| 415 |
+
img_path = os.path.join(save_path, f'{samples_processed}.png')
|
| 416 |
+
if os.path.exists(img_path):
|
| 417 |
+
samples_processed += 1
|
| 418 |
+
continue
|
| 419 |
+
|
| 420 |
+
img, _ = _preprocess_image(data[i])
|
| 421 |
+
pred_idx = predicted_indices[i].item()
|
| 422 |
+
true_idx = target_indices[i].item()
|
| 423 |
+
|
| 424 |
+
grayscale_cam = cam(
|
| 425 |
+
input_tensor=data[i:i+1],
|
| 426 |
+
targets=[ClassifierOutputTarget(pred_idx)]
|
| 427 |
+
)[0, :]
|
| 428 |
+
|
| 429 |
+
# Calculate Abnormality Score if requested
|
| 430 |
+
if show_abnormality_score:
|
| 431 |
+
abnormality_stats = _calculate_abnormality_score(grayscale_cam, threshold=0.5)
|
| 432 |
+
score = abnormality_stats["score"]
|
| 433 |
+
coverage = abnormality_stats["coverage"]
|
| 434 |
+
intensity = abnormality_stats["avg_intensity"]
|
| 435 |
+
|
| 436 |
+
print(f"Sample {samples_processed + 1} - Score: {score:.4f}, Coverage: {coverage:.4f}, Intensity: {intensity:.4f}")
|
| 437 |
+
title = f'GradCAM:\nAbnormality Score: {score:.3f}' # (Cov: {coverage:.2f}, Int: {intensity:.2f})'
|
| 438 |
+
else:
|
| 439 |
+
title = 'GradCAM Visualization'
|
| 440 |
+
|
| 441 |
+
cam_image = show_cam_on_image(img, grayscale_cam, use_rgb=True)
|
| 442 |
+
|
| 443 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
|
| 444 |
+
ax1.imshow(img)
|
| 445 |
+
ax1.set_title(f'True: {categories[true_idx]} \nPred: {categories[pred_idx]} (Confidence: {raw_predictions[i][pred_idx]:.2f})', fontsize=fontsize)
|
| 446 |
+
ax1.axis('off')
|
| 447 |
+
|
| 448 |
+
ax2.imshow(cam_image)
|
| 449 |
+
ax2.set_title(title, fontsize=fontsize)
|
| 450 |
+
ax2.axis('off')
|
| 451 |
+
|
| 452 |
+
# Add colorbar for GradCAM
|
| 453 |
+
norm_cam = colors.Normalize(vmin=grayscale_cam.min(), vmax=grayscale_cam.max())
|
| 454 |
+
sm_cam = plt.cm.ScalarMappable(cmap='jet', norm=norm_cam)
|
| 455 |
+
sm_cam.set_array([])
|
| 456 |
+
fig.colorbar(sm_cam, ax=ax2, shrink=0.8)
|
| 457 |
+
|
| 458 |
+
plt.tight_layout()
|
| 459 |
+
if save_path:
|
| 460 |
+
plt.savefig(img_path)
|
| 461 |
+
|
| 462 |
+
if print_img:
|
| 463 |
+
plt.show()
|
| 464 |
+
|
| 465 |
+
plt.close(fig)
|
| 466 |
+
samples_processed += 1
|
| 467 |
+
|
| 468 |
+
if batch_idx % print_every == 0:
|
| 469 |
+
print(f'Processed {samples_processed} samples')
|
| 470 |
+
|
| 471 |
+
def plot_XDL_SmoothGrad(
|
| 472 |
+
model: nn.Module,
|
| 473 |
+
test_loader: DataLoader,
|
| 474 |
+
device: torch.device,
|
| 475 |
+
num_samples: int = 5,
|
| 476 |
+
print_img: bool = True,
|
| 477 |
+
print_every: int = 10,
|
| 478 |
+
save_path: Optional[str] = None,
|
| 479 |
+
n_samples_smoothgrad: int = 100,
|
| 480 |
+
noise_level: float = 0.05,
|
| 481 |
+
smoothgrad_percentile: float = 99, # Slightly higher default for sharper maps
|
| 482 |
+
smoothgrad_colormap: str = 'hot',
|
| 483 |
+
smoothgrad_overlay_alpha: float = 0.5,
|
| 484 |
+
fontsize: int = 13,
|
| 485 |
+
show_abnormality_score: bool = True # NEW PARAMETER
|
| 486 |
+
) -> None:
|
| 487 |
+
"""
|
| 488 |
+
Plot SmoothGrad visualizations with Abnormality Scores.
|
| 489 |
+
"""
|
| 490 |
+
model.eval()
|
| 491 |
+
categories = test_loader.dataset.categories
|
| 492 |
+
samples_processed = 0
|
| 493 |
+
|
| 494 |
+
# Define threshold for SmoothGrad (SmoothGrad is sharper/sparser than GradCAM,
|
| 495 |
+
# so sometimes a lower threshold captures extent better, but 0.5 is standard)
|
| 496 |
+
score_threshold = 0.3
|
| 497 |
+
|
| 498 |
+
for batch_idx, (data, targets) in enumerate(test_loader):
|
| 499 |
+
if samples_processed >= num_samples:
|
| 500 |
+
break
|
| 501 |
+
|
| 502 |
+
data = data.to(device)
|
| 503 |
+
targets = targets.to(device)
|
| 504 |
+
|
| 505 |
+
_, predicted_indices, raw_probabilities = _get_model_predictions(model, data)
|
| 506 |
+
raw_predictions = raw_probabilities.cpu().numpy()
|
| 507 |
+
target_indices = torch.argmax(targets, dim=1)
|
| 508 |
+
|
| 509 |
+
for i in range(min(len(data), num_samples - samples_processed)):
|
| 510 |
+
img, img_uint8 = _preprocess_image(data[i])
|
| 511 |
+
pred_idx = predicted_indices[i].item()
|
| 512 |
+
true_idx = target_indices[i].item()
|
| 513 |
+
|
| 514 |
+
# 1. Get SmoothGrad Raw Map
|
| 515 |
+
smoothgrad_map_raw = smoothgrad(model, data[i:i+1], pred_idx, n_samples=n_samples_smoothgrad, noise_level=noise_level)
|
| 516 |
+
|
| 517 |
+
# 2. Process to Grayscale (0-1) and Heatmap (Color)
|
| 518 |
+
# smoothgrad_map here is the Normalized Grayscale Map we need for scoring
|
| 519 |
+
smoothgrad_map, heatmap = _process_smoothgrad_map(
|
| 520 |
+
smoothgrad_map_raw,
|
| 521 |
+
img_shape=(img.shape[0], img.shape[1]),
|
| 522 |
+
percentile=smoothgrad_percentile,
|
| 523 |
+
colormap=smoothgrad_colormap
|
| 524 |
+
)
|
| 525 |
+
|
| 526 |
+
# 3. Calculate Abnormality Score (NEW STEP)
|
| 527 |
+
title_suffix = ""
|
| 528 |
+
if show_abnormality_score:
|
| 529 |
+
stats = _calculate_abnormality_score(smoothgrad_map, threshold=score_threshold)
|
| 530 |
+
score = stats["score"]
|
| 531 |
+
coverage = stats["coverage"]
|
| 532 |
+
intensity = stats["avg_intensity"]
|
| 533 |
+
|
| 534 |
+
print(f"[SmoothGrad] Sample {samples_processed + 1} - Abnormality Score: {score:.4f}") # (Cov: {coverage:.3f}, Int: {intensity:.3f})
|
| 535 |
+
title_suffix = f"\nAbnormality Score: {score:.3f}"
|
| 536 |
+
|
| 537 |
+
# Adjust overlay weights
|
| 538 |
+
overlay = cv2.addWeighted(img_uint8, 1 - smoothgrad_overlay_alpha, heatmap, smoothgrad_overlay_alpha, 0)
|
| 539 |
+
|
| 540 |
+
# Create visualization
|
| 541 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
|
| 542 |
+
|
| 543 |
+
# Plot Original
|
| 544 |
+
ax1.imshow(img)
|
| 545 |
+
ax1.set_title(f'True: {categories[true_idx]} \nPred: {categories[pred_idx]} (Conf: {raw_predictions[i][pred_idx]:.2f})', fontsize=fontsize)
|
| 546 |
+
ax1.axis('off')
|
| 547 |
+
|
| 548 |
+
# Plot SmoothGrad
|
| 549 |
+
ax2.imshow(overlay)
|
| 550 |
+
ax2.set_title(f'SmoothGrad Visualization{title_suffix}', fontsize=fontsize)
|
| 551 |
+
ax2.axis('off')
|
| 552 |
+
|
| 553 |
+
# Add colorbar
|
| 554 |
+
norm_smooth = colors.Normalize(vmin=smoothgrad_map.min(), vmax=smoothgrad_map.max())
|
| 555 |
+
sm_smooth = plt.cm.ScalarMappable(cmap='viridis', norm=norm_smooth)
|
| 556 |
+
sm_smooth.set_array([])
|
| 557 |
+
fig.colorbar(sm_smooth, ax=ax2, shrink=0.8)
|
| 558 |
+
|
| 559 |
+
plt.tight_layout()
|
| 560 |
+
|
| 561 |
+
if save_path:
|
| 562 |
+
os.makedirs(save_path, exist_ok=True)
|
| 563 |
+
plt.savefig(os.path.join(save_path, f'smoothgrad_{samples_processed}.png'))
|
| 564 |
+
|
| 565 |
+
if print_img:
|
| 566 |
+
plt.show()
|
| 567 |
+
|
| 568 |
+
plt.close(fig)
|
| 569 |
+
|
| 570 |
+
samples_processed += 1
|
| 571 |
+
|
| 572 |
+
if batch_idx % print_every == 0:
|
| 573 |
+
print(f'Processed {samples_processed} samples')
|
| 574 |
+
|
| 575 |
+
def plot_comparative_scoring(
|
| 576 |
+
model: nn.Module,
|
| 577 |
+
test_loader: DataLoader,
|
| 578 |
+
device: torch.device,
|
| 579 |
+
num_samples: int = 5,
|
| 580 |
+
save_path: Optional[str] = None,
|
| 581 |
+
print_img: bool = True,
|
| 582 |
+
smoothgrad_percentile: float = 98
|
| 583 |
+
) -> None:
|
| 584 |
+
"""
|
| 585 |
+
Generates a side-by-side comparison of Original, GradCAM, and SmoothGrad
|
| 586 |
+
specifically highlighting their calculated Abnormality Scores.
|
| 587 |
+
"""
|
| 588 |
+
model.eval()
|
| 589 |
+
print(f"Generating comparative scores for {num_samples} samples...")
|
| 590 |
+
|
| 591 |
+
# 1. Setup GradCAM
|
| 592 |
+
target_layer = _get_target_layer(model)
|
| 593 |
+
cam = GradCAM(model=model, target_layers=[target_layer] if target_layer else [])
|
| 594 |
+
|
| 595 |
+
categories = test_loader.dataset.categories
|
| 596 |
+
samples_processed = 0
|
| 597 |
+
|
| 598 |
+
# 2. Loop through data
|
| 599 |
+
for batch_idx, (data, targets) in enumerate(test_loader):
|
| 600 |
+
if samples_processed >= num_samples:
|
| 601 |
+
break
|
| 602 |
+
|
| 603 |
+
data = data.to(device)
|
| 604 |
+
targets = targets.to(device)
|
| 605 |
+
|
| 606 |
+
# Get predictions
|
| 607 |
+
model_outputs_raw, predicted_indices, raw_probs = _get_model_predictions(model, data)
|
| 608 |
+
target_indices = torch.argmax(targets, dim=1)
|
| 609 |
+
|
| 610 |
+
for i in range(min(len(data), num_samples - samples_processed)):
|
| 611 |
+
|
| 612 |
+
# --- A. Preparation ---
|
| 613 |
+
img, img_uint8 = _preprocess_image(data[i])
|
| 614 |
+
pred_idx = predicted_indices[i].item()
|
| 615 |
+
true_idx = target_indices[i].item()
|
| 616 |
+
conf = raw_probs[i][pred_idx].item()
|
| 617 |
+
|
| 618 |
+
# --- B. Compute GradCAM & Score ---
|
| 619 |
+
# Generate Map
|
| 620 |
+
grayscale_cam = cam(input_tensor=data[i:i+1], targets=[ClassifierOutputTarget(pred_idx)])[0, :]
|
| 621 |
+
|
| 622 |
+
# Calculate Score (Threshold 0.5 is standard for GradCAM)
|
| 623 |
+
gcam_stats = _calculate_abnormality_score(grayscale_cam, threshold=0.5)
|
| 624 |
+
gcam_score = gcam_stats['score']
|
| 625 |
+
|
| 626 |
+
# Create Overlay
|
| 627 |
+
cam_overlay = show_cam_on_image(img, grayscale_cam, use_rgb=True)
|
| 628 |
+
|
| 629 |
+
# --- C. Compute SmoothGrad & Score ---
|
| 630 |
+
# Generate Map
|
| 631 |
+
smoothgrad_map_raw = smoothgrad(model, data[i:i+1], pred_idx)
|
| 632 |
+
smoothgrad_map, heatmap = _process_smoothgrad_map(
|
| 633 |
+
smoothgrad_map_raw,
|
| 634 |
+
img_shape=(img.shape[0], img.shape[1]),
|
| 635 |
+
percentile=smoothgrad_percentile, # High percentile for sharp contrast
|
| 636 |
+
colormap='hot'
|
| 637 |
+
)
|
| 638 |
+
|
| 639 |
+
# Calculate Score (Threshold 0.3 is often better for SmoothGrad as it is sparser)
|
| 640 |
+
sgrad_stats = _calculate_abnormality_score(smoothgrad_map, threshold=0.3)
|
| 641 |
+
sgrad_score = sgrad_stats['score']
|
| 642 |
+
|
| 643 |
+
# Create Overlay
|
| 644 |
+
smooth_overlay = cv2.addWeighted(img_uint8, 0.6, heatmap, 0.4, 0)
|
| 645 |
+
|
| 646 |
+
# --- D. Plotting ---
|
| 647 |
+
fig, axes = plt.subplots(1, 3, figsize=(18, 7))
|
| 648 |
+
|
| 649 |
+
# Panel 1: Original Image
|
| 650 |
+
axes[0].imshow(img)
|
| 651 |
+
axes[0].set_title(f"True: {categories[true_idx]}\nPred: {categories[pred_idx]} ({conf:.2f})", fontsize=14)
|
| 652 |
+
axes[0].axis('off')
|
| 653 |
+
|
| 654 |
+
# Panel 2: GradCAM
|
| 655 |
+
axes[1].imshow(cam_overlay)
|
| 656 |
+
axes[1].set_title(f"GradCAM\nAbnormality Score: {gcam_score:.4f}", fontsize=14, color='darkblue')
|
| 657 |
+
axes[1].axis('off')
|
| 658 |
+
# Colorbar 1
|
| 659 |
+
norm_g = colors.Normalize(vmin=0, vmax=1)
|
| 660 |
+
sm_g = plt.cm.ScalarMappable(cmap='jet', norm=norm_g)
|
| 661 |
+
sm_g.set_array([])
|
| 662 |
+
plt.colorbar(sm_g, ax=axes[1], fraction=0.046, pad=0.04)
|
| 663 |
+
|
| 664 |
+
# Panel 3: SmoothGrad
|
| 665 |
+
axes[2].imshow(smooth_overlay)
|
| 666 |
+
axes[2].set_title(f"SmoothGrad\nAbnormality Score: {sgrad_score:.4f}", fontsize=14, color='darkred')
|
| 667 |
+
axes[2].axis('off')
|
| 668 |
+
# Colorbar 2
|
| 669 |
+
norm_s = colors.Normalize(vmin=0, vmax=1)
|
| 670 |
+
sm_s = plt.cm.ScalarMappable(cmap='hot', norm=norm_s)
|
| 671 |
+
sm_s.set_array([])
|
| 672 |
+
plt.colorbar(sm_s, ax=axes[2], fraction=0.046, pad=0.04)
|
| 673 |
+
|
| 674 |
+
plt.tight_layout()
|
| 675 |
+
|
| 676 |
+
# Save/Print
|
| 677 |
+
if save_path:
|
| 678 |
+
os.makedirs(save_path, exist_ok=True)
|
| 679 |
+
fname = f"Score_Comparison_{samples_processed}_{categories[true_idx]}.png"
|
| 680 |
+
plt.savefig(os.path.join(save_path, fname))
|
| 681 |
+
|
| 682 |
+
if print_img:
|
| 683 |
+
plt.show()
|
| 684 |
+
|
| 685 |
+
plt.close(fig)
|
| 686 |
+
samples_processed += 1
|
| 687 |
+
|
| 688 |
+
# Print console summary
|
| 689 |
+
print(f"Sample {samples_processed}: GradCAM Score={gcam_score:.4f} | SmoothGrad Score={sgrad_score:.4f}")
|