Compare commits

...

12 Commits

Author SHA1 Message Date
w5688414
a5f3286f8f Update unitest 2023-12-29 15:40:44 +08:00
w5688414
6639388526 Update unitest 2023-12-29 15:31:32 +08:00
w5688414
731b5515c9 remove unused comments 2023-12-29 09:19:12 +08:00
w5688414
60b656e014 fix prefix decoder 2023-12-29 00:53:45 +08:00
w5688414
0734019a18 Merge branch 'develop' of https://github.com/PaddlePaddle/PaddleNLP into pip90 2023-12-28 22:25:23 +08:00
w5688414
02f07e9c38 Add flash attention unitests 2023-12-28 20:09:20 +08:00
w5688414
d992d42b75 Add flash attention2 2023-12-28 16:57:47 +08:00
w5688414
fb193b56c3 Add flash attention to predictor 2023-12-28 16:51:37 +08:00
w5688414
8b7bea1175 Fix unitest bug 2023-12-28 16:06:13 +08:00
w5688414
3cbd143638 Add test for flash attention 2023-12-28 15:12:37 +08:00
w5688414
a899fce54f Update chatglm flash attention version check 2023-12-28 14:49:12 +08:00
w5688414
887a201c2e Add kv cache support for flash attention 2023-12-27 17:20:26 +08:00
10 changed files with 67 additions and 57 deletions

View File

@@ -75,6 +75,10 @@ class PredictorArgument:
"help": "the decoding strategy of generation, which should be one of ['sampling', 'greedy_search', 'beam_search']. Default to sampling"
},
)
use_flash_attention: bool = field(
default=False,
metadata={"help": "Whether to use flash attention"},
)
mode: str = field(
default="dynamic", metadata={"help": "the type of predictor, it should be one of [dynamic, static]"}
@@ -241,6 +245,7 @@ class DygraphPredictor(BasePredictor):
if self.model is None:
self.model = AutoModelForCausalLM.from_pretrained(
config.model_name_or_path,
use_flash_attention=config.use_flash_attention,
dtype=dtype,
tensor_parallel_degree=self.tensor_parallel_degree,
tensor_parallel_rank=self.tensor_parallel_rank,
@@ -685,7 +690,9 @@ def create_predictor(
tensor_parallel_degree: int = 1,
tensor_parallel_rank: int = 0,
):
tokenizer = AutoTokenizer.from_pretrained(predictor_args.model_name_or_path)
tokenizer = AutoTokenizer.from_pretrained(
predictor_args.model_name_or_path,
)
# init chat_template for tokenizer
init_chat_template(tokenizer, predictor_args.model_name_or_path, predictor_args.chat_template)
@@ -727,6 +734,7 @@ def create_predictor(
model = AutoModelForCausalLM.from_pretrained(
predictor_args.model_name_or_path,
dtype=predictor_args.dtype,
use_flash_attention=predictor_args.use_flash_attention,
tensor_parallel_degree=tensor_parallel_degree,
tensor_parallel_rank=tensor_parallel_rank,
)

View File

@@ -405,7 +405,6 @@ class DataCollatorForSeq2Seq:
return_tensors=return_tensors,
return_attention_mask=self.return_attention_mask,
)
# prepare decoder_input_ids
if (
labels is not None

View File

@@ -17,10 +17,10 @@ import paddle
def bloom_postprocess_past_key_value(past_key_values):
# (layer_num, bs, head_num/tensor_parallel_degree, prefixlen, head_dim)*2
past_key_values = paddle.transpose(past_key_values, perm=[2, 0, 3, 1, 4]).split(2)
keys, values = paddle.transpose(past_key_values, perm=[2, 0, 1, 3, 4]).split(2)
# keys: [layer_num, bs, head_num/tensor_parallel_degree, head_dim, prefixlen]
# value: [layer_num, bs, head_num/tensor_parallel_degree, prefixlen, head_dim]
keys, values = past_key_values[0].transpose([0, 1, 2, 4, 3]), past_key_values[1]
# keys, values = past_key_values[0].transpose([0, 1, 2, 4, 3]), past_key_values[1]
return tuple(zip(keys, values))

View File

@@ -378,9 +378,23 @@ class BloomAttention(nn.Layer):
(query_layer, key_layer, value_layer) = self._split_heads(fused_qkv)
batch_size, q_length, _, _ = query_layer.shape
if layer_past is not None:
past_key, past_value = layer_past
# concatenate along seq_length dimension:
# - key: [batch_size, kv_length, self.num_heads, head_dim]
# - value: [batch_size, kv_length, self.num_heads, head_dim]
key_layer = paddle.concat((past_key, key_layer), axis=1)
value_layer = paddle.concat((past_value, value_layer), axis=1)
if use_cache is True:
present = (key_layer, value_layer)
else:
present = None
version = paddle.version.full_version
version_check = True
if version != "0.0.0" and version <= "2.5.2":
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."
)
@@ -397,6 +411,8 @@ class BloomAttention(nn.Layer):
key_states,
value_states,
attn_mask=attention_mask,
dropout_p=self.config.attention_dropout,
training=self.training,
is_causal=False,
)
attn_weights = None
@@ -404,39 +420,10 @@ class BloomAttention(nn.Layer):
attn_output = attn_output.reshape([attn_output.shape[0], attn_output.shape[1], -1])
output_tensor = self.dense(attn_output)
query_layer = query_layer.transpose([0, 2, 1, 3])
key_layer = key_layer.transpose([0, 2, 3, 1])
value_layer = value_layer.transpose([0, 2, 1, 3])
if layer_past is not None:
past_key, past_value = layer_past
# concatenate along seq_length dimension:
# - key: [batch_size, self.num_heads, head_dim, kv_length]
# - value: [batch_size, self.num_heads, kv_length, head_dim]
key_layer = paddle.concat((past_key, key_layer), axis=3)
value_layer = paddle.concat((past_value, value_layer), axis=2)
if use_cache:
present = (key_layer, value_layer)
else:
present = None
else:
query_layer = query_layer.transpose([0, 2, 1, 3])
key_layer = key_layer.transpose([0, 2, 3, 1])
value_layer = value_layer.transpose([0, 2, 1, 3])
if layer_past is not None:
past_key, past_value = layer_past
# concatenate along seq_length dimension:
# - key: [batch_size, self.num_heads, head_dim, kv_length]
# - value: [batch_size, self.num_heads, kv_length, head_dim]
key_layer = paddle.concat((past_key, key_layer), axis=3)
value_layer = paddle.concat((past_value, value_layer), axis=2)
if use_cache is True:
present = (key_layer, value_layer)
else:
present = None
_, _, _, kv_length = key_layer.shape
query_layer = query_layer.reshape([batch_size * self.num_heads, q_length, self.head_dim])
@@ -449,7 +436,6 @@ class BloomAttention(nn.Layer):
attention_scores = baddbmm(
alibi, batch1=query_layer, batch2=key_layer, beta=self.beta, alpha=self.inv_norm_factor
)
# change view to [batch_size, num_heads, q_length, kv_length]
# attention_scores = matmul_result.reshape([batch_size, self.num_heads, q_length, kv_length])
@@ -949,14 +935,13 @@ class BloomModel(BloomPreTrainedModel):
seq_length_with_past = seq_length
past_key_values_length = 0
if past_key_values[0] is not None:
past_key_values_length = past_key_values[0][0].shape[3]
past_key_values_length = past_key_values[0][0].shape[1]
seq_length_with_past = seq_length_with_past + past_key_values_length
if attention_mask is None:
attention_mask = paddle.ones([batch_size, seq_length_with_past], dtype="bool")
elif attention_mask.dtype != paddle.bool:
attention_mask = paddle.cast(attention_mask, "bool")
if len(attention_mask.shape) > 2:
_attention_mask = paddle.ones([batch_size, seq_length_with_past], dtype="bool")
alibi = build_alibi_tensor(_attention_mask, self.config.n_head, dtype=hidden_states.dtype)

View File

@@ -245,9 +245,19 @@ class ChatGLMAttention(nn.Layer):
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 version != "0.0.0" and version <= "2.5.2":
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."
)
@@ -255,15 +265,6 @@ class ChatGLMAttention(nn.Layer):
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]
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)
# [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])
@@ -286,18 +287,9 @@ class ChatGLMAttention(nn.Layer):
output, attention_probs = attn_output, attn_weights
else:
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)
seq_length, batch_size, num_heads, hidden_size = k_layer.shape
cache_kv = None
if use_cache:
cache_kv = (k_layer, v_layer)
attention_scale_coeff = float(layer_id) + 1.0
if self.attention_scale:
# [s, b, n, h/n]

