Commit
·
e9f9fd3
0
Parent(s):
Initial commit for Hugging Face sync (Clean History)
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +11 -0
- .github/CODEOWNERS +4 -0
- .github/ISSUE_TEMPLATE/bug_report.md +38 -0
- .github/ISSUE_TEMPLATE/feature_request.md +20 -0
- .github/PULL_REQUEST_TEMPLATE.md +38 -0
- .gitignore +153 -0
- .pre-commit-config.yaml +7 -0
- .pylintrc +579 -0
- .travis.yml +10 -0
- CHANGELOG.md +36 -0
- CODE_OF_CONDUCT.md +125 -0
- CONTRIBUTING.md +90 -0
- ColorFIDBenchmarkArtistic.ipynb +3 -0
- ColorizeTrainingArtistic.ipynb +3 -0
- ColorizeTrainingStable.ipynb +3 -0
- ColorizeTrainingStableLargeBatch.ipynb +3 -0
- ColorizeTrainingVideo.ipynb +3 -0
- ColorizeTrainingWandb.ipynb +3 -0
- HF_README.md +215 -0
- ImageColorizer.ipynb +3 -0
- ImageColorizerArtisticTests.ipynb +3 -0
- ImageColorizerColab.ipynb +3 -0
- ImageColorizerColabStable.ipynb +3 -0
- ImageColorizerStableTests.ipynb +3 -0
- LICENSE +21 -0
- MANIFEST.in +3 -0
- README.md +542 -0
- ROADMAP.md +189 -0
- SECURITY.md +19 -0
- TODO.md +52 -0
- USAGE_EXAMPLES.md +229 -0
- VideoColorizer.ipynb +3 -0
- VideoColorizerColab.ipynb +3 -0
- akbartus_tree.json +1 -0
- assets.txt +16 -0
- browser/README.md +39 -0
- browser/artistic.html +247 -0
- browser/index.html +71 -0
- browser/quantized.html +248 -0
- browser/serve.ps1 +27 -0
- check_remote_models.py +29 -0
- check_remote_models_v2.py +30 -0
- compare_models.py +44 -0
- deoldify/__init__.py +8 -0
- deoldify/_device.py +69 -0
- deoldify/augs.py +29 -0
- deoldify/critics.py +47 -0
- deoldify/dataset.py +20 -0
- deoldify/device_id.py +13 -0
- deoldify/fastai_compat.py +268 -0
.gitattributes
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.ipynb filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.JPG filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.JPEG filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.PNG filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
/ColorizeVisualization.ipynb filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
.github/CODEOWNERS
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# See: https://help.github.com/en/articles/about-code-owners
|
| 2 |
+
#
|
| 3 |
+
# Owners will be requested for review when someone opens a pull request.
|
| 4 |
+
* @jantic @alexandrevicenzi
|
.github/ISSUE_TEMPLATE/bug_report.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: Bug report
|
| 3 |
+
about: Create a report to help us improve
|
| 4 |
+
title: ''
|
| 5 |
+
labels: ''
|
| 6 |
+
assignees: ''
|
| 7 |
+
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
**Describe the bug**
|
| 11 |
+
A clear and concise description of what the bug is.
|
| 12 |
+
|
| 13 |
+
**To Reproduce**
|
| 14 |
+
Steps to reproduce the behavior:
|
| 15 |
+
1. Go to '...'
|
| 16 |
+
2. Click on '...'
|
| 17 |
+
3. Scroll down to '...'
|
| 18 |
+
4. See error
|
| 19 |
+
|
| 20 |
+
**Expected behavior**
|
| 21 |
+
A clear and concise description of what you expected to happen.
|
| 22 |
+
|
| 23 |
+
**Screenshots**
|
| 24 |
+
If applicable, add screenshots to help explain your problem.
|
| 25 |
+
|
| 26 |
+
**Desktop (please complete the following information):**
|
| 27 |
+
- OS: [e.g. iOS]
|
| 28 |
+
- Browser [e.g. chrome, safari]
|
| 29 |
+
- Version [e.g. 22]
|
| 30 |
+
|
| 31 |
+
**Smartphone (please complete the following information):**
|
| 32 |
+
- Device: [e.g. iPhone6]
|
| 33 |
+
- OS: [e.g. iOS8.1]
|
| 34 |
+
- Browser [e.g. stock browser, safari]
|
| 35 |
+
- Version [e.g. 22]
|
| 36 |
+
|
| 37 |
+
**Additional context**
|
| 38 |
+
Add any other context about the problem here.
|
.github/ISSUE_TEMPLATE/feature_request.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: Feature request
|
| 3 |
+
about: Suggest an idea for this project
|
| 4 |
+
title: ''
|
| 5 |
+
labels: ''
|
| 6 |
+
assignees: ''
|
| 7 |
+
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
**Is your feature request related to a problem? Please describe.**
|
| 11 |
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
| 12 |
+
|
| 13 |
+
**Describe the solution you'd like**
|
| 14 |
+
A clear and concise description of what you want to happen.
|
| 15 |
+
|
| 16 |
+
**Describe alternatives you've considered**
|
| 17 |
+
A clear and concise description of any alternative solutions or features you've considered.
|
| 18 |
+
|
| 19 |
+
**Additional context**
|
| 20 |
+
Add any other context or screenshots about the feature request here.
|
.github/PULL_REQUEST_TEMPLATE.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## Description
|
| 2 |
+
|
| 3 |
+
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
|
| 4 |
+
|
| 5 |
+
Fixes # (issue)
|
| 6 |
+
|
| 7 |
+
## Type of change
|
| 8 |
+
|
| 9 |
+
Please delete options that are not relevant.
|
| 10 |
+
|
| 11 |
+
- [ ] Bug fix (non-breaking change which fixes an issue)
|
| 12 |
+
- [ ] New feature (non-breaking change which adds functionality)
|
| 13 |
+
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
| 14 |
+
- [ ] This change requires a documentation update
|
| 15 |
+
|
| 16 |
+
## How Has This Been Tested?
|
| 17 |
+
|
| 18 |
+
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
|
| 19 |
+
|
| 20 |
+
- [ ] Test A
|
| 21 |
+
- [ ] Test B
|
| 22 |
+
|
| 23 |
+
**Test Configuration**:
|
| 24 |
+
* Firmware version:
|
| 25 |
+
* Hardware:
|
| 26 |
+
* Toolchain:
|
| 27 |
+
* SDK:
|
| 28 |
+
|
| 29 |
+
## Checklist:
|
| 30 |
+
|
| 31 |
+
- [ ] My code follows the style guidelines of this project
|
| 32 |
+
- [ ] I have performed a self-review of my own code
|
| 33 |
+
- [ ] I have commented my code, particularly in hard-to-understand areas
|
| 34 |
+
- [ ] I have made corresponding changes to the documentation
|
| 35 |
+
- [ ] My changes generate no new warnings
|
| 36 |
+
- [ ] I have added tests that prove my fix is effective or that my feature works
|
| 37 |
+
- [ ] New and existing unit tests pass locally with my changes
|
| 38 |
+
- [ ] Any dependent changes have been merged and published in downstream modules
|
.gitignore
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Byte-compiled / optimized / DLL files
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*$py.class
|
| 5 |
+
|
| 6 |
+
# C extensions
|
| 7 |
+
*.so
|
| 8 |
+
|
| 9 |
+
# Distribution / packaging
|
| 10 |
+
.Python
|
| 11 |
+
build/
|
| 12 |
+
develop-eggs/
|
| 13 |
+
dist/
|
| 14 |
+
downloads/
|
| 15 |
+
eggs/
|
| 16 |
+
.eggs/
|
| 17 |
+
lib/
|
| 18 |
+
lib64/
|
| 19 |
+
parts/
|
| 20 |
+
sdist/
|
| 21 |
+
var/
|
| 22 |
+
wheels/
|
| 23 |
+
*.egg-info/
|
| 24 |
+
.installed.cfg
|
| 25 |
+
*.egg
|
| 26 |
+
MANIFEST
|
| 27 |
+
|
| 28 |
+
# PyInstaller
|
| 29 |
+
# Usually these files are written by a python script from a template
|
| 30 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
| 31 |
+
*.manifest
|
| 32 |
+
*.spec
|
| 33 |
+
|
| 34 |
+
# Installer logs
|
| 35 |
+
pip-log.txt
|
| 36 |
+
pip-delete-this-directory.txt
|
| 37 |
+
|
| 38 |
+
# Unit test / coverage reports
|
| 39 |
+
htmlcov/
|
| 40 |
+
.tox/
|
| 41 |
+
.coverage
|
| 42 |
+
.coverage.*
|
| 43 |
+
.cache
|
| 44 |
+
nosetests.xml
|
| 45 |
+
coverage.xml
|
| 46 |
+
*.cover
|
| 47 |
+
.hypothesis/
|
| 48 |
+
.pytest_cache/
|
| 49 |
+
|
| 50 |
+
# Translations
|
| 51 |
+
*.mo
|
| 52 |
+
*.pot
|
| 53 |
+
|
| 54 |
+
# Django stuff:
|
| 55 |
+
*.log
|
| 56 |
+
local_settings.py
|
| 57 |
+
db.sqlite3
|
| 58 |
+
|
| 59 |
+
# Flask stuff:
|
| 60 |
+
instance/
|
| 61 |
+
.webassets-cache
|
| 62 |
+
|
| 63 |
+
# Scrapy stuff:
|
| 64 |
+
.scrapy
|
| 65 |
+
|
| 66 |
+
# Sphinx documentation
|
| 67 |
+
docs/_build/
|
| 68 |
+
|
| 69 |
+
# PyBuilder
|
| 70 |
+
target/
|
| 71 |
+
|
| 72 |
+
# Jupyter Notebook
|
| 73 |
+
.ipynb_checkpoints
|
| 74 |
+
|
| 75 |
+
# pyenv
|
| 76 |
+
.python-version
|
| 77 |
+
|
| 78 |
+
# celery beat schedule file
|
| 79 |
+
celerybeat-schedule
|
| 80 |
+
|
| 81 |
+
# SageMath parsed files
|
| 82 |
+
*.sage.py
|
| 83 |
+
|
| 84 |
+
# Environments
|
| 85 |
+
.env
|
| 86 |
+
.venv
|
| 87 |
+
env/
|
| 88 |
+
venv/
|
| 89 |
+
ENV/
|
| 90 |
+
env.bak/
|
| 91 |
+
venv.bak/
|
| 92 |
+
|
| 93 |
+
# Spyder project settings
|
| 94 |
+
.spyderproject
|
| 95 |
+
.spyproject
|
| 96 |
+
|
| 97 |
+
# Rope project settings
|
| 98 |
+
.ropeproject
|
| 99 |
+
|
| 100 |
+
# mkdocs documentation
|
| 101 |
+
/site
|
| 102 |
+
|
| 103 |
+
# mypy
|
| 104 |
+
.mypy_cache/
|
| 105 |
+
|
| 106 |
+
# DeOldify
|
| 107 |
+
data
|
| 108 |
+
*SymbolicLinks.sh
|
| 109 |
+
*.ipynb_checkpoints*
|
| 110 |
+
ColorizeTraining*[0-9]*.ipynb
|
| 111 |
+
*Colorizer[0-9]*.ipynb
|
| 112 |
+
lesson7-superres*.ipynb
|
| 113 |
+
test.py
|
| 114 |
+
result_images
|
| 115 |
+
*.prof
|
| 116 |
+
video
|
| 117 |
+
test_images/*.jpg
|
| 118 |
+
test_images/*.JPG
|
| 119 |
+
test_images/*.PNG
|
| 120 |
+
test_images/*.png
|
| 121 |
+
test_images/*.jpeg
|
| 122 |
+
test_images/*.JPEG
|
| 123 |
+
deoldify/.ipynb_checkpoints/*-checkpoint.py
|
| 124 |
+
tmp*
|
| 125 |
+
|
| 126 |
+
# Model weights and checkpoints
|
| 127 |
+
models/*.pth
|
| 128 |
+
models/*.pt
|
| 129 |
+
*.pth
|
| 130 |
+
*.pt
|
| 131 |
+
checkpoints/
|
| 132 |
+
|
| 133 |
+
# Logs and debugging
|
| 134 |
+
logs/
|
| 135 |
+
*.log
|
| 136 |
+
wandb/
|
| 137 |
+
.tensorboard/
|
| 138 |
+
|
| 139 |
+
# Output directories
|
| 140 |
+
output/
|
| 141 |
+
results/
|
| 142 |
+
colorized/
|
| 143 |
+
|
| 144 |
+
# IDE
|
| 145 |
+
.vscode/
|
| 146 |
+
.idea/
|
| 147 |
+
*.swp
|
| 148 |
+
*.swo
|
| 149 |
+
*~
|
| 150 |
+
|
| 151 |
+
# OS
|
| 152 |
+
.DS_Store
|
| 153 |
+
Thumbs.db
|
.pre-commit-config.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
repos:
|
| 2 |
+
- repo: https://github.com/ambv/black
|
| 3 |
+
rev: stable
|
| 4 |
+
hooks:
|
| 5 |
+
- id: black
|
| 6 |
+
args: [-S]
|
| 7 |
+
language_version: python3.6
|
.pylintrc
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[MASTER]
|
| 2 |
+
|
| 3 |
+
# A comma-separated list of package or module names from where C extensions may
|
| 4 |
+
# be loaded. Extensions are loading into the active Python interpreter and may
|
| 5 |
+
# run arbitrary code.
|
| 6 |
+
extension-pkg-whitelist=
|
| 7 |
+
|
| 8 |
+
# Add files or directories to the blacklist. They should be base names, not
|
| 9 |
+
# paths.
|
| 10 |
+
ignore=CVS
|
| 11 |
+
|
| 12 |
+
# Add files or directories matching the regex patterns to the blacklist. The
|
| 13 |
+
# regex matches against base names, not paths.
|
| 14 |
+
ignore-patterns=
|
| 15 |
+
|
| 16 |
+
# Python code to execute, usually for sys.path manipulation such as
|
| 17 |
+
# pygtk.require().
|
| 18 |
+
#init-hook='import sys; sys.path.append("./venv/lib/python3.7/site-packages")'
|
| 19 |
+
|
| 20 |
+
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
| 21 |
+
# number of processors available to use.
|
| 22 |
+
jobs=1
|
| 23 |
+
|
| 24 |
+
# Control the amount of potential inferred values when inferring a single
|
| 25 |
+
# object. This can help the performance when dealing with large functions or
|
| 26 |
+
# complex, nested conditions.
|
| 27 |
+
limit-inference-results=100
|
| 28 |
+
|
| 29 |
+
# List of plugins (as comma separated values of python modules names) to load,
|
| 30 |
+
# usually to register additional checkers.
|
| 31 |
+
load-plugins=
|
| 32 |
+
|
| 33 |
+
# Pickle collected data for later comparisons.
|
| 34 |
+
persistent=yes
|
| 35 |
+
|
| 36 |
+
# Specify a configuration file.
|
| 37 |
+
#rcfile=
|
| 38 |
+
|
| 39 |
+
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
| 40 |
+
# user-friendly hints instead of false-positive error messages.
|
| 41 |
+
suggestion-mode=yes
|
| 42 |
+
|
| 43 |
+
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
| 44 |
+
# active Python interpreter and may run arbitrary code.
|
| 45 |
+
unsafe-load-any-extension=no
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
[MESSAGES CONTROL]
|
| 49 |
+
|
| 50 |
+
# Only show warnings with the listed confidence levels. Leave empty to show
|
| 51 |
+
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
|
| 52 |
+
confidence=
|
| 53 |
+
|
| 54 |
+
# Disable the message, report, category or checker with the given id(s). You
|
| 55 |
+
# can either give multiple identifiers separated by comma (,) or put this
|
| 56 |
+
# option multiple times (only on the command line, not in the configuration
|
| 57 |
+
# file where it should appear only once). You can also use "--disable=all" to
|
| 58 |
+
# disable everything first and then reenable specific checks. For example, if
|
| 59 |
+
# you want to run only the similarities checker, you can use "--disable=all
|
| 60 |
+
# --enable=similarities". If you want to run only the classes checker, but have
|
| 61 |
+
# no Warning level messages displayed, use "--disable=all --enable=classes
|
| 62 |
+
# --disable=W".
|
| 63 |
+
disable=print-statement,
|
| 64 |
+
parameter-unpacking,
|
| 65 |
+
unpacking-in-except,
|
| 66 |
+
old-raise-syntax,
|
| 67 |
+
backtick,
|
| 68 |
+
long-suffix,
|
| 69 |
+
old-ne-operator,
|
| 70 |
+
old-octal-literal,
|
| 71 |
+
import-star-module-level,
|
| 72 |
+
non-ascii-bytes-literal,
|
| 73 |
+
raw-checker-failed,
|
| 74 |
+
bad-inline-option,
|
| 75 |
+
locally-disabled,
|
| 76 |
+
locally-enabled,
|
| 77 |
+
file-ignored,
|
| 78 |
+
suppressed-message,
|
| 79 |
+
useless-suppression,
|
| 80 |
+
deprecated-pragma,
|
| 81 |
+
use-symbolic-message-instead,
|
| 82 |
+
apply-builtin,
|
| 83 |
+
basestring-builtin,
|
| 84 |
+
buffer-builtin,
|
| 85 |
+
cmp-builtin,
|
| 86 |
+
coerce-builtin,
|
| 87 |
+
execfile-builtin,
|
| 88 |
+
file-builtin,
|
| 89 |
+
long-builtin,
|
| 90 |
+
raw_input-builtin,
|
| 91 |
+
reduce-builtin,
|
| 92 |
+
standarderror-builtin,
|
| 93 |
+
unicode-builtin,
|
| 94 |
+
xrange-builtin,
|
| 95 |
+
coerce-method,
|
| 96 |
+
delslice-method,
|
| 97 |
+
getslice-method,
|
| 98 |
+
setslice-method,
|
| 99 |
+
no-absolute-import,
|
| 100 |
+
old-division,
|
| 101 |
+
dict-iter-method,
|
| 102 |
+
dict-view-method,
|
| 103 |
+
next-method-called,
|
| 104 |
+
metaclass-assignment,
|
| 105 |
+
indexing-exception,
|
| 106 |
+
raising-string,
|
| 107 |
+
reload-builtin,
|
| 108 |
+
oct-method,
|
| 109 |
+
hex-method,
|
| 110 |
+
nonzero-method,
|
| 111 |
+
cmp-method,
|
| 112 |
+
input-builtin,
|
| 113 |
+
round-builtin,
|
| 114 |
+
intern-builtin,
|
| 115 |
+
unichr-builtin,
|
| 116 |
+
map-builtin-not-iterating,
|
| 117 |
+
zip-builtin-not-iterating,
|
| 118 |
+
range-builtin-not-iterating,
|
| 119 |
+
filter-builtin-not-iterating,
|
| 120 |
+
using-cmp-argument,
|
| 121 |
+
eq-without-hash,
|
| 122 |
+
div-method,
|
| 123 |
+
idiv-method,
|
| 124 |
+
rdiv-method,
|
| 125 |
+
exception-message-attribute,
|
| 126 |
+
invalid-str-codec,
|
| 127 |
+
sys-max-int,
|
| 128 |
+
bad-python3-import,
|
| 129 |
+
deprecated-string-function,
|
| 130 |
+
deprecated-str-translate-call,
|
| 131 |
+
deprecated-itertools-function,
|
| 132 |
+
deprecated-types-field,
|
| 133 |
+
next-method-defined,
|
| 134 |
+
dict-items-not-iterating,
|
| 135 |
+
dict-keys-not-iterating,
|
| 136 |
+
dict-values-not-iterating,
|
| 137 |
+
deprecated-operator-function,
|
| 138 |
+
deprecated-urllib-function,
|
| 139 |
+
xreadlines-attribute,
|
| 140 |
+
deprecated-sys-function,
|
| 141 |
+
exception-escape,
|
| 142 |
+
comprehension-escape,
|
| 143 |
+
# Disabled due Black
|
| 144 |
+
bad-continuation,
|
| 145 |
+
bad-whitespace,
|
| 146 |
+
# We don't care about these
|
| 147 |
+
redundant-keyword-arg,
|
| 148 |
+
|
| 149 |
+
# Enable the message, report, category or checker with the given id(s). You can
|
| 150 |
+
# either give multiple identifier separated by comma (,) or put this option
|
| 151 |
+
# multiple time (only on the command line, not in the configuration file where
|
| 152 |
+
# it should appear only once). See also the "--disable" option for examples.
|
| 153 |
+
enable=c-extension-no-member
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
[REPORTS]
|
| 157 |
+
|
| 158 |
+
# Python expression which should return a note less than 10 (10 is the highest
|
| 159 |
+
# note). You have access to the variables errors warning, statement which
|
| 160 |
+
# respectively contain the number of errors / warnings messages and the total
|
| 161 |
+
# number of statements analyzed. This is used by the global evaluation report
|
| 162 |
+
# (RP0004).
|
| 163 |
+
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
| 164 |
+
|
| 165 |
+
# Template used to display messages. This is a python new-style format string
|
| 166 |
+
# used to format the message information. See doc for all details.
|
| 167 |
+
#msg-template=
|
| 168 |
+
|
| 169 |
+
# Set the output format. Available formats are text, parseable, colorized, json
|
| 170 |
+
# and msvs (visual studio). You can also give a reporter class, e.g.
|
| 171 |
+
# mypackage.mymodule.MyReporterClass.
|
| 172 |
+
output-format=text
|
| 173 |
+
|
| 174 |
+
# Tells whether to display a full report or only the messages.
|
| 175 |
+
reports=no
|
| 176 |
+
|
| 177 |
+
# Activate the evaluation score.
|
| 178 |
+
score=yes
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
[REFACTORING]
|
| 182 |
+
|
| 183 |
+
# Maximum number of nested blocks for function / method body
|
| 184 |
+
max-nested-blocks=5
|
| 185 |
+
|
| 186 |
+
# Complete name of functions that never returns. When checking for
|
| 187 |
+
# inconsistent-return-statements if a never returning function is called then
|
| 188 |
+
# it will be considered as an explicit return statement and no message will be
|
| 189 |
+
# printed.
|
| 190 |
+
never-returning-functions=sys.exit
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
[LOGGING]
|
| 194 |
+
|
| 195 |
+
# Logging modules to check that the string format arguments are in logging
|
| 196 |
+
# function parameter format.
|
| 197 |
+
logging-modules=logging
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
[SIMILARITIES]
|
| 201 |
+
|
| 202 |
+
# Ignore comments when computing similarities.
|
| 203 |
+
ignore-comments=yes
|
| 204 |
+
|
| 205 |
+
# Ignore docstrings when computing similarities.
|
| 206 |
+
ignore-docstrings=yes
|
| 207 |
+
|
| 208 |
+
# Ignore imports when computing similarities.
|
| 209 |
+
ignore-imports=no
|
| 210 |
+
|
| 211 |
+
# Minimum lines number of a similarity.
|
| 212 |
+
min-similarity-lines=4
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
[MISCELLANEOUS]
|
| 216 |
+
|
| 217 |
+
# List of note tags to take in consideration, separated by a comma.
|
| 218 |
+
notes=FIXME,
|
| 219 |
+
XXX,
|
| 220 |
+
TODO
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
[FORMAT]
|
| 224 |
+
|
| 225 |
+
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
| 226 |
+
expected-line-ending-format=
|
| 227 |
+
|
| 228 |
+
# Regexp for a line that is allowed to be longer than the limit.
|
| 229 |
+
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
| 230 |
+
|
| 231 |
+
# Number of spaces of indent required inside a hanging or continued line.
|
| 232 |
+
indent-after-paren=4
|
| 233 |
+
|
| 234 |
+
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
| 235 |
+
# tab).
|
| 236 |
+
indent-string=' '
|
| 237 |
+
|
| 238 |
+
# Maximum number of characters on a single line.
|
| 239 |
+
max-line-length=100
|
| 240 |
+
|
| 241 |
+
# Maximum number of lines in a module.
|
| 242 |
+
max-module-lines=1000
|
| 243 |
+
|
| 244 |
+
# List of optional constructs for which whitespace checking is disabled. `dict-
|
| 245 |
+
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
|
| 246 |
+
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
|
| 247 |
+
# `empty-line` allows space-only lines.
|
| 248 |
+
no-space-check=trailing-comma,
|
| 249 |
+
dict-separator
|
| 250 |
+
|
| 251 |
+
# Allow the body of a class to be on the same line as the declaration if body
|
| 252 |
+
# contains single statement.
|
| 253 |
+
single-line-class-stmt=no
|
| 254 |
+
|
| 255 |
+
# Allow the body of an if to be on the same line as the test if there is no
|
| 256 |
+
# else.
|
| 257 |
+
single-line-if-stmt=no
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
[BASIC]
|
| 261 |
+
|
| 262 |
+
# Naming style matching correct argument names.
|
| 263 |
+
argument-naming-style=snake_case
|
| 264 |
+
|
| 265 |
+
# Regular expression matching correct argument names. Overrides argument-
|
| 266 |
+
# naming-style.
|
| 267 |
+
#argument-rgx=
|
| 268 |
+
|
| 269 |
+
# Naming style matching correct attribute names.
|
| 270 |
+
attr-naming-style=snake_case
|
| 271 |
+
|
| 272 |
+
# Regular expression matching correct attribute names. Overrides attr-naming-
|
| 273 |
+
# style.
|
| 274 |
+
#attr-rgx=
|
| 275 |
+
|
| 276 |
+
# Bad variable names which should always be refused, separated by a comma.
|
| 277 |
+
bad-names=foo,
|
| 278 |
+
bar,
|
| 279 |
+
baz,
|
| 280 |
+
toto,
|
| 281 |
+
tutu,
|
| 282 |
+
tata
|
| 283 |
+
|
| 284 |
+
# Naming style matching correct class attribute names.
|
| 285 |
+
class-attribute-naming-style=any
|
| 286 |
+
|
| 287 |
+
# Regular expression matching correct class attribute names. Overrides class-
|
| 288 |
+
# attribute-naming-style.
|
| 289 |
+
#class-attribute-rgx=
|
| 290 |
+
|
| 291 |
+
# Naming style matching correct class names.
|
| 292 |
+
class-naming-style=PascalCase
|
| 293 |
+
|
| 294 |
+
# Regular expression matching correct class names. Overrides class-naming-
|
| 295 |
+
# style.
|
| 296 |
+
#class-rgx=
|
| 297 |
+
|
| 298 |
+
# Naming style matching correct constant names.
|
| 299 |
+
const-naming-style=UPPER_CASE
|
| 300 |
+
|
| 301 |
+
# Regular expression matching correct constant names. Overrides const-naming-
|
| 302 |
+
# style.
|
| 303 |
+
#const-rgx=
|
| 304 |
+
|
| 305 |
+
# Minimum line length for functions/classes that require docstrings, shorter
|
| 306 |
+
# ones are exempt.
|
| 307 |
+
docstring-min-length=-1
|
| 308 |
+
|
| 309 |
+
# Naming style matching correct function names.
|
| 310 |
+
function-naming-style=snake_case
|
| 311 |
+
|
| 312 |
+
# Regular expression matching correct function names. Overrides function-
|
| 313 |
+
# naming-style.
|
| 314 |
+
#function-rgx=
|
| 315 |
+
|
| 316 |
+
# Good variable names which should always be accepted, separated by a comma.
|
| 317 |
+
good-names=f,
|
| 318 |
+
i,
|
| 319 |
+
j,
|
| 320 |
+
k,
|
| 321 |
+
s,
|
| 322 |
+
t,
|
| 323 |
+
ex,
|
| 324 |
+
Run,
|
| 325 |
+
_
|
| 326 |
+
|
| 327 |
+
# Include a hint for the correct naming format with invalid-name.
|
| 328 |
+
include-naming-hint=no
|
| 329 |
+
|
| 330 |
+
# Naming style matching correct inline iteration names.
|
| 331 |
+
inlinevar-naming-style=any
|
| 332 |
+
|
| 333 |
+
# Regular expression matching correct inline iteration names. Overrides
|
| 334 |
+
# inlinevar-naming-style.
|
| 335 |
+
#inlinevar-rgx=
|
| 336 |
+
|
| 337 |
+
# Naming style matching correct method names.
|
| 338 |
+
method-naming-style=snake_case
|
| 339 |
+
|
| 340 |
+
# Regular expression matching correct method names. Overrides method-naming-
|
| 341 |
+
# style.
|
| 342 |
+
#method-rgx=
|
| 343 |
+
|
| 344 |
+
# Naming style matching correct module names.
|
| 345 |
+
module-naming-style=snake_case
|
| 346 |
+
|
| 347 |
+
# Regular expression matching correct module names. Overrides module-naming-
|
| 348 |
+
# style.
|
| 349 |
+
#module-rgx=
|
| 350 |
+
|
| 351 |
+
# Colon-delimited sets of names that determine each other's naming style when
|
| 352 |
+
# the name regexes allow several styles.
|
| 353 |
+
name-group=
|
| 354 |
+
|
| 355 |
+
# Regular expression which should only match function or class names that do
|
| 356 |
+
# not require a docstring.
|
| 357 |
+
no-docstring-rgx=^_
|
| 358 |
+
|
| 359 |
+
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
| 360 |
+
# to this list to register other decorators that produce valid properties.
|
| 361 |
+
# These decorators are taken in consideration only for invalid-name.
|
| 362 |
+
property-classes=abc.abstractproperty
|
| 363 |
+
|
| 364 |
+
# Naming style matching correct variable names.
|
| 365 |
+
variable-naming-style=snake_case
|
| 366 |
+
|
| 367 |
+
# Regular expression matching correct variable names. Overrides variable-
|
| 368 |
+
# naming-style.
|
| 369 |
+
variable-rgx=_?[a-z][A-Za-z0-9_]{0,30}$
|
| 370 |
+
argument-rgx=_?[a-z][A-Za-z0-9_]{0,30}$
|
| 371 |
+
|
| 372 |
+
|
| 373 |
+
[TYPECHECK]
|
| 374 |
+
|
| 375 |
+
# List of decorators that produce context managers, such as
|
| 376 |
+
# contextlib.contextmanager. Add to this list to register other decorators that
|
| 377 |
+
# produce valid context managers.
|
| 378 |
+
contextmanager-decorators=contextlib.contextmanager
|
| 379 |
+
|
| 380 |
+
# List of members which are set dynamically and missed by pylint inference
|
| 381 |
+
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
| 382 |
+
# expressions are accepted.
|
| 383 |
+
generated-members=torch.mm,
|
| 384 |
+
torch.diag,
|
| 385 |
+
torch.symeig,
|
| 386 |
+
torch.sqrt,
|
| 387 |
+
torch.cat,
|
| 388 |
+
cv2.cvtColor,
|
| 389 |
+
cv2.COLOR_BGR2YUV,
|
| 390 |
+
cv2.COLOR_YUV2BGR,
|
| 391 |
+
|
| 392 |
+
# Tells whether missing members accessed in mixin class should be ignored. A
|
| 393 |
+
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
| 394 |
+
ignore-mixin-members=yes
|
| 395 |
+
|
| 396 |
+
# Tells whether to warn about missing members when the owner of the attribute
|
| 397 |
+
# is inferred to be None.
|
| 398 |
+
ignore-none=yes
|
| 399 |
+
|
| 400 |
+
# This flag controls whether pylint should warn about no-member and similar
|
| 401 |
+
# checks whenever an opaque object is returned when inferring. The inference
|
| 402 |
+
# can return multiple potential results while evaluating a Python object, but
|
| 403 |
+
# some branches might not be evaluated, which results in partial inference. In
|
| 404 |
+
# that case, it might be useful to still emit no-member and other checks for
|
| 405 |
+
# the rest of the inferred objects.
|
| 406 |
+
ignore-on-opaque-inference=yes
|
| 407 |
+
|
| 408 |
+
# List of class names for which member attributes should not be checked (useful
|
| 409 |
+
# for classes with dynamically set attributes). This supports the use of
|
| 410 |
+
# qualified names.
|
| 411 |
+
ignored-classes=optparse.Values,thread._local,_thread._local
|
| 412 |
+
|
| 413 |
+
# List of module names for which member attributes should not be checked
|
| 414 |
+
# (useful for modules/projects where namespaces are manipulated during runtime
|
| 415 |
+
# and thus existing member attributes cannot be deduced by static analysis. It
|
| 416 |
+
# supports qualified module names, as well as Unix pattern matching.
|
| 417 |
+
ignored-modules=
|
| 418 |
+
|
| 419 |
+
# Show a hint with possible names when a member name was not found. The aspect
|
| 420 |
+
# of finding the hint is based on edit distance.
|
| 421 |
+
missing-member-hint=yes
|
| 422 |
+
|
| 423 |
+
# The minimum edit distance a name should have in order to be considered a
|
| 424 |
+
# similar match for a missing member name.
|
| 425 |
+
missing-member-hint-distance=1
|
| 426 |
+
|
| 427 |
+
# The total number of similar names that should be taken in consideration when
|
| 428 |
+
# showing a hint for a missing member.
|
| 429 |
+
missing-member-max-choices=1
|
| 430 |
+
|
| 431 |
+
|
| 432 |
+
[VARIABLES]
|
| 433 |
+
|
| 434 |
+
# List of additional names supposed to be defined in builtins. Remember that
|
| 435 |
+
# you should avoid to define new builtins when possible.
|
| 436 |
+
additional-builtins=
|
| 437 |
+
|
| 438 |
+
# Tells whether unused global variables should be treated as a violation.
|
| 439 |
+
allow-global-unused-variables=yes
|
| 440 |
+
|
| 441 |
+
# List of strings which can identify a callback function by name. A callback
|
| 442 |
+
# name must start or end with one of those strings.
|
| 443 |
+
callbacks=cb_,
|
| 444 |
+
_cb
|
| 445 |
+
|
| 446 |
+
# A regular expression matching the name of dummy variables (i.e. expected to
|
| 447 |
+
# not be used).
|
| 448 |
+
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
| 449 |
+
|
| 450 |
+
# Argument names that match this expression will be ignored. Default to name
|
| 451 |
+
# with leading underscore.
|
| 452 |
+
ignored-argument-names=_.*|^ignored_|^unused_
|
| 453 |
+
|
| 454 |
+
# Tells whether we should check for unused import in __init__ files.
|
| 455 |
+
init-import=no
|
| 456 |
+
|
| 457 |
+
# List of qualified module names which can have objects that can redefine
|
| 458 |
+
# builtins.
|
| 459 |
+
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
| 460 |
+
|
| 461 |
+
|
| 462 |
+
[SPELLING]
|
| 463 |
+
|
| 464 |
+
# Limits count of emitted suggestions for spelling mistakes.
|
| 465 |
+
max-spelling-suggestions=4
|
| 466 |
+
|
| 467 |
+
# Spelling dictionary name. Available dictionaries: en_IE (myspell), en_ZM
|
| 468 |
+
# (myspell), en_GB (myspell), en_HK (myspell), en_BZ (myspell), en_PH
|
| 469 |
+
# (myspell), en_ZA (myspell), en_MW (myspell), en_AU (myspell), en_CA
|
| 470 |
+
# (myspell), en_JM (myspell), en_GH (myspell), en_TT (myspell), en_SG
|
| 471 |
+
# (myspell), en_BW (myspell), en_US (myspell), en_NZ (myspell), en_AG
|
| 472 |
+
# (myspell), en_ZW (myspell), en_NA (myspell), en_IN (myspell), en_BS
|
| 473 |
+
# (myspell), en_DK (myspell), en_NG (myspell)..
|
| 474 |
+
spelling-dict=
|
| 475 |
+
|
| 476 |
+
# List of comma separated words that should not be checked.
|
| 477 |
+
spelling-ignore-words=
|
| 478 |
+
|
| 479 |
+
# A path to a file that contains private dictionary; one word per line.
|
| 480 |
+
spelling-private-dict-file=
|
| 481 |
+
|
| 482 |
+
# Tells whether to store unknown words to indicated private dictionary in
|
| 483 |
+
# --spelling-private-dict-file option instead of raising a message.
|
| 484 |
+
spelling-store-unknown-words=no
|
| 485 |
+
|
| 486 |
+
|
| 487 |
+
[IMPORTS]
|
| 488 |
+
|
| 489 |
+
# Allow wildcard imports from modules that define __all__.
|
| 490 |
+
allow-wildcard-with-all=no
|
| 491 |
+
|
| 492 |
+
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
| 493 |
+
# 3 compatible code, which means that the block might have code that exists
|
| 494 |
+
# only in one or another interpreter, leading to false positives when analysed.
|
| 495 |
+
analyse-fallback-blocks=no
|
| 496 |
+
|
| 497 |
+
# Deprecated modules which should not be used, separated by a comma.
|
| 498 |
+
deprecated-modules=optparse,tkinter.tix
|
| 499 |
+
|
| 500 |
+
# Create a graph of external dependencies in the given file (report RP0402 must
|
| 501 |
+
# not be disabled).
|
| 502 |
+
ext-import-graph=
|
| 503 |
+
|
| 504 |
+
# Create a graph of every (i.e. internal and external) dependencies in the
|
| 505 |
+
# given file (report RP0402 must not be disabled).
|
| 506 |
+
import-graph=
|
| 507 |
+
|
| 508 |
+
# Create a graph of internal dependencies in the given file (report RP0402 must
|
| 509 |
+
# not be disabled).
|
| 510 |
+
int-import-graph=
|
| 511 |
+
|
| 512 |
+
# Force import order to recognize a module as part of the standard
|
| 513 |
+
# compatibility libraries.
|
| 514 |
+
known-standard-library=
|
| 515 |
+
|
| 516 |
+
# Force import order to recognize a module as part of a third party library.
|
| 517 |
+
known-third-party=enchant
|
| 518 |
+
|
| 519 |
+
|
| 520 |
+
[CLASSES]
|
| 521 |
+
|
| 522 |
+
# List of method names used to declare (i.e. assign) instance attributes.
|
| 523 |
+
defining-attr-methods=__init__,
|
| 524 |
+
__new__,
|
| 525 |
+
setUp
|
| 526 |
+
|
| 527 |
+
# List of member names, which should be excluded from the protected access
|
| 528 |
+
# warning.
|
| 529 |
+
exclude-protected=_asdict,
|
| 530 |
+
_fields,
|
| 531 |
+
_replace,
|
| 532 |
+
_source,
|
| 533 |
+
_make
|
| 534 |
+
|
| 535 |
+
# List of valid names for the first argument in a class method.
|
| 536 |
+
valid-classmethod-first-arg=cls
|
| 537 |
+
|
| 538 |
+
# List of valid names for the first argument in a metaclass class method.
|
| 539 |
+
valid-metaclass-classmethod-first-arg=cls
|
| 540 |
+
|
| 541 |
+
|
| 542 |
+
[DESIGN]
|
| 543 |
+
|
| 544 |
+
# Maximum number of arguments for function / method.
|
| 545 |
+
max-args=5
|
| 546 |
+
|
| 547 |
+
# Maximum number of attributes for a class (see R0902).
|
| 548 |
+
max-attributes=7
|
| 549 |
+
|
| 550 |
+
# Maximum number of boolean expressions in an if statement.
|
| 551 |
+
max-bool-expr=5
|
| 552 |
+
|
| 553 |
+
# Maximum number of branch for function / method body.
|
| 554 |
+
max-branches=12
|
| 555 |
+
|
| 556 |
+
# Maximum number of locals for function / method body.
|
| 557 |
+
max-locals=15
|
| 558 |
+
|
| 559 |
+
# Maximum number of parents for a class (see R0901).
|
| 560 |
+
max-parents=7
|
| 561 |
+
|
| 562 |
+
# Maximum number of public methods for a class (see R0904).
|
| 563 |
+
max-public-methods=20
|
| 564 |
+
|
| 565 |
+
# Maximum number of return / yield for function / method body.
|
| 566 |
+
max-returns=6
|
| 567 |
+
|
| 568 |
+
# Maximum number of statements in function / method body.
|
| 569 |
+
max-statements=50
|
| 570 |
+
|
| 571 |
+
# Minimum number of public methods for a class (see R0903).
|
| 572 |
+
min-public-methods=2
|
| 573 |
+
|
| 574 |
+
|
| 575 |
+
[EXCEPTIONS]
|
| 576 |
+
|
| 577 |
+
# Exceptions that will emit a warning when being caught. Defaults to
|
| 578 |
+
# "Exception".
|
| 579 |
+
overgeneral-exceptions=Exception
|
.travis.yml
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
sudo: false
|
| 2 |
+
language: python
|
| 3 |
+
install: pip install tox
|
| 4 |
+
matrix:
|
| 5 |
+
include:
|
| 6 |
+
- python: "3.6"
|
| 7 |
+
env: TOX_ENV=static
|
| 8 |
+
- python: "3.6"
|
| 9 |
+
env: TOX_ENV=format
|
| 10 |
+
script: tox -e $TOX_ENV
|
CHANGELOG.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Changelog
|
| 2 |
+
|
| 3 |
+
All notable changes to this project will be documented in this file.
|
| 4 |
+
|
| 5 |
+
## [2.0.0] - 2025-12-01
|
| 6 |
+
|
| 7 |
+
### Added
|
| 8 |
+
- **Intel GPU Support**: Added support for Intel Arc and Data Center GPUs using Intel Extension for PyTorch (IPEX).
|
| 9 |
+
- **Unified Device Management**: Implemented `deoldify.device` to automatically detect and manage CUDA, XPU (Intel), and CPU devices.
|
| 10 |
+
- **Documentation**:
|
| 11 |
+
- `docs/nvidia_setup.md`: Comprehensive guide for setting up NVIDIA GPUs with CUDA 12.x.
|
| 12 |
+
- `docs/intel_gpu_setup.md`: Guide for setting up Intel GPUs.
|
| 13 |
+
- **Verification Script**: Added `verify_refactor.py` to validate environment setup and model instantiation.
|
| 14 |
+
- **Compatibility Layer**: Created `deoldify/fastai_compat.py` to replace the obsolete `fastai` 1.x library, ensuring compatibility with modern PyTorch.
|
| 15 |
+
- **Requirements Files**: Added `requirements.txt` and `requirements_intel.txt` for pip users.
|
| 16 |
+
- **Code Quality**:
|
| 17 |
+
- Comprehensive module docstring for `fastai_compat.py`.
|
| 18 |
+
- Type hints throughout compatibility layer.
|
| 19 |
+
- README badges for Python, PyTorch, CUDA versions, and license.
|
| 20 |
+
|
| 21 |
+
### Changed
|
| 22 |
+
- **Core Dependencies**:
|
| 23 |
+
- Removed dependency on `fastai` 1.x.
|
| 24 |
+
- Upgraded PyTorch to 2.5+.
|
| 25 |
+
- Upgraded CUDA support to 12.x.
|
| 26 |
+
- Updated `environment.yml` for modern NVIDIA environments.
|
| 27 |
+
- Created `environment_intel.yml` for Intel environments.
|
| 28 |
+
- **Refactoring**:
|
| 29 |
+
- Refactored `visualize.py`, `filters.py`, `generators.py`, `unet.py`, and `layers.py` to use pure PyTorch and the new compatibility layer.
|
| 30 |
+
- Replaced FastAI-specific image processing with standard `torchvision` transforms.
|
| 31 |
+
- **Device Handling**: Updated `Learner` and `DataBunch` shims to use the new unified device manager.
|
| 32 |
+
- **.gitignore**: Enhanced to exclude model weights in `models/` directory, logs, IDE files, and OS-specific files.
|
| 33 |
+
|
| 34 |
+
### Removed
|
| 35 |
+
- **Legacy Code**: Removed direct imports of `fastai` throughout the codebase.
|
| 36 |
+
- **Archived Status**: The project is now actively maintained for modern hardware.
|
CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributor Covenant Code of Conduct
|
| 2 |
+
|
| 3 |
+
## Our Pledge
|
| 4 |
+
|
| 5 |
+
We as members, contributors, and leaders pledge to make participation in our
|
| 6 |
+
community a harassment-free experience for everyone, regardless of age, body
|
| 7 |
+
size, visible or invisible disability, ethnicity, sex, gender characteristics,
|
| 8 |
+
gender identity and expression, level of experience, education, socio-economic
|
| 9 |
+
status, nationality, personal appearance, race, caste, color, religion, or
|
| 10 |
+
sexual identity and orientation.
|
| 11 |
+
|
| 12 |
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
| 13 |
+
diverse, inclusive, and healthy community.
|
| 14 |
+
|
| 15 |
+
## Our Standards
|
| 16 |
+
|
| 17 |
+
Examples of behavior that contributes to a positive environment for our
|
| 18 |
+
community include:
|
| 19 |
+
|
| 20 |
+
* Demonstrating empathy and kindness toward other people
|
| 21 |
+
* Being respectful of differing opinions, viewpoints, and experiences
|
| 22 |
+
* Giving and gracefully accepting constructive feedback
|
| 23 |
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
| 24 |
+
and learning from the experience
|
| 25 |
+
* Focusing on what is best not just for us as individuals, but for the
|
| 26 |
+
overall community
|
| 27 |
+
|
| 28 |
+
Examples of unacceptable behavior include:
|
| 29 |
+
|
| 30 |
+
* The use of sexualized language or imagery, and sexual attention or
|
| 31 |
+
advances of any kind
|
| 32 |
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
| 33 |
+
* Public or private harassment
|
| 34 |
+
* Publishing others' private information, such as a physical or email
|
| 35 |
+
address, without their explicit permission
|
| 36 |
+
* Other conduct which could reasonably be considered inappropriate in a
|
| 37 |
+
professional setting
|
| 38 |
+
|
| 39 |
+
## Enforcement Responsibilities
|
| 40 |
+
|
| 41 |
+
Community leaders are responsible for clarifying and enforcing our standards of
|
| 42 |
+
acceptable behavior and will take appropriate and fair corrective action in
|
| 43 |
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
| 44 |
+
or harmful.
|
| 45 |
+
|
| 46 |
+
Community leaders have the right and responsibility to remove, edit, or reject
|
| 47 |
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
| 48 |
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
| 49 |
+
decisions when appropriate.
|
| 50 |
+
|
| 51 |
+
## Scope
|
| 52 |
+
|
| 53 |
+
This Code of Conduct applies within all community spaces, and also applies when
|
| 54 |
+
an individual is officially representing the community in public spaces.
|
| 55 |
+
Examples of representing our community include using an official e-mail address,
|
| 56 |
+
posting via an official social media account, or acting as an appointed
|
| 57 |
+
representative at an online or offline event.
|
| 58 |
+
|
| 59 |
+
## Enforcement
|
| 60 |
+
|
| 61 |
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
| 62 |
+
reported to the community leaders responsible for enforcement.
|
| 63 |
+
All complaints will be reviewed and investigated promptly and fairly.
|
| 64 |
+
|
| 65 |
+
All community leaders are obligated to respect the privacy and security of the
|
| 66 |
+
reporter of any incident.
|
| 67 |
+
|
| 68 |
+
## Enforcement Guidelines
|
| 69 |
+
|
| 70 |
+
Community leaders will follow these Community Impact Guidelines in determining
|
| 71 |
+
the consequences for any action they deem in violation of this Code of Conduct:
|
| 72 |
+
|
| 73 |
+
### 1. Correction
|
| 74 |
+
|
| 75 |
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
| 76 |
+
unprofessional or unwelcome in the community.
|
| 77 |
+
|
| 78 |
+
**Consequence**: A private, written warning from community leaders, providing
|
| 79 |
+
clarity around the nature of the violation and an explanation of why the
|
| 80 |
+
behavior was inappropriate. A public apology may be requested.
|
| 81 |
+
|
| 82 |
+
### 2. Warning
|
| 83 |
+
|
| 84 |
+
**Community Impact**: A violation through a single incident or series of
|
| 85 |
+
actions.
|
| 86 |
+
|
| 87 |
+
**Consequence**: A warning with consequences for continued behavior. No
|
| 88 |
+
interaction with the people involved, including unsolicited interaction with
|
| 89 |
+
those enforcing the Code of Conduct, for a specified period of time. This
|
| 90 |
+
includes avoiding interactions in community spaces as well as external channels
|
| 91 |
+
like social media. Violating these terms may lead to a temporary or
|
| 92 |
+
permanent ban.
|
| 93 |
+
|
| 94 |
+
### 3. Temporary Ban
|
| 95 |
+
|
| 96 |
+
**Community Impact**: A serious violation of community standards, including
|
| 97 |
+
sustained inappropriate behavior.
|
| 98 |
+
|
| 99 |
+
**Consequence**: A temporary ban from any sort of interaction or public
|
| 100 |
+
communication with the community for a specified period of time. No public or
|
| 101 |
+
private interaction with the people involved, including unsolicited interaction
|
| 102 |
+
with those enforcing the Code of Conduct, is allowed during this period.
|
| 103 |
+
Violating these terms may lead to a permanent ban.
|
| 104 |
+
|
| 105 |
+
### 4. Permanent Ban
|
| 106 |
+
|
| 107 |
+
**Community Impact**: Demonstrating a pattern of violation of community
|
| 108 |
+
standards, including sustained inappropriate behavior, harassment of an
|
| 109 |
+
individual, or aggression toward or disparagement of classes of individuals.
|
| 110 |
+
|
| 111 |
+
**Consequence**: A permanent ban from any sort of public interaction within
|
| 112 |
+
the community.
|
| 113 |
+
|
| 114 |
+
## Attribution
|
| 115 |
+
|
| 116 |
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
| 117 |
+
version 2.1, available at
|
| 118 |
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
| 119 |
+
|
| 120 |
+
Community Impact Guidelines were inspired by
|
| 121 |
+
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
| 122 |
+
|
| 123 |
+
[homepage]: https://www.contributor-covenant.org
|
| 124 |
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
| 125 |
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing to DeOldify
|
| 2 |
+
|
| 3 |
+
First off, thanks for taking the time to contribute! ❤️
|
| 4 |
+
|
| 5 |
+
All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
|
| 6 |
+
|
| 7 |
+
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
|
| 8 |
+
> - Star the project
|
| 9 |
+
> - Tweet about it
|
| 10 |
+
> - Refer this project in your project's readme
|
| 11 |
+
> - Mention the project at local meetups and tell your friends/colleagues
|
| 12 |
+
|
| 13 |
+
## Table of Contents
|
| 14 |
+
|
| 15 |
+
- [Code of Conduct](#code-of-conduct)
|
| 16 |
+
- [I Have a Question](#i-have-a-question)
|
| 17 |
+
- [I Want To Contribute](#i-want-to-contribute)
|
| 18 |
+
- [Reporting Bugs](#reporting-bugs)
|
| 19 |
+
- [Suggesting Enhancements](#suggesting-enhancements)
|
| 20 |
+
|
| 21 |
+
## Code of Conduct
|
| 22 |
+
|
| 23 |
+
This project and everyone participating in it is governed by the
|
| 24 |
+
[DeOldify Code of Conduct](CODE_OF_CONDUCT.md).
|
| 25 |
+
By participating, you are expected to uphold this code. Please report unacceptable behavior
|
| 26 |
+
to the project maintainers.
|
| 27 |
+
|
| 28 |
+
## I Have a Question
|
| 29 |
+
|
| 30 |
+
> If you want to ask a question, we assume that you have read the available [Documentation](README.md).
|
| 31 |
+
|
| 32 |
+
Before you ask a question, it is best to search for existing [Issues](https://github.com/thookham/DeOldify/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
|
| 33 |
+
|
| 34 |
+
If you then still feel the need to ask a question and need clarification, we recommend the following:
|
| 35 |
+
|
| 36 |
+
- Open an [Issue](https://github.com/thookham/DeOldify/issues/new).
|
| 37 |
+
- Provide as much context as you can about what you're running into.
|
| 38 |
+
- Provide project and platform versions (Python version, PyTorch version, CUDA version, etc), depending on what seems relevant.
|
| 39 |
+
|
| 40 |
+
We will then take care of the issue as soon as possible.
|
| 41 |
+
|
| 42 |
+
## I Want To Contribute
|
| 43 |
+
|
| 44 |
+
### Reporting Bugs
|
| 45 |
+
|
| 46 |
+
#### Before Submitting a Bug Report
|
| 47 |
+
|
| 48 |
+
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
|
| 49 |
+
|
| 50 |
+
- Make sure that you are using the latest version.
|
| 51 |
+
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](README.md). If you are looking for support, you might want to check [this section](#i-have-a-question)).
|
| 52 |
+
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/thookham/DeOldify/issues?q=label%3Abug).
|
| 53 |
+
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
|
| 54 |
+
- Collect information about the bug:
|
| 55 |
+
- Stack trace (Traceback)
|
| 56 |
+
- OS, Platform and Version (Windows, Linux, macOS)
|
| 57 |
+
- Python version, PyTorch version, CUDA version
|
| 58 |
+
- GPU model and driver version
|
| 59 |
+
- Possibly your input and the output
|
| 60 |
+
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
|
| 61 |
+
|
| 62 |
+
#### How to Submit a Good Bug Report
|
| 63 |
+
|
| 64 |
+
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
|
| 65 |
+
|
| 66 |
+
- Open an [Issue](https://github.com/thookham/DeOldify/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
|
| 67 |
+
- Explain the behavior you would expect and the actual behavior.
|
| 68 |
+
- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
|
| 69 |
+
- Provide the information you collected in the previous section.
|
| 70 |
+
|
| 71 |
+
### Suggesting Enhancements
|
| 72 |
+
|
| 73 |
+
This section guides you through submitting an enhancement suggestion for DeOldify, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
|
| 74 |
+
|
| 75 |
+
#### Before Submitting an Enhancement
|
| 76 |
+
|
| 77 |
+
- Make sure that you are using the latest version.
|
| 78 |
+
- Read the [documentation](README.md) carefully and find out if the functionality is already covered, maybe by an individual configuration.
|
| 79 |
+
- Perform a [search](https://github.com/thookham/DeOldify/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
| 80 |
+
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
|
| 81 |
+
|
| 82 |
+
#### How to Submit a Good Enhancement Suggestion
|
| 83 |
+
|
| 84 |
+
Enhancement suggestions are tracked as [GitHub issues](https://github.com/thookham/DeOldify/issues).
|
| 85 |
+
|
| 86 |
+
- Use a **clear and descriptive title** for the issue to identify the suggestion.
|
| 87 |
+
- Provide a **step-by-step description of the suggested enhancement** in as much detail as possible.
|
| 88 |
+
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives you do not work for you.
|
| 89 |
+
- You may want to include **screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to.
|
| 90 |
+
- **Explain why this enhancement would be useful** to most DeOldify users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
|
ColorFIDBenchmarkArtistic.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:81ff2900f2459c5f9c2a2cd7e6e28369cb47be06456911b95265dfc924c68fd6
|
| 3 |
+
size 7379
|
ColorizeTrainingArtistic.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:04151afd527032964230ea44879e76ab9d62a3b544bcdf01fe56b65e18bf71a9
|
| 3 |
+
size 15025
|
ColorizeTrainingStable.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a8439478243ef7d308267f189b18e6f25073a3c28770265587c37b2aa558a3fe
|
| 3 |
+
size 15033
|
ColorizeTrainingStableLargeBatch.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2895ec4a822ce541fd73ee58f261c51237b1819135beeb5c9a15ef3ee2d0ca10
|
| 3 |
+
size 18892
|
ColorizeTrainingVideo.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cd9153345bbbd1f032e35d51511e5cc5a60f7aeea0210147a69af2188ab97455
|
| 3 |
+
size 12035
|
ColorizeTrainingWandb.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:70096ddb975b3345850df253aeae4f1a58c2e9bae90c42e681b0b674325de42c
|
| 3 |
+
size 27053
|
HF_README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- image-colorization
|
| 5 |
+
- gan
|
| 6 |
+
- computer-vision
|
| 7 |
+
- pytorch
|
| 8 |
+
- onnx
|
| 9 |
+
library_name: pytorch
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# DeOldify Model Weights
|
| 13 |
+
|
| 14 |
+
This repository contains pretrained weights for **DeOldify**, a deep learning model for colorizing and restoring old black and white images and videos.
|
| 15 |
+
|
| 16 |
+
**Original Repository**: [thookham/DeOldify](https://github.com/thookham/DeOldify)
|
| 17 |
+
**Original Author**: Jason Antic ([jantic/DeOldify](https://github.com/jantic/DeOldify))
|
| 18 |
+
|
| 19 |
+
## Model Overview
|
| 20 |
+
|
| 21 |
+
DeOldify uses a Self-Attention Generative Adversarial Network (SAGAN) with a novel **NoGAN** training approach to achieve stable, high-quality colorization without the typical GAN artifacts.
|
| 22 |
+
|
| 23 |
+
### Three Specialized Models
|
| 24 |
+
|
| 25 |
+
1. **Artistic** - Highest quality with vibrant colors and interesting details
|
| 26 |
+
- Best for: General images, historical photos
|
| 27 |
+
- Backbone: ResNet34 U-Net
|
| 28 |
+
- Training: 5 NoGAN cycles, 32% ImageNet
|
| 29 |
+
|
| 30 |
+
2. **Stable** - Best for portraits and landscapes, reduced artifacts
|
| 31 |
+
- Best for: Faces, nature scenes
|
| 32 |
+
- Backbone: ResNet101 U-Net
|
| 33 |
+
- Training: 3 NoGAN cycles, 7% ImageNet
|
| 34 |
+
|
| 35 |
+
3. **Video** - Optimized for smooth, flicker-free video
|
| 36 |
+
- Best for: Video colorization, consistency
|
| 37 |
+
- Backbone: ResNet101 U-Net
|
| 38 |
+
- Training: Initial cycle only, 2.2% ImageNet
|
| 39 |
+
|
| 40 |
+
## Available Files
|
| 41 |
+
|
| 42 |
+
### ONNX Models (Browser/Inference)
|
| 43 |
+
|
| 44 |
+
| File | Size | Description |
|
| 45 |
+
|------|------|-------------|
|
| 46 |
+
| `deoldify-art.onnx` | 243 MB | Artistic model in ONNX format for browser use |
|
| 47 |
+
| `deoldify-quant.onnx` | 61 MB | Quantized artistic model (75% smaller, slightly lower quality) |
|
| 48 |
+
|
| 49 |
+
### PyTorch Weights (Training & Inference)
|
| 50 |
+
|
| 51 |
+
**Generator Weights** (Main):
|
| 52 |
+
- `ColorizeArtistic_gen.pth` (243 MB)
|
| 53 |
+
- `ColorizeStable_gen.pth` (834 MB)
|
| 54 |
+
- `ColorizeVideo_gen.pth` (834 MB)
|
| 55 |
+
|
| 56 |
+
**Critic Weights** (Main):
|
| 57 |
+
- `ColorizeArtistic_crit.pth` (361 MB)
|
| 58 |
+
- `ColorizeStable_crit.pth` (361 MB)
|
| 59 |
+
- `ColorizeVideo_crit.pth` (361 MB)
|
| 60 |
+
|
| 61 |
+
**PretrainOnly Weights** (For continued training):
|
| 62 |
+
- `ColorizeArtistic_PretrainOnly_gen.pth` (729 MB)
|
| 63 |
+
- `ColorizeArtistic_PretrainOnly_crit.pth` (1.05 GB)
|
| 64 |
+
- `ColorizeStable_PretrainOnly_crit.pth` (1.05 GB)
|
| 65 |
+
- `ColorizeVideo_PretrainOnly_crit.pth` (1.05 GB)
|
| 66 |
+
|
| 67 |
+
> **Note**: Stable and Video PretrainOnly generators are split files hosted on [GitHub Releases](https://github.com/thookham/DeOldify/releases/tag/v2.0-models).
|
| 68 |
+
|
| 69 |
+
## Usage
|
| 70 |
+
|
| 71 |
+
### Browser (ONNX)
|
| 72 |
+
|
| 73 |
+
```html
|
| 74 |
+
<!DOCTYPE html>
|
| 75 |
+
<html>
|
| 76 |
+
<head>
|
| 77 |
+
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js"></script>
|
| 78 |
+
</head>
|
| 79 |
+
<body>
|
| 80 |
+
<script>
|
| 81 |
+
async function colorize() {
|
| 82 |
+
// Load model from Hugging Face
|
| 83 |
+
const session = await ort.InferenceSession.create(
|
| 84 |
+
"https://huggingface.co/thookham/DeOldify/resolve/main/deoldify-art.onnx"
|
| 85 |
+
);
|
| 86 |
+
|
| 87 |
+
// Run inference (see full example in GitHub repo)
|
| 88 |
+
// ...
|
| 89 |
+
}
|
| 90 |
+
</script>
|
| 91 |
+
</body>
|
| 92 |
+
</html>
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
### PyTorch (Python)
|
| 96 |
+
|
| 97 |
+
```python
|
| 98 |
+
from huggingface_hub import hf_hub_download
|
| 99 |
+
import torch
|
| 100 |
+
|
| 101 |
+
# Download model weights
|
| 102 |
+
model_path = hf_hub_download(
|
| 103 |
+
repo_id="thookham/DeOldify",
|
| 104 |
+
filename="ColorizeArtistic_gen.pth"
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
# Load weights (requires deoldify package installed)
|
| 108 |
+
# See GitHub repository for full usage examples
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
### Installation
|
| 112 |
+
|
| 113 |
+
```bash
|
| 114 |
+
# Clone the main repository
|
| 115 |
+
git clone https://github.com/thookham/DeOldify
|
| 116 |
+
cd DeOldify
|
| 117 |
+
|
| 118 |
+
# Install dependencies
|
| 119 |
+
pip install -r requirements.txt
|
| 120 |
+
|
| 121 |
+
# Download a model
|
| 122 |
+
from huggingface_hub import hf_hub_download
|
| 123 |
+
model = hf_hub_download(repo_id="thookham/DeOldify", filename="ColorizeStable_gen.pth")
|
| 124 |
+
```
|
| 125 |
+
|
| 126 |
+
## Technical Details
|
| 127 |
+
|
| 128 |
+
### Architecture
|
| 129 |
+
- **Generator**: U-Net with ResNet34/101 backbone, spectral normalization, self-attention layers
|
| 130 |
+
- **Critic**: PatchGAN discriminator
|
| 131 |
+
- **Loss**: Perceptual loss (VGG16) + GAN loss
|
| 132 |
+
|
| 133 |
+
### NoGAN Training
|
| 134 |
+
A novel training approach that combines:
|
| 135 |
+
1. Generator pretraining with feature loss
|
| 136 |
+
2. Critic pretraining on generated images
|
| 137 |
+
3. Short GAN training (30-60 minutes) at inflection point
|
| 138 |
+
4. Optional cycle repeats for more colorful results
|
| 139 |
+
|
| 140 |
+
This eliminates typical GAN artifacts while maintaining realistic colorization.
|
| 141 |
+
|
| 142 |
+
### Training Data
|
| 143 |
+
- Dataset: ImageNet subsets (1-32% depending on model)
|
| 144 |
+
- Resolution: 192px during training
|
| 145 |
+
- Augmentation: Gaussian noise for video stability
|
| 146 |
+
|
| 147 |
+
## Model Card
|
| 148 |
+
|
| 149 |
+
### Model Details
|
| 150 |
+
- **Developed by**: Jason Antic (original), Travis Hookham (modernization)
|
| 151 |
+
- **Model type**: Conditional GAN for image-to-image translation
|
| 152 |
+
- **Language(s)**: N/A (computer vision)
|
| 153 |
+
- **License**: MIT
|
| 154 |
+
- **Parent Model**: Based on FastAI U-Net and Self-Attention GAN papers
|
| 155 |
+
|
| 156 |
+
### Intended Use
|
| 157 |
+
**Primary Use**: Colorizing black and white photographs and videos
|
| 158 |
+
**Out-of-Scope**: Real-time processing, guaranteed historical accuracy
|
| 159 |
+
|
| 160 |
+
### Limitations
|
| 161 |
+
- Colors may not be historically accurate
|
| 162 |
+
- Performance degrades on very low quality/damaged images
|
| 163 |
+
- Artistic model may require render_factor tuning
|
| 164 |
+
- Video model trades some color vibrancy for consistency
|
| 165 |
+
|
| 166 |
+
## Related Models & Resources
|
| 167 |
+
|
| 168 |
+
### Similar Colorization Models on Hugging Face
|
| 169 |
+
|
| 170 |
+
**GAN-based Colorization:**
|
| 171 |
+
- [Hammad712/GAN-Colorization-Model](https://huggingface.co/Hammad712/GAN-Colorization-Model) - GAN model for grayscale to color transformation
|
| 172 |
+
- [jessicanono/filparty_colorization](https://huggingface.co/jessicanono/filparty_colorization) - ResNet-based model for historical photos
|
| 173 |
+
|
| 174 |
+
**Stable Diffusion-based:**
|
| 175 |
+
- [rsortino/ColorizeNet](https://huggingface.co/rsortino/ColorizeNet) - ControlNet adaptation of SD 2.1 for colorization
|
| 176 |
+
- [AlekseyCalvin/ColorizeTruer_KontextFluxVar6_BySAP](https://huggingface.co/AlekseyCalvin/ColorizeTruer_KontextFluxVar6_BySAP) - Advanced Flux-based colorization
|
| 177 |
+
|
| 178 |
+
**Interactive Demos (Spaces):**
|
| 179 |
+
- [aryadytm/Photo-Colorization](https://huggingface.co/spaces/aryadytm/Photo-Colorization)
|
| 180 |
+
- [Shashank009/Black-And-White-Image-Colorization](https://huggingface.co/spaces/Shashank009/Black-And-White-Image-Colorization)
|
| 181 |
+
- [CA611/Image-Colorization](https://huggingface.co/spaces/CA611/Image-Colorization)
|
| 182 |
+
|
| 183 |
+
### Why Choose DeOldify?
|
| 184 |
+
|
| 185 |
+
DeOldify stands out for:
|
| 186 |
+
- **NoGAN Training**: Unique approach eliminating typical GAN artifacts
|
| 187 |
+
- **Specialized Models**: Three purpose-built models (Artistic, Stable, Video)
|
| 188 |
+
- **Video Support**: Flicker-free temporal consistency
|
| 189 |
+
- **Proven Track Record**: Powers MyHeritage InColor and widely adopted
|
| 190 |
+
- **ONNX Support**: Browser-ready models for offline use
|
| 191 |
+
|
| 192 |
+
## Citation
|
| 193 |
+
|
| 194 |
+
If you use these models, please cite:
|
| 195 |
+
|
| 196 |
+
```bibtex
|
| 197 |
+
@misc{deoldify,
|
| 198 |
+
author = {Antic, Jason},
|
| 199 |
+
title = {DeOldify},
|
| 200 |
+
year = {2019},
|
| 201 |
+
publisher = {GitHub},
|
| 202 |
+
url = {https://github.com/jantic/DeOldify}
|
| 203 |
+
}
|
| 204 |
+
```
|
| 205 |
+
|
| 206 |
+
## Links
|
| 207 |
+
|
| 208 |
+
- **GitHub Repository**: https://github.com/thookham/DeOldify
|
| 209 |
+
- **Original DeOldify**: https://github.com/jantic/DeOldify
|
| 210 |
+
- **MyHeritage InColor** (Commercial version): https://www.myheritage.com/incolor
|
| 211 |
+
- **Demo (Browser)**: See browser/ folder in GitHub repo
|
| 212 |
+
|
| 213 |
+
## License
|
| 214 |
+
|
| 215 |
+
MIT License. See [LICENSE](https://github.com/thookham/DeOldify/blob/master/LICENSE) file.
|
ImageColorizer.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:becb7dac71eb07d80e0b580c227e45031d5d178fc08487dfb2ecc7348238f557
|
| 3 |
+
size 5670
|
ImageColorizerArtisticTests.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b031061b6f2b56a3bdb2b26e00d6122b2f9144454e5e62eddcbdb9521145980e
|
| 3 |
+
size 79684
|
ImageColorizerColab.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:39bcb7942400ab7a373b8053ba3df94b9159ac1fd66a6441915cd7661be145ad
|
| 3 |
+
size 8484
|
ImageColorizerColabStable.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:af0f95463e10a9c46ba3f5b1656590f2be552ae8fc90dc2bf6369275f6af4085
|
| 3 |
+
size 8415
|
ImageColorizerStableTests.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3bb167d6e3751f8ee44eafb90b636b86d299ac7f44940d5adf9be616d43d8194
|
| 3 |
+
size 78929
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2018 Jason Antic
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
MANIFEST.in
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
include README.md
|
| 2 |
+
include LICENSE
|
| 3 |
+
include requirements.txt
|
README.md
ADDED
|
@@ -0,0 +1,542 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# DeOldify (Modernized)
|
| 3 |
+
|
| 4 |
+

|
| 5 |
+

|
| 6 |
+

|
| 7 |
+

|
| 8 |
+
|
| 9 |
+
# DeOldify (Modernized)
|
| 10 |
+
|
| 11 |
+
**DeOldify** has been modernized! This fork updates the project to support **PyTorch 2.5+**, **CUDA 12.x**, and **Intel GPUs (Arc/Data Center)**. It removes the dependency on the obsolete FastAI 1.x library, making it easier to run on modern hardware.
|
| 12 |
+
|
| 13 |
+
**Quick Start**:
|
| 14 |
+
- **NVIDIA GPU**: [Setup Guide](docs/nvidia_setup.md)
|
| 15 |
+
- **Intel GPU**: [Setup Guide](docs/intel_gpu_setup.md)
|
| 16 |
+
|
| 17 |
+
**Original Project**: The original DeOldify by Jason Antic can be found [here](https://github.com/jantic/DeOldify).
|
| 18 |
+
|
| 19 |
+
**In Browser (new!)**
|
| 20 |
+
You can run DeOldify directly in your browser without any installation! We've included a local browser-based implementation in this repository.
|
| 21 |
+
|
| 22 |
+
**How to use:**
|
| 23 |
+
1. Navigate to the `browser/` folder in this repository.
|
| 24 |
+
2. Open `index.html` in Chrome, Firefox, or Edge.
|
| 25 |
+
3. Choose between the **Artistic** (higher quality) or **Quantized** (faster) model.
|
| 26 |
+
4. Select an image and watch it colorize instantly!
|
| 27 |
+
|
| 28 |
+
*Note: This implementation uses ONNX models hosted on our GitHub releases and Hugging Face, ensuring privacy and availability.*
|
| 29 |
+
|
| 30 |
+
Also check out the original browser repo: https://github.com/akbartus/DeOldify-on-Browser
|
| 31 |
+
|
| 32 |
+
**Hugging Face 🤗**: All models are also available on Hugging Face: [thookham/DeOldify](https://huggingface.co/thookham/DeOldify)
|
| 33 |
+
|
| 34 |
+
The **most advanced** version of DeOldify image colorization is available here,
|
| 35 |
+
exclusively. Try a few images for free! [MyHeritage In Color](https://www.myheritage.com/incolor)
|
| 36 |
+
|
| 37 |
+
**Replicate:** Image: <a href="https://replicate.com/arielreplicate/deoldify_image"><img src="https://replicate.com/arielreplicate/deoldify_image/badge"></a> | Video: <a href="https://replicate.com/arielreplicate/deoldify_video"><img src="https://replicate.com/arielreplicate/deoldify_video/badge"></a>
|
| 38 |
+
|
| 39 |
+
----------------------------
|
| 40 |
+
|
| 41 |
+
Image (artistic) [](https://colab.research.google.com/github/jantic/DeOldify/blob/master/ImageColorizerColab.ipynb)
|
| 42 |
+
| Video [](https://colab.research.google.com/github/jantic/DeOldify/blob/master/VideoColorizerColab.ipynb)
|
| 43 |
+
|
| 44 |
+
Having trouble with the default image colorizer, aka "artistic"? Try the
|
| 45 |
+
"stable" one below. It generally won't produce colors that are as interesting as
|
| 46 |
+
"artistic", but the glitches are noticeably reduced.
|
| 47 |
+
|
| 48 |
+
Image (stable) [](https://colab.research.google.com/github/jantic/DeOldify/blob/master/ImageColorizerColabStable.ipynb)
|
| 49 |
+
|
| 50 |
+
Instructions on how to use the Colabs above have been kindly provided in video
|
| 51 |
+
tutorial form by Old Ireland in Colour's John Breslin. It's great! Click video
|
| 52 |
+
image below to watch.
|
| 53 |
+
|
| 54 |
+
[](http://www.youtube.com/watch?v=VaEl0faDw38)
|
| 55 |
+
|
| 56 |
+
Get more updates on [Twitter
|
| 57 |
+
](https://twitter.com/DeOldify).
|
| 58 |
+
|
| 59 |
+
## Table of Contents
|
| 60 |
+
|
| 61 |
+
- [About DeOldify](#about-deoldify)
|
| 62 |
+
- [Example Videos](#example-videos)
|
| 63 |
+
- [Example Images](#example-images)
|
| 64 |
+
- [Stuff That Should Probably Be In A Paper](#stuff-that-should-probably-be-in-a-paper)
|
| 65 |
+
- [How to Achieve Stable Video](#how-to-achieve-stable-video)
|
| 66 |
+
- [What is NoGAN?](#what-is-nogan)
|
| 67 |
+
- [Why Three Models?](#why-three-models)
|
| 68 |
+
- [Technical Details](#the-technical-details)
|
| 69 |
+
- [Going Forward](#this-project-going-forward)
|
| 70 |
+
- [Roadmap](ROADMAP.md)
|
| 71 |
+
- [Getting Started Yourself](#getting-started-yourself)
|
| 72 |
+
- [Easiest Approach](#easiest-approach)
|
| 73 |
+
- [Your Own Machine](#your-own-machine-not-as-easy)
|
| 74 |
+
- [Pretrained Weights](#pretrained-weights)
|
| 75 |
+
|
| 76 |
+
## About DeOldify
|
| 77 |
+
|
| 78 |
+
Simply put, the mission of this project is to colorize and restore old images and
|
| 79 |
+
film footage. We'll get into the details in a bit, but first let's see some
|
| 80 |
+
pretty pictures and videos!
|
| 81 |
+
|
| 82 |
+
### New and Exciting Stuff in DeOldify
|
| 83 |
+
|
| 84 |
+
- Glitches and artifacts are almost entirely eliminated
|
| 85 |
+
- Better skin (less zombies)
|
| 86 |
+
- More highly detailed and photorealistic renders
|
| 87 |
+
- Much less "blue bias"
|
| 88 |
+
- **Video** - it actually looks good!
|
| 89 |
+
- **NoGAN** - a new and weird but highly effective way to do GAN training for
|
| 90 |
+
image to image.
|
| 91 |
+
|
| 92 |
+
## Example Videos
|
| 93 |
+
|
| 94 |
+
**Note:** Click images to watch
|
| 95 |
+
|
| 96 |
+
### Facebook F8 Demo
|
| 97 |
+
|
| 98 |
+
[](http://www.youtube.com/watch?v=l3UXXid04Ys)
|
| 99 |
+
|
| 100 |
+
### Silent Movie Examples
|
| 101 |
+
|
| 102 |
+
[](http://www.youtube.com/watch?v=EXn-n2iqEjI)
|
| 103 |
+
|
| 104 |
+
## Example Images
|
| 105 |
+
|
| 106 |
+
"Migrant Mother" by Dorothea Lange (1936)
|
| 107 |
+
|
| 108 |
+

|
| 109 |
+
|
| 110 |
+
Woman relaxing in her livingroom in Sweden (1920)
|
| 111 |
+
|
| 112 |
+

|
| 113 |
+
|
| 114 |
+
"Toffs and Toughs" by Jimmy Sime (1937)
|
| 115 |
+
|
| 116 |
+

|
| 117 |
+
|
| 118 |
+
Thanksgiving Maskers (1911)
|
| 119 |
+
|
| 120 |
+

|
| 121 |
+
|
| 122 |
+
Glen Echo Madame Careta Gypsy Camp in Maryland (1925)
|
| 123 |
+
|
| 124 |
+

|
| 125 |
+
|
| 126 |
+
"Mr. and Mrs. Lemuel Smith and their younger children in their farm house,
|
| 127 |
+
Carroll County, Georgia." (1941)
|
| 128 |
+
|
| 129 |
+

|
| 130 |
+
|
| 131 |
+
"Building the Golden Gate Bridge" (est 1937)
|
| 132 |
+
|
| 133 |
+

|
| 134 |
+
|
| 135 |
+
> **Note:** What you might be wondering is while this render looks cool, are the
|
| 136 |
+
> colors accurate? The original photo certainly makes it look like the towers of
|
| 137 |
+
> the bridge could be white. We looked into this and it turns out the answer is
|
| 138 |
+
> no - the towers were already covered in red primer by this time. So that's
|
| 139 |
+
> something to keep in mind- historical accuracy remains a huge challenge!
|
| 140 |
+
|
| 141 |
+
"Terrasse de café, Paris" (1925)
|
| 142 |
+
|
| 143 |
+

|
| 144 |
+
|
| 145 |
+
Norwegian Bride (est late 1890s)
|
| 146 |
+
|
| 147 |
+

|
| 148 |
+
|
| 149 |
+
Zitkála-Šá (Lakota: Red Bird), also known as Gertrude Simmons Bonnin (1898)
|
| 150 |
+
|
| 151 |
+

|
| 152 |
+
|
| 153 |
+
Chinese Opium Smokers (1880)
|
| 154 |
+
|
| 155 |
+

|
| 156 |
+
|
| 157 |
+
## Stuff That Should Probably Be In A Paper
|
| 158 |
+
|
| 159 |
+
### How to Achieve Stable Video
|
| 160 |
+
|
| 161 |
+
NoGAN training is crucial to getting the kind of stable and colorful images seen
|
| 162 |
+
in this iteration of DeOldify. NoGAN training combines the benefits of GAN
|
| 163 |
+
training (wonderful colorization) while eliminating the nasty side effects
|
| 164 |
+
(like flickering objects in video). Believe it or not, video is rendered using
|
| 165 |
+
isolated image generation without any sort of temporal modeling tacked on. The
|
| 166 |
+
process performs 30-60 minutes of the GAN portion of "NoGAN" training, using 1%
|
| 167 |
+
to 3% of imagenet data once. Then, as with still image colorization, we
|
| 168 |
+
"DeOldify" individual frames before rebuilding the video.
|
| 169 |
+
|
| 170 |
+
In addition to improved video stability, there is an interesting thing going on
|
| 171 |
+
here worth mentioning. It turns out the models I run, even different ones and
|
| 172 |
+
with different training structures, keep arriving at more or less the same
|
| 173 |
+
solution. That's even the case for the colorization of things you may think
|
| 174 |
+
would be arbitrary and unknowable, like the color of clothing, cars, and even
|
| 175 |
+
special effects (as seen in "Metropolis").
|
| 176 |
+
|
| 177 |
+

|
| 178 |
+
|
| 179 |
+
My best guess is that the models are learning some interesting rules about how to
|
| 180 |
+
colorize based on subtle cues present in the black and white images that I
|
| 181 |
+
certainly wouldn't expect to exist. This result leads to nicely deterministic and
|
| 182 |
+
consistent results, and that means you don't have track model colorization
|
| 183 |
+
decisions because they're not arbitrary. Additionally, they seem remarkably
|
| 184 |
+
robust so that even in moving scenes the renders are very consistent.
|
| 185 |
+
|
| 186 |
+

|
| 187 |
+
|
| 188 |
+
Other ways to stabilize video add up as well. First, generally speaking rendering
|
| 189 |
+
at a higher resolution (higher render_factor) will increase stability of
|
| 190 |
+
colorization decisions. This stands to reason because the model has higher
|
| 191 |
+
fidelity image information to work with and will have a greater chance of making
|
| 192 |
+
the "right" decision consistently. Closely related to this is the use of
|
| 193 |
+
resnet101 instead of resnet34 as the backbone of the generator- objects are
|
| 194 |
+
detected more consistently and correctly with this. This is especially important
|
| 195 |
+
for getting good, consistent skin rendering. It can be particularly visually
|
| 196 |
+
jarring if you wind up with "zombie hands", for example.
|
| 197 |
+
|
| 198 |
+

|
| 199 |
+
|
| 200 |
+
Additionally, gaussian noise augmentation during training appears to help but at
|
| 201 |
+
this point the conclusions as to just how much are bit more tenuous (I just
|
| 202 |
+
haven't formally measured this yet). This is loosely based on work done in style
|
| 203 |
+
transfer video, described here:
|
| 204 |
+
<https://medium.com/element-ai-research-lab/stabilizing-neural-style-transfer-for-video-62675e203e42>.
|
| 205 |
+
|
| 206 |
+
Special thanks go to Rani Horev for his contributions in implementing this noise
|
| 207 |
+
augmentation.
|
| 208 |
+
|
| 209 |
+
### What is NoGAN?
|
| 210 |
+
|
| 211 |
+
This is a new type of GAN training that I've developed to solve some key problems
|
| 212 |
+
in the previous DeOldify model. It provides the benefits of GAN training while
|
| 213 |
+
spending minimal time doing direct GAN training. Instead, most of the training
|
| 214 |
+
time is spent pretraining the generator and critic separately with more
|
| 215 |
+
straight-forward, fast and reliable conventional methods. A key insight here is
|
| 216 |
+
that those more "conventional" methods generally get you most of the results you
|
| 217 |
+
need, and that GANs can be used to close the gap on realism. During the very
|
| 218 |
+
short amount of actual GAN training the generator not only gets the full
|
| 219 |
+
realistic colorization capabilities that used to take days of progressively
|
| 220 |
+
resized GAN training, but it also doesn't accrue nearly as much of the artifacts
|
| 221 |
+
and other ugly baggage of GANs. In fact, you can pretty much eliminate glitches
|
| 222 |
+
and artifacts almost entirely depending on your approach. As far as I know this
|
| 223 |
+
is a new technique. And it's incredibly effective.
|
| 224 |
+
|
| 225 |
+
#### Original DeOldify Model
|
| 226 |
+
|
| 227 |
+

|
| 228 |
+
|
| 229 |
+
#### NoGAN-Based DeOldify Model
|
| 230 |
+
|
| 231 |
+

|
| 232 |
+
|
| 233 |
+
The steps are as follows: First train the generator in a conventional way by
|
| 234 |
+
itself with just the feature loss. Next, generate images from that, and train
|
| 235 |
+
the critic on distinguishing between those outputs and real images as a basic
|
| 236 |
+
binary classifier. Finally, train the generator and critic together in a GAN
|
| 237 |
+
setting (starting right at the target size of 192px in this case). Now for
|
| 238 |
+
the weird part: All the useful GAN training here only takes place within a very
|
| 239 |
+
small window of time. There's an inflection point where it appears the critic
|
| 240 |
+
has transferred everything it can that is useful to the generator. Past this
|
| 241 |
+
point, image quality oscillates between the best that you can get at the
|
| 242 |
+
inflection point, or bad in a predictable way (orangish skin, overly red lips,
|
| 243 |
+
etc). There appears to be no productive training after the inflection point.
|
| 244 |
+
And this point lies within training on just 1% to 3% of the Imagenet Data!
|
| 245 |
+
That amounts to about 30-60 minutes of training at 192px.
|
| 246 |
+
|
| 247 |
+
The hard part is finding this inflection point. So far, I've accomplished this
|
| 248 |
+
by making a whole bunch of model save checkpoints (every 0.1% of data iterated
|
| 249 |
+
on) and then just looking for the point where images look great before they go
|
| 250 |
+
totally bonkers with orange skin (always the first thing to go). Additionally,
|
| 251 |
+
generator rendering starts immediately getting glitchy and inconsistent at this
|
| 252 |
+
point, which is no good particularly for video. What I'd really like to figure
|
| 253 |
+
out is what the tell-tale sign of the inflection point is that can be easily
|
| 254 |
+
automated as an early stopping point. Unfortunately, nothing definitive is
|
| 255 |
+
jumping out at me yet. For one, it's happening in the middle of training loss
|
| 256 |
+
decreasing- not when it flattens out, which would seem more reasonable on the surface.
|
| 257 |
+
|
| 258 |
+
Another key thing about NoGAN training is you can repeat pretraining the critic
|
| 259 |
+
on generated images after the initial GAN training, then repeat the GAN training
|
| 260 |
+
itself in the same fashion. This is how I was able to get extra colorful results
|
| 261 |
+
with the "artistic" model. But this does come at a cost currently- the output of
|
| 262 |
+
the generator becomes increasingly inconsistent and you have to experiment with
|
| 263 |
+
render resolution (render_factor) to get the best result. But the renders are
|
| 264 |
+
still glitch free and way more consistent than I was ever able to achieve with
|
| 265 |
+
the original DeOldify model. You can do about five of these repeat cycles, give
|
| 266 |
+
or take, before you get diminishing returns, as far as I can tell.
|
| 267 |
+
|
| 268 |
+
Keep in mind- I haven't been entirely rigorous in figuring out what all is going
|
| 269 |
+
on in NoGAN- I'll save that for a paper. That means there's a good chance I'm
|
| 270 |
+
wrong about something. But I think it's definitely worth putting out there now
|
| 271 |
+
because I'm finding it very useful- it's solving basically much of my remaining
|
| 272 |
+
problems I had in DeOldify.
|
| 273 |
+
|
| 274 |
+
This builds upon a technique developed in collaboration with Jeremy Howard and
|
| 275 |
+
Sylvain Gugger for Fast.AI's Lesson 7 in version 3 of Practical Deep Learning
|
| 276 |
+
for Coders Part I. The particular lesson notebook can be found here:
|
| 277 |
+
<https://github.com/fastai/course-v3/blob/master/nbs/dl1/lesson7-superres-gan.ipynb>
|
| 278 |
+
|
| 279 |
+
## Why Three Models?
|
| 280 |
+
|
| 281 |
+
There are now three models to choose from in DeOldify. Each of these has key
|
| 282 |
+
strengths and weaknesses, and so have different use cases. Video is for video
|
| 283 |
+
of course. But stable and artistic are both for images, and sometimes one will
|
| 284 |
+
do images better than the other.
|
| 285 |
+
|
| 286 |
+
More details:
|
| 287 |
+
|
| 288 |
+
- **Artistic** - This model achieves the highest quality results in image
|
| 289 |
+
coloration, in terms of interesting details and vibrance. The most notable
|
| 290 |
+
drawback however is that it's a bit of a pain to fiddle around with to get the
|
| 291 |
+
best results (you have to adjust the rendering resolution or render_factor to
|
| 292 |
+
achieve this). Additionally, the model does not do as well as stable in a few
|
| 293 |
+
key common scenarios- nature scenes and portraits. The model uses a resnet34
|
| 294 |
+
backbone on a UNet with an emphasis on depth of layers on the decoder side.
|
| 295 |
+
This model was trained with 5 critic pretrain/GAN cycle repeats via NoGAN, in
|
| 296 |
+
addition to the initial generator/critic pretrain/GAN NoGAN training, at 192px.
|
| 297 |
+
This adds up to a total of 32% of Imagenet data trained once (12.5 hours of
|
| 298 |
+
direct GAN training).
|
| 299 |
+
|
| 300 |
+
- **Stable** - This model achieves the best results with landscapes and
|
| 301 |
+
portraits. Notably, it produces less "zombies"- where faces or limbs stay gray
|
| 302 |
+
rather than being colored in properly. It generally has less weird
|
| 303 |
+
miscolorations than artistic, but it's also less colorful in general. This
|
| 304 |
+
model uses a resnet101 backbone on a UNet with an emphasis on width of layers on
|
| 305 |
+
the decoder side. This model was trained with 3 critic pretrain/GAN cycle
|
| 306 |
+
repeats via NoGAN, in addition to the initial generator/critic pretrain/GAN
|
| 307 |
+
NoGAN training, at 192px. This adds up to a total of 7% of Imagenet data
|
| 308 |
+
trained once (3 hours of direct GAN training).
|
| 309 |
+
|
| 310 |
+
- **Video** - This model is optimized for smooth, consistent and flicker-free
|
| 311 |
+
video. This would definitely be the least colorful of the three models, but
|
| 312 |
+
it's honestly not too far off from "stable". The model is the same as "stable"
|
| 313 |
+
in terms of architecture, but differs in training. It's trained for a mere 2.2%
|
| 314 |
+
of Imagenet data once at 192px, using only the initial generator/critic
|
| 315 |
+
pretrain/GAN NoGAN training (1 hour of direct GAN training).
|
| 316 |
+
|
| 317 |
+
Because the training of the artistic and stable models was done before the
|
| 318 |
+
"inflection point" of NoGAN training described in "What is NoGAN???" was
|
| 319 |
+
discovered, I believe this amount of training on them can be knocked down
|
| 320 |
+
considerably. As far as I can tell, the models were stopped at "good points"
|
| 321 |
+
that were well beyond where productive training was taking place. I'll be
|
| 322 |
+
looking into this in the future.
|
| 323 |
+
|
| 324 |
+
Ideally, eventually these three models will be consolidated into one that has all
|
| 325 |
+
these good desirable unified. I think there's a path there, but it's going to
|
| 326 |
+
require more work! So for now, the most practical solution appears to be to
|
| 327 |
+
maintain multiple models.
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
## The Technical Details
|
| 334 |
+
|
| 335 |
+
This is a deep learning based model. More specifically, what I've done is
|
| 336 |
+
combined the following approaches:
|
| 337 |
+
|
| 338 |
+
### [Self-Attention Generative Adversarial Network](https://arxiv.org/abs/1805.08318)
|
| 339 |
+
|
| 340 |
+
Except the generator is a **pretrained U-Net**, and I've just modified it to
|
| 341 |
+
have the spectral normalization and self-attention. It's a pretty
|
| 342 |
+
straightforward translation.
|
| 343 |
+
|
| 344 |
+
### [Two Time-Scale Update Rule](https://arxiv.org/abs/1706.08500)
|
| 345 |
+
|
| 346 |
+
This is also very straightforward – it's just one to one generator/critic
|
| 347 |
+
iterations and higher critic learning rate.
|
| 348 |
+
This is modified to incorporate a "threshold" critic loss that makes sure that
|
| 349 |
+
the critic is "caught up" before moving on to generator training.
|
| 350 |
+
This is particularly useful for the "NoGAN" method described below.
|
| 351 |
+
|
| 352 |
+
### NoGAN
|
| 353 |
+
|
| 354 |
+
There's no paper here! This is a new type of GAN training that I've developed to
|
| 355 |
+
solve some key problems in the previous DeOldify model.
|
| 356 |
+
The gist is that you get the benefits of GAN training while spending minimal time
|
| 357 |
+
doing direct GAN training.
|
| 358 |
+
More details are in the [What is NoGAN?](#what-is-nogan) section (it's a doozy).
|
| 359 |
+
|
| 360 |
+
### Generator Loss
|
| 361 |
+
|
| 362 |
+
Loss during NoGAN learning is two parts: One is a basic Perceptual Loss (or
|
| 363 |
+
Feature Loss) based on VGG16 – this just biases the generator model to replicate
|
| 364 |
+
the input image.
|
| 365 |
+
The second is the loss score from the critic. For the curious – Perceptual Loss
|
| 366 |
+
isn't sufficient by itself to produce good results.
|
| 367 |
+
It tends to just encourage a bunch of brown/green/blue – you know, cheating to
|
| 368 |
+
the test, basically, which neural networks are really good at doing!
|
| 369 |
+
Key thing to realize here is that GANs essentially are learning the loss function
|
| 370 |
+
for you – which is really one big step closer to toward the ideal that we're
|
| 371 |
+
shooting for in machine learning.
|
| 372 |
+
And of course you generally get much better results when you get the machine to
|
| 373 |
+
learn something you were previously hand coding.
|
| 374 |
+
That's certainly the case here.
|
| 375 |
+
|
| 376 |
+
**Of note:** There's no longer any "Progressive Growing of GANs" type training
|
| 377 |
+
going on here. It's just not needed in lieu of the superior results obtained
|
| 378 |
+
by the "NoGAN" technique described above.
|
| 379 |
+
|
| 380 |
+
The beauty of this model is that it should be generally useful for all sorts of
|
| 381 |
+
image modification, and it should do it quite well.
|
| 382 |
+
What you're seeing above are the results of the colorization model, but that's
|
| 383 |
+
just one component in a pipeline that I'm developing with the exact same approach.
|
| 384 |
+
|
| 385 |
+
## This Project, Going Forward
|
| 386 |
+
|
| 387 |
+
So that's the gist of this project – I'm looking to make old photos and film
|
| 388 |
+
look reeeeaaally good with GANs, and more importantly, make the project *useful*.
|
| 389 |
+
In the meantime though this is going to be my baby and I'll be actively updating
|
| 390 |
+
and improving the code over the foreseeable future.
|
| 391 |
+
I'll try to make this as user-friendly as possible, but I'm sure there's going
|
| 392 |
+
to be hiccups along the way.
|
| 393 |
+
|
| 394 |
+
Oh and I swear I'll document the code properly...eventually. Admittedly I'm
|
| 395 |
+
*one of those* people who believes in "self documenting code" (LOL).
|
| 396 |
+
|
| 397 |
+
## Best Practices & Golden Nuggets
|
| 398 |
+
|
| 399 |
+
Based on extensive community research and the original author's insights, here are the "Golden Nuggets" for getting the best results:
|
| 400 |
+
|
| 401 |
+
### 1. Video Flicker? Use the "Video" Model!
|
| 402 |
+
If you are experiencing flickering in your video outputs, ensure you are using the **Video** model weights (`ColorizeVideo_gen.pth`). This model was specifically trained with **NoGAN** to prioritize temporal consistency over raw color vibrancy. The "Artistic" model will almost always flicker on video.
|
| 403 |
+
|
| 404 |
+
### 2. The "NoGAN" Secret
|
| 405 |
+
The core innovation of DeOldify is **NoGAN** training. It pre-trains the generator with a conventional loss function (Perceptual Loss) before introducing the GAN component. This minimizes the "GAN artifacts" (like flicker) while keeping the colorization quality.
|
| 406 |
+
|
| 407 |
+
### 3. Post-Processing is Key
|
| 408 |
+
Even with the Video model, some flicker may persist. We recommend using **FFmpeg's `deflicker` filter** as a post-processing step.
|
| 409 |
+
* **New Feature**: We have added a `deflicker=True` option to the `VideoColorizer` to handle this automatically!
|
| 410 |
+
|
| 411 |
+
### 4. Alternative Implementations
|
| 412 |
+
* **Anime/Manga**: If you are colorizing anime sketches, check out [AnimeColorDeOldify](https://github.com/Dakini/AnimeColorDeOldify), which uses a model fine-tuned on Danbooru.
|
| 413 |
+
* **C# / .NET**: For a native C# implementation, see [DeOldify.NET](https://github.com/ColorfulSoft/DeOldify.NET).
|
| 414 |
+
|
| 415 |
+
## Getting Started Yourself
|
| 416 |
+
have that yet so I'm not going to make it the default instruction here yet.
|
| 417 |
+
|
| 418 |
+
**Alternative Install:** User daddyparodz has kindly created an installer script
|
| 419 |
+
for Ubuntu, and in particular Ubuntu on WSL, that may make things easier:
|
| 420 |
+
<https://github.com/daddyparodz/AutoDeOldifyLocal>
|
| 421 |
+
|
| 422 |
+
#### Note on test_images Folder
|
| 423 |
+
|
| 424 |
+
The images in the `test_images` folder have been removed because they were using
|
| 425 |
+
Git LFS and that costs a lot of money when GitHub actually charges for bandwidth
|
| 426 |
+
on a popular open source project (they had a billing bug for while that was
|
| 427 |
+
recently fixed). The notebooks that use them (the image test ones) still point
|
| 428 |
+
to images in that directory that I (Jason) have personally and I'd like to keep
|
| 429 |
+
it that way because, after all, I'm by far the primary and most active developer.
|
| 430 |
+
But they won't work for you. Still, those notebooks are a convenient template
|
| 431 |
+
for making your own tests if you're so inclined.
|
| 432 |
+
|
| 433 |
+
#### Typical training
|
| 434 |
+
|
| 435 |
+
The notebook `ColorizeTrainingWandb` has been created to log and monitor results
|
| 436 |
+
through [Weights & Biases](https://www.wandb.com/). You can find a description of
|
| 437 |
+
typical training by consulting [W&B Report](https://app.wandb.ai/borisd13/DeOldify/reports?view=borisd13%2FDeOldify).
|
| 438 |
+
|
| 439 |
+
## Pretrained Weights
|
| 440 |
+
|
| 441 |
+
To start right away on your own machine with your own images or videos without
|
| 442 |
+
training the models yourself, you'll need to download the "Completed Generator
|
| 443 |
+
Weights" listed below and drop them in the /models/ folder.
|
| 444 |
+
|
| 445 |
+
The colorization inference notebooks should be able to guide you from here. The
|
| 446 |
+
notebooks to use are named ImageColorizerArtistic.ipynb,
|
| 447 |
+
ImageColorizerStable.ipynb, and VideoColorizer.ipynb.
|
| 448 |
+
|
| 449 |
+
### Completed Generator Weights
|
| 450 |
+
|
| 451 |
+
- [Artistic](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeArtistic_gen.pth)
|
| 452 |
+
- [Stable](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeStable_gen.pth)
|
| 453 |
+
- [Video](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeVideo_gen.pth)
|
| 454 |
+
|
| 455 |
+
### Completed Critic Weights
|
| 456 |
+
|
| 457 |
+
- [Artistic](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeArtistic_crit.pth)
|
| 458 |
+
- [Stable](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeStable_crit.pth)
|
| 459 |
+
- [Video](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeVideo_crit.pth)
|
| 460 |
+
|
| 461 |
+
### Pretrain Only Generator Weights
|
| 462 |
+
|
| 463 |
+
> **Note:** The Stable and Video PretrainOnly generator weights are split into multiple parts due to their size. Please download all parts (e.g., `.pth.000`, `.pth.001`) and run `python reassemble_models.py` to join them.
|
| 464 |
+
|
| 465 |
+
- [Artistic](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeArtistic_PretrainOnly_gen.pth)
|
| 466 |
+
- [Stable (Part 1)](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeStable_PretrainOnly_gen.pth.000) | [Stable (Part 2)](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeStable_PretrainOnly_gen.pth.001)
|
| 467 |
+
- [Video (Part 1)](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeVideo_PretrainOnly_gen.pth.000) | [Video (Part 2)](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeVideo_PretrainOnly_gen.pth.001)
|
| 468 |
+
|
| 469 |
+
### Pretrain Only Critic Weights
|
| 470 |
+
|
| 471 |
+
- [Artistic](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeArtistic_PretrainOnly_crit.pth)
|
| 472 |
+
- [Stable](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeStable_PretrainOnly_crit.pth)
|
| 473 |
+
- [Video](https://github.com/thookham/DeOldify/releases/download/v2.0-models/ColorizeVideo_PretrainOnly_crit.pth)
|
| 474 |
+
|
| 475 |
+
### Archived Models (Browser / ONNX)
|
| 476 |
+
|
| 477 |
+
- [Artistic ONNX](https://github.com/thookham/DeOldify/releases/download/v2.0-models/deoldify-art.onnx)
|
| 478 |
+
- [Quantized ONNX](https://github.com/thookham/DeOldify/releases/download/v2.0-models/deoldify-quant.onnx)
|
| 479 |
+
|
| 480 |
+
## Want the Old DeOldify?
|
| 481 |
+
|
| 482 |
+
We suspect some of you are going to want access to the original DeOldify model
|
| 483 |
+
for various reasons. We have that archived here: <https://github.com/dana-kelley/DeOldify>
|
| 484 |
+
|
| 485 |
+
## Want More?
|
| 486 |
+
|
| 487 |
+
Follow [#DeOldify](https://twitter.com/search?q=%23Deoldify) on Twitter.
|
| 488 |
+
|
| 489 |
+
## License
|
| 490 |
+
|
| 491 |
+
All code in this repository is under the MIT license as specified by the LICENSE
|
| 492 |
+
file.
|
| 493 |
+
|
| 494 |
+
The model weights listed in this readme under the "Pretrained Weights" section
|
| 495 |
+
are trained by ourselves and are released under the MIT license.
|
| 496 |
+
|
| 497 |
+
## A Statement on Open Source Support
|
| 498 |
+
|
| 499 |
+
We believe that open source has done a lot of good for the world. After all,
|
| 500 |
+
DeOldify simply wouldn't exist without it. But we also believe that there needs
|
| 501 |
+
to be boundaries on just how much is reasonable to be expected from an open
|
| 502 |
+
source project maintained by just two developers.
|
| 503 |
+
|
| 504 |
+
Our stance is that we're providing the code and documentation on research that
|
| 505 |
+
we believe is beneficial to the world. What we have provided are novel takes
|
| 506 |
+
on colorization, GANs, and video that are hopefully somewhat friendly for
|
| 507 |
+
developers and researchers to learn from and adopt. This is the culmination of
|
| 508 |
+
well over a year of continuous work, free for you. What wasn't free was
|
| 509 |
+
shouldered by us, the developers. We left our jobs, bought expensive GPUs, and
|
| 510 |
+
had huge electric bills as a result of dedicating ourselves to this.
|
| 511 |
+
|
| 512 |
+
What we haven't provided here is a ready to use free "product" or "app", and we
|
| 513 |
+
don't ever intend on providing that. It's going to remain a Linux based project
|
| 514 |
+
without Windows support, coded in Python, and requiring people to have some extra
|
| 515 |
+
technical background to be comfortable using it. Others have stepped in with
|
| 516 |
+
their own apps made with DeOldify, some paid and some free, which is what we want!
|
| 517 |
+
We're instead focusing on what we believe we can do best- making better
|
| 518 |
+
commercial models that people will pay for.
|
| 519 |
+
Does that mean you're not getting the very best for free? Of course. We simply
|
| 520 |
+
don't believe that we're obligated to provide that, nor is it feasible! We
|
| 521 |
+
compete on research and sell that. Not a GUI or web service that wraps said
|
| 522 |
+
research- that part isn't something we're going to be great at anyways. We're not
|
| 523 |
+
about to shoot ourselves in the foot by giving away our actual competitive
|
| 524 |
+
advantage for free, quite frankly.
|
| 525 |
+
|
| 526 |
+
We're also not willing to go down the rabbit hole of providing endless, open
|
| 527 |
+
ended and personalized support on this open source project. Our position is
|
| 528 |
+
this: If you have the proper background and resources, the project provides
|
| 529 |
+
more than enough to get you started. We know this because we've seen plenty of
|
| 530 |
+
people using it and making money off of their own projects with it.
|
| 531 |
+
|
| 532 |
+
Thus, if you have an issue come up and it happens to be an actual bug that
|
| 533 |
+
having it be fixed will benefit users generally, then great- that's something
|
| 534 |
+
we'll be happy to look into.
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
In contrast, if you're asking about something that really amounts to asking for
|
| 538 |
+
personalized and time consuming support that won't benefit anybody else, we're
|
| 539 |
+
not going to help. It's simply not in our interest to do that. We have bills to
|
| 540 |
+
pay, after all. And if you're asking for help on something that can already be
|
| 541 |
+
derived from the documentation or code? That's simply annoying, and we're not
|
| 542 |
+
going to pretend to be ok with that.
|
ROADMAP.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DeOldify Roadmap
|
| 2 |
+
|
| 3 |
+
This document outlines the development roadmap for DeOldify (Modernized), organized by priority and timeline. The project has successfully completed a major modernization effort and is now focused on expanding hardware support and exploring new deployment options.
|
| 4 |
+
|
| 5 |
+
## 🎯 Project Vision
|
| 6 |
+
|
| 7 |
+
Make DeOldify accessible and performant across modern hardware platforms (NVIDIA, Intel, AMD) while maintaining the cutting-edge colorization quality that made it popular. Enable deployment in diverse environments from local machines to cloud infrastructure.
|
| 8 |
+
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
## ✅ Recently Completed (v2.0 - November 2025)
|
| 12 |
+
|
| 13 |
+
### Core Modernization
|
| 14 |
+
- ✅ **PyTorch 2.5+ Migration**: Removed dependency on obsolete FastAI 1.x library
|
| 15 |
+
- ✅ **CUDA 12.x Support**: Full support for modern NVIDIA GPUs
|
| 16 |
+
- ✅ **Intel GPU Support**: Arc and Data Center GPU support via Intel Extension for PyTorch (IPEX)
|
| 17 |
+
- ✅ **Unified Device Management**: Automatic detection and fallback (Intel → NVIDIA → CPU)
|
| 18 |
+
- ✅ **Compatibility Layer**: Created `deoldify.fastai_compat` for seamless PyTorch integration
|
| 19 |
+
|
| 20 |
+
### Infrastructure & Tooling
|
| 21 |
+
- ✅ **Model Migration**: All weights migrated to GitHub Releases with SHA256 verification
|
| 22 |
+
- ✅ **Verification Scripts**: `verify_models.py` and `verify_refactor.py` for validation
|
| 23 |
+
- ✅ **GitHub Community Standards**: Code of Conduct, Contributing Guidelines, Security Policy
|
| 24 |
+
- ✅ **CI/CD**: Unit tests and automated workflows
|
| 25 |
+
- ✅ **Browser Implementation**: Local ONNX-based colorization in browser
|
| 26 |
+
|
| 27 |
+
### Documentation
|
| 28 |
+
- ✅ **Setup Guides**: Comprehensive guides for NVIDIA and Intel GPUs
|
| 29 |
+
- ✅ **Hardware Guide**: Benchmarks and requirements
|
| 30 |
+
- ✅ **Deployment Guide**: Local serving instructions
|
| 31 |
+
- ✅ **Modernized Notebooks**: Updated Colab notebooks with file upload widgets
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
## 🔴 High Priority (Q1 2025)
|
| 36 |
+
|
| 37 |
+
### Intel NPU Support
|
| 38 |
+
**Goal**: Enable Neural Processing Unit acceleration for Intel Core Ultra processors
|
| 39 |
+
|
| 40 |
+
- [ ] **Research & Investigation**
|
| 41 |
+
- Investigate OpenVINO toolkit integration
|
| 42 |
+
- Evaluate Intel Extension for PyTorch NPU capabilities
|
| 43 |
+
- Benchmark NPU performance vs GPU/CPU inference
|
| 44 |
+
|
| 45 |
+
- [ ] **Implementation**
|
| 46 |
+
- Add NPU device detection to `deoldify.device`
|
| 47 |
+
- Implement NPU-specific optimizations
|
| 48 |
+
- Update fallback chain: Intel NPU → Intel GPU → NVIDIA GPU → CPU
|
| 49 |
+
|
| 50 |
+
- [ ] **Documentation & Testing**
|
| 51 |
+
- Create `docs/intel_npu_setup.md`
|
| 52 |
+
- Add NPU tests to CI/CD pipeline
|
| 53 |
+
- Update hardware requirements guide
|
| 54 |
+
|
| 55 |
+
**Expected Impact**: Enable efficient inference on laptops and mobile workstations without discrete GPUs.
|
| 56 |
+
|
| 57 |
+
---
|
| 58 |
+
|
| 59 |
+
## 🟠 Medium Priority (Q2 2025)
|
| 60 |
+
|
| 61 |
+
### AMD GPU Support
|
| 62 |
+
**Goal**: Support Radeon GPUs via ROCm
|
| 63 |
+
|
| 64 |
+
- [ ] Add ROCm device detection
|
| 65 |
+
- [ ] Create `environment_amd.yml` for ROCm environments
|
| 66 |
+
- [ ] Test on RDNA 2/3 architecture
|
| 67 |
+
- [ ] Document AMD setup process
|
| 68 |
+
|
| 69 |
+
### Performance Optimizations
|
| 70 |
+
**Goal**: Improve inference speed and memory efficiency
|
| 71 |
+
|
| 72 |
+
- [ ] **Quantization**: INT8/FP16 inference modes
|
| 73 |
+
- [ ] **Dynamic Batching**: Process multiple images efficiently
|
| 74 |
+
- [ ] **Model Pruning**: Reduce model size without quality loss
|
| 75 |
+
- [ ] **ONNX Runtime**: Evaluate ONNX Runtime for cross-platform inference
|
| 76 |
+
|
| 77 |
+
### Enhanced Browser Implementation
|
| 78 |
+
**Goal**: Improve browser-based colorization UX
|
| 79 |
+
|
| 80 |
+
- [ ] Add WebGPU support for hardware acceleration
|
| 81 |
+
- [ ] Implement progressive rendering for large images
|
| 82 |
+
- [ ] Add batch processing capabilities
|
| 83 |
+
- [ ] Create comparison slider UI
|
| 84 |
+
|
| 85 |
+
---
|
| 86 |
+
|
| 87 |
+
## 🟡 Low Priority (Q3-Q4 2025)
|
| 88 |
+
|
| 89 |
+
### Cloud Deployment
|
| 90 |
+
**Goal**: Simplify cloud deployment for production use
|
| 91 |
+
|
| 92 |
+
- [ ] **Google Cloud Platform**
|
| 93 |
+
- Vertex AI deployment scripts
|
| 94 |
+
- Container images for Cloud Run
|
| 95 |
+
- Example Terraform configurations
|
| 96 |
+
|
| 97 |
+
- [ ] **AWS**
|
| 98 |
+
- SageMaker deployment templates
|
| 99 |
+
- Lambda@Edge for serverless inference
|
| 100 |
+
|
| 101 |
+
- [ ] **Azure**
|
| 102 |
+
- Azure ML deployment guide
|
| 103 |
+
- Container Apps examples
|
| 104 |
+
|
| 105 |
+
### Model Improvements
|
| 106 |
+
**Goal**: Enhance colorization quality and capabilities
|
| 107 |
+
|
| 108 |
+
- [ ] **Fine-Tuning Tools**
|
| 109 |
+
- Scripts for domain-specific fine-tuning
|
| 110 |
+
- Transfer learning examples
|
| 111 |
+
- Custom dataset preparation guides
|
| 112 |
+
- **Custom Training Guides**: Documentation for fine-tuning NoGAN on domain-specific footage (e.g., anime, old film)
|
| 113 |
+
|
| 114 |
+
- [ ] **Post-Processing Tools**
|
| 115 |
+
- Advanced deflicker integration (FFmpeg)
|
| 116 |
+
- Temporal smoothing helpers
|
| 117 |
+
- Comparison tools for different render factors
|
| 118 |
+
|
| 119 |
+
- [ ] **New Model Variants**
|
| 120 |
+
- Lightweight mobile-optimized model
|
| 121 |
+
- Ultra-high-resolution model (8K+)
|
| 122 |
+
- Real-time video colorization model
|
| 123 |
+
|
| 124 |
+
### API & Integration
|
| 125 |
+
**Goal**: Make DeOldify easier to integrate into other applications
|
| 126 |
+
|
| 127 |
+
- [ ] **REST API**
|
| 128 |
+
- FastAPI/Flask-based serving
|
| 129 |
+
- Docker containers with API
|
| 130 |
+
- OpenAPI/Swagger documentation
|
| 131 |
+
|
| 132 |
+
- [ ] **Python Package**
|
| 133 |
+
- Publish to PyPI
|
| 134 |
+
- Simplified installation (`pip install deoldify`)
|
| 135 |
+
- High-level API for common use cases
|
| 136 |
+
|
| 137 |
+
---
|
| 138 |
+
|
| 139 |
+
## 🔵 Future Exploration (2026+)
|
| 140 |
+
|
| 141 |
+
### Advanced Features
|
| 142 |
+
- **Temporal Coherence**: Improved video stability with optical flow
|
| 143 |
+
- **User Guidance**: Interactive colorization with color hints
|
| 144 |
+
- **Style Transfer**: Multiple artistic colorization styles
|
| 145 |
+
- **4K/8K Support**: Native ultra-high-resolution processing
|
| 146 |
+
|
| 147 |
+
### Research Directions
|
| 148 |
+
- **Diffusion Models**: Explore stable diffusion for colorization
|
| 149 |
+
- **Transformer Architectures**: Evaluate Vision Transformers (ViT)
|
| 150 |
+
- **Few-Shot Learning**: Colorize with minimal reference images
|
| 151 |
+
- **Historical Accuracy**: Training on verified historical color photos
|
| 152 |
+
|
| 153 |
+
### Community Features
|
| 154 |
+
- **Model Zoo**: User-contributed fine-tuned models
|
| 155 |
+
- **Plugin System**: Extensible architecture for custom filters
|
| 156 |
+
- **Web Service**: Official hosted API (potential paid tier)
|
| 157 |
+
|
| 158 |
+
---
|
| 159 |
+
|
| 160 |
+
## 📊 Success Metrics
|
| 161 |
+
|
| 162 |
+
We measure progress through:
|
| 163 |
+
|
| 164 |
+
- **Hardware Coverage**: Percentage of modern GPUs supported (Target: 90%+)
|
| 165 |
+
- **Inference Speed**: FPS for 1080p video colorization (Target: 30+ FPS on modern GPU)
|
| 166 |
+
- **Model Quality**: User satisfaction and comparison to commercial solutions
|
| 167 |
+
- **Adoption**: GitHub stars, PyPI downloads, community contributions
|
| 168 |
+
- **Documentation**: Completeness and clarity based on user feedback
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
## 🤝 How to Contribute
|
| 173 |
+
|
| 174 |
+
We welcome contributions aligned with this roadmap! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
| 175 |
+
|
| 176 |
+
**High-Impact Areas**:
|
| 177 |
+
- Testing on different hardware configurations
|
| 178 |
+
- Documentation improvements and translations
|
| 179 |
+
- Performance benchmarking and optimization
|
| 180 |
+
- Bug reports with reproducible examples
|
| 181 |
+
|
| 182 |
+
---
|
| 183 |
+
|
| 184 |
+
## 📝 Roadmap Updates
|
| 185 |
+
|
| 186 |
+
This roadmap is reviewed and updated quarterly. Last updated: **December 2025**
|
| 187 |
+
|
| 188 |
+
For detailed technical tasks, see [TODO.md](TODO.md).
|
| 189 |
+
For recent changes, see [CHANGELOG.md](CHANGELOG.md).
|
SECURITY.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Security Policy
|
| 2 |
+
|
| 3 |
+
## Supported Versions
|
| 4 |
+
|
| 5 |
+
Use this section to tell people about which versions of your project are
|
| 6 |
+
currently being supported with security updates.
|
| 7 |
+
|
| 8 |
+
| Version | Supported |
|
| 9 |
+
| ------- | ------------------ |
|
| 10 |
+
| 1.0.x | :white_check_mark: |
|
| 11 |
+
| < 1.0 | :x: |
|
| 12 |
+
|
| 13 |
+
## Reporting a Vulnerability
|
| 14 |
+
|
| 15 |
+
Use this section to tell people how to report a vulnerability.
|
| 16 |
+
|
| 17 |
+
Tell them where to go, how often they can expect to get an update on a
|
| 18 |
+
reported vulnerability, what to expect if the vulnerability is accepted or
|
| 19 |
+
declined, etc.
|
TODO.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DeOldify Modernization Roadmap
|
| 2 |
+
|
| 3 |
+
This document tracks the remaining tasks to fully modernize the DeOldify repository, prioritized by user feedback.
|
| 4 |
+
|
| 5 |
+
## 🔴 Priority 1: Intel GPU Support (A-1)
|
| 6 |
+
*Goal: Ensure robust support for Intel Arc and Data Center GPUs.*
|
| 7 |
+
|
| 8 |
+
- [x] **Verify `device_id.py`**
|
| 9 |
+
- Ensure `DeviceId` enum includes Intel/XPU options if necessary.
|
| 10 |
+
- [x] **Verify Integration**
|
| 11 |
+
- Check if `visualize.py` and other scripts correctly use the `_device.py` manager for Intel hardware.
|
| 12 |
+
- Ensure fallback logic (Intel -> NVIDIA -> CPU) works as intended.
|
| 13 |
+
- [ ] **Intel NPU Support**
|
| 14 |
+
- Investigate and implement NPU detection (OpenVINO/IPEX).
|
| 15 |
+
|
| 16 |
+
## 🔴 Priority 2: NVIDIA GPU Modernization (A-2)
|
| 17 |
+
*Goal: Leverage latest CUDA and PyTorch features while maintaining reasonable backward compatibility.*
|
| 18 |
+
|
| 19 |
+
- [x] **Verify Optimization**
|
| 20 |
+
- Ensure `torch.backends.cudnn.benchmark` and other optimizations are correctly applied for modern NVIDIA GPUs.
|
| 21 |
+
- Double check `environment.yml` against latest PyTorch/CUDA matrix.
|
| 22 |
+
- [x] **Legacy CUDA Support**
|
| 23 |
+
- Document support for older drivers (last 5 years) where possible, or provide alternative environment files.
|
| 24 |
+
|
| 25 |
+
## 🟠 Priority 3: Colab Modernization
|
| 26 |
+
*Goal: Fix broken notebooks and improve UX.*
|
| 27 |
+
|
| 28 |
+
- [x] **Fix `requirements-colab.txt`**
|
| 29 |
+
- Remove `fastai==1.0.60` (conflicts with new PyTorch).
|
| 30 |
+
- Add `torch`, `torchvision`, and other modern dependencies.
|
| 31 |
+
- [x] **Update Notebooks**
|
| 32 |
+
- Remove `import fastai`.
|
| 33 |
+
- Use `deoldify.fastai_compat`.
|
| 34 |
+
- [x] **UI Improvements**
|
| 35 |
+
- Drag-and-drop, Gallery, Comparison view.
|
| 36 |
+
|
| 37 |
+
## 🟡 Priority 4: Documentation & Testing
|
| 38 |
+
*Goal: Comprehensive guides and stability.*
|
| 39 |
+
|
| 40 |
+
- [x] **Detailed Documentation**
|
| 41 |
+
- Create `docs/HARDWARE_GUIDE.md` (Benchmarks & Requirements).
|
| 42 |
+
- Create `docs/DEPLOYMENT_GUIDE.md` (Local serving).
|
| 43 |
+
- [x] **Testing**
|
| 44 |
+
- Create `tests/` directory with unit tests for device selection and compatibility layer.
|
| 45 |
+
- Add CI/CD workflow.
|
| 46 |
+
|
| 47 |
+
## 🔵 Future Work: Cloud Integration
|
| 48 |
+
- [x] **Migrate Pretrained Weights**
|
| 49 |
+
- Host models on GitHub Releases to ensure longevity.
|
| 50 |
+
- Update all notebooks and docs to point to new URLs.
|
| 51 |
+
- [ ] **Google Cloud Platform (Vertex AI)**
|
| 52 |
+
- Deployment scripts and containers.
|
USAGE_EXAMPLES.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DeOldify Usage Examples
|
| 2 |
+
|
| 3 |
+
This guide provides practical examples for using DeOldify models from Hugging Face.
|
| 4 |
+
|
| 5 |
+
## Quick Start
|
| 6 |
+
|
| 7 |
+
### Install Dependencies
|
| 8 |
+
|
| 9 |
+
```bash
|
| 10 |
+
pip install huggingface_hub torch torchvision Pillow numpy
|
| 11 |
+
```
|
| 12 |
+
|
| 13 |
+
### Download a Model
|
| 14 |
+
|
| 15 |
+
```python
|
| 16 |
+
from huggingface_hub import hf_hub_download
|
| 17 |
+
|
| 18 |
+
# Download the Stable model (recommended for portraits)
|
| 19 |
+
model_path = hf_hub_download(
|
| 20 |
+
repo_id="thookham/DeOldify",
|
| 21 |
+
filename="ColorizeStable_gen.pth"
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
print(f"Model downloaded to: {model_path}")
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
## Using PyTorch Models
|
| 28 |
+
|
| 29 |
+
> **Note**: The full DeOldify package is required to load and use the PyTorch models. Clone the repository: `git clone https://github.com/thookham/DeOldify`
|
| 30 |
+
|
| 31 |
+
### Example: Colorize an Image
|
| 32 |
+
|
| 33 |
+
```python
|
| 34 |
+
from deoldify import device
|
| 35 |
+
from deoldify.visualize import get_image_colorizer
|
| 36 |
+
from PIL import Image
|
| 37 |
+
|
| 38 |
+
# Initialize colorizer (will download model if needed)
|
| 39 |
+
colorizer = get_image_colorizer(artistic=False) # Use Stable model
|
| 40 |
+
|
| 41 |
+
# Colorize an image
|
| 42 |
+
source_path = "old_photo.jpg"
|
| 43 |
+
result_path = colorizer.plot_transformed_image(
|
| 44 |
+
path=source_path,
|
| 45 |
+
render_factor=35, # Higher = better quality, slower
|
| 46 |
+
compare=True # Show before/after
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
print(f"Colorized image saved to: {result_path}")
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
### Example: Batch Processing
|
| 53 |
+
|
| 54 |
+
```python
|
| 55 |
+
from pathlib import Path
|
| 56 |
+
from deoldify.visualize import get_image_colorizer
|
| 57 |
+
|
| 58 |
+
colorizer = get_image_colorizer(artistic=True) # Use Artistic model
|
| 59 |
+
|
| 60 |
+
input_dir = Path("black_and_white_photos")
|
| 61 |
+
output_dir = Path("colorized")
|
| 62 |
+
output_dir.mkdir(exist_ok=True)
|
| 63 |
+
|
| 64 |
+
for img_path in input_dir.glob("*.jpg"):
|
| 65 |
+
print(f"Processing {img_path.name}...")
|
| 66 |
+
result = colorizer.get_transformed_image(
|
| 67 |
+
path=str(img_path),
|
| 68 |
+
render_factor=30
|
| 69 |
+
)
|
| 70 |
+
result.save(output_dir / img_path.name)
|
| 71 |
+
|
| 72 |
+
print(f"Processed {len(list(input_dir.glob('*.jpg')))} images")
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
## Using ONNX Models (Browser)
|
| 76 |
+
|
| 77 |
+
The ONNX models can run directly in web browsers using ONNX Runtime Web.
|
| 78 |
+
|
| 79 |
+
### Example: HTML Page
|
| 80 |
+
|
| 81 |
+
```html
|
| 82 |
+
<!DOCTYPE html>
|
| 83 |
+
<html>
|
| 84 |
+
<head>
|
| 85 |
+
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js"></script>
|
| 86 |
+
</head>
|
| 87 |
+
<body>
|
| 88 |
+
<input type="file" id="imageInput" accept="image/*" />
|
| 89 |
+
<canvas id="outputCanvas"></canvas>
|
| 90 |
+
|
| 91 |
+
<script>
|
| 92 |
+
async function loadAndColorize() {
|
| 93 |
+
// Load model from Hugging Face
|
| 94 |
+
const session = await ort.InferenceSession.create(
|
| 95 |
+
"https://huggingface.co/thookham/DeOldify/resolve/main/deoldify-quant.onnx"
|
| 96 |
+
);
|
| 97 |
+
|
| 98 |
+
document.getElementById('imageInput').addEventListener('change', async (e) => {
|
| 99 |
+
const file = e.target.files[0];
|
| 100 |
+
const image = new Image();
|
| 101 |
+
image.src = URL.createObjectURL(file);
|
| 102 |
+
|
| 103 |
+
image.onload = async () => {
|
| 104 |
+
// Preprocessing (resize to 256x256, convert to Float32 tensor)
|
| 105 |
+
const canvas = document.createElement('canvas');
|
| 106 |
+
canvas.width = 256;
|
| 107 |
+
canvas.height = 256;
|
| 108 |
+
const ctx = canvas.getContext('2d');
|
| 109 |
+
ctx.drawImage(image, 0, 0, 256, 256);
|
| 110 |
+
|
| 111 |
+
const imageData = ctx.getImageData(0, 0, 256, 256);
|
| 112 |
+
// ... (preprocessing code)
|
| 113 |
+
|
| 114 |
+
// Run inference
|
| 115 |
+
const tensor = new ort.Tensor('float32', processedData, [1, 3, 256, 256]);
|
| 116 |
+
const results = await session.run({ input: tensor });
|
| 117 |
+
|
| 118 |
+
// Display result
|
| 119 |
+
// ... (postprocessing code)
|
| 120 |
+
};
|
| 121 |
+
});
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
loadAndColorize();
|
| 125 |
+
</script>
|
| 126 |
+
</body>
|
| 127 |
+
</html>
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
For a complete working example, see the [browser directory](https://github.com/thookham/DeOldify/tree/master/browser) in the GitHub repository.
|
| 131 |
+
|
| 132 |
+
## Model Selection Guide
|
| 133 |
+
|
| 134 |
+
### Artistic Model
|
| 135 |
+
- **Best for**: General historical photos, artistic colorization
|
| 136 |
+
- **Pros**: Most vibrant colors, interesting details
|
| 137 |
+
- **Cons**: May require `render_factor` tuning
|
| 138 |
+
- **Files**: `ColorizeArtistic_gen.pth`, `deoldify-art.onnx`
|
| 139 |
+
|
| 140 |
+
```python
|
| 141 |
+
colorizer = get_image_colorizer(artistic=True)
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
### Stable Model
|
| 145 |
+
- **Best for**: Portraits, landscapes
|
| 146 |
+
- **Pros**: More consistent, less artifacts
|
| 147 |
+
- **Cons**: Slightly less colorful than Artistic
|
| 148 |
+
- **Files**: `ColorizeStable_gen.pth`
|
| 149 |
+
|
| 150 |
+
```python
|
| 151 |
+
colorizer = get_image_colorizer(artistic=False)
|
| 152 |
+
```
|
| 153 |
+
|
| 154 |
+
### Video Model
|
| 155 |
+
- **Best for**: Video colorization
|
| 156 |
+
- **Pros**: Flicker-free, temporally consistent
|
| 157 |
+
- **Cons**: Least colorful of the three
|
| 158 |
+
- **Files**: `ColorizeVideo_gen.pth`
|
| 159 |
+
|
| 160 |
+
```python
|
| 161 |
+
from deoldify.visualize import get_video_colorizer
|
| 162 |
+
video_colorizer = get_video_colorizer()
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
## Advanced Usage
|
| 166 |
+
|
| 167 |
+
### Custom Render Factor
|
| 168 |
+
|
| 169 |
+
The `render_factor` parameter controls quality vs speed:
|
| 170 |
+
|
| 171 |
+
```python
|
| 172 |
+
# Low quality, fast (good for testing)
|
| 173 |
+
result = colorizer.get_transformed_image(path="photo.jpg", render_factor=10)
|
| 174 |
+
|
| 175 |
+
# High quality, slow (best results)
|
| 176 |
+
result = colorizer.get_transformed_image(path="photo.jpg", render_factor=45)
|
| 177 |
+
|
| 178 |
+
# Recommended range: 20-40
|
| 179 |
+
```
|
| 180 |
+
|
| 181 |
+
### Using Critic Weights (Training)
|
| 182 |
+
|
| 183 |
+
If you want to continue training the models:
|
| 184 |
+
|
| 185 |
+
```python
|
| 186 |
+
from huggingface_hub import hf_hub_download
|
| 187 |
+
|
| 188 |
+
# Download both generator and critic
|
| 189 |
+
gen_path = hf_hub_download(repo_id="thookham/DeOldify", filename="ColorizeArtistic_gen.pth")
|
| 190 |
+
crit_path = hf_hub_download(repo_id="thookham/DeOldify", filename="ColorizeArtistic_crit.pth")
|
| 191 |
+
|
| 192 |
+
# Load for training (see full documentation in GitHub repo)
|
| 193 |
+
```
|
| 194 |
+
|
| 195 |
+
## Troubleshooting
|
| 196 |
+
|
| 197 |
+
### "CUDA out of memory"
|
| 198 |
+
- Reduce `render_factor`
|
| 199 |
+
- Process smaller images
|
| 200 |
+
- Close other GPU applications
|
| 201 |
+
|
| 202 |
+
### "Module 'deoldify' not found"
|
| 203 |
+
- Install the DeOldify package: Clone the repo and run `pip install -e .`
|
| 204 |
+
|
| 205 |
+
### Colors look unrealistic
|
| 206 |
+
- Try the Stable model instead of Artistic
|
| 207 |
+
- Adjust `render_factor` (try values between 20-40)
|
| 208 |
+
- Some images may not colorize well due to damage or low quality
|
| 209 |
+
|
| 210 |
+
## Additional Resources
|
| 211 |
+
|
| 212 |
+
- **GitHub Repository**: https://github.com/thookham/DeOldify
|
| 213 |
+
- **Setup Guides**:
|
| 214 |
+
- [NVIDIA GPU Setup](nvidia_setup.md)
|
| 215 |
+
- [Intel GPU Setup](intel_gpu_setup.md)
|
| 216 |
+
- **Model Weights**: All available in this HF repository
|
| 217 |
+
- **Browser Demo**: See `browser/` folder in GitHub repo
|
| 218 |
+
|
| 219 |
+
## Citation
|
| 220 |
+
|
| 221 |
+
```bibtex
|
| 222 |
+
@misc{deoldify,
|
| 223 |
+
author = {Antic, Jason},
|
| 224 |
+
title = {DeOldify},
|
| 225 |
+
year = {2019},
|
| 226 |
+
publisher = {GitHub},
|
| 227 |
+
url = {https://github.com/jantic/DeOldify}
|
| 228 |
+
}
|
| 229 |
+
```
|
VideoColorizer.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:210afc44086ef08697fdad1aeb6bd5fd526ae5b62c481cacf356fed395291b12
|
| 3 |
+
size 6339
|
VideoColorizerColab.ipynb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:598bf87dac7f678cbefc0da31e7e4c9be1d064d42e69bec39482f5509c755daa
|
| 3 |
+
size 9945
|
akbartus_tree.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"sha":"43107c240f063d559708abc7639cd9f6d844458e","url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/trees/43107c240f063d559708abc7639cd9f6d844458e","tree":[{"path":"LICENSE","mode":"100644","type":"blob","sha":"6d6cdac91b8f30bc0065d6b52437b578aff18b8b","size":1065,"url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/blobs/6d6cdac91b8f30bc0065d6b52437b578aff18b8b"},{"path":"README.md","mode":"100644","type":"blob","sha":"88035e0eaf1d82b0b21fa5e85b151573164aaee5","size":3246,"url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/blobs/88035e0eaf1d82b0b21fa5e85b151573164aaee5"},{"path":"img","mode":"040000","type":"tree","sha":"d3334306495bd32f52658b5997399a34b89d33d6","url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/trees/d3334306495bd32f52658b5997399a34b89d33d6"},{"path":"img/screenshot.jpg","mode":"100644","type":"blob","sha":"3f5d6c0f9bdc3bd5f8090ecc10d86ad7c4519a5f","size":107506,"url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/blobs/3f5d6c0f9bdc3bd5f8090ecc10d86ad7c4519a5f"},{"path":"original","mode":"040000","type":"tree","sha":"4c8d377f4859a977493cf7174755ebcf73953337","url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/trees/4c8d377f4859a977493cf7174755ebcf73953337"},{"path":"original/index.html","mode":"100644","type":"blob","sha":"da12505e7ff992903c4669556188316e9934f393","size":4281,"url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/blobs/da12505e7ff992903c4669556188316e9934f393"},{"path":"quantized","mode":"040000","type":"tree","sha":"c02b79e9adb2e6204d3724812c0e498e544fc778","url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/trees/c02b79e9adb2e6204d3724812c0e498e544fc778"},{"path":"quantized/index.html","mode":"100644","type":"blob","sha":"35582686f88fbc863208251531c9471e295cc50b","size":5855,"url":"https://api.github.com/repos/akbartus/DeOldify-on-Browser/git/blobs/35582686f88fbc863208251531c9471e295cc50b"}],"truncated":false}
|
assets.txt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ColorizeArtistic_crit.pth
|
| 2 |
+
ColorizeArtistic_gen.pth
|
| 3 |
+
ColorizeArtistic_PretrainOnly_crit.pth
|
| 4 |
+
ColorizeArtistic_PretrainOnly_gen.pth
|
| 5 |
+
ColorizeStable_crit.pth
|
| 6 |
+
ColorizeStable_gen.pth
|
| 7 |
+
ColorizeStable_PretrainOnly_crit.pth
|
| 8 |
+
ColorizeStable_PretrainOnly_gen.pth.000
|
| 9 |
+
ColorizeStable_PretrainOnly_gen.pth.001
|
| 10 |
+
ColorizeVideo_crit.pth
|
| 11 |
+
ColorizeVideo_gen.pth
|
| 12 |
+
ColorizeVideo_PretrainOnly_crit.pth
|
| 13 |
+
ColorizeVideo_PretrainOnly_gen.pth.000
|
| 14 |
+
ColorizeVideo_PretrainOnly_gen.pth.001
|
| 15 |
+
deoldify-art.onnx
|
| 16 |
+
deoldify-quant.onnx
|
browser/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DeOldify Browser Integration
|
| 2 |
+
|
| 3 |
+
This directory contains a browser-based implementation of DeOldify using ONNX Runtime Web. It allows you to run colorization models directly in your web browser without a backend server (after the model is downloaded).
|
| 4 |
+
|
| 5 |
+
## ⚠️ Important: How to Run
|
| 6 |
+
|
| 7 |
+
Due to browser security policies (CORS), **you cannot simply double-click the HTML files** to run them. You must serve them via a local HTTP server.
|
| 8 |
+
|
| 9 |
+
### Quick Start (Windows/Linux/Mac)
|
| 10 |
+
|
| 11 |
+
If you have Python installed (which is likely if you're using DeOldify), simply run:
|
| 12 |
+
|
| 13 |
+
```bash
|
| 14 |
+
# Run this command in your terminal within this directory
|
| 15 |
+
python -m http.server 8000
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
Then open your browser and visit:
|
| 19 |
+
* [http://localhost:8000](http://localhost:8000)
|
| 20 |
+
|
| 21 |
+
### Using the Helper Script (Windows)
|
| 22 |
+
|
| 23 |
+
We've provided a PowerShell script to make this easy:
|
| 24 |
+
|
| 25 |
+
1. Right-click `serve.ps1` and select "Run with PowerShell"
|
| 26 |
+
2. Or run it from the terminal: `.\serve.ps1`
|
| 27 |
+
|
| 28 |
+
## Available Models
|
| 29 |
+
|
| 30 |
+
* **Artistic Model**: High quality, vibrant colors. Larger download (~243 MB).
|
| 31 |
+
* **Quantized Model**: Faster, smaller download (~61 MB), slightly lower quality.
|
| 32 |
+
|
| 33 |
+
## Troubleshooting
|
| 34 |
+
|
| 35 |
+
**"Failed to fetch" or CORS Errors:**
|
| 36 |
+
If you see an error about CORS or "Failed to fetch" in the status log, it means you are likely trying to open the file directly (`file:///...`). Please use the HTTP server method described above.
|
| 37 |
+
|
| 38 |
+
**Memory Issues:**
|
| 39 |
+
The artistic model requires a significant amount of RAM. If the tab crashes, try closing other tabs or using the Quantized model.
|
browser/artistic.html
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8" />
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
+
<title>DeOldify Artistic (Browser)</title>
|
| 8 |
+
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js"></script>
|
| 9 |
+
<style>
|
| 10 |
+
body {
|
| 11 |
+
font-family: sans-serif;
|
| 12 |
+
max-width: 800px;
|
| 13 |
+
margin: 0 auto;
|
| 14 |
+
padding: 20px;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
h1 {
|
| 18 |
+
text-align: center;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
.container {
|
| 22 |
+
display: flex;
|
| 23 |
+
flex-direction: column;
|
| 24 |
+
align-items: center;
|
| 25 |
+
gap: 20px;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
canvas {
|
| 29 |
+
border: 1px solid #ccc;
|
| 30 |
+
max-width: 100%;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
.controls {
|
| 34 |
+
margin-bottom: 20px;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
#status {
|
| 38 |
+
font-weight: bold;
|
| 39 |
+
margin-top: 10px;
|
| 40 |
+
}
|
| 41 |
+
</style>
|
| 42 |
+
</head>
|
| 43 |
+
|
| 44 |
+
<body>
|
| 45 |
+
<h1>DeOldify Artistic Model</h1>
|
| 46 |
+
<div class="container">
|
| 47 |
+
<div class="controls">
|
| 48 |
+
<input type="file" id="imageInput" accept="image/*" />
|
| 49 |
+
</div>
|
| 50 |
+
<div id="status">Select an image to start...</div>
|
| 51 |
+
<canvas id="outputCanvas"></canvas>
|
| 52 |
+
</div>
|
| 53 |
+
|
| 54 |
+
<script>
|
| 55 |
+
const MODEL_URL = "https://huggingface.co/thookham/DeOldify-on-Browser/resolve/main/deoldify-art.onnx";
|
| 56 |
+
let session = null;
|
| 57 |
+
|
| 58 |
+
const preprocess = (input_imageData, width, height) => {
|
| 59 |
+
const floatArr = new Float32Array(width * height * 3);
|
| 60 |
+
let j = 0;
|
| 61 |
+
for (let i = 0; i < input_imageData.data.length; i += 4) {
|
| 62 |
+
// Normalize to 0-1 range as expected by DeOldify
|
| 63 |
+
floatArr[j] = input_imageData.data[i] / 255.0; // red
|
| 64 |
+
floatArr[j + 1] = input_imageData.data[i + 1] / 255.0; // green
|
| 65 |
+
floatArr[j + 2] = input_imageData.data[i + 2] / 255.0; // blue
|
| 66 |
+
j += 3;
|
| 67 |
+
}
|
| 68 |
+
return floatArr;
|
| 69 |
+
};
|
| 70 |
+
|
| 71 |
+
const postprocess = (tensor) => {
|
| 72 |
+
const channels = tensor.dims[1];
|
| 73 |
+
const height = tensor.dims[2];
|
| 74 |
+
const width = tensor.dims[3];
|
| 75 |
+
const imageData = new ImageData(width, height);
|
| 76 |
+
const data = imageData.data;
|
| 77 |
+
const tensorData = new Float32Array(tensor.data);
|
| 78 |
+
|
| 79 |
+
for (let h = 0; h < height; h++) {
|
| 80 |
+
for (let w = 0; w < width; w++) {
|
| 81 |
+
let rgb = [];
|
| 82 |
+
for (let c = 0; c < channels; c++) {
|
| 83 |
+
const tensorIndex = (c * height + h) * width + w;
|
| 84 |
+
const value = tensorData[tensorIndex];
|
| 85 |
+
// Denormalize: multiply by 255 and clamp
|
| 86 |
+
let val = value * 255.0;
|
| 87 |
+
if (val < 0) val = 0;
|
| 88 |
+
if (val > 255) val = 255;
|
| 89 |
+
rgb.push(Math.round(val));
|
| 90 |
+
}
|
| 91 |
+
data[(h * width + w) * 4] = rgb[0];
|
| 92 |
+
data[(h * width + w) * 4 + 1] = rgb[1];
|
| 93 |
+
data[(h * width + w) * 4 + 2] = rgb[2];
|
| 94 |
+
data[(h * width + w) * 4 + 3] = 255;
|
| 95 |
+
}
|
| 96 |
+
}
|
| 97 |
+
return imageData;
|
| 98 |
+
};
|
| 99 |
+
|
| 100 |
+
async function init() {
|
| 101 |
+
const status = document.getElementById('status');
|
| 102 |
+
status.innerText = "Checking cache...";
|
| 103 |
+
try {
|
| 104 |
+
let buffer;
|
| 105 |
+
const cacheName = 'deoldify-models-v1';
|
| 106 |
+
|
| 107 |
+
// Try to load from cache first
|
| 108 |
+
try {
|
| 109 |
+
const cache = await caches.open(cacheName);
|
| 110 |
+
const cachedResponse = await cache.match(MODEL_URL);
|
| 111 |
+
|
| 112 |
+
if (cachedResponse) {
|
| 113 |
+
status.innerText = "Loading model from cache...";
|
| 114 |
+
const blob = await cachedResponse.blob();
|
| 115 |
+
buffer = await blob.arrayBuffer();
|
| 116 |
+
}
|
| 117 |
+
} catch (e) {
|
| 118 |
+
console.warn("Cache API not supported or failed:", e);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
// If not in cache, download it
|
| 122 |
+
if (!buffer) {
|
| 123 |
+
status.innerText = "Downloading model from Hugging Face... 0%";
|
| 124 |
+
const response = await fetch(MODEL_URL);
|
| 125 |
+
if (!response.ok) throw new Error(`Failed to fetch model: ${response.statusText}`);
|
| 126 |
+
|
| 127 |
+
const contentLength = response.headers.get('content-length');
|
| 128 |
+
const total = contentLength ? parseInt(contentLength, 10) : 0;
|
| 129 |
+
let loaded = 0;
|
| 130 |
+
|
| 131 |
+
const reader = response.body.getReader();
|
| 132 |
+
const chunks = [];
|
| 133 |
+
|
| 134 |
+
while (true) {
|
| 135 |
+
const { done, value } = await reader.read();
|
| 136 |
+
if (done) break;
|
| 137 |
+
chunks.push(value);
|
| 138 |
+
loaded += value.length;
|
| 139 |
+
if (total) {
|
| 140 |
+
const progress = Math.round((loaded / total) * 100);
|
| 141 |
+
status.innerText = `Downloading model from Hugging Face... ${progress}%`;
|
| 142 |
+
} else {
|
| 143 |
+
status.innerText = `Downloading model from Hugging Face... ${(loaded / 1024 / 1024).toFixed(1)} MB`;
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
const blob = new Blob(chunks);
|
| 148 |
+
buffer = await blob.arrayBuffer();
|
| 149 |
+
|
| 150 |
+
// Save to cache for next time
|
| 151 |
+
try {
|
| 152 |
+
const cache = await caches.open(cacheName);
|
| 153 |
+
await cache.put(MODEL_URL, new Response(blob));
|
| 154 |
+
console.log("Model saved to cache");
|
| 155 |
+
} catch (e) {
|
| 156 |
+
console.warn("Failed to save to cache:", e);
|
| 157 |
+
}
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
status.innerText = "Initializing session...";
|
| 161 |
+
session = await ort.InferenceSession.create(buffer);
|
| 162 |
+
|
| 163 |
+
status.innerText = "Model loaded! Select an image.";
|
| 164 |
+
console.log("Session created:", session);
|
| 165 |
+
} catch (e) {
|
| 166 |
+
status.innerText = "Error loading model: " + e.message;
|
| 167 |
+
console.error(e);
|
| 168 |
+
if (e.message.includes("Failed to fetch")) {
|
| 169 |
+
status.innerHTML += "<br><br>⚠️ <b>CORS Error Detected</b>: If you are running this file directly (file://), you must use a local server.<br>Run <code>python -m http.server 8000</code> in the terminal and visit <code>http://localhost:8000/artistic.html</code>";
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
document.getElementById('imageInput').addEventListener('change', async function (e) {
|
| 175 |
+
if (!session) {
|
| 176 |
+
await init();
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
const file = e.target.files[0];
|
| 180 |
+
if (!file) return;
|
| 181 |
+
|
| 182 |
+
// Validate image type
|
| 183 |
+
if (!file.type.startsWith('image/')) {
|
| 184 |
+
alert('Please select a valid image file.');
|
| 185 |
+
return;
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
const image = new Image();
|
| 189 |
+
const objectUrl = URL.createObjectURL(file);
|
| 190 |
+
image.src = objectUrl;
|
| 191 |
+
|
| 192 |
+
image.onload = async function () {
|
| 193 |
+
document.getElementById('status').innerText = "Processing...";
|
| 194 |
+
|
| 195 |
+
// Pre-processing canvas (256x256)
|
| 196 |
+
let canvas = document.createElement("canvas");
|
| 197 |
+
const size = 256;
|
| 198 |
+
canvas.width = size;
|
| 199 |
+
canvas.height = size;
|
| 200 |
+
let ctx = canvas.getContext("2d");
|
| 201 |
+
ctx.drawImage(image, 0, 0, size, size);
|
| 202 |
+
|
| 203 |
+
const input_img = ctx.getImageData(0, 0, size, size);
|
| 204 |
+
const test = preprocess(input_img, size, size);
|
| 205 |
+
const input = new ort.Tensor(new Float32Array(test), [1, 3, size, size]);
|
| 206 |
+
|
| 207 |
+
try {
|
| 208 |
+
const result = await session.run({ "input": input });
|
| 209 |
+
// Handle potential output name differences
|
| 210 |
+
const output = result["output"] || result["out"] || Object.values(result)[0];
|
| 211 |
+
|
| 212 |
+
if (!output) throw new Error("No output tensor found in model result");
|
| 213 |
+
|
| 214 |
+
const imgdata = postprocess(output);
|
| 215 |
+
|
| 216 |
+
// Render to output canvas
|
| 217 |
+
const outCanvas = document.getElementById('outputCanvas');
|
| 218 |
+
outCanvas.width = image.width;
|
| 219 |
+
outCanvas.height = image.height;
|
| 220 |
+
const outCtx = outCanvas.getContext('2d');
|
| 221 |
+
|
| 222 |
+
// Draw 256x256 result to temp canvas
|
| 223 |
+
const tempCanvas = document.createElement('canvas');
|
| 224 |
+
tempCanvas.width = size;
|
| 225 |
+
tempCanvas.height = size;
|
| 226 |
+
tempCanvas.getContext('2d').putImageData(imgdata, 0, 0);
|
| 227 |
+
|
| 228 |
+
// Resize to original
|
| 229 |
+
outCtx.drawImage(tempCanvas, 0, 0, image.width, image.height);
|
| 230 |
+
|
| 231 |
+
document.getElementById('status').innerText = "Done!";
|
| 232 |
+
} catch (err) {
|
| 233 |
+
document.getElementById('status').innerText = "Error processing: " + err.message;
|
| 234 |
+
console.error(err);
|
| 235 |
+
} finally {
|
| 236 |
+
// Clean up memory
|
| 237 |
+
URL.revokeObjectURL(objectUrl);
|
| 238 |
+
}
|
| 239 |
+
};
|
| 240 |
+
});
|
| 241 |
+
|
| 242 |
+
// Start loading immediately
|
| 243 |
+
init();
|
| 244 |
+
</script>
|
| 245 |
+
</body>
|
| 246 |
+
|
| 247 |
+
</html>
|
browser/index.html
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8">
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 7 |
+
<title>DeOldify Browser Integration</title>
|
| 8 |
+
<style>
|
| 9 |
+
body {
|
| 10 |
+
font-family: sans-serif;
|
| 11 |
+
max-width: 600px;
|
| 12 |
+
margin: 0 auto;
|
| 13 |
+
padding: 40px;
|
| 14 |
+
text-align: center;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
h1 {
|
| 18 |
+
margin-bottom: 30px;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
.card {
|
| 22 |
+
border: 1px solid #ddd;
|
| 23 |
+
border-radius: 8px;
|
| 24 |
+
padding: 20px;
|
| 25 |
+
margin-bottom: 20px;
|
| 26 |
+
transition: transform 0.2s;
|
| 27 |
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
.card:hover {
|
| 31 |
+
transform: translateY(-2px);
|
| 32 |
+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
a {
|
| 36 |
+
text-decoration: none;
|
| 37 |
+
color: inherit;
|
| 38 |
+
display: block;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
h2 {
|
| 42 |
+
margin-top: 0;
|
| 43 |
+
color: #007bff;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
p {
|
| 47 |
+
color: #666;
|
| 48 |
+
}
|
| 49 |
+
</style>
|
| 50 |
+
</head>
|
| 51 |
+
|
| 52 |
+
<body>
|
| 53 |
+
<h1>DeOldify Browser Integration</h1>
|
| 54 |
+
<p>Run DeOldify directly in your browser using ONNX models hosted on GitHub.</p>
|
| 55 |
+
|
| 56 |
+
<a href="artistic.html">
|
| 57 |
+
<div class="card">
|
| 58 |
+
<h2>Artistic Model</h2>
|
| 59 |
+
<p>High quality, vibrant colors. (243 MB download)</p>
|
| 60 |
+
</div>
|
| 61 |
+
</a>
|
| 62 |
+
|
| 63 |
+
<a href="quantized.html">
|
| 64 |
+
<div class="card">
|
| 65 |
+
<h2>Quantized Model</h2>
|
| 66 |
+
<p>Faster, lightweight. (61 MB download)</p>
|
| 67 |
+
</div>
|
| 68 |
+
</a>
|
| 69 |
+
</body>
|
| 70 |
+
|
| 71 |
+
</html>
|
browser/quantized.html
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8" />
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
+
<title>DeOldify Quantized (Browser)</title>
|
| 8 |
+
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js"></script>
|
| 9 |
+
<style>
|
| 10 |
+
body {
|
| 11 |
+
font-family: sans-serif;
|
| 12 |
+
max-width: 800px;
|
| 13 |
+
margin: 0 auto;
|
| 14 |
+
padding: 20px;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
h1 {
|
| 18 |
+
text-align: center;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
.container {
|
| 22 |
+
display: flex;
|
| 23 |
+
flex-direction: column;
|
| 24 |
+
align-items: center;
|
| 25 |
+
gap: 20px;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
canvas {
|
| 29 |
+
border: 1px solid #ccc;
|
| 30 |
+
max-width: 100%;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
.controls {
|
| 34 |
+
margin-bottom: 20px;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
#status {
|
| 38 |
+
font-weight: bold;
|
| 39 |
+
margin-top: 10px;
|
| 40 |
+
}
|
| 41 |
+
</style>
|
| 42 |
+
</head>
|
| 43 |
+
|
| 44 |
+
<body>
|
| 45 |
+
<h1>DeOldify Quantized Model</h1>
|
| 46 |
+
<p style="text-align: center;">Faster, smaller download (61MB), slightly lower quality.</p>
|
| 47 |
+
<div class="container">
|
| 48 |
+
<div class="controls">
|
| 49 |
+
<input type="file" id="imageInput" accept="image/*" />
|
| 50 |
+
</div>
|
| 51 |
+
<div id="status">Select an image to start...</div>
|
| 52 |
+
<canvas id="outputCanvas"></canvas>
|
| 53 |
+
</div>
|
| 54 |
+
|
| 55 |
+
<script>
|
| 56 |
+
const MODEL_URL = "https://huggingface.co/thookham/DeOldify-on-Browser/resolve/main/deoldify-quant.onnx";
|
| 57 |
+
let session = null;
|
| 58 |
+
|
| 59 |
+
const preprocess = (input_imageData, width, height) => {
|
| 60 |
+
const floatArr = new Float32Array(width * height * 3);
|
| 61 |
+
let j = 0;
|
| 62 |
+
for (let i = 0; i < input_imageData.data.length; i += 4) {
|
| 63 |
+
// Normalize to 0-1 range as expected by DeOldify
|
| 64 |
+
floatArr[j] = input_imageData.data[i] / 255.0; // red
|
| 65 |
+
floatArr[j + 1] = input_imageData.data[i + 1] / 255.0; // green
|
| 66 |
+
floatArr[j + 2] = input_imageData.data[i + 2] / 255.0; // blue
|
| 67 |
+
j += 3;
|
| 68 |
+
}
|
| 69 |
+
return floatArr;
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
const postprocess = (tensor) => {
|
| 73 |
+
const channels = tensor.dims[1];
|
| 74 |
+
const height = tensor.dims[2];
|
| 75 |
+
const width = tensor.dims[3];
|
| 76 |
+
const imageData = new ImageData(width, height);
|
| 77 |
+
const data = imageData.data;
|
| 78 |
+
const tensorData = new Float32Array(tensor.data);
|
| 79 |
+
|
| 80 |
+
for (let h = 0; h < height; h++) {
|
| 81 |
+
for (let w = 0; w < width; w++) {
|
| 82 |
+
let rgb = [];
|
| 83 |
+
for (let c = 0; c < channels; c++) {
|
| 84 |
+
const tensorIndex = (c * height + h) * width + w;
|
| 85 |
+
const value = tensorData[tensorIndex];
|
| 86 |
+
// Denormalize: multiply by 255 and clamp
|
| 87 |
+
let val = value * 255.0;
|
| 88 |
+
if (val < 0) val = 0;
|
| 89 |
+
if (val > 255) val = 255;
|
| 90 |
+
rgb.push(Math.round(val));
|
| 91 |
+
}
|
| 92 |
+
data[(h * width + w) * 4] = rgb[0];
|
| 93 |
+
data[(h * width + w) * 4 + 1] = rgb[1];
|
| 94 |
+
data[(h * width + w) * 4 + 2] = rgb[2];
|
| 95 |
+
data[(h * width + w) * 4 + 3] = 255;
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
return imageData;
|
| 99 |
+
};
|
| 100 |
+
|
| 101 |
+
async function init() {
|
| 102 |
+
const status = document.getElementById('status');
|
| 103 |
+
status.innerText = "Checking cache...";
|
| 104 |
+
try {
|
| 105 |
+
let buffer;
|
| 106 |
+
const cacheName = 'deoldify-models-v1';
|
| 107 |
+
|
| 108 |
+
// Try to load from cache first
|
| 109 |
+
try {
|
| 110 |
+
const cache = await caches.open(cacheName);
|
| 111 |
+
const cachedResponse = await cache.match(MODEL_URL);
|
| 112 |
+
|
| 113 |
+
if (cachedResponse) {
|
| 114 |
+
status.innerText = "Loading model from cache...";
|
| 115 |
+
const blob = await cachedResponse.blob();
|
| 116 |
+
buffer = await blob.arrayBuffer();
|
| 117 |
+
}
|
| 118 |
+
} catch (e) {
|
| 119 |
+
console.warn("Cache API not supported or failed:", e);
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
// If not in cache, download it
|
| 123 |
+
if (!buffer) {
|
| 124 |
+
status.innerText = "Downloading model from Hugging Face... 0%";
|
| 125 |
+
const response = await fetch(MODEL_URL);
|
| 126 |
+
if (!response.ok) throw new Error(`Failed to fetch model: ${response.statusText}`);
|
| 127 |
+
|
| 128 |
+
const contentLength = response.headers.get('content-length');
|
| 129 |
+
const total = contentLength ? parseInt(contentLength, 10) : 0;
|
| 130 |
+
let loaded = 0;
|
| 131 |
+
|
| 132 |
+
const reader = response.body.getReader();
|
| 133 |
+
const chunks = [];
|
| 134 |
+
|
| 135 |
+
while (true) {
|
| 136 |
+
const { done, value } = await reader.read();
|
| 137 |
+
if (done) break;
|
| 138 |
+
chunks.push(value);
|
| 139 |
+
loaded += value.length;
|
| 140 |
+
if (total) {
|
| 141 |
+
const progress = Math.round((loaded / total) * 100);
|
| 142 |
+
status.innerText = `Downloading model from Hugging Face... ${progress}%`;
|
| 143 |
+
} else {
|
| 144 |
+
status.innerText = `Downloading model from Hugging Face... ${(loaded / 1024 / 1024).toFixed(1)} MB`;
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
const blob = new Blob(chunks);
|
| 149 |
+
buffer = await blob.arrayBuffer();
|
| 150 |
+
|
| 151 |
+
// Save to cache for next time
|
| 152 |
+
try {
|
| 153 |
+
const cache = await caches.open(cacheName);
|
| 154 |
+
await cache.put(MODEL_URL, new Response(blob));
|
| 155 |
+
console.log("Model saved to cache");
|
| 156 |
+
} catch (e) {
|
| 157 |
+
console.warn("Failed to save to cache:", e);
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
status.innerText = "Initializing session...";
|
| 162 |
+
session = await ort.InferenceSession.create(buffer);
|
| 163 |
+
|
| 164 |
+
status.innerText = "Model loaded! Select an image.";
|
| 165 |
+
console.log("Session created:", session);
|
| 166 |
+
} catch (e) {
|
| 167 |
+
status.innerText = "Error loading model: " + e.message;
|
| 168 |
+
console.error(e);
|
| 169 |
+
if (e.message.includes("Failed to fetch")) {
|
| 170 |
+
status.innerHTML += "<br><br>⚠️ <b>CORS Error Detected</b>: If you are running this file directly (file://), you must use a local server.<br>Run <code>python -m http.server 8000</code> in the terminal and visit <code>http://localhost:8000/quantized.html</code>";
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
document.getElementById('imageInput').addEventListener('change', async function (e) {
|
| 176 |
+
if (!session) {
|
| 177 |
+
await init();
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
const file = e.target.files[0];
|
| 181 |
+
if (!file) return;
|
| 182 |
+
|
| 183 |
+
// Validate image type
|
| 184 |
+
if (!file.type.startsWith('image/')) {
|
| 185 |
+
alert('Please select a valid image file.');
|
| 186 |
+
return;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
const image = new Image();
|
| 190 |
+
const objectUrl = URL.createObjectURL(file);
|
| 191 |
+
image.src = objectUrl;
|
| 192 |
+
|
| 193 |
+
image.onload = async function () {
|
| 194 |
+
document.getElementById('status').innerText = "Processing...";
|
| 195 |
+
|
| 196 |
+
// Pre-processing canvas (256x256)
|
| 197 |
+
let canvas = document.createElement("canvas");
|
| 198 |
+
const size = 256;
|
| 199 |
+
canvas.width = size;
|
| 200 |
+
canvas.height = size;
|
| 201 |
+
let ctx = canvas.getContext("2d");
|
| 202 |
+
ctx.drawImage(image, 0, 0, size, size);
|
| 203 |
+
|
| 204 |
+
const input_img = ctx.getImageData(0, 0, size, size);
|
| 205 |
+
const test = preprocess(input_img, size, size);
|
| 206 |
+
const input = new ort.Tensor(new Float32Array(test), [1, 3, size, size]);
|
| 207 |
+
|
| 208 |
+
try {
|
| 209 |
+
const result = await session.run({ "input": input });
|
| 210 |
+
// Handle potential output name differences
|
| 211 |
+
const output = result["output"] || result["out"] || Object.values(result)[0];
|
| 212 |
+
|
| 213 |
+
if (!output) throw new Error("No output tensor found in model result");
|
| 214 |
+
|
| 215 |
+
const imgdata = postprocess(output);
|
| 216 |
+
|
| 217 |
+
// Render to output canvas
|
| 218 |
+
const outCanvas = document.getElementById('outputCanvas');
|
| 219 |
+
outCanvas.width = image.width;
|
| 220 |
+
outCanvas.height = image.height;
|
| 221 |
+
const outCtx = outCanvas.getContext('2d');
|
| 222 |
+
|
| 223 |
+
// Draw 256x256 result to temp canvas
|
| 224 |
+
const tempCanvas = document.createElement('canvas');
|
| 225 |
+
tempCanvas.width = size;
|
| 226 |
+
tempCanvas.height = size;
|
| 227 |
+
tempCanvas.getContext('2d').putImageData(imgdata, 0, 0);
|
| 228 |
+
|
| 229 |
+
// Resize to original
|
| 230 |
+
outCtx.drawImage(tempCanvas, 0, 0, image.width, image.height);
|
| 231 |
+
|
| 232 |
+
document.getElementById('status').innerText = "Done!";
|
| 233 |
+
} catch (err) {
|
| 234 |
+
document.getElementById('status').innerText = "Error processing: " + err.message;
|
| 235 |
+
console.error(err);
|
| 236 |
+
} finally {
|
| 237 |
+
// Clean up memory
|
| 238 |
+
URL.revokeObjectURL(objectUrl);
|
| 239 |
+
}
|
| 240 |
+
};
|
| 241 |
+
});
|
| 242 |
+
|
| 243 |
+
// Start loading immediately
|
| 244 |
+
init();
|
| 245 |
+
</script>
|
| 246 |
+
</body>
|
| 247 |
+
|
| 248 |
+
</html>
|
browser/serve.ps1
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Simple script to serve the DeOldify project root and open the browser
|
| 2 |
+
Write-Host "Starting local server for DeOldify Browser..." -ForegroundColor Cyan
|
| 3 |
+
Write-Host "Press Ctrl+C to stop the server." -ForegroundColor Yellow
|
| 4 |
+
|
| 5 |
+
# Get the root directory (parent of the script's directory)
|
| 6 |
+
$scriptPath = $MyInvocation.MyCommand.Path
|
| 7 |
+
$browserDir = Split-Path $scriptPath
|
| 8 |
+
$rootDir = Split-Path $browserDir
|
| 9 |
+
|
| 10 |
+
# Change to root directory
|
| 11 |
+
Set-Location $rootDir
|
| 12 |
+
Write-Host "Serving from: $rootDir" -ForegroundColor Gray
|
| 13 |
+
|
| 14 |
+
# Start the server in the background
|
| 15 |
+
$process = Start-Process -FilePath "python" -ArgumentList "-m http.server 8000" -PassThru
|
| 16 |
+
|
| 17 |
+
# Wait a moment for it to start
|
| 18 |
+
Start-Sleep -Seconds 2
|
| 19 |
+
|
| 20 |
+
# Open the browser to the artistic page
|
| 21 |
+
Start-Process "http://localhost:8000/browser/artistic.html"
|
| 22 |
+
|
| 23 |
+
# Wait for the user to close the script
|
| 24 |
+
Read-Host "Server is running. Press Enter to stop server and exit..."
|
| 25 |
+
|
| 26 |
+
# Stop the server
|
| 27 |
+
Stop-Process -Id $process.Id
|
check_remote_models.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import json
|
| 3 |
+
import base64
|
| 4 |
+
import re
|
| 5 |
+
|
| 6 |
+
def check_repo_file(repo, path):
|
| 7 |
+
cmd = ["gh", "api", f"repos/{repo}/contents/{path}", "--jq", ".content"]
|
| 8 |
+
try:
|
| 9 |
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
| 10 |
+
content_b64 = result.stdout.strip()
|
| 11 |
+
content = base64.b64decode(content_b64).decode('utf-8')
|
| 12 |
+
|
| 13 |
+
print(f"--- Checking {repo}/{path} ---")
|
| 14 |
+
# Search for .onnx or .pth links
|
| 15 |
+
urls = re.findall(r'https?://[^\s"\'<>]+(?:\.onnx|\.pth)', content)
|
| 16 |
+
for url in urls:
|
| 17 |
+
print(f"Found URL: {url}")
|
| 18 |
+
|
| 19 |
+
except subprocess.CalledProcessError as e:
|
| 20 |
+
print(f"Error fetching {path}: {e}")
|
| 21 |
+
except Exception as e:
|
| 22 |
+
print(f"Error processing {path}: {e}")
|
| 23 |
+
|
| 24 |
+
repos = ["thookham/DeOldify-on-Browser", "akbartus/DeOldify-on-Browser"]
|
| 25 |
+
files = ["original/index.html", "quantized/index.html"]
|
| 26 |
+
|
| 27 |
+
for repo in repos:
|
| 28 |
+
for file in files:
|
| 29 |
+
check_repo_file(repo, file)
|
check_remote_models_v2.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import json
|
| 3 |
+
import base64
|
| 4 |
+
import re
|
| 5 |
+
|
| 6 |
+
def check_repo_file(repo, path):
|
| 7 |
+
cmd = ["gh", "api", f"repos/{repo}/contents/{path}", "--jq", ".content"]
|
| 8 |
+
try:
|
| 9 |
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
| 10 |
+
content_b64 = result.stdout.strip()
|
| 11 |
+
content = base64.b64decode(content_b64).decode('utf-8')
|
| 12 |
+
|
| 13 |
+
urls = re.findall(r'https?://[^\s"\'<>]+(?:\.onnx|\.pth)', content)
|
| 14 |
+
return urls
|
| 15 |
+
|
| 16 |
+
except Exception as e:
|
| 17 |
+
return []
|
| 18 |
+
|
| 19 |
+
repos = ["thookham/DeOldify-on-Browser"]
|
| 20 |
+
files = ["original/index.html", "quantized/index.html"]
|
| 21 |
+
|
| 22 |
+
all_urls = []
|
| 23 |
+
for repo in repos:
|
| 24 |
+
for file in files:
|
| 25 |
+
urls = check_repo_file(repo, file)
|
| 26 |
+
all_urls.extend(urls)
|
| 27 |
+
|
| 28 |
+
with open("found_urls.txt", "w") as f:
|
| 29 |
+
for url in all_urls:
|
| 30 |
+
f.write(url + "\n")
|
compare_models.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib
|
| 2 |
+
import requests
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
def get_file_hash(filepath):
|
| 6 |
+
sha256_hash = hashlib.sha256()
|
| 7 |
+
with open(filepath, "rb") as f:
|
| 8 |
+
for byte_block in iter(lambda: f.read(4096), b""):
|
| 9 |
+
sha256_hash.update(byte_block)
|
| 10 |
+
return sha256_hash.hexdigest()
|
| 11 |
+
|
| 12 |
+
def download_file(url, filename):
|
| 13 |
+
print(f"Downloading {url}...")
|
| 14 |
+
r = requests.get(url, stream=True)
|
| 15 |
+
with open(filename, 'wb') as f:
|
| 16 |
+
for chunk in r.iter_content(chunk_size=8192):
|
| 17 |
+
f.write(chunk)
|
| 18 |
+
return filename
|
| 19 |
+
|
| 20 |
+
external_urls = {
|
| 21 |
+
"glitch_art.onnx": "https://huggingface.co/thookham/DeOldify-on-Browser/resolve/main/deoldify-art.onnx",
|
| 22 |
+
"glitch_quant.onnx": "https://huggingface.co/thookham/DeOldify-on-Browser/resolve/main/deoldify-quant.onnx"
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
# Local files
|
| 26 |
+
local_files = {
|
| 27 |
+
"local_art.onnx": "models/deoldify-art.onnx",
|
| 28 |
+
"local_quant.onnx": "models/deoldify-quant.onnx"
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
print("--- Local File Hashes ---")
|
| 32 |
+
for name, path in local_files.items():
|
| 33 |
+
if os.path.exists(path):
|
| 34 |
+
print(f"{name}: {get_file_hash(path)}")
|
| 35 |
+
else:
|
| 36 |
+
print(f"{name}: File not found")
|
| 37 |
+
|
| 38 |
+
print("\n--- External File Hashes ---")
|
| 39 |
+
for name, url in external_urls.items():
|
| 40 |
+
try:
|
| 41 |
+
download_file(url, name)
|
| 42 |
+
print(f"{name}: {get_file_hash(name)}")
|
| 43 |
+
except Exception as e:
|
| 44 |
+
print(f"Error downloading {name}: {e}")
|
deoldify/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import logging
|
| 3 |
+
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
|
| 4 |
+
logging.getLogger().setLevel(logging.INFO)
|
| 5 |
+
|
| 6 |
+
from deoldify._device import _Device
|
| 7 |
+
|
| 8 |
+
device = _Device()
|
deoldify/_device.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch
|
| 3 |
+
from enum import Enum
|
| 4 |
+
from .device_id import DeviceId
|
| 5 |
+
import logging
|
| 6 |
+
|
| 7 |
+
#NOTE: This must be called first before any torch imports in order to work properly!
|
| 8 |
+
|
| 9 |
+
class DeviceException(Exception):
|
| 10 |
+
pass
|
| 11 |
+
|
| 12 |
+
class _Device:
|
| 13 |
+
def __init__(self):
|
| 14 |
+
self._current_device = DeviceId.CPU
|
| 15 |
+
self._backend = 'cpu'
|
| 16 |
+
self._init_device()
|
| 17 |
+
|
| 18 |
+
def _init_device(self):
|
| 19 |
+
# Check for Intel Extension for PyTorch
|
| 20 |
+
try:
|
| 21 |
+
import intel_extension_for_pytorch as ipex
|
| 22 |
+
if torch.xpu.is_available():
|
| 23 |
+
self._backend = 'xpu'
|
| 24 |
+
return
|
| 25 |
+
except ImportError:
|
| 26 |
+
pass
|
| 27 |
+
|
| 28 |
+
# Check for CUDA
|
| 29 |
+
if torch.cuda.is_available():
|
| 30 |
+
self._backend = 'cuda'
|
| 31 |
+
return
|
| 32 |
+
|
| 33 |
+
self._backend = 'cpu'
|
| 34 |
+
|
| 35 |
+
def is_gpu(self):
|
| 36 |
+
''' Returns `True` if the current device is GPU (CUDA or XPU), `False` otherwise. '''
|
| 37 |
+
return self.current() is not DeviceId.CPU
|
| 38 |
+
|
| 39 |
+
def current(self):
|
| 40 |
+
return self._current_device
|
| 41 |
+
|
| 42 |
+
def set(self, device:DeviceId):
|
| 43 |
+
if device == DeviceId.CPU:
|
| 44 |
+
os.environ['CUDA_VISIBLE_DEVICES']=''
|
| 45 |
+
self._current_device = DeviceId.CPU
|
| 46 |
+
else:
|
| 47 |
+
# Handle GPU selection
|
| 48 |
+
if self._backend == 'cuda':
|
| 49 |
+
os.environ['CUDA_VISIBLE_DEVICES']=str(device.value)
|
| 50 |
+
torch.backends.cudnn.benchmark=True
|
| 51 |
+
elif self._backend == 'xpu':
|
| 52 |
+
# For XPU, we might need different env vars or just rely on index
|
| 53 |
+
# Currently just setting the device ID
|
| 54 |
+
pass
|
| 55 |
+
|
| 56 |
+
self._current_device = device
|
| 57 |
+
|
| 58 |
+
return device
|
| 59 |
+
|
| 60 |
+
def get_torch_device(self):
|
| 61 |
+
if self._current_device == DeviceId.CPU:
|
| 62 |
+
return torch.device('cpu')
|
| 63 |
+
|
| 64 |
+
if self._backend == 'cuda':
|
| 65 |
+
return torch.device('cuda')
|
| 66 |
+
elif self._backend == 'xpu':
|
| 67 |
+
return torch.device('xpu')
|
| 68 |
+
|
| 69 |
+
return torch.device('cpu')
|
deoldify/augs.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
|
| 3 |
+
from fastai.vision.image import TfmPixel
|
| 4 |
+
|
| 5 |
+
# Contributed by Rani Horev. Thank you!
|
| 6 |
+
def _noisify(
|
| 7 |
+
x, pct_pixels_min: float = 0.001, pct_pixels_max: float = 0.4, noise_range: int = 30
|
| 8 |
+
):
|
| 9 |
+
if noise_range > 255 or noise_range < 0:
|
| 10 |
+
raise Exception("noise_range must be between 0 and 255, inclusively.")
|
| 11 |
+
|
| 12 |
+
h, w = x.shape[1:]
|
| 13 |
+
img_size = h * w
|
| 14 |
+
mult = 10000.0
|
| 15 |
+
pct_pixels = (
|
| 16 |
+
random.randrange(int(pct_pixels_min * mult), int(pct_pixels_max * mult)) / mult
|
| 17 |
+
)
|
| 18 |
+
noise_count = int(img_size * pct_pixels)
|
| 19 |
+
|
| 20 |
+
for ii in range(noise_count):
|
| 21 |
+
yy = random.randrange(h)
|
| 22 |
+
xx = random.randrange(w)
|
| 23 |
+
noise = random.randrange(-noise_range, noise_range) / 255.0
|
| 24 |
+
x[:, yy, xx].add_(noise)
|
| 25 |
+
|
| 26 |
+
return x
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
noisify = TfmPixel(_noisify)
|
deoldify/critics.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastai.basic_train import Learner
|
| 2 |
+
from fastai.core import *
|
| 3 |
+
from fastai.layers import NormType, conv_layer
|
| 4 |
+
from fastai.torch_core import *
|
| 5 |
+
from fastai.vision import *
|
| 6 |
+
from fastai.vision.data import ImageDataBunch
|
| 7 |
+
from fastai.vision.gan import AdaptiveLoss, accuracy_thresh_expand
|
| 8 |
+
|
| 9 |
+
_conv_args = dict(leaky=0.2, norm_type=NormType.Spectral)
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def _conv(ni: int, nf: int, ks: int = 3, stride: int = 1, **kwargs):
|
| 13 |
+
return conv_layer(ni, nf, ks=ks, stride=stride, **_conv_args, **kwargs)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def custom_gan_critic(
|
| 17 |
+
n_channels: int = 3, nf: int = 256, n_blocks: int = 3, p: int = 0.15
|
| 18 |
+
):
|
| 19 |
+
"Critic to train a `GAN`."
|
| 20 |
+
layers = [_conv(n_channels, nf, ks=4, stride=2), nn.Dropout2d(p / 2)]
|
| 21 |
+
for i in range(n_blocks):
|
| 22 |
+
layers += [
|
| 23 |
+
_conv(nf, nf, ks=3, stride=1),
|
| 24 |
+
nn.Dropout2d(p),
|
| 25 |
+
_conv(nf, nf * 2, ks=4, stride=2, self_attention=(i == 0)),
|
| 26 |
+
]
|
| 27 |
+
nf *= 2
|
| 28 |
+
layers += [
|
| 29 |
+
_conv(nf, nf, ks=3, stride=1),
|
| 30 |
+
_conv(nf, 1, ks=4, bias=False, padding=0, use_activ=False),
|
| 31 |
+
Flatten(),
|
| 32 |
+
]
|
| 33 |
+
return nn.Sequential(*layers)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def colorize_crit_learner(
|
| 37 |
+
data: ImageDataBunch,
|
| 38 |
+
loss_critic=AdaptiveLoss(nn.BCEWithLogitsLoss()),
|
| 39 |
+
nf: int = 256,
|
| 40 |
+
) -> Learner:
|
| 41 |
+
return Learner(
|
| 42 |
+
data,
|
| 43 |
+
custom_gan_critic(nf=nf),
|
| 44 |
+
metrics=accuracy_thresh_expand,
|
| 45 |
+
loss_func=loss_critic,
|
| 46 |
+
wd=1e-3,
|
| 47 |
+
)
|
deoldify/dataset.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .fastai_compat import *
|
| 2 |
+
|
| 3 |
+
# Training data loading logic is currently disabled due to FastAI 1.x deprecation.
|
| 4 |
+
# To restore training support, this module needs to be rewritten using pure PyTorch Datasets/DataLoaders.
|
| 5 |
+
|
| 6 |
+
def get_colorize_data(
|
| 7 |
+
sz: int,
|
| 8 |
+
bs: int,
|
| 9 |
+
crappy_path: Path,
|
| 10 |
+
good_path: Path,
|
| 11 |
+
random_seed: int = None,
|
| 12 |
+
keep_pct: float = 1.0,
|
| 13 |
+
num_workers: int = 8,
|
| 14 |
+
stats: tuple = None,
|
| 15 |
+
xtra_tfms=[],
|
| 16 |
+
):
|
| 17 |
+
raise NotImplementedError("Training data loading not supported in this version.")
|
| 18 |
+
|
| 19 |
+
def get_dummy_databunch():
|
| 20 |
+
return DataBunch()
|
deoldify/device_id.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import IntEnum
|
| 2 |
+
|
| 3 |
+
class DeviceId(IntEnum):
|
| 4 |
+
GPU0 = 0,
|
| 5 |
+
GPU1 = 1,
|
| 6 |
+
GPU2 = 2,
|
| 7 |
+
GPU3 = 3,
|
| 8 |
+
GPU4 = 4,
|
| 9 |
+
GPU5 = 5,
|
| 10 |
+
GPU6 = 6,
|
| 11 |
+
GPU7 = 7,
|
| 12 |
+
XPU = 98,
|
| 13 |
+
CPU = 99
|
deoldify/fastai_compat.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
return p
|
| 2 |
+
|
| 3 |
+
import torchvision.models as models
|
| 4 |
+
|
| 5 |
+
class NormType(Enum):
|
| 6 |
+
Batch = 1
|
| 7 |
+
BatchZero = 2
|
| 8 |
+
Weight = 3
|
| 9 |
+
Spectral = 4
|
| 10 |
+
Instance = 5
|
| 11 |
+
InstanceZero = 6
|
| 12 |
+
Pixel = 7
|
| 13 |
+
|
| 14 |
+
SplitFuncOrIdxList = Optional[Union[Callable, List[int]]]
|
| 15 |
+
|
| 16 |
+
def to_device(m, device):
|
| 17 |
+
return m.to(device)
|
| 18 |
+
|
| 19 |
+
def apply_init(m, init_func):
|
| 20 |
+
if hasattr(m, 'apply'):
|
| 21 |
+
m.apply(lambda x: init_func(x.weight) if hasattr(x, 'weight') and hasattr(x.weight, 'data') else None)
|
| 22 |
+
|
| 23 |
+
ImageDataBunch = DataBunch
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def camel2snake(name):
|
| 27 |
+
import re
|
| 28 |
+
_camel_re1 = re.compile('(.)([A-Z][a-z]+)')
|
| 29 |
+
_camel_re2 = re.compile('([a-z0-9])([A-Z])')
|
| 30 |
+
return _camel_re2.sub(r'\1_\2', _camel_re1.sub(r'\1_\2', name)).lower()
|
| 31 |
+
|
| 32 |
+
class SequentialEx(nn.Module):
|
| 33 |
+
"Like `nn.Sequential`, but with ModuleList semantics, and can handle `MergeLayer`."
|
| 34 |
+
def __init__(self, *layers):
|
| 35 |
+
super().__init__()
|
| 36 |
+
self.layers = nn.ModuleList(layers)
|
| 37 |
+
|
| 38 |
+
def forward(self, x):
|
| 39 |
+
res = x
|
| 40 |
+
for l in self.layers:
|
| 41 |
+
res.orig = x
|
| 42 |
+
nres = l(res)
|
| 43 |
+
# We have to remove res.orig to avoid hanging references and therefore memory leaks
|
| 44 |
+
res.orig = None
|
| 45 |
+
res = nres
|
| 46 |
+
return res
|
| 47 |
+
|
| 48 |
+
def __getitem__(self, i): return self.layers[i]
|
| 49 |
+
def append(self, l): return self.layers.append(l)
|
| 50 |
+
def extend(self, l): return self.layers.extend(l)
|
| 51 |
+
def insert(self, i, l): return self.layers.insert(i, l)
|
| 52 |
+
|
| 53 |
+
class MergeLayer(nn.Module):
|
| 54 |
+
"Merge a shortcut with the result of the module by adding them or concatenating them if `dense=True`."
|
| 55 |
+
def __init__(self, dense:bool=False):
|
| 56 |
+
super().__init__()
|
| 57 |
+
self.dense = dense
|
| 58 |
+
|
| 59 |
+
def forward(self, x):
|
| 60 |
+
return torch.cat([x, x.orig], dim=1) if self.dense else (x+x.orig)
|
| 61 |
+
|
| 62 |
+
class SigmoidRange(nn.Module):
|
| 63 |
+
"Sigmoid module with range `(low, x_max)`"
|
| 64 |
+
def __init__(self, low, high):
|
| 65 |
+
super().__init__()
|
| 66 |
+
self.low, self.high = low, high
|
| 67 |
+
|
| 68 |
+
def forward(self, x):
|
| 69 |
+
return torch.sigmoid(x) * (self.high - self.low) + self.low
|
| 70 |
+
|
| 71 |
+
def conv_layer(ni:int, nf:int, ks:int=3, stride:int=1, padding:int=None, bias:bool=None, is_1d:bool=False,
|
| 72 |
+
norm_type:Optional[str]=None, use_activ:bool=True, leaky:float=None,
|
| 73 |
+
transpose:bool=False, init:Callable=nn.init.kaiming_normal_, self_attention:bool=False):
|
| 74 |
+
"Create a sequence of convolutional (`ni` to `nf`), ReLU (if `use_activ`) and batchnorm (if `bn`) layers."
|
| 75 |
+
if padding is None: padding = (ks-1)//2 if not transpose else 0
|
| 76 |
+
bn = norm_type in ('Batch', 'BatchZero')
|
| 77 |
+
if bias is None: bias = not bn
|
| 78 |
+
conv_func = nn.ConvTranspose2d if transpose else nn.Conv1d if is_1d else nn.Conv2d
|
| 79 |
+
conv = conv_func(ni, nf, kernel_size=ks, bias=bias, stride=stride, padding=padding)
|
| 80 |
+
|
| 81 |
+
if init: init(conv.weight)
|
| 82 |
+
|
| 83 |
+
if norm_type == 'Weight': conv = weight_norm(conv)
|
| 84 |
+
elif norm_type == 'Spectral': conv = spectral_norm(conv)
|
| 85 |
+
|
| 86 |
+
layers = [conv]
|
| 87 |
+
if use_activ: layers.append(relu(leaky=leaky))
|
| 88 |
+
if bn: layers.append((nn.BatchNorm1d if is_1d else nn.BatchNorm2d)(nf))
|
| 89 |
+
if self_attention: layers.append(SelfAttention(nf))
|
| 90 |
+
return nn.Sequential(*layers)
|
| 91 |
+
|
| 92 |
+
def relu(leaky:float=None):
|
| 93 |
+
return nn.LeakyReLU(ifnone(leaky,0.1), inplace=True) if leaky is not None else nn.ReLU(inplace=True)
|
| 94 |
+
|
| 95 |
+
def batchnorm_2d(nf:int, norm_type:str='Batch'):
|
| 96 |
+
return nn.BatchNorm2d(nf)
|
| 97 |
+
|
| 98 |
+
class SelfAttention(nn.Module):
|
| 99 |
+
"Self attention layer for nd."
|
| 100 |
+
def __init__(self, n_channels:int):
|
| 101 |
+
super().__init__()
|
| 102 |
+
self.query = conv1d(n_channels, n_channels//8)
|
| 103 |
+
self.key = conv1d(n_channels, n_channels//8)
|
| 104 |
+
self.value = conv1d(n_channels, n_channels)
|
| 105 |
+
self.gamma = nn.Parameter(tensor([0.]))
|
| 106 |
+
|
| 107 |
+
def forward(self, x):
|
| 108 |
+
#Notation from https://arxiv.org/abs/1805.08318
|
| 109 |
+
size = x.size()
|
| 110 |
+
x = x.view(*size[:2],-1)
|
| 111 |
+
f,g,h = self.query(x),self.key(x),self.value(x)
|
| 112 |
+
beta = F.softmax(torch.bmm(f.transpose(1,2), g), dim=1)
|
| 113 |
+
o = self.gamma * torch.bmm(h, beta) + x
|
| 114 |
+
return o.view(*size)
|
| 115 |
+
|
| 116 |
+
def conv1d(ni:int, no:int, ks:int=1, stride:int=1, padding:int=0, bias:bool=False):
|
| 117 |
+
"Create and initialize a `nn.Conv1d` layer with spectral normalization."
|
| 118 |
+
conv = nn.Conv1d(ni, no, ks, stride=stride, padding=padding, bias=bias)
|
| 119 |
+
nn.init.kaiming_normal_(conv.weight)
|
| 120 |
+
if bias: conv.bias.data.zero_()
|
| 121 |
+
return spectral_norm(conv)
|
| 122 |
+
|
| 123 |
+
def res_block(nf, dense:bool=False, norm_type:str='Batch', bottle:bool=False, **kwargs):
|
| 124 |
+
"Resnet block of `nf` features."
|
| 125 |
+
norm2 = norm_type
|
| 126 |
+
if not dense and (norm_type=='Batch'): norm2 = 'BatchZero'
|
| 127 |
+
nf_inner = nf//2 if bottle else nf
|
| 128 |
+
return SequentialEx(conv_layer(nf, nf_inner, norm_type=norm_type, **kwargs),
|
| 129 |
+
conv_layer(nf_inner, nf, norm_type=norm2, **kwargs),
|
| 130 |
+
MergeLayer(dense))
|
| 131 |
+
|
| 132 |
+
# --- Hooks & Model Sizes ---
|
| 133 |
+
|
| 134 |
+
class Hook():
|
| 135 |
+
"Create a hook on `m` with `hook_func`."
|
| 136 |
+
def __init__(self, m:nn.Module, hook_func:Callable, is_forward:bool=True, detach:bool=True):
|
| 137 |
+
self.hook_func,self.detach,self.stored = hook_func,detach,None
|
| 138 |
+
f = m.register_forward_hook if is_forward else m.register_backward_hook
|
| 139 |
+
self.hook = f(self.hook_fn)
|
| 140 |
+
self.removed = False
|
| 141 |
+
|
| 142 |
+
def hook_fn(self, module:nn.Module, input:Tensor, output:Tensor):
|
| 143 |
+
if self.detach:
|
| 144 |
+
input = (o.detach() for o in input) if isinstance(input, tuple) else input.detach()
|
| 145 |
+
output = (o.detach() for o in output) if isinstance(output, tuple) else output.detach()
|
| 146 |
+
self.stored = self.hook_func(module, input, output)
|
| 147 |
+
|
| 148 |
+
def remove(self):
|
| 149 |
+
if not self.removed:
|
| 150 |
+
self.hook.remove()
|
| 151 |
+
self.removed = True
|
| 152 |
+
|
| 153 |
+
def __enter__(self, *args): return self
|
| 154 |
+
def __exit__(self, *args): self.remove()
|
| 155 |
+
|
| 156 |
+
class Hooks():
|
| 157 |
+
"Create several hooks on the modules in `ms` with `hook_func`."
|
| 158 |
+
def __init__(self, ms:List[nn.Module], hook_func:Callable, is_forward:bool=True, detach:bool=True):
|
| 159 |
+
self.hooks = [Hook(m, hook_func, is_forward, detach) for m in ms]
|
| 160 |
+
|
| 161 |
+
def __getitem__(self,i:int)->Hook: return self.hooks[i]
|
| 162 |
+
def __len__(self)->int: return len(self.hooks)
|
| 163 |
+
def __iter__(self): return iter(self.hooks)
|
| 164 |
+
@property
|
| 165 |
+
def stored(self): return [o.stored for o in self]
|
| 166 |
+
|
| 167 |
+
def remove(self):
|
| 168 |
+
for h in self.hooks: h.remove()
|
| 169 |
+
|
| 170 |
+
def __enter__(self, *args): return self
|
| 171 |
+
def __exit__(self, *args): self.remove()
|
| 172 |
+
|
| 173 |
+
def _hook_inner(m,i,o): return o if isinstance(o,Tensor) else o if isinstance(o,list) else list(o)
|
| 174 |
+
|
| 175 |
+
def hook_outputs(modules:List[nn.Module], detach:bool=True, grad:bool=False)->Hooks:
|
| 176 |
+
"Return `Hooks` that store activations of all `modules` in `self.stored`"
|
| 177 |
+
return Hooks(modules, _hook_inner, detach=detach, is_forward=not grad)
|
| 178 |
+
|
| 179 |
+
def dummy_eval(m:nn.Module, size:Tuple=(64,64)):
|
| 180 |
+
"Evaluate `m` on a dummy input of a certain `size`"
|
| 181 |
+
ch_in = in_channels(m)
|
| 182 |
+
x = torch.randn(1,ch_in,*size)
|
| 183 |
+
if next(m.parameters()).is_cuda: x = x.cuda()
|
| 184 |
+
return m.eval()(x)
|
| 185 |
+
|
| 186 |
+
def model_sizes(m:nn.Module, size:Tuple=(64,64)):
|
| 187 |
+
"Pass a dummy input through the model `m` to get the various sizes of activations."
|
| 188 |
+
with hook_outputs(m) as hooks:
|
| 189 |
+
dummy_eval(m, size)
|
| 190 |
+
return [o.stored.shape for o in hooks]
|
| 191 |
+
|
| 192 |
+
def in_channels(m:nn.Module) -> int:
|
| 193 |
+
"Return the shape of the first weight layer in `m`."
|
| 194 |
+
for l in m.modules():
|
| 195 |
+
if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Conv3d)):
|
| 196 |
+
return l.in_channels
|
| 197 |
+
raise Exception('No weight layer')
|
| 198 |
+
|
| 199 |
+
# --- Model Creation ---
|
| 200 |
+
|
| 201 |
+
def create_body(arch:Callable, pretrained:bool=True, cut:Optional[Union[int, Callable]]=None):
|
| 202 |
+
"Cut off the head of a typically pretrained `arch`."
|
| 203 |
+
model = arch(pretrained=pretrained)
|
| 204 |
+
# Most torchvision models have 'fc' or 'classifier' as head
|
| 205 |
+
# ResNet specific cut
|
| 206 |
+
if cut is None:
|
| 207 |
+
ll = list(enumerate(model.children()))
|
| 208 |
+
cut = next(i for i,o in reversed(ll) if has_pool_type(o))
|
| 209 |
+
|
| 210 |
+
return nn.Sequential(*list(model.children())[:cut])
|
| 211 |
+
|
| 212 |
+
def has_pool_type(m):
|
| 213 |
+
if isinstance(m, (nn.AdaptiveAvgPool2d, nn.AdaptiveMaxPool2d, nn.AvgPool2d, nn.MaxPool2d)): return True
|
| 214 |
+
return False
|
| 215 |
+
|
| 216 |
+
def cnn_config(arch):
|
| 217 |
+
"Get the metadata for `arch`."
|
| 218 |
+
# Simplified config for ResNets
|
| 219 |
+
return {'split': lambda m: (m[0][6], m[1])} # Split at layer 6 for ResNet
|
| 220 |
+
|
| 221 |
+
# --- Learner Shim ---
|
| 222 |
+
|
| 223 |
+
class Learner:
|
| 224 |
+
"Minimal Learner shim for inference."
|
| 225 |
+
def __init__(self, data, model, path=None):
|
| 226 |
+
self.data = data
|
| 227 |
+
self.model = model
|
| 228 |
+
self.path = path
|
| 229 |
+
|
| 230 |
+
# Use deoldify.device to get the correct device (CUDA/XPU/CPU)
|
| 231 |
+
from deoldify import device as device_settings
|
| 232 |
+
self.device = device_settings.get_torch_device()
|
| 233 |
+
|
| 234 |
+
self.model.to(self.device)
|
| 235 |
+
|
| 236 |
+
def load(self, name):
|
| 237 |
+
# Load state dict
|
| 238 |
+
if self.path:
|
| 239 |
+
path = self.path / 'models' / f'{name}.pth'
|
| 240 |
+
else:
|
| 241 |
+
path = f'models/{name}.pth'
|
| 242 |
+
|
| 243 |
+
# Handle map_location
|
| 244 |
+
state = torch.load(path, map_location=self.device)
|
| 245 |
+
if 'model' in state: state = state['model']
|
| 246 |
+
self.model.load_state_dict(state, strict=True)
|
| 247 |
+
|
| 248 |
+
def split(self, split_on):
|
| 249 |
+
pass # Not needed for inference
|
| 250 |
+
|
| 251 |
+
def freeze(self):
|
| 252 |
+
for p in self.model.parameters(): p.requires_grad = False
|
| 253 |
+
|
| 254 |
+
class DataBunch:
|
| 255 |
+
"Minimal DataBunch shim."
|
| 256 |
+
def __init__(self, c=3, device=None):
|
| 257 |
+
self.c = c
|
| 258 |
+
if device:
|
| 259 |
+
self.device = device
|
| 260 |
+
else:
|
| 261 |
+
from deoldify import device as device_settings
|
| 262 |
+
self.device = device_settings.get_torch_device()
|
| 263 |
+
|
| 264 |
+
def get_dummy_databunch():
|
| 265 |
+
return DataBunch()
|
| 266 |
+
|
| 267 |
+
def tensor(x, *args, **kwargs):
|
| 268 |
+
return torch.tensor(x, *args, **kwargs)
|