From 2709183700aba8aea1feebb4cb08867b4de888e4 Mon Sep 17 00:00:00 2001 From: David Corvoysier Date: Wed, 24 Jan 2024 16:16:57 +0100 Subject: [PATCH] Add Llama2 inference benchmark under a new "benchmarks" section (#435) * chore: added text-generation benchmark scripts * doc: added llama2 benchmark * Apply suggestions from code review Co-authored-by: Philipp Schmid <32632186+philschmid@users.noreply.github.com> --------- Co-authored-by: Philipp Schmid <32632186+philschmid@users.noreply.github.com> --- benchmark/text-generation/README.md | 12 +++ benchmark/text-generation/benchmark.py | 92 ++++++++++++++++ benchmark/text-generation/gen_barcharts.py | 98 ++++++++++++++++++ benchmark/text-generation/llama2.py | 33 ++++++ .../inferentia-llama2/encoding_times.png | Bin 0 -> 21785 bytes .../inferentia-llama2/latencies.png | Bin 0 -> 27070 bytes .../inferentia-llama2/throughputs.png | Bin 0 -> 32260 bytes docs/source/_toctree.yml | 6 +- docs/source/benchmarks/inferentia-llama2.mdx | 77 ++++++++++++++ 9 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 benchmark/text-generation/README.md create mode 100644 benchmark/text-generation/benchmark.py create mode 100644 benchmark/text-generation/gen_barcharts.py create mode 100644 benchmark/text-generation/llama2.py create mode 100644 docs/assets/benchmarks/inferentia-llama2/encoding_times.png create mode 100644 docs/assets/benchmarks/inferentia-llama2/latencies.png create mode 100644 docs/assets/benchmarks/inferentia-llama2/throughputs.png create mode 100644 docs/source/benchmarks/inferentia-llama2.mdx diff --git a/benchmark/text-generation/README.md b/benchmark/text-generation/README.md new file mode 100644 index 000000000..83b0a846d --- /dev/null +++ b/benchmark/text-generation/README.md @@ -0,0 +1,12 @@ +# Usage + +```shell +python llama2.py +``` +This will produce several JSON files. + +```shell +python gen_barchcharts.py +``` + +This will create three barchart images for encoding times, latency and throughput. diff --git a/benchmark/text-generation/benchmark.py b/benchmark/text-generation/benchmark.py new file mode 100644 index 000000000..39f1c909a --- /dev/null +++ b/benchmark/text-generation/benchmark.py @@ -0,0 +1,92 @@ +import argparse +import json +import os +import time + +import torch +from transformers import AutoConfig, AutoTokenizer, set_seed + +from optimum.neuron import NeuronModelForCausalLM + + +def generate(model, input_ids, length): + start = time.time() + with torch.inference_mode(): + output_tokens = model.generate(input_ids, do_sample=False, min_length=length, max_length=length) + end = time.time() + return output_tokens, (end - start) + + +def run(model_id, inc_length, max_length, json_path=None): + prompts = ["One of my fondest memory"] + config = AutoConfig.from_pretrained(model_id) + batch_size = config.neuron["batch_size"] + if len(prompts) < batch_size: + prompts = prompts + [prompts[-1]] * (batch_size - len(prompts)) + model = NeuronModelForCausalLM.from_pretrained(model_id, export=False, low_cpu_mem_usage=True) + tokenizer = AutoTokenizer.from_pretrained(model_id) + # Specify padding options for decoder-only architecture + tokenizer.pad_token_id = tokenizer.eos_token_id + tokenizer.padding_side = "left" + # Encode the first input tokens + tokens = tokenizer(prompts, return_tensors="pt", padding=True) + bootstrap_input_ids = tokens.input_ids + # Generate the first set of inputs + input_ids, latency = generate(model, bootstrap_input_ids, inc_length) + input_length = input_ids.size()[-1] + neuron_config = getattr(model.config, "neuron") + benchmark = {"neuron_config": neuron_config, "results": []} + while input_length < max_length: + # Generate a single input, just to evaluate the context encoding time + _, encoding_time = generate(model, input_ids, input_length + 1) + result = { + "input_length": input_length, + "batch_size": batch_size, + "encoding_time": encoding_time, + "generations": [], + } + for sequence_length in range(input_length + inc_length, max_length + 1, inc_length): + output_ids, latency = generate(model, input_ids, sequence_length) + throughput = batch_size * sequence_length / latency + result["generations"].append( + { + "sequence_length": sequence_length, + "new_tokens": sequence_length - input_length, + "latency": latency, + "generation_time": latency - encoding_time, + "throughput": throughput, + } + ) + # Reuse the first generated tokens for the next step + input_length += inc_length + input_ids = output_ids[:, :input_length] + benchmark["results"].append(result) + if json_path is not None: + with open(json_path, "w") as fp: + json.dump(benchmark, fp, indent=4) + return benchmark + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("model", type=str, help="A neuron model in a local directory.") + parser.add_argument("--inc-length", type=int, default=128, help="The number of tokens in each increment.") + parser.add_argument("--max-length", type=int, default=2048, help="The maximum number of generated tokens.") + parser.add_argument("--seed", type=int, default=None, help="Pass a seed for reproducibility.") + args = parser.parse_args() + if args.seed is not None: + set_seed(args.seed) + model_name = os.path.basename(os.path.normpath(args.model)) + benchmark = run(args.model, args.inc_length, args.max_length, json_path=f"{model_name}.json") + # Dump encoding times + results = benchmark["results"] + print(f"{benchmark['neuron_config']}") + print("Encoding times") + print([result["input_length"] for result in results]) + print([f"{result['encoding_time']:.2f}" for result in results]) + # Just look at the first set of generations + generations = results[0]["generations"] + print(f"Latency and throughput for {args.inc_length} input tokens") + print([generation["new_tokens"] for generation in generations]) + print([f"{generation['latency']:.2f}" for generation in generations]) + print([f"{generation['throughput']:.2f}" for generation in generations]) diff --git a/benchmark/text-generation/gen_barcharts.py b/benchmark/text-generation/gen_barcharts.py new file mode 100644 index 000000000..c694b6999 --- /dev/null +++ b/benchmark/text-generation/gen_barcharts.py @@ -0,0 +1,98 @@ +import argparse +import glob +import json +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np + + +def save_bar_chart(title, labels, ylabel, series, save_path): + x = np.arange(len(labels)) # the label locations + width = 0.15 # the width of the bars + multiplier = 0 + + fig, ax = plt.subplots(layout="constrained") + fig.set_figwidth(10) + + max_value = 0 + + for attribute, measurement in series.items(): + max_value = max(max_value, max(measurement)) + offset = width * multiplier + rects = ax.bar(x + offset, measurement, width, label=attribute) + ax.bar_label(rects, padding=5) + multiplier += 1 + + # Add some text for labels, title and custom x-axis tick labels, etc. + ax.set_ylabel(ylabel) + ax.set_title(title) + ax.set_xticks(x + width, labels) + ax.legend(loc="upper left", ncols=3) + ax.set_ylim(0, max_value * 1.2) + + plt.savefig(save_path) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("inputs", type=str, nargs="*", help="A list of benchmark results files (.json).") + args = parser.parse_args() + inputs = args.inputs + if len(inputs) == 0: + inputs = glob.glob("*.json") + benchmarks = {} + for input in inputs: + model_name = Path(input).stem + with open(input) as f: + benchmarks[model_name] = json.load(f) + model_names = benchmarks.keys() + # Generate encoding barchart + input_length = [] + encoding_times = {} + for name in model_names: + results = benchmarks[name]["results"] + cur_input_length = [result["input_length"] for result in results] + if len(input_length) == 0: + input_length = cur_input_length + else: + assert cur_input_length == input_length, f"{name} does not have the same number of results" + encoding_times[name] = [round(result["encoding_time"], 1) for result in results] + save_bar_chart( + title="Encoding time per input token", + labels=input_length, + series=encoding_times, + ylabel="Encoding time (s)", + save_path="encoding_times.png", + ) + # Generate latency and throughput barcharts (for the first input length only) + new_tokens = [] + latencies = {} + throughputs = {} + for name in model_names: + generations = benchmarks[name]["results"][0]["generations"] + cur_new_tokens = [generation["new_tokens"] for generation in generations] + if len(new_tokens) == 0: + new_tokens = cur_new_tokens + else: + assert cur_new_tokens == new_tokens, f"{name} does not have the same number of results" + latencies[name] = [round(generation["latency"], 1) for generation in generations] + throughputs[name] = [round(generation["throughput"], 0) for generation in generations] + save_bar_chart( + title="End-to-end latency per generated tokens for 256 input tokens", + labels=new_tokens, + series=latencies, + ylabel="Latency (s)", + save_path="latencies.png", + ) + save_bar_chart( + title="Throughput per generated tokens for 256 input tokens", + labels=new_tokens, + series=throughputs, + ylabel="Throughput (tokens/s)", + save_path="throughputs.png", + ) + + +if __name__ == "__main__": + main() diff --git a/benchmark/text-generation/llama2.py b/benchmark/text-generation/llama2.py new file mode 100644 index 000000000..737e8a5cf --- /dev/null +++ b/benchmark/text-generation/llama2.py @@ -0,0 +1,33 @@ +import os +from tempfile import TemporaryDirectory + +from transformers import AutoTokenizer + +from benchmark import run +from optimum.neuron import NeuronModelForCausalLM + + +model_configurations = { + "Llama-2-7BL": ["meta-llama/Llama-2-7b-chat-hf", 1, 2048], + "Llama-2-7BT": ["meta-llama/Llama-2-7b-chat-hf", 4, 2048], +} + +num_cores = len(os.listdir("/sys/class/neuron_device/")) * 2 +if num_cores >= 4: + extra_model_configurations = { + "Llama-2-13BL": ["meta-llama/Llama-2-13b-chat-hf", 1, 2048], + "Llama-2-13BT": ["meta-llama/Llama-2-13b-chat-hf", 4, 2048], + } + model_configurations = {**model_configurations, **extra_model_configurations} + +for model_name, model_configuration in model_configurations.items(): + model_id, batch_size, seq_length = model_configuration + model = NeuronModelForCausalLM.from_pretrained( + model_id, export=True, batch_size=batch_size, sequence_length=seq_length, auto_cast_type="fp16" + ) + with TemporaryDirectory() as tmpdir: + model.save_pretrained(tmpdir) + tokenizer = AutoTokenizer.from_pretrained(model_id) + tokenizer.save_pretrained(tmpdir) + json_path = f"{model_name}.json" + run(tmpdir, 256, 1024, json_path=json_path) diff --git a/docs/assets/benchmarks/inferentia-llama2/encoding_times.png b/docs/assets/benchmarks/inferentia-llama2/encoding_times.png new file mode 100644 index 0000000000000000000000000000000000000000..144342227bc844f59efccaf01787f9dfb986a448 GIT binary patch literal 21785 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 z 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 TA@8vlHS#Hzz4n@+D(AUB@ijaL literal 0 HcmV?d00001 diff --git a/docs/assets/benchmarks/inferentia-llama2/throughputs.png b/docs/assets/benchmarks/inferentia-llama2/throughputs.png new file mode 100644 index 0000000000000000000000000000000000000000..e76649565d5a2ddd21efc5497225d18dfffeb73b GIT binary patch literal 32260 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%0D43A4E0N5T|zieP7>%fcuS{ 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 literal 0 HcmV?d00001 diff --git a/docs/source/_toctree.yml b/docs/source/_toctree.yml index 7730aa35c..2416dd141 100644 --- a/docs/source/_toctree.yml +++ b/docs/source/_toctree.yml @@ -17,7 +17,7 @@ - local: tutorials/llama2-13b-chatbot title: Create your own chatbot with llama-2-13B on AWS Inferentia - local: tutorials/fine_tune_llama_7b - title: Fine-tune Llama 2 7B on AWS Trainium + title: Fine-tune Llama 2 7B on AWS Trainium - local: tutorials/sentence_transformers title: Sentence Transformers on AWS Inferentia title: Tutorials @@ -51,5 +51,9 @@ - local: package_reference/modeling title: Neuron Models title: Reference + - sections: + - local: benchmarks/inferentia-llama2 + title: Llama on AWS Inferentia2 + title: Benchmarks title: Optimum Neuron isExpanded: true diff --git a/docs/source/benchmarks/inferentia-llama2.mdx b/docs/source/benchmarks/inferentia-llama2.mdx new file mode 100644 index 000000000..c7c6d7fbe --- /dev/null +++ b/docs/source/benchmarks/inferentia-llama2.mdx @@ -0,0 +1,77 @@ + + +# Llama performance on AWS Inferentia2 (Latency & Througput) + +How fast is Llama on Inferentia2? Let's figure out! + +For this benchmark we will use the LLama 2 7B and 13B models with different configurations: + +| Model type | num cores | batch_size | +|----------------------------|-----------|------------| +| Llama2 7B - L (latency) | 24 | 1 | +| Llama2 7B - T (throughput) | 24 | 4 | +| Llama2 13B - L (latency) | 24 | 1 | +| Llama2 13B - T (throughput)| 24 | 4 | + +*Note: all models are compiled with a maximum sequence length of 2048.* + +All models are compiled to use the full extent of cores available on the `inf2.48xlarge` instance. + +*Note: please refer to the [inferentia2 product page](https://aws.amazon.com/ec2/instance-types/inf2/) for details on the available instances.* + +We created two "latency" oriented configurations for the `llama2 7B` and `llama2 13B` models that can serve only one request at a time, but at full speed and two "throughput" oriented configurations to serve up to four requests in parallel. + +To evaluate the models, we generate tokens up to a total sequence length of 1024, starting from +256 input tokens (i.e. we generate 256, 512 and 768 tokens). + +## Encoding time (time to first token) + +The encoding time or time to first token is the time required to process the input tokens and generate the first output token. +It is a very important metric, as it corresponds to the latency directly perceived by the user when streaming generated tokens. + +We test the encoding time for increasing context sizes, 256 input tokens corresponding roughly to a typical Q/A usage, +while 768 is more typical of a Retrieval Augmented Generation (RAG) use-case. + +Encoding time is expressed in **seconds**. + +![Llama2 inferentia2 encoding-time](https://raw.githubusercontent.com/huggingface/optimum-neuron/main/docs/assets/benchmarks/inferentia-llama2/encoding-times.png "Encoding time") + +We can see that all deployed models exhibit excellent response times, even for long contexts. + +## End-to-end Latency + +The end-to-end latency corresponds to the total time to reach a sequence length of 1024 tokens. + +It therefore includes the encoding and generation time. + +Latency is expressed in **seconds**. + +![Llama2 inferentia2 end-to-end latency](https://raw.githubusercontent.com/huggingface/optimum-neuron/main/docs/assets/benchmarks/inferentia-llama2/latencies.png "Latency") + +All models deployed on the high-end instance exhibit a good latency, even those actually configured to optimize throughput. + +### Throughput + +We adopt the same convention as other benchmarks to evaluate the throughput, by dividing the end-to-end +latency by the sum of both input and output tokens. +In other words, we divide the end-to-end latency by `batch_size * sequence_length` to obtain the number of generated tokens per second. + +Throughput is expressed in **tokens/second**. + +![Llama2 inferentia2 throughput](https://raw.githubusercontent.com/huggingface/optimum-neuron/main/docs/assets/benchmarks/inferentia-llama2/throughputs.png "Throughput") + +Again, the models deployed on the high-end instance have a very good throughput, even those optimized for latency.