1314 lines
54 KiB
Python
1314 lines
54 KiB
Python
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||
# Copyright 2024 The Qwen team, Alibaba Group and the HuggingFace Inc. team. All rights reserved.
|
||
#
|
||
# This code ijins based on EleutherAI's GPT-NeoX library and the GPT-NeoX
|
||
# and OPT implementations in this library. It has been modified from its
|
||
# original forms to accommodate minor architectural differences compared
|
||
# to GPT-NeoX and OPT used by the Meta AI team that trained the model.
|
||
#
|
||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
# you may not use this file except in compliance with the License.
|
||
# You may obtain a copy of the License at
|
||
#
|
||
# http://www.apache.org/licenses/LICENSE-2.0
|
||
#
|
||
# Unless required by applicable law or agreed to in writing, software
|
||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
# See the License for the specific language governing permissions and
|
||
# limitations under the License.
|
||
"""Paddle Qwen2 model."""
|
||
from __future__ import annotations
|
||
|
||
import math
|
||
import warnings
|
||
from functools import partial
|
||
from typing import Dict, List, Optional, Tuple, Union
|
||
|
||
import paddle
|
||
import paddle.distributed as dist
|
||
import paddle.distributed.fleet.meta_parallel as mpu
|
||
import paddle.nn.functional as F
|
||
from paddle import Tensor, nn
|
||
from paddle.distributed import fleet
|
||
from paddle.distributed.fleet.meta_parallel import get_rng_state_tracker
|
||
from paddle.distributed.fleet.recompute.recompute import recompute
|
||
|
||
from ...utils.tools import get_env_device
|
||
from .. import linear_utils
|
||
from ..activations import ACT2FN
|
||
from ..contrastive_loss import SimpleContrastiveLoss
|
||
from ..conversion_utils import StateDictNameMapping, init_name_mappings
|
||
from ..embedding_utils import dist_gather_tensor_with_gradient
|
||
from ..linear_utils import Linear
|
||
from ..model_outputs import (
|
||
BaseModelOutputWithPast,
|
||
CausalLMOutputWithPast,
|
||
SequenceClassifierOutputWithPast,
|
||
TokenClassifierOutput,
|
||
)
|
||
from ..model_utils import PretrainedModel, register_base_model
|
||
from ..refined_recompute import (
|
||
RRColumnParallelLinear,
|
||
RRColumnSequenceParallelLinear,
|
||
RRRowParallelLinear,
|
||
RRRowSequenceParallelLinear,
|
||
get_skip_recompute_ops,
|
||
)
|
||
from ..refined_recompute import recompute as rr_recompute
|
||
from ..utils import caculate_llm_per_token_flops, logger
|
||
from .configuration import Qwen2Config
|
||
from ..llama.modeling import (
|
||
LlamaPretrainedModel,
|
||
LlamaModel,
|
||
LlamaForCausalLM,
|
||
LlamaMLP,
|
||
LlamaDecoderLayer,
|
||
LlamaRMSNorm,
|
||
LlamaRotaryEmbedding,
|
||
LlamaPretrainingCriterion,
|
||
LlamaLMHead,
|
||
fusion_ops,
|
||
)
|
||
from ..llama.modeling import apply_rotary_pos_emb, repeat_kv
|
||
|
||
|
||
try:
|
||
from paddle.incubate.nn.functional import fused_rotary_position_embedding
|
||
except ImportError:
|
||
fused_rotary_position_embedding = None
|
||
|
||
try:
|
||
from paddle.distributed.fleet.utils.sequence_parallel_utils import (
|
||
GatherOp,
|
||
ScatterOp,
|
||
mark_as_sequence_parallel_parameter,
|
||
)
|
||
except:
|
||
pass
|
||
|
||
try:
|
||
from paddle.nn.functional.flash_attention import flash_attention
|
||
except:
|
||
flash_attention = None
|
||
__all__ = [
|
||
"Qwen2Model",
|
||
"Qwen2PretrainedModel",
|
||
"Qwen2ForCausalLM",
|
||
"Qwen2PretrainingCriterion",
|
||
"Qwen2ForSequenceClassification",
|
||
"Qwen2ForTokenClassification",
|
||
"Qwen2SentenceEmbedding",
|
||
]
|
||
|
||
def get_triangle_upper_mask(x, mask=None):
|
||
if mask is not None:
|
||
return mask
|
||
# [bsz, n_head, q_len, kv_seq_len]
|
||
shape = x.shape
|
||
# [bsz, 1, q_len, kv_seq_len]
|
||
shape[1] = 1
|
||
mask = paddle.full(shape, paddle.finfo(x.dtype).min, dtype=x.dtype)
|
||
mask = paddle.triu(mask, diagonal=1)
|
||
mask.stop_gradient = True
|
||
return mask
|
||
|
||
def scaled_dot_product_attention(
|
||
query_states,
|
||
config,
|
||
key_states,
|
||
value_states,
|
||
attention_mask,
|
||
output_attentions,
|
||
attn_mask_startend_row_indices=None,
|
||
training=True,
|
||
sequence_parallel=False,
|
||
skip_recompute=False,
|
||
):
|
||
bsz, q_len, num_heads, head_dim = query_states.shape
|
||
_, kv_seq_len, _, _ = value_states.shape
|
||
|
||
if config.use_flash_attention and flash_attention:
|
||
# Paddle Flash Attention input [ bz, seqlen, nhead, head_dim]
|
||
# Torch Flash Attention input [ bz, nhead, seqlen, head_dim]
|
||
|
||
return fusion_ops.fusion_flash_attention(
|
||
query_states,
|
||
config,
|
||
key_states,
|
||
value_states,
|
||
attention_mask,
|
||
output_attentions,
|
||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||
sequence_parallel=sequence_parallel,
|
||
skip_recompute=skip_recompute,
|
||
)
|
||
else:
|
||
# [ bz, seqlen, nhead, head_dim] -> [bs, nhead, seq_len, head_dim]
|
||
query_states = paddle.transpose(query_states, [0, 2, 1, 3])
|
||
# merge with the next transpose
|
||
key_states = paddle.transpose(key_states, [0, 2, 1, 3])
|
||
value_states = paddle.transpose(value_states, [0, 2, 1, 3])
|
||
|
||
# Add pre divided factor to fix nan under float16.
|
||
if paddle.in_dynamic_mode() and query_states.dtype == paddle.float16:
|
||
pre_divided_factor = 32
|
||
else:
|
||
pre_divided_factor = 1
|
||
|
||
attn_weights = paddle.matmul(
|
||
query_states / (math.sqrt(head_dim) * pre_divided_factor), key_states.transpose([0, 1, 3, 2])
|
||
)
|
||
|
||
if attn_weights.shape != [bsz, num_heads, q_len, kv_seq_len]:
|
||
raise ValueError(
|
||
f"Attention weights should be of shape {(bsz, num_heads, q_len, kv_seq_len)}, but is"
|
||
f" {attn_weights.shape}"
|
||
)
|
||
|
||
if attention_mask is None:
|
||
attention_mask = get_triangle_upper_mask(attn_weights)
|
||
|
||
attention_mask = attention_mask.reshape([bsz, 1, q_len, kv_seq_len])
|
||
if attention_mask.shape != [bsz, 1, q_len, kv_seq_len]:
|
||
raise ValueError(
|
||
f"Attention mask should be of shape {(bsz, 1, q_len, kv_seq_len)}, but is {attention_mask.shape}"
|
||
)
|
||
|
||
attn_weights = attn_weights + attention_mask
|
||
|
||
if not paddle.in_dynamic_mode():
|
||
attn_weights = F.softmax(attn_weights * pre_divided_factor, axis=-1, dtype="float32").astype(
|
||
query_states.dtype
|
||
)
|
||
else:
|
||
with paddle.amp.auto_cast(False):
|
||
attn_weights = F.softmax(
|
||
attn_weights.astype("float32") * pre_divided_factor, axis=-1, dtype="float32"
|
||
).astype(query_states.dtype)
|
||
|
||
attn_weights = F.dropout(attn_weights, p=config.attention_dropout, training=training)
|
||
|
||
attn_output = paddle.matmul(attn_weights, value_states)
|
||
attn_output = attn_output.transpose([0, 2, 1, 3])
|
||
|
||
if sequence_parallel:
|
||
attn_output = attn_output.reshape([bsz * q_len, head_dim * num_heads])
|
||
else:
|
||
attn_output = attn_output.reshape([bsz, q_len, head_dim * num_heads])
|
||
return (attn_output, attn_weights) if output_attentions else attn_output
|
||
|
||
|
||
class Qwen2RMSNorm(LlamaRMSNorm):
|
||
"""Qwen2的RMSNorm,继承自LlamaRMSNorm"""
|
||
def __init__(self, config: Qwen2Config):
|
||
super().__init__(config)
|
||
class Qwen2RotaryEmbedding(LlamaRotaryEmbedding):
|
||
def __init__(self, dim, max_position_embeddings=2048, base=10000):
|
||
super().__init__(dim, max_position_embeddings, base)
|
||
def _set_cos_sin_cache(self, seq_len):
|
||
self.max_seq_len_cached = seq_len
|
||
if self.inv_freq.dtype != paddle.float32:
|
||
self.inv_freq = 1.0 / (
|
||
self.base ** (paddle.cast(paddle.arange(0, self.dim, 2), dtype="float32") / self.dim)
|
||
)
|
||
super()._set_cos_sin_cache(seq_len)
|
||
def forward(self, x, seq_len=None):
|
||
if seq_len > self.max_seq_len_cached:
|
||
self._set_cos_sin_cache(seq_len)
|
||
super().forward(x, seq_len)
|
||
|
||
class Qwen2MLP(LlamaMLP):
|
||
"""Qwen2的MLP,继承自LlamaMLP"""
|
||
def __init__(self, config: Qwen2Config,is_shared=False, skip_recompute_ops=None):
|
||
super().__init__(config)
|
||
if config.hidden_act == "silu":
|
||
self.act_fn = fusion_ops.swiglu
|
||
self.fuse_swiglu = True
|
||
else:
|
||
self.act_fn = ACT2FN[config.hidden_act]
|
||
self.fuse_swiglu = False
|
||
# Qwen2的MLP结构与Llama相同,但使用不同的配置
|
||
def forward(self, x):
|
||
if self.fuse_attention_ffn:
|
||
x = self.gate_up_fused_proj(x)
|
||
if self.fuse_swiglu:
|
||
y = None
|
||
else:
|
||
x, y = x.chunk(2, axis=-1)
|
||
else:
|
||
x, y = self.gate_proj(x), self.up_proj(x)
|
||
|
||
if self.fuse_swiglu:
|
||
x = self.act_fn(x, y)
|
||
else:
|
||
x = self.act_fn(x) * y
|
||
|
||
return self.down_proj(x)
|
||
|
||
class Qwen2Attention(nn.Layer):
|
||
"""
|
||
Multi-headed attention from 'Attention Is All You Need' paper. Modified to use sliding window attention: Longformer
|
||
and "Generating Long Sequences with Sparse Transformers".
|
||
"""
|
||
|
||
def __init__(self, config: Qwen2Config, layerwise_recompute: bool = True, skip_recompute_ops=None):
|
||
super().__init__()
|
||
if skip_recompute_ops is None:
|
||
skip_recompute_ops = {}
|
||
self.config = config
|
||
self.skip_recompute_ops = skip_recompute_ops
|
||
self.hidden_size = config.hidden_size
|
||
self.num_heads = config.num_attention_heads
|
||
self.num_attention_heads = config.num_attention_heads
|
||
|
||
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
||
|
||
self.num_key_value_heads = config.num_key_value_heads
|
||
assert config.num_attention_heads // config.num_key_value_heads
|
||
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
||
self.gqa_or_mqa = config.num_attention_heads != config.num_key_value_heads
|
||
self.max_position_embeddings = config.max_position_embeddings
|
||
self.rope_theta = config.rope_theta
|
||
self.is_causal = True
|
||
self.attention_dropout = config.attention_dropout
|
||
|
||
# self.seq_length = config.seq_length
|
||
self.sequence_parallel = config.sequence_parallel
|
||
self.has_bias = config.attention_bias
|
||
self.fuse_attention_qkv = config.fuse_attention_qkv
|
||
|
||
# Note that we will actually perform a recompute only if both enable_recompute and layerwise_recompute are set to True
|
||
# Enable_recompute defaults to False and is controlled by Trainer
|
||
self.enable_recompute = False
|
||
self.layerwise_recompute = layerwise_recompute
|
||
self.recompute_granularity = config.recompute_granularity
|
||
if config.tensor_parallel_degree > 1:
|
||
assert (
|
||
self.num_heads % config.tensor_parallel_degree == 0
|
||
), f"num_heads: {self.num_heads}, tensor_parallel_degree: {config.tensor_parallel_degree}"
|
||
self.num_heads = self.num_heads // config.tensor_parallel_degree
|
||
|
||
assert (
|
||
self.num_key_value_heads % config.tensor_parallel_degree == 0
|
||
), f"num_key_value_heads: {self.num_key_value_heads}, tensor_parallel_degree: {config.tensor_parallel_degree}"
|
||
self.num_key_value_heads = self.num_key_value_heads // config.tensor_parallel_degree
|
||
|
||
self.use_fused_rope = config.use_fused_rope
|
||
if self.use_fused_rope:
|
||
if get_env_device() not in ["gpu", "xpu"] or fused_rotary_position_embedding is None:
|
||
warnings.warn(
|
||
"Enable fuse rope in the config, but fuse rope is not available. "
|
||
"Will disable fuse rope. Try using latest gpu version of Paddle."
|
||
)
|
||
self.use_fused_rope = False
|
||
|
||
if config.sequence_parallel:
|
||
ColumnParallelLinear = linear_utils.ColumnSequenceParallelLinear
|
||
RowParallelLinear = linear_utils.RowSequenceParallelLinear
|
||
|
||
# NOTE: refined_recompute is only supported when `recompute_use_reentrant=False`
|
||
if config.recompute and not config.recompute_use_reentrant:
|
||
if skip_recompute_ops.get("attention_column_ln", False):
|
||
ColumnParallelLinear = RRColumnSequenceParallelLinear
|
||
if skip_recompute_ops.get("attention_row_ln", False):
|
||
RowParallelLinear = RRRowSequenceParallelLinear
|
||
else:
|
||
ColumnParallelLinear = linear_utils.ColumnParallelLinear
|
||
RowParallelLinear = linear_utils.RowParallelLinear
|
||
|
||
# NOTE: refined_recompute is only supported when `recompute_use_reentrant=False`
|
||
if config.recompute and not config.recompute_use_reentrant:
|
||
if skip_recompute_ops.get("attention_column_ln", False):
|
||
ColumnParallelLinear = RRColumnParallelLinear
|
||
if skip_recompute_ops.get("attention_row_ln", False):
|
||
RowParallelLinear = RRRowParallelLinear
|
||
|
||
if config.tensor_parallel_degree > 1:
|
||
if self.fuse_attention_qkv:
|
||
self.qkv_proj = ColumnParallelLinear(
|
||
self.hidden_size,
|
||
self.num_attention_heads * self.head_dim + 2 * self.config.num_key_value_heads * self.head_dim,
|
||
has_bias=self.has_bias,
|
||
gather_output=False,
|
||
)
|
||
else:
|
||
self.q_proj = ColumnParallelLinear(
|
||
self.hidden_size,
|
||
self.num_attention_heads * self.head_dim,
|
||
has_bias=self.has_bias,
|
||
gather_output=False,
|
||
)
|
||
self.k_proj = ColumnParallelLinear(self.hidden_size, self.config.num_key_value_heads * self.head_dim, has_bias=self.has_bias, gather_output=False) # fmt:skip
|
||
self.v_proj = ColumnParallelLinear(self.hidden_size, self.config.num_key_value_heads * self.head_dim, has_bias=self.has_bias, gather_output=False) # fmt:skip
|
||
self.o_proj = RowParallelLinear(self.hidden_size, self.hidden_size, has_bias=False, input_is_parallel=True)
|
||
else:
|
||
if self.fuse_attention_qkv:
|
||
self.qkv_proj = Linear(
|
||
self.hidden_size,
|
||
self.num_attention_heads * self.head_dim + 2 * self.config.num_key_value_heads * self.head_dim,
|
||
)
|
||
else:
|
||
self.q_proj = Linear(
|
||
self.hidden_size, self.num_attention_heads * self.head_dim, bias_attr=self.has_bias
|
||
)
|
||
self.k_proj = Linear(
|
||
self.hidden_size, self.config.num_key_value_heads * self.head_dim, bias_attr=self.has_bias
|
||
)
|
||
self.v_proj = Linear(
|
||
self.hidden_size, self.config.num_key_value_heads * self.head_dim, bias_attr=self.has_bias
|
||
)
|
||
self.o_proj = Linear(self.num_attention_heads * self.head_dim, self.hidden_size, bias_attr=False)
|
||
|
||
self.rotary_emb = Qwen2RotaryEmbedding(
|
||
self.head_dim,
|
||
max_position_embeddings=self.max_position_embeddings,
|
||
base=self.rope_theta,
|
||
)
|
||
|
||
self.attn_func = scaled_dot_product_attention
|
||
|
||
# NOTE: refined_recompute is only supported when `recompute_use_reentrant=False`
|
||
if config.recompute and not config.recompute_use_reentrant and skip_recompute_ops.get("flash_attn", False):
|
||
self.attn_func = partial(scaled_dot_product_attention, skip_recompute=True)
|
||
|
||
def forward(
|
||
self,
|
||
hidden_states,
|
||
position_ids: Optional[Tuple[paddle.Tensor]] = None,
|
||
past_key_value: Optional[Tuple[paddle.Tensor]] = None,
|
||
attention_mask: Optional[paddle.Tensor] = None,
|
||
output_attentions: bool = False,
|
||
use_cache: bool = False,
|
||
attn_mask_startend_row_indices: Optional[paddle.Tensor] = None,
|
||
batch_size: Optional[int] = None,
|
||
**kwargs,
|
||
) -> Tuple[paddle.Tensor, Optional[paddle.Tensor], Optional[Tuple[paddle.Tensor]]]:
|
||
"""Input shape: Batch x Time x Channel"""
|
||
# [bs, seq_len, num_head * head_dim] -> [seq_len / n, bs, num_head * head_dim] (n is model parallelism)
|
||
|
||
if self.fuse_attention_qkv:
|
||
mix_layer = self.qkv_proj(hidden_states)
|
||
if self.sequence_parallel:
|
||
target_shape = [
|
||
batch_size,
|
||
-1,
|
||
self.num_key_value_heads,
|
||
(self.num_key_value_groups + 2) * self.head_dim,
|
||
]
|
||
else:
|
||
target_shape = [0, 0, self.num_key_value_heads, (self.num_key_value_groups + 2) * self.head_dim]
|
||
mix_layer = paddle.reshape_(mix_layer, target_shape)
|
||
query_states, key_states, value_states = paddle.split(
|
||
mix_layer,
|
||
num_or_sections=[self.num_key_value_groups * self.head_dim, self.head_dim, self.head_dim],
|
||
axis=-1,
|
||
)
|
||
if self.gqa_or_mqa:
|
||
query_states = paddle.reshape_(query_states, [0, 0, self.num_heads, self.head_dim])
|
||
else:
|
||
query_states = self.q_proj(hidden_states)
|
||
key_states = self.k_proj(hidden_states)
|
||
value_states = self.v_proj(hidden_states)
|
||
|
||
if self.sequence_parallel:
|
||
target_query_shape = [batch_size, -1, self.num_heads, self.head_dim]
|
||
target_key_value_shape = [batch_size, -1, self.num_key_value_heads, self.head_dim]
|
||
else:
|
||
target_query_shape = [0, 0, self.num_heads, self.head_dim]
|
||
target_key_value_shape = [0, 0, self.num_key_value_heads, self.head_dim]
|
||
query_states = query_states.reshape(shape=target_query_shape)
|
||
key_states = key_states.reshape(shape=target_key_value_shape)
|
||
value_states = value_states.reshape(shape=target_key_value_shape)
|
||
|
||
if position_ids is not None and not self.use_fused_rope:
|
||
kv_seq_len = position_ids.max().item() + 1
|
||
else:
|
||
kv_seq_len = key_states.shape[-3]
|
||
if past_key_value is not None:
|
||
kv_seq_len += past_key_value[0].shape[-3]
|
||
if self.use_fused_rope:
|
||
assert past_key_value is None, "fuse rotary not support cache kv for now"
|
||
cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len)
|
||
query_states, key_states, _ = fused_rotary_position_embedding(
|
||
query_states,
|
||
key_states,
|
||
v=None,
|
||
sin=sin,
|
||
cos=cos,
|
||
position_ids=position_ids,
|
||
use_neox_rotary_style=False,
|
||
)
|
||
else:
|
||
cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len)
|
||
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
|
||
|
||
# [bs, seq_len, num_head, head_dim]
|
||
if past_key_value is not None:
|
||
key_states = paddle.concat([past_key_value[0], key_states], axis=1)
|
||
value_states = paddle.concat([past_key_value[1], value_states], axis=1)
|
||
past_key_value = (key_states, value_states) if use_cache else None
|
||
|
||
# TODO(wj-Mcat): use broadcast strategy when n_kv_heads = 1
|
||
# repeat k/v heads if n_kv_heads < n_heads
|
||
paddle_version = float(paddle.__version__[:3])
|
||
if not self.config.use_flash_attention or ((paddle_version != 0.0) and (paddle_version <= 2.6)):
|
||
key_states = repeat_kv(key_states, self.num_key_value_groups)
|
||
value_states = repeat_kv(value_states, self.num_key_value_groups)
|
||
|
||
has_gradient = not (query_states.stop_gradient and key_states.stop_gradient and value_states.stop_gradient)
|
||
if (
|
||
self.enable_recompute
|
||
and self.layerwise_recompute
|
||
and has_gradient
|
||
and self.recompute_granularity == "core_attn"
|
||
):
|
||
recompute_fn = rr_recompute if any(self.skip_recompute_ops.values()) else recompute
|
||
outputs = recompute_fn(
|
||
self.attn_func,
|
||
query_states,
|
||
self.config,
|
||
key_states,
|
||
value_states,
|
||
attention_mask,
|
||
output_attentions,
|
||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||
training=self.training,
|
||
sequence_parallel=self.sequence_parallel,
|
||
use_reentrant=self.config.recompute_use_reentrant,
|
||
)
|
||
else:
|
||
outputs = self.attn_func(
|
||
query_states,
|
||
self.config,
|
||
key_states,
|
||
value_states,
|
||
attention_mask,
|
||
output_attentions,
|
||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||
training=self.training,
|
||
sequence_parallel=self.sequence_parallel,
|
||
)
|
||
if output_attentions:
|
||
attn_output, attn_weights = outputs
|
||
else:
|
||
attn_output = outputs
|
||
|
||
# if sequence_parallel is true, out shape are [q_len / n, bs, num_head * head_dim]
|
||
# else their shape are [bs, q_len, num_head * head_dim], n is mp parallelism.
|
||
attn_output = self.o_proj(attn_output)
|
||
|
||
if not output_attentions:
|
||
attn_weights = None
|
||
|
||
outputs = (attn_output,)
|
||
|
||
if output_attentions:
|
||
outputs += (attn_weights,)
|
||
|
||
if use_cache:
|
||
outputs += (past_key_value,)
|
||
|
||
if type(outputs) is tuple and len(outputs) == 1:
|
||
outputs = outputs[0]
|
||
|
||
return outputs
|
||
|
||
|
||
class Qwen2DecoderLayer(LlamaDecoderLayer):
|
||
"""Qwen2的解码器层,继承自LlamaDecoderLayer"""
|
||
def __init__(self, config: Qwen2Config, layerwise_recompute: bool = False, skip_recompute_ops=None):
|
||
super().__init__(config)
|
||
def forward(
|
||
self,
|
||
hidden_states: paddle.Tensor,
|
||
position_ids: Optional[paddle.Tensor] = None,
|
||
attention_mask: Optional[paddle.Tensor] = None,
|
||
output_attentions: Optional[bool] = False,
|
||
past_key_value: Optional[Tuple[paddle.Tensor]] = None,
|
||
use_cache: Optional[bool] = False,
|
||
attn_mask_startend_row_indices: Optional[paddle.Tensor] = None,
|
||
batch_size: Optional[int] = None,
|
||
**kwargs,
|
||
) -> Tuple[paddle.Tensor, Optional[Tuple[paddle.Tensor, paddle.Tensor]]]:
|
||
"""
|
||
Args:
|
||
hidden_states (`paddle.Tensor`): input to the layer of shape `(batch, seq_len, embed_dim)`
|
||
attention_mask (`paddle.Tensor`, *optional*): attention mask of size
|
||
`(batch, sequence_length)` where padding elements are indicated by 0.
|
||
output_attentions (`bool`, *optional*):
|
||
Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
||
returned tensors for more detail.
|
||
use_cache (`bool`, *optional*):
|
||
If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding
|
||
(see `past_key_values`).
|
||
past_key_value (`Tuple(paddle.Tensor)`, *optional*): cached past key and value projection states
|
||
"""
|
||
|
||
# [bs * seq_len, embed_dim] -> [seq_len * bs / n, embed_dim] (sequence_parallel)
|
||
residual = hidden_states
|
||
|
||
hidden_states = self.input_layernorm(hidden_states)
|
||
|
||
# Self Attention
|
||
has_gradient = not hidden_states.stop_gradient
|
||
if (
|
||
self.enable_recompute
|
||
and self.layerwise_recompute
|
||
and has_gradient
|
||
and self.recompute_granularity == "full_attn"
|
||
):
|
||
recompute_fn = rr_recompute if any(self.skip_recompute_ops.values()) else recompute
|
||
outputs = recompute_fn(
|
||
self.self_attn,
|
||
hidden_states,
|
||
position_ids,
|
||
past_key_value,
|
||
attention_mask,
|
||
output_attentions,
|
||
use_cache,
|
||
attn_mask_startend_row_indices,
|
||
batch_size,
|
||
use_reentrant=self.config.recompute_use_reentrant,
|
||
)
|
||
else:
|
||
outputs = self.self_attn(
|
||
hidden_states,
|
||
position_ids,
|
||
past_key_value,
|
||
attention_mask,
|
||
output_attentions,
|
||
use_cache,
|
||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||
batch_size=batch_size,
|
||
)
|
||
|
||
if type(outputs) is tuple:
|
||
hidden_states = outputs[0]
|
||
else:
|
||
hidden_states = outputs
|
||
|
||
if output_attentions:
|
||
self_attn_weights = outputs[1]
|
||
|
||
if use_cache:
|
||
present_key_value = outputs[2 if output_attentions else 1]
|
||
|
||
hidden_states = residual + hidden_states
|
||
|
||
# Fully Connected
|
||
residual = hidden_states
|
||
hidden_states = self.post_attention_layernorm(hidden_states)
|
||
hidden_states = self.mlp(hidden_states)
|
||
|
||
hidden_states = residual + hidden_states
|
||
|
||
outputs = (hidden_states,)
|
||
|
||
if output_attentions:
|
||
outputs += (self_attn_weights,)
|
||
|
||
if use_cache:
|
||
outputs += (present_key_value,)
|
||
|
||
if type(outputs) is tuple and len(outputs) == 1:
|
||
outputs = outputs[0]
|
||
|
||
return outputs
|
||
|
||
|
||
class Qwen2PretrainedModel(LlamaPretrainedModel):
|
||
"""Qwen2预训练模型基类,继承自LlamaPretrainedModel"""
|
||
config_class = Qwen2Config
|
||
base_model_prefix = "qwen2"
|
||
_keys_to_ignore_on_load_unexpected = [r"self_attn.rotary_emb.inv_freq"]
|
||
@classmethod
|
||
def _get_name_mappings(cls, config: Qwen2Config) -> list[StateDictNameMapping]:
|
||
mappings: list[StateDictNameMapping] = []
|
||
model_mappings = [
|
||
["embed_tokens.weight"],
|
||
["norm.weight"],
|
||
]
|
||
for layer_index in range(config.num_hidden_layers):
|
||
layer_mappings = [
|
||
[f"layers.{layer_index}.self_attn.q_proj.weight", None, "transpose"],
|
||
[f"layers.{layer_index}.self_attn.k_proj.weight", None, "transpose"],
|
||
[f"layers.{layer_index}.self_attn.v_proj.weight", None, "transpose"],
|
||
[f"layers.{layer_index}.self_attn.q_proj.bias", None],
|
||
[f"layers.{layer_index}.self_attn.k_proj.bias", None],
|
||
[f"layers.{layer_index}.self_attn.v_proj.bias", None],
|
||
[f"layers.{layer_index}.self_attn.o_proj.weight", None, "transpose"],
|
||
[f"layers.{layer_index}.mlp.up_proj.weight", None, "transpose"],
|
||
[f"layers.{layer_index}.mlp.gate_proj.weight", None, "transpose"],
|
||
[f"layers.{layer_index}.mlp.down_proj.weight", None, "transpose"],
|
||
[f"layers.{layer_index}.self_attn.rotary_emb.inv_freq"],
|
||
[f"layers.{layer_index}.input_layernorm.weight"],
|
||
[f"layers.{layer_index}.post_attention_layernorm.weight"],
|
||
]
|
||
model_mappings.extend(layer_mappings)
|
||
|
||
init_name_mappings(mappings=model_mappings)
|
||
# base-model prefix "Qwen2MoEModel"
|
||
if "Qwen2Model" not in config.architectures:
|
||
for mapping in model_mappings:
|
||
mapping[0] = "model." + mapping[0]
|
||
mapping[1] = "qwen2." + mapping[1]
|
||
if not config.tie_word_embeddings:
|
||
model_mappings.append(["lm_head.weight", "lm_head.weight", "transpose"])
|
||
|
||
mappings = [StateDictNameMapping(*mapping, index=index) for index, mapping in enumerate(model_mappings)]
|
||
return mappings
|
||
|
||
@classmethod
|
||
def _get_tensor_parallel_mappings(cls, config: Qwen2Config, is_split=True):
|
||
|
||
from ..conversion_utils import split_or_merge_func
|
||
|
||
fn = split_or_merge_func(
|
||
is_split=is_split,
|
||
tensor_parallel_degree=config.tensor_parallel_degree,
|
||
tensor_parallel_rank=config.tensor_parallel_rank,
|
||
num_attention_heads=config.num_attention_heads,
|
||
)
|
||
|
||
def get_tensor_parallel_split_mappings(num_layers):
|
||
final_actions = {}
|
||
|
||
base_actions = {
|
||
# Row Linear
|
||
"embed_tokens.weight": partial(fn, is_column=False),
|
||
"layers.0.self_attn.o_proj.weight": partial(fn, is_column=False),
|
||
"layers.0.mlp.down_proj.weight": partial(fn, is_column=False),
|
||
}
|
||
|
||
if config.tie_word_embeddings:
|
||
base_actions["lm_head.weight"] = partial(fn, is_column=False)
|
||
else:
|
||
base_actions["lm_head.weight"] = partial(fn, is_column=True)
|
||
|
||
if not config.vocab_size % config.tensor_parallel_degree == 0:
|
||
base_actions.pop("lm_head.weight")
|
||
base_actions.pop("embed_tokens.weight")
|
||
# Column Linear
|
||
if config.fuse_attention_qkv:
|
||
base_actions["layers.0.self_attn.qkv_proj.weight"] = partial(fn, is_column=True)
|
||
base_actions["layers.0.self_attn.qkv_proj.bias"] = partial(fn, is_column=True)
|
||
else:
|
||
base_actions["layers.0.self_attn.q_proj.weight"] = partial(fn, is_column=True)
|
||
base_actions["layers.0.self_attn.q_proj.bias"] = partial(fn, is_column=True)
|
||
# if we have enough num_key_value_heads to split, then split it.
|
||
if config.num_key_value_heads % config.tensor_parallel_degree == 0:
|
||
base_actions["layers.0.self_attn.k_proj.weight"] = partial(fn, is_column=True)
|
||
base_actions["layers.0.self_attn.v_proj.weight"] = partial(fn, is_column=True)
|
||
base_actions["layers.0.self_attn.k_proj.bias"] = partial(fn, is_column=True)
|
||
base_actions["layers.0.self_attn.v_proj.bias"] = partial(fn, is_column=True)
|
||
|
||
if config.fuse_attention_ffn:
|
||
base_actions["layers.0.mlp.gate_up_fused_proj.weight"] = partial(
|
||
fn, is_column=True, is_naive_2fuse=True
|
||
)
|
||
else:
|
||
base_actions["layers.0.mlp.gate_proj.weight"] = partial(fn, is_column=True)
|
||
base_actions["layers.0.mlp.up_proj.weight"] = partial(fn, is_column=True)
|
||
|
||
for key, action in base_actions.items():
|
||
if "layers.0." in key:
|
||
for i in range(num_layers):
|
||
final_actions[key.replace("layers.0.", f"layers.{i}.")] = action
|
||
final_actions[key] = action
|
||
|
||
return final_actions
|
||
|
||
mappings = get_tensor_parallel_split_mappings(config.num_hidden_layers)
|
||
|
||
return mappings
|
||
@classmethod
|
||
def _get_fuse_or_split_param_mappings(cls, config: Qwen2Config, is_fuse=False):
|
||
# return parameter fuse utils
|
||
from ..conversion_utils import split_or_fuse_func
|
||
|
||
fn = split_or_fuse_func(is_fuse=is_fuse)
|
||
|
||
# last key is fused key, other keys are to be fused.
|
||
fuse_qkv_keys = [
|
||
(
|
||
"layers.0.self_attn.q_proj.weight",
|
||
"layers.0.self_attn.k_proj.weight",
|
||
"layers.0.self_attn.v_proj.weight",
|
||
"layers.0.self_attn.qkv_proj.weight",
|
||
),
|
||
(
|
||
"layers.0.self_attn.q_proj.bias",
|
||
"layers.0.self_attn.k_proj.bias",
|
||
"layers.0.self_attn.v_proj.bias",
|
||
"layers.0.self_attn.qkv_proj.bias",
|
||
),
|
||
]
|
||
|
||
fuse_gate_up_keys = (
|
||
"layers.0.mlp.gate_proj.weight",
|
||
"layers.0.mlp.up_proj.weight",
|
||
"layers.0.mlp.gate_up_fused_proj.weight",
|
||
)
|
||
num_heads = config.num_attention_heads
|
||
num_key_value_heads = getattr(config, "num_key_value_heads", num_heads)
|
||
fuse_attention_qkv = getattr(config, "fuse_attention_qkv", False)
|
||
fuse_attention_ffn = getattr(config, "fuse_attention_ffn", False)
|
||
|
||
final_actions = {}
|
||
if is_fuse:
|
||
if fuse_attention_qkv:
|
||
for i in range(config.num_hidden_layers):
|
||
for fuse_keys in fuse_qkv_keys:
|
||
keys = tuple([key.replace("layers.0.", f"layers.{i}.") for key in fuse_keys])
|
||
final_actions[keys] = partial(
|
||
fn, is_qkv=True, num_heads=num_heads, num_key_value_heads=num_key_value_heads
|
||
)
|
||
if fuse_attention_ffn:
|
||
for i in range(config.num_hidden_layers):
|
||
keys = tuple([key.replace("layers.0.", f"layers.{i}.") for key in fuse_gate_up_keys])
|
||
final_actions[keys] = fn
|
||
else:
|
||
if not fuse_attention_qkv:
|
||
for i in range(config.num_hidden_layers):
|
||
for fuse_keys in fuse_qkv_keys:
|
||
keys = tuple([key.replace("layers.0.", f"layers.{i}.") for key in fuse_keys])
|
||
final_actions[keys] = partial(
|
||
fn, split_nums=3, is_qkv=True, num_heads=num_heads, num_key_value_heads=num_key_value_heads
|
||
)
|
||
if not fuse_attention_ffn:
|
||
for i in range(config.num_hidden_layers):
|
||
keys = tuple([key.replace("layers.0.", f"layers.{i}.") for key in fuse_gate_up_keys])
|
||
final_actions[keys] = partial(fn, split_nums=2)
|
||
return final_actions
|
||
|
||
def _get_model_flops(self):
|
||
if hasattr(self.config, "seq_length"):
|
||
seq_length = self.config.seq_length
|
||
else:
|
||
seq_length = 2048
|
||
|
||
return caculate_llm_per_token_flops(
|
||
hidden_size=self.config.hidden_size,
|
||
intermediate_size=self.config.intermediate_size,
|
||
layer_num=self.config.num_hidden_layers,
|
||
vocab_size=self.config.vocab_size,
|
||
seq_length=seq_length,
|
||
recompute=False,
|
||
)
|
||
|
||
def _get_hardware_flops(self):
|
||
if hasattr(self.config, "seq_length"):
|
||
seq_length = self.config.seq_length
|
||
else:
|
||
seq_length = 2048
|
||
|
||
return caculate_llm_per_token_flops(
|
||
hidden_size=self.config.hidden_size,
|
||
intermediate_size=self.config.intermediate_size,
|
||
layer_num=self.config.num_hidden_layers,
|
||
vocab_size=self.config.vocab_size,
|
||
seq_length=seq_length,
|
||
recompute=self.config.recompute,
|
||
recompute_granularity=self.config.recompute_granularity,
|
||
)
|
||
|
||
|
||
@register_base_model
|
||
class Qwen2Model(LlamaModel):
|
||
"""Qwen2模型,继承自LlamaModel"""
|
||
def __init__(self, config: Qwen2Config):
|
||
super().__init__(config)
|
||
self.padding_idx = config.pad_token_id
|
||
@paddle.jit.not_to_static
|
||
def recompute_training_full(
|
||
self,
|
||
layer_module: nn.Layer,
|
||
hidden_states: Tensor,
|
||
position_ids: Optional[Tensor],
|
||
attention_mask: Tensor,
|
||
output_attentions: bool,
|
||
past_key_value: Tensor,
|
||
use_cache: bool,
|
||
attn_mask_startend_row_indices=None,
|
||
batch_size: int = None,
|
||
):
|
||
def create_custom_forward(module):
|
||
def custom_forward(*inputs):
|
||
return module(*inputs)
|
||
|
||
return custom_forward
|
||
|
||
recompute_fn = rr_recompute if any(layer_module.skip_recompute_ops.values()) else recompute
|
||
hidden_states = recompute_fn(
|
||
create_custom_forward(layer_module),
|
||
hidden_states,
|
||
position_ids,
|
||
attention_mask,
|
||
output_attentions,
|
||
past_key_value,
|
||
use_cache,
|
||
attn_mask_startend_row_indices,
|
||
batch_size,
|
||
use_reentrant=self.config.recompute_use_reentrant,
|
||
)
|
||
|
||
return hidden_states
|
||
def forward(
|
||
self,
|
||
input_ids: paddle.Tensor = None,
|
||
position_ids: Optional[paddle.Tensor] = None,
|
||
attention_mask: Optional[paddle.Tensor] = None,
|
||
inputs_embeds: Optional[paddle.Tensor] = None,
|
||
use_cache: Optional[bool] = None,
|
||
past_key_values: Optional[List[paddle.Tensor]] = None,
|
||
output_attentions: Optional[bool] = None,
|
||
output_hidden_states: Optional[bool] = None,
|
||
return_dict: Optional[bool] = None,
|
||
attn_mask_startend_row_indices=None,
|
||
) -> Union[Tuple, BaseModelOutputWithPast]:
|
||
super().forward()
|
||
class Qwen2PretrainingCriterion(LlamaPretrainingCriterion):
|
||
"""Qwen2的预训练损失计算,继承自LlamaPretrainingCriterion"""
|
||
def __init__(self, config: Qwen2Config):
|
||
super().__init__(config)
|
||
self.enable_parallel_cross_entropy = config.tensor_parallel_degree > 1 and config.tensor_parallel_output
|
||
|
||
class Qwen2LMHead(LlamaLMHead):
|
||
"""Qwen2的语言模型头,继承自LlamaLMHead"""
|
||
def __init__(self, config: Qwen2Config):
|
||
super().__init__(config)
|
||
def forward(self, hidden_states, tensor_parallel_output=None, batch_size=None):
|
||
if self.config.sequence_parallel:
|
||
hidden_states = GatherOp.apply(hidden_states)
|
||
hidden_states = paddle.reshape_(hidden_states, [batch_size, -1, self.config.hidden_size])
|
||
|
||
if tensor_parallel_output is None:
|
||
tensor_parallel_output = self.config.tensor_parallel_output
|
||
|
||
logits = parallel_matmul(
|
||
hidden_states, self.weight, transpose_y=self.transpose_y, tensor_parallel_output=tensor_parallel_output
|
||
)
|
||
return logits
|
||
class Qwen2ForCausalLM(LlamaForCausalLM):
|
||
"""用于因果语言建模的Qwen2模型,继承自LlamaForCausalLM"""
|
||
def __init__(self, config: Qwen2Config):
|
||
super().__init__(config)
|
||
@staticmethod
|
||
def update_model_kwargs_for_generation(outputs, model_kwargs, is_encoder_decoder=False):
|
||
# update cache
|
||
if isinstance(outputs, tuple) and len(outputs) > 1 and not isinstance(outputs[1], paddle.Tensor):
|
||
model_kwargs["past_key_values"] = outputs[1]
|
||
|
||
if isinstance(outputs, CausalLMOutputWithPast) and "past_key_values" in outputs:
|
||
model_kwargs["past_key_values"] = outputs.past_key_values
|
||
|
||
# update position_ids
|
||
if "position_ids" in model_kwargs and model_kwargs["position_ids"] is not None:
|
||
position_ids = model_kwargs["position_ids"]
|
||
model_kwargs["position_ids"] = paddle.concat([position_ids, position_ids[..., -1:] + 1], axis=-1)
|
||
|
||
if not is_encoder_decoder and "attention_mask" in model_kwargs:
|
||
# TODO: support attention mask for other models
|
||
attention_mask = model_kwargs["attention_mask"]
|
||
if len(attention_mask.shape) == 2:
|
||
model_kwargs["attention_mask"] = paddle.concat(
|
||
[attention_mask, paddle.ones([attention_mask.shape[0], 1], dtype=attention_mask.dtype)],
|
||
axis=-1,
|
||
)
|
||
elif len(attention_mask.shape) == 4:
|
||
model_kwargs["attention_mask"] = paddle.concat(
|
||
[attention_mask, paddle.ones([*attention_mask.shape[:3], 1], dtype=attention_mask.dtype)],
|
||
axis=-1,
|
||
)[:, :, -1:, :]
|
||
|
||
return model_kwargs
|
||
|
||
def forward(
|
||
self,
|
||
input_ids: paddle.Tensor = None,
|
||
position_ids: Optional[paddle.Tensor] = None,
|
||
attention_mask: Optional[paddle.Tensor] = None,
|
||
inputs_embeds: Optional[paddle.Tensor] = None,
|
||
labels: Optional[paddle.Tensor] = None,
|
||
use_cache: Optional[bool] = None,
|
||
past_key_values: Optional[List[paddle.Tensor]] = None,
|
||
output_attentions: Optional[bool] = None,
|
||
output_hidden_states: Optional[bool] = None,
|
||
return_dict: Optional[bool] = None,
|
||
attn_mask_startend_row_indices=None,
|
||
) -> Union[Tuple, CausalLMOutputWithPast]:
|
||
r"""
|
||
Args:
|
||
labels (`paddle.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
|
||
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
||
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
||
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
||
|
||
Returns:
|
||
|
||
Example:
|
||
|
||
```python
|
||
>>> from transformers import AutoTokenizer, Qwen2ForCausalLM
|
||
|
||
>>> model = Qwen2ForCausalLM.from_pretrained(PATH_TO_CONVERTED_WEIGHTS)
|
||
>>> tokenizer = AutoTokenizer.from_pretrained(PATH_TO_CONVERTED_TOKENIZER)
|
||
|
||
>>> prompt = "Hey, are you conscious? Can you talk to me?"
|
||
>>> inputs = tokenizer(prompt, return_tensors="pt")
|
||
|
||
>>> # Generate
|
||
>>> generate_ids = model.generate(inputs.input_ids, max_length=30)
|
||
>>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
||
"Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
|
||
```"""
|
||
|
||
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
||
output_hidden_states = (
|
||
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
||
)
|
||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||
|
||
if attn_mask_startend_row_indices is not None and attention_mask is not None:
|
||
logger.warning(
|
||
"You have provided both attn_mask_startend_row_indices and attention_mask. "
|
||
"The attn_mask_startend_row_indices will be used."
|
||
)
|
||
attention_mask = None
|
||
|
||
if input_ids is not None and inputs_embeds is not None:
|
||
raise ValueError("You cannot specify both decoder_input_ids and decoder_inputs_embeds at the same time")
|
||
elif input_ids is not None:
|
||
batch_size = input_ids.shape[0]
|
||
elif inputs_embeds is not None:
|
||
batch_size = inputs_embeds.shape[0]
|
||
else:
|
||
raise ValueError("You have to specify either decoder_input_ids or decoder_inputs_embeds")
|
||
|
||
# decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
|
||
outputs = self.qwen2(
|
||
input_ids=input_ids,
|
||
position_ids=position_ids,
|
||
attention_mask=attention_mask,
|
||
inputs_embeds=inputs_embeds,
|
||
use_cache=use_cache,
|
||
past_key_values=past_key_values,
|
||
output_attentions=output_attentions,
|
||
output_hidden_states=output_hidden_states,
|
||
return_dict=return_dict,
|
||
attn_mask_startend_row_indices=attn_mask_startend_row_indices,
|
||
)
|
||
|
||
hidden_states = outputs[0]
|
||
|
||
# add this for fused_head_and_loss_fn
|
||
if self.config.use_fused_head_and_loss_fn and self.training:
|
||
if self.config.tensor_parallel_degree > 1 and self.config.sequence_parallel:
|
||
hidden_states = GatherOp.apply(hidden_states)
|
||
hidden_states = hidden_states.reshape(
|
||
[
|
||
batch_size,
|
||
-1,
|
||
hidden_states.shape[-1],
|
||
]
|
||
)
|
||
return hidden_states, self.lm_head.weight, None, self.lm_head.transpose_y
|
||
|
||
# if labels is None,means we need full output, instead of tensor_parallel_output
|
||
# tensor_parallel_output is together with ParallelCrossEntropy
|
||
tensor_parallel_output = self.config.tensor_parallel_output and self.config.tensor_parallel_degree > 1
|
||
|
||
if labels is not None and self.config.use_fused_linear_cross_entropy:
|
||
from paddlenlp_kernel.triton.cut_cross_entropy import linear_cross_entropy
|
||
|
||
assert (
|
||
self.config.tensor_parallel_degree <= 1
|
||
), "The argument `use_fused_linear_cross_entropy` is imcompatiable with tensor parallel "
|
||
|
||
masked_lm_loss = linear_cross_entropy(hidden_states, self.lm_head.weight, targets=labels)
|
||
|
||
binary_sequence = paddle.where(
|
||
masked_lm_loss > 0, paddle.ones_like(masked_lm_loss), paddle.zeros_like(masked_lm_loss)
|
||
)
|
||
count = paddle.sum(binary_sequence)
|
||
if count == 0:
|
||
loss = paddle.sum(masked_lm_loss * binary_sequence)
|
||
else:
|
||
loss = paddle.sum(masked_lm_loss * binary_sequence) / count
|
||
logits = None
|
||
else:
|
||
logits = self.lm_head(hidden_states, tensor_parallel_output=tensor_parallel_output, batch_size=batch_size)
|
||
|
||
loss = None
|
||
if labels is not None:
|
||
loss = self.criterion(logits, labels)
|
||
|
||
if not return_dict:
|
||
output = (logits,) + outputs[1:]
|
||
return (loss,) + output if loss is not None else output
|
||
|
||
return CausalLMOutputWithPast(
|
||
loss=loss,
|
||
logits=logits,
|
||
past_key_values=outputs.past_key_values,
|
||
hidden_states=outputs.hidden_states,
|
||
attentions=outputs.attentions,
|
||
)
|
||
|
||
|
||
class Qwen2ForSequenceClassification(Qwen2PretrainedModel):
|
||
def __init__(self, config: Qwen2Config):
|
||
super().__init__(config)
|
||
self.num_labels = config.num_labels
|
||
self.qwen2 = Qwen2Model(config)
|
||
self.score = Linear(config.hidden_size, self.num_labels, bias_attr=False)
|
||
|
||
def get_input_embeddings(self):
|
||
return self.qwen2.embed_tokens
|
||
|
||
def set_input_embeddings(self, value):
|
||
self.qwen2.embed_tokens = value
|
||
|
||
def forward(
|
||
self,
|
||
input_ids: paddle.Tensor = None,
|
||
position_ids: Optional[paddle.Tensor] = None,
|
||
attention_mask: Optional[paddle.Tensor] = None,
|
||
inputs_embeds: Optional[paddle.Tensor] = None,
|
||
past_key_values: Optional[List[paddle.Tensor]] = None,
|
||
labels: Optional[paddle.Tensor] = None,
|
||
use_cache: Optional[bool] = None,
|
||
output_attentions: Optional[bool] = None,
|
||
output_hidden_states: Optional[bool] = None,
|
||
return_dict: Optional[bool] = None,
|
||
) -> Union[Tuple, SequenceClassifierOutputWithPast]:
|
||
r"""
|
||
labels (`paddle.Tensor` of shape `(batch_size,)`, *optional*):
|
||
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
||
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
||
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
||
"""
|
||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||
|
||
transformer_outputs = self.qwen2(
|
||
input_ids,
|
||
attention_mask=attention_mask,
|
||
position_ids=position_ids,
|
||
past_key_values=past_key_values,
|
||
inputs_embeds=inputs_embeds,
|
||
use_cache=use_cache,
|
||
output_attentions=output_attentions,
|
||
output_hidden_states=output_hidden_states,
|
||
return_dict=return_dict,
|
||
)
|
||
hidden_states = transformer_outputs[0]
|
||
logits = self.score(hidden_states)
|
||
|
||
if input_ids is not None:
|
||
batch_size = input_ids.shape[0]
|
||
else:
|
||
batch_size = inputs_embeds.shape[0]
|
||
|
||
if self.config.pad_token_id is None and batch_size != 1:
|
||
raise ValueError("Cannot handle batch sizes > 1 if no padding token is defined.")
|
||
if self.config.pad_token_id is None:
|
||
sequence_lengths = -1
|
||
else:
|
||
if input_ids is not None:
|
||
# if no pad token found, use modulo instead of reverse indexing for ONNX compatibility
|
||
sequence_lengths = paddle.equal(input_ids, self.config.pad_token_id).astype("int32").argmax(-1) - 1
|
||
sequence_lengths = sequence_lengths % input_ids.shape[-1]
|
||
sequence_lengths = sequence_lengths
|
||
else:
|
||
sequence_lengths = -1
|
||
|
||
# pooled_logits = logits[paddle.arange(batch_size), sequence_lengths]
|
||
pooled_logits = logits.gather_nd(paddle.stack([paddle.arange(logits.shape[0]), sequence_lengths], axis=-1))
|
||
|
||
loss = None
|
||
if labels is not None:
|
||
if self.config.problem_type is None:
|
||
if self.num_labels == 1:
|
||
self.config.problem_type = "regression"
|
||
elif self.num_labels > 1 and (labels.dtype == paddle.int64 or labels.dtype == paddle.int32):
|
||
self.config.problem_type = "single_label_classification"
|
||
else:
|
||
self.config.problem_type = "multi_label_classification"
|
||
|
||
if self.config.problem_type == "regression":
|
||
loss_fct = nn.MSELoss()
|
||
if self.num_labels == 1:
|
||
loss = loss_fct(pooled_logits.squeeze(), labels.squeeze())
|
||
else:
|
||
loss = loss_fct(pooled_logits, labels)
|
||
elif self.config.problem_type == "single_label_classification":
|
||
loss_fct = nn.CrossEntropyLoss()
|
||
loss = loss_fct(pooled_logits.reshape([-1, self.num_labels]), labels.reshape([-1]))
|
||
elif self.config.problem_type == "multi_label_classification":
|
||
loss_fct = nn.BCEWithLogitsLoss()
|
||
loss = loss_fct(pooled_logits, labels)
|
||
if not return_dict:
|
||
output = (pooled_logits,) + transformer_outputs[1:]
|
||
return ((loss,) + output) if loss is not None else output
|
||
|
||
return SequenceClassifierOutputWithPast(
|
||
loss=loss,
|
||
logits=pooled_logits,
|
||
past_key_values=transformer_outputs.past_key_values,
|
||
hidden_states=transformer_outputs.hidden_states,
|
||
attentions=transformer_outputs.attentions,
|
||
)
|
||
|
||
|
||
# Copied from transformers.models.llama.modeling_llama.LlamaForTokenClassification with Llama->Qwen2, LLAMA->QWEN2
|
||
class Qwen2ForTokenClassification(Qwen2PretrainedModel):
|
||
def __init__(self, config: Qwen2Config):
|
||
super().__init__(config)
|
||
self.num_labels = config.num_labels
|
||
self.qwen2 = Qwen2Model(config)
|
||
if getattr(config, "classifier_dropout", None) is not None:
|
||
classifier_dropout = config.classifier_dropout
|
||
elif getattr(config, "hidden_dropout", None) is not None:
|
||
classifier_dropout = config.hidden_dropout
|
||
else:
|
||
classifier_dropout = 0.1
|
||
self.dropout = nn.Dropout(classifier_dropout)
|
||
self.score = Linear(config.hidden_size, config.num_labels)
|
||
|
||
def get_input_embeddings(self):
|
||
return self.qwen2.embed_tokens
|
||
|
||
def set_input_embeddings(self, value):
|
||
self.qwen2.embed_tokens = value
|
||
|
||
def forward(
|
||
self,
|
||
input_ids: paddle.Tensor = None,
|
||
attention_mask: Optional[paddle.Tensor] = None,
|
||
position_ids: Optional[paddle.Tensor] = None,
|
||
past_key_values: Optional[List[paddle.Tensor]] = None,
|
||
inputs_embeds: Optional[paddle.Tensor] = None,
|
||
labels: Optional[paddle.Tensor] = None,
|
||
use_cache: Optional[bool] = None,
|
||
output_attentions: Optional[bool] = None,
|
||
output_hidden_states: Optional[bool] = None,
|
||
return_dict: Optional[bool] = None,
|
||
) -> Union[Tuple, SequenceClassifierOutputWithPast]:
|
||
r"""
|
||
labels (`paddle.Tensor` of shape `(batch_size,)`, *optional*):
|
||
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
||
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
||
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
||
"""
|
||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||
|
||
outputs = self.qwen2(
|
||
input_ids,
|
||
attention_mask=attention_mask,
|
||
position_ids=position_ids,
|
||
past_key_values=past_key_values,
|
||
inputs_embeds=inputs_embeds,
|
||
use_cache=use_cache,
|
||
output_attentions=output_attentions,
|
||
output_hidden_states=output_hidden_states,
|
||
return_dict=return_dict,
|
||
)
|
||
sequence_output = outputs[0]
|
||
sequence_output = self.dropout(sequence_output)
|
||
logits = self.score(sequence_output)
|
||
|
||
loss = None
|
||
if labels is not None:
|
||
loss_fct = nn.CrossEntropyLoss()
|
||
loss = loss_fct(logits.reshape([-1, self.num_labels]), labels.reshape([-1]))
|
||
|
||
if not return_dict:
|
||
output = (logits,) + outputs[2:]
|
||
return ((loss,) + output) if loss is not None else output
|
||
|
||
return TokenClassifierOutput(
|
||
loss=loss,
|
||
logits=logits,
|
||
hidden_states=outputs.hidden_states,
|
||
attentions=outputs.attentions,
|
||
)
|
||
|
||
|
||
class Qwen2SentenceEmbedding(Qwen2PretrainedModel):
|
||
def __init__(
|
||
self,
|
||
config: Qwen2Config,
|
||
embedding_temperature: float = 0.02,
|
||
):
|
||
"""Qwen2SentenceEmbedding
|
||
For getting larger batch_size, we use tensor parallel to get larger batch_size.
|
||
|
||
Args:
|
||
config (Qwen2Config): _description_
|
||
model (Qwen2Model): _description_
|
||
embedding_temperature (float, optional): _description_. Defaults to 0.02.
|
||
"""
|
||
super(Qwen2SentenceEmbedding, self).__init__(config)
|
||
self.config = config
|
||
self.qwen2 = Qwen2Model(config)
|
||
self.in_batch_negative_loss = SimpleContrastiveLoss(embedding_temperature)
|
||
self.world_size = dist.get_world_size()
|
||
self.process_rank = dist.get_rank()
|
||
self.embedding_negatives_cross_device = config.embedding_negatives_cross_device
|
||
if self.world_size <= 1:
|
||
self.embedding_negatives_cross_device = False
|
||
|
||
def forward(
|
||
self,
|
||
query: Optional[Dict[str, paddle.Tensor]] = None,
|
||
passages: Optional[Dict[str, paddle.Tensor]] = None,
|
||
return_encode=False,
|
||
):
|
||
"""forward"""
|
||
q_reps = self.encode(**query)
|
||
p_reps = self.encode(**passages)
|
||
|
||
q_reps = nn.functional.normalize(q_reps, axis=-1)
|
||
p_reps = nn.functional.normalize(p_reps, axis=-1)
|
||
|
||
if return_encode:
|
||
return q_reps, p_reps
|
||
|
||
if self.embedding_negatives_cross_device:
|
||
q_reps = dist_gather_tensor_with_gradient(q_reps)
|
||
p_reps = dist_gather_tensor_with_gradient(p_reps)
|
||
|
||
loss = self.in_batch_negative_loss(q_reps, p_reps)
|
||
return loss
|
||
|
||
def encode(
|
||
self,
|
||
input_ids,
|
||
position_ids=None,
|
||
embedding_indices=None,
|
||
attention_mask=None,
|
||
output_attentions=False,
|
||
output_hidden_states=False,
|
||
return_dict=False,
|
||
**kwargs,
|
||
):
|
||
"""encode"""
|
||
input_type = type(input_ids)
|
||
outputs = self.qwen2(
|
||
input_ids,
|
||
position_ids=position_ids,
|
||
attention_mask=attention_mask,
|
||
output_attentions=output_attentions,
|
||
output_hidden_states=output_hidden_states,
|
||
return_dict=return_dict,
|
||
**kwargs,
|
||
)
|
||
if isinstance(outputs, input_type):
|
||
hidden_states = outputs
|
||
else:
|
||
hidden_states = outputs[0]
|
||
last_hidden_states = hidden_states.gather_nd(embedding_indices)
|
||
return last_hidden_states
|
||
|