File size: 13,478 Bytes
931e0eb
ad7badd
 
 
931e0eb
ad7badd
 
 
 
 
 
 
 
 
 
 
 
 
6515e9a
931e0eb
ad7badd
 
 
6515e9a
931e0eb
ad7badd
 
6515e9a
 
 
 
 
 
 
 
931e0eb
6515e9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931e0eb
6515e9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931e0eb
ad7badd
931e0eb
ad7badd
6515e9a
 
 
931e0eb
 
6515e9a
931e0eb
6515e9a
931e0eb
ad7badd
 
 
6515e9a
931e0eb
 
ad7badd
 
 
 
 
6515e9a
ad7badd
 
 
6515e9a
ad7badd
 
6515e9a
 
 
 
ad7badd
6515e9a
ad7badd
 
 
 
 
 
6515e9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931e0eb
ad7badd
6515e9a
931e0eb
 
ad7badd
6515e9a
ad7badd
6515e9a
931e0eb
6515e9a
 
ad7badd
6515e9a
ad7badd
6515e9a
ad7badd
 
 
 
 
 
 
 
 
 
6515e9a
ad7badd
6515e9a
931e0eb
 
 
6515e9a
 
ad7badd
931e0eb
 
 
 
 
 
 
ad7badd
 
6515e9a
ad7badd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6515e9a
 
ad7badd
 
6515e9a
ad7badd
6515e9a
 
 
931e0eb
6515e9a
ad7badd
6515e9a
ad7badd
 
 
6515e9a
 
 
 
 
 
ad7badd
6515e9a
 
 
 
 
 
 
 
 
 
 
ad7badd
 
 
 
 
 
 
6515e9a
ad7badd
 
6515e9a
ad7badd
6515e9a
 
 
 
 
 
ad7badd
931e0eb
 
 
 
 
 
 
ad7badd
 
6515e9a
ad7badd
6515e9a
 
931e0eb
 
ad7badd
 
 
6515e9a
 
931e0eb
6515e9a
ad7badd
6515e9a
ad7badd
6515e9a
931e0eb
6515e9a
 
ad7badd
 
 
 
 
6515e9a
 
 
 
ad7badd
6515e9a
 
 
 
ad7badd
931e0eb
 
 
 
ad7badd
 
 
6515e9a
ad7badd
 
 
6515e9a
 
 
 
ad7badd
 
 
 
 
 
931e0eb
 
 
 
6515e9a
ad7badd
 
 
6515e9a
 
 
 
ad7badd
931e0eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ad7badd
 
 
6515e9a
931e0eb
ad7badd
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# Multi-LoRA Image Editing Implementation (Simplified)

## Overview

This implementation provides a simplified multi-LoRA (Low-Rank Adaptation) system for the Qwen-Image-Edit application, focusing on **Lightning LoRA always active as the base optimization** with only **Object Remover** as an additional LoRA for testing.

## Architecture

### Core Components

1. **LoRAManager** (`lora_manager.py`)
   - Centralized management of multiple LoRA adapters
   - Registry system for storing LoRA configurations
   - Dynamic loading and fusion capabilities
   - Memory management and cleanup

2. **LoRA Configuration** (`app.py`)
   - Centralized `LORA_CONFIG` dictionary
   - Lightning LoRA configured as always-loaded base
   - Simplified to Object Remover for focused testing

3. **Dynamic UI System** (`app.py`)
   - Conditional component visibility based on LoRA selection
   - Lightning LoRA status indication
   - Type-specific UI adaptations (edit vs base)
   - Real-time interface updates

## ⚑ Lightning LoRA Always-On Architecture

### Core Principle

**Lightning LoRA is always loaded as the base model** for fast 4-step generation, regardless of which other LoRA is selected. This provides:

- **Consistent Performance**: Always-on 4-step generation
- **Enhanced Speed**: Lightning's optimization applies to all operations
- **Multi-LoRA Fusion**: Combine Lightning speed with Object Remover capabilities

### Implementation Details

#### 1. Always-On Loading

