Files
wehub-resource-sync 2aaeece67c
Codestyle Check / Lint (push) Has been cancelled
Codestyle Check / Check bypass (push) Has been cancelled
Pipelines-Test / Pipelines-Test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:14 +08:00

984 lines
40 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Copyright (c) 2023 PaddlePaddle Authors. 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.
"""GLM model"""
from __future__ import annotations
import math
import re
from functools import partial
from typing import Any, Dict, Optional
import paddle
import paddle.nn as nn
import paddle.nn.functional as F
from paddle import Tensor
from paddle.distributed import fleet
from paddle.distributed.fleet.utils import recompute
from paddle.utils import map_structure
from paddlenlp.transformers.long_sequence_strategies import LongSequenceStrategies
from ...utils.env import CONFIG_NAME
from ...utils.log import logger
from .. import PretrainedModel, register_base_model
from ..model_outputs import (
BaseModelOutputWithPastAndCrossAttentions,
CausalLMOutputWithPast,
)
from .configuration import CHATGLM_PRETRAINED_RESOURCE_FILES_MAP, ChatGLMConfig
__all__ = [
"ChatGLMModel",
"ChatGLMPretrainedModel",
"ChatGLMForCausalLM",
]
def parallel_matmul(lm_output, logit_weights, parallel_output):
hcg = fleet.get_hybrid_communicate_group()
model_parallel_group = hcg.get_model_parallel_group()
world_size = hcg.get_model_parallel_world_size()
if world_size > 1:
# _c_identity is backwards is reduce
input_parallel = paddle.distributed.collective._c_identity(lm_output, group=model_parallel_group)
logits = paddle.matmul(input_parallel, logit_weights, transpose_y=True)
if parallel_output:
return logits
# _c_concat has not grad backwards
return paddle.distributed.collective._c_concat(logits, group=model_parallel_group)
else:
logits = paddle.matmul(lm_output, logit_weights, transpose_y=True)
return logits
class PrefixEncoder(nn.Layer):
"""
The prefix encoder for P-Tuning v2.
Input shape: [batch_size, prefix_length]
Output shape: [batch_size, prefix_length, 2 * num_layers * hidden_size]
"""
def __init__(self, config):
super().__init__()
self.prefix_projection = config.prefix_projection
if self.prefix_projection:
# Use a two-layer MLP to encode the prefix
self.embedding = nn.Embedding(config.pre_seq_len, config.hidden_size)
self.trans = nn.Sequential(
nn.Linear(config.hidden_size, config.hidden_size),
nn.Tanh(),
nn.Linear(config.hidden_size, config.num_layers * config.hidden_size * 2),
)
else:
self.embedding = nn.Embedding(config.pre_seq_len, config.num_layers * config.hidden_size * 2)
def forward(self, prefix: paddle.Tensor):
if self.prefix_projection:
prefix_tokens = self.embedding(prefix)
past_key_values = self.trans(prefix_tokens)
else:
past_key_values = self.embedding(prefix)
return past_key_values
class RotaryEmbeddings(nn.Layer):
def __init__(self, hidden_size, base=10000.0, position_encoding_2d=True):
super().__init__()
self.default_dtype = paddle.get_default_dtype()
self.inv_freq = 1.0 / (base ** (paddle.arange(0, hidden_size, 2).astype("float32") / hidden_size))
self.position_encoding_2d = position_encoding_2d
self.max_seq_len_cached = -1
self.cos_cached = None
self.sin_cached = None
def get_rotary_embeds(self, cos, sin, position_ids):
# [s, b, 1, h/n]
cos = cos.squeeze(1)[position_ids].unsqueeze(2)
sin = sin.squeeze(1)[position_ids].unsqueeze(2)
return paddle.stack([cos, sin], axis=0)
def forward(self, position_ids):
seq_len = position_ids.max() + 1
# seq_len = position_ids.shape[-1]
if self.max_seq_len_cached < 0 or seq_len > self.max_seq_len_cached:
self.max_seq_len_cached = seq_len
# x.shape = [b, s, n, h/n/2]
# TODO(duanyanhui): npu arange kernel don't support fp16, and
# it can't be fallbacked to cpu. It will be fixed in future.
t = paddle.arange(start=0, end=seq_len, dtype="float32")
# [s, h/n/2]
freqs = paddle.einsum("i,j->ij", t, self.inv_freq)
# [s, h/n]
emb = paddle.concat([freqs, freqs], axis=-1)
# [s, 1, h/n]
cos_cached = emb.cos().unsqueeze(1).cast(self.default_dtype)
sin_cached = emb.sin().unsqueeze(1).cast(self.default_dtype)
self.cos_cached, self.sin_cached = cos_cached, sin_cached
cos, sin = self.cos_cached[:seq_len, ...], self.sin_cached[:seq_len, ...]
if self.position_encoding_2d:
block_position_ids = position_ids[:, 1, :].transpose([1, 0])
position_ids = position_ids[:, 0, :].transpose([1, 0])
block_rotary_embeds = self.get_rotary_embeds(cos, sin, block_position_ids)
position_rotary_embeds = self.get_rotary_embeds(cos, sin, position_ids)
rotary_embeds = paddle.stack([position_rotary_embeds, block_rotary_embeds], axis=0)
else:
position_ids = position_ids.transpose([1, 0])
rotary_embeds = self.get_rotary_embeds(cos, sin, position_ids)
return rotary_embeds
class ChatGLMAttention(nn.Layer):
"""
Self-attention layer performs multiple attention to jointly attending to
information from different representation subspaces.
"""
def __init__(self, config: ChatGLMConfig):
super(ChatGLMAttention, self).__init__()
if config.hidden_size % config.num_attention_heads != 0:
raise ValueError(
f"The hidden size ({config.hidden_size}) is not a multiple of the number of attention "
f"heads ({config.num_attention_heads})"
)
self.config = config
self.num_attention_heads = config.num_attention_heads
self.attention_head_size = config.hidden_size // config.num_attention_heads
self.hidden_size = config.hidden_size
self.position_encoding_2d = config.position_encoding_2d
self.scale_mask_softmax = False
self.default_dtype = paddle.get_default_dtype()
self.attention_scale = config.attention_scale
if config.tensor_parallel_degree > 1:
self.query_key_value = fleet.meta_parallel.ColumnParallelLinear(
config.hidden_size, 3 * config.hidden_size, has_bias=True, gather_output=False
)
self.dense = fleet.meta_parallel.RowParallelLinear(
config.hidden_size, config.hidden_size, input_is_parallel=True, has_bias=True
)
self.num_attention_heads = config.num_attention_heads // config.tensor_parallel_degree
else:
self.query_key_value = nn.Linear(config.hidden_size, 3 * config.hidden_size)
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
# self.attention_dropout = nn.Dropout(config.attention_dropout_prob)
# self.output_dropout = nn.Dropout(config.output_dropout_prob)
def _rotate_half(self, x):
x1, x2 = paddle.chunk(x, 2, axis=-1)
return paddle.concat([-x2, x1], axis=-1)
def _apply_rotary_position_embed_index(self, q, k, cos, sin):
# q.shape = [s, b, n, h/n/2], cos.shape = [s, 1, h/n], position_ids.shape = [s, b]
# [s, b, n, h/n]
q = q * cos + self._rotate_half(q) * sin
k = k * cos + self._rotate_half(k) * sin
return q, k
def _core_attention(self, q_layer: Tensor, k_layer: Tensor, position_ids: Tensor, rotary_embeds: Tensor):
# Set store_true, position_encoding_2d=False by default.
if self.config.position_encoding_2d:
# [s, b, n, h/n/2]
q1, q2 = paddle.chunk(q_layer, 2, axis=-1)
k1, k2 = paddle.chunk(k_layer, 2, axis=-1)
pcos, psin = rotary_embeds[0][0], rotary_embeds[0][1]
bcos, bsin = rotary_embeds[1][0], rotary_embeds[1][1]
# [s, b, n, h/n]
q1, k1 = self._apply_rotary_position_embed_index(q1, k1, pcos, psin)
q2, k2 = self._apply_rotary_position_embed_index(q2, k2, bcos, bsin)
q_layer = paddle.concat([q1, q2], axis=-1)
k_layer = paddle.concat([k1, k2], axis=-1)
else:
cos, sin = rotary_embeds[0], rotary_embeds[1]
# [s, b, n, h/n]
q_layer, k_layer = self._apply_rotary_position_embed_index(q_layer, k_layer, cos, sin)
return q_layer, k_layer
def forward(
self,
hidden_states: Tensor,
attention_mask: Tensor,
position_ids: Tensor,
use_cache: bool = False,
cache: Tensor = None,
layer_id=0,
rotary_embeds=None,
):
# [s, b, h]
query_length, batch_size = hidden_states.shape[:2]
# [s, b, 3h]
mixed_layer = self.query_key_value(hidden_states)
# [s, b, n, 3h//n]
mixed_layer = mixed_layer.reshape(
[query_length, batch_size, self.num_attention_heads, self.attention_head_size * 3]
)
# [s, b, n, h//n]
q_layer, k_layer, v_layer = paddle.split(mixed_layer, 3, axis=-1)
# [s, b, n, h/n]
q_layer, k_layer = self._core_attention(q_layer, k_layer, position_ids, rotary_embeds)
if cache is not None:
cache_k, cache_v = cache[0], cache[1]
# [s + c, b, n, h/n]
k_layer = paddle.concat([cache_k, k_layer], axis=0)
v_layer = paddle.concat([cache_v, v_layer], axis=0)
cache_kv = None
if use_cache:
cache_kv = (k_layer, v_layer)
version = paddle.version.full_version
version_check = True
if self.config.use_flash_attention and version != "0.0.0" and version <= "2.5.2":
logger.warning(
"PaddlePaddle version 2.5.3 or higher is required, please upgrade your PaddlePaddle to 2.5.3 or other higher version."
)
version_check = False
if self.config.use_flash_attention and version_check:
# Paddle Flash Attention input [ bz, seqlen, nhead, head_dim]
# Torch Flash Attention input [ bz, nhead, seqlen, head_dim]
# [s, b, n, h/n] = > [batch_size, seq_len, num_heads, head_dim]
q_layer = paddle.transpose(q_layer, [1, 0, 2, 3])
k_layer = paddle.transpose(k_layer, [1, 0, 2, 3])
v_layer = paddle.transpose(v_layer, [1, 0, 2, 3])
query_states, key_states, value_states = q_layer, k_layer, v_layer
attn_output = F.scaled_dot_product_attention(
query_states,
key_states,
value_states,
attn_mask=attention_mask,
is_causal=False,
)
attn_weights = None
# [batch_size, seq_len, num_heads, head_dim] => [ batch_size, seq_len, hidden_size]
attn_output = paddle.reshape(attn_output, [attn_output.shape[0], attn_output.shape[1], -1])
# [ batch_size, seq_len, hidden_size] = > [ seq_len, batch_size, hidden_size]
attn_output = paddle.transpose(attn_output, [1, 0, 2])
attn_output = self.dense(attn_output)
output, attention_probs = attn_output, attn_weights
else:
seq_length, batch_size, num_heads, hidden_size = k_layer.shape
attention_scale_coeff = float(layer_id) + 1.0
if self.attention_scale:
# [s, b, n, h/n]
q_layer = q_layer / (math.sqrt(self.attention_head_size) * attention_scale_coeff)
q_layer = q_layer.astype(self.default_dtype)
# [b, n, s, s]
output_shape = [q_layer.shape[1], q_layer.shape[2], q_layer.shape[0], k_layer.shape[0]]
# [s, b * n, h/n]
q_layer = q_layer.reshape([output_shape[2], output_shape[0] * output_shape[1], -1])
k_layer = k_layer.reshape([output_shape[3], output_shape[0] * output_shape[1], -1])
# [b * n , s, s] = matmul([b * n, s, h/n], [b * n, h/n, s])
attention_scores = paddle.matmul(q_layer.transpose([1, 0, 2]), k_layer.transpose([1, 2, 0]))
# [b, n, s, s]
attention_scores = attention_scores.reshape(output_shape)
if self.scale_mask_softmax:
self.scale_mask_softmax.scale = attention_scale_coeff
attention_probs = self.scale_mask_softmax(attention_scores, attention_mask)
else:
attention_scores = attention_scores.astype("float32")
attention_scores = attention_scores * attention_scale_coeff
attention_scores = attention_scores + attention_mask
attention_probs = F.softmax(attention_scores, axis=-1)
attention_probs = attention_probs.astype(self.default_dtype)
v_layer = v_layer.astype(self.default_dtype)
# [b, n, s, h/n]
output_shape = [v_layer.shape[1], v_layer.shape[2], q_layer.shape[0], v_layer.shape[3]]
# [s, b * n, h/n]
v_layer = v_layer.reshape([v_layer.shape[0], output_shape[0] * output_shape[1], -1])
# [b * n, s, s]
attention_probs = attention_probs.reshape([output_shape[0] * output_shape[1], output_shape[2], -1])
# [b * n, s, h/n]
context_layer = paddle.bmm(attention_probs, v_layer.transpose([1, 0, 2]))
context_layer = context_layer.reshape(output_shape)
# [s, b, n, h/n]
context_layer = context_layer.transpose([2, 0, 1, 3])
# [s, b, h]
new_context_shape = context_layer.shape[:-2] + [self.num_attention_heads * self.attention_head_size]
context_layer = context_layer.reshape(new_context_shape)
output = self.dense(context_layer)
return output, cache_kv, attention_probs
class ChatGLMBlock(nn.Layer):
"""
The Transformer layer.
"""
def __init__(self, config: ChatGLMConfig, layer_id: int):
super(ChatGLMBlock, self).__init__()
self.config = config
self.layer_id = layer_id
self.default_dtype = paddle.get_default_dtype()
self.input_layernorm = nn.LayerNorm(config.hidden_size, epsilon=config.layernorm_epsilon)
self.attention = ChatGLMAttention(config)
self.post_attention_layernorm = nn.LayerNorm(config.hidden_size, epsilon=config.layernorm_epsilon)
self.mlp = ChatGLMMLP(config)
def forward(
self,
hidden_states: Tensor,
attention_mask: Tensor,
position_ids: Tensor,
use_cache: bool = False,
cache: Tensor = None,
rotary_embeds: Tensor = None,
):
# Layer norm before transformer layer
attention_input = self.input_layernorm(hidden_states)
# Self attention
attention_output, cache, _ = self.attention(
hidden_states=attention_input,
attention_mask=attention_mask,
position_ids=position_ids,
cache=cache,
use_cache=use_cache,
layer_id=self.layer_id,
rotary_embeds=rotary_embeds,
)
# Residual connection
alpha = (2 * self.config.num_hidden_layers) ** 0.5
layernorm_input = alpha * attention_input + attention_output
# Layernorm after attention
mlp_input = self.post_attention_layernorm(layernorm_input)
# MLP
mlp_output = self.mlp(mlp_input)
# Second residual connection
output = mlp_input * alpha + mlp_output
return output, cache
class ChatGLMMLP(nn.Layer):
def __init__(self, config: ChatGLMConfig):
super(ChatGLMMLP, self).__init__()
self.config = config
if config.inner_hidden_size is None:
inner_hidden_size = config.hidden_size * 4
else:
inner_hidden_size = config.inner_hidden_size
if config.tensor_parallel_degree > 1:
self.dense_h_to_4h = fleet.meta_parallel.ColumnParallelLinear(
config.hidden_size, inner_hidden_size, has_bias=True, gather_output=False
)
self.dense_4h_to_h = fleet.meta_parallel.RowParallelLinear(
inner_hidden_size, config.hidden_size, input_is_parallel=True, has_bias=True
)
else:
self.dense_h_to_4h = nn.Linear(config.hidden_size, inner_hidden_size)
self.dense_4h_to_h = nn.Linear(inner_hidden_size, config.hidden_size)
# self.dropout = nn.Dropout(config.output_dropout_prob)
self.activation = self.geglue if self.config.activation == "geglu" else self.gelu
def geglu(self, x):
x1, x2 = paddle.chunk(x, chunks=2, axis=-1)
x = x1 * F.gelu(x2)
return x
def gelu(self, x):
return F.gelu(x, approximate=True)
def forward(self, hidden_states):
intermediate_parallel = self.dense_h_to_4h(hidden_states)
intermediate_parallel = self.activation(intermediate_parallel)
output = self.dense_4h_to_h(intermediate_parallel)
# output = self.dropout(output)
return output
class ChatGLMStack(nn.Layer):
"""
GLM Transformer
"""
def __init__(self, config: ChatGLMConfig):
super(ChatGLMStack, self).__init__()
self.config = config
self.position_encoding_2d = config.position_encoding_2d
self.hidden_size = config.hidden_size
# Recompute defaults to False and is controlled by Trainer
self.enable_recompute = False
self.num_attention_heads = config.num_attention_heads
if config.use_long_sequence_strategies:
self.rotary_embeddings = LongSequenceStrategies.build_long_sequence_strategy(
config.long_sequence_strategy_type,
config.long_sequence_strategy_name,
**config.long_sequence_init_args,
)
else:
self.rotary_embeddings = RotaryEmbeddings(
self.hidden_size // (self.num_attention_heads * 2)
if self.position_encoding_2d
else self.hidden_size // self.num_attention_heads,
base=10000.0,
)
# self.embedding_dropout = nn.Dropout(config.embedding_dropout_prob)
if self.config.tensor_parallel_degree > 1:
self.word_embeddings = fleet.meta_parallel.VocabParallelEmbedding(
config.vocab_size,
config.hidden_size,
weight_attr=paddle.ParamAttr(initializer=nn.initializer.XavierNormal()),
)
else:
self.word_embeddings = nn.Embedding(
config.vocab_size,
config.hidden_size,
weight_attr=paddle.ParamAttr(initializer=nn.initializer.XavierNormal()),
)
self.layers = nn.LayerList()
for index in range(config.num_hidden_layers):
self.layers.append(ChatGLMBlock(config, index))
self.final_layernorm = nn.LayerNorm(config.hidden_size, epsilon=config.layernorm_epsilon)
if self.config.pre_seq_len is not None:
for param in self.parameters():
param.requires_grad = False
self.prefix_tokens = paddle.arange(self.pre_seq_len, dtype="int64")
self.prefix_encoder = PrefixEncoder(config)
self.dropout = nn.Dropout(0.1)
def get_prompt(self, batch_size, dtype=paddle.float16):
prefix_tokens = self.prefix_tokens.unsqueeze(0).expand([batch_size, -1])
past_key_values = self.prefix_encoder(prefix_tokens).astype(dtype)
past_key_values = past_key_values.reshape(
batch_size,
self.config.pre_seq_len,
self.config.num_layers * 2,
self.config.num_attention_heads,
self.config.hidden_size // self.config.num_attention_heads,
)
# seq_len, b, nh, hidden_size
past_key_values = self.dropout(past_key_values)
past_key_values = past_key_values.transpose([2, 1, 0, 3, 4]).split(2)
# past_key_values = [(v[0], v[1]) for v in past_key_values]
return past_key_values
@paddle.jit.not_to_static
def recompute_training(
self,
layer_module: nn.Layer,
hidden_states: Tensor,
attention_mask: Tensor,
position_ids: Tensor,
use_cache: bool,
cache: Tensor,
rotary_embeds: Tensor,
):
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,
attention_mask,
position_ids,
use_cache,
cache,
rotary_embeds,
use_reentrant=self.config.recompute_use_reentrant,
)
return hidden_states
def forward(
self,
input_ids: Tensor,
position_ids: Tensor,
attention_mask: Tensor,
inputs_embeds: Tensor = None,
cache: Optional[Tensor] = None,
use_cache: bool = False,
):
if input_ids is not None and inputs_embeds is not None:
input_ids = None
logger.warning("Specify both input_ids and inputs_embeds at the same time, will use inputs_embeds")
elif input_ids is not None:
batch_size, seq_length = input_ids.shape[:2]
elif inputs_embeds is not None:
batch_size, seq_length = inputs_embeds.shape[:2]
else:
raise ValueError("You have to specify either input_ids or inputs_embeds")
if inputs_embeds is None:
inputs_embeds = self.word_embeddings(input_ids)
inputs_embeds = inputs_embeds.transpose([1, 0, 2])
if self.config.use_long_sequence_strategies:
cos, sin = self.rotary_embeddings(seq_len=seq_length)
block_position_ids = position_ids[:, 1, :].transpose([1, 0])
position_ids = position_ids[:, 0, :].transpose([1, 0])
block_rotary_embeds = paddle.stack(
[cos[block_position_ids].unsqueeze(2), sin[block_position_ids].unsqueeze(2)]
)
position_rotary_embeds = paddle.stack([cos[position_ids].unsqueeze(2), sin[position_ids].unsqueeze(2)])
rotary_embeds = paddle.stack([position_rotary_embeds, block_rotary_embeds], axis=0)
else:
rotary_embeds = self.rotary_embeddings(position_ids)
if cache is None:
if self.config.pre_seq_len is not None:
cache = self.get_prompt(batch_size=input_ids.shape[0], dtype=inputs_embeds.dtype)
else:
cache = tuple([None] * len(self.layers))
# this branch is deprecated
if self.config.pre_seq_len is not None and attention_mask is not None:
prefix_attention_mask = paddle.ones([batch_size, 1, input_ids.shape[-1], self.config.pre_seq_len])
prefix_attention_mask = (prefix_attention_mask < 0.5).astype("int64")
attention_mask = paddle.concat((prefix_attention_mask, attention_mask), axis=3)
zero = paddle.zeros(attention_mask.shape, dtype=inputs_embeds.dtype)
neg_inf = paddle.full_like(attention_mask, paddle.finfo(inputs_embeds.dtype).min, dtype=inputs_embeds.dtype)
attention_mask = paddle.where(attention_mask, zero, neg_inf)
hidden_states = inputs_embeds
current_caches = [] if use_cache else None
for i, layer in enumerate(self.layers):
cache_i = cache[i]
if self.enable_recompute and not hidden_states.stop_gradient:
hidden_states, new_cache = self.recompute_training(
layer,
hidden_states=hidden_states,
attention_mask=attention_mask,
position_ids=position_ids,
use_cache=use_cache,
cache=cache_i,
rotary_embeds=rotary_embeds,
)
else:
hidden_states, new_cache = layer(
hidden_states=hidden_states,
attention_mask=attention_mask,
position_ids=position_ids,
use_cache=use_cache,
cache=cache_i,
rotary_embeds=rotary_embeds,
)
if use_cache:
current_caches.append(new_cache)
output = self.final_layernorm(hidden_states)
return (output, current_caches)
class ChatGLMPretrainedModel(PretrainedModel):
"""
An abstarct class for pretrained ChatGLM models. It provides GLM related
`model_config_file`, `resource_file_names`, `pretrained_resource_files_map`,
`pretrained_init_configuration`, `base_model_prefix` for downloading and
loading pretrained models.
See :class:`~paddlenlp.transformers.model_utils.PretrainedModel` for more details.
"""
base_model_prefix = "chatglm"
config_class = ChatGLMConfig
model_config_file = CONFIG_NAME
resource_files_names = {"model_state": "model_state.pdparams"}
pretrained_resource_files_map = CHATGLM_PRETRAINED_RESOURCE_FILES_MAP
_keys_to_ignore_on_load_missing = [r"transformer.rotary_embeddings.inv_freq", r"lm_head.decoder_weight"]
_keys_to_ignore_on_load_unexpected = [r"transformer.rotary_emb.inv_freq"]
def init_weights(self, layer):
"""Initialization hook"""
return None
def get_position_ids(self, input_ids, mask_positions, use_gmasks=None):
batch_size, seq_length = input_ids.shape
if use_gmasks is None:
use_gmasks = [False] * batch_size
context_lengths = []
for seq in input_ids:
context_lengths.append(paddle.where(seq == self.config.bos_token_id)[0][0])
if self.config.position_encoding_2d:
position_ids = paddle.arange(seq_length, dtype="int64").unsqueeze(0).tile([batch_size, 1])
for i, context_length in enumerate(context_lengths):
position_ids[i, context_length:] = mask_positions[i]
block_position_ids = [
paddle.concat(
(
paddle.zeros([context_length], dtype="int64"),
paddle.arange(seq_length - context_length, dtype="int64") + 1,
)
)
for context_length in context_lengths
]
block_position_ids = paddle.stack(block_position_ids, axis=0)
position_ids = paddle.stack((position_ids, block_position_ids), axis=1)
else:
position_ids = paddle.arange(seq_length, dtype="int64").unsqueeze(0).tile([batch_size, 1])
for i, context_length in enumerate(context_lengths):
if not use_gmasks[i]:
position_ids[context_length:] = mask_positions[i]
return position_ids
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, None, None], dtype="int64"),
"position_ids": paddle.static.InputSpec(shape=[None, 2, None], dtype="int64"),
}
@classmethod
def _get_tensor_parallel_mappings(cls, config, 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_hidden_layers):
final_actions = {}
base_actions = {
# Column Linear
"transformer.layers.0.mlp.dense_h_to_4h.bias": partial(fn, is_column=True),
"transformer.layers.0.mlp.dense_h_to_4h.weight": partial(fn, is_column=True),
"transformer.layers.0.attention.query_key_value.bias": partial(fn, is_column=True),
"transformer.layers.0.attention.query_key_value.weight": partial(fn, is_column=True),
# Row Linear
"transformer.word_embeddings.weight": partial(fn, is_column=False),
"transformer.layers.0.attention.dense.weight": partial(fn, is_column=False),
"transformer.layers.0.mlp.dense_4h_to_h.weight": partial(fn, is_column=False),
}
for key, action in base_actions.items():
if "layers.0." in key:
for i in range(num_hidden_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
@register_base_model
class ChatGLMModel(ChatGLMPretrainedModel):
r"""
The GLM Model transformer can behave as an encoder (with only self-attention) as well as a decoder, where
a layer of cross-attention is added between the self-attention layers, following the architecture
described in [Attention is all you need](https://arxiv.org/abs/1706.03762).
This model inherits from :class:`~paddlenlp.transformers.model_utils.PretrainedModel`.
Refer to the superclass documentation for the generic methods.
This model is also a Paddle `paddle.nn.Layer <https://www.paddlepaddle.org.cn/documentation
/docs/zh/api/paddle/nn/Layer_cn.html>`__ subclass. Use it as a regular Paddle Layer
and refer to the Paddle documentation for all matter related to general usage and behavior.
"""
_keys_to_ignore_on_load_unexpected = [r"transformer.layers.*.attention.rotary_emb.inv_freq", r"lm_head.weight"]
def __init__(self, config: ChatGLMConfig):
super(ChatGLMModel, self).__init__(config)
self.config = config
self.transformer = ChatGLMStack(config)
self.apply(self.init_weights)
def get_input_embeddings(self):
return self.transformer.word_embeddings
def set_input_embeddings(self, new_embeddings):
self.transformer.word_embeddings = new_embeddings
def forward(
self,
input_ids: Tensor = None,
position_ids: Tensor = None,
attention_mask: Tensor = None,
cache=None,
inputs_embeds: Tensor = None,
use_cache: bool = None,
return_dict: bool = None,
):
if input_ids is None:
assert position_ids is not None, "`position_ids` must be explicitly specified when input_ids is None."
assert attention_mask is not None, "`attention_mask` must be explicitly specified when input_ids is None."
if attention_mask is None or len(attention_mask.shape) != 4:
raise ValueError(f"attention mask shouldn't be None or has size other than 4Dim. Found {attention_mask}")
attention_mask = attention_mask.astype("bool")
if position_ids is None:
MASK, gMASK = self.config.mask_token_id, self.config.gmask_token_id
use_gmasks = []
mask_positions = []
for seq in input_ids:
mask_token = gMASK if gMASK in seq else MASK
use_gmask = mask_token == gMASK
use_gmasks.append(use_gmask)
mask_positions.append(paddle.where(seq == mask_token)[0][0])
position_ids = self.get_position_ids(input_ids, mask_positions=mask_positions, use_gmasks=use_gmasks)
use_cache = use_cache if use_cache is not None else self.config.use_cache
logits, new_caches = self.transformer(
input_ids=input_ids,
position_ids=position_ids,
attention_mask=attention_mask,
inputs_embeds=inputs_embeds,
cache=cache,
use_cache=use_cache,
)
if not return_dict:
return (logits, new_caches)
return BaseModelOutputWithPastAndCrossAttentions(last_hidden_state=logits, past_key_values=new_caches)
class ChatGLMHead(nn.Layer):
def __init__(self, config, embedding_weights=None):
super(ChatGLMHead, self).__init__()
self.decoder_weight = (
self.create_parameter(shape=[config.vocab_size, config.hidden_size], dtype=paddle.get_default_dtype())
if embedding_weights is None
else embedding_weights
)
self.config = config
def forward(self, hidden_states):
if self.config.tensor_parallel_degree > 1:
logits = parallel_matmul(hidden_states, self.decoder_weight, self.config.tensor_parallel_output)
else:
logits = F.linear(hidden_states, self.decoder_weight.T)
return logits
class ChatGLMForCausalLM(ChatGLMPretrainedModel):
_keys_to_ignore_on_save = [r"lm_head.decoder_weight"]
_tied_weights_keys = ["lm_head.decoder_weight"]
def __init__(self, config: ChatGLMConfig):
super(ChatGLMForCausalLM, self).__init__(config)
self.config = config
self.max_sequence_length = config.max_sequence_length
self.position_encoding_2d = config.position_encoding_2d
self.chatglm = ChatGLMModel(config)
self.lm_head = ChatGLMHead(config, self.chatglm.transformer.word_embeddings.weight)
# from paddlenlp.transformers import ChatGLMTokenizer
# self.tokenizer = ChatGLMTokenizer.from_pretrained("THUDM/chatglm-6b")
def prepare_inputs_for_generation(
self, input_ids, position_ids=None, attention_mask=None, past_key_values=None, cache=None, **kwargs
):
batch_size, seq_length = input_ids.shape
MASK, gMASK = self.config.mask_token_id, self.config.gmask_token_id
use_gmasks = []
mask_positions = []
for seq in input_ids:
mask_token = gMASK if gMASK in seq else MASK
use_gmask = mask_token == gMASK
use_gmasks.append(use_gmask)
mask_positions.append(paddle.where(seq == mask_token)[0][0])
if cache is not None or past_key_values is not None:
last_token = input_ids[:, -1].unsqueeze(-1)
attention_mask = attention_mask[:, :, -1:]
if position_ids is not None:
position_ids = position_ids[..., -1:]
else:
if self.position_encoding_2d:
context_lengths = []
for seq in input_ids:
context_lengths.append(paddle.where(seq == self.config.bos_token_id)[0][0])
context_lengths = paddle.to_tensor(context_lengths, dtype="int64")
block_position_ids = seq_length - context_lengths
position_ids = paddle.concat(
[
paddle.to_tensor(mask_positions, dtype="int64").unsqueeze(-1),
block_position_ids.unsqueeze(-1),
],
axis=1,
).unsqueeze(-1)
else:
position_ids = paddle.to_tensor(mask_positions, dtype="int64").unsqueeze(-1)
if cache is None:
cache = past_key_values
return {
"input_ids": last_token,
"cache": cache[-1],
"position_ids": position_ids,
"use_cache": True,
"attention_mask": attention_mask,
}
else:
if position_ids is None:
position_ids = self.get_position_ids(input_ids, mask_positions=mask_positions, use_gmasks=use_gmasks)
return {
"input_ids": input_ids,
"cache": cache,
"position_ids": position_ids,
"use_cache": True,
"attention_mask": attention_mask,
}
def reorder_cache(self, cache: paddle.Tensor, beam_idx):
cache = map_structure(lambda x: paddle.index_select(x, beam_idx, axis=1), cache)
return cache
def update_model_kwargs_for_generation(
self,
outputs,
model_kwargs: Dict[str, Any],
is_encoder_decoder: bool = False,
standardize_cache_format: bool = False,
) -> Dict[str, Any]:
# update cache
model_kwargs["cache"] = outputs[1] if isinstance(outputs, tuple) else outputs["past_key_values"]
# update attention mask
if "attention_mask" in model_kwargs:
attention_mask = model_kwargs["attention_mask"]
if attention_mask is not None:
attention_mask = paddle.concat(
[attention_mask, paddle.zeros([*attention_mask.shape[:3], 1], attention_mask.dtype)], axis=3
)
new_attention_mask = attention_mask[:, :, -1:].clone()
new_attention_mask[..., -1] = 1
model_kwargs["attention_mask"] = paddle.concat([attention_mask, new_attention_mask], axis=2)
# update position ids
if "position_ids" in model_kwargs:
position_ids = model_kwargs["position_ids"]
new_position_id = position_ids[..., -1:].clone()
new_position_id[:, 1, :] += 1
model_kwargs["position_ids"] = paddle.concat([position_ids, new_position_id], axis=-1)
return model_kwargs
def forward(
self,
input_ids=None,
position_ids=None,
attention_mask=None,
cache=None,
inputs_embeds=None,
labels=None,
use_cache=None,
return_dict=False,
):
transformer_outputs = self.chatglm(
input_ids=input_ids,
position_ids=position_ids,
attention_mask=attention_mask,
cache=cache,
inputs_embeds=inputs_embeds,
use_cache=use_cache,
return_dict=return_dict,
)
hidden_states = transformer_outputs.last_hidden_state if return_dict else transformer_outputs[0]
lm_logits = self.lm_head(hidden_states)
lm_logits = lm_logits.transpose([1, 0, 2]).astype("float32")
loss = None
if labels is not None:
if self.config.tensor_parallel_degree > 1 and self.config.tensor_parallel_output:
self.parallel_loss_func = fleet.meta_parallel.ParallelCrossEntropy()
filtered_logits = lm_logits[labels != -100]
filtered_labels = labels[labels != -100]
loss = self.parallel_loss_func(filtered_logits, filtered_labels).mean()
else:
loss = nn.functional.cross_entropy(lm_logits, labels, ignore_index=-100)
loss = loss.astype(lm_logits.dtype)
if not return_dict:
if loss is not None:
return (loss, lm_logits, transformer_outputs[1:])
else:
return (lm_logits, transformer_outputs[1:])
return CausalLMOutputWithPast(
loss=loss,
logits=lm_logits,
past_key_values=transformer_outputs.past_key_values,
)
@staticmethod
def _reorder_cache(cache, beam_idx):
return tuple(
(
layer_past[0].index_select(1, beam_idx),
layer_past[1].index_select(1, beam_idx),
)
for layer_past in cache
)
@staticmethod
def process_response(response):
response = response.strip()
response = response.replace("[[训练时间]]", "2023年")
punkts = [
[",", ""],
["!", ""],
[":", ""],
[";", ""],
["\?", ""],
]
for item in punkts:
response = re.sub(r"([\u4e00-\u9fff])%s" % item[0], r"\1%s" % item[1], response)
response = re.sub(r"%s([\u4e00-\u9fff])" % item[0], r"%s\1" % item[1], response)
return response