View File

@@ -17,6 +17,7 @@ finetune:
fp16_opt_level: "O2"
do_train: true
do_eval: true
use_flash_attention: true
disable_tqdm: true
load_best_model_at_end: true
eval_with_do_generation: false

View File

@@ -3,6 +3,7 @@ inference-predict:
mode: dynamic
max_length: 40
batch_size: 2
use_flash_attention: false
decode_strategy: greedy_search
dtype: float16
data_file: tests/fixtures/llm/data/train.json

View File

@@ -17,6 +17,7 @@ prefix_tuning:
do_train: true
do_eval: true
disable_tqdm: true
use_flash_attention: false
load_best_model_at_end: true
eval_with_do_generation: false
metric_for_best_model: "accuracy"

View File

@@ -77,6 +77,30 @@ class PredictorTest(LLMTest, unittest.TestCase):
else:
self.assertGreaterEqual(count / len(result_0), 0.4)
def test_flash_attention(self):
self.run_predictor({"inference_model": False, "use_flash_attention": False})
result_0 = self._read_result(os.path.join(self.output_dir, "predict.json"))
self.run_predictor({"inference_model": False, "use_flash_attention": True})
result_1 = self._read_result(os.path.join(self.output_dir, "predict.json"))
# compare the generation result of dygraph & flash attention model
assert len(result_0) == len(result_1)
count, full_match = 0, 0
for inference_item, no_inference_item in zip(result_0, result_1):
if self.model_name_or_path == "__internal_testing__/tiny-random-llama":
min_length = 5
else:
min_length = min(len(inference_item), len(no_inference_item))
count += int(inference_item[: min_length // 2] == no_inference_item[: min_length // 2])
full_match += int(inference_item[:min_length] == no_inference_item[:min_length])
if self.model_name_or_path == "__internal_testing__/tiny-random-llama":
self.assertGreaterEqual(count / len(result_0), 0.2)
else:
self.assertEqual(full_match / len(result_0), 1.0)
def test_wint8(self):
self.run_predictor({"inference_model": True, "quant_type": "weight_only_int8"})
result_0 = self._read_result(os.path.join(self.output_dir, "predict.json"))

View File

@@ -55,7 +55,6 @@ class PrefixTuningTest(LLMTest, unittest.TestCase):
prefix_tuning_config["dataset_name_or_path"] = self.data_dir
prefix_tuning_config["output_dir"] = self.output_dir
with argv_context_guard(prefix_tuning_config):
from finetune_generation import main