```python
# Lightning LoRA is loaded first and always remains active
LIGHTNING_LORA_NAME = "Lightning (4-Step)"

print(f"Loading always-active Lightning LoRA: {LIGHTNING_LORA_NAME}")
lightning_lora_path = hf_hub_download(
    repo_id=lightning_config["repo_id"], 
    filename=lightning_config["filename"]
)

lora_manager.register_lora(LIGHTNING_LORA_NAME, lightning_lora_path, **lightning_config)
lora_manager.configure_lora(LIGHTNING_LORA_NAME, {
    "description": lightning_config["description"],
    "is_base": True
})

# Load Lightning LoRA and keep it always active
lora_manager.load_lora(LIGHTNING_LORA_NAME)
lora_manager.fuse_lora(LIGHTNING_LORA_NAME)
```

#### 2. Multi-LoRA Combination

```python
def load_and_fuse_additional_lora(lora_name):
    """
    Load an additional LoRA while keeping Lightning LoRA always active.
    This enables combining Lightning's speed with Object Remover capabilities.
    """
    # Always keep Lightning LoRA loaded
    # Load additional LoRA without resetting to base state
    if config["method"] == "standard":
        print("Using standard loading method...")
        # Load additional LoRA without fusing (to preserve Lightning)
        pipe.load_lora_weights(lora_path, adapter_names=[lora_name])
        # Set both adapters as active
        pipe.set_adapters([LIGHTNING_LORA_NAME, lora_name])
        print(f"Lightning + {lora_name} now active.")
```

#### 3. Lightning Preservation in Inference

```python
def infer(lora_name, ...):
    """Main inference function with Lightning always active"""
    # Load additional LoRA while keeping Lightning active
    load_and_fuse_lora(lora_name)
    
    print("--- Running Inference ---")
    print(f"LoRA: {lora_name} (with Lightning always active)")
    
    # Generate with Lightning + additional LoRA
    result_image = pipe(
        image=image_for_pipeline,
        prompt=final_prompt,
        num_inference_steps=int(num_inference_steps),
        # ... other parameters
    ).images[0]
    
    # Don't unfuse Lightning - keep it active for next inference
    if lora_name != LIGHTNING_LORA_NAME:
        pipe.disable_adapters()  # Disable additional LoRA but keep Lightning
```

## Simplified LoRA Configuration

### Current Supported LoRAs

| LoRA Name | Type | Method | Always-On | Description |
|-----------|------|--------|-----------|-------------|
| **⚑ Lightning (4-Step)** | base | standard | βœ… **Always** | Fast 4-step generation - always active |
| **None** | edit | none | ❌ | Base model with Lightning optimization |
| **Object Remover** | edit | standard | ⚑ Lightning+ | Removes objects from an image while maintaining background consistency |

### Lightning + Object Remover Combination

**Lightning + Object Remover**: Fast object removal with 4-step generation optimization

### LoRA Type Classifications

- **Base LoRA**: Lightning (always loaded, always active)
- **Edit LoRAs**: Object Remover (requires input images, uses standard fusion)
- **None**: Base model with Lightning optimization

## Key Features

### 1. Dynamic UI Components

The system automatically adapts the user interface and shows Lightning status:

```python
def on_lora_change(lora_name):
    """Dynamic UI component visibility handler"""
    config = LORA_CONFIG[lora_name]
    is_style_lora = config["type"] == "style"
    
    # Lightning LoRA info
    lightning_info = "⚑ **Lightning LoRA always active** - Fast 4-step generation enabled"
    
    return {
        lora_description: gr.Markdown(visible=True, value=f"**{lightning_info}**  \n\n**Description:** {config['description']}"),
        input_image_box: gr.Image(visible=not is_style_lora, type="pil"),
        style_image_box: gr.Image(visible=is_style_lora, type="pil"),
        prompt_box: gr.Textbox(visible=(config["prompt_template"] != "change the face to face segmentation mask"))
    }
```

### 2. Always-On Lightning Performance

