From 05820e6a5f1180411bd997e10426a775a18f5afa Mon Sep 17 00:00:00 2001 From: lifeng Date: Mon, 5 Dec 2022 15:05:02 +0800 Subject: [PATCH] Document Level Sentiment Analysis v1.0.0 --- CODE_OF_CONDUCT.md | 131 +++++++ CONTRIBUTING.md | 57 +++ LICENSE | 201 ++++++++++ README.md | 3 + SECURITY.md | 13 + docs/_config.yml | 1 + docs/assets/images/DLSA_workflow.PNG | Bin 0 -> 220273 bytes docs/fine-tuning/multi-nodes-ipex.md | 50 +++ docs/fine-tuning/multi-nodes-stock-pytorch.md | 44 +++ docs/fine-tuning/single-node-ipex.md | 28 ++ docs/fine-tuning/single-node-stock-pytorch.md | 26 ++ docs/fine-tuning/single-node-trainer.md | 28 ++ docs/index.md | 69 ++++ docs/inference/hf-transformers.md | 59 +++ docs/inference/ipex.md | 65 ++++ docs/inference/stock-pytorch.md | 64 ++++ profiling-transformers/.gitignore | 149 ++++++++ .../deploy/install_torch_ccl.sh | 42 +++ .../fine-tuning/run_dist.sh | 202 +++++++++++ .../fine-tuning/run_ipex_native.sh | 38 ++ .../fine-tuning/train_native.sh | 114 ++++++ .../fine-tuning/train_trainer.sh | 115 ++++++ .../inference/cpu_multi_instance.sh | 193 ++++++++++ .../inference/cpu_single_instance.sh | 111 ++++++ .../inference/multi_instance.sh | 219 +++++++++++ .../inference/single_instance.sh | 126 +++++++ profiling-transformers/install.sh | 20 + profiling-transformers/src/__init__.py | 16 + profiling-transformers/src/run_pt.py | 137 +++++++ profiling-transformers/src/run_pt_native.py | 249 +++++++++++++ .../src/run_pt_native_ft.py | 286 +++++++++++++++ .../src/run_pt_native_inf.py | 223 ++++++++++++ profiling-transformers/src/utils.py | 343 ++++++++++++++++++ 33 files changed, 3422 insertions(+) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 docs/_config.yml create mode 100644 docs/assets/images/DLSA_workflow.PNG create mode 100644 docs/fine-tuning/multi-nodes-ipex.md create mode 100644 docs/fine-tuning/multi-nodes-stock-pytorch.md create mode 100644 docs/fine-tuning/single-node-ipex.md create mode 100644 docs/fine-tuning/single-node-stock-pytorch.md create mode 100644 docs/fine-tuning/single-node-trainer.md create mode 100644 docs/index.md create mode 100644 docs/inference/hf-transformers.md create mode 100644 docs/inference/ipex.md create mode 100644 docs/inference/stock-pytorch.md create mode 100644 profiling-transformers/.gitignore create mode 100755 profiling-transformers/deploy/install_torch_ccl.sh create mode 100755 profiling-transformers/fine-tuning/run_dist.sh create mode 100755 profiling-transformers/fine-tuning/run_ipex_native.sh create mode 100755 profiling-transformers/fine-tuning/train_native.sh create mode 100755 profiling-transformers/fine-tuning/train_trainer.sh create mode 100755 profiling-transformers/inference/cpu_multi_instance.sh create mode 100755 profiling-transformers/inference/cpu_single_instance.sh create mode 100755 profiling-transformers/inference/multi_instance.sh create mode 100755 profiling-transformers/inference/single_instance.sh create mode 100755 profiling-transformers/install.sh create mode 100644 profiling-transformers/src/__init__.py create mode 100644 profiling-transformers/src/run_pt.py create mode 100644 profiling-transformers/src/run_pt_native.py create mode 100644 profiling-transformers/src/run_pt_native_ft.py create mode 100644 profiling-transformers/src/run_pt_native_inf.py create mode 100644 profiling-transformers/src/utils.py diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..1735498 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,131 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +CommunityCodeOfConduct AT intel DOT com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..578d28d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,57 @@ +# Contributing + +### License + + is licensed under the terms in [LICENSE]. By contributing to the project, you agree to the license and copyright terms therein and release your contribution under these terms. + +### Sign your work + +Please use the sign-off line at the end of the patch. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify +the below (from [developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..aa57c80 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# E2E DLSA +DLSA is Intel optimized representative End-to-end Fine-Tuning & Inference pipeline for Document level sentiment analysis using BERT model implemented with Hugging face transformer API. + diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..5af6cb6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Report a Vulnerability + +Please report security issues or vulnerabilities to the [Intel® Security Center]. + +For more information on how Intel® works to resolve security issues, see +[Vulnerability Handling Guidelines]. + +[Intel® Security Center]:https://www.intel.com/content/www/us/en/security-center/default.html + +[Vulnerability Handling Guidelines]:https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html + diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..c419263 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file diff --git a/docs/assets/images/DLSA_workflow.PNG b/docs/assets/images/DLSA_workflow.PNG new file mode 100644 index 0000000000000000000000000000000000000000..c504a565bea4cb5d156e75056c660552c747bfe3 GIT binary patch literal 220273 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 z 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

