Moxin-LLM article #LICENSE Apache License Version 2.0 , January 2004 http://www. apache. org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2024 moxin-org 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. \n[SEP]\n#REQUIREMENTS. md \n <h1 align="center"> Moxin LLM</h1> <p align="center"> <a href="https://arxiv. org /abs/2412.06845 ">Technical Report</a>    |    <a href="https://huggingface. co /moxin-org/moxin-llm-7b">Base Model</a>    |    <a href="https://huggingface. co /moxin-org/moxin-chat-7b">Chat Model</a> </p> ## Introduction Generative AI (GAI) offers unprecedented opportunities for research and innovation, but its commercialization has raised concerns about transparency, reproducibility, and safety. Many open GAI models lack the necessary components for full understanding and reproducibility, and some use restrictive licenses whilst claiming to be “open-source”. To address these concerns, we follow the [Model Openness Framework (MOF)](https://arxiv. org /pdf/2403.13784 ), a ranked classification system that rates machine learning models based on their completeness and openness, following principles of open science, open source, open data, and open access. By promoting transparency and reproducibility, the MOF combats “openwashing” practices and establishes completeness and openness as primary criteria alongside the core tenets of responsible AI. Wide adoption of the MOF will foster a more open AI ecosystem, benefiting research, innovation, and adoption of state-of-the-art models. We follow MOF to release the datasets during training, the training scripts, and the trained models. ## Model You can download our base 7B model from this [link](https://huggingface. co /moxin-org/moxin-llm-7b) and our chat 7B model from this [link](https://huggingface. co /moxin-org/moxin-chat-7b). ## Evaluation We test the performance of our model with [lm-evaluation-harness](https://github. com /EleutherAI/lm-evaluation-harness). The evaluation results on common datasets are shown below. We test on AI2 Reasoning Challenge (25-shot), HellaSwag (10-shot), MMLU (5-shot), and Winogrande (5-shot). | Models | ARC-C | Hellaswag | MMLU | WinoGrade | Ave | |:----------------------:|:-----:|:---------:|:-----:|:---------:|:-----:| | Mistral-7B | 57.59 | 83.25 | 62.42 | 78.77 | 70.51 | | LLaMA 3.1 -8B | 54.61 | 81.95 | 65.16 | 77.35 | 69.77 | | LLaMA 3-8B | 55.46 | 82.09 | 65.29 | 77.82 | 70.17 | | LLaMA 2-7B | 49.74 | 78.94 | 45.89 | 74.27 | 62.21 | | Qwen 2-7B | 57.68 | 80.76 | 70.42 | 77.43 | 71.57 | | gemma-7b | 56.48 | 82.31 | 63.02 | 78.3 | 70.03 | | internlm2.5 -7b | 54.78 | 79.7 | 68.17 | 80.9 | 70.89 | | Baichuan2-7B | 47.87 | 73.89 | 54.13 | 70.8 | 61.67 | | Yi-1.5 -9B | 58.36 | 80.36 | 69.54 | 77.53 | 71.48 | | Moxin-7B-original | 53.75 | 75.46 | 59.43 | 70.32 | 64.74 | | Moxin-7B-finetuned | 59.47 | 83.08 | 60.97 | 78.69 | 70.55 | We also test the zero shot performance on AI2 Reasoning Challenge (0-shot), AI2 Reasoning Easy (0-shot), HellaSwag (0-shot), PIQA (0-shot) and Winogrande (0-shot). The results are shown below. | Models | HellaSwag | WinoGrade | PIQA | ARC-E | ARC-C | Ave | |:-----------------: |:---------: |:---------: |:-----: |:-----: |:-----: |:-----: | | Mistral-7B | 80.39 | 73.4 | 82.15 | 78.28 | 52.22 | 73.29 | | LLaMA 2-7B | 75.99 | 69.06 | 79.11 | 74.54 | 46.42 | 69.02 | | LLaMA 2-13B | 79.37 | 72.22 | 80.52 | 77.4 | 49.06 | 71.71 | | LLaMA 3.1 -8B | 78.92 | 74.19 | 81.12 | 81.06 | 53.67 | 73.79 | | gemma-7b | 80.45 | 73.72 | 80.9 | 79.97 | 54.1 | 73.83 | | Qwen v2-7B | 78.9 | 72.38 | 79.98 | 74.71 | 50.09 | 71.21 | | internlm2.5 -7b | 79.14 | 77.9 | 80.52 | 76.16 | 51.37 | 73.02 | | Baichuan2-7B | 72.25 | 67.17 | 77.26 | 72.98 | 42.15 | 66.36 | | Yi-1.5 -9B | 77.86 | 73.01 | 80.74 | 79.04 | 55.03 | 73.14 | | deepseek-7b | 76.13 | 69.77 | 79.76 | 71.04 | 44.8 | 68.3 | | Moxin-7B-original | 72.06 | 66.31 | 78.07 | 71.47 | 48.15 | 67.21 | | Moxin-7B-finetune | 80.03 | 75.17 | 82.24 | 81.12 | 58.64 | 75.44 | ## Inference You can use the following code to run inference with the model. The model is saved under './model/' directory. Change the model directory accordingly or use the Huggingface link. ``` import torch from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline torch. backends. cuda. enable_mem_efficient_sdp (False) torch. backends. cuda. enable_flash_sdp (False) model_name = 'moxin-org/moxin-7b' tokenizer = AutoTokenizer. from_pretrained (model_name) model = AutoModelForCausalLM. from_pretrained ( model_name, torch_dtype=torch. bfloat16 , device_map="auto", trust_remote_code=True, ) pipe = pipeline( "text-generation", model=model, tokenizer = tokenizer, torch_dtype=torch. bfloat16 , device_map="auto" ) prompt = "Can you explain the concept of regularization in machine learning?" sequences = pipe( prompt, do_sample=True, max_new_tokens=100, temperature=0.7 , top_k=50, top_p=0.95 , num_return_sequences=1, ) print(sequences[0]['generated_text']) ``` ## Environment ### 1. Dataset config To prepare the dataset, it needs to install the following package, ``` pip install datasets ``` ### 2. Cuda install We use cuda 11.7. Other cuda versions may also work. ``` get https://developer. download. nvidia. com /compute/cuda/11.7.0/local_installers/cuda_11.7.0_515.43.04_linux. run sudo sh cuda_11.7.0_515.43.04_linux. run ``` ### 3. Install pytorch We use pytorch 2.0.0. ``` conda create --name llm_train python==3.10 conda activate llm_train pip install torch==2.0.0 torchvision==0.15.1 torchaudio==2.0.1 ``` ### 4. Install other packages To install other packages, follow the requirements. txt ``` pip install -r requirements. txt ``` ### 5. Install flash attention We use flash-attention 2.2.1. ``` git clone https://github. com /Dao-AILab/flash-attention. git cd flash-attention/ git checkout a1576ad ## flash-attention 2.2.1 python setup. py install cd./csrc cd fused_dense_lib && pip install -v. cd../xentropy && pip install -v. cd../rotary && pip install -v. cd../layer_norm && pip install -v. ``` ## Datasets To use the [SlimPajama dataset](https://huggingface. co /datasets/cerebras/SlimPajama-627B) for pretraining, you can download the dataset using Hugging Face datasets: ``` import datasets ds = datasets. load_dataset ("cerebras/SlimPajama-627B") ``` SlimPajama is the largest extensively deduplicated, multi-corpora, open-source dataset for training large language models. SlimPajama was created by cleaning and deduplicating the 1.2T token RedPajama dataset from Together. By filtering out low quality data and duplicates, it removes 49.6 % of bytes, slimming down the RedPajama dataset from 1210B to 627B tokens. SlimPajama offers the highest quality and most compute efficient data to train on for runs up to 627B tokens. When upsampled, SlimPajama is expected to perform equal to or better than RedPajama-1T when training at trillion token scale. To use the [stack-dedup dataset](https://huggingface. co /datasets/bigcode/the-stack-dedup) for pretraining, you can download the dataset using Hugging Face datasets: ``` from datasets import load_dataset # full dataset (3TB of data) ds = load_dataset("bigcode/the-stack-dedup", split="train") # specific language (e. g. Dockerfiles) ds = load_dataset("bigcode/the-stack-dedup", data_dir="data/dockerfile", split="train") # dataset streaming (will only download the data as needed) ds = load_dataset("bigcode/the-stack-dedup", streaming=True, split="train") for sample in iter(ds): print(sample["content"]) ``` The Stack contains over 6TB of permissively-licensed source code files covering 358 programming languages. The dataset was created as part of the BigCode Project, an open scientific collaboration working on the responsible development of Large Language Models for Code (Code LLMs). The Stack serves as a pre-training dataset for Code LLMs, i. e., code-generating AI systems which enable the synthesis of programs from natural language descriptions as well as other from code snippets. This is the near-deduplicated version with 3TB data. You can find more details about the DCLM-baseline dataset on the [homepage](https://huggingface. co /datasets/mlfoundations/dclm-baseline-1.0 ). ## Training We follow the [ColossalAI](https://github. com /hpcaitech/ColossalAI) framework to train the LLM model. Colossal-AI provides a collection of parallel components for the training. It aims to support to write the distributed deep learning models just like how you write your model on your laptop. It provides user-friendly tools to kickstart distributed training and inference in a few lines. We provide a few examples to show how to run benchmark or pretraining based on Colossal-AI. ### 1. Training LLM You can find the shell scripts in 'scripts/train_7B' directory. The main command should be in the format of: ``` colossalai run --nproc_per_node YOUR_GPU_PER_NODE --hostfile YOUR_HOST_FILE \ benchmark. py --OTHER_CONFIGURATIONS ``` #### a. Running on a sinlge node we provide an example to run the training on a single node as below, ``` colossalai run --nproc_per_node 1 pretrain. py \ --config 7b \ --dataset togethercomputer/RedPajama-Data-1T-Sample \ --batch_size 1 \ --num_epochs 5 \ --save_interval 5000 \ --max_length 2048 \ --save_dir output-checkpoints \ --plugin zero2_cpu \ --lr 2e-5 \ --expanded_model hpcai-tech/Colossal-LLaMA-2-7b-base ``` In the example, it uses the sample dataset 'togethercomputer/RedPajama-Data-1T-Sample' for training. It trains the 7B model 'hpcai-tech/Colossal-LLaMA-2-7b-base'. You can refer the main file 'run. sh ' and 'pretrain. py ' for more details. To start the training, run the following, ```bash bash run. sh ``` #### b. Running on a sinlge node we provide an example to run the training on multiple nodes as below, ``` srun colossalai run --num_nodes 8 --nproc_per_node 8 pretrain. py \ --config 7b \ --dataset cerebras/SlimPajama-627B \ --batch_size 1 \ --num_epochs 10 \ --save_interval 50000 \ --max_length 2048 \ --save_dir output-checkpoints \ --flash_attention \ --plugin zero2_cpu \ --lr 1e-5 \ --expanded_model hpcai-tech/Colossal-LLaMA-2-7b-base ``` It uses 8 nodes. Put your host file (`hosts. txt `) in this directory with your real host ip or host name. Here is a sample `hosts. txt `: ```text hostname1 hostname2 hostname3... hostname8 ``` You can refer to the main file 'run-multi-server. sh ' and 'pretrain. py ' for more details. To start the training, run the following, ```bash bash run-multi-server. sh ``` ### 2. Benchmark You can find the shell scripts in 'scripts/benchmark_7B' directory. The benchmark mainly test the throughput of the LLM, without actual model training. The main command should be in the format of: ``` colossalai run --nproc_per_node YOUR_GPU_PER_NODE --hostfile YOUR_HOST_FILE \ benchmark. py --OTHER_CONFIGURATIONS ``` Here we will show an example of how to run training llama pretraining with 'gemini, batch_size=16, sequence_length=4096, gradient_checkpoint=True, flash_attn=True'. #### a. Running environment This experiment was performed on 4 computing nodes with 32 L40S GPUs in total for LLaMA-2 7B. The nodes are connected with RDMA and GPUs within one node are fully connected with NVLink. #### b. Running command ```bash cd scripts/benchmark_7B ``` First, put your host file (`hosts. txt `) in this directory with your real host ip or host name. Here is a sample `hosts. txt `: ```text hostname1 hostname2 hostname3 hostname4 ``` Then add environment variables to script if needed. Finally, run the following command to start training: ```bash bash gemini. sh ``` ## Citation \n[SEP]\n#requirements. txt \n absl-py==2.1.0 aiohttp==3.9.3 aiosignal==1.3.1 annotated-types==0.6.0 async-timeout==4.0.3 attrs==23.2.0 bcrypt==4.1.2 beautifulsoup4==4.12.3 cachetools==5.3.3 certifi==2024.2.2 cffi==1.16.0 cfgv==3.4.0 charset-normalizer==3.3.2 click==8.1.7 cmake==3.29.0.1 colossalai==0.3.6 contexttimer==0.3.3 cryptography==42.0.5 datasets==2.18.0 decorator==5.1.1 Deprecated==1.2.14 dill==0.3.8 distlib==0.3.8 einops==0.7.0 fabric==3.2.2 filelock==3.13.3 flash-attn==2.2.1 frozenlist==1.4.1 fsspec==2024.2.0 google==3.0.0 google-auth==2.29.0 google-auth-oauthlib==1.0.0 grpcio==1.62.1 huggingface-hub==0.22.2 identify==2.5.35 idna==3.6 invoke==2.2.0 Jinja2==3.1.3 jsonschema==4.21.1 jsonschema-specifications==2023.12.1 lit==18.1.2 Markdown==3.6 markdown-it-py==3.0.0 MarkupSafe==2.1.5 mdurl==0.1.2 mpmath==1.3.0 msgpack==1.0.8 multidict==6.0.5 multiprocess==0.70.16 networkx== 3.3 ninja==1.11.1.1 nodeenv==1.8.0 numpy==1.26.4 nvidia-cublas-cu11==11.10.3.66 nvidia-cublas-cu12==12.1.3.1 nvidia-cuda-cupti-cu11==11.7.101 nvidia-cuda-cupti-cu12==12.1.105 nvidia-cuda-nvrtc-cu11==11.7.99 nvidia-cuda-nvrtc-cu12==12.1.105 nvidia-cuda-runtime-cu11==11.7.99 nvidia-cuda-runtime-cu12==12.1.105 nvidia-cudnn-cu11==8.5.0.96 nvidia-cudnn-cu12==8.9.2.26 nvidia-cufft-cu11==10.9.0.58 nvidia-cufft-cu12==11.0.2.54 nvidia-curand-cu11==10.2.10.91 nvidia-curand-cu12==10.3.2.106 nvidia-cusolver-cu11==11.4.0.1 nvidia-cusolver-cu12==11.4.5.107 nvidia-cusparse-cu11==11.7.4.91 nvidia-cusparse-cu12==12.1.0.106 nvidia-nccl-cu11==2.14.3 nvidia-nccl-cu12==2.19.3 nvidia-nvjitlink-cu12==12.4.127 nvidia-nvtx-cu11==11.7.91 nvidia-nvtx-cu12==12.1.105 oauthlib==3.2.2 packaging==24.0 pandas==2.2.1 paramiko==3.4.0 pip==23.3.1 platformdirs==4.2.0 pre-commit==3.7.0 protobuf==5.26.1 psutil==5.9.8 pyarrow==15.0.2 pyarrow-hotfix==0.6 pyasn1==0.6.0 pyasn1_modules==0.4.0 pycparser==2.22 pydantic==2.6.4 pydantic_core==2.16.3 Pygments==2.17.2 PyNaCl==1.5.0 python-dateutil==2.9.0.post0 pytz==2024.1 PyYAML==6.0.1 ray==2.10.0 referencing==0.34.0 regex==2023.12.25 requests==2.31.0 requests-oauthlib==2.0.0 rich==13.7.1 rpds-py==0.18.0 rsa==4.9 safetensors==0.4.2 sentencepiece==0.1.99 setuptools==68.2.2 six==1.16.0 soupsieve==2.5 sympy==1.12 tensorboard==2.14.0 tensorboard-data-server==0.7.2 tokenizers==0.13.3 torch==2.0.0 tqdm==4.66.2 transformers==4.34.0 triton==2.0.0 typing_extensions==4.11.0 tzdata==2024.1 urllib3==2.2.1 virtualenv==20.25.1 Werkzeug==3.0.2 wheel==0.41.2 wrapt==1.16.0 xxhash==3.4.1 yarl==1.9.4 \n[SEP]\n#finetune. py \n import argparse import os import resource from contextlib import nullcontext from functools import partial from typing import Optional, Tuple import torch import torch. distributed as dist import torch. nn as nn from attn import replace_with_flash_attention # xuan ======================================== import sys; sys. path. append("..") # ======================================== # datasets 2.18.0 # fsspec 2024.2.0 from data_utils import load_json, prepare_dataloader, save_json from datasets import load_dataset, load_from_disk # , save_to_disk from torch. optim import Optimizer from torch. optim. lr_scheduler import _LRScheduler from torch. utils. tensorboard import SummaryWriter from tqdm import tqdm from transformers. models. llama. configuration_llama import LlamaConfig from transformers. models. llama. modeling_llama import LlamaForCausalLM from transformers. models. llama. tokenization_llama import LlamaTokenizer import colossalai from colossalai. accelerator import get_accelerator from colossalai. booster import Booster from colossalai. booster. plugin import GeminiPlugin, HybridParallelPlugin, LowLevelZeroPlugin from colossalai. cluster import DistCoordinator from colossalai. lazy import LazyInitContext from colossalai. nn. lr_scheduler import CosineAnnealingWarmupLR from colossalai. nn. optimizer import HybridAdam MODEL_CONFIGS = { "7b": LlamaConfig(max_position_embeddings=4096), "13b": LlamaConfig( hidden_size=5120, intermediate_size=13824, num_hidden_layers=40, num_attention_heads=40, max_position_embeddings=4096, ), "70b": LlamaConfig( hidden_size=8192, intermediate_size=28672, num_hidden_layers=80, num_attention_heads=64, max_position_embeddings=4096, num_key_value_heads=8, ), } def get_model_numel(model: nn. Module ) -> int: return sum(p. numel () for p in model. parameters ()) def format_numel_str(numel: int) -> str: B = 1024 ** 3 M = 1024 ** 2 K = 1024 if numel >= B: return f"{numel / B:.2f} B" elif numel >= M: return f"{numel / M:.2f} M" elif numel >= K: return f"{numel / K:.2f} K" else: return f"{numel}" def tokenize_batch_for_pretrain(batch, tokenizer: Optional[LlamaTokenizer] = None, max_length: int = 2048): texts = [sample["text"] for sample in batch] data = tokenizer(texts, return_tensors="pt", padding="max_length", truncation=True, max_length=max_length) data = {k: v. cuda () for k, v in data. items ()} data["labels"] = data["input_ids"].clone() return data def all_reduce_mean(tensor: torch. Tensor ) -> torch. Tensor : dist. all_reduce (tensor, op=dist. ReduceOp. SUM) tensor = tensor. data tensor. div_ (dist. get_world_size ()) return tensor def save( booster: Booster, model: nn. Module , optimizer: Optimizer, lr_scheduler: _LRScheduler, epoch: int, step: int, batch_size: int, coordinator: DistCoordinator, save_dir: str, ): save_dir = os. path. join(save_dir, f"epoch{epoch}-step{step}") os. makedirs (os. path. join(save_dir, "model"), exist_ok=True) booster. save_model (model, os. path. join(save_dir, "model"), shard=True) booster. save_optimizer (optimizer, os. path. join(save_dir, "optimizer"), shard=True) booster. save_lr_scheduler (lr_scheduler, os. path. join(save_dir, "lr_scheduler")) running_states = { "epoch": epoch, "step": step, "sample_start_index": step * batch_size, } if coordinator. is_master (): save_json(running_states, os. path. join(save_dir, "running_states. json ")) def load( booster: Booster, model: nn. Module , optimizer: Optimizer, lr_scheduler: _LRScheduler, load_dir: str ) -> Tuple[int, int, int]: booster. load_model (model, os. path. join(load_dir, "model")) # booster. load_optimizer (optimizer, os. path. join(load_dir, "optimizer")) # booster. load_lr_scheduler (lr_scheduler, os. path. join(load_dir, "lr_scheduler")) running_states = load_json(os. path. join(load_dir, "running_states. json ")) return running_states["epoch"], running_states["step"], running_states["sample_start_index"] def _criterion(outputs, inputs): return outputs. loss def encode_with_prompt_completion_format(example, tokenizer, max_seq_length): ''' Here we assume each example has 'prompt' and 'completion' fields. We concatenate prompt and completion and tokenize them together because otherwise prompt will be padded/trancated and it doesn't make sense to follow directly with the completion. ''' # if prompt doesn't end with space and completion doesn't start with space, add space if not example['prompt'].endswith((' ', '\n', '\t')) and not example['completion'].startswith((' ', '\n', '\t')): example_text = example['prompt'] + ' ' + example['completion'] else: example_text = example['prompt'] + example['completion'] example_text = example_text + tokenizer. eos_token tokenized_example = tokenizer(example_text, return_tensors='pt', max_length=max_seq_length, truncation=True) input_ids = tokenized_example. input_ids labels = input_ids. clone () tokenized_prompt = tokenizer(example['prompt'], return_tensors='pt', max_length=max_seq_length, truncation=True) # mask the prompt part for avoiding loss labels[:, :tokenized_prompt. input_ids. shape[1]] = -100 attention_mask = torch. ones_like (input_ids) return { 'input_ids': input_ids. flatten (), 'labels': labels. flatten (), 'attention_mask': attention_mask. flatten (), } def encode_with_messages_format(example, tokenizer, max_seq_length): ''' Here we assume each example has a 'messages' field Each message is a dict with 'role' and 'content' fields. We concatenate all messages with the roles as delimiters and tokenize them together. ''' messages = example['messages'] if len(messages) == 0: raise ValueError('messages field is empty.') def _concat_messages(messages): message_text = "" for message in messages: if message["role"] == "system": message_text += "<|system|>\n" + message["content"].strip() + "\n" elif message["role"] == "user": message_text += "<|user|>\n" + message["content"].strip() + "\n" elif message["role"] == "assistant": message_text += "<|assistant|>\n" + message["content"].strip() + tokenizer. eos_token + "\n" else: raise ValueError("Invalid role: {}".format(message["role"])) return message_text example_text = _concat_messages(messages).strip() tokenized_example = tokenizer(example_text, return_tensors='pt', max_length=max_seq_length, truncation=True) input_ids = tokenized_example. input_ids labels = input_ids. clone () # mask the non-assistant part for avoiding loss for message_idx, message in enumerate(messages): if message["role"] != "assistant": if message_idx == 0: message_start_idx = 0 else: message_start_idx = tokenizer( _concat_messages(messages[:message_idx]), return_tensors='pt', max_length=max_seq_length, truncation=True ).input_ids. shape [1] if message_idx < len(messages) - 1 and messages[message_idx + 1]["role"] == "assistant": # here we also ignore the role of the assistant messages_so_far = _concat_messages(messages[:message_idx + 1]) + "<|assistant|>\n" else: messages_so_far = _concat_messages(messages[:message_idx + 1]) message_end_idx = tokenizer( messages_so_far, return_tensors='pt', max_length=max_seq_length, truncation=True ).input_ids. shape [1] labels[:, message_start_idx:message_end_idx] = -100 if message_end_idx >= max_seq_length: break attention_mask = torch. ones_like (input_ids) return { 'input_ids': input_ids. flatten (), 'labels': labels. flatten (), 'attention_mask': attention_mask. flatten (), } def main(): # ============================== # Parse Arguments # ============================== parser = argparse. ArgumentParser () parser. add_argument ("-c", "--config", type=str, default="7b", help="Model configuration") parser. add_argument ( "-p", "--plugin", choices=["gemini", "gemini_auto", "zero2", "zero2_cpu", "hybrid_parallel"], default="gemini", help="Choose which plugin to use", ) parser. add_argument ("-e", "--num_epochs", type=int, default=1, help="Number of epochs") parser. add_argument ("-b", "--batch_size", type=int, default=2, help="Local batch size") parser. add_argument ("--lr", type=float, default=3e-4, help="Learning rate") parser. add_argument ("--data_path", type=str, default="workspace/datasets/tulu_v2.jsonl ", help="dataset path") parser. add_argument ("-w", "--weigth_decay", type=float, default=0.1 , help="Weight decay") parser. add_argument ("-s", "--warmup_steps", type=int, default=2000, help="Warmup steps") parser. add_argument ("-g", "--grad_checkpoint", action="store_true", help="Use gradient checkpointing") parser. add_argument ("-l", "--max_length", type=int, default=4096, help="Max sequence length") parser. add_argument ("-x", "--mixed_precision", default="fp16", choices=["fp16", "bf16"], help="Mixed precision") parser. add_argument ("-i", "--save_interval", type=int, default=1000, help="Save interval") parser. add_argument ("-o", "--save_dir", type=str, default="checkpoint", help="Checkpoint directory") parser. add_argument ("-f", "--load", type=str, default=None, help="Load checkpoint") parser. add_argument ("--grad_clip", type=float, default=1.0 , help="Gradient clipping") parser. add_argument ("-t", "--tensorboard_dir", type=str, default="tb_logs", help="Tensorboard directory") parser. add_argument ("-a", "--flash_attention", action="store_true", help="Use Flash Attention") # xuan ================================================================================ parser. add_argument ("--accumulation_steps", default=16, help="accumulation steps") parser. add_argument ("--expanded_model", default="", help="model path") parser. add_argument ("--tokenizer_path", default="", help="model path") # ================================================================================ args = parser. parse_args () # ============================== # Initialize Distributed Training # ============================== colossalai. launch_from_torch ({}) coordinator = DistCoordinator() # ============================== # Initialize Booster # ============================== if args. plugin == "gemini": plugin = GeminiPlugin(precision=args. mixed_precision , initial_scale=2 ** 16, max_norm=args. grad_clip ) elif args. plugin == "gemini_auto": plugin = GeminiPlugin( precision=args. mixed_precision , placement_policy="auto", initial_scale=2 ** 16, max_norm=args. grad_clip ) elif args. plugin == "zero2": plugin = LowLevelZeroPlugin( stage=2, precision=args. mixed_precision , initial_scale=2 ** 16, max_norm=args. grad_clip ) elif args. plugin == "zero2_cpu": plugin = LowLevelZeroPlugin( stage=2, precision=args. mixed_precision , initial_scale=2 ** 16, cpu_offload=True, max_norm=args. grad_clip ) elif args. plugin == "hybrid_parallel": plugin = HybridParallelPlugin( tp_size=4, pp_size=2, num_microbatches=None, microbatch_size=1, enable_jit_fused=False, zero_stage=0, precision=args. mixed_precision , initial_scale=1, ) else: raise ValueError(f"Unknown plugin {args. plugin }") booster = Booster(plugin=plugin) use_pipeline = isinstance(booster. plugin , HybridParallelPlugin) and booster. plugin. pp_size > 1 is_pp_last_stage = use_pipeline and booster. plugin. stage_manager. is_last_stage () print_flag = (not use_pipeline and coordinator. is_master ()) or (use_pipeline and is_pp_last_stage) # ============================== # Initialize Tensorboard # ============================== if print_flag: os. makedirs (args. tensorboard_dir , exist_ok=True) writer = SummaryWriter(args. tensorboard_dir ) # ============================== # Initialize Tokenizer, Dataset and Dataloader # ============================== from transformers import AutoTokenizer tokenizer = AutoTokenizer. from_pretrained (args. tokenizer_path , use_fast=False) tokenizer. pad_token = tokenizer. unk_token # ================================================================ train_file = args. data_path data_files = {} dataset_args = {} if train_file is not None: data_files["train"] = train_file raw_datasets = load_dataset( "json", data_files=data_files, **dataset_args, ) # Preprocessing the datasets. if "prompt" in raw_datasets["train"].column_names and "completion" in raw_datasets["train"].column_names: encode_function = partial( encode_with_prompt_completion_format, tokenizer=tokenizer, max_seq_length=args. max_length , ) elif "messages" in raw_datasets["train"].column_names: encode_function = partial( encode_with_messages_format, tokenizer=tokenizer, max_seq_length=args. max_length , ) else: raise ValueError("You need to have either 'prompt'&'completion' or 'messages' in your column names.") # with accelerator. main_process_first (): # if coordinator. is_master (): lm_datasets = raw_datasets. map ( encode_function, batched=False, num_proc=16, load_from_cache_file=True, remove_columns=[name for name in raw_datasets["train"].column_names if name not in ["input_ids", "labels", "attention_mask"]], desc="Tokenizing and reformatting instruction data", ) lm_datasets. set_format (type="pt") lm_datasets = lm_datasets. filter (lambda example: (example['labels'] != -100).any()) dist. barrier () train_dataset = lm_datasets["train"] train_ds = train_dataset # ============================== # Initialize Model, Optimizer and LR Scheduler # ============================== config = MODEL_CONFIGS[args. config ] init_ctx = ( LazyInitContext(default_device=get_accelerator().get_current_device()) if isinstance(plugin, GeminiPlugin) else nullcontext() ) with init_ctx: from transformers import AutoModelForCausalLM, AutoConfig model = AutoModelForCausalLM. from_pretrained (args. expanded_model , torch_dtype=torch. float16 )#, device_map='cpu') for name, weight in model. named_parameters (): weight. requires_grad = True from transformers import DataCollatorForSeq2Seq dataloader = prepare_dataloader( lm_datasets["train"], batch_size=args. batch_size , shuffle=True, drop_last=True, collate_fn=DataCollatorForSeq2Seq(tokenizer=tokenizer, model=model, padding="longest"), ) # ======================================================================= if args. grad_checkpoint : model. gradient_checkpointing_enable () model_numel = get_model_numel(model) coordinator. print_on_master (f"Model params: {format_numel_str(model_numel)}") optimizer = HybridAdam(model. parameters (), lr=args. lr , betas=(0.9 , 0.95 ), weight_decay=args. weigth_decay ) lr_scheduler = CosineAnnealingWarmupLR( optimizer, total_steps=args. num_epochs * len(dataloader), warmup_steps=args. warmup_steps , eta_min=0.1 * args. lr ) default_dtype = torch. float16 if args. mixed_precision == "fp16" else torch. bfloat16 torch. set_default_dtype (default_dtype) model, optimizer, _, dataloader, lr_scheduler = booster. boost ( model, optimizer, dataloader=dataloader, lr_scheduler=lr_scheduler ) torch. set_default_dtype (torch. float ) coordinator. print_on_master (f"Booster init max CUDA memory: {torch. cuda. max_memory_allocated() / 1024 ** 2:.2f} MB") coordinator. print_on_master ( f"Booster init max CPU memory: {resource. getrusage (resource. RUSAGE_SELF ).ru_maxrss / 1024:.2f} MB" ) # load checkpoint if specified start_epoch = 0 start_step = 0 sampler_start_idx = 0 if args. load is not None: coordinator. print_on_master ("Loading checkpoint") start_epoch, start_step, sampler_start_idx = load(booster, model, optimizer, lr_scheduler, args. load ) coordinator. print_on_master (f"Loaded checkpoint {args. load } at epoch {start_epoch} step {start_step}") num_steps_per_epoch = len(dataloader) # if resume training, set the sampler start index to the correct value dataloader. sampler. set_start_index(sampler_start_idx) for epoch in range(start_epoch, args. num_epochs ): dataloader. sampler. set_epoch(epoch) dataloader_iter = iter(dataloader) for step in range(start_step, num_steps_per_epoch): if use_pipeline: outputs = booster. execute_pipeline (dataloader_iter, model, _criterion, optimizer, return_loss=True) loss = outputs["loss"] else: batch = next(dataloader_iter) batch = batch. to (get_accelerator().get_current_device()) outputs = model(**batch) loss = outputs[0] booster. backward (loss, optimizer) if (step + 1) % args. accumulation_steps == 0: optimizer. step () # Update parameters lr_scheduler. step () optimizer. zero_grad () # Reset gradients if step + 1 == num_steps_per_epoch - 1: optimizer. step () lr_scheduler. step () optimizer. zero_grad () if not use_pipeline: all_reduce_mean(loss) if print_flag: writer. add_scalar ("loss", loss. item (), epoch * num_steps_per_epoch + step) print("Epoch: {}, step: {}, loss: {:.3f}".format( epoch, epoch * num_steps_per_epoch + step, loss. item () )) if args. save_interval > 0 and (step + 1) % args. save_interval == 0: coordinator. print_on_master (f"Saving checkpoint") save( booster, model, optimizer, lr_scheduler, epoch, step + 1, args. batch_size , coordinator, args. save_dir , ) coordinator. print_on_master (f"Saved checkpoint at epoch {epoch} step {step + 1}") # the continue epochs are not resumed, so we need to reset the sampler start index and start step dataloader. sampler. set_start_index(0) start_step = 0 coordinator. print_on_master (f"Max CUDA memory usage: {torch. cuda. max_memory_allocated() / 1024 ** 2:.2f} MB") if __name__ == "__main__": main() \n[SEP]\n#inference. py \n import torch from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline model_name = './model' tokenizer = AutoTokenizer. from_pretrained (model_name) model = AutoModelForCausalLM. from_pretrained ( model_name, torch_dtype=torch. bfloat16 , device_map="auto", trust_remote_code=True, ) pipe = pipeline( "text-generation", model=model, tokenizer = tokenizer, torch_dtype=torch. bfloat16 , device_map="auto" ) prompt = "Can you explain the concept of regularization in machine learning?" sequences = pipe( prompt, do_sample=True, max_new_tokens=100, temperature=0.7 , top_k=50, top_p=0.95 , num_return_sequences=1, ) print(sequences[0]['generated_text']) \n[SEP]\n#attn. py \n import math from types import MethodType from typing import Optional, Tuple import torch import torch. nn as nn import torch. nn. functional as F from einops import rearrange from transformers. models. llama. configuration_llama import LlamaConfig from transformers. models. llama. modeling_llama import ( LlamaAttention, LlamaForCausalLM, LlamaModel, LlamaRMSNorm, apply_rotary_pos_emb, repeat_kv, ) from colossalai. accelerator import get_accelerator from colossalai. logging import get_dist_logger logger = get_dist_logger() if get_accelerator().name == "cuda": from flash_attn. bert_padding import pad_input, unpad_input from flash_attn. flash_attn_interface import flash_attn_func, flash_attn_varlen_kvpacked_func from flash_attn. ops. rms_norm import rms_norm def _prepare_decoder_attention_mask( self: LlamaModel, attention_mask: torch. BoolTensor , input_shape: torch. Size , inputs_embeds: torch. Tensor , past_key_values_length: int, ) -> Optional[torch. Tensor ]: """ Decoder attetion mask """ if past_key_values_length > 0 and attention_mask is not None: attention_mask = torch. cat ( tensors=( torch. full ( size=(input_shape[0], past_key_values_length), fill_value=True, dtype=attention_mask. dtype , device=attention_mask. device , ), attention_mask, ), dim=-1, ) # (bsz, past_key_values_length + q_len) if attention_mask is not None and torch. all (attention_mask): return None # Faster return attention_mask def attention_forward( self: LlamaAttention, hidden_states: torch. Tensor , attention_mask: Optional[torch. Tensor ] = None, position_ids: Optional[torch. LongTensor ] = None, past_key_value: Optional[Tuple[torch. Tensor ]] = None, output_attentions: bool = False, use_cache: bool = False, **kwargs, ) -> Tuple[torch. Tensor , Optional[torch. Tensor ], Optional[Tuple[torch. Tensor ]]]: """ Re-define LLaMA-2 `LlamaAttention` forward method using flash-attention. """ if output_attentions: logger. warning ( "Argument `output_attentions` is not supported for flash-attention patched `LlamaAttention`, " "return `None` instead." ) bsz, q_len, _ = hidden_states. size () if self. config. pretraining_tp > 1: q_slicing, kv_slicing = ( dim // self. config. pretraining_tp for dim in ( self. num_heads * self. head_dim , self. num_key_value_heads * self. head_dim , ) ) # `Tuple[int, int]` q_slices, k_slices, v_slices = ( proj. weight. split(slicing, dim=0) for proj, slicing in ( (self. q_proj , q_slicing), (self. k_proj , kv_slicing), (self. v_proj , kv_slicing), ) ) # Tuple[Tuple[torch. Tensor ], Tuple[torch. Tensor ], Tuple[torch. Tensor ]] q, k, v = ( torch. cat ( [F. linear (hidden_states, slices[i]) for i in range(self. config. pretraining_tp)], dim=-1, ) for slices in (q_slices, k_slices, v_slices) ) # `Tuple[torch. Tensor , torch. Tensor , torch. Tensor ]` of shape: # (bsz, q_len, num_heads * head_dim), # (bsz, q_len, num_key_value_heads * head_dim), # (bsz, q_len, num_key_value_heads * head_dim) else: q, k, v = (proj(hidden_states) for proj in (self. q_proj , self. k_proj , self. v_proj )) # `Tuple[torch. Tensor , torch. Tensor , torch. Tensor ]` of shape: # (bsz, q_len, num_heads * head_dim), # (bsz, q_len, num_key_value_heads * head_dim), # (bsz, q_len, num_key_value_heads * head_dim) # (bsz, q_len, num_heads * head_dim) -> (bsz, num_heads, q_len, head_dim); # (bsz, q_len, num_key_value_heads * head_dim) -> (bsz, num_key_value_heads, q_len, head_dim); # (bsz, q_len, num_key_value_heads * head_dim) -> (bsz, num_key_value_heads, q_len, head_dim) q, k, v = ( states. view (bsz, q_len, num_heads, self. head_dim ).transpose(1, 2) for states, num_heads in ( (q, self. num_heads ), (k, self. num_key_value_heads ), (v, self. num_key_value_heads ), ) ) kv_len = k. shape [-2] # initially, `kv_len` == `q_len` past_kv_len = 0 if past_key_value is not None: # if `past_key_value` is not None, `kv_len` > `q_len`. past_kv_len = past_key_value[0].shape[-2] kv_len += past_kv_len # two `torch. Tensor ` objs of shape (1, 1, kv_len, head_dim) cos, sin = self. rotary_emb (v, seq_len=kv_len) # (bsz, num_heads, q_len, head_dim), (bsz, num_key_value_heads, q_len, head_dim) q, k = apply_rotary_pos_emb(q=q, k=k, cos=cos, sin=sin, position_ids=position_ids) if past_key_value is not None: # reuse k, v, self_attention k = torch. cat ([past_key_value[0], k], dim=2) v = torch. cat ([past_key_value[1], v], dim=2) past_key_value = (k, v) if use_cache else None # repeat k/v heads if n_kv_heads < n_heads k = repeat_kv(hidden_states=k, n_rep=self. num_key_value_groups ) # (bsz, num_key_value_heads, q_len, head_dim) -> (bsz, num_heads, q_len, head_dim) v = repeat_kv(hidden_states=v, n_rep=self. num_key_value_groups ) # (bsz, num_key_value_heads, q_len, head_dim) -> (bsz, num_heads, q_len, head_dim) key_padding_mask = attention_mask # (bsz, num_heads, q_len, head_dim) -> (bsz, q_len, num_heads, head_dim) q, k, v = (states. transpose (1, 2) for states in (q, k, v)) if past_kv_len > 0: q = torch. cat ( tensors=( torch. full ( size=(bsz, past_kv_len, self. num_heads , self. head_dim ), fill_value=0.0 , dtype=q. dtype , device=q. device , ), q, ), dim=1, ) # (bsz, past_kv_len + q_len, num_heads, head_dim) if key_padding_mask is None: # (bsz, past_kv_len + q_len, num_heads, head_dim) output = flash_attn_func(q=q, k=k, v=v, dropout_p=0.0 , softmax_scale=None, causal=True) # (bsz, ) output = rearrange( output, pattern="... h d ->... (h d)" ) # (bsz, past_kv_len + q_len, num_heads * head_dim) else: q, indices, cu_q_lens, max_q_len = unpad_input(hidden_states=q, attention_mask=key_padding_mask) kv, _, cu_kv_lens, max_kv_len = unpad_input( hidden_states=torch. stack (tensors=(k, v), dim=2), attention_mask=key_padding_mask, ) output_unpad = flash_attn_varlen_kvpacked_func( q=q, kv=kv, cu_seqlens_q=cu_q_lens, cu_seqlens_k=cu_kv_lens, max_seqlen_q=max_q_len, max_seqlen_k=max_kv_len, dropout_p=0.0 , softmax_scale=None, causal=True, ) output = pad_input( hidden_states=rearrange(output_unpad, pattern="nnz h d -> nnz (h d)"), indices=indices, batch=bsz, seqlen=past_kv_len + q_len, ) # (bsz, past_kv_len + q_len, num_heads * head_dim) if past_kv_len > 0: # Strip off the zero query outputs. output = output[:, past_kv_len:,...] # (bsz, q_len, num_heads * head_dim) output = self. o_proj (output) # (bsz, q_len, hidden_size) return output, None, past_key_value def rms_norm_forward(self: LlamaRMSNorm, hidden_states: torch. Tensor ) -> torch. Tensor : """ Formard function for RMS Norm """ return rms_norm(x=hidden_states, weight=self. weight , epsilon=self. variance_epsilon ) def replace_with_flash_attention(model: LlamaForCausalLM) -> None: for name, module in model. named_modules (): if isinstance(module, LlamaAttention): module. forward = MethodType(attention_forward, module) if isinstance(module, LlamaModel): module._prepare_decoder_attention_mask = MethodType(_prepare_decoder_attention_mask, module) if isinstance(module, LlamaRMSNorm): module. forward = MethodType(rms_norm_forward, module) elif get_accelerator().name == "npu": import torch_npu class NPULlamaAttention(LlamaAttention): use_flash: bool = True def __init__(self, config: LlamaConfig): super().__init__(config) self. setup () def setup(self): self._softmax_scale = 1 / math. sqrt (self. head_dim ) def forward( self, hidden_states: torch. Tensor , attention_mask: Optional[torch. Tensor ] = None, position_ids: Optional[torch. LongTensor ] = None, past_key_value: Optional[Tuple[torch. Tensor ]] = None, output_attentions: bool = False, use_cache: bool = False, ) -> Tuple[torch. Tensor , Optional[torch. Tensor ], Optional[Tuple[torch. Tensor ]]]: bsz, q_len, _ = hidden_states. size () if self. config. pretraining_tp > 1: key_value_slicing = (self. num_key_value_heads * self. head_dim ) // self. config. pretraining_tp query_slices = self. q_proj. weight. split ( (self. num_heads * self. head_dim ) // self. config. pretraining_tp, dim=0 ) key_slices = self. k_proj. weight. split (key_value_slicing, dim=0) value_slices = self. v_proj. weight. split (key_value_slicing, dim=0) query_states = [F. linear (hidden_states, query_slices[i]) for i in range(self. config. pretraining_tp)] query_states = torch. cat (query_states, dim=-1) key_states = [F. linear (hidden_states, key_slices[i]) for i in range(self. config. pretraining_tp)] key_states = torch. cat (key_states, dim=-1) value_states = [F. linear (hidden_states, value_slices[i]) for i in range(self. config. pretraining_tp)] value_states = torch. cat (value_states, dim=-1) else: query_states = self. q_proj (hidden_states) key_states = self. k_proj (hidden_states) value_states = self. v_proj (hidden_states) query_states = query_states. view (bsz, q_len, self. num_heads , self. head_dim ).transpose(1, 2) key_states = key_states. view (bsz, q_len, self. num_key_value_heads , self. head_dim ).transpose(1, 2) value_states = value_states. view (bsz, q_len, self. num_key_value_heads , self. head_dim ).transpose(1, 2) kv_seq_len = key_states. shape [-2] if past_key_value is not None: kv_seq_len += past_key_value[0].shape[-2] 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) if past_key_value is not None: # reuse k, v, self_attention key_states = torch. cat ([past_key_value[0], key_states], dim=2) value_states = torch. cat ([past_key_value[1], value_states], dim=2) past_key_value = (key_states, value_states) if use_cache else None key_states = repeat_kv(key_states, self. num_key_value_groups ) value_states = repeat_kv(value_states, self. num_key_value_groups ) if not self. use_flash : attn_weights = torch. matmul (query_states, key_states. transpose (2, 3)) / math. sqrt (self. head_dim ) if attn_weights. size () != (bsz, self. num_heads , q_len, kv_seq_len): raise ValueError( f"Attention weights should be of size {(bsz, self. num_heads , q_len, kv_seq_len)}, but is" f" {attn_weights. size ()}" ) if attention_mask is not None: if attention_mask. size () != (bsz, 1, q_len, kv_seq_len): raise ValueError( f"Attention mask should be of size {(bsz, 1, q_len, kv_seq_len)}, but is {attention_mask. size ()}" ) attn_weights = attn_weights + attention_mask # upcast attention to fp32 attn_weights = nn. functional. softmax(attn_weights, dim=-1, dtype=torch. float32 ).to(query_states. dtype ) attn_output = torch. matmul (attn_weights, value_states) else: attn_output, *_ = torch_npu. npu_fusion_attention ( query_states, key_states, value_states, self. num_heads , "BNSD", atten_mask=attention_mask. bool (), scale=self._softmax_scale , padding_mask=None, pre_tockens=65535, next_tockens=0, keep_prob=1.0 , inner_precise=0, ) if attn_output. size () != (bsz, self. num_heads , q_len, self. head_dim ): raise ValueError( f"`attn_output` should be of size {(bsz, self. num_heads , q_len, self. head_dim )}, but is" f" {attn_output. size ()}" ) attn_output = attn_output. transpose (1, 2).contiguous() attn_output = attn_output. reshape (bsz, q_len, self. hidden_size ) if self. config. pretraining_tp > 1: attn_output = attn_output. split (self. hidden_size // self. config. pretraining_tp, dim=2) o_proj_slices = self. o_proj. weight. split (self. hidden_size // self. config. pretraining_tp, dim=1) attn_output = sum( [F. linear (attn_output[i], o_proj_slices[i]) for i in range(self. config. pretraining_tp)] ) else: attn_output = self. o_proj (attn_output) if not output_attentions: attn_weights = None return attn_output, attn_weights, past_key_value class NPURMSNorm(LlamaRMSNorm): def forward(self, hidden_states): return torch_npu. npu_rms_norm (hidden_states, self. weight , epsilon=self. variance_epsilon )[0] def replace_with_flash_attention(model: LlamaForCausalLM) -> None: for name, module in model. named_modules (): if isinstance(module, LlamaAttention): module.__class__ = NPULlamaAttention module. setup () if isinstance(module, LlamaRMSNorm): module.__class__ = NPURMSNorm \n[SEP]\n#pretrain. py \n import argparse import os import resource from contextlib import nullcontext from functools import partial from typing import Optional, Tuple import torch import torch. distributed as dist import torch. nn as nn from attn import replace_with_flash_attention import sys sys. path. append("..") # datasets 2.18.0 # fsspec 2024.2.0 from data_utils import load_json, prepare_dataloader, save_json from datasets import load_dataset, load_from_disk from torch. optim import Optimizer from torch. optim. lr_scheduler import _LRScheduler from torch. utils. tensorboard import SummaryWriter from tqdm import tqdm from transformers. models. llama. configuration_llama import LlamaConfig from transformers. models. llama. modeling_llama import LlamaForCausalLM from transformers. models. llama. tokenization_llama import LlamaTokenizer import colossalai from colossalai. accelerator import get_accelerator from colossalai. booster import Booster from colossalai. booster. plugin import GeminiPlugin, HybridParallelPlugin, LowLevelZeroPlugin from colossalai. cluster import DistCoordinator from colossalai. lazy import LazyInitContext from colossalai. nn. lr_scheduler import CosineAnnealingWarmupLR from colossalai. nn. optimizer import HybridAdam MODEL_CONFIGS = { "7b": LlamaConfig(max_position_embeddings=4096), "13b": LlamaConfig( hidden_size=5120, intermediate_size=13824, num_hidden_layers=40, num_attention_heads=40, max_position_embeddings=4096, ), "70b": LlamaConfig( hidden_size=8192, intermediate_size=28672, num_hidden_layers=80, num_attention_heads=64, max_position_embeddings=4096, num_key_value_heads=8, ), } def get_model_numel(model: nn. Module ) -> int: return sum(p. numel () for p in model. parameters ()) def format_numel_str(numel: int) -> str: B = 1024**3 M = 1024**2 K = 1024 if numel >= B: return f"{numel / B:.2f} B" elif numel >= M: return f"{numel / M:.2f} M" elif numel >= K: return f"{numel / K:.2f} K" else: return f"{numel}" def tokenize_batch_for_pretrain(batch, tokenizer: Optional[LlamaTokenizer] = None, max_length: int = 2048): texts = [sample["text"] for sample in batch] data = tokenizer(texts, return_tensors="pt", padding="max_length", truncation=True, max_length=max_length) data = {k: v. cuda () for k, v in data. items ()} data["labels"] = data["input_ids"].clone() return data def all_reduce_mean(tensor: torch. Tensor ) -> torch. Tensor : dist. all_reduce (tensor, op=dist. ReduceOp. SUM) tensor = tensor. data tensor. div_ (dist. get_world_size ()) return tensor def save( booster: Booster, model: nn. Module , optimizer: Optimizer, lr_scheduler: _LRScheduler, epoch: int, step: int, batch_size: int, coordinator: DistCoordinator, save_dir: str, ): save_dir = os. path. join(save_dir, f"epoch{epoch}-step{step}") os. makedirs (os. path. join(save_dir, "model"), exist_ok=True) booster. save_model (model, os. path. join(save_dir, "model"), shard=True) booster. save_optimizer (optimizer, os. path. join(save_dir, "optimizer"), shard=True) booster. save_lr_scheduler (lr_scheduler, os. path. join(save_dir, "lr_scheduler")) running_states = { "epoch": epoch, "step": step, "sample_start_index": step * batch_size, } if coordinator. is_master (): save_json(running_states, os. path. join(save_dir, "running_states. json ")) def load( booster: Booster, model: nn. Module , optimizer: Optimizer, lr_scheduler: _LRScheduler, load_dir: str ) -> Tuple[int, int, int]: booster. load_model (model, os. path. join(load_dir, "model")) running_states = load_json(os. path. join(load_dir, "running_states. json ")) return running_states["epoch"], running_states["step"], running_states["sample_start_index"] def _criterion(outputs, inputs): return outputs. loss def main(): # ============================== # Parse Arguments # ============================== parser = argparse. ArgumentParser () parser. add_argument ("-c", "--config", type=str, default="7b", help="Model configuration") parser. add_argument ( "-p", "--plugin", choices=["gemini", "gemini_auto", "zero2", "zero2_cpu", "hybrid_parallel"], default="gemini", help="Choose which plugin to use", ) parser. add_argument ( "-d", "--dataset", type=str, default="togethercomputer/RedPajama-Data-1T-Sample", help="Data set path" ) parser. add_argument ("--cache_path", type=str, default="workspace/.cache/huggingface/datasets", help="cache path") parser. add_argument ("-e", "--num_epochs", type=int, default=1, help="Number of epochs") parser. add_argument ("-b", "--batch_size", type=int, default=2, help="Local batch size") parser. add_argument ("--lr", type=float, default=3e-4, help="Learning rate") parser. add_argument ("-w", "--weigth_decay", type=float, default=0.1 , help="Weight decay") parser. add_argument ("-s", "--warmup_steps", type=int, default=2000, help="Warmup steps") parser. add_argument ("-g", "--grad_checkpoint", action="store_true", help="Use gradient checkpointing") parser. add_argument ("-l", "--max_length", type=int, default=4096, help="Max sequence length") parser. add_argument ("-x", "--mixed_precision", default="fp16", choices=["fp16", "bf16"], help="Mixed precision") parser. add_argument ("-i", "--save_interval", type=int, default=1000, help="Save interval") parser. add_argument ("-o", "--save_dir", type=str, default="checkpoint", help="Checkpoint directory") parser. add_argument ("-f", "--load", type=str, default=None, help="Load checkpoint") parser. add_argument ("--grad_clip", type=float, default=1.0 , help="Gradient clipping") parser. add_argument ("-t", "--tensorboard_dir", type=str, default="tb_logs", help="Tensorboard directory") parser. add_argument ("-a", "--flash_attention", action="store_true", help="Use Flash Attention") parser. add_argument ("--accumulation_steps", default=8, help="accumulation steps") parser. add_argument ("--expanded_model", default="", help="model path") args = parser. parse_args () # ============================== # Initialize Distributed Training # ============================== colossalai. launch_from_torch ({}) coordinator = DistCoordinator() # ============================== # Initialize Booster # ============================== if args. plugin == "gemini": plugin = GeminiPlugin(precision=args. mixed_precision , initial_scale=2**16, max_norm=args. grad_clip ) elif args. plugin == "gemini_auto": plugin = GeminiPlugin( precision=args. mixed_precision , placement_policy="auto", initial_scale=2**16, max_norm=args. grad_clip ) elif args. plugin == "zero2": plugin = LowLevelZeroPlugin( stage=2, precision=args. mixed_precision , initial_scale=2**16, max_norm=args. grad_clip ) elif args. plugin == "zero2_cpu": plugin = LowLevelZeroPlugin( stage=2, precision=args. mixed_precision , initial_scale=2**16, cpu_offload=True, max_norm=args. grad_clip ) elif args. plugin == "hybrid_parallel": plugin = HybridParallelPlugin( tp_size=4, pp_size=2, num_microbatches=None, microbatch_size=1, enable_jit_fused=False, zero_stage=0, precision=args. mixed_precision , initial_scale=1, ) else: raise ValueError(f"Unknown plugin {args. plugin }") booster = Booster(plugin=plugin) use_pipeline = isinstance(booster. plugin , HybridParallelPlugin) and booster. plugin. pp_size > 1 is_pp_last_stage = use_pipeline and booster. plugin. stage_manager. is_last_stage () print_flag = (not use_pipeline and coordinator. is_master ()) or (use_pipeline and is_pp_last_stage) # ============================== # Initialize Tensorboard # ============================== if print_flag: os. makedirs (args. tensorboard_dir , exist_ok=True) writer = SummaryWriter(args. tensorboard_dir ) # ============================== # Initialize Tokenizer, Dataset and Dataloader # ============================== from transformers import AutoTokenizer tokenizer = AutoTokenizer. from_pretrained (args. expanded_model , use_fast=False) tokenizer. pad_token = tokenizer. unk_token tokenizer. padding_side = 'left' # ================================================================ dataset = load_dataset(args. dataset , cache_dir=args. cache_path ) train_ds = dataset["train"] dataloader = prepare_dataloader( train_ds, batch_size=args. batch_size , shuffle=True, drop_last=True, collate_fn=partial(tokenize_batch_for_pretrain, tokenizer=tokenizer, max_length=args. max_length ), ) # ============================== # Initialize Model, Optimizer and LR Scheduler # ============================== config = MODEL_CONFIGS[args. config ] init_ctx = ( LazyInitContext(default_device=get_accelerator().get_current_device()) if isinstance(plugin, GeminiPlugin) else nullcontext() ) with init_ctx: model = LlamaForCausalLM. from_pretrained (args. expanded_model , torch_dtype=torch. float16 ) if args. grad_checkpoint : model. gradient_checkpointing_enable () if args. flash_attention : replace_with_flash_attention(model) model_numel = get_model_numel(model) coordinator. print_on_master (f"Model params: {format_numel_str(model_numel)}") optimizer = HybridAdam(model. parameters (), lr=args. lr , betas=(0.9 , 0.95 ), weight_decay=args. weigth_decay ) lr_scheduler = CosineAnnealingWarmupLR( optimizer, total_steps=args. num_epochs * len(dataloader), warmup_steps=args. warmup_steps , eta_min=0.1 * args. lr ) default_dtype = torch. float16 if args. mixed_precision == "fp16" else torch. bfloat16 torch. set_default_dtype (default_dtype) model, optimizer, _, dataloader, lr_scheduler = booster. boost ( model, optimizer, dataloader=dataloader, lr_scheduler=lr_scheduler ) torch. set_default_dtype (torch. float ) coordinator. print_on_master (f"Booster init max CUDA memory: {torch. cuda. max_memory_allocated()/1024**2:.2f} MB") coordinator. print_on_master ( f"Booster init max CPU memory: {resource. getrusage (resource. RUSAGE_SELF ).ru_maxrss/1024:.2f} MB" ) # load checkpoint if specified start_epoch = 0 start_step = 0 sampler_start_idx = 0 if args. load is not None: coordinator. print_on_master ("Loading checkpoint") start_epoch, start_step, sampler_start_idx = load(booster, model, optimizer, lr_scheduler, args. load ) coordinator. print_on_master (f"Loaded checkpoint {args. load } at epoch {start_epoch} step {start_step}") num_steps_per_epoch = len(dataloader) dataloader. sampler. set_start_index(sampler_start_idx) for epoch in range(start_epoch, args. num_epochs ): dataloader. sampler. set_epoch(epoch) dataloader_iter = iter(dataloader) for step in range(start_step, num_steps_per_epoch): if use_pipeline: outputs = booster. execute_pipeline (dataloader_iter, model, _criterion, optimizer, return_loss=True) loss = outputs["loss"] else: batch = next(dataloader_iter) outputs = model(**batch) loss = outputs[0] booster. backward (loss, optimizer) if (step + 1) % args. accumulation_steps == 0: optimizer. step () # Update parameters lr_scheduler. step () optimizer. zero_grad () # Reset gradients if step + 1 == num_steps_per_epoch - 1: optimizer. step () lr_scheduler. step () optimizer. zero_grad () if not use_pipeline: all_reduce_mean(loss) if print_flag: writer. add_scalar ("loss", loss. item (), epoch * num_steps_per_epoch + step) print("Epoch: {}, step: {}, loss: {:.3f}".format( epoch, epoch * num_steps_per_epoch + step, loss. item () )) if args. save_interval > 0 and (step + 1) % args. save_interval == 0: coordinator. print_on_master (f"Saving checkpoint") save( booster, model, optimizer, lr_scheduler, epoch, step + 1, args. batch_size , coordinator, args. save_dir , ) coordinator. print_on_master (f"Saved checkpoint at epoch {epoch} step {step + 1}") dataloader. sampler. set_start_index(0) start_step = 0 coordinator. print_on_master (f"Max CUDA memory usage: {torch. cuda. max_memory_allocated()/1024**2:.2f} MB") if __name__ == "__main__": main() \n[SEP] #scripts/benchmark/README. md \n # Pretraining LLaMA-1/2/3: best practices for building LLaMA-1/2/3-like base models ### LLaMA3 <p align="center"> <img src="https://raw. githubusercontent. com/hpcaitech/public_assets/main/examples/images/LLaMA3-70B-H100.png " width=600/> </p> - 70 billion parameter LLaMA3 model training accelerated by 18% ### LLaMA2 <p align="center"> <img src="https://raw. githubusercontent. com/hpcaitech/public_assets/main/colossalai/img/llama2_pretraining. png " width=600/> </p> - 70 billion parameter LLaMA2 model training accelerated by 195% [[blog]](https://www. hpc -ai. tech /blog/70b-llama2-training) ### LLaMA1 <p align="center"> <img src="https://raw. githubusercontent. com/hpcaitech/public_assets/main/examples/images/LLaMA_pretraining. png " width=600/> </p> - 65-billion-parameter large model pretraining accelerated by 38% [[blog]](https://www. hpc -ai. tech /blog/large-model-pretraining) ## Usage > ⚠ This example only has benchmarking script. For training/finetuning, please refer to the [applications/Colossal-LLaMA](https://github. com /hpcaitech/ColossalAI/tree/main/applications/Colossal-LLaMA). ### 1. Installation Please install the latest ColossalAI from source. ```bash BUILD_EXT=1 pip install -U git+https://github. com /hpcaitech/ColossalAI ``` Then install other dependencies. ```bash pip install -r requirements. txt ``` ### 4. Shell Script Examples For your convenience, we provide some shell scripts to run benchmark with various configurations. You can find them in `scripts/benchmark_7B` and `scripts/benchmark_70B` directory. The main command should be in the format of: ```bash colossalai run --nproc_per_node YOUR_GPU_PER_NODE --hostfile YOUR_HOST_FILE \ benchmark. py --OTHER_CONFIGURATIONS ``` Here we will show an example of how to run training llama pretraining with `gemini, batch_size=16, sequence_length=4096, gradient_checkpoint=True, flash_attn=True`. #### a. Running environment This experiment was performed on 4 computing nodes with 32 A800/H800 80GB GPUs in total for LLaMA-1 65B or LLaMA-2 70B. The nodes are connected with RDMA and GPUs within one node are fully connected with NVLink. #### b. Running command ```bash cd scripts/benchmark_7B ``` First, put your host file (`hosts. txt `) in this directory with your real host ip or host name. Here is a sample `hosts. txt `: ```text hostname1 hostname2 hostname3 hostname4 ``` Then add environment variables to script if needed. Finally, run the following command to start training: ```bash bash gemini. sh ``` If you encounter out-of-memory(OOM) error during training with script `gemini. sh `, changing to script `gemini_auto. sh ` might be a solution, since gemini_auto will set a upper limit on GPU memory usage through offloading part of the model parameters and optimizer states back to CPU memory. But there's a trade-off: `gemini_auto. sh ` will be a bit slower, since more data are transmitted between CPU and GPU. #### c. Results If you run the above command successfully, you will get the following results: `max memory usage: 55491.10 MB, throughput: 24.26 samples/s, TFLOPS/GPU: 167.43 `. ## Reference ``` @article{bian2021colossal, title={Colossal-AI: A Unified Deep Learning System For Large-Scale Parallel Training}, author={Bian, Zhengda and Liu, Hongxin and Wang, Boxiang and Huang, Haichen and Li, Yongbin and Wang, Chuanrui and Cui, Fan and You, Yang}, journal={arXiv preprint arXiv:2110.14883 }, year={2021} } ``` ```bibtex @software{openlm2023openllama, author = {Geng, Xinyang and Liu, Hao}, title = {OpenLLaMA: An Open Reproduction of LLaMA}, month = May, year = 2023, url = {https://github. com /openlm-research/open_llama} } ``` ```bibtex @software{together2023redpajama, author = {Together Computer}, title = {RedPajama-Data: An Open Source Recipe to Reproduce LLaMA training dataset}, month = April, year = 2023, url = {https://github. com /togethercomputer/RedPajama-Data} } ``` ```bibtex @article{touvron2023llama, title={Llama: Open and efficient foundation language models}, author={Touvron, Hugo and Lavril, Thibaut and Izacard, Gautier and Martinet, Xavier and Lachaux, Marie-Anne and Lacroix, Timoth{\'e}e and Rozi{\`e}re, Baptiste and Goyal, Naman and Hambro, Eric and Azhar, Faisal and others}, journal={arXiv preprint arXiv:2302.13971 }, year={2023} } ``` \n[SEP] #scripts/benchmark/benchmark. py \n import argparse import resource import time from contextlib import nullcontext import torch from data_utils import RandomDataset from model_utils import format_numel_str, get_model_numel from performance_evaluator import PerformanceEvaluator, get_profile_context from torch. distributed. fsdp. fully_sharded_data_parallel import CPUOffload, MixedPrecision from tqdm import tqdm from transformers import AutoConfig, AutoModelForCausalLM from transformers. models. llama. configuration_llama import LlamaConfig import colossalai from colossalai. accelerator import get_accelerator from colossalai. booster import Booster from colossalai. booster. plugin import GeminiPlugin, HybridParallelPlugin, TorchFSDPPlugin from colossalai. cluster import DistCoordinator from colossalai. lazy import LazyInitContext from colossalai. nn. optimizer import HybridAdam from colossalai. shardformer import PipelineGradientCheckpointConfig # ============================== # Constants # ============================== MODEL_CONFIGS = { "7b": LlamaConfig(max_position_embeddings=4096), "13b": LlamaConfig( hidden_size=5120, intermediate_size=13824, num_hidden_layers=40, num_attention_heads=40, max_position_embeddings=4096, ), "70b": LlamaConfig( hidden_size=8192, intermediate_size=28672, num_hidden_layers=80, num_attention_heads=64, max_position_embeddings=4096, num_key_value_heads=8, ), } def main(): # ============================== # Parse Arguments # ============================== parser = argparse. ArgumentParser () parser. add_argument ("-c", "--config", type=str, default="7b", help="Model configuration") parser. add_argument ( "-p", "--plugin", choices=["gemini", "gemini_auto", "fsdp", "fsdp_cpu", "3d", "3d_cpu"], default="gemini", help="Choose which plugin to use", ) parser. add_argument ("-b", "--batch_size", type=int, default=2, help="Batch size") parser. add_argument ("-s", "--num_steps", type=int, default=5, help="Number of steps to run") parser. add_argument ("-i", "--ignore_steps", type=int, default=2, help="Number of steps to ignore") parser. add_argument ("-g", "--grad_checkpoint", action="store_true", help="Use gradient checkpointing") parser. add_argument ("-l", "--max_length", type=int, default=4096, help="Max sequence length") parser. add_argument ( "-w", "--warmup_ratio", type=float, default=0.8 , help="warm up ratio of non-model data. Only for gemini-auto" ) parser. add_argument ("-m", "--memory_limit", type=int, help="Gemini memory limit in mb") parser. add_argument ("-x", "--xformers", action="store_true", help="Use xformers") parser. add_argument ("--shard_param_frac", type=float, default=1.0 , help="Shard param fraction. Only for gemini") parser. add_argument ("--offload_optim_frac", type=float, default=0.0 , help="Offload optim fraction. Only for gemini") parser. add_argument ("--offload_param_frac", type=float, default=0.0 , help="Offload param fraction. Only for gemini") parser. add_argument ("--tp", type=int, default=1, help="Tensor parallel size") parser. add_argument ("--extra_dp", type=int, default=1, help="Extra data parallel size, used for Gemini") parser. add_argument ("--pp", type=int, default=1, help="Pipeline parallel size") parser. add_argument ("--mbs", type=int, default=1, help="Micro batch size of pipeline parallel") parser. add_argument ("--zero", type=int, default=0, help="Zero Stage when hybrid plugin is enabled") parser. add_argument ("--custom-ckpt", action="store_true", help="Customize checkpoint", default=False) parser. add_argument ("--profile", action="store_true", help="Enable profiling", default=False) parser. add_argument ( "--disable-async-reduce", action="store_true", help="Disable the asynchronous reduce operation", default=False ) parser. add_argument ("--prefetch_num", type=int, default=0, help="chunk prefetch max number") args = parser. parse_args () colossalai. launch_from_torch () coordinator = DistCoordinator() def empty_init(): pass # ckpt config for LLaMA3-70B on 64 H100 GPUs hybrid_kwargs = ( { "gradient_checkpoint_config": PipelineGradientCheckpointConfig( num_ckpt_layers_per_stage=[19, 19, 19, 13], ), "num_layers_per_stage": [19, 20, 20, 21], } if args. custom_ckpt else {} ) # ============================== # Initialize Booster # ============================== use_empty_init = True if args. plugin == "gemini": plugin = GeminiPlugin( precision="bf16", shard_param_frac=args. shard_param_frac , offload_optim_frac=args. offload_optim_frac , offload_param_frac=args. offload_param_frac , tp_size=args. tp , extra_dp_size=args. extra_dp , enable_fused_normalization=torch. cuda. is_available(), enable_flash_attention=args. xformers , max_prefetch=args. prefetch_num , enable_async_reduce=not args. disable_async_reduce , ) elif args. plugin == "gemini_auto": plugin = GeminiPlugin( placement_policy="auto", precision="bf16", warmup_non_model_data_ratio=args. warmup_ratio , tp_size=args. tp , extra_dp_size=args. extra_dp , enable_fused_normalization=torch. cuda. is_available(), max_prefetch=args. prefetch_num , enable_async_reduce=not args. disable_async_reduce , enable_flash_attention=args. xformers , ) elif args. plugin == "fsdp": if use_empty_init: plugin = TorchFSDPPlugin( mixed_precision=MixedPrecision( param_dtype=torch. float16 , reduce_dtype=torch. float16 , buffer_dtype=torch. float16 , ), param_init_fn=empty_init(), ) else: plugin = TorchFSDPPlugin( mixed_precision=MixedPrecision( param_dtype=torch. float16 , reduce_dtype=torch. float16 , buffer_dtype=torch. float16 , ) ) elif args. plugin == "fsdp_cpu": if use_empty_init: plugin = TorchFSDPPlugin( mixed_precision=MixedPrecision( param_dtype=torch. float16 , reduce_dtype=torch. float16 , buffer_dtype=torch. float16 , ), cpu_offload=CPUOffload(offload_params=True), param_init_fn=empty_init(), ) else: plugin = TorchFSDPPlugin( mixed_precision=MixedPrecision( param_dtype=torch. float16 , reduce_dtype=torch. float16 , buffer_dtype=torch. float16 , ), cpu_offload=CPUOffload(offload_params=True), ) elif args. plugin == "3d": plugin = HybridParallelPlugin( tp_size=args. tp , pp_size=args. pp , zero_stage=args. zero , enable_fused_normalization=torch. cuda. is_available(), enable_flash_attention=args. xformers , microbatch_size=args. mbs , precision="bf16", dp_outside=False, **hybrid_kwargs, ) elif args. plugin == "3d_cpu": plugin = HybridParallelPlugin( tp_size=args. tp , pp_size=args. pp , zero_stage=args. zero , cpu_offload=True, enable_fused_normalization=torch. cuda. is_available(), enable_flash_attention=args. xformers , microbatch_size=args. mbs , initial_scale=2**8, precision="bf16", ) else: raise ValueError(f"Unknown plugin {args. plugin }") booster = Booster(plugin=plugin) # ============================== # Initialize Dataset and Dataloader # ============================== dp_size = getattr(plugin, "dp_size", coordinator. world_size ) if args. config in MODEL_CONFIGS: config = MODEL_CONFIGS[args. config ] else: config = AutoConfig. from_pretrained (args. config , trust_remote_code=True) dataset = RandomDataset( num_samples=args. batch_size * args. num_steps * dp_size, max_length=args. max_length , vocab_size=config. vocab_size ) dataloader = plugin. prepare_dataloader (dataset, batch_size=args. batch_size , shuffle=True, drop_last=True) # ============================== # Initialize Model and Optimizer # ============================== init_ctx = ( LazyInitContext(default_device=get_accelerator().get_current_device()) if isinstance(plugin, (GeminiPlugin, HybridParallelPlugin)) else nullcontext() ) init_kwargs = {} if config. model_type == "chatglm": init_kwargs["empty_init"] = False with init_ctx: model = AutoModelForCausalLM. from_config (config, trust_remote_code=True, **init_kwargs) if args. grad_checkpoint : model. gradient_checkpointing_enable () if config. model_type == "chatglm": model. transformer. encoder. gradient_checkpointing = True model_numel = get_model_numel(model) coordinator. print_on_master (f"Model params: {format_numel_str(model_numel)}") performance_evaluator = PerformanceEvaluator( model_numel, model. config. num_hidden_layers, model. config. hidden_size, model. config. vocab_size, args. grad_checkpoint , args. ignore_steps , dp_world_size=dp_size, ) optimizer = HybridAdam(model. parameters ()) torch. set_default_dtype (torch. bfloat16 ) model, optimizer, _, dataloader, _ = booster. boost (model, optimizer, dataloader=dataloader) torch. set_default_dtype (torch. float ) coordinator. print_on_master ( f"Booster init max CUDA memory: {get_accelerator().max_memory_allocated()/1024**2:.2f} MB" ) coordinator. print_on_master ( f"Booster init max CPU memory: {resource. getrusage (resource. RUSAGE_SELF ).ru_maxrss/1024:.2f} MB" ) with get_profile_context( args. profile , 1, len(dataloader) - 1, save_dir=f"profile/{time. strftime ('%H:%M', time. localtime ())}-{args. plugin }-llama-{args. config }", ) as prof: if isinstance(plugin, HybridParallelPlugin) and args. pp > 1: data_iter = iter(dataloader) for step in tqdm(range(len(dataloader)), desc="Step", disable=not coordinator. is_master ()): performance_evaluator. on_step_start (step) booster. execute_pipeline ( data_iter, model, criterion=lambda outputs, inputs: outputs[0], optimizer=optimizer, return_loss=False, ) optimizer. step () optimizer. zero_grad () performance_evaluator. on_step_end (input_ids=torch. empty (args. batch_size , args. max_length )) prof. step () else: for step, batch in enumerate(tqdm(dataloader, desc="Step", disable=not coordinator. is_master ())): performance_evaluator. on_step_start (step) outputs = model(**batch) loss = outputs[0] booster. backward (loss, optimizer) optimizer. step () optimizer. zero_grad () performance_evaluator. on_step_end (**batch) prof. step () performance_evaluator. on_fit_end () coordinator. print_on_master (f"Max CUDA memory usage: {get_accelerator().max_memory_allocated()/1024**2:.2f} MB") if __name__ == "__main__": main() \n[SEP] #scripts/benchmark/data_utils. py \n import json import random from typing import Iterator, Optional import numpy as np import torch from torch. distributed import ProcessGroup from torch. distributed. distributed_c10d import _get_default_group from torch. utils. data import DataLoader, Dataset, DistributedSampler from colossalai. accelerator import get_accelerator class StatefulDistributedSampler(DistributedSampler): def __init__( self, dataset: Dataset, num_replicas: Optional[int] = None, rank: Optional[int] = None, shuffle: bool = True, seed: int = 0, drop_last: bool = False, ) -> None: super().__init__(dataset, num_replicas, rank, shuffle, seed, drop_last) self. start_index : int = 0 def __iter__(self) -> Iterator: iterator = super().__iter__() indices = list(iterator) indices = indices[self. start_index :] return iter(indices) def __len__(self) -> int: return self. num_samples - self. start_index def set_start_index(self, start_index: int) -> None: self. start_index = start_index def prepare_dataloader( dataset, batch_size, shuffle=False, seed=1024, drop_last=False, pin_memory=False, num_workers=0, process_group: Optional[ProcessGroup] = None, **kwargs, ): r""" Prepare a dataloader for distributed training. The dataloader will be wrapped by `torch. utils. data. DataLoader ` and `StatefulDistributedSampler`. Args: dataset (`torch. utils. data. Dataset `): The dataset to be loaded. shuffle (bool, optional): Whether to shuffle the dataset. Defaults to False. seed (int, optional): Random worker seed for sampling, defaults to 1024. add_sampler: Whether to add ``DistributedDataParallelSampler`` to the dataset. Defaults to True. drop_last (bool, optional): Set to True to drop the last incomplete batch, if the dataset size is not divisible by the batch size. If False and the size of dataset is not divisible by the batch size, then the last batch will be smaller, defaults to False. pin_memory (bool, optional): Whether to pin memory address in CPU memory. Defaults to False. num_workers (int, optional): Number of worker threads for this dataloader. Defaults to 0. kwargs (dict): optional parameters for ``torch. utils. data. DataLoader ``, more details could be found in `DataLoader <https://pytorch. org /docs/stable/_modules/torch/utils/data/dataloader. html #DataLoader>`_. Returns: :class:`torch. utils. data. DataLoader `: A DataLoader used for training or testing. """ _kwargs = kwargs. copy () process_group = process_group or _get_default_group() sampler = StatefulDistributedSampler( dataset, num_replicas=process_group. size (), rank=process_group. rank (), shuffle=shuffle ) # Deterministic dataloader def seed_worker(worker_id): worker_seed = seed np. random. seed(worker_seed) torch. manual_seed (worker_seed) random. seed (worker_seed) return DataLoader( dataset, batch_size=batch_size, sampler=sampler, worker_init_fn=seed_worker, drop_last=drop_last, pin_memory=pin_memory, num_workers=num_workers, **_kwargs, ) def load_json(file_path: str): with open(file_path, "r") as f: return json. load (f) def save_json(data, file_path: str): with open(file_path, "w") as f: json. dump (data, f, indent=4) class RandomDataset(Dataset): def __init__(self, num_samples: int = 1000, max_length: int = 2048, vocab_size: int = 32000): self. num_samples = num_samples self. max_length = max_length self. input_ids = torch. randint ( 0, vocab_size, (num_samples, max_length), device=get_accelerator().get_current_device() ) self. attention_mask = torch. ones_like (self. input_ids ) def __len__(self): return self. num_samples def __getitem__(self, idx): return { "input_ids": self. input_ids [idx], "attention_mask": self. attention_mask [idx], "labels": self. input_ids [idx], } \n[SEP] #scripts/benchmark/model_utils. py \n from contextlib import contextmanager import torch import torch. nn as nn @contextmanager def low_precision_init(target_dtype: torch. dtype = torch. float16 ): dtype = torch. get_default_dtype () try: torch. set_default_dtype (target_dtype) yield finally: torch. set_default_dtype (dtype) def get_model_numel(model: nn. Module ) -> int: return sum(p. numel () for p in model. parameters ()) def format_numel_str(numel: int) -> str: B = 1024**3 M = 1024**2 K = 1024 if numel >= B: return f"{numel / B:.2f} B" elif numel >= M: return f"{numel / M:.2f} M" elif numel >= K: return f"{numel / K:.2f} K" else: return f"{numel}" \n[SEP] #scripts/benchmark/performance_evaluator. py \n from time import time from typing import Optional import torch import torch. distributed as dist from torch import Tensor from torch. profiler import ProfilerActivity, profile, schedule, tensorboard_trace_handler from colossalai. accelerator import get_accelerator from colossalai. cluster import DistCoordinator def divide(x: float, y: float) -> float: if y == 0: return float("inf") elif y == float("inf"): return float("nan") return x / y @torch. no_grad () def all_reduce_mean(x: float, world_size: int) -> float: if world_size == 1: return x tensor = torch. tensor ([x], device=get_accelerator().get_current_device()) dist. all_reduce (tensor) tensor = tensor / world_size return tensor. item () def get_profile_context(enable_flag, warmup_steps, active_steps, save_dir): class DummyProfiler: def __init__(self): self. step_number = 0 def step(self): self. step_number += 1 def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): pass if enable_flag: return profile( activities=[ProfilerActivity. CPU , ProfilerActivity. CUDA ], schedule=schedule(wait=0, warmup=warmup_steps, active=active_steps), on_trace_ready=tensorboard_trace_handler(save_dir), record_shapes=True, profile_memory=True, with_stack=True, ) else: return DummyProfiler() class Timer: def __init__(self) -> None: self. start_time : Optional[float] = None self. duration : float = 0.0 def start(self) -> None: self. start_time = time() def end(self) -> None: assert self. start_time is not None self. duration += time() - self. start_time self. start_time = None def reset(self) -> None: self. duration = 0.0 class PerformanceEvaluator: """ Callback for valuate the performance of the model. Args: actor_num_params: The number of parameters of the actor model. critic_num_params: The number of parameters of the critic model. initial_model_num_params: The number of parameters of the initial model. reward_model_num_params: The number of parameters of the reward model. enable_grad_checkpoint: Whether to enable gradient checkpointing. ignore_episodes: The number of episodes to ignore when calculating the performance. """ def __init__( self, model_numel: int, num_layers: int, hidden_size: int, vocab_size: int, enable_grad_checkpoint: bool = False, ignore_steps: int = 0, dp_world_size: Optional[int] = None, ) -> None: self. model_numel = model_numel self. enable_grad_checkpoint = enable_grad_checkpoint self. ignore_steps = ignore_steps self. num_layers = num_layers self. hidden_size = hidden_size self. vocab_size = vocab_size self. coordinator = DistCoordinator() self. dp_world_size = dp_world_size or self. coordinator. world_size self. disable : bool = False self. timer = Timer() self. num_samples : int = 0 self. flop_megatron = 0 self. flop : int = 0 def on_step_start(self, step: int) -> None: self. disable = self. ignore_steps > 0 and step < self. ignore_steps if self. disable : return get_accelerator().synchronize() self. timer. start() def on_step_end(self, input_ids: Tensor, **kwargs) -> None: if self. disable : return get_accelerator().synchronize() self. timer. end() batch_size, seq_len = input_ids. shape self. num_samples += batch_size checkpoint_activations_factor = 3 + int(self. enable_grad_checkpoint ) self. flop_megatron += ( 24 * checkpoint_activations_factor * batch_size * seq_len * self. num_layers * (self. hidden_size **2) ) * ( 1.0 + (seq_len / (6.0 * self. hidden_size )) + (self. vocab_size / (16.0 * self. num_layers * self. hidden_size )) ) self. flop += batch_size * seq_len * self. model_numel * 2 * (3 + int(self. enable_grad_checkpoint )) def on_fit_end(self) -> None: avg_duration = all_reduce_mean(self. timer. duration, self. coordinator. world_size) avg_throughput = self. num_samples * self. dp_world_size / (avg_duration + 1e-12) mp_world_size = self. coordinator. world_size // self. dp_world_size avg_tflops_per_gpu_megatron = self. flop_megatron / 1e12 / (avg_duration + 1e-12) / mp_world_size avg_tflops_per_gpu = self. flop / 1e12 / (avg_duration + 1e-12) / mp_world_size self. coordinator. print_on_master( f"num_samples: {self. num_samples }, dp_world_size: {self. dp_world_size }, flop_megatron: {self. flop_megatron }, flop: {self. flop }, avg_duration: {avg_duration}, " f"avg_throughput: {avg_throughput}" ) self. coordinator. print_on_master( f"Throughput: {avg_throughput:.2f} samples/sec, TFLOPS per GPU by Megatron: {avg_tflops_per_gpu_megatron:.2f}, TFLOPS per GPU: {avg_tflops_per_gpu:.2f}" ) \n[SEP] #scripts/benchmark/requirements. txt \n colossalai>=0.3.6 datasets numpy tqdm transformers flash-attn>=2.0.0 SentencePiece==0.1.99 tensorboard==2.14.0 \n[SEP] #!/bin/bash ################ #Load your environments and modules here ################ HOSTFILE=$(realpath hosts. txt ) cd../.. export OMP_NUM_THREADS=8 colossalai run --nproc_per_node 8 --hostfile $HOSTFILE benchmark. py -g -x -b 16 [SEP] #!/bin/bash ################ #Load your environments and modules here ################ HOSTFILE=$(realpath hosts. txt ) cd../.. export OMP_NUM_THREADS=8 colossalai run --nproc_per_node 8 --hostfile $HOSTFILE benchmark. py -p gemini_auto -g -x -b 16