```python
# Lightning configuration as always-loaded base
"Lightning (4-Step)": {
    "repo_id": "lightx2v/Qwen-Image-Lightning",
    "filename": "Qwen-Image-Lightning-4steps-V2.0.safetensors",
    "type": "base",
    "method": "standard",
    "always_load": True,
    "prompt_template": "{prompt}",
    "description": "Fast 4-step generation LoRA - always loaded as base optimization.",
}
```

### 3. Simplified Multi-LoRA Fusion

- **Lightning Base**: Always loaded, always active
- **Object Remover**: Loaded alongside Lightning using standard fusion
- **None**: Lightning-only operation

### 4. Memory Management with Lightning

- Lightning LoRA remains loaded throughout session
- Object Remover LoRA loaded/unloaded as needed
- GPU memory optimized for Lightning + one additional LoRA
- Automatic cleanup of non-Lightning adapters

### 5. Prompt Template System

Each LoRA has a custom prompt template (Lightning provides base 4-step generation):

```python
"Object Remover": {
    "prompt_template": "Remove {prompt}",
    "type": "edit"
}
```

## Usage

### Basic Usage with Always-On Lightning

1. **Lightning is Always Active**: No selection needed - Lightning runs all operations
2. **Select Additional LoRA**: Choose "Object Remover" to combine with Lightning
3. **Upload Images**: Upload input image to edit
4. **Enter Prompt**: Describe the object to remove
5. **Configure Settings**: Adjust advanced parameters (4-step generation always enabled)
6. **Generate**: Click "Generate!" to process with Lightning optimization

### Object Remover Usage

1. **Select "Object Remover"** from the dropdown
2. **Upload Input Image**: The image containing the object to remove
3. **Enter Prompt**: Describe the object to remove (e.g., "person", "car", "tree")
4. **Generate**: Lightning + Object Remover will remove the specified object

### Advanced Configuration

#### Adding New LoRAs (with Lightning Always-On)

1. **Add to LORA_CONFIG**:
```python
"Custom LoRA": {
    "repo_id": "username/custom-lora",
    "filename": "custom.safetensors",
    "type": "edit",  # or "style"
    "method": "standard",  # or "manual_fuse"
    "prompt_template": "Custom instruction: {prompt}",
    "description": "Description of the LoRA capabilities"
}
```

2. **Register with LoRAManager**:
```python
lora_path = hf_hub_download(repo_id=config["repo_id"], filename=config["filename"])
lora_manager.register_lora("Custom LoRA", lora_path, **config)
```

3. **Lightning + Custom LoRA**: Automatically combines with always-on Lightning

## Technical Implementation

### Lightning Always-On Process

1. **Initialization**: Load Lightning LoRA first
2. **Fusion**: Fuse Lightning weights permanently
3. **Persistence**: Keep Lightning active throughout session
4. **Combination**: Load Object Remover alongside Lightning
5. **Preservation**: Never unload Lightning LoRA

### Lightning Loading Process

```python
def load_and_fuse_lora(lora_name):
    """Legacy function for backward compatibility"""
    if lora_name == LIGHTNING_LORA_NAME:
        # Lightning is already loaded, just ensure it's active
        print("Lightning LoRA is already active.")
        pipe.set_adapters([LIGHTNING_LORA_NAME])
        return
    
    load_and_fuse_additional_lora(lora_name)
```

### Memory Management with Lightning

```python
# Don't unfuse Lightning - keep it active for next inference
if lora_name != LIGHTNING_LORA_NAME:
    pipe.disable_adapters()  # Disable additional LoRA but keep Lightning
gc.collect()
torch.cuda.empty_cache()
```

## Testing and Validation

### Validation Scripts

- **test_lora_logic.py**: Validates implementation logic without dependencies
- **test_lightning_always_on.py**: Validates Lightning always-on functionality
- **test_lora_implementation.py**: Full integration testing (requires PyTorch)

### Lightning Always-On Test Coverage

βœ… **Lightning LoRA configured as always-loaded base**  
βœ… **Lightning LoRA loaded and fused on startup**  
βœ… **Inference preserves Lightning LoRA state**  
βœ… **Multi-LoRA combination supported**  
βœ… **UI indicates Lightning always active**  
βœ… **Proper loading sequence implemented**  

