Instructions to use HandEdit/HandEdit-LoRA with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use HandEdit/HandEdit-LoRA with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Simplify repository
Browse files- README.md +19 -55
- SANITIZATION.md +0 -14
- checkpoints.zip +0 -3
- docs/INFERENCE.md +0 -132
- requirements.txt +0 -14
- scripts/download_weights.py +0 -91
- scripts/verify_weights.py +0 -56
- weights_manifest.json +0 -61
README.md
CHANGED
|
@@ -4,89 +4,53 @@ tags:
|
|
| 4 |
- image-editing
|
| 5 |
- lora
|
| 6 |
- robotics
|
| 7 |
-
- hand-editing
|
| 8 |
-
base_model:
|
| 9 |
-
- meituan-longcat/LongCat-Image-Edit
|
| 10 |
-
- Shitao/OmniGen-v1
|
| 11 |
-
- black-forest-labs/FLUX.2-klein-base-4B
|
| 12 |
-
- stepfun-ai/Step1X-Edit
|
| 13 |
---
|
| 14 |
|
| 15 |
# HandEdit LoRA
|
| 16 |
|
| 17 |
-
|
| 18 |
-
|
|
|
|
| 19 |
|
| 20 |
-
|
| 21 |
-
contains an input image with a real human hand interacting with an object and a
|
| 22 |
-
corresponding target image in which only the hand is replaced by an Inspire
|
| 23 |
-
robotic hand. The training instruction asks the model to preserve the original
|
| 24 |
-
wrist pose, finger configuration, grasp relation, object contact points,
|
| 25 |
-
interaction object, background, lighting, and camera viewpoint as closely as
|
| 26 |
-
possible.
|
| 27 |
-
|
| 28 |
-
Only LoRA parameters are released; the full base-model weights are not
|
| 29 |
-
redistributed.
|
| 30 |
|
| 31 |
## Models
|
| 32 |
|
| 33 |
-
|
|
| 34 |
| --- | --- | --- |
|
| 35 |
-
| LongCat-Image-Edit |
|
| 36 |
-
| OmniGen-v1 |
|
| 37 |
-
| FLUX.2 Klein Base 4B |
|
| 38 |
-
| Step1X-Edit |
|
| 39 |
|
| 40 |
## Download
|
| 41 |
|
| 42 |
-
**[Download all four sanitized LoRA checkpoints](https://huggingface.co/HandEdit/HandEdit-LoRA/resolve/main/checkpoints.zip?download=true)**
|
| 43 |
-
|
| 44 |
-
Or download and verify them from the command line:
|
| 45 |
-
|
| 46 |
```bash
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
```
|
| 51 |
|
| 52 |
-
The published ZIP and individual adapter files are hosted in
|
| 53 |
-
[`HandEdit/HandEdit-LoRA`](https://huggingface.co/HandEdit/HandEdit-LoRA).
|
| 54 |
-
|
| 55 |
## Inference
|
| 56 |
|
| 57 |
-
|
| 58 |
-
[`docs/INFERENCE.md`](docs/INFERENCE.md). The shortest examples are:
|
| 59 |
|
| 60 |
```bash
|
| 61 |
-
# LongCat-Image-Edit
|
| 62 |
python scripts/infer_longcat_lora.py \
|
| 63 |
-
--input_dir ./
|
| 64 |
|
| 65 |
-
# OmniGen-v1
|
| 66 |
python scripts/infer_omnigen_lora.py \
|
| 67 |
-
--input_dir ./
|
| 68 |
|
| 69 |
-
# FLUX.2 Klein Base 4B
|
| 70 |
python scripts/infer_flux2_lora.py \
|
| 71 |
-
--input_dir ./
|
| 72 |
|
| 73 |
-
# Step1X-Edit
|
| 74 |
python scripts/infer_step1x_lora.py \
|
| 75 |
--repo_dir ./third_party/Step1X-Edit \
|
| 76 |
--model_dir ./weights/Step1X-Edit \
|
| 77 |
-
--input_dir ./
|
| 78 |
--quantized --offload
|
| 79 |
```
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
The public weights are sanitized copies. Training-data identifiers, dataset
|
| 84 |
-
sizes, local paths, author fields, timestamps, session information, and other
|
| 85 |
-
training-process metadata were removed without changing tensor bytes. See
|
| 86 |
-
[`SANITIZATION.md`](SANITIZATION.md) and `weights_manifest.json`.
|
| 87 |
-
|
| 88 |
-
## Base-model licenses
|
| 89 |
-
|
| 90 |
-
Users must follow the license and access terms of each official base model.
|
| 91 |
-
This repository does not redistribute the four base models.
|
| 92 |
-
|
|
|
|
| 4 |
- image-editing
|
| 5 |
- lora
|
| 6 |
- robotics
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
---
|
| 8 |
|
| 9 |
# HandEdit LoRA
|
| 10 |
|
| 11 |
+
LoRA checkpoints for replacing human hands with Inspire robot hands while
|
| 12 |
+
preserving the original pose, object interaction, background, lighting, and
|
| 13 |
+
camera view.
|
| 14 |
|
| 15 |
+
The adapters were trained on 20K+ aligned image-editing pairs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
## Models
|
| 18 |
|
| 19 |
+
| Model | Base model | Checkpoint |
|
| 20 |
| --- | --- | --- |
|
| 21 |
+
| LongCat-Image-Edit | `meituan-longcat/LongCat-Image-Edit` | `checkpoints/longcat/` |
|
| 22 |
+
| OmniGen-v1 | `Shitao/OmniGen-v1` | `checkpoints/omnigen/` |
|
| 23 |
+
| FLUX.2 Klein Base 4B | `black-forest-labs/FLUX.2-klein-base-4B` | `checkpoints/flux2/` |
|
| 24 |
+
| Step1X-Edit | `stepfun-ai/Step1X-Edit` | `checkpoints/step1x/` |
|
| 25 |
|
| 26 |
## Download
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
```bash
|
| 29 |
+
hf download HandEdit/HandEdit-LoRA \
|
| 30 |
+
--include "checkpoints/**" \
|
| 31 |
+
--local-dir .
|
| 32 |
```
|
| 33 |
|
|
|
|
|
|
|
|
|
|
| 34 |
## Inference
|
| 35 |
|
| 36 |
+
Run from the repository root:
|
|
|
|
| 37 |
|
| 38 |
```bash
|
|
|
|
| 39 |
python scripts/infer_longcat_lora.py \
|
| 40 |
+
--input_dir ./input --output_dir ./output/longcat
|
| 41 |
|
|
|
|
| 42 |
python scripts/infer_omnigen_lora.py \
|
| 43 |
+
--input_dir ./input --output_dir ./output/omnigen
|
| 44 |
|
|
|
|
| 45 |
python scripts/infer_flux2_lora.py \
|
| 46 |
+
--input_dir ./input --output_dir ./output/flux2
|
| 47 |
|
|
|
|
| 48 |
python scripts/infer_step1x_lora.py \
|
| 49 |
--repo_dir ./third_party/Step1X-Edit \
|
| 50 |
--model_dir ./weights/Step1X-Edit \
|
| 51 |
+
--input_dir ./input --output_dir ./output/step1x \
|
| 52 |
--quantized --offload
|
| 53 |
```
|
| 54 |
|
| 55 |
+
Only the LoRA adapters are included. Download the corresponding base models
|
| 56 |
+
from their official repositories.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SANITIZATION.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
| 1 |
-
# Release sanitization
|
| 2 |
-
|
| 3 |
-
The public checkpoint files are sanitized copies, not the original training
|
| 4 |
-
artifacts.
|
| 5 |
-
|
| 6 |
-
- Optional SafeTensors metadata was removed from all four adapters.
|
| 7 |
-
- Published SafeTensors headers retain only `{"format": "pt"}`.
|
| 8 |
-
- PEFT JSON files contain only adapter architecture and loading parameters.
|
| 9 |
-
- Dataset identifiers, dataset sizes, local paths, timestamps, author fields,
|
| 10 |
-
host/session information, and training-process metadata are not published.
|
| 11 |
-
- Tensor names, shapes, data types, offsets, and tensor data bytes were preserved.
|
| 12 |
-
|
| 13 |
-
`weights_manifest.json` records checksums for the sanitized release files.
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
checkpoints.zip
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:9e89032b37d439205e940821f82735c790a35e5c32b4813ab985fb5ee0fdcad2
|
| 3 |
-
size 621076920
|
|
|
|
|
|
|
|
|
|
|
|
docs/INFERENCE.md
DELETED
|
@@ -1,132 +0,0 @@
|
|
| 1 |
-
# Inference
|
| 2 |
-
|
| 3 |
-
Run commands from the repository root. The four upstream projects do not
|
| 4 |
-
necessarily share one dependency set, so separate virtual environments are
|
| 5 |
-
recommended.
|
| 6 |
-
|
| 7 |
-
## 1. Download the HandEdit adapters
|
| 8 |
-
|
| 9 |
-
Download and extract all four sanitized LoRA adapters:
|
| 10 |
-
|
| 11 |
-
```bash
|
| 12 |
-
python scripts/download_weights.py
|
| 13 |
-
```
|
| 14 |
-
|
| 15 |
-
You can verify an existing local copy with:
|
| 16 |
-
|
| 17 |
-
```bash
|
| 18 |
-
python scripts/verify_weights.py
|
| 19 |
-
```
|
| 20 |
-
|
| 21 |
-
The base models are not bundled. Download them from their official projects and
|
| 22 |
-
follow the corresponding licenses and access requirements.
|
| 23 |
-
|
| 24 |
-
## 2. LongCat-Image-Edit
|
| 25 |
-
|
| 26 |
-
Install the shared dependencies:
|
| 27 |
-
|
| 28 |
-
```bash
|
| 29 |
-
pip install -r requirements.txt
|
| 30 |
-
```
|
| 31 |
-
|
| 32 |
-
Run batch inference:
|
| 33 |
-
|
| 34 |
-
```bash
|
| 35 |
-
python scripts/infer_longcat_lora.py \
|
| 36 |
-
--input_dir ./examples/input \
|
| 37 |
-
--output_dir ./outputs/longcat \
|
| 38 |
-
--skip_existing
|
| 39 |
-
```
|
| 40 |
-
|
| 41 |
-
The default base model is `meituan-longcat/LongCat-Image-Edit`. Use `--base`
|
| 42 |
-
to point to a local model directory, and add `--local_files_only` for an
|
| 43 |
-
offline cache.
|
| 44 |
-
|
| 45 |
-
## 3. OmniGen-v1
|
| 46 |
-
|
| 47 |
-
Install the official OmniGen repository in its own environment:
|
| 48 |
-
|
| 49 |
-
```bash
|
| 50 |
-
git clone https://github.com/VectorSpaceLab/OmniGen.git third_party/OmniGen
|
| 51 |
-
pip install -e third_party/OmniGen
|
| 52 |
-
pip install peft pillow
|
| 53 |
-
```
|
| 54 |
-
|
| 55 |
-
Run:
|
| 56 |
-
|
| 57 |
-
```bash
|
| 58 |
-
python scripts/infer_omnigen_lora.py \
|
| 59 |
-
--input_dir ./examples/input \
|
| 60 |
-
--output_dir ./outputs/omnigen \
|
| 61 |
-
--offload_model \
|
| 62 |
-
--skip_existing
|
| 63 |
-
```
|
| 64 |
-
|
| 65 |
-
The default base model is `Shitao/OmniGen-v1`.
|
| 66 |
-
|
| 67 |
-
## 4. FLUX.2 Klein Base 4B
|
| 68 |
-
|
| 69 |
-
Install the shared dependencies:
|
| 70 |
-
|
| 71 |
-
```bash
|
| 72 |
-
pip install -r requirements.txt
|
| 73 |
-
```
|
| 74 |
-
|
| 75 |
-
Run:
|
| 76 |
-
|
| 77 |
-
```bash
|
| 78 |
-
python scripts/infer_flux2_lora.py \
|
| 79 |
-
--input_dir ./examples/input \
|
| 80 |
-
--output_dir ./outputs/flux2 \
|
| 81 |
-
--skip_existing
|
| 82 |
-
```
|
| 83 |
-
|
| 84 |
-
The default base model is
|
| 85 |
-
`black-forest-labs/FLUX.2-klein-base-4B`. The script uses model CPU offload by
|
| 86 |
-
default; select `--offload sequential` for lower VRAM or `--offload none` for
|
| 87 |
-
maximum speed on a sufficiently large GPU.
|
| 88 |
-
|
| 89 |
-
## 5. Step1X-Edit
|
| 90 |
-
|
| 91 |
-
Clone and install the official repository in its own environment:
|
| 92 |
-
|
| 93 |
-
```bash
|
| 94 |
-
git clone https://github.com/stepfun-ai/Step1X-Edit.git third_party/Step1X-Edit
|
| 95 |
-
pip install -r third_party/Step1X-Edit/requirements.txt
|
| 96 |
-
```
|
| 97 |
-
|
| 98 |
-
Prepare the official base-model directory expected by Step1X:
|
| 99 |
-
|
| 100 |
-
```text
|
| 101 |
-
weights/Step1X-Edit/
|
| 102 |
-
├── Qwen2.5-VL-7B-Instruct/
|
| 103 |
-
├── step1x-edit-i1258.safetensors
|
| 104 |
-
└── vae.safetensors
|
| 105 |
-
```
|
| 106 |
-
|
| 107 |
-
Run:
|
| 108 |
-
|
| 109 |
-
```bash
|
| 110 |
-
python scripts/infer_step1x_lora.py \
|
| 111 |
-
--repo_dir ./third_party/Step1X-Edit \
|
| 112 |
-
--model_dir ./weights/Step1X-Edit \
|
| 113 |
-
--input_dir ./examples/input \
|
| 114 |
-
--output_dir ./outputs/step1x \
|
| 115 |
-
--version v1.0 \
|
| 116 |
-
--quantized \
|
| 117 |
-
--offload \
|
| 118 |
-
--skip_existing
|
| 119 |
-
```
|
| 120 |
-
|
| 121 |
-
## Shared edit instruction
|
| 122 |
-
|
| 123 |
-
The scripts use the following default instruction:
|
| 124 |
-
|
| 125 |
-
> Edit only the human hand region. Replace the human hand with a realistic
|
| 126 |
-
> Inspire robotic hand with correct robotic finger structure and joints.
|
| 127 |
-
> Preserve the original wrist pose, palm orientation, finger articulation,
|
| 128 |
-
> grasp geometry, and contact points with the object. Keep the object,
|
| 129 |
-
> background, lighting, camera viewpoint, and all non-hand regions unchanged.
|
| 130 |
-
|
| 131 |
-
Override it with `--prompt` when needed.
|
| 132 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
DELETED
|
@@ -1,14 +0,0 @@
|
|
| 1 |
-
# Shared runtime for LongCat-Image-Edit and FLUX.2 Klein.
|
| 2 |
-
# OmniGen and Step1X additionally require their official repositories;
|
| 3 |
-
# see docs/INFERENCE.md.
|
| 4 |
-
accelerate>=1.2
|
| 5 |
-
huggingface_hub>=0.28
|
| 6 |
-
numpy>=1.24
|
| 7 |
-
peft>=0.18.0
|
| 8 |
-
pillow>=10.0
|
| 9 |
-
safetensors>=0.4
|
| 10 |
-
torch>=2.5
|
| 11 |
-
torchvision>=0.20
|
| 12 |
-
transformers>=4.57
|
| 13 |
-
git+https://github.com/huggingface/diffusers.git
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scripts/download_weights.py
DELETED
|
@@ -1,91 +0,0 @@
|
|
| 1 |
-
#!/usr/bin/env python3
|
| 2 |
-
"""Download and safely extract the published HandEdit LoRA archive."""
|
| 3 |
-
|
| 4 |
-
from __future__ import annotations
|
| 5 |
-
|
| 6 |
-
import argparse
|
| 7 |
-
import hashlib
|
| 8 |
-
import json
|
| 9 |
-
import shutil
|
| 10 |
-
import zipfile
|
| 11 |
-
from pathlib import Path
|
| 12 |
-
|
| 13 |
-
from huggingface_hub import hf_hub_download
|
| 14 |
-
|
| 15 |
-
DEFAULT_REPO_ID = "HandEdit/HandEdit-LoRA"
|
| 16 |
-
ARCHIVE_NAME = "checkpoints.zip"
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
def sha256(path: Path) -> str:
|
| 20 |
-
digest = hashlib.sha256()
|
| 21 |
-
with path.open("rb") as handle:
|
| 22 |
-
for chunk in iter(lambda: handle.read(8 * 1024 * 1024), b""):
|
| 23 |
-
digest.update(chunk)
|
| 24 |
-
return digest.hexdigest()
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
def safe_extract(archive: Path, destination: Path) -> None:
|
| 28 |
-
root = destination.resolve()
|
| 29 |
-
with zipfile.ZipFile(archive) as bundle:
|
| 30 |
-
for member in bundle.infolist():
|
| 31 |
-
target = (root / member.filename).resolve()
|
| 32 |
-
if target != root and root not in target.parents:
|
| 33 |
-
raise RuntimeError(f"Unsafe archive member: {member.filename}")
|
| 34 |
-
bundle.extractall(root)
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def main() -> None:
|
| 38 |
-
parser = argparse.ArgumentParser(
|
| 39 |
-
description="Download the sanitized HandEdit LoRA checkpoints."
|
| 40 |
-
)
|
| 41 |
-
parser.add_argument("--repo-id", default=DEFAULT_REPO_ID)
|
| 42 |
-
parser.add_argument(
|
| 43 |
-
"--output-dir",
|
| 44 |
-
type=Path,
|
| 45 |
-
default=Path("."),
|
| 46 |
-
help="Repository root where checkpoints/ will be extracted.",
|
| 47 |
-
)
|
| 48 |
-
parser.add_argument(
|
| 49 |
-
"--keep-archive",
|
| 50 |
-
action="store_true",
|
| 51 |
-
help="Keep checkpoints.zip after successful extraction.",
|
| 52 |
-
)
|
| 53 |
-
args = parser.parse_args()
|
| 54 |
-
|
| 55 |
-
output_dir = args.output_dir.expanduser().resolve()
|
| 56 |
-
output_dir.mkdir(parents=True, exist_ok=True)
|
| 57 |
-
archive = Path(
|
| 58 |
-
hf_hub_download(
|
| 59 |
-
repo_id=args.repo_id,
|
| 60 |
-
filename=ARCHIVE_NAME,
|
| 61 |
-
repo_type="model",
|
| 62 |
-
local_dir=output_dir,
|
| 63 |
-
)
|
| 64 |
-
)
|
| 65 |
-
|
| 66 |
-
manifest_path = Path(
|
| 67 |
-
hf_hub_download(
|
| 68 |
-
repo_id=args.repo_id,
|
| 69 |
-
filename="weights_manifest.json",
|
| 70 |
-
repo_type="model",
|
| 71 |
-
local_dir=output_dir,
|
| 72 |
-
)
|
| 73 |
-
)
|
| 74 |
-
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
| 75 |
-
expected = manifest["archive"]["sha256"]
|
| 76 |
-
actual = sha256(archive)
|
| 77 |
-
if actual != expected:
|
| 78 |
-
raise RuntimeError(
|
| 79 |
-
f"Archive checksum mismatch: expected {expected}, received {actual}"
|
| 80 |
-
)
|
| 81 |
-
|
| 82 |
-
safe_extract(archive, output_dir)
|
| 83 |
-
print(f"[OK] Extracted sanitized weights to: {output_dir / 'checkpoints'}")
|
| 84 |
-
if not args.keep_archive:
|
| 85 |
-
archive.unlink()
|
| 86 |
-
print(f"[OK] Removed downloaded archive: {archive}")
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
if __name__ == "__main__":
|
| 90 |
-
main()
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scripts/verify_weights.py
DELETED
|
@@ -1,56 +0,0 @@
|
|
| 1 |
-
#!/usr/bin/env python3
|
| 2 |
-
"""Verify local sanitized LoRA files against weights_manifest.json."""
|
| 3 |
-
|
| 4 |
-
from __future__ import annotations
|
| 5 |
-
|
| 6 |
-
import argparse
|
| 7 |
-
import hashlib
|
| 8 |
-
import json
|
| 9 |
-
from pathlib import Path
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
def sha256(path: Path) -> str:
|
| 13 |
-
digest = hashlib.sha256()
|
| 14 |
-
with path.open("rb") as handle:
|
| 15 |
-
for chunk in iter(lambda: handle.read(8 * 1024 * 1024), b""):
|
| 16 |
-
digest.update(chunk)
|
| 17 |
-
return digest.hexdigest()
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
def main() -> None:
|
| 21 |
-
parser = argparse.ArgumentParser(description="Verify HandEdit LoRA checkpoints.")
|
| 22 |
-
parser.add_argument(
|
| 23 |
-
"--root",
|
| 24 |
-
type=Path,
|
| 25 |
-
default=Path("."),
|
| 26 |
-
help="Repository root containing weights_manifest.json and checkpoints/.",
|
| 27 |
-
)
|
| 28 |
-
args = parser.parse_args()
|
| 29 |
-
|
| 30 |
-
root = args.root.expanduser().resolve()
|
| 31 |
-
manifest = json.loads(
|
| 32 |
-
(root / "weights_manifest.json").read_text(encoding="utf-8")
|
| 33 |
-
)
|
| 34 |
-
failures = []
|
| 35 |
-
for adapter in manifest["adapters"].values():
|
| 36 |
-
for item in adapter["files"]:
|
| 37 |
-
path = root / item["path"]
|
| 38 |
-
if not path.is_file():
|
| 39 |
-
failures.append(f"missing: {item['path']}")
|
| 40 |
-
continue
|
| 41 |
-
if path.stat().st_size != item["size_bytes"]:
|
| 42 |
-
failures.append(f"size mismatch: {item['path']}")
|
| 43 |
-
continue
|
| 44 |
-
if sha256(path) != item["sha256"]:
|
| 45 |
-
failures.append(f"SHA-256 mismatch: {item['path']}")
|
| 46 |
-
continue
|
| 47 |
-
print(f"[OK] {item['path']}")
|
| 48 |
-
|
| 49 |
-
if failures:
|
| 50 |
-
raise SystemExit("\n".join(failures))
|
| 51 |
-
print("[DONE] All sanitized LoRA files passed verification.")
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
if __name__ == "__main__":
|
| 55 |
-
main()
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weights_manifest.json
DELETED
|
@@ -1,61 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"repo_id": "HandEdit/HandEdit-LoRA",
|
| 3 |
-
"release_type": "sanitized_lora_adapters",
|
| 4 |
-
"archive": {
|
| 5 |
-
"path": "checkpoints.zip",
|
| 6 |
-
"size_bytes": 621076920,
|
| 7 |
-
"sha256": "9e89032b37d439205e940821f82735c790a35e5c32b4813ab985fb5ee0fdcad2"
|
| 8 |
-
},
|
| 9 |
-
"adapters": {
|
| 10 |
-
"longcat": {
|
| 11 |
-
"base_model": "meituan-longcat/LongCat-Image-Edit",
|
| 12 |
-
"files": [
|
| 13 |
-
{
|
| 14 |
-
"path": "checkpoints/longcat/adapter_config.json",
|
| 15 |
-
"size_bytes": 530,
|
| 16 |
-
"sha256": "9ec4fbd1d7c3c3d9c6eef9cbee0cadf0c1fb1ce4874fd7e0252d666bd1eb8e9a"
|
| 17 |
-
},
|
| 18 |
-
{
|
| 19 |
-
"path": "checkpoints/longcat/adapter_model.safetensors",
|
| 20 |
-
"size_bytes": 94421944,
|
| 21 |
-
"sha256": "2391face660c6e5dd5439553d96f89059c8bfa5160af89778455cf9bf8568a5e"
|
| 22 |
-
}
|
| 23 |
-
]
|
| 24 |
-
},
|
| 25 |
-
"omnigen": {
|
| 26 |
-
"base_model": "Shitao/OmniGen-v1",
|
| 27 |
-
"files": [
|
| 28 |
-
{
|
| 29 |
-
"path": "checkpoints/omnigen/adapter_config.json",
|
| 30 |
-
"size_bytes": 307,
|
| 31 |
-
"sha256": "7a285bafa03c63d6414a098f76b737fa3fb143f7257a6edf0ad0442cc412cbcc"
|
| 32 |
-
},
|
| 33 |
-
{
|
| 34 |
-
"path": "checkpoints/omnigen/adapter_model.safetensors",
|
| 35 |
-
"size_bytes": 18891496,
|
| 36 |
-
"sha256": "6863295d2829c25eeed85eb175d5d21ee5867b2536023124d9f1cd2dfce9b971"
|
| 37 |
-
}
|
| 38 |
-
]
|
| 39 |
-
},
|
| 40 |
-
"flux2": {
|
| 41 |
-
"base_model": "black-forest-labs/FLUX.2-klein-base-4B",
|
| 42 |
-
"files": [
|
| 43 |
-
{
|
| 44 |
-
"path": "checkpoints/flux2/handedit_flux2_klein4b_lora.safetensors",
|
| 45 |
-
"size_bytes": 369643968,
|
| 46 |
-
"sha256": "11a9d65f8b53a1f1de08d5bcf02c181ebc122ae79661367bdad3b5fddeac591a"
|
| 47 |
-
}
|
| 48 |
-
]
|
| 49 |
-
},
|
| 50 |
-
"step1x": {
|
| 51 |
-
"base_model": "stepfun-ai/Step1X-Edit",
|
| 52 |
-
"files": [
|
| 53 |
-
{
|
| 54 |
-
"path": "checkpoints/step1x/inspire_step1x_r32_a16_res512.safetensors",
|
| 55 |
-
"size_bytes": 306426744,
|
| 56 |
-
"sha256": "e32ef656e023b0cc503ab0a24f645a3e99ba32ce8cae3dbd0eba221b988c1156"
|
| 57 |
-
}
|
| 58 |
-
]
|
| 59 |
-
}
|
| 60 |
-
}
|
| 61 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|