R`Wquct#bD%i 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 Note: This step should be operated on all the work nodes + +## To run: + +``` +source /opt/intel/oneapi/mpi/latest/env/vars.sh +cd profiling-transformers +``` + +> Note: +> +> np: num process, means how many processes you will run on a cluster +> +> ppn: process per node, means how many processes you will run on 1 worker node. +> +> For example, if I want to run on 2 nodes, each node runs with 1 process, use the config `-np 2 -ppn 1` +> +> if I want to run on 4 nodes, each node runs with 2 processes, use the config `-np 8 -ppn 2` + +### Running single process in single node + +``` +bash fine-tuning/run_dist.sh -np 1 -ppn 1 bash fine-tuning/run_ipex_native.sh +``` + +### Running multi instances in single node + +``` +# Run 2 instances in single node +bash fine-tuning/run_dist.sh -np 2 -ppn 2 bash fine-tuning/run_ipex_native.sh +``` + +### Running with IPEX BF16 + +> Before you run BF16 fine-tuning, you need to verify whether your server supports BF16. (Only Copper Lake & Sapphire Rapids CPUs support BF16) + +add `--bf16_ipex_ft` at the end of the command: + +``` +bash fine-tuning/run_dist.sh -np 2 -ppn 2 bash fine-tuning/run_ipex_native.sh --bf16_ipex_ft 1 +``` + diff --git a/docs/fine-tuning/multi-nodes-stock-pytorch.md b/docs/fine-tuning/multi-nodes-stock-pytorch.md new file mode 100644 index 0000000..10e4320 --- /dev/null +++ b/docs/fine-tuning/multi-nodes-stock-pytorch.md @@ -0,0 +1,44 @@ +# How to Run DLSA Multi Node Fine-Tuning with Stock PyTorch(FP32) + +## Install MPI library: + +Install MPI from [here]( https://anaconda.org/intel/impi_rt ) + + +MPI is included in the Intel OneAPI Toolkit. It's recommended to use the package manager to install. + +> Note: This step should be operated on all the work nodes + +## To run: + +``` +source /opt/intel/oneapi/mpi/latest/env/vars.sh +cd profiling-transformers +``` + +> Note: +> +> np: num process, means how many processes you will run on a cluster +> +> ppn: process per node, means how many processes you will run on 1 worker node. +> +> For example, if I want to run on 2 nodes, each node runs with 1 process, use the config `-np 2 -ppn 1` +> +> if I want to run on 4 nodes, each node runs with 2 processes, use the config `-np 8 -ppn 2` + +### Running single process in single node + +``` +bash fine-tuning/run_dist.sh -np 1 -ppn 1 bash fine-tuning/run_ipex_native.sh +``` + +### Running multi-node fine-tuning + +> You need to create the `hostfile` which contains all nodes you want to run on and set password-free login. + +``` +bash fine-tuning/run_dist.sh -np 2 -ppn 1 -f hostfile bash fine-tuning/run_ipex_native.sh +``` + + + diff --git a/docs/fine-tuning/single-node-ipex.md b/docs/fine-tuning/single-node-ipex.md new file mode 100644 index 0000000..4baf9cd --- /dev/null +++ b/docs/fine-tuning/single-node-ipex.md @@ -0,0 +1,28 @@ +# How to Run DLSA Single Node Fine-Tuning with IPEX(FP32, BF16) + +## Running on CPU + +### Single node + +``` +./fine-tuning/train_native.sh +``` + +By default, it will launch 1 instance to run fine-tuning with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./fine-tuning/train_native.sh -h`: + +```markdown +Usage: ./fine-tuning/train_native.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + --bf16_ipex_ft - wether to use bf16_ipex_ft precision + --fp32_ipex_ft - wether to use fp32_ipex_ft precision + -h | --help - displays this message +``` + + + diff --git a/docs/fine-tuning/single-node-stock-pytorch.md b/docs/fine-tuning/single-node-stock-pytorch.md new file mode 100644 index 0000000..8b5f42f --- /dev/null +++ b/docs/fine-tuning/single-node-stock-pytorch.md @@ -0,0 +1,26 @@ +# How to Run DLSA Single Node Fine-Tuning Pipeline with Stock PyTorch + +## Running on CPU + +### Single node + +``` +./fine-tuning/train_native.sh +``` + +By default, it will launch 1 instance to run fine-tuning with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./fine-tuning/train_native.sh -h`: + +```markdown +Usage: ./fine-tuning/train_native.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + ~~--bf16_ipex_ft - wether to use bf16_ipex_ft precision~~ + ~~--fp32_ipex_ft - wether to use fp32_ipex_ft precision~~ + -h | --help - displays this message +``` + diff --git a/docs/fine-tuning/single-node-trainer.md b/docs/fine-tuning/single-node-trainer.md new file mode 100644 index 0000000..11da772 --- /dev/null +++ b/docs/fine-tuning/single-node-trainer.md @@ -0,0 +1,28 @@ +# How to Run DLSA Single Node Fine-Tuning with Trainer(FP32, BF16) + +## Running on CPU + +### Single node + +``` +./fine-tuning/train_trainer.sh +``` + +By default, it will launch 1 instance to run fine-tuning with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./fine-tuning/train_native.sh -h`: + +```markdown +Usage: ./fine-tuning/train_trainer.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + --bf16 - whether using hf bf16 inference + --use_ipex - whether using ipex + -h | --help - displays this message +``` + + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..61f8f2d --- /dev/null +++ b/docs/index.md @@ -0,0 +1,69 @@ +# Welcome to DLSA Pages + +DLSA is Intel optimized representative End-to-end Fine-Tuning & Inference pipeline for Document level sentiment analysis using BERT model implemented with Hugging face transformer API. + +![Image](assets/images/DLSA_workflow.PNG) + +## Prerequisites +### Download the repo + +``` +#download the repo +git clone https://github.com/intel/document-level-sentiment-analysis.git +cd frameworks.ai.end2end-ai-pipelines.dlsa/profiling-transformers +git checkout v1.0.0 +``` + +### Download the datasets: + +``` +mkdir datasets +cd datasets +#download and extract SST-2 dataset +wget https://dl.fbaipublicfiles.com/glue/data/SST-2.zip && unzip SST-2.zip && mv SST-2 sst +#download and extract IMDB dataset +wget http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz && tar -zxf aclImdb_v1.tar.gz +``` +>Note: Make sure the network connections work well for downloading the datasets. + +## Deploy the test environment +### Download Miniconda and install it + +``` +wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh +sh Miniconda3-latest-Linux-x86_64.sh +``` + +> Note: If you have already installed conda on your system, just skip this step. + +### Prepare the conda environment for DLSA + +``` +conda create -n dlsa python=3.8 --yes +conda activate dlsa +sh install.sh +``` + +## Running DLSA Inference Pipeline + +| Implementations | Model | API | Framework | Precision | +| -------------------------------------------------------- | -------- | ----------- | -------------- | -------------- | +| [Run with HF Transformers](inference/hf-transformers.md) | HF Model | Trainer | PyTorch + IPEX | FP32,BF16 | +| [Run with Stock Pytorch](inference/stock-pytorch.md) | HF Mode | Non-trainer | PyTorch | FP32 | +| [Run with IPEX](inference/ipex.md) | HF Mode | Non-trainer | PyTorch + IPEX | FP32,BF16,INT8 | + +## Running DLSA Fine-Tuning Pipeline + +### Single Node Fine-Tuning + +| Implementations | Model | Instance | API | Framework | Precision | +| ---------------------------------- | -------- | -------- | ----------- | ----------------------- | ---------- | +| [Run with HF Transformers + IPEX ](fine-tuning/single-node-trainer.md) | HF Model | Single | Trainer | PyTorch + IPEX | FP32, BF16 | +| [Run with Stock Pytorch](fine-tuning/single-node-stock-pytorch.md) | HF Model | Single | Non-trainer | PyTorch | FP32 | +| [Run with IPEX (Single Instance)](fine-tuning/single-node-ipex.md) | HF Model | Single | Non-trainer | PyTorch + IPEX | FP32,BF16 | +| [Run with IPEX (Multi Instance)](fine-tuning/multi-nodes-ipex.md) | HF Model | Multiple | Non-trainer | PyTorch + IPEX | FP32,BF16 | + + +## Issue Tracking +E2E DLSA tracks both bugs and enhancement requests using [Github](https://github.com/intel/document-level-sentiment-analysis/issues). We welcome input, however, before filing a request, please make sure you do the following: +Search the Github issue database. diff --git a/docs/inference/hf-transformers.md b/docs/inference/hf-transformers.md new file mode 100644 index 0000000..cf73841 --- /dev/null +++ b/docs/inference/hf-transformers.md @@ -0,0 +1,59 @@ +# How to Run DLSA Inference Pipeline with HF Transformers(FP32, BF16) + +## Support Matrix + +|Categoty | Script | +|---|---| +|CPU Single Instance | cpu_single_instance.sh | +|CPU Multi Instances | cpu_multi_instance.sh | + +> Note: Please use the fine-tuned model for correct accuracy. Just change the `MODEL_NAME_OR_PATH` in the script before you running. By default, the `MODEL_NAME_OR_PATH` is `bert-large-uncased` which is downloaded from the Hugging Face website. + +## Running on CPU + +### Single instance + +``` +./inference/cpu_single_instance.sh +``` + +By default, it will launch 1 instance to run inference with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./inference/cpu_single_instance.sh -h`: + +```markdown +Usage: ./inference/cpu_single_instance.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + --bf16 - whether using hf bf16 inference + --use_ipex - whether using ipex + -h | --help - displays this message +``` + + + +### Multi-instance + +``` +./inference/cpu_multi_instance.sh +``` + +By default, it will launch 2 instances (1 instance/socket) to run inference with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./inference/cpu_multi_instance.sh -h` + +```markdown +Usage: ./inference/cpu_multi_instance.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -n | --num_of_ins_per_socket - number of instance per socket + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + --bf16 - whether using hf bf16 inference + --use_ipex - whether using ipex + -h | --help - displays this message +``` diff --git a/docs/inference/ipex.md b/docs/inference/ipex.md new file mode 100644 index 0000000..e91c5df --- /dev/null +++ b/docs/inference/ipex.md @@ -0,0 +1,65 @@ +# How to Run DLSA Inference Pipeline with IPEX(FP32, BF16, INT8) + +## Support Matrix + +| Categoty | Script | +| ------------------- | ------------------ | +| CPU Single Instance | single_instance.sh | +| CPU Multi Instances | multi_instance.sh | + +> Note: Please use the fine-tuned model for correct accuracy. Just change the `MODEL_NAME_OR_PATH` in the script before you running. By default, the `MODEL_NAME_OR_PATH` is `bert-large-uncased` which is downloaded from the Hugging Face website. + +## Running on CPU + +> Note: For int8 inference, you need to quantize the model firstly. Please see the details in this link: https://github.com/IntelAI/models/tree/master/quickstart/language_modeling/pytorch/bert_large/inference/cpu + +### Single instance + +``` +./inference/single_instance.sh +``` + +By default, it will launch 1 instance to run inference with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./inference/single_instance.sh -h`: + +```markdown +Usage: ./inference/single_instance.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + --ipex_fp32 - wether to use ipex_fp32 precision + --ipex_bf16 - wether to use ipex_bf16 precision + --int8 - wether to use int8 precision + --int8_bf16 - wether to use int8_bf16 precision + -h | --help - displays this message +``` + + + +### Multi-instance + +``` +./inference/multi_instance.sh +``` + +By default, it will launch 2 instances (1 instance/socket) to run inference with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./inference/multi_instance.sh -h` + +```markdown +Usage: ./inference/multi_instance.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -n | --num_of_ins_per_socket - number of instance per socket + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + --ipex_fp32 - wether to use ipex_fp32 precision + --ipex_bf16 - wether to use ipex_bf16 precision + --int8 - wether to use int8 precision + --int8_bf16 - wether to use int8_bf16 precision + -h | --help - displays this message +``` diff --git a/docs/inference/stock-pytorch.md b/docs/inference/stock-pytorch.md new file mode 100644 index 0000000..2525fb6 --- /dev/null +++ b/docs/inference/stock-pytorch.md @@ -0,0 +1,64 @@ +# How to Run DLSA Inference Pipeline with Stock PyTorch + +## Support Matrix + +|Categoty | Script | +|---|---| +|CPU Single Instance | single_instance.sh | +|CPU Multi Instances | multi_instance.sh | + +> Note: Please use the fine-tuned model for correct accuracy. Just change the `MODEL_NAME_OR_PATH` in the script before you running. By default, the `MODEL_NAME_OR_PATH` is `bert-large-uncased` which is downloaded from the Hugging Face website. + +## Running on CPU + +### Single instance + +``` +./inference/single_instance.sh +``` + +By default, it will launch 1 instance to run inference with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./inference/single_instance.sh -h`: + +```markdown +Usage: ./inference/single_instance.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + ~~--ipex_fp32 - wether to use ipex_fp32 precision~~ + ~~--ipex_bf16 - wether to use ipex_bf16 precision~~ + ~~--int8 - wether to use int8 precision~~ + ~~--int8_bf16 - wether to use int8_bf16 precision~~ + -h | --help - displays this message +``` + + + +### Multi-instance + +``` +./inference/multi_instance.sh +``` + +By default, it will launch 2 instances (1 instance/socket) to run inference with SST-2 dataset and FP32 precision. You can change the configurations in the file or pass parameters when running the script. + +Below is the help message by using the command `./inference/multi_instance.sh -h` + +```markdown +Usage: ./inference/multi_instance.sh [OPTIONS] +OPTION includes: + -l | --log_name - the log name of this round + -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET + -n | --num_of_ins_per_socket - number of instance per socket + -b | --batch_size - batch size per instance + -s | --sequence_len - max sequence length + ~~--ipex_fp32 - wether to use ipex_fp32 precision~~ + ~~--ipex_bf16 - wether to use ipex_bf16 precision~~ + ~~--int8 - wether to use int8 precision~~ + ~~--int8_bf16 - wether to use int8_bf16 precision~~ + -h | --help - displays this message +``` + diff --git a/profiling-transformers/.gitignore b/profiling-transformers/.gitignore new file mode 100644 index 0000000..1831872 --- /dev/null +++ b/profiling-transformers/.gitignore @@ -0,0 +1,149 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + + +############## +runs/ +.vscode/ +output/ +logs/ + +*.gz.* + +api_token.txt +fine_tuned/ +bert-base-uncased-tf +output-tf +fine_tuned-tf/ +few_shot_* +traced_bert.pt +results/ +models/ +wandb/ \ No newline at end of file diff --git a/profiling-transformers/deploy/install_torch_ccl.sh b/profiling-transformers/deploy/install_torch_ccl.sh new file mode 100755 index 0000000..3fa177d --- /dev/null +++ b/profiling-transformers/deploy/install_torch_ccl.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +GCC_GOOD=`gcc --version | awk '/gcc/ && ($3+0)>=8.3{print "1"}'` +if [ "x$GCC_GOOD" != "x1" ] ; then + echo "Requires gcc version later than 8.3.0" + exit 1 +fi + +pt_version=$(python -c "import torch; print(torch.__version__)" 2> /dev/null) +if [ "x$pt_version" == "x" ] ; then + echo "Can't find pytorch version, need PyTorch 1.9 or higher..." + exit 1 +fi + +branch=$(echo $pt_version | tr "." " " | awk '{print "ccl_torch" $1 "." $2}') + +if ! test -d ./torch-ccl ; then + git clone https://github.com/intel/torch-ccl.git +fi +cd torch-ccl +# workaround to disable linker error for linking to mkl libraries +# export CMAKE_FIND_DEBUG_MODE=ON +export CMAKE_DISABLE_FIND_PACKAGE_MKL=TRUE +git checkout $branch && git submodule sync && git submodule update --init --recursive && CC=gcc CXX=g++ CMAKE_C_COMPILER=gcc CMAKE_CXX_COMPILER=g++ python setup.py install + diff --git a/profiling-transformers/fine-tuning/run_dist.sh b/profiling-transformers/fine-tuning/run_dist.sh new file mode 100755 index 0000000..8d2e94d --- /dev/null +++ b/profiling-transformers/fine-tuning/run_dist.sh @@ -0,0 +1,202 @@ +#!/bin/bash +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +function print_vars { + for VAR in ${!CCL*} ${!I_MPI*} ${!i_mpi*} ${!KMP_*} ${!OMP_*} ${!ATL_*} LD_PRELOAD ${!DLRM_*} ${!PYTORCH_*} ${!PCL_*} ${!LIBXSMM_*} ${!EMULATE_*} DATALOADER_WORKER_COUNT VIRTUAL_ENV ${!ARGS_*} $@ ; do + if ! test -z ${!VAR} ; then + echo "Using $VAR=${!VAR}" + fi + done +} + +SINGLE_SOCKET_ONLY=0 + +while (( "$#" )); do + case "$1" in + -n|-np) + ARGS_NTASKS=$2 + shift 2 + ;; + -ppn) + ARGS_PPN=$2 + shift 2 + ;; + -f) + ARGS_HOSTFILE=$2 + shift 2 + ;; + -sso) + SINGLE_SOCKET_ONLY=1 + shift + ;; + --) # end argument parsing + shift + break + ;; + -*|--*=) # unsupported flags + echo "Error: Unsupported flag $1" >&2 + exit 1 + ;; + *) # preserve positional arguments + break + ;; + esac +done + +if ! test -z $SLURM_JOB_ID ; then + PREFIX="srun -n 1 -N 1 " +else + PREFIX= +fi + +if ! test -z $ARGS_HOSTFILE ; then + if ! test -f $ARGS_HOSTFILE ; then + echo "Hostfile $ARGS_HOSTFILE does not exist!" ; exit 1 + else + OPT_HOSTFILE="-f $ARGS_HOSTFILE" + PREFIX="mpiexec.hydra -np 1 -ppn 1 -f $ARGS_HOSTFILE" + fi +fi + +CORES_PER_SOCKET=`$PREFIX lscpu | grep "Core(s) per socket" | awk '{print $NF}'` +NUM_SOCKETS=`$PREFIX lscpu | grep "Socket(s):" | awk '{print $NF}'` +NUM_NUMA_NODES=`$PREFIX lscpu | grep "NUMA node(s):" | awk '{print $NF}'` +THREADS_PER_CORE=`$PREFIX lscpu | grep "Thread(s) per core:" | awk '{print $NF}'` + +NNODES=1 +NP=1 +if [ $SINGLE_SOCKET_ONLY -eq 1 ] ; then +PPN=1 +else +PPN=$NUM_NUMA_NODES +fi + +if ! test -z $SLURM_NNODES ; then NNODES=$SLURM_NNODES ; fi +if ! test -z $SLURM_NTASKS ; then NP=$SLURM_NTASKS ; fi +if ! test -z $SLURM_NNODES && ! test -z $SLURM_NTASKS ; then PPN=$(( SLURM_NTASKS / SLURM_NNODES )) ; fi +if ! test -z $ARGS_NTASKS ; then NP=$ARGS_NTASKS ; fi +if ! test -z $ARGS_HOSTFILE ; then + NNODES=`cat $ARGS_HOSTFILE | sort -u | wc -l` +fi + +if ! test -z $ARGS_PPN ; then + PPN=$ARGS_PPN +fi +REAL_NNODES=$(( (NP + PPN - 1) / PPN )) +if [[ $REAL_NNODES -lt $NNODES ]] ; then NNODES=$REAL_NNODES ; fi + +if [ $(( NP % NNODES )) -ne 0 ] ; then + echo "Number of tasks ($NP) not multiple of number of nodes ($NNODES), exiting..." + exit 1 +fi + +PPN=$(( NP / NNODES )) + +echo "Running $NP tasks on $NNODES nodes with ppn=$PPN" + + +OPT_PPN="-ppn $PPN " + +if [ $SINGLE_SOCKET_ONLY -eq 1 ] ; then + NUM_THREADS=$(( CORES_PER_SOCKET / PPN )) +else + NUM_THREADS=$(( CORES_PER_SOCKET * NUM_SOCKETS / PPN )) +fi + +if [ "x${DATALOADER_WORKER_COUNT}" == "x" ] ; then +DATALOADER_WORKER_COUNT=0 +fi + +if [ $NP == 1 ] ; then +export CCL_WORKER_COUNT=0 +else +if [ "x${CCL_WORKER_COUNT}" == "x" ] ; then +export CCL_WORKER_COUNT=1 +fi +fi +CCL_WORKER_AFFINITY="" +PYTORCH_MPI_THREAD_AFFINITY="" + +NUM_RESV_THREADS=$(( CCL_WORKER_COUNT + DATALOADER_WORKER_COUNT )) +NUM_WORKER_THREADS=$(( NUM_THREADS - NUM_RESV_THREADS )) +USE_BC=1 +if ! which bc >& /dev/null ; then USE_BC=0 ; fi +for I in 0 1 2 3 ; do +SHFT=$(( NUM_RESV_THREADS + I )) +if [ $USE_BC -eq 1 ] ; then +PROC_MASK_STR[$I]=`BC_LINE_LENGTH=0 bc <<<"obase=16;(2^${NUM_WORKER_THREADS} - 1)*(2^${SHFT} )"` +else +PROC_MASK=$(( ( ( 1 << NUM_WORKER_THREADS ) - 1 ) << SHFT )) +PROC_MASK_STR[$I]=`printf "%X" $PROC_MASK` +fi +#echo "PROC_MASK_STR $I = ${PROC_MASK_STR[$I]}" +done +MASKS=( ) +for(( I=0; I < PPN ; I++)) ; do + SHFT=$(( I * NUM_THREADS )) + IND=$(( SHFT % 4 )) + if [ $SHFT -lt 4 ] ; then + ZEROS="" + else + ZEROS=`printf "%0*X" $(( SHFT / 4 ))` + fi + SMASK=${PROC_MASK_STR[$IND]}${ZEROS} + MASKS[$I]="0x$SMASK" + for((P=0;P < CCL_WORKER_COUNT ; P++)); do CCL_WORKER_AFFINITY="${CCL_WORKER_AFFINITY} $(( I * NUM_THREADS + P ))" ; done + PYTORCH_MPI_THREAD_AFFINITY="${PYTORCH_MPI_THREAD_AFFINITY} $(( I * NUM_THREADS ))" +done +export I_MPI_PIN_DOMAIN=[`echo ${MASKS[@]} | tr " " ","`] +export CCL_WORKER_AFFINITY=`echo ${CCL_WORKER_AFFINITY} | tr " " ","` +export OMP_NUM_THREADS=$(( NUM_THREADS - CCL_WORKER_COUNT - DATALOADER_WORKER_COUNT )) +export PYTORCH_MPI_THREAD_AFFINITY=`echo ${PYTORCH_MPI_THREAD_AFFINITY} | tr " " ","` + +which python icc gcc mpicc mpiexec.hydra 2> /dev/null + +echo "#### INITIAL ENV ####" +print_vars +echo "#### INITIAL ENV ####" + +echo "PyTorch version: `python -c "import torch; print(torch.__version__)" 2> /dev/null`" + +if ! test -z $SLURM_JOB_ID ; then +srun hostname | sort -u +fi + +export MASTER_ADDR=`$PREFIX hostname` +export MASTER_PORT=29500 +echo "MASTER_ADDR=$MASTER_ADDR" + +CMD=$1 +shift +ARGS="$@" + +MPIEXE_ARGS="-np $NP $OPT_PPN $OPT_HOSTFILE -l -genv I_MPI_PIN_DOMAIN=$I_MPI_PIN_DOMAIN -genv CCL_WORKER_AFFINITY=$CCL_WORKER_AFFINITY -genv CCL_WORKER_COUNT=$CCL_WORKER_COUNT -genv OMP_NUM_THREADS=$OMP_NUM_THREADS " + +#echo "Running mpiexec.hydra ${MPIEXE_ARGS} $CMD $@" +eval set -- "${MPIEXE_ARGS} hostname" +mpiexec.hydra $@ | sort +eval set -- "${MPIEXE_ARGS} $CMD $ARGS" +echo "Running mpiexec.hydra $@" +echo "Start Time: `date`" +SECONDS=0 +#mpiexec.hydra ${MPIEXE_ARGS} ${CMD} $@ +mpiexec.hydra $@ +echo "End Time: `date`" +duration=$SECONDS +echo "Total Time: $(($duration / 60)) min and $(($duration % 60)) sec" + diff --git a/profiling-transformers/fine-tuning/run_ipex_native.sh b/profiling-transformers/fine-tuning/run_ipex_native.sh new file mode 100755 index 0000000..4e41abf --- /dev/null +++ b/profiling-transformers/fine-tuning/run_ipex_native.sh @@ -0,0 +1,38 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +# export CUDA_VISIBLE_DEVICES="-1"; \ +MODEL_NAME_OR_PATH="${MODEL_NAME_OR_PATH:-bert-large-uncased}" +DATASET="${DATASET:-sst2}" +MAX_SEQ_LEN=55 +NUM_TRAIN_EPOCHS=1 +OUTPUT_DIR="${OUTPUT_DIR:-fine_tuned}" +TRAINNING_BS=32 +INFERENCE_BS=8 + #--bf16_ft \ +python src/run_pt_native_ft.py \ + --model_name_or_path $MODEL_NAME_OR_PATH \ + --dataset $DATASET \ + --num_train_epochs $NUM_TRAIN_EPOCHS \ + --max_seq_len $MAX_SEQ_LEN \ + --output_dir $OUTPUT_DIR \ + --do_train \ + --per_device_train_batch_size $TRAINNING_BS \ + --do_predict \ + --per_device_eval_batch_size $INFERENCE_BS \ + --logging_strategy epoch \ + $@ diff --git a/profiling-transformers/fine-tuning/train_native.sh b/profiling-transformers/fine-tuning/train_native.sh new file mode 100755 index 0000000..d22fd65 --- /dev/null +++ b/profiling-transformers/fine-tuning/train_native.sh @@ -0,0 +1,114 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +export LOG_NAME=`date "+%m%d-%H%M"` +export DATASET="sst2" +export BATCH_SIZE=32 +export SEQUENCE_LEN=55 +export BF16_IPEX_FT=0 +export FP32_IPEX_FT=0 +export TRAIN_EPOCH=1 +export MODEL_NAME_OR_PATH="bert-large-uncased" +export OUTPUT_DIR="${OUTPUT_DIR:-./logs}" + +while [ "$1" != "" ]; +do + case $1 in + -l | --log_name ) + shift + LOG_NAME="$1" + echo "log name is $LOG_NAME" + ;; + -d | --dataset ) + shift + DATASET="$1" + echo "dataset is : $DATASET" + ;; + -b | --batch_size ) + shift + BATCH_SIZE="$1" + echo "batch size per instance is : $BATCH_SIZE" + ;; + -s | --sequence_len ) + shift + SEQUENCE_LEN="$1" + echo "sequence_len is : $SEQUENCE_LEN" + ;; + --bf16_ipex_ft ) + BF16_IPEX_FT=1 + echo "bf16_ipex_ft is : $BF16_IPEX_FT" + ;; + --fp32_ipex_ft ) + FP32_IPEX_FT=1 + echo "fp32_ipex_ft is : $FP32_IPEX_FT" + ;; + -h | --help ) + echo "Usage: ./train_native.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --bf16_ipex_ft - wether to use bf16_ipex_ft precision" + echo " --fp32_ipex_ft - wether to use fp32_ipex_ft precision" + echo " -h | --help - displays this message" + exit + ;; + * ) + echo "Invalid option: $1" + echo "Usage: train_native.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --bf16_ipex_ft - wether to use bf16_ipex_ft precision" + echo " --fp32_ipex_ft - wether to use fp32_ipex_ft precision" + exit + ;; + esac + shift +done + +if [ -z "$LOG_NAME" ]; then + pre=`date "+%m%d-%H%M"` +else + pre=$LOG_NAME +fi + +OUTPUT_DIR=$OUTPUT_DIR'/'$pre'/'$DATASET +echo $OUTPUT_DIR + +mkdir -p $OUTPUT_DIR + + +export CUDA_VISIBLE_DEVICES="-1"; \ +python ./src/run_pt_native.py \ + --model_name_or_path $MODEL_NAME_OR_PATH \ + --dataset $DATASET \ + --bf16_ipex_ft $BF16_IPEX_FT \ + --fp32_ipex_ft $FP32_IPEX_FT \ + --output_dir $OUTPUT_DIR/output_test \ + --max_seq_len $SEQUENCE_LEN \ + --num_train_epochs $TRAIN_EPOCH \ + --do_train \ + --per_device_train_batch_size $BATCH_SIZE \ + --do_predict \ + --per_device_eval_batch_size 8 \ + 2>&1 | tee $OUTPUT_DIR/test_$i.log + + diff --git a/profiling-transformers/fine-tuning/train_trainer.sh b/profiling-transformers/fine-tuning/train_trainer.sh new file mode 100755 index 0000000..ece76b0 --- /dev/null +++ b/profiling-transformers/fine-tuning/train_trainer.sh @@ -0,0 +1,115 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +export LOG_NAME=`date "+%m%d-%H%M"` +export DATASET="sst2" +export BATCH_SIZE=32 +export SEQUENCE_LEN=55 +export BF16="" +export USE_IPEX="" +export TRAIN_EPOCH=1 +export MODEL_NAME_OR_PATH="bert-large-uncased" +export OUTPUT_DIR="${OUTPUT_DIR:-./logs}" + +while [ "$1" != "" ]; +do + case $1 in + -l | --log_name ) + shift + LOG_NAME="$1" + echo "log name is $LOG_NAME" + ;; + -d | --dataset ) + shift + DATASET="$1" + echo "dataset is : $DATASET" + ;; + -b | --batch_size ) + shift + BATCH_SIZE="$1" + echo "batch size per instance is : $BATCH_SIZE" + ;; + -s | --sequence_len ) + shift + SEQUENCE_LEN="$1" + echo "sequence_len is : $SEQUENCE_LEN" + ;; + --bf16 ) + BF16="--bf16" + echo "use bf16" + ;; + --use_ipex ) + USE_IPEX=1 + echo "use_ipex is : $USE_IPEX" + ;; + -h | --help ) + echo "Usage: ./fine-tuning/train_trainer.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --bf16 - whether using hf bf16 inference" + echo " --use_ipex - whether using ipex" + echo " -h | --help - displays this message" + exit + ;; + * ) + echo "Invalid option: $1" + echo "Usage: ./fine-tuning/train_trainer.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --bf16 - whether using hf bf16 inference" + echo " --use_ipex - whether using ipex" + exit + ;; + esac + shift +done + +if [ -z "$LOG_NAME" ]; then + pre=`date "+%m%d-%H%M"` +else + pre=$LOG_NAME +fi + +OUTPUT_DIR=$OUTPUT_DIR'/'$pre'/'$DATASET +echo $OUTPUT_DIR + +mkdir -p $OUTPUT_DIR + + +export CUDA_VISIBLE_DEVICES="-1"; \ +python ./src/run_pt.py \ + --model_name_or_path $MODEL_NAME_OR_PATH \ + --dataset $DATASET \ + --output_dir $OUTPUT_DIR/output_test \ + --max_seq_len $SEQUENCE_LEN \ + --num_train_epochs $TRAIN_EPOCH \ + --do_train \ + --per_device_train_batch_size $BATCH_SIZE \ + --do_predict \ + --per_device_eval_batch_size 8 \ + --no_cuda \ + $BF16 \ + $USE_IPEX \ + 2>&1 | tee $OUTPUT_DIR/test_$i.log + + diff --git a/profiling-transformers/inference/cpu_multi_instance.sh b/profiling-transformers/inference/cpu_multi_instance.sh new file mode 100755 index 0000000..807ed99 --- /dev/null +++ b/profiling-transformers/inference/cpu_multi_instance.sh @@ -0,0 +1,193 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +export KMP_SETTINGS=1 +export KMP_BLOCKTIME=1 +export OMP_MAX_ACTIVE_LEVELS=1 + +export LOG_NAME=`date "+%m%d-%H%M"` +export DATASET="sst2" +export NUMBER_OF_INSTANCE_PER_SOCKET=1 +export BATCH_SIZE=8 +export SEQUENCE_LEN=55 +export MODEL_NAME_OR_PATH="${MODEL_NAME_OR_PATH:-bert-large-uncased}" +export OUTPUT_DIR="${OUTPUT_DIR:-./logs}" +export USE_IPEX="" +export BF16="" + + +while [ "$1" != "" ]; +do + case $1 in + -l | --log_name ) + shift + LOG_NAME="$1" + echo "log name is $LOG_NAME" + ;; + -d | --dataset ) + shift + DATASET="$1" + echo "dataset is : $DATASET" + ;; + -n | --num_of_ins_per_socket ) + shift + NUMBER_OF_INSTANCE_PER_SOCKET="$1" + echo "number_of_instance_per_socket is : $NUMBER_OF_INSTANCE_PER_SOCKET" + ;; +# -c | --cores_per_instance ) +# shift +# cores_per_instance="$1" +# echo "cores_per_instance is : $cores_per_instance" +# ;; + -b | --batch_size ) + shift + BATCH_SIZE="$1" + echo "batch size per instance is : $BATCH_SIZE" + ;; + -s | --sequence_len ) + shift + SEQUENCE_LEN="$1" + echo "sequence_len is : $SEQUENCE_LEN" + ;; + --use_ipex ) + USE_IPEX="--use_ipex" + echo " use ipex" + ;; + --bf16 ) + BF16="--bf16" + echo "using hf bf16 inference" + ;; + -h | --help ) + echo "Usage: ./inference/cpu_multi_instance.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -n | --num_of_ins_per_socket - number of instance per socket" +# echo " -c | --cores_per_instance - cores per instance" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --bf16 - whether using hf bf16 inference" + echo " --use_ipex - whether using ipex" + echo " -h | --help - displays this message" + exit + ;; + * ) + echo "Invalid option: $1" + echo "Usage: inference/cpu_multi_instance.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -n | --num_of_ins_per_socket - number of instance per socket" +# echo " -c | --cores_per_instance - cores per instance" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --bf16 - whether using hf bf16 inference" + echo " --use_ipex - whether using ipex" + exit + ;; + esac + shift +done + +if [ -z "$LOG_NAME" ]; then + pre=`date "+%m%d-%H%M"` +else + pre=$LOG_NAME +fi + +if [ -z "$DATASET" ]; then + echo "Error: Please enter the DATASET ot use [imdb|sst2]" + exit +elif [ $DATASET != "imdb" -a $DATASET != "sst2" ]; then + echo "Error: The DATASET $DATASET cannot be recognized, please enter 'imdb' or 'sst2'" + exit +fi + +if [ -z "$NUMBER_OF_INSTANCE_PER_SOCKET" ]; then + echo "Error: Please set the instance number per socket using -n or --num_of_ins_per_socket" + exit +fi + +#if [ -z "$cores_per_instance" ]; then +# echo "Please set the core number per instance using -c or --cores_per_instance" +# exit +#fi + +if [ -z "$BATCH_SIZE" ]; then + echo "Error: Please set the batch size per instance using -b or --BATCH_SIZE" + exit +fi + +if [ -z $SEQUENCE_LEN ]; then + if [ $DATASET = 'imdb' ]; then + SEQUENCE_LEN=512 + elif [ $DATASET = 'sst2' ]; then + SEQUENCE_LEN=55 + fi + echo "WARNING: SEQUENCE_LEN is not set, using default DATASET ($DATASET) sequence length $SEQUENCE_LEN" +fi + + +all_core_number=`cat /proc/cpuinfo |grep "processor"|wc -l` +socket_number=`lscpu | grep "Socket(s)" | awk '{print $2}'` +core_number_per_socket=$(($all_core_number / $socket_number)) +instance_number=$(($NUMBER_OF_INSTANCE_PER_SOCKET * $socket_number)) + +if [ $(($core_number_per_socket % $NUMBER_OF_INSTANCE_PER_SOCKET)) != 0 ]; then + echo "\`instance_numberi_per_socket($NUMBER_OF_INSTANCE_PER_SOCKET)\` cannot be divisible by \`core_number_per_socket($core_number_per_socket)\`" + exit +else + cores_per_instance=$(($core_number_per_socket / $NUMBER_OF_INSTANCE_PER_SOCKET)) +fi + +if [ $DATASET = 'imdb' ]; then + max_test_samples=$((25000/$instance_number)) +else + max_test_samples=$((872/$instance_number)) +fi + +OUTPUT_DIR=$OUTPUT_DIR'/'$pre'/'$DATASET +echo "log directory is $OUTPUT_DIR" +mkdir -p $OUTPUT_DIR + + +for i in $(seq 1 $instance_number) +do + export OMP_NUM_THREADS=$cores_per_instance + start_index=$(( ($i-1) * $cores_per_instance)) + end_index=$(( ($i * $cores_per_instance) -1)) + mem_bind=$(( $start_index / $core_number_per_socket)) + echo "\`start core index\` is $start_index" + echo "\`end core index \` is $end_index" + echo "\`memory bind\` is $mem_bind" + str="numactl -C $start_index-$end_index -m $mem_bind" + echo $str + nohup numactl -C $start_index-$end_index -m $mem_bind python ./src/run_pt.py \ + --model_name_or_path $MODEL_NAME_OR_PATH \ + --dataset $DATASET \ + --multi_instance \ + --output_dir $OUTPUT_DIR/output_test \ + --do_predict \ + --max_seq_len $SEQUENCE_LEN \ + --instance_index $i \ + --max_test_samples $max_test_samples \ + --per_device_eval_batch_size $BATCH_SIZE \ + --no_cuda \ + $USE_IPEX \ + $BF16 \ + > $OUTPUT_DIR/test_$i.log 2>&1 & +done diff --git a/profiling-transformers/inference/cpu_single_instance.sh b/profiling-transformers/inference/cpu_single_instance.sh new file mode 100755 index 0000000..cb61c4f --- /dev/null +++ b/profiling-transformers/inference/cpu_single_instance.sh @@ -0,0 +1,111 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# +# +# export CUDA_VISIBLE_DEVICES="-1"; \ +export LOG_NAME=`date "+%m%d-%H%M"` +export DATASET="sst2" +export BATCH_SIZE=8 +export SEQUENCE_LEN=55 +export MODEL_NAME_OR_PATH="${MODEL_NAME_OR_PATH:-bert-large-uncased}" +export OUTPUT_DIR="${OUTPUT_DIR:-./logs}" +export USE_IPEX="" +export BF16="" + +while [ "$1" != "" ]; +do + case $1 in + -l | --log_name ) + shift + LOG_NAME="$1" + echo "log name is $LOG_NAME" + ;; + -d | --dataset ) + shift + DATASET="$1" + echo "dataset is : $DATASET" + ;; + -b | --batch_size ) + shift + BATCH_SIZE="$1" + echo "batch size per instance is : $BATCH_SIZE" + ;; + -s | --sequence_len ) + shift + SEQUENCE_LEN="$1" + echo "sequence_len is : $SEQUENCE_LEN" + ;; + --use_ipex ) + USE_IPEX="--use_ipex" + echo " use ipex" + ;; + --bf16 ) + BF16="--bf16" + echo "using hf bf16 inference" + ;; + -h | --help ) + echo "Usage: ./inference/cpu_single_instance.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --bf16 - whether using hf bf16 inference" + echo " --use_ipex - whether using ipex" + echo " -h | --help - displays this message" + exit + ;; + * ) + echo "Invalid option: $1" + echo "Usage: ./inference/cpu_single_instance.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --bf16 - whether using hf bf16 inference" + echo " --use_ipex - whether using ipex" + exit + ;; + esac + shift +done + +if [ -z "$LOG_NAME" ]; then + pre=`date "+%m%d-%H%M"` +else + pre=$LOG_NAME +fi + +OUTPUT_DIR=$OUTPUT_DIR'/'$pre'/'$DATASET +echo $OUTPUT_DIR + +mkdir -p $OUTPUT_DIR + + +export CUDA_VISIBLE_DEVICES="-1"; \ +python ./src/run_pt.py \ + --model_name_or_path $MODEL_NAME_OR_PATH \ + --dataset $DATASET \ + --output_dir $OUTPUT_DIR/output_test \ + --do_predict \ + --max_seq_len $SEQUENCE_LEN \ + --per_device_eval_batch_size $BATCH_SIZE \ + --no_cuda \ + $USE_IPEX \ + $BF16 \ + 2>&1 | tee $OUTPUT_DIR/test_$i.log + diff --git a/profiling-transformers/inference/multi_instance.sh b/profiling-transformers/inference/multi_instance.sh new file mode 100755 index 0000000..c5f7965 --- /dev/null +++ b/profiling-transformers/inference/multi_instance.sh @@ -0,0 +1,219 @@ +#!/bin/bash +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# +export KMP_SETTINGS=1 +export KMP_BLOCKTIME=1 +export OMP_MAX_ACTIVE_LEVELS=1 + +export LOG_NAME=`date "+%m%d-%H%M"` +export DATASET="sst2" +export NUMBER_OF_INSTANCE_PER_SOCKET=1 +export BATCH_SIZE=8 +export SEQUENCE_LEN=55 +export IPEX_BF16=0 +export IPEX_FP32=0 +export INT8=0 +export INT8_BF16=0 +export MODEL_NAME_OR_PATH="${MODEL_NAME_OR_PATH:-bert-large-uncased}" +export OUTPUT_DIR="${OUTPUT_DIR:-./logs}" + +while [ "$1" != "" ]; +do + case $1 in + -l | --log_name ) + shift + LOG_NAME="$1" + echo "log name is $LOG_NAME" + ;; + -d | --dataset ) + shift + DATASET="$1" + echo "dataset is : $DATASET" + ;; + -n | --num_of_ins_per_socket ) + shift + NUMBER_OF_INSTANCE_PER_SOCKET="$1" + echo "number_of_instance_per_socket is : $NUMBER_OF_INSTANCE_PER_SOCKET" + ;; +# -c | --cores_per_instance ) +# shift +# cores_per_instance="$1" +# echo "cores_per_instance is : $cores_per_instance" +# ;; + -b | --batch_size ) + shift + BATCH_SIZE="$1" + echo "batch size per instance is : $BATCH_SIZE" + ;; + -s | --sequence_len ) + shift + SEQUENCE_LEN="$1" + echo "sequence_len is : $SEQUENCE_LEN" + ;; + --ipex_bf16 ) + IPEX_BF16=1 + echo "ipex_bf16 is : $IPEX_BF16" + ;; + --ipex_fp32 ) + IPEX_FP32=1 + echo "ipex_fp32 is : $IPEX_FP32" + ;; + --int8 ) + INT8=1 + echo "int8 is : $INT8" + ;; + --int8_bf16 ) + INT8_BF16=1 + echo "int8_bf16 is : $INT8_BF16" + ;; + -h | --help ) + echo "Usage: ./inference/multi_instance.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -n | --num_of_ins_per_socket - number of instance per socket" +# echo " -c | --cores_per_instance - cores per instance" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --ipex_bf16 - wether to use ipex_bf16 precision" + echo " --ipex_fp32 - wether to use ipex_fp32 precision" + echo " --int8 - wether to use int8 precision" + echo " --int8_bf16 - wether to use int8_bf16 precision" + echo " -h | --help - displays this message" + exit + ;; + * ) + echo "Invalid option: $1" + echo "Usage: inference/multi_instance.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -n | --num_of_ins_per_socket - number of instance per socket" +# echo " -c | --cores_per_instance - cores per instance" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --ipex_bf16 - wether to use ipex_bf16 precision" + echo " --ipex_fp32 - wether to use ipex_fp32 precision" + echo " --int8 - wether to use int8 precision" + echo " --int8_bf16 - wether to use int8_bf16 precision" + exit + ;; + esac + shift +done + +if [ -z "$LOG_NAME" ]; then + pre=`date "+%m%d-%H%M"` +else + pre=$LOG_NAME +fi + +if [ -z "$DATASET" ]; then + echo "Error: Please enter the DATASET ot use [imdb|sst2]" + exit +elif [ $DATASET != "imdb" -a $DATASET != "sst2" ]; then + echo "Error: The DATASET $DATASET cannot be recognized, please enter 'imdb' or 'sst2'" + exit +fi + +if [ -z "$NUMBER_OF_INSTANCE_PER_SOCKET" ]; then + echo "Error: Please set the instance number per socket using -n or --num_of_ins_per_socket" + exit +fi + +#if [ -z "$cores_per_instance" ]; then +# echo "Please set the core number per instance using -c or --cores_per_instance" +# exit +#fi + +if [ $IPEX_BF16 = 1 ]; then + if [ $INT8 = 1 -o $INT8_BF16 = 1 ]; then + echo "Error: Cannot set IPEX_BF16 and INT8 at the same time" + exit + fi +else + if [ $INT8 = 0 -a $INT8_BF16 = 1 ]; then + echo "Error: Cannot set INT8_BF16 without INT8 option" + exit + fi +fi + +if [ -z "$BATCH_SIZE" ]; then + echo "Error: Please set the batch size per instance using -b or --BATCH_SIZE" + exit +fi + +if [ -z $SEQUENCE_LEN ]; then + if [ $DATASET = 'imdb' ]; then + SEQUENCE_LEN=512 + elif [ $DATASET = 'sst2' ]; then + SEQUENCE_LEN=55 + fi + echo "WARNING: SEQUENCE_LEN is not set, using default DATASET ($DATASET) sequence length $SEQUENCE_LEN" +fi + + +all_core_number=`cat /proc/cpuinfo |grep "processor"|wc -l` +socket_number=`lscpu | grep "Socket(s)" | awk '{print $2}'` +core_number_per_socket=$(($all_core_number / $socket_number)) +instance_number=$(($NUMBER_OF_INSTANCE_PER_SOCKET * $socket_number)) + +if [ $(($core_number_per_socket % $NUMBER_OF_INSTANCE_PER_SOCKET)) != 0 ]; then + echo "\`instance_numberi_per_socket($NUMBER_OF_INSTANCE_PER_SOCKET)\` cannot be divisible by \`core_number_per_socket($core_number_per_socket)\`" + exit +else + cores_per_instance=$(($core_number_per_socket / $NUMBER_OF_INSTANCE_PER_SOCKET)) +fi + +if [ $DATASET = 'imdb' ]; then + max_test_samples=$((25000/$instance_number)) +else + max_test_samples=$((872/$instance_number)) +fi + +OUTPUT_DIR=$OUTPUT_DIR'/'$pre'/'$DATASET +echo "log directory is $OUTPUT_DIR" +mkdir -p $OUTPUT_DIR + + +for i in $(seq 1 $instance_number) +do + export OMP_NUM_THREADS=$cores_per_instance + start_index=$(( ($i-1) * $cores_per_instance)) + end_index=$(( ($i * $cores_per_instance) -1)) + mem_bind=$(( $start_index / $core_number_per_socket)) + echo "\`start core index\` is $start_index" + echo "\`end core index \` is $end_index" + echo "\`memory bind\` is $mem_bind" + str="numactl -C $start_index-$end_index -m $mem_bind" + echo $str + nohup numactl -C $start_index-$end_index -m $mem_bind python ./src/run_pt_native_inf.py \ + --model_name_or_path $MODEL_NAME_OR_PATH \ + --dataset $DATASET \ + --int8 $INT8 \ + --int8_bf16 $INT8_BF16 \ + --ipex_bf16 $IPEX_BF16 \ + --ipex_fp32 $IPEX_FP32 \ + --multi_instance \ + --output_dir $OUTPUT_DIR/output_test \ + --do_predict \ + --max_seq_len $SEQUENCE_LEN \ + --instance_index $i \ + --max_test_samples $max_test_samples \ + --per_device_eval_batch_size $BATCH_SIZE \ + > $OUTPUT_DIR/test_$i.log 2>&1 & +done diff --git a/profiling-transformers/inference/single_instance.sh b/profiling-transformers/inference/single_instance.sh new file mode 100755 index 0000000..ea01f64 --- /dev/null +++ b/profiling-transformers/inference/single_instance.sh @@ -0,0 +1,126 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +export LOG_NAME=`date "+%m%d-%H%M"` +export DATASET="sst2" +export BATCH_SIZE=8 +export SEQUENCE_LEN=55 +export IPEX_BF16=0 +export IPEX_FP32=0 +export INT8=0 +export INT8_BF16=0 +export MODEL_NAME_OR_PATH="${MODEL_NAME_OR_PATH:-bert-large-uncased}" +export OUTPUT_DIR="${OUTPUT_DIR:-./logs}" + +while [ "$1" != "" ]; +do + case $1 in + -l | --log_name ) + shift + LOG_NAME="$1" + echo "log name is $LOG_NAME" + ;; + -d | --dataset ) + shift + DATASET="$1" + echo "dataset is : $DATASET" + ;; + -b | --batch_size ) + shift + BATCH_SIZE="$1" + echo "batch size per instance is : $BATCH_SIZE" + ;; + -s | --sequence_len ) + shift + SEQUENCE_LEN="$1" + echo "sequence_len is : $SEQUENCE_LEN" + ;; + --ipex_bf16 ) + IPEX_BF16=1 + echo "ipex_bf16 is : $IPEX_BF16" + ;; + --ipex_fp32 ) + IPEX_FP32=1 + echo "ipex_fp32 is : $IPEX_FP32" + ;; + --int8 ) + INT8=1 + echo "int8 is : $INT8" + ;; + --int8_bf16 ) + INT8_BF16=1 + echo "int8_bf16 is : $INT8_BF16" + ;; + -h | --help ) + echo "Usage: ././inference/single_instance.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --ipex_bf16 - wether to use ipex_bf16 precision" + echo " --ipex_fp32 - wether to use ipex_fp32 precision" + echo " --int8 - wether to use int8 precision" + echo " --int8_bf16 - wether to use int8_bf16 precision" + echo " -h | --help - displays this message" + exit + ;; + * ) + echo "Invalid option: $1" + echo "Usage: ./inference/single_instance.sh [OPTIONS]" + echo "OPTION includes:" + echo " -l | --log_name - the log name of this round" + echo " -d | --dataset - [imdb|sst2] wether to use imdb or sst2 DATASET" + echo " -b | --batch_size - batch size per instance" + echo " -s | --sequence_len - max sequence length" + echo " --ipex_bf16 - wether to use ipex_bf16 precision" + echo " --ipex_fp32 - wether to use ipex_fp32 precision" + echo " --int8 - wether to use int8 precision" + echo " --int8_bf16 - wether to use int8_bf16 precision" + exit + ;; + esac + shift +done + +if [ -z "$LOG_NAME" ]; then + pre=`date "+%m%d-%H%M"` +else + pre=$LOG_NAME +fi + +OUTPUT_DIR=$OUTPUT_DIR'/'$pre'/'$DATASET +echo $OUTPUT_DIR + +mkdir -p $OUTPUT_DIR + + +export CUDA_VISIBLE_DEVICES="-1"; \ +python ./src/run_pt_native_inf.py \ + --model_name_or_path $MODEL_NAME_OR_PATH \ + --dataset $DATASET \ + --int8 $INT8 \ + --int8_bf16 $INT8_BF16 \ + --ipex_bf16 $IPEX_BF16 \ + --ipex_fp32 $IPEX_FP32 \ + --output_dir $OUTPUT_DIR/output_test \ + --do_predict \ + --max_seq_len $SEQUENCE_LEN \ + --per_device_eval_batch_size $BATCH_SIZE \ + 2>&1 | tee $OUTPUT_DIR/test_$i.log + + diff --git a/profiling-transformers/install.sh b/profiling-transformers/install.sh new file mode 100755 index 0000000..4bb6d1f --- /dev/null +++ b/profiling-transformers/install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/bash +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# +conda install -y pytorch==1.12.1 torchvision torchaudio cpuonly intel-openmp gperftools ninja setuptools tqdm future cmake numpy pyyaml scikit-learn pydot -c pytorch -c intel -c conda-forge +pip install transformers==4.21.1 datasets==2.3.2 intel_extension_for_pytorch +bash deploy/install_torch_ccl.sh \ No newline at end of file diff --git a/profiling-transformers/src/__init__.py b/profiling-transformers/src/__init__.py new file mode 100644 index 0000000..356ca7b --- /dev/null +++ b/profiling-transformers/src/__init__.py @@ -0,0 +1,16 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# diff --git a/profiling-transformers/src/run_pt.py b/profiling-transformers/src/run_pt.py new file mode 100644 index 0000000..7e5010b --- /dev/null +++ b/profiling-transformers/src/run_pt.py @@ -0,0 +1,137 @@ +# Copyright (C) 2022 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions +# and limitations under the License. +# + +# + +import logging + +from datasets import load_dataset +from transformers import ( + logging as hf_logging, + HfArgumentParser, + AutoTokenizer, + AutoModelForSequenceClassification, + Trainer, + TrainingArguments, +) + +from utils import ( + Arguments, + Benchmark, + compute_metrics, + save_train_metrics, + save_test_metrics, + check_dataset +) + +hf_logging.set_verbosity_info() +logger = logging.getLogger(__name__) + + +def main(): + # See all possible arguments in src/transformers/training_args.py + # or by passing the --help flag to this script. + parser = HfArgumentParser((Arguments, TrainingArguments)) + args, training_args = parser.parse_args_into_dataclasses() + + max_train, max_test = args.max_train_samples, args.max_test_samples + if args.smoke_test: + training_args.max_steps = 3 + max_train, max_test = 10, 10 + + bench = Benchmark() + track = bench.track + with track('Total Run'): + ############################ Load Data #################################### + with track('Load Data'): + data = load_dataset(*check_dataset(args.dataset)) + train_all = data['train'] + test_split = 'validation' if args.dataset == 'sst2' else 'test' + len_train = len(train_all) + train_data = train_all.select(range(len_train - max_train, len_train)) if max_train else train_all + + # split the Test Data for multi-instance + if args.multi_instance: + start_index = (args.instance_index - 1) * args.max_test_samples + end_index = args.instance_index * args.max_test_samples + test_data = data[test_split].select(range(start_index, end_index)) + print("start_index is ", start_index) + print("end_index is ", end_index) + print("test length is ", len(test_data)) + else: + test_data = data[test_split].select(range(max_test)) if max_test else data[test_split] + + text_column = [c for c in test_data.column_names if type(test_data[c][0]) != int][0] + + ############################### Pre-process ############################### + with track('Pre-process'): + with track('----Init tokenizer'): + tokenizer = AutoTokenizer.from_pretrained( + args.tokenizer_name if args.tokenizer_name else args.model_name_or_path + ) + + max_seq_len = min(args.max_seq_len, tokenizer.model_max_length) + + with track('----Tokenize + Extract Features'): + def preprocess(examples): + return tokenizer( + examples[text_column], + padding='max_length', + truncation=True, + max_length=max_seq_len + ) + + kwargs = dict( + function=preprocess, + batched=True, + num_proc=args.preprocessing_num_workers, + remove_columns=[text_column] + (['idx'] if args.dataset == 'sst2' else []), + load_from_cache_file=not args.overwrite_cache) + + train_data = train_data.map(**kwargs) if training_args.do_train else None + test_data = test_data.map(**kwargs) if training_args.do_predict else None + + ###################### Load Model and Trainer ############################ + with track('Load Model'): + model = AutoModelForSequenceClassification.from_pretrained(args.model_name_or_path) + + trainer = Trainer( + model=model, # the instantiated HF model to be trained + args=training_args, # training arguments, defined above + train_dataset=train_data, # training dataset + compute_metrics=compute_metrics, # evaluation metrics + tokenizer=tokenizer + ) + + ############################### Fine-Tune ################################# + if training_args.do_train: + with track('Fine-Tune'): + train_result = trainer.train() + trainer.save_model() + save_train_metrics(train_result, trainer, len(train_data)) + + ############################### Inference ################################# + test_metrics = "" + if training_args.do_predict: + with track('Inference'): + preds, _, metrics = trainer.predict(test_data) + test_metrics = save_test_metrics(metrics, len(test_data), training_args.output_dir) + + bench.summary() + print(test_metrics) + + +if __name__ == "__main__": + main() diff --git a/profiling-transformers/src/run_pt_native.py b/profiling-transformers/src/run_pt_native.py new file mode 100644 index 0000000..108abaf --- /dev/null +++ b/profiling-transformers/src/run_pt_native.py @@ -0,0 +1,249 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +from pathlib import Path +import os +import logging +from tqdm import tqdm + +import numpy as np +import torch +from torch.utils.data import DataLoader +from torch import tensor + +try: + import intel_extension_for_pytorch as ipex +finally: + pass + +import transformers +from transformers import ( + HfArgumentParser, + AutoTokenizer, + AutoModelForSequenceClassification, + TrainingArguments, +) + +from utils import ( + Arguments, + read_dataset, + to_tensor_dataset, + Benchmark, + compute_metrics, + PredsLabels +) + +transformers.logging.set_verbosity_info() + +logger = logging.getLogger(__name__) + + +def main(): + # See all possible arguments in src/transformers/training_args.py + # or by passing the --help flag to this script. + + parser = HfArgumentParser((Arguments, TrainingArguments)) + args, training_args = parser.parse_args_into_dataclasses() + output_dir = Path(training_args.output_dir) + os.makedirs(output_dir, exist_ok=True) + bench = Benchmark() + track = bench.track + + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + def to_inputs(batch: dict) -> dict: + return {k: (v if torch.is_tensor(v) else tensor(v)).to(device=device) \ + for k, v in batch.items()} + + ################################# Load Data ################################# + + with track('Load Data'): + if training_args.do_train: + # Train Data + train_texts, train_labels = read_dataset(args.dataset, 'train') + max_train = args.max_train_samples if args.max_train_samples else len(train_texts) + if args.smoke_test: + training_args.max_steps = 3 + training_args.num_train_epochs = 1 + max_train = 104 + train_texts, train_labels = train_texts[:max_train], train_labels[:max_train] + + if training_args.do_predict: + max_test = 100 if args.smoke_test else (args.max_test_samples if args.max_test_samples else None) + + if not args.real_time: + # Test Data + test_texts, test_labels = read_dataset(args.dataset, 'test') + if args.multi_instance: + start_index = (args.instance_index - 1) * args.max_test_samples + end_index = args.instance_index * args.max_test_samples + test_texts, test_labels = test_texts[start_index:end_index], test_labels[start_index:end_index] + print("start_index is ", start_index) + print("end_index is ", end_index) + print("test text length is ", len(test_texts)) + print("test labels length is ", len(test_labels)) + else: + test_texts, test_labels = test_texts[:max_test], test_labels[:max_test] + + ################################# Pre-process ################################# + with track('Pre-process'): + with track('----Init tokenizer'): + # Tokenization + Feature Extraction + tokenizer = AutoTokenizer.from_pretrained( + args.tokenizer_name if args.tokenizer_name else args.model_name_or_path + ) + max_seq_len = min(args.max_seq_len, tokenizer.model_max_length) + token_args = dict(truncation=True, padding=True, max_length=max_seq_len) + + if training_args.do_train: + with track('----Training data encoding'): + train_encodings = tokenizer(train_texts, **token_args) + with track('----Training tensor data convert'): + train_dataset = to_tensor_dataset('pt', train_encodings, train_labels) + + if training_args.do_predict and not args.real_time: + with track('----PyTorch test data encoding'): + test_encodings = tokenizer(test_texts, padding='max_length', max_length=max_seq_len, + truncation=True) + with track('----PyTorch test tensor data convert'): + test_dataset = to_tensor_dataset('pt', test_encodings, test_labels) + + ################################# Load Model ################################# + if training_args.do_train or not args.torchscript: + with track('Load Model'): + if args.bf16_ipex_ft: + with torch.cpu.amp.autocast(): + model = AutoModelForSequenceClassification \ + .from_pretrained(args.model_name_or_path) \ + .to(device=device) + model = ipex.optimize(model, dtype=torch.bfloat16, level='O0') + else: + model = AutoModelForSequenceClassification \ + .from_pretrained(args.model_name_or_path) \ + .to(device=device) + + if args.fp32_ipex_ft: + model = ipex.optimize(model, dtype=torch.float32, level='O1') + + with track("Process int8 model"): + if args.int8: + # convert fp32 model to int8 + ipex.nn.utils._model_convert.replace_dropout_with_identity(model) + conf = ipex.quantization.QuantConf(configure_file=args.model_name_or_path + "/configure.json") + dumpy_tensor = torch.ones((training_args.per_device_eval_batch_size, max_seq_len), dtype=torch.long) + jit_inputs = (dumpy_tensor, dumpy_tensor, dumpy_tensor) + if args.int8_bf16: + with torch.cpu.amp.autocast(): + model = ipex.quantization.convert(model, conf, jit_inputs) + else: + model = ipex.quantization.convert(model, conf, jit_inputs) + with torch.no_grad(): + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + + with track("Process bf16 model"): + if args.ipex_bf16: + # convert fp32 model to bf16 + with torch.cpu.amp.autocast(), torch.no_grad(): + torch.jit.load('imdb_bf16model.pt') + model = ipex.optimize(model, dtype=torch.bfloat16, level='O0') + dumpy_tensor = torch.ones((training_args.per_device_eval_batch_size, max_seq_len), dtype=torch.long) + jit_inputs = (dumpy_tensor, dumpy_tensor, dumpy_tensor) + with torch.cpu.amp.autocast(), torch.no_grad(): + model = torch.jit.trace(model, jit_inputs, strict=False) + model = torch.jit.freeze(model) + with torch.no_grad(): + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + + ################################ Fine-Tune ################################# + if training_args.do_train: + with track('Fine-Tune'): + with track('--------Init Fine-Tuning'): + batch_size = training_args.per_device_train_batch_size + model.train() + weight_decay = 0.0 + no_decay = ["bias", "LayerNorm.weight"] + optimizer_grouped_parameters = [ + { + "params": [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)], + "weight_decay": weight_decay, + }, + { + "params": [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)], + "weight_decay": 0.0, + }, + ] + optim = torch.optim.AdamW(optimizer_grouped_parameters, lr=training_args.learning_rate) + + with track('--------Training Loop'): + for _ in tqdm(range(int(training_args.num_train_epochs)), desc='Epoch'): + for batch in tqdm(DataLoader(train_dataset, batch_size=batch_size, shuffle=True), + desc='Train Step'): + optim.zero_grad() + loss = model(**to_inputs(batch))[0] + loss.backward() + optim.step() + + with track('--------Save Fine-Tuned Model'): + if args.torchscript: + with track('--------Save TorchScript model'): + model.eval() + batch = to_inputs(batch) + traced_model = torch.jit.trace(model, [batch['input_ids'], batch['attention_mask']]) + torch.jit.save(traced_model, output_dir / "traced_model.pt") + else: + torch.save(model.state_dict(), output_dir / "pytorch_model.bin") + + ############################### Inference ################################# + if training_args.do_predict: + with track('Inference'): + if args.torchscript: + with track('--------Load TorchScript model'): + model_path = output_dir if training_args.do_train else Path(args.model_name_or_path) + model = torch.jit.load(model_path / "traced_model.pt").to(device=device) + + batch_size = training_args.per_device_eval_batch_size + all_outputs, all_labels = [], [] + + def prediction_step(batch, labels): + all_labels.extend(labels) + inputs = to_inputs(batch) + output = model(inputs['input_ids'], inputs['attention_mask']) if args.torchscript \ + else model(**inputs) + all_outputs.append(output['logits'].detach().cpu()) + + model.eval() + with torch.no_grad(): + if args.real_time: + data_generator = read_dataset(args.dataset, 'test', generator=True, \ + batch_size=batch_size, max_samples=max_test) + + for texts, labels in tqdm(data_generator, desc='Test Step'): + prediction_step(batch=tokenizer(texts, **token_args), labels=labels) + + else: + for batch in tqdm(DataLoader(test_dataset, batch_size=batch_size), desc='Test Step'): + prediction_step(batch=batch, labels=batch.pop('labels')) + acc = compute_metrics(PredsLabels(preds=np.concatenate(all_outputs), labels=all_labels)) + print(f"\n*********** TEST_METRICS ***********\nAccuracy: {acc['acc']}\n") + + bench.summary() + + +if __name__ == "__main__": + main() diff --git a/profiling-transformers/src/run_pt_native_ft.py b/profiling-transformers/src/run_pt_native_ft.py new file mode 100644 index 0000000..1040ced --- /dev/null +++ b/profiling-transformers/src/run_pt_native_ft.py @@ -0,0 +1,286 @@ +# Copyright (C) 2022 Intel Corporation +# +# 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. +# + +# + +from pathlib import Path +import os +import logging +from tqdm import tqdm + +import numpy as np +import torch +from torch.utils.data import DataLoader, RandomSampler +from torch.utils.data.distributed import DistributedSampler +from torch import tensor + +try: + import intel_extension_for_pytorch as ipex +finally: + pass + +import transformers +from transformers import ( + HfArgumentParser, + AutoTokenizer, + AutoModelForSequenceClassification, + TrainingArguments, + set_seed, +) + +from utils import ( + Arguments, + read_dataset, + to_tensor_dataset, + Benchmark, + compute_metrics, + PredsLabels +) + +transformers.logging.set_verbosity_info() + +logger = logging.getLogger(__name__) + + +def main(): + # See all possible arguments in src/transformers/training_args.py + # or by passing the --help flag to this script. + + parser = HfArgumentParser((Arguments, TrainingArguments)) + args, training_args = parser.parse_args_into_dataclasses() + output_dir = Path(training_args.output_dir) + os.makedirs(output_dir, exist_ok=True) + bench = Benchmark() + track = bench.track + + set_seed(training_args.seed) + + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + if int(os.environ.get('PMI_SIZE', '0')) > 1 and not args.multi_instance: + if args.dist_backend == 'ccl': + try: + import oneccl_bindings_for_pytorch + except: + print("CCL backend requested but import oneccl_bindings_for_pytorch failed") + raise + elif args.dist_backend == 'mpi': + if not torch.distributed.is_mpi_available(): + try: + import torch_mpi + except: + print("MPI backend requested but not available try installing torch_mpi module") + raise + else: + raise ValueError(f"{args.dist_backend} backend requested but not supported") + + os.environ['RANK'] = os.environ.get('PMI_RANK', '0') + os.environ['WORLD_SIZE'] = os.environ.get('PMI_SIZE', '1') + torch.distributed.init_process_group(backend=args.dist_backend) + device = torch.device("cpu") + training_args.local_rank = torch.distributed.get_rank() + if training_args.local_rank == 0: print(f"##################Using {args.dist_backend.upper()} dist run with {torch.distributed.get_world_size()} ranks", flush=True) + + def to_inputs(batch: dict) -> dict: + return {k: (v if torch.is_tensor(v) else tensor(v)).to(device=device) \ + for k, v in batch.items()} + + ################################# Load Data ################################# + + with track('Load Data'): + if training_args.do_train: + # Train Data + train_texts, train_labels = read_dataset(args.dataset, 'train') + max_train = args.max_train_samples if args.max_train_samples else len(train_texts) + if args.smoke_test: + training_args.max_steps = 3 + training_args.num_train_epochs = 1 + max_train = 104 + train_texts, train_labels = train_texts[:max_train], train_labels[:max_train] + + if training_args.do_predict: + max_test = 100 if args.smoke_test else (args.max_test_samples if args.max_test_samples else None) + + if not args.real_time: + # Test Data + test_texts, test_labels = read_dataset(args.dataset, 'test') + if args.multi_instance: + start_index = (args.instance_index - 1) * args.max_test_samples + end_index = args.instance_index * args.max_test_samples + test_texts, test_labels = test_texts[start_index:end_index], test_labels[start_index:end_index] + print("start_index is ", start_index) + print("end_index is ", end_index) + print("test text length is ", len(test_texts)) + print("test labels length is ", len(test_labels)) + else: + test_texts, test_labels = test_texts[:max_test], test_labels[:max_test] + + ################################# Pre-process ################################# + with track('Pre-process'): + with track('----Init tokenizer'): + # Tokenization + Feature Extraction + tokenizer = AutoTokenizer.from_pretrained( + args.tokenizer_name if args.tokenizer_name else args.model_name_or_path + ) + max_seq_len = min(args.max_seq_len, tokenizer.model_max_length) + token_args = dict(truncation=True, padding=True, max_length=max_seq_len) + + if training_args.do_train: + with track('----Training data encoding'): + train_encodings = tokenizer(train_texts, **token_args) + with track('----Training tensor data convert'): + train_dataset = to_tensor_dataset('pt', train_encodings, train_labels) + + if training_args.do_predict and not args.real_time: + with track('----PyTorch test data encoding'): + test_encodings = tokenizer(test_texts, padding='max_length', max_length=max_seq_len, + truncation=True) + with track('----PyTorch test tensor data convert'): + test_dataset = to_tensor_dataset('pt', test_encodings, test_labels) + + ################################# Load Model ################################# + if training_args.do_train or not args.torchscript: + with track('Load Model'): + if args.bf16_ipex_ft: + with torch.cpu.amp.autocast(): + model = AutoModelForSequenceClassification \ + .from_pretrained(args.model_name_or_path) \ + .to(device=device) + model = ipex.optimize(model, dtype=torch.bfloat16, level='O0') + else: + model = AutoModelForSequenceClassification \ + .from_pretrained(args.model_name_or_path) \ + .to(device=device) + #model = AutoModelForSequenceClassification \ + # .from_pretrained(args.model_name_or_path) \ + # .to(device=device) + + with track("Process int8 model"): + if args.int8: + # convert fp32 model to int8 + ipex.nn.utils._model_convert.replace_dropout_with_identity(model) + conf = ipex.quantization.QuantConf(configure_file=args.model_name_or_path + "/configure.json") + dumpy_tensor = torch.ones((training_args.per_device_eval_batch_size, max_seq_len), dtype=torch.long) + jit_inputs = (dumpy_tensor, dumpy_tensor, dumpy_tensor) + if args.int8_bf16: + with torch.cpu.amp.autocast(): + model = ipex.quantization.convert(model, conf, jit_inputs) + else: + model = ipex.quantization.convert(model, conf, jit_inputs) + with torch.no_grad(): + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + + with track("Process bf16 model"): + if args.ipex_bf16: + # convert fp32 model to bf16 + with torch.cpu.amp.autocast(), torch.no_grad(): + torch.jit.load('imdb_bf16model.pt') + model = ipex.optimize(model, dtype=torch.bfloat16, level='O0') + dumpy_tensor = torch.ones((training_args.per_device_eval_batch_size, max_seq_len), dtype=torch.long) + jit_inputs = (dumpy_tensor, dumpy_tensor, dumpy_tensor) + with torch.cpu.amp.autocast(), torch.no_grad(): + model = torch.jit.trace(model, jit_inputs, strict=False) + model = torch.jit.freeze(model) + with torch.no_grad(): + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + + ################################ Fine-Tune ################################# + if training_args.do_train: + with track('Fine-Tune'): + with track('--------Init Fine-Tuning'): + batch_size = training_args.per_device_train_batch_size + model.train() + weight_decay = 0.0 + no_decay = ["bias", "LayerNorm.weight"] + optimizer_grouped_parameters = [ + { + "params": [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)], + "weight_decay": weight_decay, + }, + { + "params": [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)], + "weight_decay": 0.0, + }, + ] + optim = torch.optim.AdamW(optimizer_grouped_parameters, lr=training_args.learning_rate) + if training_args.local_rank != -1: + model = torch.nn.parallel.DistributedDataParallel(model) + + with track('--------Training Loop'): + train_sampler = RandomSampler(train_dataset) if training_args.local_rank == -1 else DistributedSampler(train_dataset) + + for _ in tqdm(range(int(training_args.num_train_epochs)), desc='Epoch', disable=training_args.local_rank not in [-1, 0]): + for batch in tqdm(DataLoader(train_dataset, sampler=train_sampler, batch_size=batch_size), + desc='Train Step', disable=training_args.local_rank not in [-1, 0]): + optim.zero_grad() + loss = model(**to_inputs(batch))[0] + loss.backward() + optim.step() + + with track('--------Save Fine-Tuned Model'): + if training_args.local_rank in [-1, 0]: + # Take care of DDP wrapper + model_to_save = model.module if hasattr(model, "module") else model + if args.torchscript: + with track('--------Save TorchScript model'): + model.eval() + batch = to_inputs(batch) + traced_model = torch.jit.trace(model_to_save, [batch['input_ids'], batch['attention_mask']]) + torch.jit.save(traced_model, output_dir / "traced_model.pt") + else: + torch.save(model_to_save.state_dict(), output_dir / "pytorch_model.bin") + + ############################### Inference ################################# + if training_args.do_predict: + with track('Inference'): + if args.torchscript: + with track('--------Load TorchScript model'): + model_path = output_dir if training_args.do_train else Path(args.model_name_or_path) + model = torch.jit.load(model_path / "traced_model.pt").to(device=device) + + batch_size = training_args.per_device_eval_batch_size + all_outputs, all_labels = [], [] + + def prediction_step(batch, labels): + all_labels.extend(labels) + inputs = to_inputs(batch) + output = model(inputs['input_ids'], inputs['attention_mask']) if args.torchscript \ + else model(**inputs) + all_outputs.append(output['logits'].detach().cpu()) + + model.eval() + with torch.no_grad(): + if args.real_time: + data_generator = read_dataset(args.dataset, 'test', generator=True, \ + batch_size=batch_size, max_samples=max_test) + + for texts, labels in tqdm(data_generator, desc='Test Step'): + prediction_step(batch=tokenizer(texts, **token_args), labels=labels) + + else: + test_sampler = RandomSampler(test_dataset) if training_args.local_rank == -1 else DistributedSampler(test_dataset) + + for batch in tqdm(DataLoader(test_dataset, sampler=test_sampler, batch_size=batch_size), desc='Test Step'): + prediction_step(batch=batch, labels=batch.pop('labels')) + acc = compute_metrics(PredsLabels(preds=np.concatenate(all_outputs), labels=all_labels)) + print(f"\n*********** TEST_METRICS ***********\nAccuracy: {acc['acc']}\n") + + bench.summary() + + +if __name__ == "__main__": + main() diff --git a/profiling-transformers/src/run_pt_native_inf.py b/profiling-transformers/src/run_pt_native_inf.py new file mode 100644 index 0000000..935906f --- /dev/null +++ b/profiling-transformers/src/run_pt_native_inf.py @@ -0,0 +1,223 @@ +# Copyright (C) 2022 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions +# and limitations under the License. +# + +# + +import logging +import os + +import numpy as np +import torch +from datasets import load_dataset +from torch import tensor +from torch.utils.data import DataLoader +from tqdm import tqdm + +try: + import intel_extension_for_pytorch as ipex +finally: + pass + +from transformers import ( + logging as hf_logging, + HfArgumentParser, + AutoTokenizer, + AutoModelForSequenceClassification, + TrainingArguments, + DataCollatorWithPadding +) + +from utils import ( + Arguments, + Benchmark, + compute_metrics, + PredsLabels, + check_dataset +) + +hf_logging.set_verbosity_info() +logger = logging.getLogger(__name__) + + +def main(): + # See all possible arguments in src/transformers/training_args.py + # or by passing the --help flag to this script. + parser = HfArgumentParser((Arguments, TrainingArguments)) + args, training_args = parser.parse_args_into_dataclasses() + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + max_train, max_test = args.max_train_samples, args.max_test_samples + if args.smoke_test: + training_args.max_steps = 3 + max_train, max_test = 10, 10 + + bench = Benchmark() + track = bench.track + with track('Total Run'): + ############################ Load Data #################################### + with track('Load Data'): + data = load_dataset(*check_dataset(args.dataset)) + train_all = data['train'] + test_split = 'validation' if args.dataset == 'sst2' else 'test' + len_train = len(train_all) + train_data = train_all.select(range(len_train - max_train, len_train)) if max_train else train_all + + # split the Test Data for multi-instance + if args.multi_instance: + start_index = (args.instance_index - 1) * args.max_test_samples + end_index = args.instance_index * args.max_test_samples + test_data = data[test_split].select(range(start_index, end_index)) + print("start_index is ", start_index) + print("end_index is ", end_index) + print("test length is ", len(test_data)) + else: + test_data = data[test_split].select(range(max_test)) if max_test else data[test_split] + + text_column = [c for c in test_data.column_names if type(test_data[c][0]) != int][0] + + ############################### Pre-process ############################### + with track('Pre-process'): + with track('----Init tokenizer'): + tokenizer = AutoTokenizer.from_pretrained( + args.tokenizer_name if args.tokenizer_name else args.model_name_or_path + ) + + max_seq_len = min(args.max_seq_len, tokenizer.model_max_length) + + with track('----Tokenize + Extract Features'): + def preprocess(examples): + return tokenizer( + examples[text_column], + padding='max_length', + truncation=True, + max_length=max_seq_len + ) + + kwargs = dict( + function=preprocess, + batched=True, + num_proc=args.preprocessing_num_workers, + remove_columns=[text_column] + (['idx'] if args.dataset == 'sst2' else []), + load_from_cache_file=not args.overwrite_cache) + + train_data = train_data.map(**kwargs) if training_args.do_train else None + test_data = test_data.map(**kwargs) if training_args.do_predict else None + + ###################### Load Model and Trainer ############################ + with track('Load Model'): + model = AutoModelForSequenceClassification.from_pretrained(args.model_name_or_path).to(device=device) + + with track("Process int8 model"): + if args.int8: + # convert fp32 model to int 8 + dumpy_tensor = torch.ones((training_args.per_device_eval_batch_size, max_seq_len), dtype=torch.long) + jit_inputs = (dumpy_tensor, dumpy_tensor, dumpy_tensor) + + if os.path.exists(args.model_name_or_path + "/quantized_model.pt"): + print("load int8 model-----------------------") + if args.int8_bf16: + with torch.cpu.amp.autocast(): + model = torch.jit.load(args.model_name_or_path + "/quantized_model.pt") + model = torch.jit.freeze(model.eval()) + else: + model = torch.jit.load(args.model_name_or_path + "/quantized_model.pt") + model = torch.jit.freeze(model.eval()) + else: + print("load configure and convert the model") + ipex.nn.utils._model_convert.replace_dropout_with_identity(model) + from intel_extension_for_pytorch.quantization import prepare, convert + from torch.ao.quantization import MinMaxObserver, PerChannelMinMaxObserver, QConfig + qconfig = QConfig(activation=MinMaxObserver.with_args(qscheme=torch.per_tensor_affine, dtype=torch.quint8), weight=PerChannelMinMaxObserver.with_args(dtype=torch.qint8, qscheme=torch.per_channel_symmetric)) + prepared_model = prepare(model, qconfig, example_inputs=jit_inputs, inplace=False) + prepared_model.load_qconf_summary(qconf_summary = args.model_name_or_path + "/int8_configure.json") + if args.int8_bf16: + with torch.cpu.amp.autocast(): + model = convert(prepared_model) + model = torch.jit.trace(model, jit_inputs, strict=False) + else: + model = convert(prepared_model) + model = torch.jit.trace(model, jit_inputs, strict=False) + model = torch.jit.freeze(model) + + + with torch.no_grad(): + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + + # model.save("quantized_model.pt") + # import sys + # sys.exit(0) + + with track("Process bf16 model"): + if args.ipex_bf16: + model = ipex.optimize(model, dtype=torch.bfloat16, level='O0') + dumpy_tensor = torch.ones((training_args.per_device_eval_batch_size, max_seq_len), dtype=torch.long) + jit_inputs = (dumpy_tensor, dumpy_tensor, dumpy_tensor) + with torch.cpu.amp.autocast(), torch.no_grad(): + model = torch.jit.trace(model, jit_inputs, strict=False) + model = torch.jit.freeze(model) + with torch.no_grad(): + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + y = model(dumpy_tensor, dumpy_tensor, dumpy_tensor) + + if args.ipex_fp32: + model = ipex.optimize(model, dtype=torch.float32, level='O1') + + ############################### Inference ################################# + if training_args.do_predict: + with track('Inference'): + batch_size = training_args.per_device_eval_batch_size + all_outputs, all_labels = [], [] + + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + def to_inputs(batch: dict) -> dict: + return {k: (v if torch.is_tensor(v) else tensor(v)).to(device=device) for k, v in batch.items()} + + def prediction_step(batch, labels): + all_labels.extend(labels) + inputs = to_inputs(batch) + output = model(inputs['input_ids'], inputs['attention_mask']) if args.torchscript \ + else model(**inputs) + all_outputs.append(output['logits'].detach().cpu()) + + model.eval() + + with torch.no_grad(): + if args.profiler: + with torch.profiler.profile( + schedule=torch.profiler.schedule(wait=1, warmup=1, active=3, repeat=2), + on_trace_ready=torch.profiler.tensorboard_trace_handler('./profiler/' + args.profiler_name), + record_shapes=True, + profile_memory=True, + with_stack=True + ) as prof: + for batch in tqdm(DataLoader(test_data, batch_size=batch_size, + collate_fn=DataCollatorWithPadding(tokenizer))): + prediction_step(batch=batch, labels=batch.pop('labels')) + prof.step() + else: + for batch in tqdm(DataLoader(test_data, batch_size=batch_size, + collate_fn=DataCollatorWithPadding(tokenizer))): + prediction_step(batch=batch, labels=batch.pop('labels')) + + acc = compute_metrics(PredsLabels(preds=np.concatenate(all_outputs), labels=all_labels)) + print(f"\n*********** TEST_METRICS ***********\nAccuracy: {acc['acc']}\n") + + bench.summary() + + +if __name__ == "__main__": + main() diff --git a/profiling-transformers/src/utils.py b/profiling-transformers/src/utils.py new file mode 100644 index 0000000..85ff24c --- /dev/null +++ b/profiling-transformers/src/utils.py @@ -0,0 +1,343 @@ +# Copyright (C) 2022 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions +# and limitations under the License. +# + +# + +import json +from dataclasses import dataclass, field +from typing import Optional +from pathlib import Path +import numpy as np +from time import perf_counter_ns +from dataclasses import dataclass, field +import numpy as np +from contextlib import contextmanager +import os + +SEC_TO_NS_SCALE = 1000000000 + +SPLIT_PATHS = { + ('imdb', 'train'): './datasets/aclImdb/train', + ('imdb', 'test'): './datasets/aclImdb/test', + ('sst2', 'train'): './datasets/sst/train.tsv', + ('sst2', 'test'): './datasets/sst/dev.tsv' +} + + +@dataclass +class Benchmark: + summary_msg: str = field(default_factory=str) + + @property + def num_runs(self) -> int: + return len(self.latencies) + + @contextmanager + def track(self, step): + start = perf_counter_ns() + yield + ns = perf_counter_ns() - start + msg = f"\n{'*' * 70}\n'{step}' took {ns / SEC_TO_NS_SCALE:.3f}s ({ns:,}ns)\n{'*' * 70}\n" + print(msg) + self.summary_msg += msg + '\n' + + def summary(self): + print(f"\n{'#' * 30}\nBenchmark Summary:\n{'#' * 30}\n\n{self.summary_msg}") + + +@dataclass +class Arguments: + """ + Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. + """ + model_name_or_path: str = field( + default="bert-base-uncased", + metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} + ) + tokenizer_name: Optional[str] = field( + default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} + ) + smoke_test: Optional[bool] = field( + default=False, + metadata={"help": "Whether to execute in sanity check mode."} + ) + max_train_samples: Optional[int] = field( + default=None, + metadata={ + "help": "For debugging purposes or quicker training, truncate the number of training examples to this " + "value if set." + }, + ) + max_test_samples: Optional[int] = field( + default=None, + metadata={ + "help": "For debugging purposes or quicker training, truncate the number of testing examples to this " + "value if set." + }, + ) + instance_index: Optional[int] = field( + default=None, + metadata={ + "help": "for multi-instance inference, to indicate which instance this is." + }, + ) + dataset: Optional[str] = field( + default='imdb', + metadata={ + "help": "Select dataset ('imdb' / 'sst2'). Default is 'imdb'" + }, + ) + max_seq_len: int = field( + default=512, + metadata={ + "help": "The maximum total input sequence length after tokenization. Sequences longer " + "than this will be truncated, sequences shorter will be padded." + }, + ) + profiler: int = field( + default=0, + metadata={ + "help": "wether using pytorch profiler" + }, + ) + profiler_name: str = field( + default="test", + metadata={ + "help": "log name for pytorch profiler" + }, + ) + ipex: bool = field( + default=False, + metadata={ + "help": "Use Intel® Extension for PyTorch for fine-Tuning." + }, + ) + ipex_bf16: int = field( + default=0, + metadata={ + "help": "Auto mixed precision using bfloat16." + }, + ) + ipex_fp32: int = field( + default=0, + metadata={ + "help": "Auto mixed precision using bfloat16." + }, + ) + bf16_ipex_ft: int = field( + default=False, + metadata={ + "help": "Auto mixed precision using bfloat16 to fine-tuning." + }, + ) + fp32_ipex_ft: int = field( + default=False, + metadata={ + "help": "use ipex optimization for fp32 fine-tuning." + }, + ) + int8_bf16: int = field( + default=0, + metadata={ + "help": "Auto mixed precision using int8+bfloat16." + }, + ) + multi_instance: bool = field( + default=False, + metadata={ + "help": "Whether to use multi-instance mode" + }, + ) + int8: int = field( + default=0, + metadata={ + "help": "Whether to do inference with int8 model" + }, + ) + dist_backend: Optional[str] = field( + default="ccl", metadata={"help": "Distributed backend to use"} + ) + preprocessing_num_workers: Optional[int] = field( + default=None, + metadata={"help": "The number of processes to use for the preprocessing."}, + ) + overwrite_cache: bool = field( + default=True, metadata={"help": "Overwrite the cached training and evaluation sets."} + ) + real_time: bool = field( + default=False, metadata={"help": "Whether to pre-process the inputs in real-time."} + ) + few_shot: bool = field( + default=False, + metadata={ + "help": "Employ few-shot pattern-based MLM training on a small subset of the data." + }, + ) + pattern_id: bool = field( + default=0, metadata={"help": "Few-shot: pattern id of the pattern to use for few-shot training."} + ) + label_loss: bool = field( + default=True, metadata={"help": "Few-shot: whether to use label loss."} + ) + random_mlm: bool = field( + default=False, metadata={"help": "Few-shot: whether to use random MLM loss."} + ) + alpha: float = field( + default=0.6, metadata={"help": "Few-shot: alpha value for loss computation: ."} + ) + torchscript: bool = field( + default=False, metadata={"help": "Enable Torchscript."} + ) + + +class PredsLabels: + def __init__(self, preds, labels): + self.predictions = preds + self.label_ids = labels + + +def compute_metrics(p): + preds = np.argmax(p.predictions, axis=1) + return {"acc": (preds == p.label_ids).mean()} + + +def check_dataset(name: str): + if name == 'imdb': + return [name] + elif name == 'sst2': + return ['glue', 'sst2'] + else: + error_msg = f'Now only imdb and sst2 dataset are supported. Your dataset is {name}.' + raise ValueError(error_msg) + + +def read_dataset(name: str, split: str = "test", generator: bool = False, + return_labels: bool = True, batch_size: int = 1, max_samples: int = None): + split_path = SPLIT_PATHS[(name, split)] + args = split_path, return_labels, batch_size, max_samples + gen = imdb_gen(*args) if name == 'imdb' else sst_gen(*args) + + if generator: + return gen + + texts, labels = [], [] + for text_batch, label_batch in gen: + texts.extend(text_batch) + if return_labels: + labels.extend(label_batch) + return (texts, labels) if return_labels else texts + + +def imdb_gen(split_path, return_label, batch_size, max_samples): + text_batch, label_batch = [], [] + for label_dir in "pos", "neg": + for i, text_file in enumerate((Path(split_path) / label_dir).iterdir()): + text_batch.append(text_file.read_text()) + if return_label: + label_batch.append(0 if label_dir == 'neg' else 1) + if len(text_batch) == batch_size: + yield (text_batch, label_batch) if return_label else text_batch + text_batch, label_batch = [], [] + if max_samples is not None and i == max_samples / 2: + break + if text_batch: + yield (text_batch, label_batch) if return_label else text_batch + text_batch, label_batch = [], [] + + +def sst_gen(split_path, return_label, batch_size, max_samples): + text_batch, label_batch = [], [] + i = 0 + with open(split_path) as f: + for line in f.readlines()[1:]: + if line: + i += 1 + text, label = line.strip().split(" \t") + text_batch.append(text) + if return_label: + label_batch.append(int(label)) + if len(text_batch) == batch_size: + yield (text_batch, label_batch) if return_label else text_batch + text_batch, label_batch = [], [] + if max_samples is not None and i == max_samples: + break + if text_batch: + yield (text_batch, label_batch) if return_label else text_batch + text_batch, label_batch = [], [] + + +def to_tensor_dataset(framework, encodings, labels=None): + if framework == 'tf': + from tensorflow.data import Dataset + + data = (dict(encodings), labels) if labels else dict(encodings) + dataset = Dataset.from_tensor_slices(data) + + if framework == 'pt': + from torch import tensor + from torch.utils.data import Dataset + + class IMDbDataset(Dataset): + def __init__(self, encodings, labels): + self.encodings = encodings + self.labels = labels + + def __getitem__(self, idx): + item = {key: tensor(val[idx]) for key, val in self.encodings.items()} + item['labels'] = tensor(self.labels[idx]) + return item + + def __len__(self): + return len(self.labels) + + dataset = IMDbDataset(encodings, labels) + + return dataset + + +def save_train_metrics(train_result, trainer, max_train): + # pytorch only + if train_result: + metrics = train_result.metrics + metrics["train_samples"] = max_train + trainer.save_metrics("train", metrics) + trainer.save_state() + + +def save_test_metrics(metrics, max_test, output_dir): + metrics['test_samples'] = max_test + with open(Path(output_dir) / 'test_results.json', 'w') as f: + json.dump(metrics, f, indent=2) + return "\n\n******** TEST METRICS ********\n" + '\n'.join(f'{k}: {v}' for k, v in metrics.items()) + + +def read_imdb_split(split_dir): + texts, labels = [], [] + for label_dir in "pos", "neg": + for text_file in (Path(split_dir) / label_dir).iterdir(): + texts.append(text_file.read_text()) + labels.append(0 if label_dir == 'neg' else 1) + return texts, labels + + +def read_sst_file(sst_file): + texts, labels = [], [] + with open(sst_file) as f: + for line in f.readlines()[1:]: + if line: + text, label = line.strip().split(" \t") + texts.append(text) + labels.append(int(label)) + return texts, labels