### Object Remover Testing

βœ… **Object Remover loads alongside Lightning**  
βœ… **Lightning + Object Remover combination works**  
βœ… **Prompt template "Remove {prompt}" functions correctly**  
βœ… **Memory management for Lightning + Object Remover**  

## Performance Considerations

### Lightning Always-On Benefits

- **Consistent Speed**: All operations use 4-step generation
- **Reduced Latency**: No loading time for Lightning between requests
- **Enhanced Performance**: Lightning optimization applies to Object Remover
- **Memory Efficiency**: Lightning stays in memory, Object Remover loaded as needed

### Speed Optimization

- **4-Step Generation**: Lightning provides ultra-fast inference
- **AOT Compilation**: Ahead-of-time compilation with Lightning active
- **Adapter Combination**: Lightning + Object Remover for optimal results
- **Optimized Attention Processors**: FA3 attention with Lightning

### Memory Optimization

- Lightning LoRA always in memory (base memory usage)
- Object Remover LoRA loaded on-demand
- Efficient adapter switching
- GPU memory management for multiple adapters

## Troubleshooting

### Common Issues

1. **Lightning Not Loading**
   - Check HuggingFace Hub connectivity for Lightning repo
   - Verify `lightx2v/Qwen-Image-Lightning` repository exists
   - Ensure sufficient GPU memory for Lightning LoRA

2. **Slow Performance (Lightning Not Active)**
   - Check Lightning LoRA is loaded: Look for "Lightning LoRA is already active"
   - Verify adapter status: `pipe.get_active_adapters()`
   - Ensure Lightning is not being disabled

3. **Object Remover Issues**
   - Check Object Remover loading: Look for "Lightning + Object Remover now active"
   - Verify prompt format: Should be "Remove {object}"
   - Monitor memory usage for Lightning + Object Remover

### Debug Mode

Enable debug logging to see Lightning always-on status:
```python
import logging
logging.basicConfig(level=logging.DEBUG)

# Check Lightning status
print(f"Lightning active: {LIGHTNING_LORA_NAME in pipe.get_active_adapters()}")
print(f"All active adapters: {pipe.get_active_adapters()}")
```

## Future Enhancements

### Planned Features

1. **Additional LoRAs**: Add more LoRAs after successful Object Remover testing
2. **LoRA Blending**: Advanced blending of multiple LoRAs with Lightning
3. **Lightning Optimization**: Dynamic Lightning parameter adjustment
4. **Performance Monitoring**: Real-time Lightning performance metrics
5. **Batch Processing**: Process multiple images with Lightning always-on

### Extension Points

- Custom Lightning optimization strategies
- Multiple base LoRAs (beyond Lightning)
- Advanced multi-LoRA combination algorithms
- Lightning performance profiling

## Simplified Configuration Benefits

### Focused Testing

- **Reduced Complexity**: Only Lightning + Object Remover to test
- **Clear Validation**: Easy to verify Lightning always-on functionality
- **Debugging**: Simplified troubleshooting with fewer variables
- **Performance**: Clear performance benefits of Lightning always-on

### Risk Mitigation

- **Gradual Rollout**: Test one LoRA before adding more
- **Validation**: Ensure Lightning + LoRA combination works correctly
- **Memory Management**: Verify memory usage with Lightning + one LoRA
- **User Experience**: Validate simplified UI with fewer options

## References

- [Qwen-Image-Edit Model](https://huggingface.co/Qwen/Qwen-Image-Edit-2509)
- [Lightning LoRA Repository](https://huggingface.co/lightx2v/Qwen-Image-Lightning)
- [Object Remover LoRA Repository](https://huggingface.co/valiantcat/Qwen-Image-Edit-Remover-General-LoRA)
- [Diffusers LoRA Documentation](https://huggingface.co/docs/diffusers/main/en/using-diffusers/loading_adapters)
- [PEFT Library](https://github.com/huggingface/peft)
- [HuggingFace Spaces Pattern](https://huggingface.co/spaces)

## License

This implementation follows the same license as the original Qwen-Image-Edit project.