HandEdit commited on
Commit
7b221ac
·
verified ·
1 Parent(s): ce47bc4

Simplify repository

Browse files
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
- HandEdit provides parameter-efficient LoRA adapters that specialize four
18
- open-source image-editing backbones for human-to-robot-hand replacement.
 
19
 
20
- We build more than 20K aligned training pairs from the HandEdit data. Each pair
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
- | Adapter | Official base model | Local checkpoint |
34
  | --- | --- | --- |
35
- | LongCat-Image-Edit | [`meituan-longcat/LongCat-Image-Edit`](https://huggingface.co/meituan-longcat/LongCat-Image-Edit) | `checkpoints/longcat/` |
36
- | OmniGen-v1 | [`Shitao/OmniGen-v1`](https://huggingface.co/Shitao/OmniGen-v1) | `checkpoints/omnigen/` |
37
- | FLUX.2 Klein Base 4B | [`black-forest-labs/FLUX.2-klein-base-4B`](https://huggingface.co/black-forest-labs/FLUX.2-klein-base-4B) | `checkpoints/flux2/handedit_flux2_klein4b_lora.safetensors` |
38
- | Step1X-Edit | [`stepfun-ai/Step1X-Edit`](https://huggingface.co/stepfun-ai/Step1X-Edit) | `checkpoints/step1x/inspire_step1x_r32_a16_res512.safetensors` |
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
- pip install huggingface_hub
48
- python scripts/download_weights.py
49
- python scripts/verify_weights.py
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
- Detailed environment setup and commands are in
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 ./examples/input --output_dir ./outputs/longcat
64
 
65
- # OmniGen-v1
66
  python scripts/infer_omnigen_lora.py \
67
- --input_dir ./examples/input --output_dir ./outputs/omnigen
68
 
69
- # FLUX.2 Klein Base 4B
70
  python scripts/infer_flux2_lora.py \
71
- --input_dir ./examples/input --output_dir ./outputs/flux2
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 ./examples/input --output_dir ./outputs/step1x \
78
  --quantized --offload
79
  ```
80
 
81
- ## Release hygiene
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
- }