Instructions to use chenzeyang1/T with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use chenzeyang1/T with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("chenzeyang1/T", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
Add files using upload-large-folder tool
Browse files- LICENSE +21 -0
- LaVi-Bridge/modules/__init__.py +1 -0
- LaVi-Bridge/modules/adapters.py +62 -0
- LaVi-Bridge/modules/lora.py +1106 -0
- README.md +509 -1
- __pycache__/thera_llava.cpython-310.pyc +0 -0
- __pycache__/thera_paths.cpython-310.pyc +0 -0
- infer_custom.py +526 -0
- infer_example_guided.py +432 -0
- infer_palette.sh +30 -0
- lavi_ip2p/__init__.py +8 -0
- lavi_ip2p/llava_adapter.py +135 -0
- lavi_ip2p/unet_8ch.py +161 -0
- llava/__init__.py +1 -0
- llava/constants.py +16 -0
- llava/conversation.py +396 -0
- llava/eval/table/results/test_sqa_llava_13b_v0.json +0 -0
- llava/mm_utils.py +247 -0
- llava/rgbt_dataset.py +328 -0
- llava/train/llama_flash_attn_monkey_patch.py +115 -0
- llava/train/llama_xformers_attn_monkey_patch.py +129 -0
- llava/train/llava_trainer.py +273 -0
- llava/train/train_vlm_ip2p_256.py +109 -0
- llava/utils.py +126 -0
- requirements.txt +23 -0
- thera_llava.py +21 -0
- thera_paths.py +26 -0
- weights/.gitattributes +35 -0
- weights/README.md +3 -0
- weights/TherA_VLM/adapter_config.json +34 -0
- weights/TherA_VLM/config.json +49 -0
- weights/TherA_VLM/trainer_state.json +0 -0
- weights/llava-1.5-7b-hf/.gitattributes +35 -0
- weights/llava-1.5-7b-hf/README.md +155 -0
- weights/llava-1.5-7b-hf/added_tokens.json +4 -0
- weights/llava-1.5-7b-hf/chat_template.jinja +2 -0
- weights/llava-1.5-7b-hf/chat_template.json +3 -0
- weights/llava-1.5-7b-hf/config.json +38 -0
- weights/llava-1.5-7b-hf/generation_config.json +7 -0
- weights/llava-1.5-7b-hf/model.safetensors.index.json +693 -0
- weights/llava-1.5-7b-hf/preprocessor_config.json +28 -0
- weights/llava-1.5-7b-hf/processor_config.json +7 -0
- weights/llava-1.5-7b-hf/special_tokens_map.json +30 -0
- weights/llava-1.5-7b-hf/tokenizer.json +0 -0
- weights/llava-1.5-7b-hf/tokenizer_config.json +64 -0
- weights/merged_models/adapter/config.json +8 -0
- weights/merged_models/unet/config.json +68 -0
- weights/stable-diffusion/scheduler/.ipynb_checkpoints/scheduler_config-checkpoint.json +9 -0
- weights/stable-diffusion/scheduler/scheduler_config.json +13 -0
- weights/stable-diffusion/vae/config.json +29 -0
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 donkeymouse
|
| 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.
|
LaVi-Bridge/modules/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
"""LaVi-Bridge modules used by TherA inference."""
|
LaVi-Bridge/modules/adapters.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass
|
| 2 |
+
from inspect import isfunction
|
| 3 |
+
|
| 4 |
+
import torch
|
| 5 |
+
import torch.nn as nn
|
| 6 |
+
import torch.nn.functional as F
|
| 7 |
+
|
| 8 |
+
from diffusers.utils import BaseOutput
|
| 9 |
+
from diffusers.models.modeling_utils import ModelMixin
|
| 10 |
+
from diffusers.configuration_utils import ConfigMixin, register_to_config
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def default(val, d):
|
| 14 |
+
if val is not None: return val
|
| 15 |
+
return d() if isfunction(d) else d
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class GEGLU(nn.Module):
|
| 19 |
+
def __init__(self, dim_in, dim_out):
|
| 20 |
+
super().__init__()
|
| 21 |
+
self.proj = nn.Linear(dim_in, dim_out * 2)
|
| 22 |
+
|
| 23 |
+
def forward(self, x):
|
| 24 |
+
x, gate = self.proj(x).chunk(2, dim=-1)
|
| 25 |
+
return x * F.gelu(gate)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class FeedForward(nn.Module):
|
| 29 |
+
def __init__(self, dim, dim_out, mult=4, dropout=0.1):
|
| 30 |
+
super().__init__()
|
| 31 |
+
inner_dim = int(dim * mult)
|
| 32 |
+
dim_out = default(dim_out, dim)
|
| 33 |
+
project_in = GEGLU(dim, inner_dim)
|
| 34 |
+
self.net = nn.Sequential(
|
| 35 |
+
project_in,
|
| 36 |
+
nn.Dropout(dropout),
|
| 37 |
+
nn.Linear(inner_dim, dim_out)
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
def forward(self, x):
|
| 41 |
+
return self.net(x)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
@dataclass
|
| 45 |
+
class TextAdapterOutput(BaseOutput):
|
| 46 |
+
sample: torch.FloatTensor
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class TextAdapter(ModelMixin, ConfigMixin):
|
| 50 |
+
@register_to_config
|
| 51 |
+
def __init__(self, in_dim, int_dim, out_dim):
|
| 52 |
+
super().__init__()
|
| 53 |
+
self.in_dim = in_dim
|
| 54 |
+
self.ff1 = FeedForward(in_dim, int_dim)
|
| 55 |
+
self.ff2 = FeedForward(int_dim, out_dim)
|
| 56 |
+
self.norm1 = nn.LayerNorm(in_dim)
|
| 57 |
+
self.norm2 = nn.LayerNorm(int_dim)
|
| 58 |
+
|
| 59 |
+
def forward(self, x):
|
| 60 |
+
x = self.ff1(self.norm1(x))
|
| 61 |
+
x = self.ff2(self.norm2(x))
|
| 62 |
+
return TextAdapterOutput(x)
|
LaVi-Bridge/modules/lora.py
ADDED
|
@@ -0,0 +1,1106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from itertools import groupby
|
| 3 |
+
from typing import Dict, List, Optional, Set, Tuple, Type, Union
|
| 4 |
+
|
| 5 |
+
import torch
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
|
| 8 |
+
try:
|
| 9 |
+
from safetensors.torch import safe_open
|
| 10 |
+
from safetensors.torch import save_file as safe_save
|
| 11 |
+
|
| 12 |
+
safetensors_available = True
|
| 13 |
+
except ImportError:
|
| 14 |
+
from .safe_open import safe_open
|
| 15 |
+
|
| 16 |
+
def safe_save(
|
| 17 |
+
tensors: Dict[str, torch.Tensor],
|
| 18 |
+
filename: str,
|
| 19 |
+
metadata: Optional[Dict[str, str]] = None,
|
| 20 |
+
) -> None:
|
| 21 |
+
raise EnvironmentError(
|
| 22 |
+
"Saving safetensors requires the safetensors library. Please install with pip or similar."
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
safetensors_available = False
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class LoraInjectedLinear(nn.Module):
|
| 29 |
+
def __init__(
|
| 30 |
+
self, in_features, out_features, bias=False, r=4, dropout_p=0.1, scale=1.0
|
| 31 |
+
):
|
| 32 |
+
super().__init__()
|
| 33 |
+
|
| 34 |
+
if r > min(in_features, out_features):
|
| 35 |
+
raise ValueError(
|
| 36 |
+
f"LoRA rank {r} must be less or equal than {min(in_features, out_features)}"
|
| 37 |
+
)
|
| 38 |
+
self.r = r
|
| 39 |
+
self.linear = nn.Linear(in_features, out_features, bias)
|
| 40 |
+
self.lora_down = nn.Linear(in_features, r, bias=False)
|
| 41 |
+
self.dropout = nn.Dropout(dropout_p)
|
| 42 |
+
self.lora_up = nn.Linear(r, out_features, bias=False)
|
| 43 |
+
self.scale = scale
|
| 44 |
+
self.selector = nn.Identity()
|
| 45 |
+
|
| 46 |
+
nn.init.normal_(self.lora_down.weight, std=1 / r)
|
| 47 |
+
nn.init.zeros_(self.lora_up.weight)
|
| 48 |
+
|
| 49 |
+
def forward(self, input):
|
| 50 |
+
return (
|
| 51 |
+
self.linear(input)
|
| 52 |
+
+ self.dropout(self.lora_up(self.selector(self.lora_down(input))))
|
| 53 |
+
* self.scale
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
def realize_as_lora(self):
|
| 57 |
+
return self.lora_up.weight.data * self.scale, self.lora_down.weight.data
|
| 58 |
+
|
| 59 |
+
def set_selector_from_diag(self, diag: torch.Tensor):
|
| 60 |
+
# diag is a 1D tensor of size (r,)
|
| 61 |
+
assert diag.shape == (self.r,)
|
| 62 |
+
self.selector = nn.Linear(self.r, self.r, bias=False)
|
| 63 |
+
self.selector.weight.data = torch.diag(diag)
|
| 64 |
+
self.selector.weight.data = self.selector.weight.data.to(
|
| 65 |
+
self.lora_up.weight.device
|
| 66 |
+
).to(self.lora_up.weight.dtype)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
class LoraInjectedConv2d(nn.Module):
|
| 70 |
+
def __init__(
|
| 71 |
+
self,
|
| 72 |
+
in_channels: int,
|
| 73 |
+
out_channels: int,
|
| 74 |
+
kernel_size,
|
| 75 |
+
stride=1,
|
| 76 |
+
padding=0,
|
| 77 |
+
dilation=1,
|
| 78 |
+
groups: int = 1,
|
| 79 |
+
bias: bool = True,
|
| 80 |
+
r: int = 4,
|
| 81 |
+
dropout_p: float = 0.1,
|
| 82 |
+
scale: float = 1.0,
|
| 83 |
+
):
|
| 84 |
+
super().__init__()
|
| 85 |
+
if r > min(in_channels, out_channels):
|
| 86 |
+
raise ValueError(
|
| 87 |
+
f"LoRA rank {r} must be less or equal than {min(in_channels, out_channels)}"
|
| 88 |
+
)
|
| 89 |
+
self.r = r
|
| 90 |
+
self.conv = nn.Conv2d(
|
| 91 |
+
in_channels=in_channels,
|
| 92 |
+
out_channels=out_channels,
|
| 93 |
+
kernel_size=kernel_size,
|
| 94 |
+
stride=stride,
|
| 95 |
+
padding=padding,
|
| 96 |
+
dilation=dilation,
|
| 97 |
+
groups=groups,
|
| 98 |
+
bias=bias,
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
self.lora_down = nn.Conv2d(
|
| 102 |
+
in_channels=in_channels,
|
| 103 |
+
out_channels=r,
|
| 104 |
+
kernel_size=kernel_size,
|
| 105 |
+
stride=stride,
|
| 106 |
+
padding=padding,
|
| 107 |
+
dilation=dilation,
|
| 108 |
+
groups=groups,
|
| 109 |
+
bias=False,
|
| 110 |
+
)
|
| 111 |
+
self.dropout = nn.Dropout(dropout_p)
|
| 112 |
+
self.lora_up = nn.Conv2d(
|
| 113 |
+
in_channels=r,
|
| 114 |
+
out_channels=out_channels,
|
| 115 |
+
kernel_size=1,
|
| 116 |
+
stride=1,
|
| 117 |
+
padding=0,
|
| 118 |
+
bias=False,
|
| 119 |
+
)
|
| 120 |
+
self.selector = nn.Identity()
|
| 121 |
+
self.scale = scale
|
| 122 |
+
|
| 123 |
+
nn.init.normal_(self.lora_down.weight, std=1 / r)
|
| 124 |
+
nn.init.zeros_(self.lora_up.weight)
|
| 125 |
+
|
| 126 |
+
def forward(self, input):
|
| 127 |
+
return (
|
| 128 |
+
self.conv(input)
|
| 129 |
+
+ self.dropout(self.lora_up(self.selector(self.lora_down(input))))
|
| 130 |
+
* self.scale
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
def realize_as_lora(self):
|
| 134 |
+
return self.lora_up.weight.data * self.scale, self.lora_down.weight.data
|
| 135 |
+
|
| 136 |
+
def set_selector_from_diag(self, diag: torch.Tensor):
|
| 137 |
+
# diag is a 1D tensor of size (r,)
|
| 138 |
+
assert diag.shape == (self.r,)
|
| 139 |
+
self.selector = nn.Conv2d(
|
| 140 |
+
in_channels=self.r,
|
| 141 |
+
out_channels=self.r,
|
| 142 |
+
kernel_size=1,
|
| 143 |
+
stride=1,
|
| 144 |
+
padding=0,
|
| 145 |
+
bias=False,
|
| 146 |
+
)
|
| 147 |
+
self.selector.weight.data = torch.diag(diag)
|
| 148 |
+
|
| 149 |
+
# same device + dtype as lora_up
|
| 150 |
+
self.selector.weight.data = self.selector.weight.data.to(
|
| 151 |
+
self.lora_up.weight.device
|
| 152 |
+
).to(self.lora_up.weight.dtype)
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
UNET_DEFAULT_TARGET_REPLACE = {"CrossAttention", "Attention", "GEGLU"}
|
| 156 |
+
|
| 157 |
+
UNET_EXTENDED_TARGET_REPLACE = {"ResnetBlock2D", "CrossAttention", "Attention", "GEGLU"}
|
| 158 |
+
|
| 159 |
+
TEXT_ENCODER_DEFAULT_TARGET_REPLACE = {"CLIPAttention"}
|
| 160 |
+
|
| 161 |
+
TEXT_ENCODER_EXTENDED_TARGET_REPLACE = {"CLIPAttention"}
|
| 162 |
+
|
| 163 |
+
DEFAULT_TARGET_REPLACE = UNET_DEFAULT_TARGET_REPLACE
|
| 164 |
+
|
| 165 |
+
EMBED_FLAG = "<embed>"
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def _find_children(
|
| 169 |
+
model,
|
| 170 |
+
search_class: List[Type[nn.Module]] = [nn.Linear],
|
| 171 |
+
):
|
| 172 |
+
"""
|
| 173 |
+
Find all modules of a certain class (or union of classes).
|
| 174 |
+
|
| 175 |
+
Returns all matching modules, along with the parent of those moduless and the
|
| 176 |
+
names they are referenced by.
|
| 177 |
+
"""
|
| 178 |
+
# For each target find every linear_class module that isn't a child of a LoraInjectedLinear
|
| 179 |
+
for parent in model.modules():
|
| 180 |
+
for name, module in parent.named_children():
|
| 181 |
+
if any([isinstance(module, _class) for _class in search_class]):
|
| 182 |
+
yield parent, name, module
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
def _find_modules_v2(
|
| 186 |
+
model,
|
| 187 |
+
ancestor_class: Optional[Set[str]] = None,
|
| 188 |
+
search_class: List[Type[nn.Module]] = [nn.Linear],
|
| 189 |
+
exclude_children_of: Optional[List[Type[nn.Module]]] = [
|
| 190 |
+
LoraInjectedLinear,
|
| 191 |
+
LoraInjectedConv2d,
|
| 192 |
+
],
|
| 193 |
+
):
|
| 194 |
+
"""
|
| 195 |
+
Find all modules of a certain class (or union of classes) that are direct or
|
| 196 |
+
indirect descendants of other modules of a certain class (or union of classes).
|
| 197 |
+
|
| 198 |
+
Returns all matching modules, along with the parent of those moduless and the
|
| 199 |
+
names they are referenced by.
|
| 200 |
+
"""
|
| 201 |
+
|
| 202 |
+
# Get the targets we should replace all linears under
|
| 203 |
+
if ancestor_class is not None:
|
| 204 |
+
ancestors = (
|
| 205 |
+
module
|
| 206 |
+
for module in model.modules()
|
| 207 |
+
if module.__class__.__name__ in ancestor_class
|
| 208 |
+
)
|
| 209 |
+
else:
|
| 210 |
+
# this, incase you want to naively iterate over all modules.
|
| 211 |
+
ancestors = [module for module in model.modules()]
|
| 212 |
+
|
| 213 |
+
# For each target find every linear_class module that isn't a child of a LoraInjectedLinear
|
| 214 |
+
for ancestor in ancestors:
|
| 215 |
+
for fullname, module in ancestor.named_modules():
|
| 216 |
+
if any([isinstance(module, _class) for _class in search_class]):
|
| 217 |
+
# Find the direct parent if this is a descendant, not a child, of target
|
| 218 |
+
*path, name = fullname.split(".")
|
| 219 |
+
parent = ancestor
|
| 220 |
+
while path:
|
| 221 |
+
parent = parent.get_submodule(path.pop(0))
|
| 222 |
+
# Skip this linear if it's a child of a LoraInjectedLinear
|
| 223 |
+
if exclude_children_of and any(
|
| 224 |
+
[isinstance(parent, _class) for _class in exclude_children_of]
|
| 225 |
+
):
|
| 226 |
+
continue
|
| 227 |
+
# Otherwise, yield it
|
| 228 |
+
yield parent, name, module
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def _find_modules_old(
|
| 232 |
+
model,
|
| 233 |
+
ancestor_class: Set[str] = DEFAULT_TARGET_REPLACE,
|
| 234 |
+
search_class: List[Type[nn.Module]] = [nn.Linear],
|
| 235 |
+
exclude_children_of: Optional[List[Type[nn.Module]]] = [LoraInjectedLinear],
|
| 236 |
+
):
|
| 237 |
+
ret = []
|
| 238 |
+
for _module in model.modules():
|
| 239 |
+
if _module.__class__.__name__ in ancestor_class:
|
| 240 |
+
|
| 241 |
+
for name, _child_module in _module.named_modules():
|
| 242 |
+
if _child_module.__class__ in search_class:
|
| 243 |
+
ret.append((_module, name, _child_module))
|
| 244 |
+
print(ret)
|
| 245 |
+
return ret
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
_find_modules = _find_modules_v2
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
def inject_trainable_lora(
|
| 252 |
+
model: nn.Module,
|
| 253 |
+
target_replace_module: Set[str] = DEFAULT_TARGET_REPLACE,
|
| 254 |
+
r: int = 4,
|
| 255 |
+
loras=None, # path to lora .pt
|
| 256 |
+
verbose: bool = False,
|
| 257 |
+
dropout_p: float = 0.0,
|
| 258 |
+
scale: float = 1.0,
|
| 259 |
+
):
|
| 260 |
+
"""
|
| 261 |
+
inject lora into model, and returns lora parameter groups.
|
| 262 |
+
"""
|
| 263 |
+
|
| 264 |
+
require_grad_params = []
|
| 265 |
+
names = []
|
| 266 |
+
|
| 267 |
+
if loras != None:
|
| 268 |
+
loras = torch.load(loras)
|
| 269 |
+
|
| 270 |
+
for _module, name, _child_module in _find_modules(
|
| 271 |
+
model, target_replace_module, search_class=[nn.Linear]
|
| 272 |
+
):
|
| 273 |
+
weight = _child_module.weight
|
| 274 |
+
bias = _child_module.bias
|
| 275 |
+
if verbose:
|
| 276 |
+
print("LoRA Injection : injecting lora into ", name)
|
| 277 |
+
print("LoRA Injection : weight shape", weight.shape)
|
| 278 |
+
_tmp = LoraInjectedLinear(
|
| 279 |
+
_child_module.in_features,
|
| 280 |
+
_child_module.out_features,
|
| 281 |
+
_child_module.bias is not None,
|
| 282 |
+
r=r,
|
| 283 |
+
dropout_p=dropout_p,
|
| 284 |
+
scale=scale,
|
| 285 |
+
)
|
| 286 |
+
_tmp.linear.weight = weight
|
| 287 |
+
if bias is not None:
|
| 288 |
+
_tmp.linear.bias = bias
|
| 289 |
+
|
| 290 |
+
# switch the module
|
| 291 |
+
_tmp.to(_child_module.weight.device).to(_child_module.weight.dtype)
|
| 292 |
+
_module._modules[name] = _tmp
|
| 293 |
+
|
| 294 |
+
require_grad_params.append(_module._modules[name].lora_up.parameters())
|
| 295 |
+
require_grad_params.append(_module._modules[name].lora_down.parameters())
|
| 296 |
+
|
| 297 |
+
if loras != None:
|
| 298 |
+
_module._modules[name].lora_up.weight = loras.pop(0)
|
| 299 |
+
_module._modules[name].lora_down.weight = loras.pop(0)
|
| 300 |
+
|
| 301 |
+
_module._modules[name].lora_up.weight.requires_grad = True
|
| 302 |
+
_module._modules[name].lora_down.weight.requires_grad = True
|
| 303 |
+
names.append(name)
|
| 304 |
+
|
| 305 |
+
return require_grad_params, names
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
def inject_trainable_lora_extended(
|
| 309 |
+
model: nn.Module,
|
| 310 |
+
target_replace_module: Set[str] = UNET_EXTENDED_TARGET_REPLACE,
|
| 311 |
+
r: int = 4,
|
| 312 |
+
loras=None, # path to lora .pt
|
| 313 |
+
):
|
| 314 |
+
"""
|
| 315 |
+
inject lora into model, and returns lora parameter groups.
|
| 316 |
+
"""
|
| 317 |
+
|
| 318 |
+
require_grad_params = []
|
| 319 |
+
names = []
|
| 320 |
+
|
| 321 |
+
if loras != None:
|
| 322 |
+
loras = torch.load(loras)
|
| 323 |
+
|
| 324 |
+
for _module, name, _child_module in _find_modules(
|
| 325 |
+
model, target_replace_module, search_class=[nn.Linear, nn.Conv2d]
|
| 326 |
+
):
|
| 327 |
+
if _child_module.__class__ == nn.Linear:
|
| 328 |
+
weight = _child_module.weight
|
| 329 |
+
bias = _child_module.bias
|
| 330 |
+
_tmp = LoraInjectedLinear(
|
| 331 |
+
_child_module.in_features,
|
| 332 |
+
_child_module.out_features,
|
| 333 |
+
_child_module.bias is not None,
|
| 334 |
+
r=r,
|
| 335 |
+
)
|
| 336 |
+
_tmp.linear.weight = weight
|
| 337 |
+
if bias is not None:
|
| 338 |
+
_tmp.linear.bias = bias
|
| 339 |
+
elif _child_module.__class__ == nn.Conv2d:
|
| 340 |
+
weight = _child_module.weight
|
| 341 |
+
bias = _child_module.bias
|
| 342 |
+
_tmp = LoraInjectedConv2d(
|
| 343 |
+
_child_module.in_channels,
|
| 344 |
+
_child_module.out_channels,
|
| 345 |
+
_child_module.kernel_size,
|
| 346 |
+
_child_module.stride,
|
| 347 |
+
_child_module.padding,
|
| 348 |
+
_child_module.dilation,
|
| 349 |
+
_child_module.groups,
|
| 350 |
+
_child_module.bias is not None,
|
| 351 |
+
r=r,
|
| 352 |
+
)
|
| 353 |
+
|
| 354 |
+
_tmp.conv.weight = weight
|
| 355 |
+
if bias is not None:
|
| 356 |
+
_tmp.conv.bias = bias
|
| 357 |
+
|
| 358 |
+
# switch the module
|
| 359 |
+
_tmp.to(_child_module.weight.device).to(_child_module.weight.dtype)
|
| 360 |
+
if bias is not None:
|
| 361 |
+
_tmp.to(_child_module.bias.device).to(_child_module.bias.dtype)
|
| 362 |
+
|
| 363 |
+
_module._modules[name] = _tmp
|
| 364 |
+
|
| 365 |
+
require_grad_params.append(_module._modules[name].lora_up.parameters())
|
| 366 |
+
require_grad_params.append(_module._modules[name].lora_down.parameters())
|
| 367 |
+
|
| 368 |
+
if loras != None:
|
| 369 |
+
_module._modules[name].lora_up.weight = loras.pop(0)
|
| 370 |
+
_module._modules[name].lora_down.weight = loras.pop(0)
|
| 371 |
+
|
| 372 |
+
_module._modules[name].lora_up.weight.requires_grad = True
|
| 373 |
+
_module._modules[name].lora_down.weight.requires_grad = True
|
| 374 |
+
names.append(name)
|
| 375 |
+
|
| 376 |
+
return require_grad_params, names
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
def extract_lora_ups_down(model, target_replace_module=DEFAULT_TARGET_REPLACE):
|
| 380 |
+
|
| 381 |
+
loras = []
|
| 382 |
+
|
| 383 |
+
for _m, _n, _child_module in _find_modules(
|
| 384 |
+
model,
|
| 385 |
+
target_replace_module,
|
| 386 |
+
search_class=[LoraInjectedLinear, LoraInjectedConv2d],
|
| 387 |
+
):
|
| 388 |
+
loras.append((_child_module.lora_up, _child_module.lora_down))
|
| 389 |
+
|
| 390 |
+
if len(loras) == 0:
|
| 391 |
+
raise ValueError("No lora injected.")
|
| 392 |
+
|
| 393 |
+
return loras
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
def extract_lora_as_tensor(
|
| 397 |
+
model, target_replace_module=DEFAULT_TARGET_REPLACE, as_fp16=True
|
| 398 |
+
):
|
| 399 |
+
|
| 400 |
+
loras = []
|
| 401 |
+
|
| 402 |
+
for _m, _n, _child_module in _find_modules(
|
| 403 |
+
model,
|
| 404 |
+
target_replace_module,
|
| 405 |
+
search_class=[LoraInjectedLinear, LoraInjectedConv2d],
|
| 406 |
+
):
|
| 407 |
+
up, down = _child_module.realize_as_lora()
|
| 408 |
+
if as_fp16:
|
| 409 |
+
up = up.to(torch.float16)
|
| 410 |
+
down = down.to(torch.float16)
|
| 411 |
+
|
| 412 |
+
loras.append((up, down))
|
| 413 |
+
|
| 414 |
+
if len(loras) == 0:
|
| 415 |
+
raise ValueError("No lora injected.")
|
| 416 |
+
|
| 417 |
+
return loras
|
| 418 |
+
|
| 419 |
+
|
| 420 |
+
def save_lora_weight(
|
| 421 |
+
model,
|
| 422 |
+
path="./lora.pt",
|
| 423 |
+
target_replace_module=DEFAULT_TARGET_REPLACE,
|
| 424 |
+
):
|
| 425 |
+
weights = []
|
| 426 |
+
for _up, _down in extract_lora_ups_down(
|
| 427 |
+
model, target_replace_module=target_replace_module
|
| 428 |
+
):
|
| 429 |
+
weights.append(_up.weight.to("cpu").to(torch.float16))
|
| 430 |
+
weights.append(_down.weight.to("cpu").to(torch.float16))
|
| 431 |
+
|
| 432 |
+
torch.save(weights, path)
|
| 433 |
+
|
| 434 |
+
|
| 435 |
+
def save_lora_as_json(model, path="./lora.json"):
|
| 436 |
+
weights = []
|
| 437 |
+
for _up, _down in extract_lora_ups_down(model):
|
| 438 |
+
weights.append(_up.weight.detach().cpu().numpy().tolist())
|
| 439 |
+
weights.append(_down.weight.detach().cpu().numpy().tolist())
|
| 440 |
+
|
| 441 |
+
import json
|
| 442 |
+
|
| 443 |
+
with open(path, "w") as f:
|
| 444 |
+
json.dump(weights, f)
|
| 445 |
+
|
| 446 |
+
|
| 447 |
+
def save_safeloras_with_embeds(
|
| 448 |
+
modelmap: Dict[str, Tuple[nn.Module, Set[str]]] = {},
|
| 449 |
+
embeds: Dict[str, torch.Tensor] = {},
|
| 450 |
+
outpath="./lora.safetensors",
|
| 451 |
+
):
|
| 452 |
+
"""
|
| 453 |
+
Saves the Lora from multiple modules in a single safetensor file.
|
| 454 |
+
|
| 455 |
+
modelmap is a dictionary of {
|
| 456 |
+
"module name": (module, target_replace_module)
|
| 457 |
+
}
|
| 458 |
+
"""
|
| 459 |
+
weights = {}
|
| 460 |
+
metadata = {}
|
| 461 |
+
|
| 462 |
+
for name, (model, target_replace_module) in modelmap.items():
|
| 463 |
+
metadata[name] = json.dumps(list(target_replace_module))
|
| 464 |
+
|
| 465 |
+
for i, (_up, _down) in enumerate(
|
| 466 |
+
extract_lora_as_tensor(model, target_replace_module)
|
| 467 |
+
):
|
| 468 |
+
rank = _down.shape[0]
|
| 469 |
+
|
| 470 |
+
metadata[f"{name}:{i}:rank"] = str(rank)
|
| 471 |
+
weights[f"{name}:{i}:up"] = _up
|
| 472 |
+
weights[f"{name}:{i}:down"] = _down
|
| 473 |
+
|
| 474 |
+
for token, tensor in embeds.items():
|
| 475 |
+
metadata[token] = EMBED_FLAG
|
| 476 |
+
weights[token] = tensor
|
| 477 |
+
|
| 478 |
+
print(f"Saving weights to {outpath}")
|
| 479 |
+
safe_save(weights, outpath, metadata)
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
def save_safeloras(
|
| 483 |
+
modelmap: Dict[str, Tuple[nn.Module, Set[str]]] = {},
|
| 484 |
+
outpath="./lora.safetensors",
|
| 485 |
+
):
|
| 486 |
+
return save_safeloras_with_embeds(modelmap=modelmap, outpath=outpath)
|
| 487 |
+
|
| 488 |
+
|
| 489 |
+
def convert_loras_to_safeloras_with_embeds(
|
| 490 |
+
modelmap: Dict[str, Tuple[str, Set[str], int]] = {},
|
| 491 |
+
embeds: Dict[str, torch.Tensor] = {},
|
| 492 |
+
outpath="./lora.safetensors",
|
| 493 |
+
):
|
| 494 |
+
"""
|
| 495 |
+
Converts the Lora from multiple pytorch .pt files into a single safetensor file.
|
| 496 |
+
|
| 497 |
+
modelmap is a dictionary of {
|
| 498 |
+
"module name": (pytorch_model_path, target_replace_module, rank)
|
| 499 |
+
}
|
| 500 |
+
"""
|
| 501 |
+
|
| 502 |
+
weights = {}
|
| 503 |
+
metadata = {}
|
| 504 |
+
|
| 505 |
+
for name, (path, target_replace_module, r) in modelmap.items():
|
| 506 |
+
metadata[name] = json.dumps(list(target_replace_module))
|
| 507 |
+
|
| 508 |
+
lora = torch.load(path)
|
| 509 |
+
for i, weight in enumerate(lora):
|
| 510 |
+
is_up = i % 2 == 0
|
| 511 |
+
i = i // 2
|
| 512 |
+
|
| 513 |
+
if is_up:
|
| 514 |
+
metadata[f"{name}:{i}:rank"] = str(r)
|
| 515 |
+
weights[f"{name}:{i}:up"] = weight
|
| 516 |
+
else:
|
| 517 |
+
weights[f"{name}:{i}:down"] = weight
|
| 518 |
+
|
| 519 |
+
for token, tensor in embeds.items():
|
| 520 |
+
metadata[token] = EMBED_FLAG
|
| 521 |
+
weights[token] = tensor
|
| 522 |
+
|
| 523 |
+
print(f"Saving weights to {outpath}")
|
| 524 |
+
safe_save(weights, outpath, metadata)
|
| 525 |
+
|
| 526 |
+
|
| 527 |
+
def convert_loras_to_safeloras(
|
| 528 |
+
modelmap: Dict[str, Tuple[str, Set[str], int]] = {},
|
| 529 |
+
outpath="./lora.safetensors",
|
| 530 |
+
):
|
| 531 |
+
convert_loras_to_safeloras_with_embeds(modelmap=modelmap, outpath=outpath)
|
| 532 |
+
|
| 533 |
+
|
| 534 |
+
def parse_safeloras(
|
| 535 |
+
safeloras,
|
| 536 |
+
) -> Dict[str, Tuple[List[nn.parameter.Parameter], List[int], List[str]]]:
|
| 537 |
+
"""
|
| 538 |
+
Converts a loaded safetensor file that contains a set of module Loras
|
| 539 |
+
into Parameters and other information
|
| 540 |
+
|
| 541 |
+
Output is a dictionary of {
|
| 542 |
+
"module name": (
|
| 543 |
+
[list of weights],
|
| 544 |
+
[list of ranks],
|
| 545 |
+
target_replacement_modules
|
| 546 |
+
)
|
| 547 |
+
}
|
| 548 |
+
"""
|
| 549 |
+
loras = {}
|
| 550 |
+
metadata = safeloras.metadata()
|
| 551 |
+
|
| 552 |
+
get_name = lambda k: k.split(":")[0]
|
| 553 |
+
|
| 554 |
+
keys = list(safeloras.keys())
|
| 555 |
+
keys.sort(key=get_name)
|
| 556 |
+
|
| 557 |
+
for name, module_keys in groupby(keys, get_name):
|
| 558 |
+
info = metadata.get(name)
|
| 559 |
+
|
| 560 |
+
if not info:
|
| 561 |
+
raise ValueError(
|
| 562 |
+
f"Tensor {name} has no metadata - is this a Lora safetensor?"
|
| 563 |
+
)
|
| 564 |
+
|
| 565 |
+
# Skip Textual Inversion embeds
|
| 566 |
+
if info == EMBED_FLAG:
|
| 567 |
+
continue
|
| 568 |
+
|
| 569 |
+
# Handle Loras
|
| 570 |
+
# Extract the targets
|
| 571 |
+
target = json.loads(info)
|
| 572 |
+
|
| 573 |
+
# Build the result lists - Python needs us to preallocate lists to insert into them
|
| 574 |
+
module_keys = list(module_keys)
|
| 575 |
+
ranks = [4] * (len(module_keys) // 2)
|
| 576 |
+
weights = [None] * len(module_keys)
|
| 577 |
+
|
| 578 |
+
for key in module_keys:
|
| 579 |
+
# Split the model name and index out of the key
|
| 580 |
+
_, idx, direction = key.split(":")
|
| 581 |
+
idx = int(idx)
|
| 582 |
+
|
| 583 |
+
# Add the rank
|
| 584 |
+
ranks[idx] = int(metadata[f"{name}:{idx}:rank"])
|
| 585 |
+
|
| 586 |
+
# Insert the weight into the list
|
| 587 |
+
idx = idx * 2 + (1 if direction == "down" else 0)
|
| 588 |
+
weights[idx] = nn.parameter.Parameter(safeloras.get_tensor(key))
|
| 589 |
+
|
| 590 |
+
loras[name] = (weights, ranks, target)
|
| 591 |
+
|
| 592 |
+
return loras
|
| 593 |
+
|
| 594 |
+
|
| 595 |
+
def parse_safeloras_embeds(
|
| 596 |
+
safeloras,
|
| 597 |
+
) -> Dict[str, torch.Tensor]:
|
| 598 |
+
"""
|
| 599 |
+
Converts a loaded safetensor file that contains Textual Inversion embeds into
|
| 600 |
+
a dictionary of embed_token: Tensor
|
| 601 |
+
"""
|
| 602 |
+
embeds = {}
|
| 603 |
+
metadata = safeloras.metadata()
|
| 604 |
+
|
| 605 |
+
for key in safeloras.keys():
|
| 606 |
+
# Only handle Textual Inversion embeds
|
| 607 |
+
meta = metadata.get(key)
|
| 608 |
+
if not meta or meta != EMBED_FLAG:
|
| 609 |
+
continue
|
| 610 |
+
|
| 611 |
+
embeds[key] = safeloras.get_tensor(key)
|
| 612 |
+
|
| 613 |
+
return embeds
|
| 614 |
+
|
| 615 |
+
|
| 616 |
+
def load_safeloras(path, device="cpu"):
|
| 617 |
+
safeloras = safe_open(path, framework="pt", device=device)
|
| 618 |
+
return parse_safeloras(safeloras)
|
| 619 |
+
|
| 620 |
+
|
| 621 |
+
def load_safeloras_embeds(path, device="cpu"):
|
| 622 |
+
safeloras = safe_open(path, framework="pt", device=device)
|
| 623 |
+
return parse_safeloras_embeds(safeloras)
|
| 624 |
+
|
| 625 |
+
|
| 626 |
+
def load_safeloras_both(path, device="cpu"):
|
| 627 |
+
safeloras = safe_open(path, framework="pt", device=device)
|
| 628 |
+
return parse_safeloras(safeloras), parse_safeloras_embeds(safeloras)
|
| 629 |
+
|
| 630 |
+
|
| 631 |
+
def collapse_lora(model, alpha=1.0):
|
| 632 |
+
|
| 633 |
+
for _module, name, _child_module in _find_modules(
|
| 634 |
+
model,
|
| 635 |
+
UNET_EXTENDED_TARGET_REPLACE | TEXT_ENCODER_EXTENDED_TARGET_REPLACE,
|
| 636 |
+
search_class=[LoraInjectedLinear, LoraInjectedConv2d],
|
| 637 |
+
):
|
| 638 |
+
|
| 639 |
+
if isinstance(_child_module, LoraInjectedLinear):
|
| 640 |
+
print("Collapsing Lin Lora in", name)
|
| 641 |
+
|
| 642 |
+
_child_module.linear.weight = nn.Parameter(
|
| 643 |
+
_child_module.linear.weight.data
|
| 644 |
+
+ alpha
|
| 645 |
+
* (
|
| 646 |
+
_child_module.lora_up.weight.data
|
| 647 |
+
@ _child_module.lora_down.weight.data
|
| 648 |
+
)
|
| 649 |
+
.type(_child_module.linear.weight.dtype)
|
| 650 |
+
.to(_child_module.linear.weight.device)
|
| 651 |
+
)
|
| 652 |
+
|
| 653 |
+
else:
|
| 654 |
+
print("Collapsing Conv Lora in", name)
|
| 655 |
+
_child_module.conv.weight = nn.Parameter(
|
| 656 |
+
_child_module.conv.weight.data
|
| 657 |
+
+ alpha
|
| 658 |
+
* (
|
| 659 |
+
_child_module.lora_up.weight.data.flatten(start_dim=1)
|
| 660 |
+
@ _child_module.lora_down.weight.data.flatten(start_dim=1)
|
| 661 |
+
)
|
| 662 |
+
.reshape(_child_module.conv.weight.data.shape)
|
| 663 |
+
.type(_child_module.conv.weight.dtype)
|
| 664 |
+
.to(_child_module.conv.weight.device)
|
| 665 |
+
)
|
| 666 |
+
|
| 667 |
+
|
| 668 |
+
def monkeypatch_or_replace_lora(
|
| 669 |
+
model,
|
| 670 |
+
loras,
|
| 671 |
+
target_replace_module=DEFAULT_TARGET_REPLACE,
|
| 672 |
+
r: Union[int, List[int]] = 4,
|
| 673 |
+
):
|
| 674 |
+
for _module, name, _child_module in _find_modules(
|
| 675 |
+
model, target_replace_module, search_class=[nn.Linear, LoraInjectedLinear]
|
| 676 |
+
):
|
| 677 |
+
_source = (
|
| 678 |
+
_child_module.linear
|
| 679 |
+
if isinstance(_child_module, LoraInjectedLinear)
|
| 680 |
+
else _child_module
|
| 681 |
+
)
|
| 682 |
+
|
| 683 |
+
weight = _source.weight
|
| 684 |
+
bias = _source.bias
|
| 685 |
+
_tmp = LoraInjectedLinear(
|
| 686 |
+
_source.in_features,
|
| 687 |
+
_source.out_features,
|
| 688 |
+
_source.bias is not None,
|
| 689 |
+
r=r.pop(0) if isinstance(r, list) else r,
|
| 690 |
+
)
|
| 691 |
+
_tmp.linear.weight = weight
|
| 692 |
+
|
| 693 |
+
if bias is not None:
|
| 694 |
+
_tmp.linear.bias = bias
|
| 695 |
+
|
| 696 |
+
# switch the module
|
| 697 |
+
_module._modules[name] = _tmp
|
| 698 |
+
|
| 699 |
+
up_weight = loras.pop(0)
|
| 700 |
+
down_weight = loras.pop(0)
|
| 701 |
+
|
| 702 |
+
_module._modules[name].lora_up.weight = nn.Parameter(
|
| 703 |
+
up_weight.type(weight.dtype)
|
| 704 |
+
)
|
| 705 |
+
_module._modules[name].lora_down.weight = nn.Parameter(
|
| 706 |
+
down_weight.type(weight.dtype)
|
| 707 |
+
)
|
| 708 |
+
|
| 709 |
+
_module._modules[name].to(weight.device)
|
| 710 |
+
|
| 711 |
+
|
| 712 |
+
def monkeypatch_or_replace_lora_extended(
|
| 713 |
+
model,
|
| 714 |
+
loras,
|
| 715 |
+
target_replace_module=DEFAULT_TARGET_REPLACE,
|
| 716 |
+
r: Union[int, List[int]] = 4,
|
| 717 |
+
):
|
| 718 |
+
for _module, name, _child_module in _find_modules(
|
| 719 |
+
model,
|
| 720 |
+
target_replace_module,
|
| 721 |
+
search_class=[nn.Linear, LoraInjectedLinear, nn.Conv2d, LoraInjectedConv2d],
|
| 722 |
+
):
|
| 723 |
+
|
| 724 |
+
if (_child_module.__class__ == nn.Linear) or (
|
| 725 |
+
_child_module.__class__ == LoraInjectedLinear
|
| 726 |
+
):
|
| 727 |
+
if len(loras[0].shape) != 2:
|
| 728 |
+
continue
|
| 729 |
+
|
| 730 |
+
_source = (
|
| 731 |
+
_child_module.linear
|
| 732 |
+
if isinstance(_child_module, LoraInjectedLinear)
|
| 733 |
+
else _child_module
|
| 734 |
+
)
|
| 735 |
+
|
| 736 |
+
weight = _source.weight
|
| 737 |
+
bias = _source.bias
|
| 738 |
+
_tmp = LoraInjectedLinear(
|
| 739 |
+
_source.in_features,
|
| 740 |
+
_source.out_features,
|
| 741 |
+
_source.bias is not None,
|
| 742 |
+
r=r.pop(0) if isinstance(r, list) else r,
|
| 743 |
+
)
|
| 744 |
+
_tmp.linear.weight = weight
|
| 745 |
+
|
| 746 |
+
if bias is not None:
|
| 747 |
+
_tmp.linear.bias = bias
|
| 748 |
+
|
| 749 |
+
elif (_child_module.__class__ == nn.Conv2d) or (
|
| 750 |
+
_child_module.__class__ == LoraInjectedConv2d
|
| 751 |
+
):
|
| 752 |
+
if len(loras[0].shape) != 4:
|
| 753 |
+
continue
|
| 754 |
+
_source = (
|
| 755 |
+
_child_module.conv
|
| 756 |
+
if isinstance(_child_module, LoraInjectedConv2d)
|
| 757 |
+
else _child_module
|
| 758 |
+
)
|
| 759 |
+
|
| 760 |
+
weight = _source.weight
|
| 761 |
+
bias = _source.bias
|
| 762 |
+
_tmp = LoraInjectedConv2d(
|
| 763 |
+
_source.in_channels,
|
| 764 |
+
_source.out_channels,
|
| 765 |
+
_source.kernel_size,
|
| 766 |
+
_source.stride,
|
| 767 |
+
_source.padding,
|
| 768 |
+
_source.dilation,
|
| 769 |
+
_source.groups,
|
| 770 |
+
_source.bias is not None,
|
| 771 |
+
r=r.pop(0) if isinstance(r, list) else r,
|
| 772 |
+
)
|
| 773 |
+
|
| 774 |
+
_tmp.conv.weight = weight
|
| 775 |
+
|
| 776 |
+
if bias is not None:
|
| 777 |
+
_tmp.conv.bias = bias
|
| 778 |
+
|
| 779 |
+
# switch the module
|
| 780 |
+
_module._modules[name] = _tmp
|
| 781 |
+
|
| 782 |
+
up_weight = loras.pop(0)
|
| 783 |
+
down_weight = loras.pop(0)
|
| 784 |
+
|
| 785 |
+
_module._modules[name].lora_up.weight = nn.Parameter(
|
| 786 |
+
up_weight.type(weight.dtype)
|
| 787 |
+
)
|
| 788 |
+
_module._modules[name].lora_down.weight = nn.Parameter(
|
| 789 |
+
down_weight.type(weight.dtype)
|
| 790 |
+
)
|
| 791 |
+
|
| 792 |
+
_module._modules[name].to(weight.device)
|
| 793 |
+
|
| 794 |
+
|
| 795 |
+
def monkeypatch_or_replace_safeloras(models, safeloras):
|
| 796 |
+
loras = parse_safeloras(safeloras)
|
| 797 |
+
|
| 798 |
+
for name, (lora, ranks, target) in loras.items():
|
| 799 |
+
model = getattr(models, name, None)
|
| 800 |
+
|
| 801 |
+
if not model:
|
| 802 |
+
print(f"No model provided for {name}, contained in Lora")
|
| 803 |
+
continue
|
| 804 |
+
|
| 805 |
+
monkeypatch_or_replace_lora_extended(model, lora, target, ranks)
|
| 806 |
+
|
| 807 |
+
|
| 808 |
+
def monkeypatch_remove_lora(model):
|
| 809 |
+
for _module, name, _child_module in _find_modules(
|
| 810 |
+
model, search_class=[LoraInjectedLinear, LoraInjectedConv2d]
|
| 811 |
+
):
|
| 812 |
+
if isinstance(_child_module, LoraInjectedLinear):
|
| 813 |
+
_source = _child_module.linear
|
| 814 |
+
weight, bias = _source.weight, _source.bias
|
| 815 |
+
|
| 816 |
+
_tmp = nn.Linear(
|
| 817 |
+
_source.in_features, _source.out_features, bias is not None
|
| 818 |
+
)
|
| 819 |
+
|
| 820 |
+
_tmp.weight = weight
|
| 821 |
+
if bias is not None:
|
| 822 |
+
_tmp.bias = bias
|
| 823 |
+
|
| 824 |
+
else:
|
| 825 |
+
_source = _child_module.conv
|
| 826 |
+
weight, bias = _source.weight, _source.bias
|
| 827 |
+
|
| 828 |
+
_tmp = nn.Conv2d(
|
| 829 |
+
in_channels=_source.in_channels,
|
| 830 |
+
out_channels=_source.out_channels,
|
| 831 |
+
kernel_size=_source.kernel_size,
|
| 832 |
+
stride=_source.stride,
|
| 833 |
+
padding=_source.padding,
|
| 834 |
+
dilation=_source.dilation,
|
| 835 |
+
groups=_source.groups,
|
| 836 |
+
bias=bias is not None,
|
| 837 |
+
)
|
| 838 |
+
|
| 839 |
+
_tmp.weight = weight
|
| 840 |
+
if bias is not None:
|
| 841 |
+
_tmp.bias = bias
|
| 842 |
+
|
| 843 |
+
_module._modules[name] = _tmp
|
| 844 |
+
|
| 845 |
+
|
| 846 |
+
def monkeypatch_add_lora(
|
| 847 |
+
model,
|
| 848 |
+
loras,
|
| 849 |
+
target_replace_module=DEFAULT_TARGET_REPLACE,
|
| 850 |
+
alpha: float = 1.0,
|
| 851 |
+
beta: float = 1.0,
|
| 852 |
+
):
|
| 853 |
+
for _module, name, _child_module in _find_modules(
|
| 854 |
+
model, target_replace_module, search_class=[LoraInjectedLinear]
|
| 855 |
+
):
|
| 856 |
+
weight = _child_module.linear.weight
|
| 857 |
+
|
| 858 |
+
up_weight = loras.pop(0)
|
| 859 |
+
down_weight = loras.pop(0)
|
| 860 |
+
|
| 861 |
+
_module._modules[name].lora_up.weight = nn.Parameter(
|
| 862 |
+
up_weight.type(weight.dtype).to(weight.device) * alpha
|
| 863 |
+
+ _module._modules[name].lora_up.weight.to(weight.device) * beta
|
| 864 |
+
)
|
| 865 |
+
_module._modules[name].lora_down.weight = nn.Parameter(
|
| 866 |
+
down_weight.type(weight.dtype).to(weight.device) * alpha
|
| 867 |
+
+ _module._modules[name].lora_down.weight.to(weight.device) * beta
|
| 868 |
+
)
|
| 869 |
+
|
| 870 |
+
_module._modules[name].to(weight.device)
|
| 871 |
+
|
| 872 |
+
|
| 873 |
+
def tune_lora_scale(model, alpha: float = 1.0):
|
| 874 |
+
for _module in model.modules():
|
| 875 |
+
if _module.__class__.__name__ in ["LoraInjectedLinear", "LoraInjectedConv2d"]:
|
| 876 |
+
_module.scale = alpha
|
| 877 |
+
|
| 878 |
+
|
| 879 |
+
def set_lora_diag(model, diag: torch.Tensor):
|
| 880 |
+
for _module in model.modules():
|
| 881 |
+
if _module.__class__.__name__ in ["LoraInjectedLinear", "LoraInjectedConv2d"]:
|
| 882 |
+
_module.set_selector_from_diag(diag)
|
| 883 |
+
|
| 884 |
+
|
| 885 |
+
def _text_lora_path(path: str) -> str:
|
| 886 |
+
assert path.endswith(".pt"), "Only .pt files are supported"
|
| 887 |
+
return ".".join(path.split(".")[:-1] + ["text_encoder", "pt"])
|
| 888 |
+
|
| 889 |
+
|
| 890 |
+
def _ti_lora_path(path: str) -> str:
|
| 891 |
+
assert path.endswith(".pt"), "Only .pt files are supported"
|
| 892 |
+
return ".".join(path.split(".")[:-1] + ["ti", "pt"])
|
| 893 |
+
|
| 894 |
+
|
| 895 |
+
def apply_learned_embed_in_clip(
|
| 896 |
+
learned_embeds,
|
| 897 |
+
text_encoder,
|
| 898 |
+
tokenizer,
|
| 899 |
+
token: Optional[Union[str, List[str]]] = None,
|
| 900 |
+
idempotent=False,
|
| 901 |
+
):
|
| 902 |
+
if isinstance(token, str):
|
| 903 |
+
trained_tokens = [token]
|
| 904 |
+
elif isinstance(token, list):
|
| 905 |
+
assert len(learned_embeds.keys()) == len(
|
| 906 |
+
token
|
| 907 |
+
), "The number of tokens and the number of embeds should be the same"
|
| 908 |
+
trained_tokens = token
|
| 909 |
+
else:
|
| 910 |
+
trained_tokens = list(learned_embeds.keys())
|
| 911 |
+
|
| 912 |
+
for token in trained_tokens:
|
| 913 |
+
print(token)
|
| 914 |
+
embeds = learned_embeds[token]
|
| 915 |
+
|
| 916 |
+
# cast to dtype of text_encoder
|
| 917 |
+
dtype = text_encoder.get_input_embeddings().weight.dtype
|
| 918 |
+
num_added_tokens = tokenizer.add_tokens(token)
|
| 919 |
+
|
| 920 |
+
i = 1
|
| 921 |
+
if not idempotent:
|
| 922 |
+
while num_added_tokens == 0:
|
| 923 |
+
print(f"The tokenizer already contains the token {token}.")
|
| 924 |
+
token = f"{token[:-1]}-{i}>"
|
| 925 |
+
print(f"Attempting to add the token {token}.")
|
| 926 |
+
num_added_tokens = tokenizer.add_tokens(token)
|
| 927 |
+
i += 1
|
| 928 |
+
elif num_added_tokens == 0 and idempotent:
|
| 929 |
+
print(f"The tokenizer already contains the token {token}.")
|
| 930 |
+
print(f"Replacing {token} embedding.")
|
| 931 |
+
|
| 932 |
+
# resize the token embeddings
|
| 933 |
+
text_encoder.resize_token_embeddings(len(tokenizer))
|
| 934 |
+
|
| 935 |
+
# get the id for the token and assign the embeds
|
| 936 |
+
token_id = tokenizer.convert_tokens_to_ids(token)
|
| 937 |
+
text_encoder.get_input_embeddings().weight.data[token_id] = embeds
|
| 938 |
+
return token
|
| 939 |
+
|
| 940 |
+
|
| 941 |
+
def load_learned_embed_in_clip(
|
| 942 |
+
learned_embeds_path,
|
| 943 |
+
text_encoder,
|
| 944 |
+
tokenizer,
|
| 945 |
+
token: Optional[Union[str, List[str]]] = None,
|
| 946 |
+
idempotent=False,
|
| 947 |
+
):
|
| 948 |
+
learned_embeds = torch.load(learned_embeds_path)
|
| 949 |
+
apply_learned_embed_in_clip(
|
| 950 |
+
learned_embeds, text_encoder, tokenizer, token, idempotent
|
| 951 |
+
)
|
| 952 |
+
|
| 953 |
+
|
| 954 |
+
def patch_pipe(
|
| 955 |
+
pipe,
|
| 956 |
+
maybe_unet_path,
|
| 957 |
+
token: Optional[str] = None,
|
| 958 |
+
r: int = 4,
|
| 959 |
+
patch_unet=True,
|
| 960 |
+
patch_text=True,
|
| 961 |
+
patch_ti=True,
|
| 962 |
+
idempotent_token=True,
|
| 963 |
+
unet_target_replace_module=DEFAULT_TARGET_REPLACE,
|
| 964 |
+
text_target_replace_module=TEXT_ENCODER_DEFAULT_TARGET_REPLACE,
|
| 965 |
+
):
|
| 966 |
+
if maybe_unet_path.endswith(".pt"):
|
| 967 |
+
# torch format
|
| 968 |
+
|
| 969 |
+
if maybe_unet_path.endswith(".ti.pt"):
|
| 970 |
+
unet_path = maybe_unet_path[:-6] + ".pt"
|
| 971 |
+
elif maybe_unet_path.endswith(".text_encoder.pt"):
|
| 972 |
+
unet_path = maybe_unet_path[:-16] + ".pt"
|
| 973 |
+
else:
|
| 974 |
+
unet_path = maybe_unet_path
|
| 975 |
+
|
| 976 |
+
ti_path = _ti_lora_path(unet_path)
|
| 977 |
+
text_path = _text_lora_path(unet_path)
|
| 978 |
+
|
| 979 |
+
if patch_unet:
|
| 980 |
+
print("LoRA : Patching Unet")
|
| 981 |
+
monkeypatch_or_replace_lora(
|
| 982 |
+
pipe.unet,
|
| 983 |
+
torch.load(unet_path),
|
| 984 |
+
r=r,
|
| 985 |
+
target_replace_module=unet_target_replace_module,
|
| 986 |
+
)
|
| 987 |
+
|
| 988 |
+
if patch_text:
|
| 989 |
+
print("LoRA : Patching text encoder")
|
| 990 |
+
monkeypatch_or_replace_lora(
|
| 991 |
+
pipe.text_encoder,
|
| 992 |
+
torch.load(text_path),
|
| 993 |
+
target_replace_module=text_target_replace_module,
|
| 994 |
+
r=r,
|
| 995 |
+
)
|
| 996 |
+
if patch_ti:
|
| 997 |
+
print("LoRA : Patching token input")
|
| 998 |
+
token = load_learned_embed_in_clip(
|
| 999 |
+
ti_path,
|
| 1000 |
+
pipe.text_encoder,
|
| 1001 |
+
pipe.tokenizer,
|
| 1002 |
+
token=token,
|
| 1003 |
+
idempotent=idempotent_token,
|
| 1004 |
+
)
|
| 1005 |
+
|
| 1006 |
+
elif maybe_unet_path.endswith(".safetensors"):
|
| 1007 |
+
safeloras = safe_open(maybe_unet_path, framework="pt", device="cpu")
|
| 1008 |
+
monkeypatch_or_replace_safeloras(pipe, safeloras)
|
| 1009 |
+
tok_dict = parse_safeloras_embeds(safeloras)
|
| 1010 |
+
if patch_ti:
|
| 1011 |
+
apply_learned_embed_in_clip(
|
| 1012 |
+
tok_dict,
|
| 1013 |
+
pipe.text_encoder,
|
| 1014 |
+
pipe.tokenizer,
|
| 1015 |
+
token=token,
|
| 1016 |
+
idempotent=idempotent_token,
|
| 1017 |
+
)
|
| 1018 |
+
return tok_dict
|
| 1019 |
+
|
| 1020 |
+
|
| 1021 |
+
@torch.no_grad()
|
| 1022 |
+
def inspect_lora(model):
|
| 1023 |
+
moved = {}
|
| 1024 |
+
|
| 1025 |
+
for name, _module in model.named_modules():
|
| 1026 |
+
if _module.__class__.__name__ in ["LoraInjectedLinear", "LoraInjectedConv2d"]:
|
| 1027 |
+
ups = _module.lora_up.weight.data.clone()
|
| 1028 |
+
downs = _module.lora_down.weight.data.clone()
|
| 1029 |
+
|
| 1030 |
+
wght: torch.Tensor = ups.flatten(1) @ downs.flatten(1)
|
| 1031 |
+
|
| 1032 |
+
dist = wght.flatten().abs().mean().item()
|
| 1033 |
+
if name in moved:
|
| 1034 |
+
moved[name].append(dist)
|
| 1035 |
+
else:
|
| 1036 |
+
moved[name] = [dist]
|
| 1037 |
+
|
| 1038 |
+
return moved
|
| 1039 |
+
|
| 1040 |
+
|
| 1041 |
+
def save_all(
|
| 1042 |
+
unet,
|
| 1043 |
+
text_encoder,
|
| 1044 |
+
save_path,
|
| 1045 |
+
placeholder_token_ids=None,
|
| 1046 |
+
placeholder_tokens=None,
|
| 1047 |
+
save_lora=True,
|
| 1048 |
+
save_ti=True,
|
| 1049 |
+
target_replace_module_text=TEXT_ENCODER_DEFAULT_TARGET_REPLACE,
|
| 1050 |
+
target_replace_module_unet=DEFAULT_TARGET_REPLACE,
|
| 1051 |
+
safe_form=True,
|
| 1052 |
+
):
|
| 1053 |
+
if not safe_form:
|
| 1054 |
+
# save ti
|
| 1055 |
+
if save_ti:
|
| 1056 |
+
ti_path = _ti_lora_path(save_path)
|
| 1057 |
+
learned_embeds_dict = {}
|
| 1058 |
+
for tok, tok_id in zip(placeholder_tokens, placeholder_token_ids):
|
| 1059 |
+
learned_embeds = text_encoder.get_input_embeddings().weight[tok_id]
|
| 1060 |
+
print(
|
| 1061 |
+
f"Current Learned Embeddings for {tok}:, id {tok_id} ",
|
| 1062 |
+
learned_embeds[:4],
|
| 1063 |
+
)
|
| 1064 |
+
learned_embeds_dict[tok] = learned_embeds.detach().cpu()
|
| 1065 |
+
|
| 1066 |
+
torch.save(learned_embeds_dict, ti_path)
|
| 1067 |
+
print("Ti saved to ", ti_path)
|
| 1068 |
+
|
| 1069 |
+
# save text encoder
|
| 1070 |
+
if save_lora:
|
| 1071 |
+
|
| 1072 |
+
save_lora_weight(
|
| 1073 |
+
unet, save_path, target_replace_module=target_replace_module_unet
|
| 1074 |
+
)
|
| 1075 |
+
print("Unet saved to ", save_path)
|
| 1076 |
+
|
| 1077 |
+
save_lora_weight(
|
| 1078 |
+
text_encoder,
|
| 1079 |
+
_text_lora_path(save_path),
|
| 1080 |
+
target_replace_module=target_replace_module_text,
|
| 1081 |
+
)
|
| 1082 |
+
print("Text Encoder saved to ", _text_lora_path(save_path))
|
| 1083 |
+
|
| 1084 |
+
else:
|
| 1085 |
+
assert save_path.endswith(
|
| 1086 |
+
".safetensors"
|
| 1087 |
+
), f"Save path : {save_path} should end with .safetensors"
|
| 1088 |
+
|
| 1089 |
+
loras = {}
|
| 1090 |
+
embeds = {}
|
| 1091 |
+
|
| 1092 |
+
if save_lora:
|
| 1093 |
+
|
| 1094 |
+
loras["unet"] = (unet, target_replace_module_unet)
|
| 1095 |
+
loras["text_encoder"] = (text_encoder, target_replace_module_text)
|
| 1096 |
+
|
| 1097 |
+
if save_ti:
|
| 1098 |
+
for tok, tok_id in zip(placeholder_tokens, placeholder_token_ids):
|
| 1099 |
+
learned_embeds = text_encoder.get_input_embeddings().weight[tok_id]
|
| 1100 |
+
print(
|
| 1101 |
+
f"Current Learned Embeddings for {tok}:, id {tok_id} ",
|
| 1102 |
+
learned_embeds[:4],
|
| 1103 |
+
)
|
| 1104 |
+
embeds[tok] = learned_embeds.detach().cpu()
|
| 1105 |
+
|
| 1106 |
+
save_safeloras_with_embeds(loras, embeds, save_path)
|
README.md
CHANGED
|
@@ -1,3 +1,511 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div align="center">
|
| 2 |
+
|
| 3 |
+
# TherA: Thermal-Aware Visual-Language Prompting for<br>Controllable RGB-to-Thermal Infrared Translation
|
| 4 |
+
|
| 5 |
+
[**Dong-Guw Lee**](https://scholar.google.com/citations?user=u6VDnlgAAAAJ&hl=ko)<sup>1*</sup> 
|
| 6 |
+
[**Tai Hyoung Rhee**](https://scholar.google.com/citations?user=PF8EfdYAAAAJ&hl=en&oi=ao)<sup>1*</sup> 
|
| 7 |
+
[**Hyunsoo Jang**](https://rpm.snu.ac.kr)<sup>1</sup><br>
|
| 8 |
+
[**Young-Sik Shin**](https://scholar.google.com/citations?user=gGfBRawAAAAJ&hl=en&oi=ao)<sup>2</sup> 
|
| 9 |
+
[**Ukcheol Shin**](https://scholar.google.com/citations?user=ZvxI80EAAAAJ&hl=ko&oi=ao)<sup>3</sup> 
|
| 10 |
+
[**Ayoung Kim**](https://ayoungk.github.io/)<sup>1†</sup>
|
| 11 |
+
|
| 12 |
+
<sup>1</sup>Seoul National University 
|
| 13 |
+
<sup>2</sup>Kyungpook National University 
|
| 14 |
+
<sup>3</sup>KENTECH
|
| 15 |
+
<sup>*</sup> Equal Contribution 
|
| 16 |
+
<sup>†</sup> Corresponding Author
|
| 17 |
+
|
| 18 |
+
**CVPR 2026**
|
| 19 |
+
|
| 20 |
+
[](https://donkeymouse.github.io/thera_cvpr26/)
|
| 21 |
+
[](https://arxiv.org/abs/2602.19430)
|
| 22 |
+
[](https://github.com/donkeymouse/TherA)
|
| 23 |
+
[](https://huggingface.co/donkeymouse/TherA/tree/main)
|
| 24 |
+
[](https://huggingface.co/datasets/donkeymouse/TherA-R2T2)
|
| 25 |
+
[](https://hub.docker.com/r/donkeymouse/thera)
|
| 26 |
+
|
| 27 |
+
</div>
|
| 28 |
+
|
| 29 |
+
<p align="center">
|
| 30 |
+
<img src="assets/method.png" width="90%" alt="TherA method overview">
|
| 31 |
+
</p>
|
| 32 |
+
|
| 33 |
+
|
| 34 |
---
|
| 35 |
+
|
| 36 |
+
## News
|
| 37 |
+
|
| 38 |
+
- **2026-04-03**: TherA github repo opening
|
| 39 |
+
- **2026-05-22**: TherA inference code and R2T2 dataset release.
|
| 40 |
+
|
| 41 |
---
|
| 42 |
+
|
| 43 |
+
## Overview
|
| 44 |
+
|
| 45 |
+
**TherA** is a controllable RGB-to-thermal infrared translation framework. Given an RGB image, TherA synthesizes a long-wave thermal infrared image using a latent-diffusion translator conditioned on thermal-aware visual-language features.
|
| 46 |
+
|
| 47 |
+
TherA is designed for:
|
| 48 |
+
|
| 49 |
+
- **RGB → TIR translation** for thermal perception research.
|
| 50 |
+
- **Thermal-aware VLM conditioning** using LLaVA hidden-state features.
|
| 51 |
+
- **Scene- and object-level controllability** across weather, time of day, and object state.
|
| 52 |
+
- **Reference-cache inference**, allowing deployment without loading LLaVA at runtime.
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
<div align="center">
|
| 56 |
+
<a href="https://www.youtube.com/watch?v=X60UxjGKQkg">
|
| 57 |
+
<img src="https://img.youtube.com/vi/X60UxjGKQkg/0.jpg" alt="TherA demo video" width="720">
|
| 58 |
+
</a>
|
| 59 |
+
</div>
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
---
|
| 63 |
+
|
| 64 |
+
## Key Idea
|
| 65 |
+
|
| 66 |
+
TherA does **not** condition directly on raw text during diffusion inference. Instead, it uses a **4096-dimensional LLaVA hidden state**, either:
|
| 67 |
+
|
| 68 |
+
1. loaded from a precomputed `.pt` reference cache, or
|
| 69 |
+
2. extracted on the fly using LLaVA.
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
For resource limited environments, we recommend **reference-cache mode**. This mode uses precomputed LLaVA features such as `SUNNY.pt`, `CLOUDY.pt`, `RAINY.pt`, or `NIGHT.pt`, and therefore does **not** require loading LLaVA weights at runtime. An alternative would be to compute pre-computed LLaVA feature first followed by inferencing with reference-cache mode (upcoming feature).
|
| 74 |
+
|
| 75 |
+
---
|
| 76 |
+
## Repository Layout
|
| 77 |
+
|
| 78 |
+
```text
|
| 79 |
+
TherA/
|
| 80 |
+
├── infer_custom.py # Batch RGB → TIR inference on a folder
|
| 81 |
+
├── infer_example_guided.py # Single-image / example-guided inference
|
| 82 |
+
├── infer_palette.sh # Run multiple weather/style palettes
|
| 83 |
+
├── lavi_ip2p/ # UNet 8-channel + adapter wrapper
|
| 84 |
+
├── LaVi-Bridge/modules/ # TextAdapter architecture
|
| 85 |
+
├── llava/ # LLaVA code, only needed for on-the-fly mode
|
| 86 |
+
├── thera_paths.py # Default local weight paths
|
| 87 |
+
├── thera_llava.py # Lazy LLaVA loader
|
| 88 |
+
└── weights/ # Download weights here; not tracked by git
|
| 89 |
+
├── model.pt # TherA Model
|
| 90 |
+
├── merged_models/ # Initialization model
|
| 91 |
+
│ ├── unet/
|
| 92 |
+
│ └── adapter/
|
| 93 |
+
├── stable-diffusion/
|
| 94 |
+
│ ├── vae/
|
| 95 |
+
│ └── scheduler/
|
| 96 |
+
├── reference_caches/
|
| 97 |
+
│ ├── SUNNY.pt
|
| 98 |
+
│ ├── CLOUDY.pt
|
| 99 |
+
│ ├── RAINY.pt
|
| 100 |
+
│ └── NIGHT.pt
|
| 101 |
+
├── reference_caches/
|
| 102 |
+
│ │ ├── SUNNY.pt
|
| 103 |
+
│ │ ├── CLOUDY.pt
|
| 104 |
+
│ │ ├── RAINY.pt
|
| 105 |
+
│ │ └── NIGHT.pt
|
| 106 |
+
└── TherA-VLM/ # Optional; only for on-the-fly mode
|
| 107 |
+
├── adaptor_config.json/
|
| 108 |
+
└── adapter_model.safetensors
|
| 109 |
+
└── config.json
|
| 110 |
+
└── non_lora_trainables.bin
|
| 111 |
+
└── trainer_state.json
|
| 112 |
+
```
|
| 113 |
+
|
| 114 |
+
---
|
| 115 |
+
|
| 116 |
+
## Installation
|
| 117 |
+
|
| 118 |
+
### Option 1: Local Python Environment
|
| 119 |
+
|
| 120 |
+
```bash
|
| 121 |
+
git clone https://github.com/donkeymouse/TherA.git
|
| 122 |
+
cd TherA
|
| 123 |
+
|
| 124 |
+
python -m venv .venv
|
| 125 |
+
source .venv/bin/activate
|
| 126 |
+
|
| 127 |
+
pip install --upgrade pip
|
| 128 |
+
pip install -r requirements.txt
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
**Recommended environment**
|
| 132 |
+
|
| 133 |
+
- Python 3.10+
|
| 134 |
+
- CUDA-capable GPU
|
| 135 |
+
- 16 GB+ VRAM recommended for comfortable inference
|
| 136 |
+
|
| 137 |
+
---
|
| 138 |
+
|
| 139 |
+
### Option 2: Docker
|
| 140 |
+
|
| 141 |
+
A prebuilt Docker image is available at:
|
| 142 |
+
|
| 143 |
+
```bash
|
| 144 |
+
docker pull donkeymouse/thera:latest
|
| 145 |
+
```
|
| 146 |
+
|
| 147 |
+
Example interactive run:
|
| 148 |
+
|
| 149 |
+
```bash
|
| 150 |
+
docker run --gpus all --rm -it \
|
| 151 |
+
-v "$(pwd)":/workspace/TherA \
|
| 152 |
+
-w /workspace/TherA \
|
| 153 |
+
donkeymouse/thera:latest \
|
| 154 |
+
bash
|
| 155 |
+
```
|
| 156 |
+
|
| 157 |
+
Then run inference commands from inside the container.
|
| 158 |
+
|
| 159 |
+
---
|
| 160 |
+
|
| 161 |
+
## Download Weights
|
| 162 |
+
|
| 163 |
+
TherA weights are hosted on Hugging Face:
|
| 164 |
+
|
| 165 |
+
```bash
|
| 166 |
+
pip install -U huggingface_hub
|
| 167 |
+
|
| 168 |
+
huggingface-cli download donkeymouse/TherA \
|
| 169 |
+
--local-dir weights
|
| 170 |
+
```
|
| 171 |
+
|
| 172 |
+
After downloading, your `weights/` directory should contain:
|
| 173 |
+
|
| 174 |
+
| Path | Description | Required? |
|
| 175 |
+
|---|---|---|
|
| 176 |
+
| `weights/model.pt` | TherA trained UNet and adapter checkpoint | Yes |
|
| 177 |
+
| `weights/merged_models/unet/` | UNet architecture/config files | Yes |
|
| 178 |
+
| `weights/merged_models/adapter/` | TextAdapter architecture/config files | Yes |
|
| 179 |
+
| `weights/stable-diffusion/vae/` | Stable Diffusion VAE | Yes |
|
| 180 |
+
| `weights/stable-diffusion/scheduler/` | DDIM scheduler config | Yes |
|
| 181 |
+
| `weights/reference_caches/*.pt` | Precomputed LLaVA hidden states for inference palettes | Recommended |
|
| 182 |
+
| `weights/TherA-VLM/` | LLaVA weights for on-the-fly feature extraction | Optional |
|
| 183 |
+
|
| 184 |
+
---
|
| 185 |
+
|
| 186 |
+
## Optional: Download LLaVA Weights
|
| 187 |
+
|
| 188 |
+
LLaVA is only required for **on-the-fly feature extraction** or **two-image guided mode**. It is not required for reference-cache inference.
|
| 189 |
+
|
| 190 |
+
```bash
|
| 191 |
+
huggingface-cli download llava-hf/llava-1.5-7b-hf \
|
| 192 |
+
--local-dir weights/llava-1.5-7b-hf
|
| 193 |
+
```
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
---
|
| 197 |
+
|
| 198 |
+
## Quick Start
|
| 199 |
+
|
| 200 |
+
---
|
| 201 |
+
|
| 202 |
+
## Full RGB-TIR translation using TherA-VLM
|
| 203 |
+
|
| 204 |
+
Use this mode if you want to extract hidden states from TherA directly at runtime from an RGB image and prompt.
|
| 205 |
+
|
| 206 |
+
```bash
|
| 207 |
+
python infer_custom.py \
|
| 208 |
+
--rgb-dir examples/rgb \
|
| 209 |
+
--output-dir preds \
|
| 210 |
+
--llava-base-path weights/llava-1.5-7b-hf \
|
| 211 |
+
--llava-lora-path weights/TherA-VLM \
|
| 212 |
+
--llava-prompt "How would this RGB scene appear in long-wave thermal infrared spectrum."
|
| 213 |
+
```
|
| 214 |
+
|
| 215 |
+
This mode is more expensive because it loads LLaVA during inference.
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
### Reference-Guided Image Translation Mode
|
| 220 |
+
|
| 221 |
+
This mode extracts LLaVA features from a reference RGB image and applies them to a target RGB image.
|
| 222 |
+
|
| 223 |
+
```bash
|
| 224 |
+
python infer_example_guided.py \
|
| 225 |
+
--mode two-image \
|
| 226 |
+
--reference-image examples/ref/rgb.jpg \
|
| 227 |
+
--input-image examples/rgb/scene.jpg \
|
| 228 |
+
--output preds/scene_tir.png \
|
| 229 |
+
--llava-base-path weights/llava-1.5-7b-hf \
|
| 230 |
+
--llava-lora-path weights/TherA-VLM
|
| 231 |
+
```
|
| 232 |
+
|
| 233 |
+
---
|
| 234 |
+
|
| 235 |
+
### Recursive Folder Inference
|
| 236 |
+
|
| 237 |
+
```bash
|
| 238 |
+
python infer_custom.py \
|
| 239 |
+
--rgb-dir /path/to/dataset/RGB \
|
| 240 |
+
--output-dir preds \
|
| 241 |
+
--reference-cache weights/reference_caches/SUNNY.pt \
|
| 242 |
+
--recursive
|
| 243 |
+
```
|
| 244 |
+
|
| 245 |
+
When `--recursive` is used, the output folder preserves the input directory structure.
|
| 246 |
+
|
| 247 |
+
---
|
| 248 |
+
---
|
| 249 |
+
|
| 250 |
+
## Reference-cache Mode
|
| 251 |
+
Reference-cache mode is the recommended if you are lacking GPU memory. It does not load LLaVA at runtime.
|
| 252 |
+
|
| 253 |
+
```bash
|
| 254 |
+
python infer_custom.py \
|
| 255 |
+
--rgb-dir examples/rgb \
|
| 256 |
+
--output-dir preds/sunny \
|
| 257 |
+
--reference-cache weights/reference_caches/SUNNY.pt
|
| 258 |
+
```
|
| 259 |
+
|
| 260 |
+
The script reads all images in `examples/rgb` and writes translated TIR images to `preds/sunny`.
|
| 261 |
+
|
| 262 |
+
A lighter version of the text-guided image translation module.
|
| 263 |
+
|
| 264 |
+
Example palette caches:
|
| 265 |
+
|
| 266 |
+
```text
|
| 267 |
+
weights/reference_caches/SUNNY.pt
|
| 268 |
+
weights/reference_caches/CLOUDY.pt
|
| 269 |
+
weights/reference_caches/RAINY.pt
|
| 270 |
+
weights/reference_caches/NIGHT.pt
|
| 271 |
+
```
|
| 272 |
+
|
| 273 |
+
You can use different pallete cache to achieve different translation effects.
|
| 274 |
+
|
| 275 |
+
---
|
| 276 |
+
|
| 277 |
+
## Inference Modes
|
| 278 |
+
|
| 279 |
+
| Mode | Main flag / script | LLaVA weights needed? | Recommended use |
|
| 280 |
+
|---|---|---:|---|
|
| 281 |
+
| Reference cache | `--reference-cache path.pt` | No | Default deployment and fast inference |
|
| 282 |
+
| Per-image cache directory | `--cache-dir dir/` | No | Precomputed feature per image |
|
| 283 |
+
| Full RGB-TIR translation| `--llava-base-path ...` | Yes | Runtime prompt/image conditioning |
|
| 284 |
+
| Reference image-guided translation| `infer_example_guided.py --mode two-image` | Yes | Apply reference-image conditioning |
|
| 285 |
+
|
| 286 |
+
---
|
| 287 |
+
|
| 288 |
+
## Reference Cache Format
|
| 289 |
+
|
| 290 |
+
Reference caches are precomputed LLaVA hidden states saved as `.pt` files.
|
| 291 |
+
|
| 292 |
+
Supported tensor shapes:
|
| 293 |
+
|
| 294 |
+
```text
|
| 295 |
+
[1, L, 4096]
|
| 296 |
+
[L, 4096]
|
| 297 |
+
```
|
| 298 |
+
|
| 299 |
+
A single reference cache can be applied to all input images as a global thermal/weather/style condition.
|
| 300 |
+
|
| 301 |
+
---
|
| 302 |
+
|
| 303 |
+
## Important Arguments
|
| 304 |
+
|
| 305 |
+
| Argument | Default | Description |
|
| 306 |
+
|---|---:|---|
|
| 307 |
+
| `--checkpoint` | `weights/checkpoint` | Directory containing `model.pt` |
|
| 308 |
+
| `--merged-model-path` | `weights/merged_models` | Directory containing UNet and adapter configs |
|
| 309 |
+
| `--pretrained-sd` | `weights/stable-diffusion` | Directory containing VAE and scheduler |
|
| 310 |
+
| `--rgb-dir` | Required | Folder of RGB images for batch inference |
|
| 311 |
+
| `--output-dir` | `custom_predictions` | Output folder for predictions |
|
| 312 |
+
| `--reference-cache` | `None` | Single `.pt` cache used for all images |
|
| 313 |
+
| `--cache-dir` | `None` | Folder of per-image `.pt` caches matched by filename stem |
|
| 314 |
+
| `--llava-base-path` | `None` | Base LLaVA model path for on-the-fly mode |
|
| 315 |
+
| `--llava-lora-path` | `None` | Optional LLaVA LoRA path |
|
| 316 |
+
| `--llava-prompt` | thermal prompt | Prompt used for default inference/text-guided translation|
|
| 317 |
+
| `--num-steps` | `100` | DDIM sampling steps |
|
| 318 |
+
| `--cfg-text` | `3.5` | Text/VLM guidance strength |
|
| 319 |
+
| `--cfg-image` | `1.5` | Image guidance strength |
|
| 320 |
+
| `--target-size` | Auto | Resize image to this square size; otherwise dimensions are rounded to multiples of 32 |
|
| 321 |
+
| `--recursive` | Off | Recursively process subdirectories |
|
| 322 |
+
| `--device` | `cuda` | Device for inference |
|
| 323 |
+
|
| 324 |
+
---
|
| 325 |
+
|
| 326 |
+
## Architecture
|
| 327 |
+
|
| 328 |
+
```text
|
| 329 |
+
RGB image
|
| 330 |
+
│
|
| 331 |
+
▼
|
| 332 |
+
VAE encoder ──► RGB latents ───────────────────┐
|
| 333 |
+
│
|
| 334 |
+
├──► 8-channel diffusion UNet ──► VAE decoder ──► TIR image
|
| 335 |
+
│
|
| 336 |
+
LLaVA hidden state, 4096-d ──► TextAdapter ─────┘
|
| 337 |
+
768-d cross-attention tokens
|
| 338 |
+
```
|
| 339 |
+
|
| 340 |
+
TherA uses dual classifier-free guidance at inference by combining:
|
| 341 |
+
|
| 342 |
+
- full conditioning,
|
| 343 |
+
- image-only conditioning,
|
| 344 |
+
- text/VLM-only conditioning.
|
| 345 |
+
|
| 346 |
+
---
|
| 347 |
+
|
| 348 |
+
## R2T2 Dataset
|
| 349 |
+
|
| 350 |
+
TherA is trained with **R2T2**, a large-scale RGB–TIR–Text dataset.
|
| 351 |
+
|
| 352 |
+
R2T2 includes:
|
| 353 |
+
|
| 354 |
+
- **112,970 aligned triplets**: RGB image, TIR image, and canonical thermal schema.
|
| 355 |
+
- Scene diversity across driving, CCTV, aerial, and ego-view settings.
|
| 356 |
+
- Temporal diversity across day/night and diurnal transitions.
|
| 357 |
+
- Environmental diversity across weather, season, and illumination.
|
| 358 |
+
- Material- and object-level annotations with structured canonicalization.
|
| 359 |
+
- Data compiled from multiple aligned RGB–TIR datasets with additional pseudo-aligned pairs.
|
| 360 |
+
|
| 361 |
+
Dataset page:
|
| 362 |
+
|
| 363 |
+
```text
|
| 364 |
+
https://huggingface.co/datasets/donkeymouse/TherA-R2T2
|
| 365 |
+
```
|
| 366 |
+
|
| 367 |
+
Example structure:
|
| 368 |
+
|
| 369 |
+
```text
|
| 370 |
+
R2T2/
|
| 371 |
+
├── ${DATASET_NAME}/
|
| 372 |
+
│ └── ${SEQUENCE_NAME}/
|
| 373 |
+
│ ├── RGB/
|
| 374 |
+
│ │ ├── 1.jpg
|
| 375 |
+
│ │ └── ...
|
| 376 |
+
│ └── TIR/
|
| 377 |
+
│ ├── 1.jpg
|
| 378 |
+
│ └── ...
|
| 379 |
+
├── ViVID/
|
| 380 |
+
│ ├── img_campus_day1/
|
| 381 |
+
│ │ ├── RGB/
|
| 382 |
+
│ │ │ ├── 000001.png
|
| 383 |
+
│ │ │ └── ...
|
| 384 |
+
│ │ └── TIR/
|
| 385 |
+
│ │ ├── 000001.png
|
| 386 |
+
│ │ └── ...
|
| 387 |
+
│ └── ...
|
| 388 |
+
└── ...
|
| 389 |
+
```
|
| 390 |
+
|
| 391 |
+
---
|
| 392 |
+
|
| 393 |
+
## Troubleshooting
|
| 394 |
+
|
| 395 |
+
### `Checkpoint not found: weights/model.pt`
|
| 396 |
+
|
| 397 |
+
Download the TherA weights and make sure `model.pt` is located at:
|
| 398 |
+
|
| 399 |
+
```text
|
| 400 |
+
weights/model.pt
|
| 401 |
+
```
|
| 402 |
+
|
| 403 |
+
---
|
| 404 |
+
|
| 405 |
+
### `OSError: ... stable-diffusion/vae`
|
| 406 |
+
|
| 407 |
+
Make sure the Stable Diffusion VAE and scheduler folders are present:
|
| 408 |
+
|
| 409 |
+
```text
|
| 410 |
+
weights/stable-diffusion/vae/
|
| 411 |
+
weights/stable-diffusion/scheduler/
|
| 412 |
+
```
|
| 413 |
+
|
| 414 |
+
---
|
| 415 |
+
|
| 416 |
+
### Outputs look identical across palettes
|
| 417 |
+
|
| 418 |
+
Try increasing text/VLM guidance:
|
| 419 |
+
|
| 420 |
+
```bash
|
| 421 |
+
--cfg-text 7.5
|
| 422 |
+
```
|
| 423 |
+
|
| 424 |
+
Also verify that your reference cache files are distinct:
|
| 425 |
+
|
| 426 |
+
```text
|
| 427 |
+
SUNNY.pt
|
| 428 |
+
CLOUDY.pt
|
| 429 |
+
RAINY.pt
|
| 430 |
+
NIGHT.pt
|
| 431 |
+
```
|
| 432 |
+
|
| 433 |
+
---
|
| 434 |
+
|
| 435 |
+
### CUDA out of memory
|
| 436 |
+
|
| 437 |
+
Try reducing the image size:
|
| 438 |
+
|
| 439 |
+
```bash
|
| 440 |
+
--target-size 512
|
| 441 |
+
```
|
| 442 |
+
|
| 443 |
+
You can also run one image at a time with:
|
| 444 |
+
|
| 445 |
+
```bash
|
| 446 |
+
python infer_example_guided.py
|
| 447 |
+
```
|
| 448 |
+
|
| 449 |
+
---
|
| 450 |
+
|
| 451 |
+
### LLaVA import or loading errors
|
| 452 |
+
|
| 453 |
+
Use reference-cache mode if you do not need runtime LLaVA extraction:
|
| 454 |
+
|
| 455 |
+
```bash
|
| 456 |
+
--reference-cache weights/reference_caches/SUNNY.pt
|
| 457 |
+
```
|
| 458 |
+
|
| 459 |
+
For on-the-fly mode, make sure the LLaVA base model and TherA weights are correctly loaded`.
|
| 460 |
+
|
| 461 |
+
---
|
| 462 |
+
|
| 463 |
+
## TODOs
|
| 464 |
+
- [x] inference code and R2T2 dataset
|
| 465 |
+
- [] Upload cache extraction code
|
| 466 |
+
- [] Improve text-guidance
|
| 467 |
+
|
| 468 |
+
|
| 469 |
+
## Citation
|
| 470 |
+
|
| 471 |
+
If you find TherA useful for your research, please cite:
|
| 472 |
+
|
| 473 |
+
```bibtex
|
| 474 |
+
@inproceedings{lee2026thera,
|
| 475 |
+
title = {TherA: Thermal-Aware Visual-Language Prompting for Controllable RGB-to-Thermal Infrared Translation},
|
| 476 |
+
author = {Lee, Dong-Guw and Rhee, Tai Hyoung and Jang, Hyunsoo and Shin, Young-Sik and Shin, Ukcheol and Kim, Ayoung},
|
| 477 |
+
booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition},
|
| 478 |
+
year = {2026}
|
| 479 |
+
}
|
| 480 |
+
```
|
| 481 |
+
|
| 482 |
+
You may also cite the arXiv version:
|
| 483 |
+
|
| 484 |
+
```bibtex
|
| 485 |
+
@article{lee2026thera_arxiv,
|
| 486 |
+
title = {TherA: Thermal-Aware Visual-Language Prompting for Controllable RGB-to-Thermal Infrared Translation},
|
| 487 |
+
author = {Lee, Dong-Guw and Rhee, Tai Hyoung and Jang, Hyunsoo and Shin, Young-Sik and Shin, Ukcheol and Kim, Ayoung},
|
| 488 |
+
journal = {arXiv preprint arXiv:2602.19430},
|
| 489 |
+
year = {2026}
|
| 490 |
+
}
|
| 491 |
+
```
|
| 492 |
+
|
| 493 |
+
---
|
| 494 |
+
|
| 495 |
+
## Acknowledgements
|
| 496 |
+
|
| 497 |
+
TherA builds on open-source components from the vision-language and diffusion communities, including LLaVA, Stable Diffusion, Diffusers, and LaVi-Bridge-style adapter architectures.
|
| 498 |
+
|
| 499 |
+
---
|
| 500 |
+
|
| 501 |
+
## License
|
| 502 |
+
|
| 503 |
+
See `LICENSE` for details.
|
| 504 |
+
|
| 505 |
+
Third-party models, datasets, and libraries retain their own licenses. Please review the licenses for LLaVA, Stable Diffusion, Hugging Face model files, and any external datasets before use.
|
| 506 |
+
|
| 507 |
+
## Contact
|
| 508 |
+
If you have any questions, contact here please
|
| 509 |
+
```
|
| 510 |
+
donkeymouse@snu.ac.kr
|
| 511 |
+
```
|
__pycache__/thera_llava.cpython-310.pyc
ADDED
|
Binary file (865 Bytes). View file
|
|
|
__pycache__/thera_paths.cpython-310.pyc
ADDED
|
Binary file (967 Bytes). View file
|
|
|
infer_custom.py
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Batch RGB → TIR inference for TherA.
|
| 4 |
+
|
| 5 |
+
Recommended (no LLaVA weights needed): use a reference .pt cache
|
| 6 |
+
python infer_custom.py --rgb-dir ./examples/rgb --output-dir ./preds \\
|
| 7 |
+
--reference-cache weights/reference_caches/SUNNY.pt
|
| 8 |
+
|
| 9 |
+
On-the-fly LLaVA (optional): requires separate LLaVA checkpoints
|
| 10 |
+
python infer_custom.py --rgb-dir ./examples/rgb --output-dir ./preds \\
|
| 11 |
+
--llava-base-path weights/llava/llava-1.5-7b-hf \\
|
| 12 |
+
--llava-lora-path weights/llava/llava-miragehd-lora
|
| 13 |
+
|
| 14 |
+
Single-image example-guided mode: see infer_example_guided.py
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
from __future__ import annotations
|
| 18 |
+
|
| 19 |
+
import argparse
|
| 20 |
+
from pathlib import Path
|
| 21 |
+
from typing import List
|
| 22 |
+
|
| 23 |
+
import torch
|
| 24 |
+
from PIL import Image
|
| 25 |
+
from tqdm import tqdm
|
| 26 |
+
from contextlib import nullcontext
|
| 27 |
+
|
| 28 |
+
from thera_paths import (
|
| 29 |
+
DEFAULT_CHECKPOINT,
|
| 30 |
+
DEFAULT_MERGED_MODEL,
|
| 31 |
+
DEFAULT_PRETRAINED_SD,
|
| 32 |
+
setup_project_path,
|
| 33 |
+
)
|
| 34 |
+
from thera_llava import create_frozen_llava_extractor
|
| 35 |
+
|
| 36 |
+
setup_project_path()
|
| 37 |
+
|
| 38 |
+
from diffusers import AutoencoderKL, DDIMScheduler, UNet2DConditionModel
|
| 39 |
+
from torchvision import transforms
|
| 40 |
+
from torchvision.utils import save_image
|
| 41 |
+
|
| 42 |
+
from lavi_ip2p.llava_adapter import create_llava_adapter
|
| 43 |
+
from lavi_ip2p.unet_8ch import convert_unet_to_8ch
|
| 44 |
+
|
| 45 |
+
IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff"}
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def parse_args():
|
| 49 |
+
parser = argparse.ArgumentParser(description="Generate TIR predictions from custom RGB images")
|
| 50 |
+
|
| 51 |
+
# Model paths (defaults under weights/ — see README.md)
|
| 52 |
+
parser.add_argument(
|
| 53 |
+
"--checkpoint",
|
| 54 |
+
type=str,
|
| 55 |
+
default=str(DEFAULT_CHECKPOINT),
|
| 56 |
+
help="Directory containing model.pt (TherA UNet + adapter weights)",
|
| 57 |
+
)
|
| 58 |
+
parser.add_argument(
|
| 59 |
+
"--merged-model-path",
|
| 60 |
+
type=str,
|
| 61 |
+
default=str(DEFAULT_MERGED_MODEL),
|
| 62 |
+
help="Directory with unet/ and adapter/ architecture configs",
|
| 63 |
+
)
|
| 64 |
+
parser.add_argument(
|
| 65 |
+
"--pretrained-sd",
|
| 66 |
+
type=str,
|
| 67 |
+
default=str(DEFAULT_PRETRAINED_SD),
|
| 68 |
+
help="Stable Diffusion folder with vae/ and scheduler/ subfolders",
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
# LLaVA paths (only for on-the-fly feature extraction)
|
| 72 |
+
parser.add_argument(
|
| 73 |
+
"--llava-base-path",
|
| 74 |
+
type=str,
|
| 75 |
+
default=None,
|
| 76 |
+
help="Base LLaVA model. Required unless --reference-cache or --cache-dir is set.",
|
| 77 |
+
)
|
| 78 |
+
parser.add_argument(
|
| 79 |
+
"--llava-lora-path",
|
| 80 |
+
type=str,
|
| 81 |
+
default=None,
|
| 82 |
+
help="Optional LLaVA LoRA weights (on-the-fly mode only)",
|
| 83 |
+
)
|
| 84 |
+
parser.add_argument("--llava-prompt", type=str,
|
| 85 |
+
default="How would this RGB scene appear in long-wave thermal infrared spectrum",
|
| 86 |
+
help="Prompt for LLaVA feature extraction")
|
| 87 |
+
|
| 88 |
+
# Reference cache mode (alternative to on-the-fly extraction)
|
| 89 |
+
parser.add_argument("--reference-cache", type=str, default=None,
|
| 90 |
+
help="Path to a reference .pt cache file. If provided, uses this fixed feature for all images instead of extracting per-image.")
|
| 91 |
+
parser.add_argument("--cache-dir", type=str, default=None,
|
| 92 |
+
help="Directory with per-image .pt cache files (matched by filename stem). Alternative to --reference-cache.")
|
| 93 |
+
|
| 94 |
+
# Data
|
| 95 |
+
parser.add_argument("--rgb-dir", type=str, required=True,
|
| 96 |
+
help="Directory containing RGB images")
|
| 97 |
+
parser.add_argument("--output-dir", type=str, default="custom_predictions",
|
| 98 |
+
help="Output directory for predictions")
|
| 99 |
+
parser.add_argument("--recursive", action="store_true",
|
| 100 |
+
help="Search for images recursively in subdirectories")
|
| 101 |
+
|
| 102 |
+
# Sampling
|
| 103 |
+
parser.add_argument("--num-steps", type=int, default=100, help="DDIM sampling steps")
|
| 104 |
+
parser.add_argument("--cfg-text", type=float, default=3.5, help="CFG scale for text")
|
| 105 |
+
parser.add_argument("--cfg-image", type=float, default=1.5, help="CFG scale for image")
|
| 106 |
+
parser.add_argument("--seed", type=int, default=42, help="Random seed")
|
| 107 |
+
|
| 108 |
+
# Processing
|
| 109 |
+
parser.add_argument("--target-size", type=int, default=None,
|
| 110 |
+
help="Resize images to this size (default: keep original, round to 32)")
|
| 111 |
+
parser.add_argument("--batch-size", type=int, default=1,
|
| 112 |
+
help="Batch size (>1 for faster processing if you have enough VRAM)")
|
| 113 |
+
|
| 114 |
+
# Device
|
| 115 |
+
parser.add_argument("--device", type=str, default="cuda", help="Device (cuda/cpu)")
|
| 116 |
+
|
| 117 |
+
return parser.parse_args()
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def load_models(args):
|
| 121 |
+
"""Load VAE, UNet, Adapter, Scheduler, and optionally LLaVA Extractor"""
|
| 122 |
+
print("\n" + "="*80)
|
| 123 |
+
print(f"Loading models on device {args.device}...")
|
| 124 |
+
print("="*80)
|
| 125 |
+
|
| 126 |
+
device = torch.device(args.device)
|
| 127 |
+
|
| 128 |
+
# Determine if we need LLaVA extractor
|
| 129 |
+
use_cache = args.reference_cache is not None or args.cache_dir is not None
|
| 130 |
+
|
| 131 |
+
# 1. VAE
|
| 132 |
+
print("\n[1/5] Loading VAE...")
|
| 133 |
+
vae = AutoencoderKL.from_pretrained(args.pretrained_sd, subfolder="vae")
|
| 134 |
+
vae.requires_grad_(False)
|
| 135 |
+
vae.eval()
|
| 136 |
+
vae.to(device)
|
| 137 |
+
print("✓ VAE loaded")
|
| 138 |
+
|
| 139 |
+
# 2. Scheduler
|
| 140 |
+
print("\n[2/5] Loading scheduler...")
|
| 141 |
+
scheduler = DDIMScheduler.from_pretrained(args.pretrained_sd, subfolder="scheduler")
|
| 142 |
+
print("✓ Scheduler loaded")
|
| 143 |
+
|
| 144 |
+
# 3. UNet (load from checkpoint)
|
| 145 |
+
checkpoint_dir = Path(args.checkpoint)
|
| 146 |
+
print(f"\n[3/5] Loading UNet from checkpoint: {checkpoint_dir}")
|
| 147 |
+
checkpoint_path = checkpoint_dir / "model.pt"
|
| 148 |
+
if not checkpoint_path.exists():
|
| 149 |
+
raise FileNotFoundError(f"Checkpoint not found: {checkpoint_path}")
|
| 150 |
+
|
| 151 |
+
checkpoint = torch.load(checkpoint_path, map_location="cpu")
|
| 152 |
+
|
| 153 |
+
# Load base UNet architecture from merged model
|
| 154 |
+
merged_unet_path = Path(args.merged_model_path) / "unet"
|
| 155 |
+
unet = UNet2DConditionModel.from_pretrained(str(merged_unet_path))
|
| 156 |
+
|
| 157 |
+
# Convert to 8-channel for image-to-image task
|
| 158 |
+
print(" Converting UNet to 8-channel input...")
|
| 159 |
+
unet = convert_unet_to_8ch(unet)
|
| 160 |
+
|
| 161 |
+
# Load trained weights
|
| 162 |
+
unet.load_state_dict(checkpoint['unet'])
|
| 163 |
+
unet.requires_grad_(False)
|
| 164 |
+
unet.eval()
|
| 165 |
+
unet.to(device)
|
| 166 |
+
|
| 167 |
+
global_step = checkpoint.get('global_step', 'unknown')
|
| 168 |
+
epoch = checkpoint.get('epoch', 'unknown')
|
| 169 |
+
print(f"✓ UNet loaded (step={global_step}, epoch={epoch})")
|
| 170 |
+
|
| 171 |
+
# 4. Adapter
|
| 172 |
+
print("\n[4/5] Loading LLaVA Adapter...")
|
| 173 |
+
merged_adapter_path = Path(args.merged_model_path) / "adapter"
|
| 174 |
+
adapter = create_llava_adapter(
|
| 175 |
+
adapter_path=str(merged_adapter_path),
|
| 176 |
+
use_rms_norm=False,
|
| 177 |
+
learnable_scale=False,
|
| 178 |
+
init_scale=1.0,
|
| 179 |
+
freeze_adapter=True,
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
# Load trained adapter weights if available in checkpoint
|
| 183 |
+
if 'llava_adapter' in checkpoint:
|
| 184 |
+
adapter.load_state_dict(checkpoint['llava_adapter'])
|
| 185 |
+
print("✓ Adapter loaded from checkpoint")
|
| 186 |
+
else:
|
| 187 |
+
print("✓ Adapter loaded (using base weights)")
|
| 188 |
+
|
| 189 |
+
adapter.requires_grad_(False)
|
| 190 |
+
adapter.eval()
|
| 191 |
+
adapter.to(device)
|
| 192 |
+
|
| 193 |
+
# 5. LLaVA Extractor (optional - only if not using cache)
|
| 194 |
+
llava_extractor = None
|
| 195 |
+
if use_cache:
|
| 196 |
+
print("\n[5/5] Skipping LLaVA extractor (using cached features)")
|
| 197 |
+
else:
|
| 198 |
+
print("\n[5/5] Loading LLaVA Feature Extractor...")
|
| 199 |
+
if not args.llava_base_path:
|
| 200 |
+
raise ValueError("--llava-base-path is required when not using --reference-cache or --cache-dir")
|
| 201 |
+
llava_extractor = create_frozen_llava_extractor(
|
| 202 |
+
llava_base_path=args.llava_base_path,
|
| 203 |
+
llava_lora_path=args.llava_lora_path,
|
| 204 |
+
device=args.device,
|
| 205 |
+
load_8bit=False,
|
| 206 |
+
load_4bit=False,
|
| 207 |
+
merge_lora=True,
|
| 208 |
+
)
|
| 209 |
+
print("✓ LLaVA extractor loaded")
|
| 210 |
+
|
| 211 |
+
return vae, unet, adapter, scheduler, llava_extractor, device
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def find_images(rgb_dir: Path, recursive: bool = False) -> List[Path]:
|
| 215 |
+
"""Find all image files in directory"""
|
| 216 |
+
if recursive:
|
| 217 |
+
images = []
|
| 218 |
+
for ext in IMAGE_EXTENSIONS:
|
| 219 |
+
images.extend(rgb_dir.rglob(f"*{ext}"))
|
| 220 |
+
images.extend(rgb_dir.rglob(f"*{ext.upper()}"))
|
| 221 |
+
return sorted(set(images))
|
| 222 |
+
else:
|
| 223 |
+
images = []
|
| 224 |
+
for ext in IMAGE_EXTENSIONS:
|
| 225 |
+
images.extend(rgb_dir.glob(f"*{ext}"))
|
| 226 |
+
images.extend(rgb_dir.glob(f"*{ext.upper()}"))
|
| 227 |
+
return sorted(set(images))
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
def load_and_prepare_image(image_path: Path, target_size: int = None, device: torch.device = None):
|
| 231 |
+
"""Load RGB image and prepare for processing"""
|
| 232 |
+
rgb_img = Image.open(image_path).convert('RGB')
|
| 233 |
+
rgb_w, rgb_h = rgb_img.size
|
| 234 |
+
|
| 235 |
+
# Determine target dimensions
|
| 236 |
+
if target_size is not None:
|
| 237 |
+
target_w = target_h = target_size
|
| 238 |
+
else:
|
| 239 |
+
# Ensure dimensions divisible by 32 (required for VAE)
|
| 240 |
+
target_w = ((rgb_w + 31) // 32) * 32
|
| 241 |
+
target_h = ((rgb_h + 31) // 32) * 32
|
| 242 |
+
|
| 243 |
+
# Resize if needed
|
| 244 |
+
if target_w != rgb_w or target_h != rgb_h:
|
| 245 |
+
rgb_img = rgb_img.resize((target_w, target_h), Image.Resampling.LANCZOS)
|
| 246 |
+
|
| 247 |
+
# Convert to tensor for diffusion model
|
| 248 |
+
transform = transforms.Compose([
|
| 249 |
+
transforms.ToTensor(),
|
| 250 |
+
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]), # [-1, 1]
|
| 251 |
+
])
|
| 252 |
+
|
| 253 |
+
rgb_tensor = transform(rgb_img).unsqueeze(0)
|
| 254 |
+
if device is not None:
|
| 255 |
+
rgb_tensor = rgb_tensor.to(device)
|
| 256 |
+
|
| 257 |
+
return rgb_tensor, rgb_img # Return both tensor and PIL image
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def load_llava_cache(cache_path: Path, device: torch.device):
|
| 261 |
+
"""Load a cached LLaVA hidden state from .pt file"""
|
| 262 |
+
try:
|
| 263 |
+
llava_hidden = torch.load(cache_path, map_location="cpu", weights_only=True)
|
| 264 |
+
except TypeError:
|
| 265 |
+
# For older torch versions without weights_only
|
| 266 |
+
llava_hidden = torch.load(cache_path, map_location="cpu")
|
| 267 |
+
|
| 268 |
+
if not isinstance(llava_hidden, torch.Tensor):
|
| 269 |
+
llava_hidden = torch.tensor(llava_hidden)
|
| 270 |
+
|
| 271 |
+
# Add batch dimension if needed
|
| 272 |
+
if llava_hidden.ndim == 2:
|
| 273 |
+
llava_hidden = llava_hidden.unsqueeze(0)
|
| 274 |
+
|
| 275 |
+
return llava_hidden.to(device)
|
| 276 |
+
|
| 277 |
+
|
| 278 |
+
def find_cache_for_image(image_path: Path, cache_dir: Path) -> Path:
|
| 279 |
+
"""Find matching cache file for an image based on filename stem"""
|
| 280 |
+
stem = image_path.stem
|
| 281 |
+
for ext in ['.pt', '.pth']:
|
| 282 |
+
cache_path = cache_dir / f"{stem}{ext}"
|
| 283 |
+
if cache_path.exists():
|
| 284 |
+
return cache_path
|
| 285 |
+
raise FileNotFoundError(f"No cache file found for {image_path.name} in {cache_dir}")
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
def create_null_text(llava_tokens):
|
| 289 |
+
"""Create null tokens for unconditional generation"""
|
| 290 |
+
return torch.zeros_like(llava_tokens)
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
@torch.no_grad()
|
| 294 |
+
def translate_image(
|
| 295 |
+
vae,
|
| 296 |
+
unet,
|
| 297 |
+
adapter,
|
| 298 |
+
scheduler,
|
| 299 |
+
rgb_tensor,
|
| 300 |
+
llava_hidden,
|
| 301 |
+
num_steps=100,
|
| 302 |
+
cfg_text=3.5,
|
| 303 |
+
cfg_image=1.5,
|
| 304 |
+
device=torch.device("cuda"),
|
| 305 |
+
):
|
| 306 |
+
"""Translate RGB to TIR using LLaVA features + conditional generation with CFG"""
|
| 307 |
+
|
| 308 |
+
# Encode RGB
|
| 309 |
+
rgb_latents = vae.encode(rgb_tensor).latent_dist.mode() * vae.config.scaling_factor
|
| 310 |
+
|
| 311 |
+
# Process LLaVA features through adapter
|
| 312 |
+
use_autocast = device.type == "cuda"
|
| 313 |
+
llava_input = llava_hidden.to(device)
|
| 314 |
+
if use_autocast:
|
| 315 |
+
llava_input = llava_input.to(dtype=torch.bfloat16)
|
| 316 |
+
|
| 317 |
+
autocast_ctx = (
|
| 318 |
+
torch.autocast(device_type=device.type, dtype=torch.bfloat16)
|
| 319 |
+
if use_autocast else nullcontext()
|
| 320 |
+
)
|
| 321 |
+
with autocast_ctx:
|
| 322 |
+
llava_tokens = adapter(llava_input)
|
| 323 |
+
llava_tokens = llava_tokens.to(device=device, dtype=next(unet.parameters()).dtype)
|
| 324 |
+
|
| 325 |
+
# Create null tokens for CFG
|
| 326 |
+
null_tokens = create_null_text(llava_tokens)
|
| 327 |
+
|
| 328 |
+
# Initialize random noise
|
| 329 |
+
latent_shape = (1, 4, rgb_latents.shape[2], rgb_latents.shape[3])
|
| 330 |
+
latents = torch.randn(latent_shape, device=device, dtype=rgb_latents.dtype)
|
| 331 |
+
|
| 332 |
+
# Setup scheduler
|
| 333 |
+
scheduler.set_timesteps(num_steps, device=device)
|
| 334 |
+
|
| 335 |
+
zeros_rgb = torch.zeros_like(rgb_latents)
|
| 336 |
+
|
| 337 |
+
for t in scheduler.timesteps:
|
| 338 |
+
t_batch = torch.full((1,), int(t), device=device, dtype=torch.long)
|
| 339 |
+
|
| 340 |
+
# 3 forward passes for dual-CFG
|
| 341 |
+
x8_full = torch.cat([latents, rgb_latents], dim=1)
|
| 342 |
+
x8_no_img = torch.cat([latents, zeros_rgb], dim=1)
|
| 343 |
+
|
| 344 |
+
# Full conditioning
|
| 345 |
+
eps_full = unet(x8_full, t_batch, encoder_hidden_states=llava_tokens).sample
|
| 346 |
+
|
| 347 |
+
# No text (image only)
|
| 348 |
+
eps_no_text = unet(x8_full, t_batch, encoder_hidden_states=null_tokens).sample
|
| 349 |
+
|
| 350 |
+
# No image (text only)
|
| 351 |
+
eps_no_img = unet(x8_no_img, t_batch, encoder_hidden_states=llava_tokens).sample
|
| 352 |
+
|
| 353 |
+
# Combine with dual-CFG
|
| 354 |
+
eps = eps_full + cfg_text * (eps_full - eps_no_text) + cfg_image * (eps_full - eps_no_img)
|
| 355 |
+
eps = torch.clamp(eps, -5.0, 5.0) # Safety guard
|
| 356 |
+
|
| 357 |
+
latents = scheduler.step(eps, t, latents, eta=0.0).prev_sample
|
| 358 |
+
|
| 359 |
+
# Decode
|
| 360 |
+
pred_tir = vae.decode(latents / vae.config.scaling_factor).sample
|
| 361 |
+
pred_tir = (pred_tir / 2 + 0.5).clamp(0, 1)
|
| 362 |
+
|
| 363 |
+
return pred_tir
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
def main():
|
| 367 |
+
args = parse_args()
|
| 368 |
+
|
| 369 |
+
# Set seed
|
| 370 |
+
torch.manual_seed(args.seed)
|
| 371 |
+
if torch.cuda.is_available():
|
| 372 |
+
torch.cuda.manual_seed_all(args.seed)
|
| 373 |
+
|
| 374 |
+
# Determine processing mode
|
| 375 |
+
use_reference = args.reference_cache is not None
|
| 376 |
+
use_cache_dir = args.cache_dir is not None
|
| 377 |
+
|
| 378 |
+
if use_reference and use_cache_dir:
|
| 379 |
+
raise ValueError("Cannot use both --reference-cache and --cache-dir. Choose one.")
|
| 380 |
+
|
| 381 |
+
print("\n" + "="*80)
|
| 382 |
+
if use_reference:
|
| 383 |
+
print("Custom Dataset Inference (Reference Cache Mode)")
|
| 384 |
+
elif use_cache_dir:
|
| 385 |
+
print("Custom Dataset Inference (Per-Image Cache Mode)")
|
| 386 |
+
else:
|
| 387 |
+
print("Custom Dataset Inference (On-the-fly LLaVA Features)")
|
| 388 |
+
print("="*80)
|
| 389 |
+
print(f"RGB directory: {args.rgb_dir}")
|
| 390 |
+
print(f"Checkpoint: {args.checkpoint}")
|
| 391 |
+
|
| 392 |
+
if use_reference:
|
| 393 |
+
print(f"Reference cache: {args.reference_cache}")
|
| 394 |
+
elif use_cache_dir:
|
| 395 |
+
print(f"Cache directory: {args.cache_dir}")
|
| 396 |
+
else:
|
| 397 |
+
print(f"LLaVA base: {args.llava_base_path}")
|
| 398 |
+
if args.llava_lora_path:
|
| 399 |
+
print(f"LLaVA LoRA: {args.llava_lora_path}")
|
| 400 |
+
print(f"Prompt: {args.llava_prompt}")
|
| 401 |
+
|
| 402 |
+
print(f"Output directory: {args.output_dir}")
|
| 403 |
+
print(f"DDIM steps: {args.num_steps}")
|
| 404 |
+
print(f"CFG scales: text={args.cfg_text}, image={args.cfg_image}")
|
| 405 |
+
print("="*80)
|
| 406 |
+
|
| 407 |
+
# Create output directory
|
| 408 |
+
output_dir = Path(args.output_dir)
|
| 409 |
+
output_dir.mkdir(parents=True, exist_ok=True)
|
| 410 |
+
|
| 411 |
+
# Load models
|
| 412 |
+
vae, unet, adapter, scheduler, llava_extractor, device = load_models(args)
|
| 413 |
+
|
| 414 |
+
# Load reference cache if provided
|
| 415 |
+
reference_hidden = None
|
| 416 |
+
if use_reference:
|
| 417 |
+
print(f"\nLoading reference cache from: {args.reference_cache}")
|
| 418 |
+
reference_hidden = load_llava_cache(Path(args.reference_cache), device)
|
| 419 |
+
print(f"✓ Reference cache loaded: {reference_hidden.shape}")
|
| 420 |
+
|
| 421 |
+
# Validate cache directory if provided
|
| 422 |
+
cache_dir = None
|
| 423 |
+
if use_cache_dir:
|
| 424 |
+
cache_dir = Path(args.cache_dir)
|
| 425 |
+
if not cache_dir.exists():
|
| 426 |
+
raise FileNotFoundError(f"Cache directory not found: {cache_dir}")
|
| 427 |
+
print(f"\nUsing cache directory: {cache_dir}")
|
| 428 |
+
|
| 429 |
+
# Find all RGB images
|
| 430 |
+
rgb_dir = Path(args.rgb_dir)
|
| 431 |
+
if not rgb_dir.exists():
|
| 432 |
+
raise FileNotFoundError(f"RGB directory not found: {rgb_dir}")
|
| 433 |
+
|
| 434 |
+
image_files = find_images(rgb_dir, recursive=args.recursive)
|
| 435 |
+
print(f"\nFound {len(image_files)} images")
|
| 436 |
+
|
| 437 |
+
if len(image_files) == 0:
|
| 438 |
+
print("No images found. Exiting.")
|
| 439 |
+
return
|
| 440 |
+
|
| 441 |
+
# Process each image
|
| 442 |
+
print("\n" + "="*80)
|
| 443 |
+
print("Generating predictions...")
|
| 444 |
+
print("="*80)
|
| 445 |
+
|
| 446 |
+
successful = 0
|
| 447 |
+
failed = 0
|
| 448 |
+
skipped = 0
|
| 449 |
+
|
| 450 |
+
for img_path in tqdm(image_files, desc="Processing images"):
|
| 451 |
+
try:
|
| 452 |
+
# Load and prepare RGB image
|
| 453 |
+
rgb_tensor, rgb_pil = load_and_prepare_image(
|
| 454 |
+
img_path,
|
| 455 |
+
target_size=args.target_size,
|
| 456 |
+
device=device
|
| 457 |
+
)
|
| 458 |
+
|
| 459 |
+
# Get LLaVA hidden states based on mode
|
| 460 |
+
if use_reference:
|
| 461 |
+
# Use the same reference cache for all images
|
| 462 |
+
llava_hidden = reference_hidden
|
| 463 |
+
elif use_cache_dir:
|
| 464 |
+
# Find matching cache file for this image
|
| 465 |
+
try:
|
| 466 |
+
cache_path = find_cache_for_image(img_path, cache_dir)
|
| 467 |
+
llava_hidden = load_llava_cache(cache_path, device)
|
| 468 |
+
except FileNotFoundError as e:
|
| 469 |
+
print(f"\nWarning: {e}")
|
| 470 |
+
skipped += 1
|
| 471 |
+
continue
|
| 472 |
+
else:
|
| 473 |
+
# Extract features on-the-fly using LLaVA
|
| 474 |
+
llava_hidden = llava_extractor.extract_hidden_states([rgb_pil], [args.llava_prompt])
|
| 475 |
+
|
| 476 |
+
# Translate RGB to TIR
|
| 477 |
+
pred_tir = translate_image(
|
| 478 |
+
vae,
|
| 479 |
+
unet,
|
| 480 |
+
adapter,
|
| 481 |
+
scheduler,
|
| 482 |
+
rgb_tensor,
|
| 483 |
+
llava_hidden,
|
| 484 |
+
num_steps=args.num_steps,
|
| 485 |
+
cfg_text=args.cfg_text,
|
| 486 |
+
cfg_image=args.cfg_image,
|
| 487 |
+
device=device,
|
| 488 |
+
)
|
| 489 |
+
|
| 490 |
+
# Save prediction
|
| 491 |
+
# Preserve relative path structure if recursive
|
| 492 |
+
if args.recursive:
|
| 493 |
+
rel_path = img_path.relative_to(rgb_dir)
|
| 494 |
+
save_path = output_dir / rel_path
|
| 495 |
+
else:
|
| 496 |
+
save_path = output_dir / img_path.name
|
| 497 |
+
|
| 498 |
+
save_path.parent.mkdir(parents=True, exist_ok=True)
|
| 499 |
+
save_image(pred_tir.cpu(), str(save_path))
|
| 500 |
+
|
| 501 |
+
successful += 1
|
| 502 |
+
|
| 503 |
+
except Exception as e:
|
| 504 |
+
print(f"\nError processing {img_path}: {e}")
|
| 505 |
+
import traceback
|
| 506 |
+
traceback.print_exc()
|
| 507 |
+
failed += 1
|
| 508 |
+
continue
|
| 509 |
+
|
| 510 |
+
# Print final results
|
| 511 |
+
print("\n" + "="*80)
|
| 512 |
+
print("INFERENCE COMPLETE")
|
| 513 |
+
print("="*80)
|
| 514 |
+
print(f"Total images: {len(image_files)}")
|
| 515 |
+
print(f"Successful: {successful}")
|
| 516 |
+
if skipped > 0:
|
| 517 |
+
print(f"Skipped (no cache): {skipped}")
|
| 518 |
+
print(f"Failed: {failed}")
|
| 519 |
+
if len(image_files) > 0:
|
| 520 |
+
print(f"Success rate: {successful/len(image_files)*100:.1f}%")
|
| 521 |
+
print(f"Predictions saved to: {args.output_dir}")
|
| 522 |
+
print("="*80)
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
if __name__ == "__main__":
|
| 526 |
+
main()
|
infer_example_guided.py
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Single-image example-guided RGB → TIR translation.
|
| 4 |
+
|
| 5 |
+
Mode: cached (recommended — no LLaVA weights needed)
|
| 6 |
+
python infer_example_guided.py --mode cached \\
|
| 7 |
+
--reference-cache weights/reference_caches/SUNNY.pt \\
|
| 8 |
+
--input-image examples/rgb/scene.jpg \\
|
| 9 |
+
--output preds/scene_tir.png
|
| 10 |
+
|
| 11 |
+
Mode: two-image (extract features from a reference RGB on-the-fly)
|
| 12 |
+
python infer_example_guided.py --mode two-image \\
|
| 13 |
+
--reference-image examples/ref/rgb.jpg \\
|
| 14 |
+
--input-image examples/rgb/scene.jpg \\
|
| 15 |
+
--output preds/scene_tir.png \\
|
| 16 |
+
--llava-base-path weights/llava/llava-1.5-7b-hf \\
|
| 17 |
+
--llava-lora-path weights/llava/llava-miragehd-lora
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
from __future__ import annotations
|
| 21 |
+
|
| 22 |
+
import argparse
|
| 23 |
+
from pathlib import Path
|
| 24 |
+
import sys
|
| 25 |
+
from contextlib import nullcontext
|
| 26 |
+
|
| 27 |
+
import torch
|
| 28 |
+
from PIL import Image
|
| 29 |
+
|
| 30 |
+
from thera_paths import (
|
| 31 |
+
DEFAULT_CHECKPOINT,
|
| 32 |
+
DEFAULT_MERGED_MODEL,
|
| 33 |
+
DEFAULT_PRETRAINED_SD,
|
| 34 |
+
setup_project_path,
|
| 35 |
+
)
|
| 36 |
+
from thera_llava import create_frozen_llava_extractor
|
| 37 |
+
|
| 38 |
+
setup_project_path()
|
| 39 |
+
|
| 40 |
+
from diffusers import AutoencoderKL, DDIMScheduler, UNet2DConditionModel
|
| 41 |
+
from torchvision import transforms
|
| 42 |
+
from torchvision.utils import save_image
|
| 43 |
+
|
| 44 |
+
from lavi_ip2p.llava_adapter import create_llava_adapter
|
| 45 |
+
from lavi_ip2p.unet_8ch import convert_unet_to_8ch
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def parse_args():
|
| 49 |
+
parser = argparse.ArgumentParser(
|
| 50 |
+
description="Example-guided translation with two modes",
|
| 51 |
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
| 52 |
+
epilog=__doc__
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
# Mode selection
|
| 56 |
+
parser.add_argument("--mode", type=str, required=True, choices=["two-image", "cached"],
|
| 57 |
+
help="Translation mode: 'two-image' (extract from reference image) or 'cached' (use .pt file)")
|
| 58 |
+
|
| 59 |
+
# Input/Output
|
| 60 |
+
parser.add_argument("--input-image", type=str, required=True,
|
| 61 |
+
help="Path to input RGB image (Image B) to be translated")
|
| 62 |
+
parser.add_argument("--output", type=str, required=True,
|
| 63 |
+
help="Path to save output TIR image")
|
| 64 |
+
|
| 65 |
+
# Reference (mode-dependent)
|
| 66 |
+
parser.add_argument("--reference-image", type=str, default=None,
|
| 67 |
+
help="Path to reference RGB image (Image A). Required for 'two-image' mode.")
|
| 68 |
+
parser.add_argument("--reference-cache", type=str, default=None,
|
| 69 |
+
help="Path to reference .pt cache file. Required for 'cached' mode.")
|
| 70 |
+
|
| 71 |
+
# Model paths (defaults under weights/ — see README.md)
|
| 72 |
+
parser.add_argument(
|
| 73 |
+
"--checkpoint",
|
| 74 |
+
type=str,
|
| 75 |
+
default=str(DEFAULT_CHECKPOINT),
|
| 76 |
+
help="Directory containing model.pt",
|
| 77 |
+
)
|
| 78 |
+
parser.add_argument(
|
| 79 |
+
"--merged-model-path",
|
| 80 |
+
type=str,
|
| 81 |
+
default=str(DEFAULT_MERGED_MODEL),
|
| 82 |
+
help="Directory with unet/ and adapter/ architecture configs",
|
| 83 |
+
)
|
| 84 |
+
parser.add_argument(
|
| 85 |
+
"--pretrained-sd",
|
| 86 |
+
type=str,
|
| 87 |
+
default=str(DEFAULT_PRETRAINED_SD),
|
| 88 |
+
help="Stable Diffusion folder with vae/ and scheduler/ subfolders",
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
# LLaVA paths (required for two-image mode)
|
| 92 |
+
parser.add_argument("--llava-base-path", type=str, default=None,
|
| 93 |
+
help="Path to base LLaVA model. Required for 'two-image' mode.")
|
| 94 |
+
parser.add_argument("--llava-lora-path", type=str, default=None,
|
| 95 |
+
help="Optional: Path to LLaVA LoRA weights")
|
| 96 |
+
parser.add_argument("--llava-prompt", type=str,
|
| 97 |
+
default="How would this RGB scene appear in long-wave thermal infrared spectrum",
|
| 98 |
+
help="Prompt for LLaVA feature extraction")
|
| 99 |
+
|
| 100 |
+
# Sampling parameters
|
| 101 |
+
parser.add_argument("--num-steps", type=int, default=100, help="DDIM sampling steps")
|
| 102 |
+
parser.add_argument("--cfg-text", type=float, default=3.5, help="CFG scale for text")
|
| 103 |
+
parser.add_argument("--cfg-image", type=float, default=1.5, help="CFG scale for image")
|
| 104 |
+
parser.add_argument("--seed", type=int, default=42, help="Random seed")
|
| 105 |
+
|
| 106 |
+
# Processing
|
| 107 |
+
parser.add_argument("--target-size", type=int, default=None,
|
| 108 |
+
help="Resize images to this size (default: keep original, round to 32)")
|
| 109 |
+
parser.add_argument("--device", type=str, default="cuda", help="Device (cuda/cpu)")
|
| 110 |
+
|
| 111 |
+
return parser.parse_args()
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def validate_args(args):
|
| 115 |
+
"""Validate argument combinations based on mode"""
|
| 116 |
+
if args.mode == "two-image":
|
| 117 |
+
if args.reference_image is None:
|
| 118 |
+
print("ERROR: --reference-image required for 'two-image' mode")
|
| 119 |
+
sys.exit(1)
|
| 120 |
+
if args.llava_base_path is None:
|
| 121 |
+
print("ERROR: --llava-base-path required for 'two-image' mode")
|
| 122 |
+
sys.exit(1)
|
| 123 |
+
if not Path(args.reference_image).exists():
|
| 124 |
+
print(f"ERROR: Reference image not found: {args.reference_image}")
|
| 125 |
+
sys.exit(1)
|
| 126 |
+
|
| 127 |
+
elif args.mode == "cached":
|
| 128 |
+
if args.reference_cache is None:
|
| 129 |
+
print("ERROR: --reference-cache required for 'cached' mode")
|
| 130 |
+
sys.exit(1)
|
| 131 |
+
if not Path(args.reference_cache).exists():
|
| 132 |
+
print(f"ERROR: Reference cache not found: {args.reference_cache}")
|
| 133 |
+
sys.exit(1)
|
| 134 |
+
|
| 135 |
+
if not Path(args.input_image).exists():
|
| 136 |
+
print(f"ERROR: Input image not found: {args.input_image}")
|
| 137 |
+
sys.exit(1)
|
| 138 |
+
|
| 139 |
+
if not Path(args.checkpoint, "model.pt").exists():
|
| 140 |
+
print(f"ERROR: Checkpoint not found: {Path(args.checkpoint) / 'model.pt'}")
|
| 141 |
+
sys.exit(1)
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def load_models(args, need_llava=False):
|
| 145 |
+
"""Load diffusion models and optionally LLaVA extractor"""
|
| 146 |
+
print("\n" + "="*80)
|
| 147 |
+
print(f"Loading models on device {args.device}...")
|
| 148 |
+
print("="*80)
|
| 149 |
+
|
| 150 |
+
device = torch.device(args.device)
|
| 151 |
+
checkpoint_dir = Path(args.checkpoint)
|
| 152 |
+
|
| 153 |
+
# 1. Load VAE
|
| 154 |
+
print("\n[1/5] Loading VAE...")
|
| 155 |
+
vae = AutoencoderKL.from_pretrained(args.pretrained_sd, subfolder="vae")
|
| 156 |
+
vae.requires_grad_(False)
|
| 157 |
+
vae.eval()
|
| 158 |
+
vae.to(device)
|
| 159 |
+
print("✓ VAE loaded")
|
| 160 |
+
|
| 161 |
+
# 2. Load Scheduler
|
| 162 |
+
print("\n[2/5] Loading scheduler...")
|
| 163 |
+
scheduler = DDIMScheduler.from_pretrained(args.pretrained_sd, subfolder="scheduler")
|
| 164 |
+
print("✓ Scheduler loaded")
|
| 165 |
+
|
| 166 |
+
# 3. Load UNet (load from checkpoint)
|
| 167 |
+
print(f"\n[3/5] Loading UNet from checkpoint: {checkpoint_dir}")
|
| 168 |
+
checkpoint_path = checkpoint_dir / "model.pt"
|
| 169 |
+
if not checkpoint_path.exists():
|
| 170 |
+
print(f"ERROR: Checkpoint not found: {checkpoint_path}")
|
| 171 |
+
sys.exit(1)
|
| 172 |
+
|
| 173 |
+
checkpoint = torch.load(checkpoint_path, map_location="cpu")
|
| 174 |
+
|
| 175 |
+
# Load base UNet architecture from merged model
|
| 176 |
+
merged_unet_path = Path(args.merged_model_path) / "unet"
|
| 177 |
+
unet = UNet2DConditionModel.from_pretrained(str(merged_unet_path))
|
| 178 |
+
|
| 179 |
+
# Convert to 8-channel for image-to-image task
|
| 180 |
+
print(" Converting UNet to 8-channel input...")
|
| 181 |
+
unet = convert_unet_to_8ch(unet)
|
| 182 |
+
|
| 183 |
+
# Load trained weights
|
| 184 |
+
unet.load_state_dict(checkpoint['unet'])
|
| 185 |
+
unet.requires_grad_(False)
|
| 186 |
+
unet.eval()
|
| 187 |
+
unet.to(device)
|
| 188 |
+
|
| 189 |
+
global_step = checkpoint.get('global_step', 'unknown')
|
| 190 |
+
epoch = checkpoint.get('epoch', 'unknown')
|
| 191 |
+
print(f"✓ UNet loaded (step={global_step}, epoch={epoch})")
|
| 192 |
+
|
| 193 |
+
# 4. Load Adapter
|
| 194 |
+
print("\n[4/5] Loading LLaVA Adapter...")
|
| 195 |
+
merged_adapter_path = Path(args.merged_model_path) / "adapter"
|
| 196 |
+
adapter = create_llava_adapter(
|
| 197 |
+
adapter_path=str(merged_adapter_path),
|
| 198 |
+
use_rms_norm=False,
|
| 199 |
+
learnable_scale=False,
|
| 200 |
+
init_scale=1.0,
|
| 201 |
+
freeze_adapter=True,
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
# Load trained adapter weights if available in checkpoint
|
| 205 |
+
if 'llava_adapter' in checkpoint:
|
| 206 |
+
adapter.load_state_dict(checkpoint['llava_adapter'])
|
| 207 |
+
print("✓ Adapter loaded from checkpoint")
|
| 208 |
+
else:
|
| 209 |
+
print("✓ Adapter loaded (using base weights)")
|
| 210 |
+
|
| 211 |
+
adapter.requires_grad_(False)
|
| 212 |
+
adapter.eval()
|
| 213 |
+
adapter.to(device)
|
| 214 |
+
|
| 215 |
+
# 5. Optionally load LLaVA
|
| 216 |
+
llava_extractor = None
|
| 217 |
+
if need_llava:
|
| 218 |
+
print("\n[5/5] Loading LLaVA Feature Extractor...")
|
| 219 |
+
if not args.llava_base_path:
|
| 220 |
+
print("ERROR: --llava-base-path is required for two-image mode")
|
| 221 |
+
sys.exit(1)
|
| 222 |
+
llava_extractor = create_frozen_llava_extractor(
|
| 223 |
+
llava_base_path=args.llava_base_path,
|
| 224 |
+
llava_lora_path=args.llava_lora_path,
|
| 225 |
+
device=args.device,
|
| 226 |
+
load_8bit=False,
|
| 227 |
+
load_4bit=False,
|
| 228 |
+
merge_lora=True,
|
| 229 |
+
)
|
| 230 |
+
print("✓ LLaVA extractor loaded")
|
| 231 |
+
else:
|
| 232 |
+
print("\n[5/5] Skipping LLaVA extractor (using cached features)")
|
| 233 |
+
|
| 234 |
+
return vae, unet, adapter, scheduler, llava_extractor, device
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
def load_and_prepare_image(image_path, target_size=None, device="cuda"):
|
| 238 |
+
"""Load image and prepare tensor"""
|
| 239 |
+
rgb_img = Image.open(image_path).convert('RGB')
|
| 240 |
+
rgb_w, rgb_h = rgb_img.size
|
| 241 |
+
|
| 242 |
+
# Determine target dimensions
|
| 243 |
+
if target_size is not None:
|
| 244 |
+
target_w = target_h = target_size
|
| 245 |
+
else:
|
| 246 |
+
# Ensure dimensions divisible by 32 (required for VAE)
|
| 247 |
+
target_w = ((rgb_w + 31) // 32) * 32
|
| 248 |
+
target_h = ((rgb_h + 31) // 32) * 32
|
| 249 |
+
|
| 250 |
+
# Resize if needed
|
| 251 |
+
if target_w != rgb_w or target_h != rgb_h:
|
| 252 |
+
rgb_img = rgb_img.resize((target_w, target_h), Image.Resampling.LANCZOS)
|
| 253 |
+
|
| 254 |
+
# Convert to tensor for diffusion model
|
| 255 |
+
transform = transforms.Compose([
|
| 256 |
+
transforms.ToTensor(),
|
| 257 |
+
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]), # [-1, 1]
|
| 258 |
+
])
|
| 259 |
+
|
| 260 |
+
rgb_tensor = transform(rgb_img).unsqueeze(0)
|
| 261 |
+
if device is not None:
|
| 262 |
+
rgb_tensor = rgb_tensor.to(device)
|
| 263 |
+
|
| 264 |
+
return rgb_tensor, rgb_img # Return both tensor and PIL image
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
def load_llava_cache(cache_path, device):
|
| 268 |
+
"""Load pre-cached LLaVA hidden states"""
|
| 269 |
+
try:
|
| 270 |
+
llava_hidden = torch.load(cache_path, map_location="cpu", weights_only=True)
|
| 271 |
+
except TypeError:
|
| 272 |
+
# For older torch versions without weights_only
|
| 273 |
+
llava_hidden = torch.load(cache_path, map_location="cpu")
|
| 274 |
+
|
| 275 |
+
if not isinstance(llava_hidden, torch.Tensor):
|
| 276 |
+
llava_hidden = torch.tensor(llava_hidden)
|
| 277 |
+
|
| 278 |
+
# Add batch dimension if needed
|
| 279 |
+
if llava_hidden.ndim == 2:
|
| 280 |
+
llava_hidden = llava_hidden.unsqueeze(0)
|
| 281 |
+
|
| 282 |
+
return llava_hidden.to(device)
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
@torch.no_grad()
|
| 286 |
+
def translate_image(vae, unet, adapter, scheduler, rgb_tensor, llava_hidden,
|
| 287 |
+
num_steps=100, cfg_text=3.5, cfg_image=1.5, device="cuda"):
|
| 288 |
+
"""Translate RGB to TIR using LLaVA features + conditional generation with CFG"""
|
| 289 |
+
|
| 290 |
+
# Encode RGB
|
| 291 |
+
rgb_latents = vae.encode(rgb_tensor).latent_dist.mode() * vae.config.scaling_factor
|
| 292 |
+
batch_size = rgb_latents.shape[0]
|
| 293 |
+
|
| 294 |
+
# Process LLaVA features through adapter
|
| 295 |
+
use_autocast = device.type == "cuda"
|
| 296 |
+
llava_input = llava_hidden.to(device)
|
| 297 |
+
# If using a single cached reference for a batch of RGB images, repeat it across batch.
|
| 298 |
+
if llava_input.shape[0] == 1 and batch_size > 1:
|
| 299 |
+
llava_input = llava_input.expand(batch_size, *llava_input.shape[1:])
|
| 300 |
+
if use_autocast:
|
| 301 |
+
llava_input = llava_input.to(dtype=torch.bfloat16)
|
| 302 |
+
|
| 303 |
+
autocast_ctx = (
|
| 304 |
+
torch.autocast(device_type=device.type, dtype=torch.bfloat16)
|
| 305 |
+
if use_autocast else nullcontext()
|
| 306 |
+
)
|
| 307 |
+
with autocast_ctx:
|
| 308 |
+
llava_tokens = adapter(llava_input)
|
| 309 |
+
llava_tokens = llava_tokens.to(device=device, dtype=next(unet.parameters()).dtype)
|
| 310 |
+
# Ensure token batch matches RGB batch (some adapters may return batch=1 even if input was expanded).
|
| 311 |
+
if llava_tokens.shape[0] == 1 and batch_size > 1:
|
| 312 |
+
llava_tokens = llava_tokens.expand(batch_size, *llava_tokens.shape[1:])
|
| 313 |
+
|
| 314 |
+
# Create null tokens for CFG
|
| 315 |
+
null_tokens = torch.zeros_like(llava_tokens)
|
| 316 |
+
|
| 317 |
+
# Initialize random noise
|
| 318 |
+
latent_shape = (batch_size, 4, rgb_latents.shape[2], rgb_latents.shape[3])
|
| 319 |
+
latents = torch.randn(latent_shape, device=device, dtype=rgb_latents.dtype)
|
| 320 |
+
|
| 321 |
+
# Setup scheduler
|
| 322 |
+
scheduler.set_timesteps(num_steps, device=device)
|
| 323 |
+
|
| 324 |
+
zeros_rgb = torch.zeros_like(rgb_latents)
|
| 325 |
+
|
| 326 |
+
for t in scheduler.timesteps:
|
| 327 |
+
t_batch = torch.full((batch_size,), int(t), device=device, dtype=torch.long)
|
| 328 |
+
|
| 329 |
+
# 3 forward passes for dual-CFG
|
| 330 |
+
x8_full = torch.cat([latents, rgb_latents], dim=1)
|
| 331 |
+
x8_no_img = torch.cat([latents, zeros_rgb], dim=1)
|
| 332 |
+
|
| 333 |
+
# Full conditioning
|
| 334 |
+
eps_full = unet(x8_full, t_batch, encoder_hidden_states=llava_tokens).sample
|
| 335 |
+
|
| 336 |
+
# No text (image only)
|
| 337 |
+
eps_no_text = unet(x8_full, t_batch, encoder_hidden_states=null_tokens).sample
|
| 338 |
+
|
| 339 |
+
# No image (text only)
|
| 340 |
+
eps_no_img = unet(x8_no_img, t_batch, encoder_hidden_states=llava_tokens).sample
|
| 341 |
+
|
| 342 |
+
# Combine with dual-CFG
|
| 343 |
+
eps = eps_full + cfg_text * (eps_full - eps_no_text) + cfg_image * (eps_full - eps_no_img)
|
| 344 |
+
eps = torch.clamp(eps, -5.0, 5.0) # Safety guard
|
| 345 |
+
|
| 346 |
+
latents = scheduler.step(eps, t, latents, eta=0.0).prev_sample
|
| 347 |
+
|
| 348 |
+
# Decode
|
| 349 |
+
pred_tir = vae.decode(latents / vae.config.scaling_factor).sample
|
| 350 |
+
pred_tir = (pred_tir / 2 + 0.5).clamp(0, 1)
|
| 351 |
+
|
| 352 |
+
return pred_tir
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
def main():
|
| 356 |
+
args = parse_args()
|
| 357 |
+
validate_args(args)
|
| 358 |
+
|
| 359 |
+
# Set seed
|
| 360 |
+
torch.manual_seed(args.seed)
|
| 361 |
+
if torch.cuda.is_available():
|
| 362 |
+
torch.cuda.manual_seed_all(args.seed)
|
| 363 |
+
|
| 364 |
+
print("\n" + "="*80)
|
| 365 |
+
print(f"Example-Guided Translation - Mode: {args.mode.upper()}")
|
| 366 |
+
print("="*80)
|
| 367 |
+
print(f"Input image (B): {args.input_image}")
|
| 368 |
+
if args.mode == "two-image":
|
| 369 |
+
print(f"Reference image (A): {args.reference_image}")
|
| 370 |
+
else:
|
| 371 |
+
print(f"Reference cache: {args.reference_cache}")
|
| 372 |
+
print(f"Output: {args.output}")
|
| 373 |
+
print(f"Checkpoint: {args.checkpoint}")
|
| 374 |
+
print(f"DDIM steps: {args.num_steps}")
|
| 375 |
+
print(f"CFG scales: text={args.cfg_text}, image={args.cfg_image}")
|
| 376 |
+
print("="*80)
|
| 377 |
+
|
| 378 |
+
# Load models
|
| 379 |
+
need_llava = (args.mode == "two-image")
|
| 380 |
+
vae, unet, adapter, scheduler, llava_extractor, device = load_models(args, need_llava=need_llava)
|
| 381 |
+
|
| 382 |
+
# Get reference hidden states
|
| 383 |
+
print("\n" + "-"*80)
|
| 384 |
+
if args.mode == "two-image":
|
| 385 |
+
print(f"Extracting features from reference image: {args.reference_image}")
|
| 386 |
+
ref_tensor, ref_pil = load_and_prepare_image(
|
| 387 |
+
args.reference_image,
|
| 388 |
+
target_size=args.target_size,
|
| 389 |
+
device=device
|
| 390 |
+
)
|
| 391 |
+
llava_hidden = llava_extractor.extract_hidden_states([ref_pil], [args.llava_prompt])
|
| 392 |
+
print(f"✓ Extracted hidden states: {llava_hidden.shape}")
|
| 393 |
+
else:
|
| 394 |
+
print(f"Loading cached reference: {args.reference_cache}")
|
| 395 |
+
llava_hidden = load_llava_cache(Path(args.reference_cache), device)
|
| 396 |
+
print(f"✓ Loaded hidden states: {llava_hidden.shape}")
|
| 397 |
+
print("-"*80)
|
| 398 |
+
|
| 399 |
+
# Load input image (Image B)
|
| 400 |
+
print(f"\nLoading input image: {args.input_image}")
|
| 401 |
+
input_tensor, input_pil = load_and_prepare_image(
|
| 402 |
+
args.input_image,
|
| 403 |
+
target_size=args.target_size,
|
| 404 |
+
device=device
|
| 405 |
+
)
|
| 406 |
+
print(f"✓ Input image loaded: {input_tensor.shape}")
|
| 407 |
+
|
| 408 |
+
# Translate
|
| 409 |
+
print("\nTranslating image...")
|
| 410 |
+
pred_tir = translate_image(
|
| 411 |
+
vae, unet, adapter, scheduler,
|
| 412 |
+
input_tensor, llava_hidden,
|
| 413 |
+
num_steps=args.num_steps,
|
| 414 |
+
cfg_text=args.cfg_text,
|
| 415 |
+
cfg_image=args.cfg_image,
|
| 416 |
+
device=device
|
| 417 |
+
)
|
| 418 |
+
|
| 419 |
+
# Save output
|
| 420 |
+
output_path = Path(args.output)
|
| 421 |
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
| 422 |
+
save_image(pred_tir.cpu(), str(output_path))
|
| 423 |
+
|
| 424 |
+
print("="*80)
|
| 425 |
+
print(f"✓ Translation complete!")
|
| 426 |
+
print(f"✓ Saved to: {output_path}")
|
| 427 |
+
print("="*80)
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
if __name__ == "__main__":
|
| 431 |
+
main()
|
| 432 |
+
|
infer_palette.sh
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Run TherA inference with weather/style palette reference caches.
|
| 3 |
+
#
|
| 4 |
+
# Usage:
|
| 5 |
+
# bash scripts/infer_palette.sh /path/to/rgb [output_dir]
|
| 6 |
+
#
|
| 7 |
+
# Requires weights/reference_caches/{SUNNY,CLOUDY,RAINY,NIGHT}.pt
|
| 8 |
+
|
| 9 |
+
set -euo pipefail
|
| 10 |
+
|
| 11 |
+
cd "$(dirname "$0")/.."
|
| 12 |
+
|
| 13 |
+
RGB_DIR="${1:?RGB directory required}"
|
| 14 |
+
OUT_BASE="${2:-preds_palette}"
|
| 15 |
+
|
| 16 |
+
for PAL in SUNNY CLOUDY RAINY NIGHT; do
|
| 17 |
+
CACHE="weights/reference_caches/${PAL}.pt"
|
| 18 |
+
if [[ ! -f "$CACHE" ]]; then
|
| 19 |
+
echo "Skipping ${PAL}: missing ${CACHE}"
|
| 20 |
+
continue
|
| 21 |
+
fi
|
| 22 |
+
echo ">>> ${PAL}"
|
| 23 |
+
python infer_custom.py \
|
| 24 |
+
--rgb-dir "$RGB_DIR" \
|
| 25 |
+
--output-dir "${OUT_BASE}/${PAL}" \
|
| 26 |
+
--reference-cache "$CACHE"
|
| 27 |
+
done
|
| 28 |
+
|
| 29 |
+
echo ""
|
| 30 |
+
echo "Done. Outputs in: ${OUT_BASE}/"
|
lavi_ip2p/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
LaVi-IP2P Module
|
| 3 |
+
|
| 4 |
+
RGB→TIR translation using LaVi-Bridge + cached LLaVA semantics.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
__version__ = "0.1.0"
|
| 8 |
+
|
lavi_ip2p/llava_adapter.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
LLaVA Token Adapter for LaVi-IP2P
|
| 3 |
+
|
| 4 |
+
Adapts cached LLaVA hidden states (4096-dim) to LaVi-Bridge UNet cross-attention (768-dim).
|
| 5 |
+
Uses LaVi-Bridge's TextAdapter with optional preprocessing (RMSNorm, scaling).
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn as nn
|
| 10 |
+
from typing import Optional
|
| 11 |
+
import sys
|
| 12 |
+
import os
|
| 13 |
+
|
| 14 |
+
# Add LaVi-Bridge to path
|
| 15 |
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../LaVi-Bridge"))
|
| 16 |
+
from modules.adapters import TextAdapter
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class RMSNorm(nn.Module):
|
| 20 |
+
"""Root Mean Square Layer Normalization."""
|
| 21 |
+
|
| 22 |
+
def __init__(self, dim: int, eps: float = 1e-6):
|
| 23 |
+
super().__init__()
|
| 24 |
+
self.eps = eps
|
| 25 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
| 26 |
+
|
| 27 |
+
def forward(self, x):
|
| 28 |
+
norm = torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps)
|
| 29 |
+
return x * norm * self.weight
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
class LLaVAAdapter(nn.Module):
|
| 33 |
+
"""
|
| 34 |
+
Adapter: LLaVA hidden (4096) → LaVi-Bridge UNet conditioning (768).
|
| 35 |
+
|
| 36 |
+
FROZEN by default (use pretrained LaVi-Bridge TextAdapter as-is).
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
def __init__(
|
| 40 |
+
self,
|
| 41 |
+
adapter_path: str,
|
| 42 |
+
use_rms_norm: bool = False,
|
| 43 |
+
learnable_scale: bool = False,
|
| 44 |
+
init_scale: float = 1.0,
|
| 45 |
+
freeze_adapter: bool = True,
|
| 46 |
+
):
|
| 47 |
+
super().__init__()
|
| 48 |
+
|
| 49 |
+
self.use_rms_norm = use_rms_norm
|
| 50 |
+
self.learnable_scale = learnable_scale
|
| 51 |
+
|
| 52 |
+
# Load pretrained TextAdapter
|
| 53 |
+
print(f"\nLoading TextAdapter from {adapter_path}...")
|
| 54 |
+
self.adapter = TextAdapter.from_pretrained(adapter_path)
|
| 55 |
+
print(f"✓ TextAdapter loaded (4096→768)")
|
| 56 |
+
|
| 57 |
+
# Freeze by default
|
| 58 |
+
if freeze_adapter:
|
| 59 |
+
for param in self.adapter.parameters():
|
| 60 |
+
param.requires_grad = False
|
| 61 |
+
print(" ✓ FROZEN (using pretrained weights)")
|
| 62 |
+
else:
|
| 63 |
+
print(" ⚠️ TRAINABLE")
|
| 64 |
+
|
| 65 |
+
# Optional: RMSNorm
|
| 66 |
+
if use_rms_norm:
|
| 67 |
+
self.rms_norm = RMSNorm(4096, eps=1e-6)
|
| 68 |
+
print("✓ RMSNorm enabled")
|
| 69 |
+
|
| 70 |
+
# Optional: Learnable scale
|
| 71 |
+
if learnable_scale:
|
| 72 |
+
self.scale = nn.Parameter(torch.tensor(init_scale))
|
| 73 |
+
print(f"✓ Learnable scale (init={init_scale})")
|
| 74 |
+
else:
|
| 75 |
+
self.register_buffer('scale', torch.tensor(init_scale))
|
| 76 |
+
|
| 77 |
+
def forward(self, llava_hidden: torch.Tensor) -> torch.Tensor:
|
| 78 |
+
"""LLaVA (B,L,4096) → UNet conditioning (B,L,768)"""
|
| 79 |
+
x = llava_hidden
|
| 80 |
+
|
| 81 |
+
if self.use_rms_norm:
|
| 82 |
+
x = self.rms_norm(x)
|
| 83 |
+
|
| 84 |
+
x = self.adapter(x).sample
|
| 85 |
+
|
| 86 |
+
if self.learnable_scale:
|
| 87 |
+
x = x * self.scale
|
| 88 |
+
|
| 89 |
+
return x
|
| 90 |
+
|
| 91 |
+
def get_stats(self):
|
| 92 |
+
"""Get adapter statistics for logging"""
|
| 93 |
+
stats = {}
|
| 94 |
+
if self.learnable_scale:
|
| 95 |
+
stats['scale'] = self.scale.item()
|
| 96 |
+
return stats
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def create_llava_adapter(
|
| 100 |
+
adapter_path: str,
|
| 101 |
+
use_rms_norm: bool = False,
|
| 102 |
+
learnable_scale: bool = False,
|
| 103 |
+
init_scale: float = 1.0,
|
| 104 |
+
freeze_adapter: bool = True,
|
| 105 |
+
) -> LLaVAAdapter:
|
| 106 |
+
"""
|
| 107 |
+
Factory: Create LLaVA adapter.
|
| 108 |
+
|
| 109 |
+
DEFAULT (simple mode):
|
| 110 |
+
- Freeze TextAdapter (use LaVi-Bridge pretrained)
|
| 111 |
+
- No RMSNorm, no scale
|
| 112 |
+
- Train UNet only
|
| 113 |
+
"""
|
| 114 |
+
|
| 115 |
+
print("\n" + "="*60)
|
| 116 |
+
print("Creating LLaVA Token Adapter")
|
| 117 |
+
print("="*60)
|
| 118 |
+
print(f"Mode: {'SIMPLE (frozen)' if freeze_adapter else 'ADVANCED (trainable)'}")
|
| 119 |
+
|
| 120 |
+
adapter = LLaVAAdapter(
|
| 121 |
+
adapter_path=adapter_path,
|
| 122 |
+
use_rms_norm=use_rms_norm,
|
| 123 |
+
learnable_scale=learnable_scale,
|
| 124 |
+
init_scale=init_scale,
|
| 125 |
+
freeze_adapter=freeze_adapter,
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
total = sum(p.numel() for p in adapter.parameters())
|
| 129 |
+
trainable = sum(p.numel() for p in adapter.parameters() if p.requires_grad)
|
| 130 |
+
|
| 131 |
+
print(f"\nParameters: {total:,} total, {trainable:,} trainable")
|
| 132 |
+
print("="*60 + "\n")
|
| 133 |
+
|
| 134 |
+
return adapter
|
| 135 |
+
|
lavi_ip2p/unet_8ch.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
UNet 8-channel modification for LaVi-IP2P
|
| 3 |
+
|
| 4 |
+
Safely converts LaVi-Bridge UNet from 4-channel to 8-channel input
|
| 5 |
+
by expanding conv_in with zero-initialized extra channels (InstructPix2Pix style).
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn as nn
|
| 10 |
+
from diffusers import UNet2DConditionModel
|
| 11 |
+
from typing import Optional
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def convert_unet_to_8ch(
|
| 15 |
+
unet: UNet2DConditionModel,
|
| 16 |
+
init_scale: float = 1e-5,
|
| 17 |
+
) -> UNet2DConditionModel:
|
| 18 |
+
"""
|
| 19 |
+
Convert UNet from 4-channel to 8-channel input.
|
| 20 |
+
|
| 21 |
+
Strategy (InstructPix2Pix style):
|
| 22 |
+
1. Copy first 4 channels from pretrained conv_in weights
|
| 23 |
+
2. Initialize extra 4 channels with small random values (scaled by init_scale)
|
| 24 |
+
3. This ensures the UNet starts close to the original behavior
|
| 25 |
+
|
| 26 |
+
Args:
|
| 27 |
+
unet: Pretrained 4-channel UNet
|
| 28 |
+
init_scale: Scale for initializing extra channels (default: 1e-5 for stability)
|
| 29 |
+
|
| 30 |
+
Returns:
|
| 31 |
+
Modified 8-channel UNet
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
if unet.config.in_channels == 8:
|
| 35 |
+
print("⚠️ UNet already has 8 input channels, skipping conversion")
|
| 36 |
+
return unet
|
| 37 |
+
|
| 38 |
+
if unet.config.in_channels != 4:
|
| 39 |
+
raise ValueError(f"Expected 4-channel UNet, got {unet.config.in_channels}")
|
| 40 |
+
|
| 41 |
+
print("\n" + "="*60)
|
| 42 |
+
print("Converting UNet to 8-channel input (IP2P style)")
|
| 43 |
+
print("="*60)
|
| 44 |
+
|
| 45 |
+
old_conv = unet.conv_in
|
| 46 |
+
print(f"Original conv_in: {old_conv}")
|
| 47 |
+
print(f" in_channels: {old_conv.in_channels}")
|
| 48 |
+
print(f" out_channels: {old_conv.out_channels}")
|
| 49 |
+
print(f" kernel_size: {old_conv.kernel_size}")
|
| 50 |
+
print(f" weight shape: {old_conv.weight.shape}")
|
| 51 |
+
|
| 52 |
+
# Create new 8-channel conv
|
| 53 |
+
new_conv = nn.Conv2d(
|
| 54 |
+
in_channels=8,
|
| 55 |
+
out_channels=old_conv.out_channels,
|
| 56 |
+
kernel_size=old_conv.kernel_size,
|
| 57 |
+
stride=old_conv.stride,
|
| 58 |
+
padding=old_conv.padding,
|
| 59 |
+
bias=(old_conv.bias is not None),
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
# Initialize weights
|
| 63 |
+
with torch.no_grad():
|
| 64 |
+
# Copy first 4 channels from pretrained weights
|
| 65 |
+
new_conv.weight[:, :4, :, :].copy_(old_conv.weight)
|
| 66 |
+
|
| 67 |
+
# Initialize extra 4 channels with small random values
|
| 68 |
+
# This ensures the UNet starts close to original behavior
|
| 69 |
+
nn.init.normal_(new_conv.weight[:, 4:, :, :], mean=0.0, std=init_scale)
|
| 70 |
+
|
| 71 |
+
# Copy bias if present
|
| 72 |
+
if old_conv.bias is not None:
|
| 73 |
+
new_conv.bias.copy_(old_conv.bias)
|
| 74 |
+
|
| 75 |
+
# Replace conv_in
|
| 76 |
+
unet.conv_in = new_conv
|
| 77 |
+
|
| 78 |
+
# Update config
|
| 79 |
+
unet.register_to_config(in_channels=8)
|
| 80 |
+
|
| 81 |
+
print(f"\n✓ New conv_in: {new_conv}")
|
| 82 |
+
print(f" weight shape: {new_conv.weight.shape}")
|
| 83 |
+
print(f" Channels 0-3: copied from pretrained")
|
| 84 |
+
print(f" Channels 4-7: initialized with std={init_scale}")
|
| 85 |
+
print("="*60 + "\n")
|
| 86 |
+
|
| 87 |
+
return unet
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def load_lavi_unet_8ch(
|
| 91 |
+
pretrained_path: str,
|
| 92 |
+
lora_path: Optional[str] = None,
|
| 93 |
+
lora_rank: int = 32,
|
| 94 |
+
init_scale: float = 1e-5,
|
| 95 |
+
device: str = "cuda",
|
| 96 |
+
) -> UNet2DConditionModel:
|
| 97 |
+
"""
|
| 98 |
+
Load LaVi-Bridge UNet with LoRA and convert to 8-channel.
|
| 99 |
+
|
| 100 |
+
Args:
|
| 101 |
+
pretrained_path: Path to pretrained SD UNet (e.g., "CompVis/stable-diffusion-v1-4")
|
| 102 |
+
lora_path: Path to LaVi-Bridge LoRA weights (lora_vis.pt)
|
| 103 |
+
lora_rank: LoRA rank (default: 32)
|
| 104 |
+
init_scale: Scale for extra channels
|
| 105 |
+
device: Device to load on
|
| 106 |
+
|
| 107 |
+
Returns:
|
| 108 |
+
8-channel UNet with LaVi-Bridge LoRA applied
|
| 109 |
+
"""
|
| 110 |
+
|
| 111 |
+
print("\n" + "="*60)
|
| 112 |
+
print("Loading LaVi-Bridge UNet (8-channel)")
|
| 113 |
+
print("="*60)
|
| 114 |
+
|
| 115 |
+
# Load base UNet
|
| 116 |
+
print(f"\n[1/3] Loading base UNet from {pretrained_path}...")
|
| 117 |
+
|
| 118 |
+
# Determine subfolder based on filesystem check
|
| 119 |
+
from pathlib import Path
|
| 120 |
+
subfolder = "unet" if Path(pretrained_path).is_dir() and (Path(pretrained_path) / "unet").exists() else None
|
| 121 |
+
|
| 122 |
+
unet = UNet2DConditionModel.from_pretrained(
|
| 123 |
+
pretrained_path,
|
| 124 |
+
subfolder=subfolder,
|
| 125 |
+
)
|
| 126 |
+
print(f"✓ Base UNet loaded (subfolder: {subfolder})")
|
| 127 |
+
|
| 128 |
+
# Apply LoRA if provided
|
| 129 |
+
if lora_path is not None:
|
| 130 |
+
print(f"\n[2/3] Applying LaVi-Bridge LoRA from {lora_path}...")
|
| 131 |
+
|
| 132 |
+
# Import LoRA utilities (robust path resolution)
|
| 133 |
+
import sys
|
| 134 |
+
import os
|
| 135 |
+
lavi_bridge_path = os.path.join(os.path.dirname(__file__), "../LaVi-Bridge")
|
| 136 |
+
sys.path.insert(0, lavi_bridge_path)
|
| 137 |
+
from modules.lora import monkeypatch_or_replace_lora_extended
|
| 138 |
+
|
| 139 |
+
VIS_REPLACE_MODULES = {"ResnetBlock2D", "CrossAttention", "Attention", "GEGLU"}
|
| 140 |
+
|
| 141 |
+
monkeypatch_or_replace_lora_extended(
|
| 142 |
+
unet,
|
| 143 |
+
torch.load(lora_path, map_location='cpu'),
|
| 144 |
+
r=lora_rank,
|
| 145 |
+
target_replace_module=VIS_REPLACE_MODULES,
|
| 146 |
+
)
|
| 147 |
+
print(f"✓ LoRA applied (rank={lora_rank})")
|
| 148 |
+
else:
|
| 149 |
+
print(f"\n[2/3] No LoRA path provided, using base UNet")
|
| 150 |
+
|
| 151 |
+
# Convert to 8-channel
|
| 152 |
+
print(f"\n[3/3] Converting to 8-channel input...")
|
| 153 |
+
unet = convert_unet_to_8ch(unet, init_scale=init_scale)
|
| 154 |
+
|
| 155 |
+
# Move to device
|
| 156 |
+
unet = unet.to(device)
|
| 157 |
+
print(f"✓ Moved to {device}")
|
| 158 |
+
print("="*60 + "\n")
|
| 159 |
+
|
| 160 |
+
return unet
|
| 161 |
+
|
llava/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
from .model import LlavaLlamaForCausalLM
|
llava/constants.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
CONTROLLER_HEART_BEAT_EXPIRATION = 30
|
| 2 |
+
WORKER_HEART_BEAT_INTERVAL = 15
|
| 3 |
+
|
| 4 |
+
LOGDIR = "."
|
| 5 |
+
|
| 6 |
+
# Model Constants
|
| 7 |
+
IGNORE_INDEX = -100
|
| 8 |
+
IMAGE_TOKEN_INDEX = -200
|
| 9 |
+
DEFAULT_IMAGE_TOKEN = "<image>"
|
| 10 |
+
DEFAULT_IMAGE_PATCH_TOKEN = "<im_patch>"
|
| 11 |
+
DEFAULT_IM_START_TOKEN = "<im_start>"
|
| 12 |
+
DEFAULT_IM_END_TOKEN = "<im_end>"
|
| 13 |
+
IMAGE_PLACEHOLDER = "<image-placeholder>"
|
| 14 |
+
|
| 15 |
+
# IMG tokens for VLM-guided diffusion (16 tokens for edit conditioning)
|
| 16 |
+
IMG_TOKENS = [f"[IMG{i}]" for i in range(16)]
|
llava/conversation.py
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import dataclasses
|
| 2 |
+
from enum import auto, Enum
|
| 3 |
+
from typing import List, Tuple
|
| 4 |
+
import base64
|
| 5 |
+
from io import BytesIO
|
| 6 |
+
from PIL import Image
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class SeparatorStyle(Enum):
|
| 10 |
+
"""Different separator style."""
|
| 11 |
+
SINGLE = auto()
|
| 12 |
+
TWO = auto()
|
| 13 |
+
MPT = auto()
|
| 14 |
+
PLAIN = auto()
|
| 15 |
+
LLAMA_2 = auto()
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@dataclasses.dataclass
|
| 19 |
+
class Conversation:
|
| 20 |
+
"""A class that keeps all conversation history."""
|
| 21 |
+
system: str
|
| 22 |
+
roles: List[str]
|
| 23 |
+
messages: List[List[str]]
|
| 24 |
+
offset: int
|
| 25 |
+
sep_style: SeparatorStyle = SeparatorStyle.SINGLE
|
| 26 |
+
sep: str = "###"
|
| 27 |
+
sep2: str = None
|
| 28 |
+
version: str = "Unknown"
|
| 29 |
+
|
| 30 |
+
skip_next: bool = False
|
| 31 |
+
|
| 32 |
+
def get_prompt(self):
|
| 33 |
+
messages = self.messages
|
| 34 |
+
if len(messages) > 0 and type(messages[0][1]) is tuple:
|
| 35 |
+
messages = self.messages.copy()
|
| 36 |
+
init_role, init_msg = messages[0].copy()
|
| 37 |
+
init_msg = init_msg[0].replace("<image>", "").strip()
|
| 38 |
+
if 'mmtag' in self.version:
|
| 39 |
+
messages[0] = (init_role, init_msg)
|
| 40 |
+
messages.insert(0, (self.roles[0], "<Image><image></Image>"))
|
| 41 |
+
messages.insert(1, (self.roles[1], "Received."))
|
| 42 |
+
else:
|
| 43 |
+
messages[0] = (init_role, "<image>\n" + init_msg)
|
| 44 |
+
|
| 45 |
+
if self.sep_style == SeparatorStyle.SINGLE:
|
| 46 |
+
ret = self.system + self.sep
|
| 47 |
+
for role, message in messages:
|
| 48 |
+
if message:
|
| 49 |
+
if type(message) is tuple:
|
| 50 |
+
message, _, _ = message
|
| 51 |
+
ret += role + ": " + message + self.sep
|
| 52 |
+
else:
|
| 53 |
+
ret += role + ":"
|
| 54 |
+
elif self.sep_style == SeparatorStyle.TWO:
|
| 55 |
+
seps = [self.sep, self.sep2]
|
| 56 |
+
ret = self.system + seps[0]
|
| 57 |
+
for i, (role, message) in enumerate(messages):
|
| 58 |
+
if message:
|
| 59 |
+
if type(message) is tuple:
|
| 60 |
+
message, _, _ = message
|
| 61 |
+
ret += role + ": " + message + seps[i % 2]
|
| 62 |
+
else:
|
| 63 |
+
ret += role + ":"
|
| 64 |
+
elif self.sep_style == SeparatorStyle.MPT:
|
| 65 |
+
ret = self.system + self.sep
|
| 66 |
+
for role, message in messages:
|
| 67 |
+
if message:
|
| 68 |
+
if type(message) is tuple:
|
| 69 |
+
message, _, _ = message
|
| 70 |
+
ret += role + message + self.sep
|
| 71 |
+
else:
|
| 72 |
+
ret += role
|
| 73 |
+
elif self.sep_style == SeparatorStyle.LLAMA_2:
|
| 74 |
+
wrap_sys = lambda msg: f"<<SYS>>\n{msg}\n<</SYS>>\n\n" if len(msg) > 0 else msg
|
| 75 |
+
wrap_inst = lambda msg: f"[INST] {msg} [/INST]"
|
| 76 |
+
ret = ""
|
| 77 |
+
|
| 78 |
+
for i, (role, message) in enumerate(messages):
|
| 79 |
+
if i == 0:
|
| 80 |
+
assert message, "first message should not be none"
|
| 81 |
+
assert role == self.roles[0], "first message should come from user"
|
| 82 |
+
if message:
|
| 83 |
+
if type(message) is tuple:
|
| 84 |
+
message, _, _ = message
|
| 85 |
+
if i == 0: message = wrap_sys(self.system) + message
|
| 86 |
+
if i % 2 == 0:
|
| 87 |
+
message = wrap_inst(message)
|
| 88 |
+
ret += self.sep + message
|
| 89 |
+
else:
|
| 90 |
+
ret += " " + message + " " + self.sep2
|
| 91 |
+
else:
|
| 92 |
+
ret += ""
|
| 93 |
+
ret = ret.lstrip(self.sep)
|
| 94 |
+
elif self.sep_style == SeparatorStyle.PLAIN:
|
| 95 |
+
seps = [self.sep, self.sep2]
|
| 96 |
+
ret = self.system
|
| 97 |
+
for i, (role, message) in enumerate(messages):
|
| 98 |
+
if message:
|
| 99 |
+
if type(message) is tuple:
|
| 100 |
+
message, _, _ = message
|
| 101 |
+
ret += message + seps[i % 2]
|
| 102 |
+
else:
|
| 103 |
+
ret += ""
|
| 104 |
+
else:
|
| 105 |
+
raise ValueError(f"Invalid style: {self.sep_style}")
|
| 106 |
+
|
| 107 |
+
return ret
|
| 108 |
+
|
| 109 |
+
def append_message(self, role, message):
|
| 110 |
+
self.messages.append([role, message])
|
| 111 |
+
|
| 112 |
+
def process_image(self, image, image_process_mode, return_pil=False, image_format='PNG', max_len=1344, min_len=672):
|
| 113 |
+
if image_process_mode == "Pad":
|
| 114 |
+
def expand2square(pil_img, background_color=(122, 116, 104)):
|
| 115 |
+
width, height = pil_img.size
|
| 116 |
+
if width == height:
|
| 117 |
+
return pil_img
|
| 118 |
+
elif width > height:
|
| 119 |
+
result = Image.new(pil_img.mode, (width, width), background_color)
|
| 120 |
+
result.paste(pil_img, (0, (width - height) // 2))
|
| 121 |
+
return result
|
| 122 |
+
else:
|
| 123 |
+
result = Image.new(pil_img.mode, (height, height), background_color)
|
| 124 |
+
result.paste(pil_img, ((height - width) // 2, 0))
|
| 125 |
+
return result
|
| 126 |
+
image = expand2square(image)
|
| 127 |
+
elif image_process_mode in ["Default", "Crop"]:
|
| 128 |
+
pass
|
| 129 |
+
elif image_process_mode == "Resize":
|
| 130 |
+
image = image.resize((336, 336))
|
| 131 |
+
else:
|
| 132 |
+
raise ValueError(f"Invalid image_process_mode: {image_process_mode}")
|
| 133 |
+
if max(image.size) > max_len:
|
| 134 |
+
max_hw, min_hw = max(image.size), min(image.size)
|
| 135 |
+
aspect_ratio = max_hw / min_hw
|
| 136 |
+
shortest_edge = int(min(max_len / aspect_ratio, min_len, min_hw))
|
| 137 |
+
longest_edge = int(shortest_edge * aspect_ratio)
|
| 138 |
+
W, H = image.size
|
| 139 |
+
if H > W:
|
| 140 |
+
H, W = longest_edge, shortest_edge
|
| 141 |
+
else:
|
| 142 |
+
H, W = shortest_edge, longest_edge
|
| 143 |
+
image = image.resize((W, H))
|
| 144 |
+
if return_pil:
|
| 145 |
+
return image
|
| 146 |
+
else:
|
| 147 |
+
buffered = BytesIO()
|
| 148 |
+
image.save(buffered, format=image_format)
|
| 149 |
+
img_b64_str = base64.b64encode(buffered.getvalue()).decode()
|
| 150 |
+
return img_b64_str
|
| 151 |
+
|
| 152 |
+
def get_images(self, return_pil=False):
|
| 153 |
+
images = []
|
| 154 |
+
for i, (role, msg) in enumerate(self.messages[self.offset:]):
|
| 155 |
+
if i % 2 == 0:
|
| 156 |
+
if type(msg) is tuple:
|
| 157 |
+
msg, image, image_process_mode = msg
|
| 158 |
+
image = self.process_image(image, image_process_mode, return_pil=return_pil)
|
| 159 |
+
images.append(image)
|
| 160 |
+
return images
|
| 161 |
+
|
| 162 |
+
def to_gradio_chatbot(self):
|
| 163 |
+
ret = []
|
| 164 |
+
for i, (role, msg) in enumerate(self.messages[self.offset:]):
|
| 165 |
+
if i % 2 == 0:
|
| 166 |
+
if type(msg) is tuple:
|
| 167 |
+
msg, image, image_process_mode = msg
|
| 168 |
+
img_b64_str = self.process_image(
|
| 169 |
+
image, "Default", return_pil=False,
|
| 170 |
+
image_format='JPEG')
|
| 171 |
+
img_str = f'<img src="data:image/jpeg;base64,{img_b64_str}" alt="user upload image" />'
|
| 172 |
+
msg = img_str + msg.replace('<image>', '').strip()
|
| 173 |
+
ret.append([msg, None])
|
| 174 |
+
else:
|
| 175 |
+
ret.append([msg, None])
|
| 176 |
+
else:
|
| 177 |
+
ret[-1][-1] = msg
|
| 178 |
+
return ret
|
| 179 |
+
|
| 180 |
+
def copy(self):
|
| 181 |
+
return Conversation(
|
| 182 |
+
system=self.system,
|
| 183 |
+
roles=self.roles,
|
| 184 |
+
messages=[[x, y] for x, y in self.messages],
|
| 185 |
+
offset=self.offset,
|
| 186 |
+
sep_style=self.sep_style,
|
| 187 |
+
sep=self.sep,
|
| 188 |
+
sep2=self.sep2,
|
| 189 |
+
version=self.version)
|
| 190 |
+
|
| 191 |
+
def dict(self):
|
| 192 |
+
if len(self.get_images()) > 0:
|
| 193 |
+
return {
|
| 194 |
+
"system": self.system,
|
| 195 |
+
"roles": self.roles,
|
| 196 |
+
"messages": [[x, y[0] if type(y) is tuple else y] for x, y in self.messages],
|
| 197 |
+
"offset": self.offset,
|
| 198 |
+
"sep": self.sep,
|
| 199 |
+
"sep2": self.sep2,
|
| 200 |
+
}
|
| 201 |
+
return {
|
| 202 |
+
"system": self.system,
|
| 203 |
+
"roles": self.roles,
|
| 204 |
+
"messages": self.messages,
|
| 205 |
+
"offset": self.offset,
|
| 206 |
+
"sep": self.sep,
|
| 207 |
+
"sep2": self.sep2,
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
conv_vicuna_v0 = Conversation(
|
| 212 |
+
system="A chat between a curious human and an artificial intelligence assistant. "
|
| 213 |
+
"The assistant gives helpful, detailed, and polite answers to the human's questions.",
|
| 214 |
+
roles=("Human", "Assistant"),
|
| 215 |
+
messages=(
|
| 216 |
+
("Human", "What are the key differences between renewable and non-renewable energy sources?"),
|
| 217 |
+
("Assistant",
|
| 218 |
+
"Renewable energy sources are those that can be replenished naturally in a relatively "
|
| 219 |
+
"short amount of time, such as solar, wind, hydro, geothermal, and biomass. "
|
| 220 |
+
"Non-renewable energy sources, on the other hand, are finite and will eventually be "
|
| 221 |
+
"depleted, such as coal, oil, and natural gas. Here are some key differences between "
|
| 222 |
+
"renewable and non-renewable energy sources:\n"
|
| 223 |
+
"1. Availability: Renewable energy sources are virtually inexhaustible, while non-renewable "
|
| 224 |
+
"energy sources are finite and will eventually run out.\n"
|
| 225 |
+
"2. Environmental impact: Renewable energy sources have a much lower environmental impact "
|
| 226 |
+
"than non-renewable sources, which can lead to air and water pollution, greenhouse gas emissions, "
|
| 227 |
+
"and other negative effects.\n"
|
| 228 |
+
"3. Cost: Renewable energy sources can be more expensive to initially set up, but they typically "
|
| 229 |
+
"have lower operational costs than non-renewable sources.\n"
|
| 230 |
+
"4. Reliability: Renewable energy sources are often more reliable and can be used in more remote "
|
| 231 |
+
"locations than non-renewable sources.\n"
|
| 232 |
+
"5. Flexibility: Renewable energy sources are often more flexible and can be adapted to different "
|
| 233 |
+
"situations and needs, while non-renewable sources are more rigid and inflexible.\n"
|
| 234 |
+
"6. Sustainability: Renewable energy sources are more sustainable over the long term, while "
|
| 235 |
+
"non-renewable sources are not, and their depletion can lead to economic and social instability.\n")
|
| 236 |
+
),
|
| 237 |
+
offset=2,
|
| 238 |
+
sep_style=SeparatorStyle.SINGLE,
|
| 239 |
+
sep="###",
|
| 240 |
+
)
|
| 241 |
+
|
| 242 |
+
conv_vicuna_v1 = Conversation(
|
| 243 |
+
system="A chat between a curious user and an artificial intelligence assistant. "
|
| 244 |
+
"The assistant gives helpful, detailed, and polite answers to the user's questions.",
|
| 245 |
+
roles=("USER", "ASSISTANT"),
|
| 246 |
+
version="v1",
|
| 247 |
+
messages=(),
|
| 248 |
+
offset=0,
|
| 249 |
+
sep_style=SeparatorStyle.TWO,
|
| 250 |
+
sep=" ",
|
| 251 |
+
sep2="</s>",
|
| 252 |
+
)
|
| 253 |
+
|
| 254 |
+
conv_llama_2 = Conversation(
|
| 255 |
+
system="""You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. Your answers should not include any harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. Please ensure that your responses are socially unbiased and positive in nature.
|
| 256 |
+
|
| 257 |
+
If a question does not make any sense, or is not factually coherent, explain why instead of answering something not correct. If you don't know the answer to a question, please don't share false information.""",
|
| 258 |
+
roles=("USER", "ASSISTANT"),
|
| 259 |
+
version="llama_v2",
|
| 260 |
+
messages=(),
|
| 261 |
+
offset=0,
|
| 262 |
+
sep_style=SeparatorStyle.LLAMA_2,
|
| 263 |
+
sep="<s>",
|
| 264 |
+
sep2="</s>",
|
| 265 |
+
)
|
| 266 |
+
|
| 267 |
+
conv_llava_llama_2 = Conversation(
|
| 268 |
+
system="You are a helpful language and vision assistant. "
|
| 269 |
+
"You are able to understand the visual content that the user provides, "
|
| 270 |
+
"and assist the user with a variety of tasks using natural language.",
|
| 271 |
+
roles=("USER", "ASSISTANT"),
|
| 272 |
+
version="llama_v2",
|
| 273 |
+
messages=(),
|
| 274 |
+
offset=0,
|
| 275 |
+
sep_style=SeparatorStyle.LLAMA_2,
|
| 276 |
+
sep="<s>",
|
| 277 |
+
sep2="</s>",
|
| 278 |
+
)
|
| 279 |
+
|
| 280 |
+
conv_mpt = Conversation(
|
| 281 |
+
system="""<|im_start|>system
|
| 282 |
+
A conversation between a user and an LLM-based AI assistant. The assistant gives helpful and honest answers.""",
|
| 283 |
+
roles=("<|im_start|>user\n", "<|im_start|>assistant\n"),
|
| 284 |
+
version="mpt",
|
| 285 |
+
messages=(),
|
| 286 |
+
offset=0,
|
| 287 |
+
sep_style=SeparatorStyle.MPT,
|
| 288 |
+
sep="<|im_end|>",
|
| 289 |
+
)
|
| 290 |
+
|
| 291 |
+
conv_llava_plain = Conversation(
|
| 292 |
+
system="",
|
| 293 |
+
roles=("", ""),
|
| 294 |
+
messages=(
|
| 295 |
+
),
|
| 296 |
+
offset=0,
|
| 297 |
+
sep_style=SeparatorStyle.PLAIN,
|
| 298 |
+
sep="\n",
|
| 299 |
+
)
|
| 300 |
+
|
| 301 |
+
conv_llava_v0 = Conversation(
|
| 302 |
+
system="A chat between a curious human and an artificial intelligence assistant. "
|
| 303 |
+
"The assistant gives helpful, detailed, and polite answers to the human's questions.",
|
| 304 |
+
roles=("Human", "Assistant"),
|
| 305 |
+
messages=(
|
| 306 |
+
),
|
| 307 |
+
offset=0,
|
| 308 |
+
sep_style=SeparatorStyle.SINGLE,
|
| 309 |
+
sep="###",
|
| 310 |
+
)
|
| 311 |
+
|
| 312 |
+
conv_llava_v0_mmtag = Conversation(
|
| 313 |
+
system="A chat between a curious user and an artificial intelligence assistant. "
|
| 314 |
+
"The assistant is able to understand the visual content that the user provides, and assist the user with a variety of tasks using natural language."
|
| 315 |
+
"The visual content will be provided with the following format: <Image>visual content</Image>.",
|
| 316 |
+
roles=("Human", "Assistant"),
|
| 317 |
+
messages=(
|
| 318 |
+
),
|
| 319 |
+
offset=0,
|
| 320 |
+
sep_style=SeparatorStyle.SINGLE,
|
| 321 |
+
sep="###",
|
| 322 |
+
version="v0_mmtag",
|
| 323 |
+
)
|
| 324 |
+
|
| 325 |
+
conv_llava_v1 = Conversation(
|
| 326 |
+
system="A chat between a curious human and an artificial intelligence assistant. "
|
| 327 |
+
"The assistant gives helpful, detailed, and polite answers to the human's questions.",
|
| 328 |
+
roles=("USER", "ASSISTANT"),
|
| 329 |
+
version="v1",
|
| 330 |
+
messages=(),
|
| 331 |
+
offset=0,
|
| 332 |
+
sep_style=SeparatorStyle.TWO,
|
| 333 |
+
sep=" ",
|
| 334 |
+
sep2="</s>",
|
| 335 |
+
)
|
| 336 |
+
|
| 337 |
+
conv_llava_v1_mmtag = Conversation(
|
| 338 |
+
system="A chat between a curious user and an artificial intelligence assistant. "
|
| 339 |
+
"The assistant is able to understand the visual content that the user provides, and assist the user with a variety of tasks using natural language."
|
| 340 |
+
"The visual content will be provided with the following format: <Image>visual content</Image>.",
|
| 341 |
+
roles=("USER", "ASSISTANT"),
|
| 342 |
+
messages=(),
|
| 343 |
+
offset=0,
|
| 344 |
+
sep_style=SeparatorStyle.TWO,
|
| 345 |
+
sep=" ",
|
| 346 |
+
sep2="</s>",
|
| 347 |
+
version="v1_mmtag",
|
| 348 |
+
)
|
| 349 |
+
|
| 350 |
+
conv_mistral_instruct = Conversation(
|
| 351 |
+
system="",
|
| 352 |
+
roles=("USER", "ASSISTANT"),
|
| 353 |
+
version="llama_v2",
|
| 354 |
+
messages=(),
|
| 355 |
+
offset=0,
|
| 356 |
+
sep_style=SeparatorStyle.LLAMA_2,
|
| 357 |
+
sep="",
|
| 358 |
+
sep2="</s>",
|
| 359 |
+
)
|
| 360 |
+
|
| 361 |
+
conv_chatml_direct = Conversation(
|
| 362 |
+
system="""<|im_start|>system
|
| 363 |
+
Answer the questions.""",
|
| 364 |
+
roles=("<|im_start|>user\n", "<|im_start|>assistant\n"),
|
| 365 |
+
version="mpt",
|
| 366 |
+
messages=(),
|
| 367 |
+
offset=0,
|
| 368 |
+
sep_style=SeparatorStyle.MPT,
|
| 369 |
+
sep="<|im_end|>",
|
| 370 |
+
)
|
| 371 |
+
|
| 372 |
+
default_conversation = conv_vicuna_v1
|
| 373 |
+
conv_templates = {
|
| 374 |
+
"default": conv_vicuna_v0,
|
| 375 |
+
"v0": conv_vicuna_v0,
|
| 376 |
+
"v1": conv_vicuna_v1,
|
| 377 |
+
"vicuna_v1": conv_vicuna_v1,
|
| 378 |
+
"llama_2": conv_llama_2,
|
| 379 |
+
"mistral_instruct": conv_mistral_instruct,
|
| 380 |
+
"chatml_direct": conv_chatml_direct,
|
| 381 |
+
"mistral_direct": conv_chatml_direct,
|
| 382 |
+
|
| 383 |
+
"plain": conv_llava_plain,
|
| 384 |
+
"v0_plain": conv_llava_plain,
|
| 385 |
+
"llava_v0": conv_llava_v0,
|
| 386 |
+
"v0_mmtag": conv_llava_v0_mmtag,
|
| 387 |
+
"llava_v1": conv_llava_v1,
|
| 388 |
+
"v1_mmtag": conv_llava_v1_mmtag,
|
| 389 |
+
"llava_llama_2": conv_llava_llama_2,
|
| 390 |
+
|
| 391 |
+
"mpt": conv_mpt,
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
if __name__ == "__main__":
|
| 396 |
+
print(default_conversation.get_prompt())
|
llava/eval/table/results/test_sqa_llava_13b_v0.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
llava/mm_utils.py
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from PIL import Image
|
| 2 |
+
from io import BytesIO
|
| 3 |
+
import base64
|
| 4 |
+
import torch
|
| 5 |
+
import math
|
| 6 |
+
import ast
|
| 7 |
+
|
| 8 |
+
from transformers import StoppingCriteria
|
| 9 |
+
from llava.constants import IMAGE_TOKEN_INDEX
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def select_best_resolution(original_size, possible_resolutions):
|
| 13 |
+
"""
|
| 14 |
+
Selects the best resolution from a list of possible resolutions based on the original size.
|
| 15 |
+
|
| 16 |
+
Args:
|
| 17 |
+
original_size (tuple): The original size of the image in the format (width, height).
|
| 18 |
+
possible_resolutions (list): A list of possible resolutions in the format [(width1, height1), (width2, height2), ...].
|
| 19 |
+
|
| 20 |
+
Returns:
|
| 21 |
+
tuple: The best fit resolution in the format (width, height).
|
| 22 |
+
"""
|
| 23 |
+
original_width, original_height = original_size
|
| 24 |
+
best_fit = None
|
| 25 |
+
max_effective_resolution = 0
|
| 26 |
+
min_wasted_resolution = float('inf')
|
| 27 |
+
|
| 28 |
+
for width, height in possible_resolutions:
|
| 29 |
+
scale = min(width / original_width, height / original_height)
|
| 30 |
+
downscaled_width, downscaled_height = int(original_width * scale), int(original_height * scale)
|
| 31 |
+
effective_resolution = min(downscaled_width * downscaled_height, original_width * original_height)
|
| 32 |
+
wasted_resolution = (width * height) - effective_resolution
|
| 33 |
+
|
| 34 |
+
if effective_resolution > max_effective_resolution or (effective_resolution == max_effective_resolution and wasted_resolution < min_wasted_resolution):
|
| 35 |
+
max_effective_resolution = effective_resolution
|
| 36 |
+
min_wasted_resolution = wasted_resolution
|
| 37 |
+
best_fit = (width, height)
|
| 38 |
+
|
| 39 |
+
return best_fit
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def resize_and_pad_image(image, target_resolution):
|
| 43 |
+
"""
|
| 44 |
+
Resize and pad an image to a target resolution while maintaining aspect ratio.
|
| 45 |
+
|
| 46 |
+
Args:
|
| 47 |
+
image (PIL.Image.Image): The input image.
|
| 48 |
+
target_resolution (tuple): The target resolution (width, height) of the image.
|
| 49 |
+
|
| 50 |
+
Returns:
|
| 51 |
+
PIL.Image.Image: The resized and padded image.
|
| 52 |
+
"""
|
| 53 |
+
original_width, original_height = image.size
|
| 54 |
+
target_width, target_height = target_resolution
|
| 55 |
+
|
| 56 |
+
scale_w = target_width / original_width
|
| 57 |
+
scale_h = target_height / original_height
|
| 58 |
+
|
| 59 |
+
if scale_w < scale_h:
|
| 60 |
+
new_width = target_width
|
| 61 |
+
new_height = min(math.ceil(original_height * scale_w), target_height)
|
| 62 |
+
else:
|
| 63 |
+
new_height = target_height
|
| 64 |
+
new_width = min(math.ceil(original_width * scale_h), target_width)
|
| 65 |
+
|
| 66 |
+
# Resize the image
|
| 67 |
+
resized_image = image.resize((new_width, new_height))
|
| 68 |
+
|
| 69 |
+
new_image = Image.new('RGB', (target_width, target_height), (0, 0, 0))
|
| 70 |
+
paste_x = (target_width - new_width) // 2
|
| 71 |
+
paste_y = (target_height - new_height) // 2
|
| 72 |
+
new_image.paste(resized_image, (paste_x, paste_y))
|
| 73 |
+
|
| 74 |
+
return new_image
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def divide_to_patches(image, patch_size):
|
| 78 |
+
"""
|
| 79 |
+
Divides an image into patches of a specified size.
|
| 80 |
+
|
| 81 |
+
Args:
|
| 82 |
+
image (PIL.Image.Image): The input image.
|
| 83 |
+
patch_size (int): The size of each patch.
|
| 84 |
+
|
| 85 |
+
Returns:
|
| 86 |
+
list: A list of PIL.Image.Image objects representing the patches.
|
| 87 |
+
"""
|
| 88 |
+
patches = []
|
| 89 |
+
width, height = image.size
|
| 90 |
+
for i in range(0, height, patch_size):
|
| 91 |
+
for j in range(0, width, patch_size):
|
| 92 |
+
box = (j, i, j + patch_size, i + patch_size)
|
| 93 |
+
patch = image.crop(box)
|
| 94 |
+
patches.append(patch)
|
| 95 |
+
|
| 96 |
+
return patches
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def get_anyres_image_grid_shape(image_size, grid_pinpoints, patch_size):
|
| 100 |
+
"""
|
| 101 |
+
Calculate the shape of the image patch grid after the preprocessing for images of any resolution.
|
| 102 |
+
|
| 103 |
+
Args:
|
| 104 |
+
image_size (tuple): The size of the input image in the format (width, height).
|
| 105 |
+
grid_pinpoints (str): A string representation of a list of possible resolutions.
|
| 106 |
+
patch_size (int): The size of each image patch.
|
| 107 |
+
|
| 108 |
+
Returns:
|
| 109 |
+
tuple: The shape of the image patch grid in the format (width, height).
|
| 110 |
+
"""
|
| 111 |
+
if type(grid_pinpoints) is list:
|
| 112 |
+
possible_resolutions = grid_pinpoints
|
| 113 |
+
else:
|
| 114 |
+
possible_resolutions = ast.literal_eval(grid_pinpoints)
|
| 115 |
+
width, height = select_best_resolution(image_size, possible_resolutions)
|
| 116 |
+
return width // patch_size, height // patch_size
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def process_anyres_image(image, processor, grid_pinpoints):
|
| 120 |
+
"""
|
| 121 |
+
Process an image with variable resolutions.
|
| 122 |
+
|
| 123 |
+
Args:
|
| 124 |
+
image (PIL.Image.Image): The input image to be processed.
|
| 125 |
+
processor: The image processor object.
|
| 126 |
+
grid_pinpoints (str): A string representation of a list of possible resolutions.
|
| 127 |
+
|
| 128 |
+
Returns:
|
| 129 |
+
torch.Tensor: A tensor containing the processed image patches.
|
| 130 |
+
"""
|
| 131 |
+
if type(grid_pinpoints) is list:
|
| 132 |
+
possible_resolutions = grid_pinpoints
|
| 133 |
+
else:
|
| 134 |
+
possible_resolutions = ast.literal_eval(grid_pinpoints)
|
| 135 |
+
best_resolution = select_best_resolution(image.size, possible_resolutions)
|
| 136 |
+
image_padded = resize_and_pad_image(image, best_resolution)
|
| 137 |
+
|
| 138 |
+
patches = divide_to_patches(image_padded, processor.crop_size['height'])
|
| 139 |
+
|
| 140 |
+
image_original_resize = image.resize((processor.size['shortest_edge'], processor.size['shortest_edge']))
|
| 141 |
+
|
| 142 |
+
image_patches = [image_original_resize] + patches
|
| 143 |
+
image_patches = [processor.preprocess(image_patch, return_tensors='pt')['pixel_values'][0]
|
| 144 |
+
for image_patch in image_patches]
|
| 145 |
+
return torch.stack(image_patches, dim=0)
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
def load_image_from_base64(image):
|
| 149 |
+
return Image.open(BytesIO(base64.b64decode(image)))
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def expand2square(pil_img, background_color):
|
| 153 |
+
width, height = pil_img.size
|
| 154 |
+
if width == height:
|
| 155 |
+
return pil_img
|
| 156 |
+
elif width > height:
|
| 157 |
+
result = Image.new(pil_img.mode, (width, width), background_color)
|
| 158 |
+
result.paste(pil_img, (0, (width - height) // 2))
|
| 159 |
+
return result
|
| 160 |
+
else:
|
| 161 |
+
result = Image.new(pil_img.mode, (height, height), background_color)
|
| 162 |
+
result.paste(pil_img, ((height - width) // 2, 0))
|
| 163 |
+
return result
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def process_images(images, image_processor, model_cfg):
|
| 167 |
+
image_aspect_ratio = getattr(model_cfg, "image_aspect_ratio", None)
|
| 168 |
+
new_images = []
|
| 169 |
+
if image_aspect_ratio == 'pad':
|
| 170 |
+
for image in images:
|
| 171 |
+
image = expand2square(image, tuple(int(x*255) for x in image_processor.image_mean))
|
| 172 |
+
image = image_processor.preprocess(image, return_tensors='pt')['pixel_values'][0]
|
| 173 |
+
new_images.append(image)
|
| 174 |
+
elif image_aspect_ratio == "anyres":
|
| 175 |
+
for image in images:
|
| 176 |
+
image = process_anyres_image(image, image_processor, model_cfg.image_grid_pinpoints)
|
| 177 |
+
new_images.append(image)
|
| 178 |
+
else:
|
| 179 |
+
return image_processor(images, return_tensors='pt')['pixel_values']
|
| 180 |
+
if all(x.shape == new_images[0].shape for x in new_images):
|
| 181 |
+
new_images = torch.stack(new_images, dim=0)
|
| 182 |
+
return new_images
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
def tokenizer_image_token(prompt, tokenizer, image_token_index=IMAGE_TOKEN_INDEX, return_tensors=None):
|
| 186 |
+
prompt_chunks = [tokenizer(chunk).input_ids for chunk in prompt.split('<image>')]
|
| 187 |
+
|
| 188 |
+
def insert_separator(X, sep):
|
| 189 |
+
return [ele for sublist in zip(X, [sep]*len(X)) for ele in sublist][:-1]
|
| 190 |
+
|
| 191 |
+
input_ids = []
|
| 192 |
+
offset = 0
|
| 193 |
+
if len(prompt_chunks) > 0 and len(prompt_chunks[0]) > 0 and prompt_chunks[0][0] == tokenizer.bos_token_id:
|
| 194 |
+
offset = 1
|
| 195 |
+
input_ids.append(prompt_chunks[0][0])
|
| 196 |
+
|
| 197 |
+
for x in insert_separator(prompt_chunks, [image_token_index] * (offset + 1)):
|
| 198 |
+
input_ids.extend(x[offset:])
|
| 199 |
+
|
| 200 |
+
if return_tensors is not None:
|
| 201 |
+
if return_tensors == 'pt':
|
| 202 |
+
return torch.tensor(input_ids, dtype=torch.long)
|
| 203 |
+
raise ValueError(f'Unsupported tensor type: {return_tensors}')
|
| 204 |
+
return input_ids
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
def get_model_name_from_path(model_path):
|
| 208 |
+
model_path = model_path.strip("/")
|
| 209 |
+
model_paths = model_path.split("/")
|
| 210 |
+
if model_paths[-1].startswith('checkpoint-'):
|
| 211 |
+
return model_paths[-2] + "_" + model_paths[-1]
|
| 212 |
+
else:
|
| 213 |
+
return model_paths[-1]
|
| 214 |
+
|
| 215 |
+
class KeywordsStoppingCriteria(StoppingCriteria):
|
| 216 |
+
def __init__(self, keywords, tokenizer, input_ids):
|
| 217 |
+
self.keywords = keywords
|
| 218 |
+
self.keyword_ids = []
|
| 219 |
+
self.max_keyword_len = 0
|
| 220 |
+
for keyword in keywords:
|
| 221 |
+
cur_keyword_ids = tokenizer(keyword).input_ids
|
| 222 |
+
if len(cur_keyword_ids) > 1 and cur_keyword_ids[0] == tokenizer.bos_token_id:
|
| 223 |
+
cur_keyword_ids = cur_keyword_ids[1:]
|
| 224 |
+
if len(cur_keyword_ids) > self.max_keyword_len:
|
| 225 |
+
self.max_keyword_len = len(cur_keyword_ids)
|
| 226 |
+
self.keyword_ids.append(torch.tensor(cur_keyword_ids))
|
| 227 |
+
self.tokenizer = tokenizer
|
| 228 |
+
self.start_len = input_ids.shape[1]
|
| 229 |
+
|
| 230 |
+
def call_for_batch(self, output_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:
|
| 231 |
+
offset = min(output_ids.shape[1] - self.start_len, self.max_keyword_len)
|
| 232 |
+
self.keyword_ids = [keyword_id.to(output_ids.device) for keyword_id in self.keyword_ids]
|
| 233 |
+
for keyword_id in self.keyword_ids:
|
| 234 |
+
truncated_output_ids = output_ids[0, -keyword_id.shape[0]:]
|
| 235 |
+
if torch.equal(truncated_output_ids, keyword_id):
|
| 236 |
+
return True
|
| 237 |
+
outputs = self.tokenizer.batch_decode(output_ids[:, -offset:], skip_special_tokens=True)[0]
|
| 238 |
+
for keyword in self.keywords:
|
| 239 |
+
if keyword in outputs:
|
| 240 |
+
return True
|
| 241 |
+
return False
|
| 242 |
+
|
| 243 |
+
def __call__(self, output_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:
|
| 244 |
+
outputs = []
|
| 245 |
+
for i in range(output_ids.shape[0]):
|
| 246 |
+
outputs.append(self.call_for_batch(output_ids[i].unsqueeze(0), scores))
|
| 247 |
+
return all(outputs)
|
llava/rgbt_dataset.py
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# llava/data/rgb_tir_dataset.py
|
| 2 |
+
import os
|
| 3 |
+
import copy
|
| 4 |
+
import json
|
| 5 |
+
from typing import Dict, Sequence, Optional, Tuple
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
from torch.utils.data import Dataset
|
| 9 |
+
from PIL import Image
|
| 10 |
+
import torchvision.transforms as tvt
|
| 11 |
+
|
| 12 |
+
from llava.constants import (
|
| 13 |
+
IGNORE_INDEX, DEFAULT_IMAGE_TOKEN, DEFAULT_IM_START_TOKEN, DEFAULT_IM_END_TOKEN
|
| 14 |
+
)
|
| 15 |
+
from llava import conversation as conversation_lib
|
| 16 |
+
from llava.mm_utils import tokenizer_image_token
|
| 17 |
+
|
| 18 |
+
def _safe_replace_rgb_with_tir(path: str) -> str:
|
| 19 |
+
# handle /RGB/ or \RGB\ on any OS
|
| 20 |
+
path2 = path.replace(os.sep + "RGB" + os.sep, os.sep + "TIR" + os.sep)
|
| 21 |
+
path2 = path2.replace("/RGB/", "/TIR/").replace("\\RGB\\", "\\TIR\\")
|
| 22 |
+
return path2
|
| 23 |
+
|
| 24 |
+
def _expand2square(pil_img: Image.Image, background_color=(0, 0, 0)):
|
| 25 |
+
w, h = pil_img.size
|
| 26 |
+
if w == h:
|
| 27 |
+
return pil_img
|
| 28 |
+
if w > h:
|
| 29 |
+
result = Image.new(pil_img.mode, (w, w), background_color)
|
| 30 |
+
result.paste(pil_img, (0, (w - h) // 2))
|
| 31 |
+
return result
|
| 32 |
+
else:
|
| 33 |
+
result = Image.new(pil_img.mode, (h, h), background_color)
|
| 34 |
+
result.paste(pil_img, ((h - w) // 2, 0))
|
| 35 |
+
return result
|
| 36 |
+
|
| 37 |
+
class RGBTIRSupervisedDataset(Dataset):
|
| 38 |
+
"""
|
| 39 |
+
LLaVA-compatible dataset that also (optionally) returns RGB/TIR pairs
|
| 40 |
+
for diffusion training (instructpix2pix). When diffusion pairs are off,
|
| 41 |
+
it behaves like the stock LazySupervisedDataset.
|
| 42 |
+
|
| 43 |
+
Keys:
|
| 44 |
+
- Always for LLaVA: input_ids, labels, image (-> collated as `images`)
|
| 45 |
+
- Optional for diffusion: rgb_diffusion, tir_diffusion
|
| 46 |
+
"""
|
| 47 |
+
|
| 48 |
+
def __init__(
|
| 49 |
+
self,
|
| 50 |
+
data_path: str,
|
| 51 |
+
tokenizer,
|
| 52 |
+
image_processor,
|
| 53 |
+
image_folder: Optional[str] = None,
|
| 54 |
+
image_aspect_ratio: str = "square", # {"square","pad"}
|
| 55 |
+
model_max_length: int = 2048,
|
| 56 |
+
# diffusion extras
|
| 57 |
+
return_diffusion_pairs: bool = False,
|
| 58 |
+
diffusion_size: int = 512,
|
| 59 |
+
tir_as_rgb: bool = True, # True: convert TIR to 3ch; False: keep 1ch ("L")
|
| 60 |
+
mm_use_im_start_end: bool = False, # NEW
|
| 61 |
+
warn_missing_tir: bool = False, # optional
|
| 62 |
+
):
|
| 63 |
+
super().__init__()
|
| 64 |
+
self.data = json.load(open(data_path, "r"))
|
| 65 |
+
self.tokenizer = tokenizer
|
| 66 |
+
self.image_processor = image_processor
|
| 67 |
+
self.image_folder = image_folder or ""
|
| 68 |
+
self.image_aspect_ratio = image_aspect_ratio
|
| 69 |
+
self.model_max_length = model_max_length
|
| 70 |
+
self.return_diffusion_pairs = return_diffusion_pairs
|
| 71 |
+
self.diffusion_size = diffusion_size
|
| 72 |
+
self.tir_as_rgb = tir_as_rgb
|
| 73 |
+
self.mm_use_im_start_end = mm_use_im_start_end # NEW
|
| 74 |
+
self.warn_missing_tir = warn_missing_tir
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def make_rgb_transform():
|
| 78 |
+
return tvt.Compose([
|
| 79 |
+
tvt.CenterCrop(min(self.diffusion_size, 10**9)), # overwritten next line
|
| 80 |
+
tvt.Resize(self.diffusion_size, interpolation=Image.BICUBIC),
|
| 81 |
+
tvt.ToTensor(),
|
| 82 |
+
tvt.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
|
| 83 |
+
])
|
| 84 |
+
|
| 85 |
+
# CenterCrop to exact square first, then Resize
|
| 86 |
+
def square_then_resize(mode_rgb: bool):
|
| 87 |
+
norms = ([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) if mode_rgb else ([0.5], [0.5])
|
| 88 |
+
return tvt.Compose([
|
| 89 |
+
# crop to min side square
|
| 90 |
+
tvt.Lambda(lambda im: _expand2square(im, (0, 0, 0)) if im.size[0]!=im.size[1] else im),
|
| 91 |
+
tvt.Resize(self.diffusion_size, interpolation=Image.BICUBIC),
|
| 92 |
+
tvt.ToTensor(),
|
| 93 |
+
tvt.Normalize(*norms),
|
| 94 |
+
])
|
| 95 |
+
|
| 96 |
+
self.diffusion_transform_rgb = square_then_resize(True)
|
| 97 |
+
self.diffusion_transform_tir = square_then_resize(self.tir_as_rgb)
|
| 98 |
+
# diffusion transforms ([-1,1])
|
| 99 |
+
# self.diffusion_transform_rgb = tvt.Compose([
|
| 100 |
+
# tvt.Resize(self.diffusion_size, interpolation=Image.BICUBIC),
|
| 101 |
+
# tvt.CenterCrop(self.diffusion_size),
|
| 102 |
+
# tvt.ToTensor(),
|
| 103 |
+
# tvt.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
|
| 104 |
+
# ])
|
| 105 |
+
# allow 1ch or 3ch for TIR
|
| 106 |
+
# if self.tir_as_rgb:
|
| 107 |
+
# self.diffusion_transform_tir = tvt.Compose([
|
| 108 |
+
# tvt.Resize(self.diffusion_size, interpolation=Image.BICUBIC),
|
| 109 |
+
# tvt.CenterCrop(self.diffusion_size),
|
| 110 |
+
# tvt.ToTensor(),
|
| 111 |
+
# tvt.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
|
| 112 |
+
# ])
|
| 113 |
+
# else:
|
| 114 |
+
# self.diffusion_transform_tir = tvt.Compose([
|
| 115 |
+
# tvt.Resize(self.diffusion_size, interpolation=Image.BICUBIC),
|
| 116 |
+
# tvt.CenterCrop(self.diffusion_size),
|
| 117 |
+
# tvt.ToTensor(), # 1 x H x W
|
| 118 |
+
# tvt.Normalize([0.5], [0.5]),
|
| 119 |
+
# ])
|
| 120 |
+
|
| 121 |
+
# in RGBTIRSupervisedDataset.__init__(...)
|
| 122 |
+
self.inject_edit_tokens = True # optional flag
|
| 123 |
+
self.edit_span = " ".join([f"<edit_{k}>" for k in range(8)])
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def __len__(self):
|
| 127 |
+
return len(self.data)
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
@property
|
| 131 |
+
def lengths(self):
|
| 132 |
+
length_list = []
|
| 133 |
+
for sample in self.data:
|
| 134 |
+
img_tokens = 128 if 'image' in sample else 0
|
| 135 |
+
length_list.append(sum(len(conv['value'].split()) for conv in sample['conversations']) + img_tokens)
|
| 136 |
+
return length_list
|
| 137 |
+
|
| 138 |
+
@property
|
| 139 |
+
def modality_lengths(self):
|
| 140 |
+
length_list = []
|
| 141 |
+
for sample in self.data:
|
| 142 |
+
cur_len = sum(len(conv['value'].split()) for conv in sample['conversations'])
|
| 143 |
+
cur_len = cur_len if 'image' in sample else -cur_len
|
| 144 |
+
length_list.append(cur_len)
|
| 145 |
+
return length_list
|
| 146 |
+
|
| 147 |
+
# add this helper in the class
|
| 148 |
+
def _inject_edit_tokens_into_conversation(self, conv_rounds: list) -> list:
|
| 149 |
+
"""
|
| 150 |
+
Ensure the last assistant ('gpt') turn is exactly the 8 edit tokens.
|
| 151 |
+
If there is no assistant turn yet, append one.
|
| 152 |
+
conv_rounds: [{'from': 'human'|'gpt', 'value': str}, ...]
|
| 153 |
+
"""
|
| 154 |
+
if not self.inject_edit_tokens:
|
| 155 |
+
return conv_rounds
|
| 156 |
+
|
| 157 |
+
# find last assistant turn
|
| 158 |
+
last_gpt = None
|
| 159 |
+
for i in reversed(range(len(conv_rounds))):
|
| 160 |
+
if conv_rounds[i].get("from") == "gpt":
|
| 161 |
+
last_gpt = i
|
| 162 |
+
break
|
| 163 |
+
|
| 164 |
+
if last_gpt is None:
|
| 165 |
+
# append a new assistant turn with just the edit tokens
|
| 166 |
+
conv_rounds = conv_rounds + [{"from": "gpt", "value": self.edit_span}]
|
| 167 |
+
else:
|
| 168 |
+
# replace its content with exactly the edit tokens
|
| 169 |
+
conv_rounds = conv_rounds.copy()
|
| 170 |
+
conv_rounds[last_gpt] = {"from": "gpt", "value": self.edit_span}
|
| 171 |
+
|
| 172 |
+
return conv_rounds
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
# --- helpers mirroring your current preprocess path ---
|
| 177 |
+
def _preprocess_multimodal(self, sources):
|
| 178 |
+
use_im_tokens = self.mm_use_im_start_end
|
| 179 |
+
for source in sources:
|
| 180 |
+
for sentence in source:
|
| 181 |
+
if DEFAULT_IMAGE_TOKEN in sentence["value"]:
|
| 182 |
+
sentence["value"] = sentence["value"].replace(DEFAULT_IMAGE_TOKEN, "").strip()
|
| 183 |
+
sentence["value"] = DEFAULT_IMAGE_TOKEN + "\n" + sentence["value"]
|
| 184 |
+
sentence["value"] = sentence["value"].strip()
|
| 185 |
+
replace_token = DEFAULT_IMAGE_TOKEN
|
| 186 |
+
if use_im_tokens:
|
| 187 |
+
replace_token = DEFAULT_IM_START_TOKEN + replace_token + DEFAULT_IM_END_TOKEN
|
| 188 |
+
sentence["value"] = sentence["value"].replace(DEFAULT_IMAGE_TOKEN, replace_token)
|
| 189 |
+
return sources
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def _preprocess_text(self, sources, has_image: bool):
|
| 193 |
+
# Follow the same path as llava.data.preprocess_v1 / llama_2 depending on conv template
|
| 194 |
+
conv = conversation_lib.default_conversation.copy()
|
| 195 |
+
roles = {"human": conv.roles[0], "gpt": conv.roles[1]}
|
| 196 |
+
conversations = []
|
| 197 |
+
|
| 198 |
+
for i, source in enumerate(sources):
|
| 199 |
+
if roles[source[0]["from"]] != conv.roles[0]:
|
| 200 |
+
source = source[1:] # skip non-human first
|
| 201 |
+
conv.messages = []
|
| 202 |
+
for j, sentence in enumerate(source):
|
| 203 |
+
role = roles[sentence["from"]]
|
| 204 |
+
assert role == conv.roles[j % 2]
|
| 205 |
+
conv.append_message(role, sentence["value"])
|
| 206 |
+
conversations.append(conv.get_prompt())
|
| 207 |
+
|
| 208 |
+
if has_image:
|
| 209 |
+
input_ids = torch.stack(
|
| 210 |
+
[tokenizer_image_token(p, self.tokenizer, return_tensors="pt") for p in conversations], dim=0
|
| 211 |
+
)
|
| 212 |
+
else:
|
| 213 |
+
input_ids = self.tokenizer(
|
| 214 |
+
conversations, return_tensors="pt", padding="longest",
|
| 215 |
+
max_length=self.tokenizer.model_max_length, truncation=True
|
| 216 |
+
).input_ids
|
| 217 |
+
|
| 218 |
+
targets = input_ids.clone()
|
| 219 |
+
|
| 220 |
+
# mask human parts (match llava.data.preprocess_v1 / llama_2 implementations)
|
| 221 |
+
if conv.sep_style == conversation_lib.SeparatorStyle.TWO:
|
| 222 |
+
sep = conv.sep + conv.roles[1] + ": "
|
| 223 |
+
for conversation, target in zip(conversations, targets):
|
| 224 |
+
total_len = int(target.ne(self.tokenizer.pad_token_id).sum())
|
| 225 |
+
rounds = conversation.split(conv.sep2)
|
| 226 |
+
cur_len = 1
|
| 227 |
+
target[:cur_len] = IGNORE_INDEX
|
| 228 |
+
for i, rou in enumerate(rounds):
|
| 229 |
+
if rou == "":
|
| 230 |
+
break
|
| 231 |
+
parts = rou.split(sep)
|
| 232 |
+
if len(parts) != 2:
|
| 233 |
+
break
|
| 234 |
+
parts[0] += sep
|
| 235 |
+
if has_image:
|
| 236 |
+
round_len = len(tokenizer_image_token(rou, self.tokenizer))
|
| 237 |
+
instruction_len = len(tokenizer_image_token(parts[0], self.tokenizer)) - 2
|
| 238 |
+
else:
|
| 239 |
+
round_len = len(self.tokenizer(rou).input_ids)
|
| 240 |
+
instruction_len = len(self.tokenizer(parts[0]).input_ids) - 2
|
| 241 |
+
target[cur_len: cur_len + instruction_len] = IGNORE_INDEX
|
| 242 |
+
cur_len += round_len
|
| 243 |
+
target[cur_len:] = IGNORE_INDEX
|
| 244 |
+
if cur_len != total_len:
|
| 245 |
+
target[:] = IGNORE_INDEX # safe path
|
| 246 |
+
else:
|
| 247 |
+
# fall back to generic masking path (rare given your templates)
|
| 248 |
+
target = targets # already cloned
|
| 249 |
+
return dict(input_ids=input_ids[0], labels=targets[0])
|
| 250 |
+
|
| 251 |
+
def _load_rgb_for_llava(self, pil_img: Image.Image):
|
| 252 |
+
# honor aspect ratio option used by your current code
|
| 253 |
+
if self.image_aspect_ratio == "pad":
|
| 254 |
+
bg = tuple(int(x * 255) for x in self.image_processor.image_mean)
|
| 255 |
+
pil_img = _expand2square(pil_img, bg)
|
| 256 |
+
# LLaVA’s processor returns dict(pixel_values=...)
|
| 257 |
+
return self.image_processor.preprocess(pil_img, return_tensors="pt")["pixel_values"][0]
|
| 258 |
+
|
| 259 |
+
def __getitem__(self, idx) -> Dict[str, torch.Tensor]:
|
| 260 |
+
sample = self.data[idx]
|
| 261 |
+
rgb_rel = sample.get("image")
|
| 262 |
+
assert rgb_rel is not None, "Missing 'image' in sample"
|
| 263 |
+
|
| 264 |
+
rgb_path = os.path.join(self.image_folder, rgb_rel)
|
| 265 |
+
rgb = Image.open(rgb_path).convert("RGB")
|
| 266 |
+
|
| 267 |
+
# paired TIR (optional)
|
| 268 |
+
tir_path = _safe_replace_rgb_with_tir(rgb_path)
|
| 269 |
+
tir_exists = os.path.exists(tir_path)
|
| 270 |
+
if self.return_diffusion_pairs and (not tir_exists) and self.warn_missing_tir:
|
| 271 |
+
print(f"[RGBTIRDataset] Missing TIR for: {rgb_path}")
|
| 272 |
+
|
| 273 |
+
# LLaVA image tensor
|
| 274 |
+
image_tensor = self._load_rgb_for_llava(rgb)
|
| 275 |
+
|
| 276 |
+
# --------- NEW: build MGIE-style two-turn conversation from your JSON ---------
|
| 277 |
+
# human value is the "instruction"; gpt value is the "expressive" text
|
| 278 |
+
convs = sample["conversations"]
|
| 279 |
+
assert len(convs) >= 2, "Expected at least 2 turns (human, gpt)"
|
| 280 |
+
|
| 281 |
+
# take the first human turn as instruction
|
| 282 |
+
human_val = convs[0]["value"]
|
| 283 |
+
# strip a leading <image> (if present) to avoid double image tokens; we’ll insert ours below
|
| 284 |
+
if human_val.lstrip().startswith("<image>"):
|
| 285 |
+
human_val = human_val.lstrip()[len("<image>"):].lstrip()
|
| 286 |
+
|
| 287 |
+
# expressive text is the first gpt turn
|
| 288 |
+
expressive = convs[1]["value"].strip()
|
| 289 |
+
|
| 290 |
+
# choose the 8 tokens: use the ones you ALREADY added to the tokenizer/model
|
| 291 |
+
EDIT_TOKENS = [f"[IMG{k}]" for k in range(8)]
|
| 292 |
+
edit_span = " ".join(EDIT_TOKENS)
|
| 293 |
+
|
| 294 |
+
# build the two messages in MGIE style
|
| 295 |
+
query = f"{human_val}\n{DEFAULT_IMAGE_TOKEN}" # human: instruction + <image>
|
| 296 |
+
answer = f"{expressive} {edit_span}" # gpt: expressive + 8 tokens
|
| 297 |
+
|
| 298 |
+
sources = [[
|
| 299 |
+
{"from": "human", "value": query},
|
| 300 |
+
{"from": "gpt", "value": answer},
|
| 301 |
+
]]
|
| 302 |
+
|
| 303 |
+
# make sure image token formatting matches your config
|
| 304 |
+
sources = self._preprocess_multimodal(copy.deepcopy(sources))
|
| 305 |
+
text_dict = self._preprocess_text(sources, has_image=True)
|
| 306 |
+
|
| 307 |
+
# pack outputs for the trainer
|
| 308 |
+
out = {
|
| 309 |
+
"input_ids": text_dict["input_ids"],
|
| 310 |
+
"labels": text_dict["labels"],
|
| 311 |
+
"image": image_tensor,
|
| 312 |
+
"image_sizes": [rgb.size],
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
# --------- optional diffusion pairs ---------
|
| 316 |
+
if self.return_diffusion_pairs:
|
| 317 |
+
rgb_for_diff = rgb
|
| 318 |
+
if tir_exists:
|
| 319 |
+
tir_for_diff = Image.open(tir_path).convert("RGB" if self.tir_as_rgb else "L")
|
| 320 |
+
else:
|
| 321 |
+
tir_for_diff = rgb_for_diff.convert("RGB" if self.tir_as_rgb else "L")
|
| 322 |
+
|
| 323 |
+
out["p2p_inp"] = self.diffusion_transform_rgb(rgb_for_diff)
|
| 324 |
+
out["p2p_ans"] = self.diffusion_transform_tir(tir_for_diff)
|
| 325 |
+
|
| 326 |
+
return out
|
| 327 |
+
|
| 328 |
+
|
llava/train/llama_flash_attn_monkey_patch.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Optional, Tuple
|
| 2 |
+
import warnings
|
| 3 |
+
|
| 4 |
+
import torch
|
| 5 |
+
|
| 6 |
+
import transformers
|
| 7 |
+
from transformers.models.llama.modeling_llama import apply_rotary_pos_emb, repeat_kv
|
| 8 |
+
|
| 9 |
+
try:
|
| 10 |
+
from flash_attn.flash_attn_interface import flash_attn_unpadded_qkvpacked_func
|
| 11 |
+
except ImportError:
|
| 12 |
+
from flash_attn.flash_attn_interface import flash_attn_varlen_qkvpacked_func as flash_attn_unpadded_qkvpacked_func
|
| 13 |
+
from flash_attn.bert_padding import unpad_input, pad_input
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def forward(
|
| 17 |
+
self,
|
| 18 |
+
hidden_states: torch.Tensor,
|
| 19 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 20 |
+
position_ids: Optional[torch.Tensor] = None,
|
| 21 |
+
past_key_value: Optional[Tuple[torch.Tensor]] = None,
|
| 22 |
+
output_attentions: bool = False,
|
| 23 |
+
use_cache: bool = False,
|
| 24 |
+
) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
| 25 |
+
if output_attentions:
|
| 26 |
+
warnings.warn(
|
| 27 |
+
"Output attentions is not supported for patched `LlamaAttention`, returning `None` instead."
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
bsz, q_len, _ = hidden_states.size()
|
| 31 |
+
|
| 32 |
+
query_states = (
|
| 33 |
+
self.q_proj(hidden_states)
|
| 34 |
+
.view(bsz, q_len, self.num_heads, self.head_dim)
|
| 35 |
+
.transpose(1, 2)
|
| 36 |
+
)
|
| 37 |
+
key_states = (
|
| 38 |
+
self.k_proj(hidden_states)
|
| 39 |
+
.view(bsz, q_len, self.num_key_value_heads, self.head_dim)
|
| 40 |
+
.transpose(1, 2)
|
| 41 |
+
)
|
| 42 |
+
value_states = (
|
| 43 |
+
self.v_proj(hidden_states)
|
| 44 |
+
.view(bsz, q_len, self.num_key_value_heads, self.head_dim)
|
| 45 |
+
.transpose(1, 2)
|
| 46 |
+
) # shape: (b, num_heads, s, head_dim)
|
| 47 |
+
|
| 48 |
+
kv_seq_len = key_states.shape[-2]
|
| 49 |
+
if past_key_value is not None:
|
| 50 |
+
kv_seq_len += past_key_value[0].shape[-2]
|
| 51 |
+
|
| 52 |
+
cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len)
|
| 53 |
+
query_states, key_states = apply_rotary_pos_emb(
|
| 54 |
+
query_states, key_states, cos, sin, position_ids
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
if past_key_value is not None:
|
| 58 |
+
# reuse k, v
|
| 59 |
+
key_states = torch.cat([past_key_value[0], key_states], dim=2)
|
| 60 |
+
value_states = torch.cat([past_key_value[1], value_states], dim=2)
|
| 61 |
+
|
| 62 |
+
past_key_value = (key_states, value_states) if use_cache else None
|
| 63 |
+
|
| 64 |
+
# repeat k/v heads if n_kv_heads < n_heads
|
| 65 |
+
key_states = repeat_kv(key_states, self.num_key_value_groups)
|
| 66 |
+
value_states = repeat_kv(value_states, self.num_key_value_groups)
|
| 67 |
+
|
| 68 |
+
# Transform the data into the format required by flash attention
|
| 69 |
+
qkv = torch.stack([query_states, key_states, value_states], dim=2)
|
| 70 |
+
qkv = qkv.transpose(1, 3) # shape: [b, s, 3, num_heads, head_dim]
|
| 71 |
+
key_padding_mask = attention_mask
|
| 72 |
+
|
| 73 |
+
if key_padding_mask is None:
|
| 74 |
+
qkv = qkv.reshape(-1, 3, self.num_heads, self.head_dim)
|
| 75 |
+
cu_q_lens = torch.arange(
|
| 76 |
+
0, (bsz + 1) * q_len, step=q_len, dtype=torch.int32, device=qkv.device
|
| 77 |
+
)
|
| 78 |
+
max_s = q_len
|
| 79 |
+
output = flash_attn_unpadded_qkvpacked_func(
|
| 80 |
+
qkv, cu_q_lens, max_s, 0.0, softmax_scale=None, causal=True
|
| 81 |
+
)
|
| 82 |
+
output = output.view(bsz, q_len, -1)
|
| 83 |
+
else:
|
| 84 |
+
qkv = qkv.reshape(bsz, q_len, -1)
|
| 85 |
+
qkv, indices, cu_q_lens, max_s = unpad_input(qkv, key_padding_mask)
|
| 86 |
+
qkv = qkv.view(-1, 3, self.num_heads, self.head_dim)
|
| 87 |
+
output_unpad = flash_attn_unpadded_qkvpacked_func(
|
| 88 |
+
qkv, cu_q_lens, max_s, 0.0, softmax_scale=None, causal=True
|
| 89 |
+
)
|
| 90 |
+
output_unpad = output_unpad.reshape(-1, self.num_heads * self.head_dim)
|
| 91 |
+
output = pad_input(output_unpad, indices, bsz, q_len)
|
| 92 |
+
|
| 93 |
+
return self.o_proj(output), None, past_key_value
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
# Disable the transformation of the attention mask in LlamaModel as the flash attention
|
| 97 |
+
# requires the attention mask to be the same as the key_padding_mask
|
| 98 |
+
def _prepare_decoder_attention_mask(
|
| 99 |
+
self, attention_mask, input_shape, inputs_embeds, past_key_values_length
|
| 100 |
+
):
|
| 101 |
+
# [bsz, seq_len]
|
| 102 |
+
return attention_mask
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def replace_llama_attn_with_flash_attn():
|
| 106 |
+
cuda_major, cuda_minor = torch.cuda.get_device_capability()
|
| 107 |
+
if cuda_major < 8:
|
| 108 |
+
warnings.warn(
|
| 109 |
+
"Flash attention is only supported on A100 or H100 GPU during training due to head dim > 64 backward."
|
| 110 |
+
"ref: https://github.com/HazyResearch/flash-attention/issues/190#issuecomment-1523359593"
|
| 111 |
+
)
|
| 112 |
+
transformers.models.llama.modeling_llama.LlamaModel._prepare_decoder_attention_mask = (
|
| 113 |
+
_prepare_decoder_attention_mask
|
| 114 |
+
)
|
| 115 |
+
transformers.models.llama.modeling_llama.LlamaAttention.forward = forward
|
llava/train/llama_xformers_attn_monkey_patch.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Directly copied the code from https://raw.githubusercontent.com/oobabooga/text-generation-webui/main/modules/llama_attn_hijack.py and made some adjustments
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import logging
|
| 6 |
+
import math
|
| 7 |
+
from typing import Optional, Tuple
|
| 8 |
+
|
| 9 |
+
import torch
|
| 10 |
+
import transformers.models.llama.modeling_llama
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
try:
|
| 14 |
+
import xformers.ops
|
| 15 |
+
except ImportError:
|
| 16 |
+
logging.error("xformers not found! Please install it before trying to use it.")
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def replace_llama_attn_with_xformers_attn():
|
| 20 |
+
transformers.models.llama.modeling_llama.LlamaAttention.forward = xformers_forward
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def xformers_forward(
|
| 24 |
+
self,
|
| 25 |
+
hidden_states: torch.Tensor,
|
| 26 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 27 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 28 |
+
past_key_value: Optional[Tuple[torch.Tensor]] = None,
|
| 29 |
+
output_attentions: bool = False,
|
| 30 |
+
use_cache: bool = False,
|
| 31 |
+
) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
| 32 |
+
# pylint: disable=duplicate-code
|
| 33 |
+
bsz, q_len, _ = hidden_states.size()
|
| 34 |
+
|
| 35 |
+
query_states = (
|
| 36 |
+
self.q_proj(hidden_states)
|
| 37 |
+
.view(bsz, q_len, self.num_heads, self.head_dim)
|
| 38 |
+
.transpose(1, 2)
|
| 39 |
+
)
|
| 40 |
+
key_states = (
|
| 41 |
+
self.k_proj(hidden_states)
|
| 42 |
+
.view(bsz, q_len, self.num_heads, self.head_dim)
|
| 43 |
+
.transpose(1, 2)
|
| 44 |
+
)
|
| 45 |
+
value_states = (
|
| 46 |
+
self.v_proj(hidden_states)
|
| 47 |
+
.view(bsz, q_len, self.num_heads, self.head_dim)
|
| 48 |
+
.transpose(1, 2)
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
kv_seq_len = key_states.shape[-2]
|
| 52 |
+
if past_key_value is not None:
|
| 53 |
+
kv_seq_len += past_key_value[0].shape[-2]
|
| 54 |
+
cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len)
|
| 55 |
+
(
|
| 56 |
+
query_states,
|
| 57 |
+
key_states,
|
| 58 |
+
) = transformers.models.llama.modeling_llama.apply_rotary_pos_emb(
|
| 59 |
+
query_states, key_states, cos, sin, position_ids
|
| 60 |
+
)
|
| 61 |
+
# [bsz, nh, t, hd]
|
| 62 |
+
|
| 63 |
+
if past_key_value is not None:
|
| 64 |
+
# reuse k, v, self_attention
|
| 65 |
+
key_states = torch.cat([past_key_value[0], key_states], dim=2)
|
| 66 |
+
value_states = torch.cat([past_key_value[1], value_states], dim=2)
|
| 67 |
+
|
| 68 |
+
past_key_value = (key_states, value_states) if use_cache else None
|
| 69 |
+
|
| 70 |
+
# We only apply xformers optimizations if we don't need to output the whole attention matrix
|
| 71 |
+
if not output_attentions:
|
| 72 |
+
query_states = query_states.transpose(1, 2)
|
| 73 |
+
key_states = key_states.transpose(1, 2)
|
| 74 |
+
value_states = value_states.transpose(1, 2)
|
| 75 |
+
|
| 76 |
+
# This is a nasty hack. We know attention_mask in transformers is either LowerTriangular or all Zeros.
|
| 77 |
+
# We therefore check if one element in the upper triangular portion is zero. If it is, then the mask is all zeros.
|
| 78 |
+
if attention_mask is None or attention_mask[0, 0, 0, 1] == 0:
|
| 79 |
+
# input and output should be of form (bsz, q_len, num_heads, head_dim)
|
| 80 |
+
attn_output = xformers.ops.memory_efficient_attention(
|
| 81 |
+
query_states, key_states, value_states, attn_bias=None
|
| 82 |
+
)
|
| 83 |
+
else:
|
| 84 |
+
# input and output should be of form (bsz, q_len, num_heads, head_dim)
|
| 85 |
+
attn_output = xformers.ops.memory_efficient_attention(
|
| 86 |
+
query_states,
|
| 87 |
+
key_states,
|
| 88 |
+
value_states,
|
| 89 |
+
attn_bias=xformers.ops.LowerTriangularMask(),
|
| 90 |
+
)
|
| 91 |
+
attn_weights = None
|
| 92 |
+
else:
|
| 93 |
+
attn_weights = torch.matmul(
|
| 94 |
+
query_states, key_states.transpose(2, 3)
|
| 95 |
+
) / math.sqrt(self.head_dim)
|
| 96 |
+
|
| 97 |
+
if attn_weights.size() != (bsz, self.num_heads, q_len, kv_seq_len):
|
| 98 |
+
raise ValueError(
|
| 99 |
+
f"Attention weights should be of size {(bsz * self.num_heads, q_len, kv_seq_len)}, but is"
|
| 100 |
+
f" {attn_weights.size()}"
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
if attention_mask is not None:
|
| 104 |
+
if attention_mask.size() != (bsz, 1, q_len, kv_seq_len):
|
| 105 |
+
raise ValueError(
|
| 106 |
+
f"Attention mask should be of size {(bsz, 1, q_len, kv_seq_len)}, but is {attention_mask.size()}"
|
| 107 |
+
)
|
| 108 |
+
attn_weights = attn_weights + attention_mask
|
| 109 |
+
attn_weights = torch.max(
|
| 110 |
+
attn_weights, torch.tensor(torch.finfo(attn_weights.dtype).min)
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
# upcast attention to fp32
|
| 114 |
+
attn_weights = nn.functional.softmax(
|
| 115 |
+
attn_weights, dim=-1, dtype=torch.float32
|
| 116 |
+
).to(query_states.dtype)
|
| 117 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
| 118 |
+
|
| 119 |
+
if attn_output.size() != (bsz, self.num_heads, q_len, self.head_dim):
|
| 120 |
+
raise ValueError(
|
| 121 |
+
f"`attn_output` should be of size {(bsz, self.num_heads, q_len, self.head_dim)}, but is"
|
| 122 |
+
f" {attn_output.size()}"
|
| 123 |
+
)
|
| 124 |
+
|
| 125 |
+
attn_output = attn_output.transpose(1, 2)
|
| 126 |
+
|
| 127 |
+
attn_output = attn_output.reshape(bsz, q_len, self.hidden_size)
|
| 128 |
+
attn_output = self.o_proj(attn_output)
|
| 129 |
+
return attn_output, attn_weights, past_key_value
|
llava/train/llava_trainer.py
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn as nn
|
| 4 |
+
|
| 5 |
+
from torch.utils.data import Sampler
|
| 6 |
+
|
| 7 |
+
from transformers import Trainer
|
| 8 |
+
from transformers.trainer import (
|
| 9 |
+
is_sagemaker_mp_enabled,
|
| 10 |
+
get_parameter_names,
|
| 11 |
+
has_length,
|
| 12 |
+
ALL_LAYERNORM_LAYERS,
|
| 13 |
+
logger,
|
| 14 |
+
)
|
| 15 |
+
from typing import List, Optional
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def maybe_zero_3(param, ignore_status=False, name=None):
|
| 19 |
+
from deepspeed import zero
|
| 20 |
+
from deepspeed.runtime.zero.partition_parameters import ZeroParamStatus
|
| 21 |
+
if hasattr(param, "ds_id"):
|
| 22 |
+
if param.ds_status == ZeroParamStatus.NOT_AVAILABLE:
|
| 23 |
+
if not ignore_status:
|
| 24 |
+
print(name, 'no ignore status')
|
| 25 |
+
with zero.GatheredParameters([param]):
|
| 26 |
+
param = param.data.detach().cpu().clone()
|
| 27 |
+
else:
|
| 28 |
+
param = param.detach().cpu().clone()
|
| 29 |
+
return param
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def get_mm_adapter_state_maybe_zero_3(named_params, keys_to_match):
|
| 33 |
+
to_return = {k: t for k, t in named_params if any(key_match in k for key_match in keys_to_match)}
|
| 34 |
+
to_return = {k: maybe_zero_3(v, ignore_status=True, name=k).cpu() for k, v in to_return.items()}
|
| 35 |
+
return to_return
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def split_to_even_chunks(indices, lengths, num_chunks):
|
| 39 |
+
"""
|
| 40 |
+
Split a list of indices into `chunks` chunks of roughly equal lengths.
|
| 41 |
+
"""
|
| 42 |
+
|
| 43 |
+
if len(indices) % num_chunks != 0:
|
| 44 |
+
return [indices[i::num_chunks] for i in range(num_chunks)]
|
| 45 |
+
|
| 46 |
+
num_indices_per_chunk = len(indices) // num_chunks
|
| 47 |
+
|
| 48 |
+
chunks = [[] for _ in range(num_chunks)]
|
| 49 |
+
chunks_lengths = [0 for _ in range(num_chunks)]
|
| 50 |
+
for index in indices:
|
| 51 |
+
shortest_chunk = chunks_lengths.index(min(chunks_lengths))
|
| 52 |
+
chunks[shortest_chunk].append(index)
|
| 53 |
+
chunks_lengths[shortest_chunk] += lengths[index]
|
| 54 |
+
if len(chunks[shortest_chunk]) == num_indices_per_chunk:
|
| 55 |
+
chunks_lengths[shortest_chunk] = float("inf")
|
| 56 |
+
|
| 57 |
+
return chunks
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def get_modality_length_grouped_indices(lengths, batch_size, world_size, generator=None):
|
| 61 |
+
# We need to use torch for the random part as a distributed sampler will set the random seed for torch.
|
| 62 |
+
assert all(l != 0 for l in lengths), "Should not have zero length."
|
| 63 |
+
if all(l > 0 for l in lengths) or all(l < 0 for l in lengths):
|
| 64 |
+
# all samples are in the same modality
|
| 65 |
+
return get_length_grouped_indices(lengths, batch_size, world_size, generator=generator)
|
| 66 |
+
mm_indices, mm_lengths = zip(*[(i, l) for i, l in enumerate(lengths) if l > 0])
|
| 67 |
+
lang_indices, lang_lengths = zip(*[(i, -l) for i, l in enumerate(lengths) if l < 0])
|
| 68 |
+
|
| 69 |
+
mm_shuffle = [mm_indices[i] for i in get_length_grouped_indices(mm_lengths, batch_size, world_size, generator=None)]
|
| 70 |
+
lang_shuffle = [lang_indices[i] for i in get_length_grouped_indices(lang_lengths, batch_size, world_size, generator=None)]
|
| 71 |
+
megabatch_size = world_size * batch_size
|
| 72 |
+
mm_megabatches = [mm_shuffle[i : i + megabatch_size] for i in range(0, len(mm_shuffle), megabatch_size)]
|
| 73 |
+
lang_megabatches = [lang_shuffle[i : i + megabatch_size] for i in range(0, len(lang_shuffle), megabatch_size)]
|
| 74 |
+
|
| 75 |
+
last_mm = mm_megabatches[-1]
|
| 76 |
+
last_lang = lang_megabatches[-1]
|
| 77 |
+
additional_batch = last_mm + last_lang
|
| 78 |
+
megabatches = mm_megabatches[:-1] + lang_megabatches[:-1]
|
| 79 |
+
megabatch_indices = torch.randperm(len(megabatches), generator=generator)
|
| 80 |
+
megabatches = [megabatches[i] for i in megabatch_indices]
|
| 81 |
+
|
| 82 |
+
if len(additional_batch) > 0:
|
| 83 |
+
megabatches.append(sorted(additional_batch))
|
| 84 |
+
|
| 85 |
+
return [i for megabatch in megabatches for i in megabatch]
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def get_length_grouped_indices(lengths, batch_size, world_size, generator=None, merge=True):
|
| 89 |
+
# We need to use torch for the random part as a distributed sampler will set the random seed for torch.
|
| 90 |
+
indices = torch.randperm(len(lengths), generator=generator)
|
| 91 |
+
megabatch_size = world_size * batch_size
|
| 92 |
+
megabatches = [indices[i : i + megabatch_size].tolist() for i in range(0, len(lengths), megabatch_size)]
|
| 93 |
+
megabatches = [sorted(megabatch, key=lambda i: lengths[i], reverse=True) for megabatch in megabatches]
|
| 94 |
+
megabatches = [split_to_even_chunks(megabatch, lengths, world_size) for megabatch in megabatches]
|
| 95 |
+
|
| 96 |
+
return [i for megabatch in megabatches for batch in megabatch for i in batch]
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
class LengthGroupedSampler(Sampler):
|
| 100 |
+
r"""
|
| 101 |
+
Sampler that samples indices in a way that groups together features of the dataset of roughly the same length while
|
| 102 |
+
keeping a bit of randomness.
|
| 103 |
+
"""
|
| 104 |
+
|
| 105 |
+
def __init__(
|
| 106 |
+
self,
|
| 107 |
+
batch_size: int,
|
| 108 |
+
world_size: int,
|
| 109 |
+
lengths: Optional[List[int]] = None,
|
| 110 |
+
generator=None,
|
| 111 |
+
group_by_modality: bool = False,
|
| 112 |
+
):
|
| 113 |
+
if lengths is None:
|
| 114 |
+
raise ValueError("Lengths must be provided.")
|
| 115 |
+
|
| 116 |
+
self.batch_size = batch_size
|
| 117 |
+
self.world_size = world_size
|
| 118 |
+
self.lengths = lengths
|
| 119 |
+
self.generator = generator
|
| 120 |
+
self.group_by_modality = group_by_modality
|
| 121 |
+
|
| 122 |
+
def __len__(self):
|
| 123 |
+
return len(self.lengths)
|
| 124 |
+
|
| 125 |
+
def __iter__(self):
|
| 126 |
+
if self.group_by_modality:
|
| 127 |
+
indices = get_modality_length_grouped_indices(self.lengths, self.batch_size, self.world_size, generator=self.generator)
|
| 128 |
+
else:
|
| 129 |
+
indices = get_length_grouped_indices(self.lengths, self.batch_size, self.world_size, generator=self.generator)
|
| 130 |
+
return iter(indices)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
class LLaVATrainer(Trainer):
|
| 134 |
+
|
| 135 |
+
def _get_train_sampler(self) -> Optional[torch.utils.data.Sampler]:
|
| 136 |
+
if self.train_dataset is None or not has_length(self.train_dataset):
|
| 137 |
+
return None
|
| 138 |
+
|
| 139 |
+
if self.args.group_by_modality_length:
|
| 140 |
+
lengths = self.train_dataset.modality_lengths
|
| 141 |
+
return LengthGroupedSampler(
|
| 142 |
+
self.args.train_batch_size,
|
| 143 |
+
world_size=self.args.world_size * self.args.gradient_accumulation_steps,
|
| 144 |
+
lengths=lengths,
|
| 145 |
+
group_by_modality=True,
|
| 146 |
+
)
|
| 147 |
+
else:
|
| 148 |
+
return super()._get_train_sampler()
|
| 149 |
+
|
| 150 |
+
def create_optimizer(self):
|
| 151 |
+
"""
|
| 152 |
+
Setup the optimizer.
|
| 153 |
+
|
| 154 |
+
We provide a reasonable default that works well. If you want to use something else, you can pass a tuple in the
|
| 155 |
+
Trainer's init through `optimizers`, or subclass and override this method in a subclass.
|
| 156 |
+
"""
|
| 157 |
+
if is_sagemaker_mp_enabled():
|
| 158 |
+
return super().create_optimizer()
|
| 159 |
+
|
| 160 |
+
opt_model = self.model
|
| 161 |
+
|
| 162 |
+
if self.optimizer is None:
|
| 163 |
+
decay_parameters = get_parameter_names(opt_model, ALL_LAYERNORM_LAYERS)
|
| 164 |
+
decay_parameters = [name for name in decay_parameters if "bias" not in name]
|
| 165 |
+
if self.args.mm_projector_lr is not None:
|
| 166 |
+
projector_parameters = [name for name, _ in opt_model.named_parameters() if "mm_projector" in name]
|
| 167 |
+
optimizer_grouped_parameters = [
|
| 168 |
+
{
|
| 169 |
+
"params": [
|
| 170 |
+
p for n, p in opt_model.named_parameters() if (n in decay_parameters and n not in projector_parameters and p.requires_grad)
|
| 171 |
+
],
|
| 172 |
+
"weight_decay": self.args.weight_decay,
|
| 173 |
+
},
|
| 174 |
+
{
|
| 175 |
+
"params": [
|
| 176 |
+
p for n, p in opt_model.named_parameters() if (n not in decay_parameters and n not in projector_parameters and p.requires_grad)
|
| 177 |
+
],
|
| 178 |
+
"weight_decay": 0.0,
|
| 179 |
+
},
|
| 180 |
+
{
|
| 181 |
+
"params": [
|
| 182 |
+
p for n, p in opt_model.named_parameters() if (n in decay_parameters and n in projector_parameters and p.requires_grad)
|
| 183 |
+
],
|
| 184 |
+
"weight_decay": self.args.weight_decay,
|
| 185 |
+
"lr": self.args.mm_projector_lr,
|
| 186 |
+
},
|
| 187 |
+
{
|
| 188 |
+
"params": [
|
| 189 |
+
p for n, p in opt_model.named_parameters() if (n not in decay_parameters and n in projector_parameters and p.requires_grad)
|
| 190 |
+
],
|
| 191 |
+
"weight_decay": 0.0,
|
| 192 |
+
"lr": self.args.mm_projector_lr,
|
| 193 |
+
},
|
| 194 |
+
]
|
| 195 |
+
else:
|
| 196 |
+
optimizer_grouped_parameters = [
|
| 197 |
+
{
|
| 198 |
+
"params": [
|
| 199 |
+
p for n, p in opt_model.named_parameters() if (n in decay_parameters and p.requires_grad)
|
| 200 |
+
],
|
| 201 |
+
"weight_decay": self.args.weight_decay,
|
| 202 |
+
},
|
| 203 |
+
{
|
| 204 |
+
"params": [
|
| 205 |
+
p for n, p in opt_model.named_parameters() if (n not in decay_parameters and p.requires_grad)
|
| 206 |
+
],
|
| 207 |
+
"weight_decay": 0.0,
|
| 208 |
+
},
|
| 209 |
+
]
|
| 210 |
+
|
| 211 |
+
optimizer_cls, optimizer_kwargs = Trainer.get_optimizer_cls_and_kwargs(self.args)
|
| 212 |
+
|
| 213 |
+
self.optimizer = optimizer_cls(optimizer_grouped_parameters, **optimizer_kwargs)
|
| 214 |
+
if optimizer_cls.__name__ == "Adam8bit":
|
| 215 |
+
import bitsandbytes
|
| 216 |
+
|
| 217 |
+
manager = bitsandbytes.optim.GlobalOptimManager.get_instance()
|
| 218 |
+
|
| 219 |
+
skipped = 0
|
| 220 |
+
for module in opt_model.modules():
|
| 221 |
+
if isinstance(module, nn.Embedding):
|
| 222 |
+
skipped += sum({p.data_ptr(): p.numel() for p in module.parameters()}.values())
|
| 223 |
+
logger.info(f"skipped {module}: {skipped/2**20}M params")
|
| 224 |
+
manager.register_module_override(module, "weight", {"optim_bits": 32})
|
| 225 |
+
logger.debug(f"bitsandbytes: will optimize {module} in fp32")
|
| 226 |
+
logger.info(f"skipped: {skipped/2**20}M params")
|
| 227 |
+
|
| 228 |
+
return self.optimizer
|
| 229 |
+
|
| 230 |
+
def _save_checkpoint(self, model, trial, metrics=None):
|
| 231 |
+
if getattr(self.args, 'tune_mm_mlp_adapter', False):
|
| 232 |
+
from transformers.trainer_utils import PREFIX_CHECKPOINT_DIR
|
| 233 |
+
checkpoint_folder = f"{PREFIX_CHECKPOINT_DIR}-{self.state.global_step}"
|
| 234 |
+
|
| 235 |
+
run_dir = self._get_output_dir(trial=trial)
|
| 236 |
+
output_dir = os.path.join(run_dir, checkpoint_folder)
|
| 237 |
+
|
| 238 |
+
# Only save Adapter
|
| 239 |
+
keys_to_match = ['mm_projector', 'vision_resampler']
|
| 240 |
+
if getattr(self.args, "use_im_start_end", False):
|
| 241 |
+
keys_to_match.extend(['embed_tokens', 'embed_in'])
|
| 242 |
+
|
| 243 |
+
weight_to_save = get_mm_adapter_state_maybe_zero_3(self.model.named_parameters(), keys_to_match)
|
| 244 |
+
|
| 245 |
+
if self.args.local_rank == 0 or self.args.local_rank == -1:
|
| 246 |
+
self.model.config.save_pretrained(output_dir)
|
| 247 |
+
torch.save(weight_to_save, os.path.join(output_dir, f'mm_projector.bin'))
|
| 248 |
+
else:
|
| 249 |
+
super(LLaVATrainer, self)._save_checkpoint(model, trial, metrics)
|
| 250 |
+
|
| 251 |
+
def _save(self, output_dir: Optional[str] = None, state_dict=None):
|
| 252 |
+
if getattr(self.args, 'tune_mm_mlp_adapter', False):
|
| 253 |
+
pass
|
| 254 |
+
else:
|
| 255 |
+
super(LLaVATrainer, self)._save(output_dir, state_dict)
|
| 256 |
+
|
| 257 |
+
def compute_loss(self, model, inputs, return_outputs=False):
|
| 258 |
+
outputs = model(**inputs)
|
| 259 |
+
loss = outputs.loss
|
| 260 |
+
|
| 261 |
+
logs = {}
|
| 262 |
+
# ALWAYS convert tensors -> floats before self.log(...)
|
| 263 |
+
if hasattr(outputs, "loss_ce") and outputs.loss_ce is not None:
|
| 264 |
+
logs["ce_loss"] = outputs.loss_ce.detach().float().mean().item()
|
| 265 |
+
if hasattr(outputs, "loss_edit") and outputs.loss_edit is not None:
|
| 266 |
+
logs["diffusion_loss"] = outputs.loss_edit.detach().float().mean().item()
|
| 267 |
+
# (optional) also log total loss as a scalar
|
| 268 |
+
logs["loss"] = loss.detach().float().item()
|
| 269 |
+
|
| 270 |
+
if logs:
|
| 271 |
+
self.log(logs)
|
| 272 |
+
|
| 273 |
+
return (loss, outputs) if return_outputs else loss
|
llava/train/train_vlm_ip2p_256.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Training script for VLM-guided InstructPix2Pix (256x256 resolution).
|
| 4 |
+
|
| 5 |
+
Optimized for faster training with 256x256 images.
|
| 6 |
+
|
| 7 |
+
Key Features:
|
| 8 |
+
1. 256x256 diffusion resolution (4x faster than 512x512)
|
| 9 |
+
2. Choice of EditMapper: Simple MLP or MGIE-style Transformer
|
| 10 |
+
3. All cross-attention blocks injected by default
|
| 11 |
+
4. Compatible with base IP2P model (no need for fine-tuned checkpoint)
|
| 12 |
+
|
| 13 |
+
Usage:
|
| 14 |
+
deepspeed --num_gpus=4 llava/train/train_vlm_ip2p_256.py \\
|
| 15 |
+
--llava-base-path checkpoints/llava-1.5-7b-hf \\
|
| 16 |
+
--llava-lora-path checkpoints/llava-miragehd-prior-bbox \\
|
| 17 |
+
--ip2p-pretrained ../diffusers/ip2p_ema_safetensor \\
|
| 18 |
+
--data-path data/llava_no_ranking_nobbox.json \\
|
| 19 |
+
--image-folder ../ \\
|
| 20 |
+
--output-dir ./outputs/ip_adapter_256_v1 \\
|
| 21 |
+
--batch-size 4 \\
|
| 22 |
+
--num-epochs 100 \\
|
| 23 |
+
--use-mgie-mapper \\
|
| 24 |
+
--deepspeed ./scripts/deepspeed_zero2_vlm_ip2p.json
|
| 25 |
+
"""
|
| 26 |
+
|
| 27 |
+
import argparse
|
| 28 |
+
import os
|
| 29 |
+
import sys
|
| 30 |
+
from pathlib import Path
|
| 31 |
+
|
| 32 |
+
import torch
|
| 33 |
+
import torch.nn as nn
|
| 34 |
+
|
| 35 |
+
try:
|
| 36 |
+
import deepspeed
|
| 37 |
+
DEEPSPEED_AVAILABLE = True
|
| 38 |
+
except ImportError:
|
| 39 |
+
DEEPSPEED_AVAILABLE = False
|
| 40 |
+
|
| 41 |
+
# Import the base trainer
|
| 42 |
+
sys.path.append(str(Path(__file__).parent.parent.parent))
|
| 43 |
+
from llava.train.train_vlm_guided_ip2p import VLMGuidedIP2PTrainer, parse_args
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class VLMGuidedIP2P256Trainer(VLMGuidedIP2PTrainer):
|
| 47 |
+
"""
|
| 48 |
+
Trainer optimized for 256x256 resolution.
|
| 49 |
+
|
| 50 |
+
Inherits from base trainer and overrides data loading
|
| 51 |
+
to use 256x256 images for diffusion.
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
def setup_dataloaders(self):
|
| 55 |
+
"""Setup dataloaders with 256x256 resolution for diffusion"""
|
| 56 |
+
from llava.data import create_dataloaders
|
| 57 |
+
|
| 58 |
+
print("\n" + "="*80)
|
| 59 |
+
print("SETTING UP DATALOADERS (256x256 RESOLUTION)")
|
| 60 |
+
print("="*80)
|
| 61 |
+
|
| 62 |
+
# Override diffusion_size to 256
|
| 63 |
+
original_diffusion_size = self.args.diffusion_size if hasattr(self.args, 'diffusion_size') else 512
|
| 64 |
+
self.args.diffusion_size = 256 # Force 256x256 for diffusion
|
| 65 |
+
|
| 66 |
+
print(f" Diffusion resolution: {self.args.diffusion_size}x{self.args.diffusion_size}")
|
| 67 |
+
print(f" (Original was: {original_diffusion_size}x{original_diffusion_size})")
|
| 68 |
+
|
| 69 |
+
# Call parent setup with modified args
|
| 70 |
+
super().setup_dataloaders()
|
| 71 |
+
|
| 72 |
+
print("="*80 + "\n")
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def main():
|
| 76 |
+
# Parse arguments
|
| 77 |
+
args = parse_args()
|
| 78 |
+
|
| 79 |
+
# Override defaults for 256x256 training
|
| 80 |
+
print("\n" + "="*80)
|
| 81 |
+
print("VLM-GUIDED IP2P TRAINING (256x256 OPTIMIZED)")
|
| 82 |
+
print("="*80)
|
| 83 |
+
print(f"Resolution: 256x256 (4x faster than 512x512)")
|
| 84 |
+
print(f"EditMapper: {'MGIE-style' if args.use_mgie_mapper else 'Simple MLP'}")
|
| 85 |
+
print(f"Target blocks: {'All cross-attention' if args.target_blocks is None else args.target_blocks}")
|
| 86 |
+
print(f"IP2P checkpoint: {args.ip2p_pretrained}")
|
| 87 |
+
|
| 88 |
+
# Warn if using fine-tuned checkpoint
|
| 89 |
+
if args.ip2p_checkpoint:
|
| 90 |
+
print("\n⚠ WARNING: You specified --ip2p-checkpoint")
|
| 91 |
+
print(" For 256x256 training, you should use the base model (--ip2p-pretrained only)")
|
| 92 |
+
print(" Fine-tuned checkpoints may be trained on 512x512 resolution")
|
| 93 |
+
response = input(" Continue anyway? (y/N): ")
|
| 94 |
+
if response.lower() != 'y':
|
| 95 |
+
print("Exiting...")
|
| 96 |
+
return
|
| 97 |
+
|
| 98 |
+
print("="*80 + "\n")
|
| 99 |
+
|
| 100 |
+
# Create trainer
|
| 101 |
+
trainer = VLMGuidedIP2P256Trainer(args)
|
| 102 |
+
|
| 103 |
+
# Train
|
| 104 |
+
trainer.train()
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
if __name__ == "__main__":
|
| 108 |
+
main()
|
| 109 |
+
|
llava/utils.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import datetime
|
| 2 |
+
import logging
|
| 3 |
+
import logging.handlers
|
| 4 |
+
import os
|
| 5 |
+
import sys
|
| 6 |
+
|
| 7 |
+
import requests
|
| 8 |
+
|
| 9 |
+
from llava.constants import LOGDIR
|
| 10 |
+
|
| 11 |
+
server_error_msg = "**NETWORK ERROR DUE TO HIGH TRAFFIC. PLEASE REGENERATE OR REFRESH THIS PAGE.**"
|
| 12 |
+
moderation_msg = "YOUR INPUT VIOLATES OUR CONTENT MODERATION GUIDELINES. PLEASE TRY AGAIN."
|
| 13 |
+
|
| 14 |
+
handler = None
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def build_logger(logger_name, logger_filename):
|
| 18 |
+
global handler
|
| 19 |
+
|
| 20 |
+
formatter = logging.Formatter(
|
| 21 |
+
fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
|
| 22 |
+
datefmt="%Y-%m-%d %H:%M:%S",
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
# Set the format of root handlers
|
| 26 |
+
if not logging.getLogger().handlers:
|
| 27 |
+
logging.basicConfig(level=logging.INFO)
|
| 28 |
+
logging.getLogger().handlers[0].setFormatter(formatter)
|
| 29 |
+
|
| 30 |
+
# Redirect stdout and stderr to loggers
|
| 31 |
+
stdout_logger = logging.getLogger("stdout")
|
| 32 |
+
stdout_logger.setLevel(logging.INFO)
|
| 33 |
+
sl = StreamToLogger(stdout_logger, logging.INFO)
|
| 34 |
+
sys.stdout = sl
|
| 35 |
+
|
| 36 |
+
stderr_logger = logging.getLogger("stderr")
|
| 37 |
+
stderr_logger.setLevel(logging.ERROR)
|
| 38 |
+
sl = StreamToLogger(stderr_logger, logging.ERROR)
|
| 39 |
+
sys.stderr = sl
|
| 40 |
+
|
| 41 |
+
# Get logger
|
| 42 |
+
logger = logging.getLogger(logger_name)
|
| 43 |
+
logger.setLevel(logging.INFO)
|
| 44 |
+
|
| 45 |
+
# Add a file handler for all loggers
|
| 46 |
+
if handler is None:
|
| 47 |
+
os.makedirs(LOGDIR, exist_ok=True)
|
| 48 |
+
filename = os.path.join(LOGDIR, logger_filename)
|
| 49 |
+
handler = logging.handlers.TimedRotatingFileHandler(
|
| 50 |
+
filename, when='D', utc=True, encoding='UTF-8')
|
| 51 |
+
handler.setFormatter(formatter)
|
| 52 |
+
|
| 53 |
+
for name, item in logging.root.manager.loggerDict.items():
|
| 54 |
+
if isinstance(item, logging.Logger):
|
| 55 |
+
item.addHandler(handler)
|
| 56 |
+
|
| 57 |
+
return logger
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
class StreamToLogger(object):
|
| 61 |
+
"""
|
| 62 |
+
Fake file-like stream object that redirects writes to a logger instance.
|
| 63 |
+
"""
|
| 64 |
+
def __init__(self, logger, log_level=logging.INFO):
|
| 65 |
+
self.terminal = sys.stdout
|
| 66 |
+
self.logger = logger
|
| 67 |
+
self.log_level = log_level
|
| 68 |
+
self.linebuf = ''
|
| 69 |
+
|
| 70 |
+
def __getattr__(self, attr):
|
| 71 |
+
return getattr(self.terminal, attr)
|
| 72 |
+
|
| 73 |
+
def write(self, buf):
|
| 74 |
+
temp_linebuf = self.linebuf + buf
|
| 75 |
+
self.linebuf = ''
|
| 76 |
+
for line in temp_linebuf.splitlines(True):
|
| 77 |
+
# From the io.TextIOWrapper docs:
|
| 78 |
+
# On output, if newline is None, any '\n' characters written
|
| 79 |
+
# are translated to the system default line separator.
|
| 80 |
+
# By default sys.stdout.write() expects '\n' newlines and then
|
| 81 |
+
# translates them so this is still cross platform.
|
| 82 |
+
if line[-1] == '\n':
|
| 83 |
+
self.logger.log(self.log_level, line.rstrip())
|
| 84 |
+
else:
|
| 85 |
+
self.linebuf += line
|
| 86 |
+
|
| 87 |
+
def flush(self):
|
| 88 |
+
if self.linebuf != '':
|
| 89 |
+
self.logger.log(self.log_level, self.linebuf.rstrip())
|
| 90 |
+
self.linebuf = ''
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def disable_torch_init():
|
| 94 |
+
"""
|
| 95 |
+
Disable the redundant torch default initialization to accelerate model creation.
|
| 96 |
+
"""
|
| 97 |
+
import torch
|
| 98 |
+
setattr(torch.nn.Linear, "reset_parameters", lambda self: None)
|
| 99 |
+
setattr(torch.nn.LayerNorm, "reset_parameters", lambda self: None)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def violates_moderation(text):
|
| 103 |
+
"""
|
| 104 |
+
Check whether the text violates OpenAI moderation API.
|
| 105 |
+
"""
|
| 106 |
+
url = "https://api.openai.com/v1/moderations"
|
| 107 |
+
headers = {"Content-Type": "application/json",
|
| 108 |
+
"Authorization": "Bearer " + os.environ["OPENAI_API_KEY"]}
|
| 109 |
+
text = text.replace("\n", "")
|
| 110 |
+
data = "{" + '"input": ' + f'"{text}"' + "}"
|
| 111 |
+
data = data.encode("utf-8")
|
| 112 |
+
try:
|
| 113 |
+
ret = requests.post(url, headers=headers, data=data, timeout=5)
|
| 114 |
+
flagged = ret.json()["results"][0]["flagged"]
|
| 115 |
+
except requests.exceptions.RequestException as e:
|
| 116 |
+
flagged = False
|
| 117 |
+
except KeyError as e:
|
| 118 |
+
flagged = False
|
| 119 |
+
|
| 120 |
+
return flagged
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def pretty_print_semaphore(semaphore):
|
| 124 |
+
if semaphore is None:
|
| 125 |
+
return "None"
|
| 126 |
+
return f"Semaphore(value={semaphore._value}, locked={semaphore.locked()})"
|
requirements.txt
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Core inference
|
| 2 |
+
torch>=2.0.0
|
| 3 |
+
torchvision>=0.15.0
|
| 4 |
+
diffusers>=0.21.0
|
| 5 |
+
transformers>=4.36.0
|
| 6 |
+
accelerate>=0.25.0
|
| 7 |
+
safetensors>=0.4.0
|
| 8 |
+
|
| 9 |
+
# Image I/O
|
| 10 |
+
pillow>=9.0.0
|
| 11 |
+
tqdm>=4.65.0
|
| 12 |
+
|
| 13 |
+
# LLaVA on-the-fly mode only (optional for reference-cache inference)
|
| 14 |
+
peft>=0.7.0
|
| 15 |
+
sentencepiece>=0.1.99
|
| 16 |
+
protobuf>=3.20.0
|
| 17 |
+
|
| 18 |
+
# LLaVA vision backbone
|
| 19 |
+
timm>=0.9.0
|
| 20 |
+
einops>=0.7.0
|
| 21 |
+
|
| 22 |
+
# Hugging Face hub (weight download)
|
| 23 |
+
huggingface-hub>=0.20.0
|
thera_llava.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Lazy loader for FrozenLLaVAExtractor.
|
| 3 |
+
|
| 4 |
+
Reference-cache inference does not need LLaVA weights at runtime. The extractor
|
| 5 |
+
is imported only when on-the-fly feature extraction is requested.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
import inspect
|
| 11 |
+
from typing import Any
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def create_frozen_llava_extractor(**kwargs: Any):
|
| 15 |
+
"""Construct FrozenLLaVAExtractor; imports LLaVA stack on first use."""
|
| 16 |
+
from llava.model.frozen_llava_extractor import FrozenLLaVAExtractor
|
| 17 |
+
|
| 18 |
+
sig = inspect.signature(FrozenLLaVAExtractor.__init__)
|
| 19 |
+
if "merge_lora" not in sig.parameters:
|
| 20 |
+
kwargs.pop("merge_lora", None)
|
| 21 |
+
return FrozenLLaVAExtractor(**kwargs)
|
thera_paths.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Default paths for TherA inference (relative to this repository root).
|
| 3 |
+
|
| 4 |
+
Download model weights into the `weights/` directory — see README.md.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
import sys
|
| 10 |
+
from pathlib import Path
|
| 11 |
+
|
| 12 |
+
PROJECT_ROOT = Path(__file__).resolve().parent
|
| 13 |
+
WEIGHTS_DIR = PROJECT_ROOT / "weights"
|
| 14 |
+
|
| 15 |
+
DEFAULT_CHECKPOINT = WEIGHTS_DIR / "checkpoint"
|
| 16 |
+
DEFAULT_MERGED_MODEL = WEIGHTS_DIR / "merged_models"
|
| 17 |
+
DEFAULT_PRETRAINED_SD = WEIGHTS_DIR / "stable-diffusion"
|
| 18 |
+
DEFAULT_REFERENCE_CACHES = WEIGHTS_DIR / "reference_caches"
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def setup_project_path() -> Path:
|
| 22 |
+
"""Ensure TherA root is on sys.path so local packages import correctly."""
|
| 23 |
+
root = str(PROJECT_ROOT)
|
| 24 |
+
if root not in sys.path:
|
| 25 |
+
sys.path.insert(0, root)
|
| 26 |
+
return PROJECT_ROOT
|
weights/.gitattributes
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
weights/README.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
---
|
weights/TherA_VLM/adapter_config.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"alpha_pattern": {},
|
| 3 |
+
"auto_mapping": null,
|
| 4 |
+
"base_model_name_or_path": "./checkpoints/llava-1.5-7b-hf",
|
| 5 |
+
"bias": "none",
|
| 6 |
+
"fan_in_fan_out": false,
|
| 7 |
+
"inference_mode": true,
|
| 8 |
+
"init_lora_weights": true,
|
| 9 |
+
"layer_replication": null,
|
| 10 |
+
"layers_pattern": null,
|
| 11 |
+
"layers_to_transform": null,
|
| 12 |
+
"loftq_config": {},
|
| 13 |
+
"lora_alpha": 256,
|
| 14 |
+
"lora_dropout": 0.05,
|
| 15 |
+
"megatron_config": null,
|
| 16 |
+
"megatron_core": "megatron.core",
|
| 17 |
+
"modules_to_save": null,
|
| 18 |
+
"peft_type": "LORA",
|
| 19 |
+
"r": 128,
|
| 20 |
+
"rank_pattern": {},
|
| 21 |
+
"revision": null,
|
| 22 |
+
"target_modules": [
|
| 23 |
+
"up_proj",
|
| 24 |
+
"v_proj",
|
| 25 |
+
"q_proj",
|
| 26 |
+
"o_proj",
|
| 27 |
+
"gate_proj",
|
| 28 |
+
"down_proj",
|
| 29 |
+
"k_proj"
|
| 30 |
+
],
|
| 31 |
+
"task_type": "CAUSAL_LM",
|
| 32 |
+
"use_dora": false,
|
| 33 |
+
"use_rslora": false
|
| 34 |
+
}
|
weights/TherA_VLM/config.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_name_or_path": "./checkpoints/llava-1.5-7b-hf",
|
| 3 |
+
"architectures": [
|
| 4 |
+
"LlavaLlamaForCausalLM"
|
| 5 |
+
],
|
| 6 |
+
"attention_bias": false,
|
| 7 |
+
"attention_dropout": 0.0,
|
| 8 |
+
"bos_token_id": 1,
|
| 9 |
+
"eos_token_id": 2,
|
| 10 |
+
"freeze_mm_mlp_adapter": false,
|
| 11 |
+
"freeze_mm_vision_resampler": false,
|
| 12 |
+
"hidden_act": "silu",
|
| 13 |
+
"hidden_size": 4096,
|
| 14 |
+
"image_aspect_ratio": "pad",
|
| 15 |
+
"initializer_range": 0.02,
|
| 16 |
+
"intermediate_size": 11008,
|
| 17 |
+
"max_length": 4096,
|
| 18 |
+
"max_position_embeddings": 4096,
|
| 19 |
+
"mm_hidden_size": 1024,
|
| 20 |
+
"mm_patch_merge_type": "flat",
|
| 21 |
+
"mm_projector_lr": 2e-05,
|
| 22 |
+
"mm_projector_type": "mlp2x_gelu",
|
| 23 |
+
"mm_resampler_type": null,
|
| 24 |
+
"mm_use_im_patch_token": false,
|
| 25 |
+
"mm_use_im_start_end": false,
|
| 26 |
+
"mm_vision_select_feature": "patch",
|
| 27 |
+
"mm_vision_select_layer": -2,
|
| 28 |
+
"mm_vision_tower": "openai/clip-vit-large-patch14-336",
|
| 29 |
+
"model_type": "llava_llama",
|
| 30 |
+
"num_attention_heads": 32,
|
| 31 |
+
"num_hidden_layers": 32,
|
| 32 |
+
"num_key_value_heads": 32,
|
| 33 |
+
"pad_token_id": 0,
|
| 34 |
+
"pretraining_tp": 1,
|
| 35 |
+
"rms_norm_eps": 1e-05,
|
| 36 |
+
"rope_scaling": null,
|
| 37 |
+
"rope_theta": 10000.0,
|
| 38 |
+
"tie_word_embeddings": false,
|
| 39 |
+
"tokenizer_model_max_length": 2048,
|
| 40 |
+
"tokenizer_padding_side": "right",
|
| 41 |
+
"torch_dtype": "float16",
|
| 42 |
+
"transformers_version": "4.37.2",
|
| 43 |
+
"tune_mm_mlp_adapter": false,
|
| 44 |
+
"tune_mm_vision_resampler": false,
|
| 45 |
+
"unfreeze_mm_vision_tower": false,
|
| 46 |
+
"use_cache": true,
|
| 47 |
+
"use_mm_proj": true,
|
| 48 |
+
"vocab_size": 32000
|
| 49 |
+
}
|
weights/TherA_VLM/trainer_state.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
weights/llava-1.5-7b-hf/.gitattributes
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
weights/llava-1.5-7b-hf/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- en
|
| 4 |
+
datasets:
|
| 5 |
+
- liuhaotian/LLaVA-Instruct-150K
|
| 6 |
+
pipeline_tag: image-text-to-text
|
| 7 |
+
arxiv: 2304.08485
|
| 8 |
+
license: llama2
|
| 9 |
+
tags:
|
| 10 |
+
- vision
|
| 11 |
+
- image-text-to-text
|
| 12 |
+
---
|
| 13 |
+
# LLaVA Model Card
|
| 14 |
+
|
| 15 |
+

|
| 16 |
+
|
| 17 |
+
Below is the model card of Llava model 7b, which is copied from the original Llava model card that you can find [here](https://huggingface.co/liuhaotian/llava-v1.5-13b).
|
| 18 |
+
|
| 19 |
+
Check out also the Google Colab demo to run Llava on a free-tier Google Colab instance: [](https://colab.research.google.com/drive/1qsl6cd2c8gGtEW1xV5io7S8NHh-Cp1TV?usp=sharing)
|
| 20 |
+
|
| 21 |
+
Or check out our Spaces demo! [](https://huggingface.co/spaces/llava-hf/llava-4bit)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
## Model details
|
| 25 |
+
|
| 26 |
+
**Model type:**
|
| 27 |
+
LLaVA is an open-source chatbot trained by fine-tuning LLaMA/Vicuna on GPT-generated multimodal instruction-following data.
|
| 28 |
+
It is an auto-regressive language model, based on the transformer architecture.
|
| 29 |
+
|
| 30 |
+
**Model date:**
|
| 31 |
+
LLaVA-v1.5-7B was trained in September 2023.
|
| 32 |
+
|
| 33 |
+
**Paper or resources for more information:**
|
| 34 |
+
https://llava-vl.github.io/
|
| 35 |
+
|
| 36 |
+
## How to use the model
|
| 37 |
+
|
| 38 |
+
First, make sure to have `transformers >= 4.35.3`.
|
| 39 |
+
The model supports multi-image and multi-prompt generation. Meaning that you can pass multiple images in your prompt. Make sure also to follow the correct prompt template (`USER: xxx\nASSISTANT:`) and add the token `<image>` to the location where you want to query images:
|
| 40 |
+
|
| 41 |
+
### Using `pipeline`:
|
| 42 |
+
|
| 43 |
+
Below we used [`"llava-hf/llava-1.5-7b-hf"`](https://huggingface.co/llava-hf/llava-1.5-7b-hf) checkpoint.
|
| 44 |
+
|
| 45 |
+
```python
|
| 46 |
+
from transformers import pipeline
|
| 47 |
+
|
| 48 |
+
pipe = pipeline("image-text-to-text", model="llava-hf/llava-1.5-7b-hf")
|
| 49 |
+
messages = [
|
| 50 |
+
{
|
| 51 |
+
"role": "user",
|
| 52 |
+
"content": [
|
| 53 |
+
{"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/ai2d-demo.jpg"},
|
| 54 |
+
{"type": "text", "text": "What does the label 15 represent? (1) lava (2) core (3) tunnel (4) ash cloud"},
|
| 55 |
+
],
|
| 56 |
+
},
|
| 57 |
+
]
|
| 58 |
+
|
| 59 |
+
out = pipe(text=messages, max_new_tokens=20)
|
| 60 |
+
print(out)
|
| 61 |
+
>>> [{'input_text': [{'role': 'user', 'content': [{'type': 'image', 'url': 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/ai2d-demo.jpg'}, {'type': 'text', 'text': 'What does the label 15 represent? (1) lava (2) core (3) tunnel (4) ash cloud'}]}], 'generated_text': 'Lava'}]
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
### Using pure `transformers`:
|
| 65 |
+
|
| 66 |
+
Below is an example script to run generation in `float16` precision on a GPU device:
|
| 67 |
+
|
| 68 |
+
```python
|
| 69 |
+
import requests
|
| 70 |
+
from PIL import Image
|
| 71 |
+
|
| 72 |
+
import torch
|
| 73 |
+
from transformers import AutoProcessor, LlavaForConditionalGeneration
|
| 74 |
+
|
| 75 |
+
model_id = "llava-hf/llava-1.5-7b-hf"
|
| 76 |
+
model = LlavaForConditionalGeneration.from_pretrained(
|
| 77 |
+
model_id,
|
| 78 |
+
torch_dtype=torch.float16,
|
| 79 |
+
low_cpu_mem_usage=True,
|
| 80 |
+
).to(0)
|
| 81 |
+
|
| 82 |
+
processor = AutoProcessor.from_pretrained(model_id)
|
| 83 |
+
|
| 84 |
+
# Define a chat history and use `apply_chat_template` to get correctly formatted prompt
|
| 85 |
+
# Each value in "content" has to be a list of dicts with types ("text", "image")
|
| 86 |
+
conversation = [
|
| 87 |
+
{
|
| 88 |
+
|
| 89 |
+
"role": "user",
|
| 90 |
+
"content": [
|
| 91 |
+
{"type": "text", "text": "What are these?"},
|
| 92 |
+
{"type": "image"},
|
| 93 |
+
],
|
| 94 |
+
},
|
| 95 |
+
]
|
| 96 |
+
prompt = processor.apply_chat_template(conversation, add_generation_prompt=True)
|
| 97 |
+
|
| 98 |
+
image_file = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 99 |
+
raw_image = Image.open(requests.get(image_file, stream=True).raw)
|
| 100 |
+
inputs = processor(images=raw_image, text=prompt, return_tensors='pt').to(0, torch.float16)
|
| 101 |
+
|
| 102 |
+
output = model.generate(**inputs, max_new_tokens=200, do_sample=False)
|
| 103 |
+
print(processor.decode(output[0][2:], skip_special_tokens=True))
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
-----------
|
| 107 |
+
From transformers>=v4.48, you can also pass image url or local path to the conversation history, and let the chat template handle the rest.
|
| 108 |
+
Chat template will load the image for you and return inputs in `torch.Tensor` which you can pass directly to `model.generate()`
|
| 109 |
+
|
| 110 |
+
```python
|
| 111 |
+
messages = [
|
| 112 |
+
{
|
| 113 |
+
"role": "user",
|
| 114 |
+
"content": [
|
| 115 |
+
{"type": "image", "url": "https://www.ilankelman.org/stopsigns/australia.jpg"}
|
| 116 |
+
{"type": "text", "text": "What is shown in this image?"},
|
| 117 |
+
],
|
| 118 |
+
},
|
| 119 |
+
]
|
| 120 |
+
|
| 121 |
+
inputs = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors"pt")
|
| 122 |
+
output = model.generate(**inputs, max_new_tokens=50)
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
### Model optimization
|
| 126 |
+
|
| 127 |
+
#### 4-bit quantization through `bitsandbytes` library
|
| 128 |
+
|
| 129 |
+
First make sure to install `bitsandbytes`, `pip install bitsandbytes` and make sure to have access to a CUDA compatible GPU device. Simply change the snippet above with:
|
| 130 |
+
|
| 131 |
+
```diff
|
| 132 |
+
model = LlavaForConditionalGeneration.from_pretrained(
|
| 133 |
+
model_id,
|
| 134 |
+
torch_dtype=torch.float16,
|
| 135 |
+
low_cpu_mem_usage=True,
|
| 136 |
+
+ load_in_4bit=True
|
| 137 |
+
)
|
| 138 |
+
```
|
| 139 |
+
|
| 140 |
+
#### Use Flash-Attention 2 to further speed-up generation
|
| 141 |
+
|
| 142 |
+
First make sure to install `flash-attn`. Refer to the [original repository of Flash Attention](https://github.com/Dao-AILab/flash-attention) regarding that package installation. Simply change the snippet above with:
|
| 143 |
+
|
| 144 |
+
```diff
|
| 145 |
+
model = LlavaForConditionalGeneration.from_pretrained(
|
| 146 |
+
model_id,
|
| 147 |
+
torch_dtype=torch.float16,
|
| 148 |
+
low_cpu_mem_usage=True,
|
| 149 |
+
+ use_flash_attention_2=True
|
| 150 |
+
).to(0)
|
| 151 |
+
```
|
| 152 |
+
|
| 153 |
+
## License
|
| 154 |
+
Llama 2 is licensed under the LLAMA 2 Community License,
|
| 155 |
+
Copyright (c) Meta Platforms, Inc. All Rights Reserved.
|
weights/llava-1.5-7b-hf/added_tokens.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"<image>": 32000,
|
| 3 |
+
"<pad>": 32001
|
| 4 |
+
}
|
weights/llava-1.5-7b-hf/chat_template.jinja
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% for message in messages %}{% if message['role'] != 'system' %}{{ message['role'].upper() + ': '}}{% endif %}{# Render all images first #}{% for content in message['content'] | selectattr('type', 'equalto', 'image') %}{{ '<image>
|
| 2 |
+
' }}{% endfor %}{# Render all text next #}{% if message['role'] != 'assistant' %}{% for content in message['content'] | selectattr('type', 'equalto', 'text') %}{{ content['text'] + ' '}}{% endfor %}{% else %}{% for content in message['content'] | selectattr('type', 'equalto', 'text') %}{% generation %}{{ content['text'] + ' '}}{% endgeneration %}{% endfor %}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ 'ASSISTANT:' }}{% endif %}
|
weights/llava-1.5-7b-hf/chat_template.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"chat_template": "{% for message in messages %}{% if message['role'] != 'system' %}{{ message['role'].upper() + ': '}}{% endif %}{# Render all images first #}{% for content in message['content'] | selectattr('type', 'equalto', 'image') %}{{ '<image>\n' }}{% endfor %}{# Render all text next #}{% if message['role'] != 'assistant' %}{% for content in message['content'] | selectattr('type', 'equalto', 'text') %}{{ content['text'] + ' '}}{% endfor %}{% else %}{% for content in message['content'] | selectattr('type', 'equalto', 'text') %}{% generation %}{{ content['text'] + ' '}}{% endgeneration %}{% endfor %}{% endif %}{% endfor %}{% if add_generation_prompt %}{{ 'ASSISTANT:' }}{% endif %}"
|
| 3 |
+
}
|
weights/llava-1.5-7b-hf/config.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"LlavaForConditionalGeneration"
|
| 4 |
+
],
|
| 5 |
+
"ignore_index": -100,
|
| 6 |
+
"image_token_index": 32000,
|
| 7 |
+
"model_type": "llava",
|
| 8 |
+
"pad_token_id": 32001,
|
| 9 |
+
"projector_hidden_act": "gelu",
|
| 10 |
+
"text_config": {
|
| 11 |
+
"_name_or_path": "lmsys/vicuna-7b-v1.5",
|
| 12 |
+
"architectures": [
|
| 13 |
+
"LlamaForCausalLM"
|
| 14 |
+
],
|
| 15 |
+
"max_position_embeddings": 4096,
|
| 16 |
+
"model_type": "llama",
|
| 17 |
+
"rms_norm_eps": 1e-05,
|
| 18 |
+
"torch_dtype": "float16",
|
| 19 |
+
"vocab_size": 32064
|
| 20 |
+
},
|
| 21 |
+
"tie_word_embeddings": false,
|
| 22 |
+
"torch_dtype": "float16",
|
| 23 |
+
"transformers_version": "4.36.0.dev0",
|
| 24 |
+
"vision_config": {
|
| 25 |
+
"hidden_size": 1024,
|
| 26 |
+
"image_size": 336,
|
| 27 |
+
"intermediate_size": 4096,
|
| 28 |
+
"model_type": "clip_vision_model",
|
| 29 |
+
"num_attention_heads": 16,
|
| 30 |
+
"num_hidden_layers": 24,
|
| 31 |
+
"patch_size": 14,
|
| 32 |
+
"projection_dim": 768,
|
| 33 |
+
"vocab_size": 32000
|
| 34 |
+
},
|
| 35 |
+
"vision_feature_layer": -2,
|
| 36 |
+
"vision_feature_select_strategy": "default",
|
| 37 |
+
"vocab_size": 32064
|
| 38 |
+
}
|
weights/llava-1.5-7b-hf/generation_config.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"bos_token_id": 1,
|
| 4 |
+
"eos_token_id": 2,
|
| 5 |
+
"pad_token_id": 32001,
|
| 6 |
+
"transformers_version": "4.36.0.dev0"
|
| 7 |
+
}
|
weights/llava-1.5-7b-hf/model.safetensors.index.json
ADDED
|
@@ -0,0 +1,693 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"metadata": {
|
| 3 |
+
"total_size": 14126854144
|
| 4 |
+
},
|
| 5 |
+
"weight_map": {
|
| 6 |
+
"language_model.lm_head.weight": "model-00003-of-00003.safetensors",
|
| 7 |
+
"language_model.model.embed_tokens.weight": "model-00001-of-00003.safetensors",
|
| 8 |
+
"language_model.model.layers.0.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 9 |
+
"language_model.model.layers.0.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 10 |
+
"language_model.model.layers.0.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 11 |
+
"language_model.model.layers.0.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 12 |
+
"language_model.model.layers.0.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 13 |
+
"language_model.model.layers.0.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 14 |
+
"language_model.model.layers.0.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 15 |
+
"language_model.model.layers.0.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 16 |
+
"language_model.model.layers.0.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 17 |
+
"language_model.model.layers.1.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 18 |
+
"language_model.model.layers.1.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 19 |
+
"language_model.model.layers.1.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 20 |
+
"language_model.model.layers.1.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 21 |
+
"language_model.model.layers.1.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 22 |
+
"language_model.model.layers.1.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 23 |
+
"language_model.model.layers.1.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 24 |
+
"language_model.model.layers.1.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 25 |
+
"language_model.model.layers.1.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 26 |
+
"language_model.model.layers.10.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 27 |
+
"language_model.model.layers.10.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 28 |
+
"language_model.model.layers.10.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 29 |
+
"language_model.model.layers.10.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 30 |
+
"language_model.model.layers.10.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 31 |
+
"language_model.model.layers.10.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 32 |
+
"language_model.model.layers.10.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 33 |
+
"language_model.model.layers.10.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 34 |
+
"language_model.model.layers.10.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 35 |
+
"language_model.model.layers.11.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 36 |
+
"language_model.model.layers.11.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 37 |
+
"language_model.model.layers.11.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 38 |
+
"language_model.model.layers.11.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 39 |
+
"language_model.model.layers.11.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 40 |
+
"language_model.model.layers.11.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 41 |
+
"language_model.model.layers.11.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 42 |
+
"language_model.model.layers.11.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 43 |
+
"language_model.model.layers.11.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 44 |
+
"language_model.model.layers.12.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 45 |
+
"language_model.model.layers.12.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 46 |
+
"language_model.model.layers.12.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 47 |
+
"language_model.model.layers.12.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 48 |
+
"language_model.model.layers.12.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 49 |
+
"language_model.model.layers.12.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 50 |
+
"language_model.model.layers.12.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 51 |
+
"language_model.model.layers.12.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 52 |
+
"language_model.model.layers.12.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 53 |
+
"language_model.model.layers.13.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 54 |
+
"language_model.model.layers.13.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 55 |
+
"language_model.model.layers.13.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 56 |
+
"language_model.model.layers.13.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 57 |
+
"language_model.model.layers.13.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 58 |
+
"language_model.model.layers.13.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 59 |
+
"language_model.model.layers.13.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 60 |
+
"language_model.model.layers.13.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 61 |
+
"language_model.model.layers.13.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 62 |
+
"language_model.model.layers.14.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 63 |
+
"language_model.model.layers.14.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 64 |
+
"language_model.model.layers.14.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 65 |
+
"language_model.model.layers.14.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 66 |
+
"language_model.model.layers.14.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 67 |
+
"language_model.model.layers.14.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 68 |
+
"language_model.model.layers.14.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 69 |
+
"language_model.model.layers.14.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 70 |
+
"language_model.model.layers.14.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 71 |
+
"language_model.model.layers.15.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 72 |
+
"language_model.model.layers.15.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 73 |
+
"language_model.model.layers.15.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 74 |
+
"language_model.model.layers.15.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 75 |
+
"language_model.model.layers.15.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 76 |
+
"language_model.model.layers.15.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 77 |
+
"language_model.model.layers.15.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 78 |
+
"language_model.model.layers.15.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 79 |
+
"language_model.model.layers.15.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 80 |
+
"language_model.model.layers.16.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 81 |
+
"language_model.model.layers.16.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 82 |
+
"language_model.model.layers.16.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 83 |
+
"language_model.model.layers.16.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 84 |
+
"language_model.model.layers.16.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 85 |
+
"language_model.model.layers.16.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 86 |
+
"language_model.model.layers.16.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 87 |
+
"language_model.model.layers.16.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 88 |
+
"language_model.model.layers.16.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 89 |
+
"language_model.model.layers.17.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 90 |
+
"language_model.model.layers.17.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 91 |
+
"language_model.model.layers.17.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 92 |
+
"language_model.model.layers.17.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 93 |
+
"language_model.model.layers.17.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 94 |
+
"language_model.model.layers.17.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 95 |
+
"language_model.model.layers.17.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 96 |
+
"language_model.model.layers.17.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 97 |
+
"language_model.model.layers.17.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 98 |
+
"language_model.model.layers.18.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 99 |
+
"language_model.model.layers.18.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 100 |
+
"language_model.model.layers.18.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 101 |
+
"language_model.model.layers.18.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 102 |
+
"language_model.model.layers.18.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 103 |
+
"language_model.model.layers.18.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 104 |
+
"language_model.model.layers.18.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 105 |
+
"language_model.model.layers.18.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 106 |
+
"language_model.model.layers.18.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 107 |
+
"language_model.model.layers.19.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 108 |
+
"language_model.model.layers.19.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 109 |
+
"language_model.model.layers.19.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 110 |
+
"language_model.model.layers.19.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 111 |
+
"language_model.model.layers.19.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 112 |
+
"language_model.model.layers.19.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 113 |
+
"language_model.model.layers.19.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 114 |
+
"language_model.model.layers.19.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 115 |
+
"language_model.model.layers.19.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 116 |
+
"language_model.model.layers.2.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 117 |
+
"language_model.model.layers.2.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 118 |
+
"language_model.model.layers.2.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 119 |
+
"language_model.model.layers.2.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 120 |
+
"language_model.model.layers.2.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 121 |
+
"language_model.model.layers.2.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 122 |
+
"language_model.model.layers.2.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 123 |
+
"language_model.model.layers.2.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 124 |
+
"language_model.model.layers.2.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 125 |
+
"language_model.model.layers.20.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 126 |
+
"language_model.model.layers.20.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 127 |
+
"language_model.model.layers.20.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 128 |
+
"language_model.model.layers.20.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 129 |
+
"language_model.model.layers.20.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 130 |
+
"language_model.model.layers.20.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 131 |
+
"language_model.model.layers.20.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 132 |
+
"language_model.model.layers.20.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 133 |
+
"language_model.model.layers.20.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 134 |
+
"language_model.model.layers.21.input_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 135 |
+
"language_model.model.layers.21.mlp.down_proj.weight": "model-00002-of-00003.safetensors",
|
| 136 |
+
"language_model.model.layers.21.mlp.gate_proj.weight": "model-00002-of-00003.safetensors",
|
| 137 |
+
"language_model.model.layers.21.mlp.up_proj.weight": "model-00002-of-00003.safetensors",
|
| 138 |
+
"language_model.model.layers.21.post_attention_layernorm.weight": "model-00002-of-00003.safetensors",
|
| 139 |
+
"language_model.model.layers.21.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 140 |
+
"language_model.model.layers.21.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 141 |
+
"language_model.model.layers.21.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 142 |
+
"language_model.model.layers.21.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 143 |
+
"language_model.model.layers.22.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 144 |
+
"language_model.model.layers.22.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 145 |
+
"language_model.model.layers.22.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 146 |
+
"language_model.model.layers.22.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 147 |
+
"language_model.model.layers.22.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 148 |
+
"language_model.model.layers.22.self_attn.k_proj.weight": "model-00002-of-00003.safetensors",
|
| 149 |
+
"language_model.model.layers.22.self_attn.o_proj.weight": "model-00002-of-00003.safetensors",
|
| 150 |
+
"language_model.model.layers.22.self_attn.q_proj.weight": "model-00002-of-00003.safetensors",
|
| 151 |
+
"language_model.model.layers.22.self_attn.v_proj.weight": "model-00002-of-00003.safetensors",
|
| 152 |
+
"language_model.model.layers.23.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 153 |
+
"language_model.model.layers.23.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 154 |
+
"language_model.model.layers.23.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 155 |
+
"language_model.model.layers.23.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 156 |
+
"language_model.model.layers.23.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 157 |
+
"language_model.model.layers.23.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 158 |
+
"language_model.model.layers.23.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 159 |
+
"language_model.model.layers.23.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 160 |
+
"language_model.model.layers.23.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 161 |
+
"language_model.model.layers.24.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 162 |
+
"language_model.model.layers.24.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 163 |
+
"language_model.model.layers.24.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 164 |
+
"language_model.model.layers.24.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 165 |
+
"language_model.model.layers.24.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 166 |
+
"language_model.model.layers.24.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 167 |
+
"language_model.model.layers.24.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 168 |
+
"language_model.model.layers.24.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 169 |
+
"language_model.model.layers.24.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 170 |
+
"language_model.model.layers.25.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 171 |
+
"language_model.model.layers.25.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 172 |
+
"language_model.model.layers.25.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 173 |
+
"language_model.model.layers.25.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 174 |
+
"language_model.model.layers.25.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 175 |
+
"language_model.model.layers.25.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 176 |
+
"language_model.model.layers.25.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 177 |
+
"language_model.model.layers.25.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 178 |
+
"language_model.model.layers.25.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 179 |
+
"language_model.model.layers.26.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 180 |
+
"language_model.model.layers.26.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 181 |
+
"language_model.model.layers.26.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 182 |
+
"language_model.model.layers.26.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 183 |
+
"language_model.model.layers.26.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 184 |
+
"language_model.model.layers.26.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 185 |
+
"language_model.model.layers.26.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 186 |
+
"language_model.model.layers.26.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 187 |
+
"language_model.model.layers.26.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 188 |
+
"language_model.model.layers.27.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 189 |
+
"language_model.model.layers.27.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 190 |
+
"language_model.model.layers.27.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 191 |
+
"language_model.model.layers.27.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 192 |
+
"language_model.model.layers.27.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 193 |
+
"language_model.model.layers.27.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 194 |
+
"language_model.model.layers.27.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 195 |
+
"language_model.model.layers.27.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 196 |
+
"language_model.model.layers.27.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 197 |
+
"language_model.model.layers.28.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 198 |
+
"language_model.model.layers.28.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 199 |
+
"language_model.model.layers.28.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 200 |
+
"language_model.model.layers.28.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 201 |
+
"language_model.model.layers.28.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 202 |
+
"language_model.model.layers.28.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 203 |
+
"language_model.model.layers.28.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 204 |
+
"language_model.model.layers.28.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 205 |
+
"language_model.model.layers.28.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 206 |
+
"language_model.model.layers.29.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 207 |
+
"language_model.model.layers.29.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 208 |
+
"language_model.model.layers.29.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 209 |
+
"language_model.model.layers.29.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 210 |
+
"language_model.model.layers.29.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 211 |
+
"language_model.model.layers.29.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 212 |
+
"language_model.model.layers.29.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 213 |
+
"language_model.model.layers.29.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 214 |
+
"language_model.model.layers.29.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 215 |
+
"language_model.model.layers.3.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 216 |
+
"language_model.model.layers.3.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 217 |
+
"language_model.model.layers.3.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 218 |
+
"language_model.model.layers.3.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 219 |
+
"language_model.model.layers.3.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 220 |
+
"language_model.model.layers.3.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 221 |
+
"language_model.model.layers.3.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 222 |
+
"language_model.model.layers.3.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 223 |
+
"language_model.model.layers.3.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 224 |
+
"language_model.model.layers.30.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 225 |
+
"language_model.model.layers.30.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 226 |
+
"language_model.model.layers.30.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 227 |
+
"language_model.model.layers.30.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 228 |
+
"language_model.model.layers.30.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 229 |
+
"language_model.model.layers.30.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 230 |
+
"language_model.model.layers.30.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 231 |
+
"language_model.model.layers.30.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 232 |
+
"language_model.model.layers.30.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 233 |
+
"language_model.model.layers.31.input_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 234 |
+
"language_model.model.layers.31.mlp.down_proj.weight": "model-00003-of-00003.safetensors",
|
| 235 |
+
"language_model.model.layers.31.mlp.gate_proj.weight": "model-00003-of-00003.safetensors",
|
| 236 |
+
"language_model.model.layers.31.mlp.up_proj.weight": "model-00003-of-00003.safetensors",
|
| 237 |
+
"language_model.model.layers.31.post_attention_layernorm.weight": "model-00003-of-00003.safetensors",
|
| 238 |
+
"language_model.model.layers.31.self_attn.k_proj.weight": "model-00003-of-00003.safetensors",
|
| 239 |
+
"language_model.model.layers.31.self_attn.o_proj.weight": "model-00003-of-00003.safetensors",
|
| 240 |
+
"language_model.model.layers.31.self_attn.q_proj.weight": "model-00003-of-00003.safetensors",
|
| 241 |
+
"language_model.model.layers.31.self_attn.v_proj.weight": "model-00003-of-00003.safetensors",
|
| 242 |
+
"language_model.model.layers.4.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 243 |
+
"language_model.model.layers.4.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 244 |
+
"language_model.model.layers.4.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 245 |
+
"language_model.model.layers.4.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 246 |
+
"language_model.model.layers.4.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 247 |
+
"language_model.model.layers.4.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 248 |
+
"language_model.model.layers.4.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 249 |
+
"language_model.model.layers.4.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 250 |
+
"language_model.model.layers.4.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 251 |
+
"language_model.model.layers.5.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 252 |
+
"language_model.model.layers.5.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 253 |
+
"language_model.model.layers.5.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 254 |
+
"language_model.model.layers.5.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 255 |
+
"language_model.model.layers.5.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 256 |
+
"language_model.model.layers.5.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 257 |
+
"language_model.model.layers.5.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 258 |
+
"language_model.model.layers.5.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 259 |
+
"language_model.model.layers.5.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 260 |
+
"language_model.model.layers.6.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 261 |
+
"language_model.model.layers.6.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 262 |
+
"language_model.model.layers.6.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 263 |
+
"language_model.model.layers.6.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 264 |
+
"language_model.model.layers.6.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 265 |
+
"language_model.model.layers.6.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 266 |
+
"language_model.model.layers.6.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 267 |
+
"language_model.model.layers.6.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 268 |
+
"language_model.model.layers.6.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 269 |
+
"language_model.model.layers.7.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 270 |
+
"language_model.model.layers.7.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 271 |
+
"language_model.model.layers.7.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 272 |
+
"language_model.model.layers.7.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 273 |
+
"language_model.model.layers.7.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 274 |
+
"language_model.model.layers.7.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 275 |
+
"language_model.model.layers.7.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 276 |
+
"language_model.model.layers.7.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 277 |
+
"language_model.model.layers.7.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 278 |
+
"language_model.model.layers.8.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 279 |
+
"language_model.model.layers.8.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 280 |
+
"language_model.model.layers.8.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 281 |
+
"language_model.model.layers.8.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 282 |
+
"language_model.model.layers.8.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 283 |
+
"language_model.model.layers.8.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 284 |
+
"language_model.model.layers.8.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 285 |
+
"language_model.model.layers.8.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 286 |
+
"language_model.model.layers.8.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 287 |
+
"language_model.model.layers.9.input_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 288 |
+
"language_model.model.layers.9.mlp.down_proj.weight": "model-00001-of-00003.safetensors",
|
| 289 |
+
"language_model.model.layers.9.mlp.gate_proj.weight": "model-00001-of-00003.safetensors",
|
| 290 |
+
"language_model.model.layers.9.mlp.up_proj.weight": "model-00001-of-00003.safetensors",
|
| 291 |
+
"language_model.model.layers.9.post_attention_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 292 |
+
"language_model.model.layers.9.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 293 |
+
"language_model.model.layers.9.self_attn.o_proj.weight": "model-00001-of-00003.safetensors",
|
| 294 |
+
"language_model.model.layers.9.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 295 |
+
"language_model.model.layers.9.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 296 |
+
"language_model.model.norm.weight": "model-00003-of-00003.safetensors",
|
| 297 |
+
"multi_modal_projector.linear_1.bias": "model-00001-of-00003.safetensors",
|
| 298 |
+
"multi_modal_projector.linear_1.weight": "model-00001-of-00003.safetensors",
|
| 299 |
+
"multi_modal_projector.linear_2.bias": "model-00001-of-00003.safetensors",
|
| 300 |
+
"multi_modal_projector.linear_2.weight": "model-00001-of-00003.safetensors",
|
| 301 |
+
"vision_tower.vision_model.embeddings.class_embedding": "model-00001-of-00003.safetensors",
|
| 302 |
+
"vision_tower.vision_model.embeddings.patch_embedding.weight": "model-00001-of-00003.safetensors",
|
| 303 |
+
"vision_tower.vision_model.embeddings.position_embedding.weight": "model-00001-of-00003.safetensors",
|
| 304 |
+
"vision_tower.vision_model.encoder.layers.0.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 305 |
+
"vision_tower.vision_model.encoder.layers.0.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 306 |
+
"vision_tower.vision_model.encoder.layers.0.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 307 |
+
"vision_tower.vision_model.encoder.layers.0.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 308 |
+
"vision_tower.vision_model.encoder.layers.0.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 309 |
+
"vision_tower.vision_model.encoder.layers.0.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 310 |
+
"vision_tower.vision_model.encoder.layers.0.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 311 |
+
"vision_tower.vision_model.encoder.layers.0.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 312 |
+
"vision_tower.vision_model.encoder.layers.0.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 313 |
+
"vision_tower.vision_model.encoder.layers.0.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 314 |
+
"vision_tower.vision_model.encoder.layers.0.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 315 |
+
"vision_tower.vision_model.encoder.layers.0.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 316 |
+
"vision_tower.vision_model.encoder.layers.0.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 317 |
+
"vision_tower.vision_model.encoder.layers.0.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 318 |
+
"vision_tower.vision_model.encoder.layers.0.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 319 |
+
"vision_tower.vision_model.encoder.layers.0.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 320 |
+
"vision_tower.vision_model.encoder.layers.1.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 321 |
+
"vision_tower.vision_model.encoder.layers.1.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 322 |
+
"vision_tower.vision_model.encoder.layers.1.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 323 |
+
"vision_tower.vision_model.encoder.layers.1.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 324 |
+
"vision_tower.vision_model.encoder.layers.1.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 325 |
+
"vision_tower.vision_model.encoder.layers.1.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 326 |
+
"vision_tower.vision_model.encoder.layers.1.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 327 |
+
"vision_tower.vision_model.encoder.layers.1.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 328 |
+
"vision_tower.vision_model.encoder.layers.1.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 329 |
+
"vision_tower.vision_model.encoder.layers.1.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 330 |
+
"vision_tower.vision_model.encoder.layers.1.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 331 |
+
"vision_tower.vision_model.encoder.layers.1.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 332 |
+
"vision_tower.vision_model.encoder.layers.1.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 333 |
+
"vision_tower.vision_model.encoder.layers.1.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 334 |
+
"vision_tower.vision_model.encoder.layers.1.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 335 |
+
"vision_tower.vision_model.encoder.layers.1.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 336 |
+
"vision_tower.vision_model.encoder.layers.10.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 337 |
+
"vision_tower.vision_model.encoder.layers.10.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 338 |
+
"vision_tower.vision_model.encoder.layers.10.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 339 |
+
"vision_tower.vision_model.encoder.layers.10.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 340 |
+
"vision_tower.vision_model.encoder.layers.10.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 341 |
+
"vision_tower.vision_model.encoder.layers.10.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 342 |
+
"vision_tower.vision_model.encoder.layers.10.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 343 |
+
"vision_tower.vision_model.encoder.layers.10.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 344 |
+
"vision_tower.vision_model.encoder.layers.10.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 345 |
+
"vision_tower.vision_model.encoder.layers.10.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 346 |
+
"vision_tower.vision_model.encoder.layers.10.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 347 |
+
"vision_tower.vision_model.encoder.layers.10.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 348 |
+
"vision_tower.vision_model.encoder.layers.10.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 349 |
+
"vision_tower.vision_model.encoder.layers.10.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 350 |
+
"vision_tower.vision_model.encoder.layers.10.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 351 |
+
"vision_tower.vision_model.encoder.layers.10.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 352 |
+
"vision_tower.vision_model.encoder.layers.11.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 353 |
+
"vision_tower.vision_model.encoder.layers.11.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 354 |
+
"vision_tower.vision_model.encoder.layers.11.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 355 |
+
"vision_tower.vision_model.encoder.layers.11.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 356 |
+
"vision_tower.vision_model.encoder.layers.11.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 357 |
+
"vision_tower.vision_model.encoder.layers.11.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 358 |
+
"vision_tower.vision_model.encoder.layers.11.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 359 |
+
"vision_tower.vision_model.encoder.layers.11.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 360 |
+
"vision_tower.vision_model.encoder.layers.11.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 361 |
+
"vision_tower.vision_model.encoder.layers.11.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 362 |
+
"vision_tower.vision_model.encoder.layers.11.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 363 |
+
"vision_tower.vision_model.encoder.layers.11.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 364 |
+
"vision_tower.vision_model.encoder.layers.11.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 365 |
+
"vision_tower.vision_model.encoder.layers.11.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 366 |
+
"vision_tower.vision_model.encoder.layers.11.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 367 |
+
"vision_tower.vision_model.encoder.layers.11.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 368 |
+
"vision_tower.vision_model.encoder.layers.12.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 369 |
+
"vision_tower.vision_model.encoder.layers.12.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 370 |
+
"vision_tower.vision_model.encoder.layers.12.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 371 |
+
"vision_tower.vision_model.encoder.layers.12.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 372 |
+
"vision_tower.vision_model.encoder.layers.12.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 373 |
+
"vision_tower.vision_model.encoder.layers.12.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 374 |
+
"vision_tower.vision_model.encoder.layers.12.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 375 |
+
"vision_tower.vision_model.encoder.layers.12.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 376 |
+
"vision_tower.vision_model.encoder.layers.12.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 377 |
+
"vision_tower.vision_model.encoder.layers.12.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 378 |
+
"vision_tower.vision_model.encoder.layers.12.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 379 |
+
"vision_tower.vision_model.encoder.layers.12.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 380 |
+
"vision_tower.vision_model.encoder.layers.12.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 381 |
+
"vision_tower.vision_model.encoder.layers.12.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 382 |
+
"vision_tower.vision_model.encoder.layers.12.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 383 |
+
"vision_tower.vision_model.encoder.layers.12.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 384 |
+
"vision_tower.vision_model.encoder.layers.13.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 385 |
+
"vision_tower.vision_model.encoder.layers.13.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 386 |
+
"vision_tower.vision_model.encoder.layers.13.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 387 |
+
"vision_tower.vision_model.encoder.layers.13.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 388 |
+
"vision_tower.vision_model.encoder.layers.13.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 389 |
+
"vision_tower.vision_model.encoder.layers.13.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 390 |
+
"vision_tower.vision_model.encoder.layers.13.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 391 |
+
"vision_tower.vision_model.encoder.layers.13.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 392 |
+
"vision_tower.vision_model.encoder.layers.13.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 393 |
+
"vision_tower.vision_model.encoder.layers.13.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 394 |
+
"vision_tower.vision_model.encoder.layers.13.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 395 |
+
"vision_tower.vision_model.encoder.layers.13.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 396 |
+
"vision_tower.vision_model.encoder.layers.13.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 397 |
+
"vision_tower.vision_model.encoder.layers.13.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 398 |
+
"vision_tower.vision_model.encoder.layers.13.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 399 |
+
"vision_tower.vision_model.encoder.layers.13.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 400 |
+
"vision_tower.vision_model.encoder.layers.14.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 401 |
+
"vision_tower.vision_model.encoder.layers.14.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 402 |
+
"vision_tower.vision_model.encoder.layers.14.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 403 |
+
"vision_tower.vision_model.encoder.layers.14.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 404 |
+
"vision_tower.vision_model.encoder.layers.14.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 405 |
+
"vision_tower.vision_model.encoder.layers.14.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 406 |
+
"vision_tower.vision_model.encoder.layers.14.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 407 |
+
"vision_tower.vision_model.encoder.layers.14.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 408 |
+
"vision_tower.vision_model.encoder.layers.14.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 409 |
+
"vision_tower.vision_model.encoder.layers.14.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 410 |
+
"vision_tower.vision_model.encoder.layers.14.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 411 |
+
"vision_tower.vision_model.encoder.layers.14.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 412 |
+
"vision_tower.vision_model.encoder.layers.14.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 413 |
+
"vision_tower.vision_model.encoder.layers.14.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 414 |
+
"vision_tower.vision_model.encoder.layers.14.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 415 |
+
"vision_tower.vision_model.encoder.layers.14.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 416 |
+
"vision_tower.vision_model.encoder.layers.15.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 417 |
+
"vision_tower.vision_model.encoder.layers.15.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 418 |
+
"vision_tower.vision_model.encoder.layers.15.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 419 |
+
"vision_tower.vision_model.encoder.layers.15.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 420 |
+
"vision_tower.vision_model.encoder.layers.15.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 421 |
+
"vision_tower.vision_model.encoder.layers.15.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 422 |
+
"vision_tower.vision_model.encoder.layers.15.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 423 |
+
"vision_tower.vision_model.encoder.layers.15.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 424 |
+
"vision_tower.vision_model.encoder.layers.15.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 425 |
+
"vision_tower.vision_model.encoder.layers.15.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 426 |
+
"vision_tower.vision_model.encoder.layers.15.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 427 |
+
"vision_tower.vision_model.encoder.layers.15.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 428 |
+
"vision_tower.vision_model.encoder.layers.15.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 429 |
+
"vision_tower.vision_model.encoder.layers.15.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 430 |
+
"vision_tower.vision_model.encoder.layers.15.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 431 |
+
"vision_tower.vision_model.encoder.layers.15.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 432 |
+
"vision_tower.vision_model.encoder.layers.16.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 433 |
+
"vision_tower.vision_model.encoder.layers.16.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 434 |
+
"vision_tower.vision_model.encoder.layers.16.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 435 |
+
"vision_tower.vision_model.encoder.layers.16.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 436 |
+
"vision_tower.vision_model.encoder.layers.16.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 437 |
+
"vision_tower.vision_model.encoder.layers.16.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 438 |
+
"vision_tower.vision_model.encoder.layers.16.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 439 |
+
"vision_tower.vision_model.encoder.layers.16.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 440 |
+
"vision_tower.vision_model.encoder.layers.16.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 441 |
+
"vision_tower.vision_model.encoder.layers.16.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 442 |
+
"vision_tower.vision_model.encoder.layers.16.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 443 |
+
"vision_tower.vision_model.encoder.layers.16.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 444 |
+
"vision_tower.vision_model.encoder.layers.16.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 445 |
+
"vision_tower.vision_model.encoder.layers.16.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 446 |
+
"vision_tower.vision_model.encoder.layers.16.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 447 |
+
"vision_tower.vision_model.encoder.layers.16.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 448 |
+
"vision_tower.vision_model.encoder.layers.17.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 449 |
+
"vision_tower.vision_model.encoder.layers.17.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 450 |
+
"vision_tower.vision_model.encoder.layers.17.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 451 |
+
"vision_tower.vision_model.encoder.layers.17.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 452 |
+
"vision_tower.vision_model.encoder.layers.17.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 453 |
+
"vision_tower.vision_model.encoder.layers.17.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 454 |
+
"vision_tower.vision_model.encoder.layers.17.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 455 |
+
"vision_tower.vision_model.encoder.layers.17.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 456 |
+
"vision_tower.vision_model.encoder.layers.17.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 457 |
+
"vision_tower.vision_model.encoder.layers.17.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 458 |
+
"vision_tower.vision_model.encoder.layers.17.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 459 |
+
"vision_tower.vision_model.encoder.layers.17.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 460 |
+
"vision_tower.vision_model.encoder.layers.17.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 461 |
+
"vision_tower.vision_model.encoder.layers.17.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 462 |
+
"vision_tower.vision_model.encoder.layers.17.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 463 |
+
"vision_tower.vision_model.encoder.layers.17.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 464 |
+
"vision_tower.vision_model.encoder.layers.18.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 465 |
+
"vision_tower.vision_model.encoder.layers.18.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 466 |
+
"vision_tower.vision_model.encoder.layers.18.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 467 |
+
"vision_tower.vision_model.encoder.layers.18.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 468 |
+
"vision_tower.vision_model.encoder.layers.18.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 469 |
+
"vision_tower.vision_model.encoder.layers.18.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 470 |
+
"vision_tower.vision_model.encoder.layers.18.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 471 |
+
"vision_tower.vision_model.encoder.layers.18.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 472 |
+
"vision_tower.vision_model.encoder.layers.18.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 473 |
+
"vision_tower.vision_model.encoder.layers.18.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 474 |
+
"vision_tower.vision_model.encoder.layers.18.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 475 |
+
"vision_tower.vision_model.encoder.layers.18.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 476 |
+
"vision_tower.vision_model.encoder.layers.18.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 477 |
+
"vision_tower.vision_model.encoder.layers.18.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 478 |
+
"vision_tower.vision_model.encoder.layers.18.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 479 |
+
"vision_tower.vision_model.encoder.layers.18.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 480 |
+
"vision_tower.vision_model.encoder.layers.19.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 481 |
+
"vision_tower.vision_model.encoder.layers.19.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 482 |
+
"vision_tower.vision_model.encoder.layers.19.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 483 |
+
"vision_tower.vision_model.encoder.layers.19.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 484 |
+
"vision_tower.vision_model.encoder.layers.19.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 485 |
+
"vision_tower.vision_model.encoder.layers.19.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 486 |
+
"vision_tower.vision_model.encoder.layers.19.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 487 |
+
"vision_tower.vision_model.encoder.layers.19.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 488 |
+
"vision_tower.vision_model.encoder.layers.19.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 489 |
+
"vision_tower.vision_model.encoder.layers.19.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 490 |
+
"vision_tower.vision_model.encoder.layers.19.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 491 |
+
"vision_tower.vision_model.encoder.layers.19.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 492 |
+
"vision_tower.vision_model.encoder.layers.19.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 493 |
+
"vision_tower.vision_model.encoder.layers.19.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 494 |
+
"vision_tower.vision_model.encoder.layers.19.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 495 |
+
"vision_tower.vision_model.encoder.layers.19.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 496 |
+
"vision_tower.vision_model.encoder.layers.2.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 497 |
+
"vision_tower.vision_model.encoder.layers.2.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 498 |
+
"vision_tower.vision_model.encoder.layers.2.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 499 |
+
"vision_tower.vision_model.encoder.layers.2.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 500 |
+
"vision_tower.vision_model.encoder.layers.2.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 501 |
+
"vision_tower.vision_model.encoder.layers.2.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 502 |
+
"vision_tower.vision_model.encoder.layers.2.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 503 |
+
"vision_tower.vision_model.encoder.layers.2.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 504 |
+
"vision_tower.vision_model.encoder.layers.2.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 505 |
+
"vision_tower.vision_model.encoder.layers.2.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 506 |
+
"vision_tower.vision_model.encoder.layers.2.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 507 |
+
"vision_tower.vision_model.encoder.layers.2.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 508 |
+
"vision_tower.vision_model.encoder.layers.2.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 509 |
+
"vision_tower.vision_model.encoder.layers.2.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 510 |
+
"vision_tower.vision_model.encoder.layers.2.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 511 |
+
"vision_tower.vision_model.encoder.layers.2.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 512 |
+
"vision_tower.vision_model.encoder.layers.20.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 513 |
+
"vision_tower.vision_model.encoder.layers.20.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 514 |
+
"vision_tower.vision_model.encoder.layers.20.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 515 |
+
"vision_tower.vision_model.encoder.layers.20.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 516 |
+
"vision_tower.vision_model.encoder.layers.20.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 517 |
+
"vision_tower.vision_model.encoder.layers.20.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 518 |
+
"vision_tower.vision_model.encoder.layers.20.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 519 |
+
"vision_tower.vision_model.encoder.layers.20.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 520 |
+
"vision_tower.vision_model.encoder.layers.20.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 521 |
+
"vision_tower.vision_model.encoder.layers.20.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 522 |
+
"vision_tower.vision_model.encoder.layers.20.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 523 |
+
"vision_tower.vision_model.encoder.layers.20.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 524 |
+
"vision_tower.vision_model.encoder.layers.20.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 525 |
+
"vision_tower.vision_model.encoder.layers.20.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 526 |
+
"vision_tower.vision_model.encoder.layers.20.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 527 |
+
"vision_tower.vision_model.encoder.layers.20.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 528 |
+
"vision_tower.vision_model.encoder.layers.21.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 529 |
+
"vision_tower.vision_model.encoder.layers.21.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 530 |
+
"vision_tower.vision_model.encoder.layers.21.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 531 |
+
"vision_tower.vision_model.encoder.layers.21.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 532 |
+
"vision_tower.vision_model.encoder.layers.21.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 533 |
+
"vision_tower.vision_model.encoder.layers.21.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 534 |
+
"vision_tower.vision_model.encoder.layers.21.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 535 |
+
"vision_tower.vision_model.encoder.layers.21.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 536 |
+
"vision_tower.vision_model.encoder.layers.21.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 537 |
+
"vision_tower.vision_model.encoder.layers.21.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 538 |
+
"vision_tower.vision_model.encoder.layers.21.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 539 |
+
"vision_tower.vision_model.encoder.layers.21.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 540 |
+
"vision_tower.vision_model.encoder.layers.21.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 541 |
+
"vision_tower.vision_model.encoder.layers.21.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 542 |
+
"vision_tower.vision_model.encoder.layers.21.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 543 |
+
"vision_tower.vision_model.encoder.layers.21.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 544 |
+
"vision_tower.vision_model.encoder.layers.22.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 545 |
+
"vision_tower.vision_model.encoder.layers.22.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 546 |
+
"vision_tower.vision_model.encoder.layers.22.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 547 |
+
"vision_tower.vision_model.encoder.layers.22.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 548 |
+
"vision_tower.vision_model.encoder.layers.22.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 549 |
+
"vision_tower.vision_model.encoder.layers.22.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 550 |
+
"vision_tower.vision_model.encoder.layers.22.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 551 |
+
"vision_tower.vision_model.encoder.layers.22.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 552 |
+
"vision_tower.vision_model.encoder.layers.22.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 553 |
+
"vision_tower.vision_model.encoder.layers.22.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 554 |
+
"vision_tower.vision_model.encoder.layers.22.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 555 |
+
"vision_tower.vision_model.encoder.layers.22.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 556 |
+
"vision_tower.vision_model.encoder.layers.22.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 557 |
+
"vision_tower.vision_model.encoder.layers.22.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 558 |
+
"vision_tower.vision_model.encoder.layers.22.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 559 |
+
"vision_tower.vision_model.encoder.layers.22.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 560 |
+
"vision_tower.vision_model.encoder.layers.23.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 561 |
+
"vision_tower.vision_model.encoder.layers.23.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 562 |
+
"vision_tower.vision_model.encoder.layers.23.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 563 |
+
"vision_tower.vision_model.encoder.layers.23.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 564 |
+
"vision_tower.vision_model.encoder.layers.23.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 565 |
+
"vision_tower.vision_model.encoder.layers.23.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 566 |
+
"vision_tower.vision_model.encoder.layers.23.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 567 |
+
"vision_tower.vision_model.encoder.layers.23.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 568 |
+
"vision_tower.vision_model.encoder.layers.23.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 569 |
+
"vision_tower.vision_model.encoder.layers.23.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 570 |
+
"vision_tower.vision_model.encoder.layers.23.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 571 |
+
"vision_tower.vision_model.encoder.layers.23.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 572 |
+
"vision_tower.vision_model.encoder.layers.23.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 573 |
+
"vision_tower.vision_model.encoder.layers.23.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 574 |
+
"vision_tower.vision_model.encoder.layers.23.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 575 |
+
"vision_tower.vision_model.encoder.layers.23.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 576 |
+
"vision_tower.vision_model.encoder.layers.3.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 577 |
+
"vision_tower.vision_model.encoder.layers.3.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 578 |
+
"vision_tower.vision_model.encoder.layers.3.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 579 |
+
"vision_tower.vision_model.encoder.layers.3.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 580 |
+
"vision_tower.vision_model.encoder.layers.3.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 581 |
+
"vision_tower.vision_model.encoder.layers.3.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 582 |
+
"vision_tower.vision_model.encoder.layers.3.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 583 |
+
"vision_tower.vision_model.encoder.layers.3.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 584 |
+
"vision_tower.vision_model.encoder.layers.3.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 585 |
+
"vision_tower.vision_model.encoder.layers.3.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 586 |
+
"vision_tower.vision_model.encoder.layers.3.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 587 |
+
"vision_tower.vision_model.encoder.layers.3.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 588 |
+
"vision_tower.vision_model.encoder.layers.3.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 589 |
+
"vision_tower.vision_model.encoder.layers.3.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 590 |
+
"vision_tower.vision_model.encoder.layers.3.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 591 |
+
"vision_tower.vision_model.encoder.layers.3.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 592 |
+
"vision_tower.vision_model.encoder.layers.4.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 593 |
+
"vision_tower.vision_model.encoder.layers.4.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 594 |
+
"vision_tower.vision_model.encoder.layers.4.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 595 |
+
"vision_tower.vision_model.encoder.layers.4.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 596 |
+
"vision_tower.vision_model.encoder.layers.4.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 597 |
+
"vision_tower.vision_model.encoder.layers.4.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 598 |
+
"vision_tower.vision_model.encoder.layers.4.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 599 |
+
"vision_tower.vision_model.encoder.layers.4.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 600 |
+
"vision_tower.vision_model.encoder.layers.4.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 601 |
+
"vision_tower.vision_model.encoder.layers.4.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 602 |
+
"vision_tower.vision_model.encoder.layers.4.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 603 |
+
"vision_tower.vision_model.encoder.layers.4.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 604 |
+
"vision_tower.vision_model.encoder.layers.4.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 605 |
+
"vision_tower.vision_model.encoder.layers.4.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 606 |
+
"vision_tower.vision_model.encoder.layers.4.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 607 |
+
"vision_tower.vision_model.encoder.layers.4.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 608 |
+
"vision_tower.vision_model.encoder.layers.5.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 609 |
+
"vision_tower.vision_model.encoder.layers.5.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 610 |
+
"vision_tower.vision_model.encoder.layers.5.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 611 |
+
"vision_tower.vision_model.encoder.layers.5.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 612 |
+
"vision_tower.vision_model.encoder.layers.5.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 613 |
+
"vision_tower.vision_model.encoder.layers.5.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 614 |
+
"vision_tower.vision_model.encoder.layers.5.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 615 |
+
"vision_tower.vision_model.encoder.layers.5.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 616 |
+
"vision_tower.vision_model.encoder.layers.5.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 617 |
+
"vision_tower.vision_model.encoder.layers.5.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 618 |
+
"vision_tower.vision_model.encoder.layers.5.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 619 |
+
"vision_tower.vision_model.encoder.layers.5.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 620 |
+
"vision_tower.vision_model.encoder.layers.5.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 621 |
+
"vision_tower.vision_model.encoder.layers.5.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 622 |
+
"vision_tower.vision_model.encoder.layers.5.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 623 |
+
"vision_tower.vision_model.encoder.layers.5.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 624 |
+
"vision_tower.vision_model.encoder.layers.6.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 625 |
+
"vision_tower.vision_model.encoder.layers.6.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 626 |
+
"vision_tower.vision_model.encoder.layers.6.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 627 |
+
"vision_tower.vision_model.encoder.layers.6.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 628 |
+
"vision_tower.vision_model.encoder.layers.6.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 629 |
+
"vision_tower.vision_model.encoder.layers.6.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 630 |
+
"vision_tower.vision_model.encoder.layers.6.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 631 |
+
"vision_tower.vision_model.encoder.layers.6.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 632 |
+
"vision_tower.vision_model.encoder.layers.6.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 633 |
+
"vision_tower.vision_model.encoder.layers.6.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 634 |
+
"vision_tower.vision_model.encoder.layers.6.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 635 |
+
"vision_tower.vision_model.encoder.layers.6.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 636 |
+
"vision_tower.vision_model.encoder.layers.6.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 637 |
+
"vision_tower.vision_model.encoder.layers.6.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 638 |
+
"vision_tower.vision_model.encoder.layers.6.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 639 |
+
"vision_tower.vision_model.encoder.layers.6.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 640 |
+
"vision_tower.vision_model.encoder.layers.7.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 641 |
+
"vision_tower.vision_model.encoder.layers.7.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 642 |
+
"vision_tower.vision_model.encoder.layers.7.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 643 |
+
"vision_tower.vision_model.encoder.layers.7.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 644 |
+
"vision_tower.vision_model.encoder.layers.7.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 645 |
+
"vision_tower.vision_model.encoder.layers.7.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 646 |
+
"vision_tower.vision_model.encoder.layers.7.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 647 |
+
"vision_tower.vision_model.encoder.layers.7.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 648 |
+
"vision_tower.vision_model.encoder.layers.7.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 649 |
+
"vision_tower.vision_model.encoder.layers.7.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 650 |
+
"vision_tower.vision_model.encoder.layers.7.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 651 |
+
"vision_tower.vision_model.encoder.layers.7.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 652 |
+
"vision_tower.vision_model.encoder.layers.7.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 653 |
+
"vision_tower.vision_model.encoder.layers.7.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 654 |
+
"vision_tower.vision_model.encoder.layers.7.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 655 |
+
"vision_tower.vision_model.encoder.layers.7.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 656 |
+
"vision_tower.vision_model.encoder.layers.8.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 657 |
+
"vision_tower.vision_model.encoder.layers.8.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 658 |
+
"vision_tower.vision_model.encoder.layers.8.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 659 |
+
"vision_tower.vision_model.encoder.layers.8.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 660 |
+
"vision_tower.vision_model.encoder.layers.8.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 661 |
+
"vision_tower.vision_model.encoder.layers.8.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 662 |
+
"vision_tower.vision_model.encoder.layers.8.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 663 |
+
"vision_tower.vision_model.encoder.layers.8.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 664 |
+
"vision_tower.vision_model.encoder.layers.8.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 665 |
+
"vision_tower.vision_model.encoder.layers.8.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 666 |
+
"vision_tower.vision_model.encoder.layers.8.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 667 |
+
"vision_tower.vision_model.encoder.layers.8.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 668 |
+
"vision_tower.vision_model.encoder.layers.8.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 669 |
+
"vision_tower.vision_model.encoder.layers.8.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 670 |
+
"vision_tower.vision_model.encoder.layers.8.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 671 |
+
"vision_tower.vision_model.encoder.layers.8.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 672 |
+
"vision_tower.vision_model.encoder.layers.9.layer_norm1.bias": "model-00001-of-00003.safetensors",
|
| 673 |
+
"vision_tower.vision_model.encoder.layers.9.layer_norm1.weight": "model-00001-of-00003.safetensors",
|
| 674 |
+
"vision_tower.vision_model.encoder.layers.9.layer_norm2.bias": "model-00001-of-00003.safetensors",
|
| 675 |
+
"vision_tower.vision_model.encoder.layers.9.layer_norm2.weight": "model-00001-of-00003.safetensors",
|
| 676 |
+
"vision_tower.vision_model.encoder.layers.9.mlp.fc1.bias": "model-00001-of-00003.safetensors",
|
| 677 |
+
"vision_tower.vision_model.encoder.layers.9.mlp.fc1.weight": "model-00001-of-00003.safetensors",
|
| 678 |
+
"vision_tower.vision_model.encoder.layers.9.mlp.fc2.bias": "model-00001-of-00003.safetensors",
|
| 679 |
+
"vision_tower.vision_model.encoder.layers.9.mlp.fc2.weight": "model-00001-of-00003.safetensors",
|
| 680 |
+
"vision_tower.vision_model.encoder.layers.9.self_attn.k_proj.bias": "model-00001-of-00003.safetensors",
|
| 681 |
+
"vision_tower.vision_model.encoder.layers.9.self_attn.k_proj.weight": "model-00001-of-00003.safetensors",
|
| 682 |
+
"vision_tower.vision_model.encoder.layers.9.self_attn.out_proj.bias": "model-00001-of-00003.safetensors",
|
| 683 |
+
"vision_tower.vision_model.encoder.layers.9.self_attn.out_proj.weight": "model-00001-of-00003.safetensors",
|
| 684 |
+
"vision_tower.vision_model.encoder.layers.9.self_attn.q_proj.bias": "model-00001-of-00003.safetensors",
|
| 685 |
+
"vision_tower.vision_model.encoder.layers.9.self_attn.q_proj.weight": "model-00001-of-00003.safetensors",
|
| 686 |
+
"vision_tower.vision_model.encoder.layers.9.self_attn.v_proj.bias": "model-00001-of-00003.safetensors",
|
| 687 |
+
"vision_tower.vision_model.encoder.layers.9.self_attn.v_proj.weight": "model-00001-of-00003.safetensors",
|
| 688 |
+
"vision_tower.vision_model.post_layernorm.bias": "model-00001-of-00003.safetensors",
|
| 689 |
+
"vision_tower.vision_model.post_layernorm.weight": "model-00001-of-00003.safetensors",
|
| 690 |
+
"vision_tower.vision_model.pre_layrnorm.bias": "model-00001-of-00003.safetensors",
|
| 691 |
+
"vision_tower.vision_model.pre_layrnorm.weight": "model-00001-of-00003.safetensors"
|
| 692 |
+
}
|
| 693 |
+
}
|
weights/llava-1.5-7b-hf/preprocessor_config.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"crop_size": {
|
| 3 |
+
"height": 336,
|
| 4 |
+
"width": 336
|
| 5 |
+
},
|
| 6 |
+
"do_center_crop": true,
|
| 7 |
+
"do_convert_rgb": true,
|
| 8 |
+
"do_normalize": true,
|
| 9 |
+
"do_rescale": true,
|
| 10 |
+
"do_resize": true,
|
| 11 |
+
"image_mean": [
|
| 12 |
+
0.48145466,
|
| 13 |
+
0.4578275,
|
| 14 |
+
0.40821073
|
| 15 |
+
],
|
| 16 |
+
"image_processor_type": "CLIPImageProcessor",
|
| 17 |
+
"image_std": [
|
| 18 |
+
0.26862954,
|
| 19 |
+
0.26130258,
|
| 20 |
+
0.27577711
|
| 21 |
+
],
|
| 22 |
+
"processor_class": "LlavaProcessor",
|
| 23 |
+
"resample": 3,
|
| 24 |
+
"rescale_factor": 0.00392156862745098,
|
| 25 |
+
"size": {
|
| 26 |
+
"shortest_edge": 336
|
| 27 |
+
}
|
| 28 |
+
}
|
weights/llava-1.5-7b-hf/processor_config.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_token": "<image>",
|
| 3 |
+
"num_additional_image_tokens": 1,
|
| 4 |
+
"patch_size": 14,
|
| 5 |
+
"processor_class": "LlavaProcessor",
|
| 6 |
+
"vision_feature_select_strategy": "default"
|
| 7 |
+
}
|
weights/llava-1.5-7b-hf/special_tokens_map.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"bos_token": {
|
| 3 |
+
"content": "<s>",
|
| 4 |
+
"lstrip": false,
|
| 5 |
+
"normalized": false,
|
| 6 |
+
"rstrip": false,
|
| 7 |
+
"single_word": false
|
| 8 |
+
},
|
| 9 |
+
"eos_token": {
|
| 10 |
+
"content": "</s>",
|
| 11 |
+
"lstrip": false,
|
| 12 |
+
"normalized": false,
|
| 13 |
+
"rstrip": false,
|
| 14 |
+
"single_word": false
|
| 15 |
+
},
|
| 16 |
+
"pad_token": {
|
| 17 |
+
"content": "<pad>",
|
| 18 |
+
"lstrip": false,
|
| 19 |
+
"normalized": false,
|
| 20 |
+
"rstrip": false,
|
| 21 |
+
"single_word": false
|
| 22 |
+
},
|
| 23 |
+
"unk_token": {
|
| 24 |
+
"content": "<unk>",
|
| 25 |
+
"lstrip": false,
|
| 26 |
+
"normalized": false,
|
| 27 |
+
"rstrip": false,
|
| 28 |
+
"single_word": false
|
| 29 |
+
}
|
| 30 |
+
}
|
weights/llava-1.5-7b-hf/tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
weights/llava-1.5-7b-hf/tokenizer_config.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_bos_token": true,
|
| 3 |
+
"add_eos_token": false,
|
| 4 |
+
"add_prefix_space": null,
|
| 5 |
+
"added_tokens_decoder": {
|
| 6 |
+
"0": {
|
| 7 |
+
"content": "<unk>",
|
| 8 |
+
"lstrip": false,
|
| 9 |
+
"normalized": false,
|
| 10 |
+
"rstrip": false,
|
| 11 |
+
"single_word": false,
|
| 12 |
+
"special": true
|
| 13 |
+
},
|
| 14 |
+
"1": {
|
| 15 |
+
"content": "<s>",
|
| 16 |
+
"lstrip": false,
|
| 17 |
+
"normalized": false,
|
| 18 |
+
"rstrip": false,
|
| 19 |
+
"single_word": false,
|
| 20 |
+
"special": true
|
| 21 |
+
},
|
| 22 |
+
"2": {
|
| 23 |
+
"content": "</s>",
|
| 24 |
+
"lstrip": false,
|
| 25 |
+
"normalized": false,
|
| 26 |
+
"rstrip": false,
|
| 27 |
+
"single_word": false,
|
| 28 |
+
"special": true
|
| 29 |
+
},
|
| 30 |
+
"32000": {
|
| 31 |
+
"content": "<image>",
|
| 32 |
+
"lstrip": false,
|
| 33 |
+
"normalized": false,
|
| 34 |
+
"rstrip": false,
|
| 35 |
+
"single_word": false,
|
| 36 |
+
"special": true
|
| 37 |
+
},
|
| 38 |
+
"32001": {
|
| 39 |
+
"content": "<pad>",
|
| 40 |
+
"lstrip": false,
|
| 41 |
+
"normalized": false,
|
| 42 |
+
"rstrip": false,
|
| 43 |
+
"single_word": false,
|
| 44 |
+
"special": true
|
| 45 |
+
}
|
| 46 |
+
},
|
| 47 |
+
"bos_token": "<s>",
|
| 48 |
+
"clean_up_tokenization_spaces": false,
|
| 49 |
+
"eos_token": "</s>",
|
| 50 |
+
"extra_special_tokens": {
|
| 51 |
+
"image_token": "<image>"
|
| 52 |
+
},
|
| 53 |
+
"image_token": "<image>",
|
| 54 |
+
"legacy": false,
|
| 55 |
+
"model_max_length": 1000000000000000019884624838656,
|
| 56 |
+
"pad_token": "<pad>",
|
| 57 |
+
"padding_side": "left",
|
| 58 |
+
"processor_class": "LlavaProcessor",
|
| 59 |
+
"sp_model_kwargs": {},
|
| 60 |
+
"tokenizer_class": "LlamaTokenizer",
|
| 61 |
+
"trust_remote_code": false,
|
| 62 |
+
"unk_token": "<unk>",
|
| 63 |
+
"use_default_system_prompt": false
|
| 64 |
+
}
|
weights/merged_models/adapter/config.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "TextAdapter",
|
| 3 |
+
"_diffusers_version": "0.24.0",
|
| 4 |
+
"_name_or_path": "pretrained_weights/lavi-bridge/llama2_unet/adapter",
|
| 5 |
+
"in_dim": 4096,
|
| 6 |
+
"int_dim": 2432,
|
| 7 |
+
"out_dim": 768
|
| 8 |
+
}
|
weights/merged_models/unet/config.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "UNet2DConditionModel",
|
| 3 |
+
"_diffusers_version": "0.24.0",
|
| 4 |
+
"_name_or_path": "pretrained_weights/stable-diffusion",
|
| 5 |
+
"act_fn": "silu",
|
| 6 |
+
"addition_embed_type": null,
|
| 7 |
+
"addition_embed_type_num_heads": 64,
|
| 8 |
+
"addition_time_embed_dim": null,
|
| 9 |
+
"attention_head_dim": 8,
|
| 10 |
+
"attention_type": "default",
|
| 11 |
+
"block_out_channels": [
|
| 12 |
+
320,
|
| 13 |
+
640,
|
| 14 |
+
1280,
|
| 15 |
+
1280
|
| 16 |
+
],
|
| 17 |
+
"center_input_sample": false,
|
| 18 |
+
"class_embed_type": null,
|
| 19 |
+
"class_embeddings_concat": false,
|
| 20 |
+
"conv_in_kernel": 3,
|
| 21 |
+
"conv_out_kernel": 3,
|
| 22 |
+
"cross_attention_dim": 768,
|
| 23 |
+
"cross_attention_norm": null,
|
| 24 |
+
"down_block_types": [
|
| 25 |
+
"CrossAttnDownBlock2D",
|
| 26 |
+
"CrossAttnDownBlock2D",
|
| 27 |
+
"CrossAttnDownBlock2D",
|
| 28 |
+
"DownBlock2D"
|
| 29 |
+
],
|
| 30 |
+
"downsample_padding": 1,
|
| 31 |
+
"dropout": 0.0,
|
| 32 |
+
"dual_cross_attention": false,
|
| 33 |
+
"encoder_hid_dim": null,
|
| 34 |
+
"encoder_hid_dim_type": null,
|
| 35 |
+
"flip_sin_to_cos": true,
|
| 36 |
+
"freq_shift": 0,
|
| 37 |
+
"in_channels": 4,
|
| 38 |
+
"layers_per_block": 2,
|
| 39 |
+
"mid_block_only_cross_attention": null,
|
| 40 |
+
"mid_block_scale_factor": 1,
|
| 41 |
+
"mid_block_type": "UNetMidBlock2DCrossAttn",
|
| 42 |
+
"norm_eps": 1e-05,
|
| 43 |
+
"norm_num_groups": 32,
|
| 44 |
+
"num_attention_heads": null,
|
| 45 |
+
"num_class_embeds": null,
|
| 46 |
+
"only_cross_attention": false,
|
| 47 |
+
"out_channels": 4,
|
| 48 |
+
"projection_class_embeddings_input_dim": null,
|
| 49 |
+
"resnet_out_scale_factor": 1.0,
|
| 50 |
+
"resnet_skip_time_act": false,
|
| 51 |
+
"resnet_time_scale_shift": "default",
|
| 52 |
+
"reverse_transformer_layers_per_block": null,
|
| 53 |
+
"sample_size": 64,
|
| 54 |
+
"time_cond_proj_dim": null,
|
| 55 |
+
"time_embedding_act_fn": null,
|
| 56 |
+
"time_embedding_dim": null,
|
| 57 |
+
"time_embedding_type": "positional",
|
| 58 |
+
"timestep_post_act": null,
|
| 59 |
+
"transformer_layers_per_block": 1,
|
| 60 |
+
"up_block_types": [
|
| 61 |
+
"UpBlock2D",
|
| 62 |
+
"CrossAttnUpBlock2D",
|
| 63 |
+
"CrossAttnUpBlock2D",
|
| 64 |
+
"CrossAttnUpBlock2D"
|
| 65 |
+
],
|
| 66 |
+
"upcast_attention": false,
|
| 67 |
+
"use_linear_projection": false
|
| 68 |
+
}
|
weights/stable-diffusion/scheduler/.ipynb_checkpoints/scheduler_config-checkpoint.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "PNDMScheduler",
|
| 3 |
+
"_diffusers_version": "0.2.2",
|
| 4 |
+
"beta_end": 0.012,
|
| 5 |
+
"beta_schedule": "scaled_linear",
|
| 6 |
+
"beta_start": 0.00085,
|
| 7 |
+
"num_train_timesteps": 1000,
|
| 8 |
+
"skip_prk_steps": true
|
| 9 |
+
}
|
weights/stable-diffusion/scheduler/scheduler_config.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "PNDMScheduler",
|
| 3 |
+
"_diffusers_version": "0.7.0.dev0",
|
| 4 |
+
"beta_end": 0.012,
|
| 5 |
+
"beta_schedule": "scaled_linear",
|
| 6 |
+
"beta_start": 0.00085,
|
| 7 |
+
"num_train_timesteps": 1000,
|
| 8 |
+
"set_alpha_to_one": false,
|
| 9 |
+
"skip_prk_steps": true,
|
| 10 |
+
"steps_offset": 1,
|
| 11 |
+
"trained_betas": null,
|
| 12 |
+
"clip_sample": false
|
| 13 |
+
}
|
weights/stable-diffusion/vae/config.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "AutoencoderKL",
|
| 3 |
+
"_diffusers_version": "0.2.2",
|
| 4 |
+
"act_fn": "silu",
|
| 5 |
+
"block_out_channels": [
|
| 6 |
+
128,
|
| 7 |
+
256,
|
| 8 |
+
512,
|
| 9 |
+
512
|
| 10 |
+
],
|
| 11 |
+
"down_block_types": [
|
| 12 |
+
"DownEncoderBlock2D",
|
| 13 |
+
"DownEncoderBlock2D",
|
| 14 |
+
"DownEncoderBlock2D",
|
| 15 |
+
"DownEncoderBlock2D"
|
| 16 |
+
],
|
| 17 |
+
"in_channels": 3,
|
| 18 |
+
"latent_channels": 4,
|
| 19 |
+
"layers_per_block": 2,
|
| 20 |
+
"out_channels": 3,
|
| 21 |
+
"sample_size": 512,
|
| 22 |
+
"scaling_factor": 0.18215,
|
| 23 |
+
"up_block_types": [
|
| 24 |
+
"UpDecoderBlock2D",
|
| 25 |
+
"UpDecoderBlock2D",
|
| 26 |
+
"UpDecoderBlock2D",
|
| 27 |
+
"UpDecoderBlock2D"
|
| 28 |
+
]
|
| 29 |
+
}
|