1597 lines
63 KiB
Python
1597 lines
63 KiB
Python
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||
# Copyright 2024 EleutherAI and the HuggingFace Inc. team. All rights reserved.
|
||
#
|
||
# 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.
|
||
|
||
import math
|
||
import warnings
|
||
from functools import partial
|
||
from typing import List, Optional, Tuple
|
||
|
||
import paddle
|
||
import paddle.distributed.fleet.meta_parallel as mpu
|
||
import paddle.nn.functional as F
|
||
from paddle import Tensor, nn
|
||
from paddle.autograd import PyLayer
|
||
from paddle.distributed import fleet
|
||
from paddle.distributed.fleet.meta_parallel import get_rng_state_tracker
|
||
from paddle.distributed.fleet.utils import recompute
|
||
from paddle.utils import try_import
|
||
|
||
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
|
||
|
||
from paddlenlp.transformers.conversion_utils import (
|
||
StateDictNameMapping,
|
||
init_name_mappings,
|
||
)
|
||
from paddlenlp.transformers.model_outputs import (
|
||
BaseModelOutputWithPastAndCrossAttentions,
|
||
CausalLMOutputWithCrossAttentions,
|
||
)
|
||
from paddlenlp.transformers.model_utils import PretrainedModel, register_base_model
|
||
|
||
from .. import linear_utils
|
||
from ..linear_utils import Linear
|
||
from ..segment_parallel_utils import ReshardLayer
|
||
from ..utils import caculate_llm_per_token_flops
|
||
from .configuration import (
|
||
GEMMA_PRETRAINED_INIT_CONFIGURATION,
|
||
GEMMA_PRETRAINED_RESOURCE_FILES_MAP,
|
||
GemmaConfig,
|
||
)
|
||
|
||
try:
|
||
from paddle.nn.functional.flash_attention import flash_attention
|
||
except:
|
||
flash_attention = None
|
||
|
||
|
||
def _get_interleave(n):
|
||
def _get_interleave_power_of_2(n):
|
||
start = 2 ** (-(2 ** -(math.log2(n) - 3)))
|
||
ratio = start
|
||
return [start * ratio**i for i in range(n)]
|
||
|
||
if math.log2(n).is_integer():
|
||
return _get_interleave_power_of_2(n)
|
||
else:
|
||
closest_power_of_2 = 2 ** math.floor(math.log2(n))
|
||
return (
|
||
_get_interleave_power_of_2(closest_power_of_2)
|
||
+ _get_interleave(2 * closest_power_of_2)[0::2][: n - closest_power_of_2]
|
||
)
|
||
|
||
|
||
def rms_norm_fused(x_in, w, eps):
|
||
fused_ln = try_import("fused_ln")
|
||
return fused_ln.fused_rms_norm(x_in, w, eps)[0]
|
||
|
||
|
||
def assign_kv_heads(num_kv_heads: int, num_gpus: int):
|
||
# Initialize the assignment list
|
||
"""
|
||
Assign kv heads to different GPUs in the Tensor Parallel Setup
|
||
|
||
Examples:
|
||
assign_kv_heads(num_kv_heads=1, num_gpus=2): [[0], [0]]
|
||
assign_kv_heads(num_kv_heads=2, num_gpus=2): [[0], [1]]
|
||
assign_kv_heads(num_kv_heads=4, num_gpus=2): [[0,1], [2,3]]
|
||
assign_kv_heads(num_kv_heads=1, num_gpus=4): [[0],[0],[0],[0]]
|
||
assign_kv_heads(num_kv_heads=2, num_gpus=4): [[0],[0],[1],[1]]
|
||
assign_kv_heads(num_kv_heads=4, num_gpus=4): [[0],[1],[2],[3]]
|
||
"""
|
||
assignment_list = [[] for _ in range(num_gpus)]
|
||
# Case 1: more heads than cards
|
||
if num_kv_heads > num_gpus:
|
||
num_heads_per_card = num_kv_heads // num_gpus
|
||
for i in range(num_gpus):
|
||
for j in range(num_heads_per_card):
|
||
assignment_list[i].append(i * num_heads_per_card + j)
|
||
# Case 2: more cards than heads. each card get only 1 head.
|
||
else:
|
||
num_card_per_heads = num_gpus // num_kv_heads
|
||
for i in range(num_kv_heads):
|
||
for j in range(num_card_per_heads):
|
||
assignment_list[i * num_card_per_heads + j].append(i)
|
||
return assignment_list
|
||
|
||
|
||
def build_alibi_tensor(
|
||
bool_attention_mask: Tensor, num_heads: int, dtype: paddle.dtype, tensor_parallel_degree=1
|
||
) -> Tensor:
|
||
attention_mask = bool_attention_mask.astype("float32")
|
||
batch_size, seq_length = attention_mask.shape[0], attention_mask.shape[-1]
|
||
slopes = paddle.to_tensor(_get_interleave(num_heads), dtype="float32")
|
||
alibi = slopes.unsqueeze(axis=[1, 2]) * paddle.arange(seq_length, dtype="float32").unsqueeze(axis=[0, 1]).expand(
|
||
[num_heads, -1, -1]
|
||
)
|
||
alibi = alibi.reshape(shape=(1, num_heads, 1, seq_length)).expand([batch_size, -1, -1, -1])
|
||
return paddle.cast(alibi, dtype)
|
||
|
||
|
||
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 repeat_kv(hidden_states: paddle.Tensor, n_rep: int) -> paddle.Tensor:
|
||
"""
|
||
This is the equivalent of paddle.repeat_interleave(hidden_states, n_rep, axis=1). The hidden states go from (batch,
|
||
num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
|
||
"""
|
||
batch, slen, num_key_value_heads, head_dim = hidden_states.shape
|
||
if n_rep == 1:
|
||
return hidden_states
|
||
|
||
hidden_states = hidden_states.unsqueeze(-2).tile([1, 1, 1, n_rep, 1])
|
||
return hidden_states.reshape([batch, slen, num_key_value_heads * n_rep, head_dim])
|
||
|
||
|
||
def parallel_matmul(x: Tensor, y, tensor_parallel_output=True, transpose_y=False):
|
||
is_fleet_init = True
|
||
tensor_parallel_degree = 1
|
||
try:
|
||
hcg = fleet.get_hybrid_communicate_group()
|
||
model_parallel_group = hcg.get_model_parallel_group()
|
||
tensor_parallel_degree = hcg.get_model_parallel_world_size()
|
||
except:
|
||
is_fleet_init = False
|
||
|
||
if paddle.in_dynamic_mode():
|
||
y_is_distributed = y.is_distributed
|
||
else:
|
||
y_is_distributed = tensor_parallel_degree > 1
|
||
|
||
if is_fleet_init and tensor_parallel_degree > 1 and y_is_distributed:
|
||
# if not running under distributed.launch, it will raise AttributeError: 'Fleet' object has no attribute '_hcg'
|
||
input_parallel = paddle.distributed.collective._c_identity(x, group=model_parallel_group)
|
||
logits = paddle.matmul(input_parallel, y, transpose_y=transpose_y)
|
||
|
||
if tensor_parallel_output:
|
||
return logits
|
||
|
||
return paddle.distributed.collective._c_concat(logits, group=model_parallel_group)
|
||
|
||
else:
|
||
logits = paddle.matmul(x, y, transpose_y=transpose_y)
|
||
return logits
|
||
|
||
|
||
def scaled_dot_product_attention(
|
||
query_states,
|
||
config,
|
||
key_states,
|
||
value_states,
|
||
attention_mask,
|
||
output_attentions,
|
||
alibi=None,
|
||
sequence_parallel=False,
|
||
reshard_layer=None,
|
||
attn_dropout_prob=0.0,
|
||
trainer_mode=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]
|
||
|
||
version = paddle.version.full_version
|
||
if version != "0.0.0" and version <= "2.5.2":
|
||
if alibi is not None:
|
||
raise ValueError("Flash Attention doesn't support alibi")
|
||
attn_output, attn_weights = flash_attention(
|
||
query_states,
|
||
key_states,
|
||
value_states,
|
||
causal=True,
|
||
dropout=attn_dropout_prob,
|
||
return_softmax=output_attentions,
|
||
)
|
||
else:
|
||
if alibi is not None:
|
||
alibi = alibi.reshape([bsz, num_heads, 1, -1])
|
||
attention_mask = attention_mask.cast(alibi.dtype) + alibi
|
||
attn_output = F.scaled_dot_product_attention(
|
||
query_states,
|
||
key_states,
|
||
value_states,
|
||
attn_mask=attention_mask,
|
||
is_causal=attention_mask is None,
|
||
)
|
||
attn_weights = None
|
||
|
||
if reshard_layer is not None:
|
||
# attn_output shape: [bs, seqlen, num_head/sep, head_dim]
|
||
attn_output = reshard_layer(
|
||
attn_output,
|
||
split_axis=1,
|
||
concat_axis=2,
|
||
)
|
||
# attn_output shape: [bs, seqlen/sep, num_head, head_dim]
|
||
assert (
|
||
config.sep_parallel_degree > 1 and q_len % config.sep_parallel_degree == 0
|
||
), f"q_len:{q_len}, config.sep_parallel_degree:{config.sep_parallel_degree}"
|
||
q_len = q_len // config.sep_parallel_degree
|
||
num_heads = num_heads * config.sep_parallel_degree
|
||
|
||
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
|
||
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])
|
||
|
||
# matmul and devide by sqrt(head_dim)
|
||
attn_weights = paddle.matmul(query_states / math.sqrt(head_dim), key_states.transpose([0, 1, 3, 2]))
|
||
# then add alibi bias
|
||
if alibi is not None:
|
||
alibi = alibi.reshape([bsz, num_heads, 1, -1])
|
||
attn_weights = attn_weights + alibi
|
||
|
||
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}"
|
||
)
|
||
|
||
# In sep mode, the attenion mask should be created in the runtime.
|
||
if reshard_layer is not None:
|
||
attention_mask = None
|
||
|
||
# NOTE: we only call get_triangle_upper_mask under PP setup
|
||
# FIXME ZHUI when we use pipeline parallel, the attention_mask can be None
|
||
# we just make it triangle_upper_mask
|
||
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, axis=-1, dtype="float32").astype(query_states.dtype)
|
||
else:
|
||
with paddle.amp.auto_cast(False):
|
||
attn_weights = F.softmax(attn_weights, axis=-1, dtype="float32").astype(query_states.dtype)
|
||
attn_weights = F.dropout(attn_weights, attn_dropout_prob, training=trainer_mode)
|
||
attn_output = paddle.matmul(attn_weights, value_states)
|
||
attn_output = attn_output.transpose([0, 2, 1, 3])
|
||
|
||
if reshard_layer is not None:
|
||
attn_output = reshard_layer(
|
||
attn_output,
|
||
split_axis=1,
|
||
concat_axis=2,
|
||
)
|
||
q_len = q_len // config.sep_parallel_degree
|
||
num_heads = num_heads * config.sep_parallel_degree
|
||
|
||
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
|
||
|
||
|
||
def is_casual_mask(attention_mask):
|
||
"""
|
||
Upper triangular of attention_mask equals to attention_mask is casual
|
||
"""
|
||
return (paddle.triu(attention_mask) == attention_mask).all().item()
|
||
|
||
|
||
def _make_causal_mask(input_ids_shape, past_key_values_length):
|
||
"""
|
||
Make causal mask used for self-attention
|
||
"""
|
||
batch_size, target_length = input_ids_shape # target_length: seq_len
|
||
|
||
mask = paddle.tril(paddle.ones((target_length, target_length), dtype="bool"))
|
||
|
||
if past_key_values_length > 0:
|
||
# [tgt_len, tgt_len + past_len]
|
||
mask = paddle.concat([paddle.ones([target_length, past_key_values_length], dtype="bool"), mask], axis=-1)
|
||
|
||
# [bs, 1, tgt_len, tgt_len + past_len]
|
||
return mask[None, None, :, :].expand([batch_size, 1, target_length, target_length + past_key_values_length])
|
||
|
||
|
||
def _expand_2d_mask(mask, dtype, tgt_length):
|
||
"""
|
||
Expands attention_mask from `[batch_size, src_length]` to `[batch_size, 1, tgt_length, src_length]`.
|
||
"""
|
||
batch_size, src_length = mask.shape[0], mask.shape[-1]
|
||
tgt_length = tgt_length if tgt_length is not None else src_length
|
||
|
||
mask = mask[:, None, None, :].astype("bool")
|
||
mask.stop_gradient = True
|
||
expanded_mask = mask.expand([batch_size, 1, tgt_length, src_length])
|
||
|
||
return expanded_mask
|
||
|
||
|
||
class GemmaRMSNorm(nn.Layer):
|
||
def __init__(self, config):
|
||
super().__init__()
|
||
self.hidden_size = config.hidden_size
|
||
self.weight = paddle.create_parameter(
|
||
shape=[self.hidden_size],
|
||
dtype=paddle.get_default_dtype(),
|
||
default_initializer=nn.initializer.Constant(1.0),
|
||
)
|
||
self.variance_epsilon = config.rms_norm_eps
|
||
self.config = config
|
||
|
||
if config.sequence_parallel:
|
||
mark_as_sequence_parallel_parameter(self.weight)
|
||
|
||
def _norm(self, x):
|
||
return x * paddle.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.variance_epsilon)
|
||
|
||
def forward(self, x):
|
||
if self.config.use_fused_rms_norm:
|
||
return rms_norm_fused(x, self.weight + 1, self.variance_epsilon)
|
||
|
||
output = self._norm(x.astype(paddle.float32)).astype(x.dtype)
|
||
return output * (self.weight + 1)
|
||
|
||
|
||
class GemmaRotaryEmbedding(nn.Layer):
|
||
def __init__(self, dim, max_position_embeddings=2048, base=10000):
|
||
super().__init__()
|
||
|
||
self.dim = dim
|
||
self.max_position_embeddings = max_position_embeddings
|
||
self.base = base
|
||
self.inv_freq = 1.0 / (self.base ** (paddle.cast(paddle.arange(0, self.dim, 2), dtype="float32") / self.dim))
|
||
|
||
def forward(self, x, seq_len=None):
|
||
# x: [bs, num_attention_heads, seq_len, head_size]
|
||
t = paddle.arange(seq_len, dtype="float32")
|
||
freqs = paddle.einsum("i,j->ij", t, self.inv_freq)
|
||
emb = paddle.concat([freqs, freqs], axis=-1)
|
||
return (emb.cos()[None, :, None, :].cast(dtype=x.dtype), emb.sin()[None, :, None, :].cast(dtype=x.dtype))
|
||
|
||
|
||
def rotate_half(x):
|
||
"""Rotates half the hidden dims of the input."""
|
||
x1 = x[..., : x.shape[-1] // 2]
|
||
x2 = x[..., x.shape[-1] // 2 :]
|
||
return paddle.concat([-x2, x1], axis=-1) # shape is the same as x
|
||
|
||
|
||
def apply_rotary_pos_emb(q, k, cos, sin, position_ids):
|
||
|
||
if position_ids is None:
|
||
# Note: Only for ForCausalLMPipe model pretraining
|
||
cos = cos[:, : q.shape[1], :, :] # [bs, seq_len, 1, dim]
|
||
sin = sin[:, : q.shape[1], :, :] # [bs, seq_len, 1, dim]
|
||
else:
|
||
cos = cos.squeeze(axis=[0, 2]) # [seq_len, dim]
|
||
sin = sin.squeeze(axis=[0, 2]) # [seq_len, dim]
|
||
cos = cos[position_ids].unsqueeze(2) # [bs, seq_len, 1, dim]
|
||
sin = sin[position_ids].unsqueeze(2) # [bs, seq_len, 1, dim]
|
||
q_embed = (q * cos) + (rotate_half(q) * sin)
|
||
k_embed = (k * cos) + (rotate_half(k) * sin)
|
||
return q_embed, k_embed
|
||
|
||
|
||
class GemmaMLP(nn.Layer):
|
||
def __init__(self, config):
|
||
super().__init__()
|
||
self.hidden_size = config.hidden_size
|
||
self.intermediate_size = config.intermediate_size
|
||
self.tensor_parallel_degree = config.tensor_parallel_degree
|
||
|
||
if config.sequence_parallel:
|
||
ColumnParallelLinear = linear_utils.ColumnSequenceParallelLinear
|
||
RowParallelLinear = linear_utils.RowSequenceParallelLinear
|
||
else:
|
||
ColumnParallelLinear = linear_utils.ColumnParallelLinear
|
||
RowParallelLinear = linear_utils.RowParallelLinear
|
||
|
||
if config.tensor_parallel_degree > 1:
|
||
self.gate_proj = ColumnParallelLinear(
|
||
self.hidden_size,
|
||
self.intermediate_size,
|
||
gather_output=False,
|
||
has_bias=False,
|
||
)
|
||
self.up_proj = ColumnParallelLinear(
|
||
self.hidden_size,
|
||
self.intermediate_size,
|
||
gather_output=False,
|
||
has_bias=False,
|
||
)
|
||
self.down_proj = RowParallelLinear(
|
||
self.intermediate_size,
|
||
self.hidden_size,
|
||
input_is_parallel=True,
|
||
has_bias=False,
|
||
)
|
||
else:
|
||
self.gate_proj = Linear(self.hidden_size, self.intermediate_size, bias_attr=False)
|
||
self.up_proj = Linear(self.hidden_size, self.intermediate_size, bias_attr=False)
|
||
self.down_proj = Linear(self.intermediate_size, self.hidden_size, bias_attr=False)
|
||
|
||
def forward(self, x):
|
||
# GeGLU
|
||
out = self.down_proj(F.gelu(self.gate_proj(x)) * self.up_proj(x))
|
||
return out
|
||
|
||
|
||
class GemmaAttention(nn.Layer):
|
||
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
||
|
||
def __init__(self, config: GemmaConfig, layerwise_recompute: bool = False):
|
||
super().__init__()
|
||
|
||
self.config = config
|
||
self.attention_dropout = config.attention_dropout # add
|
||
self.hidden_size = config.hidden_size
|
||
self.num_heads = config.num_attention_heads
|
||
self.head_dim = config.head_dim
|
||
|
||
self.num_key_value_heads = config.num_key_value_heads
|
||
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
||
|
||
self.max_position_embeddings = config.max_position_embeddings
|
||
self.seq_length = config.seq_length
|
||
self.rope_theta = config.rope_theta
|
||
self.sequence_parallel = config.sequence_parallel
|
||
|
||
self.kv_indices = None
|
||
# 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
|
||
|
||
if self.num_key_value_heads % config.tensor_parallel_degree == 0:
|
||
self.num_key_value_heads = self.num_key_value_heads // config.tensor_parallel_degree
|
||
else:
|
||
self.kv_indices = paddle.to_tensor(
|
||
assign_kv_heads(self.num_key_value_heads, config.tensor_parallel_degree)[
|
||
config.tensor_parallel_rank
|
||
]
|
||
)
|
||
|
||
self.use_fused_rope = config.use_fused_rope
|
||
if self.use_fused_rope:
|
||
if "gpu" not in paddle.device.get_device() 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
|
||
else:
|
||
ColumnParallelLinear = linear_utils.ColumnParallelLinear
|
||
RowParallelLinear = linear_utils.RowParallelLinear
|
||
|
||
if config.tensor_parallel_degree > 1:
|
||
self.q_proj = ColumnParallelLinear(
|
||
self.hidden_size,
|
||
self.config.num_attention_heads * self.head_dim,
|
||
has_bias=config.attention_bias,
|
||
gather_output=False,
|
||
)
|
||
if self.kv_indices is None:
|
||
# to revise shape
|
||
self.k_proj = ColumnParallelLinear(
|
||
self.hidden_size,
|
||
self.config.num_key_value_heads * self.head_dim,
|
||
has_bias=config.attention_bias,
|
||
gather_output=False,
|
||
)
|
||
self.v_proj = ColumnParallelLinear(
|
||
self.hidden_size,
|
||
self.config.num_key_value_heads * self.head_dim,
|
||
has_bias=config.attention_bias,
|
||
gather_output=False,
|
||
)
|
||
else:
|
||
self.k_proj = Linear(
|
||
self.hidden_size,
|
||
self.config.num_key_value_heads * self.head_dim,
|
||
bias_attr=False,
|
||
)
|
||
self.v_proj = Linear(
|
||
self.hidden_size,
|
||
self.config.num_key_value_heads * self.head_dim,
|
||
bias_attr=False,
|
||
)
|
||
|
||
else:
|
||
self.q_proj = Linear(
|
||
self.hidden_size,
|
||
self.config.num_attention_heads * self.head_dim,
|
||
bias_attr=False,
|
||
)
|
||
self.k_proj = Linear(
|
||
self.hidden_size,
|
||
self.config.num_key_value_heads * self.head_dim,
|
||
bias_attr=False,
|
||
)
|
||
self.v_proj = Linear(
|
||
self.hidden_size,
|
||
self.config.num_key_value_heads * self.head_dim,
|
||
bias_attr=False,
|
||
)
|
||
|
||
if config.tensor_parallel_degree > 1:
|
||
self.o_proj = RowParallelLinear(
|
||
self.config.num_attention_heads * self.head_dim,
|
||
self.hidden_size,
|
||
has_bias=False,
|
||
input_is_parallel=True,
|
||
)
|
||
else:
|
||
self.o_proj = Linear(
|
||
self.config.num_attention_heads * self.head_dim,
|
||
self.hidden_size,
|
||
bias_attr=False,
|
||
)
|
||
self.rotary_emb = GemmaRotaryEmbedding(
|
||
self.head_dim,
|
||
max_position_embeddings=self.max_position_embeddings,
|
||
base=self.rope_theta,
|
||
)
|
||
|
||
self.reshard_layer = None
|
||
if config.sep_parallel_degree > 1:
|
||
assert self.num_key_value_heads % config.sep_parallel_degree == 0
|
||
assert self.num_heads % config.sep_parallel_degree == 0
|
||
self.reshard_layer = ReshardLayer()
|
||
|
||
self.config = config
|
||
|
||
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,
|
||
alibi: Optional[paddle.Tensor] = None,
|
||
) -> 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)
|
||
query_states = self.q_proj(hidden_states)
|
||
key_states = self.k_proj(hidden_states)
|
||
value_states = self.v_proj(hidden_states)
|
||
if self.reshard_layer is not None:
|
||
if self.sequence_parallel:
|
||
assert self.seq_length % self.config.sep_parallel_degree == 0
|
||
query_states = paddle.reshape(
|
||
query_states,
|
||
[-1, self.seq_length // self.config.sep_parallel_degree, self.num_heads * self.head_dim],
|
||
)
|
||
key_states = paddle.reshape(
|
||
key_states,
|
||
[-1, self.seq_length // self.config.sep_parallel_degree, self.num_heads * self.head_dim],
|
||
)
|
||
value_states = paddle.reshape(
|
||
value_states,
|
||
[-1, self.seq_length // self.config.sep_parallel_degree, self.num_heads * self.head_dim],
|
||
)
|
||
query_states = self.reshard_layer(
|
||
query_states,
|
||
split_axis=2,
|
||
concat_axis=1,
|
||
)
|
||
key_states = self.reshard_layer(
|
||
key_states,
|
||
split_axis=2,
|
||
concat_axis=1,
|
||
)
|
||
value_states = self.reshard_layer(
|
||
value_states,
|
||
split_axis=2,
|
||
concat_axis=1,
|
||
)
|
||
query_states = paddle.reshape(
|
||
query_states, [0, self.seq_length, -1, self.head_dim]
|
||
) # [bs, seq_len, num_head/k, head_dim], k is sep degree
|
||
key_states = paddle.reshape(key_states, [0, self.seq_length, -1, self.head_dim])
|
||
value_states = paddle.reshape(value_states, [0, self.seq_length, -1, self.head_dim])
|
||
else:
|
||
if self.sequence_parallel:
|
||
target_query_shape = [-1, self.seq_length, self.num_heads, self.head_dim]
|
||
target_key_value_shape = [-1, self.seq_length, 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)
|
||
|
||
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.config.rope:
|
||
if self.reshard_layer is not None:
|
||
batch_size, seq_length, _, _ = query_states.shape
|
||
position_ids = paddle.arange(seq_length, dtype="int64").expand((batch_size, seq_length))
|
||
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)
|
||
paddle_version = float(paddle.__version__[:3])
|
||
if ((paddle_version != 0.0) and (paddle_version <= 2.6)) and (
|
||
self.num_heads != self.num_key_value_heads
|
||
):
|
||
query_states, _, _ = fused_rotary_position_embedding(
|
||
query_states,
|
||
None,
|
||
None,
|
||
sin=sin,
|
||
cos=cos,
|
||
position_ids=position_ids,
|
||
use_neox_rotary_style=False,
|
||
)
|
||
key_states, _, _ = fused_rotary_position_embedding(
|
||
key_states,
|
||
None,
|
||
None,
|
||
sin=sin,
|
||
cos=cos,
|
||
position_ids=position_ids,
|
||
use_neox_rotary_style=False,
|
||
)
|
||
else:
|
||
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:
|
||
# reuse k, v, self_attention
|
||
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
|
||
|
||
if self.kv_indices is not None:
|
||
key_states = paddle.index_select(key_states, self.kv_indices, axis=2)
|
||
value_states = paddle.index_select(value_states, self.kv_indices, axis=2)
|
||
key_states = paddle.broadcast_to(key_states, query_states.shape)
|
||
value_states = paddle.broadcast_to(value_states, query_states.shape)
|
||
else:
|
||
# repeat k/v heads if n_kv_heads < n_heads
|
||
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"
|
||
):
|
||
outputs = recompute(
|
||
scaled_dot_product_attention,
|
||
query_states,
|
||
self.config,
|
||
key_states,
|
||
value_states,
|
||
attention_mask,
|
||
output_attentions,
|
||
alibi,
|
||
self.sequence_parallel,
|
||
reshard_layer=self.reshard_layer,
|
||
use_reentrant=self.config.recompute_use_reentrant,
|
||
attn_dropout_prob=self.attention_dropout,
|
||
trainer_mode=self.training,
|
||
)
|
||
else:
|
||
outputs = scaled_dot_product_attention(
|
||
query_states,
|
||
self.config,
|
||
key_states,
|
||
value_states,
|
||
attention_mask,
|
||
output_attentions,
|
||
alibi,
|
||
self.sequence_parallel,
|
||
reshard_layer=self.reshard_layer,
|
||
attn_dropout_prob=self.attention_dropout,
|
||
trainer_mode=self.training,
|
||
)
|
||
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 GemmaDecoderLayer(nn.Layer):
|
||
def __init__(self, config, layerwise_recompute: bool = False):
|
||
super().__init__()
|
||
self.config = config
|
||
self.hidden_size = config.hidden_size
|
||
self.self_attn = GemmaAttention(config, layerwise_recompute)
|
||
self.mlp = GemmaMLP(config)
|
||
self.input_layernorm = GemmaRMSNorm(config)
|
||
self.post_attention_layernorm = GemmaRMSNorm(config)
|
||
self.sequence_parallel = config.sequence_parallel
|
||
# 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
|
||
|
||
def forward(
|
||
self,
|
||
hidden_states: paddle.Tensor,
|
||
position_ids: Optional[Tuple[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,
|
||
alibi: Optional[paddle.Tensor] = None,
|
||
) -> 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, 1, tgt_len, src_len)` where padding elements are indicated by very large negative values.
|
||
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`, `cache` key value states are returned and can be used to speed up decoding
|
||
(see `cache`).
|
||
cache (`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"
|
||
):
|
||
outputs = recompute(
|
||
self.self_attn,
|
||
hidden_states,
|
||
position_ids,
|
||
past_key_value,
|
||
attention_mask,
|
||
output_attentions,
|
||
use_cache,
|
||
alibi,
|
||
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,
|
||
alibi,
|
||
)
|
||
|
||
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,)
|
||
|
||
# remove empty tuple for pipeline parallel
|
||
if type(outputs) is tuple and len(outputs) == 1:
|
||
outputs = outputs[0]
|
||
|
||
return outputs
|
||
|
||
|
||
class GemmaPretrainedModel(PretrainedModel):
|
||
config_class = GemmaConfig
|
||
base_model_prefix = "gemma"
|
||
pretrained_init_configuration = GEMMA_PRETRAINED_INIT_CONFIGURATION
|
||
pretrained_resource_files_map = GEMMA_PRETRAINED_RESOURCE_FILES_MAP
|
||
_keys_to_ignore_on_load_unexpected = []
|
||
_keep_in_fp32_modules = ["inv_freq", "rotary_emb", "cos_cached", "sin_cached"]
|
||
|
||
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,
|
||
)
|
||
|
||
@classmethod
|
||
def _get_name_mappings(cls, config: GemmaConfig) -> 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.o_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}.mlp.up_proj.weight", None, "transpose"],
|
||
[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 "GemmaModel"
|
||
if "GemmaModel" not in config.architectures:
|
||
for mapping in model_mappings:
|
||
mapping[0] = "model." + mapping[0]
|
||
mapping[1] = "gemma." + mapping[1]
|
||
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: GemmaConfig, is_split=True):
|
||
|
||
from paddlenlp.transformers.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 = {
|
||
# Column Linear
|
||
"lm_head.weight": partial(fn, is_column=not config.tie_word_embeddings),
|
||
# 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 not config.vocab_size % config.tensor_parallel_degree == 0:
|
||
base_actions.pop("lm_head.weight")
|
||
base_actions.pop("embed_tokens.weight")
|
||
|
||
base_actions["layers.0.self_attn.q_proj.weight"] = 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)
|
||
|
||
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
|
||
|
||
def _init_weights(self, layer):
|
||
"""Initialization hook"""
|
||
if self.config.tensor_parallel_degree > 1:
|
||
rng_tracker = get_rng_state_tracker().rng_state
|
||
if isinstance(
|
||
layer,
|
||
(
|
||
nn.Linear,
|
||
nn.Embedding,
|
||
mpu.VocabParallelEmbedding,
|
||
mpu.RowParallelLinear,
|
||
mpu.ColumnParallelLinear,
|
||
linear_utils.RowSequenceParallelLinear,
|
||
linear_utils.ColumnSequenceParallelLinear,
|
||
GemmaLMHead,
|
||
),
|
||
):
|
||
# In the dygraph mode, use the `set_value` to reset the parameter directly,
|
||
# and reset the `state_dict` to update parameter in static mode.
|
||
if isinstance(layer.weight, paddle.Tensor):
|
||
if layer.weight.is_distributed:
|
||
with rng_tracker():
|
||
layer.weight.set_value(
|
||
paddle.tensor.normal(
|
||
mean=0.0,
|
||
std=self.config.initializer_range
|
||
if hasattr(self.config, "initializer_range")
|
||
else self.gemma.config.initializer_range,
|
||
shape=layer.weight.shape,
|
||
)
|
||
)
|
||
else:
|
||
layer.weight.set_value(
|
||
paddle.tensor.normal(
|
||
mean=0.0,
|
||
std=self.config.initializer_range
|
||
if hasattr(self.config, "initializer_range")
|
||
else self.gemma.config.initializer_range,
|
||
shape=layer.weight.shape,
|
||
)
|
||
)
|
||
# Layer.apply is DFS https://github.com/PaddlePaddle/Paddle/blob/a6f5021fcc58b21f4414bae6bf4731ef6971582c/python/paddle/nn/layer/layers.py#L527-L530
|
||
# sublayer is init first
|
||
# scale RowParallelLinear weight
|
||
with paddle.no_grad():
|
||
if isinstance(layer, GemmaMLP):
|
||
factor = 1 / math.sqrt(2 * self.config.num_hidden_layers)
|
||
layer.down_proj.weight.scale_(factor)
|
||
if isinstance(layer, GemmaAttention):
|
||
factor = 1 / math.sqrt(2 * self.config.num_hidden_layers)
|
||
layer.o_proj.weight.scale_(factor)
|
||
|
||
|
||
@register_base_model
|
||
class GemmaModel(GemmaPretrainedModel):
|
||
"""
|
||
Transformer decoder consisting of *config.num_hidden_layers* layers. Each layer is a [`GemmaDecoderLayer`]
|
||
Args:
|
||
config: GemmaConfig
|
||
"""
|
||
|
||
def __init__(self, config: GemmaConfig):
|
||
super().__init__(config)
|
||
self.vocab_size = config.vocab_size
|
||
self.hidden_size = config.hidden_size
|
||
self.sequence_parallel = config.sequence_parallel
|
||
self.recompute_granularity = config.recompute_granularity
|
||
self.no_recompute_layers = config.no_recompute_layers if config.no_recompute_layers is not None else []
|
||
|
||
# Recompute defaults to False and is controlled by Trainer
|
||
self.enable_recompute = False
|
||
if config.tensor_parallel_degree > 1 and config.vocab_size % config.tensor_parallel_degree == 0:
|
||
self.embed_tokens = mpu.VocabParallelEmbedding(
|
||
self.vocab_size,
|
||
self.hidden_size,
|
||
weight_attr=paddle.ParamAttr(initializer=nn.initializer.XavierNormal()),
|
||
)
|
||
self.embed_tokens.weight.is_distributed = True
|
||
else:
|
||
self.embed_tokens = nn.Embedding(
|
||
self.vocab_size,
|
||
self.hidden_size,
|
||
)
|
||
self.embed_tokens.weight.is_distributed = False
|
||
|
||
self.layers = nn.LayerList(
|
||
[GemmaDecoderLayer(config, i not in self.no_recompute_layers) for i in range(config.num_hidden_layers)]
|
||
)
|
||
self.norm = GemmaRMSNorm(config)
|
||
|
||
self.gradient_checkpointing = False
|
||
|
||
def get_input_embeddings(self):
|
||
return self.embed_tokens
|
||
|
||
def set_input_embeddings(self, value):
|
||
self.embed_tokens = value
|
||
|
||
@staticmethod
|
||
def _prepare_decoder_attention_mask(attention_mask, input_shape, past_key_values_length, dtype):
|
||
if attention_mask is not None:
|
||
# [bsz, seq_len] -> [bsz, 1, tgt_seq_len, src_seq_len]
|
||
if len(attention_mask.shape) == 2:
|
||
expanded_attn_mask = _expand_2d_mask(attention_mask, dtype, tgt_length=input_shape[-1])
|
||
# For decoding phase in generation, seq_length = 1, we don't need to add causal mask
|
||
if input_shape[-1] > 1:
|
||
combined_attention_mask = _make_causal_mask(
|
||
input_shape, past_key_values_length=past_key_values_length
|
||
)
|
||
expanded_attn_mask = expanded_attn_mask & combined_attention_mask
|
||
# [bsz, seq_len, seq_len] -> [bsz, 1, seq_len, seq_len]
|
||
elif len(attention_mask.shape) == 3:
|
||
expanded_attn_mask = attention_mask.unsqueeze(1).astype("bool")
|
||
# if attention_mask is already 4-D, do nothing
|
||
else:
|
||
expanded_attn_mask = attention_mask
|
||
else:
|
||
expanded_attn_mask = _make_causal_mask(input_shape, past_key_values_length=past_key_values_length)
|
||
# Convert bool attention_mask to float attention mask, which will be added to attention_scores later
|
||
expanded_attn_mask = paddle.where(expanded_attn_mask.to("bool"), 0.0, paddle.finfo(dtype).min).astype(dtype)
|
||
return expanded_attn_mask
|
||
|
||
@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,
|
||
alibi=None,
|
||
):
|
||
def create_custom_forward(module):
|
||
def custom_forward(*inputs):
|
||
return module(*inputs)
|
||
|
||
return custom_forward
|
||
|
||
hidden_states = recompute(
|
||
create_custom_forward(layer_module),
|
||
hidden_states,
|
||
position_ids,
|
||
attention_mask,
|
||
output_attentions,
|
||
past_key_value,
|
||
use_cache,
|
||
alibi,
|
||
use_reentrant=self.config.recompute_use_reentrant,
|
||
)
|
||
|
||
return hidden_states
|
||
|
||
def forward(
|
||
self,
|
||
input_ids=None,
|
||
attention_mask=None,
|
||
position_ids=None,
|
||
past_key_values=None,
|
||
inputs_embeds=None,
|
||
use_cache=None,
|
||
output_attentions=False,
|
||
output_hidden_states=None,
|
||
return_dict=False,
|
||
**kwargs,
|
||
):
|
||
if self.sequence_parallel and use_cache:
|
||
raise ValueError("We currently only support sequence parallel without cache.")
|
||
|
||
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
|
||
)
|
||
use_cache = use_cache if use_cache is not None else self.config.use_cache
|
||
|
||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||
|
||
# retrieve input_ids and inputs_embeds
|
||
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, seq_length = input_ids.shape
|
||
elif inputs_embeds is not None:
|
||
batch_size, seq_length, _ = inputs_embeds.shape
|
||
else:
|
||
raise ValueError("You have to specify either decoder_input_ids or decoder_inputs_embeds")
|
||
if self.sequence_parallel:
|
||
# [bs, seq_len, num_head * head_dim] -> [bs * seq_len, num_head * head_dim]
|
||
bs, seq_len, hidden_size = inputs_embeds.shape
|
||
inputs_embeds = paddle.reshape_(inputs_embeds, [bs * seq_len, hidden_size])
|
||
# [seq_len * bs / n, num_head * head_dim] (n is mp parallelism)
|
||
inputs_embeds = ScatterOp.apply(inputs_embeds)
|
||
if inputs_embeds is None:
|
||
inputs_embeds = self.embed_tokens(input_ids)
|
||
|
||
if past_key_values is None:
|
||
past_key_values = tuple([None] * len(self.layers))
|
||
# NOTE: to make cache can be clear in-time
|
||
past_key_values = list(past_key_values)
|
||
|
||
seq_length_with_past = seq_length
|
||
cache_length = 0
|
||
if past_key_values[0] is not None:
|
||
cache_length = paddle.shape(past_key_values[0][0])[1]
|
||
seq_length_with_past += cache_length
|
||
|
||
if position_ids is None:
|
||
position_ids = paddle.arange(seq_length, dtype="int64").expand((batch_size, seq_length))
|
||
|
||
if attention_mask is None:
|
||
# [bs, seq_len]
|
||
attention_mask = paddle.ones((batch_size, seq_length_with_past), dtype=paddle.bool)
|
||
if self.config.alibi:
|
||
alibi = build_alibi_tensor(attention_mask, self.config.num_attention_heads, dtype=inputs_embeds.dtype)
|
||
if self.config.tensor_parallel_degree > 1:
|
||
block_size = self.config.num_attention_heads // self.config.tensor_parallel_degree
|
||
alibi = alibi[
|
||
:,
|
||
self.config.tensor_parallel_rank
|
||
* block_size : (self.config.tensor_parallel_rank + 1)
|
||
* block_size,
|
||
]
|
||
alibi = alibi.reshape([batch_size * block_size, 1, seq_length_with_past])
|
||
else:
|
||
alibi = alibi.reshape([batch_size * self.config.num_attention_heads, 1, seq_length_with_past])
|
||
else:
|
||
alibi = None
|
||
|
||
if position_ids is None:
|
||
position_ids = paddle.arange(seq_length, dtype="int64").expand((batch_size, seq_length))
|
||
|
||
attention_mask = self._prepare_decoder_attention_mask(
|
||
attention_mask, (batch_size, seq_length), cache_length, inputs_embeds.dtype
|
||
) # [bs, 1, seq_len, seq_len]
|
||
if self.config.use_flash_attention:
|
||
is_casual = is_casual_mask(attention_mask)
|
||
if is_casual and alibi is None:
|
||
attention_mask = None
|
||
|
||
# embed positions
|
||
hidden_states = inputs_embeds
|
||
|
||
# normalized
|
||
hidden_states = hidden_states * (self.config.hidden_size**0.5)
|
||
|
||
# decoder layers
|
||
all_hidden_states = () if output_hidden_states else None
|
||
all_self_attns = () if output_attentions else None
|
||
next_decoder_cache = () if use_cache else None
|
||
|
||
for idx, (decoder_layer) in enumerate(self.layers):
|
||
if output_hidden_states:
|
||
all_hidden_states += (hidden_states,)
|
||
past_key_value = past_key_values[idx] if past_key_values is not None else None
|
||
|
||
has_gradient = not hidden_states.stop_gradient
|
||
if (
|
||
self.enable_recompute
|
||
and idx not in self.no_recompute_layers
|
||
and has_gradient
|
||
and self.recompute_granularity == "full"
|
||
):
|
||
layer_outputs = self.recompute_training_full(
|
||
decoder_layer,
|
||
hidden_states,
|
||
position_ids,
|
||
attention_mask,
|
||
output_attentions,
|
||
past_key_value,
|
||
use_cache,
|
||
alibi=alibi,
|
||
)
|
||
else:
|
||
layer_outputs = decoder_layer(
|
||
hidden_states,
|
||
position_ids,
|
||
attention_mask,
|
||
output_attentions,
|
||
past_key_value,
|
||
use_cache,
|
||
alibi=alibi,
|
||
)
|
||
|
||
# NOTE: clear outdate cache after it has been used for memory saving
|
||
past_key_value = past_key_values[idx] = None
|
||
if type(layer_outputs) is tuple:
|
||
hidden_states = layer_outputs[0]
|
||
else:
|
||
hidden_states = layer_outputs
|
||
|
||
if output_attentions:
|
||
all_self_attns += (layer_outputs[1],)
|
||
|
||
if use_cache:
|
||
next_decoder_cache += (layer_outputs[2 if output_attentions else 1],)
|
||
|
||
hidden_states = self.norm(hidden_states)
|
||
|
||
# add hidden states from the last decoder layer
|
||
if output_hidden_states:
|
||
all_hidden_states += (hidden_states,)
|
||
|
||
next_cache = next_decoder_cache if use_cache else None
|
||
|
||
if not return_dict:
|
||
return tuple(v for v in [hidden_states, next_cache, all_hidden_states, all_self_attns] if v is not None)
|
||
return BaseModelOutputWithPastAndCrossAttentions(
|
||
last_hidden_state=hidden_states,
|
||
past_key_values=next_cache,
|
||
hidden_states=all_hidden_states,
|
||
attentions=all_self_attns,
|
||
cross_attentions=None,
|
||
)
|
||
|
||
|
||
class GemmaPretrainingCriterion(nn.Layer):
|
||
"""
|
||
Criterion for gemma. Copied From Llama
|
||
It calculates the final loss.
|
||
"""
|
||
|
||
def __init__(self, config):
|
||
|
||
super().__init__()
|
||
self.ignore_index = getattr(config, "ignore_index", -100)
|
||
self.config = config
|
||
self.enable_parallel_cross_entropy = config.tensor_parallel_degree > 1 and config.tensor_parallel_output
|
||
|
||
if self.enable_parallel_cross_entropy: # and False: # and lm_head is distributed
|
||
self.loss_func = mpu.ParallelCrossEntropy(ignore_index=self.ignore_index)
|
||
else:
|
||
self.loss_func = paddle.nn.CrossEntropyLoss(reduction="none", ignore_index=self.ignore_index)
|
||
|
||
def forward(self, prediction_scores, masked_lm_labels):
|
||
if self.enable_parallel_cross_entropy:
|
||
if prediction_scores.shape[-1] == self.config.vocab_size:
|
||
warnings.warn(
|
||
f"enable_parallel_cross_entropy, the vocab_size should be split: {prediction_scores.shape[-1]}, {self.config.vocab_size}"
|
||
)
|
||
self.loss_func = paddle.nn.CrossEntropyLoss(reduction="none", ignore_index=self.ignore_index)
|
||
|
||
with paddle.amp.auto_cast(False):
|
||
masked_lm_loss = self.loss_func(prediction_scores.astype("float32"), masked_lm_labels.unsqueeze(2))
|
||
|
||
if self.config.sep_parallel_degree > 1:
|
||
_hcg = fleet.get_hybrid_communicate_group()
|
||
masked_lm_loss = ConcatSePMaskedLoss.apply(masked_lm_loss, axis=1, group=_hcg.get_sep_parallel_group())
|
||
# skip ignore_index which loss == 0
|
||
masked_lm_loss = masked_lm_loss[masked_lm_loss > 0]
|
||
loss = paddle.mean(masked_lm_loss)
|
||
|
||
return loss
|
||
|
||
|
||
class ConcatSePMaskedLoss(PyLayer):
|
||
@staticmethod
|
||
def forward(ctx, inp, axis, group):
|
||
inputs = []
|
||
paddle.distributed.all_gather(inputs, inp, group=group)
|
||
with paddle.no_grad():
|
||
cat = paddle.concat(inputs, axis=axis)
|
||
ctx.args_axis = axis
|
||
ctx.args_group = group
|
||
return cat
|
||
|
||
@staticmethod
|
||
def backward(ctx, grad):
|
||
axis = ctx.args_axis
|
||
group = ctx.args_group
|
||
with paddle.no_grad():
|
||
grads = paddle.split(grad, paddle.distributed.get_world_size(group), axis=axis)
|
||
grad = grads[paddle.distributed.get_rank(group)]
|
||
return grad
|
||
|
||
|
||
class GemmaLMHead(nn.Layer):
|
||
def __init__(self, config: GemmaConfig):
|
||
super().__init__()
|
||
self.config = config
|
||
if config.tensor_parallel_degree > 1 and config.vocab_size % config.tensor_parallel_degree == 0:
|
||
vocab_size = config.vocab_size // config.tensor_parallel_degree
|
||
else:
|
||
vocab_size = config.vocab_size
|
||
|
||
if vocab_size != config.vocab_size:
|
||
with get_rng_state_tracker().rng_state():
|
||
self.weight = self.create_parameter(
|
||
shape=[vocab_size, config.hidden_size]
|
||
if config.tie_word_embeddings
|
||
else [config.hidden_size, vocab_size],
|
||
dtype=paddle.get_default_dtype(),
|
||
)
|
||
else:
|
||
self.weight = self.create_parameter(
|
||
shape=[vocab_size, config.hidden_size]
|
||
if config.tie_word_embeddings
|
||
else [config.hidden_size, vocab_size],
|
||
dtype=paddle.get_default_dtype(),
|
||
)
|
||
# Must set distributed attr for Tensor Parallel !
|
||
self.weight.is_distributed = True if (vocab_size != config.vocab_size) else False
|
||
if self.weight.is_distributed:
|
||
self.weight.split_axis = 1
|
||
|
||
def forward(self, hidden_states, tensor_parallel_output=None):
|
||
if self.config.sequence_parallel:
|
||
hidden_states = GatherOp.apply(hidden_states)
|
||
seq_length = self.config.seq_length
|
||
if self.config.sep_parallel_degree > 1:
|
||
assert seq_length % self.config.sep_parallel_degree == 0
|
||
seq_length = seq_length // self.config.sep_parallel_degree
|
||
hidden_states = paddle.reshape_(hidden_states, [-1, seq_length, 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,
|
||
tensor_parallel_output=tensor_parallel_output,
|
||
transpose_y=self.config.tie_word_embeddings,
|
||
)
|
||
return logits
|
||
|
||
|
||
class GemmaForCausalLM(GemmaPretrainedModel):
|
||
enable_to_static_method = True
|
||
|
||
def __init__(self, config):
|
||
super().__init__(config)
|
||
self.config = config
|
||
self.lm_head = self.lm_head = GemmaLMHead(config)
|
||
self.gemma = GemmaModel(config)
|
||
self.criterion = GemmaPretrainingCriterion(config)
|
||
|
||
self.tie_weights()
|
||
|
||
def get_input_embeddings(self):
|
||
return self.gemma.embed_tokens
|
||
|
||
def get_output_embeddings(self):
|
||
return self.lm_head
|
||
|
||
def set_input_embeddings(self, value):
|
||
self.gemma.embed_tokens = value
|
||
|
||
def set_decoder(self, decoder):
|
||
self.gemma = decoder
|
||
|
||
def get_decoder(self):
|
||
return self.gemma
|
||
|
||
def prepare_inputs_for_generation(
|
||
self, input_ids, use_cache=False, past_key_values=None, inputs_embeds=None, **kwargs
|
||
):
|
||
batch_size, seq_length = input_ids.shape
|
||
position_ids = kwargs.get("position_ids", paddle.arange(seq_length).expand((batch_size, seq_length)))
|
||
attention_mask = kwargs.get("attention_mask", None)
|
||
if past_key_values:
|
||
input_ids = input_ids[:, -1].unsqueeze(axis=-1)
|
||
position_ids = position_ids[:, -1].unsqueeze(-1)
|
||
|
||
# if `inputs_embeds` are passed, we only want to use them in the 1st generation step
|
||
if inputs_embeds is not None and past_key_values is None:
|
||
model_inputs = {"inputs_embeds": inputs_embeds}
|
||
else:
|
||
model_inputs = {"input_ids": input_ids}
|
||
|
||
model_inputs.update(
|
||
{
|
||
"position_ids": position_ids,
|
||
"past_key_values": past_key_values,
|
||
"use_cache": use_cache,
|
||
"attention_mask": attention_mask,
|
||
}
|
||
)
|
||
return model_inputs
|
||
|
||
def _get_model_inputs_spec(self, dtype: str):
|
||
return {
|
||
"input_ids": paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||
"attention_mask": paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||
"position_ids": paddle.static.InputSpec(shape=[None, None], dtype="int64"),
|
||
}
|
||
|
||
@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, CausalLMOutputWithCrossAttentions) 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:
|
||
attention_mask = model_kwargs["attention_mask"]
|
||
model_kwargs["attention_mask"] = paddle.concat(
|
||
[attention_mask, paddle.ones([attention_mask.shape[0], 1], dtype=attention_mask.dtype)], axis=-1
|
||
)
|
||
|
||
return model_kwargs
|
||
|
||
def forward(
|
||
self,
|
||
input_ids=None,
|
||
position_ids=None,
|
||
attention_mask=None,
|
||
inputs_embeds=None,
|
||
labels=None,
|
||
use_cache=False,
|
||
past_key_values=None,
|
||
output_attentions=None,
|
||
output_hidden_states=None,
|
||
return_dict=None,
|
||
):
|
||
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
|
||
outputs = self.gemma(
|
||
input_ids, # [bs, seq_len]
|
||
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,
|
||
)
|
||
|
||
hidden_states = outputs[0] # [bs, seq_len, dim]
|
||
|
||
# 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)
|
||
|
||
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 CausalLMOutputWithCrossAttentions(
|
||
loss=loss,
|
||
logits=logits,
|
||
past_key_values=outputs.past_key_values,
|
||
hidden_states=outputs.hidden_states,
|
||
attentions=outputs.attentions,
|
||
)
|