tencent-rosetta / rosetta /modeling.py
multimodalart's picture
multimodalart HF Staff
Initial Rosetta multimodal demo
22d08f8 verified
Raw
History Blame Contribute Delete
83.4 kB
import math
from argparse import Namespace
from contextlib import nullcontext
from dataclasses import dataclass
from typing import Any, Dict, List, Optional, Tuple, Union
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn.attention.flex_attention import BlockMask, flex_attention
from transformers.cache_utils import Cache, StaticCache
from transformers.utils.generic import ModelOutput
from .autoencoder import (
TimestepEmbedder,
normal_weight_reset_parameters,
project_in_layer,
project_out_layer,
)
from .configuration import MultimodalConfig, TransformerConfig
from .utils import PRECISION_TO_TYPE, default, is_package_version
@dataclass
class MultimodalModelOutput(ModelOutput):
losses: Optional[dict] = None
logits: Optional[torch.Tensor] = None
past_key_values: Optional[Cache] = None
diffusion_prediction: Optional[torch.Tensor] = None
class RMSNorm(nn.Module):
def __init__(self, hidden_size, eps=1e-6, device=None, dtype=None):
factory_kwargs = {"device": device, "dtype": dtype}
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size, **factory_kwargs))
self.variance_epsilon = eps
def reset_parameters(self):
nn.init.ones_(self.weight)
def forward(self, hidden_states):
input_dtype = hidden_states.dtype
hidden_states = hidden_states.to(torch.float32)
variance = hidden_states.pow(2).mean(-1, keepdim=True)
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
return self.weight * hidden_states.to(input_dtype)
def extra_repr(self):
return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
def get_vision_position_ids(
start_position: int,
grid_thw: List[int],
spatial_merge_size: int = 1,
device: Optional[torch.device] = None,
) -> torch.Tensor:
t, h, w = grid_thw[0], grid_thw[1], grid_thw[2]
if isinstance(t, torch.Tensor):
t, h, w = t.item(), h.item(), w.item()
llm_grid_t = t
llm_grid_h = h // spatial_merge_size
llm_grid_w = w // spatial_merge_size
image_seq_length = llm_grid_h * llm_grid_w * llm_grid_t
position_width = torch.arange(start_position, start_position + llm_grid_w, device=device).repeat(
llm_grid_h * llm_grid_t
)
position_height = torch.arange(start_position, start_position + llm_grid_h, device=device).repeat_interleave(
llm_grid_w * llm_grid_t
)
position_temporal = torch.full((image_seq_length,), start_position, device=device, dtype=torch.long)
vision_position_ids = torch.stack([position_temporal, position_height, position_width], dim=0)
return vision_position_ids
def get_text_position_ids(
length: int,
start_position: int = 0,
device: Optional[torch.device] = None,
) -> torch.Tensor:
return torch.arange(length, device=device).view(1, -1).expand(3, -1) + start_position
def get_interleaved_mrope_index(
image_infos: List[Optional[List[Tuple[slice, Tuple[int, int], dict]]]],
seq_len: int,
spatial_merge_size: int,
sample_offsets: Optional[torch.Tensor] = None,
device: Optional[torch.device] = None,
) -> torch.Tensor:
if image_infos is None:
image_infos = [None]
batch_size = len(image_infos)
position_ids = torch.zeros(3, batch_size, seq_len, dtype=torch.int64, device=device)
for i, image_info in enumerate(image_infos):
llm_pos_ids_list = []
current_pos = 0
st = 0
if image_info is None:
image_info = []
for sec_slice, (h, w), _ in image_info:
img_start = sec_slice.start
text_len = img_start - st
if text_len > 0:
llm_pos_ids_list.append(get_text_position_ids(text_len, current_pos, device))
current_pos += text_len
grid_thw = [1, h, w]
llm_pos_ids_list.append(
get_vision_position_ids(current_pos, grid_thw, spatial_merge_size=spatial_merge_size, device=device)
)
llm_grid_h = h // spatial_merge_size
llm_grid_w = w // spatial_merge_size
current_pos += max(llm_grid_h, llm_grid_w)
st = img_start + llm_grid_h * llm_grid_w
if st < seq_len:
llm_pos_ids_list.append(get_text_position_ids(seq_len - st, current_pos, device))
if len(llm_pos_ids_list) == 0:
llm_pos_ids_list.append(get_text_position_ids(seq_len, 0, device))
llm_positions = torch.cat(llm_pos_ids_list, dim=1).reshape(3, -1)
if llm_positions.shape[1] < seq_len:
padding = llm_positions[:, -1:].expand(3, seq_len - llm_positions.shape[1])
llm_positions = torch.cat([llm_positions, padding], dim=1)
elif llm_positions.shape[1] > seq_len:
llm_positions = llm_positions[:, :seq_len]
position_ids[:, i, :] = llm_positions
if sample_offsets is not None and sample_offsets[i] is not None:
offsets = sample_offsets[i].tolist()
if len(offsets) >= 2:
assert offsets[0] == 0, "First offset must be 0"
assert offsets[-1] <= seq_len, "Last offset must be less than or equal to seq_len"
for start, end in zip(offsets[:-1], offsets[1:]):
assert end > start, "End must be greater than start"
seg_base = position_ids[:, i, start].clone()
position_ids[:, i, start:end] = position_ids[:, i, start:end] - seg_base.view(3, 1)
return position_ids
def apply_interleaved_mrope(freqs: torch.Tensor, mrope_section: List[int]) -> torch.Tensor:
freqs_t = freqs[0].clone()
for dim, offset in enumerate((1, 2), start=1):
length = mrope_section[dim] * 3
idx = slice(offset, length, 3)
freqs_t[..., idx] = freqs[dim, ..., idx]
return freqs_t
def get_batch_interleaved_mrope(
image_infos: List[List[Tuple[slice, Tuple[int, int]]]],
seq_len: int,
n_elem: int,
mrope_section: List[int],
device: Optional[torch.device] = None,
base: float = 10000.0,
base_rescale_factor: float = 1.0,
spatial_merge_size: int = 1,
sample_offsets: Optional[torch.Tensor] = None,
) -> Tuple[torch.Tensor, torch.Tensor]:
position_ids = get_interleaved_mrope_index(image_infos, seq_len, spatial_merge_size, sample_offsets, device)
position_ids = position_ids.to(device)
if base_rescale_factor != 1.0:
base *= base_rescale_factor ** (n_elem / (n_elem - 2))
theta = 1.0 / (base ** (torch.arange(0, n_elem, 2, device=device).float() / n_elem))
inv_freq_expanded = theta[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1)
position_ids_expanded = position_ids[:, :, None, :].float()
device_type = device.type if isinstance(device.type, str) and device.type != "mps" else "cpu"
with torch.autocast(device_type=device_type, enabled=False):
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(2, 3)
freqs = apply_interleaved_mrope(freqs, mrope_section)
emb = torch.cat((freqs, freqs), dim=-1)
cos = emb.cos()
sin = emb.sin()
return cos, sin
def apply_rope(
x: torch.Tensor,
cos: torch.Tensor,
sin: torch.Tensor,
unsqueeze_dim=-3,
) -> torch.Tensor:
head_size = x.size(-1)
x1 = x[..., : head_size // 2]
x2 = x[..., head_size // 2:]
rotated = torch.cat((-x2, x1), dim=-1)
if cos.dim() > 1:
cos = cos.unsqueeze(unsqueeze_dim)
sin = sin.unsqueeze(unsqueeze_dim)
return (x * cos) + (rotated * sin)
class CachedRoPE(object):
def __init__(self, config):
self._config = config
self.cos_cache = None
self.sin_cache = None
self.seq_len = None
self.rope_media_info = None
@torch.autocast(device_type='cuda', enabled=False)
def __call__(self, seq_len, device, rope_media_info=None, input_pos=None, sample_offsets=None):
if (self.seq_len != seq_len) or (self.rope_media_info != rope_media_info):
self.cos_cache, self.sin_cache = get_batch_interleaved_mrope(
image_infos=rope_media_info,
seq_len=seq_len,
mrope_section=self._config.mrope_section,
n_elem=self._config.attention_head_size,
device=device,
base=self._config.rope_theta,
base_rescale_factor=1.0,
sample_offsets=sample_offsets
)
if input_pos is None:
cos, sin = self.cos_cache, self.sin_cache
else:
assert input_pos.dim() == 2, f"{input_pos.shape=}"
head_size = self.cos_cache.size(-1)
cos = torch.gather(self.cos_cache, dim=1, index=input_pos.unsqueeze(-1).expand(-1, -1, head_size))
sin = torch.gather(self.sin_cache, dim=1, index=input_pos.unsqueeze(-1).expand(-1, -1, head_size))
return cos, sin
# Attention and KV cache layers
flex_attention = torch.compile(flex_attention, dynamic=False)
BatchRaggedMedia = Union[torch.Tensor, list[Union[torch.Tensor, list[torch.Tensor]]]]
BatchRaggedTensor = Union[torch.Tensor, list[torch.Tensor]]
class MultimodalStaticCache(StaticCache):
def __init__(self, *args, **kwargs):
self.dynamic = kwargs.pop("dynamic", False)
super().__init__(*args, **kwargs)
def update(
self,
key_states: torch.Tensor,
value_states: torch.Tensor,
layer_idx: int,
cache_kwargs: Optional[Dict[str, Any]] = None,
) -> Tuple[torch.Tensor, torch.Tensor]:
cache_position = cache_kwargs.get("cache_position")
if is_package_version("transformers", "<=", "4.53.3"):
if self.key_cache[layer_idx].device != key_states.device:
self.key_cache[layer_idx] = self.key_cache[layer_idx].to(key_states.device)
self.value_cache[layer_idx] = self.value_cache[layer_idx].to(value_states.device)
k_out = self.key_cache[layer_idx] # max_batch_size x num_key_value_heads x max_cache_len x head_dim
v_out = self.value_cache[layer_idx] # max_batch_size x num_key_value_heads x max_cache_len x head_dim
else:
if self.layers[layer_idx].keys is None:
self.layers[layer_idx].lazy_initialization(value_states)
k_out = self.layers[layer_idx].keys
v_out = self.layers[layer_idx].values
key_states = key_states.to(k_out.dtype)
value_states = value_states.to(v_out.dtype)
if cache_position is None:
k_out.copy_(key_states)
v_out.copy_(value_states)
else:
if cache_position.dim() == 1:
k_out.index_copy_(2, cache_position, key_states)
v_out.index_copy_(2, cache_position, value_states)
if self.dynamic:
end = cache_position[-1].item() + 1
k_out = k_out[:, :, :end]
v_out = v_out[:, :, :end]
else:
# first step of gen_text or all steps of gen_image
assert cache_position.dim() == 2, f"multiple batch dims not yet {cache_position.shape=}"
batch_size, idx_size = cache_position.shape
assert batch_size == k_out.size(0)
assert batch_size == v_out.size(0)
assert batch_size == key_states.size(0)
assert batch_size == value_states.size(0)
for i in range(batch_size):
unbatched_dim = 1
k_out[i].index_copy_(unbatched_dim, cache_position[i], key_states[i])
v_out[i].index_copy_(unbatched_dim, cache_position[i], value_states[i])
if self.dynamic:
assert len(cache_position) == 1
# end = cache_position[0, -1].item() + 1
end = int(cache_position[0, -1]) + 1 # Tensor.item()导致图中断
k_out = k_out[:, :, :end]
v_out = v_out[:, :, :end]
return k_out, v_out
def get_device(tensor: BatchRaggedMedia):
if isinstance(tensor, torch.Tensor):
return tensor.device
elif isinstance(tensor, list):
return get_device(tensor[0])
else:
raise ValueError(f"Unsupported type for get_device: {type(tensor)}")
class CausalSelfAttention(nn.Module):
def __init__(
self,
config: MultimodalConfig,
layer_idx: int,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
) -> None:
factory_kwargs = {'device': device, 'dtype': dtype}
super().__init__()
self._config = config
self.layer_idx = layer_idx
self.q_proj = nn.Linear(
config.hidden_size, config.num_attention_heads * config.attention_head_size,
bias=False, **factory_kwargs
)
self.k_proj = nn.Linear(
config.hidden_size, config.num_kv_heads * config.attention_head_size,
bias=False, **factory_kwargs
)
self.v_proj = nn.Linear(
config.hidden_size, config.num_kv_heads * config.attention_head_size,
bias=False, **factory_kwargs
)
self.o_proj = nn.Linear(
config.attention_head_size * config.num_attention_heads, config.hidden_size,
bias=False, **factory_kwargs
)
self.query_layernorm = config.norm_class(config.attention_head_size, eps=config.norm_eps, **factory_kwargs)
self.key_layernorm = config.norm_class(config.attention_head_size, eps=config.norm_eps, **factory_kwargs)
def forward(
self,
hidden_states: torch.Tensor,
attention_mask: Optional[torch.Tensor] = None,
rotary_position_embeddings: tuple[torch.Tensor, torch.Tensor] = None,
input_pos: Optional[torch.Tensor] = None,
past_key_values: Optional[MultimodalStaticCache] = None,
) -> torch.Tensor:
bsz, seqlen, _ = hidden_states.size() # batch size, sequence length, embedding dimensionality (n_embd)
head_size = self._config.attention_head_size
n_q_head = self._config.num_attention_heads
n_kv_head = self._config.num_kv_heads
q_per_kv = n_q_head // n_kv_head
new_q = self.q_proj(hidden_states).view(bsz, seqlen, n_kv_head, q_per_kv, head_size)
new_k = self.k_proj(hidden_states).view(bsz, seqlen, n_kv_head, 1, head_size)
new_v = self.v_proj(hidden_states).view(bsz, seqlen, n_kv_head, 1, head_size)
q, k, v = map(lambda x: x.permute(0, 2, 3, 1, 4), [new_q, new_k, new_v])
q = q.reshape(bsz, -1, seqlen, head_size) # (B, n_q_head, T, hs)
k = k.reshape(bsz, -1, seqlen, head_size) # (B, n_kv_head, T, hs)
v = v.reshape(bsz, -1, seqlen, head_size) # (B, n_kv_head, T, hs)
q = self.query_layernorm(q)
k = self.key_layernorm(k)
q = apply_rope(q, *rotary_position_embeddings)
k = apply_rope(k, *rotary_position_embeddings)
q = q.to(v.dtype)
k = k.to(v.dtype)
if input_pos is not None:
cache_kwargs = {"cache_position": input_pos}
k, v = past_key_values.update(k, v, self.layer_idx, cache_kwargs)
# If restore from cache, kv_seqlen >= seqlen
kv_seqlen = k.size(2)
# maybe repeat k and v if for the non multi-head attention cases
# training: flash attention requires it
# inference: multi-query would require a full kv cache so avoid it to limit its memory usage
if n_kv_head != n_q_head and (input_pos is None or q_per_kv != 1):
k = k.unsqueeze(dim=2).expand(-1, -1, q_per_kv, -1, -1).reshape(bsz, -1, kv_seqlen, head_size)
v = v.unsqueeze(dim=2).expand(-1, -1, q_per_kv, -1, -1).reshape(bsz, -1, kv_seqlen, head_size)
y = self.scaled_dot_product_attention(q, k, v, attention_mask)
y = y.reshape(bsz, seqlen, head_size * n_q_head) # re-assemble all head outputs side by side
# output projection
return self.o_proj(y)
def scaled_dot_product_attention(
self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, mask: Optional[torch.Tensor] = None
) -> torch.Tensor:
# q, k, v: (bsz, n_head, seqlen, head_size)
scale = 1.0 / math.sqrt(self._config.attention_head_size)
if isinstance(mask, BlockMask):
q = q.to(dtype=v.dtype)
k = k.to(dtype=v.dtype)
y = flex_attention(q, k, v, block_mask=mask, scale=scale)
else:
y = torch.nn.functional.scaled_dot_product_attention(
q, k, v, attn_mask=mask, dropout_p=0.0, scale=scale,
# If q only has one token (typically in AR model decoding stage), we should use full attention.
is_causal=mask is None and q.size(2) > 1
)
return y.transpose(1, 2)
class CausalSelfAttentionMoT(CausalSelfAttention):
def __init__(
self,
config: MultimodalConfig,
config_mot_gen: MultimodalConfig,
layer_idx: int,
mot_und_frozen: bool = False,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
) -> None:
factory_kwargs = {'device': device, 'dtype': dtype}
super().__init__(config, layer_idx, dtype, device)
self.mot_und_frozen = mot_und_frozen
self.q_proj_mot_gen = nn.Linear(
config_mot_gen.hidden_size, config_mot_gen.num_attention_heads * config_mot_gen.attention_head_size,
bias=False, **factory_kwargs
)
self.k_proj_mot_gen = nn.Linear(
config_mot_gen.hidden_size, config_mot_gen.num_kv_heads * config_mot_gen.attention_head_size,
bias=False, **factory_kwargs
)
self.v_proj_mot_gen = nn.Linear(
config_mot_gen.hidden_size, config_mot_gen.num_kv_heads * config_mot_gen.attention_head_size,
bias=False, **factory_kwargs
)
self.o_proj_mot_gen = nn.Linear(
config_mot_gen.attention_head_size * config_mot_gen.num_attention_heads, config_mot_gen.hidden_size,
bias=False, **factory_kwargs
)
self.query_layernorm_mot_gen = config_mot_gen.norm_class(config_mot_gen.attention_head_size, eps=config_mot_gen.norm_eps, **factory_kwargs)
self.key_layernorm_mot_gen = config_mot_gen.norm_class(config_mot_gen.attention_head_size, eps=config_mot_gen.norm_eps, **factory_kwargs)
if self.mot_und_frozen:
self.q_proj.eval()
self.q_proj.requires_grad_(False)
self.k_proj.eval()
self.k_proj.requires_grad_(False)
self.v_proj.eval()
self.v_proj.requires_grad_(False)
self.o_proj.eval()
self.o_proj.requires_grad_(False)
self.query_layernorm.eval()
self.query_layernorm.requires_grad_(False)
self.key_layernorm.eval()
self.key_layernorm.requires_grad_(False)
def forward(
self,
hidden_states: tuple[torch.Tensor, torch.Tensor],
attention_mask: Optional[torch.Tensor] = None,
rotary_position_embeddings: tuple[torch.Tensor, torch.Tensor] = None,
input_pos: Optional[torch.Tensor] = None,
past_key_values: Optional[MultimodalStaticCache] = None,
und_token_indices: Optional[torch.Tensor] = None,
gen_token_indices: Optional[torch.Tensor] = None,
) -> torch.Tensor:
und_hidden_states, gen_hidden_states = hidden_states
bsz = und_hidden_states.shape[0]
und_seqlen, gen_seqlen = und_hidden_states.shape[1], gen_hidden_states.shape[1]
head_size = self._config.attention_head_size
n_q_head = self._config.num_attention_heads
n_kv_head = self._config.num_kv_heads
q_per_kv = n_q_head // n_kv_head
q = self.q_proj(und_hidden_states).view(bsz, -1, n_kv_head, q_per_kv, head_size)
k = self.k_proj(und_hidden_states).view(bsz, -1, n_kv_head, 1, head_size)
v = self.v_proj(und_hidden_states).view(bsz, -1, n_kv_head, 1, head_size)
gen_q = self.q_proj_mot_gen(gen_hidden_states).view(bsz, -1, n_kv_head, q_per_kv, head_size)
gen_k = self.k_proj_mot_gen(gen_hidden_states).view(bsz, -1, n_kv_head, 1, head_size)
gen_v = self.v_proj_mot_gen(gen_hidden_states).view(bsz, -1, n_kv_head, 1, head_size)
q, k, v = map(lambda x: x.permute(0, 2, 3, 1, 4), [q, k, v])
gen_q, gen_k, gen_v = map(lambda x: x.permute(0, 2, 3, 1, 4), [gen_q, gen_k, gen_v])
# [bsz, h, seqlen, head_size]
q = q.reshape(bsz, n_q_head, und_seqlen, head_size)
k = k.reshape(bsz, n_kv_head, und_seqlen, head_size)
v = v.reshape(bsz, n_kv_head, und_seqlen, head_size)
gen_q = gen_q.reshape(bsz, n_q_head, gen_seqlen, head_size)
gen_k = gen_k.reshape(bsz, n_kv_head, gen_seqlen, head_size)
gen_v = gen_v.reshape(bsz, n_kv_head, gen_seqlen, head_size)
# Scatter understanding and generation tokens for rope
und_token_indices_q = und_token_indices.unsqueeze(-1).unsqueeze(1).expand(-1, q.size(1), -1, q.size(-1))
gen_token_indices_q = gen_token_indices.unsqueeze(-1).unsqueeze(1).expand(-1, q.size(1), -1, q.size(-1))
und_token_indices_kv = und_token_indices.unsqueeze(-1).unsqueeze(1).expand(-1, k.size(1), -1, k.size(-1))
gen_token_indices_kv = gen_token_indices.unsqueeze(-1).unsqueeze(1).expand(-1, k.size(1), -1, k.size(-1))
def _scatter(und_src, gen_src, und_token_indices, gen_token_indices, n_head):
target = torch.zeros((bsz, n_head, und_seqlen+gen_seqlen, head_size), dtype=und_src.dtype, device=und_src.device)
target.scatter_(dim=2, index=und_token_indices, src=und_src)
target.scatter_(dim=2, index=gen_token_indices, src=gen_src)
return target
q_merge = _scatter(q, gen_q, und_token_indices_q, gen_token_indices_q, n_q_head)
k_merge = _scatter(k, gen_k, und_token_indices_kv, gen_token_indices_kv, n_kv_head)
v_merge = _scatter(v, gen_v, und_token_indices_kv, gen_token_indices_kv, n_kv_head)
q_ = torch.zeros_like(q_merge)
k_ = torch.zeros_like(k_merge)
q_.scatter_(dim=2, index=und_token_indices_q, src=self.query_layernorm(q_merge.gather(2, und_token_indices_q)).to(q_.dtype))
q_.scatter_(dim=2, index=gen_token_indices_q, src=self.query_layernorm_mot_gen(q_merge.gather(2, gen_token_indices_q)).to(q_.dtype))
k_.scatter_(dim=2, index=und_token_indices_kv, src=self.key_layernorm(k_merge.gather(2, und_token_indices_kv)).to(k_.dtype))
k_.scatter_(dim=2, index=gen_token_indices_kv, src=self.key_layernorm_mot_gen(k_merge.gather(2, gen_token_indices_kv)).to(k_.dtype))
q_merge = q_
k_merge = k_
# apply rotary position embeddings
q_merge = apply_rope(q_merge, *rotary_position_embeddings)
k_merge = apply_rope(k_merge, *rotary_position_embeddings)
q_merge = q_merge.to(v_merge.dtype)
k_merge = k_merge.to(v_merge.dtype)
# Restore from kv_cache and update
if input_pos is not None:
cache_kwargs = {"cache_position": input_pos}
k_merge, v_merge = past_key_values.update(k_merge, v_merge, self.layer_idx, cache_kwargs)
# If restore from cache, kv_seqlen >= seqlen
kv_seqlen = k_merge.size(2)
# maybe repeat k and v if for the non multi-head attention cases
# training: flash attention requires it
# inference: multi-query would require a full kv cache so avoid it to limit its memory usage
if n_kv_head != n_q_head and (input_pos is None or q_per_kv != 1):
k_merge = k_merge.unsqueeze(dim=2).expand(-1, -1, q_per_kv, -1, -1).reshape(bsz, -1, kv_seqlen, head_size)
v_merge = v_merge.unsqueeze(dim=2).expand(-1, -1, q_per_kv, -1, -1).reshape(bsz, -1, kv_seqlen, head_size)
y = self.scaled_dot_product_attention(q_merge, k_merge, v_merge, attention_mask)
# re-assemble all head outputs side by side
y = y.reshape(bsz, -1, head_size * n_q_head)
core_attn_out = y.gather(dim=1, index=und_token_indices.unsqueeze(-1).expand(-1, -1, y.size(-1)))
gen_core_attn_out = y.gather(dim=1, index=gen_token_indices.unsqueeze(-1).expand(-1, -1, y.size(-1)))
und_hidden_states = self.o_proj(core_attn_out)
gen_hidden_states = self.o_proj_mot_gen(gen_core_attn_out)
return und_hidden_states, gen_hidden_states
class MLP(nn.Module):
def __init__(
self,
config: TransformerConfig,
layer_idx: int,
is_shared_mlp: bool = False,
is_moe: bool = False,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
):
factory_kwargs = {"device": device, "dtype": dtype}
super().__init__()
self._config = config
self.layer_idx = layer_idx
self.ffn_hidden_size = config.ffn_hidden_size
if is_shared_mlp or is_moe:
self.ffn_hidden_size = config.moe_ffn_hidden_size
self.gate_proj = nn.Linear(config.hidden_size, self.ffn_hidden_size, bias=False, **factory_kwargs)
self.up_proj = nn.Linear(config.hidden_size, self.ffn_hidden_size, bias=False, **factory_kwargs)
self.down_proj = nn.Linear(self.ffn_hidden_size, config.hidden_size, bias=False, **factory_kwargs)
self.act_fn = config.act_class()
def forward(self, x):
up = self.up_proj(x)
gate = self.gate_proj(x)
out = self.down_proj(up * self.act_fn(gate))
return out
class DeepSeekMoEGate(nn.Module):
def __init__(
self,
config: TransformerConfig,
layer_idx: int,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
):
factory_kwargs = {"device": device, "dtype": dtype}
super().__init__()
self._config = config
self.layer_idx = layer_idx
self.num_experts = config.num_experts
self.top_k = config.moe_topk
if config.use_modality_routing:
assert config.num_text_experts > 0 and config.num_vit_experts > 0 and config.num_vae_experts > 0, \
"num_text_experts / num_vit_experts / num_vae_experts must be set when use_modality_routing=True"
assert config.num_text_experts + config.num_vit_experts + config.num_vae_experts == self.num_experts, \
f"num_text({config.num_text_experts}) + num_vit({config.num_vit_experts}) + num_vae({config.num_vae_experts}) " \
f"must equal num_experts({self.num_experts})"
self.wg_text = nn.Linear(config.hidden_size, config.num_text_experts, bias=False, **factory_kwargs)
self.wg_vit = nn.Linear(config.hidden_size, config.num_vit_experts, bias=False, **factory_kwargs)
self.wg_vae = nn.Linear(config.hidden_size, config.num_vae_experts, bias=False, **factory_kwargs)
else:
self.wg = nn.Linear(config.hidden_size, self.num_experts, bias=False, **factory_kwargs)
def _score(self, logits):
return F.softmax(logits.float(), dim=1)
def _forward_modality_routing(self, flat_hidden, bsz, seqlen, token_modalities):
N = bsz * seqlen
cfg = self._config
n_text = cfg.num_text_experts
n_vit = cfg.num_vit_experts
n_vae = cfg.num_vae_experts
vit_offset = n_text
vae_offset = n_text + n_vit
flat_mod = token_modalities.reshape(-1)
topk_weights = torch.zeros(N, self.top_k, dtype=torch.float32, device=flat_hidden.device)
topk_idx = torch.zeros(N, self.top_k, dtype=torch.long, device=flat_hidden.device)
for mod_id, wg, offset, n_local in (
(0, self.wg_text, 0, n_text),
(1, self.wg_vit, vit_offset, n_vit),
(2, self.wg_vae, vae_offset, n_vae),
):
mask = (flat_mod == mod_id)
if not mask.any():
continue
h_m = flat_hidden[mask].to(wg.weight.dtype)
logits_m = wg(h_m)
scores_m = self._score(logits_m)
tw_m, ti_m = torch.topk(scores_m, self.top_k, dim=-1)
topk_weights[mask] = tw_m
topk_idx[mask] = ti_m + offset
if self.top_k > 1:
denom = topk_weights.sum(dim=-1, keepdim=True).clamp(
min=torch.finfo(topk_weights.dtype).eps
)
topk_weights = topk_weights / denom
return topk_weights, topk_idx
def forward(self, hidden_states, token_modalities=None):
bsz, seqlen, hdim = hidden_states.size()
hidden_states = hidden_states.reshape(-1, hidden_states.size(-1))
if self._config.use_modality_routing:
if token_modalities is None:
N = hidden_states.shape[0]
token_modalities = torch.zeros(N, dtype=torch.long, device=hidden_states.device)
return self._forward_modality_routing(hidden_states, bsz, seqlen, token_modalities)
logits = self.wg(hidden_states.to(self.wg.weight.dtype))
scores = F.softmax(logits, dim=1)
topk_weights, topk_idx = torch.topk(scores, self.top_k, dim=-1)
if self.top_k > 1:
denominator = topk_weights.sum(dim=-1, keepdim=True).clamp(min=torch.finfo(topk_weights.dtype).eps)
topk_weights = topk_weights / denominator
return topk_weights, topk_idx
class DeepSeekMoE(nn.Module):
def __init__(
self,
config: TransformerConfig,
layer_idx: Optional[int] = None,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
):
factory_kwargs = {"device": device, "dtype": dtype}
super().__init__()
self._config = config
self.layer_idx = layer_idx
self.num_experts = config.num_experts
self.top_k = config.moe_topk
self.gate = DeepSeekMoEGate(config, layer_idx, device=device, dtype=torch.float32)
self.experts = nn.ModuleList(
[MLP(config, layer_idx, is_moe=True, **factory_kwargs)
for _ in range(self.num_experts)]
)
self.shared_mlp = MLP(config, layer_idx=layer_idx, is_shared_mlp=True, **factory_kwargs)
def forward(self, hidden_states: torch.Tensor, token_modalities: Optional[torch.Tensor] = None) -> torch.Tensor:
bsz, seqlen, hdim = hidden_states.size()
input_hidden_states = hidden_states
with torch.autocast('cuda', enabled=False):
topk_weights, topk_idx = self.gate(hidden_states, token_modalities)
topk_weights = topk_weights.to(hidden_states.dtype)
flat_topk_idx = topk_idx.view(-1)
hidden_states = hidden_states.view(-1, hdim)
hidden_states = hidden_states.repeat_interleave(self.top_k, dim=0)
expert_outputs = torch.zeros_like(hidden_states, dtype=hidden_states.dtype, device=hidden_states.device)
for i in range(self.num_experts):
expert_mask = (flat_topk_idx == i)
selected_inputs = hidden_states[expert_mask]
expert_output = self.experts[i](selected_inputs)
expert_outputs[expert_mask] = expert_output.to(hidden_states.dtype)
weighted_outputs = (expert_outputs.view(
bsz * seqlen, self.top_k, hdim) * topk_weights.unsqueeze(-1)).sum(dim=1)
weighted_outputs = weighted_outputs.to(hidden_states.dtype).view(bsz, seqlen, hdim)
shared_out = self.shared_mlp(input_hidden_states)
cfg = self._config
if (
token_modalities is not None
and getattr(cfg, 'shield_step', 0) > 0
and getattr(cfg, '_current_training_iter', 0) < cfg.shield_step
):
text_mask = (token_modalities == 0).unsqueeze(-1)
shared_out = shared_out * text_mask + shared_out.detach() * (~text_mask)
return weighted_outputs + shared_out
class MultimodalDecoderLayer(nn.Module):
def __init__(
self,
config: MultimodalConfig,
layer_idx: int,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
):
factory_kwargs = {'device': device, 'dtype': dtype}
super().__init__()
self._config = config
self.hidden_size = config.hidden_size
self.layer_idx = layer_idx
self.self_attn = CausalSelfAttention(config, layer_idx, **factory_kwargs)
self.input_layernorm = config.norm_class(config.hidden_size, eps=config.norm_eps, **factory_kwargs)
self.post_attention_layernorm = config.norm_class(config.hidden_size, eps=config.norm_eps, **factory_kwargs)
self.mlp = DeepSeekMoE(config, layer_idx, **factory_kwargs)
def forward(
self,
hidden_states: torch.Tensor,
attention_mask: Optional[torch.Tensor] = None,
rotary_position_embeddings: tuple[torch.Tensor, torch.Tensor] = None,
input_pos: Optional[torch.Tensor] = None,
past_key_values: Optional[MultimodalStaticCache] = None,
und_token_indices: Optional[torch.Tensor] = None,
gen_token_indices: Optional[torch.Tensor] = None,
token_modalities: Optional[torch.Tensor] = None,
):
residual = hidden_states
hidden_states = self.input_layernorm(hidden_states)
hidden_states = self.self_attn(
hidden_states,
attention_mask=attention_mask,
rotary_position_embeddings=rotary_position_embeddings,
input_pos=input_pos,
past_key_values=past_key_values,
)
hidden_states = residual + hidden_states
residual = hidden_states
hidden_states = self.post_attention_layernorm(hidden_states)
hidden_states = self.mlp(hidden_states, token_modalities=token_modalities) \
if token_modalities is not None and hasattr(self.mlp, 'gate') and hasattr(self.mlp.gate, 'wg_text') \
else self.mlp(hidden_states)
hidden_states = residual + hidden_states
return hidden_states
class MultimodalMoTDecoderLayer(MultimodalDecoderLayer):
def __init__(
self,
config: MultimodalConfig,
layer_idx: int,
mot_und_frozen: bool = False,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
gen_config: Optional[MultimodalConfig] = None,
):
factory_kwargs = {'device': device, 'dtype': dtype}
gen_config = gen_config if gen_config is not None else config
super().__init__(config, layer_idx, dtype, device)
self.mot_und_frozen = mot_und_frozen
self.self_attn = CausalSelfAttentionMoT(config, gen_config, layer_idx, mot_und_frozen, **factory_kwargs)
self.input_layernorm_mot_gen = gen_config.norm_class(
gen_config.hidden_size, eps=gen_config.norm_eps, **factory_kwargs
)
self.post_attention_layernorm_mot_gen = gen_config.norm_class(
gen_config.hidden_size, eps=gen_config.norm_eps, **factory_kwargs
)
self.mlp_mot_gen = DeepSeekMoE(gen_config, layer_idx, **factory_kwargs)
if self.mot_und_frozen:
self.input_layernorm.eval()
self.input_layernorm.requires_grad_(False)
self.post_attention_layernorm.eval()
self.post_attention_layernorm.requires_grad_(False)
self.mlp.eval()
self.mlp.requires_grad_(False)
@staticmethod
def _attach_zero_param_dependency(hidden_states, modules):
dep = None
for module in modules:
for param in module.parameters():
if param.requires_grad and param.numel() > 0:
term = param.reshape(-1)[0] * 0.0
dep = term if dep is None else dep + term
return hidden_states if dep is None else hidden_states + dep.to(hidden_states.dtype)
def _und_branch_modules(self):
return (
self.input_layernorm,
self.post_attention_layernorm,
self.mlp,
self.self_attn.q_proj,
self.self_attn.k_proj,
self.self_attn.v_proj,
self.self_attn.o_proj,
self.self_attn.query_layernorm,
self.self_attn.key_layernorm,
)
def _gen_branch_modules(self):
return (
self.input_layernorm_mot_gen,
self.post_attention_layernorm_mot_gen,
self.mlp_mot_gen,
self.self_attn.q_proj_mot_gen,
self.self_attn.k_proj_mot_gen,
self.self_attn.v_proj_mot_gen,
self.self_attn.o_proj_mot_gen,
self.self_attn.query_layernorm_mot_gen,
self.self_attn.key_layernorm_mot_gen,
)
def forward(
self,
hidden_states: torch.Tensor,
attention_mask: Optional[torch.Tensor] = None,
rotary_position_embeddings: tuple[torch.Tensor, torch.Tensor] = None,
input_pos: Optional[torch.Tensor] = None,
past_key_values: Optional[MultimodalStaticCache] = None,
und_token_indices: Optional[torch.Tensor] = None,
gen_token_indices: Optional[torch.Tensor] = None,
token_modalities: Optional[torch.Tensor] = None,
):
und_hidden_states, gen_hidden_states = hidden_states
und_residual, gen_residual = und_hidden_states, gen_hidden_states
# Pre-attn norm
und_hidden_states = self.input_layernorm(und_hidden_states)
gen_hidden_states = self.input_layernorm_mot_gen(gen_hidden_states)
# Self attention
core_attn_out = self.self_attn(
(und_hidden_states, gen_hidden_states),
attention_mask=attention_mask,
rotary_position_embeddings=rotary_position_embeddings,
input_pos=input_pos,
past_key_values=past_key_values,
und_token_indices=und_token_indices,
gen_token_indices=gen_token_indices,
)
und_hidden_states, gen_hidden_states = core_attn_out
und_hidden_states = und_residual + und_hidden_states
gen_hidden_states = gen_residual + gen_hidden_states
# Pre-mlp norm
und_residual, gen_residual = und_hidden_states, gen_hidden_states
und_hidden_states = self.post_attention_layernorm(und_hidden_states)
gen_hidden_states = self.post_attention_layernorm_mot_gen(gen_hidden_states)
# Keep inactive MoT branch parameters connected to the loss with zero
# gradients, so fixed-modality shard groups follow the same FSDP path.
und_has_tokens = und_hidden_states.nelement() != 0
gen_has_tokens = gen_hidden_states.nelement() != 0
if und_has_tokens:
und_hidden_states = self.mlp(und_hidden_states)
if gen_has_tokens:
gen_hidden_states = self.mlp_mot_gen(gen_hidden_states)
if und_has_tokens and not gen_has_tokens:
und_hidden_states = self._attach_zero_param_dependency(
und_hidden_states, self._gen_branch_modules()
)
if gen_has_tokens and not und_has_tokens:
gen_hidden_states = self._attach_zero_param_dependency(
gen_hidden_states, self._und_branch_modules()
)
und_hidden_states = und_residual + und_hidden_states
gen_hidden_states = gen_residual + gen_hidden_states
return (und_hidden_states, gen_hidden_states)
class MultimodalModelBase(nn.Module):
def get_input_embeddings(self):
return self.model["embed_tokens"]
def get_output_embeddings(self):
return getattr(self, "lm_head", None)
def __post_init__(
self,
config: MultimodalConfig,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
args: Namespace = None,
initialize_weights: bool = True,
):
factory_kwargs = {'device': device, 'dtype': dtype}
# Set as protected member to avoid conflict with potential parent classes
self._config = config
if self._config.use_mot:
self._config_mot_gen = self._config.to_mot_gen_config()
self._dtype = dtype
# For inference, args can be None
self.args = args or Namespace()
self.vit_frozen = getattr(args, "vit_frozen", True)
self.vit_precision = PRECISION_TO_TYPE[default(getattr(args, "vit_precision", None), dtype)]
self.mot_und_frozen = getattr(args, "mot_und_frozen", False)
self.lm_frozen = getattr(args, "lm_frozen", False)
self.moe_aux_loss_coeff = getattr(args, "moe_aux_loss_coeff", 0.0)
# ======================================
# Define vae projector modules
# ======================================
if config.use_vae:
vae_hidden_size = self._config_mot_gen.hidden_size if config.use_mot else config.hidden_size
vae_config = self._config_mot_gen if config.use_mot else config
if config.use_timestep_token:
self.timestep_emb = TimestepEmbedder(hidden_size=vae_hidden_size, **factory_kwargs)
# One for patch_embed and other for final_layer
self.time_embed = TimestepEmbedder(hidden_size=vae_hidden_size, **factory_kwargs)
self.time_embed_2 = TimestepEmbedder(hidden_size=vae_hidden_size, **factory_kwargs)
self.patch_embed = project_in_layer(vae_config, **factory_kwargs)
self.final_layer = project_out_layer(vae_config, **factory_kwargs)
# ======================================
# Define vit and aligner modules
# ======================================
if config.use_vit:
from .visual_encoder import load_vit
self.vit = load_vit(
vision_model_type=config.vit_type,
vision_model_precision=self.vit_precision,
device=device,
require_grad=not self.vit_frozen,
eval_mode=self.vit_frozen,
vision_model_params=config.vit_config,
# Set True to skip default ViT loading if the main checkpoint already
# contains the vision weights.
no_load_pretrained=(
getattr(args, "vit_no_load_pretrained", False)
or (device is not None and torch.device(device).type == "meta")
),
)
self.vit_context = torch.no_grad if self.vit_frozen else nullcontext
if self.vit_frozen and config.vit_type == "qwen3vl-vit-for-0.6b":
trainable_modules = []
merger_fc2 = getattr(getattr(self.vit, "merger", None), "linear_fc2", None)
if merger_fc2 is not None:
trainable_modules.append(merger_fc2)
for merger in getattr(self.vit, "deepstack_merger_list", []):
fc2 = getattr(merger, "linear_fc2", None)
if fc2 is not None:
trainable_modules.append(fc2)
if trainable_modules:
for module in trainable_modules:
module.requires_grad_(True)
module.train()
self.vit_context = nullcontext
# ======================================
# Define language modules
# ======================================
if config.use_mot:
self.model = nn.ModuleDict(
dict(
embed_tokens=nn.Embedding(config.vocab_size, config.hidden_size, **factory_kwargs),
layers=nn.ModuleList([
MultimodalMoTDecoderLayer(
config, block_idx, self.mot_und_frozen,
gen_config=self._config_mot_gen,
**factory_kwargs
)
for block_idx in range(config.num_layers)
]),
norm=config.norm_class(config.hidden_size, eps=config.norm_eps, **factory_kwargs),
)
)
else:
self.model = nn.ModuleDict(
dict(
embed_tokens=nn.Embedding(config.vocab_size, config.hidden_size, **factory_kwargs),
layers=nn.ModuleList([
MultimodalDecoderLayer(config, block_idx, **factory_kwargs)
for block_idx in range(config.num_layers)
]),
norm=config.norm_class(config.hidden_size, eps=config.norm_eps, **factory_kwargs),
)
)
if self.lm_frozen:
# Freeze entire LLM backbone: embed_tokens, all transformer layers, norm.
# Used for Stage 2.1 where only the vision-language connector is trained.
self.model.eval()
self.model.requires_grad_(False)
# ====================== Finish model building =====================
# Initialize cached rope, supporting automatic cache update
self.cached_rope = CachedRoPE(config)
self.use_rope_sample_offsets = getattr(args, "use_rope_sample_offsets", False)
# Initialize weights if needed
self._prepare_reset_parameters()
if initialize_weights:
for name, module in self.named_modules():
if hasattr(module, "reset_parameters"):
module.reset_parameters()
def _prepare_reset_parameters(self):
# Globally set Linear and Embedding init methods to normal
for module in self.modules():
if isinstance(module, (nn.Linear, nn.Embedding)):
module.reset_parameters = normal_weight_reset_parameters(
std=self._config.init_std, bias_type="zeros").__get__(module)
for name, module in self.named_modules():
if hasattr(module, "prepare_reset_parameters"):
module.prepare_reset_parameters()
@property
def dtype(self):
"""Get the dtype of the model parameters."""
if self._dtype is not None:
return self._dtype
# Fallback to getting dtype from model parameters
try:
return next(self.parameters()).dtype
except StopIteration:
# If no parameters, try buffers
try:
return next(self.buffers()).dtype
except StopIteration:
# Default fallback
return torch.float32
def scatter_to_hidden_states(
self,
src: torch.Tensor,
index: torch.Tensor,
hidden_states: torch.Tensor,
gen_hidden_states: Optional[torch.Tensor] = None,
dim: int = 1,
slice_idx: Optional[int] = None,
) -> Union[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:
n_embd = src.shape[-1]
hidden_target = hidden_states if slice_idx is None else hidden_states[slice_idx:slice_idx + 1]
if n_embd == hidden_states.shape[-1]:
hidden_target.scatter_(dim=dim, index=index, src=src)
else:
assert gen_hidden_states is not None, "gen_hidden_states is required when hidden dim of src and hidden_states differ"
assert gen_hidden_states.shape[-1] == n_embd, \
f"Expect gen_hidden_states and src to have same hidden_size, but got {gen_hidden_states.shape[-1]} and {n_embd}"
gen_target = gen_hidden_states if slice_idx is None else gen_hidden_states[slice_idx:slice_idx + 1]
gen_target.scatter_(dim=dim, index=index, src=src)
return hidden_states, gen_hidden_states
def instantiate_vae_image_tokens(
self,
hidden_states: Optional[Union[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]],
timesteps: BatchRaggedTensor,
medias: BatchRaggedMedia,
media_mask: torch.Tensor,
):
if hidden_states is None:
hidden_size = self._config_mot_gen.hidden_size if self._config.use_mot else self._config.hidden_size
if isinstance(medias, list):
emb_list = []
for i in range(len(medias)):
t_i = timesteps[i:i+1] if isinstance(timesteps, torch.Tensor) else timesteps[i]
t_emb_i = self.time_embed(t_i)
img_emb_i, _, _ = self.patch_embed(medias[i], t_emb_i)
emb_list.append(img_emb_i)
max_tokens = max(e.size(1) for e in emb_list)
padded_img_emb = torch.zeros(len(medias), max_tokens, hidden_size, device=emb_list[0].device, dtype=emb_list[0].dtype)
for i, emb in enumerate(emb_list):
padded_img_emb[i, :emb.size(1), :] = emb[0]
timestep_emb = self.timestep_emb(timesteps).reshape(len(medias), -1, hidden_size)
hidden_states = torch.cat([timestep_emb, padded_img_emb], dim=1)
return hidden_states
t_emb = self.time_embed(timesteps)
image_emb, _, _ = self.patch_embed(medias, t_emb)
hidden_size = self._config_mot_gen.hidden_size if self._config.use_mot else self._config.hidden_size
timestep_emb = self.timestep_emb(timesteps).reshape(medias.size(0), -1, hidden_size)
hidden_states = torch.cat([timestep_emb, image_emb], dim=1)
return hidden_states
if isinstance(hidden_states, tuple):
hidden_states, gen_hidden_states = hidden_states
else:
gen_hidden_states = None
bsz, seqlen, n_embd = hidden_states.shape
assert isinstance(medias, (torch.Tensor, list)), f"images should be BatchRaggedMedia, got {type(medias)}"
if isinstance(medias, torch.Tensor):
assert medias.ndim in [4, 5], f"images should be a 4-D or 5-D tensor, got {medias.ndim}-D tensor"
assert isinstance(timesteps, torch.Tensor), f"timesteps should be 1-D tensor, got {type(timesteps)}"
index = torch.arange(seqlen, device=hidden_states.device).unsqueeze(0).repeat(bsz, 1) # (bsz, seqlen)
t_emb = self.time_embed(timesteps) # (bsz, n_embd)
media_seq, *_ = self.patch_embed(medias, t_emb) # (bsz, num_patches, n_embd)
media_index = index.masked_select(media_mask.bool()).reshape(bsz, -1) # (bsz, num_patches)
assert media_seq.size(1) == media_index.size(1), \
f"image_seq ({list(media_seq.size())}) has inconsistent shape with index ({list(media_index.size())})"
n_embd = media_seq.shape[-1]
index_exp = media_index.unsqueeze(-1).repeat(1, 1, n_embd)
hidden_states, gen_hidden_states = self.scatter_to_hidden_states(
media_seq.to(hidden_states.dtype), index_exp, hidden_states, gen_hidden_states
)
else: # list
index = torch.arange(seqlen, device=hidden_states.device).unsqueeze(0).repeat(bsz, 1) # (bsz, seqlen)
for i in range(len(medias)):
media_i = medias[i]
t_i = timesteps[i:i+1] if isinstance(timesteps, torch.Tensor) else timesteps[i]
t_i_emb = self.time_embed(t_i) # (n_i, n_embd)
if isinstance(media_i, torch.Tensor):
media_i_seq, *_ = self.patch_embed(media_i, t_i_emb) # (n_i, num_patches, n_embd)
elif isinstance(media_i, list):
media_i_seq_list = []
for j in range(len(media_i)):
media_ij = media_i[j].unsqueeze(0)
assert media_ij.ndim in [4, 5], \
f"image_ij should have size of (1, C, H, W) or (1, C, D, H, W), got {list(media_ij.size())}"
media_ij_seq, *_ = self.patch_embed(media_ij, t_i_emb[j:j + 1]) # (1, num_patches, n_embd)
media_i_seq_list.append(media_ij_seq)
media_i_seq = torch.cat(media_i_seq_list, dim=1) # (1, Σj num_patches_j, n_embd)
else:
raise TypeError(f"image_i should be a 4-D or 5-D tensor or a list, got {type(media_i)}")
media_i_index = index[i:i + 1].masked_select(media_mask[i:i + 1].bool()).reshape(1, -1) # (1, img_seqlen)
n_embd = media_i_seq.shape[-1]
media_i_index_exp = media_i_index.unsqueeze(-1).repeat(1, 1, n_embd)
media_i_seq_flat = media_i_seq.reshape(1, -1, n_embd)
assert media_i_seq_flat.shape[1] == media_i_index_exp.shape[1], \
f"media_i_seq_flat ({list(media_i_seq_flat.size())}) has inconsistent shape with media_i_index_exp ({list(media_i_index_exp.size())})"
hidden_states, gen_hidden_states = self.scatter_to_hidden_states(
media_i_seq_flat.to(hidden_states.dtype), media_i_index_exp, hidden_states, gen_hidden_states,
slice_idx=i,
)
if gen_hidden_states is not None:
return hidden_states, gen_hidden_states
return hidden_states
def _forward_vision_encoder(self, images, **image_kwargs):
with self.vit_context():
image_embeds = self.vit(images, **image_kwargs)
if isinstance(image_embeds, tuple):
image_embeds, deepstack_image_embeds = image_embeds
else:
deepstack_image_embeds = None
image_embeds = image_embeds.last_hidden_state
return image_embeds, deepstack_image_embeds
@staticmethod
def _accumulate_deepstack_embeds(all_embeds, new_embeds):
if new_embeds is None:
return all_embeds
if all_embeds is None:
all_embeds = [[] for _ in range(len(new_embeds))]
for layer_idx, layer_embeds in enumerate(new_embeds):
all_embeds[layer_idx].append(layer_embeds)
return all_embeds
def instantiate_vit_image_tokens(
self,
hidden_states: torch.Tensor,
images: torch.Tensor | list[torch.Tensor],
image_masks: torch.Tensor,
image_kwargs: dict[str, torch.Tensor],
):
if isinstance(hidden_states, tuple):
hidden_states, gen_hidden_states = hidden_states
else:
gen_hidden_states = None
bsz, seqlen, _ = hidden_states.shape
index = torch.arange(seqlen, device=hidden_states.device).unsqueeze(0).repeat(bsz, 1)
if isinstance(images, torch.Tensor):
assert images.ndim in [3, 4, 5], f"images should be a 3-D, 4-D, or 5-D tensor, got {images.ndim}-D tensor."
if images.ndim in [4, 5]:
bsz, n = images.shape[:2]
images = images.view(bsz * n, *images.shape[2:])
image_kwargs = image_kwargs if image_kwargs is not None else {}
for k, v in image_kwargs.items():
image_kwargs[k] = v.reshape(bsz * n, *v.shape[2:])
else:
n = 1
image_embeds, deepstack_image_embeds = self._forward_vision_encoder(images, **image_kwargs)
image_seqlen, n_embd = image_embeds.size(1), image_embeds.size(-1)
image_scatter_index = index.masked_select(image_masks.bool()).reshape(bsz, -1)
index = image_scatter_index.unsqueeze(-1).repeat(1, 1, n_embd)
src = image_embeds.reshape(bsz, n * image_seqlen, n_embd)
assert src.shape[1] == index.shape[1], \
f"src ({list(src.size())}) has inconsistent shape with index ({list(index.size())})"
hidden_states, gen_hidden_states = self.scatter_to_hidden_states(
src.to(hidden_states.dtype), index, hidden_states, gen_hidden_states
)
elif isinstance(images, list):
all_deepstack_embeds = None
for i, (image, image_mask) in enumerate(zip(images, image_masks)):
start_index = 0
image_scatter_index = index[i].masked_select(image_mask.bool()).reshape(1, -1)
for j, singel_image in enumerate(image):
cur_kwargs = {k: v[i][j:j+1] for k, v in image_kwargs.items()} if image_kwargs is not None else {}
if isinstance(singel_image, list):
image_embed_list = []
for _single_image in singel_image:
image_embed, deepstack_image_embeds = self._forward_vision_encoder(_single_image, **cur_kwargs)
image_embed_list.append(image_embed)
all_deepstack_embeds = self._accumulate_deepstack_embeds(all_deepstack_embeds, deepstack_image_embeds)
image_embed = torch.cat(image_embed_list, dim=1)
if image_embed.ndim == 3:
n, image_seqlen, n_embd = image_embed.shape
image_embed = image_embed.reshape(n * image_seqlen, n_embd)
else:
n_embd = image_embed.shape[-1]
else:
image_embed, deepstack_image_embeds = self._forward_vision_encoder(singel_image, **cur_kwargs)
all_deepstack_embeds = self._accumulate_deepstack_embeds(all_deepstack_embeds, deepstack_image_embeds)
if image_embed.ndim == 3:
n, image_seqlen, n_embd = image_embed.shape
image_embed = image_embed.reshape(n * image_seqlen, n_embd)
else:
n_embd = image_embed.shape[-1]
image_scatter_index_j = image_scatter_index[:, start_index:start_index + image_embed.shape[0]]
image_scatter_index_j = image_scatter_index_j.unsqueeze(-1).repeat(1, 1, n_embd)
image_embed = image_embed.reshape(1, -1, n_embd)
start_index += image_embed.shape[1]
assert image_scatter_index_j.shape[1] == image_embed.shape[1], \
f"image_scatter_index_j ({list(image_scatter_index_j.size())}) has inconsistent shape with image_embed ({list(image_embed.size())})"
hidden_states, gen_hidden_states = self.scatter_to_hidden_states(
image_embed.to(hidden_states.dtype), image_scatter_index_j, hidden_states, gen_hidden_states,
slice_idx=i,
)
if all_deepstack_embeds is not None:
deepstack_image_embeds = []
for layer_embeds_list in all_deepstack_embeds:
valid_embeds = [e for e in layer_embeds_list if e is not None]
if len(valid_embeds) == 0:
continue
flattened_embeds = []
for e in valid_embeds:
if isinstance(e, list):
flattened_embeds.extend([item for item in e if isinstance(item, torch.Tensor)])
elif isinstance(e, torch.Tensor):
flattened_embeds.append(e)
if len(flattened_embeds) == 1:
deepstack_image_embeds.append(flattened_embeds[0])
elif len(flattened_embeds) > 1:
deepstack_image_embeds.append(torch.cat(flattened_embeds, dim=0))
else:
deepstack_image_embeds = None
else:
raise ValueError(f"und_images should be Tensor or List, but got {type(images)}")
if gen_hidden_states is not None:
return (hidden_states, gen_hidden_states), deepstack_image_embeds
return hidden_states, deepstack_image_embeds
def instantiate_continuous_tokens(
self,
hidden_states: torch.Tensor,
emb_layer: nn.Module,
scatter_src: Optional[BatchRaggedTensor] = None,
scatter_index: Optional[BatchRaggedTensor] = None,
):
if isinstance(hidden_states, tuple):
hidden_states, gen_hidden_states = hidden_states
else:
gen_hidden_states = None
bsz, seqlen, _ = hidden_states.shape
if isinstance(scatter_src, list):
for i, scatter_src_i in enumerate(scatter_src):
src = emb_layer(scatter_src_i) # (n, n_embd)
n_embd = src.shape[-1]
index = scatter_index[i].unsqueeze(0).unsqueeze(-1).repeat(1, 1, n_embd)
src = src.reshape(1, -1, n_embd)
assert index.shape[1] == src.shape[1], \
f"index ({list(index.size())}) has inconsistent shape with src ({list(src.size())})"
hidden_states, gen_hidden_states = self.scatter_to_hidden_states(
src.to(hidden_states.dtype), index, hidden_states, gen_hidden_states,
slice_idx=i,
)
else:
src = emb_layer(scatter_src.reshape(-1)) # (bsz * n, n_embd)
n_embd = src.shape[-1]
index = scatter_index.unsqueeze(-1).repeat(1, 1, n_embd)
src = src.reshape(bsz, -1, n_embd)
assert index.shape[1] == src.shape[1], \
f"index ({list(index.size())}) has inconsistent shape with src ({list(src.size())})"
hidden_states, gen_hidden_states = self.scatter_to_hidden_states(
src.to(hidden_states.dtype), index, hidden_states, gen_hidden_states
)
if gen_hidden_states is not None:
return hidden_states, gen_hidden_states
return hidden_states
def get_image_tokens_hw(self, images: BatchRaggedMedia):
assert isinstance(images, (torch.Tensor, list)), f"images should be BatchRaggedMedia, got {type(images)}"
if isinstance(images, torch.Tensor):
token_h = images.shape[-2]
token_w = images.shape[-1]
else:
token_h, token_w = [], []
for image_i in images:
assert isinstance(image_i, (torch.Tensor, list)), \
f"image_i should be a tensor or a list of tensors, got {type(image_i)}"
if isinstance(image_i, torch.Tensor):
token_h.append(image_i.shape[-2])
token_w.append(image_i.shape[-1])
else:
token_h.append([])
token_w.append([])
for j in range(len(image_i)):
token_h[-1].append(image_i[j].shape[-2])
token_w[-1].append(image_i[j].shape[-1])
return token_h, token_w
def ragged_final_layer(self, hidden_states, image_mask, timesteps, token_h, token_w, first_step=None, batch_image_sizes=None):
n_embd = hidden_states.size(-1)
if batch_image_sizes is not None:
# For batch multi-resolution inference
# bsz可能包含cond/uncond大小,而batch_image_sizes只包含实际的image大小
bsz = hidden_states.size(0)
actual_bsz = len(batch_image_sizes)
pred = []
for i in range(bsz):
h_lat, w_lat = batch_image_sizes[i % actual_bsz]
th_i = h_lat
tw_i = w_lat
n_tokens_i = th_i * tw_i
assert n_tokens_i == image_mask[i].sum().item(), \
f"n_tokens_i ({n_tokens_i}) has inconsistent shape with image_mask[i].sum().item() ({image_mask[i].sum().item()})"
if first_step is False:
# 非首步:hidden_states = [timestep_emb, img_emb(1D padded)],因为有效 token 在前,直接按数量截取
image_output_i = hidden_states[i:i+1, 1:1+n_tokens_i, :]
else:
# 首步:从完整序列中按 image_mask 布尔索引提取 image token
image_output_i = hidden_states[i, image_mask[i].bool(), :].unsqueeze(0)
t_emb_i = self.time_embed_2(timesteps[i:i+1])
pred_i = self.final_layer(image_output_i, t_emb_i, th_i, tw_i)
pred.append(pred_i)
return pred
if isinstance(timesteps, torch.Tensor):
# When timesteps is a tensor, images must be a 4-D tensor (B, C, H, W), which means only one target image
t_emb = self.time_embed_2(timesteps)
if first_step is False:
# only for gen_image non-first-step inference
image_output = hidden_states[:, 1:, :]
else: # first_step is True or None
image_output = hidden_states.masked_select(
image_mask.unsqueeze(-1).bool()).reshape(-1, token_h * token_w, n_embd)
pred = self.final_layer(image_output, t_emb, token_h, token_w)
else:
# When timesteps is a list, images must be a list of 4-D tensors or a list of list of 3-D tensors, and token_h and token_w must be a list of int or a list of list of int.
# In this case, each line of the image_mask may contain different number of Trues, leading
# the `reshape(batch_size, ...)` is not possible.
sections = image_mask.sum(1).tolist()
image_output = hidden_states.masked_select(
image_mask.unsqueeze(-1).bool()).reshape(-1, n_embd).split(sections)
pred = []
for image_output_i, t_i, token_h_i, token_w_i in zip(image_output, timesteps, token_h, token_w):
t_emb_i = self.time_embed_2(t_i)
if isinstance(token_h_i, int):
# corresponds to image_output as a list of 4-D tensors, image_output_i as a 4-D tensor
image_output_i = image_output_i.reshape(-1, token_h_i * token_w_i, n_embd)
pred_i = self.final_layer(image_output_i, t_emb_i, token_h_i, token_w_i)
pred.append(pred_i)
else:
# corresponds to image_output as a list of list of 3-D tensors, image_output_i as a list of 3-D tensors
subsections = [token_h_ij * token_w_ij for token_h_ij, token_w_ij in zip(token_h_i, token_w_i)]
assert sum(subsections) == image_output_i.shape[0], \
f"sum(subsections) ({sum(subsections)}) has inconsistent shape with image_output_i.shape[0] ({image_output_i.shape[0]})"
image_output_i = image_output_i.split(subsections)
pred_i = []
for j, image_output_ij in enumerate(image_output_i):
pred_ij = self.final_layer(image_output_ij[None], t_emb_i[j:j+1], token_h_i[j], token_w_i[j])
pred_i.append(pred_ij)
pred.append(pred_i)
return pred
def _deepstack_process(
self, hidden_states: torch.Tensor, visual_pos_masks: torch.Tensor, visual_embeds: torch.Tensor
):
visual_pos_masks = visual_pos_masks.to(hidden_states.device)
if isinstance(visual_embeds, list):
if len(visual_embeds) == 0:
raise ValueError("visual_embeds is an empty list")
elif len(visual_embeds) == 1:
visual_embeds = visual_embeds[0]
if not isinstance(visual_embeds, torch.Tensor):
raise ValueError(f"visual_embeds list contains non-tensor element: {type(visual_embeds)}")
else:
if all(isinstance(e, torch.Tensor) for e in visual_embeds):
visual_embeds = torch.cat(visual_embeds, dim=0)
else:
raise ValueError(f"visual_embeds list contains non-tensor elements")
visual_embeds = visual_embeds.to(hidden_states.device, hidden_states.dtype)
bsz = hidden_states.shape[0]
for i in range(bsz):
batch_mask = visual_pos_masks[i]
batch_hidden = hidden_states[i]
num_visual_tokens = batch_mask.sum().item()
if num_visual_tokens == 0:
continue
visual_hidden = batch_hidden[batch_mask]
if visual_embeds.shape[0] >= num_visual_tokens:
batch_visual_embeds = visual_embeds[:num_visual_tokens]
else:
batch_visual_embeds = visual_embeds
if visual_embeds.shape[0] < num_visual_tokens:
padding = visual_embeds[-1:].repeat(num_visual_tokens - visual_embeds.shape[0], 1)
batch_visual_embeds = torch.cat([visual_embeds, padding], dim=0)
visual_hidden = visual_hidden + batch_visual_embeds
batch_hidden[batch_mask] = visual_hidden
hidden_states[i] = batch_hidden
return hidden_states
def forward(
self,
input_ids: Optional[torch.Tensor] = None, # bsz x seqlen
attention_mask: Optional[torch.Tensor] = None, # bsz x 1 x seqlen x seqlen
rope_image_info: Optional[list[list[tuple[slice, tuple[int, int], dict]]]] = None,
return_dict: bool = True,
# for gen images
images: Optional[BatchRaggedMedia] = None, # bsz x c x h x w, or bsz x (n_i x (c x h_ij x w_ij))
image_mask: Optional[torch.Tensor] = None, # bsz x seqlen
timesteps: Optional[BatchRaggedTensor] = None, # bsz, or bsz x (n_i)
timesteps_index: Optional[BatchRaggedTensor] = None, # bsz x k, or bsz x (k_i)
# for cond images
cond_vae_images: Optional[BatchRaggedMedia] = None, # bsz x c x h x w, or bsz x (m_i x (c x h_ij x w_ij))
cond_vae_image_mask: Optional[torch.Tensor] = None, # bsz x seqlen
cond_timesteps: Optional[BatchRaggedTensor] = None, # bsz, or bsz x (m_i)
cond_timesteps_index: Optional[BatchRaggedTensor] = None,
cond_vit_images: Optional[BatchRaggedMedia] = None,
cond_vit_image_mask: Optional[torch.Tensor] = None,
cond_vit_image_kwargs: Optional[dict[str, Any]] = None,
# only for inference
input_pos: Optional[torch.Tensor] = None, # bsz x seq_len-1, used for KVCache
past_key_values: Optional[MultimodalStaticCache] = None,
mode: Optional[str] = None,
first_step: Optional[bool] = None,
und_token_indices: Optional[torch.Tensor] = None,
gen_token_indices: Optional[torch.Tensor] = None,
sample_offsets: Optional[list[torch.Tensor]] = None,
batch_image_sizes: Optional[list[tuple[int, int]]] = None,
) -> MultimodalModelOutput | tuple:
# Sanity check
if input_ids is None and images is None:
raise ValueError("Either input_ids or images should be provided.")
if input_ids is not None:
bsz = input_ids.size(0)
device = input_ids.device
else:
bsz = images.size(0) if isinstance(images, torch.Tensor) else len(images)
device = get_device(images)
if self.training:
seqlen = input_ids.size(1)
else:
seqlen = self._config.max_position_embeddings
assert self._config.max_position_embeddings >= seqlen, (
f"Cannot forward sequence of length {seqlen}, "
f"max position embeddings is only {self._config.max_position_embeddings}, "
f"try set --max-position-embeddings to a larger value."
)
cos, sin = self.cached_rope(
seqlen, device, rope_media_info=rope_image_info, input_pos=input_pos, sample_offsets=sample_offsets if self.use_rope_sample_offsets else None,
)
cos = cos.to(dtype=self.dtype)
sin = sin.to(dtype=self.dtype)
if input_ids is not None:
hidden_states = self.model["embed_tokens"](input_ids) # (bsz, seqlen, n_embd)
if self._config.use_mot and self._config_mot_gen.hidden_size != self._config.hidden_size:
und_hidden_states = hidden_states
gen_hidden_states = torch.zeros(
(hidden_states.size(0), hidden_states.size(1), self._config_mot_gen.hidden_size),
device=hidden_states.device, dtype=hidden_states.dtype
)
hidden_states = (und_hidden_states, gen_hidden_states)
else:
hidden_states = None # only for non-first step inference of the image generation
deepstack_image_embeds = None
if images is not None:
hidden_states = self.instantiate_vae_image_tokens(hidden_states, timesteps, images, image_mask)
if cond_vae_images is not None:
hidden_states = self.instantiate_vae_image_tokens(hidden_states, cond_timesteps, cond_vae_images, cond_vae_image_mask)
if cond_vit_images is not None:
hidden_states, deepstack_image_embeds = self.instantiate_vit_image_tokens(hidden_states, cond_vit_images, cond_vit_image_mask, cond_vit_image_kwargs)
if timesteps_index is not None:
hidden_states = self.instantiate_continuous_tokens(hidden_states, emb_layer=self.timestep_emb, scatter_src=timesteps, scatter_index=timesteps_index)
if cond_timesteps_index is not None:
hidden_states = self.instantiate_continuous_tokens(hidden_states, emb_layer=self.timestep_emb, scatter_src=cond_timesteps, scatter_index=cond_timesteps_index)
if self._config.use_mot:
if und_token_indices is None or gen_token_indices is None:
seq_for_indices = hidden_states[0].shape[1] if isinstance(hidden_states, tuple) else hidden_states.shape[1]
all_indices = torch.arange(seq_for_indices, device=device).unsqueeze(0).expand(bsz, -1)
gen_mask = torch.zeros(bsz, seq_for_indices, dtype=torch.bool, device=device)
for mask in (image_mask, cond_vae_image_mask):
if mask is not None:
gen_mask |= mask.to(device=device, dtype=torch.bool)
gen_token_indices = all_indices[gen_mask].reshape(bsz, -1)
und_token_indices = all_indices[~gen_mask].reshape(bsz, -1)
if isinstance(hidden_states, tuple):
und_hidden_states, gen_hidden_states = hidden_states
else:
if first_step is False:
step_indices = torch.arange(
hidden_states.shape[1],
device=hidden_states.device,
).unsqueeze(0).expand(hidden_states.shape[0], -1)
if images is not None:
und_hidden_states = hidden_states.new_zeros(
hidden_states.shape[0], 0, self._config.hidden_size
)
gen_hidden_states = hidden_states
und_token_indices = step_indices[:, :0]
gen_token_indices = step_indices
else:
und_hidden_states = hidden_states
gen_hidden_states = hidden_states.new_zeros(
hidden_states.shape[0], 0, self._config_mot_gen.hidden_size
)
und_token_indices = step_indices
gen_token_indices = step_indices[:, :0]
else:
und_hidden_states = hidden_states
gen_hidden_states = hidden_states
und_token_indices_ = und_token_indices.unsqueeze(-1).expand(-1, -1, und_hidden_states.shape[-1])
gen_token_indices_ = gen_token_indices.unsqueeze(-1).expand(-1, -1, gen_hidden_states.shape[-1])
und_hidden_states = und_hidden_states.gather(dim=1, index=und_token_indices_)
gen_hidden_states = gen_hidden_states.gather(dim=1, index=gen_token_indices_)
hidden_states = (und_hidden_states, gen_hidden_states)
if self._config.use_modality_routing:
_hs_for_seqlen = hidden_states[0] if isinstance(hidden_states, tuple) else hidden_states
actual_seqlen = _hs_for_seqlen.size(1)
token_modalities = torch.zeros(bsz, actual_seqlen, dtype=torch.long, device=device)
if input_ids is not None:
if cond_vit_image_mask is not None:
token_modalities[cond_vit_image_mask.bool()] = 1
if image_mask is not None:
token_modalities[image_mask.bool()] = 2
if cond_vae_image_mask is not None:
token_modalities[cond_vae_image_mask.bool()] = 2
else:
token_modalities[:, 1:] = 2
else:
token_modalities = None
for layer_idx, layer in enumerate(self.model["layers"]): # noqa
layer_inputs = [
hidden_states,
attention_mask,
(cos, sin),
input_pos,
past_key_values,
und_token_indices,
gen_token_indices
]
hidden_states = layer(*layer_inputs, token_modalities=token_modalities)
if deepstack_image_embeds is not None and layer_idx in range(len(deepstack_image_embeds)):
if isinstance(hidden_states, tuple):
und_hs, gen_hs = hidden_states
und_vit_image_mask = cond_vit_image_mask.gather(
dim=1,
index=und_token_indices.to(cond_vit_image_mask.device),
)
und_hs = self._deepstack_process(
und_hs,
und_vit_image_mask,
deepstack_image_embeds[layer_idx],
)
hidden_states = (und_hs, gen_hs)
else:
hidden_states = self._deepstack_process(
hidden_states,
cond_vit_image_mask,
deepstack_image_embeds[layer_idx],
)
if isinstance(hidden_states, tuple):
und_hidden_states_, gen_hidden_states_ = hidden_states
bsz = und_hidden_states_.shape[0]
und_seqlen = und_hidden_states_.shape[1]
gen_seqlen = gen_hidden_states_.shape[1]
und_hidden_states = torch.zeros(
(bsz, und_seqlen+gen_seqlen, und_hidden_states_.shape[-1]),
device=und_hidden_states_.device, dtype=und_hidden_states_.dtype
)
und_hidden_states.scatter_(dim=1, index=und_token_indices_.to(und_hidden_states_.device), src=und_hidden_states_)
gen_hidden_states = torch.zeros(
(bsz, und_seqlen+gen_seqlen, gen_hidden_states_.shape[-1]),
device=gen_hidden_states_.device, dtype=gen_hidden_states_.dtype
)
gen_hidden_states.scatter_(dim=1, index=gen_token_indices_, src=gen_hidden_states_)
else:
und_hidden_states, gen_hidden_states = hidden_states, hidden_states
if images is not None:
token_h, token_w = self.get_image_tokens_hw(images)
gen_hidden_states = gen_hidden_states.to(device=get_device(images))
diff_pred = self.ragged_final_layer(
gen_hidden_states, image_mask, timesteps, token_h, token_w, first_step, batch_image_sizes=batch_image_sizes)
else:
diff_pred = None
if input_ids is None or mode == "gen_image":
logits = None
else:
und_hidden_states = self.model["norm"](und_hidden_states)
logits = F.linear(und_hidden_states, self.model.embed_tokens.weight)
if not return_dict:
return logits, past_key_values, diff_pred
return MultimodalModelOutput(
logits=logits,
past_key_values=past_key_values,
diffusion_prediction=diff_pred,
)
class MultimodalModel(MultimodalModelBase):
def __init__(
self,
args: Namespace,
config: MultimodalConfig,
dtype: Optional[torch.dtype] = None,
device: Optional[torch.device] = None,
initialize_weights: bool = True,
):
super().__init__()
self.__post_init__(config, dtype, device, args, initialize_weights)
# Model construction helpers
def build_model(
args,
logger=None,
dtype=None,
device=None,
**kwargs,
) -> tuple[torch.nn.Module, Any]:
# Support cpu, cuda, meta devices
factor_kwargs = {"device": device, "dtype": dtype}
if logger is None:
from loguru import logger
model_structure = args.model_structure
logger.info(f"Building model {model_structure} for {args.model_name}")
if device == 'meta':
context = torch.device('meta')
else:
context = nullcontext()
with context:
if model_structure in {"MultimodalModel", "MultimodalHFModel"}:
model, model_config = _build_multimodal_model(
args, logger=logger, **kwargs, **factor_kwargs)
else:
raise NotImplementedError(f"Model structure {model_structure} not implemented.")
return model, model_config
def _build_multimodal_model(args, logger=None, dtype=None, device=None, **kwargs):
factory_kwargs = {"device": device or 'cpu', "dtype": dtype}
model_structure = args.model_structure
valid_keywords = {"initialize_weights"}
valid_kwargs = {key: value for key, value in kwargs.items() if key in valid_keywords}
if model_structure == "MultimodalModel":
from .configuration import core_model_config_from_args
model_name = args.model_name.split(".")[-1]
model_config_dict = core_model_config_from_args(args)
model_config = MultimodalConfig.from_name(model_name, **model_config_dict)
model = MultimodalModel(args, model_config, **factory_kwargs, **valid_kwargs)
elif model_structure == "MultimodalHFModel":
from .pipeline import MultimodalHFModel
from .configuration import core_model_config_from_args
model_name = args.model_name.split(".")[-1]
model_config_dict = core_model_config_from_args(args)
model_config = MultimodalConfig.from_name(model_name, **model_config_dict)
model = MultimodalHFModel(args, model_config, **factory_kwargs, **valid_kwargs)
else:
raise NotImplementedError(f"Model structure {model_structure} not implemented.")
logger.info(f"Build Model {model.__class__.__name__} finished.")
return model, model_config