Files
1038lab-ComfyUI-RMBG/models/florence2/model.py
T
2026-10-20 00:25:57 -07:00

580 lines
31 KiB
Python

# Based on code from ComfyUI-Florence2 by Jukka Seppänen (kijai), MIT License
"""BART encoder-decoder language model, Florence2 top-level model, and autoregressive generation."""
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from .davit import DaViT
import comfy.ops
from comfy.ldm.modules.attention import optimized_attention_for_device
from comfy.utils import ProgressBar
from tqdm.auto import tqdm
_POSITION_OFFSET = 2 # BART positional id offset
def make_attention_mask(mask_2d, dtype):
"""[B, S] -> [B, 1, 1, S] with -inf for padding positions."""
inverted = 1.0 - mask_2d[:, None, None, :].to(dtype)
return inverted.masked_fill(inverted.bool(), torch.finfo(dtype).min)
def make_causal_mask(shape, dtype, device, past_kv_len=0):
"""Create [B, 1, T, T+past] causal mask with -inf above diagonal."""
bsz, tgt_len = shape
mask = torch.full((tgt_len, tgt_len), torch.finfo(dtype).min, device=device, dtype=dtype)
cond = torch.arange(tgt_len, device=device)
mask.masked_fill_(cond < (cond + 1).view(-1, 1), 0)
if past_kv_len > 0:
mask = torch.cat([torch.zeros(tgt_len, past_kv_len, dtype=dtype, device=device), mask], dim=-1)
return mask[None, None].expand(bsz, 1, tgt_len, tgt_len + past_kv_len)
def _make_position_ids(input_ids, past_key_values_length, device):
bsz, seq_len = input_ids.shape[:2]
positions = torch.arange(past_key_values_length, past_key_values_length + seq_len, dtype=torch.long, device=device).expand(bsz, -1)
return positions + _POSITION_OFFSET
class Attention(nn.Module):
"""Multi-headed attention with optional KV cache for decoder layers."""
def __init__(self, embed_dim, num_heads, is_decoder, is_causal, dtype=None, device=None, operations=None):
super().__init__()
self.embed_dim = embed_dim
self.num_heads = num_heads
self.head_dim = embed_dim // num_heads
self.is_decoder = is_decoder
self.is_causal = is_causal
self.q_proj = operations.Linear(embed_dim, embed_dim, bias=True, dtype=dtype, device=device)
self.k_proj = operations.Linear(embed_dim, embed_dim, bias=True, dtype=dtype, device=device)
self.v_proj = operations.Linear(embed_dim, embed_dim, bias=True, dtype=dtype, device=device)
self.out_proj = operations.Linear(embed_dim, embed_dim, bias=True, dtype=dtype, device=device)
def _shape(self, tensor, seq_len, bsz):
return tensor.view(bsz, seq_len, self.num_heads, self.head_dim).transpose(1, 2).contiguous()
def forward(self, hidden_states, key_value_states=None, past_key_value=None, attention_mask=None):
is_cross_attention = key_value_states is not None
bsz, tgt_len, _ = hidden_states.size()
query_states = self._shape(self.q_proj(hidden_states), tgt_len, bsz)
if is_cross_attention and past_key_value is not None and past_key_value[0].shape[2] == key_value_states.shape[1]:
key_states = past_key_value[0]
value_states = past_key_value[1]
elif is_cross_attention:
key_states = self._shape(self.k_proj(key_value_states), -1, bsz)
value_states = self._shape(self.v_proj(key_value_states), -1, bsz)
elif past_key_value is not None:
key_states = self._shape(self.k_proj(hidden_states), -1, bsz)
value_states = self._shape(self.v_proj(hidden_states), -1, bsz)
key_states = torch.cat([past_key_value[0], key_states], dim=2)
value_states = torch.cat([past_key_value[1], value_states], dim=2)
else:
key_states = self._shape(self.k_proj(hidden_states), -1, bsz)
value_states = self._shape(self.v_proj(hidden_states), -1, bsz)
if self.is_decoder:
past_key_value = (key_states, value_states)
# Ensure matching dtypes (cross-attention cache may differ when using manual_cast ops)
if key_states.dtype != query_states.dtype:
key_states = key_states.to(query_states.dtype)
value_states = value_states.to(query_states.dtype)
optimized_attention = optimized_attention_for_device(hidden_states.device, mask=attention_mask is not None, small_input=True)
attn_output = optimized_attention(query_states, key_states, value_states, self.num_heads, mask=attention_mask, skip_reshape=True, skip_output_reshape=True)
attn_output = attn_output.transpose(1, 2).reshape(bsz, tgt_len, self.embed_dim)
attn_output = self.out_proj(attn_output)
return attn_output, past_key_value
class EncoderLayer(nn.Module):
def __init__(self, config, dtype=None, device=None, operations=None):
super().__init__()
d = config.d_model
self.self_attn = Attention(d, config.encoder_attention_heads, is_decoder=False, is_causal=False, dtype=dtype, device=device, operations=operations)
self.self_attn_layer_norm = operations.LayerNorm(d, dtype=dtype, device=device)
self.fc1 = operations.Linear(d, config.encoder_ffn_dim, dtype=dtype, device=device)
self.fc2 = operations.Linear(config.encoder_ffn_dim, d, dtype=dtype, device=device)
self.final_layer_norm = operations.LayerNorm(d, dtype=dtype, device=device)
def forward(self, hidden_states, attention_mask=None):
residual = hidden_states
hidden_states, _ = self.self_attn(hidden_states=hidden_states, attention_mask=attention_mask)
hidden_states = residual + hidden_states
hidden_states = self.self_attn_layer_norm(hidden_states)
residual = hidden_states
hidden_states = F.gelu(self.fc1(hidden_states))
hidden_states = self.fc2(hidden_states)
hidden_states = residual + hidden_states
hidden_states = self.final_layer_norm(hidden_states)
return hidden_states
class DecoderLayer(nn.Module):
def __init__(self, config, dtype=None, device=None, operations=None):
super().__init__()
d = config.d_model
self.self_attn = Attention(d, config.decoder_attention_heads, is_decoder=True, is_causal=True, dtype=dtype, device=device, operations=operations)
self.self_attn_layer_norm = operations.LayerNorm(d, dtype=dtype, device=device)
self.encoder_attn = Attention(d, config.decoder_attention_heads, is_decoder=True, is_causal=False, dtype=dtype, device=device, operations=operations)
self.encoder_attn_layer_norm = operations.LayerNorm(d, dtype=dtype, device=device)
self.fc1 = operations.Linear(d, config.decoder_ffn_dim, dtype=dtype, device=device)
self.fc2 = operations.Linear(config.decoder_ffn_dim, d, dtype=dtype, device=device)
self.final_layer_norm = operations.LayerNorm(d, dtype=dtype, device=device)
def forward(self, hidden_states, attention_mask=None, encoder_hidden_states=None, encoder_attention_mask=None, past_key_value=None):
# Self-attention
self_attn_past = past_key_value[:2] if past_key_value is not None else None
residual = hidden_states
hidden_states, self_attn_cache = self.self_attn(hidden_states=hidden_states, past_key_value=self_attn_past, attention_mask=attention_mask)
hidden_states = residual + hidden_states
hidden_states = self.self_attn_layer_norm(hidden_states)
# Cross-attention
cross_attn_cache = None
if encoder_hidden_states is not None:
cross_attn_past = past_key_value[2:] if past_key_value is not None else None
residual = hidden_states
hidden_states, cross_attn_cache = self.encoder_attn(
hidden_states=hidden_states, key_value_states=encoder_hidden_states,
past_key_value=cross_attn_past, attention_mask=encoder_attention_mask,
)
hidden_states = residual + hidden_states
hidden_states = self.encoder_attn_layer_norm(hidden_states)
# FFN
residual = hidden_states
hidden_states = F.gelu(self.fc1(hidden_states))
hidden_states = self.fc2(hidden_states)
hidden_states = residual + hidden_states
hidden_states = self.final_layer_norm(hidden_states)
present_key_value = None
if self_attn_cache is not None:
present_key_value = self_attn_cache
if cross_attn_cache is not None:
present_key_value = present_key_value + cross_attn_cache
return hidden_states, present_key_value
class Encoder(nn.Module):
def __init__(self, config, embed_tokens=None, dtype=None, device=None, operations=None):
super().__init__()
d = config.d_model
self.embed_scale = math.sqrt(d) if config.scale_embedding else 1.0
self.embed_tokens = operations.Embedding(config.vocab_size, d, padding_idx=config.pad_token_id, dtype=dtype, device=device)
if embed_tokens is not None:
self.embed_tokens.weight = embed_tokens.weight
self.embed_positions = operations.Embedding(config.max_position_embeddings + _POSITION_OFFSET, d, dtype=dtype, device=device)
self.layers = nn.ModuleList([EncoderLayer(config, dtype=dtype, device=device, operations=operations) for _ in range(config.encoder_layers)])
self.layernorm_embedding = operations.LayerNorm(d, dtype=dtype, device=device)
def forward(self, input_ids=None, attention_mask=None, inputs_embeds=None):
if input_ids is not None and inputs_embeds is None:
inputs_embeds = self.embed_tokens(input_ids) * self.embed_scale
pos_input = input_ids if input_ids is not None else inputs_embeds[:, :, -1]
position_ids = _make_position_ids(pos_input, 0, self.embed_positions.weight.device)
embed_pos = self.embed_positions(position_ids).to(inputs_embeds.device)
hidden_states = self.layernorm_embedding(inputs_embeds + embed_pos)
if attention_mask is not None:
attention_mask = make_attention_mask(attention_mask, hidden_states.dtype)
for layer in self.layers:
hidden_states = layer(hidden_states, attention_mask=attention_mask)
return (hidden_states,)
class Decoder(nn.Module):
def __init__(self, config, embed_tokens=None, dtype=None, device=None, operations=None):
super().__init__()
d = config.d_model
self.embed_scale = math.sqrt(d) if config.scale_embedding else 1.0
self.embed_tokens = operations.Embedding(config.vocab_size, d, padding_idx=config.pad_token_id, dtype=dtype, device=device)
if embed_tokens is not None:
self.embed_tokens.weight = embed_tokens.weight
self.embed_positions = operations.Embedding(config.max_position_embeddings + _POSITION_OFFSET, d, dtype=dtype, device=device)
self.layers = nn.ModuleList([DecoderLayer(config, dtype=dtype, device=device, operations=operations) for _ in range(config.decoder_layers)])
self.layernorm_embedding = operations.LayerNorm(d, dtype=dtype, device=device)
def forward(self, input_ids=None, attention_mask=None, encoder_hidden_states=None, encoder_attention_mask=None,
past_key_values=None, use_cache=True, inputs_embeds=None):
if input_ids is not None and inputs_embeds is None:
inputs_embeds = self.embed_tokens(input_ids) * self.embed_scale
if input_ids is not None:
input_shape = input_ids.shape
pos_input = input_ids
else:
input_shape = inputs_embeds.size()[:-1]
pos_input = inputs_embeds[:, :, -1]
past_key_values_length = past_key_values[0][0].shape[2] if past_key_values is not None else 0
position_ids = _make_position_ids(pos_input, past_key_values_length, self.embed_positions.weight.device)
positions = self.embed_positions(position_ids).to(inputs_embeds.device)
hidden_states = self.layernorm_embedding(inputs_embeds + positions)
# When decoding with KV cache and single token, the causal mask is trivially all-attend
# (a 1xN mask with no masking). Skip mask computation entirely for this fast path.
tgt_len = input_shape[-1]
if past_key_values is not None and tgt_len == 1:
causal_mask = None
else:
causal_mask = make_causal_mask(input_shape, hidden_states.dtype, hidden_states.device, past_kv_len=past_key_values_length)
if attention_mask is not None:
causal_mask = causal_mask + make_attention_mask(attention_mask, hidden_states.dtype)
enc_attn_mask = None
if encoder_hidden_states is not None and encoder_attention_mask is not None:
if encoder_attention_mask.ndim == 4:
enc_attn_mask = encoder_attention_mask # already expanded
else:
enc_attn_mask = make_attention_mask(encoder_attention_mask, hidden_states.dtype)
next_cache = () if use_cache else None
for idx, layer in enumerate(self.layers):
past_kv = past_key_values[idx] if past_key_values is not None else None
hidden_states, present_kv = layer(
hidden_states, attention_mask=causal_mask,
encoder_hidden_states=encoder_hidden_states, encoder_attention_mask=enc_attn_mask,
past_key_value=past_kv,
)
if use_cache:
next_cache = next_cache + (present_kv,)
return (hidden_states, next_cache)
class LanguageModel(nn.Module):
def __init__(self, config, dtype=None, device=None, operations=None):
super().__init__()
self.shared = operations.Embedding(config.vocab_size, config.d_model, dtype=dtype, device=device)
self.encoder = Encoder(config, self.shared, dtype=dtype, device=device, operations=operations)
self.decoder = Decoder(config, self.shared, dtype=dtype, device=device, operations=operations)
def forward(self, input_ids=None, attention_mask=None, decoder_input_ids=None, encoder_outputs=None, past_key_values=None, inputs_embeds=None, use_cache=True):
if encoder_outputs is None:
encoder_outputs = self.encoder(input_ids=input_ids, attention_mask=attention_mask, inputs_embeds=inputs_embeds)
decoder_outputs = self.decoder(
input_ids=decoder_input_ids, encoder_hidden_states=encoder_outputs[0],
encoder_attention_mask=attention_mask, past_key_values=past_key_values, use_cache=use_cache,
)
return decoder_outputs + encoder_outputs
class LanguageModelWithLMHead(nn.Module):
def __init__(self, config, dtype=None, device=None, operations=None):
super().__init__()
self.config = config
self.model = LanguageModel(config, dtype=dtype, device=device, operations=operations)
self.lm_head = operations.Linear(config.d_model, config.vocab_size, bias=False, dtype=dtype, device=device)
# Always zero — exists so the key loads from safetensors without warnings
self.register_buffer("final_logits_bias", torch.zeros((1, config.vocab_size)))
def forward(self, input_ids=None, attention_mask=None, decoder_input_ids=None, encoder_outputs=None, past_key_values=None, inputs_embeds=None, use_cache=True):
outputs = self.model(input_ids=input_ids, attention_mask=attention_mask, decoder_input_ids=decoder_input_ids, encoder_outputs=encoder_outputs, past_key_values=past_key_values, inputs_embeds=inputs_embeds, use_cache=use_cache)
return self.lm_head(outputs[0]), outputs
def tie_weights(self):
self.model.encoder.embed_tokens.weight = self.model.shared.weight
self.model.decoder.embed_tokens.weight = self.model.shared.weight
self.lm_head.weight = self.model.shared.weight
class PositionEmbedding2D(nn.Module):
"""Learned absolute 2D positional embedding (row + column)."""
def __init__(self, embedding_dim, num_pos, dtype=None, device=None, operations=None):
super().__init__()
self.row_embeddings = operations.Embedding(num_pos, embedding_dim // 2, dtype=dtype, device=device)
self.column_embeddings = operations.Embedding(num_pos, embedding_dim - (embedding_dim // 2), dtype=dtype, device=device)
def forward(self, pixel_values):
"""pixel_values: [B, H, W, C] -> [B, H, W, embedding_dim]"""
height, width = pixel_values.shape[1:3]
x_emb = self.column_embeddings(torch.arange(width, device=pixel_values.device))
y_emb = self.row_embeddings(torch.arange(height, device=pixel_values.device))
pos = torch.cat([x_emb.unsqueeze(0).repeat(height, 1, 1), y_emb.unsqueeze(1).repeat(1, width, 1)], dim=-1)
pos = pos.permute(2, 0, 1).unsqueeze(0).repeat(pixel_values.shape[0], 1, 1, 1).permute(0, 2, 3, 1)
return pos
class CosinePositionEmbedding1D(nn.Module):
"""Fixed sinusoidal 1D positional encoding. Buffer key: pos_idx_to_embed"""
def __init__(self, embed_dim, max_seq_len):
super().__init__()
self.embed_dim = embed_dim
self.max_seq_len = max_seq_len
factor = math.log(10000)
denominator = torch.exp(-factor * torch.arange(0, embed_dim, 2) / embed_dim)
frequencies = torch.arange(0, max_seq_len).reshape(max_seq_len, 1) * denominator
pos_idx_to_embed = torch.zeros((max_seq_len, embed_dim))
pos_idx_to_embed[:, 0::2] = torch.sin(frequencies)
pos_idx_to_embed[:, 1::2] = torch.cos(frequencies)
self.register_buffer("pos_idx_to_embed", pos_idx_to_embed)
def forward(self, seq_embeds):
"""seq_embeds: [T, D] or [B, T, D] -> positional embeddings of matching shape."""
shape_len = len(seq_embeds.shape)
assert 2 <= shape_len <= 3
pos_embeds = comfy.ops.cast_to_input(self.pos_idx_to_embed[:seq_embeds.size(-2), :], seq_embeds)
if shape_len == 3:
pos_embeds = pos_embeds.view(1, pos_embeds.size(0), pos_embeds.size(1))
return pos_embeds
class Florence2(nn.Module):
"""Florence2 = DaViT vision encoder + image projection + BART LM."""
def __init__(self, config, dtype=None, device=None, operations=None):
super().__init__()
self.config = config
vision_cfg = config.vision_config
text_cfg = config.text_config
self.vision_tower = DaViT(vision_cfg, dtype=dtype, device=device, operations=operations)
image_dim_out = vision_cfg.dim_embed[-1]
projection_dim = vision_cfg.projection_dim
self.image_projection = nn.Parameter(torch.empty(image_dim_out, projection_dim, dtype=dtype, device=device))
self.image_proj_norm = operations.LayerNorm(projection_dim, dtype=dtype, device=device)
image_pos_embed_config = vision_cfg.image_pos_embed
if image_pos_embed_config is not None and image_pos_embed_config.get("type") == "learned_abs_2d":
self.image_pos_embed = PositionEmbedding2D(embedding_dim=image_dim_out, num_pos=image_pos_embed_config["max_pos_embeddings"], dtype=dtype, device=device, operations=operations)
else:
self.image_pos_embed = None
visual_temporal_config = vision_cfg.visual_temporal_embedding
if visual_temporal_config is not None and visual_temporal_config.get("type") == "COSINE":
self.visual_temporal_embed = CosinePositionEmbedding1D(embed_dim=image_dim_out, max_seq_len=visual_temporal_config["max_temporal_embeddings"])
else:
self.visual_temporal_embed = None
self.image_feature_source = vision_cfg.image_feature_source
self.language_model = LanguageModelWithLMHead(text_cfg, dtype=dtype, device=device, operations=operations)
def encode_image(self, pixel_values):
"""Encode image through DaViT + projection. [B, 3, H, W] -> [B, num_tokens, projection_dim]"""
batch_size = pixel_values.shape[0]
T = 1
x = self.vision_tower.forward_features_unpool(pixel_values)
if self.image_pos_embed is not None:
x = x.view(batch_size * T, -1, x.shape[-1])
num_tokens = x.shape[-2]
h = w = int(num_tokens ** 0.5)
assert h * w == num_tokens, "only square feature maps supported"
x = x.view(batch_size * T, h, w, x.shape[-1])
x = x + self.image_pos_embed(x)
x = x.view(batch_size, T * h * w, x.shape[-1])
if self.visual_temporal_embed is not None:
temporal = self.visual_temporal_embed(x.view(batch_size, T, -1, x.shape[-1])[:, :, 0])
x = x.view(batch_size, T, -1, x.shape[-1]) + temporal.view(1, T, 1, x.shape[-1])
x_feat_dict = {
"spatial_avg_pool": x.view(batch_size, T, -1, x.shape[-1]).mean(dim=2),
"temporal_avg_pool": x.view(batch_size, T, -1, x.shape[-1]).mean(dim=1),
"last_frame": x.view(batch_size, T, -1, x.shape[-1])[:, -1],
}
x = torch.cat([x_feat_dict[src] for src in self.image_feature_source], dim=1)
# Project — cast nn.Parameter to match x dtype (manual_cast doesn't cover raw params)
x = x @ self.image_projection.to(dtype=x.dtype, device=x.device)
x = self.image_proj_norm(x)
return x
def _merge_input_ids_with_image_features(self, image_features, inputs_embeds):
batch_size, image_token_length = image_features.size()[:-1]
device = image_features.device
image_attention_mask = torch.ones(batch_size, image_token_length, device=device)
if inputs_embeds is None:
return image_features, image_attention_mask
text_attention_mask = torch.ones(batch_size, inputs_embeds.size(1), device=device)
return torch.cat([image_features, inputs_embeds], dim=1), torch.cat([image_attention_mask, text_attention_mask], dim=1)
@torch.inference_mode()
def generate(self, input_ids, pixel_values, max_new_tokens=1024, num_beams=3, do_sample=False, temperature=1.0):
eos_token_id = self.config.text_config.eos_token_id
decoder_start_token_id = self.config.text_config.decoder_start_token_id
forced_bos_token_id = self.config.text_config.forced_bos_token_id
image_features = self.encode_image(pixel_values)
if input_ids is not None:
embed_scale = self.language_model.model.encoder.embed_scale
inputs_embeds = self.language_model.model.shared(input_ids) * embed_scale
else:
inputs_embeds = None
merged_embeds, attention_mask = self._merge_input_ids_with_image_features(image_features, inputs_embeds)
attention_mask = attention_mask.to(merged_embeds.dtype)
encoder_outputs = self.language_model.model.encoder(inputs_embeds=merged_embeds, attention_mask=attention_mask)
# Florence2 has no padding — the encoder attention mask is all-attend.
# Passing None skips mask computation in cross-attention (faster).
batch_size = merged_embeds.shape[0]
args = dict(encoder_outputs=encoder_outputs, encoder_attention_mask=None, batch_size=batch_size,
decoder_start_token_id=decoder_start_token_id, eos_token_id=eos_token_id,
forced_bos_token_id=forced_bos_token_id, max_new_tokens=max_new_tokens)
if num_beams > 1:
return self._beam_search(**args, num_beams=num_beams, do_sample=do_sample)
else:
return self._greedy_or_sample(**args, do_sample=do_sample, temperature=temperature)
def _greedy_or_sample(self, encoder_outputs, encoder_attention_mask, batch_size,
decoder_start_token_id, eos_token_id, forced_bos_token_id,
max_new_tokens, do_sample, temperature):
device = encoder_outputs[0].device
generated = torch.full((batch_size, 1), decoder_start_token_id, dtype=torch.long, device=device)
past_key_values = None
finished = torch.zeros(batch_size, dtype=torch.bool, device=device)
pbar = ProgressBar(max_new_tokens)
tbar = tqdm(total=max_new_tokens, desc="Florence2", unit="tok")
for step in range(max_new_tokens):
cur_input_ids = generated[:, -1:] if past_key_values is not None else generated
decoder_outputs = self.language_model.model.decoder(
input_ids=cur_input_ids, encoder_hidden_states=encoder_outputs[0],
encoder_attention_mask=encoder_attention_mask, past_key_values=past_key_values, use_cache=True,
)
past_key_values = decoder_outputs[1]
logits = self.language_model.lm_head(decoder_outputs[0][:, -1:, :])[:, -1, :]
if step == 0 and forced_bos_token_id is not None:
next_token = torch.full((batch_size, 1), forced_bos_token_id, dtype=torch.long, device=device)
else:
if forced_bos_token_id is not None and step > 0:
logits[:, forced_bos_token_id] = torch.finfo(logits.dtype).min
if do_sample:
next_token = torch.multinomial(F.softmax(logits / temperature, dim=-1), num_samples=1)
else:
next_token = logits.argmax(dim=-1, keepdim=True)
generated = torch.cat([generated, next_token], dim=-1)
finished = finished | (next_token.squeeze(-1) == eos_token_id)
pbar.update(1)
tbar.update(1)
if finished.all():
break
tbar.close()
return generated
def _beam_search(self, encoder_outputs, encoder_attention_mask, batch_size,
decoder_start_token_id, eos_token_id, forced_bos_token_id,
max_new_tokens, num_beams, do_sample=False):
device = encoder_outputs[0].device
vocab_size = self.language_model.config.vocab_size
# Expand encoder outputs for beams
encoder_hidden = encoder_outputs[0].unsqueeze(1).expand(-1, num_beams, -1, -1).reshape(batch_size * num_beams, -1, encoder_outputs[0].shape[-1])
encoder_outputs_expanded = (encoder_hidden,)
generated = torch.full((batch_size * num_beams, 1), decoder_start_token_id, dtype=torch.long, device=device)
past_key_values = None
beam_scores = torch.zeros(batch_size, num_beams, device=device)
beam_scores[:, 1:] = torch.finfo(beam_scores.dtype).min
beam_scores = beam_scores.view(-1)
pbar = ProgressBar(max_new_tokens)
tbar = tqdm(total=max_new_tokens, desc="Florence2 beam", unit="tok")
for step in range(max_new_tokens):
cur_input_ids = generated[:, -1:] if past_key_values is not None else generated
decoder_outputs = self.language_model.model.decoder(
input_ids=cur_input_ids, encoder_hidden_states=encoder_outputs_expanded[0],
encoder_attention_mask=encoder_attention_mask, past_key_values=past_key_values, use_cache=True,
)
past_key_values = decoder_outputs[1]
next_token_logits = self.language_model.lm_head(decoder_outputs[0][:, -1:, :])[:, -1, :]
# Force bos at step 0, suppress it after
if step == 0 and forced_bos_token_id is not None:
forced_scores = torch.full_like(next_token_logits, torch.finfo(next_token_logits.dtype).min)
forced_scores[:, forced_bos_token_id] = 0
next_token_scores = forced_scores
else:
if forced_bos_token_id is not None and step > 0:
next_token_logits[:, forced_bos_token_id] = torch.finfo(next_token_logits.dtype).min
next_token_scores = F.log_softmax(next_token_logits, dim=-1)
next_scores = (next_token_scores + beam_scores[:, None]).view(batch_size, num_beams * vocab_size)
# Step 0 with forced_bos is deterministic (only one valid token across all beams),
# so skip sampling there — multinomial would fail with fewer nonzero entries than samples.
sampling = do_sample and not (step == 0 and forced_bos_token_id is not None)
if sampling:
# HF beam-sample: multinomial without replacement over softmax(next_scores), then sort desc
probs = F.softmax(next_scores, dim=-1)
topk_indices = torch.multinomial(probs, num_samples=2 * num_beams)
topk_scores = torch.gather(next_scores, -1, topk_indices)
topk_scores, _sort_idx = torch.sort(topk_scores, descending=True, dim=-1)
topk_indices = torch.gather(topk_indices, -1, _sort_idx)
else:
topk_scores, topk_indices = torch.topk(next_scores, 2 * num_beams, dim=-1, largest=True, sorted=True)
topk_beam_indices = topk_indices.div(vocab_size, rounding_mode='floor')
topk_token_ids = topk_indices % vocab_size
next_beam_scores = topk_scores[:, :num_beams]
next_beam_tokens = topk_token_ids[:, :num_beams]
next_beam_flat_indices = topk_beam_indices[:, :num_beams]
beam_offset = torch.arange(batch_size, device=device).unsqueeze(1) * num_beams
beam_idx_flat = (next_beam_flat_indices + beam_offset).view(-1)
beam_scores = next_beam_scores.view(-1)
beam_tokens = next_beam_tokens.view(-1)
generated = torch.cat([generated[beam_idx_flat], beam_tokens.unsqueeze(-1)], dim=-1)
past_key_values = self._reorder_cache(past_key_values, beam_idx_flat)
pbar.update(1)
tbar.update(1)
if (beam_tokens.view(batch_size, num_beams) == eos_token_id).all():
break
tbar.close()
# Select best beam, truncate at first eos
beam_scores = beam_scores.view(batch_size, num_beams)
best_indices = beam_scores.argmax(dim=-1) + torch.arange(batch_size, device=device) * num_beams
generated = generated[best_indices]
results = []
for b in range(batch_size):
seq = generated[b]
eos_positions = (seq == eos_token_id).nonzero(as_tuple=False)
for pos in eos_positions:
if pos.item() > 0:
seq = seq[:pos.item() + 1]
break
results.append(seq)
max_len = max(r.shape[0] for r in results)
pad_token_id = self.language_model.config.pad_token_id
padded = torch.full((batch_size, max_len), pad_token_id, dtype=torch.long, device=device)
for b, r in enumerate(results):
padded[b, :r.shape[0]] = r
return padded
@staticmethod
def _reorder_cache(past_key_values, beam_idx):
if hasattr(past_key_values, "reorder_cache"):
past_key_values.reorder_cache(beam_idx)
return past_key_values
return tuple(
tuple(past_state.index_select(0, beam_idx.to(past_state.device)) for past_state in layer_past)
for layer_past in past_key_values
)