diff --git a/.circleci/create_circleci_config.py b/.circleci/create_circleci_config.py index d10ede2b93ee..5633b6067722 100644 --- a/.circleci/create_circleci_config.py +++ b/.circleci/create_circleci_config.py @@ -174,10 +174,7 @@ def to_dict(self): f"--{key}={value}" if (value is not None or key in ["doctest-modules"]) else f"-{key}" for key, value in all_options.items() ] - pytest_flags.append( - f"--make-reports={self.name}" if "examples" in self.name else f"--make-reports=tests_{self.name}" - ) - # Examples special case: we need to download NLTK files in advance to avoid cuncurrency issues + pytest_flags.append(f"--make-reports=tests_{self.name}") timeout_cmd = f"timeout {self.command_timeout} " if self.command_timeout else "" marker_cmd = f"-m '{self.marker}'" if self.marker is not None else "" junit_flags = " -p no:warning -o junit_family=xunit1 --junitxml=test-results/junit.xml" @@ -189,14 +186,6 @@ def to_dict(self): {"attach_workspace": {"at": "test_preparation"}}, {"run": "apt-get update && apt-get install -y curl"}, {"run": " && ".join(self.install_steps)}, - { - "run": { - "name": "Download NLTK files", - "command": """python -c "import nltk; nltk.download('punkt', quiet=True)" """, - } - if "example" in self.name - else "echo Skipping" - }, { "run": { "name": "Show installed libraries and their size", @@ -310,11 +299,7 @@ def to_dict(self): @property def job_name(self): - return ( - self.name - if ("examples" in self.name or "pipeline" in self.name or "pr_documentation" in self.name) - else f"tests_{self.name}" - ) + return self.name if ("pipeline" in self.name or "pr_documentation" in self.name) else f"tests_{self.name}" # JOBS @@ -361,16 +346,6 @@ def job_name(self): docker_image=[{"image": "huggingface/transformers-custom-tokenizers"}], ) -examples_torch_job = CircleCIJob( - "examples_torch", - disabled=True, # examples-torch docker image is too large for the large runner - additional_env={"OMP_NUM_THREADS": 8}, - docker_image=[{"image": "huggingface/transformers-examples-torch"}], - # TODO @ArthurZucker remove this once docker is easier to build - install_steps=["uv pip install . && uv pip install -r examples/pytorch/_tests_requirements.txt"], - pytest_num_workers=4, -) - exotic_models_job = CircleCIJob( "exotic_models", docker_image=[{"image": "huggingface/transformers-exotic-models"}], @@ -454,7 +429,6 @@ def job_name(self): ) REGULAR_TESTS = [torch_job, tokenization_job, processor_job, generate_job, non_model_job] # fmt: skip -EXAMPLES_TESTS = [examples_torch_job] PIPELINE_TESTS = [pipelines_torch_job] REPO_UTIL_TESTS = [repo_utils_job] DOC_TESTS = [doc_test_job] @@ -462,7 +436,7 @@ def job_name(self): TENSOR_PARALLEL_CI_TESTS = [tensor_parallel_ci_job] FSDP_CI_TESTS = [fsdp_ci_job] PEFT_INTEGRATION_TESTS = [peft_integration_job] -ALL_TESTS = REGULAR_TESTS + EXAMPLES_TESTS + PIPELINE_TESTS + REPO_UTIL_TESTS + DOC_TESTS + [custom_tokenizers_job] + [exotic_models_job] + TRAINING_CI_TESTS + TENSOR_PARALLEL_CI_TESTS + FSDP_CI_TESTS + PEFT_INTEGRATION_TESTS # fmt: skip +ALL_TESTS = REGULAR_TESTS + PIPELINE_TESTS + REPO_UTIL_TESTS + DOC_TESTS + [custom_tokenizers_job] + [exotic_models_job] + TRAINING_CI_TESTS + TENSOR_PARALLEL_CI_TESTS + FSDP_CI_TESTS + PEFT_INTEGRATION_TESTS # fmt: skip def create_circleci_config(folder=None): diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index a43cd097f605..8ac1f18eb31c 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -79,24 +79,6 @@ body: placeholder: "@Username ..." - - type: checkboxes - id: information-scripts-examples - attributes: - label: Information - description: 'The problem arises when using:' - options: - - label: "The official example scripts" - - label: "My own modified scripts" - - - type: checkboxes - id: information-tasks - attributes: - label: Tasks - description: "The tasks I am working on are:" - options: - - label: "An officially supported task in the `examples` folder (such as GLUE/SQuAD, ...)" - - label: "My own task or dataset (give details below)" - - type: textarea id: reproduction validations: diff --git a/.github/ISSUE_TEMPLATE/migration.yml b/.github/ISSUE_TEMPLATE/migration.yml index 081e644ff01c..5445d52a424b 100644 --- a/.github/ISSUE_TEMPLATE/migration.yml +++ b/.github/ISSUE_TEMPLATE/migration.yml @@ -12,24 +12,6 @@ body: validations: required: true - - type: checkboxes - id: information-scripts-examples - attributes: - label: Information - description: 'The problem arises when using:' - options: - - label: "The official example scripts" - - label: "My own modified scripts" - - - type: checkboxes - id: information-tasks - attributes: - label: Tasks - description: "The tasks I am working on are:" - options: - - label: "An officially supported task in the `examples` folder (such as GLUE/SQuAD, ...)" - - label: "My own task or dataset (give details below)" - - type: textarea id: reproduction validations: @@ -68,5 +50,3 @@ body: ([pytorch-transformers](https://github.com/huggingface/transformers#migrating-from-pytorch-transformers-to-transformers); [pytorch-pretrained-bert](https://github.com/huggingface/transformers#migrating-from-pytorch-pretrained-bert-to-transformers))" required: true - - label: "I checked if a related official extension example runs on my machine." - required: true diff --git a/.github/workflows/build-ci-docker-images.yml b/.github/workflows/build-ci-docker-images.yml index 0ef34d263cfd..04e23d728102 100644 --- a/.github/workflows/build-ci-docker-images.yml +++ b/.github/workflows/build-ci-docker-images.yml @@ -31,7 +31,7 @@ jobs: strategy: matrix: - file: ["quality", "consistency", "custom-tokenizers", "torch-light", "exotic-models", "examples-torch"] + file: ["quality", "consistency", "custom-tokenizers", "torch-light", "exotic-models"] continue-on-error: true steps: diff --git a/.github/workflows/self-scheduled-amd-mi250-caller.yml b/.github/workflows/self-scheduled-amd-mi250-caller.yml index ac68be46b2d6..fc4d65560c97 100644 --- a/.github/workflows/self-scheduled-amd-mi250-caller.yml +++ b/.github/workflows/self-scheduled-amd-mi250-caller.yml @@ -37,18 +37,6 @@ jobs: report_repo_id: optimum-amd/transformers_daily_ci secrets: inherit - example-ci: - name: Example CI - uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@63657f571a92cc9759159442936061c51d6d9ae4 # main - with: - job: run_examples_gpu - slack_report_channel: "#transformers-ci-daily-amd" - runner: mi250 - docker: huggingface/transformers-pytorch-amd-gpu - ci_event: Scheduled CI (AMD) - mi250 - report_repo_id: optimum-amd/transformers_daily_ci - secrets: inherit - deepspeed-ci: name: DeepSpeed CI uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@63657f571a92cc9759159442936061c51d6d9ae4 # main diff --git a/.github/workflows/self-scheduled-amd-mi300-caller.yml b/.github/workflows/self-scheduled-amd-mi300-caller.yml index 3dfd027b56ee..b16201c64718 100644 --- a/.github/workflows/self-scheduled-amd-mi300-caller.yml +++ b/.github/workflows/self-scheduled-amd-mi300-caller.yml @@ -86,20 +86,6 @@ jobs: commit_sha: ${{ github.event.workflow_run.head_sha || github.sha }} secrets: inherit - example-ci: - name: Example CI - uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled_arc_scale_set.yaml@main - with: - job: run_examples_gpu - slack_report_channel: "#amd-hf-ci" - runner_group: amd-mi300 - docker: huggingface/transformers-pytorch-amd-gpu - ci_event: Scheduled CI (AMD) - mi300 - report_repo_id: optimum-amd/transformers_daily_ci - env_file: /etc/podinfo/gha-gpu-isolation-settings - commit_sha: ${{ github.event.workflow_run.head_sha || github.sha }} - secrets: inherit - deepspeed-ci: name: DeepSpeed CI uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled_arc_scale_set.yaml@main diff --git a/.github/workflows/self-scheduled-amd-mi355-caller.yml b/.github/workflows/self-scheduled-amd-mi355-caller.yml index ff0fe8193f53..65ca562d1e35 100644 --- a/.github/workflows/self-scheduled-amd-mi355-caller.yml +++ b/.github/workflows/self-scheduled-amd-mi355-caller.yml @@ -41,18 +41,6 @@ jobs: report_repo_id: hf-transformers-bot/transformers-ci-dummy secrets: inherit - example-ci: - name: Example CI - uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled_arc_scale_set.yaml@50acccfe9afb8927b9b74ed7e750f2b0d3991b62 # main - with: - job: run_examples_gpu - slack_report_channel: "#amd-hf-ci" - runner_group: hfc-amd-mi355 - docker: huggingface/transformers-pytorch-amd-gpu - ci_event: Scheduled CI (AMD) - mi355 - report_repo_id: hf-transformers-bot/transformers-ci-dummy - secrets: inherit - deepspeed-ci: name: DeepSpeed CI uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled_arc_scale_set.yaml@50acccfe9afb8927b9b74ed7e750f2b0d3991b62 # main diff --git a/.github/workflows/self-scheduled-caller.yml b/.github/workflows/self-scheduled-caller.yml index 4de07c652801..446e55eccd4f 100644 --- a/.github/workflows/self-scheduled-caller.yml +++ b/.github/workflows/self-scheduled-caller.yml @@ -76,18 +76,6 @@ jobs: commit_sha: ${{ github.sha }} secrets: inherit - example-ci: - name: Example CI - uses: huggingface/transformers-ci/.github/workflows/daily-ci_reusable.yml@main - with: - job: run_examples_gpu - slack_report_channel: "#transformers-ci-daily-examples" - docker: huggingface/transformers-all-latest-gpu - ci_event: Daily CI - report_repo_id: hf-internal-testing/transformers_daily_ci - commit_sha: ${{ github.sha }} - secrets: inherit - trainer-fsdp-ci: name: Trainer/FSDP CI uses: huggingface/transformers-ci/.github/workflows/daily-ci_reusable.yml@main diff --git a/.github/workflows/self-scheduled-intel-gaudi.yml b/.github/workflows/self-scheduled-intel-gaudi.yml index a9ea2563021a..47d577fce930 100644 --- a/.github/workflows/self-scheduled-intel-gaudi.yml +++ b/.github/workflows/self-scheduled-intel-gaudi.yml @@ -183,81 +183,6 @@ jobs: name: ${{ env.machine_type }}_run_pipelines_torch_gpu_test_reports path: reports/${{ env.machine_type }}_run_pipelines_torch_gpu_test_reports - run_examples_gpu: - permissions: - contents: read - if: ${{ inputs.job == 'run_examples_gpu' }} - name: Examples directory - strategy: - fail-fast: false - matrix: - machine_type: [1gaudi] - runs-on: - group: ${{ inputs.runner_scale_set }}-${{ matrix.machine_type }} - container: - image: vault.habana.ai/gaudi-docker/1.21.1/ubuntu22.04/habanalabs/pytorch-installer-2.6.0:latest - options: --runtime=habana - -v /mnt/cache/.cache/huggingface:/mnt/cache/.cache/huggingface - --env OMPI_MCA_btl_vader_single_copy_mechanism=none - --env HABANA_VISIBLE_DEVICES - --env HABANA_VISIBLE_MODULES - --cap-add=sys_nice - --shm-size=64G - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Install dependencies - run: | - pip install -e .[testing,torch] "numpy<2.0.0" scipy scikit-learn librosa soundfile - - - name: HL-SMI - run: | - hl-smi - echo "HABANA_VISIBLE_DEVICES=${HABANA_VISIBLE_DEVICES}" - echo "HABANA_VISIBLE_MODULES=${HABANA_VISIBLE_MODULES}" - - - name: Environment - run: | - python3 utils/print_env.py - - - name: Show installed libraries and their versions - run: | - pip freeze - - - name: Set `machine_type` for report and artifact names - shell: bash - run: | - if [ "${{ matrix.machine_type }}" = "1gaudi" ]; then - machine_type=single-gpu - elif [ "${{ matrix.machine_type }}" = "2gaudi" ]; then - machine_type=multi-gpu - else - machine_type=${{ matrix.machine_type }} - fi - echo "machine_type=$machine_type" >> $GITHUB_ENV - - - name: Run examples tests on Intel Gaudi - run: | - pip install -r examples/pytorch/_tests_requirements.txt - python3 -m pytest -v --make-reports="${machine_type}_run_examples_gpu_test_reports" examples/pytorch -m "not not_device_test" - - - name: Failure short reports - if: ${{ failure() }} - continue-on-error: true - run: | - cat "reports/${machine_type}_run_examples_gpu_test_reports/failures_short.txt" - - - name: "Test suite reports artifacts: ${{ env.machine_type }}_run_examples_gpu_test_reports" - if: ${{ always() }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: ${{ env.machine_type }}_run_examples_gpu_test_reports - path: reports/${{ env.machine_type }}_run_examples_gpu_test_reports - run_torch_cuda_extensions_gpu: permissions: contents: read @@ -318,7 +243,7 @@ jobs: - name: Run all deepspeed tests on intel Gaudi run: | - python3 -m pytest -v --make-reports="${machine_type}_run_torch_cuda_extensions_gpu_test_reports" tests/deepspeed -m "not not_device_test" + python3 -m pytest -v --make-reports="${machine_type}_run_torch_cuda_extensions_gpu_test_reports" tests/trainer/distributed/test_trainer_distributed_deepspeed.py -m "not not_device_test" - name: Failure short reports if: ${{ failure() }} @@ -427,7 +352,6 @@ jobs: [ setup, run_models_gpu, - run_examples_gpu, run_torch_cuda_extensions_gpu, run_pipelines_torch_gpu, run_trainer_and_fsdp_gpu, diff --git a/.github/workflows/self-scheduled-intel-gaudi3-caller.yml b/.github/workflows/self-scheduled-intel-gaudi3-caller.yml index 1a2337d9d2fc..f4d3269816d6 100644 --- a/.github/workflows/self-scheduled-intel-gaudi3-caller.yml +++ b/.github/workflows/self-scheduled-intel-gaudi3-caller.yml @@ -34,18 +34,6 @@ jobs: secrets: inherit - example-ci: - name: Example CI - uses: ./.github/workflows/self-scheduled-intel-gaudi.yml - with: - job: run_examples_gpu - ci_event: Scheduled CI (Intel) - Gaudi3 - runner_scale_set: itac-bm-emr-gaudi3-dell - slack_report_channel: "#transformers-ci-daily-intel-gaudi3" - report_repo_id: optimum-intel/transformers_daily_ci_intel_gaudi3 - - secrets: inherit - deepspeed-ci: name: DeepSpeed CI uses: ./.github/workflows/self-scheduled-intel-gaudi.yml diff --git a/Makefile b/Makefile index 08dbb61cb1eb..1d39e5a34a9e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # make sure to test the local checkout in scripts and not the pre-installed one (don't use quotes!) export PYTHONPATH = src -.PHONY: style typing check-code-quality check-repository-consistency check-repo fix-repo test test-examples benchmark codex claude clean-ai +.PHONY: style typing check-code-quality check-repository-consistency check-repo fix-repo test benchmark codex claude clean-ai # Checker lists. The two CI jobs (CircleCI runs `make check-code-quality` and @@ -66,10 +66,6 @@ fix-repo: test: python -m pytest -p random_order -n auto --dist=loadfile -s -v --random-order-bucket=module ./tests/ -# Run tests for examples, requires pytest-random-order -test-examples: - python -m pytest -p random_order -n auto --dist=loadfile -s -v --random-order-bucket=module ./examples/pytorch/ - # Run benchmark benchmark: python3 benchmark/benchmark.py --config-dir benchmark/config --config-name generation --commit=diff backend.model=google/gemma-2b backend.cache_implementation=null,static backend.torch_compile=false,true --multirun diff --git a/README.md b/README.md index be98f3641441..425174b3602b 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,6 @@ pipeline( - This library is not a modular toolbox of building blocks for neural nets. The code in the model files is not refactored with additional abstractions on purpose, so that researchers can quickly iterate on each of the models without diving into additional abstractions/files. - The training API is optimized to work with PyTorch models provided by Transformers. For generic machine learning loops, you should use another library like [Accelerate](https://huggingface.co/docs/accelerate). -- The [example scripts](https://github.com/huggingface/transformers/tree/main/examples) are only *examples*. They may not necessarily work out-of-the-box on your specific use case and you'll need to adapt the code for it to work. ## 100 projects using Transformers diff --git a/docker/docker-bake.hcl b/docker/docker-bake.hcl index a8293dd4cbf5..23a10c9e1c17 100644 --- a/docker/docker-bake.hcl +++ b/docker/docker-bake.hcl @@ -32,7 +32,7 @@ target "ci-base" { target "ci-image" { name = image matrix = { - image = ["quality", "consistency", "custom-tokenizers", "torch-light", "exotic-models", "examples-torch", "pipeline-torch"] + image = ["quality", "consistency", "custom-tokenizers", "torch-light", "exotic-models", "pipeline-torch"] } context = "docker" dockerfile = "${image}.dockerfile" diff --git a/docker/examples-torch.dockerfile b/docker/examples-torch.dockerfile deleted file mode 100644 index 7f9aa8390818..000000000000 --- a/docker/examples-torch.dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM ci-base -ARG REF=main -RUN apt-get update && apt-get install -y --no-install-recommends libsndfile1-dev espeak-ng time git g++ cmake pkg-config openssh-client git-lfs ffmpeg curl -RUN uv pip install --no-cache-dir 'torch<=2.14.0' 'torchaudio' 'torchvision' 'torchcodec<=0.16.0' --index-url https://download.pytorch.org/whl/cpu -RUN uv pip install --no-deps timm accelerate --extra-index-url https://download.pytorch.org/whl/cpu -RUN uv pip install --no-cache-dir librosa "git+https://github.com/huggingface/transformers.git@${REF}#egg=transformers[sklearn,sentencepiece,vision,testing]" seqeval albumentations jiwer - -# Use a custom patched pytest to force exit the process at the end, to avoid `Too long with no output (exceeded 10m0s): context deadline exceeded` (#40201) -RUN uv pip install --no-cache-dir git+https://github.com/ydshieh/pytest.git@8.4.1-ydshieh -RUN uv pip install --no-cache-dir pytest-random-order -RUN uv pip install --no-cache-dir 'transformers-ci[otel] @ git+https://github.com/huggingface/transformers-ci@main' - -# fetch test data and hub objects within CircleCI docker images to reduce even more connections -# we don't need a full clone of `transformers` to run `fetch_hub_objects_for_ci.py` -# the data are downloaded to the directory `/test_data` and during CircleCI's CI runtime, we need to move them to the root of `transformers` -RUN mkdir test_data && cd test_data && curl -O https://raw.githubusercontent.com/huggingface/transformers/${REF}/utils/fetch_hub_objects_for_ci.py && python3 fetch_hub_objects_for_ci.py - - -RUN uv pip uninstall transformers -RUN apt-get clean && rm -rf /var/lib/apt/lists/* diff --git a/docker/transformers-intel-cpu/Dockerfile b/docker/transformers-intel-cpu/Dockerfile index 1b60c683fc15..19fddad18e6e 100644 --- a/docker/transformers-intel-cpu/Dockerfile +++ b/docker/transformers-intel-cpu/Dockerfile @@ -47,9 +47,9 @@ ENV PATH="$VIRTUAL_ENV/bin:$PATH" RUN pip install --upgrade pip wheel RUN pip install torch torchvision torchaudio torchcodec torchao --index-url https://download.pytorch.org/whl/cpu --no-cache-dir -RUN pip install av pyctcdecode pytesseract decord galore-torch fire scipy scikit-learn sentencepiece sentence_transformers sacremoses nltk rouge_score librosa soundfile mpi4py pytorch_msssim +RUN pip install av pyctcdecode pytesseract decord galore-torch scipy scikit-learn sentencepiece sentence_transformers sacremoses nltk librosa soundfile mpi4py pytorch_msssim RUN pip install onnx optimum onnxruntime -RUN pip install -U datasets timm transformers accelerate peft diffusers opencv-python kenlm evaluate +RUN pip install -U datasets timm transformers accelerate peft diffusers opencv-python kenlm RUN pip install -U intel-openmp RUN pip install kernels RUN pip install gptqmodel bitsandbytes diff --git a/docker/transformers-pytorch-deepspeed-latest-gpu/Dockerfile b/docker/transformers-pytorch-deepspeed-latest-gpu/Dockerfile index c10539f6ea89..1c3d923ad898 100644 --- a/docker/transformers-pytorch-deepspeed-latest-gpu/Dockerfile +++ b/docker/transformers-pytorch-deepspeed-latest-gpu/Dockerfile @@ -37,10 +37,7 @@ WORKDIR /workspace ARG REF=main RUN git clone https://github.com/huggingface/transformers && cd transformers && git checkout $REF -# `sklearn` on top of `deepspeed-testing`: the model zoo tests drive the example scripts, which -# compute metrics with scikit-learn (and scipy, which it pulls in). `transformers-all-latest-gpu` -# gets these through `[dev]`, and the previous `nvcr.io` base image happened to preinstall them. -RUN python3 -m pip install --no-cache-dir './transformers[deepspeed-testing,sklearn]' +RUN python3 -m pip install --no-cache-dir './transformers[deepspeed-testing]' # Install latest release PyTorch # (PyTorch must be installed before pre-compiling any DeepSpeed c++/cuda ops.) diff --git a/docker/transformers-pytorch-tpu/Dockerfile b/docker/transformers-pytorch-tpu/Dockerfile deleted file mode 100644 index b61f4add5146..000000000000 --- a/docker/transformers-pytorch-tpu/Dockerfile +++ /dev/null @@ -1,65 +0,0 @@ -FROM google/cloud-sdk:slim - -# Build args. -ARG GITHUB_REF=refs/heads/main - -# TODO: This Dockerfile installs pytorch/xla 3.6 wheels. There are also 3.7 -# wheels available; see below. -ENV PYTHON_VERSION=3.6 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - build-essential \ - cmake \ - git \ - curl \ - ca-certificates - -# Install conda and python. -# NOTE new Conda does not forward the exit status... https://github.com/conda/conda/issues/8385 -RUN curl -o ~/miniconda.sh https://repo.anaconda.com/miniconda/Miniconda3-4.7.12-Linux-x86_64.sh && \ - chmod +x ~/miniconda.sh && \ - ~/miniconda.sh -b && \ - rm ~/miniconda.sh - -ENV PATH=/root/miniconda3/bin:$PATH - -RUN conda create -y --name container python=$PYTHON_VERSION - -# Run the rest of commands within the new conda env. -# Use absolute path to appease Codefactor. -SHELL ["/root/miniconda3/bin/conda", "run", "-n", "container", "/bin/bash", "-c"] -RUN conda install -y python=$PYTHON_VERSION mkl - -RUN pip uninstall -y torch && \ - # Python 3.7 wheels are available. Replace cp36-cp36m with cp37-cp37m - gsutil cp 'gs://tpu-pytorch/wheels/torch-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' . && \ - gsutil cp 'gs://tpu-pytorch/wheels/torch_xla-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' . && \ - gsutil cp 'gs://tpu-pytorch/wheels/torchvision-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' . && \ - pip install 'torch-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' && \ - pip install 'torch_xla-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' && \ - pip install 'torchvision-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' && \ - rm 'torch-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' && \ - rm 'torch_xla-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' && \ - rm 'torchvision-nightly-cp${PYTHON_VERSION/./}-cp${PYTHON_VERSION/./}m-linux_x86_64.whl' && \ - apt-get install -y libomp5 - -ENV LD_LIBRARY_PATH=root/miniconda3/envs/container/lib - - -# Install huggingface/transformers at the current PR, plus dependencies. -RUN git clone https://github.com/huggingface/transformers.git && \ - cd transformers && \ - git fetch origin $GITHUB_REF:CI && \ - git checkout CI && \ - cd .. && \ - pip install ./transformers && \ - pip install -r ./transformers/examples/pytorch/_test_requirements.txt && \ - pip install pytest - -RUN python -c "import torch_xla; print(torch_xla.__version__)" -RUN python -c "import transformers as trf; print(trf.__version__)" -RUN conda init bash -COPY docker-entrypoint.sh /usr/local/bin/ -RUN chmod +x /usr/local/bin/docker-entrypoint.sh -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -CMD ["bash"] diff --git a/docker/transformers-pytorch-tpu/bert-base-cased.jsonnet b/docker/transformers-pytorch-tpu/bert-base-cased.jsonnet deleted file mode 100644 index 84608b5d8249..000000000000 --- a/docker/transformers-pytorch-tpu/bert-base-cased.jsonnet +++ /dev/null @@ -1,38 +0,0 @@ -local base = import 'templates/base.libsonnet'; -local tpus = import 'templates/tpus.libsonnet'; -local utils = import "templates/utils.libsonnet"; -local volumes = import "templates/volumes.libsonnet"; - -local bertBaseCased = base.BaseTest { - frameworkPrefix: "hf", - modelName: "bert-base-cased", - mode: "example", - configMaps: [], - - timeout: 3600, # 1 hour, in seconds - - image: std.extVar('image'), - imageTag: std.extVar('image-tag'), - - tpuSettings+: { - softwareVersion: "pytorch-nightly", - }, - accelerator: tpus.v3_8, - - volumeMap+: { - datasets: volumes.PersistentVolumeSpec { - name: "huggingface-cluster-disk", - mountPath: "/datasets", - }, - }, - command: utils.scriptCommand( - ||| - python -m pytest -s transformers/examples/pytorch/test_xla_examples.py -v - test_exit_code=$? - echo "\nFinished running commands.\n" - test $test_exit_code -eq 0 - ||| - ), -}; - -bertBaseCased.oneshotJob diff --git a/docker/transformers-pytorch-tpu/dataset.yaml b/docker/transformers-pytorch-tpu/dataset.yaml deleted file mode 100644 index ce022ea6c184..000000000000 --- a/docker/transformers-pytorch-tpu/dataset.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: v1 -kind: PersistentVolume -metadata: - name: huggingface-cluster-disk -spec: - storageClassName: "" - capacity: - storage: 500Gi - accessModes: - - ReadOnlyMany - claimRef: - namespace: default - name: huggingface-cluster-disk-claim - gcePersistentDisk: - pdName: huggingface-cluster-disk - fsType: ext4 - readOnly: true ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: huggingface-cluster-disk-claim -spec: - # Specify "" as the storageClassName so it matches the PersistentVolume's StorageClass. - # A nil storageClassName value uses the default StorageClass. For details, see - # https://kubernetes.io/docs/concepts/storage/persistent-volumes/#class-1 - storageClassName: "" - accessModes: - - ReadOnlyMany - resources: - requests: - storage: 1Ki diff --git a/docker/transformers-pytorch-tpu/docker-entrypoint.sh b/docker/transformers-pytorch-tpu/docker-entrypoint.sh deleted file mode 100644 index fbe59566fdcd..000000000000 --- a/docker/transformers-pytorch-tpu/docker-entrypoint.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -source ~/.bashrc -echo "running docker-entrypoint.sh" -conda activate container -echo $KUBE_GOOGLE_CLOUD_TPU_ENDPOINTS -echo "printed TPU info" -export XRT_TPU_CONFIG="tpu_worker;0;${KUBE_GOOGLE_CLOUD_TPU_ENDPOINTS:7}" -exec "$@"#!/bin/bash diff --git a/docker/transformers-pytorch-xpu/Dockerfile b/docker/transformers-pytorch-xpu/Dockerfile index 6b12dc898707..efa212c08bed 100644 --- a/docker/transformers-pytorch-xpu/Dockerfile +++ b/docker/transformers-pytorch-xpu/Dockerfile @@ -69,8 +69,8 @@ RUN uv pip install torchcodec==0.16.0 --index-url https://download.pytorch.org/w RUN uv pip install torchdata --no-cache-dir -RUN uv pip install evaluate pyctcdecode pytesseract decord fire scipy scikit-learn sentencepiece sacremoses nltk rouge_score librosa soundfile g2p_en mpi4py requests_mock onnx deepspeed kenlm opencv-python albumentations --no-cache-dir -RUN uv pip install pretty_midi essentia resampy Levenshtein av sacrebleu phonemizer invisible_watermark schedulefree parameterized mistral-common --no-cache-dir +RUN uv pip install pyctcdecode pytesseract decord scipy scikit-learn sentencepiece sacremoses nltk librosa soundfile g2p_en mpi4py requests_mock onnx deepspeed kenlm opencv-python --no-cache-dir +RUN uv pip install pretty_midi essentia resampy Levenshtein av phonemizer invisible_watermark schedulefree parameterized mistral-common --no-cache-dir RUN uv pip install gguf hqq fp-quant compressed_tensors bitsandbytes --no-cache-dir --extra-index-url https://download.pytorch.org/whl/xpu "torch==2.14.0+xpu" "triton==3.8.0" RUN uv pip install gptqmodel --no-cache-dir diff --git a/docs/source/ar/_toctree.yml b/docs/source/ar/_toctree.yml index fa4378e93b59..9016e70c1c7d 100644 --- a/docs/source/ar/_toctree.yml +++ b/docs/source/ar/_toctree.yml @@ -15,8 +15,6 @@ title: معالجة البيانات مسبقًا - local: training title: ضبط نموذج مسبق التدريب - - local: run_scripts - title: التدريب باستخدام نص برمجي - local: accelerate title: إعداد تدريب موزع باستخدام 🤗 Accelerate - local: peft diff --git a/docs/source/ar/installation.md b/docs/source/ar/installation.md index e548e788bf60..987b062fed97 100644 --- a/docs/source/ar/installation.md +++ b/docs/source/ar/installation.md @@ -133,13 +133,6 @@ conda install conda-forge::transformers -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -يجب أن يعمل هذا البرنامج النصي دون توقف أو انتظار انتهاء المهلة الزمنية لأنه لن يحاول تنزيل النموذج من Hub. - يمكنك أيضًا تجاوز تحميل نموذج من Hub من كل استدعاء [`~PreTrainedModel.from_pretrained`] باستخدام معلمة [`local_files_only`]. عندما يتم تعيينها على `True`، يتم تحميل الملفات المحلية فقط: ```py diff --git a/docs/source/ar/multilingual.md b/docs/source/ar/multilingual.md index b4b2a94fd40a..ccb55086f3c5 100644 --- a/docs/source/ar/multilingual.md +++ b/docs/source/ar/multilingual.md @@ -59,8 +59,6 @@ >>> outputs = model(input_ids, langs=langs) ``` -يمكن لنص البرنامج النصي [run_generation.py](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-generation/run_generation.py) توليد النص باستخدام تضمينات اللغة مع نقاط تفتيش `xlm-clm`. - ### XLM بدون تضمينات اللغة النماذج التالية من XLM لا تتطلب تضمينات اللغة أثناء الاستنتاج: diff --git a/docs/source/ar/run_scripts.md b/docs/source/ar/run_scripts.md deleted file mode 100644 index 052e6e1d8440..000000000000 --- a/docs/source/ar/run_scripts.md +++ /dev/null @@ -1,280 +0,0 @@ -# التدريب باستخدام نص برمجى - -بالإضافة إلى دفاتر الملاحظات [notebooks](./notebooks) الخاصة بـ 🤗 Transformers، هناك أيضًا نصوص برمجية توضيحية تُظهر كيفية تدريب نموذج لمهمة باستخدام [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch) أو [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow) أو [JAX/Flax](https://github.com/huggingface/transformers/tree/main/examples/flax). - -كما ستجد النصوص البرمجية التي استخدمناها في [مشاريع الأبحاث](https://github.com/huggingface/transformers-research-projects/) و [الأمثلة القديمة](https://github.com/huggingface/transformers/tree/main/examples/legacy) والتي ساهم بها المجتمع بشكل أساسي. هذه النصوص البرمجية غير مدعومة بشكل نشط وقد تتطلب إصدارًا محددًا من مكتبة 🤗 Transformers والذي من المحتمل أن يكون غير متوافق مع الإصدار الأحدث من المكتبة. - -لا يُتوقع أن تعمل النصوص البرمجية التوضيحية بشكل مباشر على كل مشكلة، وقد تحتاج إلى تكييف النص البرمجي مع المشكلة التي تحاول حلها. ولمساعدتك في ذلك، تعرض معظم النصوص البرمجية كيفية معالجة البيانات قبل التدريب بشكل كامل، مما يتيح لك تحريرها حسب الحاجة لحالتك الاستخدام. - -بالنسبة لأي ميزة ترغب في تنفيذها في نص برمجي توضيحي، يرجى مناقشتها في [المنتدى](https://discuss.huggingface.co/) أو في [قضية](https://github.com/huggingface/transformers/issues) قبل إرسال طلب سحب. وفي حين أننا نرحب بإصلاح الأخطاء، فمن غير المرجح أن نقوم بدمج طلب سحب الذي يضيف المزيد من الوظائف على حساب قابلية القراءة. - -سيوضح هذا الدليل كيفية تشغيل نص برمجي توضيحي للتدريب على التلخيص في [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) و [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization). يُتوقع أن تعمل جميع الأمثلة مع كلا الإطارين ما لم يُنص على خلاف ذلك. - -## الإعداد - -لتشغيل الإصدار الأحدث من النصوص البرمجية التوضيحية بنجاح، يجب عليك **تثبيت 🤗 Transformers من المصدر** في بيئة افتراضية جديدة: - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -بالنسبة للإصدارات الأقدم من النصوص البرمجية التوضيحية، انقر فوق الزر أدناه: -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -بالنسبة للإصدارات الأقدم من النصوص البرمجية التوضيحية، انقر فوق الزر أدناه: - -
- أمثلة للإصدارات الأقدم من 🤗 Transformers - -
- -ثم قم بالتبديل إلى النسخة الحالية من 🤗 Transformers إلى إصدار محدد، مثل v3.5.1 على سبيل المثال: - -```bash -git checkout tags/v3.5.1 -``` - -بعد إعداد إصدار المكتبة الصحيح، انتقل إلى مجلد الأمثلة الذي تختاره وقم بتثبيت المتطلبات المحددة: - -```bash -pip install -r requirements.txt -``` - -## تشغيل نص برمجي - - -- يقوم النص البرمجي التوضيحي بتنزيل مجموعة بيانات ومعالجتها مسبقًا من مكتبة 🤗 [Datasets](https://huggingface.co/docs/datasets). -- ثم يقوم النص البرمجي بضبط نموذج بيانات دقيق باستخدام [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) على بنية تدعم الملخص. -- يوضح المثال التالي كيفية ضبط نموذج [T5-small](https://huggingface.co/google-t5/t5-small) على مجموعة بيانات [CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail). -- يتطلب نموذج T5 معامل `source_prefix` إضافية بسبب الطريقة التي تم تدريبه بها. يتيح هذا المطالبة لـ T5 معرفة أن هذه مهمة التلخيص. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## التدريب الموزع والدقة المختلطة - -يدعم [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) التدريب الموزع والدقة المختلطة، مما يعني أنه يمكنك أيضًا استخدامه في نص برمجي. لتمكين كلتا الميزتين: - -- أضف معامل `fp16` لتمكين الدقة المختلطة. -- قم بتعيين عدد وحدات معالجة الرسومات (GPUs) التي تريد استخدامها باستخدام حجة `nproc_per_node`. - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -تستخدم نصوص TensorFlow البرمجية استراتيجية [`MirroredStrategy`](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy) للتدريب الموزع، ولا تحتاج إلى إضافة أي معامﻻت إضافية إلى النص البرمجي التدريبي. سيستخدم نص TensorFlow البرمجي وحدات معالجة الرسومات (GPUs) متعددة بشكل افتراضي إذا كانت متوفرة. - -## تشغيل نص برمجي على وحدة معالجة الدقة الفائقة (TPU) - - -تُعد وحدات معالجة الدقة الفائقة (TPUs) مصممة خصيصًا لتسريع الأداء. يدعم PyTorch وحدات معالجة الدقة الفائقة (TPUs) مع [XLA](https://www.tensorflow.org/xla) مجمع الدقة الفائقة للتعلم العميق (راجع [هنا](https://github.com/pytorch/xla/blob/master/README.md) لمزيد من التفاصيل). لاستخدام وحدة معالجة الدقة الفائقة (TPU)، قم بتشغيل نص `xla_spawn.py` البرمجي واستخدم معامل `num_cores` لتعيين عدد وحدات معالجة الدقة الفائقة (TPU) التي تريد استخدامها. - -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## تشغيل نص برمجي باستخدام 🤗 Accelerate - -🤗 [Accelerate](https://huggingface.co/docs/accelerate) هي مكتبة خاصة بـ PyTorch فقط توفر طريقة موحدة لتدريب نموذج على عدة أنواع من الإعدادات (الاعتماد على وحدة المعالجة المركزية (CPU) فقط، أو وحدات معالجة الرسومات (GPUs) المتعددة، أو وحدات معالجة الدقة الفائقة (TPUs)) مع الحفاظ على الرؤية الكاملة لحلقة تدريب PyTorch. تأكد من تثبيت 🤗 Accelerate إذا لم يكن لديك بالفعل: - -> ملاحظة: نظرًا لأن Accelerate في حالة تطوير سريع، يجب تثبيت إصدار Git من Accelerate لتشغيل النصوص البرمجية. -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -بدلاً من إستخدام النص البرمجي `run_summarization.py` يجب عليك استخدام النص البرمجي `run_summarization_no_trainer.py` . ستكون النصوص البرمجية المدعومة من 🤗 Accelerate لها ملف `task_no_trainer.py` في المجلد. ابدأ بتشغيل الأمر التالي لإنشاء وحفظ ملف تكوين: - -```bash -accelerate config -``` - -اختبر إعدادك للتأكد من أنه تم تكوينه بشكل صحيح: - -```bash -accelerate test -``` - -الآن أنت مستعد لبدء التدريب: - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## استخدام مجموعة بيانات مخصصة - -يدعم النص البرمجي للتلخيص مجموعة بيانات مخصصة طالما أنها ملف CSV أو JSON Line. عندما تستخدم مجموعة بياناتك الخاصة، تحتاج إلى تحديد العديد من المعلمات الإضافية: - -- `train_file` و`validation_file` يحددان مسار ملفات التدريب والتحقق الخاصة بك. -- `text_column` النص المدخل الذي سيتم تلخيصه. -- `summary_column` النص الملخص المستهدف الذي سيتم إخراجه. - -سيبدو النص البرمجي للتلخيص الذي يستخدم مجموعة بيانات مخصصة على النحو التالي: - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## اختبار البرنامج النصي - -من الجيد غالبًا تشغيل نصك البرمجي على عدد أقل من أمثلة مجموعة البيانات للتأكد من أن كل شيء يعمل كما هو متوقع قبل الالتزام بمجموعة بيانات كاملة والتي قد تستغرق ساعات لإكمالها. استخدم المعلمات التالية لتقليص مجموعة البيانات إلى عدد أقصى من العينات: - -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -لا تدعم جميع أمثلة النصوص البرمجية المعلمة `max_predict_samples`. إذا لم تكن متأكدًا مما إذا كان نصك البرمجي يدعم هذه المعلمة، فأضف معلمة `-h` للتحقق: - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## استئناف التدريب من نقطة تفتيش - -خيار آخر مفيد لتمكينه هو استئناف التدريب من نقطة تفتيش سابقة. سيضمن ذلك أنك تستطيع الاستمرار من حيث توقفت دون البدء من جديد إذا تم مقاطعة تدريبك. هناك طريقتان لاستئناف التدريب من نقطة تفتيش. - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## شارك نموذجك - -يمكن لجميع النصوص البرمجية رفع نموذجك النهائي إلى [مركز النماذج](https://huggingface.co/models). تأكد من تسجيل الدخول إلى Hugging Face قبل البدء: - -```bash -hf auth login -``` - -ثم أضف المعلمة `push_to_hub` إلى النص البرمجي . ستقوم هذه المعلمة بإنشاء مستودع باستخدام اسم مستخدم Hugging Face واسم المجلد المحدد في `output_dir`. - -لإعطاء مستودعك اسمًا محددًا، استخدم المعلمة `push_to_hub_model_id` لإضافته. سيتم عرض المستودع تلقائيًا ضمن مساحة الاسم الخاصة بك. - -يوضح المثال التالي كيفية رفع نموذج باستخدام اسم مستودع محدد: - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` diff --git a/docs/source/ar/trainer.md b/docs/source/ar/trainer.md index be9e44cfa620..6f1162698339 100644 --- a/docs/source/ar/trainer.md +++ b/docs/source/ar/trainer.md @@ -597,42 +597,4 @@ use_cpu: false يُعد أمر [`accelerate_launch`](https://huggingface.co/docs/accelerate/package_reference/cli#accelerate-launch) هو الطريقة المُوصى بها لتشغيل نص البرمجى للتدريب على نظام موزع باستخدام Accelerate و [`Trainer`] مع المعلمات المحددة في `config_file.yaml`. يتم حفظ هذا الملف في مجلد ذاكرة التخزين المؤقت لـ Accelerate ويتم تحميله تلقائيًا عند تشغيل `accelerate_launch`. -على سبيل المثال، لتشغيل النص البرنامجي للتدريب [run_glue.py](https://github.com/huggingface/transformers/blob/f4db565b695582891e43a5e042e5d318e28f20b8/examples/pytorch/text-classification/run_glue.py#L4) مع تكوين FSDP: - -```bash -accelerate launch \ - ./examples/pytorch/text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 16 \ - --learning_rate 5e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` - -يمكنك أيضًا تحديد المعلمات من ملف `config_file.yaml` مباشرة في سطر الأوامر: - -```bash -accelerate launch --num_processes=2 \ - --use_fsdp \ - --mixed_precision=bf16 \ - --fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \ - --fsdp_transformer_layer_cls_to_wrap="BertLayer" \ - --fsdp_sharding_strategy=1 \ - --fsdp_state_dict_type=FULL_STATE_DICT \ - ./examples/pytorch/text-classification/run_glue.py - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 16 \ - --learning_rate 5e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` - اطلع على برنامج تعليمي [Launching your Accelerate scripts](https://huggingface.co/docs/accelerate/basic_tutorials/launch) لمعرفة المزيد حول `accelerate_launch` والتكوينات المخصصة. diff --git a/docs/source/ar/training.md b/docs/source/ar/training.md index 875c3fe031d0..8b8aff5a8efb 100644 --- a/docs/source/ar/training.md +++ b/docs/source/ar/training.md @@ -288,7 +288,4 @@ torch.cuda.empty_cache() لمزيد من الأمثلة على الضبط الدقيق، راجع: -- [🤗 أمثلة المحولات](https://github.com/huggingface/transformers/tree/main/examples) تتضمن - النصوص البرمجية لتدريب مهام NLP الشائعة في PyTorch وTensorFlow. - - [🤗 دفاتر ملاحظات المحولات](notebooks) يحتوي على دفاتر ملاحظات مختلفة حول كيفية ضبط نموذج لمهمة محددة في PyTorch وTensorFlow. diff --git a/docs/source/de/_toctree.yml b/docs/source/de/_toctree.yml index df772c6c788f..fe2bc4d23086 100644 --- a/docs/source/de/_toctree.yml +++ b/docs/source/de/_toctree.yml @@ -15,8 +15,6 @@ title: Vorverarbeiten - local: training title: Optimierung eines vortrainierten Modells - - local: run_scripts - title: Trainieren mit einem Skript - local: accelerate title: Verteiltes Training mit 🤗 Accelerate - local: peft diff --git a/docs/source/de/contributing.md b/docs/source/de/contributing.md index 3f2773a9b267..728de2c15b6e 100644 --- a/docs/source/de/contributing.md +++ b/docs/source/de/contributing.md @@ -242,7 +242,7 @@ Um mehr über die Prüfungen zu erfahren, die bei einer Pull-Anfrage ausgelöst ### Tests -Eine umfangreiche Test-Suite ist enthalten, um das Verhalten der Bibliothek und mehrerer Beispiele zu testen. Tests für die Bibliothek und Beispiele finden Sie jeweils im [tests](https://github.com/huggingface/transformers/tree/main/tests) und im [examples](https://github.com/huggingface/transformers/tree/main/examples) Ordner. +Eine umfangreiche Test-Suite ist enthalten, um das Verhalten der Bibliothek zu testen. Tests für die Bibliothek finden Sie im [tests](https://github.com/huggingface/transformers/tree/main/tests) Ordner. Wir bevorzugen `pytest` und `pytest-xdist`, weil es schneller ist. Geben Sie einen *Pfad zu einem Unterordner oder einer Testdatei* vom Hauptverzeichnis des Repositorys aus an, um den Test auszuführen: @@ -250,14 +250,7 @@ Wir bevorzugen `pytest` und `pytest-xdist`, weil es schneller ist. Geben Sie ein python -m pytest -n auto --dist=loadfile -s -v ./tests/models/my_new_model ``` -Analog für den `examples` Ordner, geben Sie einen *Pfad zu einem Unterordner oder einer Testdatei* an, um den Test auszuführen. Z. B. führt der folgende Befehl den Test des Unterordners für Textklassifizierung im PyTorch `examples` Ordner durch: - -```bash -pip install -r examples/xxx/requirements.txt # nur beim ersten Mal erforderlich -python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classification -``` - -Tatsächlich ist dies genau, wie unsere `make test` und `make test-examples` Befehle implementiert sind (abgesehen von `pip install`)! +Tatsächlich ist dies genau, wie unser `make test` Befehl implementiert ist! Sie können auch eine kleinere Anzahl an Tests angeben, um nur die Funktion, an der Sie arbeiten, zu testen. @@ -265,13 +258,12 @@ Standardmäßig werden langsame Tests übersprungen, aber Sie können die Umgebu -Vergessen Sie nicht, einen *Pfad zu einem Unterordner oder einer Testdatei* anzugeben, um den Test auszuführen. Sonst führen Sie alle Tests im `tests` oder `examples` Ordner aus, was sehr lange dauern wird! +Vergessen Sie nicht, einen *Pfad zu einem Unterordner oder einer Testdatei* anzugeben, um den Test auszuführen. Sonst führen Sie alle Tests im `tests` Ordner aus, was sehr lange dauern wird! ```bash RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./tests/models/my_new_model -RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classification ``` Wie bei den langsamen Tests gibt es auch andere Umgebungsvariablen, die standardmäßig beim Testen nicht gesetzt sind: @@ -286,7 +278,6 @@ Das bedeutet, `unittest` wird vollständig unterstützt. Folgend wird beschriebe ```bash python -m unittest discover -s tests -t . -v -python -m unittest discover -s examples -t examples -v ``` ### Stil-Leitfaden diff --git a/docs/source/de/installation.md b/docs/source/de/installation.md index f06c72c6ad4b..651c76acc91e 100644 --- a/docs/source/de/installation.md +++ b/docs/source/de/installation.md @@ -150,22 +150,6 @@ Fügen sie [🤗 Datasets](https://huggingface.co/docs/datasets/) zu Ihrem Offli -So würden Sie beispielsweise ein Programm in einem normalen Netzwerk mit einer Firewall für externe Instanzen mit dem folgenden Befehl ausführen: - -```bash -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -Führen Sie das gleiche Programm in einer Offline-Instanz mit aus: - -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -Das Skript sollte nun laufen, ohne sich aufzuhängen oder eine Zeitüberschreitung abzuwarten, da es weiß, dass es nur nach lokalen Dateien suchen soll. - - ### Abrufen von Modellen und Tokenizern zur Offline-Verwendung Eine andere Möglichkeit, 🤗 Transformers offline zu verwenden, besteht darin, die Dateien im Voraus herunterzuladen und dann auf ihren lokalen Pfad zu verweisen, wenn Sie sie offline verwenden müssen. Es gibt drei Möglichkeiten, dies zu tun: diff --git a/docs/source/de/run_scripts.md b/docs/source/de/run_scripts.md deleted file mode 100644 index 833d886c7e81..000000000000 --- a/docs/source/de/run_scripts.md +++ /dev/null @@ -1,284 +0,0 @@ - - -# Trainieren mit einem Skript - -Neben den 🤗 Transformers [notebooks](./notebooks) gibt es auch Beispielskripte, die zeigen, wie man ein Modell für eine Aufgabe mit [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch), [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow) oder [JAX/Flax](https://github.com/huggingface/transformers/tree/main/examples/flax) trainiert. - -Sie werden auch Skripte finden, die wir in unseren [Forschungsprojekten](https://github.com/huggingface/transformers-research-projects/) und [Legacy-Beispielen](https://github.com/huggingface/transformers/tree/main/examples/legacy) verwendet haben und die größtenteils von der Community stammen. Diese Skripte werden nicht aktiv gepflegt und erfordern eine bestimmte Version von 🤗 Transformers, die höchstwahrscheinlich nicht mit der neuesten Version der Bibliothek kompatibel ist. - -Es wird nicht erwartet, dass die Beispielskripte bei jedem Problem sofort funktionieren. Möglicherweise müssen Sie das Skript an das Problem anpassen, das Sie zu lösen versuchen. Um Ihnen dabei zu helfen, legen die meisten Skripte vollständig offen, wie die Daten vorverarbeitet werden, so dass Sie sie nach Bedarf für Ihren Anwendungsfall bearbeiten können. - -Für jede Funktion, die Sie in einem Beispielskript implementieren möchten, diskutieren Sie bitte im [Forum](https://discuss.huggingface.co/) oder in einem [issue](https://github.com/huggingface/transformers/issues), bevor Sie einen Pull Request einreichen. Wir freuen uns zwar über Fehlerkorrekturen, aber es ist unwahrscheinlich, dass wir einen Pull Request zusammenführen, der mehr Funktionalität auf Kosten der Lesbarkeit hinzufügt. - -Diese Anleitung zeigt Ihnen, wie Sie ein Beispiel für ein Trainingsskript zur Zusammenfassung in [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) und [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization) ausführen können. Sofern nicht anders angegeben, sollten alle Beispiele mit beiden Frameworks funktionieren. - -## Einrichtung - -Um die neueste Version der Beispielskripte erfolgreich auszuführen, **müssen Sie 🤗 Transformers aus dem Quellcode** in einer neuen virtuellen Umgebung installieren: - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -Für ältere Versionen der Beispielskripte klicken Sie auf die Umschalttaste unten: - -
- Beispiele für ältere Versionen von 🤗 Transformers - -
- -Dann stellen Sie Ihren aktuellen Klon von 🤗 Transformers auf eine bestimmte Version um, z.B. v3.5.1: - -```bash -git checkout tags/v3.5.1 -``` - -Nachdem Sie die richtige Bibliotheksversion eingerichtet haben, navigieren Sie zu dem Beispielordner Ihrer Wahl und installieren die beispielspezifischen Anforderungen: - -```bash -pip install -r requirements.txt -``` - -## Ein Skript ausführen - -Das Beispielskript lädt einen Datensatz aus der 🤗 [Datasets](https://huggingface.co/docs/datasets/) Bibliothek herunter und verarbeitet ihn vor. Dann nimmt das Skript eine Feinabstimmung eines Datensatzes mit dem [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) auf einer Architektur vor, die eine Zusammenfassung unterstützt. Das folgende Beispiel zeigt, wie die Feinabstimmung von [T5-small](https://huggingface.co/google-t5/t5-small) auf dem Datensatz [CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail) durchgeführt wird. Das T5-Modell benötigt aufgrund der Art und Weise, wie es trainiert wurde, ein zusätzliches Argument `source_prefix`. Mit dieser Eingabeaufforderung weiß T5, dass es sich um eine Zusammenfassungsaufgabe handelt. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Verteiltes Training und gemischte Präzision - -Der [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) unterstützt verteiltes Training und gemischte Präzision, d.h. Sie können ihn auch in einem Skript verwenden. So aktivieren Sie diese beiden Funktionen: - -- Fügen Sie das Argument `fp16` hinzu, um gemischte Genauigkeit zu aktivieren. -- Legen Sie die Anzahl der zu verwendenden GPUs mit dem Argument `nproc_per_node` fest. - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -TensorFlow-Skripte verwenden eine [`MirroredStrategy`](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy) für verteiltes Training, und Sie müssen dem Trainingsskript keine zusätzlichen Argumente hinzufügen. Das TensorFlow-Skript verwendet standardmäßig mehrere GPUs, wenn diese verfügbar sind. - -## Ein Skript auf einer TPU ausführen - -Tensor Processing Units (TPUs) sind speziell für die Beschleunigung der Leistung konzipiert. PyTorch unterstützt TPUs mit dem [XLA](https://www.tensorflow.org/xla) Deep Learning Compiler (siehe [hier](https://github.com/pytorch/xla/blob/master/README.md) für weitere Details). Um eine TPU zu verwenden, starten Sie das Skript `xla_spawn.py` und verwenden das Argument `num_cores`, um die Anzahl der TPU-Kerne festzulegen, die Sie verwenden möchten. - -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Führen Sie ein Skript mit 🤗 Accelerate aus. - -🤗 [Accelerate](https://huggingface.co/docs/accelerate) ist eine reine PyTorch-Bibliothek, die eine einheitliche Methode für das Training eines Modells auf verschiedenen Arten von Setups (nur CPU, mehrere GPUs, TPUs) bietet und dabei die vollständige Transparenz der PyTorch-Trainingsschleife beibehält. Stellen Sie sicher, dass Sie 🤗 Accelerate installiert haben, wenn Sie es nicht bereits haben: - -> Hinweis: Da Accelerate schnell weiterentwickelt wird, muss die Git-Version von Accelerate installiert sein, um die Skripte auszuführen. -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -Anstelle des Skripts `run_summarization.py` müssen Sie das Skript `run_summarization_no_trainer.py` verwenden. Die von Accelerate unterstützten Skripte haben eine Datei `task_no_trainer.py` im Ordner. Beginnen Sie mit dem folgenden Befehl, um eine Konfigurationsdatei zu erstellen und zu speichern: - -```bash -accelerate config -``` - -Testen Sie Ihre Einrichtung, um sicherzustellen, dass sie korrekt konfiguriert ist: - -```bash -accelerate test -``` - -Jetzt sind Sie bereit, das Training zu starten: - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## Verwenden Sie einen benutzerdefinierten Datensatz - -Das Verdichtungsskript unterstützt benutzerdefinierte Datensätze, solange es sich um eine CSV- oder JSON-Line-Datei handelt. Wenn Sie Ihren eigenen Datensatz verwenden, müssen Sie mehrere zusätzliche Argumente angeben: - -- `train_file` und `validation_file` geben den Pfad zu Ihren Trainings- und Validierungsdateien an. -- `text_column` ist der Eingabetext, der zusammengefasst werden soll. -- Summary_column" ist der auszugebende Zieltext. - -Ein Zusammenfassungsskript, das einen benutzerdefinierten Datensatz verwendet, würde wie folgt aussehen: - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Testen Sie ein Skript - -Es ist oft eine gute Idee, Ihr Skript an einer kleineren Anzahl von Beispielen für Datensätze auszuführen, um sicherzustellen, dass alles wie erwartet funktioniert, bevor Sie sich auf einen ganzen Datensatz festlegen, dessen Fertigstellung Stunden dauern kann. Verwenden Sie die folgenden Argumente, um den Datensatz auf eine maximale Anzahl von Stichproben zu beschränken: - -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Nicht alle Beispielskripte unterstützen das Argument `max_predict_samples`. Wenn Sie sich nicht sicher sind, ob Ihr Skript dieses Argument unterstützt, fügen Sie das Argument `-h` hinzu, um dies zu überprüfen: - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## Training vom Kontrollpunkt fortsetzen - -Eine weitere hilfreiche Option, die Sie aktivieren können, ist die Wiederaufnahme des Trainings von einem früheren Kontrollpunkt aus. Auf diese Weise können Sie im Falle einer Unterbrechung Ihres Trainings dort weitermachen, wo Sie aufgehört haben, ohne von vorne beginnen zu müssen. Es gibt zwei Methoden, um das Training von einem Kontrollpunkt aus wieder aufzunehmen. - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## Teilen Sie Ihr Modell - -Alle Skripte können Ihr endgültiges Modell in den [Model Hub](https://huggingface.co/models) hochladen. Stellen Sie sicher, dass Sie bei Hugging Face angemeldet sind, bevor Sie beginnen: - -```bash -hf auth login -``` - -Dann fügen Sie dem Skript das Argument `push_to_hub` hinzu. Mit diesem Argument wird ein Repository mit Ihrem Hugging Face-Benutzernamen und dem in `output_dir` angegebenen Ordnernamen erstellt. - -Wenn Sie Ihrem Repository einen bestimmten Namen geben möchten, fügen Sie ihn mit dem Argument `push_to_hub_model_id` hinzu. Das Repository wird automatisch unter Ihrem Namensraum aufgeführt. - -Das folgende Beispiel zeigt, wie Sie ein Modell mit einem bestimmten Repository-Namen hochladen können: - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` diff --git a/docs/source/de/testing.md b/docs/source/de/testing.md index fa8e762f0b0a..e8f1b5c55c9a 100644 --- a/docs/source/de/testing.md +++ b/docs/source/de/testing.md @@ -46,7 +46,6 @@ Es gibt 2 Testsuiten im Repository: ```bash RUN_SLOW=1 pytest tests/ -RUN_SLOW=1 pytest examples/ ``` Die Ergebnisse können Sie [hier](https://github.com/huggingface/transformers/actions) sehen. @@ -528,7 +527,7 @@ einen normalen Prozess erzeugt, der dann mehrere Worker erzeugt und die IO-Pipes Hier sind einige Tests, die dies verwenden: - [test_trainer_distributed.py](https://github.com/huggingface/transformers/tree/main/tests/trainer/distributed/test_trainer_distributed.py) -- [test_deepspeed.py](https://github.com/huggingface/transformers/tree/main/tests/deepspeed/test_deepspeed.py) +- [test_trainer_distributed_deepspeed.py](https://github.com/huggingface/transformers/tree/main/tests/trainer/distributed/test_trainer_distributed_deepspeed.py) Um direkt mit der Ausführung zu beginnen, suchen Sie in diesen Tests nach dem Aufruf `execute_subprocess_async`. @@ -734,7 +733,7 @@ from transformers.testing_utils import TestCasePlus class PathExampleTest(TestCasePlus): def test_something_involving_local_locations(self): - data_dir = self.tests_dir / "fixtures/tests_samples/wmt_en_ro" + data_dir = self.tests_dir / "fixtures/tests_samples/wmt16" ``` Wenn Sie Pfade nicht über `pathlib` manipulieren müssen oder nur einen Pfad als String benötigen, können Sie jederzeit diff --git a/docs/source/de/training.md b/docs/source/de/training.md index a671b5948374..8989fd8d5a7e 100644 --- a/docs/source/de/training.md +++ b/docs/source/de/training.md @@ -306,7 +306,4 @@ Genauso wie Sie eine Bewertungsfunktion zu [`Trainer`] hinzugefügt haben, müss Weitere Beispiele für die Feinabstimmung finden Sie unter: -- [🤗 Transformers Examples](https://github.com/huggingface/transformers/tree/main/examples) enthält Skripte - um gängige NLP-Aufgaben in PyTorch und TensorFlow zu trainieren. - - [🤗 Transformers Notebooks](notebooks) enthält verschiedene Notebooks zur Feinabstimmung eines Modells für bestimmte Aufgaben in PyTorch und TensorFlow. diff --git a/docs/source/en/_redirects.yml b/docs/source/en/_redirects.yml index 14c683b1f6b8..3493a629b7e4 100644 --- a/docs/source/en/_redirects.yml +++ b/docs/source/en/_redirects.yml @@ -16,3 +16,4 @@ task_summary: pipeline_tutorial model_summary: index migration: index tflite: community_integrations/litert +run_scripts: training diff --git a/docs/source/en/_toctree.yml b/docs/source/en/_toctree.yml index aaced448e647..d121696f960a 100644 --- a/docs/source/en/_toctree.yml +++ b/docs/source/en/_toctree.yml @@ -446,8 +446,6 @@ title: Visual document retrieval title: Multimodal title: Task recipes - - local: run_scripts - title: Training scripts - local: glossary title: Glossary - local: philosophy diff --git a/docs/source/en/installation.md b/docs/source/en/installation.md index 4aa8a5282be3..a18fea135c21 100644 --- a/docs/source/en/installation.md +++ b/docs/source/en/installation.md @@ -195,11 +195,6 @@ snapshot_download(repo_id="meta-llama/Llama-2-7b-hf", repo_type="model") Set the environment variable `HF_HUB_OFFLINE=1` to prevent HTTP calls to the Hub when loading a model. -```bash -HF_HUB_OFFLINE=1 \ -python examples/pytorch/language-modeling/run_clm.py --model_name_or_path meta-llama/Llama-2-7b-hf --dataset_name Salesforce/wikitext ... -``` - Another option for only loading cached files is to set `local_files_only=True` in [`~PreTrainedModel.from_pretrained`]. ```py diff --git a/docs/source/en/main_classes/data_collator.md b/docs/source/en/main_classes/data_collator.md index f921bd3da67c..cad3cf203f00 100644 --- a/docs/source/en/main_classes/data_collator.md +++ b/docs/source/en/main_classes/data_collator.md @@ -23,7 +23,7 @@ To be able to build batches, data collators may apply some processing (like padd [`DataCollatorForLanguageModeling`]) also apply some random data augmentation (like random masking) on the formed batch. -Examples of use can be found in the [example scripts](https://github.com/huggingface/transformers/tree/main/examples) or [example notebooks](https://github.com/huggingface/notebooks/tree/main/examples). +Examples of use can be found in the [example notebooks](https://github.com/huggingface/notebooks/tree/main/examples). ## Default data collator diff --git a/docs/source/en/model_doc/albert.md b/docs/source/en/model_doc/albert.md index 61fc46327dca..4a53e106ad57 100644 --- a/docs/source/en/model_doc/albert.md +++ b/docs/source/en/model_doc/albert.md @@ -99,32 +99,28 @@ The resources provided in the following sections consist of a list of official H -- [`AlbertForSequenceClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification). - - Check the [Text classification task guide](../tasks/sequence_classification) on how to use the model. -- [`AlbertForTokenClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification). - - [Token classification](https://huggingface.co/course/chapter7/2?fw=pt) chapter of the 🤗 Hugging Face Course. - Check the [Token classification task guide](../tasks/token_classification) on how to use the model. -- [`AlbertForMaskedLM`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). +- [`AlbertForMaskedLM`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). - [Masked language modeling](https://huggingface.co/course/chapter7/3?fw=pt) chapter of the 🤗 Hugging Face Course. - Check the [Masked language modeling task guide](../tasks/masked_language_modeling) on how to use the model. -- [`AlbertForQuestionAnswering`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb). +- [`AlbertForQuestionAnswering`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb). - [Question answering](https://huggingface.co/course/chapter7/7?fw=pt) chapter of the 🤗 Hugging Face Course. - Check the [Question answering task guide](../tasks/question_answering) on how to use the model. **Multiple choice** -- [`AlbertForMultipleChoice`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/multiple-choice) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb). +- [`AlbertForMultipleChoice`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb). - Check the [Multiple choice task guide](../tasks/multiple_choice) on how to use the model. ## AlbertConfig diff --git a/docs/source/en/model_doc/audio-spectrogram-transformer.md b/docs/source/en/model_doc/audio-spectrogram-transformer.md index cffafcf078d5..675203757f3f 100644 --- a/docs/source/en/model_doc/audio-spectrogram-transformer.md +++ b/docs/source/en/model_doc/audio-spectrogram-transformer.md @@ -86,7 +86,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h - A notebook illustrating inference with AST for audio classification can be found [here](https://github.com/NielsRogge/Transformers-Tutorials/tree/master/AST). -- [`ASTForAudioClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/audio-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb). +- [`ASTForAudioClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb). - See also: [Audio classification](../tasks/audio_classification). If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/beit.md b/docs/source/en/model_doc/beit.md index 62a7ea4ad4fc..6b6a2acda8da 100644 --- a/docs/source/en/model_doc/beit.md +++ b/docs/source/en/model_doc/beit.md @@ -120,7 +120,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`BeitForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`BeitForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) **Semantic segmentation** diff --git a/docs/source/en/model_doc/bit.md b/docs/source/en/model_doc/bit.md index 140e5000a9fe..7f8789ab87e4 100644 --- a/docs/source/en/model_doc/bit.md +++ b/docs/source/en/model_doc/bit.md @@ -43,7 +43,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`BitForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`BitForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/bloom.md b/docs/source/en/model_doc/bloom.md index 63945adf6b43..27e119a8e3d2 100644 --- a/docs/source/en/model_doc/bloom.md +++ b/docs/source/en/model_doc/bloom.md @@ -37,7 +37,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`BloomForCausalLM`] is supported by this [causal language modeling example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#gpt-2gpt-and-causal-language-modeling) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). +- [`BloomForCausalLM`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). See also: diff --git a/docs/source/en/model_doc/conditional_detr.md b/docs/source/en/model_doc/conditional_detr.md index af47e13fdf99..65a6096e81c3 100644 --- a/docs/source/en/model_doc/conditional_detr.md +++ b/docs/source/en/model_doc/conditional_detr.md @@ -35,7 +35,6 @@ This model was contributed by [DepuMeng](https://huggingface.co/DepuMeng). The o ## Resources -- Scripts for finetuning [`ConditionalDetrForObjectDetection`] with [`Trainer`] or [Accelerate](https://huggingface.co/docs/accelerate/index) can be found [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/object-detection). - See also: [Object detection task guide](../tasks/object_detection). ## ConditionalDetrConfig diff --git a/docs/source/en/model_doc/convnext.md b/docs/source/en/model_doc/convnext.md index 7ca389799bcc..7588aa2cf5a9 100644 --- a/docs/source/en/model_doc/convnext.md +++ b/docs/source/en/model_doc/convnext.md @@ -47,7 +47,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`ConvNextForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`ConvNextForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/convnextv2.md b/docs/source/en/model_doc/convnextv2.md index 37c9c345a78d..c2cd6ccc7581 100644 --- a/docs/source/en/model_doc/convnextv2.md +++ b/docs/source/en/model_doc/convnextv2.md @@ -40,7 +40,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`ConvNextV2ForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`ConvNextV2ForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/ctrl.md b/docs/source/en/model_doc/ctrl.md index 53c0ecf6d795..4deb2442f66f 100644 --- a/docs/source/en/model_doc/ctrl.md +++ b/docs/source/en/model_doc/ctrl.md @@ -52,8 +52,7 @@ This model was contributed by [keskarnitishr](https://huggingface.co/keskarnitis - CTRL is a model with absolute position embeddings so it's usually advised to pad the inputs on the right rather than the left. - CTRL was trained with a causal language modeling (CLM) objective and is therefore powerful at predicting the next - token in a sequence. Leveraging this feature allows CTRL to generate syntactically coherent text as it can be - observed in the *run_generation.py* example script. + token in a sequence. Leveraging this feature allows CTRL to generate syntactically coherent text. - The PyTorch models can take the `past_key_values` as input, which is the previously computed key/value attention pairs. Using the `past_key_values` value prevents the model from re-computing pre-computed values in the context of text generation. See the [`~CTRLModel#forward`] diff --git a/docs/source/en/model_doc/data2vec.md b/docs/source/en/model_doc/data2vec.md index 0ff1f771b49c..5f16c5fd7d22 100644 --- a/docs/source/en/model_doc/data2vec.md +++ b/docs/source/en/model_doc/data2vec.md @@ -101,7 +101,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`Data2VecVisionForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`Data2VecVisionForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). **Data2VecText documentation resources** diff --git a/docs/source/en/model_doc/deit.md b/docs/source/en/model_doc/deit.md index c0312ba47da7..e3e0298c1323 100644 --- a/docs/source/en/model_doc/deit.md +++ b/docs/source/en/model_doc/deit.md @@ -110,13 +110,9 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`DeiTForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`DeiTForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) -Besides that: - -- [`DeiTForMaskedImageModeling`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. ## DeiTConfig diff --git a/docs/source/en/model_doc/dinat.md b/docs/source/en/model_doc/dinat.md index 6dea9c5b6564..4829cfc982a5 100644 --- a/docs/source/en/model_doc/dinat.md +++ b/docs/source/en/model_doc/dinat.md @@ -74,7 +74,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`DinatForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`DinatForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/gptj.md b/docs/source/en/model_doc/gptj.md index 83e7e571d54c..01a9cfe729ac 100644 --- a/docs/source/en/model_doc/gptj.md +++ b/docs/source/en/model_doc/gptj.md @@ -129,7 +129,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h - A notebook for [GPT-J-6B Inference Demo](https://colab.research.google.com/github/kingoflolz/mesh-transformer-jax/blob/master/colab_demo.ipynb). 🌎 - Another notebook demonstrating [Inference with GPT-J-6B](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/GPT-J-6B/Inference_with_GPT_J_6B.ipynb). - [Causal language modeling](https://huggingface.co/course/en/chapter7/6?fw=pt#training-a-causal-language-model-from-scratch) chapter of the 🤗 Hugging Face Course. -- [`GPTJForCausalLM`] is supported by this [causal language modeling example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#gpt-2gpt-and-causal-language-modeling), [text generation example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-generation), and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). +- [`GPTJForCausalLM`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). **Documentation resources** diff --git a/docs/source/en/model_doc/hiera.md b/docs/source/en/model_doc/hiera.md index 9c33db5a78c8..cb487c80adf2 100644 --- a/docs/source/en/model_doc/hiera.md +++ b/docs/source/en/model_doc/hiera.md @@ -41,7 +41,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`HieraForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`HieraForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) ## HieraConfig diff --git a/docs/source/en/model_doc/imagegpt.md b/docs/source/en/model_doc/imagegpt.md index 2df08338a055..55c454e529e5 100644 --- a/docs/source/en/model_doc/imagegpt.md +++ b/docs/source/en/model_doc/imagegpt.md @@ -82,7 +82,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h - Demo notebooks for ImageGPT can be found [here](https://github.com/NielsRogge/Transformers-Tutorials/tree/master/ImageGPT). -- [`ImageGPTForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`ImageGPTForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/levit.md b/docs/source/en/model_doc/levit.md index 90331302393a..210ea9a18117 100644 --- a/docs/source/en/model_doc/levit.md +++ b/docs/source/en/model_doc/levit.md @@ -73,7 +73,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`LevitForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`LevitForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/lw_detr.md b/docs/source/en/model_doc/lw_detr.md index f1165e3bf52d..cef36e5b5688 100644 --- a/docs/source/en/model_doc/lw_detr.md +++ b/docs/source/en/model_doc/lw_detr.md @@ -96,7 +96,6 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- Scripts for finetuning [`LwDetrForObjectDetection`] with [`Trainer`] or [Accelerate](https://huggingface.co/docs/accelerate/index) can be found [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/object-detection). - See also: [Object detection task guide](../tasks/object_detection). ## LwDetrConfig diff --git a/docs/source/en/model_doc/mask2former.md b/docs/source/en/model_doc/mask2former.md index 6573af89280e..a5d637479c1f 100644 --- a/docs/source/en/model_doc/mask2former.md +++ b/docs/source/en/model_doc/mask2former.md @@ -43,7 +43,6 @@ This model was contributed by [Shivalika Singh](https://huggingface.co/shivi) an A list of official Hugging Face and community (indicated by 🌎) resources to help you get started with Mask2Former. - Demo notebooks regarding inference + fine-tuning Mask2Former on custom data can be found [here](https://github.com/NielsRogge/Transformers-Tutorials/tree/master/Mask2Former). -- Scripts for finetuning [`Mask2Former`] with [`Trainer`] or [Accelerate](https://huggingface.co/docs/accelerate/index) can be found [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/instance-segmentation). If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we will review it. The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/maskformer.md b/docs/source/en/model_doc/maskformer.md index 7d9de34c4558..36427b250d36 100644 --- a/docs/source/en/model_doc/maskformer.md +++ b/docs/source/en/model_doc/maskformer.md @@ -53,7 +53,6 @@ This model was contributed by [francesco](https://huggingface.co/francesco). The - All notebooks that illustrate inference as well as fine-tuning on custom data with MaskFormer can be found [here](https://github.com/NielsRogge/Transformers-Tutorials/tree/master/MaskFormer). -- Scripts for finetuning [`MaskFormer`] with [`Trainer`] or [Accelerate](https://huggingface.co/docs/accelerate/index) can be found [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/instance-segmentation). ## MaskFormer specific outputs diff --git a/docs/source/en/model_doc/modernbert.md b/docs/source/en/model_doc/modernbert.md index c130af456351..03c3751ed8eb 100644 --- a/docs/source/en/model_doc/modernbert.md +++ b/docs/source/en/model_doc/modernbert.md @@ -164,7 +164,3 @@ out = model(**inputs) [[autodoc]] ModernBertForQuestionAnswering - forward - -### Usage tips - -The ModernBert model can be fine-tuned using the HuggingFace Transformers library with its [official script](https://github.com/huggingface/transformers/blob/main/examples/pytorch/question-answering/run_qa.py) for question-answering tasks. diff --git a/docs/source/en/model_doc/poolformer.md b/docs/source/en/model_doc/poolformer.md index 8610e022d997..c7818d2168a9 100644 --- a/docs/source/en/model_doc/poolformer.md +++ b/docs/source/en/model_doc/poolformer.md @@ -52,7 +52,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`PoolFormerForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`PoolFormerForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/regnet.md b/docs/source/en/model_doc/regnet.md index 16e3f65bf4a6..a3ba98aed2f8 100644 --- a/docs/source/en/model_doc/regnet.md +++ b/docs/source/en/model_doc/regnet.md @@ -39,7 +39,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`RegNetForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`RegNetForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/resnet.md b/docs/source/en/model_doc/resnet.md index b2114a71e453..fa7b8e892437 100644 --- a/docs/source/en/model_doc/resnet.md +++ b/docs/source/en/model_doc/resnet.md @@ -41,7 +41,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`ResNetForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`ResNetForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/rf_detr.md b/docs/source/en/model_doc/rf_detr.md index 048b33909537..dc935394cc6a 100644 --- a/docs/source/en/model_doc/rf_detr.md +++ b/docs/source/en/model_doc/rf_detr.md @@ -194,9 +194,6 @@ sv.plot_image(annotated_image) ## Resources -- Scripts for finetuning [`RfDetrForObjectDetection`] with [`Trainer`] - or [Accelerate](https://huggingface.co/docs/accelerate/index) can be - found [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/object-detection). - See also: [Object detection task guide](../tasks/object_detection). ## RfDetrConfig diff --git a/docs/source/en/model_doc/rt_detr.md b/docs/source/en/model_doc/rt_detr.md index c0c7f8162aef..1c6e5b18e3a1 100644 --- a/docs/source/en/model_doc/rt_detr.md +++ b/docs/source/en/model_doc/rt_detr.md @@ -78,7 +78,6 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- Scripts for finetuning [`RTDetrForObjectDetection`] with [`Trainer`] or [Accelerate](https://huggingface.co/docs/accelerate/index) can be found [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/object-detection). - See also: [Object detection task guide](../tasks/object_detection). - Notebooks regarding inference and fine-tuning RT-DETR on a custom dataset can be found [here](https://github.com/NielsRogge/Transformers-Tutorials/tree/master/RT-DETR). 🌎 diff --git a/docs/source/en/model_doc/rt_detr_v2.md b/docs/source/en/model_doc/rt_detr_v2.md index 5a19dc2a09a6..cdfc15320921 100644 --- a/docs/source/en/model_doc/rt_detr_v2.md +++ b/docs/source/en/model_doc/rt_detr_v2.md @@ -81,7 +81,6 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- Scripts for finetuning [`RTDetrV2ForObjectDetection`] with [`Trainer`] or [Accelerate](https://huggingface.co/docs/accelerate/index) can be found [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/object-detection). - See also: [Object detection task guide](../tasks/object_detection). - Notebooks for [inference](https://github.com/qubvel/transformers-notebooks/blob/main/notebooks/RT_DETR_v2_inference.ipynb) and [fine-tuning](https://github.com/qubvel/transformers-notebooks/blob/main/notebooks/RT_DETR_v2_finetune_on_a_custom_dataset.ipynb) RT-DETRv2 on a custom dataset (🌎). diff --git a/docs/source/en/model_doc/splinter.md b/docs/source/en/model_doc/splinter.md index 6fae43e096bc..750ecb12859f 100644 --- a/docs/source/en/model_doc/splinter.md +++ b/docs/source/en/model_doc/splinter.md @@ -44,10 +44,9 @@ This model was contributed by [yuvalkirstain](https://huggingface.co/yuvalkirsta to question representations which are used to predict the answers. This layer is called QASS, and is the default behaviour in the [`SplinterForQuestionAnswering`] class. Therefore: - Use [`SplinterTokenizer`] (rather than [`BertTokenizer`]), as it already - contains this special token. Also, its default behavior is to use this token when two sequences are given (for - example, in the *run_qa.py* script). -- If you plan on using Splinter outside *run_qa.py*, please keep in mind the question token - it might be important for - the success of your model, especially in a few-shot setting. + contains this special token. Also, its default behavior is to use this token when two sequences are given. +- Keep in mind the question token - it might be important for the success of your model, especially in a few-shot + setting. - Please note there are two different checkpoints for each size of Splinter. Both are basically the same, except that one also has the pretrained weights of the QASS layer (*tau/splinter-base-qass* and *tau/splinter-large-qass*) and one doesn't (*tau/splinter-base* and *tau/splinter-large*). This is done to support randomly initializing this layer at diff --git a/docs/source/en/model_doc/upernet.md b/docs/source/en/model_doc/upernet.md index 2f162e664d47..cb721e1e1152 100644 --- a/docs/source/en/model_doc/upernet.md +++ b/docs/source/en/model_doc/upernet.md @@ -68,7 +68,7 @@ Note that this will randomly initialize all the weights of the model. A list of official Hugging Face and community (indicated by 🌎) resources to help you get started with UPerNet. - Demo notebooks for UPerNet can be found [here](https://github.com/NielsRogge/Transformers-Tutorials/tree/master/UPerNet). -- [`UperNetForSemanticSegmentation`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/semantic-segmentation) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/semantic_segmentation.ipynb). +- [`UperNetForSemanticSegmentation`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/semantic_segmentation.ipynb). - See also: [Semantic segmentation task guide](../tasks/semantic_segmentation) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/vit_msn.md b/docs/source/en/model_doc/vit_msn.md index 6d0789388d98..5f16118c6991 100644 --- a/docs/source/en/model_doc/vit_msn.md +++ b/docs/source/en/model_doc/vit_msn.md @@ -91,7 +91,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h -- [`ViTMSNForImageClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). +- [`ViTMSNForImageClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb). - See also: [Image classification task guide](../tasks/image_classification) If you're interested in submitting a resource to be included here, please feel free to open a Pull Request and we'll review it! The resource should ideally demonstrate something new instead of duplicating an existing resource. diff --git a/docs/source/en/model_doc/wav2vec2-bert.md b/docs/source/en/model_doc/wav2vec2-bert.md index 454908c7e898..de81988c1641 100644 --- a/docs/source/en/model_doc/wav2vec2-bert.md +++ b/docs/source/en/model_doc/wav2vec2-bert.md @@ -49,12 +49,10 @@ This model was contributed by [ylacombe](https://huggingface.co/ylacombe). The o -- [`Wav2Vec2BertForCTC`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/speech-recognition). - You can also adapt these notebooks on [how to finetune a speech recognition model in English](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/speech_recognition.ipynb), and [how to finetune a speech recognition model in any language](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multi_lingual_speech_recognition.ipynb). -- [`Wav2Vec2BertForSequenceClassification`] can be used by adapting this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/audio-classification). - See also: [Audio classification task guide](../tasks/audio_classification) ## Wav2Vec2BertConfig diff --git a/docs/source/en/model_doc/wav2vec2.md b/docs/source/en/model_doc/wav2vec2.md index 58b6ef615ad1..d9658e5b3fe8 100644 --- a/docs/source/en/model_doc/wav2vec2.md +++ b/docs/source/en/model_doc/wav2vec2.md @@ -91,7 +91,7 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h - A notebook on how to [leverage a pretrained Wav2Vec2 model for emotion classification](https://colab.research.google.com/github/m3hrdadfi/soxan/blob/main/notebooks/Emotion_recognition_in_Greek_speech_using_Wav2Vec2.ipynb). 🌎 -- [`Wav2Vec2ForCTC`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/audio-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb). +- [`Wav2Vec2ForCTC`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb). - [Audio classification task guide](../tasks/audio_classification) diff --git a/docs/source/en/model_doc/xlm-roberta.md b/docs/source/en/model_doc/xlm-roberta.md index 3ebaea819fdf..870c4f455d8b 100644 --- a/docs/source/en/model_doc/xlm-roberta.md +++ b/docs/source/en/model_doc/xlm-roberta.md @@ -121,37 +121,37 @@ A list of official Hugging Face and community (indicated by 🌎) resources to h - A blog post on how to [finetune XLM RoBERTa for multiclass classification with Habana Gaudi on AWS](https://www.philschmid.de/habana-distributed-training) -- [`XLMRobertaForSequenceClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb).. +- [`XLMRobertaForSequenceClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb).. - [Text classification](../tasks/sequence_classification) chapter of the 🤗 Hugging Face Task Guides. - [Text classification task guide](../tasks/sequence_classification) -- [`XLMRobertaForTokenClassification`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb). +- [`XLMRobertaForTokenClassification`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb). - [Token classification](https://huggingface.co/course/chapter7/2?fw=pt) chapter of the 🤗 Hugging Face Course. - [Token classification task guide](../tasks/token_classification) -- [`XLMRobertaForCausalLM`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). +- [`XLMRobertaForCausalLM`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). - [Causal language modeling](../tasks/language_modeling) chapter of the 🤗 Hugging Face Task Guides. - [Causal language modeling task guide](../tasks/language_modeling) -- [`XLMRobertaForMaskedLM`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). +- [`XLMRobertaForMaskedLM`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). - [Masked language modeling](https://huggingface.co/course/chapter7/3?fw=pt) chapter of the 🤗 Hugging Face Course. - [Masked language modeling](../tasks/masked_language_modeling) -- [`XLMRobertaForQuestionAnswering`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb). +- [`XLMRobertaForQuestionAnswering`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb). - [Question answering](https://huggingface.co/course/chapter7/7?fw=pt) chapter of the 🤗 Hugging Face Course. - [Question answering task guide](../tasks/question_answering) **Multiple choice** -- [`XLMRobertaForMultipleChoice`] is supported by this [example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/multiple-choice) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb). +- [`XLMRobertaForMultipleChoice`] is supported by this [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb). - [Multiple choice task guide](../tasks/multiple_choice) 🚀 Deploy diff --git a/docs/source/en/model_doc/xlnet.md b/docs/source/en/model_doc/xlnet.md index d145e2c4a6c8..fddc99742c26 100644 --- a/docs/source/en/model_doc/xlnet.md +++ b/docs/source/en/model_doc/xlnet.md @@ -45,8 +45,7 @@ This model was contributed by [thomwolf](https://huggingface.co/thomwolf). The o - Due to the difficulty of training a fully auto-regressive model over various factorization order, XLNet is pretrained using only a sub-set of the output tokens as target which are selected with the `target_mapping` input. - To use XLNet for sequential decoding (i.e. not in fully bi-directional setting), use the `perm_mask` and - `target_mapping` inputs to control the attention span and outputs (see examples in - *examples/pytorch/text-generation/run_generation.py*) + `target_mapping` inputs to control the attention span and outputs - XLNet is one of the few models that has no sequence length limit. - XLNet is not a traditional autoregressive model but uses a training strategy that builds on that. It permutes the tokens in the sentence, then allows the model to use the last n tokens to predict the token n+1. Since this is all done with a mask, the sentence is actually fed in the model in the right order, but instead of masking the first n tokens for n+1, XLNet uses a mask that hides the previous tokens in some given permutation of 1,…,sequence length. - XLNet also uses the same recurrence mechanism as Transformer-XL to build long-term dependencies. diff --git a/docs/source/en/perf_train_cpu.md b/docs/source/en/perf_train_cpu.md index c4db98d310f5..7991b58ff34f 100644 --- a/docs/source/en/perf_train_cpu.md +++ b/docs/source/en/perf_train_cpu.md @@ -28,25 +28,7 @@ All distributed examples use [Intel MPI](https://www.intel.com/content/www/us/en -[`Trainer`] supports bf16 mixed precision training on CPU. Prefer bf16 over fp16 for CPU training because it's more numerically stable. Pass `--bf16` to enable PyTorch's CPU autocast and `--use_cpu` to force CPU training. The example below runs the [run_qa.py](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) script. - -```bash -python run_qa.py \ - --model_name_or_path google-bert/bert-base-uncased \ - --dataset_name rajpurkar/squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ \ - --bf16 \ - --use_cpu -``` - -You can pass the same parameters to [`TrainingArguments`] directly. +[`Trainer`] supports bf16 mixed precision training on CPU. Prefer bf16 over fp16 for CPU training because it's more numerically stable. Pass `--bf16` to enable PyTorch's CPU autocast and `--use_cpu` to force CPU training. You can pass the same parameters to [`TrainingArguments`] directly. ```py from transformers import TrainingArguments @@ -61,7 +43,7 @@ training_args = TrainingArguments( -On a dual-socket CPU, run one process per socket. Keeping memory accesses local to each socket improves throughput. The example below launches two processes on a single machine with one process per socket. +On a dual-socket CPU, run one process per socket. Keeping memory accesses local to each socket improves throughput. The example below launches two processes on a single machine with one process per socket, where `train.py` is your [`Trainer`] training script. > [!TIP] > Set `OMP_NUM_THREADS` to the number of physical cores on one socket, minus one core reserved for the OS. For example, on a 24-core socket set `OMP_NUM_THREADS=23`. @@ -69,17 +51,10 @@ On a dual-socket CPU, run one process per socket. Keeping memory accesses local ```bash export MASTER_ADDR=127.0.0.1 mpirun -n 2 -genv OMP_NUM_THREADS=23 \ -python3 run_qa.py \ - --model_name_or_path google-bert/bert-large-uncased \ - --dataset_name rajpurkar/squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ +python3 train.py \ + --output_dir ./outputs \ + --use_cpu \ + --bf16 ``` @@ -106,17 +81,8 @@ Then run the training script. export MASTER_ADDR=xxx.xxx.xxx.xxx #node0 ip mpirun -f hostfile -n 4 -ppn 2 \ -genv OMP_NUM_THREADS=23 \ -python3 run_qa.py \ - --model_name_or_path google-bert/bert-large-uncased \ - --dataset_name rajpurkar/squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ \ +python3 train.py \ + --output_dir ./outputs \ --use_cpu \ --bf16 ``` @@ -150,12 +116,9 @@ RUN apt-get update -y && \ WORKDIR /workspace -# Download and extract the transformers code -ARG HF_TRANSFORMERS_VER="4.46.0" -RUN pip install --no-cache-dir \ - transformers==${HF_TRANSFORMERS_VER} && \ - mkdir transformers && \ - curl -sSL --retry 5 https://github.com/huggingface/transformers/archive/refs/tags/v${HF_TRANSFORMERS_VER}.tar.gz | tar -C transformers --strip-components=1 -xzf - +# Install Transformers and copy your training script into the image +RUN pip install --no-cache-dir transformers +COPY train.py /workspace/train.py ``` Build the image and push it to a registry accessible from your cluster's nodes before deploying. @@ -164,7 +127,7 @@ Build the image and push it to a registry accessible from your cluster's nodes b [PyTorchJob](https://www.kubeflow.org/docs/components/training/user-guides/pytorch/) is a Kubernetes custom resource that manages PyTorch distributed training jobs. It handles worker pod lifecycle, restart policy, and process coordination. Your training script only needs to handle the model and data. -The example yaml file below sets up four workers running the [run_qa.py](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) script with bf16 enabled. +The example yaml file below sets up four workers running a training script with bf16 enabled. When setting CPU resource limits and requests, use [CPU units](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-cpu) where one unit equals one physical core or virtual core. Set both limits and requests to the same value for a `Guaranteed` [quality of service](https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod). Leave some cores unallocated for kubelet and system processes. Set `OMP_NUM_THREADS` to match the number of allocated CPU units so PyTorch uses all available cores. @@ -194,18 +157,14 @@ spec: command: ["/bin/bash", "-c"] args: - >- - cd /workspace/transformers; - pip install -r /workspace/transformers/examples/pytorch/question-answering/requirements.txt; - torchrun /workspace/transformers/examples/pytorch/question-answering/run_qa.py \ + cd /workspace; + torchrun train.py \ --model_name_or_path distilbert/distilbert-base-uncased \ - --dataset_name rajpurkar/squad \ --do_train \ --do_eval \ --per_device_train_batch_size 12 \ --learning_rate 3e-5 \ --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ --output_dir /tmp/pvc-mount/output_$(date +%Y%m%d_%H%M%S) \ --bf16; env: diff --git a/docs/source/en/run_scripts.md b/docs/source/en/run_scripts.md deleted file mode 100644 index 8e99339cc058..000000000000 --- a/docs/source/en/run_scripts.md +++ /dev/null @@ -1,202 +0,0 @@ - - -# Training scripts - -Transformers provides many example training scripts for PyTorch and tasks in [transformers/examples](https://github.com/huggingface/transformers/tree/main/examples). There are additional scripts in [transformers/research projects](https://github.com/huggingface/transformers-research-projects/) and [transformers/legacy](https://github.com/huggingface/transformers/tree/main/examples/legacy), but these aren't actively maintained and requires a specific version of Transformers. - -Example scripts are only examples and you may need to adapt the script to your use-case. To help you with this, most scripts are very transparent in how data is preprocessed, allowing you to edit it as necessary. - -For any feature you'd like to implement in an example script, please discuss it on the [forum](https://discuss.huggingface.co/) or in an [issue](https://github.com/huggingface/transformers/issues) before submitting a pull request. While we welcome contributions, it is unlikely a pull request that adds more functionality is added at the cost of readability. - -This guide will show you how to run an example summarization training script in [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization). - -## Setup - -Install Transformers from source in a new virtual environment to run the latest version of the example script. - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -Run the command below to checkout a script from a specific or older version of Transformers. - -```bash -git checkout tags/v3.5.1 -``` - -After you've setup the correct version, navigate to the example folder of your choice and install the example specific requirements. - -```bash -pip install -r requirements.txt -``` - -## Run a script - -Start with a smaller dataset by including the `max_train_samples`, `max_eval_samples`, and `max_predict_samples` parameters to truncate the dataset to a maximum number of samples. This helps ensure training works as expected before committing to the entire dataset which can take hours to complete. - -> [!WARNING] -> Not all example scripts support the `max_predict_samples` parameter. Run the command below to check whether a script supports it or not. -> -> ```bash -> python examples/pytorch/summarization/run_summarization.py -h -> ``` - -The example below fine-tunes [T5-small](https://huggingface.co/google-t5/t5-small) on the [CNN/DailyMail](https://huggingface.co/datasets/abisee/cnn_dailymail) dataset. T5 requires an additional `source_prefix` parameter to prompt it to summarize. - -The example script downloads and preprocesses a dataset, and then fine-tunes it with [`Trainer`] with a supported model architecture. - -Resuming training from a checkpoint is very useful if training is interrupted because you don't have to start over again: - -* `--resume_from_checkpoint path_to_specific_checkpoint` resumes training from a specific checkpoint folder. - -Share your model on the [Hub](https://huggingface.co/) with the `--push_to_hub` parameter. It creates a repository and uploads the model to the folder name specified in `--output_dir`. You could also use the `--push_to_hub_model_id` parameter to specify the repository name. - -Drop the `max_train_samples`, `max_eval_samples`, and `max_predict_samples` parameters once everything works, and add `--resume_from_checkpoint path_to_specific_checkpoint` to resume from a checkpoint. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name abisee/cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --predict_with_generate -``` - -For mixed precision and distributed training, include the following parameters and launch training with [torchrun](https://pytorch.org/docs/stable/elastic/run.html). - -* Add the `fp16` or `bf16` parameters to enable mixed precision training. XPU devices only supports `bf16`. -* Add the `nproc_per_node` parameter to set number of GPUs to train with. - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - ... - ... -``` - -PyTorch supports TPUs, hardware designed to accelerate performance, through the [PyTorch/XLA](https://github.com/pytorch/xla/blob/master/README.md) package. Launch the `xla_spawn.py` script and use `num_cores` to set the number of TPU cores to train with. - -```bash -python xla_spawn.py --num_cores 8 pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - ... - ... -``` - -### Run a script on Hugging Face Jobs - -The example scripts declare their dependencies in a [PEP 723](https://peps.python.org/pep-0723/) `# /// script` header, so they run on [Hugging Face Jobs](https://huggingface.co/docs/hub/jobs) straight from their GitHub URL. You rent a GPU for the length of the run and skip setting up a local environment. - -[Install](https://huggingface.co/docs/huggingface_hub/en/guides/cli#getting-started) the `hf` CLI and run `hf auth login`. Pass the script URL to `hf jobs uv run` and put the script arguments after it. - -- `--flavor`: pick the hardware -- `--timeout`: set the timeout limit (30 minutes by default) -- `-s HF_TOKEN`: forward your token so `--push_to_hub` works - -The `--` before the URL keeps Job flags and script flags apart, so a script argument that shares a name with an `hf` flag, such as `--token`, goes to the script. - -```bash -hf jobs uv run --flavor a10g-small --timeout 30m -s HF_TOKEN -- \ - https://raw.githubusercontent.com/huggingface/transformers/main/examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name abisee/cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --max_train_samples 500 \ - --max_eval_samples 100 \ - --output_dir finetuned-t5-cnn_dailymail \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --push_to_hub \ - --predict_with_generate -``` - -This trains on 500 examples and finishes in about three minutes. For the full run, drop `--max_train_samples` and `--max_eval_samples` and raise `--timeout`. The header installs Transformers from `main`, so the run uses the same code as the script. See [Train Models on Jobs](https://huggingface.co/docs/hub/jobs-training) for hardware, checkpoints, and multi-GPU runs. - -## Accelerate - -[Accelerate](https://huggingface.co/docs/accelerate) is designed to simplify distributed training while offering complete visibility into the PyTorch training loop. If you're planning on training with a script with Accelerate, use the `_no_trainer.py` version of the script. - -Install Accelerate from source to ensure you have the latest version. - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -Run the [accelerate config](https://huggingface.co/docs/accelerate/package_reference/cli#accelerate-config) command to answer a few questions about your training setup. This creates and saves a config file about your system. - -```bash -accelerate config -``` - -You can use [accelerate test](https://huggingface.co/docs/accelerate/package_reference/cli#accelerate-test) to ensure your system is properly configured. - -```bash -accelerate test -``` - -Run [accelerate launch](https://huggingface.co/docs/accelerate/package_reference/cli#accelerate-launch) to start training. - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name abisee/cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization \ -``` - -## Custom dataset - -The summarization scripts supports custom datasets as long as they are a CSV or JSONL file. When using your own dataset, you need to specify the following additional parameters. - -* `train_file` and `validation_file` specify the path to your training and validation files. -* `text_column` is the input text to summarize. -* `summary_column` is the target text to output. - -An example command for summarizing a custom dataset is shown below. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate \ -``` diff --git a/docs/source/en/tasks/semantic_segmentation.md b/docs/source/en/tasks/semantic_segmentation.md index e9f56b76d608..37a9c155299a 100644 --- a/docs/source/en/tasks/semantic_segmentation.md +++ b/docs/source/en/tasks/semantic_segmentation.md @@ -261,58 +261,6 @@ You'll also want to create a dictionary that maps a label id to a label class wh >>> num_labels = len(id2label) ``` -#### Custom dataset - -You could also create and use your own dataset if you prefer to train with the [run_semantic_segmentation.py](https://github.com/huggingface/transformers/blob/main/examples/pytorch/semantic-segmentation/run_semantic_segmentation.py) script instead of a notebook instance. The script requires: - -1. a [`~datasets.DatasetDict`] with two [`~datasets.Image`] columns, "image" and "label" - - ```py - from datasets import Dataset, DatasetDict, Image - - image_paths_train = ["path/to/image_1.jpg/jpg", "path/to/image_2.jpg/jpg", ..., "path/to/image_n.jpg/jpg"] - label_paths_train = ["path/to/annotation_1.png", "path/to/annotation_2.png", ..., "path/to/annotation_n.png"] - - image_paths_validation = [...] - label_paths_validation = [...] - - def create_dataset(image_paths, label_paths): - dataset = Dataset.from_dict({"image": sorted(image_paths), - "label": sorted(label_paths)}) - dataset = dataset.cast_column("image", Image()) - dataset = dataset.cast_column("label", Image()) - return dataset - - # step 1: create Dataset objects - train_dataset = create_dataset(image_paths_train, label_paths_train) - validation_dataset = create_dataset(image_paths_validation, label_paths_validation) - - # step 2: create DatasetDict - dataset = DatasetDict({ - "train": train_dataset, - "validation": validation_dataset, - } - ) - - # step 3: push to Hub (assumes you have ran the hf auth login command in a terminal/notebook) - dataset.push_to_hub("your-name/dataset-repo") - - # optionally, you can push to a private repo on the Hub - # dataset.push_to_hub("name of repo on the hub", private=True) - ``` - -2. an id2label dictionary mapping the class integers to their class names - - ```py - import json - # simple example - id2label = {0: 'cat', 1: 'dog'} - with open('id2label.json', 'w') as fp: - json.dump(id2label, fp) - ``` - -As an example, take a look at this [example dataset](https://huggingface.co/datasets/nielsr/ade20k-demo) which was created with the steps shown above. - ### Preprocess The next step is to load a SegFormer image processor to prepare the images and annotations for the model. Some datasets, like this one, use the zero-index as the background class. However, the background class isn't actually included in the 150 classes, so you'll need to set `do_reduce_labels=True` to subtract one from all the labels. The zero-index is replaced by `255` so it's ignored by SegFormer's loss function: diff --git a/docs/source/en/training.md b/docs/source/en/training.md index d6fcf36338b6..019bf092b378 100644 --- a/docs/source/en/training.md +++ b/docs/source/en/training.md @@ -159,5 +159,5 @@ trainer.push_to_hub() - Read the [Subclassing Trainer methods](./trainer_customize) guide to learn how to subclass [`Trainer`] methods to support new and custom functionalities. - Read the [Callbacks](./trainer_callbacks) guide to learn how to hook into training events for logging, early stopping, and other custom behavior. - Read the [Data collators](./data_collators) guide to learn how to customize how samples are assembled into batches. -- Run any example script on a rented GPU with [Hugging Face Jobs](https://huggingface.co/docs/hub/jobs-training) (see [Run a script on Hugging Face Jobs](./run_scripts#run-a-script-on-hugging-face-jobs)). -- Browse [transformers/examples/pytorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch), [notebooks](./notebooks), or the **Resources > Task Recipes** section for additional training examples on different text, audio, vision, and multimodal tasks. +- Run a training script on a rented GPU with [Hugging Face Jobs](https://huggingface.co/docs/hub/jobs-training). +- Browse [notebooks](./notebooks) or the **Resources > Task Recipes** section for additional training examples on different text, audio, vision, and multimodal tasks. diff --git a/docs/source/es/_toctree.yml b/docs/source/es/_toctree.yml index dba06471b72a..36870da925dd 100644 --- a/docs/source/es/_toctree.yml +++ b/docs/source/es/_toctree.yml @@ -58,8 +58,6 @@ title: Crea una arquitectura personalizada - local: custom_models title: Compartir modelos personalizados - - local: run_scripts - title: Entrenamiento con scripts - local: chat_templating title: Plantillas para Modelos de Chat - local: trainer diff --git a/docs/source/es/installation.md b/docs/source/es/installation.md index 2cd8b3a6d0bd..34eaebb304ad 100644 --- a/docs/source/es/installation.md +++ b/docs/source/es/installation.md @@ -142,21 +142,6 @@ Puedes añadir [🤗 Datasets](https://huggingface.co/docs/datasets/) al flujo d -Por ejemplo, normalmente ejecutarías un programa en una red normal con firewall para instancias externas con el siguiente comando: - -```bash -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -Ejecuta este mismo programa en una instancia offline con el siguiente comando: - -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -El script ahora debería ejecutarse sin bloquearse ni esperar a que se agote el tiempo de espera porque sabe que solo debe buscar archivos locales. - ### Obtener modelos y tokenizers para uso offline Otra opción para usar 🤗 Transformers offline es descargando previamente los archivos y después apuntar al path local donde se encuentren. Hay tres maneras de hacer esto: diff --git a/docs/source/es/multilingual.md b/docs/source/es/multilingual.md index d49d54f196d5..fae0a0f4ca6e 100644 --- a/docs/source/es/multilingual.md +++ b/docs/source/es/multilingual.md @@ -77,8 +77,6 @@ Ahora puedes pasar los `input_ids` y el language embedding al modelo: >>> outputs = model(input_ids, langs=langs) ``` -El script [run_generation.py](https://github.com/huggingface/transformers/tree/master/examples/pytorch/text-generation/run_generation.py) puede generar texto con language embeddings utilizando los checkpoints `xlm-clm`. - ### XLM sin language embeddings Los siguientes modelos XLM no requieren language embeddings durante la inferencia: diff --git a/docs/source/es/run_scripts.md b/docs/source/es/run_scripts.md deleted file mode 100644 index 6db78af2ce5e..000000000000 --- a/docs/source/es/run_scripts.md +++ /dev/null @@ -1,284 +0,0 @@ - - -# Entrenamiento con scripts - -Junto con los [notebooks](./notebooks) de 🤗 Transformers, también hay scripts con ejemplos que muestran cómo entrenar un modelo para una tarea en [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch), [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow), o [JAX/Flax](https://github.com/huggingface/transformers/tree/main/examples/flax). - -También encontrarás scripts que hemos usado en nuestros [proyectos de investigación](https://github.com/huggingface/transformers-research-projects/) y [ejemplos pasados](https://github.com/huggingface/transformers/tree/main/examples/legacy) que en su mayoría son aportados por la comunidad. Estos scripts no se mantienen activamente y requieren una versión específica de 🤗 Transformers que probablemente sea incompatible con la última versión de la biblioteca. - -No se espera que los scripts de ejemplo funcionen de inmediato en todos los problemas, y es posible que debas adaptar el script al problema que estás tratando de resolver. Para ayudarte con esto, la mayoría de los scripts exponen completamente cómo se preprocesan los datos, lo que te permite editarlos según sea necesario para tu caso de uso. - -Para cualquier característica que te gustaría implementar en un script de ejemplo, por favor discútelo en el [foro](https://discuss.huggingface.co/) o con un [issue](https://github.com/huggingface/transformers/issues) antes de enviar un Pull Request. Si bien agradecemos las correcciones de errores, es poco probable que fusionemos un Pull Request que agregue más funcionalidad a costa de la legibilidad. - -Esta guía te mostrará cómo ejecutar un ejemplo de un script de entrenamiento para resumir texto en [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) y [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization). Se espera que todos los ejemplos funcionen con ambos frameworks a menos que se especifique lo contrario. - -## Configuración - -Para ejecutar con éxito la última versión de los scripts de ejemplo debes **instalar 🤗 Transformers desde su fuente** en un nuevo entorno virtual: - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -Para versiones anteriores de los scripts de ejemplo, haz clic en alguno de los siguientes links: - -
- Ejemplos de versiones anteriores de 🤗 Transformers - -
- -Luego cambia tu clon actual de 🤗 Transformers a una versión específica, por ejemplo v3.5.1: - -```bash -git checkout tags/v3.5.1 -``` - -Una vez que hayas configurado la versión correcta de la biblioteca, ve a la carpeta de ejemplo de tu elección e instala los requisitos específicos del ejemplo: - -```bash -pip install -r requirements.txt -``` - -## Ejecutar un script - -El script de ejemplo descarga y preprocesa un conjunto de datos de la biblioteca 🤗 [Datasets](https://huggingface.co/docs/datasets/). Luego, el script ajusta un conjunto de datos con [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) en una arquitectura que soporta la tarea de resumen. El siguiente ejemplo muestra cómo ajustar un [T5-small](https://huggingface.co/google-t5/t5-small) en el conjunto de datos [CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail). El modelo T5 requiere un argumento adicional `source_prefix` debido a cómo fue entrenado. Este aviso le permite a T5 saber que se trata de una tarea de resumir. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Entrenamiento distribuido y de precisión mixta - -[Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) admite un entrenamiento distribuido y de precisión mixta, lo que significa que también puedes usarlo en un script. Para habilitar ambas características: - -- Agrega el argumento `fp16` para habilitar la precisión mixta. -- Establece la cantidad de GPU que se usará con el argumento `nproc_per_node`. - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Los scripts de TensorFlow utilizan [`MirroredStrategy`](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy) para el entrenamiento distribuido, y no es necesario agregar argumentos adicionales al script de entrenamiento. El script de TensorFlow utilizará múltiples GPUs de forma predeterminada si están disponibles. - -## Ejecutar un script en una TPU - -Las Unidades de Procesamiento de Tensor (TPUs) están diseñadas específicamente para acelerar el rendimiento. PyTorch admite TPU con el compilador de aprendizaje profundo [XLA](https://www.tensorflow.org/xla) (consulta [aquí](https://github.com/pytorch/xla/blob/master/README.md) para obtener más detalles). Para usar una TPU, inicia el script `xla_spawn.py` y usa el argumento `num_cores` para establecer la cantidad de núcleos de TPU que deseas usar. - -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Ejecutar un script con 🤗 Accelerate - -🤗 [Accelerate](https://huggingface.co/docs/accelerate) es una biblioteca exclusiva de PyTorch que ofrece un método unificado para entrenar un modelo en varios tipos de configuraciones (solo CPU, GPU múltiples, TPU) mientras mantiene una visibilidad completa en el ciclo de entrenamiento de PyTorch. Asegúrate de tener 🤗 Accelerate instalado si aún no lo tienes: - -> Nota: Como Accelerate se está desarrollando rápidamente, debes instalar la versión git de Accelerate para ejecutar los scripts -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -En lugar del script `run_summarization.py`, debes usar el script `run_summarization_no_trainer.py`. Los scripts compatibles con 🤗 Accelerate tendrán un archivo `task_no_trainer.py` en la carpeta. Comienza ejecutando el siguiente comando para crear y guardar un archivo de configuración: - -```bash -accelerate config -``` - -Prueba tu configuración para asegurarte que está configurada correctamente: - -```bash -accelerate test -``` - -Todo listo para iniciar el entrenamiento: - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## Usar un conjunto de datos personalizado - -El script de la tarea resumir admite conjuntos de datos personalizados siempre que sean un archivo CSV o JSON Line. Cuando uses tu propio conjunto de datos, necesitas especificar varios argumentos adicionales: - -- `train_file` y `validation_file` especifican la ruta a tus archivos de entrenamiento y validación. -- `text_column` es el texto de entrada para resumir. -- `summary_column` es el texto de destino para la salida. - -Un script para resumir que utiliza un conjunto de datos personalizado se vera así: - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Prueba un script - -A veces, es una buena idea ejecutar tu secuencia de comandos en una cantidad menor de ejemplos para asegurarte de que todo funciona como se espera antes de comprometerte con un conjunto de datos completo, lo que puede demorar horas en completarse. Utiliza los siguientes argumentos para truncar el conjunto de datos a un número máximo de muestras: - -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -No todos los scripts de ejemplo admiten el argumento `max_predict_samples`. Puede que desconozcas si la secuencia de comandos admite este argumento, agrega `-h` para verificar: - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## Reanudar el entrenamiento desde el punto de control - -Otra opción útil para habilitar es reanudar el entrenamiento desde un punto de control anterior. Esto asegurará que puedas continuar donde lo dejaste sin comenzar de nuevo si tu entrenamiento se interrumpe. Hay dos métodos para reanudar el entrenamiento desde un punto de control. - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## Comparte tu modelo - -Todos los scripts pueden cargar tu modelo final en el [Model Hub](https://huggingface.co/models). Asegúrate de haber iniciado sesión en Hugging Face antes de comenzar: - -```bash -hf auth login -``` - -Luego agrega el argumento `push_to_hub` al script. Este argumento creará un repositorio con tu nombre de usuario Hugging Face y el nombre de la carpeta especificado en `output_dir`. - -Para darle a tu repositorio un nombre específico, usa el argumento `push_to_hub_model_id` para añadirlo. El repositorio se incluirá automáticamente en tu namespace. - -El siguiente ejemplo muestra cómo cargar un modelo con un nombre de repositorio específico: - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` diff --git a/docs/source/es/trainer.md b/docs/source/es/trainer.md index 335ec54b39bd..1792c590674c 100644 --- a/docs/source/es/trainer.md +++ b/docs/source/es/trainer.md @@ -367,42 +367,4 @@ use_cpu: false El comando [`accelerate_launch`](https://huggingface.co/docs/accelerate/package_reference/cli#accelerate-launch) es la forma recomendada de lanzar tu script de entrenamiento en un sistema distribuido con Accelerate y [`Trainer`] con los parámetros especificados en `config_file.yaml`. Este archivo se guarda en la carpeta de caché de Accelerate y se carga automáticamente cuando ejecutas `accelerate_launch`. -Por ejemplo, para ejecutar el script de entrenamiento [`run_glue.py`](https://github.com/huggingface/transformers/blob/f4db565b695582891e43a5e042e5d318e28f20b8/examples/pytorch/text-classification/run_glue.py#L4) con la configuración de FSDP: - -```bash -accelerate launch \ - ./examples/pytorch/text-classification/run_glue.py \ - --model_name_or_path bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 16 \ - --learning_rate 5e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` - -También puedes especificar los parámetros del archivo config_file.yaml directamente en la línea de comandos: - -```bash -accelerate launch --num_processes=2 \ - --use_fsdp \ - --mixed_precision=bf16 \ - --fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \ - --fsdp_transformer_layer_cls_to_wrap="BertLayer" \ - --fsdp_sharding_strategy=1 \ - --fsdp_state_dict_type=FULL_STATE_DICT \ - ./examples/pytorch/text-classification/run_glue.py - --model_name_or_path bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 16 \ - --learning_rate 5e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` - Consulta el tutorial [Lanzamiento de tus scripts con Accelerate](https://huggingface.co/docs/accelerate/basic_tutorials/launch) para obtener más información sobre `accelerate_launch` y las configuraciones personalizadas. diff --git a/docs/source/es/training.md b/docs/source/es/training.md index dd7285a5c2ca..a44c08577eed 100644 --- a/docs/source/es/training.md +++ b/docs/source/es/training.md @@ -365,7 +365,4 @@ De la misma manera que necesitas añadir una función de evaluación al [`Traine Para más ejemplos de fine-tuning consulta: -- [🤗 Transformers Examples](https://github.com/huggingface/transformers/tree/main/examples) incluye scripts - para entrenar tareas comunes de NLP en PyTorch y TensorFlow. - - [🤗 Transformers Notebooks](notebooks) contiene varios notebooks sobre cómo aplicar fine-tuning a un modelo para tareas específicas en PyTorch y TensorFlow. diff --git a/docs/source/fr/_toctree.yml b/docs/source/fr/_toctree.yml index 3b85bcab8284..1a619a362150 100755 --- a/docs/source/fr/_toctree.yml +++ b/docs/source/fr/_toctree.yml @@ -15,8 +15,6 @@ title: Préparation des données - local: in_translation title: Fine-tune un modèle pré-entraîné - - local: run_scripts_fr - title: Entraînement avec un script - local: in_translation title: Entraînement distribué avec 🤗 Accelerate - local: in_translation diff --git a/docs/source/fr/installation.md b/docs/source/fr/installation.md index 9923437d6b8f..caf6ef62b252 100644 --- a/docs/source/fr/installation.md +++ b/docs/source/fr/installation.md @@ -146,13 +146,6 @@ Ajoutez [🤗 Datasets](https://huggingface.co/docs/datasets/) à votre processu -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -Le script devrait maintenant s'exécuter sans rester en attente ou attendre une expiration, car il n'essaiera pas de télécharger des modèle sur le Hub. - Vous pouvez aussi éviter de télécharger un modèle à chaque appel de la fonction [`~PreTrainedModel.from_pretrained`] en utilisant le paramètre [local_files_only]. Seuls les fichiers locaux sont chargés lorsque ce paramètre est activé (c.-à-d. `local_files_only=True`) : ```py diff --git a/docs/source/fr/run_scripts_fr.md b/docs/source/fr/run_scripts_fr.md deleted file mode 100644 index 43e3ed024150..000000000000 --- a/docs/source/fr/run_scripts_fr.md +++ /dev/null @@ -1,287 +0,0 @@ - - -# Entraîner avec un script - -En plus des [notebooks](./notebooks) de 🤗 Transformers, il existe également des exemples de scripts démontrant comment entraîner un modèle pour une tâche avec [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch), [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow) ou [JAX/Flax](https://github.com/huggingface/transformers/tree/main/examples/flax). - - -Vous trouverez également des scripts que nous avons utilisé dans nos [projets de recherche](https://github.com/huggingface/transformers-research-projects/) et des [exemples "legacy"](https://github.com/huggingface/transformers/tree/main/examples/legacy) qui sont des contributions de la communauté. Ces scripts ne sont pas activement maintenus et nécessitent une version spécifique de 🤗 Transformers qui sera probablement incompatible avec la dernière version de la librairie. - -Les exemples de scripts ne sont pas censés fonctionner immédiatement pour chaque problème, et il se peut que vous ayez besoin d'adapter le script au problème que vous essayez de résoudre. Pour vous aider dans cette tâche, la plupart des scripts exposent entièrement la manière dont les données sont prétraitées, vous permettant de les modifier selon vos besoins. - -Pour toute fonctionnalité que vous souhaitez implémenter dans un script d'exemple, veuillez en discuter sur le [forum](https://discuss.huggingface.co/) ou dans une [issue](https://github.com/huggingface/transformers/issues) avant de soumettre une Pull Request. Bien que nous acceptions les corrections de bugs, il est peu probable que nous fusionnions une Pull Request (opération "merge" dans Git) ajoutant plus de fonctionnalités au détriment de la lisibilité. - -Ce guide vous montrera comment exécuter un script d'entraînement de résumé en exemple avec [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) et [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization). Tous les exemples sont censés fonctionner avec les deux frameworks, sauf indication contraire. - -## Configuration - -Pour exécuter avec succès la dernière version des scripts d'exemple, vous devez **installer 🤗 Transformers à partir du code source** dans un nouvel environnement virtuel : - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -Pour les versions plus anciennes des exemples de scripts, cliquez sur le bouton ci-dessous : - -
- Exemples pour les anciennes versions de Transformers 🤗 - -
- -Ensuite, changez votre clone actuel de 🤗 Transformers pour une version spécifique, comme par exemple v3.5.1 : - -```bash -git checkout tags/v3.5.1 -``` - -Après avoir configuré la bonne version de la librairie, accédez au dossier d'exemple de votre choix et installez les prérequis spécifiques à l'exemple. - -```bash -pip install -r requirements.txt -``` - -## Exécuter un script - - -Le script d'exemple télécharge et prétraite un jeu de données à partir de la bibliothèque 🤗 [Datasets](https://huggingface.co/docs/datasets/). Ensuite, le script affine un ensemble de données à l'aide de [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) sur une architecture qui prend en charge la tâche de résumé. L'exemple suivant montre comment ajuster le modèle [T5-small](https://huggingface.co/google-t5/t5-small) sur les données [CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail). Le modèle T5 nécessite un argument supplémentaire `source_prefix` en raison de la façon dont il a été entraîné. Cette invite permet à T5 de savoir qu'il s'agit d'une tâche de résumé. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Entraînement distribué et précision mixte - -[Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) prend en charge l'entraînement distribué et la précision mixte, ce qui signifie que vous pouvez également les utiliser dans un script. Pour activer ces deux fonctionnalités : - -- Ajoutez l'argument fp16 pour activer la précision mixte. -- Définissez le nombre de GPU à utiliser avec l'argument `nproc_per_node`. - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Les scripts TensorFlow utilisent une Strategie en Miroir [`MirroredStrategy`](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy) pour l'entraînement distribué, et vous n'avez pas besoin d'ajouter d'arguments supplémentaires au script d'entraînement. Le script TensorFlow utilisera plusieurs GPU par défaut s'ils sont disponibles. - -## Exécuter un script sur un TPU - - -Les unités de traitement de tenseurs (UTT) (TPU) sont spécialement conçues pour accélérer les performances. PyTorch prend en charge les TPU avec le compilateur de deep learning [XLA](https://www.tensorflow.org/xla). Pour utiliser un TPU, lancez le script xla_spawn.py et utilisez l'argument num_cores pour définir le nombre de cœurs TPU que vous souhaitez utilise - -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Exécuter un script avec 🤗 Accelerate - -🤗 [Accelerate](https://huggingface.co/docs/accelerate) est une bibliothèque uniquement pour PyTorch qui offre une méthode unifiée pour entraîner un modèle sur plusieurs types de configurations (CPU uniquement, plusieurs GPU, TPU) tout en maintenant une visibilité complète sur la boucle d'entraînement PyTorch. Assurez-vous que vous avez installé 🤗 Accelerate si ce n'est pas déjà le cas. - -> Note : Comme Accelerate est en développement rapide, la version git d'accelerate doit être installée pour exécuter les scripts. -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -Au lieu du script `run_summarization.py`, vous devez utiliser le script `run_summarization_no_trainer.py`. Les scripts compatibles avec 🤗 Accelerate auront un fichier `task_no_trainer.py` dans le dossier. Commencez par exécuter la commande suivante pour créer et enregistrer un fichier de configuration. - -```bash -accelerate config -``` - -Testez votre configuration pour vous assurer qu'elle est correctement configurée : - -```bash -accelerate test -``` - -Maintenant, vous êtes prêt à lancer l'entraînement : - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## Utiliser un jeu de données personnalisé - -Le script de résumé prend en charge les jeux de données personnalisés tant qu'ils sont au format CSV ou JSON Line. Lorsque vous utilisez votre propre jeu de données, vous devez spécifier plusieurs arguments supplémentaires : - -- `train_file` et `validation_file` spécifient le chemin vers vos fichiers d'entraînement et de validation. -- `text_column` est le texte d'entrée à résumer. -- `summary_column` est le texte cible à produire. - -Un exemple de script de résumé utilisant un ensemble de données personnalisé ressemblerait à ceci : - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Tester un script -Il est souvent judicieux d'exécuter votre script sur un plus petit nombre d'exemples de jeu de données pour s'assurer que tout fonctionne comme prévu avant de s'engager sur un jeu de données complet qui pourrait prendre des heures à traiter. Utilisez les arguments suivants pour tronquer le jeu de données à un nombre maximal d'échantillons : - -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Tous les scripts d'exemple ne prennent pas en charge l'argument `max_predict_samples`. Si vous n'êtes pas sûr que votre script prenne en charge cet argument, ajoutez l'argument `-h` pour vérifier. - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## Reprendre l'entraînement à partir d'un point de contrôle - -Une autre option utile est de reprendre l'entraînement à partir d'un point de contrôle précédent. Cela vous permettra de reprendre là où vous vous étiez arrêté sans recommencer si votre entraînement est interrompu: - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## Partage ton modèle - -Tous les scripts peuvent télécharger votre modèle final sur le Model Hub. Assurez-vous que vous êtes connecté à Hugging Face avant de commencer : - -```bash -hf auth login -``` - -Ensuite, ajoutez l'argument `push_to_hub` au script. Cet argument créera un dépôt avec votre nom d'utilisateur Hugging Face et le nom du dossier spécifié dans `output_dir`. - - -Pour donner un nom spécifique à votre dépôt, utilisez l'argument `push_to_hub_model_id` pour l'ajouter. Le dépôt sera automatiquement listé sous votre namespace. - -L'exemple suivant montre comment télécharger un modèle avec un nom de dépôt spécifique : - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` diff --git a/docs/source/it/_toctree.yml b/docs/source/it/_toctree.yml index 6e0371fb2470..aeb9c96e20c6 100644 --- a/docs/source/it/_toctree.yml +++ b/docs/source/it/_toctree.yml @@ -1,66 +1,64 @@ -- sections: - - local: index - title: 🤗 Transformers - - local: quicktour - title: Tour rapido - - local: installation - title: Installazione - title: Iniziare -- sections: - - local: pipeline_tutorial - title: Pipeline per l'inferenza - - local: autoclass_tutorial - title: Carica istanze pre-allenate con AutoClass - - local: preprocessing - title: Preprocess - - local: training - title: Fine-tuning di un modello pre-addestrato - - local: accelerate - title: Allenamento distribuito con 🤗 Accelerate - - local: model_sharing - title: Condividere un modello - title: Esercitazione -- sections: - - local: create_a_model - title: Crea un'architettura personalizzata - - local: custom_models - title: Condividere modelli personalizzati - - local: run_scripts - title: Addestramento con script - - local: multilingual - title: Modelli multilingua per l'inferenza - - local: perf_train_cpu - title: Addestramento efficiente su CPU - - local: perf_train_cpu_many - title: Addestramento efficiente su multiple CPU - - local: perf_train_tpu - title: Addestramento su TPU - - local: perf_train_special - title: Addestramento su Hardware Specializzato - - local: perf_infer_cpu - title: Inferenza Efficiente su CPU - - local: perf_infer_gpu_one - title: Inferenza su una GPU - - local: perf_infer_gpu_many - title: Inferenza Efficiente su GPU Multiple - - local: perf_infer_special - title: Inferenza su Hardware Specializzato - - local: big_models - title: Istanziare un big model - - local: migration - title: Passaggio da pacchetti precedenti - - local: debugging - title: Debugging - title: Guide pratiche -- sections: - - local: add_new_pipeline - title: Come aggiungere una pipeline a 🤗 Transformers? - - local: add_new_model - title: Come aggiungere un modello a 🤗 Transformers? - - local: perf_hardware - title: Hardware ottimizzato per l'addestramento - - local: community - title: Risorse della comunità - - local: pr_checks - title: Controlli su una Pull Request - title: Guide How-to +- sections: + - local: index + title: 🤗 Transformers + - local: quicktour + title: Tour rapido + - local: installation + title: Installazione + title: Iniziare +- sections: + - local: pipeline_tutorial + title: Pipeline per l'inferenza + - local: autoclass_tutorial + title: Carica istanze pre-allenate con AutoClass + - local: preprocessing + title: Preprocess + - local: training + title: Fine-tuning di un modello pre-addestrato + - local: accelerate + title: Allenamento distribuito con 🤗 Accelerate + - local: model_sharing + title: Condividere un modello + title: Esercitazione +- sections: + - local: create_a_model + title: Crea un'architettura personalizzata + - local: custom_models + title: Condividere modelli personalizzati + - local: multilingual + title: Modelli multilingua per l'inferenza + - local: perf_train_cpu + title: Addestramento efficiente su CPU + - local: perf_train_cpu_many + title: Addestramento efficiente su multiple CPU + - local: perf_train_tpu + title: Addestramento su TPU + - local: perf_train_special + title: Addestramento su Hardware Specializzato + - local: perf_infer_cpu + title: Inferenza Efficiente su CPU + - local: perf_infer_gpu_one + title: Inferenza su una GPU + - local: perf_infer_gpu_many + title: Inferenza Efficiente su GPU Multiple + - local: perf_infer_special + title: Inferenza su Hardware Specializzato + - local: big_models + title: Istanziare un big model + - local: migration + title: Passaggio da pacchetti precedenti + - local: debugging + title: Debugging + title: Guide pratiche +- sections: + - local: add_new_pipeline + title: Come aggiungere una pipeline a 🤗 Transformers? + - local: add_new_model + title: Come aggiungere un modello a 🤗 Transformers? + - local: perf_hardware + title: Hardware ottimizzato per l'addestramento + - local: community + title: Risorse della comunità + - local: pr_checks + title: Controlli su una Pull Request + title: Guide How-to diff --git a/docs/source/it/installation.md b/docs/source/it/installation.md index 5a8033e52003..7b74826ddbe8 100644 --- a/docs/source/it/installation.md +++ b/docs/source/it/installation.md @@ -140,21 +140,6 @@ Aggiungi [🤗 Datasets](https://huggingface.co/docs/datasets/) al tuo flusso di -Ad esempio, in genere si esegue un programma su una rete normale, protetta da firewall per le istanze esterne, con il seguente comando: - -```bash -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -Esegui lo stesso programma in un'istanza offline con: - -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -Lo script viene ora eseguito senza bloccarsi o attendere il timeout, perché sa di dover cercare solo file locali. - ### Ottenere modelli e tokenizer per l'uso offline Un'altra opzione per utilizzare offline 🤗 Transformers è scaricare i file in anticipo, e poi puntare al loro path locale quando hai la necessità di utilizzarli offline. Ci sono tre modi per fare questo: diff --git a/docs/source/it/multilingual.md b/docs/source/it/multilingual.md index e9e85beec1d9..443488fd111d 100644 --- a/docs/source/it/multilingual.md +++ b/docs/source/it/multilingual.md @@ -77,8 +77,6 @@ Adesso puoi inserire `input_ids` e language embedding nel modello: >>> outputs = model(input_ids, langs=langs) ``` -Lo script [run_generation.py](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-generation/run_generation.py) può generare testo tramite i language embeddings usando i checkpoints `xlm-clm`. - ### XLM senza language embeddings I seguenti modelli XLM non richiedono l'utilizzo dei language embeddings per fare inferenza: diff --git a/docs/source/it/perf_hardware.md b/docs/source/it/perf_hardware.md index 946dcb3238d0..2ad124594b62 100644 --- a/docs/source/it/perf_hardware.md +++ b/docs/source/it/perf_hardware.md @@ -115,41 +115,3 @@ Ogni nuova generazione fornisce una larghezza di banda più veloce, ad es. ecco > (Note that 3-Way and 4-Way SLI configurations are not supported.) Quindi più `X` si ottiene nel rapporto di `NVX` nell'output di `nvidia-smi topo -m`, meglio è. La generazione dipenderà dall'architettura della tua GPU. - -Confrontiamo l'esecuzione di un training del modello di linguaggio openai-community/gpt2 su un piccolo campione di wikitext - -I risultati sono: - - -| NVlink | Time | -| ----- | ---: | -| Y | 101s | -| N | 131s | - - -Puoi vedere che NVLink completa l'addestramento circa il 23% più velocemente. Nel secondo benchmark utilizziamo `NCCL_P2P_DISABLE=1` per dire alle GPU di non utilizzare NVLink. - -Ecco il codice benchmark completo e gli output: - -```bash -# DDP w/ NVLink - -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 torchrun \ ---nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \ ---dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train \ ---output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 101.9003, 'train_samples_per_second': 1.963, 'epoch': 0.69} - -# DDP w/o NVLink - -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 NCCL_P2P_DISABLE=1 torchrun \ ---nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \ ---dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train ---output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 131.4367, 'train_samples_per_second': 1.522, 'epoch': 0.69} -``` - -Hardware: 2x TITAN RTX 24GB each + NVlink with 2 NVLinks (`NV2` in `nvidia-smi topo -m`) -Software: `pytorch-1.8-to-be` + `cuda-11.0` / `transformers==4.3.0.dev0` \ No newline at end of file diff --git a/docs/source/it/perf_train_cpu.md b/docs/source/it/perf_train_cpu.md index 25ee63997b5e..dd5e0fce8d2f 100644 --- a/docs/source/it/perf_train_cpu.md +++ b/docs/source/it/perf_train_cpu.md @@ -42,28 +42,6 @@ pip install intel_extension_for_pytorch== -f https://developer.int Vedi altri approcci per [IPEX installation](https://intel.github.io/intel-extension-for-pytorch/cpu/latest/tutorials/installation.html). -### Utilizzo nel Trainer - -Per abilitare la auto mixed precision con IPEX in Trainer, l'utende dovrebbe aggiungere `use_ipex`, `bf16` e `no_cuda` negli argomenti del comando di addestramento. - -Vedi un sempio di un caso d'uso [Transformers question-answering](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) - -- Training with IPEX using BF16 auto mixed precision on CPU: - -
 python run_qa.py \
---model_name_or_path google-bert/bert-base-uncased \
---dataset_name squad \
---do_train \
---do_eval \
---per_device_train_batch_size 12 \
---learning_rate 3e-5 \
---num_train_epochs 2 \
---max_seq_length 384 \
---doc_stride 128 \
---output_dir /tmp/debug_squad/ \
---use_ipex \
---bf16 --no_cuda
- ### Esempi pratici Blog: [Accelerating PyTorch Transformers with Intel Sapphire Rapids](https://huggingface.co/blog/intel-sapphire-rapids) diff --git a/docs/source/it/perf_train_cpu_many.md b/docs/source/it/perf_train_cpu_many.md index c1f8833829ac..04ea96f95844 100644 --- a/docs/source/it/perf_train_cpu_many.md +++ b/docs/source/it/perf_train_cpu_many.md @@ -75,67 +75,3 @@ source $torch_ccl_path/env/setvars.sh #### Installazione IPEX: IPEX fornisce ottimizzazioni delle prestazioni per l'addestramento della CPU sia con Float32 che con BFloat16; puoi fare riferimento a [single CPU section](./perf_train_cpu). - -Il seguente "Utilizzo in Trainer" prende come esempio mpirun nella libreria Intel® MPI. - -## Utilizzo in Trainer - -Per abilitare l'addestramento distribuito multi CPU nel Trainer con il ccl backend, gli utenti devono aggiungere **`--ddp_backend ccl`** negli argomenti del comando. - -Vediamo un esempio per il [question-answering example](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) - -Il seguente comando abilita due processi sul nodo Xeon, con un processo in esecuzione per ogni socket. Le variabili OMP_NUM_THREADS/CCL_WORKER_COUNT possono essere impostate per una prestazione ottimale. - -```shell script - export CCL_WORKER_COUNT=1 - export MASTER_ADDR=127.0.0.1 - mpirun -n 2 -genv OMP_NUM_THREADS=23 \ - python3 run_qa.py \ - --model_name_or_path google-bert/bert-large-uncased \ - --dataset_name squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ \ - --no_cuda \ - --ddp_backend ccl \ - --use_ipex -``` - -Il seguente comando abilita l'addestramento per un totale di quattro processi su due Xeon (node0 e node1, prendendo node0 come processo principale), ppn (processes per node) è impostato a 2, on un processo in esecuzione per ogni socket. Le variabili OMP_NUM_THREADS/CCL_WORKER_COUNT possono essere impostate per una prestazione ottimale. - -In node0, è necessario creare un file di configurazione che contenga gli indirizzi IP di ciascun nodo (per esempio hostfile) e passare il percorso del file di configurazione come parametro. - -```shell script - cat hostfile - xxx.xxx.xxx.xxx #node0 ip - xxx.xxx.xxx.xxx #node1 ip -``` - -A questo punto, esegui il seguente comando nel nodo0 e **4DDP** sarà abilitato in node0 e node1 con BF16 auto mixed precision: - -```shell script - export CCL_WORKER_COUNT=1 - export MASTER_ADDR=xxx.xxx.xxx.xxx #node0 ip - mpirun -f hostfile -n 4 -ppn 2 \ - -genv OMP_NUM_THREADS=23 \ - python3 run_qa.py \ - --model_name_or_path google-bert/bert-large-uncased \ - --dataset_name squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ \ - --no_cuda \ - --ddp_backend ccl \ - --use_ipex \ - --bf16 -``` diff --git a/docs/source/it/run_scripts.md b/docs/source/it/run_scripts.md deleted file mode 100644 index e0986b839771..000000000000 --- a/docs/source/it/run_scripts.md +++ /dev/null @@ -1,284 +0,0 @@ - - -# Addestramento con script - -Insieme ai [notebooks](./notebooks) 🤗 Transformers, ci sono anche esempi di script che dimostrano come addestrare un modello per un task con [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch), [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow), o [JAX/Flax](https://github.com/huggingface/transformers/tree/main/examples/flax). - -Troverai anche script che abbiamo usato nei nostri [progetti di ricerca](https://github.com/huggingface/transformers-research-projects/) e [precedenti esempi](https://github.com/huggingface/transformers/tree/main/examples/legacy) a cui contribuisce per lo più la comunità. Questi script non sono attivamente mantenuti e richiedono una specifica versione di 🤗 Transformers che sarà molto probabilmente incompatibile con l'ultima versione della libreria. - -Non è dato per scontato che gli script di esempio funzionino senza apportare modifiche per ogni problema, bensì potrebbe essere necessario adattare lo script al tuo caso specifico. Per aiutarti in ciò, la maggioranza degli script espone le modalità di pre-processamento dei dati, consentendoti di modificare lo script come preferisci. - -Per qualsiasi feature che vorresti implementare in uno script d'esempio, per favore discutine nel [forum](https://discuss.huggingface.co/) o in un'[issue](https://github.com/huggingface/transformers/issues) prima di inviare una Pull Request. Mentre accogliamo con piacere la correzione di bug, è più improbabile che faremo la stessa con una PR che aggiunge funzionalità sacrificando la leggibilità. - -Questa guida ti mostrerà come eseguire uno script di esempio relativo al task di summarization in [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) e [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization). Tutti gli esempi funzioneranno con entrambi i framework a meno che non sia specificato altrimenti. - -## Installazione - -Per eseguire con successo l'ultima versione degli script di esempio, devi **installare 🤗 Transformers dalla fonte** in un nuovo ambiente virtuale: - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` -Per le precedenti versioni degli script di esempio, clicca sul pulsante di seguito: - -
- Esempi per versioni precedenti di 🤗 Transformers - -
- -Successivamente, cambia la tua attuale copia di 🤗 Transformers specificandone la versione, ad esempio v3.5.1: - -```bash -git checkout tags/v3.5.1 -``` - - Dopo aver configurato correttamente la versione della libreria, naviga nella cartella degli esempi di tua scelta e installa i requisiti: - -```bash -pip install -r requirements.txt -``` - -## Esegui uno script - - -Lo script di esempio scarica e pre-processa un dataset dalla libreria 🤗 [Datasets](https://huggingface.co/docs/datasets/). Successivamente, lo script esegue il fine-tuning su un dataset usando il [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) su un'architettura che supporta la summarization. Il seguente esempio mostra come eseguire il fine-tuning di [T5-small](https://huggingface.co/google-t5/t5-small) sul dataset [CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail). Il modello T5 richiede un parametro addizionale `source_prefix` a causa del modo in cui è stato addestrato. Questo prefisso permette a T5 di sapere che si tratta di un task di summarization. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Addestramento distribuito e precisione mista - -Il [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) supporta l'addestramento distribuito e la precisione mista, che significa che puoi anche usarla in uno script. Per abilitare entrambe le funzionalità: - -- Aggiunto l'argomento `fp16` per abilitare la precisione mista. -- Imposta un numero di GPU da usare con l'argomento `nproc_per_node`. - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Gli script TensorFlow utilizzano una [`MirroredStrategy`](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy) per il training distribuito e non devi aggiungere alcun argomento addizionale allo script di training. Lo script TensorFlow userà multiple GPU in modo predefinito se quest'ultime sono disponibili: - -## Esegui uno script su TPU - -Le Tensor Processing Units (TPU) sono state progettate per migliorare le prestazioni. PyTorch supporta le TPU con il compilatore per deep learning [XLA](https://www.tensorflow.org/xla) (guarda [questo link](https://github.com/pytorch/xla/blob/master/README.md) per maggiori dettagli). Per usare una TPU, avvia lo script `xla_spawn.py` e usa l'argomento `num_cores` per impostare il numero di core TPU che intendi usare. - -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Esegui uno script con 🤗 Accelerate - -🤗 [Accelerate](https://huggingface.co/docs/accelerate) è una libreria compatibile solo con PyTorch che offre un metodo unificato per addestrare modelli su diverse tipologie di configurazioni (CPU, multiple GPU, TPU) mantenendo una completa visibilità rispetto al ciclo di training di PyTorch. Assicurati di aver effettuato l'installazione di 🤗 Accelerate, nel caso non lo avessi fatto: - -> Nota: dato che Accelerate è in rapido sviluppo, è necessario installare la versione proveniente da git per eseguire gli script: -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -Invece che usare lo script `run_summarization.py`, devi usare lo script `run_summarization_no_trainer.py`. Gli script supportati in 🤗 Accelerate avranno un file chiamato `task_no_trainer.py` nella rispettiva cartella. Per iniziare, esegui il seguente comando per creare e salvare un file di configurazione: - -```bash -accelerate config -``` - -Testa la tua configurazione per assicurarti della sua correttezza: - -```bash -accelerate test -``` - -Ora sei pronto per avviare l'addestramento: - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## Uso di un dataset personalizzato - -Lo script di summarization supporta dataset personalizzati purché siano file CSV o JSON Line. Quando usi il tuo dataset, devi specificare diversi argomenti aggiuntivi: - -- `train_file` e `validation_file` specificano dove si trovano i file di addestramento e validazione. -- `text_column` è il file di input da riassumere. -- `summary_column` è il file di destinazione per l'output. - -Uno script di summarization usando un dataset personalizzato sarebbe simile a questo: - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Testare uno script - -È spesso una buona idea avviare il tuo script su un numero inferiore di esempi tratti dal dataset, per assicurarti che tutto funzioni come previsto prima di eseguire lo script sull'intero dataset, che potrebbe necessitare di ore. Usa i seguenti argomenti per limitare il dataset ad un massimo numero di esempi: - -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Non tutti gli esempi di script supportano l'argomento `max_predict_samples`. Se non sei sicuro circa il supporto di questo argomento da parte del tuo script, aggiungi l'argomento `-h` per controllare: - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## Riavviare addestramento da un checkpoint - -Un'altra utile opzione è riavviare un addestramento da un checkpoint precedente. Questo garantirà che tu possa riprendere da dove hai interrotto senza ricominciare se l'addestramento viene interrotto. Ci sono due metodi per riavviare l'addestramento da un checkpoint: - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## Condividi il tuo modello - -Tutti gli script possono caricare il tuo modello finale al [Model Hub](https://huggingface.co/models). Prima di iniziare, assicurati di aver effettuato l'accesso su Hugging Face: - -```bash -hf auth login -``` - -Poi, aggiungi l'argomento `push_to_hub` allo script. Questo argomento consentirà di creare un repository con il tuo username Hugging Face e la cartella specificata in `output_dir`. - -Per dare uno specifico nome al repository, usa l'argomento `push_to_hub_model_id`. Il repository verrà automaticamente elencata sotto al tuo namespace. - -Il seguente esempio mostra come caricare un modello specificando il nome del repository: - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` diff --git a/docs/source/it/training.md b/docs/source/it/training.md index e15bae2afc2a..22e4c814d4d9 100644 --- a/docs/source/it/training.md +++ b/docs/source/it/training.md @@ -297,6 +297,4 @@ Proprio come è necessario aggiungere una funzione di valutazione del [`Trainer` Per altri esempi sul fine-tuning, fai riferimento a: -- [🤗 Transformers Examples](https://github.com/huggingface/transformers/tree/main/examples) include scripts per addestrare compiti comuni di NLP in PyTorch e TensorFlow. - - [🤗 Transformers Notebooks](https://github.com/huggingface/notebooks) contiene diversi notebooks su come mettere a punto un modello per compiti specifici in PyTorch e TensorFlow. diff --git a/docs/source/ja/_toctree.yml b/docs/source/ja/_toctree.yml index 1cf076a3a1b6..b9cd652204af 100644 --- a/docs/source/ja/_toctree.yml +++ b/docs/source/ja/_toctree.yml @@ -15,8 +15,6 @@ title: データの前処理 - local: training title: 事前トレーニングされたモデルを微調整する - - local: run_scripts - title: スクリプトを使用してトレーニングする - local: accelerate title: 🤗 Accelerate を使用して分散トレーニングをセットアップする - local: peft diff --git a/docs/source/ja/installation.md b/docs/source/ja/installation.md index 83e436920a06..fc3c13cc7e9d 100644 --- a/docs/source/ja/installation.md +++ b/docs/source/ja/installation.md @@ -145,21 +145,6 @@ conda install conda-forge::transformers -例えば、外部インスタンスに対してファイアウォールで保護された通常のネットワーク上でプログラムを実行する場合、通常以下のようなコマンドで実行することになります: - -```bash -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -オフラインインスタンスでこの同じプログラムを実行します: - -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -このスクリプトは、ローカルファイルのみを検索することが分かっているので、ハングアップしたりタイムアウトを待ったりすることなく実行されるはずです。 - ### オフラインで使用するためにモデルやトークナイザーを取得する オフラインで🤗 Transformersを使用するもう1つの方法は、前もってファイルをダウンロードしておき、オフラインで使用する必要があるときにそのローカルパスを指定することです。これには3つの方法があります: diff --git a/docs/source/ja/main_classes/data_collator.md b/docs/source/ja/main_classes/data_collator.md index 7b4f4e3221c2..1d6a0ce73410 100644 --- a/docs/source/ja/main_classes/data_collator.md +++ b/docs/source/ja/main_classes/data_collator.md @@ -23,7 +23,7 @@ rendered properly in your Markdown viewer. [`DataCollat​​orForLanguageModeling`]) ランダムなデータ拡張 (ランダム マスキングなど) も適用します 形成されたバッチ上で。 -使用例は、[サンプル スクリプト](../examples) または [サンプル ノートブック](../notebooks) にあります。 +使用例は、[サンプル ノートブック](../notebooks) にあります。 ## Default data collator diff --git a/docs/source/ja/main_classes/deepspeed.md b/docs/source/ja/main_classes/deepspeed.md index 8290052d9c13..928b07c62e95 100644 --- a/docs/source/ja/main_classes/deepspeed.md +++ b/docs/source/ja/main_classes/deepspeed.md @@ -182,18 +182,6 @@ deepspeed --num_gpus=2 your_program.py --deepspeed ds_config.js `deepspeed`ランチャーを使用し、利用可能なすべての GPU を使用したい場合は、`--num_gpus`フラグを省略するだけです。 -以下は、利用可能なすべての GPU をデプロイする DeepSpeed で`run_translation.py`を実行する例です。 - -```bash -deepspeed examples/pytorch/translation/run_translation.py \ ---deepspeed tests/deepspeed/ds_config_zero3.json \ ---model_name_or_path google-t5/t5-small --per_device_train_batch_size 1 \ ---output_dir output_dir --fp16 \ ---do_train --max_train_samples 500 --num_train_epochs 1 \ ---dataset_name wmt16 --dataset_config "ro-en" \ ---source_lang en --target_lang ro -``` - DeepSpeed のドキュメントには、`--deepspeed --deepspeed_config ds_config.json`が表示される可能性が高いことに注意してください。 DeepSpeed 関連の引数が 2 つありますが、簡単にするためであり、処理すべき引数がすでに非常に多いためです。 この 2 つを 1 つの引数に結合しました。 @@ -205,22 +193,6 @@ DeepSpeed 関連の引数が 2 つありますが、簡単にするためであ ### Deployment with one GPU -1 つの GPU で DeepSpeed をデプロイするには、[`Trainer`] コマンド ライン引数を次のように調整します。 - -```bash -deepspeed --num_gpus=1 examples/pytorch/translation/run_translation.py \ ---deepspeed tests/deepspeed/ds_config_zero2.json \ ---model_name_or_path google-t5/t5-small --per_device_train_batch_size 1 \ ---output_dir output_dir --fp16 \ ---do_train --max_train_samples 500 --num_train_epochs 1 \ ---dataset_name wmt16 --dataset_config "ro-en" \ ---source_lang en --target_lang ro -``` - -これは複数の GPU の場合とほぼ同じですが、ここでは、DeepSpeed に 1 つの GPU だけを使用するように明示的に指示します。 -`--num_gpus=1`。デフォルトでは、DeepSpeed は指定されたノード上で認識できるすべての GPU をデプロイします。起動する GPU が 1 つだけの場合 -の場合、この引数は必要ありません。次の [ドキュメント](https://www.deepspeed.ai/getting-started/#resource-configuration-multi-node) では、ランチャー オプションについて説明しています。 - 1 つの GPU だけで DeepSpeed を使用したいのはなぜですか? 1. 一部の計算とメモリをホストの CPU と RAM に委任できる ZeRO オフロード機能を備えているため、 @@ -257,17 +229,6 @@ DeepSpeed を使用するには、構成ファイルに少なくとも次の構 このドキュメントで詳しく説明されているように、CPU および NVMe オフロードを備えた ZeRO-3 を試すこともできます。 -ノート: - -- GPU 0 とは異なる特定の GPU で実行する必要がある場合、`CUDA_VISIBLE_DEVICES` を使用して制限することはできません。 - 利用可能な GPU の表示範囲。代わりに、次の構文を使用する必要があります。 - - ```bash - deepspeed --include localhost:1 examples/pytorch/translation/run_translation.py ... - ``` - - この例では、DeepSpeed に GPU 1 (2 番目の GPU) を使用するように指示します。 - ### 複数のノードを使用したデプロイメント @@ -451,29 +412,6 @@ cat <<'EOT' > ds_config_zero3.json EOT ``` -トレーニング スクリプトがノートブックのセルではなく通常のファイルにある場合は、次のようにして`deepspeed`を通常どおり起動できます。 -細胞からのシェル。たとえば、`run_translation.py` を使用するには、次のように起動します。 - -```python no-style -!git clone https://github.com/huggingface/transformers -!cd transformers; deepspeed examples/pytorch/translation/run_translation.py ... -``` - -または、`%%bash` マジックを使用すると、シェル プログラムを実行するための複数行のコードを記述することができます。 - -```python no-style -%%bash - -git clone https://github.com/huggingface/transformers -cd transformers -deepspeed examples/pytorch/translation/run_translation.py ... -``` - -そのような場合、このセクションの最初に示したコードは必要ありません。 - -注: `%%bash` マジックは優れていますが、現時点では出力をバッファリングするため、プロセスが終了するまでログは表示されません。 -完了します。 - ### Configuration @@ -1730,9 +1668,6 @@ model = AutoModel.from_pretrained("google-t5/t5-small") trainer = Trainer(model=model, args=training_args, ...) ``` -公式のサンプル スクリプトを使用していて、コマンド ライン引数に `--deepspeed ds_config.json` が含まれている場合 -ZeRO-3 設定を有効にすると、これがサンプル スクリプトの記述方法であるため、すべてがすでに完了しています。 - 注: モデルの fp16 重みが単一の GPU のメモリに収まらない場合は、この機能を使用する必要があります。 この方法とその他の関連機能の詳細については、[大規模モデルの構築](https://deepspeed.readthedocs.io/en/latest/zero3.html#constructing-massive-models) を参照してください。 @@ -1778,21 +1713,6 @@ deepspeed --num_gpus=2 your_program.py --do_eval --deepspeed ds 唯一重要なことは、ZeRO-2 には何の利点もないため、ZeRO-3 構成を使用する必要があるということです。 ZeRO-3 のみがパラメーターのシャーディングを実行するのに対し、ZeRO-1 は勾配とオプティマイザーの状態をシャーディングするため、推論に役立ちます。 -以下は、利用可能なすべての GPU をデプロイする DeepSpeed で`run_translation.py`を実行する例です。 - - -```bash -deepspeed examples/pytorch/translation/run_translation.py \ ---deepspeed tests/deepspeed/ds_config_zero3.json \ ---model_name_or_path google-t5/t5-small --output_dir output_dir \ ---do_eval --max_eval_samples 50 --warmup_steps 50 \ ---max_source_length 128 --val_max_target_length 128 \ ---per_device_eval_batch_size 4 \ ---predict_with_generate --dataset_config "ro-en" --fp16 \ ---source_lang en --target_lang ro --dataset_name wmt16 \ ---source_prefix "translate English to Romanian: " -``` - 推論のために、オプティマイザーの状態と勾配によって使用される追加の大きなメモリは必要ないため、 はるかに大きなバッチやシーケンス長を同じハードウェアに適合できる必要があります。 @@ -1884,8 +1804,6 @@ SW: Model with 2783M total params, 65M largest layer params. 5. 不可能でない限り、カスタムデータセットではなく、常に使用できる標準データセットを使用してください。 -6. 可能であれば、既存の [サンプル](https://github.com/huggingface/transformers/tree/main/examples/pytorch) のいずれかを使用して問題を再現してみてください。 - - Deepspeed が問題の原因ではないことがよくあります。 提出された問題の一部は、Deepspeed とは無関係であることが判明しました。それは、Deepspeed がセットアップから削除された後です。 @@ -2189,16 +2107,9 @@ DeepSpeed 統合を含む PR を送信する場合は、CircleCI PR CI セット DeepSpeed テストを実行するには、少なくとも以下を実行してください。 ```bash -RUN_SLOW=1 pytest tests/deepspeed/test_deepspeed.py +RUN_SLOW=1 pytest tests/trainer/distributed/test_trainer_distributed_deepspeed.py ``` -モデリングまたは pytorch サンプル コードのいずれかを変更した場合は、Model Zoo テストも実行します。以下はすべての DeepSpeed テストを実行します。 - -```bash -RUN_SLOW=1 pytest tests/deepspeed -``` - - ## Main DeepSpeed Resources - [プロジェクトの github](https://github.com/deepspeedai/DeepSpeed) diff --git a/docs/source/ja/main_classes/trainer.md b/docs/source/ja/main_classes/trainer.md index e5d55ff77b4c..67234b818499 100644 --- a/docs/source/ja/main_classes/trainer.md +++ b/docs/source/ja/main_classes/trainer.md @@ -16,7 +16,7 @@ rendered properly in your Markdown viewer. # Trainer -[`Trainer`] クラスは、ほとんどの標準的なユースケースに対して、PyTorch で機能を完全にトレーニングするための API を提供します。これは、[サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples) のほとんどで使用されています。 +[`Trainer`] クラスは、ほとんどの標準的なユースケースに対して、PyTorch で機能を完全にトレーニングするための API を提供します。 [`Trainer`] をインスタンス化する前に、トレーニング中にカスタマイズのすべてのポイントにアクセスするために [`TrainingArguments`] を作成します。 @@ -519,22 +519,6 @@ MacOS マシンに PyTorch >= 1.13 (執筆時点ではナイトリー バージ **使用法**: `mps` デバイスは、`cuda` デバイスが使用される方法と同様に利用可能な場合、デフォルトで使用されます。 したがって、ユーザーによるアクションは必要ありません。 -たとえば、以下のコマンドを使用して、Apple Silicon GPU を使用して公式の Glue テキスト分類タスクを (ルート フォルダーから) 実行できます。 - -```bash -export TASK_NAME=mrpc - -python examples/pytorch/text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` **注意すべきいくつかの注意事項** @@ -652,47 +636,8 @@ MPS バックエンドの使用に関して問題や質問がある場合は、 ``` 3. 加速設定またはランチャー引数によって上記で処理された引数以外の引数を使用して、トレーナー スクリプトを実行します。 -以下は、上記の FSDP 構成で`accelerate launcher`を使用して`run_glue.py`を実行する例です。 -```bash -cd transformers - -accelerate launch \ -./examples/pytorch/text-classification/run_glue.py \ ---model_name_or_path google-bert/bert-base-cased \ ---task_name $TASK_NAME \ ---do_train \ ---do_eval \ ---max_seq_length 128 \ ---per_device_train_batch_size 16 \ ---learning_rate 5e-5 \ ---num_train_epochs 3 \ ---output_dir /tmp/$TASK_NAME/ \ -``` - -4. `accelerate launch`するための cmd 引数を直接使用することもできます。上の例は次のようにマッピングされます。 - -```bash -cd transformers - -accelerate launch --num_processes=2 \ ---use_fsdp \ ---mixed_precision=bf16 \ ---fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \ ---fsdp_transformer_layer_cls_to_wrap="BertLayer" \ ---fsdp_sharding_strategy=1 \ ---fsdp_state_dict_type=FULL_STATE_DICT \ -./examples/pytorch/text-classification/run_glue.py ---model_name_or_path google-bert/bert-base-cased \ ---task_name $TASK_NAME \ ---do_train \ ---do_eval \ ---max_seq_length 128 \ ---per_device_train_batch_size 16 \ ---learning_rate 5e-5 \ ---num_train_epochs 3 \ ---output_dir /tmp/$TASK_NAME/ \ -``` +4. `accelerate launch`するための cmd 引数を直接使用することもできます。 詳細については、🤗 Accelerate CLI ガイドを参照してください: [🤗 Accelerate スクリプトの起動](https://huggingface.co/docs/accelerate/basic_tutorials/launch)。 diff --git a/docs/source/ja/model_doc/audio-spectrogram-transformer.md b/docs/source/ja/model_doc/audio-spectrogram-transformer.md index eb0c3cf6e36e..d59865be9e64 100644 --- a/docs/source/ja/model_doc/audio-spectrogram-transformer.md +++ b/docs/source/ja/model_doc/audio-spectrogram-transformer.md @@ -44,7 +44,7 @@ Audio Spectrogram Transformerの使用を開始するのに役立つ公式のHug - ASTを用いた音声分類の推論を説明するノートブックは[こちら](https://github.com/NielsRogge/Transformers-Tutorials/tree/master/AST)で見ることができます。 -- [`ASTForAudioClassification`]は、この[例示スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/audio-classification)と[ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb)によってサポートされています。 +- [`ASTForAudioClassification`]は、この[ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb)によってサポートされています。 - こちらも参照:[音声分類タスク](../tasks/audio_classification)。 ここに参考資料を提出したい場合は、気兼ねなくPull Requestを開いてください。私たちはそれをレビューいたします!参考資料は、既存のものを複製するのではなく、何か新しいことを示すことが理想的です。 diff --git a/docs/source/ja/model_doc/bart.md b/docs/source/ja/model_doc/bart.md index ee584b8013e0..46590943376f 100644 --- a/docs/source/ja/model_doc/bart.md +++ b/docs/source/ja/model_doc/bart.md @@ -61,8 +61,6 @@ Bart モデルは、[BART: Denoising Sequence-to-Sequence Pre-training for Natur ### Examples -- シーケンス間タスク用の BART およびその他のモデルを微調整するための例とスクリプトは、次の場所にあります。 - [examples/pytorch/summarization/](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization/README.md)。 - Hugging Face `datasets` を使用して [`BartForConditionalGeneration`] をトレーニングする方法の例 オブジェクトは、この [フォーラム ディスカッション](https://discuss.huggingface.co/t/train-bart-for-conditional-generation-e-g-summarization/1904) で見つけることができます。 - [抽出されたチェックポイント](https://huggingface.co/models?search=distilbart) は、この [論文](https://huggingface.co/papers/2010.13002) で説明されています。 @@ -107,25 +105,24 @@ BART を始めるのに役立つ公式 Hugging Face およびコミュニティ - に関するブログ投稿 [分散トレーニング: 🤗 Transformers と Amazon SageMaker を使用した要約のための BART/T5 のトレーニング](https://huggingface.co/blog/sagemaker-distributed-training-seq2seq)。 - 方法に関するノートブック [blurr を使用して fastai で要約するために BART を微調整する](https://colab.research.google.com/github/ohmeow/ohmeow_website/blob/master/posts/2021-05-25-mbart-sequence-classification-with-blurr.ipynb). 🌎 🌎 - 方法に関するノートブック [トレーナー クラスを使用して 2 つの言語で要約するために BART を微調整する](https://colab.research.google.com/github/elsanns/xai-nlp-notebooks/blob/master/fine_tune_bart_summarization_two_langs.ipynb)。 🌎 -- [`BartForConditionalGeneration`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization.ipynb)。 -- [`TFBartForConditionalGeneration`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization-tf.ipynb)。 -- [`FlaxBartForConditionalGeneration`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/flax/summarization) でサポートされています。 +- [`BartForConditionalGeneration`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization.ipynb)。 +- [`TFBartForConditionalGeneration`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization-tf.ipynb)。 - [要約](https://huggingface.co/course/chapter7/5?fw=pt#summarization) 🤗 ハグフェイスコースの章。 - [要約タスクガイド](../tasks/summarization) -- [`BartForConditionalGeneration`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling) でサポートされており、 [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)。 -- [`TFBartForConditionalGeneration`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/language-modeling#run_mlmpy) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)。 -- [`FlaxBartForConditionalGeneration`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/flax/language-modeling#masked-language-modeling) および [ノートブック]( https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)。 +- [`BartForConditionalGeneration`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb) でサポートされています。 +- [`TFBartForConditionalGeneration`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)。 +- [`FlaxBartForConditionalGeneration`] は、この [ノートブック]( https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)。 - [マスクされた言語モデリング](https://huggingface.co/course/chapter7/3?fw=pt) 🤗 顔ハグ コースの章。 - [マスクされた言語モデリング タスク ガイド](../tasks/masked_lang_modeling) - [ヒンディー語から英語への翻訳に Seq2SeqTrainer を使用して mBART を微調整する方法に関するノート](https://colab.research.google.com/github/vasudevgupta7/huggingface-tutorials/blob/main/translation_training.ipynb)。 🌎 -- [`BartForConditionalGeneration`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/translation) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb)。 -- [`TFBartForConditionalGeneration`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/translation) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation-tf.ipynb)。 +- [`BartForConditionalGeneration`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb)。 +- [`TFBartForConditionalGeneration`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation-tf.ipynb)。 - [翻訳タスクガイド](../tasks/translation) 以下も参照してください。 diff --git a/docs/source/ja/model_doc/barthez.md b/docs/source/ja/model_doc/barthez.md index 5668772c2636..dcd9c2fcd66b 100644 --- a/docs/source/ja/model_doc/barthez.md +++ b/docs/source/ja/model_doc/barthez.md @@ -45,12 +45,6 @@ BARThez の実装は、トークン化を除いて BART と同じです。詳細 -### Resources - -- BARThez は、BART と同様の方法でシーケンス間のタスクを微調整できます。以下を確認してください。 - [examples/pytorch/summarization/](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization/README.md)。 - - ## BarthezTokenizer [[autodoc]] BarthezTokenizer diff --git a/docs/source/ja/model_doc/beit.md b/docs/source/ja/model_doc/beit.md index af52e03ebf37..807132007a76 100644 --- a/docs/source/ja/model_doc/beit.md +++ b/docs/source/ja/model_doc/beit.md @@ -77,7 +77,7 @@ BEiT の使用を開始するのに役立つ公式 Hugging Face およびコミ -- [`BeitForImageClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 +- [`BeitForImageClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 - 参照: [画像分類タスク ガイド](../tasks/image_classification) **セマンティック セグメンテーション** diff --git a/docs/source/ja/model_doc/bert.md b/docs/source/ja/model_doc/bert.md index 4bb582966277..f0a57d917f3d 100644 --- a/docs/source/ja/model_doc/bert.md +++ b/docs/source/ja/model_doc/bert.md @@ -73,41 +73,39 @@ BERT を始めるのに役立つ公式 Hugging Face およびコミュニティ - [マルチラベル テキスト分類のための BERT (およびその友人) の微調整](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/BERT/Fine_tuning_BERT_(and_friends)_for_multi_label_text_classification.ipynb) のノートブック. - 方法に関するノートブック [PyTorch を使用したマルチラベル分類のための BERT の微調整](https://colab.research.google.com/github/abhmishra91/transformers-tutorials/blob/master/transformers_multi_label_classification.ipynb)。 - 方法に関するノートブック [要約のために BERT を使用して EncoderDecoder モデルをウォームスタートする](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/BERT2BERT_for_CNN_Dailymail.ipynb)。 -- [`BertForSequenceClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)。 -- [`TFBertForSequenceClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/text-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)。 -- [`FlaxBertForSequenceClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/flax/text-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_flax.ipynb)。 +- [`BertForSequenceClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)。 +- [`TFBertForSequenceClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)。 +- [`FlaxBertForSequenceClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_flax.ipynb)。 - [テキスト分類タスクガイド(英語版)](../../en/tasks/sequence_classification) - [Hugging Face Transformers with Keras: Fine-tune a non-English BERT for Named Entity Recognition](https://www.philschmid.de/huggingface-transformers-keras-tf) の使用方法に関するブログ投稿。 - 各単語の最初の単語部分のみを使用した [固有表現認識のための BERT の微調整](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/Custom_Named_Entity_Recognition_with_BERT_only_first_wordpiece.ipynb) のノートブックトークン化中の単語ラベル内。単語のラベルをすべての単語部分に伝播するには、代わりにノートブックのこの [バージョン](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/BERT/Custom_Named_Entity_Recognition_with_BERT.ipynb) を参照してください。 -- [`BertForTokenClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)。 -- [`TFBertForTokenClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/token-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)。 -- [`FlaxBertForTokenClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/flax/token-classification) によってサポートされています。 +- [`BertForTokenClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)。 +- [`TFBertForTokenClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)。 - [トークン分類](https://huggingface.co/course/chapter7/2?fw=pt) 🤗 ハグフェイスコースの章。 - [トークン分類タスクガイド](../tasks/token_classification) -- [`BertForMaskedLM`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling) でサポートされており、 [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)。 -- [`TFBertForMaskedLM`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/lang-modeling#run_mlmpy) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)。 -- [`FlaxBertForMaskedLM`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/flax/language-modeling#masked-language-modeling) および [ノートブック]( https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)。 +- [`BertForMaskedLM`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb) でサポートされています。 +- [`TFBertForMaskedLM`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)。 +- [`FlaxBertForMaskedLM`] は、この [ノートブック]( https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)。 - [マスクされた言語モデリング](https://huggingface.co/course/chapter7/3?fw=pt) 🤗 顔ハグ コースの章。 - [マスクされた言語モデリング タスク ガイド](../tasks/masked_lang_modeling) -- [`BertForQuestionAnswering`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)。 -- [`TFBertForQuestionAnswering`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/question-answering) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)。 -- [`FlaxBertForQuestionAnswering`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/flax/question-answering) でサポートされています。 +- [`BertForQuestionAnswering`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)。 +- [`TFBertForQuestionAnswering`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)。 - [質問回答](https://huggingface.co/course/chapter7/7?fw=pt) 🤗 ハグフェイスコースの章。 - [質問回答タスク ガイド](../tasks/question_answering) **複数の選択肢** -- [`BertForMultipleChoice`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/multiple-choice) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)。 -- [`TFBertForMultipleChoice`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/multiple-choice) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)。 +- [`BertForMultipleChoice`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)。 +- [`TFBertForMultipleChoice`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)。 - [多肢選択タスク ガイド](../tasks/multiple_choice) ⚡️ **推論** diff --git a/docs/source/ja/model_doc/biogpt.md b/docs/source/ja/model_doc/biogpt.md index 0634062a6b72..ee19c213ebc5 100644 --- a/docs/source/ja/model_doc/biogpt.md +++ b/docs/source/ja/model_doc/biogpt.md @@ -27,7 +27,7 @@ BioGPT モデルは、[BioGPT: generative pre-trained transformer for biomedical ## Usage tips - BioGPT は絶対位置埋め込みを備えたモデルであるため、通常は入力を左側ではなく右側にパディングすることをお勧めします。 -- BioGPT は因果言語モデリング (CLM) 目的でトレーニングされているため、シーケンス内の次のトークンを予測するのに強力です。 run_generation.py サンプル スクリプトで確認できるように、この機能を利用すると、BioGPT は構文的に一貫したテキストを生成できます。 +- BioGPT は因果言語モデリング (CLM) 目的でトレーニングされているため、シーケンス内の次のトークンを予測するのに強力です。この機能を利用すると、BioGPT は構文的に一貫したテキストを生成できます。 - モデルは、以前に計算されたキーと値のアテンション ペアである`past_key_values`(PyTorch の場合) を入力として受け取ることができます。この (past_key_values または past) 値を使用すると、モデルがテキスト生成のコンテキストで事前に計算された値を再計算できなくなります。 PyTorch の使用法の詳細については、BioGptForCausalLM.forward() メソッドの past_key_values 引数を参照してください。 このモデルは、[kamalkraj](https://huggingface.co/kamalkraj) によって提供されました。元のコードは [ここ](https://github.com/microsoft/BioGPT) にあります。 diff --git a/docs/source/ja/model_doc/bit.md b/docs/source/ja/model_doc/bit.md index 07029272e545..cd2d8ad33325 100644 --- a/docs/source/ja/model_doc/bit.md +++ b/docs/source/ja/model_doc/bit.md @@ -40,7 +40,7 @@ BiT を始めるのに役立つ公式 Hugging Face およびコミュニティ ( -- [`BitForImageClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 +- [`BitForImageClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 - 参照: [画像分類タスク ガイド](../tasks/image_classification) ここに含めるリソースの送信に興味がある場合は、お気軽にプル リクエストを開いてください。審査させていただきます。リソースは、既存のリソースを複製するのではなく、何か新しいものを示すことが理想的です。 diff --git a/docs/source/ja/model_doc/bloom.md b/docs/source/ja/model_doc/bloom.md index d9f0e28eaf4e..cedb2be0616c 100644 --- a/docs/source/ja/model_doc/bloom.md +++ b/docs/source/ja/model_doc/bloom.md @@ -35,7 +35,7 @@ BLOOM を使い始めるのに役立つ公式 Hugging Face およびコミュニ -- [`BloomForCausalLM`] これによってサポートされています [causal language modeling example script](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#gpt-2gpt-and-causal-language-modeling) and [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). +- [`BloomForCausalLM`] これによってサポートされています [notebook](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb). 以下も参照してください。 - [因果言語モデリング タスク ガイド](../tasks/language_modeling) diff --git a/docs/source/ja/model_doc/clip.md b/docs/source/ja/model_doc/clip.md index 7de3be2ce294..3f547ea1142c 100644 --- a/docs/source/ja/model_doc/clip.md +++ b/docs/source/ja/model_doc/clip.md @@ -83,7 +83,6 @@ CLIP は、マルチモーダルなビジョンおよび言語モデルです。 CLIP を使い始めるのに役立つ公式 Hugging Face およびコミュニティ (🌎 で示されている) リソースのリスト。 - [リモート センシング (衛星) 画像とキャプションを使用した CLIP の微調整](https://huggingface.co/blog/fine-tune-clip-rsicd)、[RSICD データセット] を使用して CLIP を微調整する方法に関するブログ投稿(https://github.com/201528014227051/RSICD_optimal) と、データ拡張によるパフォーマンスの変化の比較。 -- この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/contrastive-image-text) は、プレ- [COCO データセット](https://cocodataset.org/#home) を使用してトレーニングされたビジョンおよびテキスト エンコーダー。 diff --git a/docs/source/ja/model_doc/convnext.md b/docs/source/ja/model_doc/convnext.md index 93c9edb4b2b3..63f7758ef148 100644 --- a/docs/source/ja/model_doc/convnext.md +++ b/docs/source/ja/model_doc/convnext.md @@ -46,7 +46,7 @@ ConvNeXT の使用を開始するのに役立つ公式 Hugging Face およびコ -- [`ConvNextForImageClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 +- [`ConvNextForImageClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 - 参照: [画像分類タスク ガイド](../tasks/image_classification) ここに含めるリソースの送信に興味がある場合は、お気軽にプル リクエストを開いてください。審査させていただきます。リソースは、既存のリソースを複製するのではなく、何か新しいものを示すことが理想的です。 diff --git a/docs/source/ja/model_doc/convnextv2.md b/docs/source/ja/model_doc/convnextv2.md index cf80bcd63bbf..d541fe7cd302 100644 --- a/docs/source/ja/model_doc/convnextv2.md +++ b/docs/source/ja/model_doc/convnextv2.md @@ -38,7 +38,7 @@ ConvNeXt V2 の使用を開始するのに役立つ公式 Hugging Face および -- [`ConvNextV2ForImageClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 +- [`ConvNextV2ForImageClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 ここに含めるリソースの送信に興味がある場合は、お気軽にプル リクエストを開いてください。審査させていただきます。リソースは、既存のリソースを複製するのではなく、何か新しいものを示すことが理想的です。 diff --git a/docs/source/ja/model_doc/ctrl.md b/docs/source/ja/model_doc/ctrl.md index 44b6892cdc02..343042551002 100644 --- a/docs/source/ja/model_doc/ctrl.md +++ b/docs/source/ja/model_doc/ctrl.md @@ -53,7 +53,6 @@ CTRL モデルは、Nitish Shirish Keskar*、Bryan McCann*、Lav R. Varshney、C 左。 - CTRL は因果言語モデリング (CLM) の目的でトレーニングされているため、次の予測に強力です。 シーケンス内のトークン。この機能を利用すると、CTRL は構文的に一貫したテキストを生成できるようになります。 - *run_generation.py* サンプル スクリプトで確認できます。 - PyTorch モデルは、以前に計算されたキーと値のアテンション ペアである`past_key_values`を入力として受け取ることができます。 TensorFlow モデルは`past`を入力として受け入れます。 `past_key_values`値を使用すると、モデルが再計算されなくなります。 テキスト生成のコンテキストで事前に計算された値。 [`forward`](model_doc/ctrl#transformers.CTRLModel.forward) を参照してください。 diff --git a/docs/source/ja/model_doc/cvt.md b/docs/source/ja/model_doc/cvt.md index 51616de75b26..49c1a4404f83 100644 --- a/docs/source/ja/model_doc/cvt.md +++ b/docs/source/ja/model_doc/cvt.md @@ -48,7 +48,7 @@ CvT を始めるのに役立つ公式 Hugging Face およびコミュニティ ( -- [`CvtForImageClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 +- [`CvtForImageClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 - 参照: [画像分類タスク ガイド](../tasks/image_classification) ここに含めるリソースの送信に興味がある場合は、お気軽にプル リクエストを開いてください。審査させていただきます。リソースは、既存のリソースを複製するのではなく、何か新しいものを示すことが理想的です。 diff --git a/docs/source/ja/model_doc/data2vec.md b/docs/source/ja/model_doc/data2vec.md index b01e43b4a6f5..5c351bb156b3 100644 --- a/docs/source/ja/model_doc/data2vec.md +++ b/docs/source/ja/model_doc/data2vec.md @@ -54,7 +54,7 @@ Data2Vec の使用を開始するのに役立つ公式 Hugging Face およびコ -- [`Data2VecVisionForImageClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) および [ノートブック](https://cola.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 +- [`Data2VecVisionForImageClassification`] は、この [ノートブック](https://cola.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 - カスタム データセットで [`TFData2VecVisionForImageClassification`] を微調整するには、[このノートブック](https://colab.research.google.com/github/sayakpaul/TF-2.0-Hacks/blob/master/data2vec_vision_image_classification.ipynb) を参照してください。 )。 **Data2VecText ドキュメント リソース** diff --git a/docs/source/ja/model_doc/deberta.md b/docs/source/ja/model_doc/deberta.md index 58bc1ed214e5..e2e60e565ba6 100644 --- a/docs/source/ja/model_doc/deberta.md +++ b/docs/source/ja/model_doc/deberta.md @@ -50,29 +50,29 @@ DeBERTa を使い始めるのに役立つ公式 Hugging Face およびコミュ - DeBERTa を使用して [DeepSpeed を使用して大規模モデルのトレーニングを加速する](https://huggingface.co/blog/accelerate-deepspeed) 方法に関するブログ投稿。 - DeBERTa による [機械学習によるスーパーチャージされた顧客サービス](https://huggingface.co/blog/supercharge-customer-service-with-machine-learning) に関するブログ投稿。 -- [`DebertaForSequenceClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)。 -- [`TFDebertaForSequenceClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/text-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)。 +- [`DebertaForSequenceClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)。 +- [`TFDebertaForSequenceClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)。 - [テキスト分類タスクガイド(英語版)](../../en/tasks/sequence_classification) -- [`DebertaForTokenClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)。 -- [`TFDebertaForTokenClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/token-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)。 +- [`DebertaForTokenClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)。 +- [`TFDebertaForTokenClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)。 - [トークン分類](https://huggingface.co/course/chapter7/2?fw=pt) 🤗 ハグフェイスコースの章。 - 🤗 ハグフェイスコースの [バイトペアエンコーディングのトークン化](https://huggingface.co/course/chapter6/5?fw=pt) の章。 - [トークン分類タスクガイド](../tasks/token_classification) -- [`DebertaForMaskedLM`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling) でサポートされています。 [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)。 -- [`TFDebertaForMaskedLM`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/lang-modeling#run_mlmpy) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)。 +- [`DebertaForMaskedLM`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb) でサポートされています。 +- [`TFDebertaForMaskedLM`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)。 - [マスクされた言語モデリング](https://huggingface.co/course/chapter7/3?fw=pt) 🤗 顔のハグ コースの章。 - [マスク言語モデリング タスク ガイド](../tasks/masked_language_modeling) -- [`DebertaForQuestionAnswering`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)。 -- [`TFDebertaForQuestionAnswering`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/question-answering) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)。 +- [`DebertaForQuestionAnswering`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)。 +- [`TFDebertaForQuestionAnswering`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)。 - [質問回答](https://huggingface.co/course/chapter7/7?fw=pt) 🤗 ハグフェイスコースの章。 - [質問回答タスク ガイド](../tasks/question_answering) diff --git a/docs/source/ja/model_doc/deit.md b/docs/source/ja/model_doc/deit.md index 18ec1737f404..a4244dc8d9c1 100644 --- a/docs/source/ja/model_doc/deit.md +++ b/docs/source/ja/model_doc/deit.md @@ -75,13 +75,9 @@ DeiT を始めるのに役立つ公式 Hugging Face およびコミュニティ -- [`DeiTForImageClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 +- [`DeiTForImageClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 - 参照: [画像分類タスク ガイド](../tasks/image_classification) -それに加えて: - -- [`DeiTForMaskedImageModeling`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining) でサポートされています。 - ここに含めるリソースの送信に興味がある場合は、お気軽にプル リクエストを開いてください。審査させていただきます。リソースは、既存のリソースを複製するのではなく、何か新しいものを示すことが理想的です。 ## DeiTConfig diff --git a/docs/source/ja/model_doc/dinat.md b/docs/source/ja/model_doc/dinat.md index ee373cdd75ad..224525044b74 100644 --- a/docs/source/ja/model_doc/dinat.md +++ b/docs/source/ja/model_doc/dinat.md @@ -73,7 +73,7 @@ DiNAT の使用を開始するのに役立つ公式 Hugging Face およびコミ -- [`DinatForImageClassification`] は、この [サンプル スクリプト](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) および [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 +- [`DinatForImageClassification`] は、この [ノートブック](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)。 - 参照: [画像分類タスク ガイド](../tasks/image_classification) ここに含めるリソースの送信に興味がある場合は、お気軽にプル リクエストを開いてください。審査させていただきます。リソースは、既存のリソースを複製するのではなく、何か新しいものを示すことが理想的です。 diff --git a/docs/source/ja/multilingual.md b/docs/source/ja/multilingual.md index 39524195f888..9edfd4d956ac 100644 --- a/docs/source/ja/multilingual.md +++ b/docs/source/ja/multilingual.md @@ -77,8 +77,6 @@ XLM には10の異なるチェックポイントがあり、そのうちの1つ >>> outputs = model(input_ids, langs=langs) ``` -[run_generation.py](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-generation/run_generation.py) スクリプトは、`xlm-clm` チェックポイントを使用して、言語が埋め込まれたテキストを生成できます。 - ### 言語の埋め込みがないXLM 次の XLM モデルは、推論中に言語の埋め込みを必要としません。 diff --git a/docs/source/ja/perf_hardware.md b/docs/source/ja/perf_hardware.md index 0d104ed3ddb0..82a8225685b6 100644 --- a/docs/source/ja/perf_hardware.md +++ b/docs/source/ja/perf_hardware.md @@ -116,45 +116,3 @@ GPU1 PHB X 0-11 N/A > (Note that 3-Way and 4-Way SLI configurations are not supported.) したがって、`nvidia-smi topo -m` の出力の `NVX` レポートで取得する `X` が高いほど良いです。世代はあなたのGPUアーキテクチャに依存します。 - -小さなサンプルのwikitextを使用したgpt2言語モデルのトレーニングの実行を比較しましょう。 - -結果は次のとおりです: - -(ここに結果を挿入) - -上記のテキストの日本語訳を提供しました。Markdownコードとしてフォーマットしました。どんな他の質問があれば、お気軽にお知らせください! - -| NVlink | Time | -| ----- | ---: | -| Y | 101s | -| N | 131s | - - -NVLinkを使用すると、トレーニングが約23%速く完了することがわかります。2番目のベンチマークでは、`NCCL_P2P_DISABLE=1`を使用して、GPUがNVLinkを使用しないように指示しています。 - -以下は、完全なベンチマークコードと出力です: - - -```bash -# DDP w/ NVLink - -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 torchrun \ ---nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \ ---dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train \ ---output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 101.9003, 'train_samples_per_second': 1.963, 'epoch': 0.69} - -# DDP w/o NVLink - -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 NCCL_P2P_DISABLE=1 torchrun \ ---nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \ ---dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train ---output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 131.4367, 'train_samples_per_second': 1.522, 'epoch': 0.69} -``` - -Hardware: 2x TITAN RTX 24GB each + NVlink with 2 NVLinks (`NV2` in `nvidia-smi topo -m`) -Software: `pytorch-1.8-to-be` + `cuda-11.0` / `transformers==4.3.0.dev0` diff --git a/docs/source/ja/perf_infer_gpu_one.md b/docs/source/ja/perf_infer_gpu_one.md index b17c13cf8806..1189d0525075 100644 --- a/docs/source/ja/perf_infer_gpu_one.md +++ b/docs/source/ja/perf_infer_gpu_one.md @@ -59,7 +59,7 @@ model = AutoModelForCausalLM.from_pretrained( 特に長いシーケンスに対して、微調整と推論の際には、かなりの高速化が期待できます。ただし、Flash Attentionはパディングトークンを使用してアテンションスコアを計算しないため、シーケンスにパディングトークンが含まれる場合、バッチ推論においてアテンションスコアを手動でパッド/アンパッドする必要があり、パディングトークンを含むバッチ生成の大幅な遅延が発生します。 -これを克服するために、トレーニング中にシーケンスにパディングトークンを使用せずにFlash Attentionを使用する必要があります(たとえば、データセットをパックすることにより、シーケンスを最大シーケンス長に達するまで連結することなど)。ここに[例](https://github.com/huggingface/transformers/blob/main/examples/pytorch/language-modeling/run_clm.py#L516)が提供されています。 +これを克服するために、トレーニング中にシーケンスにパディングトークンを使用せずにFlash Attentionを使用する必要があります(たとえば、データセットをパックすることにより、シーケンスを最大シーケンス長に達するまで連結することなど)。 以下は、パディングトークンのない場合に、シーケンス長が4096の[tiiuae/falcon-7b](https://hf.co/tiiuae/falcon-7b)に対する単純なフォワードパスの予想される高速化です。さまざまなバッチサイズが示されています: diff --git a/docs/source/ja/perf_train_cpu.md b/docs/source/ja/perf_train_cpu.md index bf623d131363..08bdc683858e 100644 --- a/docs/source/ja/perf_train_cpu.md +++ b/docs/source/ja/perf_train_cpu.md @@ -42,26 +42,6 @@ pip install intel_extension_for_pytorch== -f https://developer.int [IPEXのインストール方法](https://intel.github.io/intel-extension-for-pytorch/cpu/latest/tutorials/installation.html)について、さらなるアプローチを確認してください。 -### Trainerでの使用方法 -TrainerでIPEXの自動混合精度を有効にするには、ユーザーはトレーニングコマンド引数に `use_ipex`、`bf16`、および `no_cuda` を追加する必要があります。 - -[Transformersの質問応答](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering)のユースケースを例に説明します。 - -- CPU上でBF16自動混合精度を使用してIPEXでトレーニングを行う場合: -
 python run_qa.py \
---model_name_or_path google-bert/bert-base-uncased \
---dataset_name squad \
---do_train \
---do_eval \
---per_device_train_batch_size 12 \
---learning_rate 3e-5 \
---num_train_epochs 2 \
---max_seq_length 384 \
---doc_stride 128 \
---output_dir /tmp/debug_squad/ \
---use_ipex \
---bf16 --no_cuda
- ### Practice example Blog: [Accelerating PyTorch Transformers with Intel Sapphire Rapids](https://huggingface.co/blog/intel-sapphire-rapids) diff --git a/docs/source/ja/perf_train_cpu_many.md b/docs/source/ja/perf_train_cpu_many.md index 26da32f57725..2843fe088b29 100644 --- a/docs/source/ja/perf_train_cpu_many.md +++ b/docs/source/ja/perf_train_cpu_many.md @@ -84,68 +84,3 @@ source $torch_ccl_path/env/setvars.sh #### IPEX installation: IPEXは、Float32およびBFloat16の両方でCPUトレーニングのパフォーマンス最適化を提供します。詳細は[こちらのシングルCPUセクション](./perf_train_cpu)をご参照ください。 - -以下の「トレーナーでの使用」は、Intel® MPIライブラリでmpirunを使用する例を示しています。 - -## Usage in Trainer -トレーナーでのマルチCPU分散トレーニングを有効にするために、ユーザーはコマンド引数に **`--ddp_backend ccl`** を追加する必要があります。 - -例を見てみましょう。[質問応答の例](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) - -以下のコマンドは、1つのXeonノードで2つのプロセスを使用してトレーニングを有効にします。1つのプロセスが1つのソケットで実行されます。OMP_NUM_THREADS/CCL_WORKER_COUNT変数は、最適なパフォーマンスを調整するために調整できます。 - - -```shell script - export CCL_WORKER_COUNT=1 - export MASTER_ADDR=127.0.0.1 - mpirun -n 2 -genv OMP_NUM_THREADS=23 \ - python3 run_qa.py \ - --model_name_or_path google-bert/bert-large-uncased \ - --dataset_name squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ \ - --no_cuda \ - --ddp_backend ccl \ - --use_ipex -``` - -以下のコマンドは、2つのXeonプロセッサ(node0とnode1、node0をメインプロセスとして使用)で合計4つのプロセスを使用してトレーニングを有効にします。ppn(ノードごとのプロセス数)は2に設定され、1つのソケットごとに1つのプロセスが実行されます。最適なパフォーマンスを得るために、OMP_NUM_THREADS/CCL_WORKER_COUNT変数を調整できます。 - -node0では、各ノードのIPアドレスを含む構成ファイルを作成し、その構成ファイルのパスを引数として渡す必要があります。 - -```shell script - cat hostfile - xxx.xxx.xxx.xxx #node0 ip - xxx.xxx.xxx.xxx #node1 ip -``` - -ノード0で次のコマンドを実行すると、ノード0とノード1で**4DDP**がBF16自動混合精度で有効になります。 - - -```shell script - export CCL_WORKER_COUNT=1 - export MASTER_ADDR=xxx.xxx.xxx.xxx #node0 ip - mpirun -f hostfile -n 4 -ppn 2 \ - -genv OMP_NUM_THREADS=23 \ - python3 run_qa.py \ - --model_name_or_path google-bert/bert-large-uncased \ - --dataset_name squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ \ - --no_cuda \ - --ddp_backend ccl \ - --use_ipex \ - --bf16 -``` \ No newline at end of file diff --git a/docs/source/ja/perf_train_gpu_many.md b/docs/source/ja/perf_train_gpu_many.md index 862171fecec4..ac499be0040e 100644 --- a/docs/source/ja/perf_train_gpu_many.md +++ b/docs/source/ja/perf_train_gpu_many.md @@ -111,57 +111,6 @@ DPとDDPの他にも違いがありますが、この議論には関係ありま これら2つのモードを深く理解したい場合、この[記事](https://www.telesens.co/2019/04/04/distributed-data-parallel-training-using-pytorch-on-aws/)を強くお勧めします。素晴らしいダイアグラムを含み、さまざまなハードウェアでの複数のベンチマークとプロファイラの出力を示し、知っておく必要があるすべての微妙なニュアンスを説明しています。 -実際のベンチマークを見てみましょう: - -| Type | NVlink | Time | -| :----- | ----- | ---: | -| 2:DP | Y | 110s | -| 2:DDP | Y | 101s | -| 2:DDP | N | 131s | - - -解析: - -ここで、DPはNVlinkを使用したDDPに比べて約10%遅く、NVlinkを使用しないDDPに比べて約15%高速であることが示されています。 - -実際の違いは、各GPUが他のGPUと同期する必要があるデータの量に依存します。同期するデータが多いほど、遅いリンクが合計の実行時間を遅くする可能性が高くなります。 - -以下は完全なベンチマークコードと出力です: - -`NCCL_P2P_DISABLE=1`を使用して、対応するベンチマークでNVLink機能を無効にしました。 - - -```bash - -# DP -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 \ -python examples/pytorch/language-modeling/run_clm.py \ ---model_name_or_path openai-community/gpt2 --dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 \ ---do_train --output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 110.5948, 'train_samples_per_second': 1.808, 'epoch': 0.69} - -# DDP w/ NVlink -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 \ -torchrun --nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py \ ---model_name_or_path openai-community/gpt2 --dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 \ ---do_train --output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 101.9003, 'train_samples_per_second': 1.963, 'epoch': 0.69} - -# DDP w/o NVlink -rm -r /tmp/test-clm; NCCL_P2P_DISABLE=1 CUDA_VISIBLE_DEVICES=0,1 \ -torchrun --nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py \ ---model_name_or_path openai-community/gpt2 --dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 \ ---do_train --output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 131.4367, 'train_samples_per_second': 1.522, 'epoch': 0.69} -``` - -ハードウェア: 2x TITAN RTX、各24GB + 2つのNVLink(`nvidia-smi topo -m`で `NV2`) - -ソフトウェア: `pytorch-1.8-to-be` + `cuda-11.0` / `transformers==4.3.0.dev0` - ## ZeRO Data Parallelism ZeROパワードデータ並列処理(ZeRO-DP)は、次の[ブログ投稿](https://www.microsoft.com/en-us/research/blog/zero-deepspeed-new-system-optimizations-enable-training-models-with-over-100-billion-parameters/)のダイアグラムで説明されています。 diff --git a/docs/source/ja/run_scripts.md b/docs/source/ja/run_scripts.md deleted file mode 100644 index bf0ed8627024..000000000000 --- a/docs/source/ja/run_scripts.md +++ /dev/null @@ -1,301 +0,0 @@ - - -# Train with a script - -🤗 Transformersの[notebooks](./notebooks/README)と一緒に、[PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch)、[TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow)、または[JAX/Flax](https://github.com/huggingface/transformers/tree/main/examples/flax)を使用してモデルをトレーニングする方法を示すサンプルスクリプトもあります。 - -また、私たちの[研究プロジェクト](https://github.com/huggingface/transformers-research-projects/)や[レガシーの例](https://github.com/huggingface/transformers/tree/main/examples/legacy)で使用したスクリプトも見つかります。これらのスクリプトは現在メンテナンスされておらず、おそらく最新バージョンのライブラリと互換性がない特定の🤗 Transformersのバージョンが必要です。 - -サンプルスクリプトはすべての問題でそのまま動作することは期待されておらず、解決しようとしている問題にスクリプトを適応させる必要があるかもしれません。この点をサポートするために、ほとんどのスクリプトはデータがどのように前処理されているかを完全に公開し、必要に応じて編集できるようにしています。 - -サンプルスクリプトで実装したい機能がある場合は、[フォーラム](https://discuss.huggingface.co/)か[イシュートラッカー](https://github.com/huggingface/transformers/issues)で議論してからプルリクエストを提出してください。バグ修正は歓迎しますが、読みやすさのコストで機能を追加するプルリクエストはほとんどマージされない可能性が高いです。 - -このガイドでは、[PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization)と[TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization)で実行するサマリゼーショントレーニングスクリプトの実行方法を示します。すべての例は、明示的に指定されていない限り、両方のフレームワークともに動作することが期待されています。 - -## Setup - -最新バージョンのサンプルスクリプトを正常に実行するには、新しい仮想環境に🤗 Transformersをソースからインストールする必要があります: - - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -以前のスクリプトのバージョンについては、以下のトグルをクリックしてください: - -
- 以前の🤗 Transformersのバージョンに関する例 - -
- -次に、現在の🤗 Transformersのクローンを特定のバージョンに切り替えてください。たとえば、v3.5.1などです。 - - -```bash -git checkout tags/v3.5.1 -``` - - -適切なライブラリバージョンを設定したら、任意の例のフォルダに移動し、例固有の要件をインストールします: - - - -```bash -pip install -r requirements.txt -``` - -## Run a script - -この例のスクリプトは、🤗 [Datasets](https://huggingface.co/docs/datasets/) ライブラリからデータセットをダウンロードし、前処理を行います。次に、[Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) を使用して要約をサポートするアーキテクチャ上でデータセットをファインチューニングします。以下の例では、[CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail) データセット上で [T5-small](https://huggingface.co/google-t5/t5-small) をファインチューニングする方法が示されています。T5 モデルは、そのトレーニング方法に起因して追加の `source_prefix` 引数が必要です。このプロンプトにより、T5 はこれが要約タスクであることを知ることができます。 - - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - - -## Distributed training and mixed precision - -[Trainer](https://huggingface.co/docs/transformers/main_classes/trainer)は、分散トレーニングと混合精度をサポートしています。つまり、この機能をスクリプトで使用することができます。これらの機能を有効にするには、次の手順を実行します。 - -- `fp16`引数を追加して混合精度を有効にします。 -- `nproc_per_node`引数で使用するGPUの数を設定します。 - -以下は提供されたBashコードです。このコードの日本語訳をMarkdown形式で記載します。 - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - - -TensorFlowスクリプトは、分散トレーニングに[`MirroredStrategy`](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy)を使用し、トレーニングスクリプトに追加の引数を追加する必要はありません。TensorFlowスクリプトは、デフォルトで複数のGPUが利用可能な場合にそれらを使用します。 - -## Run a script on a TPU - -Tensor Processing Units (TPUs)は、パフォーマンスを加速させるために特別に設計されています。PyTorchは、[XLA](https://www.tensorflow.org/xla)ディープラーニングコンパイラを使用してTPUsをサポートしており、詳細については[こちら](https://github.com/pytorch/xla/blob/master/README.md)をご覧ください。TPUを使用するには、`xla_spawn.py`スクリプトを起動し、`num_cores`引数を使用して使用するTPUコアの数を設定します。 -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Run a script with 🤗 Accelerate - -🤗 [Accelerate](https://huggingface.co/docs/accelerate)は、PyTorch専用のライブラリで、CPUのみ、複数のGPU、TPUなど、さまざまなセットアップでモデルをトレーニングするための統一された方法を提供します。PyTorchのトレーニングループを完全に可視化しながら実行できます。まだインストールしていない場合は、🤗 Accelerateをインストールしてください: - -> 注意:Accelerateは急速に開発が進行しているため、スクリプトを実行するにはaccelerateのgitバージョンをインストールする必要があります -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -代わりに、`run_summarization_no_trainer.py` スクリプトを使用する必要があります。 🤗 Accelerate がサポートするスクリプトには、フォルダ内に `task_no_trainer.py` ファイルが含まれています。まず、次のコマンドを実行して設定ファイルを作成し、保存します: - -```bash -accelerate config -``` - -テストを行い、設定が正しく構成されているか確認してください: - - -```bash -accelerate test -``` - -Now you are ready to launch the training: - - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## Use a custom dataset - -要約スクリプトは、CSVまたはJSON Lineファイルであれば、カスタムデータセットをサポートしています。独自のデータセットを使用する場合、いくつかの追加の引数を指定する必要があります。 - -- `train_file`および`validation_file`は、トレーニングとバリデーションのファイルへのパスを指定します。 -- `text_column`は要約するための入力テキストです。 -- `summary_column`は出力する対象テキストです。 - -カスタムデータセットを使用した要約スクリプトは、以下のようになります: - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Test a script - -すべてが予想通りに動作することを確認するために、データセット全体を処理する前に、データセットの一部の例でスクリプトを実行することは良いアイデアです。以下の引数を使用して、データセットを最大サンプル数に切り詰めます: - -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -一部の例のスクリプトは、`max_predict_samples`引数をサポートしていないことがあります。この引数がサポートされているかどうかがわからない場合は、`-h`引数を追加して確認してください。 - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## Resume training from checkpoint - -以前のチェックポイントからトレーニングを再開するための役立つオプションもあります。これにより、トレーニングが中断された場合でも、最初からやり直すことなく、中断したところから再開できます。チェックポイントからトレーニングを再開するための2つの方法があります。 - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## Share your model - -すべてのスクリプトは、最終的なモデルを [Model Hub](https://huggingface.co/models) にアップロードできます。開始する前に Hugging Face にログインしていることを確認してください。 - -```bash -hf auth login -``` - -次に、スクリプトに `push_to_hub` 引数を追加します。この引数は、Hugging Face のユーザー名と `output_dir` で指定したフォルダ名でリポジトリを作成します。 - -特定の名前をリポジトリに付けるには、`push_to_hub_model_id` 引数を使用して追加します。このリポジトリは自動的にあなたの名前空間の下にリストされます。 - -以下の例は、特定のリポジトリ名でモデルをアップロードする方法を示しています: - - - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - - - - diff --git a/docs/source/ja/testing.md b/docs/source/ja/testing.md index df5936dc7043..d3a0f92f4924 100644 --- a/docs/source/ja/testing.md +++ b/docs/source/ja/testing.md @@ -39,7 +39,6 @@ rendered properly in your Markdown viewer. ```bash RUN_SLOW=1 pytest tests/ -RUN_SLOW=1 pytest examples/ ``` 結果は[here](https://github.com/huggingface/transformers/actions)で観察できます。 @@ -499,7 +498,7 @@ TRANSFORMERS_TEST_BACKEND="torch_npu" pytest tests/utils/test_logging.py これを使用するいくつかのテストがあります: - [test_trainer_distributed.py](https://github.com/huggingface/transformers/tree/main/tests/trainer/distributed/test_trainer_distributed.py) -- [test_deepspeed.py](https://github.com/huggingface/transformers/tree/main/tests/deepspeed/test_deepspeed.py) +- [test_trainer_distributed_deepspeed.py](https://github.com/huggingface/transformers/tree/main/tests/trainer/distributed/test_trainer_distributed_deepspeed.py) 実行ポイントにすぐに移動するには、これらのテスト内で `execute_subprocess_async` 呼び出しを検索してください。 @@ -696,7 +695,7 @@ from transformers.testing_utils import TestCasePlus class PathExampleTest(TestCasePlus): def test_something_involving_local_locations(self): - data_dir = self.tests_dir / "fixtures/tests_samples/wmt_en_ro" + data_dir = self.tests_dir / "fixtures/tests_samples/wmt16" ``` もし、`pathlib` を介してパスを操作する必要がない場合、または単に文字列としてパスが必要な場合は、`pathlib` オブジェクトに `str()` を呼び出すか、`_str` で終わるアクセサを使用できます。例: diff --git a/docs/source/ja/training.md b/docs/source/ja/training.md index 19dfa7a54db7..fc93fb2500f0 100644 --- a/docs/source/ja/training.md +++ b/docs/source/ja/training.md @@ -315,6 +315,4 @@ PyTorchから[`AdamW`](https://pytorch.org/docs/stable/generated/torch.optim.Ada さらなるファインチューニングの例については、以下を参照してください: -- [🤗 Transformers Examples](https://github.com/huggingface/transformers/tree/main/examples) には、PyTorchとTensorFlowで一般的なNLPタスクをトレーニングするスクリプトが含まれています。 - - [🤗 Transformers Notebooks](notebooks) には、特定のタスクにモデルをファインチューニングする方法に関するさまざまなノートブックが含まれています。 diff --git a/docs/source/ko/_toctree.yml b/docs/source/ko/_toctree.yml index 9bacb12cd487..ade628e326e7 100644 --- a/docs/source/ko/_toctree.yml +++ b/docs/source/ko/_toctree.yml @@ -283,8 +283,6 @@ title: (번역중) Visual Document Retrieval title: 멀티모달 title: 태스크 레시피 - - local: run_scripts - title: 스크립트로 학습하기 - local: glossary title: Glossary - local: philosophy diff --git a/docs/source/ko/contributing.md b/docs/source/ko/contributing.md index ed9d5d161ccd..b39c293998ae 100644 --- a/docs/source/ko/contributing.md +++ b/docs/source/ko/contributing.md @@ -243,7 +243,7 @@ Pull Request에서 실행되는 검사에 대한 자세한 정보는 [Pull Reque ### 테스트 [[tests]] -라이브러리 동작과 여러 예제를 테스트할 수 있는 광범위한 테스트 스위트가 포함되어 있습니다. 라이브러리 테스트는 [tests](https://github.com/huggingface/transformers/tree/main/tests) 폴더에, 예제 테스트는 [examples](https://github.com/huggingface/transformers/tree/main/examples) 폴더에 있습니다. +라이브러리 동작을 테스트할 수 있는 광범위한 테스트 스위트가 포함되어 있습니다. 라이브러리 테스트는 [tests](https://github.com/huggingface/transformers/tree/main/tests) 폴더에 있습니다. 속도가 빠른 `pytest`와 `pytest-xdist`를 선호합니다. 저장소의 루트 디렉터리에서 테스트를 실행할 *하위 폴더 경로 또는 테스트 파일 경로*를 지정하세요: @@ -251,14 +251,7 @@ Pull Request에서 실행되는 검사에 대한 자세한 정보는 [Pull Reque python -m pytest -n auto --dist=loadfile -s -v ./tests/models/my_new_model ``` -마찬가지로 `examples` 디렉터리에서도 *하위 폴더 경로 또는 테스트 파일 경로*를 지정하세요. 예를 들어, 다음 명령은 PyTorch `examples` 디렉터리의 텍스트 분류 하위 폴더를 테스트합니다: - -```bash -pip install -r examples/xxx/requirements.txt # only needed the first time -python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classification -``` - -이것이 실제로 `make test` 및 `make test-examples` 명령이 구현되는 방식입니다 (`pip install`은 제외합니다)! +이것이 실제로 `make test` 명령이 구현되는 방식입니다! 또한 특정 기능만 테스트하기 위한 더 작은 테스트를 지정할 수 있습니다. @@ -272,7 +265,6 @@ python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classific ```bash RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./tests/models/my_new_model -RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classification ``` 느린 테스트와 마찬가지로, 다음과 같이 테스트 중에 기본적으로 활성화되지 않는 다른 환경 변수도 있습니다: @@ -286,7 +278,6 @@ RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/t ```bash python -m unittest discover -s tests -t . -v -python -m unittest discover -s examples -t examples -v ``` ### 스타일 가이드 [[style-guide]] diff --git a/docs/source/ko/deepspeed.md b/docs/source/ko/deepspeed.md index 32c3f199a042..c21302cb2238 100644 --- a/docs/source/ko/deepspeed.md +++ b/docs/source/ko/deepspeed.md @@ -583,33 +583,13 @@ bf16은 설정 파일에서 설정하거나 다음 인수를 전달하면 명령 -여러 GPU에 DeepSpeed를 배포하려면 `--num_gpus` 매개변수를 추가하세요. 사용 가능한 모든 GPU를 사용하려는 경우 `--num_gpus`를 추가할 필요가 없습니다. 아래 예제에서는 2개의 GPU를 사용합니다. - -```bash -deepspeed --num_gpus=2 examples/pytorch/translation/run_translation.py \ ---deepspeed tests/deepspeed/ds_config_zero3.json \ ---model_name_or_path google-t5/t5-small --per_device_train_batch_size 1 \ ---output_dir output_dir --fp16 \ ---do_train --max_train_samples 500 --num_train_epochs 1 \ ---dataset_name wmt16 --dataset_config "ro-en" \ ---source_lang en --target_lang ro -``` +여러 GPU에 DeepSpeed를 배포하려면 `--num_gpus` 매개변수를 추가하세요. 사용 가능한 모든 GPU를 사용하려는 경우 `--num_gpus`를 추가할 필요가 없습니다. 단일 GPU에 DeepSpeed를 배포하려면 `--num_gpus` 매개변수를 추가하세요. GPU가 1개만 있는 경우 이 값을 명시적으로 설정할 필요는 없습니다. DeepSpeed는 지정된 노드에서 볼 수 있는 모든 GPU를 배포하므로 이 값을 명시적으로 설정할 필요는 없습니다. -```bash -deepspeed --num_gpus=1 examples/pytorch/translation/run_translation.py \ ---deepspeed tests/deepspeed/ds_config_zero2.json \ ---model_name_or_path google-t5/t5-small --per_device_train_batch_size 1 \ ---output_dir output_dir --fp16 \ ---do_train --max_train_samples 500 --num_train_epochs 1 \ ---dataset_name wmt16 --dataset_config "ro-en" \ ---source_lang en --target_lang ro -``` - DeepSpeed는 단 하나의 GPU로도 여전히 유용합니다: 1. 일부 계산과 메모리를 CPU로 오프로드하여 더 큰 배치 크기를 사용하거나 일반적으로 맞지 않는 매우 큰 모델을 맞추기 위해 모델에 더 많은 GPU 리소스를 사용할 수 있도록 합니다. @@ -787,23 +767,10 @@ cat <<'EOT' > ds_config_zero3.json EOT ``` -트레이닝 스크립트가 노트북 셀이 아닌 파일에 있는 경우, 노트북 셀의 셸에서 `deepspeed`를 정상적으로 실행할 수 있습니다. 예를 들어 `run_translation.py`를 시작하려면 다음과 같이 하세요.: - -```py -!git clone https://github.com/huggingface/transformers -!cd transformers; deepspeed examples/pytorch/translation/run_translation.py ... -``` +트레이닝 스크립트가 노트북 셀이 아닌 파일에 있는 경우, 노트북 셀의 셸에서 `deepspeed`를 정상적으로 실행할 수 있습니다. 또한 `%%bash` 매직을 사용하여 여러 줄의 코드를 작성하여 셸 프로그램을 실행할 수도 있지만 교육이 완료될 때까지 로그를 볼 수 없습니다. `%%bash` 매직으로 분산 환경을 에뮬레이션할 필요는 없습니다. -```py -%%bash - -git clone https://github.com/huggingface/transformers -cd transformers -deepspeed examples/pytorch/translation/run_translation.py ... -``` - ## 모델 가중치 저장하기[[save-model-weights]] 딥스피드는 기본 고정밀 fp32 가중치를 사용자 지정 체크포인트 최적화 파일(glob 패턴은 `global_step*/*optim_states.pt`처럼 보입니다)에 저장하고 일반 체크포인트 아래에 저장합니다. diff --git a/docs/source/ko/installation.md b/docs/source/ko/installation.md index af6378b570a0..b65c8632d276 100644 --- a/docs/source/ko/installation.md +++ b/docs/source/ko/installation.md @@ -145,21 +145,6 @@ conda install conda-forge::transformers -예를 들어 외부 기기 사이에 방화벽을 둔 일반 네트워크에서 평소처럼 프로그램을 다음과 같이 실행할 수 있습니다. - -```bash -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -오프라인 기기에서 동일한 프로그램을 다음과 같이 실행할 수 있습니다. - -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -이제 스크립트는 로컬 파일에 한해서만 검색할 것이므로, 스크립트가 중단되거나 시간이 초과될 때까지 멈춰있지 않고 잘 실행될 것입니다. - ### 오프라인용 모델 및 토크나이저 만들어두기[[fetch-models-and-tokenizers-to-use-offline]] Another option for using 🤗 Transformers offline is to download the files ahead of time, and then point to their local path when you need to use them offline. There are three ways to do this: diff --git a/docs/source/ko/main_classes/data_collator.md b/docs/source/ko/main_classes/data_collator.md index 22a3e3a3b092..8509976951c3 100644 --- a/docs/source/ko/main_classes/data_collator.md +++ b/docs/source/ko/main_classes/data_collator.md @@ -16,7 +16,7 @@ rendered properly in your Markdown viewer. # 데이터 콜레이터(Data Collator)[[data-collator]] -데이터 콜레이터는 데이터셋 요소들의 리스트를 입력으로 사용하여 배치를 형성하는 객체입니다. 이러한 요소들은 `train_dataset` 또는 `eval_dataset의` 요소들과 동일한 타입 입니다. 배치를 구성하기 위해, 데이터 콜레이터는 (패딩과 같은) 일부 처리를 적용할 수 있습니다. [`DataCollatorForLanguageModeling`]과 같은 일부 콜레이터는 형성된 배치에 (무작위 마스킹과 같은) 일부 무작위 데이터 증강도 적용합니다. 사용 예시는 [예제 스크립트](../examples)나 [예제 노트북](../notebooks)에서 찾을 수 있습니다. +데이터 콜레이터는 데이터셋 요소들의 리스트를 입력으로 사용하여 배치를 형성하는 객체입니다. 이러한 요소들은 `train_dataset` 또는 `eval_dataset의` 요소들과 동일한 타입 입니다. 배치를 구성하기 위해, 데이터 콜레이터는 (패딩과 같은) 일부 처리를 적용할 수 있습니다. [`DataCollatorForLanguageModeling`]과 같은 일부 콜레이터는 형성된 배치에 (무작위 마스킹과 같은) 일부 무작위 데이터 증강도 적용합니다. 사용 예시는 [예제 노트북](../notebooks)에서 찾을 수 있습니다. ## 기본 데이터 콜레이터[[transformers.default_data_collator]] diff --git a/docs/source/ko/model_doc/albert.md b/docs/source/ko/model_doc/albert.md index 8f49d265c61a..c3083f9d3b88 100644 --- a/docs/source/ko/model_doc/albert.md +++ b/docs/source/ko/model_doc/albert.md @@ -100,43 +100,35 @@ for token_id in top_k[0]: -- [`AlbertForSequenceClassification`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification)에서 지원됩니다. - -- [`TFAlbertForSequenceClassification`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/text-classification)에서 지원됩니다. - -- [`FlaxAlbertForSequenceClassification`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_flax.ipynb)에서 지원됩니다. +- [`FlaxAlbertForSequenceClassification`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_flax.ipynb)에서 지원됩니다. - [텍스트 분류 작업 가이드](../tasks/sequence_classification)에서 모델 사용법을 확인하세요. -- [`AlbertForTokenClassification`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification)에서 지원됩니다. - -- [`TFAlbertForTokenClassification`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/token-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)에서 지원됩니다. +- [`TFAlbertForTokenClassification`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)에서 지원됩니다. -- [`FlaxAlbertForTokenClassification`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/token-classification)에서 지원됩니다. - 🤗 Hugging Face의 [토큰 분류](https://huggingface.co/course/chapter7/2?fw=pt) 강좌 - [토큰 분류 작업 가이드](../tasks/token_classification)에서 모델 사용법을 확인하세요. -- [`AlbertForMaskedLM`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에서 지원됩니다. -- [`TFAlbertForMaskedLM`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/language-modeling#run_mlmpy)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에서 지원됩니다. -- [`FlaxAlbertForMaskedLM`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/language-modeling#masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)에서 지원됩니다. +- [`AlbertForMaskedLM`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에서 지원됩니다. +- [`TFAlbertForMaskedLM`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에서 지원됩니다. +- [`FlaxAlbertForMaskedLM`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)에서 지원됩니다. - 🤗 Hugging Face의 [마스킹 언어 모델링](https://huggingface.co/course/chapter7/3?fw=pt) 강좌 - [마스킹 언어 모델링 작업 가이드](../tasks/masked_language_modeling)에서 모델 사용법을 확인하세요. -- [`AlbertForQuestionAnswering`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)에서 지원됩니다. -- [`TFAlbertForQuestionAnswering`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/question-answering)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)에서 지원됩니다. -- [`FlaxAlbertForQuestionAnswering`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/question-answering)에서 지원됩니다. +- [`AlbertForQuestionAnswering`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)에서 지원됩니다. +- [`TFAlbertForQuestionAnswering`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)에서 지원됩니다. - [질의응답](https://huggingface.co/course/chapter7/7?fw=pt) 🤗 Hugging Face 강좌의 챕터. - [질의응답 작업 가이드](../tasks/question_answering)에서 모델 사용법을 확인하세요. **다중 선택(Multiple choice)** -- [`AlbertForMultipleChoice`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/multiple-choice)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)에서 지원됩니다. -- [`TFAlbertForMultipleChoice`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/multiple-choice)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)에서 지원됩니다. +- [`AlbertForMultipleChoice`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)에서 지원됩니다. +- [`TFAlbertForMultipleChoice`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)에서 지원됩니다. - [다중 선택 작업 가이드](../tasks/multiple_choice)에서 모델 사용법을 확인하세요. diff --git a/docs/source/ko/model_doc/bart.md b/docs/source/ko/model_doc/bart.md index fdcc3db43877..9cdb842d9cb3 100644 --- a/docs/source/ko/model_doc/bart.md +++ b/docs/source/ko/model_doc/bart.md @@ -85,26 +85,25 @@ BART를 시작하는 데 도움이 되는 Hugging Face와 community 자료 목 - [분산형 학습: 🤗 Transformers와 Amazon SageMaker를 이용하여 요약하기 위한 BART/T5 학습](https://huggingface.co/blog/sagemaker-distributed-training-seq2seq)에 대한 블로그 포스트. - [blurr를 이용하여 fastai로 요약하기 위한 BART를 미세 조정](https://colab.research.google.com/github/ohmeow/ohmeow_website/blob/master/posts/2021-05-25-mbart-sequence-classification-with-blurr.ipynb)하는 방법에 대한 노트북. 🌎 - [Trainer 클래스를 사용하여 두 가지 언어로 요약하기 위한 BART 미세 조정](https://colab.research.google.com/github/elsanns/xai-nlp-notebooks/blob/master/fine_tune_bart_summarization_two_langs.ipynb)하는 방법에 대한 노트북. 🌎 -- 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization.ipynb)에서는 [`BartForConditionalGeneration`]이 지원됩니다. -- [`TFBartForConditionalGeneration`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization-tf.ipynb)에서 지원됩니다. -- 이 [예제 스크립트에서는](https://github.com/huggingface/transformers/tree/main/examples/flax/summarization)[`FlaxBartForConditionalGeneration`]이 지원됩니다. +- 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization.ipynb)에서는 [`BartForConditionalGeneration`]이 지원됩니다. +- [`TFBartForConditionalGeneration`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization-tf.ipynb)에서 지원됩니다. - Hugging Face `datasets` 객체를 활용하여 [`BartForConditionalGeneration`]을 학습시키는 방법의 예는 이 [포럼 토론](https://discuss.huggingface.co/t/train-bart-for-conditional-generation-e-g-summarization/1904)에서 찾을 수 있습니다. - 🤗 Hugging Face 코스의 [요약](https://huggingface.co/course/chapter7/5?fw=pt#summarization)장. - [요약 작업 가이드](../tasks/summarization) -- [`BartForConditionalGeneration`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)을 참고하세요. -- [`TFBartForConditionalGeneration`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/language-modeling#run_mlmpy)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)을 참고하세요. -- [`FlaxBartForConditionalGeneration`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/language-modeling#masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)을 참고 하세요. +- [`BartForConditionalGeneration`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)을 참고하세요. +- [`TFBartForConditionalGeneration`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)을 참고하세요. +- [`FlaxBartForConditionalGeneration`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)을 참고 하세요. - 🤗 Hugging Face 코스의 [마스크 언어 모델링](https://huggingface.co/course/chapter7/3?fw=pt) 챕터. - [마스크 언어 모델링 작업 가이드](../tasks/masked_language_modeling) - [Seq2SeqTrainer를 이용하여 인도어를 영어로 번역하는 mBART를 미세 조정](https://colab.research.google.com/github/vasudevgupta7/huggingface-tutorials/blob/main/translation_training.ipynb)하는 방법에 대한 가이드. 🌎 -- [`BartForConditionalGeneration`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/translation)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb)을 참고하세요. -- [`TFBartForConditionalGeneration`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/translation)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation-tf.ipynb)을 참고 하세요. +- [`BartForConditionalGeneration`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb)을 참고하세요. +- [`TFBartForConditionalGeneration`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation-tf.ipynb)을 참고 하세요. - [번역 작업 가이드](../tasks/translation) 추가적으로 볼 것들: diff --git a/docs/source/ko/model_doc/barthez.md b/docs/source/ko/model_doc/barthez.md index 4df8eb2cd699..827cc1742059 100644 --- a/docs/source/ko/model_doc/barthez.md +++ b/docs/source/ko/model_doc/barthez.md @@ -45,12 +45,6 @@ BARThez 전용 토크나이저는 아래에 문서화되어 있습니다. -## 리소스 [[resources]] - -- BARThez는 🤗 BART와 유사한 방식으로 시퀀스-투-시퀀스 작업에 맞춰 미세 조정될 수 있습니다. 다음을 확인하세요: - [examples/pytorch/summarization/](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization/README.md). - - ## BarthezTokenizer [[bartheztokenizer]] [[autodoc]] BarthezTokenizer diff --git a/docs/source/ko/model_doc/bert.md b/docs/source/ko/model_doc/bert.md index 3e14b7957522..5fc34c587383 100644 --- a/docs/source/ko/model_doc/bert.md +++ b/docs/source/ko/model_doc/bert.md @@ -100,40 +100,38 @@ BERT를 시작하는 데 도움이 되는 Hugging Face와 community 자료 목 - [다중 레이블 텍스트 분류를 위한 BERT (및 관련 모델) 미세 조정](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/BERT/Fine_tuning_BERT_(and_friends)_for_multi_label_text_classification.ipynb)에 대한 노트북. - [PyTorch를 이용해 BERT를 다중 레이블 분류를 위해 미세 조정하는 방법](htt기ps://colab.research.google.com/github/abhimishra91/transformers-tutorials/blob/master/transformers_multi_label_classification.ipynb)에 대한 노트북. 🌎 - [BERT로 EncoderDecoder 모델을 warm-start하여 요약하기](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/BERT2BERT_for_CNN_Dailymail.ipynb)에 대한 노트북. -- [`BertForSequenceClassification`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)에서 지원됩니다. -- [`TFBertForSequenceClassification`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)에서 지원됩니다. -- [`FlaxBertForSequenceClassification`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_flax.ipynb)에서 지원됩니다. +- [`BertForSequenceClassification`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)에서 지원됩니다. +- [`TFBertForSequenceClassification`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)에서 지원됩니다. +- [`FlaxBertForSequenceClassification`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_flax.ipynb)에서 지원됩니다. - [텍스트 분류 작업 가이드](../tasks/sequence_classification) - [Keras와 함께 Hugging Face Transformers를 사용하여 비영리 BERT를 개체명 인식(NER)용으로 미세 조정하는 방법](https://www.philschmid.de/huggingface-transformers-keras-tf)에 대한 블로그 포스트. - [BERT를 개체명 인식을 위해 미세 조정하기](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/BERT/Custom_Named_Entity_Recognition_with_BERT_only_first_wordpiece.ipynb)에 대한 노트북. 각 단어의 첫 번째 wordpiece에만 레이블을 지정하여 학습하는 방법을 설명합니다. 모든 wordpiece에 레이블을 전파하는 방법은 [이 버전](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/BERT/Custom_Named_Entity_Recognition_with_BERT.ipynb)에서 확인할 수 있습니다. -- [`BertForTokenClassification`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)에서 지원됩니다. -- [`TFBertForTokenClassification`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/token-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)에서 지원됩니다. -- [`FlaxBertForTokenClassification`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/token-classification)에서 지원됩니다. +- [`BertForTokenClassification`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)에서 지원됩니다. +- [`TFBertForTokenClassification`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)에서 지원됩니다. - 🤗 Hugging Face 코스의 [토큰 분류 챕터](https://huggingface.co/course/chapter7/2?fw=pt). - [토큰 분류 작업 가이드](../tasks/token_classification) -- [`BertForMaskedLM`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에서 지원됩니다. -- [`TFBertForMaskedLM`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/language-modeling#run_mlmpy) 와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에서 지원됩니다. -- [`FlaxBertForMaskedLM`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/language-modeling#masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)에서 지원됩니다. +- [`BertForMaskedLM`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에서 지원됩니다. +- [`TFBertForMaskedLM`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에서 지원됩니다. +- [`FlaxBertForMaskedLM`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)에서 지원됩니다. - 🤗 Hugging Face 코스의 [마스킹된 언어 모델링 챕터](https://huggingface.co/course/chapter7/3?fw=pt). - [마스킹된 언어 모델링 작업 가이드](../tasks/masked_language_modeling) -- [`BertForQuestionAnswering`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)에서 지원됩니다. -- [`TFBertForQuestionAnswering`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/question-answering) 와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)에서 지원됩니다. -- [`FlaxBertForQuestionAnswering`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/question-answering)에서 지원됩니다. +- [`BertForQuestionAnswering`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)에서 지원됩니다. +- [`TFBertForQuestionAnswering`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)에서 지원됩니다. - 🤗 Hugging Face 코스의 [질문 답변 챕터](https://huggingface.co/course/chapter7/7?fw=pt). - [질문 답변 작업 가이드](../tasks/question_answering) **다중 선택** -- [`BertForMultipleChoice`]이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/multiple-choice)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)에서 지원됩니다. -- [`TFBertForMultipleChoice`]이 [에제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/multiple-choice)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)에서 지원됩니다. +- [`BertForMultipleChoice`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)에서 지원됩니다. +- [`TFBertForMultipleChoice`]이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)에서 지원됩니다. - [다중 선택 작업 가이드](../tasks/multiple_choice) ⚡️ **추론** diff --git a/docs/source/ko/model_doc/biogpt.md b/docs/source/ko/model_doc/biogpt.md index 783f86389ebb..05dd169a1307 100644 --- a/docs/source/ko/model_doc/biogpt.md +++ b/docs/source/ko/model_doc/biogpt.md @@ -29,7 +29,7 @@ BioGPT는 Renqian Luo, Liai Sun, Yingce Xia, Tao Qin, Sheng Zhang, Hoifung Poon, ## 사용 팁 [[usage-tips]] - BioGPT는 절대적 위치 임베딩(absolute position embedding)을 사용하므로, 입력을 왼쪽이 아닌 오른쪽에서 패딩하는 것이 권장됩니다. -- BioGPT는 인과적 언어 모델링(Causal Langague Modeling, CLM) 목표로 학습되었기 때문에, 다음 토큰을 예측하는 데 강력한 성능을 보입니다. 이 기능을 활용하여 BioGPT는 구문적으로 일관된 텍스트를 생성할 수 있으며, 예시 스크립트 `run_generation.py`에서 이를 확인할 수 있습니다. +- BioGPT는 인과적 언어 모델링(Causal Langague Modeling, CLM) 목표로 학습되었기 때문에, 다음 토큰을 예측하는 데 강력한 성능을 보입니다. 이 기능을 활용하여 BioGPT는 구문적으로 일관된 텍스트를 생성할 수 있습니다. - 이 모델은 `past_key_values`(PyTorch 용)를 입력으로 받을 수 있는데, 이는 이전에 계산된 키/값 어텐션 쌍입니다. 이 값을 사용하면 텍스트 생성 중 이미 계산된 값을 다시 계산하지 않도록 할 수 있습니다. PyTorch에서 `past_key_values` 인수는 BioGptForCausalLM.forward() 메소드에서 자세히 설명되어 있습니다. ### Scaled Dot Product Attention(SDPA) 사용 [[using-scaled-dot-product-attention-sdpa]] diff --git a/docs/source/ko/model_doc/clip.md b/docs/source/ko/model_doc/clip.md index f2bb6bd57f96..dc9e7ce47168 100644 --- a/docs/source/ko/model_doc/clip.md +++ b/docs/source/ko/model_doc/clip.md @@ -177,7 +177,6 @@ CLIP을 시작하는 데 도움이 되는 Hugging Face와 community 자료 목 - [원격 센싱 (인공위성) 이미지와 캡션을 가지고 CLIP 미세조정하기](https://huggingface.co/blog/fine-tune-clip-rsicd): [RSICD dataset](https://github.com/201528014227051/RSICD_optimal)을 가지고 CLIP을 미세조정 하는 방법과 데이터 증강에 대한 성능 비교에 대한 블로그 포스트 -- 이 [예시 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/contrastive-image-text)는 [COCO dataset](https://cocodataset.org/#home)를 이용한 사전학습된 비전과 텍스트와 인코더를 사용해서 CLIP같은 비전-텍스트 듀얼 모델을 어떻게 학습시키는지 보여줍니다. diff --git a/docs/source/ko/model_doc/deberta.md b/docs/source/ko/model_doc/deberta.md index 5fcac9fee06d..99fd0ac12ba4 100644 --- a/docs/source/ko/model_doc/deberta.md +++ b/docs/source/ko/model_doc/deberta.md @@ -38,29 +38,29 @@ DeBERTa를 시작하는 데 도움이 되는 Hugging Face와 community 자료 - DeBERTa와 [DeepSpeed를 이용해서 대형 모델 학습을 가속시키는](https://huggingface.co/blog/accelerate-deepspeed) 방법에 대한 포스트. - DeBERTa와 [머신러닝으로 한층 향상된 고객 서비스](https://huggingface.co/blog/supercharge-customer-service-with-machine-learning)에 대한 블로그 포스트. -- [`DebertaForSequenceClassification`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)에서 지원됩니다. -- [`TFDebertaForSequenceClassification`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)에서 지원됩니다. +- [`DebertaForSequenceClassification`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)에서 지원됩니다. +- [`TFDebertaForSequenceClassification`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)에서 지원됩니다. - [텍스트 분류 작업 가이드](../tasks/sequence_classification) -- [`DebertaForTokenClassification`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)에서 지원합니다. -- [`TFDebertaForTokenClassification`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/token-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)에서 지원합니다. +- [`DebertaForTokenClassification`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)에서 지원합니다. +- [`TFDebertaForTokenClassification`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)에서 지원합니다. - 🤗 Hugging Face 코스의 [토큰 분류](https://huggingface.co/course/chapter7/2?fw=pt) 장. - 🤗 Hugging Face 코스의 [BPE(Byte-Pair Encoding) 토큰화](https://huggingface.co/course/chapter6/5?fw=pt) 장. - [토큰 분류 작업 가이드](../tasks/token_classification) -- [`DebertaForMaskedLM`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에서 지원합니다. -- [`TFDebertaForMaskedLM`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/language-modeling#run_mlmpy)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에서 지원합니다. +- [`DebertaForMaskedLM`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에서 지원합니다. +- [`TFDebertaForMaskedLM`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에서 지원합니다. - 🤗 Hugging Face 코스의 [마스크 언어 모델링](https://huggingface.co/course/chapter7/3?fw=pt) 장. - [마스크 언어 모델링 작업 가이드](../tasks/masked_language_modeling) -- [`DebertaForQuestionAnswering`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)에서 지원합니다. -- [`TFDebertaForQuestionAnswering`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/question-answering)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)에서 지원합니다. +- [`DebertaForQuestionAnswering`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)에서 지원합니다. +- [`TFDebertaForQuestionAnswering`]는 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)에서 지원합니다. - 🤗 Hugging Face 코스의 [질의응답(Question answering)](https://huggingface.co/course/chapter7/7?fw=pt) 장. - [질의응답 작업 가이드](../tasks/question_answering) diff --git a/docs/source/ko/model_doc/marian.md b/docs/source/ko/model_doc/marian.md index a0701b6cfcaa..8a89668989c8 100644 --- a/docs/source/ko/model_doc/marian.md +++ b/docs/source/ko/model_doc/marian.md @@ -57,7 +57,6 @@ BART와 동일한 모델을 사용하는 번역 모델 프레임워크입니다. ## 예시[[Examples]] - Marian 모델은 라이브러리의 다른 번역 모델들보다 크기가 작아 파인튜닝 실험과 통합 테스트에 유용합니다. -- [GPU에서 파인튜닝하기](https://github.com/huggingface/transformers/blob/master/examples/legacy/seq2seq/train_distil_marian_enro.sh) ## 다국어 모델 사용법[[Multilingual Models]] diff --git a/docs/source/ko/model_doc/openai-gpt.md b/docs/source/ko/model_doc/openai-gpt.md index 9452561ca60f..81dbfd9f7df8 100644 --- a/docs/source/ko/model_doc/openai-gpt.md +++ b/docs/source/ko/model_doc/openai-gpt.md @@ -40,7 +40,7 @@ OpenAI GPT 모델은 Alec Radford, Karthik Narasimhan, Tim Salimans, Ilya Sutske ## 사용 팁 [[usage-tips]] - GPT는 절대 위치 임베딩을 사용하는 모델이므로 입력을 일반적으로 왼쪽보다는 오른쪽에 패딩하는 것이 권장됩니다. -- GPT는 인과 언어 모델링(Causal Language Modeling, CLM) 목표로 학습되었기 때문에 시퀀스에서 다음 토큰을 예측하는 데 강력한 성능을 보여줍니다. 이를 활용하면 *run_generation.py* 예제 스크립트에서 볼 수 있듯이 GPT-2는 구문적으로 일관된 텍스트를 생성할 수 있습니다. +- GPT는 인과 언어 모델링(Causal Language Modeling, CLM) 목표로 학습되었기 때문에 시퀀스에서 다음 토큰을 예측하는 데 강력한 성능을 보여줍니다. 이를 활용하면 GPT-2는 구문적으로 일관된 텍스트를 생성할 수 있습니다. 참고: @@ -72,8 +72,8 @@ OpenAI GPT를 시작하는 데 도움이 되는 공식 Hugging Face 및 커뮤 - [좋아하는 아티스트의 스타일로 가사를 생성하도록 GPT2를 미세 조정하는 방법](https://colab.research.google.com/github/AlekseyKorshuk/huggingartists/blob/master/huggingartists-demo.ipynb)에 대한 노트북. 🌎 - [좋아하는 트위터 사용자의 스타일로 트윗을 생성하도록 GPT2를 미세 조정하는 방법](https://colab.research.google.com/github/borisdayma/huggingtweets/blob/master/huggingtweets-demo.ipynb)에 대한 노트북. 🌎 - 🤗 Hugging Face 코스의 [인과 언어 모델링](https://huggingface.co/course/en/chapter7/6?fw=pt#training-a-causal-language-model-from-scratch) 장. -- [`OpenAIGPTLMHeadModel`]은 [인과 언어 모델링 예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#gpt-2gpt-and-causal-language-modeling), [텍스트 생성 예제 스크립트](https://github.com/huggingface/transformers/blob/main/examples/pytorch/text-generation/run_generation.py) 및 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에 의해 지원됩니다. -- [`TFOpenAIGPTLMHeadModel`]은 [인과 언어 모델링 예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/language-modeling#run_clmpy) 및 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에 의해 지원됩니다. +- [`OpenAIGPTLMHeadModel`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에 의해 지원됩니다. +- [`TFOpenAIGPTLMHeadModel`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에 의해 지원됩니다. - 추가 자료: [인과 언어 모델링 과제 가이드](../tasks/language_modeling) diff --git a/docs/source/ko/model_doc/roberta.md b/docs/source/ko/model_doc/roberta.md index fe9ea309fc28..c4a4d5f2a3c3 100644 --- a/docs/source/ko/model_doc/roberta.md +++ b/docs/source/ko/model_doc/roberta.md @@ -59,40 +59,38 @@ RoBERTa를 처음 다룰 때 도움이 되는 Hugging Face 공식 자료와 커 - RoBERTa와 [Inference API](https://huggingface.co/inference-api)를 활용한 [트위터 감성 분석 시작하기](https://huggingface.co/blog/sentiment-analysis-twitter) 블로그 포스트. - RoBERTa를 활용한 [Kili 및 Hugging Face AutoTrain을 이용한 의견 분류](https://huggingface.co/blog/opinion-classification-with-kili)에 관한 블로그 포스트. - [감성 분석을 위한 RoBERTa 미세조정](https://colab.research.google.com/github/DhavalTaunk08/NLP_scripts/blob/master/sentiment_analysis_using_roberta.ipynb)을 하는 방법에 대한 노트북.🌎 -- ['RobertaForSequenceClassification']은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)에서 지원됩니다. -- [`TFRobertaForSequenceClassification`]는 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)에서 지원됩니다. -- [`FlaxRobertaForSequenceClassification`]는 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/text-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_flax.ipynb)에서 지원됩니다. +- ['RobertaForSequenceClassification']은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)에서 지원됩니다. +- [`TFRobertaForSequenceClassification`]는 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)에서 지원됩니다. +- [`FlaxRobertaForSequenceClassification`]는 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_flax.ipynb)에서 지원됩니다. - [텍스트 분류 작업 가이드](../tasks/sequence_classification) -- [`RobertaForTokenClassification`]은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)에서 지원됩니다. -- [`TFRobertaForTokenClassification`]은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/token-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)에서 지원됩니다. -- [`FlaxRobertaForTokenClassification`]는 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/token-classification)에서 지원됩니다. +- [`RobertaForTokenClassification`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)에서 지원됩니다. +- [`TFRobertaForTokenClassification`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)에서 지원됩니다. - 🤗 Hugging Face 코스의 [토큰 분류 챕터](https://huggingface.co/course/chapter7/2?fw=pt) - [토큰 분류 작업 가이드](../tasks/token_classification) - RoBERTa를 활용한 [Transformers와 Tokenizers를 활용한 새로운 언어 모델을 처음부터 학습하는 방법](https://huggingface.co/blog/how-to-train)에 대한 블로그 포스트. -- [`RobertaForMaskedLM`]은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling#robertabertdistilbert-and-masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에서 지원됩니다. -- [`TFRobertaForMaskedLM`]은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/language-modeling#run_mlmpy)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에서 지원됩니다. -- [`FlaxRobertaForMaskedLM`]은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/language-modeling#masked-language-modeling)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)에서 지원됩니다. +- [`RobertaForMaskedLM`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)에서 지원됩니다. +- [`TFRobertaForMaskedLM`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)에서 지원됩니다. +- [`FlaxRobertaForMaskedLM`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/masked_language_modeling_flax.ipynb)에서 지원됩니다. - 🤗 Hugging Face 코스의 [마스킹 언어 모델링 챕터](https://huggingface.co/course/chapter7/3?fw=pt) - [마스킹 언어 모델링 작업 가이드](../tasks/masked_language_modeling) - RoBERTa를 활용한 질문 응답 작업에서의 [Optimum과 Transformers 파이프라인을 이용한 추론 가속화](https://huggingface.co/blog/optimum-inference)에 대한 블로그 포스트. -- [`RobertaForQuestionAnswering`]은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)에서 지원됩니다. -- [`TFRobertaForQuestionAnswering`]은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/question-answering)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)에서 지원됩니다. -- [`FlaxRobertaForQuestionAnswering`]은 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/flax/question-answering)에서 지원됩니다. +- [`RobertaForQuestionAnswering`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)에서 지원됩니다. +- [`TFRobertaForQuestionAnswering`]은 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)에서 지원됩니다. - 🤗 Hugging Face 코스의 [질의응답 챕터](https://huggingface.co/course/chapter7/7?fw=pt) - [질의응답 작업 가이드](../tasks/question_answering) **다중 선택** -- [`RobertaForMultipleChoice`]는 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/multiple-choice)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)에서 지원됩니다. -- [`TFRobertaForMultipleChoice`]는 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/multiple-choice)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)에서 지원됩니다. +- [`RobertaForMultipleChoice`]는 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)에서 지원됩니다. +- [`TFRobertaForMultipleChoice`]는 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)에서 지원됩니다. - [다중 선택 작업 가이드](../tasks/multiple_choice) ## RobertaConfig diff --git a/docs/source/ko/model_doc/swin.md b/docs/source/ko/model_doc/swin.md index 6d90dc8226ae..72d330681bbe 100644 --- a/docs/source/ko/model_doc/swin.md +++ b/docs/source/ko/model_doc/swin.md @@ -42,13 +42,9 @@ Swin Transformer의 사용을 도울 수 있는 Hugging Face 및 커뮤니티( -- [`SwinForImageClassification`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)을 통해 지원됩니다. +- [`SwinForImageClassification`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)을 통해 지원됩니다. - 관련 자료: [이미지 분류 작업 가이드](../tasks/image_classification) -또한: - -- [`SwinForMaskedImageModeling`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining)를 통해 지원됩니다. - 새로운 자료를 추가하고 싶으시다면, 언제든지 Pull Request를 열어주세요! 저희가 검토해 드릴게요. 이때, 추가하는 자료는 기존 자료와 중복되지 않고 새로운 내용을 보여주는 자료여야 합니다. ## SwinConfig [[transformers.SwinConfig]] diff --git a/docs/source/ko/model_doc/swinv2.md b/docs/source/ko/model_doc/swinv2.md index 40b9268cb21e..446a6047ccf5 100644 --- a/docs/source/ko/model_doc/swinv2.md +++ b/docs/source/ko/model_doc/swinv2.md @@ -34,13 +34,9 @@ Swin Transformer v2의 사용을 도울 수 있는 Hugging Face 및 커뮤니티 -- [`Swinv2ForImageClassification`]은 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification)와 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)을 통해 지원됩니다. +- [`Swinv2ForImageClassification`]은 이 [노트북](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)을 통해 지원됩니다. - 관련 자료: [이미지 분류 작업 가이드](../tasks/image_classification) -또한: - -- [`Swinv2ForMaskedImageModeling`]는 이 [예제 스크립트](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining)를 통해 지원됩니다. - 새로운 자료를 추가하고 싶으시다면, 언제든지 Pull Request를 열어주세요! 저희가 검토해 드릴게요. 이때, 추가하는 자료는 기존 자료와 중복되지 않고 새로운 내용을 보여주는 자료여야 합니다. ## Swinv2Config [[transformers.Swinv2Config]] diff --git a/docs/source/ko/perf_hardware.md b/docs/source/ko/perf_hardware.md index 01282a0c7111..881f54327184 100644 --- a/docs/source/ko/perf_hardware.md +++ b/docs/source/ko/perf_hardware.md @@ -116,41 +116,3 @@ GPU1 PHB X 0-11 N/A 따라서 `nvidia-smi topo -m`의 결과에서 `NVX`의 값이 높을수록 더 좋습니다. 세대는 GPU 아키텍처에 따라 다를 수 있습니다. - -그렇다면, openai-community/gpt2를 작은 wikitext 샘플로 학습시키는 예제를 통해, NVLink가 훈련에 어떤 영향을 미치는지 살펴보겠습니다. - -결과는 다음과 같습니다: - - -| NVlink | Time | -| ----- | ---: | -| Y | 101s | -| N | 131s | - - -NVLink 사용 시 훈련이 약 23% 더 빠르게 완료됨을 확인할 수 있습니다. 두 번째 벤치마크에서는 `NCCL_P2P_DISABLE=1`을 사용하여 NVLink를 사용하지 않도록 설정했습니다. - -전체 벤치마크 코드와 결과는 다음과 같습니다: - -```bash -# DDP w/ NVLink - -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 torchrun \ ---nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \ ---dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train \ ---output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 101.9003, 'train_samples_per_second': 1.963, 'epoch': 0.69} - -# DDP w/o NVLink - -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 NCCL_P2P_DISABLE=1 torchrun \ ---nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \ ---dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train ---output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 131.4367, 'train_samples_per_second': 1.522, 'epoch': 0.69} -``` - -하드웨어: 각각 2개의 TITAN RTX 24GB + 2개의 NVLink (`NV2` in `nvidia-smi topo -m`) -소프트웨어: `pytorch-1.8-to-be` + `cuda-11.0` / `transformers==4.3.0.dev0` diff --git a/docs/source/ko/perf_train_cpu.md b/docs/source/ko/perf_train_cpu.md index 1a6c58b25afa..8eecd8186c4a 100644 --- a/docs/source/ko/perf_train_cpu.md +++ b/docs/source/ko/perf_train_cpu.md @@ -42,26 +42,6 @@ pip install intel_extension_for_pytorch== -f https://developer.int [IPEX 설치](https://intel.github.io/intel-extension-for-pytorch/cpu/latest/tutorials/installation.html)에 대한 더 많은 접근 방법을 확인하십시오. -### Trainer에서의 사용법 [[usage-in-trainer]] -Trainer에서 IPEX의 자동 혼합 정밀도를 활성화하려면 사용자는 훈련 명령 인수에 `use_ipex`, `bf16`, `no_cuda`를 추가해야 합니다. - -[Transformers 질문-응답](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering)의 사용 사례를 살펴보겠습니다. - -- CPU에서 BF16 자동 혼합 정밀도를 사용하여 IPEX로 훈련하기: -
 python run_qa.py \
---model_name_or_path google-bert/bert-base-uncased \
---dataset_name squad \
---do_train \
---do_eval \
---per_device_train_batch_size 12 \
---learning_rate 3e-5 \
---num_train_epochs 2 \
---max_seq_length 384 \
---doc_stride 128 \
---output_dir /tmp/debug_squad/ \
---use_ipex \
---bf16 --no_cuda
- ### 실습 예시 [[practice-example]] 블로그: [Intel Sapphire Rapids로 PyTorch Transformers 가속화](https://huggingface.co/blog/intel-sapphire-rapids) \ No newline at end of file diff --git a/docs/source/ko/perf_train_cpu_many.md b/docs/source/ko/perf_train_cpu_many.md index e7a68971a7dc..395185a6e24d 100644 --- a/docs/source/ko/perf_train_cpu_many.md +++ b/docs/source/ko/perf_train_cpu_many.md @@ -71,64 +71,3 @@ source $torch_ccl_path/env/setvars.sh #### IPEX 설치: [[ipex-installation]] IPEX는 Float32와 BFloat16을 모두 사용하는 CPU 훈련을 위한 성능 최적화를 제공합니다. [single CPU section](./perf_train_cpu)을 참조하세요. - - -이어서 나오는 "Trainer에서의 사용"은 Intel® MPI 라이브러리의 mpirun을 예로 들었습니다. - - -## Trainer에서의 사용 [[usage-in-trainer]] -Trainer에서 ccl 백엔드를 사용하여 멀티 CPU 분산 훈련을 활성화하려면 명령 인수에 **`--ddp_backend ccl`**을 추가해야 합니다. - -[질의 응답 예제](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering)를 사용한 예를 살펴보겠습니다. - - -다음 명령은 한 Xeon 노드에서 2개의 프로세스로 훈련을 활성화하며, 각 소켓당 하나의 프로세스가 실행됩니다. OMP_NUM_THREADS/CCL_WORKER_COUNT 변수는 최적의 성능을 위해 조정할 수 있습니다. -```shell script - export CCL_WORKER_COUNT=1 - export MASTER_ADDR=127.0.0.1 - mpirun -n 2 -genv OMP_NUM_THREADS=23 \ - python3 run_qa.py \ - --model_name_or_path google-bert/bert-large-uncased \ - --dataset_name squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ \ - --no_cuda \ - --ddp_backend ccl \ - --use_ipex -``` -다음 명령은 두 개의 Xeon(노드0 및 노드1, 주 프로세스로 노드0을 사용)에서 총 4개의 프로세스로 훈련을 활성화하며, 각 소켓당 하나의 프로세스가 실행됩니다. OMP_NUM_THREADS/CCL_WORKER_COUNT 변수는 최적의 성능을 위해 조정할 수 있습니다. - -노드0에서는 각 노드의 IP 주소를 포함하는 구성 파일(예: hostfile)을 생성하고 해당 구성 파일 경로를 인수로 전달해야 합니다. -```shell script - cat hostfile - xxx.xxx.xxx.xxx #node0 ip - xxx.xxx.xxx.xxx #node1 ip -``` -이제 노드0에서 다음 명령을 실행하면 **4DDP**가 노드0 및 노드1에서 BF16 자동 혼합 정밀도로 활성화됩니다. -```shell script - export CCL_WORKER_COUNT=1 - export MASTER_ADDR=xxx.xxx.xxx.xxx #node0 ip - mpirun -f hostfile -n 4 -ppn 2 \ - -genv OMP_NUM_THREADS=23 \ - python3 run_qa.py \ - --model_name_or_path google-bert/bert-large-uncased \ - --dataset_name squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ \ - --no_cuda \ - --ddp_backend ccl \ - --use_ipex \ - --bf16 -``` diff --git a/docs/source/ko/perf_train_gpu_many.md b/docs/source/ko/perf_train_gpu_many.md index 6f01eb22a344..6fe61a20bd4a 100644 --- a/docs/source/ko/perf_train_gpu_many.md +++ b/docs/source/ko/perf_train_gpu_many.md @@ -114,55 +114,8 @@ DP와 DDP 사이에는 다른 차이점이 있지만, 이 토론과는 관련이 이 2가지 모드를 깊게 이해하고 싶다면, [이 문서](https://www.telesens.co/2019/04/04/distributed-data-parallel-training-using-pytorch-on-aws/)를 강력히 추천합니다. 이 문서는 멋진 다이어그램을 포함하고 있으며, 다양한 하드웨어에서 여러 벤치마크와 프로파일러 출력을 설명하여 필요한 세부 사항을 모두 설명합니다. -실제 벤치마크를 살펴보겠습니다: - -| Type | NVlink | Time | -| :----- | ----- | ---: | -| 2:DP | Y | 110s | -| 2:DDP | Y | 101s | -| 2:DDP | N | 131s | - - -분석: - -여기서 DP는 NVlink가 있는 DDP보다 약 10% 느립니다. 그러나 NVlink가 없는 DDP보다 약 15% 빠릅니다. - 실제 차이는 각 GPU가 다른 GPU와 동기화해야 하는 데이터 양에 따라 달라질 것입니다. 동기화할 데이터가 많을수록 느린 링크가 총 실행 시간을 늦출 수 있습니다. -다음은 전체 벤치마크 코드와 출력입니다: - -해당 벤치마크에서 `NCCL_P2P_DISABLE=1`을 사용하여 NVLink 기능을 비활성화했습니다. - -```bash - -# DP -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 \ -python examples/pytorch/language-modeling/run_clm.py \ ---model_name_or_path openai-community/gpt2 --dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 \ ---do_train --output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 110.5948, 'train_samples_per_second': 1.808, 'epoch': 0.69} - -# DDP w/ NVlink -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 \ -torchrun --nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py \ ---model_name_or_path openai-community/gpt2 --dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 \ ---do_train --output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 101.9003, 'train_samples_per_second': 1.963, 'epoch': 0.69} - -# DDP w/o NVlink -rm -r /tmp/test-clm; NCCL_P2P_DISABLE=1 CUDA_VISIBLE_DEVICES=0,1 \ -torchrun --nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py \ ---model_name_or_path openai-community/gpt2 --dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 \ ---do_train --output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 131.4367, 'train_samples_per_second': 1.522, 'epoch': 0.69} -``` - -하드웨어: 각각 24GB의 TITAN RTX 2개 + NVlink과 2개의 NVLink (`nvidia-smi topo -m`에서 `NV2`입니다.) -소프트웨어: `pytorch-1.8-to-be` + `cuda-11.0` / `transformers==4.3.0.dev0` - ## ZeRO 데이터 병렬화 [[zero-data-parallelism]] ZeRO를 기반으로 한 데이터 병렬화 (ZeRO-DP)는 다음 [블로그 글](https://www.microsoft.com/en-us/research/blog/zero-deepspeed-new-system-optimizations-enable-training-models-with-over-100-billion-parameters/)의 다음 다이어그램에서 설명되고 있습니다. diff --git a/docs/source/ko/perf_train_special.md b/docs/source/ko/perf_train_special.md index 7927f3748f07..41d34c0afc29 100644 --- a/docs/source/ko/perf_train_special.md +++ b/docs/source/ko/perf_train_special.md @@ -39,23 +39,7 @@ Pytorch가 설치되어 있는지 확인하고 시작하세요. MPS 가속은 ma pip install torch torchvision torchaudio ``` -[`TrainingArguments`]는 `mps` 장치가 사용 가능한 경우 이를 기본적으로 사용하므로 장치를 따로 설정할 필요가 없습니다. 예를 들어, MPS 백엔드를 자동으로 활성화하여 [run_glue.py](https://github.com/huggingface/transformers/blob/main/examples/pytorch/text-classification/run_glue.py) 스크립트를 아무 수정 없이 실행할 수 있습니다. - -```diff -export TASK_NAME=mrpc - -python examples/pytorch/text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ -- --use_mps_device \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ -``` +[`TrainingArguments`]는 `mps` 장치가 사용 가능한 경우 이를 기본적으로 사용하므로 장치를 따로 설정할 필요가 없습니다. `gloco`와 `nccl`과 같은 [분산 학습 백엔드](https://pytorch.org/docs/stable/distributed.html#backends)는 `mps` 장치에서 지원되지 않으므로, MPS 백엔드에서는 단일 GPU로만 학습이 가능합니다. diff --git a/docs/source/ko/run_scripts.md b/docs/source/ko/run_scripts.md deleted file mode 100644 index 2db8fe16c600..000000000000 --- a/docs/source/ko/run_scripts.md +++ /dev/null @@ -1,304 +0,0 @@ - - -# 스크립트로 실행하기[[train-with-a-script]] - -🤗 Transformers 노트북과 함께 [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch), [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow), 또는 [JAX/Flax](https://github.com/huggingface/transformers/tree/main/examples/flax)를 사용해 특정 태스크에 대한 모델을 훈련하는 방법을 보여주는 예제 스크립트도 있습니다. - -또한 [연구 프로젝트](https://github.com/huggingface/transformers-research-projects/) 및 [레거시 예제](https://github.com/huggingface/transformers/tree/main/examples/legacy)에서 대부분 커뮤니티에서 제공한 스크립트를 찾을 수 있습니다. -이러한 스크립트는 적극적으로 유지 관리되지 않으며 최신 버전의 라이브러리와 호환되지 않을 가능성이 높은 특정 버전의 🤗 Transformers를 필요로 합니다. - -예제 스크립트가 모든 문제에서 바로 작동하는 것은 아니며, 해결하려는 문제에 맞게 스크립트를 변경해야 할 수도 있습니다. -이를 위해 대부분의 스크립트에는 데이터 전처리 방법이 나와있어 필요에 따라 수정할 수 있습니다. - -예제 스크립트에 구현하고 싶은 기능이 있으면 pull request를 제출하기 전에 [포럼](https://discuss.huggingface.co/) 또는 [이슈](https://github.com/huggingface/transformers/issues)에서 논의해 주세요. -버그 수정은 환영하지만 가독성을 희생하면서까지 더 많은 기능을 추가하는 pull request는 병합(merge)하지 않을 가능성이 높습니다. - -이 가이드에서는 [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) 및 [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization)에서 요약 훈련하는 - 스크립트 예제를 실행하는 방법을 설명합니다. -특별한 설명이 없는 한 모든 예제는 두 프레임워크 모두에서 작동할 것으로 예상됩니다. - -## 설정하기[[setup]] - -최신 버전의 예제 스크립트를 성공적으로 실행하려면 새 가상 환경에서 **소스로부터 🤗 Transformers를 설치**해야 합니다: - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -이전 버전의 예제 스크립트를 보려면 아래 토글을 클릭하세요: - -
- 이전 버전의 🤗 Transformers 예제 - -
- -그리고 다음과 같이 복제(clone)해온 🤗 Transformers 버전을 특정 버전(예: v3.5.1)으로 전환하세요: - -```bash -git checkout tags/v3.5.1 -``` - -올바른 라이브러리 버전을 설정한 후 원하는 예제 폴더로 이동하여 예제별로 라이브러리에 대한 요구 사항(requirements)을 설치합니다: - -```bash -pip install -r requirements.txt -``` - -## 스크립트 실행하기[[run-a-script]] - -예제 스크립트는 🤗 [Datasets](https://huggingface.co/docs/datasets/) 라이브러리에서 데이터 세트를 다운로드하고 전처리합니다. -그런 다음 스크립트는 요약 기능을 지원하는 아키텍처에서 [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer)를 사용하여 데이터 세트를 미세 조정합니다. -다음 예는 [CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail) 데이터 세트에서 [T5-small](https://huggingface.co/google-t5/t5-small)을 미세 조정합니다. -T5 모델은 훈련 방식에 따라 추가 `source_prefix` 인수가 필요하며, 이 프롬프트는 요약 작업임을 T5에 알려줍니다. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## 혼합 정밀도(mixed precision)로 분산 훈련하기[[distributed-training-and-mixed-precision]] - -[Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) 클래스는 분산 훈련과 혼합 정밀도(mixed precision)를 지원하므로 스크립트에서도 사용할 수 있습니다. -이 두 가지 기능을 모두 활성화하려면 다음 두 가지를 설정해야 합니다: - -- `fp16` 인수를 추가해 혼합 정밀도(mixed precision)를 활성화합니다. -- `nproc_per_node` 인수를 추가해 사용할 GPU 개수를 설정합니다. - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -TensorFlow 스크립트는 분산 훈련을 위해 [`MirroredStrategy`](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy)를 활용하며, 훈련 스크립트에 인수를 추가할 필요가 없습니다. -다중 GPU 환경이라면, TensorFlow 스크립트는 기본적으로 여러 개의 GPU를 사용합니다. - -## TPU 위에서 스크립트 실행하기[[run-a-script-on-a-tpu]] - -Tensor Processing Units (TPUs)는 성능을 가속화하기 위해 특별히 설계되었습니다. -PyTorch는 [XLA](https://www.tensorflow.org/xla) 딥러닝 컴파일러와 함께 TPU를 지원합니다(자세한 내용은 [여기](https://github.com/pytorch/xla/blob/master/README.md) 참조). -TPU를 사용하려면 `xla_spawn.py` 스크립트를 실행하고 `num_cores` 인수를 사용하여 사용하려는 TPU 코어 수를 설정합니다. - -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## 🤗 Accelerate로 스크립트 실행하기[[run-a-script-with-accelerate]] - -🤗 [Accelerate](https://huggingface.co/docs/accelerate)는 PyTorch 훈련 과정에 대한 완전한 가시성을 유지하면서 여러 유형의 설정(CPU 전용, 다중 GPU, TPU)에서 모델을 훈련할 수 있는 통합 방법을 제공하는 PyTorch 전용 라이브러리입니다. -🤗 Accelerate가 설치되어 있는지 확인하세요: - -> 참고: Accelerate는 빠르게 개발 중이므로 스크립트를 실행하려면 accelerate를 설치해야 합니다. -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -`run_summarization.py` 스크립트 대신 `run_summarization_no_trainer.py` 스크립트를 사용해야 합니다. -🤗 Accelerate 클래스가 지원되는 스크립트는 폴더에 `task_no_trainer.py` 파일이 있습니다. -다음 명령을 실행하여 구성 파일을 생성하고 저장합니다: -```bash -accelerate config -``` - -설정을 테스트하여 올바르게 구성되었는지 확인합니다: - -```bash -accelerate test -``` - -이제 훈련을 시작할 준비가 되었습니다: - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## 사용자 정의 데이터 세트 사용하기[[use-a-custom-dataset]] - -요약 스크립트는 사용자 지정 데이터 세트가 CSV 또는 JSON 파일인 경우 지원합니다. -사용자 지정 데이터 세트를 사용하는 경우에는 몇 가지 추가 인수를 지정해야 합니다: - -- `train_file`과 `validation_file`은 훈련 및 검증 파일의 경로를 지정합니다. -- `text_column`은 요약할 입력 텍스트입니다. -- `summary_column`은 출력할 대상 텍스트입니다. - -사용자 지정 데이터 세트를 사용하는 요약 스크립트는 다음과 같습니다: - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## 스크립트 테스트하기[[test-a-script]] - -전체 데이터 세트를 대상으로 훈련을 완료하는데 꽤 오랜 시간이 걸리기 때문에, 작은 데이터 세트에서 모든 것이 예상대로 실행되는지 확인하는 것이 좋습니다. - -다음 인수를 사용하여 데이터 세트를 최대 샘플 수로 잘라냅니다: -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -모든 예제 스크립트가 `max_predict_samples` 인수를 지원하지는 않습니다. -스크립트가 이 인수를 지원하는지 확실하지 않은 경우 `-h` 인수를 추가하여 확인하세요: - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## 체크포인트(checkpoint)에서 훈련 이어서 하기[[resume-training-from-checkpoint]] - -또 다른 유용한 옵션은 이전 체크포인트에서 훈련을 재개하는 것입니다. -이렇게 하면 훈련이 중단되더라도 처음부터 다시 시작하지 않고 중단한 부분부터 다시 시작할 수 있습니다. -체크포인트에서 훈련을 재개하는 방법에는 두 가지가 있습니다. - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## 모델 공유하기[[share-your-model]] - -모든 스크립트는 최종 모델을 [Model Hub](https://huggingface.co/models)에 업로드할 수 있습니다. -시작하기 전에 Hugging Face에 로그인했는지 확인하세요: -```bash -hf auth login -``` - -그런 다음 스크립트에 `push_to_hub` 인수를 추가합니다. -이 인수는 Hugging Face 사용자 이름과 `output_dir`에 지정된 폴더 이름으로 저장소를 생성합니다. - -저장소에 특정 이름을 지정하려면 `push_to_hub_model_id` 인수를 사용하여 추가합니다. -저장소는 네임스페이스 아래에 자동으로 나열됩니다. -다음 예는 특정 저장소 이름으로 모델을 업로드하는 방법입니다: - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` diff --git a/docs/source/ko/testing.md b/docs/source/ko/testing.md index e1027c764dbb..7eff6d74ec7d 100644 --- a/docs/source/ko/testing.md +++ b/docs/source/ko/testing.md @@ -47,7 +47,6 @@ rendered properly in your Markdown viewer. ```bash RUN_SLOW=1 pytest tests/ -RUN_SLOW=1 pytest examples/ ``` 결과는 [여기](https://github.com/huggingface/transformers/actions)에서 확인할 수 있습니다. @@ -513,7 +512,7 @@ n_gpu = get_gpu_count() #torch와 tf와 함께 작동 다음은 사용 가능한 테스트입니다: - [test_trainer_distributed.py](https://github.com/huggingface/transformers/tree/main/tests/trainer/distributed/test_trainer_distributed.py) -- [test_deepspeed.py](https://github.com/huggingface/transformers/tree/main/tests/deepspeed/test_deepspeed.py) +- [test_trainer_distributed_deepspeed.py](https://github.com/huggingface/transformers/tree/main/tests/trainer/distributed/test_trainer_distributed_deepspeed.py) 실행 지점으로 바로 이동하려면, 해당 테스트에서 `execute_subprocess_async` 호출을 검색하세요. @@ -719,7 +718,7 @@ from transformers.testing_utils import TestCasePlus class PathExampleTest(TestCasePlus): def test_something_involving_local_locations(self): - data_dir = self.tests_dir / "fixtures/tests_samples/wmt_en_ro" + data_dir = self.tests_dir / "fixtures/tests_samples/wmt16" ``` 만약 `pathlib`를 통해 경로를 조작할 필요가 없거나 경로를 문자열로만 필요로 하는 경우에는 `pathlib` 객체에 `str()`을 호출하거나 `_str`로 끝나는 접근자를 사용할 수 있습니다. diff --git a/docs/source/ko/trainer.md b/docs/source/ko/trainer.md index 65c3fbef982f..bee24be84175 100644 --- a/docs/source/ko/trainer.md +++ b/docs/source/ko/trainer.md @@ -491,42 +491,4 @@ use_cpu: false [`accelerate_launch`](https://huggingface.co/docs/accelerate/package_reference/cli#accelerate-launch) 명령은 Accelerate와 [`Trainer`]를 사용하여 분산 시스템에서 훈련 스크립트를 실행하는 권장 방법이며, `config_file.yaml`에 지정된 매개변수를 사용합니다. 이 파일은 Accelerate 캐시 폴더에 저장되며 `accelerate_launch`를 실행할 때 자동으로 로드됩니다. -예를 들어, FSDP 구성을 사용하여 [run_glue.py](https://github.com/huggingface/transformers/blob/f4db565b695582891e43a5e042e5d318e28f20b8/examples/pytorch/text-classification/run_glue.py#L4) 훈련 스크립트를 실행하려면 다음과 같이 합니다: - -```bash -accelerate launch \ - ./examples/pytorch/text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 16 \ - --learning_rate 5e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` - -`config_file.yaml` 파일의 매개변수를 직접 지정할 수도 있습니다: - -```bash -accelerate launch --num_processes=2 \ - --use_fsdp \ - --mixed_precision=bf16 \ - --fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \ - --fsdp_transformer_layer_cls_to_wrap="BertLayer" \ - --fsdp_sharding_strategy=1 \ - --fsdp_state_dict_type=FULL_STATE_DICT \ - ./examples/pytorch/text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 16 \ - --learning_rate 5e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` - `accelerate_launch`와 사용자 정의 구성에 대해 더 알아보려면 [Accelerate 스크립트 실행](https://huggingface.co/docs/accelerate/basic_tutorials/launch) 튜토리얼을 확인하세요. \ No newline at end of file diff --git a/docs/source/ko/training.md b/docs/source/ko/training.md index 6fb38e378ec7..c0876ee055b6 100644 --- a/docs/source/ko/training.md +++ b/docs/source/ko/training.md @@ -306,6 +306,4 @@ torch.cuda.empty_cache() 더 많은 미세 튜닝 예제는 다음을 참조하세요: -- [🤗 Trnasformers 예제](https://github.com/huggingface/transformers/tree/main/examples)에는 PyTorch 및 텐서플로우에서 일반적인 NLP 작업을 훈련할 수 있는 스크립트가 포함되어 있습니다. - - [🤗 Transformers 노트북](notebooks)에는 PyTorch 및 텐서플로우에서 특정 작업을 위해 모델을 미세 튜닝하는 방법에 대한 다양한 노트북이 포함되어 있습니다. diff --git a/docs/source/pt/_toctree.yml b/docs/source/pt/_toctree.yml index 04a636414204..11da350b7247 100644 --- a/docs/source/pt/_toctree.yml +++ b/docs/source/pt/_toctree.yml @@ -21,8 +21,6 @@ title: Criando uma arquitetura customizada - local: custom_models title: Compartilhando modelos customizados - - local: run_scripts - title: Treinamento a partir de um script - sections: - local: tasks/sequence_classification title: Classificação de texto diff --git a/docs/source/pt/installation.md b/docs/source/pt/installation.md index c1240758de36..804313ae1d84 100644 --- a/docs/source/pt/installation.md +++ b/docs/source/pt/installation.md @@ -160,21 +160,6 @@ Você pode adicionar o [🤗 Datasets](https://huggingface.co/docs/datasets/) ao -Segue um exemplo de execução do programa numa rede padrão com firewall para instâncias externas, usando o seguinte comando: - -```bash -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -Execute esse mesmo programa numa instância offline com o seguinte comando: - -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -O script agora deve ser executado sem travar ou expirar, pois procurará apenas por arquivos locais. - ### Obtendo modelos e tokenizers para uso offline Outra opção para usar o 🤗 Transformers offline é baixar os arquivos antes e depois apontar para o caminho local onde estão localizados. Existem três maneiras de fazer isso: diff --git a/docs/source/pt/multilingual.md b/docs/source/pt/multilingual.md index 5515c6a922a7..db1b15adb624 100644 --- a/docs/source/pt/multilingual.md +++ b/docs/source/pt/multilingual.md @@ -86,8 +86,6 @@ Agora você pode passar os `input_ids` e a language embedding ao modelo: >>> outputs = model(input_ids, langs=langs) ``` -O script [run_generation.py](https://github.com/huggingface/transformers/tree/master/examples/pytorch/text-generation/run_generation.py) pode gerar um texto com language embeddings utilizando os checkpoints `xlm-clm`. - ### XLM sem language embeddings Os seguintes modelos XLM não requerem o uso de language embeddings durante a inferência: diff --git a/docs/source/pt/run_scripts.md b/docs/source/pt/run_scripts.md deleted file mode 100644 index 72060f98571d..000000000000 --- a/docs/source/pt/run_scripts.md +++ /dev/null @@ -1,286 +0,0 @@ - - -# Treinamento a partir de um script - -Junto com os 🤗 Transformers [notebooks](./notebooks), também há scripts de exemplo demonstrando como treinar um modelo para uma tarefa com [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch), [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow) ou [JAX/Flax](https://github.com/huggingface/transformers/tree/main/examples/flax). - -Você também encontrará scripts que usamos em nossos [projetos de pesquisa](https://github.com/huggingface/transformers-research-projects/) e [exemplos legados](https://github.com/huggingface/transformers/tree/main/examples/legacy) que são principalmente contribuições da comunidade. Esses scripts não são mantidos ativamente e exigem uma versão específica de 🤗 Transformers que provavelmente será incompatível com a versão mais recente da biblioteca. - -Não se espera que os scripts de exemplo funcionem imediatamente em todos os problemas, você pode precisar adaptar o script ao problema que está tentando resolver. Para ajudá-lo com isso, a maioria dos scripts expõe totalmente como os dados são pré-processados, permitindo que você os edite conforme necessário para seu caso de uso. - -Para qualquer recurso que você gostaria de implementar em um script de exemplo, discuta-o no [fórum](https://discuss.huggingface.co/) ou em uma [issue](https://github.com/huggingface/transformers/issues) antes de enviar um Pull Request. Embora recebamos correções de bugs, é improvável que mesclaremos um Pull Request que adicione mais funcionalidades ao custo de legibilidade. - -Este guia mostrará como executar um exemplo de script de treinamento de sumarização em [PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) e [TensorFlow](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/summarization). Espera-se que todos os exemplos funcionem com ambas as estruturas, a menos que especificado de outra forma. - -## Configuração - -Para executar com êxito a versão mais recente dos scripts de exemplo, você precisa **instalar o 🤗 Transformers da fonte** em um novo ambiente virtual: - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -Para versões mais antigas dos scripts de exemplo, clique no botão abaixo: - -
- Exemplos para versões antigas dos 🤗 Transformers - -
- -Em seguida, mude seu clone atual dos 🤗 Transformers para uma versão específica, como v3.5.1, por exemplo: - -```bash -git checkout tags/v3.5.1 -``` - -Depois de configurar a versão correta da biblioteca, navegue até a pasta de exemplo de sua escolha e instale os requisitos específicos do exemplo: - -```bash -pip install -r requirements.txt -``` - -## Executando um script - - -O script de exemplo baixa e pré-processa um conjunto de dados da biblioteca 🤗 [Datasets](https://huggingface.co/docs/datasets/). Em seguida, o script ajusta um conjunto de dados com o [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) em uma arquitetura que oferece suporte à sumarização. O exemplo a seguir mostra como ajustar [T5-small](https://huggingface.co/google-t5/t5-small) no conjunto de dados [CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail). O modelo T5 requer um argumento `source_prefix` adicional devido à forma como foi treinado. Este prompt informa ao T5 que esta é uma tarefa de sumarização. - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Treinamento distribuído e precisão mista - -O [Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) oferece suporte a treinamento distribuído e precisão mista, o que significa que você também pode usá-lo em um script. Para habilitar esses dois recursos: - -- Adicione o argumento `fp16` para habilitar a precisão mista. -- Defina o número de GPUs a serem usadas com o argumento `nproc_per_node`. - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Os scripts do TensorFlow utilizam um [`MirroredStrategy`](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy) para treinamento distribuído, e você não precisa adicionar argumentos adicionais ao script de treinamento. O script do TensorFlow usará várias GPUs por padrão, se estiverem disponíveis. - -## Executando um script em uma TPU - -As Unidades de Processamento de Tensor (TPUs) são projetadas especificamente para acelerar o desempenho. O PyTorch oferece suporte a TPUs com o compilador de aprendizado profundo [XLA](https://www.tensorflow.org/xla) (consulte [aqui](https://github.com/pytorch/xla/blob/master/README.md) para mais detalhes). Para usar uma TPU, inicie o script `xla_spawn.py` e use o argumento `num_cores` para definir o número de núcleos de TPU que você deseja usar. - -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Execute um script com 🤗 Accelerate - -🤗 [Accelerate](https://huggingface.co/docs/accelerate) é uma biblioteca somente do PyTorch que oferece um método unificado para treinar um modelo em vários tipos de configurações (CPU, multiplas GPUs, TPUs), mantendo visibilidade no loop de treinamento do PyTorch. Certifique-se de ter o 🤗 Accelerate instalado se ainda não o tiver: - -> Nota: Como o Accelerate está se desenvolvendo rapidamente, a versão git do Accelerate deve ser instalada para executar os scripts - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -Em vez do script `run_summarization.py`, você precisa usar o script `run_summarization_no_trainer.py`. Os scripts suportados pelo 🤗 Accelerate terão um arquivo `task_no_trainer.py` na pasta. Comece executando o seguinte comando para criar e salvar um arquivo de configuração: - -```bash -accelerate config -``` - -Teste sua configuração para garantir que ela esteja corretamente configurada : - -```bash -accelerate test -``` - -Agora você está pronto para iniciar o treinamento: - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## Usando um conjunto de dados personalizado - -O script de resumo oferece suporte a conjuntos de dados personalizados, desde que sejam um arquivo CSV ou JSON. Ao usar seu próprio conjunto de dados, você precisa especificar vários argumentos adicionais: - -- `train_file` e `validation_file` especificam o caminho para seus arquivos de treinamento e validação respectivamente. -- `text_column` é o texto de entrada para sumarização. -- `summary_column` é o texto de destino para saída. - -Um script para sumarização usando um conjunto de dados customizado ficaria assim: - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## Testando um script - -Geralmente, é uma boa ideia executar seu script em um número menor de exemplos de conjuntos de dados para garantir que tudo funcione conforme o esperado antes de se comprometer com um conjunto de dados inteiro, que pode levar horas para ser concluído. Use os seguintes argumentos para truncar o conjunto de dados para um número máximo de amostras: - -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Nem todos os scripts de exemplo suportam o argumento `max_predict_samples`. Se você não tiver certeza se seu script suporta este argumento, adicione o argumento `-h` para verificar: - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## Retomar o treinamento a partir de um checkpoint - -Outra opção útil para habilitar é retomar o treinamento de um checkpoint anterior. Isso garantirá que você possa continuar de onde parou sem recomeçar se o seu treinamento for interrompido. Existem dois métodos para retomar o treinamento a partir de um checkpoint. - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## Compartilhando seu modelo - -Todos os scripts podem enviar seu modelo final para o [Model Hub](https://huggingface.co/models). Certifique-se de estar conectado ao Hugging Face antes de começar: - -```bash -hf auth login -``` - -Em seguida, adicione o argumento `push_to_hub` ao script. Este argumento criará um repositório com seu nome de usuário do Hugging Face e o nome da pasta especificado em `output_dir`. - -Para dar um nome específico ao seu repositório, use o argumento `push_to_hub_model_id` para adicioná-lo. O repositório será listado automaticamente em seu namespace. - -O exemplo a seguir mostra como fazer upload de um modelo com um nome de repositório específico: - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` diff --git a/docs/source/pt/training.md b/docs/source/pt/training.md index 84372ce879fa..0ddb98ec443b 100644 --- a/docs/source/pt/training.md +++ b/docs/source/pt/training.md @@ -409,8 +409,5 @@ e calcular a métrica apenas no final. Para mais exemplos de fine-tuning acesse: -- [🤗 Transformers Examples](https://github.com/huggingface/transformers/tree/main/examples) inclui scripts -para treinas tarefas comuns de NLP em PyTorch e TensorFlow. - - [🤗 Transformers Notebooks](notebooks) contém vários notebooks sobre como aplicar o fine-tuning a um modelo para tarefas específicas no PyTorch e TensorFlow. diff --git a/docs/source/ro/contributing.md b/docs/source/ro/contributing.md index eb4cde3867b8..9e267087834e 100644 --- a/docs/source/ro/contributing.md +++ b/docs/source/ro/contributing.md @@ -490,9 +490,8 @@ Pentru mai multe informații despre verificările rulate pe un pull request, aru ### Teste -O suită extinsă de teste este inclusă pentru a testa comportamentul bibliotecii și mai multe exemple. Testele de bibliotecă se găsesc în -folder-ul [tests](https://github.com/huggingface/transformers/tree/main/tests) și testele de exemple în -folder-ul [examples](https://github.com/huggingface/transformers/tree/main/examples). +O suită extinsă de teste este inclusă pentru a testa comportamentul bibliotecii. Testele de bibliotecă se găsesc în +folder-ul [tests](https://github.com/huggingface/transformers/tree/main/tests). Preferăm `pytest` și `pytest-xdist` deoarece este mai rapid. Din root-ul repository-ului, specifică un *path către un subfolder sau un fișier de test* pentru a rula testul: @@ -501,14 +500,7 @@ repository-ului, specifică un *path către un subfolder sau un fișier de test* python -m pytest -n auto --dist=loadfile -s -v ./tests/models/my_new_model ``` -Similar, pentru directorul `examples`, specifică o *cale către un subfolder sau fișier de test* pentru a rula testul. De exemplu, următoarea comandă testează subfolderul de clasificare text din directorul PyTorch `examples`: - -```bash -pip install -r examples/xxx/requirements.txt # necesar doar prima dată -python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classification -``` - -De fapt, acesta este modul în care comenzile noastre `make test` și `make test-examples` sunt implementate (fără a include `pip install`)! +De fapt, acesta este modul în care comanda noastră `make test` este implementată! Poți, de asemenea, să specifici un set mai mic de teste pentru a testa doar funcția la care lucrezi. @@ -518,13 +510,12 @@ ai suficient spațiu pe disc, o conexiune bună la internet sau multă răbdare! -Ține minte să specifici un *path către un subfolder sau un fișier de test* pentru a rula testul. Altfel, vei rula toate testele din folderul `tests` sau `examples`, ceea ce va dura foarte mult timp! +Ține minte să specifici un *path către un subfolder sau un fișier de test* pentru a rula testul. Altfel, vei rula toate testele din folderul `tests`, ceea ce va dura foarte mult timp! ```bash RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./tests/models/my_new_model -RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classification ``` Ca și testele lente, există și alte variabile de mediu disponibile care nu sunt activate implicit în timpul testării: @@ -541,7 +532,6 @@ Aceasta înseamnă că `unittest` este suportat în totalitate. Iată cum să ru ```bash python -m unittest discover -s tests -t . -v -python -m unittest discover -s examples -t examples -v ``` ### Ghid de stil diff --git a/docs/source/ro/installation.md b/docs/source/ro/installation.md index 47a4244d2014..ceb81fc4e2a7 100644 --- a/docs/source/ro/installation.md +++ b/docs/source/ro/installation.md @@ -150,11 +150,6 @@ snapshot_download(repo_id="meta-llama/Llama-2-7b-hf", repo_type="model") Setează variabila de mediu `HF_HUB_OFFLINE=1` pentru a preveni HTTP calls către Hub la descărcarea unui model. -```bash -HF_HUB_OFFLINE=1 \ -python examples/pytorch/language-modeling/run_clm.py --model_name_or_path meta-llama/Llama-2-7b-hf --dataset_name wikitext ... -``` - O altă opțiune pentru încărcarea exclusivă a fișierelor salvate în cache este setarea `local_files_only=True` în [`~PreTrainedModel.from_pretrained`]. ```py diff --git a/docs/source/tr/installation.md b/docs/source/tr/installation.md index 58532062d83a..024eeb3006c9 100644 --- a/docs/source/tr/installation.md +++ b/docs/source/tr/installation.md @@ -150,11 +150,6 @@ snapshot_download(repo_id="meta-llama/Llama-2-7b-hf", repo_type="model") Bir model yüklerken Hub'a HTTP çağrılarını engellemek için `HF_HUB_OFFLINE=1` ortam değişkenini ayarla. -```bash -HF_HUB_OFFLINE=1 \ -python examples/pytorch/language-modeling/run_clm.py --model_name_or_path meta-llama/Llama-2-7b-hf --dataset_name wikitext ... -``` - Yalnızca önbelleğe alınmış dosyaları yüklemek için başka bir seçenek de [`~PreTrainedModel.from_pretrained`] içinde `local_files_only=True` ayarlamaktır. ```py diff --git a/docs/source/zh/_toctree.yml b/docs/source/zh/_toctree.yml index feb0177792b1..5b7221f5dec9 100644 --- a/docs/source/zh/_toctree.yml +++ b/docs/source/zh/_toctree.yml @@ -15,8 +15,6 @@ title: 预处理数据 - local: training title: 微调预训练模型 - - local: run_scripts - title: 通过脚本训练模型 - local: accelerate title: 使用🤗Accelerate进行分布式训练 - local: peft diff --git a/docs/source/zh/contributing.md b/docs/source/zh/contributing.md index e10a52641d20..2d08104d6bbe 100644 --- a/docs/source/zh/contributing.md +++ b/docs/source/zh/contributing.md @@ -234,7 +234,7 @@ python src/transformers/commands/transformers_cli.py env ### 测试 -包含了广泛的测试套件来测试库的行为和一些示例。库测试可以在 [tests](https://github.com/huggingface/transformers/tree/main/tests) 文件夹中找到,示例测试可以在 [examples](https://github.com/huggingface/transformers/tree/main/examples) 文件夹中找到。 +包含了广泛的测试套件来测试库的行为。库测试可以在 [tests](https://github.com/huggingface/transformers/tree/main/tests) 文件夹中找到。 我们喜欢使用 `pytest` 和 `pytest-xdist`,因为它运行更快。在仓库的根目录,指定一个*子文件夹的路径或测试文件*来运行测试: @@ -242,14 +242,7 @@ python src/transformers/commands/transformers_cli.py env python -m pytest -n auto --dist=loadfile -s -v ./tests/models/my_new_model ``` -同样地,在 `examples` 目录,指定一个*子文件夹的路径或测试文件* 来运行测试。例如,以下命令会测试 PyTorch `examples` 目录中的文本分类子文件夹: - -```bash -pip install -r examples/xxx/requirements.txt # 仅在第一次需要 -python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classification -``` - -实际上这就是我们的 `make test` 和 `make test-examples` 命令的实现方式(不包括 `pip install`)! +实际上这就是我们的 `make test` 命令的实现方式! 你也可以指定一个较小的测试集来仅测试特定功能。 @@ -257,13 +250,12 @@ python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classific -记得指定一个*子文件夹的路径或测试文件*来运行测试。否则你将会运行 `tests` 或 `examples` 文件夹中的所有测试,它会花费很长时间! +记得指定一个*子文件夹的路径或测试文件*来运行测试。否则你将会运行 `tests` 文件夹中的所有测试,它会花费很长时间! ```bash RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./tests/models/my_new_model -RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/text-classification ``` 和时间较长的测试一样,还有其他环境变量在测试过程中,在默认情况下是未启用的: @@ -277,7 +269,6 @@ RUN_SLOW=yes python -m pytest -n auto --dist=loadfile -s -v ./examples/pytorch/t ```bash python -m unittest discover -s tests -t . -v -python -m unittest discover -s examples -t examples -v ``` ### 风格指南 diff --git a/docs/source/zh/installation.md b/docs/source/zh/installation.md index 21d026f0368d..4fa00bc8ddaf 100644 --- a/docs/source/zh/installation.md +++ b/docs/source/zh/installation.md @@ -145,21 +145,6 @@ conda install conda-forge::transformers -例如,你通常会使用以下命令对外部实例进行防火墙保护的的普通网络上运行程序: - -```bash -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -在离线环境中运行相同的程序: - -```bash -HF_DATASETS_OFFLINE=1 HF_HUB_OFFLINE=1 \ -python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... -``` - -现在脚本可以应该正常运行,而无需挂起或等待超时,因为它知道只应查找本地文件。 - ### 获取离线时使用的模型和分词器 另一种离线时使用 🤗 Transformers 的方法是预先下载好文件,然后在需要离线使用时指向它们的离线路径。有三种实现的方法: diff --git a/docs/source/zh/main_classes/data_collator.md b/docs/source/zh/main_classes/data_collator.md index 01013b9d3ba8..8351bdcfad8f 100644 --- a/docs/source/zh/main_classes/data_collator.md +++ b/docs/source/zh/main_classes/data_collator.md @@ -20,7 +20,7 @@ Data collators是一个对象,通过使用数据集元素列表作为输入来 为了能够构建批次,Data collators可能会应用一些预处理(比如填充)。其中一些(比如[`DataCollatorForLanguageModeling`])还会在形成的批次上应用一些随机数据增强(比如随机掩码)。 -在[示例脚本](../examples)或[示例notebooks](../notebooks)中可以找到使用的示例。 +在[示例notebooks](../notebooks)中可以找到使用的示例。 ## Default data collator diff --git a/docs/source/zh/main_classes/deepspeed.md b/docs/source/zh/main_classes/deepspeed.md index 672ad71cc8d5..fc4bf3b76a48 100644 --- a/docs/source/zh/main_classes/deepspeed.md +++ b/docs/source/zh/main_classes/deepspeed.md @@ -172,19 +172,6 @@ deepspeed --num_gpus=2 your_program.py --deepspeed ds_config.js 当您使用 `deepspeed` 启动器并且希望使用所有可用的 GPU 时,您可以简单地省略 `--num_gpus` 标志。 -以下是在 DeepSpeed 中启用使用所有可用 GPU情况下, 运行 `run_translation.py` 的示例: - - -```bash -deepspeed examples/pytorch/translation/run_translation.py \ ---deepspeed tests/deepspeed/ds_config_zero3.json \ ---model_name_or_path google-t5/t5-small --per_device_train_batch_size 1 \ ---output_dir output_dir --fp16 \ ---do_train --max_train_samples 500 --num_train_epochs 1 \ ---dataset_name wmt16 --dataset_config "ro-en" \ ---source_lang en --target_lang ro -``` - 请注意,在 DeepSpeed 文档中,您可能会看到 `--deepspeed --deepspeed_config ds_config.json` - 即两个与 DeepSpeed 相关的参数,但为简单起见,并且因为已经有很多参数要处理,我们将两者合并为一个单一参数。 有关一些实际使用示例,请参阅 [此帖](https://github.com/huggingface/transformers/issues/8771#issuecomment-759248400)。 @@ -195,19 +182,6 @@ deepspeed examples/pytorch/translation/run_translation.py \ ### 单GPU启用 -要使用一张 GPU 启用 DeepSpeed,调整 [`Trainer`] 的命令行参数如下: - - -```bash -deepspeed --num_gpus=1 examples/pytorch/translation/run_translation.py \ ---deepspeed tests/deepspeed/ds_config_zero2.json \ ---model_name_or_path google-t5/t5-small --per_device_train_batch_size 1 \ ---output_dir output_dir --fp16 \ ---do_train --max_train_samples 500 --num_train_epochs 1 \ ---dataset_name wmt16 --dataset_config "ro-en" \ ---source_lang en --target_lang ro -``` - 这与多 GPU 的情况几乎相同,但在这里我们通过 `--num_gpus=1` 明确告诉 DeepSpeed 仅使用一张 GPU。默认情况下,DeepSpeed 启用给定节点上可以看到的所有 GPU。如果您一开始只有一张 GPU,那么您不需要这个参数。以下 [文档](https://www.deepspeed.ai/getting-started/#resource-configuration-multi-node) 讨论了启动器的选项。 为什么要在仅使用一张 GPU 的情况下使用 DeepSpeed 呢? @@ -246,16 +220,6 @@ deepspeed --num_gpus=1 examples/pytorch/translation/run_translation.py \ -注意: - -- 如果您需要在特定的 GPU 上运行,而不是 GPU 0,则无法使用 `CUDA_VISIBLE_DEVICES` 来限制可用 GPU 的可见范围。相反,您必须使用以下语法: - - ```bash - deepspeed --include localhost:1 examples/pytorch/translation/run_translation.py ... - ``` - - 在这个例子中,我们告诉 DeepSpeed 使用 GPU 1(第二个 GPU)。 - @@ -443,22 +407,7 @@ cat <<'EOT' > ds_config_zero3.json EOT ``` -如果训练脚本在一个普通文件中而不是在notebook cells中,您可以通过笔记本中的 shell 正常启动 `deepspeed`。例如,要使用 `run_translation.py`,您可以这样启动: - -```python no-style -!git clone https://github.com/huggingface/transformers -!cd transformers; deepspeed examples/pytorch/translation/run_translation.py ... -``` - -或者使用 `%%bash` 魔术命令,您可以编写多行代码,用于运行 shell 程序: - -```python no-style -%%bash - -git clone https://github.com/huggingface/transformers -cd transformers -deepspeed examples/pytorch/translation/run_translation.py ... -``` +如果训练脚本在一个普通文件中而不是在notebook cells中,您可以通过笔记本中的 shell 正常启动 `deepspeed`。 在这种情况下,您不需要本节开头呈现的任何代码。 @@ -1610,8 +1559,6 @@ model = AutoModel.from_pretrained("google-t5/t5-small") trainer = Trainer(model=model, args=training_args, ...) ``` -如果您使用的是官方示例脚本,并且命令行参数中包含`--deepspeed ds_config.json`且启用了ZeRO-3配置,那么一切都已经为您准备好了,因为这是示例脚本的编写方式。 - 注意:如果模型的fp16权重无法适应单个GPU的内存,则必须使用此功能。 有关此方法和其他相关功能的完整详细信息,请参阅[构建大模型](https://deepspeed.readthedocs.io/en/latest/zero3.html#constructing-massive-models)。 @@ -1651,20 +1598,6 @@ deepspeed --num_gpus=2 your_program.py --do_eval --deepspeed ds 唯一的重要事情是您需要使用ZeRO-3配置,因为ZeRO-2对于推理没有任何优势,因为只有ZeRO-3才对参数进行分片,而ZeRO-1则对梯度和优化器状态进行分片。 -以下是在DeepSpeed下运行`run_translation.py`启用所有可用GPU的示例: - -```bash -deepspeed examples/pytorch/translation/run_translation.py \ ---deepspeed tests/deepspeed/ds_config_zero3.json \ ---model_name_or_path google-t5/t5-small --output_dir output_dir \ ---do_eval --max_eval_samples 50 --warmup_steps 50 \ ---max_source_length 128 --val_max_target_length 128 \ ---per_device_eval_batch_size 4 \ ---predict_with_generate --dataset_config "ro-en" --fp16 \ ---source_lang en --target_lang ro --dataset_name wmt16 \ ---source_prefix "translate English to Romanian: " -``` - 由于在推理阶段,优化器状态和梯度不需要额外的大量内存,您应该能够将更大的批次和/或序列长度放到相同的硬件上。 此外,DeepSpeed目前正在开发一个名为Deepspeed-Inference的相关产品,它与ZeRO技术无关,而是使用张量并行来扩展无法适应单个GPU的模型。这是一个正在进行的工作,一旦该产品完成,我们将提供集成。 @@ -1745,7 +1678,6 @@ SW: Model with 2783M total params, 65M largest layer params. 4. 如果可能,请包含一个Google Colab notebook链接,我们可以使用它来重现问题。您可以使用这个[notebook](https://github.com/stas00/porting/blob/master/transformers/deepspeed/DeepSpeed_on_colab_CLI.ipynb)作为起点。 5. 除非不可能,否则请始终使用标准数据集,而不是自定义数据集。 -6. 如果可能,尝试使用现有[示例](https://github.com/huggingface/transformers/tree/main/examples/pytorch)之一来重现问题。 需要考虑的因素: @@ -2041,13 +1973,7 @@ rank1: 要运行DeepSpeed测试,请至少运行以下命令: ```bash -RUN_SLOW=1 pytest tests/deepspeed/test_deepspeed.py -``` - -如果你更改了任何模型或PyTorch示例代码,请同时运行多模型测试。以下将运行所有DeepSpeed测试: - -```bash -RUN_SLOW=1 pytest tests/deepspeed +RUN_SLOW=1 pytest tests/trainer/distributed/test_trainer_distributed_deepspeed.py ``` ## 主要的DeepSpeed资源 diff --git a/docs/source/zh/main_classes/trainer.md b/docs/source/zh/main_classes/trainer.md index 5d587fd6d575..703c89416cd3 100644 --- a/docs/source/zh/main_classes/trainer.md +++ b/docs/source/zh/main_classes/trainer.md @@ -16,7 +16,7 @@ rendered properly in your Markdown viewer. # Trainer -[`Trainer`] 类提供了一个 PyTorch 的 API,用于处理大多数标准用例的全功能训练。它在大多数[示例脚本](https://github.com/huggingface/transformers/tree/main/examples)中被使用。 +[`Trainer`] 类提供了一个 PyTorch 的 API,用于处理大多数标准用例的全功能训练。 @@ -456,22 +456,7 @@ sudo ln -s /usr/bin/g++-7 /usr/local/cuda-10.2/bin/g++ **先决条件**:要安装带有 mps 支持的 torch,请按照这篇精彩的 Medium 文章操作 [GPU-Acceleration Comes to PyTorch on M1 Macs](https://medium.com/towards-data-science/gpu-acceleration-comes-to-pytorch-on-m1-macs-195c399efcc1)。 **用法**: -如果可用,`mps` 设备将默认使用,类似于使用 `cuda` 设备的方式。因此,用户无需采取任何操作。例如,您可以使用以下命令在 Apple Silicon GPU 上运行官方的 Glue 文本分类任务(从根文件夹运行): - -```bash -export TASK_NAME=mrpc - -python examples/pytorch/text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` +如果可用,`mps` 设备将默认使用,类似于使用 `cuda` 设备的方式。因此,用户无需采取任何操作。 **需要注意的一些注意事项** @@ -589,47 +574,9 @@ Accelerate 现在支持 Trainer。用户可以期待以下内容: use_cpu: false ``` -3. 使用accelerate配置文件参数或启动器参数以外的参数运行Trainer脚本。以下是一个使用上述FSDP配置从accelerate启动器运行`run_glue.py`的示例。 +3. 使用accelerate配置文件参数或启动器参数以外的参数运行Trainer脚本。 -```bash -cd transformers - -accelerate launch \ -./examples/pytorch/text-classification/run_glue.py \ ---model_name_or_path google-bert/bert-base-cased \ ---task_name $TASK_NAME \ ---do_train \ ---do_eval \ ---max_seq_length 128 \ ---per_device_train_batch_size 16 \ ---learning_rate 5e-5 \ ---num_train_epochs 3 \ ---output_dir /tmp/$TASK_NAME/ \ -``` - -4. 你也可以直接使用`accelerate launch`的cmd参数。上面的示例将映射到: - -```bash -cd transformers - -accelerate launch --num_processes=2 \ ---use_fsdp \ ---mixed_precision=bf16 \ ---fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \ ---fsdp_transformer_layer_cls_to_wrap="BertLayer" \ ---fsdp_sharding_strategy=1 \ ---fsdp_state_dict_type=FULL_STATE_DICT \ -./examples/pytorch/text-classification/run_glue.py ---model_name_or_path google-bert/bert-base-cased \ ---task_name $TASK_NAME \ ---do_train \ ---do_eval \ ---max_seq_length 128 \ ---per_device_train_batch_size 16 \ ---learning_rate 5e-5 \ ---num_train_epochs 3 \ ---output_dir /tmp/$TASK_NAME/ \ -``` +4. 你也可以直接使用`accelerate launch`的cmd参数。 有关更多信息,请参阅 🤗 Accelerate CLI 指南:[启动您的 🤗 Accelerate 脚本](https://huggingface.co/docs/accelerate/basic_tutorials/launch)。 diff --git a/docs/source/zh/multilingual.md b/docs/source/zh/multilingual.md index 9c27bd5f335b..6ccbf4d1f6a7 100644 --- a/docs/source/zh/multilingual.md +++ b/docs/source/zh/multilingual.md @@ -77,8 +77,6 @@ XLM 有十个不同的检查点,其中只有一个是单语言的。剩下的 >>> outputs = model(input_ids, langs=langs) ``` -[run_generation.py](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-generation/run_generation.py) 脚本可以使用 `xlm-clm` 检查点生成带有语言嵌入的文本。 - ### 不带语言嵌入的 XLM 以下 XLM 模型在推理时不需要语言嵌入: diff --git a/docs/source/zh/perf_hardware.md b/docs/source/zh/perf_hardware.md index 95a09eaab4e1..812bce5aa615 100644 --- a/docs/source/zh/perf_hardware.md +++ b/docs/source/zh/perf_hardware.md @@ -116,41 +116,3 @@ GPU1 PHB X 0-11 N/A > (Note that 3-Way and 4-Way SLI configurations are not supported.) 所以,在`nvidia-smi topo -m`输出的`NVX`报告中获取到的更高的`X`值意味着更好的性能。生成的结果将取决于您的GPU架构。 - -让我们比较在小样本wikitext上训练gpt2语言模型的执行结果。 - -结果是: - - -| NVlink | Time | -| ----- | ---: | -| Y | 101s | -| N | 131s | - - -可以看到,NVLink使训练速度提高了约23%。在第二个基准测试中,我们使用`NCCL_P2P_DISABLE=1`告诉GPU不要使用NVLink。 - -这里是完整的基准测试代码和输出: - -```bash -# DDP w/ NVLink - -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 torchrun \ ---nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \ ---dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train \ ---output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 101.9003, 'train_samples_per_second': 1.963, 'epoch': 0.69} - -# DDP w/o NVLink - -rm -r /tmp/test-clm; CUDA_VISIBLE_DEVICES=0,1 NCCL_P2P_DISABLE=1 torchrun \ ---nproc_per_node 2 examples/pytorch/language-modeling/run_clm.py --model_name_or_path openai-community/gpt2 \ ---dataset_name wikitext --dataset_config_name wikitext-2-raw-v1 --do_train ---output_dir /tmp/test-clm --per_device_train_batch_size 4 --max_steps 200 - -{'train_runtime': 131.4367, 'train_samples_per_second': 1.522, 'epoch': 0.69} -``` - -硬件: 2x TITAN RTX 24GB each + NVlink with 2 NVLinks (`NV2` in `nvidia-smi topo -m`) -软件: `pytorch-1.8-to-be` + `cuda-11.0` / `transformers==4.3.0.dev0` diff --git a/docs/source/zh/perf_train_cpu.md b/docs/source/zh/perf_train_cpu.md index f576c3fa855f..8a2c2de3b771 100644 --- a/docs/source/zh/perf_train_cpu.md +++ b/docs/source/zh/perf_train_cpu.md @@ -47,39 +47,6 @@ pip install intel_extension_for_pytorch== -f https://developer.int 查看更多 [安装IPEX](https://intel.github.io/intel-extension-for-pytorch/cpu/latest/tutorials/installation.html) 的方法。 - -### 在 Trainer 中使用 IPEX -在 Trainer 中使用 IPEX 时,您应在训练命令参数中添加 `use_ipex`、`bf16` 或 `fp16` 以及 `no_cuda` 来启用自动混合精度。 - -以 [Transformers 问答任务](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering)为例: - -- 在 CPU 上使用 BF16 自动混合精度训练 IPEX 的示例如下: -
 python examples/pytorch/question-answering/run_qa.py \
---model_name_or_path google-bert/bert-base-uncased \
---dataset_name squad \
---do_train \
---do_eval \
---per_device_train_batch_size 12 \
---learning_rate 3e-5 \
---num_train_epochs 2 \
---max_seq_length 384 \
---doc_stride 128 \
---output_dir /tmp/debug_squad/ \
---use_ipex \
---bf16 \
---use_cpu
- -如果您想在脚本中启用 `use_ipex` 和 `bf16`,请像下面这样将这些参数添加到 `TrainingArguments` 中: -```diff -training_args = TrainingArguments( - output_dir=args.output_path, -+ bf16=True, -+ use_ipex=True, -+ use_cpu=True, - **kwargs -) -``` - ### 实践示例 博客: [使用 Intel Sapphire Rapids 加速 PyTorch Transformers](https://huggingface.co/blog/intel-sapphire-rapids) diff --git a/docs/source/zh/perf_train_special.md b/docs/source/zh/perf_train_special.md index 8e7929ecb1cd..cb0b83805441 100644 --- a/docs/source/zh/perf_train_special.md +++ b/docs/source/zh/perf_train_special.md @@ -34,23 +34,7 @@ rendered properly in your Markdown viewer. pip install torch torchvision torchaudio ``` -[`TrainingArguments`]类默认使用`mps`设备(如果可用)因此无需显式设置设备。例如,您可以直接运行[run_glue.py](https://github.com/huggingface/transformers/blob/main/examples/pytorch/text-classification/run_glue.py)脚本,在无需进行任何修改的情况下自动启用 MPS 后端。 - -```diff -export TASK_NAME=mrpc - -python examples/pytorch/text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ -- --use_mps_device \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ \ -``` +[`TrainingArguments`]类默认使用`mps`设备(如果可用)因此无需显式设置设备。 用于[分布式设置](https://pytorch.org/docs/stable/distributed.html#backends)的后端(如`gloo`和`nccl`)不支持`mps`设备,这也意味着使用 MPS 后端时只能在单个 GPU 上进行训练。 diff --git a/docs/source/zh/run_scripts.md b/docs/source/zh/run_scripts.md deleted file mode 100644 index 60e78fcb9e9b..000000000000 --- a/docs/source/zh/run_scripts.md +++ /dev/null @@ -1,287 +0,0 @@ - - -# 使用脚本进行训练 - -除了 🤗 Transformers [notebooks](./notebooks),还有示例脚本演示了如何使用[PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch)训练模型以解决特定任务。 - -您还可以在这些示例中找到我们在[研究项目](https://github.com/huggingface/transformers-research-projects/)和[遗留示例](https://github.com/huggingface/transformers/tree/main/examples/legacy)中使用过的脚本,这些脚本主要是由社区贡献的。这些脚本已不再被积极维护,需要使用特定版本的🤗 Transformers, 可能与库的最新版本不兼容。 - -示例脚本可能无法在初始配置下直接解决每个问题,您可能需要根据要解决的问题调整脚本。为了帮助您,大多数脚本都完全暴露了数据预处理的方式,允许您根据需要对其进行编辑。 - -如果您想在示例脚本中实现任何功能,请在[论坛](https://discuss.huggingface.co/)或[issue](https://github.com/huggingface/transformers/issues)上讨论,然后再提交Pull Request。虽然我们欢迎修复错误,但不太可能合并添加更多功能的Pull Request,因为这会降低可读性。 - -本指南将向您展示如何在[PyTorch](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization)中运行示例摘要训练脚本。 - -## 设置 - -要成功运行示例脚本的最新版本,您必须在新虚拟环境中**从源代码安装 🤗 Transformers**: - -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` - -对于旧版本的示例脚本,请点击下面的切换按钮: - -
- 老版本🤗 Transformers示例 - -
- -然后切换您clone的 🤗 Transformers 仓到特定的版本,例如v3.5.1: - -```bash -git checkout tags/v3.5.1 -``` - -在安装了正确的库版本后,进入您选择的版本的`example`文件夹并安装例子要求的环境: - -```bash -pip install -r requirements.txt -``` - -## 运行脚本 - - -示例脚本从🤗 [Datasets](https://huggingface.co/docs/datasets/)库下载并预处理数据集。然后,脚本通过[Trainer](https://huggingface.co/docs/transformers/main_classes/trainer)使用支持摘要任务的架构对数据集进行微调。以下示例展示了如何在[CNN/DailyMail](https://huggingface.co/datasets/cnn_dailymail)数据集上微调[T5-small](https://huggingface.co/google-t5/t5-small)。由于T5模型的训练方式,它需要一个额外的`source_prefix`参数。这个提示让T5知道这是一个摘要任务。 - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## 分布式训练和混合精度 - -[Trainer](https://huggingface.co/docs/transformers/main_classes/trainer) 支持分布式训练和混合精度,这意味着你也可以在脚本中使用它。要启用这两个功能,可以做如下设置: - -- 添加 `fp16` 参数以启用混合精度。 -- 使用 `nproc_per_node` 参数设置使用的GPU数量。 - - -```bash -torchrun \ - --nproc_per_node 8 pytorch/summarization/run_summarization.py \ - --fp16 \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## 在TPU上运行脚本 - - -张量处理单元(TPUs)是专门设计用于加速性能的。PyTorch使用 [PyTorch/XLA](https://github.com/pytorch/xla/blob/master/README.md) 支持TPU。要使用TPU,请启动`xla_spawn.py`脚本并使用`num_cores`参数设置要使用的TPU核心数量。 - -```bash -python xla_spawn.py --num_cores 8 \ - summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## 基于🤗 Accelerate运行脚本 - -🤗 [Accelerate](https://huggingface.co/docs/accelerate) 是一个仅支持 PyTorch 的库,它提供了一种统一的方法来在不同类型的设置(仅 CPU、多个 GPU、多个TPU)上训练模型,同时保持对 PyTorch 训练循环的完全可见性。如果你还没有安装 🤗 Accelerate,请确保你已经安装了它: - -> 注意:由于 Accelerate 正在快速发展,因此必须安装 git 版本的 accelerate 来运行脚本。 - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -你需要使用`run_summarization_no_trainer.py`脚本,而不是`run_summarization.py`脚本。🤗 Accelerate支持的脚本需要在文件夹中有一个`task_no_trainer.py`文件。首先运行以下命令以创建并保存配置文件: - -```bash -accelerate config -``` -检测您的设置以确保配置正确: - -```bash -accelerate test -``` - -现在您可以开始训练模型了: - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -## 使用自定义数据集 - -摘要脚本支持自定义数据集,只要它们是CSV或JSON Line文件。当你使用自己的数据集时,需要指定一些额外的参数: -- `train_file` 和 `validation_file` 分别指定您的训练和验证文件的路径。 -- `text_column` 是输入要进行摘要的文本。 -- `summary_column` 是目标输出的文本。 - -使用自定义数据集的摘要脚本看起来是这样的: - - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --text_column text_column_name \ - --summary_column summary_column_name \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -## 测试脚本 - -通常,在提交整个数据集之前,最好先在较少的数据集示例上运行脚本,以确保一切按预期工作,因为完整数据集的处理可能需要花费几个小时的时间。使用以下参数将数据集截断为最大样本数: - -- `max_train_samples` -- `max_eval_samples` -- `max_predict_samples` - - -```bash -python examples/pytorch/summarization/run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --max_train_samples 50 \ - --max_eval_samples 50 \ - --max_predict_samples 50 \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -并非所有示例脚本都支持`max_predict_samples`参数。如果您不确定您的脚本是否支持此参数,请添加`-h`参数进行检查: - -```bash -examples/pytorch/summarization/run_summarization.py -h -``` - -## 从checkpoint恢复训练 - -另一个有用的选项是从之前的checkpoint恢复训练。这将确保在训练中断时,您可以从之前停止的地方继续进行,而无需重新开始。有两种方法可以从checkpoint恢复训练。 - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --resume_from_checkpoint path_to_specific_checkpoint \ - --predict_with_generate -``` - -## 分享模型 - -所有脚本都可以将您的最终模型上传到[Model Hub](https://huggingface.co/models)。在开始之前,请确保您已登录Hugging Face: - -```bash -hf auth login -``` - -然后,在脚本中添加`push_to_hub`参数。这个参数会创建一个带有您Hugging Face用户名和`output_dir`中指定的文件夹名称的仓库。 - -为了给您的仓库指定一个特定的名称,使用`push_to_hub_model_id`参数来添加它。该仓库将自动列出在您的命名空间下。 - -以下示例展示了如何上传具有特定仓库名称的模型: - - -```bash -python examples/pytorch/summarization/run_summarization.py - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --push_to_hub \ - --push_to_hub_model_id finetuned-t5-cnn_dailymail \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` diff --git a/docs/source/zh/training.md b/docs/source/zh/training.md index fb96590ae351..b346e9934f73 100644 --- a/docs/source/zh/training.md +++ b/docs/source/zh/training.md @@ -304,6 +304,4 @@ torch.cuda.empty_cache() 更多微调例子可参考如下链接: -- [🤗 Transformers 示例](https://github.com/huggingface/transformers/tree/main/examples) 包含用于在 PyTorch 和 TensorFlow 中训练常见自然语言处理任务的脚本。 - - [🤗 Transformers 笔记](notebooks) 包含针对特定任务在 PyTorch 和 TensorFlow 中微调模型的各种`notebook`。 diff --git a/examples/3D_parallel.py b/examples/3D_parallel.py deleted file mode 100644 index d500e9aec41c..000000000000 --- a/examples/3D_parallel.py +++ /dev/null @@ -1,434 +0,0 @@ -# Copyright 2024 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""": -This script is used to test training a model using Tensor Parallelism and Data Parallelism. - -Usage: -export CUDA_VISIBLE_DEVICES=0,1,2,3 -export CUDA_VISIBLE_DEVICES=4,5,6,7 -export CUDA_VISIBLE_DEVICES=5,6,7 -TP_SIZE=2 DP_SIZE=2 torchrun --nproc_per_node=4 --rdzv_endpoint=localhost:29503 examples/3D_parallel.py -CP_SIZE=2 DP_SIZE=2 torchrun --nproc_per_node=4 examples/3D_parallel.py -CP_SIZE=2 TP_SIZE=2 torchrun --nproc_per_node=4 examples/3D_parallel.py -DP_SIZE=2 CP_SIZE=2 TP_SIZE=2 torchrun --nproc_per_node=8 examples/3D_parallel.py - -TP_SIZE=1 CP_SIZE=4 torchrun --nproc_per_node=4 examples/3D_parallel.py -TP_SIZE=1 DP_SIZE=4 torchrun --nproc_per_node=4 examples/3D_parallel.py -TP_SIZE=4 DP_SIZE=1 torchrun --nproc_per_node=4 --rdzv_endpoint=localhost:29503 examples/3D_parallel.py -IGNORE_SANITY=1 CP_SIZE=1 TP_SIZE=1 DP_SIZE=1 torchrun --nproc_per_node=1 --rdzv_endpoint=localhost:29504 examples/3D_parallel.py -ocalhost:29504 test_train.py -""" - -import logging -import os -from collections.abc import Iterable -from contextlib import nullcontext - -import torch -import torch.distributed as dist -import torch.distributed.checkpoint as dcp -import torch.optim as optim -import wandb -from datasets import load_dataset -from torch.distributed.checkpoint.state_dict import get_state_dict, set_state_dict -from torch.distributed.checkpoint.stateful import Stateful -from torch.distributed.device_mesh import DeviceMesh -from torch.distributed.fsdp import FullyShardedDataParallel as FSDP -from torch.distributed.fsdp import ShardingStrategy -from torch.distributed.tensor import DTensor -from torch.distributed.tensor.experimental import context_parallel -from torch.nn.attention import SDPBackend, sdpa_kernel -from torch.utils.data import DataLoader -from torch.utils.data.distributed import DistributedSampler - -from transformers import AutoModelForCausalLM, AutoTokenizer - - -# torch.use_deterministic_algorithms(True) -torch.backends.cudnn.deterministic = True - -# Set up logging -logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, -) -logger = logging.getLogger(__name__) - -# from torch.distributed.tensor.experimental._attention import set_rotate_method - -# set_rotate_method("alltoall") # CP rotate shards using all-to-all - - -def main(): - tp_size = int(os.environ.get("TP_SIZE", "1")) - dp_size = int(os.environ.get("DP_SIZE", "1")) - cp_size = int(os.environ.get("CP_SIZE", "1")) # Add CP size configuration - sdpa_backend = SDPBackend.FLASH_ATTENTION # For CP - # sdpa_backend = SDPBackend.MATH # For CP - global_batch_size = 8 # Desired global batch size - seq_len = 1024 # Sequence length - num_train_steps = 10000 # Number of training steps - LR = 1e-5 - model_name = "HuggingFaceTB/SmolLM2-1.7B" - # model_name = "unsloth/Llama-3.2-1B" - - CHECKPOINT_DIR = f"checkpoint_tp{tp_size}_dp{dp_size}_cp{cp_size}" - - # Initialize distributed environment - if "RANK" in os.environ and "WORLD_SIZE" in os.environ: - dist.init_process_group("nccl") - rank = dist.get_rank() - world_size = dist.get_world_size() - local_rank = int(os.environ["LOCAL_RANK"]) - torch.cuda.set_device(local_rank) - - assert world_size == tp_size * dp_size * cp_size, ( - f"World size ({world_size}) must equal TP size ({tp_size}) * DP size ({dp_size}) * CP size ({cp_size})" - ) - - mesh = torch.arange(world_size).reshape(dp_size, tp_size, cp_size) - world_mesh = DeviceMesh(device_type="cuda", mesh=mesh, mesh_dim_names=("dp", "tp", "cp")) - tp_mesh = world_mesh["tp"] - dp_mesh = world_mesh["dp"] - cp_mesh = world_mesh["cp"] - world_mesh["dp", "cp"]._flatten(mesh_dim_name="dp_cp") - logger.info(f"Created DeviceMesh: {world_mesh}") - logger.info( - f"Distributed setup - Rank: {rank}, World size: {world_size}, Local rank: {local_rank}, DP: {dp_mesh.get_local_rank()}, TP: {tp_mesh.get_local_rank()}, CP: {cp_mesh.get_local_rank()}" - ) - - if dist.get_rank() == 0: - wandb.init( - project="tp_dp_test", - config={ - "tp_size": tp_size, - "dp_size": dp_size, - "cp_size": cp_size, - "global_batch_size": global_batch_size, - "model_name": model_name, - "dataset": "roneneldan/TinyStories-1M", - "seq_len": seq_len, - "lr": LR, - "weight_decay": 0.1, - }, - name=f"llama_tp{tp_size}_dp{dp_size}_cp{cp_size}" - if model_name == "unsloth/Llama-3.2-1B" - else f"tp{tp_size}_dp{dp_size}_cp{cp_size}", - ) - logger.info("Wandb initialized.") - # Log the current file to wandb - wandb.save("test_train.py") - - # Load model and tokenizer - logger.info(f"Loading model and tokenizer from {model_name}") - tokenizer = AutoTokenizer.from_pretrained(model_name) - if tokenizer.pad_token is None: - tokenizer.pad_token = tokenizer.eos_token - logger.info(f"Set pad_token to eos_token: {tokenizer.pad_token}") - - model = AutoModelForCausalLM.from_pretrained( - model_name, - device_mesh=tp_mesh if dist.is_initialized() else None, - tp_plan="auto", - dtype=torch.bfloat16, - ) - logger.info(f"Model loaded onto device mesh: {tp_mesh}") - device = torch.device(f"cuda:{local_rank}") - logger.info(f"Using device: {device} for non-model tensors") - use_ddp = False - if dist.is_initialized() and dp_mesh.size() > 1: - model = FSDP(model, device_mesh=dp_mesh, sharding_strategy=ShardingStrategy.NO_SHARD) - use_ddp = True - - model.train() - - logger.info("Loading TinyStories dataset...") - raw_dataset = load_dataset("roneneldan/TinyStories", split="train[:1%]") # Use 1% for faster testing - - def tokenize_function(examples): - # Tokenize the text without padding - tokenized_batch = tokenizer( - examples["text"], padding=False, truncation=True, max_length=seq_len, return_tensors=None - ) - # Set labels to be the same as input_ids for Causal LM - tokenized_batch["labels"] = tokenized_batch["input_ids"].copy() - return tokenized_batch - - tokenized_dataset = raw_dataset.map(tokenize_function, batched=True, remove_columns=["text"]) - logger.info(f"Dataset loaded and tokenized. Size: {len(tokenized_dataset)}") - - # Create packed sequences - def create_packed_sequences(examples): - # Flatten all sequences - all_tokens = [] - for input_ids in examples["input_ids"]: - all_tokens.extend(input_ids) - - # Split into sequences of seq_len + 1 (for input + label) - num_sequences = len(all_tokens) // (seq_len + 1) - packed_input_ids = [] - packed_labels = [] - - for i in range(num_sequences): - start_idx = i * (seq_len + 1) - end_idx = start_idx + (seq_len + 1) - # Get the full sequence - full_sequence = all_tokens[start_idx:end_idx] - # For input_ids, remove the last token - packed_input_ids.append(full_sequence[:-1]) - # For labels, remove the first token - packed_labels.append(full_sequence[1:]) - - return {"input_ids": packed_input_ids, "labels": packed_labels} - - # Apply packing to the dataset - packed_dataset = tokenized_dataset.map( - create_packed_sequences, - batched=True, - remove_columns=tokenized_dataset.column_names, - batch_size=1000, # Process in batches for efficiency - num_proc=60, - ) - logger.info(f"Dataset packed. New size: {len(packed_dataset)}") - - # Shuffle the packed dataset - packed_dataset = packed_dataset.shuffle(seed=42) - logger.info("Packed dataset shuffled") - - # Calculate local batch size - if dist.is_initialized(): - assert global_batch_size % dp_mesh.size() == 0, ( - f"Global batch size ({global_batch_size}) must be divisible by DP size ({dp_mesh.size()})" - ) - local_batch_size = global_batch_size // dp_mesh.size() - else: - local_batch_size = global_batch_size - - logger.info( - f"Global batch size: {global_batch_size}, DP size: {dp_size if dist.is_initialized() else 1}, Local batch size: {local_batch_size}" - ) - - # Simple collate function since sequences are already packed - def collate_fn(batch): - input_ids = torch.tensor([item["input_ids"] for item in batch], dtype=torch.long) - labels = torch.tensor([item["labels"] for item in batch], dtype=torch.long) - return {"input_ids": input_ids, "labels": labels} - - if dist.is_initialized(): - sampler = DistributedSampler( - packed_dataset, num_replicas=dp_mesh.size(), rank=dp_mesh.get_local_rank(), shuffle=False - ) - else: - sampler = None - - dataloader = DataLoader( - packed_dataset, - batch_size=local_batch_size, - sampler=sampler, - shuffle=False, - collate_fn=collate_fn, - pin_memory=True, - ) - logger.info(f"DataLoader created. Distributed: {dist.is_initialized()}") - - optimizer = optim.AdamW(model.parameters(), lr=LR, weight_decay=0.1) - - # Training loop - logger.info(f"Starting training for {num_train_steps} steps...") - model.train() - step = 0 - while step < num_train_steps: - for batch in dataloader: - if step >= num_train_steps: - break # Exit loop if max steps reached - - # Move batch to appropriate device - batch = {k: v.to(device) for k, v in batch.items()} - optimizer.zero_grad() - - # Add position_ids to batch before CP sharding - batch_size = batch["input_ids"].shape[0] - position_ids = torch.arange(0, seq_len, dtype=torch.long, device=device) - position_ids = position_ids.unsqueeze(0).expand(batch_size, -1) - batch["position_ids"] = position_ids - from torch.distributed.tensor.experimental._attention import _cp_options - - _cp_options.enable_load_balance = False - - with sdpa_kernel(sdpa_backend): # TODO: ideally move this to attention implementation - cp_context = ( - nullcontext() - if cp_mesh.size() == 1 - else context_parallel( - cp_mesh, - buffers=[ - batch["input_ids"], - batch["labels"], - batch["position_ids"], - ], - buffer_seq_dims=[1, 1, 1], - ) - ) - with cp_context: - # Pop labels from batch before model forward pass - labels = batch.pop("labels") - outputs = model(**batch) # [mbs, seq_len/cp] - loss = outputs.loss - logits = outputs.logits - - # Compute loss with shifted labels - loss = model.loss_function( - logits=logits, labels=None, shift_labels=labels, vocab_size=model.config.vocab_size - ) - loss.backward() - - # all reduce grads across dp_cp if applicable - all_reduce_grads(model, world_mesh, use_ddp=use_ddp) - - if hasattr(model, "clip_grad_norm_"): - gradnorm = model.clip_grad_norm_(max_norm=1.0, norm_type=2.0) # TODO: fix reported gradnorm - else: - # only works with FSDP's NO_SHARD otherwise we should use FSDP's clip_grad_norm_ - assert len(list(model.parameters())) > 5, "No parameters found in model. Probably DDP bug.." - gradnorm = clip_grad_norm_(model.parameters(), max_norm=1.0, norm_type=2.0, foreach=True) - - optimizer.step() - # allreduce loss across cp_dp before logging - if dist.is_initialized() and (cp_mesh.size() > 1 or dp_mesh.size() > 1): - dist.all_reduce(loss, group=world_mesh["dp_cp"].get_group(), op=dist.ReduceOp.AVG) - current_loss = loss.item() - - # Log loss and gradnorm to wandb (only on rank 0 of dp group) - if not dist.is_initialized() or dist.get_rank() == 0: - logger.info( - f"Step: {step} | GBS: {global_batch_size} | DP: {dp_mesh.size()} | TP: {tp_mesh.size()} | CP: {cp_mesh.size()} | Loss: {current_loss} | Gradnorm: {gradnorm} | lr: {LR}" - ) - wandb.log( - { - "train/loss": current_loss, - "train/gradnorm": gradnorm, - "step": step, - "lr": LR, - "GBS": global_batch_size, - } - ) - - step += 1 # Increment step count - - logger.info("Training loop finished.") - - # Save model using DCP (only if distributed) - if dist.is_initialized(): - state_dict = {"app": AppState(model, optimizer)} - dcp.save( - state_dict=state_dict, - checkpoint_id=CHECKPOINT_DIR, - ) - logger.info(f"Saved checkpoint to {CHECKPOINT_DIR}") - else: - # Fallback to regular save for non-distributed case - save_dir = "test_model_nondist" - model.save_pretrained(save_dir) - tokenizer.save_pretrained(save_dir) # Save tokenizer too - logger.info(f"Saved model to {save_dir}") - - dist.destroy_process_group() - logger.info("Cleaned up distributed process group") - # Finish wandb run on rank 0 - if dist.get_rank() == 0: - wandb.finish() - logger.info("Wandb run finished.") - - -def all_reduce_grads(model, world_mesh, use_ddp): - """All reduce gradients across dp_cp if applicable.""" - cp_mesh = world_mesh["cp"] - if use_ddp: - # DDP/FSDP takes care of syncing grads - mesh = cp_mesh - else: - mesh = world_mesh["dp", "cp"]._flatten(mesh_dim_name="dp_cp") - if dist.is_initialized() and mesh.size() > 1: - for name, param in model.named_parameters(): - if param.grad is not None: - # Workaround for cross-mesh communication limitation with DTensor gradients - if isinstance(param.grad, DTensor): - local_grad = param.grad.to_local() - # Ensure grad requires grad for inplace modification checks (might not be needed) - # local_grad = local_grad.detach().requires_grad_(True) - torch.distributed.all_reduce(local_grad, op=torch.distributed.ReduceOp.SUM, group=mesh.get_group()) - local_grad = local_grad / mesh.size() - # Assign averaged grad back - need careful handling if DTensor structure is complex - # This simple assignment might work if the grad structure matches param structure - param.grad = DTensor.from_local( - local_grad, device_mesh=param.grad.device_mesh, placements=param.grad.placements - ) - else: - # Handle regular tensors if any exist (e.g. buffers not converted to DTensor) - torch.distributed.all_reduce(param.grad, op=torch.distributed.ReduceOp.AVG, group=mesh.get_group()) - - -class AppState(Stateful): - """Wrapper for checkpointing the Application State including model and optimizer.""" - - def __init__(self, model, optimizer=None): - self.model = model - self.optimizer = optimizer - - def state_dict(self): - model_state_dict, optimizer_state_dict = get_state_dict(self.model, self.optimizer) - return {"model": model_state_dict, "optim": optimizer_state_dict} - - def load_state_dict(self, state_dict): - set_state_dict( - self.model, self.optimizer, model_state_dict=state_dict["model"], optim_state_dict=state_dict["optim"] - ) - - -def clip_grad_norm_( - parameters: Iterable[torch.Tensor], - max_norm: float, - norm_type: float = 2.0, - error_if_nonfinite: bool = False, - foreach: bool | None = None, -) -> torch.Tensor: - """ - Clip the gradient norm of an iterable of parameters. - """ - # Filter out parameters with no gradients - parameters = [p for p in parameters if p.grad is not None] - assert len(parameters) > 0, "No parameters with gradients found" - - # Calculate total norm - if norm_type == float("inf"): - total_norm = max(p.grad.detach().abs().max() for p in parameters) - else: - total_norm = torch.norm(torch.stack([torch.norm(p.grad.detach(), norm_type) for p in parameters]), norm_type) - - # Convert DTensor to local tensor if needed - if isinstance(total_norm, DTensor): - total_norm = total_norm.full_tensor() - - # Clip gradients - clip_coef = max_norm / (total_norm + 1e-6) - if clip_coef < 1: - for p in parameters: - p.grad.detach().mul_(clip_coef) - - return total_norm - - -if __name__ == "__main__": - main() diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index ba2a9abd6e37..000000000000 --- a/examples/README.md +++ /dev/null @@ -1,150 +0,0 @@ - - -# Examples - -We host a wide range of example scripts, in addition to [research projects](https://github.com/huggingface/transformers-research-projects/), as well as some [legacy examples](https://github.com/huggingface/transformers/tree/main/examples/legacy). Note that unlike the main examples these are not actively maintained, and may require specific older versions of dependencies in order to run. - -While we strive to present as many use cases as possible, the example scripts are just that - examples. It is expected that they won't work out-of-the-box on your specific problem and that you will be required to change a few lines of code to adapt them to your needs. To help you with that, most of the examples fully expose the preprocessing of the data, allowing you to tweak and edit them as required. - -Please discuss on the [forum](https://discuss.huggingface.co/) or in an [issue](https://github.com/huggingface/transformers/issues) a feature you would like to implement in an example before submitting a PR; we welcome bug fixes, but since we want to keep the examples as simple as possible it's unlikely that we will merge a pull request adding more functionality at the cost of readability. - -## Important note - -**Important** - -To make sure you can successfully run the latest versions of the example scripts, you have to **install the library from source** and install some example-specific requirements. To do this, execute the following steps in a new virtual environment: -```bash -git clone https://github.com/huggingface/transformers -cd transformers -pip install . -``` -Then cd in the example folder of your choice and run -```bash -pip install -r requirements.txt -``` - -To browse the examples corresponding to released versions of 🤗 Transformers, click on the line below and then on your desired version of the library: - -
- Examples for older versions of 🤗 Transformers - -
- -Alternatively, you can switch your cloned 🤗 Transformers to a specific version (for instance with v3.5.1) with -```bash -git checkout tags/v3.5.1 -``` -and run the example command as usual afterward. - -## Running the Examples on Hugging Face Jobs - -Each example script declares its dependencies in a [PEP 723](https://peps.python.org/pep-0723/) `# /// script` header, so it runs on [Hugging Face Jobs](https://huggingface.co/docs/hub/jobs) straight from its GitHub URL, with no environment to set up. Pass the URL to `hf jobs uv run` and the script's arguments after it: - -```bash -hf jobs uv run --flavor a10g-small --timeout 30m -s HF_TOKEN -- \ - https://raw.githubusercontent.com/huggingface/transformers/main/examples/pytorch/image-classification/run_image_classification.py \ - --model_name_or_path google/vit-base-patch16-224-in21k \ - --dataset_name ethz/food101 \ - --do_train --do_eval \ - --remove_unused_columns False \ - --max_train_samples 2000 --max_eval_samples 500 --num_train_epochs 1 \ - --output_dir vit-food101 \ - --push_to_hub -``` - -`--flavor` picks the hardware, `--timeout` sets the time limit (30 minutes by default), and `-s HF_TOKEN` forwards your token so the script can push the model. The `--` before the URL keeps the two apart, so a script argument that shares a name with an `hf` flag, such as `--token`, goes to the script. This trains on 2,000 images and finishes in about three minutes. For the full run, drop the `--max_*` and `--num_train_epochs` flags and raise `--timeout` to `2h`: three epochs over Food-101 take about an hour on `a10g-small`. See [Train Models on Jobs](https://huggingface.co/docs/hub/jobs-training) for the details. - -## Running the Examples on Remote Hardware with Auto-Setup - -[run_on_remote.py](./run_on_remote.py) is a script that launches any example on remote self-hosted hardware, -with automatic hardware and environment setup. It uses [Runhouse](https://github.com/run-house/runhouse) to launch -on self-hosted hardware (e.g. in your own cloud account or on-premise cluster) but there are other options -for running remotely as well. You can easily customize the example used, command line arguments, dependencies, -and type of compute hardware, and then run the script to automatically launch the example. - -You can refer to -[hardware setup](https://www.run.house/docs/tutorials/quick-start-cloud) -for more information about hardware and dependency setup with Runhouse, or this -[Colab tutorial](https://colab.research.google.com/drive/1sh_aNQzJX5BKAdNeXthTNGxKz7sM9VPc) for a more in-depth -walkthrough. - -You can run the script with the following commands: - -```bash -# First install runhouse: -pip install runhouse - -# For an on-demand V100 with whichever cloud provider you have configured: -python run_on_remote.py \ - --example pytorch/text-generation/run_generation.py \ - --model_type=gpt2 \ - --model_name_or_path=openai-community/gpt2 \ - --prompt "I am a language model and" - -# For byo (bring your own) cluster: -python run_on_remote.py --host --user --key_path \ - --example - -# For on-demand instances -python run_on_remote.py --instance --provider \ - --example -``` - -You can also adapt the script to your own needs. diff --git a/examples/pytorch/continuous_batching.py b/examples/generate/continuous_batching.py similarity index 97% rename from examples/pytorch/continuous_batching.py rename to examples/generate/continuous_batching.py index bd0b2c3b16c9..c84a361bb2f4 100644 --- a/examples/pytorch/continuous_batching.py +++ b/examples/generate/continuous_batching.py @@ -315,6 +315,6 @@ def batch_generate( prof.export_chrome_trace(filename) # Example usage: -# python examples/pytorch/continuous_batching.py --attn sdpa --add-prefix --samples 10 --compare -# python examples/pytorch/continuous_batching.py --attn flash_attention_2 -mp none --add-prefix --samples 500 -# python examples/pytorch/continuous_batching.py -mp none -cg yes --samples 10 --max-new-tokens 32 --profile profile_wip.json +# python examples/generate/continuous_batching.py --attn sdpa --add-prefix --samples 10 --compare +# python examples/generate/continuous_batching.py --attn flash_attention_2 -mp none --add-prefix --samples 500 +# python examples/generate/continuous_batching.py -mp none -cg yes --samples 10 --max-new-tokens 32 --profile profile_wip.json diff --git a/examples/pytorch/continuous_batching_simple.py b/examples/generate/continuous_batching_simple.py similarity index 100% rename from examples/pytorch/continuous_batching_simple.py rename to examples/generate/continuous_batching_simple.py diff --git a/examples/pytorch/transformers_serve_cb_eval_job.py b/examples/generate/transformers_serve_cb_eval_job.py similarity index 100% rename from examples/pytorch/transformers_serve_cb_eval_job.py rename to examples/generate/transformers_serve_cb_eval_job.py diff --git a/examples/pytorch/3d_parallel_checks.py b/examples/pytorch/3d_parallel_checks.py deleted file mode 100644 index a99988d98247..000000000000 --- a/examples/pytorch/3d_parallel_checks.py +++ /dev/null @@ -1,792 +0,0 @@ -# Copyright 2024 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""": -This script is used to test training a model using Tensor Parallelism and Data Parallelism. - -Usage: -export CUDA_VISIBLE_DEVICES=0,1,2,3 -export CUDA_VISIBLE_DEVICES=4,5,6,7 -export CUDA_VISIBLE_DEVICES=5,6,7 -TP_SIZE=2 DP_SIZE=2 torchrun --nproc_per_node=4 --rdzv_endpoint=localhost:29503 test_train.py -CP_SIZE=2 DP_SIZE=2 torchrun --nproc_per_node=4 test_train.py -CP_SIZE=2 TP_SIZE=2 torchrun --nproc_per_node=4 test_train.py - -TP_SIZE=1 CP_SIZE=4 torchrun --nproc_per_node=4 test_train.py -TP_SIZE=1 DP_SIZE=4 torchrun --nproc_per_node=4 test_train.py -TP_SIZE=4 DP_SIZE=1 torchrun --nproc_per_node=4 --rdzv_endpoint=localhost:29503 test_train.py -IGNORE_SANITY=1 CP_SIZE=1 TP_SIZE=1 DP_SIZE=1 torchrun --nproc_per_node=1 --rdzv_endpoint=l -ocalhost:29504 test_train.py -""" - -import logging -import os -from collections.abc import Iterable -from contextlib import nullcontext - -import torch -import torch.distributed as dist -import torch.distributed.checkpoint as dcp -import torch.nn as nn -import torch.optim as optim -import wandb -from datasets import load_dataset -from torch.distributed.checkpoint.state_dict import get_state_dict, set_state_dict -from torch.distributed.checkpoint.stateful import Stateful -from torch.distributed.device_mesh import DeviceMesh -from torch.distributed.fsdp import FullyShardedDataParallel as FSDP -from torch.distributed.fsdp import ShardingStrategy -from torch.distributed.tensor import DTensor -from torch.distributed.tensor.experimental import context_parallel -from torch.nn.attention import SDPBackend, sdpa_kernel -from torch.utils.data import DataLoader, default_collate -from torch.utils.data.distributed import DistributedSampler - -from transformers import AutoModelForCausalLM, AutoTokenizer - - -ignore_sanity_checks = int(os.environ.get("IGNORE_SANITY", "0")) == 1 -# torch.use_deterministic_algorithms(True) -torch.backends.cudnn.deterministic = True - -# Set up logging -logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, -) -logger = logging.getLogger(__name__) - -# from torch.distributed.tensor.experimental._attention import set_rotate_method - -# set_rotate_method("alltoall") # rotate shards using all-to-all - - -def main(): - tp_size = int(os.environ.get("TP_SIZE", "1")) - dp_size = int(os.environ.get("DP_SIZE", "4")) - cp_size = int(os.environ.get("CP_SIZE", "1")) # Add CP size configuration - sdpa_backend = SDPBackend.FLASH_ATTENTION # For CP - # sdpa_backend = SDPBackend.MATH # For CP - global_batch_size = 8 # Desired global batch size - seq_len = 1024 # Sequence length - num_train_steps = 10000 # Number of training steps - LR = 1e-5 - model_name = "HuggingFaceTB/SmolLM2-1.7B" - # model_name = "unsloth/Llama-3.2-1B" - - CHECKPOINT_DIR = f"checkpoint_tp{tp_size}_dp{dp_size}_cp{cp_size}" - - # Initialize distributed environment - if "RANK" in os.environ and "WORLD_SIZE" in os.environ: - dist.init_process_group("nccl") - rank = dist.get_rank() - world_size = dist.get_world_size() - local_rank = int(os.environ["LOCAL_RANK"]) - torch.cuda.set_device(local_rank) - - assert world_size == tp_size * dp_size * cp_size, ( - f"World size ({world_size}) must equal TP size ({tp_size}) * DP size ({dp_size}) * CP size ({cp_size})" - ) - - mesh = torch.arange(world_size).reshape(dp_size, tp_size, cp_size) - world_mesh = DeviceMesh(device_type="cuda", mesh=mesh, mesh_dim_names=("dp", "tp", "cp")) - tp_mesh = world_mesh["tp"] - dp_mesh = world_mesh["dp"] - cp_mesh = world_mesh["cp"] - world_mesh["dp", "cp"]._flatten(mesh_dim_name="dp_cp") - logger.info(f"Created DeviceMesh: {world_mesh}") - logger.info( - f"Distributed setup - Rank: {rank}, World size: {world_size}, Local rank: {local_rank}, DP: {dp_mesh.get_local_rank()}, TP: {tp_mesh.get_local_rank()}, CP: {cp_mesh.get_local_rank()}" - ) - - if dist.get_rank() == 0: - wandb.init( - project="tp_dp_test", - config={ - "tp_size": tp_size, - "dp_size": dp_size, - "cp_size": cp_size, - "global_batch_size": global_batch_size, - "model_name": model_name, - "dataset": "roneneldan/TinyStories-1M", - "seq_len": seq_len, - "lr": LR, - "weight_decay": 0.1, - }, - name=f"llama_tp{tp_size}_dp{dp_size}_cp{cp_size}" - if model_name == "unsloth/Llama-3.2-1B" - else f"tp{tp_size}_dp{dp_size}_cp{cp_size}", - ) - logger.info(f"ignore_sanity_checks is set to: {ignore_sanity_checks}") - logger.info("Wandb initialized.") - # Log the current file to wandb - wandb.save("test_train.py") - - else: - logger.info("Running in non-distributed mode. DeviceMesh not applicable.") - rank = 0 - world_size = 1 - local_rank = 0 - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - wandb.init( - project="tp_dp_test", - config={ - "tp_size": 1, - "dp_size": 1, - "global_batch_size": global_batch_size, - "model_name": model_name, - "dataset": "roneneldan/TinyStories-1M", - "seq_len": seq_len, - }, - name="llama_tp1_dp1_nondist" if model_name == "unsloth/Llama-3.2-1B" else "tp1_dp1_nondist", - ) - logger.info("Wandb initialized for non-distributed run.") - - # Load model and tokenizer - logger.info(f"Loading model and tokenizer from {model_name}") - tokenizer = AutoTokenizer.from_pretrained(model_name) - if tokenizer.pad_token is None: - tokenizer.pad_token = tokenizer.eos_token - logger.info(f"Set pad_token to eos_token: {tokenizer.pad_token}") - - model = AutoModelForCausalLM.from_pretrained( - model_name, - device_mesh=tp_mesh if dist.is_initialized() else None, - tp_plan="auto", - dtype=torch.bfloat16, - ) - logger.info(f"Model loaded onto device mesh: {tp_mesh}") - - if dist.is_initialized(): - assert model.config.num_key_value_heads % tp_mesh.size() == 0, ( - f"num_key_value_heads={model.config.num_key_value_heads} must be divisible by tp_size={tp_mesh.size()}" - ) - device = torch.device(f"cuda:{local_rank}") - else: - model = model.to(device) - - logger.info(f"Using device: {device} for non-model tensors") - use_ddp = False - if dist.is_initialized() and dp_mesh.size() > 1: - # FSDP1 - model = FSDP(model, device_mesh=dp_mesh, sharding_strategy=ShardingStrategy.NO_SHARD) - # FSDP2 - # for transformer_block in model.model.layers: - # fully_shard(transformer_block, mesh=dp_mesh, reshard_after_forward=False) - # fully_shard(model.model, mesh=dp_mesh, reshard_after_forward=False) - # DDP - # replicate(model, device_mesh=dp_mesh, bucket_cap_mb=100) - # assert len(list(model.parameters()))>5, "No parameters found in model. Probably DDP/FSDP bug.." # TODO: we should be cautious abt using model.parameters() - use_ddp = True - - model.train() - assert len(list(model.parameters())) > 0, "No parameters found in model. Probably DDP bug.." - assert len([p for p in model.parameters() if p.requires_grad]) > 0, ( - "No gradients found in model. Probably DDP bug.." - ) - - if dist.is_initialized() and not ignore_sanity_checks: - # assert model is replicated across all dp - for name, param in model.named_parameters(): - sanity_check_tensor_sync(param, dp_mesh) - - # assert model is different across tp (only for sharded params) - for name, param in model.named_parameters(): - if isinstance(param, DTensor) and param.placements[0].is_shard(): - # Only check sharded parameters for non-sync across TP - sanity_check_tensor_sync(param, tp_mesh, not_sync=True) - elif isinstance(param, DTensor) and param.placements[0].is_replicate(): - # Replicated parameters should be the same across TP - sanity_check_tensor_sync(param, tp_mesh) - - # assert model is replicated across cp - for name, param in model.named_parameters(): - sanity_check_tensor_sync(param, cp_mesh) - - # Load and preprocess TinyStories dataset - logger.info("Loading TinyStories dataset...") - raw_dataset = load_dataset("roneneldan/TinyStories", split="train[:1%]") # Use 1% for faster testing - - def tokenize_function(examples): - # Tokenize the text without padding - tokenized_batch = tokenizer( - examples["text"], padding=False, truncation=True, max_length=seq_len, return_tensors=None - ) - # Set labels to be the same as input_ids for Causal LM - tokenized_batch["labels"] = tokenized_batch["input_ids"].copy() - return tokenized_batch - - tokenized_dataset = raw_dataset.map(tokenize_function, batched=True, remove_columns=["text"]) - logger.info(f"Dataset loaded and tokenized. Size: {len(tokenized_dataset)}") - - # Create packed sequences - def create_packed_sequences(examples): - # Flatten all sequences - all_tokens = [] - for input_ids in examples["input_ids"]: - all_tokens.extend(input_ids) - - # Split into sequences of seq_len + 1 (for input + label) - num_sequences = len(all_tokens) // (seq_len + 1) - packed_input_ids = [] - packed_labels = [] - - for i in range(num_sequences): - start_idx = i * (seq_len + 1) - end_idx = start_idx + (seq_len + 1) - # Get the full sequence - full_sequence = all_tokens[start_idx:end_idx] - # For input_ids, remove the last token - packed_input_ids.append(full_sequence[:-1]) - # For labels, remove the first token - packed_labels.append(full_sequence[1:]) - - return {"input_ids": packed_input_ids, "labels": packed_labels} - - # Apply packing to the dataset - packed_dataset = tokenized_dataset.map( - create_packed_sequences, - batched=True, - remove_columns=tokenized_dataset.column_names, - batch_size=1000, # Process in batches for efficiency - num_proc=60, - ) - logger.info(f"Dataset packed. New size: {len(packed_dataset)}") - - # Shuffle the packed dataset - packed_dataset = packed_dataset.shuffle(seed=42) - logger.info("Packed dataset shuffled") - - # Calculate local batch size - if dist.is_initialized(): - assert global_batch_size % dp_mesh.size() == 0, ( - f"Global batch size ({global_batch_size}) must be divisible by DP size ({dp_mesh.size()})" - ) - local_batch_size = global_batch_size // dp_mesh.size() - else: - local_batch_size = global_batch_size - - logger.info( - f"Global batch size: {global_batch_size}, DP size: {dp_size if dist.is_initialized() else 1}, Local batch size: {local_batch_size}" - ) - - # Simple collate function since sequences are already packed - def collate_fn(batch): - input_ids = torch.tensor([item["input_ids"] for item in batch], dtype=torch.long) - labels = torch.tensor([item["labels"] for item in batch], dtype=torch.long) - return {"input_ids": input_ids, "labels": labels} - - if dist.is_initialized(): - sampler = DistributedSampler( - packed_dataset, num_replicas=dp_mesh.size(), rank=dp_mesh.get_local_rank(), shuffle=False - ) - else: - sampler = None - - dataloader = DataLoader( - packed_dataset, - batch_size=local_batch_size, - sampler=sampler, - shuffle=False, - collate_fn=collate_fn, - ) - logger.info(f"DataLoader created. Distributed: {dist.is_initialized()}") - - optimizer = optim.AdamW(model.parameters(), lr=LR, weight_decay=0.1) - - # Training loop - logger.info(f"Starting training for {num_train_steps} steps...") - model.train() - step = 0 - while step < num_train_steps: - for batch in dataloader: - if step >= num_train_steps: - break # Exit loop if max steps reached - - # Move batch to appropriate device - batch = {k: v.to(device) for k, v in batch.items()} - - # Sanity checks for batch distribution (only if distributed) - if dist.is_initialized() and not ignore_sanity_checks: - # check batch is same across all tp - sanity_check_tensor_sync(batch["input_ids"], tp_mesh) - # check batch is different across dp - sanity_check_tensor_sync(batch["input_ids"], dp_mesh, not_sync=True) - - optimizer.zero_grad() - - # Add position_ids to batch before CP sharding - batch_size = batch["input_ids"].shape[0] - position_ids = torch.arange(0, seq_len, dtype=torch.long, device=device) - position_ids = position_ids.unsqueeze(0).expand(batch_size, -1) - batch["position_ids"] = position_ids - from torch.distributed.tensor.experimental._attention import _cp_options - - _cp_options.enable_load_balance = False - - with sdpa_kernel(sdpa_backend): # TODO: ideally move this to attention implementation - cp_context = ( - nullcontext() - if cp_mesh.size() == 1 - else context_parallel( - cp_mesh, - buffers=[ - batch["input_ids"], - batch["labels"], - batch["position_ids"], - ], # TODO: need to add attention mask - buffer_seq_dims=[1, 1, 1], - ) - ) - with cp_context: - # Pop labels from batch before model forward pass - labels = batch.pop("labels") - outputs = model(**batch) # [mbs, seq_len/cp] - loss = outputs.loss - logits = outputs.logits - - # Compute loss with shifted labels - loss = model.loss_function( - logits=logits, labels=None, shift_labels=labels, vocab_size=model.config.vocab_size - ) - - # Sanity checks for logits - if dist.is_initialized() and not ignore_sanity_checks: - # sanity_check_tensor_sync(logits, tp_mesh) # TODO: only true without sequence parallel - sanity_check_tensor_sync(logits, dp_mesh, not_sync=True) - sanity_check_tensor_sync(logits, cp_mesh, not_sync=True) - - loss.backward() - - # all reduce grads across dp_cp if applicable - all_reduce_grads(model, world_mesh, use_ddp=use_ddp) - - # Sanity checks for gradients (only if distributed) - if dist.is_initialized() and not ignore_sanity_checks: - # check grads are not same across all tp (for sharded grads) - for name, param in model.named_parameters(): - if param.grad is not None and isinstance(param.grad, DTensor): - if param.grad.placements[0].is_shard(): - sanity_check_tensor_sync(param.grad, tp_mesh, not_sync=True) - elif param.grad.placements[0].is_replicate(): - sanity_check_tensor_sync(param.grad, tp_mesh) - # check grads are same across dp - for name, param in model.named_parameters(): - if param.grad is not None and dp_mesh.size() > 1: - sanity_check_tensor_sync(param.grad, dp_mesh) - # check grads are same across cp - for name, param in model.named_parameters(): - if param.grad is not None and cp_mesh.size() > 1: - sanity_check_tensor_sync(param.grad, cp_mesh) - - # Calculate gradient norm and clip gradients - if hasattr(model, "clip_grad_norm_"): - # when using FSDP or DDP, model.parameters() doesn't work - gradnorm = model.clip_grad_norm_(max_norm=1.0, norm_type=2.0) - else: - assert len(list(model.parameters())) > 2, "No parameters found in model. Probably DDP bug.." - assert len([p for p in model.parameters() if p.requires_grad]) > 2, ( - "No gradients found in model. Probably DDP bug.." - ) - assert len([p for p in model.parameters() if p.grad is not None]) > 2, ( - "No gradients found in model. Probably DDP bug.." - ) - # only works with FSDP's NO_SHARD otherwise we should use FSDP's clip_grad_norm_ - gradnorm = clip_grad_norm_(model.parameters(), max_norm=1.0, norm_type=2.0, foreach=True) - - optimizer.step() - # Sanity checks for updated model parameters (only if distributed) - if dist.is_initialized() and not ignore_sanity_checks: - # check updated model is different across all tp (for sharded params) - for name, param in model.named_parameters(): - if isinstance(param, DTensor): - if param.placements[0].is_shard(): - sanity_check_tensor_sync(param, tp_mesh, not_sync=True) - elif param.placements[0].is_replicate(): - sanity_check_tensor_sync(param, tp_mesh) - # check updated model is same across dp - for name, param in model.named_parameters(): - sanity_check_tensor_sync(param, dp_mesh) - # check updated model is same across cp - for name, param in model.named_parameters(): - sanity_check_tensor_sync(param, cp_mesh) - - # allreduce loss across cp_dp before logging - if dist.is_initialized() and (cp_mesh.size() > 1 or dp_mesh.size() > 1): - dist.all_reduce(loss, group=world_mesh["dp_cp"].get_group(), op=dist.ReduceOp.AVG) - current_loss = loss.item() - - # Log loss and gradnorm to wandb (only on rank 0 of dp group) - if not dist.is_initialized() or dist.get_rank() == 0: - logger.info( - f"Step: {step} | GBS: {global_batch_size} | DP: {dp_mesh.size()} | TP: {tp_mesh.size()} | CP: {cp_mesh.size()} | Loss: {current_loss} | Gradnorm: {gradnorm} | lr: {LR}" - ) - wandb.log( - { - "train/loss": current_loss, - "train/gradnorm": gradnorm, - "step": step, - "lr": LR, - "GBS": global_batch_size, - } - ) - - step += 1 # Increment step count - - logger.info("Training loop finished.") - - # Save model using DCP (only if distributed) - if dist.is_initialized(): - state_dict = {"app": AppState(model, optimizer)} - dcp.save( - state_dict=state_dict, - checkpoint_id=CHECKPOINT_DIR, - ) - logger.info(f"Saved checkpoint to {CHECKPOINT_DIR}") - else: - # Fallback to regular save for non-distributed case - save_dir = "test_model_nondist" - model.save_pretrained(save_dir) - tokenizer.save_pretrained(save_dir) # Save tokenizer too - logger.info(f"Saved model to {save_dir}") - - # Example of loading the checkpoint (only if distributed) - if dist.is_initialized(): - # Create a new model instance - logger.info("Creating new model instance for verification") - new_model = AutoModelForCausalLM.from_pretrained( - model_name, - device_mesh=tp_mesh, - dtype=torch.bfloat16, # Use same dtype - ) - new_optimizer = optim.AdamW(new_model.parameters(), lr=LR) - - # Load checkpoint into new model - state_dict = {"app": AppState(new_model, new_optimizer)} - dcp.load( - state_dict=state_dict, - checkpoint_id=CHECKPOINT_DIR, - ) - logger.info("Loaded checkpoint into new model") - - # Verify model weights match - logger.info("Verifying model weights match...") - for (name1, param1), (name2, param2) in zip(model.named_parameters(), new_model.named_parameters()): - torch.testing.assert_close( - param1.to_local(), - param2.to_local(), - rtol=1e-3, - atol=1e-3, - msg=f"Weights mismatch in {name1} vs {name2}", - ) - - # Verify optimizer states match - logger.info("Verifying optimizer states match...") - for name1, state1 in optimizer.state_dict().items(): - state2 = new_optimizer.state_dict()[name1] - if name1 == "state": - # Compare state dictionaries for each parameter - for param_id, param_state1 in state1.items(): - param_state2 = state2[param_id] - # Compare each state component (step, exp_avg, exp_avg_sq) - for key, value1 in param_state1.items(): - value2 = param_state2[key] - if isinstance(value1, DTensor): - # Convert DTensors to local tensors for comparison - torch.testing.assert_close( - value1.to_local(), - value2.to_local(), - rtol=1e-5, - atol=1e-5, - msg=f"Optimizer state mismatch in state[{param_id}][{key}]", - ) - else: - torch.testing.assert_close( - value1, - value2, - rtol=1e-5, - atol=1e-5, - msg=f"Optimizer state mismatch in state[{param_id}][{key}]", - ) - elif name1 == "param_groups": - # Compare param_groups (excluding the actual params list) - for i, (group1, group2) in enumerate(zip(state1, state2)): - for key in group1: - if key != "params": # Skip comparing the params list - assert group1[key] == group2[key], f"Param group mismatch in param_groups[{i}][{key}]" - - # Run a forward pass with both models to verify outputs match - logger.info("Running forward pass verification...") - with torch.no_grad(): - # Use the last batch for verification - batch = {k: v.to(device) for k, v in batch.items()} # Ensure batch is on correct device - original_outputs = model(**batch) - new_outputs = new_model(**batch) - torch.testing.assert_close( - original_outputs.logits.to_local(), - new_outputs.logits.to_local(), - rtol=1e-3, - atol=1e-3, - msg="Model outputs do not match!", - ) # Increased tolerance slightly for bf16 - - # Clean up distributed environment and finish wandb run - if dist.is_initialized(): - dist.destroy_process_group() - logger.info("Cleaned up distributed process group") - # Finish wandb run on rank 0 - if dist.get_rank() == 0: - wandb.finish() - logger.info("Wandb run finished.") - else: - wandb.finish() - logger.info("Wandb run finished.") - - -def all_reduce_grads(model, world_mesh, use_ddp): - """All reduce gradients across dp_cp if applicable.""" - cp_mesh = world_mesh["cp"] - if use_ddp: - # DDP takes care of syncing grads - mesh = cp_mesh - else: - mesh = world_mesh["dp", "cp"]._flatten(mesh_dim_name="dp_cp") - if dist.is_initialized() and mesh.size() > 1: - for name, param in model.named_parameters(): - if param.grad is not None: - # Workaround for cross-mesh communication limitation with DTensor gradients - if isinstance(param.grad, DTensor): - local_grad = param.grad.to_local() - # Ensure grad requires grad for inplace modification checks (might not be needed) - # local_grad = local_grad.detach().requires_grad_(True) - torch.distributed.all_reduce(local_grad, op=torch.distributed.ReduceOp.SUM, group=mesh.get_group()) - local_grad = local_grad / mesh.size() - # Assign averaged grad back - need careful handling if DTensor structure is complex - # This simple assignment might work if the grad structure matches param structure - param.grad = DTensor.from_local( - local_grad, device_mesh=param.grad.device_mesh, placements=param.grad.placements - ) - else: - # Handle regular tensors if any exist (e.g. buffers not converted to DTensor) - torch.distributed.all_reduce(param.grad, op=torch.distributed.ReduceOp.AVG, group=mesh.get_group()) - - -class ContextParallelCollator: - """Collator for context parallel training that splits sequences into chunks.""" - - def __init__(self, cp_mesh: DeviceMesh | None = None): - self.cp_mesh = cp_mesh - - def __call__(self, batch: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: - batch = default_collate(batch) - if self.cp_mesh is not None and self.cp_mesh.size() > 1: - # Get sequence length from the input batch - seq_len = batch["input_ids"].shape[1] - assert seq_len % self.cp_mesh.size() == 0, ( - f"Sequence length {seq_len} must be divisible by CP size {self.cp_mesh.size()}" - ) - chunk_size = seq_len // self.cp_mesh.size() - cp_rank = self.cp_mesh.get_local_rank() - start_idx = cp_rank * chunk_size - end_idx = start_idx + chunk_size - - # Keep only the local chunk of the sequence - batch["input_ids"] = batch["input_ids"][:, start_idx:end_idx] - batch["attention_mask"] = batch["attention_mask"][:, start_idx:end_idx] - batch["labels"] = batch["labels"][:, start_idx:end_idx] - - return batch - - -class AppState(Stateful): - """Wrapper for checkpointing the Application State including model and optimizer.""" - - def __init__(self, model, optimizer=None): - self.model = model - self.optimizer = optimizer - - def state_dict(self): - model_state_dict, optimizer_state_dict = get_state_dict(self.model, self.optimizer) - return {"model": model_state_dict, "optim": optimizer_state_dict} - - def load_state_dict(self, state_dict): - set_state_dict( - self.model, self.optimizer, model_state_dict=state_dict["model"], optim_state_dict=state_dict["optim"] - ) - - -def sanity_check_tensor_sync( - tensor: torch.Tensor, mesh: DeviceMesh, rtol: float = 1e-4, atol: float = 1e-4, not_sync: bool = False -) -> None: - """ - Verify that a tensor is synchronized (or not synchronized) across all processes in the mesh's process group. - Handles both regular tensors and DTensors. - - Args: - tensor (torch.Tensor): The tensor to check for synchronization (can be DTensor) - mesh (DeviceMesh): The device mesh containing the process group - rtol (float): Relative tolerance for comparison - atol (float): Absolute tolerance for comparison - not_sync (bool): If True, asserts that tensors are NOT synchronized. If False, asserts they are synchronized. - """ - if not dist.is_initialized() or mesh.size() == 1: - return # No need to check in non-distributed mode - - # Get the process group from the mesh - pg = mesh.get_group() - - # Convert DTensor to local tensor if needed - if hasattr(tensor, "to_local"): - local_tensor = tensor.to_local() - else: - local_tensor = tensor - - # Gather tensors from all processes - world_size = dist.get_world_size(pg) - gathered_tensors = [torch.empty_like(local_tensor) for _ in range(world_size)] - dist.all_gather(gathered_tensors, local_tensor, group=pg) - - # Compare each tensor with the first one - for i in range(1, world_size): - try: - torch.testing.assert_close(gathered_tensors[0], gathered_tensors[i], rtol=rtol, atol=atol) - except AssertionError as e: - if not_sync: - continue - # # Add detailed debugging for logit synchronization issues - # print(f"\nLogit synchronization error between rank 0 and rank {i}:") - # print(f"Tensor shape: {gathered_tensors[0].shape}") - # print(f"Number of mismatched elements: {(gathered_tensors[0] != gathered_tensors[i]).sum()}") - # print(f"Percentage of mismatched elements: {((gathered_tensors[0] != gathered_tensors[i]).sum() / gathered_tensors[0].numel() * 100):.2f}%") - - # # Find the first few mismatches - # mismatches = torch.nonzero(gathered_tensors[0] != gathered_tensors[i]) - # print("\nFirst few mismatches:") - # for idx in mismatches[:5]: - # idx = tuple(idx.tolist()) - # print(f"Index {idx}:") - # print(f"Rank 0 value: {gathered_tensors[0][idx]}") - # print(f"Rank {i} value: {gathered_tensors[i][idx]}") - # print(f"Absolute difference: {abs(gathered_tensors[0][idx] - gathered_tensors[i][idx])}") - # print(f"Relative difference: {abs(gathered_tensors[0][idx] - gathered_tensors[i][idx]) / max(abs(gathered_tensors[0][idx]), abs(gathered_tensors[i][idx]))}") - - # # Check if differences are systematic (e.g., all positive or negative) - # diff = gathered_tensors[0] - gathered_tensors[i] - # print(f"\nDifference statistics:") - # print(f"Mean difference: {diff.mean()}") - # print(f"Std difference: {diff.std()}") - # print(f"Max positive difference: {diff.max()}") - # print(f"Max negative difference: {diff.min()}") - raise e - - -def clip_grad_norm_( - parameters: Iterable[torch.Tensor], - max_norm: float, - norm_type: float = 2.0, - error_if_nonfinite: bool = False, - foreach: bool | None = None, -) -> torch.Tensor: - """ - Clip the gradient norm of an iterable of parameters. - """ - # Filter out parameters with no gradients - parameters = [p for p in parameters if p.grad is not None] - assert len(parameters) > 0, "No parameters with gradients found" - - # Calculate total norm - if norm_type == float("inf"): - total_norm = max(p.grad.detach().abs().max() for p in parameters) - else: - total_norm = torch.norm(torch.stack([torch.norm(p.grad.detach(), norm_type) for p in parameters]), norm_type) - - # Convert DTensor to local tensor if needed - if isinstance(total_norm, DTensor): - total_norm = total_norm.full_tensor() - - # Clip gradients - clip_coef = max_norm / (total_norm + 1e-6) - if clip_coef < 1: - for p in parameters: - p.grad.detach().mul_(clip_coef) - - return total_norm - - -def check_params_sync(model_params, original_params): - """ - Check if original_params are being updated in sync with model parameters. - - Args: - model_params: Iterator of model parameters after update - original_params: List of original parameters before DDP wrapping - """ - for mp, op in zip(model_params, original_params): - if isinstance(mp, DTensor): - mp = mp.to_local() - if isinstance(op, DTensor): - op = op.to_local() - if not torch.allclose(mp.data, op.data, rtol=0, atol=0): - raise RuntimeError(f"Parameters out of sync: model param {mp.data} != original param {op.data}") - return True - - -def get_parameters(model: nn.Module) -> Iterable[torch.Tensor]: - """ - Get all parameters from a model by iterating over its modules. - This is an alternative to model.parameters() that works with DTensor models. - - Args: - model (nn.Module): The model to get parameters from - - Returns: - Iterable[torch.Tensor]: An iterator over all parameters in the model - """ - for module in model._modules.values(): - # Look for parameters in module attributes - for attr in module.__dict__.values(): - if isinstance(attr, torch.Tensor) and attr.requires_grad: - yield attr - # Recursively get parameters from submodules - yield from get_parameters(module) - - -def update_model_parameters(model: nn.Module) -> None: - """ - Update model._parameters using named_modules() to ensure all parameters are properly tracked. - - Args: - model (nn.Module): The model to update parameters for - """ - # Clear existing parameters - model._parameters = {} - - # Add parameters from named_modules - for name, module in model.named_modules(): - # Skip the root module itself - if name == "": - continue - - # Get the parameter name by removing 'module.' prefix if it exists - param_name = name.replace("module.", "") - - # Add weight and bias parameters if they exist - if hasattr(module, "weight") and module.weight is not None: - model._parameters[f"{param_name}.weight"] = module.weight - if hasattr(module, "bias") and module.bias is not None: - model._parameters[f"{param_name}.bias"] = module.bias - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/README.md b/examples/pytorch/README.md deleted file mode 100644 index 2712ee047d50..000000000000 --- a/examples/pytorch/README.md +++ /dev/null @@ -1,293 +0,0 @@ - - -# Examples - -This folder contains actively maintained examples of use of 🤗 Transformers using the PyTorch backend, organized by ML task. - -## The Big Table of Tasks - -Here is the list of all our examples: -- with information on whether they are **built on top of `Trainer`** (if not, they still work, they might - just lack some features), -- whether or not they have a version using the [🤗 Accelerate](https://github.com/huggingface/accelerate) library. -- whether or not they leverage the [🤗 Datasets](https://github.com/huggingface/datasets) library. -- links to **Colab notebooks** to walk through the scripts and run them easily, - - -| Task | Example datasets | Trainer support | 🤗 Accelerate | 🤗 Datasets | Colab -|---|---|:---:|:---:|:---:|:---:| -| [**`language-modeling`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/language-modeling) | [WikiText-2](https://huggingface.co/datasets/Salesforce/wikitext) | ✅ | ✅ | ✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb) -| [**`multiple-choice`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/multiple-choice) | [SWAG](https://huggingface.co/datasets/allenai/swag) | ✅ | ✅ | ✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb) -| [**`question-answering`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/question-answering) | [SQuAD](https://huggingface.co/datasets/rajpurkar/squad) | ✅ | ✅ | ✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb) -| [**`summarization`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/summarization) | [XSum](https://huggingface.co/datasets/EdinburghNLP/xsum) | ✅ | ✅ | ✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization.ipynb) -| [**`text-classification`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-classification) | [GLUE](https://huggingface.co/datasets/nyu-mll/glue) | ✅ | ✅ | ✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb) -| [**`text-generation`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-generation) | - | n/a | - | - | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/blog/blob/main/notebooks/02_how_to_generate.ipynb) -| [**`token-classification`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/token-classification) | [CoNLL NER](https://huggingface.co/datasets/tomaarsen/conll2003) | ✅ |✅ | ✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb) -| [**`translation`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/translation) | [WMT](https://huggingface.co/datasets/wmt/wmt17) | ✅ | ✅ |✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb) -| [**`speech-recognition`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/speech-recognition) | [TIMIT](https://huggingface.co/datasets/timit-asr/timit_asr) | ✅ | - |✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/speech_recognition.ipynb) -| [**`multi-lingual speech-recognition`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/speech-recognition) | [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice) | ✅ | - |✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multi_lingual_speech_recognition.ipynb) -| [**`audio-classification`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/audio-classification) | [SUPERB KS](https://huggingface.co/datasets/s3prl/superb) | ✅ | - |✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb) -| [**`image-pretraining`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining) | [ImageNet-1k](https://huggingface.co/datasets/ILSVRC/imagenet-1k) | ✅ | - |✅ | / -| [**`image-classification`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-classification) | [CIFAR-10](https://huggingface.co/datasets/uoft-cs/cifar10) | ✅ | ✅ |✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb) -| [**`semantic-segmentation`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/semantic-segmentation) | [SCENE_PARSE_150](https://huggingface.co/datasets/merve/scene_parse_150) | ✅ | ✅ |✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/semantic_segmentation.ipynb) -| [**`object-detection`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/object-detection) | [CPPE-5](https://huggingface.co/datasets/rishitdagli/cppe-5) | ✅ | ✅ |✅ | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/notebooks/blob/main/transformers_doc/en/pytorch/object_detection.ipynb) -| [**`instance-segmentation`**](https://github.com/huggingface/transformers/tree/main/examples/pytorch/instance-segmentation) | [ADE20K sample](https://huggingface.co/datasets/qubvel-hf/ade20k-mini) | ✅ | ✅ |✅ | - - -## Running quick tests - -Most examples are equipped with a mechanism to truncate the number of dataset samples to the desired length. This is useful for debugging purposes, for example to quickly check that all stages of the programs can complete, before running the same setup on the full dataset which may take hours to complete. - -For example here is how to truncate all three splits to just 50 samples each: -```bash -examples/pytorch/token-classification/run_ner.py \ ---max_train_samples 50 \ ---max_eval_samples 50 \ ---max_predict_samples 50 \ -[...] -``` - -Most example scripts should have the first two command line arguments and some have the third one. You can quickly check if a given example supports any of these by passing a `-h` option, e.g.: -```bash -token-classification/run_ner.py -h -``` - -## Resuming training - -You can resume training from a previous checkpoint like this: - -1. Pass `--resume_from_checkpoint path_to_a_specific_checkpoint` to resume training from that checkpoint folder. - -Should you want to turn an example into a notebook where you'd no longer have access to the command -line, 🤗 Trainer supports resuming from a checkpoint via `trainer.train(resume_from_checkpoint)`. - -1. If `resume_from_checkpoint` is `True` it will look for the last checkpoint in the value of `output_dir` passed via `TrainingArguments`. -2. If `resume_from_checkpoint` is a path to a specific checkpoint it will use that saved checkpoint folder to resume the training from. - - -### Upload the trained/fine-tuned model to the Hub - -All the example scripts support automatic upload of your final model to the [Model Hub](https://huggingface.co/models) by adding a `--push_to_hub` argument. It will then create a repository with your username slash the name of the folder you are using as `output_dir`. For instance, `"sgugger/test-mrpc"` if your username is `sgugger` and you are working in the folder `~/tmp/test-mrpc`. - -To specify a given repository name, use the `--hub_model_id` argument. You will need to specify the whole repository name (including your username), for instance `--hub_model_id sgugger/finetuned-bert-mrpc`. To upload to an organization you are a member of, just use the name of that organization instead of your username: `--hub_model_id huggingface/finetuned-bert-mrpc`. - -A few notes on this integration: - -- you will need to be logged in to the Hugging Face website locally for it to work, the easiest way to achieve this is to run `hf auth login` and then type your username and password when prompted. You can also pass along your authentication token with the `--hub_token` argument. -- the `output_dir` you pick will either need to be a new folder or a local clone of the distant repository you are using. - -## Distributed training and mixed precision - -All the PyTorch scripts mentioned above work out of the box with distributed training and mixed precision, thanks to -the [Trainer API](https://huggingface.co/transformers/main_classes/trainer.html). To launch one of them on _n_ GPUs, -use the following command: - -```bash -torchrun \ - --nproc_per_node number_of_gpu_you_have path_to_script.py \ - --all_arguments_of_the_script -``` - -As an example, here is how you would fine-tune the BERT large model (with whole word masking) on the text -classification MNLI task using the `run_glue` script, with 8 GPUs: - -```bash -torchrun \ - --nproc_per_node 8 text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-large-uncased-whole-word-masking \ - --task_name mnli \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 8 \ - --learning_rate 2e-5 \ - --num_train_epochs 3.0 \ - --output_dir /tmp/mnli_output/ -``` - -If you have a GPU with mixed precision capabilities (architecture Pascal or more recent), you can use mixed precision -training with PyTorch 1.6.0 or latest. Just add the flag `--fp16` to your command launching one of the scripts mentioned above! - -Using mixed precision training usually results in 2x-speedup for training with the same final results (as shown in -[this table](https://github.com/huggingface/transformers/tree/main/examples/text-classification#mixed-precision-training) -for text classification). - -## Running on TPUs - -When using Tensorflow, TPUs are supported out of the box as a `tf.distribute.Strategy`. - -When using PyTorch, we support TPUs thanks to `pytorch/xla`. For more context and information on how to setup your TPU environment refer to Google's documentation and to the -very detailed [pytorch/xla README](https://github.com/pytorch/xla/blob/master/README.md). - -In this repo, we provide a very simple launcher script named -[xla_spawn.py](https://github.com/huggingface/transformers/tree/main/examples/pytorch/xla_spawn.py) that lets you run our -example scripts on multiple TPU cores without any boilerplate. Just pass a `--num_cores` flag to this script, then your -regular training script with its arguments (this is similar to the `torch.distributed.launch` helper for -`torch.distributed`): - -```bash -python xla_spawn.py --num_cores num_tpu_you_have \ - path_to_script.py \ - --all_arguments_of_the_script -``` - -As an example, here is how you would fine-tune the BERT large model (with whole word masking) on the text -classification MNLI task using the `run_glue` script, with 8 TPUs (from this folder): - -```bash -python xla_spawn.py --num_cores 8 \ - text-classification/run_glue.py \ - --model_name_or_path google-bert/bert-large-uncased-whole-word-masking \ - --task_name mnli \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 8 \ - --learning_rate 2e-5 \ - --num_train_epochs 3.0 \ - --output_dir /tmp/mnli_output/ -``` - -## Using Accelerate - -Most PyTorch example scripts have a version using the [🤗 Accelerate](https://github.com/huggingface/accelerate) library -that exposes the training loop so it's easy for you to customize or tweak them to your needs. They all require you to -install `accelerate` with the latest development version - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -Then you can easily launch any of the scripts by running - -```bash -accelerate config -``` - -and reply to the questions asked. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -accelerate launch path_to_script.py --args_to_script -``` - -## Logging & Experiment tracking - -You can easily log and monitor your runs code. The following are currently supported: - -* [TensorBoard](https://www.tensorflow.org/tensorboard) -* [Weights & Biases](https://docs.wandb.ai/integrations/huggingface) -* [Comet ML](https://www.comet.com/docs/v2/integrations/ml-frameworks/transformers/) -* [ClearML](https://clear.ml/docs/latest/docs/getting_started/ds/ds_first_steps) -* [DVCLive](https://dvc.org/doc/dvclive/ml-frameworks/huggingface) - -### Weights & Biases - -To use Weights & Biases, install the wandb package with: - -```bash -pip install wandb -``` - -Then log in the command line: - -```bash -wandb login -``` - -If you are in Jupyter or Colab, you should login with: - -```python -import wandb -wandb.login() -``` - -To enable logging to W&B, include `"wandb"` in the `report_to` of your `TrainingArguments` or script. Or just pass along `--report_to_all` if you have `wandb` installed. - -Whenever you use the `Trainer` class, your losses, evaluation metrics, model topology and gradients will automatically be logged. - -Advanced configuration is possible by setting environment variables: - -| Environment Variable | Value | -|---|---| -| WANDB_LOG_MODEL | Log the model as artifact (log the model as artifact at the end of training) (`false` by default) | -| WANDB_WATCH | one of `gradients` (default) to log histograms of gradients, `all` to log histograms of both gradients and parameters, or `false` for no histogram logging | -| WANDB_PROJECT | Organize runs by project | - -Set run names with `run_name` argument present in scripts or as part of `TrainingArguments`. - -Additional configuration options are available through generic [wandb environment variables](https://docs.wandb.com/library/environment-variables). - -Refer to related [documentation & examples](https://docs.wandb.ai/integrations/huggingface). - -### Comet - -To use `comet_ml`, install the Python package with: - -```bash -pip install comet_ml -``` - -or if in a Conda environment: - -```bash -conda install -c comet_ml -c anaconda -c conda-forge comet_ml -``` - -### ClearML - -To use ClearML, install the clearml package with: - -```bash -pip install clearml -``` - -Then [create new credentials]() from the ClearML Server. You can get a free hosted server [here]() or [self-host your own]()! -After creating your new credentials, you can either copy the local snippet which you can paste after running: - -```bash -clearml-init -``` - -Or you can copy the jupyter snippet if you are in Jupyter or Colab: - -```python -%env CLEARML_WEB_HOST=https://app.clear.ml -%env CLEARML_API_HOST=https://api.clear.ml -%env CLEARML_FILES_HOST=https://files.clear.ml -%env CLEARML_API_ACCESS_KEY=*** -%env CLEARML_API_SECRET_KEY=*** -``` - - -To enable logging to ClearML, include `"clearml"` in the `report_to` of your `TrainingArguments` or script. Or just pass along `--report_to all` if you have `clearml` already installed. - -Advanced configuration is possible by setting environment variables: - -| Environment Variable | Value | -|---|---| -| CLEARML_PROJECT | Name of the project in ClearML. (default: `"HuggingFace Transformers"`) | -| CLEARML_TASK | Name of the task in ClearML. (default: `"Trainer"`) | - -Additional configuration options are available through generic [clearml environment variables](https://clear.ml/docs/latest/docs/configs/env_vars). diff --git a/examples/pytorch/_tests_requirements.txt b/examples/pytorch/_tests_requirements.txt deleted file mode 100644 index 210f560740b3..000000000000 --- a/examples/pytorch/_tests_requirements.txt +++ /dev/null @@ -1,33 +0,0 @@ -tensorboard -scikit-learn -seqeval -psutil -sacrebleu >= 1.4.12 -git+https://github.com/huggingface/accelerate@main#egg=accelerate -rouge-score -tensorflow_datasets -matplotlib -git-python==1.0.3 -faiss-cpu -streamlit -elasticsearch -nltk -pandas -datasets >= 1.13.3 -fire -pytest -conllu -sentencepiece != 0.1.92 -protobuf -torch -torchvision -torchaudio -torchcodec -jiwer -librosa -evaluate >= 0.2.0 -timm -albumentations >= 1.4.16 -torchmetrics -pycocotools -Pillow>=10.0.1,<=15.0 diff --git a/examples/pytorch/audio-classification/README.md b/examples/pytorch/audio-classification/README.md deleted file mode 100644 index 6802e9263715..000000000000 --- a/examples/pytorch/audio-classification/README.md +++ /dev/null @@ -1,146 +0,0 @@ - - -# Audio classification examples - -The following examples showcase how to fine-tune `Wav2Vec2` for audio classification using PyTorch. - -Speech recognition models that have been pretrained in unsupervised fashion on audio data alone, -*e.g.* [Wav2Vec2](https://huggingface.co/transformers/main/model_doc/wav2vec2.html), -[HuBERT](https://huggingface.co/transformers/main/model_doc/hubert.html), -[XLSR-Wav2Vec2](https://huggingface.co/transformers/main/model_doc/xlsr_wav2vec2.html), have shown to require only -very little annotated data to yield good performance on speech classification datasets. - -## Single-GPU - -The following command shows how to fine-tune [wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base) on the 🗣️ [Keyword Spotting subset](https://huggingface.co/datasets/s3prl/superb#ks) of the SUPERB dataset. - -```bash -python run_audio_classification.py \ - --model_name_or_path facebook/wav2vec2-base \ - --dataset_name s3prl/superb \ - --dataset_config_name ks \ - --output_dir wav2vec2-base-ft-keyword-spotting \ - --remove_unused_columns False \ - --do_train \ - --do_eval \ - --fp16 \ - --learning_rate 3e-5 \ - --max_length_seconds 1 \ - --attention_mask False \ - --warmup_steps 0.1 \ - --num_train_epochs 5 \ - --per_device_train_batch_size 32 \ - --gradient_accumulation_steps 4 \ - --per_device_eval_batch_size 32 \ - --dataloader_num_workers 4 \ - --logging_strategy steps \ - --logging_steps 10 \ - --eval_strategy epoch \ - --save_strategy epoch \ - --load_best_model_at_end True \ - --metric_for_best_model accuracy \ - --save_total_limit 3 \ - --seed 0 \ - --push_to_hub -``` - -On a single V100 GPU (16GB), this script should run in ~14 minutes and yield accuracy of **98.26%**. - -👀 See the results here: [anton-l/wav2vec2-base-ft-keyword-spotting](https://huggingface.co/anton-l/wav2vec2-base-ft-keyword-spotting) - -> If your model classification head dimensions do not fit the number of labels in the dataset, you can specify `--ignore_mismatched_sizes` to adapt it. - -## Multi-GPU - -The following command shows how to fine-tune [wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base) for 🌎 **Language Identification** on the [CommonLanguage dataset](https://huggingface.co/datasets/regisss/common_language). - -```bash -python run_audio_classification.py \ - --model_name_or_path facebook/wav2vec2-base \ - --dataset_name regisss/common_language \ - --audio_column_name audio \ - --label_column_name language \ - --output_dir wav2vec2-base-lang-id \ - --remove_unused_columns False \ - --do_train \ - --do_eval \ - --fp16 \ - --learning_rate 3e-4 \ - --max_length_seconds 16 \ - --attention_mask False \ - --warmup_steps 0.1 \ - --num_train_epochs 10 \ - --per_device_train_batch_size 8 \ - --gradient_accumulation_steps 4 \ - --per_device_eval_batch_size 1 \ - --dataloader_num_workers 8 \ - --logging_strategy steps \ - --logging_steps 10 \ - --eval_strategy epoch \ - --save_strategy epoch \ - --load_best_model_at_end True \ - --metric_for_best_model accuracy \ - --save_total_limit 3 \ - --seed 0 \ - --push_to_hub -``` - -On 4 V100 GPUs (16GB), this script should run in ~1 hour and yield accuracy of **79.45%**. - -👀 See the results here: [anton-l/wav2vec2-base-lang-id](https://huggingface.co/anton-l/wav2vec2-base-lang-id) - -## Sharing your model on 🤗 Hub - -0. If you haven't already, [sign up](https://huggingface.co/join) for a 🤗 account - -1. Make sure you have `git-lfs` installed and git set up. - -```bash -$ apt install git-lfs -``` - -2. Log in with your HuggingFace account credentials using `hf` - -```bash -$ hf auth login -# ...follow the prompts -``` - -3. When running the script, pass the following arguments: - -```bash -python run_audio_classification.py \ - --push_to_hub \ - --hub_model_id \ - ... -``` - -### Examples - -The following table shows a couple of demonstration fine-tuning runs. -It has been verified that the script works for the following datasets: - -- [SUPERB Keyword Spotting](https://huggingface.co/datasets/s3prl/superb#ks) -- [Common Language](https://huggingface.co/datasets/regisss/common_language) - -| Dataset | Pretrained Model | # transformer layers | Accuracy on eval | GPU setup | Training time | Fine-tuned Model & Logs | -|---------|------------------|----------------------|------------------|-----------|---------------|--------------------------| -| Keyword Spotting | [ntu-spml/distilhubert](https://huggingface.co/ntu-spml/distilhubert) | 2 | 0.9706 | 1 V100 GPU | 11min | [here](https://huggingface.co/anton-l/distilhubert-ft-keyword-spotting) | -| Keyword Spotting | [facebook/wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base) | 12 | 0.9826 | 1 V100 GPU | 14min | [here](https://huggingface.co/anton-l/wav2vec2-base-ft-keyword-spotting) | -| Keyword Spotting | [facebook/hubert-base-ls960](https://huggingface.co/facebook/hubert-base-ls960) | 12 | 0.9819 | 1 V100 GPU | 14min | [here](https://huggingface.co/anton-l/hubert-base-ft-keyword-spotting) | -| Keyword Spotting | [asapp/sew-mid-100k](https://huggingface.co/asapp/sew-mid-100k) | 24 | 0.9757 | 1 V100 GPU | 15min | [here](https://huggingface.co/anton-l/sew-mid-100k-ft-keyword-spotting) | -| Common Language | [facebook/wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base) | 12 | 0.7945 | 4 V100 GPUs | 1h10m | [here](https://huggingface.co/anton-l/wav2vec2-base-lang-id) | diff --git a/examples/pytorch/audio-classification/requirements.txt b/examples/pytorch/audio-classification/requirements.txt deleted file mode 100644 index d23b9b86f190..000000000000 --- a/examples/pytorch/audio-classification/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -datasets[audio]>=1.14.0 -evaluate -librosa -torchaudio -torch>=1.6 diff --git a/examples/pytorch/audio-classification/run_audio_classification.py b/examples/pytorch/audio-classification/run_audio_classification.py deleted file mode 100644 index 844cbe7fb795..000000000000 --- a/examples/pytorch/audio-classification/run_audio_classification.py +++ /dev/null @@ -1,401 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "datasets[audio]>=1.14.0", -# "evaluate", -# "librosa", -# "torchaudio", -# "torch>=1.6", -# ] -# /// - -import logging -import os -import sys -from dataclasses import dataclass, field -from random import randint - -import datasets -import evaluate -import numpy as np -from datasets import DatasetDict, load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoFeatureExtractor, - AutoModelForAudioClassification, - HfArgumentParser, - Trainer, - TrainingArguments, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.14.0", "To fix: pip install -r examples/pytorch/audio-classification/requirements.txt") - - -def random_subsample(wav: np.ndarray, max_length: float, sample_rate: int = 16000): - """Randomly sample chunks of `max_length` seconds from the input audio""" - sample_length = int(round(sample_rate * max_length)) - if len(wav) <= sample_length: - return wav - random_offset = randint(0, len(wav) - sample_length - 1) - return wav[random_offset : random_offset + sample_length] - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - Using `HfArgumentParser` we can turn this class - into argparse arguments to be able to specify them on - the command line. - """ - - dataset_name: str | None = field(default=None, metadata={"help": "Name of a dataset from the datasets package"}) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_file: str | None = field( - default=None, metadata={"help": "A file containing the training audio paths and labels."} - ) - eval_file: str | None = field( - default=None, metadata={"help": "A file containing the validation audio paths and labels."} - ) - train_split_name: str = field( - default="train", - metadata={ - "help": "The name of the training data set split to use (via the datasets library). Defaults to 'train'" - }, - ) - eval_split_name: str = field( - default="validation", - metadata={ - "help": ( - "The name of the training data set split to use (via the datasets library). Defaults to 'validation'" - ) - }, - ) - audio_column_name: str = field( - default="audio", - metadata={"help": "The name of the dataset column containing the audio data. Defaults to 'audio'"}, - ) - label_column_name: str = field( - default="label", metadata={"help": "The name of the dataset column containing the labels. Defaults to 'label'"} - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_length_seconds: float = field( - default=20, - metadata={"help": "Audio clips will be randomly cut to this length during training if the value is set."}, - ) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - default="facebook/wav2vec2-base", - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from the Hub"} - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - feature_extractor_name: str | None = field(default=None, metadata={"help": "Name or path of preprocessor config."}) - freeze_feature_encoder: bool = field( - default=True, metadata={"help": "Whether to freeze the feature encoder layers of the model."} - ) - attention_mask: bool = field( - default=True, metadata={"help": "Whether to generate an attention mask in the feature extractor."} - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - ignore_mismatched_sizes: bool = field( - default=False, - metadata={"help": "Will enable to load a pretrained model whose head dimensions are different."}, - ) - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Initialize our dataset and prepare it for the audio classification task. - raw_datasets = DatasetDict() - raw_datasets["train"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=data_args.train_split_name, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - raw_datasets["eval"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=data_args.eval_split_name, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - if data_args.audio_column_name not in raw_datasets["train"].column_names: - raise ValueError( - f"--audio_column_name {data_args.audio_column_name} not found in dataset '{data_args.dataset_name}'. " - "Make sure to set `--audio_column_name` to the correct audio column - one of " - f"{', '.join(raw_datasets['train'].column_names)}." - ) - - if data_args.label_column_name not in raw_datasets["train"].column_names: - raise ValueError( - f"--label_column_name {data_args.label_column_name} not found in dataset '{data_args.dataset_name}'. " - "Make sure to set `--label_column_name` to the correct text column - one of " - f"{', '.join(raw_datasets['train'].column_names)}." - ) - - # Setting `return_attention_mask=True` is the way to get a correctly masked mean-pooling over - # transformer outputs in the classifier, but it doesn't always lead to better accuracy - feature_extractor = AutoFeatureExtractor.from_pretrained( - model_args.feature_extractor_name or model_args.model_name_or_path, - return_attention_mask=model_args.attention_mask, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # `datasets` takes care of automatically loading and resampling the audio, - # so we just need to set the correct target sampling rate. - raw_datasets = raw_datasets.cast_column( - data_args.audio_column_name, datasets.features.Audio(sampling_rate=feature_extractor.sampling_rate) - ) - - model_input_name = feature_extractor.model_input_names[0] - - def train_transforms(batch): - """Apply train_transforms across a batch.""" - subsampled_wavs = [] - for audio in batch[data_args.audio_column_name]: - wav = random_subsample( - audio["array"], max_length=data_args.max_length_seconds, sample_rate=feature_extractor.sampling_rate - ) - subsampled_wavs.append(wav) - inputs = feature_extractor(subsampled_wavs, sampling_rate=feature_extractor.sampling_rate) - output_batch = {model_input_name: inputs.get(model_input_name)} - output_batch["labels"] = list(batch[data_args.label_column_name]) - - return output_batch - - def val_transforms(batch): - """Apply val_transforms across a batch.""" - wavs = [audio["array"] for audio in batch[data_args.audio_column_name]] - inputs = feature_extractor(wavs, sampling_rate=feature_extractor.sampling_rate) - output_batch = {model_input_name: inputs.get(model_input_name)} - output_batch["labels"] = list(batch[data_args.label_column_name]) - - return output_batch - - # Prepare label mappings. - # We'll include these in the model's config to get human readable labels in the Inference API. - labels = raw_datasets["train"].features[data_args.label_column_name].names - label2id, id2label = {}, {} - for i, label in enumerate(labels): - label2id[label] = str(i) - id2label[str(i)] = label - - # Load the accuracy metric from the datasets package - metric = evaluate.load("accuracy", cache_dir=model_args.cache_dir) - - # Define our compute_metrics function. It takes an `EvalPrediction` object (a namedtuple with - # `predictions` and `label_ids` fields) and has to return a dictionary string to float. - def compute_metrics(eval_pred): - """Computes accuracy on a batch of predictions""" - predictions = np.argmax(eval_pred.predictions, axis=1) - return metric.compute(predictions=predictions, references=eval_pred.label_ids) - - config = AutoConfig.from_pretrained( - model_args.config_name or model_args.model_name_or_path, - num_labels=len(labels), - label2id=label2id, - id2label=id2label, - finetuning_task="audio-classification", - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForAudioClassification.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ignore_mismatched_sizes=model_args.ignore_mismatched_sizes, - ) - - # freeze the convolutional waveform encoder - if model_args.freeze_feature_encoder: - model.freeze_feature_encoder() - - if training_args.do_train: - if data_args.max_train_samples is not None: - raw_datasets["train"] = ( - raw_datasets["train"].shuffle(seed=training_args.seed).select(range(data_args.max_train_samples)) - ) - # Set the training transforms - raw_datasets["train"].set_transform(train_transforms, output_all_columns=False) - - if training_args.do_eval: - if data_args.max_eval_samples is not None: - raw_datasets["eval"] = ( - raw_datasets["eval"].shuffle(seed=training_args.seed).select(range(data_args.max_eval_samples)) - ) - # Set the validation transforms - raw_datasets["eval"].set_transform(val_transforms, output_all_columns=False) - - # Initialize our trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=raw_datasets["train"] if training_args.do_train else None, - eval_dataset=raw_datasets["eval"] if training_args.do_eval else None, - compute_metrics=compute_metrics, - processing_class=feature_extractor, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - trainer.log_metrics("train", train_result.metrics) - trainer.save_metrics("train", train_result.metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - metrics = trainer.evaluate() - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Write model card and (optionally) push to hub - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "tasks": "audio-classification", - "dataset": data_args.dataset_name, - "tags": ["audio-classification"], - } - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/conftest.py b/examples/pytorch/conftest.py deleted file mode 100644 index 7d7a38084f9b..000000000000 --- a/examples/pytorch/conftest.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# tests directory-specific settings - this file is run automatically -# by pytest before any tests are run - -import sys -import warnings -from os.path import abspath, dirname, join - - -# allow having multiple repository checkouts and not needing to remember to rerun -# `pip install -e '.[dev]'` when switching between checkouts and running tests. -git_repo_path = abspath(join(dirname(dirname(dirname(__file__))), "src")) -sys.path.insert(1, git_repo_path) -tests_path = abspath(join(dirname(dirname(dirname(__file__))), "tests")) -sys.path.insert(1, tests_path) - - -# silence FutureWarning warnings in tests since often we can't act on them until -# they become normal warnings - i.e. the tests still need to test the current functionality -warnings.simplefilter(action="ignore", category=FutureWarning) - - -def pytest_addoption(parser): - from transformers.testing_utils import pytest_addoption_shared - - pytest_addoption_shared(parser) - - -def pytest_terminal_summary(terminalreporter): - from transformers.testing_utils import pytest_terminal_summary_main - - make_reports = terminalreporter.config.getoption("--make-reports") - if make_reports: - pytest_terminal_summary_main(terminalreporter, id=make_reports) diff --git a/examples/pytorch/context_parallel.py b/examples/pytorch/context_parallel.py deleted file mode 100644 index d24ff45873db..000000000000 --- a/examples/pytorch/context_parallel.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2024 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import os - -import torch -import torch.distributed as dist -from torch.distributed.device_mesh import init_device_mesh -from torch.distributed.tensor.experimental import context_parallel -from torch.nn.attention import SDPBackend, sdpa_kernel -from torch.nn.parallel import DistributedDataParallel as DDP - -from transformers import AutoModelForCausalLM -from transformers.loss.loss_utils import ForCausalLMLoss - - -world_size = int(os.environ.get("WORLD_SIZE", "1")) -cp_mesh = init_device_mesh("cuda", (world_size,)) -rank = torch.distributed.get_node_local_rank() - -device = "cuda" -dtype = torch.bfloat16 -sdpa_backend = SDPBackend.FLASH_ATTENTION - -# prepare inputs -batch_size = 1 -seq_len = 128 - -input_ids = torch.randint(low=8, high=64, size=(batch_size, seq_len), device=device) - -ignore_index = -100 -# When using CP, we need to use `shift_labels` -shift_labels = torch.nn.functional.pad(input_ids, (0, 1), value=ignore_index) -shift_labels = shift_labels[..., 1:].contiguous() - -position_ids = ( - torch.cumsum(torch.ones(size=input_ids.size(), dtype=input_ids.dtype, device=input_ids.device), dim=1) - 1 -) - -# sync input as they are created randomly -dist.broadcast(input_ids, src=0) -dist.broadcast(shift_labels, src=0) -dist.broadcast(position_ids, src=0) - -# model and optimizer -repo_id = "Qwen/Qwen2.5-Coder-0.5B-Instruct" -model = AutoModelForCausalLM.from_pretrained(repo_id, dtype=dtype, device_map=device) -optimizer = torch.optim.Adam(model.parameters(), lr=1e-5) - -model.train() -model.zero_grad() -optimizer.zero_grad() - -# For loss -vocab_size = model.config.vocab_size - -# so training could be synced -model = DDP(model, device_ids=[rank]) - -# prepare for CP -buffers = (input_ids, shift_labels, position_ids) -buffer_seq_dims = (1, 1, 1) -# `no_restore_buffers=set(buffers)` is required if `loss.backward` is outside `context_parallel`. -# no_restore_buffers = set(buffers) -no_restore_buffers = None - -# run with CP -with sdpa_kernel(sdpa_backend): - with context_parallel( - cp_mesh, - buffers=buffers, - buffer_seq_dims=buffer_seq_dims, - no_restore_buffers=no_restore_buffers, - ): - outputs = model(input_ids, shift_labels=shift_labels, position_ids=position_ids) - print(outputs.logits.shape) - - # So far we need to compute `loss` outside `model.forward` when using `shift_labels` - # loss = outputs.loss - loss = ForCausalLMLoss(logits=outputs.logits, labels=None, shift_labels=shift_labels, vocab_size=vocab_size) - - # This could be outside `context_parallel` context if `no_restore_buffers` is specified - loss.backward() - optimizer.step() diff --git a/examples/pytorch/contrastive-image-text/README.md b/examples/pytorch/contrastive-image-text/README.md deleted file mode 100644 index 9211c0cc59f9..000000000000 --- a/examples/pytorch/contrastive-image-text/README.md +++ /dev/null @@ -1,101 +0,0 @@ - - -# VisionTextDualEncoder and CLIP model training examples - -The following example showcases how to train a CLIP-like vision-text dual encoder model -using a pre-trained vision and text encoder. - -Such a model can be used for natural language image search and potentially zero-shot image classification. -The model is inspired by [CLIP](https://openai.com/blog/clip/), introduced by Alec Radford et al. -The idea is to train a vision encoder and a text encoder jointly to project the representation of images and their -captions into the same embedding space, such that the caption embeddings are located near the embeddings -of the images they describe. - -### Download COCO dataset (2017) -This example uses COCO dataset (2017) through a custom dataset script, which requires users to manually download the -COCO dataset before training. - -```bash -mkdir data -cd data -wget http://images.cocodataset.org/zips/train2017.zip -wget http://images.cocodataset.org/zips/val2017.zip -wget http://images.cocodataset.org/zips/test2017.zip -wget http://images.cocodataset.org/annotations/annotations_trainval2017.zip -wget http://images.cocodataset.org/annotations/image_info_test2017.zip -cd .. -``` - -Having downloaded COCO dataset manually you should be able to load with the `ydshieh/coc_dataset_script` dataset loading script: - -```py -import os -import datasets - -COCO_DIR = os.path.join(os.getcwd(), "data") -ds = datasets.load_dataset("ydshieh/coco_dataset_script", "2017", data_dir=COCO_DIR) -``` - -### Create a model from a vision encoder model and a text encoder model -Next, we create a [VisionTextDualEncoderModel](https://huggingface.co/docs/transformers/model_doc/vision-text-dual-encoder#visiontextdualencoder). -The `VisionTextDualEncoderModel` class lets you load any vision and text encoder model to create a dual encoder. -Here is an example of how to load the model using pre-trained vision and text models. - -```python3 -from transformers import ( - VisionTextDualEncoderModel, - VisionTextDualEncoderProcessor, - AutoTokenizer, - AutoImageProcessor -) - -model = VisionTextDualEncoderModel.from_vision_text_pretrained( - "openai/clip-vit-base-patch32", "FacebookAI/roberta-base" -) - -tokenizer = AutoTokenizer.from_pretrained("FacebookAI/roberta-base") -image_processor = AutoImageProcessor.from_pretrained("openai/clip-vit-base-patch32") -processor = VisionTextDualEncoderProcessor(image_processor, tokenizer) - -# save the model and processor -model.save_pretrained("clip-roberta") -processor.save_pretrained("clip-roberta") -``` - -This loads both the text and vision encoders using pre-trained weights, the projection layers are randomly -initialized except for CLIP's vision model. If you use CLIP to initialize the vision model then the vision projection weights are also -loaded using the pre-trained weights. - -### Train the model -Finally, we can run the example script to train the model: - -```bash -python run_clip.py \ - --output_dir ./clip-roberta-finetuned \ - --model_name_or_path ./clip-roberta \ - --data_dir $PWD/data \ - --dataset_name ydshieh/coco_dataset_script \ - --dataset_config_name=2017 \ - --image_column image_path \ - --caption_column caption \ - --remove_unused_columns=False \ - --do_train --do_eval \ - --per_device_train_batch_size="64" \ - --per_device_eval_batch_size="64" \ - --learning_rate="5e-5" --warmup_steps="0" --weight_decay 0.1 \ - --push_to_hub -``` diff --git a/examples/pytorch/contrastive-image-text/requirements.txt b/examples/pytorch/contrastive-image-text/requirements.txt deleted file mode 100644 index a789fee85eef..000000000000 --- a/examples/pytorch/contrastive-image-text/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -torch>=1.5.0 -torchvision>=0.6.0 -datasets>=1.8.0 \ No newline at end of file diff --git a/examples/pytorch/contrastive-image-text/run_clip.py b/examples/pytorch/contrastive-image-text/run_clip.py deleted file mode 100644 index a28723c1d424..000000000000 --- a/examples/pytorch/contrastive-image-text/run_clip.py +++ /dev/null @@ -1,518 +0,0 @@ -#!/usr/bin/env python -# Copyright 2022 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "torch>=1.5.0", -# "torchvision>=0.6.0", -# "datasets>=1.8.0", -# ] -# /// - -""" -Training a CLIP like dual encoder models using text and vision encoders in the library. - -The script can be used to train CLIP like models for languages other than English by using -a text encoder pre-trained in the desired language. Currently this script supports the following vision -and text models: -Vision models: ViT(https://huggingface.co/models?filter=vit), CLIP (https://huggingface.co/models?filter=clip) -Text models: BERT, ROBERTa (https://huggingface.co/models?filter=fill-mask) -""" - -import logging -import os -import sys -from dataclasses import dataclass, field - -import torch -from datasets import load_dataset -from PIL import Image -from torchvision.io import ImageReadMode, read_image -from torchvision.transforms import CenterCrop, ConvertImageDtype, Normalize, Resize -from torchvision.transforms.functional import InterpolationMode - -import transformers -from transformers import ( - AutoImageProcessor, - AutoModel, - AutoTokenizer, - HfArgumentParser, - Trainer, - TrainingArguments, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/contrastive-image-text/requirements.txt") - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune, or train from scratch. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - image_processor_name: str = field(default=None, metadata={"help": "Name or path of preprocessor config."}) - cache_dir: str | None = field( - default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"} - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - freeze_vision_model: bool = field( - default=False, metadata={"help": "Whether to freeze the vision model parameters or not."} - ) - freeze_text_model: bool = field( - default=False, metadata={"help": "Whether to freeze the text model parameters or not."} - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - data_dir: str | None = field(default=None, metadata={"help": "The data directory containing input files."}) - image_column: str | None = field( - default="image_path", - metadata={"help": "The name of the column in the datasets containing the full image file paths."}, - ) - caption_column: str | None = field( - default="caption", - metadata={"help": "The name of the column in the datasets containing the image captions."}, - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a jsonlines file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file (a jsonlines file)."}, - ) - max_seq_length: int | None = field( - default=128, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - - def __post_init__(self): - if self.dataset_name is None and self.train_file is None and self.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - - -dataset_name_mapping = { - "image_caption_dataset.py": ("image_path", "caption"), -} - - -# We use torchvision for faster image pre-processing. The transforms are implemented as nn.Module, -# so we jit it to be faster. -class Transform(torch.nn.Module): - def __init__(self, image_size, mean, std): - super().__init__() - self.transforms = torch.nn.Sequential( - Resize([image_size], interpolation=InterpolationMode.BICUBIC), - CenterCrop(image_size), - ConvertImageDtype(torch.float), - Normalize(mean, std), - ) - - def forward(self, x) -> torch.Tensor: - """`x` should be an instance of `PIL.Image.Image`""" - with torch.no_grad(): - x = self.transforms(x) - return x - - -def collate_fn(examples): - pixel_values = torch.stack([example["pixel_values"] for example in examples]) - input_ids = torch.tensor([example["input_ids"] for example in examples], dtype=torch.long) - attention_mask = torch.tensor([example["attention_mask"] for example in examples], dtype=torch.long) - return { - "pixel_values": pixel_values, - "input_ids": input_ids, - "attention_mask": attention_mask, - "return_loss": True, - } - - -def main(): - # 1. Parse input arguments - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # 2. Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # 4. Load dataset - # Get the datasets: you can either provide your own CSV/JSON training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files this script will use the first column for the full image path and the second column for the - # captions (unless you specify column names for this with the `image_column` and `caption_column` arguments). - # - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - dataset = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - keep_in_memory=False, - data_dir=data_args.data_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - dataset = load_dataset( - extension, - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # 5. Load pretrained model, tokenizer, and image processor - if model_args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - elif model_args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - # Load image_processor, in this script we only use this to get the mean and std for normalization. - image_processor = AutoImageProcessor.from_pretrained( - model_args.image_processor_name or model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - model = AutoModel.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - config = model.config - - def _freeze_params(module): - for param in module.parameters(): - param.requires_grad = False - - if model_args.freeze_vision_model: - _freeze_params(model.vision_model) - - if model_args.freeze_text_model: - _freeze_params(model.text_model) - - # set seed for torch dataloaders - set_seed(training_args.seed) - - # Preprocessing the datasets. - # We need to tokenize inputs and targets. - if training_args.do_train: - column_names = dataset["train"].column_names - elif training_args.do_eval: - column_names = dataset["validation"].column_names - else: - logger.info("There is nothing to do. Please pass `do_train`, `do_eval` and/or `do_predict`.") - return - - # 6. Get the column names for input/target. - dataset_columns = dataset_name_mapping.get(data_args.dataset_name) - if data_args.image_column is None: - image_column = dataset_columns[0] if dataset_columns is not None else column_names[0] - else: - image_column = data_args.image_column - if image_column not in column_names: - raise ValueError( - f"--image_column' value '{data_args.image_column}' needs to be one of: {', '.join(column_names)}" - ) - if data_args.caption_column is None: - caption_column = dataset_columns[1] if dataset_columns is not None else column_names[1] - else: - caption_column = data_args.caption_column - if caption_column not in column_names: - raise ValueError( - f"--caption_column' value '{data_args.caption_column}' needs to be one of: {', '.join(column_names)}" - ) - - # 7. Preprocessing the datasets. - # Initialize torchvision transforms and jit it for faster processing. - image_transformations = Transform( - config.vision_config.image_size, image_processor.image_mean, image_processor.image_std - ) - image_transformations = torch.jit.script(image_transformations) - - # Preprocessing the datasets. - # We need to tokenize input captions and transform the images. - def tokenize_captions(examples): - captions = list(examples[caption_column]) - text_inputs = tokenizer(captions, max_length=data_args.max_seq_length, padding="max_length", truncation=True) - examples["input_ids"] = text_inputs.input_ids - examples["attention_mask"] = text_inputs.attention_mask - return examples - - def transform_images(examples): - images = [read_image(image_file, mode=ImageReadMode.RGB) for image_file in examples[image_column]] - examples["pixel_values"] = [image_transformations(image) for image in images] - return examples - - def filter_corrupt_images(examples): - """remove problematic images""" - valid_images = [] - for image_file in examples[image_column]: - try: - Image.open(image_file) - valid_images.append(True) - except Exception: - valid_images.append(False) - return valid_images - - if training_args.do_train: - if "train" not in dataset: - raise ValueError("--do_train requires a train dataset") - train_dataset = dataset["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - train_dataset = train_dataset.filter( - filter_corrupt_images, batched=True, num_proc=data_args.preprocessing_num_workers - ) - train_dataset = train_dataset.map( - function=tokenize_captions, - batched=True, - remove_columns=[col for col in column_names if col != image_column], - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - - # Transform images on the fly as doing it on the whole dataset takes too much time. - train_dataset.set_transform(transform_images) - - if training_args.do_eval: - if "validation" not in dataset: - raise ValueError("--do_eval requires a train validation") - eval_dataset = dataset["validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - eval_dataset = eval_dataset.filter( - filter_corrupt_images, batched=True, num_proc=data_args.preprocessing_num_workers - ) - eval_dataset = eval_dataset.map( - function=tokenize_captions, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=[col for col in column_names if col != image_column], - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - - # Transform images on the fly as doing it on the whole dataset takes too much time. - eval_dataset.set_transform(transform_images) - - # 8. Initialize our trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - data_collator=collate_fn, - ) - - # 9. Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - tokenizer.save_pretrained(training_args.output_dir) - image_processor.save_pretrained(training_args.output_dir) - trainer.log_metrics("train", train_result.metrics) - trainer.save_metrics("train", train_result.metrics) - trainer.save_state() - - # 10. Evaluation - if training_args.do_eval: - metrics = trainer.evaluate() - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # 11. Write Training Stats and push to hub. - finetuned_from = model_args.model_name_or_path - # If from a local directory, don't set `finetuned_from` as this is required to be a valid repo. id on the Hub. - if os.path.isdir(finetuned_from): - finetuned_from = None - kwargs = {"finetuned_from": finetuned_from, "tasks": "contrastive-image-text-modeling"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/image-classification/README.md b/examples/pytorch/image-classification/README.md deleted file mode 100644 index ac68bd7c51e4..000000000000 --- a/examples/pytorch/image-classification/README.md +++ /dev/null @@ -1,212 +0,0 @@ - - -# Image classification examples - -This directory contains 2 scripts that showcase how to fine-tune any model supported by the [`AutoModelForImageClassification` API](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoModelForImageClassification) (such as [ViT](https://huggingface.co/docs/transformers/main/en/model_doc/vit), [ConvNeXT](https://huggingface.co/docs/transformers/main/en/model_doc/convnext), [ResNet](https://huggingface.co/docs/transformers/main/en/model_doc/resnet), [Swin Transformer](https://huggingface.co/docs/transformers/main/en/model_doc/swin)...) using PyTorch. They can be used to fine-tune models on both [datasets from the hub](#using-datasets-from-hub) as well as on [your own custom data](#using-your-own-data). - - - -Try out the inference widget here: https://huggingface.co/google/vit-base-patch16-224 - -Content: -- [PyTorch version, Trainer](#pytorch-version-trainer) -- [PyTorch version, no Trainer](#pytorch-version-no-trainer) - -## PyTorch version, Trainer - -Based on the script [`run_image_classification.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/image-classification/run_image_classification.py). - -The script leverages the 🤗 [Trainer API](https://huggingface.co/docs/transformers/main_classes/trainer) to automatically take care of the training for you, running on distributed environments right away. - -### Using datasets from Hub - -Here we show how to fine-tune a Vision Transformer (`ViT`) on the [beans](https://huggingface.co/datasets/AI-Lab-Makerere/beans) dataset, to classify the disease type of bean leaves. - -```bash -python run_image_classification.py \ - --dataset_name AI-Lab-Makerere/beans \ - --output_dir ./beans_outputs/ \ - --remove_unused_columns False \ - --label_column_name labels \ - --do_train \ - --do_eval \ - --push_to_hub \ - --push_to_hub_model_id vit-base-beans \ - --learning_rate 2e-5 \ - --num_train_epochs 5 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --logging_strategy steps \ - --logging_steps 10 \ - --eval_strategy epoch \ - --save_strategy epoch \ - --load_best_model_at_end True \ - --save_total_limit 3 \ - --seed 1337 -``` - -👀 See the results here: [nateraw/vit-base-beans](https://huggingface.co/nateraw/vit-base-beans). - -Note that you can replace the model and dataset by simply setting the `model_name_or_path` and `dataset_name` arguments respectively, with any model or dataset from the [hub](https://huggingface.co/). For an overview of all possible arguments, we refer to the [docs](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments) of the `TrainingArguments`, which can be passed as flags. - -> If your model classification head dimensions do not fit the number of labels in the dataset, you can specify `--ignore_mismatched_sizes` to adapt it. - -### Using your own data - -To use your own dataset, there are 2 ways: -- you can either provide your own folders as `--train_dir` and/or `--validation_dir` arguments -- you can upload your dataset to the hub (possibly as a private repo, if you prefer so), and simply pass the `--dataset_name` argument. - -Below, we explain both in more detail. - -#### Provide them as folders - -If you provide your own folders with images, the script expects the following directory structure: - -```bash -root/dog/xxx.png -root/dog/xxy.png -root/dog/[...]/xxz.png - -root/cat/123.png -root/cat/nsdf3.png -root/cat/[...]/asd932_.png -``` - -In other words, you need to organize your images in subfolders, based on their class. You can then run the script like this: - -```bash -python run_image_classification.py \ - --train_dir \ - --output_dir ./outputs/ \ - --remove_unused_columns False \ - --do_train \ - --do_eval -``` - -Internally, the script will use the [`ImageFolder`](https://huggingface.co/docs/datasets/v2.0.0/en/image_process#imagefolder) feature which will automatically turn the folders into 🤗 Dataset objects. - -##### 💡 The above will split the train dir into training and evaluation sets - - To control the split amount, use the `--train_val_split` flag. - - To provide your own validation split in its own directory, you can pass the `--validation_dir ` flag. - -#### Upload your data to the hub, as a (possibly private) repo - -It's very easy (and convenient) to upload your image dataset to the hub using the [`ImageFolder`](https://huggingface.co/docs/datasets/v2.0.0/en/image_process#imagefolder) feature available in 🤗 Datasets. Simply do the following: - -```python -from datasets import load_dataset - -# example 1: local folder -dataset = load_dataset("imagefolder", data_dir="path_to_your_folder") - -# example 2: local files (supported formats are tar, gzip, zip, xz, rar, zstd) -dataset = load_dataset("imagefolder", data_files="path_to_zip_file") - -# example 3: remote files (supported formats are tar, gzip, zip, xz, rar, zstd) -dataset = load_dataset("imagefolder", data_files="https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_3367a.zip") - -# example 4: providing several splits -dataset = load_dataset("imagefolder", data_files={"train": ["path/to/file1", "path/to/file2"], "test": ["path/to/file3", "path/to/file4"]}) -``` - -`ImageFolder` will create a `label` column, and the label name is based on the directory name. - -Next, push it to the hub! - -```python -# assuming you have ran the hf auth login command in a terminal -dataset.push_to_hub("name_of_your_dataset") - -# if you want to push to a private repo, simply pass private=True: -dataset.push_to_hub("name_of_your_dataset", private=True) -``` - -and that's it! You can now train your model by simply setting the `--dataset_name` argument to the name of your dataset on the hub (as explained in [Using datasets from the 🤗 hub](#using-datasets-from-hub)). - -More on this can also be found in [this blog post](https://huggingface.co/blog/image-search-datasets). - -### Sharing your model on 🤗 Hub - -0. If you haven't already, [sign up](https://huggingface.co/join) for a 🤗 account - -1. Make sure you have `git-lfs` installed and git set up. - -```bash -$ apt install git-lfs -$ git config --global user.email "you@example.com" -$ git config --global user.name "Your Name" -``` - -2. Log in with your HuggingFace account credentials using `hf`: - -```bash -$ hf auth login -# ...follow the prompts -``` - -3. When running the script, pass the following arguments: - -```bash -python run_image_classification.py \ - --push_to_hub \ - --push_to_hub_model_id \ - ... -``` - -## PyTorch version, no Trainer - -Based on the script [`run_image_classification_no_trainer.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/image-classification/run_image_classification_no_trainer.py). - -Like `run_image_classification.py`, this script allows you to fine-tune any of the models on the [hub](https://huggingface.co/models) on an image classification task. The main difference is that this script exposes the bare training loop, to allow you to quickly experiment and add any customization you would like. - -It offers less options than the script with `Trainer` (for instance you can easily change the options for the optimizer -or the dataloaders directly in the script) but still run in a distributed setup, and supports mixed precision by -the means of the [🤗 `Accelerate`](https://github.com/huggingface/accelerate) library. You can use the script normally -after installing it: - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -You can then use your usual launchers to run in it in a distributed environment, but the easiest way is to run - -```bash -accelerate config -``` - -and reply to the questions asked. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -accelerate launch run_image_classification_no_trainer.py --image_column_name img -``` - -This command is the same and will work for: - -- single/multiple CPUs -- single/multiple GPUs -- TPUs - -Note that this library is in alpha release so your feedback is more than welcome if you encounter any problem using it. - -Regarding using custom data with this script, we refer to [using your own data](#using-your-own-data). diff --git a/examples/pytorch/image-classification/requirements.txt b/examples/pytorch/image-classification/requirements.txt deleted file mode 100644 index 2779c1c6a870..000000000000 --- a/examples/pytorch/image-classification/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -accelerate>=0.12.0 -torch>=1.5.0 -torchvision>=0.6.0 -datasets>=2.14.0 -evaluate -scikit-learn \ No newline at end of file diff --git a/examples/pytorch/image-classification/run_image_classification.py b/examples/pytorch/image-classification/run_image_classification.py deleted file mode 100755 index 5b13753175a6..000000000000 --- a/examples/pytorch/image-classification/run_image_classification.py +++ /dev/null @@ -1,432 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate>=0.12.0", -# "torch>=1.5.0", -# "torchvision>=0.6.0", -# "datasets>=2.14.0", -# "evaluate", -# "scikit-learn", -# ] -# /// - -import logging -import os -import sys -from dataclasses import dataclass, field - -import evaluate -import numpy as np -import torch -from datasets import load_dataset -from PIL import Image -from torchvision.transforms import ( - CenterCrop, - Compose, - Lambda, - Normalize, - RandomHorizontalFlip, - RandomResizedCrop, - Resize, - ToTensor, -) - -import transformers -from transformers import ( - MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING, - AutoConfig, - AutoImageProcessor, - AutoModelForImageClassification, - HfArgumentParser, - TimmWrapperImageProcessor, - Trainer, - TrainingArguments, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -""" Fine-tuning a 🤗 Transformers model for image classification""" - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.14.0", "To fix: pip install -r examples/pytorch/image-classification/requirements.txt") - -MODEL_CONFIG_CLASSES = list(MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -def pil_loader(path: str): - with open(path, "rb") as f: - im = Image.open(f) - return im.convert("RGB") - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - Using `HfArgumentParser` we can turn this class into argparse arguments to be able to specify - them on the command line. - """ - - dataset_name: str | None = field( - default=None, - metadata={ - "help": "Name of a dataset from the hub (could be your own, possibly private dataset hosted on the hub)." - }, - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_dir: str | None = field(default=None, metadata={"help": "A folder containing the training data."}) - validation_dir: str | None = field(default=None, metadata={"help": "A folder containing the validation data."}) - train_val_split: float | None = field( - default=0.15, metadata={"help": "Percent to split off of train for validation."} - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - image_column_name: str = field( - default="image", - metadata={"help": "The name of the dataset column containing the image data. Defaults to 'image'."}, - ) - label_column_name: str = field( - default="label", - metadata={"help": "The name of the dataset column containing the labels. Defaults to 'label'."}, - ) - - def __post_init__(self): - if self.dataset_name is None and (self.train_dir is None and self.validation_dir is None): - raise ValueError( - "You must specify either a dataset name from the hub or a train and/or validation directory." - ) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - default="google/vit-base-patch16-224-in21k", - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}, - ) - model_type: str | None = field( - default=None, - metadata={"help": "If training from scratch, pass a model type from the list: " + ", ".join(MODEL_TYPES)}, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"} - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - image_processor_name: str = field(default=None, metadata={"help": "Name or path of preprocessor config."}) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - ignore_mismatched_sizes: bool = field( - default=False, - metadata={"help": "Will enable to load a pretrained model whose head dimensions are different."}, - ) - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Initialize our dataset and prepare it for the 'image-classification' task. - if data_args.dataset_name is not None: - dataset = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_dir is not None: - data_files["train"] = os.path.join(data_args.train_dir, "**") - if data_args.validation_dir is not None: - data_files["validation"] = os.path.join(data_args.validation_dir, "**") - dataset = load_dataset( - "imagefolder", - data_files=data_files, - cache_dir=model_args.cache_dir, - ) - - dataset_column_names = dataset["train"].column_names if "train" in dataset else dataset["validation"].column_names - if data_args.image_column_name not in dataset_column_names: - raise ValueError( - f"--image_column_name {data_args.image_column_name} not found in dataset '{data_args.dataset_name}'. " - "Make sure to set `--image_column_name` to the correct audio column - one of " - f"{', '.join(dataset_column_names)}." - ) - if data_args.label_column_name not in dataset_column_names: - raise ValueError( - f"--label_column_name {data_args.label_column_name} not found in dataset '{data_args.dataset_name}'. " - "Make sure to set `--label_column_name` to the correct text column - one of " - f"{', '.join(dataset_column_names)}." - ) - - def collate_fn(examples): - pixel_values = torch.stack([example["pixel_values"] for example in examples]) - labels = torch.tensor([example[data_args.label_column_name] for example in examples]) - return {"pixel_values": pixel_values, "labels": labels} - - # If we don't have a validation split, split off a percentage of train as validation. - data_args.train_val_split = None if "validation" in dataset else data_args.train_val_split - if isinstance(data_args.train_val_split, float) and data_args.train_val_split > 0.0: - split = dataset["train"].train_test_split(data_args.train_val_split) - dataset["train"] = split["train"] - dataset["validation"] = split["test"] - - # Prepare label mappings. - # We'll include these in the model's config to get human readable labels in the Inference API. - labels = dataset["train"].features[data_args.label_column_name].names - label2id, id2label = {}, {} - for i, label in enumerate(labels): - label2id[label] = str(i) - id2label[str(i)] = label - - # Load the accuracy metric from the datasets package - metric = evaluate.load("accuracy", cache_dir=model_args.cache_dir) - - # Define our compute_metrics function. It takes an `EvalPrediction` object (a namedtuple with a - # predictions and label_ids field) and has to return a dictionary string to float. - def compute_metrics(p): - """Computes accuracy on a batch of predictions""" - return metric.compute(predictions=np.argmax(p.predictions, axis=1), references=p.label_ids) - - config = AutoConfig.from_pretrained( - model_args.config_name or model_args.model_name_or_path, - num_labels=len(labels), - label2id=label2id, - id2label=id2label, - finetuning_task="image-classification", - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForImageClassification.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ignore_mismatched_sizes=model_args.ignore_mismatched_sizes, - ) - image_processor = AutoImageProcessor.from_pretrained( - model_args.image_processor_name or model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # Define torchvision transforms to be applied to each image. - if isinstance(image_processor, TimmWrapperImageProcessor): - _train_transforms = image_processor.train_transforms - _val_transforms = image_processor.val_transforms - else: - if "shortest_edge" in image_processor.size: - size = image_processor.size["shortest_edge"] - else: - size = (image_processor.size["height"], image_processor.size["width"]) - - # Create normalization transform - if hasattr(image_processor, "image_mean") and hasattr(image_processor, "image_std"): - normalize = Normalize(mean=image_processor.image_mean, std=image_processor.image_std) - else: - normalize = Lambda(lambda x: x) - _train_transforms = Compose( - [ - RandomResizedCrop(size), - RandomHorizontalFlip(), - ToTensor(), - normalize, - ] - ) - _val_transforms = Compose( - [ - Resize(size), - CenterCrop(size), - ToTensor(), - normalize, - ] - ) - - def train_transforms(example_batch): - """Apply _train_transforms across a batch.""" - example_batch["pixel_values"] = [ - _train_transforms(pil_img.convert("RGB")) for pil_img in example_batch[data_args.image_column_name] - ] - return example_batch - - def val_transforms(example_batch): - """Apply _val_transforms across a batch.""" - example_batch["pixel_values"] = [ - _val_transforms(pil_img.convert("RGB")) for pil_img in example_batch[data_args.image_column_name] - ] - return example_batch - - if training_args.do_train: - if "train" not in dataset: - raise ValueError("--do_train requires a train dataset") - if data_args.max_train_samples is not None: - dataset["train"] = ( - dataset["train"].shuffle(seed=training_args.seed).select(range(data_args.max_train_samples)) - ) - # Set the training transforms - dataset["train"].set_transform(train_transforms) - - if training_args.do_eval: - if "validation" not in dataset: - raise ValueError("--do_eval requires a validation dataset") - if data_args.max_eval_samples is not None: - dataset["validation"] = ( - dataset["validation"].shuffle(seed=training_args.seed).select(range(data_args.max_eval_samples)) - ) - # Set the validation transforms - dataset["validation"].set_transform(val_transforms) - - # Initialize our trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=dataset["train"] if training_args.do_train else None, - eval_dataset=dataset["validation"] if training_args.do_eval else None, - compute_metrics=compute_metrics, - processing_class=image_processor, - data_collator=collate_fn, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - trainer.log_metrics("train", train_result.metrics) - trainer.save_metrics("train", train_result.metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - metrics = trainer.evaluate() - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Write model card and (optionally) push to hub - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "tasks": "image-classification", - "dataset": data_args.dataset_name, - "tags": ["image-classification", "vision"], - } - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/image-classification/run_image_classification_no_trainer.py b/examples/pytorch/image-classification/run_image_classification_no_trainer.py deleted file mode 100644 index 33b9e42e3b01..000000000000 --- a/examples/pytorch/image-classification/run_image_classification_no_trainer.py +++ /dev/null @@ -1,658 +0,0 @@ -# Copyright 2022 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate>=0.12.0", -# "torch>=1.5.0", -# "torchvision>=0.6.0", -# "datasets>=2.14.0", -# "evaluate", -# "scikit-learn", -# ] -# /// - -"""Finetuning any 🤗 Transformers model for image classification leveraging 🤗 Accelerate.""" - -import argparse -import json -import logging -import math -import os -from pathlib import Path - -import datasets -import evaluate -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from torchvision.transforms import ( - CenterCrop, - Compose, - Lambda, - Normalize, - RandomHorizontalFlip, - RandomResizedCrop, - Resize, - ToTensor, -) -from tqdm.auto import tqdm - -import transformers -from transformers import AutoConfig, AutoImageProcessor, AutoModelForImageClassification, SchedulerType, get_scheduler -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) - -require_version("datasets>=2.0.0", "To fix: pip install -r examples/pytorch/image-classification/requirements.txt") - - -def parse_args(): - parser = argparse.ArgumentParser(description="Fine-tune a Transformers model on an image classification dataset") - parser.add_argument( - "--dataset_name", - type=str, - default="uoft-cs/cifar10", - help=( - "The name of the Dataset (from the HuggingFace hub) to train on (could be your own, possibly private," - " dataset)." - ), - ) - parser.add_argument("--train_dir", type=str, default=None, help="A folder containing the training data.") - parser.add_argument("--validation_dir", type=str, default=None, help="A folder containing the validation data.") - parser.add_argument( - "--max_train_samples", - type=int, - default=None, - help=( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ), - ) - parser.add_argument( - "--max_eval_samples", - type=int, - default=None, - help=( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ), - ) - parser.add_argument( - "--train_val_split", - type=float, - default=0.15, - help="Percent to split off of train for validation", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - default="google/vit-base-patch16-224-in21k", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - parser.add_argument( - "--ignore_mismatched_sizes", - action="store_true", - help="Whether or not to enable to load a pretrained model whose head dimensions are different.", - ) - parser.add_argument( - "--image_column_name", - type=str, - default="image", - help="The name of the dataset column containing the image data. Defaults to 'image'.", - ) - parser.add_argument( - "--label_column_name", - type=str, - default="label", - help="The name of the dataset column containing the labels. Defaults to 'label'.", - ) - args = parser.parse_args() - - # Sanity checks - if args.dataset_name is None and args.train_dir is None and args.validation_dir is None: - raise ValueError("Need either a dataset name or a training/validation folder.") - - if args.push_to_hub or args.with_tracking: - if args.output_dir is None: - raise ValueError( - "Need an `output_dir` to create a repo when `--push_to_hub` or `with_tracking` is specified." - ) - - if args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - logger.info(accelerator.state) - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own training and evaluation files (see below) - # or specify a Dataset from the hub (the dataset will be downloaded automatically from the datasets Hub). - - # In distributed training, the load_dataset function guarantees that only one local process can concurrently - # download the dataset. - if ( - args.dataset_name is not None and args.train_dir is None and args.validation_dir is None - ): # Downloading and loading a dataset from the hub. - dataset = load_dataset(args.dataset_name, trust_remote_code=args.trust_remote_code) - else: - data_files = {} - if args.train_dir is not None: - data_files["train"] = os.path.join(args.train_dir, "**") - if args.validation_dir is not None: - data_files["validation"] = os.path.join(args.validation_dir, "**") - dataset = load_dataset( - "imagefolder", - data_files=data_files, - ) - # See more about loading custom images at - # https://huggingface.co/docs/datasets/v2.0.0/en/image_process#imagefolder. - - dataset_column_names = dataset["train"].column_names if "train" in dataset else dataset["validation"].column_names - if args.image_column_name not in dataset_column_names: - raise ValueError( - f"--image_column_name {args.image_column_name} not found in dataset '{args.dataset_name}'. " - "Make sure to set `--image_column_name` to the correct audio column - one of " - f"{', '.join(dataset_column_names)}." - ) - if args.label_column_name not in dataset_column_names: - raise ValueError( - f"--label_column_name {args.label_column_name} not found in dataset '{args.dataset_name}'. " - "Make sure to set `--label_column_name` to the correct text column - one of " - f"{', '.join(dataset_column_names)}." - ) - - # If we don't have a validation split, split off a percentage of train as validation. - args.train_val_split = None if "validation" in dataset else args.train_val_split - if isinstance(args.train_val_split, float) and args.train_val_split > 0.0: - split = dataset["train"].train_test_split(args.train_val_split) - dataset["train"] = split["train"] - dataset["validation"] = split["test"] - - # Prepare label mappings. - # We'll include these in the model's config to get human readable labels in the Inference API. - labels = dataset["train"].features[args.label_column_name].names - label2id = {label: str(i) for i, label in enumerate(labels)} - id2label = {str(i): label for i, label in enumerate(labels)} - - # Load pretrained model and image processor - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - args.model_name_or_path, - num_labels=len(labels), - id2label=id2label, - label2id=label2id, - finetuning_task="image-classification", - trust_remote_code=args.trust_remote_code, - ) - image_processor = AutoImageProcessor.from_pretrained( - args.model_name_or_path, - trust_remote_code=args.trust_remote_code, - ) - model = AutoModelForImageClassification.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - ignore_mismatched_sizes=args.ignore_mismatched_sizes, - trust_remote_code=args.trust_remote_code, - ) - - # Preprocessing the datasets - - # Define torchvision transforms to be applied to each image. - if "shortest_edge" in image_processor.size: - size = image_processor.size["shortest_edge"] - else: - size = (image_processor.size["height"], image_processor.size["width"]) - normalize = ( - Normalize(mean=image_processor.image_mean, std=image_processor.image_std) - if hasattr(image_processor, "image_mean") and hasattr(image_processor, "image_std") - else Lambda(lambda x: x) - ) - train_transforms = Compose( - [ - RandomResizedCrop(size), - RandomHorizontalFlip(), - ToTensor(), - normalize, - ] - ) - val_transforms = Compose( - [ - Resize(size), - CenterCrop(size), - ToTensor(), - normalize, - ] - ) - - def preprocess_train(example_batch): - """Apply _train_transforms across a batch.""" - example_batch["pixel_values"] = [ - train_transforms(image.convert("RGB")) for image in example_batch[args.image_column_name] - ] - return example_batch - - def preprocess_val(example_batch): - """Apply _val_transforms across a batch.""" - example_batch["pixel_values"] = [ - val_transforms(image.convert("RGB")) for image in example_batch[args.image_column_name] - ] - return example_batch - - with accelerator.main_process_first(): - if args.max_train_samples is not None: - dataset["train"] = dataset["train"].shuffle(seed=args.seed).select(range(args.max_train_samples)) - # Set the training transforms - train_dataset = dataset["train"].with_transform(preprocess_train) - if args.max_eval_samples is not None: - dataset["validation"] = dataset["validation"].shuffle(seed=args.seed).select(range(args.max_eval_samples)) - # Set the validation transforms - eval_dataset = dataset["validation"].with_transform(preprocess_val) - - # DataLoaders creation: - def collate_fn(examples): - pixel_values = torch.stack([example["pixel_values"] for example in examples]) - labels = torch.tensor([example[args.label_column_name] for example in examples]) - return {"pixel_values": pixel_values, "labels": labels} - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=collate_fn, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader(eval_dataset, collate_fn=collate_fn, batch_size=args.per_device_eval_batch_size) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("image_classification_no_trainer", experiment_config) - - # Get the metric function - metric = evaluate.load("accuracy") - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, - is_main_process=accelerator.is_main_process, - save_function=accelerator.save, - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if completed_steps >= args.max_train_steps: - break - - model.eval() - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - predictions = outputs.logits.argmax(dim=-1) - predictions, references = accelerator.gather_for_metrics((predictions, batch["labels"])) - metric.add_batch( - predictions=predictions, - references=references, - ) - - eval_metric = metric.compute() - logger.info(f"epoch {epoch}: {eval_metric}") - - if args.with_tracking: - accelerator.log( - { - "accuracy": eval_metric, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - all_results = {f"eval_{k}": v for k, v in eval_metric.items()} - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump(all_results, f) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/image-pretraining/README.md b/examples/pytorch/image-pretraining/README.md deleted file mode 100644 index 767f857e8dd0..000000000000 --- a/examples/pytorch/image-pretraining/README.md +++ /dev/null @@ -1,254 +0,0 @@ - - -# Image pretraining examples - -This directory contains Python scripts that allow you to pre-train Transformer-based vision models (like [ViT](https://huggingface.co/docs/transformers/model_doc/vit), [Swin Transformer](https://huggingface.co/docs/transformers/model_doc/swin)) on your own data, after which you can easily load the weights into a [`AutoModelForImageClassification`](https://huggingface.co/docs/transformers/model_doc/auto#transformers.AutoModelForImageClassification). It currently includes scripts for: -- [SimMIM](#simmim) (by Microsoft Research) -- [MAE](#mae) (by Facebook AI). - -NOTE: If you encounter problems/have suggestions for improvement, open an issue on Github and tag @NielsRogge. - - -## SimMIM - -The `run_mim.py` script can be used to pre-train any Transformer-based vision model in the library (concretely, any model supported by the `AutoModelForMaskedImageModeling` API) for masked image modeling as proposed in [SimMIM: A Simple Framework for Masked Image Modeling](https://huggingface.co/papers/2111.09886) using PyTorch. - - - - SimMIM framework. Taken from the original paper. - -The goal for the model is to predict raw pixel values for the masked patches, using just a linear layer as prediction head. The model is trained using a simple L1 loss. - -### Using datasets from 🤗 datasets - -Here we show how to pre-train a `ViT` from scratch for masked image modeling on the [cifar10](https://huggingface.co/datasets/uoft-cs/cifar10) dataset. - -Alternatively, one can decide to further pre-train an already pre-trained (or fine-tuned) checkpoint from the [hub](https://huggingface.co/). This can be done by setting the `model_name_or_path` argument to "google/vit-base-patch16-224-in21k" for example (and not specifying the `model_type` argument). - -```bash -!python run_mim.py \ - --model_type vit \ - --output_dir ./outputs/ \ - --remove_unused_columns False \ - --label_names bool_masked_pos \ - --do_train \ - --do_eval \ - --learning_rate 2e-5 \ - --weight_decay 0.05 \ - --num_train_epochs 100 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --logging_strategy steps \ - --logging_steps 10 \ - --eval_strategy epoch \ - --save_strategy epoch \ - --load_best_model_at_end True \ - --save_total_limit 3 \ - --seed 1337 -``` - -Here, we train for 100 epochs with a learning rate of 2e-5. Note that the SimMIM authors used a more sophisticated learning rate schedule, see the [config files](https://github.com/microsoft/SimMIM/blob/main/configs/vit_base__800ep/simmim_pretrain__vit_base__img224__800ep.yaml) for more info. One can easily tweak the script to include this learning rate schedule (several learning rate schedulers are supported via the [training arguments](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments)). - -We can also for instance replicate the pre-training of a Swin Transformer using the same architecture as used by the SimMIM authors. For this, we first create a custom configuration and save it locally: - -```python -from transformers import SwinConfig - -IMAGE_SIZE = 192 -PATCH_SIZE = 4 -EMBED_DIM = 128 -DEPTHS = [2, 2, 18, 2] -NUM_HEADS = [4, 8, 16, 32] -WINDOW_SIZE = 6 - -config = SwinConfig( - image_size=IMAGE_SIZE, - patch_size=PATCH_SIZE, - embed_dim=EMBED_DIM, - depths=DEPTHS, - num_heads=NUM_HEADS, - window_size=WINDOW_SIZE, -) -config.save_pretrained("path_to_config") -``` - -Next, we can run the script by providing the path to this custom configuration (replace `path_to_config` below with your path): - -```bash -!python run_mim.py \ - --config_name_or_path path_to_config \ - --model_type swin \ - --output_dir ./outputs/ \ - --remove_unused_columns False \ - --label_names bool_masked_pos \ - --do_train \ - --do_eval \ - --learning_rate 2e-5 \ - --num_train_epochs 5 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --logging_strategy steps \ - --logging_steps 10 \ - --eval_strategy epoch \ - --save_strategy epoch \ - --load_best_model_at_end True \ - --save_total_limit 3 \ - --seed 1337 -``` - -This will train a Swin Transformer from scratch. - -### Using your own data - -To use your own dataset, the training script expects the following directory structure: - -```bash -root/dog/xxx.png -root/dog/xxy.png -root/dog/[...]/xxz.png - -root/cat/123.png -root/cat/nsdf3.png -root/cat/[...]/asd932_.png -``` - -Note that you can put images in dummy subfolders, whose names will be ignored by default (as labels aren't required). You can also just place all images into a single dummy subfolder. Once you've prepared your dataset, you can run the script like this: - -```bash -python run_mim.py \ - --model_type vit \ - --dataset_name nateraw/image-folder \ - --train_dir \ - --output_dir ./outputs/ \ - --remove_unused_columns False \ - --label_names bool_masked_pos \ - --do_train \ - --do_eval -``` - -## MAE - -The `run_mae.py` script can be used to pre-train a Vision Transformer as a masked autoencoder (MAE), as proposed in [Masked Autoencoders Are Scalable Vision Learners](https://huggingface.co/papers/2111.06377). The script can be used to train a `ViTMAEForPreTraining` model in the Transformers library, using PyTorch. After self-supervised pre-training, one can load the weights of the encoder directly into a `ViTForImageClassification`. The MAE method allows for learning high-capacity models that generalize well: e.g., a vanilla ViT-Huge model achieves the best accuracy (87.8%) among methods that use only ImageNet-1K data. - -The goal for the model is to predict raw pixel values for the masked patches. As the model internally masks patches and learns to reconstruct them, there's no need for any labels. The model uses the mean squared error (MSE) between the reconstructed and original images in the pixel space. - -### Using datasets from 🤗 `datasets` - -One can use the following command to pre-train a `ViTMAEForPreTraining` model from scratch on the [cifar10](https://huggingface.co/datasets/uoft-cs/cifar10) dataset: - -```bash -python run_mae.py \ - --dataset_name uoft-cs/cifar10 \ - --output_dir ./vit-mae-demo \ - --remove_unused_columns False \ - --label_names pixel_values \ - --mask_ratio 0.75 \ - --norm_pix_loss \ - --do_train \ - --do_eval \ - --base_learning_rate 1.5e-4 \ - --lr_scheduler_type cosine \ - --weight_decay 0.05 \ - --num_train_epochs 800 \ - --warmup_steps 0.05 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --logging_strategy steps \ - --logging_steps 10 \ - --eval_strategy epoch \ - --save_strategy epoch \ - --load_best_model_at_end True \ - --save_total_limit 3 \ - --seed 1337 -``` - -Here we set: -- `mask_ratio` to 0.75 (to mask 75% of the patches for each image) -- `norm_pix_loss` to use normalized pixel values as target (the authors reported better representations with this enabled) -- `base_learning_rate` to 1.5e-4. Note that the effective learning rate is computed by the [linear schedule](https://huggingface.co/papers/1706.02677): `lr` = `blr` * total training batch size / 256. The total training batch size is computed as `training_args.train_batch_size` * `training_args.gradient_accumulation_steps` * `training_args.world_size`. - -This replicates the same hyperparameters as used in the original implementation, as shown in the table below. - - - - Original hyperparameters. Taken from the original paper. - -Alternatively, one can decide to further pre-train an already pre-trained (or fine-tuned) checkpoint from the [hub](https://huggingface.co/). This can be done by setting the `model_name_or_path` argument to "facebook/vit-mae-base" for example. - - -### Using your own data - -To use your own dataset, the training script expects the following directory structure: - -```bash -root/dog/xxx.png -root/dog/xxy.png -root/dog/[...]/xxz.png - -root/cat/123.png -root/cat/nsdf3.png -root/cat/[...]/asd932_.png -``` - -Note that you can put images in dummy subfolders, whose names will be ignored by default (as labels aren't required). You can also just place all images into a single dummy subfolder. Once you've prepared your dataset, you can run the script like this: - -```bash -python run_mae.py \ - --model_type vit_mae \ - --dataset_name nateraw/image-folder \ - --train_dir \ - --output_dir ./outputs/ \ - --remove_unused_columns False \ - --label_names pixel_values \ - --do_train \ - --do_eval -``` - -#### 💡 The above will split the train dir into training and evaluation sets - - To control the split amount, use the `--train_val_split` flag. - - To provide your own validation split in its own directory, you can pass the `--validation_dir ` flag. - - -## Sharing your model on 🤗 Hub - -0. If you haven't already, [sign up](https://huggingface.co/join) for a 🤗 account - -1. Make sure you have `git-lfs` installed and git set up. - -```bash -$ apt install git-lfs -$ git config --global user.email "you@example.com" -$ git config --global user.name "Your Name" -``` - -2. Log in with your HuggingFace account credentials using `hf` - -```bash -$ hf auth login -# ...follow the prompts -``` - -3. When running the script, pass the following arguments: - -```bash -python run_xxx.py \ - --push_to_hub \ - --push_to_hub_model_id \ - ... -``` \ No newline at end of file diff --git a/examples/pytorch/image-pretraining/requirements.txt b/examples/pytorch/image-pretraining/requirements.txt deleted file mode 100644 index a789fee85eef..000000000000 --- a/examples/pytorch/image-pretraining/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -torch>=1.5.0 -torchvision>=0.6.0 -datasets>=1.8.0 \ No newline at end of file diff --git a/examples/pytorch/image-pretraining/run_mae.py b/examples/pytorch/image-pretraining/run_mae.py deleted file mode 100644 index 272f74e94fef..000000000000 --- a/examples/pytorch/image-pretraining/run_mae.py +++ /dev/null @@ -1,395 +0,0 @@ -#!/usr/bin/env python -# Copyright 2022 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "torch>=1.5.0", -# "torchvision>=0.6.0", -# "datasets>=1.8.0", -# ] -# /// - -import logging -import os -import sys -from dataclasses import dataclass, field - -import torch -from datasets import load_dataset -from torchvision.transforms import Compose, Lambda, Normalize, RandomHorizontalFlip, RandomResizedCrop, ToTensor -from torchvision.transforms.functional import InterpolationMode - -import transformers -from transformers import ( - HfArgumentParser, - Trainer, - TrainingArguments, - ViTImageProcessor, - ViTMAEConfig, - ViTMAEForPreTraining, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -""" Pre-training a 🤗 ViT model as an MAE (masked autoencoder), as proposed in https://huggingface.co/papers/2111.06377.""" - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/image-pretraining/requirements.txt") - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - Using `HfArgumentParser` we can turn this class - into argparse arguments to be able to specify them on - the command line. - """ - - dataset_name: str | None = field( - default="uoft-cs/cifar10", metadata={"help": "Name of a dataset from the datasets package"} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - image_column_name: str | None = field( - default=None, metadata={"help": "The column name of the images in the files."} - ) - train_dir: str | None = field(default=None, metadata={"help": "A folder containing the training data."}) - validation_dir: str | None = field(default=None, metadata={"help": "A folder containing the validation data."}) - train_val_split: float | None = field( - default=0.15, metadata={"help": "Percent to split off of train for validation."} - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - - def __post_init__(self): - data_files = {} - if self.train_dir is not None: - data_files["train"] = self.train_dir - if self.validation_dir is not None: - data_files["val"] = self.validation_dir - self.data_files = data_files if data_files else None - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/image processor we are going to pre-train. - """ - - model_name_or_path: str = field( - default=None, - metadata={ - "help": ( - "The model checkpoint for weights initialization. Don't set if you want to train a model from scratch." - ) - }, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name_or_path"} - ) - config_overrides: str | None = field( - default=None, - metadata={ - "help": ( - "Override some existing default config settings when a model is trained from scratch. Example: " - "n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index" - ) - }, - ) - cache_dir: str | None = field( - default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"} - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - image_processor_name: str = field(default=None, metadata={"help": "Name or path of preprocessor config."}) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - mask_ratio: float = field( - default=0.75, metadata={"help": "The ratio of the number of masked tokens in the input sequence."} - ) - norm_pix_loss: bool = field( - default=True, metadata={"help": "Whether or not to train with normalized pixel values as target."} - ) - - -@dataclass -class CustomTrainingArguments(TrainingArguments): - base_learning_rate: float = field( - default=1e-3, metadata={"help": "Base learning rate: absolute_lr = base_lr * total_batch_size / 256."} - ) - - -def collate_fn(examples): - pixel_values = torch.stack([example["pixel_values"] for example in examples]) - return {"pixel_values": pixel_values} - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, CustomTrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Initialize our dataset. - ds = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - data_files=data_args.data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - # If we don't have a validation split, split off a percentage of train as validation. - data_args.train_val_split = None if "validation" in ds else data_args.train_val_split - if isinstance(data_args.train_val_split, float) and data_args.train_val_split > 0.0: - split = ds["train"].train_test_split(data_args.train_val_split) - ds["train"] = split["train"] - ds["validation"] = split["test"] - - # Load pretrained model and image processor - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config_kwargs = { - "cache_dir": model_args.cache_dir, - "revision": model_args.model_revision, - "token": model_args.token, - } - if model_args.config_name: - config = ViTMAEConfig.from_pretrained(model_args.config_name, **config_kwargs) - elif model_args.model_name_or_path: - config = ViTMAEConfig.from_pretrained(model_args.model_name_or_path, **config_kwargs) - else: - config = ViTMAEConfig() - logger.warning("You are instantiating a new config instance from scratch.") - if model_args.config_overrides is not None: - logger.info(f"Overriding config: {model_args.config_overrides}") - config.update_from_string(model_args.config_overrides) - logger.info(f"New config: {config}") - - # adapt config - config.update( - { - "mask_ratio": model_args.mask_ratio, - "norm_pix_loss": model_args.norm_pix_loss, - } - ) - - # create image processor - if model_args.image_processor_name: - image_processor = ViTImageProcessor.from_pretrained(model_args.image_processor_name, **config_kwargs) - elif model_args.model_name_or_path: - image_processor = ViTImageProcessor.from_pretrained(model_args.model_name_or_path, **config_kwargs) - else: - image_processor = ViTImageProcessor() - - # create model - if model_args.model_name_or_path: - model = ViTMAEForPreTraining.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - ) - else: - logger.info("Training new model from scratch") - model = ViTMAEForPreTraining(config) - - if training_args.do_train: - column_names = ds["train"].column_names - else: - column_names = ds["validation"].column_names - - if data_args.image_column_name is not None: - image_column_name = data_args.image_column_name - elif "image" in column_names: - image_column_name = "image" - elif "img" in column_names: - image_column_name = "img" - else: - image_column_name = column_names[0] - - # transformations as done in original MAE paper - # source: https://github.com/facebookresearch/mae/blob/main/main_pretrain.py - if "shortest_edge" in image_processor.size: - size = image_processor.size["shortest_edge"] - else: - size = (image_processor.size["height"], image_processor.size["width"]) - transforms = Compose( - [ - Lambda(lambda img: img.convert("RGB") if img.mode != "RGB" else img), - RandomResizedCrop(size, scale=(0.2, 1.0), interpolation=InterpolationMode.BICUBIC), - RandomHorizontalFlip(), - ToTensor(), - Normalize(mean=image_processor.image_mean, std=image_processor.image_std), - ] - ) - - def preprocess_images(examples): - """Preprocess a batch of images by applying transforms.""" - - examples["pixel_values"] = [transforms(image) for image in examples[image_column_name]] - return examples - - if training_args.do_train: - if "train" not in ds: - raise ValueError("--do_train requires a train dataset") - if data_args.max_train_samples is not None: - ds["train"] = ds["train"].shuffle(seed=training_args.seed).select(range(data_args.max_train_samples)) - # Set the training transforms - ds["train"].set_transform(preprocess_images) - - if training_args.do_eval: - if "validation" not in ds: - raise ValueError("--do_eval requires a validation dataset") - if data_args.max_eval_samples is not None: - ds["validation"] = ( - ds["validation"].shuffle(seed=training_args.seed).select(range(data_args.max_eval_samples)) - ) - # Set the validation transforms - ds["validation"].set_transform(preprocess_images) - - # Compute absolute learning rate - total_train_batch_size = ( - training_args.train_batch_size * training_args.gradient_accumulation_steps * training_args.world_size - ) - if training_args.base_learning_rate is not None: - training_args.learning_rate = training_args.base_learning_rate * total_train_batch_size / 256 - - # Initialize our trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=ds["train"] if training_args.do_train else None, - eval_dataset=ds["validation"] if training_args.do_eval else None, - processing_class=image_processor, - data_collator=collate_fn, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - trainer.log_metrics("train", train_result.metrics) - trainer.save_metrics("train", train_result.metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - metrics = trainer.evaluate() - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Write model card and (optionally) push to hub - kwargs = { - "tasks": "masked-auto-encoding", - "dataset": data_args.dataset_name, - "tags": ["masked-auto-encoding"], - } - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/image-pretraining/run_mim.py b/examples/pytorch/image-pretraining/run_mim.py deleted file mode 100644 index be9f4af71c2a..000000000000 --- a/examples/pytorch/image-pretraining/run_mim.py +++ /dev/null @@ -1,470 +0,0 @@ -#!/usr/bin/env python -# Copyright 2022 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "torch>=1.5.0", -# "torchvision>=0.6.0", -# "datasets>=1.8.0", -# ] -# /// - -import logging -import os -import sys -from dataclasses import dataclass, field - -import numpy as np -import torch -from datasets import load_dataset -from torchvision.transforms import Compose, Lambda, Normalize, RandomHorizontalFlip, RandomResizedCrop, ToTensor - -import transformers -from transformers import ( - CONFIG_MAPPING, - IMAGE_PROCESSOR_MAPPING, - MODEL_FOR_MASKED_IMAGE_MODELING_MAPPING, - AutoConfig, - AutoImageProcessor, - AutoModelForMaskedImageModeling, - HfArgumentParser, - Trainer, - TrainingArguments, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -""" Pre-training a 🤗 Transformers model for simple masked image modeling (SimMIM). -Any model supported by the AutoModelForMaskedImageModeling API can be used. -""" - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/image-pretraining/requirements.txt") - -MODEL_CONFIG_CLASSES = list(MODEL_FOR_MASKED_IMAGE_MODELING_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - Using `HfArgumentParser` we can turn this class into argparse arguments to be able to - specify them on the command line. - """ - - dataset_name: str | None = field( - default="uoft-cs/cifar10", metadata={"help": "Name of a dataset from the datasets package"} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - image_column_name: str | None = field( - default=None, - metadata={"help": "The column name of the images in the files. If not set, will try to use 'image' or 'img'."}, - ) - train_dir: str | None = field(default=None, metadata={"help": "A folder containing the training data."}) - validation_dir: str | None = field(default=None, metadata={"help": "A folder containing the validation data."}) - train_val_split: float | None = field( - default=0.15, metadata={"help": "Percent to split off of train for validation."} - ) - mask_patch_size: int = field(default=32, metadata={"help": "The size of the square patches to use for masking."}) - mask_ratio: float = field( - default=0.6, - metadata={"help": "Percentage of patches to mask."}, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - - def __post_init__(self): - data_files = {} - if self.train_dir is not None: - data_files["train"] = self.train_dir - if self.validation_dir is not None: - data_files["val"] = self.validation_dir - self.data_files = data_files if data_files else None - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/image processor we are going to pre-train. - """ - - model_name_or_path: str = field( - default=None, - metadata={ - "help": ( - "The model checkpoint for weights initialization. Can be a local path to a pytorch_model.bin or a " - "checkpoint identifier on the hub. " - "Don't set if you want to train a model from scratch." - ) - }, - ) - model_type: str | None = field( - default=None, - metadata={"help": "If training from scratch, pass a model type from the list: " + ", ".join(MODEL_TYPES)}, - ) - config_name_or_path: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - config_overrides: str | None = field( - default=None, - metadata={ - "help": ( - "Override some existing default config settings when a model is trained from scratch. Example: " - "n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index" - ) - }, - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store (cache) the pretrained models/datasets downloaded from the hub"}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - image_processor_name: str = field(default=None, metadata={"help": "Name or path of preprocessor config."}) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - image_size: int | None = field( - default=None, - metadata={ - "help": ( - "The size (resolution) of each image. If not specified, will use `image_size` of the configuration." - ) - }, - ) - patch_size: int | None = field( - default=None, - metadata={ - "help": ( - "The size (resolution) of each patch. If not specified, will use `patch_size` of the configuration." - ) - }, - ) - encoder_stride: int | None = field( - default=None, - metadata={"help": "Stride to use for the encoder."}, - ) - - -class MaskGenerator: - """ - A class to generate boolean masks for the pretraining task. - - A mask is a 1D tensor of shape (model_patch_size**2,) where the value is either 0 or 1, - where 1 indicates "masked". - """ - - def __init__(self, input_size=192, mask_patch_size=32, model_patch_size=4, mask_ratio=0.6): - self.input_size = input_size - self.mask_patch_size = mask_patch_size - self.model_patch_size = model_patch_size - self.mask_ratio = mask_ratio - - if self.input_size % self.mask_patch_size != 0: - raise ValueError("Input size must be divisible by mask patch size") - if self.mask_patch_size % self.model_patch_size != 0: - raise ValueError("Mask patch size must be divisible by model patch size") - - self.rand_size = self.input_size // self.mask_patch_size - self.scale = self.mask_patch_size // self.model_patch_size - - self.token_count = self.rand_size**2 - self.mask_count = int(np.ceil(self.token_count * self.mask_ratio)) - - def __call__(self): - mask_idx = np.random.permutation(self.token_count)[: self.mask_count] - mask = np.zeros(self.token_count, dtype=int) - mask[mask_idx] = 1 - - mask = mask.reshape((self.rand_size, self.rand_size)) - mask = mask.repeat(self.scale, axis=0).repeat(self.scale, axis=1) - - return torch.tensor(mask.flatten()) - - -def collate_fn(examples): - pixel_values = torch.stack([example["pixel_values"] for example in examples]) - mask = torch.stack([example["mask"] for example in examples]) - return {"pixel_values": pixel_values, "bool_masked_pos": mask} - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Initialize our dataset. - ds = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - data_files=data_args.data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # If we don't have a validation split, split off a percentage of train as validation. - data_args.train_val_split = None if "validation" in ds else data_args.train_val_split - if isinstance(data_args.train_val_split, float) and data_args.train_val_split > 0.0: - split = ds["train"].train_test_split(data_args.train_val_split) - ds["train"] = split["train"] - ds["validation"] = split["test"] - - # Create config - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config_kwargs = { - "cache_dir": model_args.cache_dir, - "revision": model_args.model_revision, - "token": model_args.token, - "trust_remote_code": model_args.trust_remote_code, - } - if model_args.config_name_or_path: - config = AutoConfig.from_pretrained(model_args.config_name_or_path, **config_kwargs) - elif model_args.model_name_or_path: - config = AutoConfig.from_pretrained(model_args.model_name_or_path, **config_kwargs) - else: - config = CONFIG_MAPPING[model_args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - if model_args.config_overrides is not None: - logger.info(f"Overriding config: {model_args.config_overrides}") - config.update_from_string(model_args.config_overrides) - logger.info(f"New config: {config}") - - # make sure the decoder_type is "simmim" (only relevant for BEiT) - if hasattr(config, "decoder_type"): - config.decoder_type = "simmim" - - # adapt config - model_args.image_size = model_args.image_size if model_args.image_size is not None else config.image_size - model_args.patch_size = model_args.patch_size if model_args.patch_size is not None else config.patch_size - model_args.encoder_stride = ( - model_args.encoder_stride if model_args.encoder_stride is not None else config.encoder_stride - ) - - config.update( - { - "image_size": model_args.image_size, - "patch_size": model_args.patch_size, - "encoder_stride": model_args.encoder_stride, - } - ) - - # create image processor - if model_args.image_processor_name: - image_processor = AutoImageProcessor.from_pretrained(model_args.image_processor_name, **config_kwargs) - elif model_args.model_name_or_path: - image_processor = AutoImageProcessor.from_pretrained(model_args.model_name_or_path, **config_kwargs) - else: - IMAGE_PROCESSOR_TYPES = { - conf.model_type: image_processor_class for conf, image_processor_class in IMAGE_PROCESSOR_MAPPING.items() - } - image_processor = IMAGE_PROCESSOR_TYPES[model_args.model_type][-1]() - - # create model - if model_args.model_name_or_path: - model = AutoModelForMaskedImageModeling.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForMaskedImageModeling.from_config(config, trust_remote_code=model_args.trust_remote_code) - - if training_args.do_train: - column_names = ds["train"].column_names - else: - column_names = ds["validation"].column_names - - if data_args.image_column_name is not None: - image_column_name = data_args.image_column_name - elif "image" in column_names: - image_column_name = "image" - elif "img" in column_names: - image_column_name = "img" - else: - image_column_name = column_names[0] - - # transformations as done in original SimMIM paper - # source: https://github.com/microsoft/SimMIM/blob/main/data/data_simmim.py - transforms = Compose( - [ - Lambda(lambda img: img.convert("RGB") if img.mode != "RGB" else img), - RandomResizedCrop(model_args.image_size, scale=(0.67, 1.0), ratio=(3.0 / 4.0, 4.0 / 3.0)), - RandomHorizontalFlip(), - ToTensor(), - Normalize(mean=image_processor.image_mean, std=image_processor.image_std), - ] - ) - - # create mask generator - mask_generator = MaskGenerator( - input_size=model_args.image_size, - mask_patch_size=data_args.mask_patch_size, - model_patch_size=model_args.patch_size, - mask_ratio=data_args.mask_ratio, - ) - - def preprocess_images(examples): - """Preprocess a batch of images by applying transforms + creating a corresponding mask, indicating - which patches to mask.""" - - examples["pixel_values"] = [transforms(image) for image in examples[image_column_name]] - examples["mask"] = [mask_generator() for i in range(len(examples[image_column_name]))] - - return examples - - if training_args.do_train: - if "train" not in ds: - raise ValueError("--do_train requires a train dataset") - if data_args.max_train_samples is not None: - ds["train"] = ds["train"].shuffle(seed=training_args.seed).select(range(data_args.max_train_samples)) - # Set the training transforms - ds["train"].set_transform(preprocess_images) - - if training_args.do_eval: - if "validation" not in ds: - raise ValueError("--do_eval requires a validation dataset") - if data_args.max_eval_samples is not None: - ds["validation"] = ( - ds["validation"].shuffle(seed=training_args.seed).select(range(data_args.max_eval_samples)) - ) - # Set the validation transforms - ds["validation"].set_transform(preprocess_images) - - # Initialize our trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=ds["train"] if training_args.do_train else None, - eval_dataset=ds["validation"] if training_args.do_eval else None, - processing_class=image_processor, - data_collator=collate_fn, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - trainer.log_metrics("train", train_result.metrics) - trainer.save_metrics("train", train_result.metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - metrics = trainer.evaluate() - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Write model card and (optionally) push to hub - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "tasks": "masked-image-modeling", - "dataset": data_args.dataset_name, - "tags": ["masked-image-modeling"], - } - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/image-pretraining/run_mim_no_trainer.py b/examples/pytorch/image-pretraining/run_mim_no_trainer.py deleted file mode 100644 index 7c99231aedb6..000000000000 --- a/examples/pytorch/image-pretraining/run_mim_no_trainer.py +++ /dev/null @@ -1,811 +0,0 @@ -#!/usr/bin/env python -# Copyright 2023 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "torch>=1.5.0", -# "torchvision>=0.6.0", -# "datasets>=1.8.0", -# ] -# /// - -import argparse -import logging -import math -import os -from pathlib import Path - -import datasets -import numpy as np -import torch -from accelerate import Accelerator, DistributedType -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from torchvision.transforms import Compose, Lambda, Normalize, RandomHorizontalFlip, RandomResizedCrop, ToTensor -from tqdm.auto import tqdm - -import transformers -from transformers import ( - CONFIG_MAPPING, - IMAGE_PROCESSOR_MAPPING, - MODEL_FOR_MASKED_IMAGE_MODELING_MAPPING, - AutoConfig, - AutoImageProcessor, - AutoModelForMaskedImageModeling, - SchedulerType, - get_scheduler, -) -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -""" Pre-training a 🤗 Transformers model for simple masked image modeling (SimMIM) -without using HuggingFace Trainer. -Any model supported by the AutoModelForMaskedImageModeling API can be used. -""" - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/image-pretraining/requirements.txt") - -MODEL_CONFIG_CLASSES = list(MODEL_FOR_MASKED_IMAGE_MODELING_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -def parse_args(): - parser = argparse.ArgumentParser( - description="Finetune a transformers model on a simple Masked Image Modeling task" - ) - parser.add_argument( - "--dataset_name", - type=str, - default="uoft-cs/cifar10", - help="Name of a dataset from the datasets package", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--image_column_name", - type=str, - default=None, - help="The column name of the images in the files. If not set, will try to use 'image' or 'img'.", - ) - parser.add_argument( - "--train_dir", - type=str, - default=None, - help="A folder containing the training data.", - ) - parser.add_argument( - "--validation_dir", - type=None, - default=None, - help="A folder containing the validation data.", - ) - parser.add_argument( - "--train_val_split", - type=float, - default=0.15, - help="Percent to split off of train for validation.", - ) - parser.add_argument( - "--mask_patch_size", - type=int, - default=32, - help="The size of the square patches to use for masking.", - ) - parser.add_argument( - "--mask_ratio", - type=float, - default=0.6, - help="Percentage of patches to mask.", - ) - parser.add_argument( - "--max_train_samples", - type=int, - default=None, - help=( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ), - ) - parser.add_argument( - "--max_eval_samples", - type=int, - default=None, - help=( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ), - ) - parser.add_argument( - "--model_name_or_path", - type=str, - default=None, - help=( - "The model checkpoint for weights initialization. Can be a local path to a pytorch_model.bin or a " - "checkpoint identifier on the hub. " - "Don't set if you want to train a model from scratch." - ), - ) - parser.add_argument( - "--model_type", - type=str, - default=None, - help="If training from scratch, pass a model type from the list: " + ", ".join(MODEL_TYPES), - ) - parser.add_argument( - "--config_name_or_path", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--config_overrides", - type=str, - default=None, - help=( - "Override some existing default config settings when a model is trained from scratch. Example: " - "n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index" - ), - ) - parser.add_argument( - "--cache_dir", - type=str, - default=None, - help="Where do you want to store (cache) the pretrained models/datasets downloaded from the hub", - ) - parser.add_argument( - "--model_revision", - type=str, - default="main", - help="The specific model version to use (can be a branch name, tag name or commit id).", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--image_processor_name", - type=str, - default=None, - help="Name or path of preprocessor config.", - ) - parser.add_argument( - "--token", - type=str, - default=None, - help=( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ), - ) - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--image_size", - type=int, - default=None, - help="The size (resolution) of each image. If not specified, will use `image_size` of the configuration.", - ) - parser.add_argument( - "--patch_size", - type=int, - default=None, - help="The size (resolution) of each patch. If not specified, will use `patch_size` of the configuration.", - ) - parser.add_argument( - "--encoder_stride", - type=int, - default=None, - help={"help": "Stride to use for the encoder."}, - ) - parser.add_argument( - "--push_to_hub", - action="store_true", - help="Whether or not to push the model to the Hub.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - parser.add_argument( - "--seed", - type=int, - default=None, - help="A seed for reproducible training.", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="The initial learning rate for [`AdamW`] optimizer.", - ) - parser.add_argument( - "--weight_decay", - type=float, - default=0.0, - help="Weight decay to use.", - ) - parser.add_argument( - "--num_train_epochs", - type=float, - default=3.0, - help="Total number of training epochs to perform (if not an integer, will perform the decimal part percents of the last epoch before stopping training).", - ) - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", - type=int, - default=0, - help="Number of steps for the warmup in the lr scheduler.", - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--output_dir", - type=str, - default=None, - help="Where to store the final model.", - ) - args = parser.parse_args() - - # Sanity checks - data_files = {} - if args.train_dir is not None: - data_files["train"] = args.train_dir - if args.validation_dir is not None: - data_files["val"] = args.validation_dir - args.data_files = data_files if data_files else None - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - return args - - -class MaskGenerator: - """ - A class to generate boolean masks for the pretraining task. - - A mask is a 1D tensor of shape (model_patch_size**2,) where the value is either 0 or 1, - where 1 indicates "masked". - """ - - def __init__(self, input_size=192, mask_patch_size=32, model_patch_size=4, mask_ratio=0.6): - self.input_size = input_size - self.mask_patch_size = mask_patch_size - self.model_patch_size = model_patch_size - self.mask_ratio = mask_ratio - - if self.input_size % self.mask_patch_size != 0: - raise ValueError("Input size must be divisible by mask patch size") - if self.mask_patch_size % self.model_patch_size != 0: - raise ValueError("Mask patch size must be divisible by model patch size") - - self.rand_size = self.input_size // self.mask_patch_size - self.scale = self.mask_patch_size // self.model_patch_size - - self.token_count = self.rand_size**2 - self.mask_count = int(np.ceil(self.token_count * self.mask_ratio)) - - def __call__(self): - mask_idx = np.random.permutation(self.token_count)[: self.mask_count] - mask = np.zeros(self.token_count, dtype=int) - mask[mask_idx] = 1 - - mask = mask.reshape((self.rand_size, self.rand_size)) - mask = mask.repeat(self.scale, axis=0).repeat(self.scale, axis=1) - - return torch.tensor(mask.flatten()) - - -def collate_fn(examples): - pixel_values = torch.stack([example["pixel_values"] for example in examples]) - mask = torch.stack([example["mask"] for example in examples]) - return {"pixel_values": pixel_values, "bool_masked_pos": mask} - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator( - gradient_accumulation_steps=args.gradient_accumulation_steps, - **accelerator_log_kwargs, - ) - - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Initialize our dataset. - ds = load_dataset( - args.dataset_name, - args.dataset_config_name, - data_files=args.data_files, - cache_dir=args.cache_dir, - token=args.token, - trust_remote_code=args.trust_remote_code, - ) - - # If we don't have a validation split, split off a percentage of train as validation. - args.train_val_split = None if "validation" in ds else args.train_val_split - if isinstance(args.train_val_split, float) and args.train_val_split > 0.0: - split = ds["train"].train_test_split(args.train_val_split) - ds["train"] = split["train"] - ds["validation"] = split["test"] - - # Create config - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config_kwargs = { - "cache_dir": args.cache_dir, - "revision": args.model_revision, - "token": args.token, - "trust_remote_code": args.trust_remote_code, - } - if args.config_name_or_path: - config = AutoConfig.from_pretrained(args.config_name_or_path, **config_kwargs) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained(args.model_name_or_path, **config_kwargs) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - if args.config_overrides is not None: - logger.info(f"Overriding config: {args.config_overrides}") - config.update_from_string(args.config_overrides) - logger.info(f"New config: {config}") - - # make sure the decoder_type is "simmim" (only relevant for BEiT) - if hasattr(config, "decoder_type"): - config.decoder_type = "simmim" - - # adapt config - args.image_size = args.image_size if args.image_size is not None else config.image_size - args.patch_size = args.patch_size if args.patch_size is not None else config.patch_size - args.encoder_stride = args.encoder_stride if args.encoder_stride is not None else config.encoder_stride - - config.update( - { - "image_size": args.image_size, - "patch_size": args.patch_size, - "encoder_stride": args.encoder_stride, - } - ) - - # create image processor - if args.image_processor_name: - image_processor = AutoImageProcessor.from_pretrained(args.image_processor_name, **config_kwargs) - elif args.model_name_or_path: - image_processor = AutoImageProcessor.from_pretrained(args.model_name_or_path, **config_kwargs) - else: - IMAGE_PROCESSOR_TYPES = { - conf.model_type: image_processor_class for conf, image_processor_class in IMAGE_PROCESSOR_MAPPING.items() - } - image_processor = IMAGE_PROCESSOR_TYPES[args.model_type]() - - # create model - if args.model_name_or_path: - model = AutoModelForMaskedImageModeling.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - cache_dir=args.cache_dir, - revision=args.model_revision, - token=args.token, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForMaskedImageModeling.from_config( - config, - token=args.token, - trust_remote_code=args.trust_remote_code, - ) - - column_names = ds["train"].column_names - - if args.image_column_name is not None: - image_column_name = args.image_column_name - elif "image" in column_names: - image_column_name = "image" - elif "img" in column_names: - image_column_name = "img" - else: - image_column_name = column_names[0] - - # transformations as done in original SimMIM paper - # source: https://github.com/microsoft/SimMIM/blob/main/data/data_simmim.py - transforms = Compose( - [ - Lambda(lambda img: img.convert("RGB")), - RandomResizedCrop(args.image_size, scale=(0.67, 1.0), ratio=(3.0 / 4.0, 4.0 / 3.0)), - RandomHorizontalFlip(), - ToTensor(), - Normalize(mean=image_processor.image_mean, std=image_processor.image_std), - ] - ) - - # create mask generator - mask_generator = MaskGenerator( - input_size=args.image_size, - mask_patch_size=args.mask_patch_size, - model_patch_size=args.patch_size, - mask_ratio=args.mask_ratio, - ) - - def preprocess_images(examples): - """Preprocess a batch of images by applying transforms + creating a corresponding mask, indicating - which patches to mask.""" - - examples["pixel_values"] = [transforms(image) for image in examples[image_column_name]] - examples["mask"] = [mask_generator() for i in range(len(examples[image_column_name]))] - - return examples - - if args.max_train_samples is not None: - ds["train"] = ds["train"].shuffle(seed=args.seed).select(range(args.max_train_samples)) - # Set the training transforms - ds["train"].set_transform(preprocess_images) - - if args.max_eval_samples is not None: - ds["validation"] = ds["validation"].shuffle(seed=args.seed).select(range(args.max_eval_samples)) - # Set the validation transforms - ds["validation"].set_transform(preprocess_images) - - # DataLoaders creation: - train_dataloader = DataLoader( - ds["train"], - shuffle=True, - collate_fn=collate_fn, - batch_size=args.per_device_train_batch_size, - ) - eval_dataloader = DataLoader( - ds["validation"], - collate_fn=collate_fn, - batch_size=args.per_device_eval_batch_size, - ) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Note -> the training dataloader needs to be prepared before we grab his length below (cause its length will be - # shorter in multiprocess) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, - optimizer, - train_dataloader, - eval_dataloader, - lr_scheduler, - ) - - # On TPU, the tie weights in our model have been disconnected, so we need to restore the ties. - if accelerator.distributed_type == DistributedType.TPU: - model.tie_weights() - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("mim_no_trainer", experiment_config) - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(ds['train'])}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(int(args.max_train_steps)), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if completed_steps >= args.max_train_steps: - break - - model.eval() - losses = [] - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - - loss = outputs.loss - losses.append(accelerator.gather_for_metrics(loss.repeat(args.per_device_eval_batch_size))) - - losses = torch.cat(losses) - eval_loss = torch.mean(losses) - - logger.info(f"epoch {epoch}: eval_loss: {eval_loss}") - - if args.with_tracking: - accelerator.log( - { - "eval_loss": eval_loss, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/instance-segmentation/README.md b/examples/pytorch/instance-segmentation/README.md deleted file mode 100644 index 7385a077e620..000000000000 --- a/examples/pytorch/instance-segmentation/README.md +++ /dev/null @@ -1,235 +0,0 @@ - - -# Instance Segmentation Examples - -This directory contains two scripts that demonstrate how to fine-tune [MaskFormer](https://huggingface.co/docs/transformers/model_doc/maskformer) and [Mask2Former](https://huggingface.co/docs/transformers/model_doc/mask2former) for instance segmentation using PyTorch. -For other instance segmentation models, such as [DETR](https://huggingface.co/docs/transformers/model_doc/detr) and [Conditional DETR](https://huggingface.co/docs/transformers/model_doc/conditional_detr), the scripts need to be adjusted to properly handle input and output data. - -Content: -- [PyTorch Version with Trainer](#pytorch-version-with-trainer) -- [PyTorch Version with Accelerate](#pytorch-version-with-accelerate) -- [Reload and Perform Inference](#reload-and-perform-inference) -- [Note on Custom Data](#note-on-custom-data) - -## PyTorch Version with Trainer - -This example is based on the script [`run_instance_segmentation.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/instance-segmentation/run_instance_segmentation.py). - -The script uses the [🤗 Trainer API](https://huggingface.co/docs/transformers/main_classes/trainer) to manage training automatically, including distributed environments. - -Here, we show how to fine-tune a [Mask2Former](https://huggingface.co/docs/transformers/model_doc/mask2former) model on a subsample of the [ADE20K](https://huggingface.co/datasets/merve/scene_parse_150) dataset. We created a [small dataset](https://huggingface.co/datasets/qubvel-hf/ade20k-mini) with approximately 2,000 images containing only "person" and "car" annotations; all other pixels are marked as "background." - -Here is the `label2id` mapping for this dataset: - -```python -label2id = { - "background": 0, - "person": 1, - "car": 2, -} -``` - -Since the `background` label is not an instance and we don't want to predict it, we will use `do_reduce_labels` to remove it from the data. - -Run the training with the following command: - -```bash -python run_instance_segmentation.py \ - --model_name_or_path facebook/mask2former-swin-tiny-coco-instance \ - --output_dir finetune-instance-segmentation-ade20k-mini-mask2former \ - --dataset_name qubvel-hf/ade20k-mini \ - --do_reduce_labels \ - --image_height 256 \ - --image_width 256 \ - --do_train \ - --fp16 \ - --num_train_epochs 40 \ - --learning_rate 1e-5 \ - --lr_scheduler_type constant \ - --per_device_train_batch_size 8 \ - --gradient_accumulation_steps 2 \ - --dataloader_num_workers 8 \ - --dataloader_persistent_workers \ - --dataloader_prefetch_factor 4 \ - --do_eval \ - --eval_strategy epoch \ - --logging_strategy epoch \ - --save_strategy epoch \ - --save_total_limit 2 \ - --push_to_hub -``` - -The resulting model can be viewed [here](https://huggingface.co/qubvel-hf/finetune-instance-segmentation-ade20k-mini-mask2former). Always refer to the original paper for details on training hyperparameters. To improve model quality, consider: -- Changing image size parameters (`--image_height`/`--image_width`) -- Adjusting training parameters such as learning rate, batch size, warmup, optimizer, and more (see [TrainingArguments](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments)) -- Adding more image augmentations (we created a helpful [HF Space](https://huggingface.co/spaces/qubvel-hf/albumentations-demo) to choose some) - -You can also replace the model [checkpoint](https://huggingface.co/models?search=maskformer). - -## PyTorch Version with Accelerate - -This example is based on the script [`run_instance_segmentation_no_trainer.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/instance-segmentation/run_instance_segmentation_no_trainer.py). - -The script uses [🤗 Accelerate](https://github.com/huggingface/accelerate) to write your own training loop in PyTorch and run it on various environments, including CPU, multi-CPU, GPU, multi-GPU, and TPU, with support for mixed precision. - -First, configure the environment: - -```bash -accelerate config -``` - -Answer the questions regarding your training environment. Then, run: - -```bash -accelerate test -``` - -This command ensures everything is ready for training. Finally, launch training with: - -```bash -accelerate launch run_instance_segmentation_no_trainer.py \ - --model_name_or_path facebook/mask2former-swin-tiny-coco-instance \ - --output_dir finetune-instance-segmentation-ade20k-mini-mask2former-no-trainer \ - --dataset_name qubvel-hf/ade20k-mini \ - --do_reduce_labels \ - --image_height 256 \ - --image_width 256 \ - --num_train_epochs 40 \ - --learning_rate 1e-5 \ - --lr_scheduler_type constant \ - --per_device_train_batch_size 8 \ - --gradient_accumulation_steps 2 \ - --dataloader_num_workers 8 \ - --push_to_hub -``` - -With this setup, you can train on multiple GPUs, log everything to trackers (like Weights and Biases, Tensorboard), and regularly push your model to the hub (with the repo name set to `args.output_dir` under your HF username). -With the default settings, the script fine-tunes a [Mask2Former](https://huggingface.co/docs/transformers/model_doc/mask2former) model on the sample of [ADE20K](https://huggingface.co/datasets/qubvel-hf/ade20k-mini) dataset. The resulting model can be viewed [here](https://huggingface.co/qubvel-hf/finetune-instance-segmentation-ade20k-mini-mask2former-no-trainer). - -## Reload and Perform Inference - -After training, you can easily load your trained model and perform inference as follows: - -```python -import torch -import requests -import matplotlib.pyplot as plt - -from PIL import Image -from transformers import Mask2FormerForUniversalSegmentation, Mask2FormerImageProcessor - -# Load image -image = Image.open(requests.get("http://farm4.staticflickr.com/3017/3071497290_31f0393363_z.jpg", stream=True).raw) - -# Load model and image processor -device = "cuda" -checkpoint = "qubvel-hf/finetune-instance-segmentation-ade20k-mini-mask2former" - -model = Mask2FormerForUniversalSegmentation.from_pretrained(checkpoint, device_map=device) -image_processor = Mask2FormerImageProcessor.from_pretrained(checkpoint) - -# Run inference on image -inputs = image_processor(images=[image], return_tensors="pt").to(device) -with torch.no_grad(): - outputs = model(**inputs) - -# Post-process outputs -outputs = image_processor.post_process_instance_segmentation(outputs, target_sizes=[(image.height, image.width)]) - -print("Mask shape: ", outputs[0]["segmentation"].shape) -print("Mask values: ", outputs[0]["segmentation"].unique()) -for segment in outputs[0]["segments_info"]: - print("Segment: ", segment) -``` - -``` -Mask shape: torch.Size([427, 640]) -Mask values: tensor([-1., 0., 1., 2., 3., 4., 5., 6.]) -Segment: {'id': 0, 'label_id': 0, 'was_fused': False, 'score': 0.946127} -Segment: {'id': 1, 'label_id': 1, 'was_fused': False, 'score': 0.961582} -Segment: {'id': 2, 'label_id': 1, 'was_fused': False, 'score': 0.968367} -Segment: {'id': 3, 'label_id': 1, 'was_fused': False, 'score': 0.819527} -Segment: {'id': 4, 'label_id': 1, 'was_fused': False, 'score': 0.655761} -Segment: {'id': 5, 'label_id': 1, 'was_fused': False, 'score': 0.531299} -Segment: {'id': 6, 'label_id': 1, 'was_fused': False, 'score': 0.929477} -``` - -Use the following code to visualize the results: - -```python -import numpy as np -import matplotlib.pyplot as plt - -segmentation = outputs[0]["segmentation"].numpy() - -plt.figure(figsize=(10, 10)) -plt.subplot(1, 2, 1) -plt.imshow(np.array(image)) -plt.axis("off") -plt.subplot(1, 2, 2) -plt.imshow(segmentation) -plt.axis("off") -plt.show() -``` - -![Result](https://i.imgur.com/rZmaRjD.png) - -## Note on Custom Data - -Here is a short script demonstrating how to create your own dataset for instance segmentation and push it to the hub: - -> Note: Annotations should be represented as 3-channel images (similar to the [scene_parsing_150](https://huggingface.co/datasets/zhoubolei/scene_parse_150#instance_segmentation-1) dataset). The first channel is a semantic-segmentation map with values corresponding to `label2id`, the second is an instance-segmentation map where each instance has a unique value, and the third channel should be empty (filled with zeros). - -```python -from datasets import Dataset, DatasetDict -from datasets import Image as DatasetImage - -label2id = { - "background": 0, - "person": 1, - "car": 2, -} - -train_split = { - "image": [, , , ...], - "annotation": [, , , ...], -} - -validation_split = { - "image": [, , , ...], - "annotation": [, , , ...], -} - -def create_instance_segmentation_dataset(label2id, **splits): - dataset_dict = {} - for split_name, split in splits.items(): - split["semantic_class_to_id"] = [label2id] * len(split["image"]) - dataset_split = ( - Dataset.from_dict(split) - .cast_column("image", DatasetImage()) - .cast_column("annotation", DatasetImage()) - ) - dataset_dict[split_name] = dataset_split - return DatasetDict(dataset_dict) - -dataset = create_instance_segmentation_dataset(label2id, train=train_split, validation=validation_split) -dataset.push_to_hub("qubvel-hf/ade20k-nano") -``` - -Use this dataset for fine-tuning by specifying its name with `--dataset_name `. - -See also: [Dataset Creation Guide](https://huggingface.co/docs/datasets/image_dataset#create-an-image-dataset) \ No newline at end of file diff --git a/examples/pytorch/instance-segmentation/requirements.txt b/examples/pytorch/instance-segmentation/requirements.txt deleted file mode 100644 index 7772958dee7a..000000000000 --- a/examples/pytorch/instance-segmentation/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -albumentations >= 1.4.16 -timm -datasets -torchmetrics -pycocotools diff --git a/examples/pytorch/instance-segmentation/run_instance_segmentation.py b/examples/pytorch/instance-segmentation/run_instance_segmentation.py deleted file mode 100644 index be0a1a2c115e..000000000000 --- a/examples/pytorch/instance-segmentation/run_instance_segmentation.py +++ /dev/null @@ -1,476 +0,0 @@ -#!/usr/bin/env python -# Copyright 2024 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "timm", -# "datasets", -# "torchmetrics", -# "pycocotools", -# ] -# /// - -"""Finetuning 🤗 Transformers model for instance segmentation leveraging the Trainer API.""" - -import logging -import os -import sys -from collections.abc import Mapping -from dataclasses import dataclass, field -from functools import partial -from typing import Any - -import albumentations as A -import numpy as np -import torch -from datasets import load_dataset -from torchmetrics.detection.mean_ap import MeanAveragePrecision - -import transformers -from transformers import ( - AutoImageProcessor, - AutoModelForUniversalSegmentation, - HfArgumentParser, - Trainer, - TrainingArguments, -) -from transformers.image_processing_utils import BatchFeature -from transformers.trainer import EvalPrediction -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.0.0", "To fix: pip install -r examples/pytorch/instance-segmentation/requirements.txt") - - -@dataclass -class Arguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - Using `HfArgumentParser` we can turn this class into argparse arguments to be able to specify - them on the command line. - """ - - model_name_or_path: str = field( - default="facebook/mask2former-swin-tiny-coco-instance", - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}, - ) - dataset_name: str = field( - default="qubvel-hf/ade20k-mini", - metadata={ - "help": "Name of a dataset from the hub (could be your own, possibly private dataset hosted on the hub)." - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - image_height: int | None = field(default=512, metadata={"help": "Image height after resizing."}) - image_width: int | None = field(default=512, metadata={"help": "Image width after resizing."}) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - do_reduce_labels: bool = field( - default=False, - metadata={ - "help": ( - "If background class is labeled as 0 and you want to remove it from the labels, set this flag to True." - ) - }, - ) - - -def augment_and_transform_batch( - examples: Mapping[str, Any], transform: A.Compose, image_processor: AutoImageProcessor -) -> BatchFeature: - batch = { - "pixel_values": [], - "mask_labels": [], - "class_labels": [], - } - - for pil_image, pil_annotation in zip(examples["image"], examples["annotation"]): - image = np.array(pil_image) - semantic_and_instance_masks = np.array(pil_annotation)[..., :2] - - # Apply augmentations - output = transform(image=image, mask=semantic_and_instance_masks) - - aug_image = output["image"] - aug_semantic_and_instance_masks = output["mask"] - aug_instance_mask = aug_semantic_and_instance_masks[..., 1] - - # Create mapping from instance id to semantic id - unique_semantic_id_instance_id_pairs = np.unique(aug_semantic_and_instance_masks.reshape(-1, 2), axis=0) - instance_id_to_semantic_id = { - instance_id: semantic_id for semantic_id, instance_id in unique_semantic_id_instance_id_pairs - } - - # Apply the image processor transformations: resizing, rescaling, normalization - model_inputs = image_processor( - images=[aug_image], - segmentation_maps=[aug_instance_mask], - instance_id_to_semantic_id=instance_id_to_semantic_id, - return_tensors="pt", - ) - - batch["pixel_values"].append(model_inputs.pixel_values[0]) - batch["mask_labels"].append(model_inputs.mask_labels[0]) - batch["class_labels"].append(model_inputs.class_labels[0]) - - return batch - - -def collate_fn(examples): - batch = {} - batch["pixel_values"] = torch.stack([example["pixel_values"] for example in examples]) - batch["class_labels"] = [example["class_labels"] for example in examples] - batch["mask_labels"] = [example["mask_labels"] for example in examples] - if "pixel_mask" in examples[0]: - batch["pixel_mask"] = torch.stack([example["pixel_mask"] for example in examples]) - return batch - - -@dataclass -class ModelOutput: - class_queries_logits: torch.Tensor - masks_queries_logits: torch.Tensor - - -def nested_cpu(tensors): - if isinstance(tensors, (list, tuple)): - return type(tensors)(nested_cpu(t) for t in tensors) - elif isinstance(tensors, Mapping): - return type(tensors)({k: nested_cpu(t) for k, t in tensors.items()}) - elif isinstance(tensors, torch.Tensor): - return tensors.cpu().detach() - else: - return tensors - - -class Evaluator: - """ - Compute metrics for the instance segmentation task. - """ - - def __init__( - self, - image_processor: AutoImageProcessor, - id2label: Mapping[int, str], - threshold: float = 0.0, - ): - """ - Initialize evaluator with image processor, id2label mapping and threshold for filtering predictions. - - Args: - image_processor (AutoImageProcessor): Image processor for - `post_process_instance_segmentation` method. - id2label (Mapping[int, str]): Mapping from class id to class name. - threshold (float): Threshold to filter predicted boxes by confidence. Defaults to 0.0. - """ - self.image_processor = image_processor - self.id2label = id2label - self.threshold = threshold - self.metric = self.get_metric() - - def get_metric(self): - metric = MeanAveragePrecision(iou_type="segm", class_metrics=True) - return metric - - def reset_metric(self): - self.metric.reset() - - def postprocess_target_batch(self, target_batch) -> list[dict[str, torch.Tensor]]: - """Collect targets in a form of list of dictionaries with keys "masks", "labels".""" - batch_masks = target_batch[0] - batch_labels = target_batch[1] - post_processed_targets = [] - for masks, labels in zip(batch_masks, batch_labels): - post_processed_targets.append( - { - "masks": masks.to(dtype=torch.bool), - "labels": labels, - } - ) - return post_processed_targets - - def get_target_sizes(self, post_processed_targets) -> list[list[int]]: - target_sizes = [] - for target in post_processed_targets: - target_sizes.append(target["masks"].shape[-2:]) - return target_sizes - - def postprocess_prediction_batch(self, prediction_batch, target_sizes) -> list[dict[str, torch.Tensor]]: - """Collect predictions in a form of list of dictionaries with keys "masks", "labels", "scores".""" - - model_output = ModelOutput(class_queries_logits=prediction_batch[0], masks_queries_logits=prediction_batch[1]) - post_processed_output = self.image_processor.post_process_instance_segmentation( - model_output, - threshold=self.threshold, - target_sizes=target_sizes, - return_binary_maps=True, - ) - - post_processed_predictions = [] - for image_predictions, target_size in zip(post_processed_output, target_sizes): - if image_predictions["segments_info"]: - post_processed_image_prediction = { - "masks": image_predictions["segmentation"].to(dtype=torch.bool), - "labels": torch.tensor([x["label_id"] for x in image_predictions["segments_info"]]), - "scores": torch.tensor([x["score"] for x in image_predictions["segments_info"]]), - } - else: - # for void predictions, we need to provide empty tensors - post_processed_image_prediction = { - "masks": torch.zeros([0, *target_size], dtype=torch.bool), - "labels": torch.tensor([]), - "scores": torch.tensor([]), - } - post_processed_predictions.append(post_processed_image_prediction) - - return post_processed_predictions - - @torch.no_grad() - def __call__(self, evaluation_results: EvalPrediction, compute_result: bool = False) -> Mapping[str, float]: - """ - Update metrics with current evaluation results and return metrics if `compute_result` is True. - - Args: - evaluation_results (EvalPrediction): Predictions and targets from evaluation. - compute_result (bool): Whether to compute and return metrics. - - Returns: - Mapping[str, float]: Metrics in a form of dictionary {: } - """ - prediction_batch = nested_cpu(evaluation_results.predictions) - target_batch = nested_cpu(evaluation_results.label_ids) - - # For metric computation we need to provide: - # - targets in a form of list of dictionaries with keys "masks", "labels" - # - predictions in a form of list of dictionaries with keys "masks", "labels", "scores" - post_processed_targets = self.postprocess_target_batch(target_batch) - target_sizes = self.get_target_sizes(post_processed_targets) - post_processed_predictions = self.postprocess_prediction_batch(prediction_batch, target_sizes) - - # Compute metrics - self.metric.update(post_processed_predictions, post_processed_targets) - - if not compute_result: - return - - metrics = self.metric.compute() - - # Replace list of per class metrics with separate metric for each class - classes = metrics.pop("classes") - map_per_class = metrics.pop("map_per_class") - mar_100_per_class = metrics.pop("mar_100_per_class") - for class_id, class_map, class_mar in zip(classes, map_per_class, mar_100_per_class): - class_name = self.id2label[class_id.item()] if self.id2label is not None else class_id.item() - metrics[f"map_{class_name}"] = class_map - metrics[f"mar_100_{class_name}"] = class_mar - - metrics = {k: round(v.item(), 4) for k, v in metrics.items()} - - # Reset metric for next evaluation - self.reset_metric() - - return metrics - - -def setup_logging(training_args: TrainingArguments) -> None: - """Setup logging according to `training_args`.""" - - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - -def find_last_checkpoint(training_args: TrainingArguments) -> str | None: - """Find the last checkpoint in the output directory according to parameters specified in `training_args`.""" - - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - - return checkpoint - - -def main(): - # See all possible arguments in https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments - # or by passing the --help flag to this script. - - parser = HfArgumentParser([Arguments, TrainingArguments]) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - args, training_args = parser.parse_args_into_dataclasses() - - # Set default training arguments for instance segmentation - training_args.eval_do_concat_batches = False - training_args.batch_eval_metrics = True - training_args.remove_unused_columns = False - - # Setup logging and log on each process the small summary: - setup_logging(training_args) - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Load last checkpoint from output_dir if it exists (and we are not overwriting it) - checkpoint = find_last_checkpoint(training_args) - - # ------------------------------------------------------------------------------------------------ - # Load dataset, prepare splits - # ------------------------------------------------------------------------------------------------ - - dataset = load_dataset(args.dataset_name, trust_remote_code=args.trust_remote_code) - - # We need to specify the label2id mapping for the model - # it is a mapping from semantic class name to class index. - # In case your dataset does not provide it, you can create it manually: - # label2id = {"background": 0, "cat": 1, "dog": 2} - label2id = dataset["train"][0]["semantic_class_to_id"] - - if args.do_reduce_labels: - label2id = {name: idx for name, idx in label2id.items() if idx != 0} # remove background class - label2id = {name: idx - 1 for name, idx in label2id.items()} # shift class indices by -1 - - id2label = {v: k for k, v in label2id.items()} - - # ------------------------------------------------------------------------------------------------ - # Load pretrained config, model and image processor - # ------------------------------------------------------------------------------------------------ - model = AutoModelForUniversalSegmentation.from_pretrained( - args.model_name_or_path, - label2id=label2id, - id2label=id2label, - ignore_mismatched_sizes=True, - token=args.token, - ) - - image_processor = AutoImageProcessor.from_pretrained( - args.model_name_or_path, - do_resize=True, - size={"height": args.image_height, "width": args.image_width}, - do_reduce_labels=args.do_reduce_labels, - reduce_labels=args.do_reduce_labels, # TODO: remove when mask2former support `do_reduce_labels` - token=args.token, - ) - - # ------------------------------------------------------------------------------------------------ - # Define image augmentations and dataset transforms - # ------------------------------------------------------------------------------------------------ - train_augment_and_transform = A.Compose( - [ - A.HorizontalFlip(p=0.5), - A.RandomBrightnessContrast(p=0.5), - A.HueSaturationValue(p=0.1), - ], - ) - validation_transform = A.Compose( - [A.NoOp()], - ) - - # Make transform functions for batch and apply for dataset splits - train_transform_batch = partial( - augment_and_transform_batch, transform=train_augment_and_transform, image_processor=image_processor - ) - validation_transform_batch = partial( - augment_and_transform_batch, transform=validation_transform, image_processor=image_processor - ) - - dataset["train"] = dataset["train"].with_transform(train_transform_batch) - dataset["validation"] = dataset["validation"].with_transform(validation_transform_batch) - - # ------------------------------------------------------------------------------------------------ - # Model training and evaluation with Trainer API - # ------------------------------------------------------------------------------------------------ - - compute_metrics = Evaluator(image_processor=image_processor, id2label=id2label, threshold=0.0) - - trainer = Trainer( - model=model, - args=training_args, - train_dataset=dataset["train"] if training_args.do_train else None, - eval_dataset=dataset["validation"] if training_args.do_eval else None, - processing_class=image_processor, - data_collator=collate_fn, - compute_metrics=compute_metrics, - ) - - # Training - if training_args.do_train: - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - trainer.log_metrics("train", train_result.metrics) - trainer.save_metrics("train", train_result.metrics) - trainer.save_state() - - # Final evaluation - if training_args.do_eval: - metrics = trainer.evaluate(eval_dataset=dataset["validation"], metric_key_prefix="test") - trainer.log_metrics("test", metrics) - trainer.save_metrics("test", metrics) - - # Write model card and (optionally) push to hub - kwargs = { - "finetuned_from": args.model_name_or_path, - "dataset": args.dataset_name, - "tags": ["image-segmentation", "instance-segmentation", "vision"], - } - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/instance-segmentation/run_instance_segmentation_no_trainer.py b/examples/pytorch/instance-segmentation/run_instance_segmentation_no_trainer.py deleted file mode 100644 index 2559498ec85b..000000000000 --- a/examples/pytorch/instance-segmentation/run_instance_segmentation_no_trainer.py +++ /dev/null @@ -1,751 +0,0 @@ -#!/usr/bin/env python -# Copyright 2024 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "timm", -# "datasets", -# "torchmetrics", -# "pycocotools", -# ] -# /// - -"""Finetuning 🤗 Transformers model for instance segmentation with Accelerate 🚀.""" - -import argparse -import json -import logging -import math -import os -import sys -from collections.abc import Mapping -from functools import partial -from pathlib import Path -from typing import Any - -import albumentations as A -import datasets -import numpy as np -import torch -from accelerate import Accelerator -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch.utils.data import DataLoader -from torchmetrics.detection.mean_ap import MeanAveragePrecision -from tqdm import tqdm - -import transformers -from transformers import ( - AutoImageProcessor, - AutoModelForUniversalSegmentation, - SchedulerType, - get_scheduler, -) -from transformers.image_processing_utils import BatchFeature -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.0.0", "To fix: pip install -r examples/pytorch/instance-segmentation/requirements.txt") - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model for instance segmentation task") - - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to a pretrained model or model identifier from huggingface.co/models.", - default="facebook/mask2former-swin-tiny-coco-instance", - ) - parser.add_argument( - "--dataset_name", - type=str, - help="Name of the dataset on the hub.", - default="qubvel-hf/ade20k-mini", - ) - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--image_height", - type=int, - default=384, - help="The height of the images to feed the model.", - ) - parser.add_argument( - "--image_width", - type=int, - default=384, - help="The width of the images to feed the model.", - ) - parser.add_argument( - "--do_reduce_labels", - action="store_true", - help="Whether to reduce the number of labels by removing the background class.", - ) - parser.add_argument( - "--cache_dir", - type=str, - help="Path to a folder in which the model and dataset will be cached.", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--dataloader_num_workers", - type=int, - default=4, - help="Number of workers to use for the dataloaders.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument( - "--adam_beta1", - type=float, - default=0.9, - help="Beta1 for AdamW optimizer", - ) - parser.add_argument( - "--adam_beta2", - type=float, - default=0.999, - help="Beta2 for AdamW optimizer", - ) - parser.add_argument( - "--adam_epsilon", - type=float, - default=1e-8, - help="Epsilon for AdamW optimizer", - ) - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - required=False, - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - if args.push_to_hub or args.with_tracking: - if args.output_dir is None: - raise ValueError( - "Need an `output_dir` to create a repo when `--push_to_hub` or `with_tracking` is specified." - ) - - if args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - - return args - - -def augment_and_transform_batch( - examples: Mapping[str, Any], transform: A.Compose, image_processor: AutoImageProcessor -) -> BatchFeature: - batch = { - "pixel_values": [], - "mask_labels": [], - "class_labels": [], - } - - for pil_image, pil_annotation in zip(examples["image"], examples["annotation"]): - image = np.array(pil_image) - semantic_and_instance_masks = np.array(pil_annotation)[..., :2] - - # Apply augmentations - output = transform(image=image, mask=semantic_and_instance_masks) - - aug_image = output["image"] - aug_semantic_and_instance_masks = output["mask"] - aug_instance_mask = aug_semantic_and_instance_masks[..., 1] - - # Create mapping from instance id to semantic id - unique_semantic_id_instance_id_pairs = np.unique(aug_semantic_and_instance_masks.reshape(-1, 2), axis=0) - instance_id_to_semantic_id = { - instance_id: semantic_id for semantic_id, instance_id in unique_semantic_id_instance_id_pairs - } - - # Apply the image processor transformations: resizing, rescaling, normalization - model_inputs = image_processor( - images=[aug_image], - segmentation_maps=[aug_instance_mask], - instance_id_to_semantic_id=instance_id_to_semantic_id, - return_tensors="pt", - ) - - batch["pixel_values"].append(model_inputs.pixel_values[0]) - batch["mask_labels"].append(model_inputs.mask_labels[0]) - batch["class_labels"].append(model_inputs.class_labels[0]) - - return batch - - -def collate_fn(examples): - batch = {} - batch["pixel_values"] = torch.stack([example["pixel_values"] for example in examples]) - batch["class_labels"] = [example["class_labels"] for example in examples] - batch["mask_labels"] = [example["mask_labels"] for example in examples] - if "pixel_mask" in examples[0]: - batch["pixel_mask"] = torch.stack([example["pixel_mask"] for example in examples]) - return batch - - -def nested_cpu(tensors): - if isinstance(tensors, (list, tuple)): - return type(tensors)(nested_cpu(t) for t in tensors) - elif isinstance(tensors, Mapping): - return type(tensors)({k: nested_cpu(t) for k, t in tensors.items()}) - elif isinstance(tensors, torch.Tensor): - return tensors.cpu().detach() - else: - return tensors - - -def evaluation_loop(model, image_processor, accelerator: Accelerator, dataloader, id2label): - metric = MeanAveragePrecision(iou_type="segm", class_metrics=True) - - for inputs in tqdm(dataloader, total=len(dataloader), disable=not accelerator.is_local_main_process): - with torch.no_grad(): - outputs = model(**inputs) - - inputs = accelerator.gather_for_metrics(inputs) - inputs = nested_cpu(inputs) - - outputs = accelerator.gather_for_metrics(outputs) - outputs = nested_cpu(outputs) - - # For metric computation we need to provide: - # - targets in a form of list of dictionaries with keys "masks", "labels" - # - predictions in a form of list of dictionaries with keys "masks", "labels", "scores" - - post_processed_targets = [] - post_processed_predictions = [] - target_sizes = [] - - # Collect targets - for masks, labels in zip(inputs["mask_labels"], inputs["class_labels"]): - post_processed_targets.append( - { - "masks": masks.to(dtype=torch.bool), - "labels": labels, - } - ) - target_sizes.append(masks.shape[-2:]) - - # Collect predictions - post_processed_output = image_processor.post_process_instance_segmentation( - outputs, - threshold=0.0, - target_sizes=target_sizes, - return_binary_maps=True, - ) - - for image_predictions, target_size in zip(post_processed_output, target_sizes): - if image_predictions["segments_info"]: - post_processed_image_prediction = { - "masks": image_predictions["segmentation"].to(dtype=torch.bool), - "labels": torch.tensor([x["label_id"] for x in image_predictions["segments_info"]]), - "scores": torch.tensor([x["score"] for x in image_predictions["segments_info"]]), - } - else: - # for void predictions, we need to provide empty tensors - post_processed_image_prediction = { - "masks": torch.zeros([0, *target_size], dtype=torch.bool), - "labels": torch.tensor([]), - "scores": torch.tensor([]), - } - post_processed_predictions.append(post_processed_image_prediction) - - # Update metric for batch targets and predictions - metric.update(post_processed_predictions, post_processed_targets) - - # Compute metrics - metrics = metric.compute() - - # Replace list of per class metrics with separate metric for each class - classes = metrics.pop("classes") - map_per_class = metrics.pop("map_per_class") - mar_100_per_class = metrics.pop("mar_100_per_class") - for class_id, class_map, class_mar in zip(classes, map_per_class, mar_100_per_class): - class_name = id2label[class_id.item()] if id2label is not None else class_id.item() - metrics[f"map_{class_name}"] = class_map - metrics[f"mar_100_{class_name}"] = class_mar - - metrics = {k: round(v.item(), 4) for k, v in metrics.items()} - - return metrics - - -def setup_logging(accelerator: Accelerator) -> None: - """Setup logging according to `training_args`.""" - - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - logger.setLevel(logging.INFO) - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - -def handle_repository_creation(accelerator: Accelerator, args: argparse.Namespace): - """Create a repository for the model and dataset if `args.push_to_hub` is set.""" - - repo_id = None - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - return repo_id - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - setup_logging(accelerator) - - # If passed along, set the training seed now. - # We set device_specific to True as we want different data augmentation per device. - if args.seed is not None: - set_seed(args.seed, device_specific=True) - - # Create repository if push ot hub is specified - repo_id = handle_repository_creation(accelerator, args) - - if args.push_to_hub: - api = HfApi() - - # ------------------------------------------------------------------------------------------------ - # Load dataset, prepare splits - # ------------------------------------------------------------------------------------------------ - - # In distributed training, the load_dataset function guarantees that only one local process can concurrently - # download the dataset. - dataset = load_dataset(args.dataset_name, cache_dir=args.cache_dir, trust_remote_code=args.trust_remote_code) - - # We need to specify the label2id mapping for the model - # it is a mapping from semantic class name to class index. - # In case your dataset does not provide it, you can create it manually: - # label2id = {"background": 0, "cat": 1, "dog": 2} - label2id = dataset["train"][0]["semantic_class_to_id"] - - if args.do_reduce_labels: - label2id = {name: idx for name, idx in label2id.items() if idx != 0} # remove background class - label2id = {name: idx - 1 for name, idx in label2id.items()} # shift class indices by -1 - - id2label = {v: k for k, v in label2id.items()} - - # ------------------------------------------------------------------------------------------------ - # Load pretrained model and image processor - # ------------------------------------------------------------------------------------------------ - model = AutoModelForUniversalSegmentation.from_pretrained( - args.model_name_or_path, - label2id=label2id, - id2label=id2label, - ignore_mismatched_sizes=True, - token=args.hub_token, - ) - - image_processor = AutoImageProcessor.from_pretrained( - args.model_name_or_path, - do_resize=True, - size={"height": args.image_height, "width": args.image_width}, - do_reduce_labels=args.do_reduce_labels, - reduce_labels=args.do_reduce_labels, # TODO: remove when mask2former support `do_reduce_labels` - token=args.hub_token, - ) - - # ------------------------------------------------------------------------------------------------ - # Define image augmentations and dataset transforms - # ------------------------------------------------------------------------------------------------ - train_augment_and_transform = A.Compose( - [ - A.HorizontalFlip(p=0.5), - A.RandomBrightnessContrast(p=0.5), - A.HueSaturationValue(p=0.1), - ], - ) - validation_transform = A.Compose( - [A.NoOp()], - ) - - # Make transform functions for batch and apply for dataset splits - train_transform_batch = partial( - augment_and_transform_batch, transform=train_augment_and_transform, image_processor=image_processor - ) - validation_transform_batch = partial( - augment_and_transform_batch, transform=validation_transform, image_processor=image_processor - ) - - with accelerator.main_process_first(): - dataset["train"] = dataset["train"].with_transform(train_transform_batch) - dataset["validation"] = dataset["validation"].with_transform(validation_transform_batch) - - dataloader_common_args = { - "num_workers": args.dataloader_num_workers, - "persistent_workers": True, - "collate_fn": collate_fn, - } - train_dataloader = DataLoader( - dataset["train"], shuffle=True, batch_size=args.per_device_train_batch_size, **dataloader_common_args - ) - valid_dataloader = DataLoader( - dataset["validation"], shuffle=False, batch_size=args.per_device_eval_batch_size, **dataloader_common_args - ) - - # ------------------------------------------------------------------------------------------------ - # Define optimizer, scheduler and prepare everything with the accelerator - # ------------------------------------------------------------------------------------------------ - - # Optimizer - optimizer = torch.optim.AdamW( - list(model.parameters()), - lr=args.learning_rate, - betas=[args.adam_beta1, args.adam_beta2], - eps=args.adam_epsilon, - ) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, valid_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, valid_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("instance_segmentation_no_trainer", experiment_config) - - # ------------------------------------------------------------------------------------------------ - # Run training with evaluation on each epoch - # ------------------------------------------------------------------------------------------------ - - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(dataset['train'])}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, - is_main_process=accelerator.is_main_process, - save_function=accelerator.save, - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - repo_id=repo_id, - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_type="model", - token=args.hub_token, - ) - - if completed_steps >= args.max_train_steps: - break - - logger.info("***** Running evaluation *****") - metrics = evaluation_loop(model, image_processor, accelerator, valid_dataloader, id2label) - - logger.info(f"epoch {epoch}: {metrics}") - - if args.with_tracking: - accelerator.log( - { - "train_loss": total_loss.item() / len(train_dataloader), - **metrics, - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - # ------------------------------------------------------------------------------------------------ - # Run evaluation on test dataset and save the model - # ------------------------------------------------------------------------------------------------ - - logger.info("***** Running evaluation on test dataset *****") - metrics = evaluation_loop(model, image_processor, accelerator, valid_dataloader, id2label) - metrics = {f"test_{k}": v for k, v in metrics.items()} - - logger.info(f"Test metrics: {metrics}") - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump(metrics, f, indent=2) - - image_processor.save_pretrained(args.output_dir) - - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ignore_patterns=["epoch_*"], - ) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/language-modeling/README.md b/examples/pytorch/language-modeling/README.md deleted file mode 100644 index df268387269e..000000000000 --- a/examples/pytorch/language-modeling/README.md +++ /dev/null @@ -1,240 +0,0 @@ - - -## Language model training - -Fine-tuning (or training from scratch) the library models for language modeling on a text dataset for GPT, GPT-2, -ALBERT, BERT, DistilBERT, RoBERTa, XLNet... GPT and GPT-2 are trained or fine-tuned using a causal language modeling -(CLM) loss while ALBERT, BERT, DistilBERT and RoBERTa are trained or fine-tuned using a masked language modeling (MLM) -loss. XLNet uses permutation language modeling (PLM), you can find more information about the differences between those -objectives in our [model summary](https://huggingface.co/transformers/model_summary.html). - -There are two sets of scripts provided. The first set leverages the Trainer API. The second set with `no_trainer` in the suffix uses a custom training loop and leverages the 🤗 Accelerate library . Both sets use the 🤗 Datasets library. You can easily customize them to your needs if you need extra processing on your datasets. - -The following examples, will run on datasets hosted on our [hub](https://huggingface.co/datasets) or with your own -text files for training and validation. We give examples of both below. - -### GPT-2/GPT and causal language modeling - -The following example fine-tunes GPT-2 on WikiText-2. We're using the raw WikiText-2 (no tokens were replaced before -the tokenization). The loss here is that of causal language modeling. - -```bash -python run_clm.py \ - --model_name_or_path openai-community/gpt2 \ - --dataset_name Salesforce/wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --do_train \ - --do_eval \ - --output_dir /tmp/test-clm -``` - -This takes about half an hour to train on a single K80 GPU and about one minute for the evaluation to run. It reaches -a score of ~20 perplexity once fine-tuned on the dataset. - -To run on your own training and validation files, use the following command: - -```bash -python run_clm.py \ - --model_name_or_path openai-community/gpt2 \ - --train_file path_to_train_file \ - --validation_file path_to_validation_file \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --do_train \ - --do_eval \ - --output_dir /tmp/test-clm -``` - -This uses the built in HuggingFace `Trainer` for training. If you want to use a custom training loop, you can utilize or adapt the `run_clm_no_trainer.py` script. Take a look at the script for a list of supported arguments. An example is shown below: - -```bash -python run_clm_no_trainer.py \ - --dataset_name Salesforce/wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --model_name_or_path openai-community/gpt2 \ - --output_dir /tmp/test-clm -``` - -### GPT-2/GPT and causal language modeling with fill-in-the middle objective - -The following example fine-tunes GPT-2 on WikiText-2 but using the Fill-in-middle training objective. FIM objective was proposed in [Efficient Training of Language Models to Fill in the Middle](https://huggingface.co/papers/2207.14255). They showed that autoregressive language models can learn to infill text after applying a straightforward transformation to the dataset, which simply moves a span of text from the middle of a document to its end. - -We're using the raw WikiText-2 (no tokens were replaced before the tokenization). The loss here is that of causal language modeling. - -```bash -python run_fim.py \ - --model_name_or_path gpt2 \ - --dataset_name Salesforce/wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --fim_rate 0.5 \ - --fim_spm_rate 0.2 \ - --do_train \ - --do_eval \ - --output_dir /tmp/test-clm -``` - -To run on your own training and validation files, use the following command: - -```bash -python run_fim.py \ - --model_name_or_path gpt2 \ - --train_file path_to_train_file \ - --validation_file path_to_validation_file \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --fim_rate 0.5 \ - --fim_spm_rate 0.2 \ - --do_train \ - --do_eval \ - --output_dir /tmp/test-clm -``` - -This uses the built in HuggingFace `Trainer` for training. If you want to use a custom training loop, you can utilize or adapt the `run_fim_no_trainer.py` script. Take a look at the script for a list of supported arguments. An example is shown below: - -```bash -python run_fim_no_trainer.py \ - --model_name_or_path gpt2 \ - --dataset_name Salesforce/wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --model_name_or_path gpt2 \ - --fim_rate 0.5 \ - --fim_spm_rate 0.2 \ - --output_dir /tmp/test-clm -``` - -**Note**: Passing in FIM rate as `0.5` means that FIM transformations will be applied to the dataset with a probability of 50%. Whereas passing in FIM SPM rate as `0.2` means that 20% of FIM transformations will use SPM (or Suffix-Prefix-Middle) and the remaining 80% will use PSM (or Prefix-Suffix-Middle) mode of transformation. - -### RoBERTa/BERT/DistilBERT and masked language modeling - -The following example fine-tunes RoBERTa on WikiText-2. Here too, we're using the raw WikiText-2. The loss is different -as BERT/RoBERTa have a bidirectional mechanism; we're therefore using the same loss that was used during their -pre-training: masked language modeling. - -In accordance to the RoBERTa paper, we use dynamic masking rather than static masking. The model may, therefore, -converge slightly slower (over-fitting takes more epochs). - -```bash -python run_mlm.py \ - --model_name_or_path FacebookAI/roberta-base \ - --dataset_name Salesforce/wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --do_train \ - --do_eval \ - --output_dir /tmp/test-mlm -``` - -To run on your own training and validation files, use the following command: - -```bash -python run_mlm.py \ - --model_name_or_path FacebookAI/roberta-base \ - --train_file path_to_train_file \ - --validation_file path_to_validation_file \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --do_train \ - --do_eval \ - --output_dir /tmp/test-mlm -``` - -If your dataset is organized with one sample per line, you can use the `--line_by_line` flag (otherwise the script -concatenates all texts and then splits them in blocks of the same length). - -This uses the built in HuggingFace `Trainer` for training. If you want to use a custom training loop, you can utilize or adapt the `run_mlm_no_trainer.py` script. Take a look at the script for a list of supported arguments. An example is shown below: - -```bash -python run_mlm_no_trainer.py \ - --dataset_name Salesforce/wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --model_name_or_path FacebookAI/roberta-base \ - --output_dir /tmp/test-mlm -``` - -**Note:** On TPU, you should use the flag `--pad_to_max_length` in conjunction with the `--line_by_line` flag to make -sure all your batches have the same length. - -### Whole word masking - -This part was moved to https://github.com/huggingface/transformers-research-projects/tree/main/mlm_wwm. - -### XLNet and permutation language modeling - -XLNet uses a different training objective, which is permutation language modeling. It is an autoregressive method -to learn bidirectional contexts by maximizing the expected likelihood over all permutations of the input -sequence factorization order. - -We use the `--plm_probability` flag to define the ratio of length of a span of masked tokens to surrounding -context length for permutation language modeling. - -The `--max_span_length` flag may also be used to limit the length of a span of masked tokens used -for permutation language modeling. - -Here is how to fine-tune XLNet on wikitext-2: - -```bash -python run_plm.py \ - --model_name_or_path=xlnet/xlnet-base-cased \ - --dataset_name Salesforce/wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --do_train \ - --do_eval \ - --output_dir /tmp/test-plm -``` - -To fine-tune it on your own training and validation file, run: - -```bash -python run_plm.py \ - --model_name_or_path=xlnet/xlnet-base-cased \ - --train_file path_to_train_file \ - --validation_file path_to_validation_file \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --do_train \ - --do_eval \ - --output_dir /tmp/test-plm -``` - -If your dataset is organized with one sample per line, you can use the `--line_by_line` flag (otherwise the script -concatenates all texts and then splits them in blocks of the same length). - -**Note:** On TPU, you should use the flag `--pad_to_max_length` in conjunction with the `--line_by_line` flag to make -sure all your batches have the same length. - -## Streaming - -To use the streaming dataset mode which can be very useful for large datasets, add `--streaming` to the command line. This is supported by `run_mlm.py`, `run_clm.py` and `run_fim.py`. Make sure to adapt the other scripts to your use case by taking inspiration from them. - -## Creating a model on the fly - -When training a model from scratch, configuration values may be overridden with the help of `--config_overrides`: - - -```bash -python run_clm.py --model_type gpt2 --tokenizer_name openai-community/gpt2 \ --config_overrides="n_embd=1024,n_head=16,n_layer=48,n_positions=102" \ -[...] -``` - -This feature is only available in `run_clm.py`, `run_plm.py`, `run_mlm.py` and `run_fim.py`. diff --git a/examples/pytorch/language-modeling/requirements.txt b/examples/pytorch/language-modeling/requirements.txt deleted file mode 100644 index 851e8de09ccd..000000000000 --- a/examples/pytorch/language-modeling/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -accelerate >= 0.12.0 -torch >= 1.3 -datasets >= 2.14.0 -sentencepiece != 0.1.92 -protobuf -evaluate -scikit-learn diff --git a/examples/pytorch/language-modeling/run_clm.py b/examples/pytorch/language-modeling/run_clm.py deleted file mode 100755 index a2d0034fb62a..000000000000 --- a/examples/pytorch/language-modeling/run_clm.py +++ /dev/null @@ -1,712 +0,0 @@ -#!/usr/bin/env python -# Copyright 2020 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "accelerate >= 0.12.0", -# "torch >= 1.3", -# "datasets >= 2.14.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "evaluate", -# "scikit-learn", -# ] -# /// - -""" -Fine-tuning the library models for causal language modeling (GPT, GPT-2, CTRL, ...) on a text file or a dataset. - -Here is the full list of checkpoints on the hub that can be fine-tuned by this script: -https://huggingface.co/models?filter=text-generation -""" -# You can also adapt this script on your own causal language modeling task. Pointers for this are left as comments. - -import logging -import math -import os -import sys -from dataclasses import dataclass, field -from itertools import chain - -import datasets -import evaluate -import torch -from datasets import IterableDataset, IterableDatasetDict, load_dataset - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_FOR_CAUSAL_LM_MAPPING, - AutoConfig, - AutoModelForCausalLM, - AutoTokenizer, - HfArgumentParser, - Trainer, - TrainingArguments, - default_data_collator, - is_torch_xla_available, - set_seed, -) -from transformers.testing_utils import CaptureLogger -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.14.0", "To fix: pip install -r examples/pytorch/language-modeling/requirements.txt") - -logger = logging.getLogger(__name__) - - -MODEL_CONFIG_CLASSES = list(MODEL_FOR_CAUSAL_LM_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune, or train from scratch. - """ - - model_name_or_path: str | None = field( - default=None, - metadata={ - "help": ( - "The model checkpoint for weights initialization. Don't set if you want to train a model from scratch." - ) - }, - ) - model_type: str | None = field( - default=None, - metadata={"help": "If training from scratch, pass a model type from the list: " + ", ".join(MODEL_TYPES)}, - ) - config_overrides: str | None = field( - default=None, - metadata={ - "help": ( - "Override some existing default config settings when a model is trained from scratch. Example: " - "n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index" - ) - }, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - dtype: str | None = field( - default=None, - metadata={ - "help": ( - "Override the default `torch.dtype` and load the model under this dtype. If `auto` is passed, the " - "dtype will be automatically derived from the model's weights." - ), - "choices": ["auto", "bfloat16", "float16", "float32"], - }, - ) - - def __post_init__(self): - if self.config_overrides is not None and (self.config_name is not None or self.model_name_or_path is not None): - raise ValueError( - "--config_overrides can't be used in combination with --config_name or --model_name_or_path" - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a text file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."}, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - streaming: bool = field(default=False, metadata={"help": "Enable streaming mode"}) - block_size: int | None = field( - default=None, - metadata={ - "help": ( - "Optional input sequence length after tokenization. " - "The training dataset will be truncated in block of this size for training. " - "Default to the model max input length for single sentence inputs (take into account special tokens)." - ) - }, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - validation_split_percentage: int | None = field( - default=5, - metadata={ - "help": "The percentage of the train set used as validation set in case there's no validation split" - }, - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - keep_linebreaks: bool = field( - default=True, metadata={"help": "Whether to keep line breaks when using TXT files or not."} - ) - - def __post_init__(self): - if self.streaming: - require_version("datasets>=2.0.0", "The streaming feature requires `datasets>=2.0.0`") - - if self.dataset_name is None and self.train_file is None and self.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json", "txt"], "`train_file` should be a csv, a json or a txt file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json", "txt"], "`validation_file` should be a csv, a json or a txt file." - - -def split_streaming_dataset( - full_streaming_dataset, - validation_percentage: int = 5, -) -> IterableDatasetDict: - """ - Splits a streaming dataset into - training and validation IterableDatasets, and supports methods like .map(), .filter(), - .take() and properties like .features on the resulting streams. - - Args: - full_streaming_dataset (Dataset): The name of the dataset to load (e.g., "HuggingFaceFW/fineweb"). - validation_percentage (int): The proportion of the dataset to be used for validation split. - - Returns: - IterableDatasetDict: An IterableDatasetDict containing two IterableDataset objects: (train_stream, validation_stream). - """ - if not (0 < validation_percentage < 100): - raise ValueError( - f"validation_percentage must be between 0 and 100 (exclusive). Passed: {validation_percentage}" - ) - - def split_generator(is_train: bool): - for i, example in enumerate(full_streaming_dataset): - if is_train: - if i % 100 > validation_percentage: - yield example - else: - if i % 100 < validation_percentage: - yield example - - features = full_streaming_dataset.features - train_stream = IterableDataset.from_generator(split_generator, gen_kwargs={"is_train": True}, features=features) - validation_stream = IterableDataset.from_generator( - split_generator, gen_kwargs={"is_train": False}, features=features - ) - - return IterableDatasetDict({"train": train_stream, "validation": validation_stream}) - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - if "validation" not in raw_datasets: - if data_args.streaming: - dataset_stream = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split="train", - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - raw_datasets = split_streaming_dataset(dataset_stream, data_args.validation_split_percentage) - else: - raw_datasets["validation"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=f"train[:{data_args.validation_split_percentage}%]", - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - raw_datasets["train"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=f"train[{data_args.validation_split_percentage}%:]", - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - dataset_args = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = ( - data_args.train_file.split(".")[-1] - if data_args.train_file is not None - else data_args.validation_file.split(".")[-1] - ) - if extension == "txt": - extension = "text" - dataset_args["keep_linebreaks"] = data_args.keep_linebreaks - raw_datasets = load_dataset( - extension, - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - **dataset_args, - ) - # If no validation data is there, validation_split_percentage will be used to divide the dataset. - if "validation" not in raw_datasets: - if data_args.streaming: - dataset_stream = load_dataset( - extension, - data_files=data_files, - split="train", - cache_dir=model_args.cache_dir, - token=model_args.token, - **dataset_args, - ) - raw_datasets = split_streaming_dataset(dataset_stream, data_args.validation_split_percentage) - else: - raw_datasets["validation"] = load_dataset( - extension, - data_files=data_files, - split=f"train[:{data_args.validation_split_percentage}%]", - cache_dir=model_args.cache_dir, - token=model_args.token, - **dataset_args, - ) - - raw_datasets["train"] = load_dataset( - extension, - data_files=data_files, - split=f"train[{data_args.validation_split_percentage}%:]", - cache_dir=model_args.cache_dir, - token=model_args.token, - **dataset_args, - ) - - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - - config_kwargs = { - "cache_dir": model_args.cache_dir, - "revision": model_args.model_revision, - "token": model_args.token, - "trust_remote_code": model_args.trust_remote_code, - } - if model_args.config_name: - config = AutoConfig.from_pretrained(model_args.config_name, **config_kwargs) - elif model_args.model_name_or_path: - config = AutoConfig.from_pretrained(model_args.model_name_or_path, **config_kwargs) - else: - config = CONFIG_MAPPING[model_args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - if model_args.config_overrides is not None: - logger.info(f"Overriding config: {model_args.config_overrides}") - config.update_from_string(model_args.config_overrides) - logger.info(f"New config: {config}") - - tokenizer_kwargs = { - "cache_dir": model_args.cache_dir, - "use_fast": model_args.use_fast_tokenizer, - "revision": model_args.model_revision, - "token": model_args.token, - "trust_remote_code": model_args.trust_remote_code, - } - if model_args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained(model_args.tokenizer_name, **tokenizer_kwargs) - elif model_args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained(model_args.model_name_or_path, **tokenizer_kwargs) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if model_args.model_name_or_path: - dtype = model_args.dtype if model_args.dtype in ["auto", None] else getattr(torch, model_args.dtype) - model = AutoModelForCausalLM.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - dtype=dtype, - ) - else: - model = AutoModelForCausalLM.from_config(config, trust_remote_code=model_args.trust_remote_code) - n_params = sum({p.data_ptr(): p.numel() for p in model.parameters()}.values()) - logger.info(f"Training new model from scratch - Total size={n_params / 2**20:.2f}M params") - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Preprocessing the datasets. - # First we tokenize all the texts. - if training_args.do_train: - column_names = list(raw_datasets["train"].features) - else: - column_names = list(raw_datasets["validation"].features) - text_column_name = "text" if "text" in column_names else column_names[0] - - # since this will be pickled to avoid _LazyModule error in Hasher force logger loading before tokenize_function - tok_logger = transformers.utils.logging.get_logger("transformers.tokenization_utils_base") - - def tokenize_function(examples): - with CaptureLogger(tok_logger) as cl: - output = tokenizer(examples[text_column_name]) - # clm input could be much much longer than block_size - if "Token indices sequence length is longer than the" in cl.out: - tok_logger.warning( - "^^^^^^^^^^^^^^^^ Please ignore the warning above - this long input will be chunked into smaller bits" - " before being passed to the model." - ) - return output - - with training_args.main_process_first(desc="dataset map tokenization"): - if not data_args.streaming: - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - else: - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - remove_columns=column_names, - ) - if hasattr(config, "max_position_embeddings"): - max_pos_embeddings = config.max_position_embeddings - else: - # Define a default value if the attribute is missing in the config. - max_pos_embeddings = 1024 - - if data_args.block_size is None: - block_size = tokenizer.model_max_length - if block_size > max_pos_embeddings: - logger.warning( - f"The tokenizer picked seems to have a very large `model_max_length` ({tokenizer.model_max_length}). " - f"Using block_size={min(1024, max_pos_embeddings)} instead. You can change that default value by passing --block_size xxx." - ) - if max_pos_embeddings > 0: - block_size = min(1024, max_pos_embeddings) - else: - block_size = 1024 - else: - if data_args.block_size > tokenizer.model_max_length: - logger.warning( - f"The block_size passed ({data_args.block_size}) is larger than the maximum length for the model " - f"({tokenizer.model_max_length}). Using block_size={tokenizer.model_max_length}." - ) - block_size = min(data_args.block_size, tokenizer.model_max_length) - - # Main data processing function that will concatenate all texts from our dataset and generate chunks of block_size. - def group_texts(examples): - # Concatenate all texts. - concatenated_examples = {k: list(chain(*examples[k])) for k in examples} - total_length = len(concatenated_examples[list(examples.keys())[0]]) - # We drop the small remainder, and if the total_length < block_size we exclude this batch and return an empty dict. - # We could add padding if the model supported it instead of this drop, you can customize this part to your needs. - total_length = (total_length // block_size) * block_size - # Split by chunks of max_len. - result = { - k: [t[i : i + block_size] for i in range(0, total_length, block_size)] - for k, t in concatenated_examples.items() - } - result["labels"] = result["input_ids"].copy() - return result - - # Note that with `batched=True`, this map processes 1,000 texts together, so group_texts throws away a remainder - # for each of those groups of 1,000 texts. You can adjust that batch_size here but a higher value might be slower - # to preprocess. - # - # To speed up this part, we use multiprocessing. See the documentation of the map method for more information: - # https://huggingface.co/docs/datasets/process#map - - with training_args.main_process_first(desc="grouping texts together"): - if not data_args.streaming: - lm_datasets = tokenized_datasets.map( - group_texts, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc=f"Grouping texts in chunks of {block_size}", - ) - else: - lm_datasets = tokenized_datasets.map( - group_texts, - batched=True, - ) - - if training_args.do_train: - if "train" not in tokenized_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = lm_datasets["train"] - if data_args.max_train_samples is not None: - if data_args.streaming: - train_dataset = train_dataset.take(data_args.max_train_samples) - else: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - if training_args.do_eval: - if "validation" not in tokenized_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_dataset = lm_datasets["validation"] - if data_args.max_eval_samples is not None: - if data_args.streaming: - eval_dataset = eval_dataset.take(data_args.max_eval_samples) - else: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - def preprocess_logits_for_metrics(logits, labels): - if isinstance(logits, tuple): - # Depending on the model and config, logits may contain extra tensors, - # like past_key_values, but logits always come first - logits = logits[0] - return logits.argmax(dim=-1) - - metric = evaluate.load("accuracy", cache_dir=model_args.cache_dir) - - def compute_metrics(eval_preds): - preds, labels = eval_preds - # preds have the same shape as the labels, after the argmax(-1) has been calculated - # by preprocess_logits_for_metrics but we need to shift the labels - labels = labels[:, 1:].reshape(-1) - preds = preds[:, :-1].reshape(-1) - return metric.compute(predictions=preds, references=labels) - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - processing_class=tokenizer, - # Data collator will default to DataCollatorWithPadding, so we change it. - data_collator=default_data_collator, - compute_metrics=compute_metrics if training_args.do_eval and not is_torch_xla_available() else None, - preprocess_logits_for_metrics=preprocess_logits_for_metrics - if training_args.do_eval and not is_torch_xla_available() - else None, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - - metrics = train_result.metrics - - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - if data_args.streaming: - metrics["train_samples"] = max_train_samples - else: - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - - metrics = trainer.evaluate() - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - if data_args.streaming: - metrics["eval_samples"] = max_eval_samples - else: - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - try: - perplexity = math.exp(metrics["eval_loss"]) - except OverflowError: - perplexity = float("inf") - metrics["perplexity"] = perplexity - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "text-generation"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/language-modeling/run_clm_no_trainer.py b/examples/pytorch/language-modeling/run_clm_no_trainer.py deleted file mode 100755 index 659c2866330c..000000000000 --- a/examples/pytorch/language-modeling/run_clm_no_trainer.py +++ /dev/null @@ -1,737 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "accelerate >= 0.12.0", -# "torch >= 1.3", -# "datasets >= 2.14.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "evaluate", -# "scikit-learn", -# ] -# /// - -""" -Fine-tuning the library models for causal language modeling (GPT, GPT-2, CTRL, ...) -on a text file or a dataset without using HuggingFace Trainer. - -Here is the full list of checkpoints on the hub that can be fine-tuned by this script: -https://huggingface.co/models?filter=text-generation -""" -# You can also adapt this script on your own causal language modeling task. Pointers for this are left as comments. - -import argparse -import json -import logging -import math -import os -import random -from itertools import chain -from pathlib import Path - -import datasets -import torch -from accelerate import Accelerator, DistributedType -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_MAPPING, - AutoConfig, - AutoModelForCausalLM, - AutoTokenizer, - SchedulerType, - default_data_collator, - get_scheduler, -) -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) - -require_version("datasets>=2.14.0", "To fix: pip install -r examples/pytorch/language-modeling/requirements.txt") - -MODEL_CONFIG_CLASSES = list(MODEL_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a causal language modeling task") - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv, txt or a json file containing the training data." - ) - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv, txt or a json file containing the validation data." - ) - parser.add_argument( - "--validation_split_percentage", - default=5, - help="The percentage of the train set used as validation set in case there's no validation split", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=False, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--tokenizer_name", - type=str, - default=None, - help="Pretrained tokenizer name or path if not the same as model_name", - ) - parser.add_argument( - "--use_slow_tokenizer", - action="store_true", - help="If passed, will use a slow tokenizer (not backed by the Hugging Face Tokenizers library).", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument( - "--model_type", - type=str, - default=None, - help="Model type to use if training from scratch.", - choices=MODEL_TYPES, - ) - parser.add_argument( - "--block_size", - type=int, - default=None, - help=( - "Optional input sequence length after tokenization. The training dataset will be truncated in block of" - " this size for training. Default to the model max input length for single sentence inputs (take into" - " account special tokens)." - ), - ) - parser.add_argument( - "--preprocessing_num_workers", - type=int, - default=None, - help="The number of processes to use for the preprocessing.", - ) - parser.add_argument( - "--overwrite_cache", action="store_true", help="Overwrite the cached training and evaluation sets" - ) - parser.add_argument( - "--no_keep_linebreaks", action="store_true", help="Do not keep line breaks when using TXT files." - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - if args.dataset_name is None and args.train_file is None and args.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - if extension not in ["csv", "json", "txt"]: - raise ValueError("`train_file` should be a csv, json or txt file.") - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - if extension not in ["csv", "json", "txt"]: - raise ValueError("`validation_file` should be a csv, json or txt file.") - - if args.push_to_hub: - if args.output_dir is None: - raise ValueError("Need an `output_dir` to create a repo when `--push_to_hub` is passed.") - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - os.makedirs(args.output_dir, exist_ok=True) - gitignore_path = os.path.join(args.output_dir, ".gitignore") - content = "" - if os.path.exists(gitignore_path): - with open(gitignore_path, "r", encoding="utf-8") as f: - content = f.read() - with open(gitignore_path, "a", encoding="utf-8") as f: - if content and not content.endswith("\n"): - f.write("\n") - if "step_*" not in content: - f.write("step_*\n") - if "epoch_*" not in content: - f.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - args.dataset_name, - args.dataset_config_name, - split=f"train[:{args.validation_split_percentage}%]", - trust_remote_code=args.trust_remote_code, - ) - raw_datasets["train"] = load_dataset( - args.dataset_name, - args.dataset_config_name, - split=f"train[{args.validation_split_percentage}%:]", - trust_remote_code=args.trust_remote_code, - ) - else: - data_files = {} - dataset_args = {} - if args.train_file is not None: - data_files["train"] = args.train_file - extension = args.train_file.split(".")[-1] - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.validation_file.split(".")[-1] - if extension == "txt": - extension = "text" - dataset_args["keep_linebreaks"] = not args.no_keep_linebreaks - raw_datasets = load_dataset(extension, data_files=data_files, **dataset_args) - # If no validation data is there, validation_split_percentage will be used to divide the dataset. - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - extension, - data_files=data_files, - split=f"train[:{args.validation_split_percentage}%]", - **dataset_args, - ) - raw_datasets["train"] = load_dataset( - extension, - data_files=data_files, - split=f"train[{args.validation_split_percentage}%:]", - **dataset_args, - ) - - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - if args.config_name: - config = AutoConfig.from_pretrained( - args.config_name, - trust_remote_code=args.trust_remote_code, - ) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained( - args.model_name_or_path, - trust_remote_code=args.trust_remote_code, - ) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - - if args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained( - args.tokenizer_name, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - elif args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained( - args.model_name_or_path, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if args.model_name_or_path: - model = AutoModelForCausalLM.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForCausalLM.from_config(config, trust_remote_code=args.trust_remote_code) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Preprocessing the datasets. - # First we tokenize all the texts. - column_names = raw_datasets["train"].column_names - text_column_name = "text" if "text" in column_names else column_names[0] - - def tokenize_function(examples): - return tokenizer(examples[text_column_name]) - - with accelerator.main_process_first(): - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - - if args.block_size is None: - block_size = tokenizer.model_max_length - if block_size > config.max_position_embeddings: - logger.warning( - f"The tokenizer picked seems to have a very large `model_max_length` ({tokenizer.model_max_length}). " - f"Using block_size={min(1024, config.max_position_embeddings)} instead. You can change that default value by passing --block_size xxx." - ) - block_size = min(1024, config.max_position_embeddings) - else: - if args.block_size > tokenizer.model_max_length: - logger.warning( - f"The block_size passed ({args.block_size}) is larger than the maximum length for the model " - f"({tokenizer.model_max_length}). Using block_size={tokenizer.model_max_length}." - ) - block_size = min(args.block_size, tokenizer.model_max_length) - - # Main data processing function that will concatenate all texts from our dataset and generate chunks of block_size. - def group_texts(examples): - # Concatenate all texts. - concatenated_examples = {k: list(chain(*examples[k])) for k in examples} - total_length = len(concatenated_examples[list(examples.keys())[0]]) - # We drop the small remainder, and if the total_length < block_size we exclude this batch and return an empty dict. - # We could add padding if the model supported it instead of this drop, you can customize this part to your needs. - total_length = (total_length // block_size) * block_size - # Split by chunks of max_len. - result = { - k: [t[i : i + block_size] for i in range(0, total_length, block_size)] - for k, t in concatenated_examples.items() - } - result["labels"] = result["input_ids"].copy() - return result - - # Note that with `batched=True`, this map processes 1,000 texts together, so group_texts throws away a remainder - # for each of those groups of 1,000 texts. You can adjust that batch_size here but a higher value might be slower - # to preprocess. - # - # To speed up this part, we use multiprocessing. See the documentation of the map method for more information: - # https://huggingface.co/docs/datasets/process#map - - with accelerator.main_process_first(): - lm_datasets = tokenized_datasets.map( - group_texts, - batched=True, - num_proc=args.preprocessing_num_workers, - load_from_cache_file=not args.overwrite_cache, - desc=f"Grouping texts in chunks of {block_size}", - ) - - train_dataset = lm_datasets["train"] - eval_dataset = lm_datasets["validation"] - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # DataLoaders creation: - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=default_data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader( - eval_dataset, collate_fn=default_data_collator, batch_size=args.per_device_eval_batch_size - ) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # On TPU, the tie weights in our model have been disconnected, so we need to restore the ties. - if accelerator.distributed_type == DistributedType.TPU: - model.tie_weights() - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("clm_no_trainer", experiment_config) - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - if completed_steps >= args.max_train_steps: - break - - model.eval() - losses = [] - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - - loss = outputs.loss - losses.append(accelerator.gather_for_metrics(loss.repeat(args.per_device_eval_batch_size))) - - losses = torch.cat(losses) - try: - eval_loss = torch.mean(losses) - perplexity = math.exp(eval_loss) - except OverflowError: - perplexity = float("inf") - - logger.info(f"epoch {epoch}: perplexity: {perplexity} eval_loss: {eval_loss}") - - if args.with_tracking: - accelerator.log( - { - "perplexity": perplexity, - "eval_loss": eval_loss, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump({"perplexity": perplexity}, f) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/language-modeling/run_fim.py b/examples/pytorch/language-modeling/run_fim.py deleted file mode 100644 index 4df34b2a0779..000000000000 --- a/examples/pytorch/language-modeling/run_fim.py +++ /dev/null @@ -1,846 +0,0 @@ -#!/usr/bin/env python -# Copyright 2024 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "accelerate >= 0.12.0", -# "torch >= 1.3", -# "datasets >= 2.14.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "evaluate", -# "scikit-learn", -# ] -# /// - -""" -Fine-tuning the library models for causal language modeling using -Fill-in-the middle (FIM) objective on a text file or a dataset. - -Here is the full list of checkpoints on the hub that can be fine-tuned by this script: -https://huggingface.co/models?filter=text-generation -""" -# You should adapt this script on your own causal language modeling task. Pointers for this are left as comments. - -import logging -import math -import os -import sys -from dataclasses import dataclass, field -from itertools import chain - -import datasets -import evaluate -import numpy as np -import torch -from datasets import load_dataset - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_FOR_CAUSAL_LM_MAPPING, - AutoConfig, - AutoModelForCausalLM, - AutoTokenizer, - HfArgumentParser, - Trainer, - TrainingArguments, - default_data_collator, - is_torch_xla_available, - set_seed, -) -from transformers.integrations import is_deepspeed_zero3_enabled -from transformers.testing_utils import CaptureLogger -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.14.0", "To fix: pip install -r examples/pytorch/language-modeling/requirements.txt") - -logger = logging.getLogger(__name__) - - -MODEL_CONFIG_CLASSES = list(MODEL_FOR_CAUSAL_LM_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune, or train from scratch. - """ - - model_name_or_path: str | None = field( - default=None, - metadata={ - "help": ( - "The model checkpoint for weights initialization. Don't set if you want to train a model from scratch." - ) - }, - ) - model_type: str | None = field( - default=None, - metadata={"help": "If training from scratch, pass a model type from the list: " + ", ".join(MODEL_TYPES)}, - ) - config_overrides: str | None = field( - default=None, - metadata={ - "help": ( - "Override some existing default config settings when a model is trained from scratch. Example: " - "n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index" - ) - }, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - dtype: str | None = field( - default=None, - metadata={ - "help": ( - "Override the default `torch.dtype` and load the model under this dtype. If `auto` is passed, the " - "dtype will be automatically derived from the model's weights." - ), - "choices": ["auto", "bfloat16", "float16", "float32"], - }, - ) - pad_to_multiple_of: bool = field( - default=False, - metadata={ - "help": ( - "Whether to pad the embedding layer to a multiple depending on the device. ", - "For NVIDIA GPUs, this will be a multiple of 8, for TPUs a multiple of 128.", - ) - }, - ) - attn_implementation: str | None = field( - default="sdpa", metadata={"help": ("The attention implementation to use. ")} - ) - - def __post_init__(self): - if self.config_overrides is not None and (self.config_name is not None or self.model_name_or_path is not None): - raise ValueError( - "--config_overrides can't be used in combination with --config_name or --model_name_or_path" - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a text file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."}, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - streaming: bool = field(default=False, metadata={"help": "Enable streaming mode"}) - block_size: int | None = field( - default=None, - metadata={ - "help": ( - "Optional input sequence length after tokenization. " - "The training dataset will be truncated in block of this size for training. " - "Default to the model max input length for single sentence inputs (take into account special tokens)." - ) - }, - ) - fim_rate: float | None = field( - default=0.5, - metadata={ - "help": ( - "Optional probability with which the FIM transformation is applied to the example. " - "Default is 0.5. A rate of 1.0 means every example will undergo FIM transformation, " - "while a rate of 0.0 means no example will." - ) - }, - ) - fim_spm_rate: float | None = field( - default=0.5, - metadata={ - "help": ( - "Within the examples undergoing FIM transformation, this rate determines the probability " - "of applying the Sentence Permutation Mode (SPM). " - "Default is 0.5. A rate of 1.0 means all FIM transformations will use SPM, " - "while a rate of 0.0 means none will." - ) - }, - ) - truncate_or_pad: bool | None = field( - default=True, - metadata={ - "help": ( - "Indicates whether the transformed example should be truncated or padded to maintain " - "the same length as the original example. " - "Default is True. If False, the function will not truncate or pad the examples." - ) - }, - ) - fim_prefix_token: str | None = field( - default="", - metadata={"help": ("Fill-in-Middle Prefix token. Defaults to ''.")}, - ) - fim_middle_token: str | None = field( - default="", - metadata={"help": ("Fill-in-Middle Middle token. Defaults to ''.")}, - ) - fim_suffix_token: str | None = field( - default="", - metadata={"help": ("Fill-in-Middle Suffix token. Defaults to ''.")}, - ) - pad_token: str | None = field( - default="", - metadata={ - "help": ( - "Fill-in-Middle Pad token. Used only when 'truncate_or_pad' is set to True. Defaults to ''." - ) - }, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - validation_split_percentage: int | None = field( - default=5, - metadata={ - "help": "The percentage of the train set used as validation set in case there's no validation split" - }, - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - keep_linebreaks: bool = field( - default=True, metadata={"help": "Whether to keep line breaks when using TXT files or not."} - ) - - def __post_init__(self): - if self.streaming: - require_version("datasets>=2.0.0", "The streaming feature requires `datasets>=2.0.0`") - - if self.dataset_name is None and self.train_file is None and self.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json", "txt"], "`train_file` should be a csv, a json or a txt file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json", "txt"], "`validation_file` should be a csv, a json or a txt file." - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Set a numpy random state for FIM transformations - np_rng = np.random.RandomState(seed=training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=f"train[:{data_args.validation_split_percentage}%]", - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - raw_datasets["train"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=f"train[{data_args.validation_split_percentage}%:]", - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - dataset_args = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = ( - data_args.train_file.split(".")[-1] - if data_args.train_file is not None - else data_args.validation_file.split(".")[-1] - ) - if extension == "txt": - extension = "text" - dataset_args["keep_linebreaks"] = data_args.keep_linebreaks - raw_datasets = load_dataset( - extension, - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - **dataset_args, - ) - # If no validation data is there, validation_split_percentage will be used to divide the dataset. - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - extension, - data_files=data_files, - split=f"train[:{data_args.validation_split_percentage}%]", - cache_dir=model_args.cache_dir, - token=model_args.token, - **dataset_args, - ) - raw_datasets["train"] = load_dataset( - extension, - data_files=data_files, - split=f"train[{data_args.validation_split_percentage}%:]", - cache_dir=model_args.cache_dir, - token=model_args.token, - **dataset_args, - ) - - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets.html. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - - config_kwargs = { - "cache_dir": model_args.cache_dir, - "revision": model_args.model_revision, - "token": model_args.token, - "trust_remote_code": model_args.trust_remote_code, - } - if model_args.config_name: - config = AutoConfig.from_pretrained(model_args.config_name, **config_kwargs) - elif model_args.model_name_or_path: - config = AutoConfig.from_pretrained(model_args.model_name_or_path, **config_kwargs) - else: - config = CONFIG_MAPPING[model_args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - if model_args.config_overrides is not None: - logger.info(f"Overriding config: {model_args.config_overrides}") - config.update_from_string(model_args.config_overrides) - logger.info(f"New config: {config}") - - tokenizer_kwargs = { - "cache_dir": model_args.cache_dir, - "use_fast": model_args.use_fast_tokenizer, - "revision": model_args.model_revision, - "token": model_args.token, - "trust_remote_code": model_args.trust_remote_code, - } - if model_args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained(model_args.tokenizer_name, **tokenizer_kwargs) - elif model_args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained(model_args.model_name_or_path, **tokenizer_kwargs) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if model_args.model_name_or_path: - dtype = model_args.dtype if model_args.dtype in ["auto", None] else getattr(torch, model_args.dtype) - model = AutoModelForCausalLM.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - dtype=dtype, - attn_implementation=model_args.attn_implementation, - ) - - else: - model = AutoModelForCausalLM.from_config( - config, - trust_remote_code=model_args.trust_remote_code, - attn_implementation=model_args.attn_implementation, - ) - n_params = sum({p.data_ptr(): p.numel() for p in model.parameters()}.values()) - logger.info(f"Training new model from scratch - Total size={n_params / 2**20:.2f}M params") - - # Add the new FIM tokens to the tokenizer and resize model's vocab embeddings - special_tokens = [data_args.fim_prefix_token, data_args.fim_middle_token, data_args.fim_suffix_token] - if data_args.truncate_or_pad: - special_tokens.append(data_args.pad_token) - - # Get the factor by which the embedding layer should be padded based on the device - pad_factor = 1 - if torch.cuda.is_available(): - pad_factor = 8 - - elif is_torch_xla_available(check_is_tpu=True): - pad_factor = 128 - - # Add the new tokens to the tokenizer - tokenizer.add_tokens(special_tokens) - original_embeddings = model.get_input_embeddings() - - if is_deepspeed_zero3_enabled(): - import deepspeed - - with deepspeed.zero.GatheredParameters(original_embeddings.weight, modifier_rank=0): - # Get the pre-expansion embeddings of the model and resize the embedding layer - model.resize_token_embeddings(len(tokenizer), pad_to_multiple_of=pad_factor) - embeddings = model.get_input_embeddings() - - # Sample the embeddings for the new tokens from a multivariate normal distribution - # We do this so that the new embeddings are close to the original embeddings and not necessarily zero - # More on this: https://nlp.stanford.edu/~johnhew/vocab-expansion.html - mean = original_embeddings.mean(dim=0) - n = original_embeddings.size()[0] - sigma = ((original_embeddings - mean).T @ (original_embeddings - mean)) / n - dist = torch.distributions.multivariate_normal.MultivariateNormal( - mean, - covariance_matrix=1e-5 * sigma, - ) - new_token_embeddings = torch.stack( - tuple(dist.sample() for _ in range(len(special_tokens))), - dim=0, - ) - else: - original_embeddings = model.get_input_embeddings() - # Get the pre-expansion embeddings of the model and resize the embedding layer - model.resize_token_embeddings(len(tokenizer), pad_to_multiple_of=pad_factor) - embeddings = model.get_input_embeddings() - - # Sample the embeddings for the new tokens from a multivariate normal distribution - # We do this so that the new embeddings are close to the original embeddings and not necessarily zero - # More on this: https://nlp.stanford.edu/~johnhew/vocab-expansion.html - mean = original_embeddings.mean(dim=0) - n = original_embeddings.size()[0] - sigma = ((original_embeddings - mean).T @ (original_embeddings - mean)) / n - dist = torch.distributions.multivariate_normal.MultivariateNormal( - mean, - covariance_matrix=1e-5 * sigma, - ) - new_token_embeddings = torch.stack( - tuple(dist.sample() for _ in range(len(special_tokens))), - dim=0, - ) - - if is_deepspeed_zero3_enabled(): - import deepspeed - - with deepspeed.zero.GatheredParameters(embeddings.weight, modifier_rank=0): - # Set the new tokens' embeddings to the newly sampled embeddings - embeddings.weight.data[-len(special_tokens) :] = new_token_embeddings - else: - # Set the new tokens' embeddings to the newly sampled embeddings - embeddings.weight.data[-len(special_tokens) :] = new_token_embeddings - - # Update the model's embeddings with the new embeddings - model.set_input_embeddings(embeddings) - - logger.info("Added special tokens to the tokenizer and resized model's embedding layer") - - # Preprocessing the datasets. - # First we tokenize all the texts. - if training_args.do_train: - column_names = list(raw_datasets["train"].features) - else: - column_names = list(raw_datasets["validation"].features) - text_column_name = "text" if "text" in column_names else column_names[0] - - # since this will be pickled to avoid _LazyModule error in Hasher force logger loading before tokenize_function - tok_logger = transformers.utils.logging.get_logger("transformers.tokenization_utils_base") - - def tokenize_function(examples): - with CaptureLogger(tok_logger) as cl: - output = tokenizer(examples[text_column_name]) - # clm-fim input could be much much longer than block_size - if "Token indices sequence length is longer than the" in cl.out: - tok_logger.warning( - "^^^^^^^^^^^^^^^^ Please ignore the warning above - this long input will be chunked into smaller bits" - " before being passed to the model." - ) - return output - - with training_args.main_process_first(desc="dataset map tokenization"): - if not data_args.streaming: - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - else: - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - remove_columns=column_names, - ) - - if data_args.block_size is None: - block_size = tokenizer.model_max_length - if block_size > config.max_position_embeddings: - logger.warning( - f"The tokenizer picked seems to have a very large `model_max_length` ({tokenizer.model_max_length}). " - f"Using block_size={min(1024, config.max_position_embeddings)} instead. You can change that default value by passing --block_size xxx." - ) - block_size = min(1024, config.max_position_embeddings) - else: - if data_args.block_size > tokenizer.model_max_length: - logger.warning( - f"The block_size passed ({data_args.block_size}) is larger than the maximum length for the model " - f"({tokenizer.model_max_length}). Using block_size={tokenizer.model_max_length}." - ) - block_size = min(data_args.block_size, tokenizer.model_max_length) - - # Data processing function that will concatenate all texts from our dataset and generate chunks of block_size. - def group_texts(examples): - # Concatenate all texts. - concatenated_examples = {k: list(chain(*examples[k])) for k in examples} - total_length = len(concatenated_examples[list(examples.keys())[0]]) - # We drop the small remainder, and if the total_length < block_size we exclude this batch and return an empty dict. - # We could add padding if the model supported it instead of this drop, you can customize this part to your needs. - total_length = (total_length // block_size) * block_size - # Split by chunks of max_len. - result = { - k: [t[i : i + block_size] for i in range(0, total_length, block_size)] - for k, t in concatenated_examples.items() - } - result["labels"] = result["input_ids"].copy() - return result - - # Get the FIM-specific token ids - prefix_tok_id = tokenizer.convert_tokens_to_ids(data_args.fim_prefix_token) - middle_tok_id = tokenizer.convert_tokens_to_ids(data_args.fim_middle_token) - suffix_tok_id = tokenizer.convert_tokens_to_ids(data_args.fim_suffix_token) - pad_tok_id = None - - # If truncate_or_pad is on, also get pad token id - if data_args.truncate_or_pad: - pad_tok_id = tokenizer.convert_tokens_to_ids(data_args.pad_token) - - # The two functions below perform the FIM transformation on the data (either PSM or SPM or PSM+SPM) - # Don't call fim_transform directly in .map() - # Adapted from https://github.com/loubnabnl/santacoder-finetuning/blob/main/fim.py#L22C13-L83 - def fim_transform(example): - """ - This function performs FIM transformation on a single example (list of tokens) - """ - if np_rng.binomial(1, data_args.fim_rate): - boundaries = sorted(np_rng.randint(low=0, high=len(example) + 1, size=2)) - - prefix = example[: boundaries[0]] - middle = example[boundaries[0] : boundaries[1]] - suffix = example[boundaries[1] :] - - if data_args.truncate_or_pad: - total_length = len(prefix) + len(middle) + len(suffix) + 3 - diff = total_length - len(example) - if diff > 0: - suffix = suffix[: max(0, len(suffix) - diff)] - elif diff < 0: - suffix.extend([pad_tok_id] * (-diff)) - - if np_rng.binomial(1, data_args.fim_spm_rate): - # Apply Suffix-Prefix-Middle (SPM) transformation - transformed_example = [prefix_tok_id, suffix_tok_id] + suffix + [middle_tok_id] + prefix + middle - else: - # Apply Prefix-Suffix-Middle (PSM) transformation - transformed_example = [prefix_tok_id] + prefix + [suffix_tok_id] + suffix + [middle_tok_id] + middle - else: - transformed_example = example - - return transformed_example - - # Below function is the one you are supposed to call in the .map() function - def apply_fim(examples): - """ - Apply FIM transformation to a batch of examples - """ - fim_transform_ids = [fim_transform(ids) for ids in examples["input_ids"]] - examples["input_ids"] = fim_transform_ids - examples["labels"] = fim_transform_ids - # If your application requires custom attention mask, please adjust this function's below line. - # Since FIM transformation increases the number of tokens in input_ids and labels - # but leaves the number of tokens unchanged in attention_masks which would cause problems - examples["attention_mask"] = [[1] * len(mask) for mask in examples["input_ids"]] - return examples - - # Note that with `batched=True`, this map processes 1,000 texts together, so group_texts throws away a remainder - # for each of those groups of 1,000 texts. You can adjust that batch_size here but a higher value might be slower - # to preprocess. - # - # To speed up this part, we use multiprocessing. See the documentation of the map method for more information: - # https://huggingface.co/docs/datasets/process#map - - # FIM transformations are only supposed to be applied before group_texts processing otherwise some sentences will - # have 3-4 more tokens than others due to probabilistic addition of FIM-specific tokens which will raise errors - with training_args.main_process_first(desc="processing texts together"): - if not data_args.streaming: - fim_datasets = tokenized_datasets.map( - apply_fim, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc="Performing FIM transformation", - ) - lm_datasets = fim_datasets.map( - group_texts, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc=f"Grouping texts in chunks of {block_size}", - ) - else: - fim_datasets = tokenized_datasets.map( - apply_fim, - batched=True, - ) - lm_datasets = fim_datasets.map( - group_texts, - batched=True, - ) - - if training_args.do_train: - if "train" not in tokenized_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = lm_datasets["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - if training_args.do_eval: - if "validation" not in tokenized_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_dataset = lm_datasets["validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - def preprocess_logits_for_metrics(logits, labels): - if isinstance(logits, tuple): - # Depending on the model and config, logits may contain extra tensors, - # like past_key_values, but logits always come first - logits = logits[0] - return logits.argmax(dim=-1) - - metric = evaluate.load("accuracy") - - def compute_metrics(eval_preds): - preds, labels = eval_preds - # preds have the same shape as the labels, after the argmax(-1) has been calculated - # by preprocess_logits_for_metrics but we need to shift the labels - labels = labels[:, 1:].reshape(-1) - preds = preds[:, :-1].reshape(-1) - return metric.compute(predictions=preds, references=labels) - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - processing_class=tokenizer, - # Data collator will default to DataCollatorWithPadding, so we change it. - data_collator=default_data_collator, - compute_metrics=compute_metrics - if training_args.do_eval and not is_torch_xla_available(check_is_tpu=True) - else None, - preprocess_logits_for_metrics=( - preprocess_logits_for_metrics - if training_args.do_eval and not is_torch_xla_available(check_is_tpu=True) - else None - ), - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - - metrics = train_result.metrics - - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - - metrics = trainer.evaluate() - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - try: - perplexity = math.exp(metrics["eval_loss"]) - except OverflowError: - perplexity = float("inf") - metrics["perplexity"] = perplexity - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "text-generation"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/language-modeling/run_fim_no_trainer.py b/examples/pytorch/language-modeling/run_fim_no_trainer.py deleted file mode 100644 index b6bdc3a552c8..000000000000 --- a/examples/pytorch/language-modeling/run_fim_no_trainer.py +++ /dev/null @@ -1,918 +0,0 @@ -#!/usr/bin/env python -# Copyright 2024 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "accelerate >= 0.12.0", -# "torch >= 1.3", -# "datasets >= 2.14.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "evaluate", -# "scikit-learn", -# ] -# /// - -""" -Fine-tuning the library models for causal language modeling using -Fill-in-the middle (FIM) objective on a text file or a dataset without using HuggingFace Trainer. - -Here is the full list of checkpoints on the hub that can be fine-tuned by this script: -https://huggingface.co/models?filter=text-generation -""" -# You can also adapt this script on your own fim causal language modeling task. Pointers for this are left as comments. - -import argparse -import json -import logging -import math -import os -import random -from itertools import chain -from pathlib import Path - -import datasets -import numpy as np -import torch -from accelerate import Accelerator, DistributedType -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import Repository, create_repo -from torch import nn -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_MAPPING, - AutoConfig, - AutoModelForCausalLM, - AutoTokenizer, - SchedulerType, - default_data_collator, - get_scheduler, - is_torch_xla_available, -) -from transformers.integrations import is_deepspeed_zero3_enabled -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) - -require_version("datasets>=2.14.0", "To fix: pip install -r examples/pytorch/language-modeling/requirements.txt") - -MODEL_CONFIG_CLASSES = list(MODEL_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -def parse_args(): - parser = argparse.ArgumentParser( - description="Finetune a transformers model on a causal language modeling task using fill-in-the middle objective" - ) - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv, txt or a json file containing the training data." - ) - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv, txt or a json file containing the validation data." - ) - parser.add_argument( - "--validation_split_percentage", - default=5, - help="The percentage of the train set used as validation set in case there's no validation split", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=False, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--tokenizer_name", - type=str, - default=None, - help="Pretrained tokenizer name or path if not the same as model_name", - ) - parser.add_argument( - "--use_slow_tokenizer", - action="store_true", - help="If passed, will use a slow tokenizer (not backed by the Tokenizers library).", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=42, help="A seed for reproducible training.") - parser.add_argument( - "--model_type", - type=str, - default=None, - help="Model type to use if training from scratch.", - choices=MODEL_TYPES, - ) - parser.add_argument( - "--block_size", - type=int, - default=None, - help=( - "Optional input sequence length after tokenization. The training dataset will be truncated in block of" - " this size for training. Default to the model max input length for single sentence inputs (take into" - " account special tokens)." - ), - ) - parser.add_argument( - "--fim_rate", - type=float, - default=0.5, - help=( - " Optional probability with which the FIM transformation is applied to the example." - " Default is 0.5. A rate of 1.0 means every example will undergo FIM transformation," - " while a rate of 0.0 means no example will." - ), - ) - parser.add_argument( - "--fim_spm_rate", - type=float, - default=0.5, - help=( - "Within the examples undergoing FIM transformation, this rate determines the probability" - " of applying the Sentence Permutation Mode (SPM)." - " Default is 0.5. A rate of 1.0 means all FIM transformations will use SPM," - " while a rate of 0.0 means none will." - ), - ) - parser.add_argument( - "--truncate_or_pad", - type=bool, - default=True, - help=( - "Indicates whether the transformed example should be truncated or padded to maintain" - " the same length as the original example." - " Default is True. If False, the function will not truncate or pad the examples." - ), - ) - parser.add_argument( - "--fim_prefix_token", - type=str, - default="", - help="Fill-in-Middle Prefix token. Defaults to ''.", - ) - parser.add_argument( - "--fim_middle_token", - type=str, - default="", - help="Fill-in-Middle Middle token. Defaults to ''.", - ) - parser.add_argument( - "--fim_suffix_token", - type=str, - default="", - help="Fill-in-Middle Middle token. Defaults to ''.", - ) - parser.add_argument( - "--fim_pad_token", - type=str, - default="", - help=("Fill-in-Middle Pad token. Used only when 'truncate_or_pad' is set to True. Defaults to ''."), - ) - parser.add_argument( - "--preprocessing_num_workers", - type=int, - default=None, - help="The number of processes to use for the preprocessing.", - ) - parser.add_argument( - "--overwrite_cache", action="store_true", help="Overwrite the cached training and evaluation sets" - ) - parser.add_argument( - "--no_keep_linebreaks", action="store_true", help="Do not keep line breaks when using TXT files." - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - if args.dataset_name is None and args.train_file is None and args.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - if extension not in ["csv", "json", "txt"]: - raise ValueError("`train_file` should be a csv, json or txt file.") - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - if extension not in ["csv", "json", "txt"]: - raise ValueError("`validation_file` should be a csv, json or txt file.") - - if args.push_to_hub: - if args.output_dir is None: - raise ValueError("Need an `output_dir` to create a repo when `--push_to_hub` is passed.") - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - # Set a numpy random state for FIM transformations - np_rng = np.random.RandomState(seed=args.seed) - else: - # Still set a random state for FIM transformations - np_rng = np.random.RandomState(seed=42) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - repo_id = create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - # Clone repo locally - repo = Repository(args.output_dir, clone_from=repo_id, token=args.hub_token) - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - args.dataset_name, - args.dataset_config_name, - split=f"train[:{args.validation_split_percentage}%]", - trust_remote_code=args.trust_remote_code, - ) - raw_datasets["train"] = load_dataset( - args.dataset_name, - args.dataset_config_name, - split=f"train[{args.validation_split_percentage}%:]", - trust_remote_code=args.trust_remote_code, - ) - else: - data_files = {} - dataset_args = {} - if args.train_file is not None: - data_files["train"] = args.train_file - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.train_file.split(".")[-1] - if extension == "txt": - extension = "text" - dataset_args["keep_linebreaks"] = not args.no_keep_linebreaks - raw_datasets = load_dataset(extension, data_files=data_files, **dataset_args) - # If no validation data is there, validation_split_percentage will be used to divide the dataset. - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - extension, - data_files=data_files, - split=f"train[:{args.validation_split_percentage}%]", - **dataset_args, - ) - raw_datasets["train"] = load_dataset( - extension, - data_files=data_files, - split=f"train[{args.validation_split_percentage}%:]", - **dataset_args, - ) - - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets.html. - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - if args.config_name: - config = AutoConfig.from_pretrained( - args.config_name, - trust_remote_code=args.trust_remote_code, - ) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained( - args.model_name_or_path, - trust_remote_code=args.trust_remote_code, - ) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - - if args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained( - args.tokenizer_name, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - elif args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained( - args.model_name_or_path, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if args.model_name_or_path: - model = AutoModelForCausalLM.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForCausalLM.from_config(config, trust_remote_code=args.trust_remote_code) - - # Add the new FIM tokens to the tokenizer and resize model's vocab embeddings - special_tokens = [args.fim_prefix_token, args.fim_middle_token, args.fim_suffix_token] - if args.truncate_or_pad: - special_tokens.append(args.fim_pad_token) - - # Get the factor by which the embedding layer should be padded based on the device - pad_factor = 1 - if torch.cuda.is_available(): - pad_factor = 8 - - elif is_torch_xla_available(check_is_tpu=True): - pad_factor = 128 - - # Add the new tokens to the tokenizer - tokenizer.add_tokens(special_tokens) - original_embeddings = model.get_input_embeddings() - - if is_deepspeed_zero3_enabled(): - import deepspeed - - with deepspeed.zero.GatheredParameters(original_embeddings.weight, modifier_rank=0): - # Get the pre-expansion embeddings of the model and resize the embedding layer - model.resize_token_embeddings(len(tokenizer), pad_to_multiple_of=pad_factor) - embeddings = model.get_input_embeddings() - - # Sample the embeddings for the new tokens from a multivariate normal distribution - # We do this so that the new embeddings are close to the original embeddings and not necessarily zero - # More on this: https://nlp.stanford.edu/~johnhew/vocab-expansion.html - mean = original_embeddings.mean(dim=0) - n = original_embeddings.size()[0] - sigma = ((original_embeddings - mean).T @ (original_embeddings - mean)) / n - dist = torch.distributions.multivariate_normal.MultivariateNormal( - mean, - covariance_matrix=1e-5 * sigma, - ) - new_token_embeddings = torch.stack( - tuple(dist.sample() for _ in range(len(special_tokens))), - dim=0, - ) - else: - original_embeddings = model.get_input_embeddings() - # Get the pre-expansion embeddings of the model and resize the embedding layer - model.resize_token_embeddings(len(tokenizer), pad_to_multiple_of=pad_factor) - embeddings = model.get_input_embeddings() - - # Sample the embeddings for the new tokens from a multivariate normal distribution - # We do this so that the new embeddings are close to the original embeddings and not necessarily zero - # More on this: https://nlp.stanford.edu/~johnhew/vocab-expansion.html - mean = original_embeddings.mean(dim=0) - n = original_embeddings.size()[0] - sigma = ((original_embeddings - mean).T @ (original_embeddings - mean)) / n - dist = torch.distributions.multivariate_normal.MultivariateNormal( - mean, - covariance_matrix=1e-5 * sigma, - ) - new_token_embeddings = torch.stack( - tuple(dist.sample() for _ in range(len(special_tokens))), - dim=0, - ) - - if is_deepspeed_zero3_enabled(): - import deepspeed - - with deepspeed.zero.GatheredParameters(embeddings.weight, modifier_rank=0): - # Set the new tokens' embeddings to the newly sampled embeddings - embeddings.weight.data[-len(special_tokens) :] = new_token_embeddings - else: - # Set the new tokens' embeddings to the newly sampled embeddings - embeddings.weight.data[-len(special_tokens) :] = new_token_embeddings - - # Update the model's embeddings with the new embeddings - model.set_input_embeddings(embeddings) - - logger.info("Added special tokens to the tokenizer and resized model's embedding layer") - - # Preprocessing the datasets. - # First we tokenize all the texts. - column_names = raw_datasets["train"].column_names - text_column_name = "text" if "text" in column_names else column_names[0] - - def tokenize_function(examples): - return tokenizer(examples[text_column_name]) - - with accelerator.main_process_first(): - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - - if args.block_size is None: - block_size = tokenizer.model_max_length - if block_size > config.max_position_embeddings: - logger.warning( - f"The tokenizer picked seems to have a very large `model_max_length` ({tokenizer.model_max_length}). " - f"Using block_size={min(1024, config.max_position_embeddings)} instead. You can change that default value by passing --block_size xxx." - ) - block_size = min(1024, config.max_position_embeddings) - else: - if args.block_size > tokenizer.model_max_length: - logger.warning( - f"The block_size passed ({args.block_size}) is larger than the maximum length for the model " - f"({tokenizer.model_max_length}). Using block_size={tokenizer.model_max_length}." - ) - block_size = min(args.block_size, tokenizer.model_max_length) - - # Main data processing function that will concatenate all texts from our dataset and generate chunks of block_size. - def group_texts(examples): - # Concatenate all texts. - concatenated_examples = {k: list(chain(*examples[k])) for k in examples} - total_length = len(concatenated_examples[list(examples.keys())[0]]) - # We drop the small remainder, and if the total_length < block_size we exclude this batch and return an empty dict. - # We could add padding if the model supported it instead of this drop, you can customize this part to your needs. - total_length = (total_length // block_size) * block_size - # Split by chunks of max_len. - result = { - k: [t[i : i + block_size] for i in range(0, total_length, block_size)] - for k, t in concatenated_examples.items() - } - result["labels"] = result["input_ids"].copy() - return result - - # Get the FIM-specific token ids - prefix_tok_id = tokenizer.convert_tokens_to_ids(args.fim_prefix_token) - middle_tok_id = tokenizer.convert_tokens_to_ids(args.fim_middle_token) - suffix_tok_id = tokenizer.convert_tokens_to_ids(args.fim_suffix_token) - pad_tok_id = None - - # If truncate_or_pad is on, also get pad token id - if args.truncate_or_pad: - pad_tok_id = tokenizer.convert_tokens_to_ids(args.fim_pad_token) - - # The two functions below perform the FIM transformation on the data (either PSM or SPM or PSM+SPM) - # Don't call fim_transform directly in .map() - # Adapted from https://github.com/loubnabnl/santacoder-finetuning/blob/main/fim.py#L22C13-L83 - def fim_transform(example): - """ - This function performs FIM transformation on a single example (list of tokens) - """ - if np_rng.binomial(1, args.fim_rate): - boundaries = sorted(np_rng.randint(low=0, high=len(example) + 1, size=2)) - - prefix = example[: boundaries[0]] - middle = example[boundaries[0] : boundaries[1]] - suffix = example[boundaries[1] :] - - if args.truncate_or_pad: - total_length = len(prefix) + len(middle) + len(suffix) + 3 - diff = total_length - len(example) - if diff > 0: - suffix = suffix[: max(0, len(suffix) - diff)] - elif diff < 0: - suffix.extend([pad_tok_id] * (-diff)) - - if np_rng.binomial(1, args.fim_spm_rate): - # Apply Suffix-Prefix-Middle (SPM) transformation - transformed_example = [prefix_tok_id, suffix_tok_id] + suffix + [middle_tok_id] + prefix + middle - else: - # Apply Prefix-Suffix-Middle (PSM) transformation - transformed_example = [prefix_tok_id] + prefix + [suffix_tok_id] + suffix + [middle_tok_id] + middle - else: - transformed_example = example - - return transformed_example - - # Below function is the one you are supposed to call in the .map() function - def apply_fim(examples): - """ - Apply FIM transformation to a batch of examples - """ - fim_transform_ids = [fim_transform(ids) for ids in examples["input_ids"]] - examples["input_ids"] = fim_transform_ids - examples["labels"] = fim_transform_ids - # If your application requires custom attention mask, please adjust this function's below line. - # Since FIM transformation increases the number of tokens in input_ids and labels - # but leaves the number of tokens unchanged in attention_masks which would cause problems - examples["attention_mask"] = [[1] * len(mask) for mask in examples["input_ids"]] - return examples - - # Note that with `batched=True`, this map processes 1,000 texts together, so group_texts throws away a remainder - # for each of those groups of 1,000 texts. You can adjust that batch_size here but a higher value might be slower - # to preprocess. - # - # To speed up this part, we use multiprocessing. See the documentation of the map method for more information: - # https://huggingface.co/docs/datasets/process#map - - # FIM transformations are only supposed to be applied before group_texts processing otherwise some sentences will - # have 3-4 more tokens than others due to probabilistic addition of FIM-specific tokens which will raise errors - with accelerator.main_process_first(): - fim_datasets = tokenized_datasets.map( - apply_fim, - batched=True, - num_proc=args.preprocessing_num_workers, - load_from_cache_file=not args.overwrite_cache, - desc="Performing FIM transformation", - ) - lm_datasets = fim_datasets.map( - group_texts, - batched=True, - num_proc=args.preprocessing_num_workers, - load_from_cache_file=not args.overwrite_cache, - desc=f"Grouping texts in chunks of {block_size}", - ) - - train_dataset = lm_datasets["train"] - eval_dataset = lm_datasets["validation"] - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # DataLoaders creation: - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=default_data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader( - eval_dataset, collate_fn=default_data_collator, batch_size=args.per_device_eval_batch_size - ) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * args.gradient_accumulation_steps, - num_training_steps=args.max_train_steps * args.gradient_accumulation_steps, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # On TPU, the tie weights in our model have been disconnected, so we need to restore the ties. - if accelerator.distributed_type == DistributedType.TPU: - model.tie_weights() - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("fim_no_trainer", experiment_config) - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - if completed_steps >= args.max_train_steps: - break - - model.eval() - losses = [] - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - - loss = outputs.loss - losses.append(accelerator.gather_for_metrics(loss.repeat(args.per_device_eval_batch_size))) - - losses = torch.cat(losses) - try: - eval_loss = torch.mean(losses) - perplexity = math.exp(eval_loss) - except OverflowError: - perplexity = float("inf") - - logger.info(f"epoch {epoch}: perplexity: {perplexity} eval_loss: {eval_loss}") - - if args.with_tracking: - accelerator.log( - { - "perplexity": perplexity, - "eval_loss": eval_loss, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - repo.push_to_hub( - commit_message=f"Training in progress epoch {epoch}", blocking=False, auto_lfs_prune=True - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - repo.push_to_hub(commit_message="End of training", auto_lfs_prune=True) - - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump({"perplexity": perplexity}, f) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/language-modeling/run_mlm.py b/examples/pytorch/language-modeling/run_mlm.py deleted file mode 100755 index 129a2f7952cb..000000000000 --- a/examples/pytorch/language-modeling/run_mlm.py +++ /dev/null @@ -1,670 +0,0 @@ -#!/usr/bin/env python -# Copyright 2020 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "accelerate >= 0.12.0", -# "torch >= 1.3", -# "datasets >= 2.14.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "evaluate", -# "scikit-learn", -# ] -# /// - -""" -Fine-tuning the library models for masked language modeling (BERT, ALBERT, RoBERTa...) on a text file or a dataset. - -Here is the full list of checkpoints on the hub that can be fine-tuned by this script: -https://huggingface.co/models?filter=fill-mask -""" -# You can also adapt this script on your own masked language modeling task. Pointers for this are left as comments. - -import logging -import math -import os -import sys -from dataclasses import dataclass, field -from itertools import chain - -import datasets -import evaluate -import torch -from datasets import load_dataset - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_FOR_MASKED_LM_MAPPING, - AutoConfig, - AutoModelForMaskedLM, - AutoTokenizer, - DataCollatorForLanguageModeling, - HfArgumentParser, - Trainer, - TrainingArguments, - is_torch_xla_available, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.14.0", "To fix: pip install -r examples/pytorch/language-modeling/requirements.txt") - -logger = logging.getLogger(__name__) -MODEL_CONFIG_CLASSES = list(MODEL_FOR_MASKED_LM_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune, or train from scratch. - """ - - model_name_or_path: str | None = field( - default=None, - metadata={ - "help": ( - "The model checkpoint for weights initialization. Don't set if you want to train a model from scratch." - ) - }, - ) - model_type: str | None = field( - default=None, - metadata={"help": "If training from scratch, pass a model type from the list: " + ", ".join(MODEL_TYPES)}, - ) - config_overrides: str | None = field( - default=None, - metadata={ - "help": ( - "Override some existing default config settings when a model is trained from scratch. Example: " - "n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index" - ) - }, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - dtype: str | None = field( - default=None, - metadata={ - "help": ( - "Override the default `torch.dtype` and load the model under this dtype. If `auto` is passed, the " - "dtype will be automatically derived from the model's weights." - ), - "choices": ["auto", "bfloat16", "float16", "float32"], - }, - ) - - def __post_init__(self): - if self.config_overrides is not None and (self.config_name is not None or self.model_name_or_path is not None): - raise ValueError( - "--config_overrides can't be used in combination with --config_name or --model_name_or_path" - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a text file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."}, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - validation_split_percentage: int | None = field( - default=5, - metadata={ - "help": "The percentage of the train set used as validation set in case there's no validation split" - }, - ) - max_seq_length: int | None = field( - default=None, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated." - ) - }, - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - mlm_probability: float = field( - default=0.15, metadata={"help": "Ratio of tokens to mask for masked language modeling loss"} - ) - line_by_line: bool = field( - default=False, - metadata={"help": "Whether distinct lines of text in the dataset are to be handled as distinct sequences."}, - ) - pad_to_max_length: bool = field( - default=False, - metadata={ - "help": ( - "Whether to pad all samples to `max_seq_length`. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - streaming: bool = field(default=False, metadata={"help": "Enable streaming mode"}) - - def __post_init__(self): - if self.streaming: - require_version("datasets>=2.0.0", "The streaming feature requires `datasets>=2.0.0`") - - if self.dataset_name is None and self.train_file is None and self.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - if extension not in ["csv", "json", "txt"]: - raise ValueError("`train_file` should be a csv, a json or a txt file.") - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - if extension not in ["csv", "json", "txt"]: - raise ValueError("`validation_file` should be a csv, a json or a txt file.") - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - # Set the verbosity to info of the Transformers logger (on main process only): - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub - # - # For CSV/JSON files, this script will use the column called 'text' or the first column. You can easily tweak this - # behavior (see below) - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=f"train[:{data_args.validation_split_percentage}%]", - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - raw_datasets["train"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=f"train[{data_args.validation_split_percentage}%:]", - cache_dir=model_args.cache_dir, - token=model_args.token, - streaming=data_args.streaming, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - if extension == "txt": - extension = "text" - raw_datasets = load_dataset( - extension, - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - - # If no validation data is there, validation_split_percentage will be used to divide the dataset. - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - extension, - data_files=data_files, - split=f"train[:{data_args.validation_split_percentage}%]", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - raw_datasets["train"] = load_dataset( - extension, - data_files=data_files, - split=f"train[{data_args.validation_split_percentage}%:]", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config_kwargs = { - "cache_dir": model_args.cache_dir, - "revision": model_args.model_revision, - "token": model_args.token, - "trust_remote_code": model_args.trust_remote_code, - } - if model_args.config_name: - config = AutoConfig.from_pretrained(model_args.config_name, **config_kwargs) - elif model_args.model_name_or_path: - config = AutoConfig.from_pretrained(model_args.model_name_or_path, **config_kwargs) - else: - config = CONFIG_MAPPING[model_args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - if model_args.config_overrides is not None: - logger.info(f"Overriding config: {model_args.config_overrides}") - config.update_from_string(model_args.config_overrides) - logger.info(f"New config: {config}") - - tokenizer_kwargs = { - "cache_dir": model_args.cache_dir, - "use_fast": model_args.use_fast_tokenizer, - "revision": model_args.model_revision, - "token": model_args.token, - "trust_remote_code": model_args.trust_remote_code, - } - if model_args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained(model_args.tokenizer_name, **tokenizer_kwargs) - elif model_args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained(model_args.model_name_or_path, **tokenizer_kwargs) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if model_args.model_name_or_path: - dtype = model_args.dtype if model_args.dtype in ["auto", None] else getattr(torch, model_args.dtype) - model = AutoModelForMaskedLM.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - dtype=dtype, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForMaskedLM.from_config(config, trust_remote_code=model_args.trust_remote_code) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Preprocessing the datasets. - # First we tokenize all the texts. - if training_args.do_train: - column_names = list(raw_datasets["train"].features) - else: - column_names = list(raw_datasets["validation"].features) - text_column_name = "text" if "text" in column_names else column_names[0] - - if data_args.max_seq_length is None: - max_seq_length = tokenizer.model_max_length - if max_seq_length > 1024: - logger.warning( - "The chosen tokenizer supports a `model_max_length` that is longer than the default `block_size` value" - " of 1024. If you would like to use a longer `block_size` up to `tokenizer.model_max_length` you can" - " override this default with `--block_size xxx`." - ) - max_seq_length = 1024 - else: - if data_args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({data_args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) - - if data_args.line_by_line: - # When using line_by_line, we just tokenize each nonempty line. - padding = "max_length" if data_args.pad_to_max_length else False - - def tokenize_function(examples): - # Remove empty lines - examples[text_column_name] = [ - line for line in examples[text_column_name] if len(line) > 0 and not line.isspace() - ] - return tokenizer( - examples[text_column_name], - padding=padding, - truncation=True, - max_length=max_seq_length, - # We use this option because DataCollatorForLanguageModeling (see below) is more efficient when it - # receives the `special_tokens_mask`. - return_special_tokens_mask=True, - ) - - with training_args.main_process_first(desc="dataset map tokenization"): - if not data_args.streaming: - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=[text_column_name], - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on dataset line_by_line", - ) - else: - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - remove_columns=[text_column_name], - ) - else: - # Otherwise, we tokenize every text, then concatenate them together before splitting them in smaller parts. - # We use `return_special_tokens_mask=True` because DataCollatorForLanguageModeling (see below) is more - # efficient when it receives the `special_tokens_mask`. - def tokenize_function(examples): - return tokenizer(examples[text_column_name], return_special_tokens_mask=True) - - with training_args.main_process_first(desc="dataset map tokenization"): - if not data_args.streaming: - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on every text in dataset", - ) - else: - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - remove_columns=column_names, - ) - - # Main data processing function that will concatenate all texts from our dataset and generate chunks of - # max_seq_length. - def group_texts(examples): - # Concatenate all texts. - concatenated_examples = {k: list(chain(*examples[k])) for k in examples} - total_length = len(concatenated_examples[list(examples.keys())[0]]) - # We drop the small remainder, and if the total_length < max_seq_length we exclude this batch and return an empty dict. - # We could add padding if the model supported it instead of this drop, you can customize this part to your needs. - total_length = (total_length // max_seq_length) * max_seq_length - # Split by chunks of max_len. - result = { - k: [t[i : i + max_seq_length] for i in range(0, total_length, max_seq_length)] - for k, t in concatenated_examples.items() - } - return result - - # Note that with `batched=True`, this map processes 1,000 texts together, so group_texts throws away a - # remainder for each of those groups of 1,000 texts. You can adjust that batch_size here but a higher value - # might be slower to preprocess. - # - # To speed up this part, we use multiprocessing. See the documentation of the map method for more information: - # https://huggingface.co/docs/datasets/process#map - - with training_args.main_process_first(desc="grouping texts together"): - if not data_args.streaming: - tokenized_datasets = tokenized_datasets.map( - group_texts, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc=f"Grouping texts in chunks of {max_seq_length}", - ) - else: - tokenized_datasets = tokenized_datasets.map( - group_texts, - batched=True, - ) - - if training_args.do_train: - if "train" not in tokenized_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = tokenized_datasets["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - if training_args.do_eval: - if "validation" not in tokenized_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_dataset = tokenized_datasets["validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - def preprocess_logits_for_metrics(logits, labels): - if isinstance(logits, tuple): - # Depending on the model and config, logits may contain extra tensors, - # like past_key_values, but logits always come first - logits = logits[0] - return logits.argmax(dim=-1) - - metric = evaluate.load("accuracy", cache_dir=model_args.cache_dir) - - def compute_metrics(eval_preds): - preds, labels = eval_preds - # preds have the same shape as the labels, after the argmax(-1) has been calculated - # by preprocess_logits_for_metrics - labels = labels.reshape(-1) - preds = preds.reshape(-1) - mask = labels != -100 - labels = labels[mask] - preds = preds[mask] - return metric.compute(predictions=preds, references=labels) - - # Data collator - # This one will take care of randomly masking the tokens. - pad_to_multiple_of_8 = data_args.line_by_line and training_args.fp16 and not data_args.pad_to_max_length - data_collator = DataCollatorForLanguageModeling( - tokenizer=tokenizer, - mlm_probability=data_args.mlm_probability, - pad_to_multiple_of=8 if pad_to_multiple_of_8 else None, - ) - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - processing_class=tokenizer, - data_collator=data_collator, - compute_metrics=compute_metrics if training_args.do_eval and not is_torch_xla_available() else None, - preprocess_logits_for_metrics=preprocess_logits_for_metrics - if training_args.do_eval and not is_torch_xla_available() - else None, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - metrics = train_result.metrics - - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - - metrics = trainer.evaluate() - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - try: - perplexity = math.exp(metrics["eval_loss"]) - except OverflowError: - perplexity = float("inf") - metrics["perplexity"] = perplexity - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "fill-mask"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/language-modeling/run_mlm_no_trainer.py b/examples/pytorch/language-modeling/run_mlm_no_trainer.py deleted file mode 100755 index 714abf6acd55..000000000000 --- a/examples/pytorch/language-modeling/run_mlm_no_trainer.py +++ /dev/null @@ -1,767 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "accelerate >= 0.12.0", -# "torch >= 1.3", -# "datasets >= 2.14.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "evaluate", -# "scikit-learn", -# ] -# /// - -""" -Fine-tuning the library models for masked language modeling (BERT, ALBERT, RoBERTa...) -on a text file or a dataset without using HuggingFace Trainer. - -Here is the full list of checkpoints on the hub that can be fine-tuned by this script: -https://huggingface.co/models?filter=fill-mask -""" -# You can also adapt this script on your own mlm task. Pointers for this are left as comments. - -import argparse -import json -import logging -import math -import os -import random -from itertools import chain -from pathlib import Path - -import datasets -import torch -from accelerate import Accelerator, DistributedType -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_MAPPING, - AutoConfig, - AutoModelForMaskedLM, - AutoTokenizer, - DataCollatorForLanguageModeling, - SchedulerType, - get_scheduler, -) -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) -require_version("datasets>=2.14.0", "To fix: pip install -r examples/pytorch/language-modeling/requirements.txt") -MODEL_CONFIG_CLASSES = list(MODEL_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a Masked Language Modeling task") - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv or a json file containing the training data." - ) - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv or a json file containing the validation data." - ) - parser.add_argument( - "--validation_split_percentage", - default=5, - help="The percentage of the train set used as validation set in case there's no validation split", - ) - parser.add_argument( - "--pad_to_max_length", - action="store_true", - help="If passed, pad all samples to `max_length`. Otherwise, dynamic padding is used.", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=False, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--tokenizer_name", - type=str, - default=None, - help="Pretrained tokenizer name or path if not the same as model_name", - ) - parser.add_argument( - "--use_slow_tokenizer", - action="store_true", - help="If passed, will use a slow tokenizer (not backed by the Hugging Face Tokenizers library).", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument( - "--model_type", - type=str, - default=None, - help="Model type to use if training from scratch.", - choices=MODEL_TYPES, - ) - parser.add_argument( - "--max_seq_length", - type=int, - default=None, - help=( - "The maximum total input sequence length after tokenization. Sequences longer than this will be truncated." - ), - ) - parser.add_argument( - "--line_by_line", - type=bool, - default=False, - help="Whether distinct lines of text in the dataset are to be handled as distinct sequences.", - ) - parser.add_argument( - "--preprocessing_num_workers", - type=int, - default=None, - help="The number of processes to use for the preprocessing.", - ) - parser.add_argument( - "--overwrite_cache", action="store_true", help="Overwrite the cached training and evaluation sets" - ) - parser.add_argument( - "--mlm_probability", type=float, default=0.15, help="Ratio of tokens to mask for masked language modeling loss" - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - if args.dataset_name is None and args.train_file is None and args.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - if extension not in ["csv", "json", "txt"]: - raise ValueError("`train_file` should be a csv, json or txt file.") - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - if extension not in ["csv", "json", "txt"]: - raise ValueError("`validation_file` should be a csv, json or txt file.") - - if args.push_to_hub: - if args.output_dir is None: - raise ValueError("Need an `output_dir` to create a repo when `--push_to_hub` is passed.") - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - args.dataset_name, - args.dataset_config_name, - split=f"train[:{args.validation_split_percentage}%]", - trust_remote_code=args.trust_remote_code, - ) - raw_datasets["train"] = load_dataset( - args.dataset_name, - args.dataset_config_name, - split=f"train[{args.validation_split_percentage}%:]", - trust_remote_code=args.trust_remote_code, - ) - else: - data_files = {} - if args.train_file is not None: - data_files["train"] = args.train_file - extension = args.train_file.split(".")[-1] - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.validation_file.split(".")[-1] - if extension == "txt": - extension = "text" - raw_datasets = load_dataset(extension, data_files=data_files) - # If no validation data is there, validation_split_percentage will be used to divide the dataset. - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - extension, - data_files=data_files, - split=f"train[:{args.validation_split_percentage}%]", - ) - raw_datasets["train"] = load_dataset( - extension, - data_files=data_files, - split=f"train[{args.validation_split_percentage}%:]", - ) - - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - if args.config_name: - config = AutoConfig.from_pretrained(args.config_name, trust_remote_code=args.trust_remote_code) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained(args.model_name_or_path, trust_remote_code=args.trust_remote_code) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - - if args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained( - args.tokenizer_name, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - elif args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained( - args.model_name_or_path, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if args.model_name_or_path: - model = AutoModelForMaskedLM.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForMaskedLM.from_config(config, trust_remote_code=args.trust_remote_code) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Preprocessing the datasets. - # First we tokenize all the texts. - column_names = raw_datasets["train"].column_names - text_column_name = "text" if "text" in column_names else column_names[0] - - if args.max_seq_length is None: - max_seq_length = tokenizer.model_max_length - if max_seq_length > 1024: - logger.warning( - "The chosen tokenizer supports a `model_max_length` that is longer than the default `block_size` value" - " of 1024. If you would like to use a longer `block_size` up to `tokenizer.model_max_length` you can" - " override this default with `--block_size xxx`." - ) - max_seq_length = 1024 - else: - if args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(args.max_seq_length, tokenizer.model_max_length) - - if args.line_by_line: - # When using line_by_line, we just tokenize each nonempty line. - padding = "max_length" if args.pad_to_max_length else False - - def tokenize_function(examples): - # Remove empty lines - examples[text_column_name] = [ - line for line in examples[text_column_name] if len(line) > 0 and not line.isspace() - ] - return tokenizer( - examples[text_column_name], - padding=padding, - truncation=True, - max_length=max_seq_length, - # We use this option because DataCollatorForLanguageModeling (see below) is more efficient when it - # receives the `special_tokens_mask`. - return_special_tokens_mask=True, - ) - - with accelerator.main_process_first(): - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=[text_column_name], - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on dataset line_by_line", - ) - else: - # Otherwise, we tokenize every text, then concatenate them together before splitting them in smaller parts. - # We use `return_special_tokens_mask=True` because DataCollatorForLanguageModeling (see below) is more - # efficient when it receives the `special_tokens_mask`. - def tokenize_function(examples): - return tokenizer(examples[text_column_name], return_special_tokens_mask=True) - - with accelerator.main_process_first(): - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on every text in dataset", - ) - - # Main data processing function that will concatenate all texts from our dataset and generate chunks of - # max_seq_length. - def group_texts(examples): - # Concatenate all texts. - concatenated_examples = {k: list(chain(*examples[k])) for k in examples} - total_length = len(concatenated_examples[list(examples.keys())[0]]) - # We drop the small remainder, and if the total_length < max_seq_length we exclude this batch and return an empty dict. - # We could add padding if the model supported it instead of this drop, you can customize this part to your needs. - total_length = (total_length // max_seq_length) * max_seq_length - # Split by chunks of max_len. - result = { - k: [t[i : i + max_seq_length] for i in range(0, total_length, max_seq_length)] - for k, t in concatenated_examples.items() - } - return result - - # Note that with `batched=True`, this map processes 1,000 texts together, so group_texts throws away a - # remainder for each of those groups of 1,000 texts. You can adjust that batch_size here but a higher value - # might be slower to preprocess. - # - # To speed up this part, we use multiprocessing. See the documentation of the map method for more information: - # https://huggingface.co/docs/datasets/process#map - - with accelerator.main_process_first(): - tokenized_datasets = tokenized_datasets.map( - group_texts, - batched=True, - num_proc=args.preprocessing_num_workers, - load_from_cache_file=not args.overwrite_cache, - desc=f"Grouping texts in chunks of {max_seq_length}", - ) - - train_dataset = tokenized_datasets["train"] - eval_dataset = tokenized_datasets["validation"] - - # Conditional for small test subsets - if len(train_dataset) > 3: - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # Data collator - # This one will take care of randomly masking the tokens. - data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=args.mlm_probability) - - # DataLoaders creation: - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader(eval_dataset, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Note -> the training dataloader needs to be prepared before we grab his length below (cause its length will be - # shorter in multiprocess) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # On TPU, the tie weights in our model have been disconnected, so we need to restore the ties. - if accelerator.distributed_type == DistributedType.TPU: - model.tie_weights() - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("mlm_no_trainer", experiment_config) - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if completed_steps >= args.max_train_steps: - break - - model.eval() - losses = [] - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - - loss = outputs.loss - losses.append(accelerator.gather_for_metrics(loss.repeat(args.per_device_eval_batch_size))) - - losses = torch.cat(losses) - try: - eval_loss = torch.mean(losses) - perplexity = math.exp(eval_loss) - except OverflowError: - perplexity = float("inf") - - logger.info(f"epoch {epoch}: perplexity: {perplexity} eval_loss: {eval_loss}") - - if args.with_tracking: - accelerator.log( - { - "perplexity": perplexity, - "eval_loss": eval_loss, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump({"perplexity": perplexity}, f) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/language-modeling/run_plm.py b/examples/pytorch/language-modeling/run_plm.py deleted file mode 100755 index 709ba74ce985..000000000000 --- a/examples/pytorch/language-modeling/run_plm.py +++ /dev/null @@ -1,567 +0,0 @@ -#!/usr/bin/env python -# Copyright 2020 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "accelerate >= 0.12.0", -# "torch >= 1.3", -# "datasets >= 2.14.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "evaluate", -# "scikit-learn", -# ] -# /// - -""" -Fine-tuning the library models for permutation language modeling. -""" -# You can also adapt this script on your own permutation language modeling task. Pointers for this are left as comments. - -import logging -import math -import os -import sys -from dataclasses import dataclass, field -from itertools import chain - -import datasets -from datasets import load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoTokenizer, - DataCollatorForPermutationLanguageModeling, - HfArgumentParser, - Trainer, - TrainingArguments, - XLNetConfig, - XLNetLMHeadModel, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.14.0", "To fix: pip install -r examples/pytorch/language-modeling/requirements.txt") - -logger = logging.getLogger(__name__) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune, or train from scratch. - """ - - model_name_or_path: str | None = field( - default=None, - metadata={ - "help": ( - "The model checkpoint for weights initialization. Don't set if you want to train a model from scratch." - ) - }, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - config_overrides: str | None = field( - default=None, - metadata={ - "help": ( - "Override some existing default config settings when a model is trained from scratch. Example: " - "n_embd=10,resid_pdrop=0.2,scale_attn_weights=false,summary_type=cls_index" - ) - }, - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - - def __post_init__(self): - if self.config_overrides is not None and (self.config_name is not None or self.model_name_or_path is not None): - raise ValueError( - "--config_overrides can't be used in combination with --config_name or --model_name_or_path" - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a text file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."}, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - validation_split_percentage: int | None = field( - default=5, - metadata={ - "help": "The percentage of the train set used as validation set in case there's no validation split" - }, - ) - max_seq_length: int = field( - default=512, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated." - ) - }, - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - plm_probability: float = field( - default=1 / 6, - metadata={ - "help": ( - "Ratio of length of a span of masked tokens to surrounding context length for " - "permutation language modeling." - ) - }, - ) - max_span_length: int = field( - default=5, metadata={"help": "Maximum length of a span of masked tokens for permutation language modeling."} - ) - line_by_line: bool = field( - default=False, - metadata={"help": "Whether distinct lines of text in the dataset are to be handled as distinct sequences."}, - ) - pad_to_max_length: bool = field( - default=False, - metadata={ - "help": ( - "Whether to pad all samples to `max_seq_length`. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - - def __post_init__(self): - if self.dataset_name is None and self.train_file is None and self.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json", "txt"], "`train_file` should be a csv, a json or a txt file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json", "txt"], "`validation_file` should be a csv, a json or a txt file." - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=f"train[:{data_args.validation_split_percentage}%]", - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - raw_datasets["train"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=f"train[{data_args.validation_split_percentage}%:]", - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - if extension == "txt": - extension = "text" - raw_datasets = load_dataset(extension, data_files=data_files, cache_dir=model_args.cache_dir) - # If no validation data is there, validation_split_percentage will be used to divide the dataset. - if "validation" not in raw_datasets: - raw_datasets["validation"] = load_dataset( - extension, - data_files=data_files, - split=f"train[:{data_args.validation_split_percentage}%]", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - raw_datasets["train"] = load_dataset( - extension, - data_files=data_files, - split=f"train[{data_args.validation_split_percentage}%:]", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config_kwargs = { - "cache_dir": model_args.cache_dir, - "revision": model_args.model_revision, - "token": model_args.token, - } - if model_args.config_name: - config = AutoConfig.from_pretrained(model_args.config_name, **config_kwargs) - elif model_args.model_name_or_path: - config = AutoConfig.from_pretrained(model_args.model_name_or_path, **config_kwargs) - else: - config = XLNetConfig() - logger.warning("You are instantiating a new config instance from scratch.") - if model_args.config_overrides is not None: - logger.info(f"Overriding config: {model_args.config_overrides}") - config.update_from_string(model_args.config_overrides) - logger.info(f"New config: {config}") - - tokenizer_kwargs = { - "cache_dir": model_args.cache_dir, - "use_fast": model_args.use_fast_tokenizer, - "revision": model_args.model_revision, - "token": model_args.token, - } - if model_args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained(model_args.tokenizer_name, **tokenizer_kwargs) - elif model_args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained(model_args.model_name_or_path, **tokenizer_kwargs) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if model_args.model_name_or_path: - model = XLNetLMHeadModel.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - ) - else: - logger.info("Training new model from scratch") - model = XLNetLMHeadModel(config) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Preprocessing the datasets. - # First we tokenize all the texts. - if training_args.do_train: - column_names = raw_datasets["train"].column_names - else: - column_names = raw_datasets["validation"].column_names - text_column_name = "text" if "text" in column_names else column_names[0] - - if data_args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({data_args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) - - if data_args.line_by_line: - # When using line_by_line, we just tokenize each nonempty line. - padding = "max_length" if data_args.pad_to_max_length else False - - def tokenize_function(examples): - # Remove empty lines - examples["text"] = [line for line in examples["text"] if len(line) > 0 and not line.isspace()] - return tokenizer(examples["text"], padding=padding, truncation=True, max_length=max_seq_length) - - with training_args.main_process_first(desc="dataset map tokenization"): - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=[text_column_name], - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on dataset line_by_line", - ) - else: - # Otherwise, we tokenize every text, then concatenate them together before splitting them in smaller parts. - def tokenize_function(examples): - return tokenizer(examples[text_column_name]) - - with training_args.main_process_first(desc="dataset map tokenization"): - tokenized_datasets = raw_datasets.map( - tokenize_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on every text in dataset", - ) - - # Main data processing function that will concatenate all texts from our dataset and generate chunks of - # max_seq_length. - def group_texts(examples): - # Concatenate all texts. - concatenated_examples = {k: list(chain(*examples[k])) for k in examples} - total_length = len(concatenated_examples[list(examples.keys())[0]]) - # We drop the small remainder, and if the total_length < max_seq_length we exclude this batch and return an empty dict. - # We could add padding if the model supported it instead of this drop, you can customize this part to your needs. - total_length = (total_length // max_seq_length) * max_seq_length - # Split by chunks of max_len. - result = { - k: [t[i : i + max_seq_length] for i in range(0, total_length, max_seq_length)] - for k, t in concatenated_examples.items() - } - return result - - # Note that with `batched=True`, this map processes 1,000 texts together, so group_texts throws away a - # remainder for each of those groups of 1,000 texts. You can adjust that batch_size here but a higher value - # might be slower to preprocess. - # - # To speed up this part, we use multiprocessing. See the documentation of the map method for more information: - # https://huggingface.co/docs/datasets/process#map - - with training_args.main_process_first(desc="grouping texts together"): - tokenized_datasets = tokenized_datasets.map( - group_texts, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc=f"Grouping texts in chunks of {max_seq_length}", - ) - - if training_args.do_train: - if "train" not in tokenized_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = tokenized_datasets["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - if training_args.do_eval: - if "validation" not in tokenized_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_dataset = tokenized_datasets["validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - # Data collator - data_collator = DataCollatorForPermutationLanguageModeling( - tokenizer=tokenizer, - plm_probability=data_args.plm_probability, - max_span_length=data_args.max_span_length, - ) - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - processing_classtokenizer=tokenizer, - data_collator=data_collator, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - metrics = train_result.metrics - - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - - metrics = trainer.evaluate() - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - try: - perplexity = math.exp(metrics["eval_loss"]) - except OverflowError: - perplexity = float("inf") - metrics["perplexity"] = perplexity - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "language-modeling"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/multiple-choice/README.md b/examples/pytorch/multiple-choice/README.md deleted file mode 100644 index 59b2ba7b81e6..000000000000 --- a/examples/pytorch/multiple-choice/README.md +++ /dev/null @@ -1,108 +0,0 @@ - - -# Multiple Choice - -## Fine-tuning on SWAG with the Trainer - -`run_swag` allows you to fine-tune any model from our [hub](https://huggingface.co/models) (as long as its architecture as a `ForMultipleChoice` version in the library) on the SWAG dataset or your own csv/jsonlines files as long as they are structured the same way. To make it works on another dataset, you will need to tweak the `preprocess_function` inside the script. - -```bash -python run_swag.py \ ---model_name_or_path FacebookAI/roberta-base \ ---do_train \ ---do_eval \ ---learning_rate 5e-5 \ ---num_train_epochs 3 \ ---output_dir /tmp/swag_base \ ---per_device_eval_batch_size=16 \ ---per_device_train_batch_size=16 \ ---overwrite_output -``` -Training with the defined hyper-parameters yields the following results: -``` -***** Eval results ***** -eval_acc = 0.8338998300509847 -eval_loss = 0.44457291918821606 -``` - -## With Accelerate - -Based on the script [run_swag_no_trainer.py](https://github.com/huggingface/transformers/blob/main/examples/pytorch/multiple-choice/run_swag_no_trainer.py). - -Like `run_swag.py`, this script allows you to fine-tune any of the models on the [hub](https://huggingface.co/models) (as long as its architecture as a `ForMultipleChoice` version in the library) on -the SWAG dataset or your own data in a csv or a JSON file. The main difference is that this -script exposes the bare training loop, to allow you to quickly experiment and add any customization you would like. - -It offers less options than the script with `Trainer` (but you can easily change the options for the optimizer -or the dataloaders directly in the script) but still run in a distributed setup, on TPU and supports mixed precision by -the mean of the [🤗 `Accelerate`](https://github.com/huggingface/accelerate) library. You can use the script normally -after installing it: - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -then - -```bash -export DATASET_NAME=allenai/swag - -python run_swag_no_trainer.py \ - --model_name_or_path google-bert/bert-base-cased \ - --dataset_name $DATASET_NAME \ - --max_seq_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$DATASET_NAME/ -``` - -You can then use your usual launchers to run in it in a distributed environment, but the easiest way is to run - -```bash -accelerate config -``` - -and reply to the questions asked. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -export DATASET_NAME=allenai/swag - -accelerate launch run_swag_no_trainer.py \ - --model_name_or_path google-bert/bert-base-cased \ - --dataset_name $DATASET_NAME \ - --max_seq_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$DATASET_NAME/ -``` - -This command is the same and will work for: - -- a CPU-only setup -- a setup with one GPU -- a distributed training with several GPUs (single or multi node) -- a training on TPUs - -Note that this library is in alpha release so your feedback is more than welcome if you encounter any problem using it. diff --git a/examples/pytorch/multiple-choice/requirements.txt b/examples/pytorch/multiple-choice/requirements.txt deleted file mode 100644 index 3bbfaef38eab..000000000000 --- a/examples/pytorch/multiple-choice/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -accelerate >= 0.12.0 -sentencepiece != 0.1.92 -protobuf -torch >= 1.3 -evaluate diff --git a/examples/pytorch/multiple-choice/run_no_trainer.sh b/examples/pytorch/multiple-choice/run_no_trainer.sh deleted file mode 100755 index ed07f25e8265..000000000000 --- a/examples/pytorch/multiple-choice/run_no_trainer.sh +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -accelerate launch run_swag_no_trainer.py \ - --model_name_or_path bert-base-uncased \ - --dataset_name allenai/swag \ - --output_dir /tmp/test-swag-no-trainer \ - --pad_to_max_length diff --git a/examples/pytorch/multiple-choice/run_swag.py b/examples/pytorch/multiple-choice/run_swag.py deleted file mode 100755 index 3c2f9ebf5a25..000000000000 --- a/examples/pytorch/multiple-choice/run_swag.py +++ /dev/null @@ -1,434 +0,0 @@ -#!/usr/bin/env python -# Copyright The HuggingFace Team and The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -""" -Fine-tuning the library models for multiple choice. -""" -# You can also adapt this script on your own multiple choice task. Pointers for this are left as comments. - -import logging -import os -import sys -from dataclasses import dataclass, field -from itertools import chain - -import datasets -import numpy as np -from datasets import load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoModelForMultipleChoice, - AutoTokenizer, - DataCollatorForMultipleChoice, - HfArgumentParser, - Trainer, - TrainingArguments, - default_data_collator, - set_seed, -) -from transformers.utils import check_min_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = logging.getLogger(__name__) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether or not to allow for custom models defined on the Hub in their own modeling files. This option " - "should only be set to `True` for repositories you trust and in which you have read the code, as it will " - "execute code present on the Hub on your local machine." - ) - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a text file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."}, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_seq_length: int | None = field( - default=None, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. If passed, sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - pad_to_max_length: bool = field( - default=False, - metadata={ - "help": ( - "Whether to pad all samples to the maximum sentence length. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch. More " - "efficient on GPU but very bad for TPU." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - - def __post_init__(self): - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.train_file is not None or data_args.validation_file is not None: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - raw_datasets = load_dataset( - extension, - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - else: - # Downloading and loading the swag dataset from the hub. - raw_datasets = load_dataset( - "allenai/swag", - "regular", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForMultipleChoice.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # When using your own dataset or a different dataset from swag, you will probably need to change this. - ending_names = [f"ending{i}" for i in range(4)] - context_name = "sent1" - question_header_name = "sent2" - - if data_args.max_seq_length is None: - max_seq_length = tokenizer.model_max_length - if max_seq_length > 1024: - logger.warning( - "The chosen tokenizer supports a `model_max_length` that is longer than the default `block_size` value" - " of 1024. If you would like to use a longer `block_size` up to `tokenizer.model_max_length` you can" - " override this default with `--block_size xxx`." - ) - max_seq_length = 1024 - else: - if data_args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({data_args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) - - # Preprocessing the datasets. - def preprocess_function(examples): - first_sentences = [[context] * 4 for context in examples[context_name]] - question_headers = examples[question_header_name] - second_sentences = [ - [f"{header} {examples[end][i]}" for end in ending_names] for i, header in enumerate(question_headers) - ] - - # Flatten out - first_sentences = list(chain(*first_sentences)) - second_sentences = list(chain(*second_sentences)) - - # Tokenize - tokenized_examples = tokenizer( - first_sentences, - second_sentences, - truncation=True, - max_length=max_seq_length, - padding="max_length" if data_args.pad_to_max_length else False, - ) - # Un-flatten - return {k: [v[i : i + 4] for i in range(0, len(v), 4)] for k, v in tokenized_examples.items()} - - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - with training_args.main_process_first(desc="train dataset map pre-processing"): - train_dataset = train_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - ) - - if training_args.do_eval: - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_dataset = raw_datasets["validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - with training_args.main_process_first(desc="validation dataset map pre-processing"): - eval_dataset = eval_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - ) - - # Data collator - data_collator = ( - default_data_collator - if data_args.pad_to_max_length - else DataCollatorForMultipleChoice( - tokenizer=tokenizer, pad_to_multiple_of=8 if training_args.fp16 else None, return_tensors="pt" - ) - ) - - # Metric - def compute_metrics(eval_predictions): - predictions, label_ids = eval_predictions - preds = np.argmax(predictions, axis=1) - return {"accuracy": (preds == label_ids).astype(np.float32).mean().item()} - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - processing_class=tokenizer, - data_collator=data_collator, - compute_metrics=compute_metrics, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - metrics = train_result.metrics - - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - - metrics = trainer.evaluate() - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "tasks": "multiple-choice", - "dataset_tags": "swag", - "dataset_args": "regular", - "dataset": "SWAG", - "language": "en", - } - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/multiple-choice/run_swag_no_trainer.py b/examples/pytorch/multiple-choice/run_swag_no_trainer.py deleted file mode 100755 index 070c39b61642..000000000000 --- a/examples/pytorch/multiple-choice/run_swag_no_trainer.py +++ /dev/null @@ -1,661 +0,0 @@ -#!/usr/bin/env python -# Copyright The HuggingFace Team and The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -""" -Fine-tuning a 🤗 Transformers model on multiple choice relying on the accelerate library without using a Trainer. -""" -# You can also adapt this script on your own multiple choice task. Pointers for this are left as comments. - -import argparse -import json -import logging -import math -import os -import random -from itertools import chain -from pathlib import Path - -import datasets -import evaluate -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_MAPPING, - AutoConfig, - AutoModelForMultipleChoice, - AutoTokenizer, - DataCollatorForMultipleChoice, - SchedulerType, - default_data_collator, - get_scheduler, -) -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) -# You should update this to your particular problem to have better documentation of `model_type` -MODEL_CONFIG_CLASSES = list(MODEL_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a multiple choice task") - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv or a json file containing the training data." - ) - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv or a json file containing the validation data." - ) - parser.add_argument( - "--max_seq_length", - type=int, - default=128, - help=( - "The maximum total input sequence length after tokenization. Sequences longer than this will be truncated," - " sequences shorter will be padded if `--pad_to_max_length` is passed." - ), - ) - parser.add_argument( - "--pad_to_max_length", - action="store_true", - help="If passed, pad all samples to `max_length`. Otherwise, dynamic padding is used.", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=False, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--tokenizer_name", - type=str, - default=None, - help="Pretrained tokenizer name or path if not the same as model_name", - ) - parser.add_argument( - "--use_slow_tokenizer", - action="store_true", - help="If passed, will use a slow tokenizer (not backed by the HuggingFace Tokenizers library).", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument( - "--model_type", - type=str, - default=None, - help="Model type to use if training from scratch.", - choices=MODEL_TYPES, - ) - parser.add_argument( - "--debug", - action="store_true", - help="Activate debug mode and run training only with a subset of data.", - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - else: - data_files = {} - if args.train_file is not None: - data_files["train"] = args.train_file - extension = args.train_file.split(".")[-1] - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.validation_file.split(".")[-1] - raw_datasets = load_dataset(extension, data_files=data_files) - # Trim a number of training examples - if args.debug: - for split in raw_datasets: - raw_datasets[split] = raw_datasets[split].select(range(100)) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - if raw_datasets["train"] is not None: - column_names = raw_datasets["train"].column_names - else: - column_names = raw_datasets["validation"].column_names - - # When using your own dataset or a different dataset from swag, you will probably need to change this. - ending_names = [f"ending{i}" for i in range(4)] - context_name = "sent1" - question_header_name = "sent2" - label_column_name = "label" if "label" in column_names else "labels" - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - if args.config_name: - config = AutoConfig.from_pretrained(args.model_name_or_path, trust_remote_code=args.trust_remote_code) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained(args.model_name_or_path, trust_remote_code=args.trust_remote_code) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - - if args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained( - args.tokenizer_name, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - elif args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained( - args.model_name_or_path, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if args.model_name_or_path: - model = AutoModelForMultipleChoice.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForMultipleChoice.from_config(config, trust_remote_code=args.trust_remote_code) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Preprocessing the datasets. - # First we tokenize all the texts. - padding = "max_length" if args.pad_to_max_length else False - - def preprocess_function(examples): - first_sentences = [[context] * 4 for context in examples[context_name]] - question_headers = examples[question_header_name] - second_sentences = [ - [f"{header} {examples[end][i]}" for end in ending_names] for i, header in enumerate(question_headers) - ] - labels = examples[label_column_name] - - # Flatten out - first_sentences = list(chain(*first_sentences)) - second_sentences = list(chain(*second_sentences)) - - # Tokenize - tokenized_examples = tokenizer( - first_sentences, - second_sentences, - max_length=args.max_seq_length, - padding=padding, - truncation=True, - ) - # Un-flatten - tokenized_inputs = {k: [v[i : i + 4] for i in range(0, len(v), 4)] for k, v in tokenized_examples.items()} - tokenized_inputs["labels"] = labels - return tokenized_inputs - - with accelerator.main_process_first(): - processed_datasets = raw_datasets.map( - preprocess_function, batched=True, remove_columns=raw_datasets["train"].column_names - ) - - train_dataset = processed_datasets["train"] - eval_dataset = processed_datasets["validation"] - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # DataLoaders creation: - if args.pad_to_max_length: - # If padding was already done ot max length, we use the default data collator that will just convert everything - # to tensors. - data_collator = default_data_collator - else: - # Otherwise, `DataCollatorWithPadding` will apply dynamic padding for us (by padding to the maximum length of - # the samples passed). When using mixed precision, we add `pad_to_multiple_of=8` to pad all tensors to multiple - # of 8s, which will enable the use of Tensor Cores on NVIDIA hardware with compute capability >= 7.5 (Volta). - # For fp8, we pad to multiple of 16. - if accelerator.mixed_precision == "fp8": - pad_to_multiple_of = 16 - elif accelerator.mixed_precision != "no": - pad_to_multiple_of = 8 - else: - pad_to_multiple_of = None - data_collator = DataCollatorForMultipleChoice( - tokenizer, pad_to_multiple_of=pad_to_multiple_of, return_tensors="pt" - ) - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader(eval_dataset, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Use the device given by the `accelerator` object. - device = accelerator.device - model.to(device) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("swag_no_trainer", experiment_config) - - # Metrics - metric = evaluate.load("accuracy") - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if completed_steps >= args.max_train_steps: - break - - model.eval() - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - predictions = outputs.logits.argmax(dim=-1) - predictions, references = accelerator.gather_for_metrics((predictions, batch["labels"])) - metric.add_batch( - predictions=predictions, - references=references, - ) - - eval_metric = metric.compute() - accelerator.print(f"epoch {epoch}: {eval_metric}") - - if args.with_tracking: - accelerator.log( - { - "accuracy": eval_metric, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - all_results = {f"eval_{k}": v for k, v in eval_metric.items()} - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump(all_results, f) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/object-detection/README.md b/examples/pytorch/object-detection/README.md deleted file mode 100644 index cdbc6c5f8a9f..000000000000 --- a/examples/pytorch/object-detection/README.md +++ /dev/null @@ -1,233 +0,0 @@ - - -# Object detection examples - -This directory contains 2 scripts that showcase how to fine-tune any model supported by the [`AutoModelForObjectDetection` API](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoModelForObjectDetection) (such as [DETR](https://huggingface.co/docs/transformers/main/en/model_doc/detr), [DETA](https://huggingface.co/docs/transformers/main/en/model_doc/deta), [Deformable DETR](https://huggingface.co/docs/transformers/main/en/model_doc/deformable_detr)) using PyTorch. - -Content: -* [PyTorch version, Trainer](#pytorch-version-trainer) -* [PyTorch version, no Trainer](#pytorch-version-no-trainer) -* [Reload and perform inference](#reload-and-perform-inference) -* [Note on custom data](#note-on-custom-data) - - -## PyTorch version, Trainer - -Based on the script [`run_object_detection.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/object-detection/run_object_detection.py). - -The script leverages the [🤗 Trainer API](https://huggingface.co/docs/transformers/main_classes/trainer) to automatically take care of the training for you, running on distributed environments right away. - -Here we show how to fine-tune a [DETR](https://huggingface.co/facebook/detr-resnet-50) model on the [CPPE-5](https://huggingface.co/datasets/rishitdagli/cppe-5) dataset: - -```bash -python run_object_detection.py \ - --model_name_or_path facebook/detr-resnet-50 \ - --dataset_name rishitdagli/cppe-5 \ - --do_train true \ - --do_eval true \ - --output_dir detr-finetuned-cppe-5-10k-steps \ - --num_train_epochs 100 \ - --image_square_size 600 \ - --fp16 true \ - --learning_rate 5e-5 \ - --weight_decay 1e-4 \ - --dataloader_num_workers 4 \ - --dataloader_prefetch_factor 2 \ - --per_device_train_batch_size 8 \ - --gradient_accumulation_steps 1 \ - --remove_unused_columns false \ - --eval_do_concat_batches false \ - --ignore_mismatched_sizes true \ - --metric_for_best_model eval_map \ - --greater_is_better true \ - --load_best_model_at_end true \ - --logging_strategy epoch \ - --eval_strategy epoch \ - --save_strategy epoch \ - --save_total_limit 2 \ - --push_to_hub true \ - --push_to_hub_model_id detr-finetuned-cppe-5-10k-steps \ - --hub_strategy end \ - --seed 1337 -``` - -> Note: -`--eval_do_concat_batches false` is required for correct evaluation of detection models; -`--ignore_mismatched_sizes true` is required to load detection model for finetuning with different number of classes. - -The resulting model can be seen here: https://huggingface.co/qubvel-hf/qubvel-hf/detr-resnet-50-finetuned-10k-cppe5. The corresponding Weights and Biases report [here](https://api.wandb.ai/links/qubvel-hf-co/bnm0r5ex). Note that it's always advised to check the original paper to know the details regarding training hyperparameters. Hyperparameters for current example were not tuned. To improve model quality you could try: - - changing image size parameters (`--shortest_edge`/`--longest_edge`) - - changing training parameters, such as learning rate, batch size, warmup, optimizer and many more (see [TrainingArguments](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments)) - - adding more image augmentations (we created a helpful [HF Space](https://huggingface.co/spaces/qubvel-hf/albumentations-demo) to choose some) - -Note that you can replace the model and dataset by simply setting the `model_name_or_path` and `dataset_name` arguments respectively, with model or dataset from the [hub](https://huggingface.co/). -For dataset, make sure it provides labels in the same format as [CPPE-5](https://huggingface.co/datasets/rishitdagli/cppe-5) dataset and boxes are provided in [COCO format](https://albumentations.ai/docs/getting_started/bounding_boxes_augmentation/#coco). - -![W&B report](https://i.imgur.com/ASNjamQ.png) - - -## PyTorch version, no Trainer - -Based on the script [`run_object_detection_no_trainer.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/object-detection/run_object_detection.py). - -The script leverages [🤗 `Accelerate`](https://github.com/huggingface/accelerate), which allows to write your own training loop in PyTorch, but have it run instantly on any (distributed) environment, including CPU, multi-CPU, GPU, multi-GPU and TPU. It also supports mixed precision. - -First, run: - -```bash -accelerate config -``` - -and reply to the questions asked regarding the environment on which you'd like to train. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -accelerate launch run_object_detection_no_trainer.py \ - --model_name_or_path "facebook/detr-resnet-50" \ - --dataset_name rishitdagli/cppe-5 \ - --output_dir "detr-resnet-50-finetuned" \ - --num_train_epochs 100 \ - --image_square_size 600 \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --checkpointing_steps epoch \ - --learning_rate 5e-5 \ - --ignore_mismatched_sizes \ - --with_tracking \ - --push_to_hub -``` - -and boom, you're training, possibly on multiple GPUs, logging everything to all trackers found in your environment (like Weights and Biases, Tensorboard) and regularly pushing your model to the hub (with the repo name being equal to `args.output_dir` at your HF username) 🤗 - -With the default settings, the script fine-tunes a [DETR](https://huggingface.co/facebook/detr-resnet-50) model on the [CPPE-5](https://huggingface.co/datasets/rishitdagli/cppe-5) dataset. The resulting model can be seen here: https://huggingface.co/qubvel-hf/detr-resnet-50-finetuned-10k-cppe5-no-trainer. - - -## Reload and perform inference - -This means that after training, you can easily load your trained model and perform inference as follows:: - -```python -import requests -import torch - -from PIL import Image -from transformers import AutoImageProcessor, AutoModelForObjectDetection - -# Name of repo on the hub or path to a local folder -model_name = "qubvel-hf/detr-resnet-50-finetuned-10k-cppe5" - -image_processor = AutoImageProcessor.from_pretrained(model_name) -model = AutoModelForObjectDetection.from_pretrained(model_name) - -# Load image for inference -url = "https://images.pexels.com/photos/8413299/pexels-photo-8413299.jpeg?auto=compress&cs=tinysrgb&w=630&h=375&dpr=2" -image = Image.open(requests.get(url, stream=True).raw) - -# Prepare image for the model -inputs = image_processor(images=image, return_tensors="pt") - -with torch.no_grad(): - outputs = model(**inputs) - -# Post process model predictions -# this include conversion to Pascal VOC format and filtering non confident boxes -width, height = image.size -target_sizes = torch.tensor([height, width]).unsqueeze(0) # add batch dim -results = image_processor.post_process_object_detection(outputs, threshold=0.5, target_sizes=target_sizes)[0] - -for score, label, box in zip(results["scores"], results["labels"], results["boxes"]): - box = [round(i, 2) for i in box.tolist()] - print( - f"Detected {model.config.id2label[label.item()]} with confidence " - f"{round(score.item(), 3)} at location {box}" - ) -``` - -And visualize with the following code: -```python -from PIL import ImageDraw -draw = ImageDraw.Draw(image) - -for score, label, box in zip(results["scores"], results["labels"], results["boxes"]): - box = [round(i, 2) for i in box.tolist()] - x, y, x2, y2 = tuple(box) - draw.rectangle((x, y, x2, y2), outline="red", width=1) - draw.text((x, y), model.config.id2label[label.item()], fill="white") - -image -``` - - -## Note on custom data - -In case you'd like to use the script with custom data, you could prepare your data with the following way: - -```bash -custom_dataset/ -└── train - ├── 0001.jpg - ├── 0002.jpg - ├── ... - └── metadata.jsonl -└── validation - └── ... -└── test - └── ... -``` - -Where `metadata.jsonl` is a file with the following structure: -```json -{"file_name": "0001.jpg", "objects": {"bbox": [[302.0, 109.0, 73.0, 52.0]], "categories": [0], "id": [1], "area": [50.0]}} -{"file_name": "0002.jpg", "objects": {"bbox": [[810.0, 100.0, 57.0, 28.0]], "categories": [1], "id": [2], "area": [40.0]}} -... -``` -Trining script support bounding boxes in COCO format (x_min, y_min, width, height). - -Then, you cat load the dataset with just a few lines of code: - -```python -from datasets import load_dataset - -# Load dataset -dataset = load_dataset("imagefolder", data_dir="custom_dataset/") - -# >>> DatasetDict({ -# ... train: Dataset({ -# ... features: ['image', 'objects'], -# ... num_rows: 2 -# ... }) -# ... }) - -# Push to hub (assumes you have ran the hf auth login command in a terminal/notebook) -dataset.push_to_hub("name of repo on the hub") - -# optionally, you can push to a private repo on the hub -# dataset.push_to_hub("name of repo on the hub", private=True) -``` - -And the final step, for training you should provide id2label mapping in the following way: -```python -id2label = {0: "Car", 1: "Bird", ...} -``` -Just find it in code and replace for simplicity, or save `json` locally and with the dataset on the hub! - -See also: [Dataset Creation Guide](https://huggingface.co/docs/datasets/image_dataset#create-an-image-dataset) diff --git a/examples/pytorch/object-detection/requirements.txt b/examples/pytorch/object-detection/requirements.txt deleted file mode 100644 index 8a9ba6ddcd16..000000000000 --- a/examples/pytorch/object-detection/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -albumentations >= 1.4.16 -timm -datasets>=4.0 -torchmetrics -pycocotools diff --git a/examples/pytorch/object-detection/run_object_detection.py b/examples/pytorch/object-detection/run_object_detection.py deleted file mode 100644 index 602245da1756..000000000000 --- a/examples/pytorch/object-detection/run_object_detection.py +++ /dev/null @@ -1,522 +0,0 @@ -#!/usr/bin/env python -# Copyright 2024 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "timm", -# "datasets>=4.0", -# "torchmetrics", -# "pycocotools", -# ] -# /// - -"""Finetuning any 🤗 Transformers model supported by AutoModelForObjectDetection for object detection leveraging the Trainer API.""" - -import logging -import os -import sys -from collections.abc import Mapping -from dataclasses import dataclass, field -from functools import partial -from typing import Any - -import albumentations as A -import numpy as np -import torch -from datasets import load_dataset -from torchmetrics.detection.mean_ap import MeanAveragePrecision - -import transformers -from transformers import ( - AutoConfig, - AutoImageProcessor, - AutoModelForObjectDetection, - HfArgumentParser, - Trainer, - TrainingArguments, -) -from transformers.image_processing_utils import BatchFeature -from transformers.image_transforms import center_to_corners_format -from transformers.trainer import EvalPrediction -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.0.0", "To fix: pip install -r examples/pytorch/object-detection/requirements.txt") - - -@dataclass -class ModelOutput: - logits: torch.Tensor - pred_boxes: torch.Tensor - - -def format_image_annotations_as_coco( - image_id: str, categories: list[int], areas: list[float], bboxes: list[tuple[float]] -) -> dict: - """Format one set of image annotations to the COCO format - - Args: - image_id (str): image id. e.g. "0001" - categories (list[int]): list of categories/class labels corresponding to provided bounding boxes - areas (list[float]): list of corresponding areas to provided bounding boxes - bboxes (list[tuple[float]]): list of bounding boxes provided in COCO format - ([center_x, center_y, width, height] in absolute coordinates) - - Returns: - dict: { - "image_id": image id, - "annotations": list of formatted annotations - } - """ - annotations = [] - for category, area, bbox in zip(categories, areas, bboxes): - formatted_annotation = { - "image_id": image_id, - "category_id": category, - "iscrowd": 0, - "area": area, - "bbox": list(bbox), - } - annotations.append(formatted_annotation) - - return { - "image_id": image_id, - "annotations": annotations, - } - - -def convert_bbox_yolo_to_pascal(boxes: torch.Tensor, image_size: tuple[int, int]) -> torch.Tensor: - """ - Convert bounding boxes from YOLO format (x_center, y_center, width, height) in range [0, 1] - to Pascal VOC format (x_min, y_min, x_max, y_max) in absolute coordinates. - - Args: - boxes (torch.Tensor): Bounding boxes in YOLO format - image_size (tuple[int, int]): Image size in format (height, width) - - Returns: - torch.Tensor: Bounding boxes in Pascal VOC format (x_min, y_min, x_max, y_max) - """ - # convert center to corners format - boxes = center_to_corners_format(boxes) - - # convert to absolute coordinates - height, width = image_size - boxes = boxes * torch.tensor([[width, height, width, height]]) - - return boxes - - -def augment_and_transform_batch( - examples: Mapping[str, Any], - transform: A.Compose, - image_processor: AutoImageProcessor, - return_pixel_mask: bool = False, -) -> BatchFeature: - """Apply augmentations and format annotations in COCO format for object detection task""" - - images = [] - annotations = [] - for image_id, image, objects in zip(examples["image_id"], examples["image"], examples["objects"]): - image = np.array(image.convert("RGB")) - - # apply augmentations - output = transform(image=image, bboxes=objects["bbox"], category=objects["category"]) - images.append(output["image"]) - - # format annotations in COCO format - formatted_annotations = format_image_annotations_as_coco( - image_id, output["category"], objects["area"], output["bboxes"] - ) - annotations.append(formatted_annotations) - - # Apply the image processor transformations: resizing, rescaling, normalization - result = image_processor(images=images, annotations=annotations, return_tensors="pt") - - if not return_pixel_mask: - result.pop("pixel_mask", None) - - return result - - -def collate_fn(batch: list[BatchFeature]) -> Mapping[str, torch.Tensor | list[Any]]: - data = {} - data["pixel_values"] = torch.stack([x["pixel_values"] for x in batch]) - data["labels"] = [x["labels"] for x in batch] - if "pixel_mask" in batch[0]: - data["pixel_mask"] = torch.stack([x["pixel_mask"] for x in batch]) - return data - - -@torch.no_grad() -def compute_metrics( - evaluation_results: EvalPrediction, - image_processor: AutoImageProcessor, - threshold: float = 0.0, - id2label: Mapping[int, str] | None = None, -) -> Mapping[str, float]: - """ - Compute mean average mAP, mAR and their variants for the object detection task. - - Args: - evaluation_results (EvalPrediction): Predictions and targets from evaluation. - threshold (float, optional): Threshold to filter predicted boxes by confidence. Defaults to 0.0. - id2label (Optional[dict], optional): Mapping from class id to class name. Defaults to None. - - Returns: - Mapping[str, float]: Metrics in a form of dictionary {: } - """ - - predictions, targets = evaluation_results.predictions, evaluation_results.label_ids - - # For metric computation we need to provide: - # - targets in a form of list of dictionaries with keys "boxes", "labels" - # - predictions in a form of list of dictionaries with keys "boxes", "scores", "labels" - - image_sizes = [] - post_processed_targets = [] - post_processed_predictions = [] - - # Collect targets in the required format for metric computation - for batch in targets: - # collect image sizes, we will need them for predictions post processing - batch_image_sizes = torch.tensor([x["orig_size"] for x in batch]) - image_sizes.append(batch_image_sizes) - # collect targets in the required format for metric computation - # boxes were converted to YOLO format needed for model training - # here we will convert them to Pascal VOC format (x_min, y_min, x_max, y_max) - for image_target in batch: - boxes = torch.tensor(image_target["boxes"]) - boxes = convert_bbox_yolo_to_pascal(boxes, image_target["orig_size"]) - labels = torch.tensor(image_target["class_labels"]) - post_processed_targets.append({"boxes": boxes, "labels": labels}) - - # Collect predictions in the required format for metric computation, - # model produce boxes in YOLO format, then image_processor convert them to Pascal VOC format - for batch, target_sizes in zip(predictions, image_sizes): - batch_logits, batch_boxes = batch[1], batch[2] - output = ModelOutput(logits=torch.tensor(batch_logits), pred_boxes=torch.tensor(batch_boxes)) - post_processed_output = image_processor.post_process_object_detection( - output, threshold=threshold, target_sizes=target_sizes - ) - post_processed_predictions.extend(post_processed_output) - - # Compute metrics - metric = MeanAveragePrecision(box_format="xyxy", class_metrics=True) - metric.update(post_processed_predictions, post_processed_targets) - metrics = metric.compute() - - # Replace list of per class metrics with separate metric for each class - classes = metrics.pop("classes") - map_per_class = metrics.pop("map_per_class") - mar_100_per_class = metrics.pop("mar_100_per_class") - for class_id, class_map, class_mar in zip(classes, map_per_class, mar_100_per_class): - class_name = id2label[class_id.item()] if id2label is not None else class_id.item() - metrics[f"map_{class_name}"] = class_map - metrics[f"mar_100_{class_name}"] = class_mar - - metrics = {k: round(v.item(), 4) for k, v in metrics.items()} - - return metrics - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - Using `HfArgumentParser` we can turn this class into argparse arguments to be able to specify - them on the command line. - """ - - dataset_name: str = field( - default="rishitdagli/cppe-5", - metadata={ - "help": "Name of a dataset from the hub (could be your own, possibly private dataset hosted on the hub)." - }, - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_val_split: float | None = field( - default=0.15, metadata={"help": "Percent to split off of train for validation."} - ) - image_square_size: int | None = field( - default=600, - metadata={"help": "Image longest size will be resized to this value, then image will be padded to square."}, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - use_fast: bool | None = field( - default=True, - metadata={"help": "Use a fast torchvision-base image processor if it is supported for a given model."}, - ) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - default="facebook/detr-resnet-50", - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"} - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - image_processor_name: str = field(default=None, metadata={"help": "Name or path of preprocessor config."}) - ignore_mismatched_sizes: bool = field( - default=False, - metadata={ - "help": "Whether or not to raise an error if some of the weights from the checkpoint do not have the same size as the weights of the model (if for instance, you are instantiating a model with 10 labels from a checkpoint with 3 labels)." - }, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # ------------------------------------------------------------------------------------------------ - # Load dataset, prepare splits - # ------------------------------------------------------------------------------------------------ - - dataset = load_dataset( - data_args.dataset_name, cache_dir=model_args.cache_dir, trust_remote_code=model_args.trust_remote_code - ) - - # If we don't have a validation split, split off a percentage of train as validation - data_args.train_val_split = None if "validation" in dataset else data_args.train_val_split - if isinstance(data_args.train_val_split, float) and data_args.train_val_split > 0.0: - split = dataset["train"].train_test_split(data_args.train_val_split, seed=training_args.seed) - dataset["train"] = split["train"] - dataset["validation"] = split["test"] - - # Get dataset categories and prepare mappings for label_name <-> label_id - if isinstance(dataset["train"].features["objects"], dict): - categories = dataset["train"].features["objects"]["category"].feature.names - else: # (for old versions of `datasets` that used Sequence({...}) of the objects) - categories = dataset["train"].features["objects"].feature["category"].names - id2label = dict(enumerate(categories)) - label2id = {v: k for k, v in id2label.items()} - - # ------------------------------------------------------------------------------------------------ - # Load pretrained config, model and image processor - # ------------------------------------------------------------------------------------------------ - - common_pretrained_args = { - "cache_dir": model_args.cache_dir, - "revision": model_args.model_revision, - "token": model_args.token, - "trust_remote_code": model_args.trust_remote_code, - } - config = AutoConfig.from_pretrained( - model_args.config_name or model_args.model_name_or_path, - label2id=label2id, - id2label=id2label, - **common_pretrained_args, - ) - model = AutoModelForObjectDetection.from_pretrained( - model_args.model_name_or_path, - config=config, - ignore_mismatched_sizes=model_args.ignore_mismatched_sizes, - **common_pretrained_args, - ) - image_processor = AutoImageProcessor.from_pretrained( - model_args.image_processor_name or model_args.model_name_or_path, - do_resize=True, - size={"max_height": data_args.image_square_size, "max_width": data_args.image_square_size}, - do_pad=True, - pad_size={"height": data_args.image_square_size, "width": data_args.image_square_size}, - use_fast=data_args.use_fast, - **common_pretrained_args, - ) - - # ------------------------------------------------------------------------------------------------ - # Define image augmentations and dataset transforms - # ------------------------------------------------------------------------------------------------ - max_size = data_args.image_square_size - train_augment_and_transform = A.Compose( - [ - A.Compose( - [ - A.SmallestMaxSize(max_size=max_size, p=1.0), - A.RandomSizedBBoxSafeCrop(height=max_size, width=max_size, p=1.0), - ], - p=0.2, - ), - A.OneOf( - [ - A.Blur(blur_limit=7, p=0.5), - A.MotionBlur(blur_limit=7, p=0.5), - A.Defocus(radius=(1, 5), alias_blur=(0.1, 0.25), p=0.1), - ], - p=0.1, - ), - A.Perspective(p=0.1), - A.HorizontalFlip(p=0.5), - A.RandomBrightnessContrast(p=0.5), - A.HueSaturationValue(p=0.1), - ], - bbox_params=A.BboxParams(format="coco", label_fields=["category"], clip=True, min_area=25), - ) - validation_transform = A.Compose( - [A.NoOp()], - bbox_params=A.BboxParams(format="coco", label_fields=["category"], clip=True), - ) - - # Make transform functions for batch and apply for dataset splits - train_transform_batch = partial( - augment_and_transform_batch, transform=train_augment_and_transform, image_processor=image_processor - ) - validation_transform_batch = partial( - augment_and_transform_batch, transform=validation_transform, image_processor=image_processor - ) - - dataset["train"] = dataset["train"].with_transform(train_transform_batch) - dataset["validation"] = dataset["validation"].with_transform(validation_transform_batch) - dataset["test"] = dataset["test"].with_transform(validation_transform_batch) - - # ------------------------------------------------------------------------------------------------ - # Model training and evaluation with Trainer API - # ------------------------------------------------------------------------------------------------ - - eval_compute_metrics_fn = partial( - compute_metrics, image_processor=image_processor, id2label=id2label, threshold=0.0 - ) - - trainer = Trainer( - model=model, - args=training_args, - train_dataset=dataset["train"] if training_args.do_train else None, - eval_dataset=dataset["validation"] if training_args.do_eval else None, - processing_class=image_processor, - data_collator=collate_fn, - compute_metrics=eval_compute_metrics_fn, - ) - - # Training - if training_args.do_train: - train_result = trainer.train(resume_from_checkpoint=training_args.resume_from_checkpoint) - trainer.save_model() - trainer.log_metrics("train", train_result.metrics) - trainer.save_metrics("train", train_result.metrics) - trainer.save_state() - - # Final evaluation - if training_args.do_eval: - metrics = trainer.evaluate(eval_dataset=dataset["test"], metric_key_prefix="test") - trainer.log_metrics("test", metrics) - trainer.save_metrics("test", metrics) - - # Write model card and (optionally) push to hub - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "dataset": data_args.dataset_name, - "tags": ["object-detection", "vision"], - } - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/object-detection/run_object_detection_no_trainer.py b/examples/pytorch/object-detection/run_object_detection_no_trainer.py deleted file mode 100644 index a5ecc56add20..000000000000 --- a/examples/pytorch/object-detection/run_object_detection_no_trainer.py +++ /dev/null @@ -1,795 +0,0 @@ -# Copyright 2024 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "albumentations >= 1.4.16", -# "timm", -# "datasets>=4.0", -# "torchmetrics", -# "pycocotools", -# ] -# /// - -"""Finetuning 🤗 Transformers model for object detection with Accelerate.""" - -import argparse -import json -import logging -import math -import os -from collections.abc import Mapping -from functools import partial -from pathlib import Path -from typing import Any - -import albumentations as A -import datasets -import numpy as np -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch.utils.data import DataLoader -from torchmetrics.detection.mean_ap import MeanAveragePrecision -from tqdm.auto import tqdm - -import transformers -from transformers import ( - AutoConfig, - AutoImageProcessor, - AutoModelForObjectDetection, - SchedulerType, - get_scheduler, -) -from transformers.image_processing_utils import BatchFeature -from transformers.image_transforms import center_to_corners_format -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logging.basicConfig(level=logging.INFO) -logger = get_logger(__name__) - -require_version("datasets>=2.0.0", "To fix: pip install -r examples/pytorch/semantic-segmentation/requirements.txt") - - -# Copied from examples/pytorch/object-detection/run_object_detection.format_image_annotations_as_coco -def format_image_annotations_as_coco( - image_id: str, categories: list[int], areas: list[float], bboxes: list[tuple[float]] -) -> dict: - """Format one set of image annotations to the COCO format - - Args: - image_id (str): image id. e.g. "0001" - categories (list[int]): list of categories/class labels corresponding to provided bounding boxes - areas (list[float]): list of corresponding areas to provided bounding boxes - bboxes (list[tuple[float]]): list of bounding boxes provided in COCO format - ([center_x, center_y, width, height] in absolute coordinates) - - Returns: - dict: { - "image_id": image id, - "annotations": list of formatted annotations - } - """ - annotations = [] - for category, area, bbox in zip(categories, areas, bboxes): - formatted_annotation = { - "image_id": image_id, - "category_id": category, - "iscrowd": 0, - "area": area, - "bbox": list(bbox), - } - annotations.append(formatted_annotation) - - return { - "image_id": image_id, - "annotations": annotations, - } - - -# Copied from examples/pytorch/object-detection/run_object_detection.convert_bbox_yolo_to_pascal -def convert_bbox_yolo_to_pascal(boxes: torch.Tensor, image_size: tuple[int, int]) -> torch.Tensor: - """ - Convert bounding boxes from YOLO format (x_center, y_center, width, height) in range [0, 1] - to Pascal VOC format (x_min, y_min, x_max, y_max) in absolute coordinates. - - Args: - boxes (torch.Tensor): Bounding boxes in YOLO format - image_size (tuple[int, int]): Image size in format (height, width) - - Returns: - torch.Tensor: Bounding boxes in Pascal VOC format (x_min, y_min, x_max, y_max) - """ - # convert center to corners format - boxes = center_to_corners_format(boxes) - - # convert to absolute coordinates - height, width = image_size - boxes = boxes * torch.tensor([[width, height, width, height]]) - - return boxes - - -# Copied from examples/pytorch/object-detection/run_object_detection.augment_and_transform_batch -def augment_and_transform_batch( - examples: Mapping[str, Any], - transform: A.Compose, - image_processor: AutoImageProcessor, - return_pixel_mask: bool = False, -) -> BatchFeature: - """Apply augmentations and format annotations in COCO format for object detection task""" - - images = [] - annotations = [] - for image_id, image, objects in zip(examples["image_id"], examples["image"], examples["objects"]): - image = np.array(image.convert("RGB")) - - # apply augmentations - output = transform(image=image, bboxes=objects["bbox"], category=objects["category"]) - images.append(output["image"]) - - # format annotations in COCO format - formatted_annotations = format_image_annotations_as_coco( - image_id, output["category"], objects["area"], output["bboxes"] - ) - annotations.append(formatted_annotations) - - # Apply the image processor transformations: resizing, rescaling, normalization - result = image_processor(images=images, annotations=annotations, return_tensors="pt") - - if not return_pixel_mask: - result.pop("pixel_mask", None) - - return result - - -# Copied from examples/pytorch/object-detection/run_object_detection.collate_fn -def collate_fn(batch: list[BatchFeature]) -> Mapping[str, torch.Tensor | list[Any]]: - data = {} - data["pixel_values"] = torch.stack([x["pixel_values"] for x in batch]) - data["labels"] = [x["labels"] for x in batch] - if "pixel_mask" in batch[0]: - data["pixel_mask"] = torch.stack([x["pixel_mask"] for x in batch]) - return data - - -def nested_to_cpu(objects): - """Move nested tesnors in objects to CPU if they are on GPU""" - if isinstance(objects, torch.Tensor): - return objects.cpu() - elif isinstance(objects, Mapping): - return type(objects)({k: nested_to_cpu(v) for k, v in objects.items()}) - elif isinstance(objects, (list, tuple)): - return type(objects)([nested_to_cpu(v) for v in objects]) - elif isinstance(objects, (np.ndarray, str, int, float, bool)): - return objects - raise ValueError(f"Unsupported type {type(objects)}") - - -def evaluation_loop( - model: torch.nn.Module, - image_processor: AutoImageProcessor, - accelerator: Accelerator, - dataloader: DataLoader, - id2label: Mapping[int, str], -) -> dict: - model.eval() - metric = MeanAveragePrecision(box_format="xyxy", class_metrics=True) - - for step, batch in enumerate(tqdm(dataloader, disable=not accelerator.is_local_main_process)): - with torch.no_grad(): - outputs = model(**batch) - - # For metric computation we need to collect ground truth and predicted boxes in the same format - - # 1. Collect predicted boxes, classes, scores - # image_processor convert boxes from YOLO format to Pascal VOC format - # ([x_min, y_min, x_max, y_max] in absolute coordinates) - image_size = torch.stack([example["orig_size"] for example in batch["labels"]], dim=0) - predictions = image_processor.post_process_object_detection(outputs, threshold=0.0, target_sizes=image_size) - predictions = nested_to_cpu(predictions) - - # 2. Collect ground truth boxes in the same format for metric computation - # Do the same, convert YOLO boxes to Pascal VOC format - target = [] - for label in batch["labels"]: - label = nested_to_cpu(label) - boxes = convert_bbox_yolo_to_pascal(label["boxes"], label["orig_size"]) - labels = label["class_labels"] - target.append({"boxes": boxes, "labels": labels}) - - metric.update(predictions, target) - - metrics = metric.compute() - - # Replace list of per class metrics with separate metric for each class - classes = metrics.pop("classes") - map_per_class = metrics.pop("map_per_class") - mar_100_per_class = metrics.pop("mar_100_per_class") - for class_id, class_map, class_mar in zip(classes, map_per_class, mar_100_per_class): - class_name = id2label[class_id.item()] - metrics[f"map_{class_name}"] = class_map - metrics[f"mar_100_{class_name}"] = class_mar - - # Convert metrics to float - metrics = {k: round(v.item(), 4) for k, v in metrics.items()} - - return metrics - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model for object detection task") - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to a pretrained model or model identifier from huggingface.co/models.", - default="facebook/detr-resnet-50", - ) - parser.add_argument( - "--dataset_name", - type=str, - help="Name of the dataset on the hub.", - default="rishitdagli/cppe-5", - ) - parser.add_argument( - "--train_val_split", - type=float, - default=0.15, - help="Fraction of the dataset to be used for validation.", - ) - parser.add_argument( - "--ignore_mismatched_sizes", - action="store_true", - help="Ignore mismatched sizes between the model and the dataset.", - ) - parser.add_argument( - "--image_square_size", - type=int, - default=1333, - help="Image longest size will be resized to this value, then image will be padded to square.", - ) - parser.add_argument( - "--use_fast", - type=bool, - default=True, - help="Use a fast torchvision-base image processor if it is supported for a given model.", - ) - parser.add_argument( - "--cache_dir", - type=str, - help="Path to a folder in which the model and dataset will be cached.", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--dataloader_num_workers", - type=int, - default=4, - help="Number of workers to use for the dataloaders.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument( - "--adam_beta1", - type=float, - default=0.9, - help="Beta1 for AdamW optimizer", - ) - parser.add_argument( - "--adam_beta2", - type=float, - default=0.999, - help="Beta2 for AdamW optimizer", - ) - parser.add_argument( - "--adam_epsilon", - type=float, - default=1e-8, - help="Epsilon for AdamW optimizer", - ) - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - required=False, - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - if args.push_to_hub or args.with_tracking: - if args.output_dir is None: - raise ValueError( - "Need an `output_dir` to create a repo when `--push_to_hub` or `with_tracking` is specified." - ) - - if args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - # We set device_specific to True as we want different data augmentation per device. - if args.seed is not None: - set_seed(args.seed, device_specific=True) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Load dataset - # In distributed training, the load_dataset function guarantees that only one local process can concurrently - # download the dataset. - dataset = load_dataset(args.dataset_name, cache_dir=args.cache_dir, trust_remote_code=args.trust_remote_code) - - # If we don't have a validation split, split off a percentage of train as validation. - args.train_val_split = None if "validation" in dataset else args.train_val_split - if isinstance(args.train_val_split, float) and args.train_val_split > 0.0: - split = dataset["train"].train_test_split(args.train_val_split, seed=args.seed) - dataset["train"] = split["train"] - dataset["validation"] = split["test"] - - # Get dataset categories and prepare mappings for label_name <-> label_id - if isinstance(dataset["train"].features["objects"], dict): - categories = dataset["train"].features["objects"]["category"].feature.names - else: # (for old versions of `datasets` that used Sequence({...}) of the objects) - categories = dataset["train"].features["objects"].feature["category"].names - id2label = dict(enumerate(categories)) - label2id = {v: k for k, v in id2label.items()} - - # ------------------------------------------------------------------------------------------------ - # Load pretrained config, model and image processor - # ------------------------------------------------------------------------------------------------ - - common_pretrained_args = { - "cache_dir": args.cache_dir, - "token": args.hub_token, - "trust_remote_code": args.trust_remote_code, - } - config = AutoConfig.from_pretrained( - args.model_name_or_path, label2id=label2id, id2label=id2label, **common_pretrained_args - ) - model = AutoModelForObjectDetection.from_pretrained( - args.model_name_or_path, - config=config, - ignore_mismatched_sizes=args.ignore_mismatched_sizes, - **common_pretrained_args, - ) - image_processor = AutoImageProcessor.from_pretrained( - args.model_name_or_path, - do_resize=True, - size={"max_height": args.image_square_size, "max_width": args.image_square_size}, - do_pad=True, - pad_size={"height": args.image_square_size, "width": args.image_square_size}, - use_fast=args.use_fast, - **common_pretrained_args, - ) - - # ------------------------------------------------------------------------------------------------ - # Define image augmentations and dataset transforms - # ------------------------------------------------------------------------------------------------ - max_size = args.image_square_size - train_augment_and_transform = A.Compose( - [ - A.Compose( - [ - A.SmallestMaxSize(max_size=max_size, p=1.0), - A.RandomSizedBBoxSafeCrop(height=max_size, width=max_size, p=1.0), - ], - p=0.2, - ), - A.OneOf( - [ - A.Blur(blur_limit=7, p=0.5), - A.MotionBlur(blur_limit=7, p=0.5), - A.Defocus(radius=(1, 5), alias_blur=(0.1, 0.25), p=0.1), - ], - p=0.1, - ), - A.Perspective(p=0.1), - A.HorizontalFlip(p=0.5), - A.RandomBrightnessContrast(p=0.5), - A.HueSaturationValue(p=0.1), - ], - bbox_params=A.BboxParams(format="coco", label_fields=["category"], clip=True, min_area=25), - ) - validation_transform = A.Compose( - [A.NoOp()], - bbox_params=A.BboxParams(format="coco", label_fields=["category"], clip=True), - ) - - # Make transform functions for batch and apply for dataset splits - train_transform_batch = partial( - augment_and_transform_batch, transform=train_augment_and_transform, image_processor=image_processor - ) - validation_transform_batch = partial( - augment_and_transform_batch, transform=validation_transform, image_processor=image_processor - ) - - with accelerator.main_process_first(): - train_dataset = dataset["train"].with_transform(train_transform_batch) - valid_dataset = dataset["validation"].with_transform(validation_transform_batch) - test_dataset = dataset["test"].with_transform(validation_transform_batch) - - dataloader_common_args = { - "num_workers": args.dataloader_num_workers, - "collate_fn": collate_fn, - } - train_dataloader = DataLoader( - train_dataset, shuffle=True, batch_size=args.per_device_train_batch_size, **dataloader_common_args - ) - valid_dataloader = DataLoader( - valid_dataset, shuffle=False, batch_size=args.per_device_eval_batch_size, **dataloader_common_args - ) - test_dataloader = DataLoader( - test_dataset, shuffle=False, batch_size=args.per_device_eval_batch_size, **dataloader_common_args - ) - - # ------------------------------------------------------------------------------------------------ - # Define optimizer, scheduler and prepare everything with the accelerator - # ------------------------------------------------------------------------------------------------ - - # Optimizer - optimizer = torch.optim.AdamW( - list(model.parameters()), - lr=args.learning_rate, - betas=[args.adam_beta1, args.adam_beta2], - eps=args.adam_epsilon, - ) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, valid_dataloader, test_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, valid_dataloader, test_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("object_detection_no_trainer", experiment_config) - - # ------------------------------------------------------------------------------------------------ - # Run training with evaluation on each epoch - # ------------------------------------------------------------------------------------------------ - - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, - is_main_process=accelerator.is_main_process, - save_function=accelerator.save, - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if completed_steps >= args.max_train_steps: - break - - logger.info("***** Running evaluation *****") - metrics = evaluation_loop(model, image_processor, accelerator, valid_dataloader, id2label) - - logger.info(f"epoch {epoch}: {metrics}") - - if args.with_tracking: - accelerator.log( - { - "train_loss": total_loss.item() / len(train_dataloader), - **metrics, - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - # ------------------------------------------------------------------------------------------------ - # Run evaluation on test dataset and save the model - # ------------------------------------------------------------------------------------------------ - - logger.info("***** Running evaluation on test dataset *****") - metrics = evaluation_loop(model, image_processor, accelerator, test_dataloader, id2label) - metrics = {f"test_{k}": v for k, v in metrics.items()} - - logger.info(f"Test metrics: {metrics}") - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump(metrics, f, indent=2) - - image_processor.save_pretrained(args.output_dir) - - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ignore_patterns=["epoch_*"], - ) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/old_test_xla_examples.py b/examples/pytorch/old_test_xla_examples.py deleted file mode 100644 index 320182d19499..000000000000 --- a/examples/pytorch/old_test_xla_examples.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2018 HuggingFace Inc.. -# -# 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 -import logging -import os -import sys -from time import time -from unittest.mock import patch - -from transformers.testing_utils import TestCasePlus, require_torch_xla - - -logging.basicConfig(level=logging.DEBUG) - -logger = logging.getLogger() - - -def get_results(output_dir): - results = {} - path = os.path.join(output_dir, "all_results.json") - if os.path.exists(path): - with open(path, encoding="utf-8") as f: - results = json.load(f) - else: - raise ValueError(f"can't find {path}") - return results - - -stream_handler = logging.StreamHandler(sys.stdout) -logger.addHandler(stream_handler) - - -@require_torch_xla -class TorchXLAExamplesTests(TestCasePlus): - def test_run_glue(self): - import xla_spawn - - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - ./examples/pytorch/text-classification/run_glue.py - --num_cores=8 - ./examples/pytorch/text-classification/run_glue.py - --model_name_or_path distilbert/distilbert-base-uncased - --output_dir {tmp_dir} - --train_file ./tests/fixtures/tests_samples/MRPC/train.csv - --validation_file ./tests/fixtures/tests_samples/MRPC/dev.csv - --do_train - --do_eval - --debug tpu_metrics_debug - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --learning_rate=1e-4 - --max_steps=10 - --warmup_steps=2 - --seed=42 - --max_seq_length=128 - """.split() - - with patch.object(sys, "argv", testargs): - start = time() - xla_spawn.main() - end = time() - - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_accuracy"], 0.75) - - # Assert that the script takes less than 500 seconds to make sure it doesn't hang. - self.assertLess(end - start, 500) - - def test_trainer_tpu(self): - import xla_spawn - - testargs = """ - ./tests/test_trainer_tpu.py - --num_cores=8 - ./tests/test_trainer_tpu.py - """.split() - with patch.object(sys, "argv", testargs): - xla_spawn.main() diff --git a/examples/pytorch/question-answering/README.md b/examples/pytorch/question-answering/README.md deleted file mode 100644 index 75f47a3dae65..000000000000 --- a/examples/pytorch/question-answering/README.md +++ /dev/null @@ -1,183 +0,0 @@ - - -# Question answering - -This folder contains several scripts that showcase how to fine-tune a 🤗 Transformers model on a question answering dataset, -like SQuAD. - -## Trainer-based scripts - -The [`run_qa.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/question-answering/run_qa.py), -[`run_qa_beam_search.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/question-answering/run_qa_beam_search.py) and [`run_seq2seq_qa.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/question-answering/run_seq2seq_qa.py) leverage the 🤗 [Trainer](https://huggingface.co/transformers/main_classes/trainer.html) for fine-tuning. - -### Fine-tuning BERT on SQuAD1.0 - -The [`run_qa.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/question-answering/run_qa.py) script -allows to fine-tune any model from our [hub](https://huggingface.co/models) (as long as its architecture has a `ForQuestionAnswering` version in the library) on a question-answering dataset (such as SQuAD, or any other QA dataset available in the `datasets` library, or your own csv/jsonlines files) as long as they are structured the same way as SQuAD. You might need to tweak the data processing inside the script if your data is structured differently. - -**Note:** This script only works with models that have a fast tokenizer (backed by the 🤗 Tokenizers library) as it -uses special features of those tokenizers. You can check if your favorite model has a fast tokenizer in -[this table](https://huggingface.co/transformers/index.html#supported-frameworks), if it doesn't you can still use the old version of the script which can be found [here](https://github.com/huggingface/transformers/tree/main/examples/legacy/question-answering). - -Note that if your dataset contains samples with no possible answers (like SQuAD version 2), you need to pass along the flag `--version_2_with_negative`. - -This example code fine-tunes BERT on the SQuAD1.0 dataset. It runs in 24 min (with BERT-base) or 68 min (with BERT-large) -on a single tesla V100 16GB. - -```bash -python run_qa.py \ - --model_name_or_path google-bert/bert-base-uncased \ - --dataset_name rajpurkar/squad \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_squad/ -``` - -Training with the previously defined hyper-parameters yields the following results: - -```bash -f1 = 88.52 -exact_match = 81.22 -``` - -### Fine-tuning XLNet with beam search on SQuAD - -The [`run_qa_beam_search.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/question-answering/run_qa_beam_search.py) script is only meant to fine-tune XLNet, which is a special encoder-only Transformer model. The example code below fine-tunes XLNet on the SQuAD1.0 and SQuAD2.0 datasets. - -#### Command for SQuAD1.0: - -```bash -python run_qa_beam_search.py \ - --model_name_or_path xlnet/xlnet-large-cased \ - --dataset_name rajpurkar/squad \ - --do_train \ - --do_eval \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir ./wwm_cased_finetuned_squad/ \ - --per_device_eval_batch_size=4 \ - --per_device_train_batch_size=4 \ - --save_steps 5000 -``` - -#### Command for SQuAD2.0: - -```bash -export SQUAD_DIR=/path/to/SQUAD - -python run_qa_beam_search.py \ - --model_name_or_path xlnet/xlnet-large-cased \ - --dataset_name rajpurkar/squad_v2 \ - --do_train \ - --do_eval \ - --version_2_with_negative \ - --learning_rate 3e-5 \ - --num_train_epochs 4 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir ./wwm_cased_finetuned_squad/ \ - --per_device_eval_batch_size=2 \ - --per_device_train_batch_size=2 \ - --save_steps 5000 -``` - -### Fine-tuning T5 on SQuAD2.0 - -The [`run_seq2seq_qa.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/question-answering/run_seq2seq_qa.py) script is meant for encoder-decoder (also called seq2seq) Transformer models, such as T5 or BART. These -models are generative, rather than discriminative. This means that they learn to generate the correct answer, rather than predicting the start and end position of the tokens of the answer. - -This example code fine-tunes T5 on the SQuAD2.0 dataset. - -```bash -python run_seq2seq_qa.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name rajpurkar/squad_v2 \ - --context_column context \ - --question_column question \ - --answer_column answers \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 12 \ - --learning_rate 3e-5 \ - --num_train_epochs 2 \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir /tmp/debug_seq2seq_squad/ -``` - -## Accelerate-based scripts - -Based on the scripts `run_qa_no_trainer.py` and `run_qa_beam_search_no_trainer.py`. - -Like `run_qa.py` and `run_qa_beam_search.py`, these scripts allow you to fine-tune any of the models supported on a -SQuAD or a similar dataset, the main difference is that this script exposes the bare training loop, to allow you to quickly experiment and add any customization you would like. It offers less options than the script with `Trainer` (for instance you can easily change the options for the optimizer or the dataloaders directly in the script), but still run in a distributed setup, on TPU and supports mixed precision by leveraging the [🤗 `Accelerate`](https://github.com/huggingface/accelerate) library. - -You can use the script normally after installing it: - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -then - -```bash -python run_qa_no_trainer.py \ - --model_name_or_path google-bert/bert-base-uncased \ - --dataset_name rajpurkar/squad \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir ~/tmp/debug_squad -``` - -You can then use your usual launchers to run in it in a distributed environment, but the easiest way is to run - -```bash -accelerate config -``` - -and reply to the questions asked. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -accelerate launch run_qa_no_trainer.py \ - --model_name_or_path google-bert/bert-base-uncased \ - --dataset_name rajpurkar/squad \ - --max_seq_length 384 \ - --doc_stride 128 \ - --output_dir ~/tmp/debug_squad -``` - -This command is the same and will work for: - -- a CPU-only setup -- a setup with one GPU -- a distributed training with several GPUs (single or multi node) -- a training on TPUs - -Note that this library is in alpha release so your feedback is more than welcome if you encounter any problem using it. diff --git a/examples/pytorch/question-answering/requirements.txt b/examples/pytorch/question-answering/requirements.txt deleted file mode 100644 index c8200d867ec4..000000000000 --- a/examples/pytorch/question-answering/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -accelerate >= 0.12.0 -datasets >= 1.8.0 -torch >= 1.3.0 -evaluate \ No newline at end of file diff --git a/examples/pytorch/question-answering/run_qa.py b/examples/pytorch/question-answering/run_qa.py deleted file mode 100755 index e1945f4f7727..000000000000 --- a/examples/pytorch/question-answering/run_qa.py +++ /dev/null @@ -1,693 +0,0 @@ -#!/usr/bin/env python -# Copyright 2020 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Fine-tuning the library models for question answering using a slightly adapted version of the 🤗 Trainer. -""" -# You can also adapt this script on your own question answering task. Pointers for this are left as comments. - -import logging -import os -import sys -import warnings -from dataclasses import dataclass, field - -import datasets -import evaluate -from datasets import load_dataset -from trainer_qa import QuestionAnsweringTrainer -from utils_qa import postprocess_qa_predictions - -import transformers -from transformers import ( - AutoConfig, - AutoModelForQuestionAnswering, - AutoTokenizer, - DataCollatorWithPadding, - EvalPrediction, - HfArgumentParser, - TrainingArguments, - default_data_collator, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/question-answering/requirements.txt") - -logger = logging.getLogger(__name__) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Path to directory to store the pretrained models downloaded from huggingface.co"}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a text file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."}, - ) - test_file: str | None = field( - default=None, - metadata={"help": "An optional input test data file to evaluate the perplexity on (a text file)."}, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_seq_length: int = field( - default=384, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - pad_to_max_length: bool = field( - default=True, - metadata={ - "help": ( - "Whether to pad all samples to `max_seq_length`. If False, will pad the samples dynamically when" - " batching to the maximum length in the batch (which can be faster on GPU but will be slower on TPU)." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - version_2_with_negative: bool = field( - default=False, metadata={"help": "If true, some of the examples do not have an answer."} - ) - null_score_diff_threshold: float = field( - default=0.0, - metadata={ - "help": ( - "The threshold used to select the null answer: if the best answer has a score that is less than " - "the score of the null answer minus this threshold, the null answer is selected for this example. " - "Only useful when `version_2_with_negative=True`." - ) - }, - ) - doc_stride: int = field( - default=128, - metadata={"help": "When splitting up a long document into chunks, how much stride to take between chunks."}, - ) - n_best_size: int = field( - default=20, - metadata={"help": "The total number of n-best predictions to generate when looking for an answer."}, - ) - max_answer_length: int = field( - default=30, - metadata={ - "help": ( - "The maximum length of an answer that can be generated. This is needed because the start " - "and end predictions are not conditioned on one another." - ) - }, - ) - - def __post_init__(self): - if ( - self.dataset_name is None - and self.train_file is None - and self.validation_file is None - and self.test_file is None - ): - raise ValueError("Need either a dataset name or a training/validation file/test_file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - if self.test_file is not None: - extension = self.test_file.split(".")[-1] - assert extension in ["csv", "json"], "`test_file` should be a csv or a json file." - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - if data_args.test_file is not None: - data_files["test"] = data_args.test_file - extension = data_args.test_file.split(".")[-1] - raw_datasets = load_dataset( - extension, - data_files=data_files, - field="data", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=True, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForQuestionAnswering.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # Tokenizer check: this script requires a fast tokenizer. - # Check if tokenizer has _tokenizer attribute (from tokenizers library) or is_fast property - if not (hasattr(tokenizer, "_tokenizer") or getattr(tokenizer, "is_fast", False)): - raise TypeError( - "This example script only works for models that have a fast tokenizer. Check out the big table of models at" - " https://huggingface.co/transformers/index.html#supported-frameworks to find the model types that meet" - " this requirement" - ) - - # Preprocessing the datasets. - # Preprocessing is slightly different for training and evaluation. - if training_args.do_train: - column_names = raw_datasets["train"].column_names - elif training_args.do_eval: - column_names = raw_datasets["validation"].column_names - else: - column_names = raw_datasets["test"].column_names - question_column_name = "question" if "question" in column_names else column_names[0] - context_column_name = "context" if "context" in column_names else column_names[1] - answer_column_name = "answers" if "answers" in column_names else column_names[2] - - # Padding side determines if we do (question|context) or (context|question). - pad_on_right = tokenizer.padding_side == "right" - - if data_args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({data_args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) - - # Training preprocessing - def prepare_train_features(examples): - # Some of the questions have lots of whitespace on the left, which is not useful and will make the - # truncation of the context fail (the tokenized question will take a lots of space). So we remove that - # left whitespace - examples[question_column_name] = [q.lstrip() for q in examples[question_column_name]] - - # Tokenize our examples with truncation and maybe padding, but keep the overflows using a stride. This results - # in one example possible giving several features when a context is long, each of those features having a - # context that overlaps a bit the context of the previous feature. - tokenized_examples = tokenizer( - examples[question_column_name if pad_on_right else context_column_name], - examples[context_column_name if pad_on_right else question_column_name], - truncation="only_second" if pad_on_right else "only_first", - max_length=max_seq_length, - stride=data_args.doc_stride, - return_overflowing_tokens=True, - return_offsets_mapping=True, - padding="max_length" if data_args.pad_to_max_length else False, - ) - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") - # The offset mappings will give us a map from token to character position in the original context. This will - # help us compute the start_positions and end_positions. - offset_mapping = tokenized_examples.pop("offset_mapping") - - # Let's label those examples! - tokenized_examples["start_positions"] = [] - tokenized_examples["end_positions"] = [] - - for i, offsets in enumerate(offset_mapping): - # We will label impossible answers with the index of the CLS token. - input_ids = tokenized_examples["input_ids"][i] - if tokenizer.cls_token_id in input_ids: - cls_index = input_ids.index(tokenizer.cls_token_id) - elif tokenizer.bos_token_id in input_ids: - cls_index = input_ids.index(tokenizer.bos_token_id) - else: - cls_index = 0 - - # Grab the sequence corresponding to that example (to know what is the context and what is the question). - sequence_ids = tokenized_examples.sequence_ids(i) - - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - answers = examples[answer_column_name][sample_index] - # If no answers are given, set the cls_index as answer. - if len(answers["answer_start"]) == 0: - tokenized_examples["start_positions"].append(cls_index) - tokenized_examples["end_positions"].append(cls_index) - else: - # Start/end character index of the answer in the text. - start_char = answers["answer_start"][0] - end_char = start_char + len(answers["text"][0]) - - # Start token index of the current span in the text. - token_start_index = 0 - while sequence_ids[token_start_index] != (1 if pad_on_right else 0): - token_start_index += 1 - - # End token index of the current span in the text. - token_end_index = len(input_ids) - 1 - while sequence_ids[token_end_index] != (1 if pad_on_right else 0): - token_end_index -= 1 - - # Detect if the answer is out of the span (in which case this feature is labeled with the CLS index). - if not (offsets[token_start_index][0] <= start_char and offsets[token_end_index][1] >= end_char): - tokenized_examples["start_positions"].append(cls_index) - tokenized_examples["end_positions"].append(cls_index) - else: - # Otherwise move the token_start_index and token_end_index to the two ends of the answer. - # Note: we could go after the last offset if the answer is the last word (edge case). - while token_start_index < len(offsets) and offsets[token_start_index][0] <= start_char: - token_start_index += 1 - tokenized_examples["start_positions"].append(token_start_index - 1) - while offsets[token_end_index][1] >= end_char: - token_end_index -= 1 - tokenized_examples["end_positions"].append(token_end_index + 1) - - return tokenized_examples - - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if data_args.max_train_samples is not None: - # We will select sample from whole data if argument is specified - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - # Create train feature from dataset - with training_args.main_process_first(desc="train dataset map pre-processing"): - train_dataset = train_dataset.map( - prepare_train_features, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - if data_args.max_train_samples is not None: - # Number of samples might increase during Feature Creation, We select only specified max samples - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - # Validation preprocessing - def prepare_validation_features(examples): - # Some of the questions have lots of whitespace on the left, which is not useful and will make the - # truncation of the context fail (the tokenized question will take a lots of space). So we remove that - # left whitespace - examples[question_column_name] = [q.lstrip() for q in examples[question_column_name]] - - # Tokenize our examples with truncation and maybe padding, but keep the overflows using a stride. This results - # in one example possible giving several features when a context is long, each of those features having a - # context that overlaps a bit the context of the previous feature. - tokenized_examples = tokenizer( - examples[question_column_name if pad_on_right else context_column_name], - examples[context_column_name if pad_on_right else question_column_name], - truncation="only_second" if pad_on_right else "only_first", - max_length=max_seq_length, - stride=data_args.doc_stride, - return_overflowing_tokens=True, - return_offsets_mapping=True, - padding="max_length" if data_args.pad_to_max_length else False, - ) - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") - - # For evaluation, we will need to convert our predictions to substrings of the context, so we keep the - # corresponding example_id and we will store the offset mappings. - tokenized_examples["example_id"] = [] - - for i in range(len(tokenized_examples["input_ids"])): - # Grab the sequence corresponding to that example (to know what is the context and what is the question). - sequence_ids = tokenized_examples.sequence_ids(i) - context_index = 1 if pad_on_right else 0 - - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - tokenized_examples["example_id"].append(examples["id"][sample_index]) - - # Set to None the offset_mapping that are not part of the context so it's easy to determine if a token - # position is part of the context or not. - tokenized_examples["offset_mapping"][i] = [ - (o if sequence_ids[k] == context_index else None) - for k, o in enumerate(tokenized_examples["offset_mapping"][i]) - ] - - return tokenized_examples - - if training_args.do_eval: - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_examples = raw_datasets["validation"] - if data_args.max_eval_samples is not None: - # We will select sample from whole data - max_eval_samples = min(len(eval_examples), data_args.max_eval_samples) - eval_examples = eval_examples.select(range(max_eval_samples)) - # Validation Feature Creation - with training_args.main_process_first(desc="validation dataset map pre-processing"): - eval_dataset = eval_examples.map( - prepare_validation_features, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - if data_args.max_eval_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - if training_args.do_predict: - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_examples = raw_datasets["test"] - if data_args.max_predict_samples is not None: - # We will select sample from whole data - predict_examples = predict_examples.select(range(data_args.max_predict_samples)) - # Predict Feature Creation - with training_args.main_process_first(desc="prediction dataset map pre-processing"): - predict_dataset = predict_examples.map( - prepare_validation_features, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - if data_args.max_predict_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - - # Data collator - # We have already padded to max length if the corresponding flag is True, otherwise we need to pad in the data - # collator. - data_collator = ( - default_data_collator - if data_args.pad_to_max_length - else DataCollatorWithPadding(tokenizer, pad_to_multiple_of=8 if training_args.fp16 else None) - ) - - # Post-processing: - def post_processing_function(examples, features, predictions, stage="eval"): - # Post-processing: we match the start logits and end logits to answers in the original context. - predictions = postprocess_qa_predictions( - examples=examples, - features=features, - predictions=predictions, - version_2_with_negative=data_args.version_2_with_negative, - n_best_size=data_args.n_best_size, - max_answer_length=data_args.max_answer_length, - null_score_diff_threshold=data_args.null_score_diff_threshold, - output_dir=training_args.output_dir, - log_level=log_level, - prefix=stage, - ) - # Format the result to the format the metric expects. - if data_args.version_2_with_negative: - formatted_predictions = [ - {"id": str(k), "prediction_text": v, "no_answer_probability": 0.0} for k, v in predictions.items() - ] - else: - formatted_predictions = [{"id": str(k), "prediction_text": v} for k, v in predictions.items()] - - references = [{"id": str(ex["id"]), "answers": ex[answer_column_name]} for ex in examples] - return EvalPrediction(predictions=formatted_predictions, label_ids=references) - - if data_args.version_2_with_negative: - accepted_best_metrics = ("exact", "f1", "HasAns_exact", "HasAns_f1") - else: - accepted_best_metrics = ("exact_match", "f1") - - if training_args.load_best_model_at_end and training_args.metric_for_best_model not in accepted_best_metrics: - warnings.warn(f"--metric_for_best_model should be set to one of {accepted_best_metrics}") - - metric = evaluate.load( - "squad_v2" if data_args.version_2_with_negative else "squad", cache_dir=model_args.cache_dir - ) - - def compute_metrics(p: EvalPrediction): - return metric.compute(predictions=p.predictions, references=p.label_ids) - - # Initialize our Trainer - trainer = QuestionAnsweringTrainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - eval_examples=eval_examples if training_args.do_eval else None, - processing_class=tokenizer, - data_collator=data_collator, - post_process_function=post_processing_function, - compute_metrics=compute_metrics, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - metrics = trainer.evaluate() - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Prediction - if training_args.do_predict: - logger.info("*** Predict ***") - results = trainer.predict(predict_dataset, predict_examples) - metrics = results.metrics - - max_predict_samples = ( - data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset) - ) - metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset)) - - trainer.log_metrics("predict", metrics) - trainer.save_metrics("predict", metrics) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "question-answering"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/question-answering/run_qa_beam_search.py b/examples/pytorch/question-answering/run_qa_beam_search.py deleted file mode 100755 index 592cf78a39e6..000000000000 --- a/examples/pytorch/question-answering/run_qa_beam_search.py +++ /dev/null @@ -1,720 +0,0 @@ -#!/usr/bin/env python -# Copyright 2020 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Fine-tuning XLNet for question answering with beam search using a slightly adapted version of the 🤗 Trainer. -""" -# You can also adapt this script on your own question answering task. Pointers for this are left as comments. - -import logging -import os -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -from datasets import load_dataset -from trainer_qa import QuestionAnsweringTrainer -from utils_qa import postprocess_qa_predictions_with_beam_search - -import transformers -from transformers import ( - DataCollatorWithPadding, - EvalPrediction, - HfArgumentParser, - TrainingArguments, - XLNetConfig, - XLNetForQuestionAnswering, - XLNetTokenizerFast, - default_data_collator, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/question-answering/requirements.txt") - -logger = logging.getLogger(__name__) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a text file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."}, - ) - test_file: str | None = field( - default=None, - metadata={"help": "An optional input test data file to test the perplexity on (a text file)."}, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_seq_length: int = field( - default=384, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - pad_to_max_length: bool = field( - default=True, - metadata={ - "help": ( - "Whether to pad all samples to `max_seq_length`. If False, will pad the samples dynamically when" - " batching to the maximum length in the batch (which can be faster on GPU but will be slower on TPU)." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - version_2_with_negative: bool = field( - default=False, metadata={"help": "If true, some of the examples do not have an answer."} - ) - null_score_diff_threshold: float = field( - default=0.0, - metadata={ - "help": ( - "The threshold used to select the null answer: if the best answer has a score that is less than " - "the score of the null answer minus this threshold, the null answer is selected for this example. " - "Only useful when `version_2_with_negative=True`." - ) - }, - ) - doc_stride: int = field( - default=128, - metadata={"help": "When splitting up a long document into chunks, how much stride to take between chunks."}, - ) - n_best_size: int = field( - default=20, - metadata={"help": "The total number of n-best predictions to generate when looking for an answer."}, - ) - max_answer_length: int = field( - default=30, - metadata={ - "help": ( - "The maximum length of an answer that can be generated. This is needed because the start " - "and end predictions are not conditioned on one another." - ) - }, - ) - - def __post_init__(self): - if ( - self.dataset_name is None - and self.train_file is None - and self.validation_file is None - and self.test_file is None - ): - raise ValueError("Need either a dataset name or a training/validation/test file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - if self.test_file is not None: - extension = self.test_file.split(".")[-1] - assert extension in ["csv", "json"], "`test_file` should be a csv or a json file." - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - if data_args.test_file is not None: - data_files["test"] = data_args.test_file - extension = data_args.test_file.split(".")[-1] - raw_datasets = load_dataset( - extension, - data_files=data_files, - field="data", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = XLNetConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - ) - tokenizer = XLNetTokenizerFast.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - ) - model = XLNetForQuestionAnswering.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - ) - - # Preprocessing the datasets. - # Preprocessing is slightly different for training and evaluation. - if training_args.do_train: - column_names = raw_datasets["train"].column_names - elif training_args.do_eval: - column_names = raw_datasets["validation"].column_names - else: - column_names = raw_datasets["test"].column_names - question_column_name = "question" if "question" in column_names else column_names[0] - context_column_name = "context" if "context" in column_names else column_names[1] - answer_column_name = "answers" if "answers" in column_names else column_names[2] - - # Padding side determines if we do (question|context) or (context|question). - pad_on_right = tokenizer.padding_side == "right" - - if data_args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({data_args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) - - # Training preprocessing - def prepare_train_features(examples): - # Some of the questions have lots of whitespace on the left, which is not useful and will make the - # truncation of the context fail (the tokenized question will take a lots of space). So we remove that - # left whitespace - examples[question_column_name] = [q.lstrip() for q in examples[question_column_name]] - - # Tokenize our examples with truncation and maybe padding, but keep the overflows using a stride. This results - # in one example possible giving several features when a context is long, each of those features having a - # context that overlaps a bit the context of the previous feature. - tokenized_examples = tokenizer( - examples[question_column_name if pad_on_right else context_column_name], - examples[context_column_name if pad_on_right else question_column_name], - truncation="only_second" if pad_on_right else "only_first", - max_length=max_seq_length, - stride=data_args.doc_stride, - return_overflowing_tokens=True, - return_offsets_mapping=True, - return_special_tokens_mask=True, - return_token_type_ids=True, - padding="max_length", - ) - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") - # The offset mappings will give us a map from token to character position in the original context. This will - # help us compute the start_positions and end_positions. - offset_mapping = tokenized_examples.pop("offset_mapping") - # The special tokens will help us build the p_mask (which indicates the tokens that can't be in answers). - special_tokens = tokenized_examples.pop("special_tokens_mask") - - # Let's label those examples! - tokenized_examples["start_positions"] = [] - tokenized_examples["end_positions"] = [] - tokenized_examples["is_impossible"] = [] - tokenized_examples["cls_index"] = [] - tokenized_examples["p_mask"] = [] - - for i, offsets in enumerate(offset_mapping): - # We will label impossible answers with the index of the CLS token. - input_ids = tokenized_examples["input_ids"][i] - if tokenizer.cls_token_id in input_ids: - cls_index = input_ids.index(tokenizer.cls_token_id) - elif tokenizer.bos_token_id in input_ids: - cls_index = input_ids.index(tokenizer.bos_token_id) - else: - cls_index = 0 - tokenized_examples["cls_index"].append(cls_index) - - # Grab the sequence corresponding to that example (to know what is the context and what is the question). - sequence_ids = tokenized_examples["token_type_ids"][i] - for k, s in enumerate(special_tokens[i]): - if s: - sequence_ids[k] = 3 - context_idx = 1 if pad_on_right else 0 - - # Build the p_mask: non special tokens and context gets 0.0, the others get 1.0. - # The cls token gets 1.0 too (for predictions of empty answers). - tokenized_examples["p_mask"].append( - [ - 0.0 if (not special_tokens[i][k] and s == context_idx) or k == cls_index else 1.0 - for k, s in enumerate(sequence_ids) - ] - ) - - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - answers = examples[answer_column_name][sample_index] - # If no answers are given, set the cls_index as answer. - if len(answers["answer_start"]) == 0: - tokenized_examples["start_positions"].append(cls_index) - tokenized_examples["end_positions"].append(cls_index) - tokenized_examples["is_impossible"].append(1.0) - else: - # Start/end character index of the answer in the text. - start_char = answers["answer_start"][0] - end_char = start_char + len(answers["text"][0]) - - # Start token index of the current span in the text. - token_start_index = 0 - while sequence_ids[token_start_index] != context_idx: - token_start_index += 1 - - # End token index of the current span in the text. - token_end_index = len(input_ids) - 1 - while sequence_ids[token_end_index] != context_idx: - token_end_index -= 1 - # Detect if the answer is out of the span (in which case this feature is labeled with the CLS index). - if not (offsets[token_start_index][0] <= start_char and offsets[token_end_index][1] >= end_char): - tokenized_examples["start_positions"].append(cls_index) - tokenized_examples["end_positions"].append(cls_index) - tokenized_examples["is_impossible"].append(1.0) - else: - # Otherwise move the token_start_index and token_end_index to the two ends of the answer. - # Note: we could go after the last offset if the answer is the last word (edge case). - while token_start_index < len(offsets) and offsets[token_start_index][0] <= start_char: - token_start_index += 1 - tokenized_examples["start_positions"].append(token_start_index - 1) - while offsets[token_end_index][1] >= end_char: - token_end_index -= 1 - tokenized_examples["end_positions"].append(token_end_index + 1) - tokenized_examples["is_impossible"].append(0.0) - - return tokenized_examples - - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if data_args.max_train_samples is not None: - # Select samples from Dataset, This will help to decrease processing time - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - # Create Training Features - with training_args.main_process_first(desc="train dataset map pre-processing"): - train_dataset = train_dataset.map( - prepare_train_features, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - if data_args.max_train_samples is not None: - # Select samples from dataset again since Feature Creation might increase number of features - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - # Validation preprocessing - def prepare_validation_features(examples): - # Tokenize our examples with truncation and maybe padding, but keep the overflows using a stride. This results - # in one example possible giving several features when a context is long, each of those features having a - # context that overlaps a bit the context of the previous feature. - tokenized_examples = tokenizer( - examples[question_column_name if pad_on_right else context_column_name], - examples[context_column_name if pad_on_right else question_column_name], - truncation="only_second" if pad_on_right else "only_first", - max_length=max_seq_length, - stride=data_args.doc_stride, - return_overflowing_tokens=True, - return_offsets_mapping=True, - return_special_tokens_mask=True, - return_token_type_ids=True, - padding="max_length", - ) - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") - - # The special tokens will help us build the p_mask (which indicates the tokens that can't be in answers). - special_tokens = tokenized_examples.pop("special_tokens_mask") - - # For evaluation, we will need to convert our predictions to substrings of the context, so we keep the - # corresponding example_id and we will store the offset mappings. - tokenized_examples["example_id"] = [] - - # We still provide the index of the CLS token and the p_mask to the model, but not the is_impossible label. - tokenized_examples["cls_index"] = [] - tokenized_examples["p_mask"] = [] - - for i, input_ids in enumerate(tokenized_examples["input_ids"]): - # Find the CLS token in the input ids. - if tokenizer.cls_token_id in input_ids: - cls_index = input_ids.index(tokenizer.cls_token_id) - elif tokenizer.bos_token_id in input_ids: - cls_index = input_ids.index(tokenizer.bos_token_id) - else: - cls_index = 0 - tokenized_examples["cls_index"].append(cls_index) - - # Grab the sequence corresponding to that example (to know what is the context and what is the question). - sequence_ids = tokenized_examples["token_type_ids"][i] - for k, s in enumerate(special_tokens[i]): - if s: - sequence_ids[k] = 3 - context_idx = 1 if pad_on_right else 0 - - # Build the p_mask: non special tokens and context gets 0.0, the others 1.0. - tokenized_examples["p_mask"].append( - [ - 0.0 if (not special_tokens[i][k] and s == context_idx) or k == cls_index else 1.0 - for k, s in enumerate(sequence_ids) - ] - ) - - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - tokenized_examples["example_id"].append(examples["id"][sample_index]) - - # Set to None the offset_mapping that are not part of the context so it's easy to determine if a token - # position is part of the context or not. - tokenized_examples["offset_mapping"][i] = [ - (o if sequence_ids[k] == context_idx else None) - for k, o in enumerate(tokenized_examples["offset_mapping"][i]) - ] - - return tokenized_examples - - if training_args.do_eval: - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_examples = raw_datasets["validation"] - if data_args.max_eval_samples is not None: - # Selecting Eval Samples from Dataset - max_eval_samples = min(len(eval_examples), data_args.max_eval_samples) - eval_examples = eval_examples.select(range(max_eval_samples)) - # Create Features from Eval Dataset - with training_args.main_process_first(desc="validation dataset map pre-processing"): - eval_dataset = eval_examples.map( - prepare_validation_features, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - if data_args.max_eval_samples is not None: - # Selecting Samples from Dataset again since Feature Creation might increase samples size - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - if training_args.do_predict: - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_examples = raw_datasets["test"] - if data_args.max_predict_samples is not None: - # We will select sample from whole data - predict_examples = predict_examples.select(range(data_args.max_predict_samples)) - # Test Feature Creation - with training_args.main_process_first(desc="prediction dataset map pre-processing"): - predict_dataset = predict_examples.map( - prepare_validation_features, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - if data_args.max_predict_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - - # Data collator - # We have already padded to max length if the corresponding flag is True, otherwise we need to pad in the data - # collator. - data_collator = ( - default_data_collator - if data_args.pad_to_max_length - else DataCollatorWithPadding(tokenizer, pad_to_multiple_of=8 if training_args.fp16 else None) - ) - - # Post-processing: - def post_processing_function(examples, features, predictions, stage="eval"): - # Post-processing: we match the start logits and end logits to answers in the original context. - predictions, scores_diff_json = postprocess_qa_predictions_with_beam_search( - examples=examples, - features=features, - predictions=predictions, - version_2_with_negative=data_args.version_2_with_negative, - n_best_size=data_args.n_best_size, - max_answer_length=data_args.max_answer_length, - start_n_top=model.config.start_n_top, - end_n_top=model.config.end_n_top, - output_dir=training_args.output_dir, - log_level=log_level, - prefix=stage, - ) - # Format the result to the format the metric expects. - if data_args.version_2_with_negative: - formatted_predictions = [ - {"id": k, "prediction_text": v, "no_answer_probability": scores_diff_json[k]} - for k, v in predictions.items() - ] - else: - formatted_predictions = [{"id": k, "prediction_text": v} for k, v in predictions.items()] - - references = [{"id": ex["id"], "answers": ex[answer_column_name]} for ex in examples] - return EvalPrediction(predictions=formatted_predictions, label_ids=references) - - metric = evaluate.load( - "squad_v2" if data_args.version_2_with_negative else "squad", cache_dir=model_args.cache_dir - ) - - def compute_metrics(p: EvalPrediction): - return metric.compute(predictions=p.predictions, references=p.label_ids) - - # Initialize our Trainer - trainer = QuestionAnsweringTrainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - eval_examples=eval_examples if training_args.do_eval else None, - processing_class=tokenizer, - data_collator=data_collator, - post_process_function=post_processing_function, - compute_metrics=compute_metrics, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - - metrics = train_result.metrics - - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - metrics = trainer.evaluate() - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Prediction - if training_args.do_predict: - logger.info("*** Predict ***") - results = trainer.predict(predict_dataset, predict_examples) - metrics = results.metrics - - max_predict_samples = ( - data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset) - ) - metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset)) - - trainer.log_metrics("predict", metrics) - trainer.save_metrics("predict", metrics) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "question-answering"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/question-answering/run_qa_beam_search_no_trainer.py b/examples/pytorch/question-answering/run_qa_beam_search_no_trainer.py deleted file mode 100644 index 1af4d95f065b..000000000000 --- a/examples/pytorch/question-answering/run_qa_beam_search_no_trainer.py +++ /dev/null @@ -1,1064 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Fine-tuning XLNet for question answering with beam search using 🤗 Accelerate. -""" -# You can also adapt this script on your own question answering task. Pointers for this are left as comments. - -import argparse -import json -import logging -import math -import os -import random -from pathlib import Path - -import datasets -import evaluate -import numpy as np -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from tqdm.auto import tqdm -from utils_qa import postprocess_qa_predictions_with_beam_search - -import transformers -from transformers import ( - DataCollatorWithPadding, - EvalPrediction, - SchedulerType, - XLNetConfig, - XLNetForQuestionAnswering, - XLNetTokenizerFast, - default_data_collator, - get_scheduler, -) -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/question-answering/requirements.txt") - -logger = get_logger(__name__) - - -def save_prefixed_metrics(results, output_dir, file_name: str = "all_results.json", metric_key_prefix: str = "eval"): - """ - Save results while prefixing metric names. - - Args: - results: (:obj:`dict`): - A dictionary of results. - output_dir: (:obj:`str`): - An output directory. - file_name: (:obj:`str`, `optional`, defaults to :obj:`all_results.json`): - An output file name. - metric_key_prefix: (:obj:`str`, `optional`, defaults to :obj:`eval`): - A metric name prefix. - """ - # Prefix all keys with metric_key_prefix + '_' - for key in list(results.keys()): - if not key.startswith(f"{metric_key_prefix}_"): - results[f"{metric_key_prefix}_{key}"] = results.pop(key) - - with open(os.path.join(output_dir, file_name), "w", encoding="utf-8") as f: - json.dump(results, f, indent=4) - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a Question Answering task") - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv or a json file containing the training data." - ) - parser.add_argument( - "--preprocessing_num_workers", type=int, default=1, help="A csv or a json file containing the training data." - ) - parser.add_argument("--do_predict", action="store_true", help="Eval the question answering model") - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv or a json file containing the validation data." - ) - parser.add_argument( - "--test_file", type=str, default=None, help="A csv or a json file containing the Prediction data." - ) - parser.add_argument( - "--max_seq_length", - type=int, - default=384, - help=( - "The maximum total input sequence length after tokenization. Sequences longer than this will be truncated," - " sequences shorter will be padded if `--pad_to_max_length` is passed." - ), - ) - parser.add_argument( - "--pad_to_max_length", - action="store_true", - help="If passed, pad all samples to `max_seq_length`. Otherwise, dynamic padding is used.", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=True, - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument( - "--doc_stride", - type=int, - default=128, - help="When splitting up a long document into chunks how much stride to take between chunks.", - ) - parser.add_argument( - "--n_best_size", - type=int, - default=20, - help="The total number of n-best predictions to generate when looking for an answer.", - ) - parser.add_argument( - "--null_score_diff_threshold", - type=float, - default=0.0, - help=( - "The threshold used to select the null answer: if the best answer has a score that is less than " - "the score of the null answer minus this threshold, the null answer is selected for this example. " - "Only useful when `version_2_with_negative=True`." - ), - ) - parser.add_argument( - "--version_2_with_negative", - action="store_true", - help="If true, some of the examples do not have an answer.", - ) - parser.add_argument( - "--max_answer_length", - type=int, - default=30, - help=( - "The maximum length of an answer that can be generated. This is needed because the start " - "and end predictions are not conditioned on one another." - ), - ) - parser.add_argument( - "--max_train_samples", - type=int, - default=None, - help=( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ), - ) - parser.add_argument( - "--max_eval_samples", - type=int, - default=None, - help=( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ), - ) - parser.add_argument( - "--overwrite_cache", action="store_true", help="Overwrite the cached training and evaluation sets" - ) - parser.add_argument( - "--max_predict_samples", - type=int, - default=None, - help="For debugging purposes or quicker training, truncate the number of prediction examples to this", - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to load in all available experiment trackers from the environment and use them for logging.", - ) - args = parser.parse_args() - - # Sanity checks - if ( - args.dataset_name is None - and args.train_file is None - and args.validation_file is None - and args.test_file is None - ): - raise ValueError("Need either a dataset name or a training/validation/test file.") - else: - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - if args.test_file is not None: - extension = args.test_file.split(".")[-1] - assert extension in ["csv", "json"], "`test_file` should be a csv or a json file." - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - else: - data_files = {} - if args.train_file is not None: - data_files["train"] = args.train_file - extension = args.train_file.split(".")[-1] - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.validation_file.split(".")[-1] - if args.test_file is not None: - data_files["test"] = args.test_file - extension = args.test_file.split(".")[-1] - raw_datasets = load_dataset(extension, data_files=data_files, field="data") - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - - config = XLNetConfig.from_pretrained(args.model_name_or_path) - tokenizer = XLNetTokenizerFast.from_pretrained(args.model_name_or_path) - model = XLNetForQuestionAnswering.from_pretrained( - args.model_name_or_path, from_tf=bool(".ckpt" in args.model_name_or_path), config=config - ) - - # Preprocessing the datasets. - # Preprocessing is slightly different for training and evaluation. - column_names = raw_datasets["train"].column_names - - question_column_name = "question" if "question" in column_names else column_names[0] - context_column_name = "context" if "context" in column_names else column_names[1] - answer_column_name = "answers" if "answers" in column_names else column_names[2] - - # Padding side determines if we do (question|context) or (context|question). - pad_on_right = tokenizer.padding_side == "right" - - if args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - - max_seq_length = min(args.max_seq_length, tokenizer.model_max_length) - - # Training preprocessing - def prepare_train_features(examples): - # Some of the questions have lots of whitespace on the left, which is not useful and will make the - # truncation of the context fail (the tokenized question will take a lots of space). So we remove that - # left whitespace - examples[question_column_name] = [q.lstrip() for q in examples[question_column_name]] - - # Tokenize our examples with truncation and maybe padding, but keep the overflows using a stride. This results - # in one example possible giving several features when a context is long, each of those features having a - # context that overlaps a bit the context of the previous feature. - tokenized_examples = tokenizer( - examples[question_column_name if pad_on_right else context_column_name], - examples[context_column_name if pad_on_right else question_column_name], - truncation="only_second" if pad_on_right else "only_first", - max_length=max_seq_length, - stride=args.doc_stride, - return_overflowing_tokens=True, - return_offsets_mapping=True, - return_special_tokens_mask=True, - return_token_type_ids=True, - padding="max_length", - ) - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") - # The offset mappings will give us a map from token to character position in the original context. This will - # help us compute the start_positions and end_positions. - offset_mapping = tokenized_examples.pop("offset_mapping") - # The special tokens will help us build the p_mask (which indicates the tokens that can't be in answers). - special_tokens = tokenized_examples.pop("special_tokens_mask") - - # Let's label those examples! - tokenized_examples["start_positions"] = [] - tokenized_examples["end_positions"] = [] - tokenized_examples["is_impossible"] = [] - tokenized_examples["cls_index"] = [] - tokenized_examples["p_mask"] = [] - - for i, offsets in enumerate(offset_mapping): - # We will label impossible answers with the index of the CLS token. - input_ids = tokenized_examples["input_ids"][i] - if tokenizer.cls_token_id in input_ids: - cls_index = input_ids.index(tokenizer.cls_token_id) - elif tokenizer.bos_token_id in input_ids: - cls_index = input_ids.index(tokenizer.bos_token_id) - else: - cls_index = 0 - tokenized_examples["cls_index"].append(cls_index) - - # Grab the sequence corresponding to that example (to know what is the context and what is the question). - sequence_ids = tokenized_examples["token_type_ids"][i] - for k, s in enumerate(special_tokens[i]): - if s: - sequence_ids[k] = 3 - context_idx = 1 if pad_on_right else 0 - - # Build the p_mask: non special tokens and context gets 0.0, the others get 1.0. - # The cls token gets 1.0 too (for predictions of empty answers). - tokenized_examples["p_mask"].append( - [ - 0.0 if (not special_tokens[i][k] and s == context_idx) or k == cls_index else 1.0 - for k, s in enumerate(sequence_ids) - ] - ) - - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - answers = examples[answer_column_name][sample_index] - # If no answers are given, set the cls_index as answer. - if len(answers["answer_start"]) == 0: - tokenized_examples["start_positions"].append(cls_index) - tokenized_examples["end_positions"].append(cls_index) - tokenized_examples["is_impossible"].append(1.0) - else: - # Start/end character index of the answer in the text. - start_char = answers["answer_start"][0] - end_char = start_char + len(answers["text"][0]) - - # Start token index of the current span in the text. - token_start_index = 0 - while sequence_ids[token_start_index] != context_idx: - token_start_index += 1 - - # End token index of the current span in the text. - token_end_index = len(input_ids) - 1 - while sequence_ids[token_end_index] != context_idx: - token_end_index -= 1 - # Detect if the answer is out of the span (in which case this feature is labeled with the CLS index). - if not (offsets[token_start_index][0] <= start_char and offsets[token_end_index][1] >= end_char): - tokenized_examples["start_positions"].append(cls_index) - tokenized_examples["end_positions"].append(cls_index) - tokenized_examples["is_impossible"].append(1.0) - else: - # Otherwise move the token_start_index and token_end_index to the two ends of the answer. - # Note: we could go after the last offset if the answer is the last word (edge case). - while token_start_index < len(offsets) and offsets[token_start_index][0] <= start_char: - token_start_index += 1 - tokenized_examples["start_positions"].append(token_start_index - 1) - while offsets[token_end_index][1] >= end_char: - token_end_index -= 1 - tokenized_examples["end_positions"].append(token_end_index + 1) - tokenized_examples["is_impossible"].append(0.0) - - return tokenized_examples - - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if args.max_train_samples is not None: - # We will select sample from whole data if argument is specified - train_dataset = train_dataset.select(range(args.max_train_samples)) - # Create train feature from dataset - with accelerator.main_process_first(): - train_dataset = train_dataset.map( - prepare_train_features, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - if args.max_train_samples is not None: - # Number of samples might increase during Feature Creation, We select only specified max samples - train_dataset = train_dataset.select(range(args.max_train_samples)) - - # Validation preprocessing - def prepare_validation_features(examples): - # Some of the questions have lots of whitespace on the left, which is not useful and will make the - # truncation of the context fail (the tokenized question will take a lots of space). So we remove that - # left whitespace - examples[question_column_name] = [q.lstrip() for q in examples[question_column_name]] - - # Tokenize our examples with truncation and maybe padding, but keep the overflows using a stride. This results - # in one example possible giving several features when a context is long, each of those features having a - # context that overlaps a bit the context of the previous feature. - tokenized_examples = tokenizer( - examples[question_column_name if pad_on_right else context_column_name], - examples[context_column_name if pad_on_right else question_column_name], - truncation="only_second" if pad_on_right else "only_first", - max_length=max_seq_length, - stride=args.doc_stride, - return_overflowing_tokens=True, - return_offsets_mapping=True, - return_special_tokens_mask=True, - return_token_type_ids=True, - padding="max_length", - ) - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") - - # The special tokens will help us build the p_mask (which indicates the tokens that can't be in answers). - special_tokens = tokenized_examples.pop("special_tokens_mask") - - # For evaluation, we will need to convert our predictions to substrings of the context, so we keep the - # corresponding example_id and we will store the offset mappings. - tokenized_examples["example_id"] = [] - - # We still provide the index of the CLS token and the p_mask to the model, but not the is_impossible label. - tokenized_examples["cls_index"] = [] - tokenized_examples["p_mask"] = [] - - for i, input_ids in enumerate(tokenized_examples["input_ids"]): - # Find the CLS token in the input ids. - if tokenizer.cls_token_id in input_ids: - cls_index = input_ids.index(tokenizer.cls_token_id) - elif tokenizer.bos_token_id in input_ids: - cls_index = input_ids.index(tokenizer.bos_token_id) - else: - cls_index = 0 - tokenized_examples["cls_index"].append(cls_index) - - # Grab the sequence corresponding to that example (to know what is the context and what is the question). - sequence_ids = tokenized_examples["token_type_ids"][i] - for k, s in enumerate(special_tokens[i]): - if s: - sequence_ids[k] = 3 - context_idx = 1 if pad_on_right else 0 - - # Build the p_mask: non special tokens and context gets 0.0, the others 1.0. - tokenized_examples["p_mask"].append( - [ - 0.0 if (not special_tokens[i][k] and s == context_idx) or k == cls_index else 1.0 - for k, s in enumerate(sequence_ids) - ] - ) - - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - tokenized_examples["example_id"].append(examples["id"][sample_index]) - - # Set to None the offset_mapping that are not part of the context so it's easy to determine if a token - # position is part of the context or not. - tokenized_examples["offset_mapping"][i] = [ - (o if sequence_ids[k] == context_idx else None) - for k, o in enumerate(tokenized_examples["offset_mapping"][i]) - ] - - return tokenized_examples - - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_examples = raw_datasets["validation"] - if args.max_eval_samples is not None: - # We will select sample from whole data - eval_examples = eval_examples.select(range(args.max_eval_samples)) - # Validation Feature Creation - with accelerator.main_process_first(): - eval_dataset = eval_examples.map( - prepare_validation_features, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - - if args.max_eval_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - eval_dataset = eval_dataset.select(range(args.max_eval_samples)) - - if args.do_predict: - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_examples = raw_datasets["test"] - if args.max_predict_samples is not None: - # We will select sample from whole data - predict_examples = predict_examples.select(range(args.max_predict_samples)) - # Predict Feature Creation - with accelerator.main_process_first(): - predict_dataset = predict_examples.map( - prepare_validation_features, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - if args.max_predict_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - predict_dataset = predict_dataset.select(range(args.max_predict_samples)) - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # DataLoaders creation: - if args.pad_to_max_length: - # If padding was already done ot max length, we use the default data collator that will just convert everything - # to tensors. - data_collator = default_data_collator - else: - # Otherwise, `DataCollatorWithPadding` will apply dynamic padding for us (by padding to the maximum length of - # the samples passed). When using mixed precision, we add `pad_to_multiple_of=8` to pad all tensors to multiple - # of 8s, which will enable the use of Tensor Cores on NVIDIA hardware with compute capability >= 7.5 (Volta). - # For fp8, we pad to multiple of 16. - if accelerator.mixed_precision == "fp8": - pad_to_multiple_of = 16 - elif accelerator.mixed_precision != "no": - pad_to_multiple_of = 8 - else: - pad_to_multiple_of = None - data_collator = DataCollatorWithPadding(tokenizer, pad_to_multiple_of=pad_to_multiple_of) - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=data_collator, batch_size=args.per_device_train_batch_size - ) - - eval_dataset_for_model = eval_dataset.remove_columns(["example_id", "offset_mapping"]) - eval_dataloader = DataLoader( - eval_dataset_for_model, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size - ) - - if args.do_predict: - predict_dataset_for_model = predict_dataset.remove_columns(["example_id", "offset_mapping"]) - predict_dataloader = DataLoader( - predict_dataset_for_model, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size - ) - - # Post-processing: - def post_processing_function(examples, features, predictions, stage="eval"): - # Post-processing: we match the start logits and end logits to answers in the original context. - predictions, scores_diff_json = postprocess_qa_predictions_with_beam_search( - examples=examples, - features=features, - predictions=predictions, - version_2_with_negative=args.version_2_with_negative, - n_best_size=args.n_best_size, - max_answer_length=args.max_answer_length, - start_n_top=model.config.start_n_top, - end_n_top=model.config.end_n_top, - output_dir=args.output_dir, - prefix=stage, - ) - # Format the result to the format the metric expects. - if args.version_2_with_negative: - formatted_predictions = [ - {"id": k, "prediction_text": v, "no_answer_probability": scores_diff_json[k]} - for k, v in predictions.items() - ] - else: - formatted_predictions = [{"id": k, "prediction_text": v} for k, v in predictions.items()] - - references = [{"id": ex["id"], "answers": ex[answer_column_name]} for ex in examples] - return EvalPrediction(predictions=formatted_predictions, label_ids=references) - - metric = evaluate.load("squad_v2" if args.version_2_with_negative else "squad") - - def create_and_fill_np_array(start_or_end_logits, dataset, max_len): - """ - Create and fill numpy array of size len_of_validation_data * max_length_of_output_tensor - - Args: - start_or_end_logits(:obj:`tensor`): - This is the output predictions of the model. We can only enter either start or end logits. - eval_dataset: Evaluation dataset - max_len(:obj:`int`): - The maximum length of the output tensor. ( See the model.eval() part for more details ) - """ - - step = 0 - # create a numpy array and fill it with -100. - logits_concat = np.full((len(dataset), max_len), -100, dtype=np.float32) - # Now since we have create an array now we will populate it with the outputs gathered using accelerator.gather_for_metrics - for i, output_logit in enumerate(start_or_end_logits): # populate columns - # We have to fill it such that we have to take the whole tensor and replace it on the newly created array - # And after every iteration we have to change the step - - batch_size = output_logit.shape[0] - cols = output_logit.shape[1] - if step + batch_size < len(dataset): - logits_concat[step : step + batch_size, :cols] = output_logit - else: - logits_concat[step:, :cols] = output_logit[: len(dataset) - step] - - step += batch_size - - return logits_concat - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("qa_beam_search_no_trainer", experiment_config) - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - - accelerator.backward(loss) - - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - accelerator.save_state(f"step_{completed_steps}") - - if completed_steps >= args.max_train_steps: - break - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - # initialize all lists to collect the batches - all_start_top_log_probs = [] - all_start_top_index = [] - all_end_top_log_probs = [] - all_end_top_index = [] - all_cls_logits = [] - - model.eval() - - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - start_top_log_probs = outputs.start_top_log_probs - start_top_index = outputs.start_top_index - end_top_log_probs = outputs.end_top_log_probs - end_top_index = outputs.end_top_index - cls_logits = outputs.cls_logits - - if not args.pad_to_max_length: # necessary to pad predictions and labels for being gathered - start_top_log_probs = accelerator.pad_across_processes(start_top_log_probs, dim=1, pad_index=-100) - start_top_index = accelerator.pad_across_processes(start_top_index, dim=1, pad_index=-100) - end_top_log_probs = accelerator.pad_across_processes(end_top_log_probs, dim=1, pad_index=-100) - end_top_index = accelerator.pad_across_processes(end_top_index, dim=1, pad_index=-100) - cls_logits = accelerator.pad_across_processes(cls_logits, dim=1, pad_index=-100) - - all_start_top_log_probs.append(accelerator.gather_for_metrics(start_top_log_probs).cpu().numpy()) - all_start_top_index.append(accelerator.gather_for_metrics(start_top_index).cpu().numpy()) - all_end_top_log_probs.append(accelerator.gather_for_metrics(end_top_log_probs).cpu().numpy()) - all_end_top_index.append(accelerator.gather_for_metrics(end_top_index).cpu().numpy()) - all_cls_logits.append(accelerator.gather_for_metrics(cls_logits).cpu().numpy()) - - max_len = max(x.shape[1] for x in all_end_top_log_probs) # Get the max_length of the tensor - - # concatenate all numpy arrays collected above - start_top_log_probs_concat = create_and_fill_np_array(all_start_top_log_probs, eval_dataset, max_len) - start_top_index_concat = create_and_fill_np_array(all_start_top_index, eval_dataset, max_len) - end_top_log_probs_concat = create_and_fill_np_array(all_end_top_log_probs, eval_dataset, max_len) - end_top_index_concat = create_and_fill_np_array(all_end_top_index, eval_dataset, max_len) - cls_logits_concat = np.concatenate(all_cls_logits, axis=0) - - # delete the list of numpy arrays - del start_top_log_probs - del start_top_index - del end_top_log_probs - del end_top_index - del cls_logits - - outputs_numpy = ( - start_top_log_probs_concat, - start_top_index_concat, - end_top_log_probs_concat, - end_top_index_concat, - cls_logits_concat, - ) - prediction = post_processing_function(eval_examples, eval_dataset, outputs_numpy) - eval_metric = metric.compute(predictions=prediction.predictions, references=prediction.label_ids) - logger.info(f"Evaluation metrics: {eval_metric}") - - if args.do_predict: - # initialize all lists to collect the batches - - all_start_top_log_probs = [] - all_start_top_index = [] - all_end_top_log_probs = [] - all_end_top_index = [] - all_cls_logits = [] - - model.eval() - - for step, batch in enumerate(predict_dataloader): - with torch.no_grad(): - outputs = model(**batch) - start_top_log_probs = outputs.start_top_log_probs - start_top_index = outputs.start_top_index - end_top_log_probs = outputs.end_top_log_probs - end_top_index = outputs.end_top_index - cls_logits = outputs.cls_logits - - if not args.pad_to_max_length: # necessary to pad predictions and labels for being gathered - start_top_log_probs = accelerator.pad_across_processes(start_top_log_probs, dim=1, pad_index=-100) - start_top_index = accelerator.pad_across_processes(start_top_index, dim=1, pad_index=-100) - end_top_log_probs = accelerator.pad_across_processes(end_top_log_probs, dim=1, pad_index=-100) - end_top_index = accelerator.pad_across_processes(end_top_index, dim=1, pad_index=-100) - cls_logits = accelerator.pad_across_processes(cls_logits, dim=1, pad_index=-100) - - all_start_top_log_probs.append(accelerator.gather_for_metrics(start_top_log_probs).cpu().numpy()) - all_start_top_index.append(accelerator.gather_for_metrics(start_top_index).cpu().numpy()) - all_end_top_log_probs.append(accelerator.gather_for_metrics(end_top_log_probs).cpu().numpy()) - all_end_top_index.append(accelerator.gather_for_metrics(end_top_index).cpu().numpy()) - all_cls_logits.append(accelerator.gather_for_metrics(cls_logits).cpu().numpy()) - - max_len = max(x.shape[1] for x in all_end_top_log_probs) # Get the max_length of the tensor - - # concatenate all numpy arrays collected above - start_top_log_probs_concat = create_and_fill_np_array(all_start_top_log_probs, predict_dataset, max_len) - start_top_index_concat = create_and_fill_np_array(all_start_top_index, predict_dataset, max_len) - end_top_log_probs_concat = create_and_fill_np_array(all_end_top_log_probs, predict_dataset, max_len) - end_top_index_concat = create_and_fill_np_array(all_end_top_index, predict_dataset, max_len) - cls_logits_concat = np.concatenate(all_cls_logits, axis=0) - - # delete the list of numpy arrays - del start_top_log_probs - del start_top_index - del end_top_log_probs - del end_top_index - del cls_logits - - outputs_numpy = ( - start_top_log_probs_concat, - start_top_index_concat, - end_top_log_probs_concat, - end_top_index_concat, - cls_logits_concat, - ) - - prediction = post_processing_function(predict_examples, predict_dataset, outputs_numpy) - predict_metric = metric.compute(predictions=prediction.predictions, references=prediction.label_ids) - logger.info(f"Predict metrics: {predict_metric}") - - if args.with_tracking: - log = { - "squad_v2" if args.version_2_with_negative else "squad": eval_metric, - "train_loss": total_loss, - "epoch": epoch, - "step": completed_steps, - } - if args.do_predict: - log["squad_v2_predict" if args.version_2_with_negative else "squad_predict"] = predict_metric - - accelerator.log(log) - - if args.checkpointing_steps == "epoch": - accelerator.save_state(f"epoch_{epoch}") - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - logger.info(json.dumps(eval_metric, indent=4)) - save_prefixed_metrics(eval_metric, args.output_dir) - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/question-answering/run_qa_no_trainer.py b/examples/pytorch/question-answering/run_qa_no_trainer.py deleted file mode 100755 index 517cab8d21b9..000000000000 --- a/examples/pytorch/question-answering/run_qa_no_trainer.py +++ /dev/null @@ -1,1042 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Fine-tuning a 🤗 Transformers model for question answering using 🤗 Accelerate. -""" -# You can also adapt this script on your own question answering task. Pointers for this are left as comments. - -import argparse -import json -import logging -import math -import os -import random -from pathlib import Path - -import datasets -import evaluate -import numpy as np -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from tqdm.auto import tqdm -from utils_qa import postprocess_qa_predictions - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_MAPPING, - AutoConfig, - AutoModelForQuestionAnswering, - AutoTokenizer, - DataCollatorWithPadding, - EvalPrediction, - SchedulerType, - default_data_collator, - get_scheduler, -) -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/question-answering/requirements.txt") - -logger = get_logger(__name__) -# You should update this to your particular problem to have better documentation of `model_type` -MODEL_CONFIG_CLASSES = list(MODEL_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -def save_prefixed_metrics(results, output_dir, file_name: str = "all_results.json", metric_key_prefix: str = "eval"): - """ - Save results while prefixing metric names. - - Args: - results: (:obj:`dict`): - A dictionary of results. - output_dir: (:obj:`str`): - An output directory. - file_name: (:obj:`str`, `optional`, defaults to :obj:`all_results.json`): - An output file name. - metric_key_prefix: (:obj:`str`, `optional`, defaults to :obj:`eval`): - A metric name prefix. - """ - # Prefix all keys with metric_key_prefix + '_' - for key in list(results.keys()): - if not key.startswith(f"{metric_key_prefix}_"): - results[f"{metric_key_prefix}_{key}"] = results.pop(key) - - with open(os.path.join(output_dir, file_name), "w", encoding="utf-8") as f: - json.dump(results, f, indent=4) - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a Question Answering task") - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv or a json file containing the training data." - ) - parser.add_argument( - "--preprocessing_num_workers", type=int, default=1, help="A csv or a json file containing the training data." - ) - parser.add_argument("--do_predict", action="store_true", help="To do prediction on the question answering model") - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv or a json file containing the validation data." - ) - parser.add_argument( - "--test_file", type=str, default=None, help="A csv or a json file containing the Prediction data." - ) - parser.add_argument( - "--max_seq_length", - type=int, - default=384, - help=( - "The maximum total input sequence length after tokenization. Sequences longer than this will be truncated," - " sequences shorter will be padded if `--pad_to_max_length` is passed." - ), - ) - parser.add_argument( - "--pad_to_max_length", - action="store_true", - help="If passed, pad all samples to `max_seq_length`. Otherwise, dynamic padding is used.", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=False, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--tokenizer_name", - type=str, - default=None, - help="Pretrained tokenizer name or path if not the same as model_name", - ) - parser.add_argument( - "--use_slow_tokenizer", - action="store_true", - help="If passed, will use a slow tokenizer (not backed by the Hugging Face Tokenizers library).", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument( - "--doc_stride", - type=int, - default=128, - help="When splitting up a long document into chunks how much stride to take between chunks.", - ) - parser.add_argument( - "--n_best_size", - type=int, - default=20, - help="The total number of n-best predictions to generate when looking for an answer.", - ) - parser.add_argument( - "--null_score_diff_threshold", - type=float, - default=0.0, - help=( - "The threshold used to select the null answer: if the best answer has a score that is less than " - "the score of the null answer minus this threshold, the null answer is selected for this example. " - "Only useful when `version_2_with_negative=True`." - ), - ) - parser.add_argument( - "--version_2_with_negative", - action="store_true", - help="If true, some of the examples do not have an answer.", - ) - parser.add_argument( - "--max_answer_length", - type=int, - default=30, - help=( - "The maximum length of an answer that can be generated. This is needed because the start " - "and end predictions are not conditioned on one another." - ), - ) - parser.add_argument( - "--max_train_samples", - type=int, - default=None, - help=( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ), - ) - parser.add_argument( - "--max_eval_samples", - type=int, - default=None, - help=( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ), - ) - parser.add_argument( - "--overwrite_cache", action="store_true", help="Overwrite the cached training and evaluation sets" - ) - parser.add_argument( - "--max_predict_samples", - type=int, - default=None, - help="For debugging purposes or quicker training, truncate the number of prediction examples to this", - ) - parser.add_argument( - "--model_type", - type=str, - default=None, - help="Model type to use if training from scratch.", - choices=MODEL_TYPES, - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - if ( - args.dataset_name is None - and args.train_file is None - and args.validation_file is None - and args.test_file is None - ): - raise ValueError("Need either a dataset name or a training/validation/test file.") - else: - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - if args.test_file is not None: - extension = args.test_file.split(".")[-1] - assert extension in ["csv", "json"], "`test_file` should be a csv or a json file." - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - else: - data_files = {} - if args.train_file is not None: - data_files["train"] = args.train_file - extension = args.train_file.split(".")[-1] - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.validation_file.split(".")[-1] - if args.test_file is not None: - data_files["test"] = args.test_file - extension = args.test_file.split(".")[-1] - raw_datasets = load_dataset(extension, data_files=data_files, field="data") - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - - if args.config_name: - config = AutoConfig.from_pretrained(args.config_name, trust_remote_code=args.trust_remote_code) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained(args.model_name_or_path, trust_remote_code=args.trust_remote_code) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - - if args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained( - args.tokenizer_name, use_fast=True, trust_remote_code=args.trust_remote_code - ) - elif args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained( - args.model_name_or_path, use_fast=True, trust_remote_code=args.trust_remote_code - ) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if args.model_name_or_path: - model = AutoModelForQuestionAnswering.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForQuestionAnswering.from_config(config, trust_remote_code=args.trust_remote_code) - - # Preprocessing the datasets. - # Preprocessing is slightly different for training and evaluation. - - column_names = raw_datasets["train"].column_names - - question_column_name = "question" if "question" in column_names else column_names[0] - context_column_name = "context" if "context" in column_names else column_names[1] - answer_column_name = "answers" if "answers" in column_names else column_names[2] - - # Padding side determines if we do (question|context) or (context|question). - pad_on_right = tokenizer.padding_side == "right" - - if args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - - max_seq_length = min(args.max_seq_length, tokenizer.model_max_length) - - # Training preprocessing - def prepare_train_features(examples): - # Some of the questions have lots of whitespace on the left, which is not useful and will make the - # truncation of the context fail (the tokenized question will take a lots of space). So we remove that - # left whitespace - examples[question_column_name] = [q.lstrip() for q in examples[question_column_name]] - - # Tokenize our examples with truncation and maybe padding, but keep the overflows using a stride. This results - # in one example possible giving several features when a context is long, each of those features having a - # context that overlaps a bit the context of the previous feature. - tokenized_examples = tokenizer( - examples[question_column_name if pad_on_right else context_column_name], - examples[context_column_name if pad_on_right else question_column_name], - truncation="only_second" if pad_on_right else "only_first", - max_length=max_seq_length, - stride=args.doc_stride, - return_overflowing_tokens=True, - return_offsets_mapping=True, - padding="max_length" if args.pad_to_max_length else False, - ) - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") - # The offset mappings will give us a map from token to character position in the original context. This will - # help us compute the start_positions and end_positions. - offset_mapping = tokenized_examples.pop("offset_mapping") - - # Let's label those examples! - tokenized_examples["start_positions"] = [] - tokenized_examples["end_positions"] = [] - - for i, offsets in enumerate(offset_mapping): - # We will label impossible answers with the index of the CLS token. - input_ids = tokenized_examples["input_ids"][i] - if tokenizer.cls_token_id in input_ids: - cls_index = input_ids.index(tokenizer.cls_token_id) - elif tokenizer.bos_token_id in input_ids: - cls_index = input_ids.index(tokenizer.bos_token_id) - else: - cls_index = 0 - - # Grab the sequence corresponding to that example (to know what is the context and what is the question). - sequence_ids = tokenized_examples.sequence_ids(i) - - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - answers = examples[answer_column_name][sample_index] - # If no answers are given, set the cls_index as answer. - if len(answers["answer_start"]) == 0: - tokenized_examples["start_positions"].append(cls_index) - tokenized_examples["end_positions"].append(cls_index) - else: - # Start/end character index of the answer in the text. - start_char = answers["answer_start"][0] - end_char = start_char + len(answers["text"][0]) - - # Start token index of the current span in the text. - token_start_index = 0 - while sequence_ids[token_start_index] != (1 if pad_on_right else 0): - token_start_index += 1 - - # End token index of the current span in the text. - token_end_index = len(input_ids) - 1 - while sequence_ids[token_end_index] != (1 if pad_on_right else 0): - token_end_index -= 1 - - # Detect if the answer is out of the span (in which case this feature is labeled with the CLS index). - if not (offsets[token_start_index][0] <= start_char and offsets[token_end_index][1] >= end_char): - tokenized_examples["start_positions"].append(cls_index) - tokenized_examples["end_positions"].append(cls_index) - else: - # Otherwise move the token_start_index and token_end_index to the two ends of the answer. - # Note: we could go after the last offset if the answer is the last word (edge case). - while token_start_index < len(offsets) and offsets[token_start_index][0] <= start_char: - token_start_index += 1 - tokenized_examples["start_positions"].append(token_start_index - 1) - while offsets[token_end_index][1] >= end_char: - token_end_index -= 1 - tokenized_examples["end_positions"].append(token_end_index + 1) - - return tokenized_examples - - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if args.max_train_samples is not None: - # We will select sample from whole data if argument is specified - train_dataset = train_dataset.select(range(args.max_train_samples)) - - # Create train feature from dataset - with accelerator.main_process_first(): - train_dataset = train_dataset.map( - prepare_train_features, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - if args.max_train_samples is not None: - # Number of samples might increase during Feature Creation, We select only specified max samples - train_dataset = train_dataset.select(range(args.max_train_samples)) - - # Validation preprocessing - def prepare_validation_features(examples): - # Some of the questions have lots of whitespace on the left, which is not useful and will make the - # truncation of the context fail (the tokenized question will take a lots of space). So we remove that - # left whitespace - examples[question_column_name] = [q.lstrip() for q in examples[question_column_name]] - - # Tokenize our examples with truncation and maybe padding, but keep the overflows using a stride. This results - # in one example possible giving several features when a context is long, each of those features having a - # context that overlaps a bit the context of the previous feature. - tokenized_examples = tokenizer( - examples[question_column_name if pad_on_right else context_column_name], - examples[context_column_name if pad_on_right else question_column_name], - truncation="only_second" if pad_on_right else "only_first", - max_length=max_seq_length, - stride=args.doc_stride, - return_overflowing_tokens=True, - return_offsets_mapping=True, - padding="max_length" if args.pad_to_max_length else False, - ) - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping") - - # For evaluation, we will need to convert our predictions to substrings of the context, so we keep the - # corresponding example_id and we will store the offset mappings. - tokenized_examples["example_id"] = [] - - for i in range(len(tokenized_examples["input_ids"])): - # Grab the sequence corresponding to that example (to know what is the context and what is the question). - sequence_ids = tokenized_examples.sequence_ids(i) - context_index = 1 if pad_on_right else 0 - - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - tokenized_examples["example_id"].append(examples["id"][sample_index]) - - # Set to None the offset_mapping that are not part of the context so it's easy to determine if a token - # position is part of the context or not. - tokenized_examples["offset_mapping"][i] = [ - (o if sequence_ids[k] == context_index else None) - for k, o in enumerate(tokenized_examples["offset_mapping"][i]) - ] - - return tokenized_examples - - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_examples = raw_datasets["validation"] - if args.max_eval_samples is not None: - # We will select sample from whole data - eval_examples = eval_examples.select(range(args.max_eval_samples)) - # Validation Feature Creation - with accelerator.main_process_first(): - eval_dataset = eval_examples.map( - prepare_validation_features, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - - if args.max_eval_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - eval_dataset = eval_dataset.select(range(args.max_eval_samples)) - - if args.do_predict: - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_examples = raw_datasets["test"] - if args.max_predict_samples is not None: - # We will select sample from whole data - predict_examples = predict_examples.select(range(args.max_predict_samples)) - # Predict Feature Creation - with accelerator.main_process_first(): - predict_dataset = predict_examples.map( - prepare_validation_features, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - if args.max_predict_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - predict_dataset = predict_dataset.select(range(args.max_predict_samples)) - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # DataLoaders creation: - if args.pad_to_max_length: - # If padding was already done ot max length, we use the default data collator that will just convert everything - # to tensors. - data_collator = default_data_collator - else: - # Otherwise, `DataCollatorWithPadding` will apply dynamic padding for us (by padding to the maximum length of - # the samples passed). When using mixed precision, we add `pad_to_multiple_of=8` to pad all tensors to multiple - # of 8s, which will enable the use of Tensor Cores on NVIDIA hardware with compute capability >= 7.5 (Volta). - # For fp8, we pad to multiple of 16. - if accelerator.mixed_precision == "fp8": - pad_to_multiple_of = 16 - elif accelerator.mixed_precision != "no": - pad_to_multiple_of = 8 - else: - pad_to_multiple_of = None - data_collator = DataCollatorWithPadding(tokenizer, pad_to_multiple_of=pad_to_multiple_of) - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=data_collator, batch_size=args.per_device_train_batch_size - ) - - eval_dataset_for_model = eval_dataset.remove_columns(["example_id", "offset_mapping"]) - eval_dataloader = DataLoader( - eval_dataset_for_model, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size - ) - - if args.do_predict: - predict_dataset_for_model = predict_dataset.remove_columns(["example_id", "offset_mapping"]) - predict_dataloader = DataLoader( - predict_dataset_for_model, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size - ) - - # Post-processing: - def post_processing_function(examples, features, predictions, stage="eval"): - # Post-processing: we match the start logits and end logits to answers in the original context. - predictions = postprocess_qa_predictions( - examples=examples, - features=features, - predictions=predictions, - version_2_with_negative=args.version_2_with_negative, - n_best_size=args.n_best_size, - max_answer_length=args.max_answer_length, - null_score_diff_threshold=args.null_score_diff_threshold, - output_dir=args.output_dir, - prefix=stage, - ) - # Format the result to the format the metric expects. - if args.version_2_with_negative: - formatted_predictions = [ - {"id": k, "prediction_text": v, "no_answer_probability": 0.0} for k, v in predictions.items() - ] - else: - formatted_predictions = [{"id": k, "prediction_text": v} for k, v in predictions.items()] - - references = [{"id": ex["id"], "answers": ex[answer_column_name]} for ex in examples] - return EvalPrediction(predictions=formatted_predictions, label_ids=references) - - metric = evaluate.load("squad_v2" if args.version_2_with_negative else "squad") - - # Create and fill numpy array of size len_of_validation_data * max_length_of_output_tensor - def create_and_fill_np_array(start_or_end_logits, dataset, max_len): - """ - Create and fill numpy array of size len_of_validation_data * max_length_of_output_tensor - - Args: - start_or_end_logits(:obj:`tensor`): - This is the output predictions of the model. We can only enter either start or end logits. - eval_dataset: Evaluation dataset - max_len(:obj:`int`): - The maximum length of the output tensor. ( See the model.eval() part for more details ) - """ - - step = 0 - # create a numpy array and fill it with -100. - logits_concat = np.full((len(dataset), max_len), -100, dtype=np.float64) - # Now since we have create an array now we will populate it with the outputs gathered using accelerator.gather_for_metrics - for i, output_logit in enumerate(start_or_end_logits): # populate columns - # We have to fill it such that we have to take the whole tensor and replace it on the newly created array - # And after every iteration we have to change the step - - batch_size = output_logit.shape[0] - cols = output_logit.shape[1] - - if step + batch_size < len(dataset): - logits_concat[step : step + batch_size, :cols] = output_logit - else: - logits_concat[step:, :cols] = output_logit[: len(dataset) - step] - - step += batch_size - - return logits_concat - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("qa_no_trainer", experiment_config) - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if completed_steps >= args.max_train_steps: - break - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - # Evaluation - logger.info("***** Running Evaluation *****") - logger.info(f" Num examples = {len(eval_dataset)}") - logger.info(f" Batch size = {args.per_device_eval_batch_size}") - - all_start_logits = [] - all_end_logits = [] - - model.eval() - - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - start_logits = outputs.start_logits - end_logits = outputs.end_logits - - if not args.pad_to_max_length: # necessary to pad predictions and labels for being gathered - start_logits = accelerator.pad_across_processes(start_logits, dim=1, pad_index=-100) - end_logits = accelerator.pad_across_processes(end_logits, dim=1, pad_index=-100) - - all_start_logits.append(accelerator.gather_for_metrics(start_logits).cpu().numpy()) - all_end_logits.append(accelerator.gather_for_metrics(end_logits).cpu().numpy()) - - max_len = max(x.shape[1] for x in all_start_logits) # Get the max_length of the tensor - - # concatenate the numpy array - start_logits_concat = create_and_fill_np_array(all_start_logits, eval_dataset, max_len) - end_logits_concat = create_and_fill_np_array(all_end_logits, eval_dataset, max_len) - - # delete the list of numpy arrays - del all_start_logits - del all_end_logits - - outputs_numpy = (start_logits_concat, end_logits_concat) - prediction = post_processing_function(eval_examples, eval_dataset, outputs_numpy) - eval_metric = metric.compute(predictions=prediction.predictions, references=prediction.label_ids) - logger.info(f"Evaluation metrics: {eval_metric}") - - # Prediction - if args.do_predict: - logger.info("***** Running Prediction *****") - logger.info(f" Num examples = {len(predict_dataset)}") - logger.info(f" Batch size = {args.per_device_eval_batch_size}") - - all_start_logits = [] - all_end_logits = [] - - model.eval() - - for step, batch in enumerate(predict_dataloader): - with torch.no_grad(): - outputs = model(**batch) - start_logits = outputs.start_logits - end_logits = outputs.end_logits - - if not args.pad_to_max_length: # necessary to pad predictions and labels for being gathered - start_logits = accelerator.pad_across_processes(start_logits, dim=1, pad_index=-100) - end_logits = accelerator.pad_across_processes(end_logits, dim=1, pad_index=-100) - - all_start_logits.append(accelerator.gather_for_metrics(start_logits).cpu().numpy()) - all_end_logits.append(accelerator.gather_for_metrics(end_logits).cpu().numpy()) - - max_len = max(x.shape[1] for x in all_start_logits) # Get the max_length of the tensor - # concatenate the numpy array - start_logits_concat = create_and_fill_np_array(all_start_logits, predict_dataset, max_len) - end_logits_concat = create_and_fill_np_array(all_end_logits, predict_dataset, max_len) - - # delete the list of numpy arrays - del all_start_logits - del all_end_logits - - outputs_numpy = (start_logits_concat, end_logits_concat) - prediction = post_processing_function(predict_examples, predict_dataset, outputs_numpy) - predict_metric = metric.compute(predictions=prediction.predictions, references=prediction.label_ids) - logger.info(f"Predict metrics: {predict_metric}") - - if args.with_tracking: - log = { - "squad_v2" if args.version_2_with_negative else "squad": eval_metric, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - } - if args.do_predict: - log["squad_v2_predict" if args.version_2_with_negative else "squad_predict"] = predict_metric - - accelerator.log(log, step=completed_steps) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - logger.info(json.dumps(eval_metric, indent=4)) - save_prefixed_metrics(eval_metric, args.output_dir) - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/question-answering/run_seq2seq_qa.py b/examples/pytorch/question-answering/run_seq2seq_qa.py deleted file mode 100644 index f220e8eaa2dc..000000000000 --- a/examples/pytorch/question-answering/run_seq2seq_qa.py +++ /dev/null @@ -1,722 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Fine-tuning the library's seq2seq models for question answering using the 🤗 Seq2SeqTrainer. -""" -# You can also adapt this script on your own question answering task. Pointers for this are left as comments. - -import logging -import os -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -import numpy as np -from datasets import load_dataset -from trainer_seq2seq_qa import QuestionAnsweringSeq2SeqTrainer - -import transformers -from transformers import ( - AutoConfig, - AutoModelForSeq2SeqLM, - AutoTokenizer, - DataCollatorForSeq2Seq, - HfArgumentParser, - Seq2SeqTrainingArguments, - set_seed, -) -from transformers.trainer_utils import EvalLoopOutput, EvalPrediction -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/question-answering/requirements.txt") - -logger = logging.getLogger(__name__) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Path to directory to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - context_column: str | None = field( - default="context", - metadata={"help": "The name of the column in the datasets containing the contexts (for question answering)."}, - ) - question_column: str | None = field( - default="question", - metadata={"help": "The name of the column in the datasets containing the questions (for question answering)."}, - ) - answer_column: str | None = field( - default="answers", - metadata={"help": "The name of the column in the datasets containing the answers (for question answering)."}, - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a text file)."}) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."}, - ) - test_file: str | None = field( - default=None, - metadata={"help": "An optional input test data file to evaluate the perplexity on (a text file)."}, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_seq_length: int = field( - default=384, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - max_answer_length: int = field( - default=30, - metadata={ - "help": ( - "The maximum length of an answer that can be generated. This is needed because the start " - "and end predictions are not conditioned on one another." - ) - }, - ) - val_max_answer_length: int | None = field( - default=None, - metadata={ - "help": ( - "The maximum total sequence length for validation target text after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded. Will default to `max_answer_length`. " - "This argument is also used to override the ``max_length`` param of ``model.generate``, which is used " - "during ``evaluate`` and ``predict``." - ) - }, - ) - pad_to_max_length: bool = field( - default=True, - metadata={ - "help": ( - "Whether to pad all samples to `max_seq_length`. If False, will pad the samples dynamically when" - " batching to the maximum length in the batch (which can be faster on GPU but will be slower on TPU)." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - version_2_with_negative: bool = field( - default=False, metadata={"help": "If true, some of the examples do not have an answer."} - ) - null_score_diff_threshold: float = field( - default=0.0, - metadata={ - "help": ( - "The threshold used to select the null answer: if the best answer has a score that is less than " - "the score of the null answer minus this threshold, the null answer is selected for this example. " - "Only useful when `version_2_with_negative=True`." - ) - }, - ) - doc_stride: int = field( - default=128, - metadata={"help": "When splitting up a long document into chunks, how much stride to take between chunks."}, - ) - n_best_size: int = field( - default=20, - metadata={"help": "The total number of n-best predictions to generate when looking for an answer."}, - ) - num_beams: int | None = field( - default=None, - metadata={ - "help": ( - "Number of beams to use for evaluation. This argument will be passed to ``model.generate``, " - "which is used during ``evaluate`` and ``predict``." - ) - }, - ) - ignore_pad_token_for_loss: bool = field( - default=True, - metadata={ - "help": "Whether to ignore the tokens corresponding to padded labels in the loss computation or not." - }, - ) - - def __post_init__(self): - if ( - self.dataset_name is None - and self.train_file is None - and self.validation_file is None - and self.test_file is None - ): - raise ValueError("Need either a dataset name or a training/validation file/test_file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - if self.test_file is not None: - extension = self.test_file.split(".")[-1] - assert extension in ["csv", "json"], "`test_file` should be a csv or a json file." - if self.val_max_answer_length is None: - self.val_max_answer_length = self.max_answer_length - - -question_answering_column_name_mapping = { - "squad_v2": ("question", "context", "answer"), -} - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, Seq2SeqTrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - if data_args.test_file is not None: - data_files["test"] = data_args.test_file - extension = data_args.test_file.split(".")[-1] - raw_datasets = load_dataset( - extension, - data_files=data_files, - field="data", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForSeq2SeqLM.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - if model.config.decoder_start_token_id is None: - raise ValueError("Make sure that `config.decoder_start_token_id` is correctly defined") - - # Preprocessing the datasets. - # We need to generate and tokenize inputs and targets. - if training_args.do_train: - column_names = raw_datasets["train"].column_names - elif training_args.do_eval: - column_names = raw_datasets["validation"].column_names - elif training_args.do_predict: - column_names = raw_datasets["test"].column_names - else: - logger.info("There is nothing to do. Please pass `do_train`, `do_eval` and/or `do_predict`.") - return - - # Get the column names for input/target. - dataset_columns = question_answering_column_name_mapping.get(data_args.dataset_name) - if data_args.question_column is None: - question_column = dataset_columns[0] if dataset_columns is not None else column_names[0] - else: - question_column = data_args.question_column - if question_column not in column_names: - raise ValueError( - f"--question_column' value '{data_args.question_column}' needs to be one of: {', '.join(column_names)}" - ) - if data_args.context_column is None: - context_column = dataset_columns[1] if dataset_columns is not None else column_names[1] - else: - context_column = data_args.context_column - if context_column not in column_names: - raise ValueError( - f"--context_column' value '{data_args.context_column}' needs to be one of: {', '.join(column_names)}" - ) - if data_args.answer_column is None: - answer_column = dataset_columns[2] if dataset_columns is not None else column_names[2] - else: - answer_column = data_args.answer_column - if answer_column not in column_names: - raise ValueError( - f"--answer_column' value '{data_args.answer_column}' needs to be one of: {', '.join(column_names)}" - ) - - # Temporarily set max_answer_length for training. - max_answer_length = data_args.max_answer_length - padding = "max_length" if data_args.pad_to_max_length else False - - if training_args.label_smoothing_factor > 0 and not hasattr(model, "prepare_decoder_input_ids_from_labels"): - logger.warning( - "label_smoothing is enabled but the `prepare_decoder_input_ids_from_labels` method is not defined for " - f"`{model.__class__.__name__}`. This will lead to loss being calculated twice and will take up more memory" - ) - - if data_args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({data_args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) - - def preprocess_squad_batch( - examples, - question_column: str, - context_column: str, - answer_column: str, - ) -> tuple[list[str], list[str]]: - questions = examples[question_column] - contexts = examples[context_column] - answers = examples[answer_column] - - def generate_input(_question, _context): - return " ".join(["question:", _question.lstrip(), "context:", _context.lstrip()]) - - inputs = [generate_input(question, context) for question, context in zip(questions, contexts)] - targets = [answer["text"][0] if len(answer["text"]) > 0 else "" for answer in answers] - return inputs, targets - - def preprocess_function(examples): - inputs, targets = preprocess_squad_batch(examples, question_column, context_column, answer_column) - - model_inputs = tokenizer(inputs, max_length=max_seq_length, padding=padding, truncation=True) - # Tokenize targets with text_target=... - labels = tokenizer(text_target=targets, max_length=max_answer_length, padding=padding, truncation=True) - - # If we are padding here, replace all tokenizer.pad_token_id in the labels by -100 when we want to ignore - # padding in the loss. - if padding == "max_length" and data_args.ignore_pad_token_for_loss: - labels["input_ids"] = [ - [(l if l != tokenizer.pad_token_id else -100) for l in label] for label in labels["input_ids"] - ] - - model_inputs["labels"] = labels["input_ids"] - return model_inputs - - # Validation preprocessing - def preprocess_validation_function(examples): - inputs, targets = preprocess_squad_batch(examples, question_column, context_column, answer_column) - - model_inputs = tokenizer( - inputs, - max_length=max_seq_length, - padding=padding, - truncation=True, - return_overflowing_tokens=True, - return_offsets_mapping=True, - ) - # Tokenize targets with the `text_target` keyword argument - labels = tokenizer(text_target=targets, max_length=max_answer_length, padding=padding, truncation=True) - - # If we are padding here, replace all tokenizer.pad_token_id in the labels by -100 when we want to ignore - # padding in the loss. - if padding == "max_length" and data_args.ignore_pad_token_for_loss: - labels["input_ids"] = [ - [(l if l != tokenizer.pad_token_id else -100) for l in label] for label in labels["input_ids"] - ] - - # Since one example might give us several features if it has a long context, we need a map from a feature to - # its corresponding example. This key gives us just that. - sample_mapping = model_inputs.pop("overflow_to_sample_mapping") - - # For evaluation, we will need to convert our predictions to substrings of the context, so we keep the - # corresponding example_id and we will store the offset mappings. - model_inputs["example_id"] = [] - # Augment the overflowing tokens to the labels - labels_out = [] - - for i in range(len(model_inputs["input_ids"])): - # One example can give several spans, this is the index of the example containing this span of text. - sample_index = sample_mapping[i] - model_inputs["example_id"].append(examples["id"][sample_index]) - labels_out.append(labels["input_ids"][sample_index]) - - model_inputs["labels"] = labels_out - return model_inputs - - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if data_args.max_train_samples is not None: - # We will select sample from whole data if argument is specified - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - # Create train feature from dataset - with training_args.main_process_first(desc="train dataset map pre-processing"): - train_dataset = train_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - if data_args.max_train_samples is not None: - # Number of samples might increase during Feature Creation, We select only specified max samples - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - if training_args.do_eval: - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_examples = raw_datasets["validation"] - if data_args.max_eval_samples is not None: - # We will select sample from whole data - max_eval_samples = min(len(eval_examples), data_args.max_eval_samples) - eval_examples = eval_examples.select(range(max_eval_samples)) - # Validation Feature Creation - with training_args.main_process_first(desc="validation dataset map pre-processing"): - eval_dataset = eval_examples.map( - preprocess_validation_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - if data_args.max_eval_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - if training_args.do_predict: - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_examples = raw_datasets["test"] - if data_args.max_predict_samples is not None: - # We will select sample from whole data - predict_examples = predict_examples.select(range(data_args.max_predict_samples)) - # Predict Feature Creation - with training_args.main_process_first(desc="prediction dataset map pre-processing"): - predict_dataset = predict_examples.map( - preprocess_validation_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - if data_args.max_predict_samples is not None: - # During Feature creation dataset samples might increase, we will select required samples again - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - - # Data collator - label_pad_token_id = -100 if data_args.ignore_pad_token_for_loss else tokenizer.pad_token_id - data_collator = DataCollatorForSeq2Seq( - tokenizer, - model=model, - label_pad_token_id=label_pad_token_id, - pad_to_multiple_of=8 if training_args.fp16 else None, - ) - - metric = evaluate.load( - "squad_v2" if data_args.version_2_with_negative else "squad", cache_dir=model_args.cache_dir - ) - - def compute_metrics(p: EvalPrediction): - return metric.compute(predictions=p.predictions, references=p.label_ids) - - # Post-processing: - def post_processing_function( - examples: datasets.Dataset, features: datasets.Dataset, outputs: EvalLoopOutput, stage="eval" - ): - # Decode the predicted tokens. - preds = outputs.predictions - if isinstance(preds, tuple): - preds = preds[0] - # Replace -100s used for padding as we can't decode them - preds = np.where(preds != -100, preds, tokenizer.pad_token_id) - decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True) - - # Build a map example to its corresponding features. - example_id_to_index = {k: i for i, k in enumerate(examples["id"])} - feature_per_example = {example_id_to_index[feature["example_id"]]: i for i, feature in enumerate(features)} - predictions = {} - # Let's loop over all the examples! - for example_index, example in enumerate(examples): - # This is the index of the feature associated to the current example. - feature_index = feature_per_example[example_index] - predictions[example["id"]] = decoded_preds[feature_index] - - # Format the result to the format the metric expects. - if data_args.version_2_with_negative: - formatted_predictions = [ - {"id": k, "prediction_text": v, "no_answer_probability": 0.0} for k, v in predictions.items() - ] - else: - formatted_predictions = [{"id": k, "prediction_text": v} for k, v in predictions.items()] - - references = [{"id": ex["id"], "answers": ex[answer_column]} for ex in examples] - return EvalPrediction(predictions=formatted_predictions, label_ids=references) - - # Initialize our Trainer - trainer = QuestionAnsweringSeq2SeqTrainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - eval_examples=eval_examples if training_args.do_eval else None, - processing_class=tokenizer, - data_collator=data_collator, - compute_metrics=compute_metrics if training_args.predict_with_generate else None, - post_process_function=post_processing_function, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - results = {} - max_length = ( - training_args.generation_max_length - if training_args.generation_max_length is not None - else data_args.val_max_answer_length - ) - num_beams = data_args.num_beams if data_args.num_beams is not None else training_args.generation_num_beams - if training_args.do_eval: - logger.info("*** Evaluate ***") - metrics = trainer.evaluate(max_length=max_length, num_beams=num_beams, metric_key_prefix="eval") - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Prediction - if training_args.do_predict: - logger.info("*** Predict ***") - results = trainer.predict(predict_dataset, predict_examples) - metrics = results.metrics - - max_predict_samples = ( - data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset) - ) - metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset)) - - trainer.log_metrics("predict", metrics) - trainer.save_metrics("predict", metrics) - - if training_args.push_to_hub: - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "question-answering"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - trainer.push_to_hub(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/question-answering/trainer_qa.py b/examples/pytorch/question-answering/trainer_qa.py deleted file mode 100644 index de6a1d76734c..000000000000 --- a/examples/pytorch/question-answering/trainer_qa.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2020 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -A subclass of `Trainer` specific to Question-Answering tasks -""" - -import math -import time - -from transformers import Trainer, is_torch_xla_available -from transformers.trainer_utils import PredictionOutput, speed_metrics - - -if is_torch_xla_available(): - import torch_xla.core.xla_model as xm - import torch_xla.debug.metrics as met - - -class QuestionAnsweringTrainer(Trainer): - def __init__(self, *args, eval_examples=None, post_process_function=None, **kwargs): - super().__init__(*args, **kwargs) - self.eval_examples = eval_examples - self.post_process_function = post_process_function - - def evaluate(self, eval_dataset=None, eval_examples=None, ignore_keys=None, metric_key_prefix: str = "eval"): - eval_dataset = self.eval_dataset if eval_dataset is None else eval_dataset - eval_dataloader = self.get_eval_dataloader(eval_dataset) - eval_examples = self.eval_examples if eval_examples is None else eval_examples - - # Temporarily disable metric computation, we will do it in the loop here. - compute_metrics = self.compute_metrics - self.compute_metrics = None - start_time = time.time() - try: - output = self.evaluation_loop( - eval_dataloader, - description="Evaluation", - # No point gathering the predictions if there are no metrics, otherwise we defer to - # self.args.prediction_loss_only - prediction_loss_only=True if compute_metrics is None else None, - ignore_keys=ignore_keys, - metric_key_prefix=metric_key_prefix, - ) - finally: - self.compute_metrics = compute_metrics - total_batch_size = self.args.eval_batch_size * self.args.world_size - output.metrics.update( - speed_metrics( - metric_key_prefix, - start_time, - num_samples=output.num_samples, - num_steps=math.ceil(output.num_samples / total_batch_size), - ) - ) - if self.post_process_function is not None and self.compute_metrics is not None and self.args.should_save: - # Only the main node write the results by default - eval_preds = self.post_process_function(eval_examples, eval_dataset, output.predictions) - metrics = self.compute_metrics(eval_preds) - - # Prefix all keys with metric_key_prefix + '_' - for key in list(metrics.keys()): - if not key.startswith(f"{metric_key_prefix}_"): - metrics[f"{metric_key_prefix}_{key}"] = metrics.pop(key) - metrics.update(output.metrics) - else: - metrics = output.metrics - - if self.args.should_log: - # Only the main node log the results by default - self.log(metrics) - - if self.args.debug: - # tpu-comment: Logging debug metrics for PyTorch/XLA (compile, execute times, ops, etc.) - xm.master_print(met.metrics_report()) - - self.control = self.callback_handler.on_evaluate(self.args, self.state, self.control, metrics) - return metrics - - def predict(self, predict_dataset, predict_examples, ignore_keys=None, metric_key_prefix: str = "test"): - predict_dataloader = self.get_test_dataloader(predict_dataset) - - # Temporarily disable metric computation, we will do it in the loop here. - compute_metrics = self.compute_metrics - self.compute_metrics = None - start_time = time.time() - try: - output = self.evaluation_loop( - predict_dataloader, - description="Prediction", - # No point gathering the predictions if there are no metrics, otherwise we defer to - # self.args.prediction_loss_only - prediction_loss_only=True if compute_metrics is None else None, - ignore_keys=ignore_keys, - metric_key_prefix=metric_key_prefix, - ) - finally: - self.compute_metrics = compute_metrics - total_batch_size = self.args.eval_batch_size * self.args.world_size - output.metrics.update( - speed_metrics( - metric_key_prefix, - start_time, - num_samples=output.num_samples, - num_steps=math.ceil(output.num_samples / total_batch_size), - ) - ) - - if self.post_process_function is None or self.compute_metrics is None: - return output - - predictions = self.post_process_function(predict_examples, predict_dataset, output.predictions, "predict") - metrics = self.compute_metrics(predictions) - - # Prefix all keys with metric_key_prefix + '_' - for key in list(metrics.keys()): - if not key.startswith(f"{metric_key_prefix}_"): - metrics[f"{metric_key_prefix}_{key}"] = metrics.pop(key) - metrics.update(output.metrics) - return PredictionOutput(predictions=predictions.predictions, label_ids=predictions.label_ids, metrics=metrics) diff --git a/examples/pytorch/question-answering/trainer_seq2seq_qa.py b/examples/pytorch/question-answering/trainer_seq2seq_qa.py deleted file mode 100644 index 8de1fa009479..000000000000 --- a/examples/pytorch/question-answering/trainer_seq2seq_qa.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright 2021 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -A subclass of `Trainer` specific to Question-Answering tasks -""" - -import math -import time - -from torch.utils.data import Dataset - -from transformers import Seq2SeqTrainer, is_torch_xla_available -from transformers.trainer_utils import PredictionOutput, speed_metrics - - -if is_torch_xla_available(): - import torch_xla.core.xla_model as xm - import torch_xla.debug.metrics as met - - -class QuestionAnsweringSeq2SeqTrainer(Seq2SeqTrainer): - def __init__(self, *args, eval_examples=None, post_process_function=None, **kwargs): - super().__init__(*args, **kwargs) - self.eval_examples = eval_examples - self.post_process_function = post_process_function - - # def evaluate(self, eval_dataset=None, eval_examples=None, ignore_keys=None, metric_key_prefix: str = "eval"): - def evaluate( - self, - eval_dataset: Dataset | None = None, - eval_examples=None, - ignore_keys: list[str] | None = None, - metric_key_prefix: str = "eval", - **gen_kwargs, - ) -> dict[str, float]: - gen_kwargs = gen_kwargs.copy() - - # Use legacy argument setting if a) the option is not explicitly passed; and b) the argument is set in the - # training args - if gen_kwargs.get("max_length") is None and self.args.generation_max_length is not None: - gen_kwargs["max_length"] = self.args.generation_max_length - if gen_kwargs.get("num_beams") is None and self.args.generation_num_beams is not None: - gen_kwargs["num_beams"] = self.args.generation_num_beams - self._gen_kwargs = gen_kwargs - - eval_dataset = self.eval_dataset if eval_dataset is None else eval_dataset - eval_dataloader = self.get_eval_dataloader(eval_dataset) - eval_examples = self.eval_examples if eval_examples is None else eval_examples - - # Temporarily disable metric computation, we will do it in the loop here. - compute_metrics = self.compute_metrics - self.compute_metrics = None - start_time = time.time() - try: - output = self.evaluation_loop( - eval_dataloader, - description="Evaluation", - # No point gathering the predictions if there are no metrics, otherwise we defer to - # self.args.prediction_loss_only - prediction_loss_only=True if compute_metrics is None else None, - ignore_keys=ignore_keys, - metric_key_prefix=metric_key_prefix, - ) - finally: - self.compute_metrics = compute_metrics - total_batch_size = self.args.eval_batch_size * self.args.world_size - output.metrics.update( - speed_metrics( - metric_key_prefix, - start_time, - num_samples=output.num_samples, - num_steps=math.ceil(output.num_samples / total_batch_size), - ) - ) - - if self.post_process_function is not None and self.compute_metrics is not None and self.args.should_save: - # Only the main node write the results by default - eval_preds = self.post_process_function(eval_examples, eval_dataset, output) - metrics = self.compute_metrics(eval_preds) - - # Prefix all keys with metric_key_prefix + '_' - for key in list(metrics.keys()): - if not key.startswith(f"{metric_key_prefix}_"): - metrics[f"{metric_key_prefix}_{key}"] = metrics.pop(key) - - metrics.update(output.metrics) - else: - metrics = output.metrics - - if self.args.should_log: - # Only the main node log the results by default - self.log(metrics) - - if self.args.debug: - # tpu-comment: Logging debug metrics for PyTorch/XLA (compile, execute times, ops, etc.) - xm.master_print(met.metrics_report()) - - self.control = self.callback_handler.on_evaluate(self.args, self.state, self.control, metrics) - return metrics - - def predict( - self, predict_dataset, predict_examples, ignore_keys=None, metric_key_prefix: str = "test", **gen_kwargs - ): - self._gen_kwargs = gen_kwargs.copy() - - predict_dataloader = self.get_test_dataloader(predict_dataset) - - # Temporarily disable metric computation, we will do it in the loop here. - compute_metrics = self.compute_metrics - self.compute_metrics = None - start_time = time.time() - try: - output = self.evaluation_loop( - predict_dataloader, - description="Prediction", - # No point gathering the predictions if there are no metrics, otherwise we defer to - # self.args.prediction_loss_only - prediction_loss_only=True if compute_metrics is None else None, - ignore_keys=ignore_keys, - metric_key_prefix=metric_key_prefix, - ) - finally: - self.compute_metrics = compute_metrics - - total_batch_size = self.args.eval_batch_size * self.args.world_size - output.metrics.update( - speed_metrics( - metric_key_prefix, - start_time, - num_samples=output.num_samples, - num_steps=math.ceil(output.num_samples / total_batch_size), - ) - ) - if self.post_process_function is None or self.compute_metrics is None: - return output - - predictions = self.post_process_function(predict_examples, predict_dataset, output, "predict") - metrics = self.compute_metrics(predictions) - - # Prefix all keys with metric_key_prefix + '_' - for key in list(metrics.keys()): - if not key.startswith(f"{metric_key_prefix}_"): - metrics[f"{metric_key_prefix}_{key}"] = metrics.pop(key) - metrics.update(output.metrics) - return PredictionOutput(predictions=predictions.predictions, label_ids=predictions.label_ids, metrics=metrics) diff --git a/examples/pytorch/question-answering/utils_qa.py b/examples/pytorch/question-answering/utils_qa.py deleted file mode 100644 index 84a0b503da0c..000000000000 --- a/examples/pytorch/question-answering/utils_qa.py +++ /dev/null @@ -1,442 +0,0 @@ -# Copyright 2020 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -Post-processing utilities for question answering. -""" - -import collections -import json -import logging -import os - -import numpy as np -from tqdm.auto import tqdm - - -logger = logging.getLogger(__name__) - - -def postprocess_qa_predictions( - examples, - features, - predictions: tuple[np.ndarray, np.ndarray], - version_2_with_negative: bool = False, - n_best_size: int = 20, - max_answer_length: int = 30, - null_score_diff_threshold: float = 0.0, - output_dir: str | None = None, - prefix: str | None = None, - log_level: int | None = logging.WARNING, -): - """ - Post-processes the predictions of a question-answering model to convert them to answers that are substrings of the - original contexts. This is the base postprocessing functions for models that only return start and end logits. - - Args: - examples: The non-preprocessed dataset (see the main script for more information). - features: The processed dataset (see the main script for more information). - predictions (:obj:`tuple[np.ndarray, np.ndarray]`): - The predictions of the model: two arrays containing the start logits and the end logits respectively. Its - first dimension must match the number of elements of :obj:`features`. - version_2_with_negative (:obj:`bool`, `optional`, defaults to :obj:`False`): - Whether or not the underlying dataset contains examples with no answers. - n_best_size (:obj:`int`, `optional`, defaults to 20): - The total number of n-best predictions to generate when looking for an answer. - max_answer_length (:obj:`int`, `optional`, defaults to 30): - The maximum length of an answer that can be generated. This is needed because the start and end predictions - are not conditioned on one another. - null_score_diff_threshold (:obj:`float`, `optional`, defaults to 0): - The threshold used to select the null answer: if the best answer has a score that is less than the score of - the null answer minus this threshold, the null answer is selected for this example (note that the score of - the null answer for an example giving several features is the minimum of the scores for the null answer on - each feature: all features must be aligned on the fact they `want` to predict a null answer). - - Only useful when :obj:`version_2_with_negative` is :obj:`True`. - output_dir (:obj:`str`, `optional`): - If provided, the dictionaries of predictions, n_best predictions (with their scores and logits) and, if - :obj:`version_2_with_negative=True`, the dictionary of the scores differences between best and null - answers, are saved in `output_dir`. - prefix (:obj:`str`, `optional`): - If provided, the dictionaries mentioned above are saved with `prefix` added to their names. - log_level (:obj:`int`, `optional`, defaults to ``logging.WARNING``): - ``logging`` log level (e.g., ``logging.WARNING``) - """ - if len(predictions) != 2: - raise ValueError("`predictions` should be a tuple with two elements (start_logits, end_logits).") - all_start_logits, all_end_logits = predictions - - if len(predictions[0]) != len(features): - raise ValueError(f"Got {len(predictions[0])} predictions and {len(features)} features.") - - # Build a map example to its corresponding features. - example_id_to_index = {k: i for i, k in enumerate(examples["id"])} - features_per_example = collections.defaultdict(list) - for i, feature in enumerate(features): - features_per_example[example_id_to_index[feature["example_id"]]].append(i) - - # The dictionaries we have to fill. - all_predictions = collections.OrderedDict() - all_nbest_json = collections.OrderedDict() - if version_2_with_negative: - scores_diff_json = collections.OrderedDict() - - # Logging. - logger.setLevel(log_level) - logger.info(f"Post-processing {len(examples)} example predictions split into {len(features)} features.") - - # Let's loop over all the examples! - for example_index, example in enumerate(tqdm(examples)): - # Those are the indices of the features associated to the current example. - feature_indices = features_per_example[example_index] - - min_null_prediction = None - prelim_predictions = [] - - # Looping through all the features associated to the current example. - for feature_index in feature_indices: - # We grab the predictions of the model for this feature. - start_logits = all_start_logits[feature_index] - end_logits = all_end_logits[feature_index] - # This is what will allow us to map some the positions in our logits to span of texts in the original - # context. - offset_mapping = features[feature_index]["offset_mapping"] - # Optional `token_is_max_context`, if provided we will remove answers that do not have the maximum context - # available in the current feature. - token_is_max_context = features[feature_index].get("token_is_max_context", None) - - # Update minimum null prediction. - feature_null_score = start_logits[0] + end_logits[0] - if min_null_prediction is None or min_null_prediction["score"] > feature_null_score: - min_null_prediction = { - "offsets": (0, 0), - "score": feature_null_score, - "start_logit": start_logits[0], - "end_logit": end_logits[0], - } - - # Go through all possibilities for the `n_best_size` greater start and end logits. - start_indexes = np.argsort(start_logits)[-1 : -n_best_size - 1 : -1].tolist() - end_indexes = np.argsort(end_logits)[-1 : -n_best_size - 1 : -1].tolist() - for start_index in start_indexes: - for end_index in end_indexes: - # Don't consider out-of-scope answers, either because the indices are out of bounds or correspond - # to part of the input_ids that are not in the context. - if ( - start_index >= len(offset_mapping) - or end_index >= len(offset_mapping) - or offset_mapping[start_index] is None - or len(offset_mapping[start_index]) < 2 - or offset_mapping[end_index] is None - or len(offset_mapping[end_index]) < 2 - ): - continue - # Don't consider answers with a length that is either < 0 or > max_answer_length. - if end_index < start_index or end_index - start_index + 1 > max_answer_length: - continue - # Don't consider answer that don't have the maximum context available (if such information is - # provided). - if token_is_max_context is not None and not token_is_max_context.get(str(start_index), False): - continue - - prelim_predictions.append( - { - "offsets": (offset_mapping[start_index][0], offset_mapping[end_index][1]), - "score": start_logits[start_index] + end_logits[end_index], - "start_logit": start_logits[start_index], - "end_logit": end_logits[end_index], - } - ) - if version_2_with_negative and min_null_prediction is not None: - # Add the minimum null prediction - prelim_predictions.append(min_null_prediction) - null_score = min_null_prediction["score"] - - # Only keep the best `n_best_size` predictions. - predictions = sorted(prelim_predictions, key=lambda x: x["score"], reverse=True)[:n_best_size] - - # Add back the minimum null prediction if it was removed because of its low score. - if ( - version_2_with_negative - and min_null_prediction is not None - and not any(p["offsets"] == (0, 0) for p in predictions) - ): - predictions.append(min_null_prediction) - - # Use the offsets to gather the answer text in the original context. - context = example["context"] - for pred in predictions: - offsets = pred.pop("offsets") - pred["text"] = context[offsets[0] : offsets[1]] - - # In the very rare edge case we have not a single non-null prediction, we create a fake prediction to avoid - # failure. - if len(predictions) == 0 or (len(predictions) == 1 and predictions[0]["text"] == ""): - predictions.insert(0, {"text": "empty", "start_logit": 0.0, "end_logit": 0.0, "score": 0.0}) - - # Compute the softmax of all scores (we do it with numpy to stay independent from torch in this file, using - # the LogSumExp trick). - scores = np.array([pred.pop("score") for pred in predictions]) - exp_scores = np.exp(scores - np.max(scores)) - probs = exp_scores / exp_scores.sum() - - # Include the probabilities in our predictions. - for prob, pred in zip(probs, predictions): - pred["probability"] = prob - - # Pick the best prediction. If the null answer is not possible, this is easy. - if not version_2_with_negative: - all_predictions[example["id"]] = predictions[0]["text"] - else: - # Otherwise we first need to find the best non-empty prediction. - i = 0 - while predictions[i]["text"] == "": - i += 1 - best_non_null_pred = predictions[i] - - # Then we compare to the null prediction using the threshold. - score_diff = null_score - best_non_null_pred["start_logit"] - best_non_null_pred["end_logit"] - scores_diff_json[example["id"]] = float(score_diff) # To be JSON-serializable. - if score_diff > null_score_diff_threshold: - all_predictions[example["id"]] = "" - else: - all_predictions[example["id"]] = best_non_null_pred["text"] - - # Make `predictions` JSON-serializable by casting np.float back to float. - all_nbest_json[example["id"]] = [ - {k: (float(v) if isinstance(v, (np.float16, np.float32, np.float64)) else v) for k, v in pred.items()} - for pred in predictions - ] - - # If we have an output_dir, let's save all those dicts. - if output_dir is not None: - if not os.path.isdir(output_dir): - raise OSError(f"{output_dir} is not a directory.") - - prediction_file = os.path.join( - output_dir, "predictions.json" if prefix is None else f"{prefix}_predictions.json" - ) - nbest_file = os.path.join( - output_dir, "nbest_predictions.json" if prefix is None else f"{prefix}_nbest_predictions.json" - ) - if version_2_with_negative: - null_odds_file = os.path.join( - output_dir, "null_odds.json" if prefix is None else f"{prefix}_null_odds.json" - ) - - logger.info(f"Saving predictions to {prediction_file}.") - with open(prediction_file, "w", encoding="utf-8") as writer: - writer.write(json.dumps(all_predictions, indent=4) + "\n") - logger.info(f"Saving nbest_preds to {nbest_file}.") - with open(nbest_file, "w", encoding="utf-8") as writer: - writer.write(json.dumps(all_nbest_json, indent=4) + "\n") - if version_2_with_negative: - logger.info(f"Saving null_odds to {null_odds_file}.") - with open(null_odds_file, "w", encoding="utf-8") as writer: - writer.write(json.dumps(scores_diff_json, indent=4) + "\n") - - return all_predictions - - -def postprocess_qa_predictions_with_beam_search( - examples, - features, - predictions: tuple[np.ndarray, np.ndarray], - version_2_with_negative: bool = False, - n_best_size: int = 20, - max_answer_length: int = 30, - start_n_top: int = 5, - end_n_top: int = 5, - output_dir: str | None = None, - prefix: str | None = None, - log_level: int | None = logging.WARNING, -): - """ - Post-processes the predictions of a question-answering model with beam search to convert them to answers that are substrings of the - original contexts. This is the postprocessing functions for models that return start and end logits, indices, as well as - cls token predictions. - - Args: - examples: The non-preprocessed dataset (see the main script for more information). - features: The processed dataset (see the main script for more information). - predictions (:obj:`tuple[np.ndarray, np.ndarray]`): - The predictions of the model: two arrays containing the start logits and the end logits respectively. Its - first dimension must match the number of elements of :obj:`features`. - version_2_with_negative (:obj:`bool`, `optional`, defaults to :obj:`False`): - Whether or not the underlying dataset contains examples with no answers. - n_best_size (:obj:`int`, `optional`, defaults to 20): - The total number of n-best predictions to generate when looking for an answer. - max_answer_length (:obj:`int`, `optional`, defaults to 30): - The maximum length of an answer that can be generated. This is needed because the start and end predictions - are not conditioned on one another. - start_n_top (:obj:`int`, `optional`, defaults to 5): - The number of top start logits too keep when searching for the :obj:`n_best_size` predictions. - end_n_top (:obj:`int`, `optional`, defaults to 5): - The number of top end logits too keep when searching for the :obj:`n_best_size` predictions. - output_dir (:obj:`str`, `optional`): - If provided, the dictionaries of predictions, n_best predictions (with their scores and logits) and, if - :obj:`version_2_with_negative=True`, the dictionary of the scores differences between best and null - answers, are saved in `output_dir`. - prefix (:obj:`str`, `optional`): - If provided, the dictionaries mentioned above are saved with `prefix` added to their names. - log_level (:obj:`int`, `optional`, defaults to ``logging.WARNING``): - ``logging`` log level (e.g., ``logging.WARNING``) - """ - if len(predictions) != 5: - raise ValueError("`predictions` should be a tuple with five elements.") - start_top_log_probs, start_top_index, end_top_log_probs, end_top_index, cls_logits = predictions - - if len(predictions[0]) != len(features): - raise ValueError(f"Got {len(predictions[0])} predictions and {len(features)} features.") - - # Build a map example to its corresponding features. - example_id_to_index = {k: i for i, k in enumerate(examples["id"])} - features_per_example = collections.defaultdict(list) - for i, feature in enumerate(features): - features_per_example[example_id_to_index[feature["example_id"]]].append(i) - - # The dictionaries we have to fill. - all_predictions = collections.OrderedDict() - all_nbest_json = collections.OrderedDict() - scores_diff_json = collections.OrderedDict() if version_2_with_negative else None - - # Logging. - logger.setLevel(log_level) - logger.info(f"Post-processing {len(examples)} example predictions split into {len(features)} features.") - - # Let's loop over all the examples! - for example_index, example in enumerate(tqdm(examples)): - # Those are the indices of the features associated to the current example. - feature_indices = features_per_example[example_index] - - min_null_score = None - prelim_predictions = [] - - # Looping through all the features associated to the current example. - for feature_index in feature_indices: - # We grab the predictions of the model for this feature. - start_log_prob = start_top_log_probs[feature_index] - start_indexes = start_top_index[feature_index] - end_log_prob = end_top_log_probs[feature_index] - end_indexes = end_top_index[feature_index] - feature_null_score = cls_logits[feature_index] - # This is what will allow us to map some the positions in our logits to span of texts in the original - # context. - offset_mapping = features[feature_index]["offset_mapping"] - # Optional `token_is_max_context`, if provided we will remove answers that do not have the maximum context - # available in the current feature. - token_is_max_context = features[feature_index].get("token_is_max_context", None) - - # Update minimum null prediction - if min_null_score is None or feature_null_score < min_null_score: - min_null_score = feature_null_score - - # Go through all possibilities for the `n_start_top`/`n_end_top` greater start and end logits. - for i in range(start_n_top): - for j in range(end_n_top): - start_index = int(start_indexes[i]) - j_index = i * end_n_top + j - end_index = int(end_indexes[j_index]) - # Don't consider out-of-scope answers (last part of the test should be unnecessary because of the - # p_mask but let's not take any risk) - if ( - start_index >= len(offset_mapping) - or end_index >= len(offset_mapping) - or offset_mapping[start_index] is None - or len(offset_mapping[start_index]) < 2 - or offset_mapping[end_index] is None - or len(offset_mapping[end_index]) < 2 - ): - continue - - # Don't consider answers with a length negative or > max_answer_length. - if end_index < start_index or end_index - start_index + 1 > max_answer_length: - continue - # Don't consider answer that don't have the maximum context available (if such information is - # provided). - if token_is_max_context is not None and not token_is_max_context.get(str(start_index), False): - continue - prelim_predictions.append( - { - "offsets": (offset_mapping[start_index][0], offset_mapping[end_index][1]), - "score": start_log_prob[i] + end_log_prob[j_index], - "start_log_prob": start_log_prob[i], - "end_log_prob": end_log_prob[j_index], - } - ) - - # Only keep the best `n_best_size` predictions. - predictions = sorted(prelim_predictions, key=lambda x: x["score"], reverse=True)[:n_best_size] - - # Use the offsets to gather the answer text in the original context. - context = example["context"] - for pred in predictions: - offsets = pred.pop("offsets") - pred["text"] = context[offsets[0] : offsets[1]] - - # In the very rare edge case we have not a single non-null prediction, we create a fake prediction to avoid - # failure. - if len(predictions) == 0: - # Without predictions min_null_score is going to be None and None will cause an exception later - min_null_score = -2e-6 - predictions.insert(0, {"text": "", "start_logit": -1e-6, "end_logit": -1e-6, "score": min_null_score}) - - # Compute the softmax of all scores (we do it with numpy to stay independent from torch in this file, using - # the LogSumExp trick). - scores = np.array([pred.pop("score") for pred in predictions]) - exp_scores = np.exp(scores - np.max(scores)) - probs = exp_scores / exp_scores.sum() - - # Include the probabilities in our predictions. - for prob, pred in zip(probs, predictions): - pred["probability"] = prob - - # Pick the best prediction and set the probability for the null answer. - all_predictions[example["id"]] = predictions[0]["text"] - if version_2_with_negative: - scores_diff_json[example["id"]] = float(min_null_score) - - # Make `predictions` JSON-serializable by casting np.float back to float. - all_nbest_json[example["id"]] = [ - {k: (float(v) if isinstance(v, (np.float16, np.float32, np.float64)) else v) for k, v in pred.items()} - for pred in predictions - ] - - # If we have an output_dir, let's save all those dicts. - if output_dir is not None: - if not os.path.isdir(output_dir): - raise OSError(f"{output_dir} is not a directory.") - - prediction_file = os.path.join( - output_dir, "predictions.json" if prefix is None else f"{prefix}_predictions.json" - ) - nbest_file = os.path.join( - output_dir, "nbest_predictions.json" if prefix is None else f"{prefix}_nbest_predictions.json" - ) - if version_2_with_negative: - null_odds_file = os.path.join( - output_dir, "null_odds.json" if prefix is None else f"{prefix}_null_odds.json" - ) - - logger.info(f"Saving predictions to {prediction_file}.") - with open(prediction_file, "w", encoding="utf-8") as writer: - writer.write(json.dumps(all_predictions, indent=4) + "\n") - logger.info(f"Saving nbest_preds to {nbest_file}.") - with open(nbest_file, "w", encoding="utf-8") as writer: - writer.write(json.dumps(all_nbest_json, indent=4) + "\n") - if version_2_with_negative: - logger.info(f"Saving null_odds to {null_odds_file}.") - with open(null_odds_file, "w", encoding="utf-8") as writer: - writer.write(json.dumps(scores_diff_json, indent=4) + "\n") - - return all_predictions, scores_diff_json diff --git a/examples/pytorch/semantic-segmentation/README.md b/examples/pytorch/semantic-segmentation/README.md deleted file mode 100644 index 5b53dd67bf37..000000000000 --- a/examples/pytorch/semantic-segmentation/README.md +++ /dev/null @@ -1,207 +0,0 @@ - - -# Semantic segmentation examples - -This directory contains 2 scripts that showcase how to fine-tune any model supported by the [`AutoModelForSemanticSegmentation` API](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoModelForSemanticSegmentation) (such as [SegFormer](https://huggingface.co/docs/transformers/main/en/model_doc/segformer), [BEiT](https://huggingface.co/docs/transformers/main/en/model_doc/beit), [DPT](https://huggingface.co/docs/transformers/main/en/model_doc/dpt)) using PyTorch. - -![segformer_inference_widget](https://user-images.githubusercontent.com/48327001/163667406-01f323a6-72ec-4e7e-bdeb-7d9da71b0697.gif) - -Content: -* [Note on custom data](#note-on-custom-data) -* [PyTorch version, Trainer](#pytorch-version-trainer) -* [PyTorch version, no Trainer](#pytorch-version-no-trainer) -* [Reload and perform inference](#reload-and-perform-inference) -* [Important notes](#important-notes) - -## Note on custom data - -In case you'd like to use the script with custom data, there are 2 things required: 1) creating a DatasetDict 2) creating an id2label mapping. Below, these are explained in more detail. - -### Creating a `DatasetDict` - -The script assumes that you have a `DatasetDict` with 2 columns, "image" and "label", both of type [Image](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Image). This can be created as follows: - -```python -from datasets import Dataset, DatasetDict, Image - -# your images can of course have a different extension -# semantic segmentation maps are typically stored in the png format -image_paths_train = ["path/to/image_1.jpg/jpg", "path/to/image_2.jpg/jpg", ..., "path/to/image_n.jpg/jpg"] -label_paths_train = ["path/to/annotation_1.png", "path/to/annotation_2.png", ..., "path/to/annotation_n.png"] - -# same for validation -# image_paths_validation = [...] -# label_paths_validation = [...] - -def create_dataset(image_paths, label_paths): - dataset = Dataset.from_dict({"image": sorted(image_paths), - "label": sorted(label_paths)}) - dataset = dataset.cast_column("image", Image()) - dataset = dataset.cast_column("label", Image()) - - return dataset - -# step 1: create Dataset objects -train_dataset = create_dataset(image_paths_train, label_paths_train) -validation_dataset = create_dataset(image_paths_validation, label_paths_validation) - -# step 2: create DatasetDict -dataset = DatasetDict({ - "train": train_dataset, - "validation": validation_dataset, - } -) - -# step 3: push to hub (assumes you have ran the hf auth login command in a terminal/notebook) -dataset.push_to_hub("name of repo on the hub") - -# optionally, you can push to a private repo on the hub -# dataset.push_to_hub("name of repo on the hub", private=True) -``` - -An example of such a dataset can be seen at [nielsr/ade20k-demo](https://huggingface.co/datasets/nielsr/ade20k-demo). - -### Creating an id2label mapping - -Besides that, the script also assumes the existence of an `id2label.json` file in the repo, containing a mapping from integers to actual class names. An example of that can be seen [here](https://huggingface.co/datasets/nielsr/ade20k-demo/blob/main/id2label.json). This can be created in Python as follows: - -```python -import json -# simple example -id2label = {0: 'cat', 1: 'dog'} -with open('id2label.json', 'w') as fp: - json.dump(id2label, fp) -``` - -You can easily upload this by clicking on "Add file" in the "Files and versions" tab of your repo on the hub. - -## PyTorch version, Trainer - -Based on the script [`run_semantic_segmentation.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/semantic-segmentation/run_semantic_segmentation.py). - -The script leverages the [🤗 Trainer API](https://huggingface.co/docs/transformers/main_classes/trainer) to automatically take care of the training for you, running on distributed environments right away. - -Here we show how to fine-tune a [SegFormer](https://huggingface.co/nvidia/mit-b0) model on the [segments/sidewalk-semantic](https://huggingface.co/datasets/segments/sidewalk-semantic) dataset: - -In order to use `segments/sidewalk-semantic`: - - Log in to Hugging Face with `hf auth login` (token can be accessed [here](https://huggingface.co/settings/tokens)). - - Accept terms of use for `sidewalk-semantic` on [dataset page](https://huggingface.co/datasets/segments/sidewalk-semantic). - -```bash -python run_semantic_segmentation.py \ - --model_name_or_path nvidia/mit-b0 \ - --dataset_name segments/sidewalk-semantic \ - --output_dir ./segformer_outputs/ \ - --remove_unused_columns False \ - --do_train \ - --do_eval \ - --push_to_hub \ - --push_to_hub_model_id segformer-finetuned-sidewalk-10k-steps \ - --max_steps 10000 \ - --learning_rate 0.00006 \ - --lr_scheduler_type polynomial \ - --per_device_train_batch_size 8 \ - --per_device_eval_batch_size 8 \ - --logging_strategy steps \ - --logging_steps 100 \ - --eval_strategy epoch \ - --save_strategy epoch \ - --seed 1337 -``` - -The resulting model can be seen here: https://huggingface.co/nielsr/segformer-finetuned-sidewalk-10k-steps. The corresponding Weights and Biases report [here](https://wandb.ai/nielsrogge/huggingface/reports/SegFormer-fine-tuning--VmlldzoxODY5NTQ2). Note that it's always advised to check the original paper to know the details regarding training hyperparameters. E.g. from the SegFormer paper: - -> We trained the models using AdamW optimizer for 160K iterations on ADE20K, Cityscapes, and 80K iterations on COCO-Stuff. (...) We used a batch size of 16 for ADE20K and COCO-Stuff, and a batch size of 8 for Cityscapes. The learning rate was set to an initial value of 0.00006 and then used a “poly” LR schedule with factor 1.0 by default. - -Note that you can replace the model and dataset by simply setting the `model_name_or_path` and `dataset_name` arguments respectively, with any model or dataset from the [hub](https://huggingface.co/). For an overview of all possible arguments, we refer to the [docs](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments) of the `TrainingArguments`, which can be passed as flags. - -## PyTorch version, no Trainer - -Based on the script [`run_semantic_segmentation_no_trainer.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/semantic-segmentation/run_semantic_segmentation.py). - -The script leverages [🤗 `Accelerate`](https://github.com/huggingface/accelerate), which allows to write your own training loop in PyTorch, but have it run instantly on any (distributed) environment, including CPU, multi-CPU, GPU, multi-GPU and TPU. It also supports mixed precision. - -First, run: - -```bash -accelerate config -``` - -and reply to the questions asked regarding the environment on which you'd like to train. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -accelerate launch run_semantic_segmentation_no_trainer.py --output_dir segformer-finetuned-sidewalk --with_tracking --push_to_hub -``` - -and boom, you're training, possibly on multiple GPUs, logging everything to all trackers found in your environment (like Weights and Biases, Tensorboard) and regularly pushing your model to the hub (with the repo name being equal to `args.output_dir` at your HF username) 🤗 - -With the default settings, the script fine-tunes a [SegFormer](https://huggingface.co/docs/transformers/main/en/model_doc/segformer) model on the [segments/sidewalk-semantic](https://huggingface.co/datasets/segments/sidewalk-semantic) dataset. - -The resulting model can be seen here: https://huggingface.co/nielsr/segformer-finetuned-sidewalk. Note that the script usually requires quite a few epochs to achieve great results, e.g. the SegFormer authors fine-tuned their model for 160k steps (batches) on [`scene_parse_150`](https://huggingface.co/datasets/merve/scene_parse_150). - -## Reload and perform inference - -This means that after training, you can easily load your trained model as follows: - -```python -from transformers import AutoImageProcessor, AutoModelForSemanticSegmentation - -model_name = "name_of_repo_on_the_hub_or_path_to_local_folder" - -image_processor = AutoImageProcessor.from_pretrained(model_name) -model = AutoModelForSemanticSegmentation.from_pretrained(model_name) -``` - -and perform inference as follows: - -```python -from PIL import Image -import requests -import torch - -url = "http://images.cocodataset.org/val2017/000000039769.jpg" -image = Image.open(requests.get(url, stream=True).raw) - -# prepare image for the model -inputs = image_processor(images=image, return_tensors="pt") - -with torch.no_grad(): - outputs = model(**inputs) - logits = outputs.logits - -# rescale logits to original image size -logits = nn.functional.interpolate(outputs.logits.detach().cpu(), - size=image.size[::-1], # (height, width) - mode='bilinear', - align_corners=False) - -predicted = logits.argmax(1) -``` - -For visualization of the segmentation maps, we refer to the [example notebook](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/SegFormer/Segformer_inference_notebook.ipynb). - -## Important notes - -Some datasets, like [`scene_parse_150`](https://huggingface.co/datasets/merve/scene_parse_150), contain a "background" label that is not part of the classes. The Scene Parse 150 dataset for instance contains labels between 0 and 150, with 0 being the background class, and 1 to 150 being actual class names (like "tree", "person", etc.). For these kind of datasets, one replaces the background label (0) by 255, which is the `ignore_index` of the PyTorch model's loss function, and reduces all labels by 1. This way, the `labels` are PyTorch tensors containing values between 0 and 149, and 255 for all background/padding. - -In case you're training on such a dataset, make sure to set the ``do_reduce_labels`` flag, which will take care of this. diff --git a/examples/pytorch/semantic-segmentation/requirements.txt b/examples/pytorch/semantic-segmentation/requirements.txt deleted file mode 100644 index 7d62aa141db3..000000000000 --- a/examples/pytorch/semantic-segmentation/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -datasets >= 2.0.0 -torch >= 1.3 -accelerate -evaluate -Pillow -albumentations >= 1.4.16 diff --git a/examples/pytorch/semantic-segmentation/run_semantic_segmentation.py b/examples/pytorch/semantic-segmentation/run_semantic_segmentation.py deleted file mode 100644 index 69c2cb515c10..000000000000 --- a/examples/pytorch/semantic-segmentation/run_semantic_segmentation.py +++ /dev/null @@ -1,421 +0,0 @@ -#!/usr/bin/env python -# Copyright 2022 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "datasets >= 2.0.0", -# "torch >= 1.3", -# "accelerate", -# "evaluate"" -# "Pillow", -# "albumentations >= 1.4.16", -# ] -# /// - -import json -import logging -import os -import sys -from dataclasses import dataclass, field -from functools import partial - -import albumentations as A -import evaluate -import numpy as np -import torch -from albumentations.pytorch import ToTensorV2 -from datasets import load_dataset -from huggingface_hub import hf_hub_download -from torch import nn - -import transformers -from transformers import ( - AutoConfig, - AutoImageProcessor, - AutoModelForSemanticSegmentation, - HfArgumentParser, - Trainer, - TrainingArguments, - default_data_collator, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -""" Finetuning any 🤗 Transformers model supported by AutoModelForSemanticSegmentation for semantic segmentation leveraging the Trainer API.""" - -logger = logging.getLogger(__name__) - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=2.0.0", "To fix: pip install -r examples/pytorch/semantic-segmentation/requirements.txt") - - -def reduce_labels_transform(labels: np.ndarray, **kwargs) -> np.ndarray: - """Set `0` label as with value 255 and then reduce all other labels by 1. - - Example: - Initial class labels: 0 - background; 1 - road; 2 - car; - Transformed class labels: 255 - background; 0 - road; 1 - car; - - **kwargs are required to use this function with albumentations. - """ - labels[labels == 0] = 255 - labels = labels - 1 - labels[labels == 254] = 255 - return labels - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - Using `HfArgumentParser` we can turn this class into argparse arguments to be able to specify - them on the command line. - """ - - dataset_name: str | None = field( - default="segments/sidewalk-semantic", - metadata={ - "help": "Name of a dataset from the hub (could be your own, possibly private dataset hosted on the hub)." - }, - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_val_split: float | None = field( - default=0.15, metadata={"help": "Percent to split off of train for validation."} - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - do_reduce_labels: bool | None = field( - default=False, - metadata={"help": "Whether or not to reduce all labels by 1 and replace background by 255."}, - ) - - def __post_init__(self): - if self.dataset_name is None and (self.train_dir is None and self.validation_dir is None): - raise ValueError( - "You must specify either a dataset name from the hub or a train and/or validation directory." - ) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - default="nvidia/mit-b0", - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"}, - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"} - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - image_processor_name: str = field(default=None, metadata={"help": "Name or path of preprocessor config."}) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Load dataset - # In distributed training, the load_dataset function guarantees that only one local process can concurrently - # download the dataset. - # TODO support datasets from local folders - dataset = load_dataset( - data_args.dataset_name, cache_dir=model_args.cache_dir, trust_remote_code=model_args.trust_remote_code - ) - - # Rename column names to standardized names (only "image" and "label" need to be present) - if "pixel_values" in dataset["train"].column_names: - dataset = dataset.rename_columns({"pixel_values": "image"}) - if "annotation" in dataset["train"].column_names: - dataset = dataset.rename_columns({"annotation": "label"}) - - # If we don't have a validation split, split off a percentage of train as validation. - data_args.train_val_split = None if "validation" in dataset else data_args.train_val_split - if isinstance(data_args.train_val_split, float) and data_args.train_val_split > 0.0: - split = dataset["train"].train_test_split(data_args.train_val_split) - dataset["train"] = split["train"] - dataset["validation"] = split["test"] - - # Prepare label mappings. - # We'll include these in the model's config to get human readable labels in the Inference API. - if data_args.dataset_name == "scene_parse_150": - repo_id = "huggingface/label-files" - filename = "ade20k-id2label.json" - else: - repo_id = data_args.dataset_name - filename = "id2label.json" - id2label = json.load(open(hf_hub_download(repo_id, filename, repo_type="dataset"), encoding="utf-8")) - id2label = {int(k): v for k, v in id2label.items()} - label2id = {v: str(k) for k, v in id2label.items()} - - # Load the mean IoU metric from the evaluate package - metric = evaluate.load("mean_iou", cache_dir=model_args.cache_dir) - - # Define our compute_metrics function. It takes an `EvalPrediction` object (a namedtuple with a - # predictions and label_ids field) and has to return a dictionary string to float. - @torch.no_grad() - def compute_metrics(eval_pred): - logits, labels = eval_pred - logits_tensor = torch.from_numpy(logits) - # scale the logits to the size of the label - logits_tensor = nn.functional.interpolate( - logits_tensor, - size=labels.shape[-2:], - mode="bilinear", - align_corners=False, - ).argmax(dim=1) - - pred_labels = logits_tensor.detach().cpu().numpy() - metrics = metric.compute( - predictions=pred_labels, - references=labels, - num_labels=len(id2label), - ignore_index=0, - reduce_labels=image_processor.do_reduce_labels, - ) - # add per category metrics as individual key-value pairs - per_category_accuracy = metrics.pop("per_category_accuracy").tolist() - per_category_iou = metrics.pop("per_category_iou").tolist() - - metrics.update({f"accuracy_{id2label[i]}": v for i, v in enumerate(per_category_accuracy)}) - metrics.update({f"iou_{id2label[i]}": v for i, v in enumerate(per_category_iou)}) - - return metrics - - config = AutoConfig.from_pretrained( - model_args.config_name or model_args.model_name_or_path, - label2id=label2id, - id2label=id2label, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForSemanticSegmentation.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - image_processor = AutoImageProcessor.from_pretrained( - model_args.image_processor_name or model_args.model_name_or_path, - do_reduce_labels=data_args.do_reduce_labels, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # Define transforms to be applied to each image and target. - if "shortest_edge" in image_processor.size: - # We instead set the target size as (shortest_edge, shortest_edge) to here to ensure all images are batchable. - height, width = image_processor.size["shortest_edge"], image_processor.size["shortest_edge"] - else: - height, width = image_processor.size["height"], image_processor.size["width"] - train_transforms = A.Compose( - [ - A.Lambda( - name="reduce_labels", - mask=reduce_labels_transform if data_args.do_reduce_labels else None, - p=1.0, - ), - # pad image with 255, because it is ignored by loss - A.PadIfNeeded(min_height=height, min_width=width, border_mode=0, value=255, p=1.0), - A.RandomCrop(height=height, width=width, p=1.0), - A.HorizontalFlip(p=0.5), - A.Normalize(mean=image_processor.image_mean, std=image_processor.image_std, max_pixel_value=255.0, p=1.0), - ToTensorV2(), - ] - ) - val_transforms = A.Compose( - [ - A.Lambda( - name="reduce_labels", - mask=reduce_labels_transform if data_args.do_reduce_labels else None, - p=1.0, - ), - A.Resize(height=height, width=width, p=1.0), - A.Normalize(mean=image_processor.image_mean, std=image_processor.image_std, max_pixel_value=255.0, p=1.0), - ToTensorV2(), - ] - ) - - def preprocess_batch(example_batch, transforms: A.Compose): - pixel_values = [] - labels = [] - for image, target in zip(example_batch["image"], example_batch["label"]): - transformed = transforms(image=np.array(image.convert("RGB")), mask=np.array(target)) - pixel_values.append(transformed["image"]) - labels.append(transformed["mask"]) - - encoding = {} - encoding["pixel_values"] = torch.stack(pixel_values).to(torch.float) - encoding["labels"] = torch.stack(labels).to(torch.long) - - return encoding - - # Preprocess function for dataset should have only one argument, - # so we use partial to pass the transforms - preprocess_train_batch_fn = partial(preprocess_batch, transforms=train_transforms) - preprocess_val_batch_fn = partial(preprocess_batch, transforms=val_transforms) - - if training_args.do_train: - if "train" not in dataset: - raise ValueError("--do_train requires a train dataset") - if data_args.max_train_samples is not None: - dataset["train"] = ( - dataset["train"].shuffle(seed=training_args.seed).select(range(data_args.max_train_samples)) - ) - # Set the training transforms - dataset["train"].set_transform(preprocess_train_batch_fn) - - if training_args.do_eval: - if "validation" not in dataset: - raise ValueError("--do_eval requires a validation dataset") - if data_args.max_eval_samples is not None: - dataset["validation"] = ( - dataset["validation"].shuffle(seed=training_args.seed).select(range(data_args.max_eval_samples)) - ) - # Set the validation transforms - dataset["validation"].set_transform(preprocess_val_batch_fn) - - # Initialize our trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=dataset["train"] if training_args.do_train else None, - eval_dataset=dataset["validation"] if training_args.do_eval else None, - compute_metrics=compute_metrics, - processing_class=image_processor, - data_collator=default_data_collator, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - trainer.log_metrics("train", train_result.metrics) - trainer.save_metrics("train", train_result.metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - metrics = trainer.evaluate() - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Write model card and (optionally) push to hub - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "dataset": data_args.dataset_name, - "tags": ["image-segmentation", "vision"], - } - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/semantic-segmentation/run_semantic_segmentation_no_trainer.py b/examples/pytorch/semantic-segmentation/run_semantic_segmentation_no_trainer.py deleted file mode 100644 index 75f2b7cb48ca..000000000000 --- a/examples/pytorch/semantic-segmentation/run_semantic_segmentation_no_trainer.py +++ /dev/null @@ -1,622 +0,0 @@ -# Copyright 2022 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "datasets >= 2.0.0", -# "torch >= 1.3", -# "accelerate", -# "evaluate"" -# "Pillow", -# "albumentations >= 1.4.16", -# ] -# /// - -"""Finetuning any 🤗 Transformers model supported by AutoModelForSemanticSegmentation for semantic segmentation.""" - -import argparse -import json -import math -import os -from functools import partial -from pathlib import Path - -import albumentations as A -import datasets -import evaluate -import numpy as np -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from albumentations.pytorch import ToTensorV2 -from datasets import load_dataset -from huggingface_hub import HfApi, hf_hub_download -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - AutoConfig, - AutoImageProcessor, - AutoModelForSemanticSegmentation, - SchedulerType, - default_data_collator, - get_scheduler, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) - -require_version("datasets>=2.0.0", "To fix: pip install -r examples/pytorch/semantic-segmentation/requirements.txt") - - -def reduce_labels_transform(labels: np.ndarray, **kwargs) -> np.ndarray: - """Set `0` label as with value 255 and then reduce all other labels by 1. - - Example: - Initial class labels: 0 - background; 1 - road; 2 - car; - Transformed class labels: 255 - background; 0 - road; 1 - car; - - **kwargs are required to use this function with albumentations. - """ - labels[labels == 0] = 255 - labels = labels - 1 - labels[labels == 254] = 255 - return labels - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a image semantic segmentation task") - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to a pretrained model or model identifier from huggingface.co/models.", - default="nvidia/mit-b0", - ) - parser.add_argument( - "--dataset_name", - type=str, - help="Name of the dataset on the hub.", - default="segments/sidewalk-semantic", - ) - parser.add_argument( - "--do_reduce_labels", - action="store_true", - help="Whether or not to reduce all labels by 1 and replace background by 255.", - ) - parser.add_argument( - "--train_val_split", - type=float, - default=0.15, - help="Fraction of the dataset to be used for validation.", - ) - parser.add_argument( - "--cache_dir", - type=str, - help="Path to a folder in which the model and dataset will be cached.", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument( - "--adam_beta1", - type=float, - default=0.9, - help="Beta1 for AdamW optimizer", - ) - parser.add_argument( - "--adam_beta2", - type=float, - default=0.999, - help="Beta2 for AdamW optimizer", - ) - parser.add_argument( - "--adam_epsilon", - type=float, - default=1e-8, - help="Epsilon for AdamW optimizer", - ) - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="polynomial", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - required=False, - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - if args.push_to_hub or args.with_tracking: - if args.output_dir is None: - raise ValueError( - "Need an `output_dir` to create a repo when `--push_to_hub` or `with_tracking` is specified." - ) - - if args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - # We set device_specific to True as we want different data augmentation per device. - if args.seed is not None: - set_seed(args.seed, device_specific=True) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Load dataset - # In distributed training, the load_dataset function guarantees that only one local process can concurrently - # download the dataset. - # TODO support datasets from local folders - dataset = load_dataset(args.dataset_name, cache_dir=args.cache_dir, trust_remote_code=args.trust_remote_code) - - # Rename column names to standardized names (only "image" and "label" need to be present) - if "pixel_values" in dataset["train"].column_names: - dataset = dataset.rename_columns({"pixel_values": "image"}) - if "annotation" in dataset["train"].column_names: - dataset = dataset.rename_columns({"annotation": "label"}) - - # If we don't have a validation split, split off a percentage of train as validation. - args.train_val_split = None if "validation" in dataset else args.train_val_split - if isinstance(args.train_val_split, float) and args.train_val_split > 0.0: - split = dataset["train"].train_test_split(args.train_val_split) - dataset["train"] = split["train"] - dataset["validation"] = split["test"] - - # Prepare label mappings. - # We'll include these in the model's config to get human readable labels in the Inference API. - if args.dataset_name == "scene_parse_150": - repo_id = "huggingface/label-files" - filename = "ade20k-id2label.json" - else: - repo_id = args.dataset_name - filename = "id2label.json" - id2label = json.load(open(hf_hub_download(repo_id, filename, repo_type="dataset"), encoding="utf-8")) - id2label = {int(k): v for k, v in id2label.items()} - label2id = {v: k for k, v in id2label.items()} - - # Load pretrained model and image processor - config = AutoConfig.from_pretrained( - args.model_name_or_path, id2label=id2label, label2id=label2id, trust_remote_code=args.trust_remote_code - ) - image_processor = AutoImageProcessor.from_pretrained( - args.model_name_or_path, trust_remote_code=args.trust_remote_code, do_reduce_labels=args.do_reduce_labels - ) - model = AutoModelForSemanticSegmentation.from_pretrained( - args.model_name_or_path, - config=config, - trust_remote_code=args.trust_remote_code, - ) - - # Define transforms to be applied to each image and target. - if "shortest_edge" in image_processor.size: - # We instead set the target size as (shortest_edge, shortest_edge) to here to ensure all images are batchable. - height, width = image_processor.size["shortest_edge"], image_processor.size["shortest_edge"] - else: - height, width = image_processor.size["height"], image_processor.size["width"] - train_transforms = A.Compose( - [ - A.Lambda(name="reduce_labels", mask=reduce_labels_transform if args.do_reduce_labels else None, p=1.0), - # pad image with 255, because it is ignored by loss - A.PadIfNeeded(min_height=height, min_width=width, border_mode=0, value=255, p=1.0), - A.RandomCrop(height=height, width=width, p=1.0), - A.HorizontalFlip(p=0.5), - A.Normalize(mean=image_processor.image_mean, std=image_processor.image_std, max_pixel_value=255.0, p=1.0), - ToTensorV2(), - ] - ) - val_transforms = A.Compose( - [ - A.Lambda(name="reduce_labels", mask=reduce_labels_transform if args.do_reduce_labels else None, p=1.0), - A.Resize(height=height, width=width, p=1.0), - A.Normalize(mean=image_processor.image_mean, std=image_processor.image_std, max_pixel_value=255.0, p=1.0), - ToTensorV2(), - ] - ) - - def preprocess_batch(example_batch, transforms: A.Compose): - pixel_values = [] - labels = [] - for image, target in zip(example_batch["image"], example_batch["label"]): - transformed = transforms(image=np.array(image.convert("RGB")), mask=np.array(target)) - pixel_values.append(transformed["image"]) - labels.append(transformed["mask"]) - - encoding = {} - encoding["pixel_values"] = torch.stack(pixel_values).to(torch.float) - encoding["labels"] = torch.stack(labels).to(torch.long) - - return encoding - - # Preprocess function for dataset should have only one input argument, - # so we use partial to pass transforms - preprocess_train_batch_fn = partial(preprocess_batch, transforms=train_transforms) - preprocess_val_batch_fn = partial(preprocess_batch, transforms=val_transforms) - - with accelerator.main_process_first(): - train_dataset = dataset["train"].with_transform(preprocess_train_batch_fn) - eval_dataset = dataset["validation"].with_transform(preprocess_val_batch_fn) - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=default_data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader( - eval_dataset, collate_fn=default_data_collator, batch_size=args.per_device_eval_batch_size - ) - - # Optimizer - optimizer = torch.optim.AdamW( - list(model.parameters()), - lr=args.learning_rate, - betas=[args.adam_beta1, args.adam_beta2], - eps=args.adam_epsilon, - ) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Instantiate metric - metric = evaluate.load("mean_iou", cache_dir=args.cache_dir) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("semantic_segmentation_no_trainer", experiment_config) - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, - is_main_process=accelerator.is_main_process, - save_function=accelerator.save, - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if completed_steps >= args.max_train_steps: - break - - logger.info("***** Running evaluation *****") - model.eval() - for step, batch in enumerate(tqdm(eval_dataloader, disable=not accelerator.is_local_main_process)): - with torch.no_grad(): - outputs = model(**batch) - - upsampled_logits = torch.nn.functional.interpolate( - outputs.logits, size=batch["labels"].shape[-2:], mode="bilinear", align_corners=False - ) - predictions = upsampled_logits.argmax(dim=1) - - predictions, references = accelerator.gather_for_metrics((predictions, batch["labels"])) - - metric.add_batch( - predictions=predictions, - references=references, - ) - - eval_metrics = metric.compute( - num_labels=len(id2label), - ignore_index=255, - reduce_labels=False, # we've already reduced the labels before - ) - logger.info(f"epoch {epoch}: {eval_metrics}") - - if args.with_tracking: - accelerator.log( - { - "mean_iou": eval_metrics["mean_iou"], - "mean_accuracy": eval_metrics["mean_accuracy"], - "overall_accuracy": eval_metrics["overall_accuracy"], - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - image_processor.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - all_results = { - f"eval_{k}": v.tolist() if isinstance(v, np.ndarray) else v for k, v in eval_metrics.items() - } - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump(all_results, f, indent=2) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/speech-pretraining/README.md b/examples/pytorch/speech-pretraining/README.md deleted file mode 100644 index fe6ec176b505..000000000000 --- a/examples/pytorch/speech-pretraining/README.md +++ /dev/null @@ -1,161 +0,0 @@ - - -# Speech Recognition Pre-Training - - -## Wav2Vec2 Speech Pre-Training - -The script [`run_speech_wav2vec2_pretraining_no_trainer.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/speech-pretraining/run_wav2vec2_pretraining_no_trainer.py) can be used to pre-train a [Wav2Vec2](https://huggingface.co/transformers/model_doc/wav2vec2.html?highlight=wav2vec2) model from scratch. - -In the script [`run_speech_wav2vec2_pretraining_no_trainer`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/speech-pretraining/run_wav2vec2_pretraining_no_trainer.py), a Wav2Vec2 model is pre-trained on audio data alone using [Wav2Vec2's contrastive loss objective](https://huggingface.co/papers/2006.11477). - -The following examples show how to fine-tune a `"base"`-sized Wav2Vec2 model as well as a `"large"`-sized Wav2Vec2 model using [`accelerate`](https://github.com/huggingface/accelerate). - - ---- -**NOTE 1** - -Wav2Vec2's pre-training is known to be quite unstable. -It is advised to do a couple of test runs with a smaller dataset, -*i.e.* `--dataset_config_names clean clean`, `--dataset_split_names validation test` -to find good hyper-parameters for `learning_rate`, `batch_size`, `num_warmup_steps`, -and the optimizer. -A good metric to observe during training is the gradient norm which should ideally be between 0.5 and 2. - ---- - ---- -**NOTE 2** - -When training a model on large datasets it is recommended to run the data preprocessing -in a first run in a **non-distributed** mode via `--preprocessing_only` so that -when running the model in **distributed** mode in a second step the preprocessed data -can easily be loaded on each distributed device. - ---- - -### Demo - -In this demo run we pre-train a `"base-sized"` Wav2Vec2 model simply only on the validation -and test data of [librispeech_asr](https://huggingface.co/datasets/openslr/librispeech_asr). - -The demo is run on two Titan RTX (24 GB RAM each). In case you have less RAM available -per device, consider reducing `--batch_size` and/or the `--max_duration_in_seconds`. - - -```bash -accelerate launch run_wav2vec2_pretraining_no_trainer.py \ - --dataset_name="openslr/librispeech_asr" \ - --dataset_config_names clean clean \ - --dataset_split_names validation test \ - --model_name_or_path="patrickvonplaten/wav2vec2-base-v2" \ - --output_dir="./wav2vec2-pretrained-demo" \ - --max_train_steps="20000" \ - --num_warmup_steps="32000" \ - --gradient_accumulation_steps="8" \ - --learning_rate="0.005" \ - --weight_decay="0.01" \ - --max_duration_in_seconds="20.0" \ - --min_duration_in_seconds="2.0" \ - --logging_steps="1" \ - --saving_steps="10000" \ - --per_device_train_batch_size="8" \ - --per_device_eval_batch_size="8" \ - --adam_beta1="0.9" \ - --adam_beta2="0.98" \ - --adam_epsilon="1e-06" \ - --gradient_checkpointing \ - --mask_time_prob="0.65" \ - --mask_time_length="10" -``` - -The results of this run can be seen [here](https://wandb.ai/patrickvonplaten/wav2vec2-pretrained-demo/reports/Wav2Vec2-PreTraining-Demo-Run--VmlldzoxMDk3MjAw?accessToken=oa05s1y57lizo2ocxy3k01g6db1u4pt8m6ur2n8nl4cb0ug02ms2cw313kb8ruch). - -### Base - -To pre-train `"base-sized"` Wav2Vec2 model, *e.g.* [facebook/wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base) -on [librispeech_asr](https://huggingface.co/datasets/openslr/librispeech_asr), the following command can be run: - -```bash -accelerate launch run_wav2vec2_pretraining_no_trainer.py \ - --dataset_name=openslr/librispeech_asr \ - --dataset_config_names clean clean other \ - --dataset_split_names train.100 train.360 train.500 \ - --model_name_or_path="patrickvonplaten/wav2vec2-base-v2" \ - --output_dir="./wav2vec2-pretrained-demo" \ - --max_train_steps="200000" \ - --num_warmup_steps="32000" \ - --gradient_accumulation_steps="4" \ - --learning_rate="0.001" \ - --weight_decay="0.01" \ - --max_duration_in_seconds="20.0" \ - --min_duration_in_seconds="2.0" \ - --logging_steps="1" \ - --saving_steps="10000" \ - --per_device_train_batch_size="8" \ - --per_device_eval_batch_size="8" \ - --adam_beta1="0.9" \ - --adam_beta2="0.98" \ - --adam_epsilon="1e-06" \ - --gradient_checkpointing \ - --mask_time_prob="0.65" \ - --mask_time_length="10" -``` - -The experiment was run on 8 GPU V100 (16 GB RAM each) for 4 days. -In case you have more than 8 GPUs available for a higher effective `batch_size`, -it is recommended to increase the `learning_rate` to `0.005` for faster convergence. - -The results of this run can be seen [here](https://wandb.ai/patrickvonplaten/test/reports/Wav2Vec2-Base--VmlldzoxMTUyODQ0?accessToken=rg6e8u9yizx964k8q47zctq1m4afpvtn1i3qi9exgdmzip6xwkfzvagfajpzj55n) and the checkpoint pretrained for 85,000 steps can be accessed [here](https://huggingface.co/patrickvonplaten/wav2vec2-base-repro-960h-libri-85k-steps) - - -### Large - -To pre-train `"large-sized"` Wav2Vec2 model, *e.g.* [facebook/wav2vec2-large-lv60](https://huggingface.co/facebook/wav2vec2-large-lv60), -on [librispeech_asr](https://huggingface.co/datasets/openslr/librispeech_asr), the following command can be run: - -```bash -accelerate launch run_wav2vec2_pretraining_no_trainer.py \ - --dataset_name=openslr/librispeech_asr \ - --dataset_config_names clean clean other \ - --dataset_split_names train.100 train.360 train.500 \ - --output_dir=./test \ - --max_train_steps=200000 \ - --num_warmup_steps=32000 \ - --gradient_accumulation_steps=8 \ - --learning_rate=0.001 \ - --weight_decay=0.01 \ - --max_duration_in_seconds=20.0 \ - --min_duration_in_seconds=2.0 \ - --model_name_or_path=./ \ - --logging_steps=1 \ - --saving_steps=10000 \ - --per_device_train_batch_size=2 \ - --per_device_eval_batch_size=4 \ - --adam_beta1=0.9 \ - --adam_beta2=0.98 \ - --adam_epsilon=1e-06 \ - --gradient_checkpointing \ - --mask_time_prob=0.65 \ - --mask_time_length=10 -``` - -The experiment was run on 8 GPU V100 (16 GB RAM each) for 7 days. -In case you have more than 8 GPUs available for a higher effective `batch_size`, -it is recommended to increase the `learning_rate` to `0.005` for faster convergence. - -The results of this run can be seen [here](https://wandb.ai/patrickvonplaten/pretraining-wav2vec2/reports/Wav2Vec2-Large--VmlldzoxMTAwODM4?accessToken=wm3qzcnldrwsa31tkvf2pdmilw3f63d4twtffs86ou016xjbyilh55uoi3mo1qzc) and the checkpoint pretrained for 120,000 steps can be accessed [here](https://huggingface.co/patrickvonplaten/wav2vec2-large-repro-960h-libri-120k-steps) diff --git a/examples/pytorch/speech-pretraining/requirements.txt b/examples/pytorch/speech-pretraining/requirements.txt deleted file mode 100644 index 57851d2a09d1..000000000000 --- a/examples/pytorch/speech-pretraining/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -datasets[audio] >= 1.12.0 -torch >= 1.5 -torchaudio -accelerate >= 0.12.0 -librosa \ No newline at end of file diff --git a/examples/pytorch/speech-pretraining/run_wav2vec2_pretraining_no_trainer.py b/examples/pytorch/speech-pretraining/run_wav2vec2_pretraining_no_trainer.py deleted file mode 100755 index 10d367918126..000000000000 --- a/examples/pytorch/speech-pretraining/run_wav2vec2_pretraining_no_trainer.py +++ /dev/null @@ -1,807 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "datasets[audio] >= 1.12.0", -# "torch >= 1.5", -# "torchaudio", -# "accelerate >= 0.12.0", -# "librosa", -# ] -# /// - -"""Pre-Training a 🤗 Wav2Vec2 model on unlabeled audio data""" - -import argparse -import math -import os -from dataclasses import dataclass -from pathlib import Path - -import aiohttp -import datasets -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from datasets import DatasetDict, concatenate_datasets, load_dataset -from huggingface_hub import HfApi -from torch.utils.data.dataloader import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - SchedulerType, - Wav2Vec2Config, - Wav2Vec2FeatureExtractor, - Wav2Vec2ForPreTraining, - get_scheduler, - is_wandb_available, - set_seed, -) -from transformers.models.wav2vec2.modeling_wav2vec2 import _compute_mask_indices, _sample_negative_indices - - -logger = get_logger(__name__) - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a text classification task") - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_names", - nargs="+", - type=str, - required=True, - help="The configuration names of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_split_names", - nargs="+", - type=str, - required=True, - help="The names of the training data set splits to use (via the datasets library).", - ) - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--preprocessing_num_workers", - type=int, - default=None, - help="The number of processes to use for the preprocessing.", - ) - parser.add_argument( - "--overwrite_cache", action="store_true", help="Overwrite the cached training and evaluation sets" - ) - parser.add_argument( - "--preprocessing_only", - action="store_true", - help="Only run the preprocessing script to be cached for future use", - ) - parser.add_argument( - "--cache_dir", - type=str, - default=None, - help="Where do you want to store the pretrained models downloaded from huggingface.co", - ) - parser.add_argument( - "--validation_split_percentage", - type=int, - default=1, - help="Percentage of training data that should be used for validation if no validation is present in dataset.", - ) - parser.add_argument( - "--logging_steps", - type=int, - default=500, - help="Number of steps between each logging", - ) - parser.add_argument( - "--saving_steps", - type=int, - default=500, - help="Number of steps between each logging", - ) - parser.add_argument( - "--audio_column_name", - type=str, - default="audio", - help="Column in the dataset that contains speech file path. Defaults to 'audio'", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=True, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--train_cache_file_name", - type=str, - default=None, - help="Path to the train cached file name", - ) - parser.add_argument( - "--validation_cache_file_name", - type=str, - default=None, - help="Path to the validation cached file name", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--gradient_checkpointing", - action="store_true", - help="If True, use gradient checkpointing to save memory at the expense of slower backward pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=0, help="A seed for reproducible training.") - parser.add_argument( - "--max_gumbel_temperature", - type=float, - default=2.0, - help="Maximum temperature for gumbel softmax.", - ) - parser.add_argument( - "--min_gumbel_temperature", - type=float, - default=0.5, - help="Minimum temperature for gumbel softmax.", - ) - parser.add_argument( - "--gumbel_temperature_decay", type=float, default=0.999995, help="Decay of gumbel temperature during training." - ) - parser.add_argument( - "--max_duration_in_seconds", - type=float, - default=5.0, - help="Filter out audio files that are longer than `max_duration_in_seconds` seconds", - ) - parser.add_argument( - "--min_duration_in_seconds", - type=float, - default=3.0, - help="Filter out audio files that are shorter than `min_duration_in_seconds` seconds", - ) - parser.add_argument( - "--pad_to_multiple_of", - type=int, - default=None, - help=( - "If set will pad the sequence to a multiple of the provided value. This is especially useful to enable the" - " use of Tensor Cores on NVIDIA hardware with compute capability >= 7.5 (Volta)." - ), - ) - parser.add_argument( - "--adam_beta1", - type=float, - default=0.9, - help="Beta1 for AdamW optimizer", - ) - parser.add_argument( - "--adam_beta2", - type=float, - default=0.999, - help="Beta2 for AdamW optimizer", - ) - parser.add_argument( - "--adam_epsilon", - type=float, - default=1e-8, - help="Epsilon for AdamW optimizer", - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--mask_time_prob", - type=float, - default=None, - help=( - "Percentage (between 0 and 1) of all feature vectors along the time axis which will be masked in the" - " contrastive task. If omitted, will pull value from model config." - ), - ) - parser.add_argument( - "--mask_time_length", - type=int, - default=None, - help=( - "Length of each vector mask span to mask along the time axis in the contrastive task." - " If omitted, will pull value from model config." - ), - ) - args = parser.parse_args() - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - if args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - - return args - - -@dataclass -class DataCollatorForWav2Vec2Pretraining: - """ - Data collator that will dynamically pad the inputs received and prepare masked indices - for self-supervised pretraining. - - Args: - model (:class:`~transformers.Wav2Vec2ForPreTraining`): - The Wav2Vec2 model used for pretraining. The data collator needs to have access - to config and ``_get_feat_extract_output_lengths`` function for correct padding. - feature_extractor (:class:`~transformers.Wav2Vec2FeatureExtractor`): - The processor used for processing the data. - padding (:obj:`bool`, :obj:`str` or :class:`~transformers.tokenization_utils_base.PaddingStrategy`, `optional`, defaults to :obj:`True`): - Select a strategy to pad the returned sequences (according to the model's padding side and padding index) - among: - * :obj:`True` or :obj:`'longest'`: Pad to the longest sequence in the batch (or no padding if only a single - sequence if provided). - * :obj:`'max_length'`: Pad to a maximum length specified with the argument :obj:`max_length` or to the - maximum acceptable input length for the model if that argument is not provided. - * :obj:`False` or :obj:`'do_not_pad'` (default): No padding (i.e., can output a batch with sequences of - different lengths). - max_length (:obj:`int`, `optional`): - Maximum length of the ``input_values`` of the returned list and optionally padding length (see above). - pad_to_multiple_of (:obj:`int`, `optional`): - If set will pad the sequence to a multiple of the provided value. - This is especially useful to enable the use of Tensor Cores on NVIDIA hardware with compute capability >= - 7.5 (Volta). - mask_time_prob (:obj:`float`, `optional`, defaults to :obj:`0.65`): - Percentage (between 0 and 1) of all feature vectors along the time axis which will be masked for the contrastive task. - Note that overlap between masked sequences may decrease the actual percentage of masked vectors. - The default value is taken from the original wav2vec 2.0 article (https://huggingface.co/papers/2006.11477), - and results in about 49 percent of each sequence being masked on average. - mask_time_length (:obj:`int`, `optional`, defaults to :obj:`10`): - Length of each vector mask span to mask along the time axis in the contrastive task. The default value - originates from the original wav2vec 2.0 article and corresponds to the ``M`` variable mentioned there. - """ - - model: Wav2Vec2ForPreTraining - feature_extractor: Wav2Vec2FeatureExtractor - padding: bool | str = "longest" - pad_to_multiple_of: int | None = None - mask_time_prob: float | None = 0.65 - mask_time_length: int | None = 10 - - def __call__(self, features: list[dict[str, list[int] | torch.Tensor]]) -> dict[str, torch.Tensor]: - # reformat list to dict and set to pytorch format - batch = self.feature_extractor.pad( - features, - padding=self.padding, - pad_to_multiple_of=self.pad_to_multiple_of, - return_tensors="pt", - ) - - device = batch["input_values"].device - batch_size = batch["input_values"].shape[0] - - mask_indices_seq_length = self.model._get_feat_extract_output_lengths(batch["input_values"].shape[-1]) - # make sure masked sequence length is a Python scalar - mask_indices_seq_length = int(mask_indices_seq_length) - - # make sure that no loss is computed on padded inputs - if batch.get("attention_mask") is not None: - # compute real output lengths according to convolution formula - batch["sub_attention_mask"] = self.model._get_feature_vector_attention_mask( - mask_indices_seq_length, batch["attention_mask"] - ) - - features_shape = (batch_size, mask_indices_seq_length) - - # sample randomly masked indices - mask_time_indices = _compute_mask_indices( - features_shape, - self.mask_time_prob, - self.mask_time_length, - attention_mask=batch.get("sub_attention_mask"), - ) - - # sample negative indices - sampled_negative_indices = _sample_negative_indices( - features_shape, - self.model.config.num_negatives, - mask_time_indices=mask_time_indices, - ) - batch["mask_time_indices"] = torch.tensor(mask_time_indices, dtype=torch.long, device=device) - batch["sampled_negative_indices"] = torch.tensor(sampled_negative_indices, dtype=torch.long, device=device) - - return batch - - -def multiply_grads(params, c): - """Multiplies grads by a constant *c*.""" - for p in params: - if p.grad is not None: - if torch.is_tensor(c): - c = c.to(p.grad.device) - p.grad.data.mul_(c) - - -def get_grad_norm(params, scale=1): - """Compute grad norm given a gradient scale.""" - total_norm = 0.0 - for p in params: - if p.grad is not None: - param_norm = (p.grad.detach().data / scale).norm(2) - total_norm += param_norm.item() ** 2 - total_norm = total_norm**0.5 - return total_norm - - -def main(): - # See all possible arguments in src/transformers/args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - accelerator = Accelerator() - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - - # set up weights and biases if available - if is_wandb_available(): - import wandb - - wandb.init(project=args.output_dir.split("/")[-1]) - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub and not args.preprocessing_only: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # 1. Download and create train, validation dataset - # We load all dataset configuration and dataset split pairs passed in - # ``args.dataset_config_names`` and ``args.dataset_split_names`` - datasets_splits = [] - for dataset_config_name, train_split_name in zip(args.dataset_config_names, args.dataset_split_names): - # load dataset - dataset_split = load_dataset( - args.dataset_name, - dataset_config_name, - split=train_split_name, - cache_dir=args.cache_dir, - trust_remote_code=args.trust_remote_code, - storage_options={"client_kwargs": {"timeout": aiohttp.ClientTimeout(total=60 * 60)}}, - ) - datasets_splits.append(dataset_split) - - # Next, we concatenate all configurations and splits into a single training dataset - raw_datasets = DatasetDict() - if len(datasets_splits) > 1: - raw_datasets["train"] = concatenate_datasets(datasets_splits).shuffle(seed=args.seed) - else: - raw_datasets["train"] = datasets_splits[0] - - # Take ``args.validation_split_percentage`` from the training dataset for the validation_split_percentage - num_validation_samples = raw_datasets["train"].num_rows * args.validation_split_percentage // 100 - - if num_validation_samples == 0: - raise ValueError( - "`args.validation_split_percentage` is less than a single sample " - f"for {len(raw_datasets['train'])} training samples. Increase " - "`args.num_validation_split_percentage`. " - ) - - raw_datasets["validation"] = raw_datasets["train"].select(range(num_validation_samples)) - raw_datasets["train"] = raw_datasets["train"].select(range(num_validation_samples, raw_datasets["train"].num_rows)) - - # 2. Now we preprocess the datasets including loading the audio, resampling and normalization - # Thankfully, `datasets` takes care of automatically loading and resampling the audio, - # so that we just need to set the correct target sampling rate and normalize the input - # via the `feature_extractor` - feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(args.model_name_or_path) - - # make sure that dataset decodes audio with correct sampling rate - raw_datasets = raw_datasets.cast_column( - args.audio_column_name, datasets.features.Audio(sampling_rate=feature_extractor.sampling_rate) - ) - - # only normalized-inputs-training is supported - if not feature_extractor.do_normalize: - raise ValueError( - "Training is only supported for normalized inputs. Make sure ``feature_extractor.do_normalize == True``" - ) - - # set max & min audio length in number of samples - max_length = int(args.max_duration_in_seconds * feature_extractor.sampling_rate) - min_length = int(args.min_duration_in_seconds * feature_extractor.sampling_rate) - - def prepare_dataset(batch): - sample = batch[args.audio_column_name] - - inputs = feature_extractor( - sample["array"], sampling_rate=sample["sampling_rate"], max_length=max_length, truncation=True - ) - batch["input_values"] = inputs.input_values[0] - batch["input_length"] = len(inputs.input_values[0]) - - return batch - - # load via mapped files via path - cache_file_names = None - if args.train_cache_file_name is not None: - cache_file_names = {"train": args.train_cache_file_name, "validation": args.validation_cache_file_name} - - # load audio files into numpy arrays - with accelerator.main_process_first(): - vectorized_datasets = raw_datasets.map( - prepare_dataset, - num_proc=args.preprocessing_num_workers, - remove_columns=raw_datasets["train"].column_names, - cache_file_names=cache_file_names, - ) - - if min_length > 0.0: - vectorized_datasets = vectorized_datasets.filter( - lambda x: x > min_length, - num_proc=args.preprocessing_num_workers, - input_columns=["input_length"], - ) - - vectorized_datasets = vectorized_datasets.remove_columns("input_length") - - # for large datasets it is advised to run the preprocessing on a - # single machine first with ``args.preprocessing_only`` since there will mostly likely - # be a timeout when running the script in distributed mode. - # In a second step ``args.preprocessing_only`` can then be set to `False` to load the - # cached dataset - if args.preprocessing_only: - return - - # 3. Load model - config = Wav2Vec2Config.from_pretrained(args.model_name_or_path) - - # pretraining is only supported for "newer" stable layer norm architecture - # apply_spec_augment has to be True, mask_feature_prob has to be 0.0 - if not config.do_stable_layer_norm or config.feat_extract_norm != "layer": - raise ValueError( - "PreTraining is only supported for ``config.do_stable_layer_norm=True`` and" - " ``config.feat_extract_norm='layer'" - ) - - # initialize random model - model = Wav2Vec2ForPreTraining(config) - - # Activate gradient checkpointing if needed - if args.gradient_checkpointing: - model.gradient_checkpointing_enable() - - # 4. Define data collator, optimizer and scheduler - - mask_time_prob = config.mask_time_prob if args.mask_time_prob is None else args.mask_time_prob - mask_time_length = config.mask_time_length if args.mask_time_length is None else args.mask_time_length - - data_collator = DataCollatorForWav2Vec2Pretraining( - model=model, - feature_extractor=feature_extractor, - pad_to_multiple_of=args.pad_to_multiple_of, - mask_time_prob=mask_time_prob, - mask_time_length=mask_time_length, - ) - train_dataloader = DataLoader( - vectorized_datasets["train"], - shuffle=True, - collate_fn=data_collator, - batch_size=args.per_device_train_batch_size, - ) - eval_dataloader = DataLoader( - vectorized_datasets["validation"], collate_fn=data_collator, batch_size=args.per_device_eval_batch_size - ) - - # Optimizer - optimizer = torch.optim.AdamW( - list(model.parameters()), - lr=args.learning_rate, - betas=[args.adam_beta1, args.adam_beta2], - eps=args.adam_epsilon, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader - ) - - # Scheduler and math around the number of training steps. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps, - num_training_steps=args.max_train_steps, - ) - - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # 5. Train - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(vectorized_datasets['train'])}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - completed_steps = 0 - starting_epoch = 0 - - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - for step, batch in enumerate(train_dataloader): - # compute num of losses - num_losses = batch["mask_time_indices"].sum() - sub_attention_mask = batch.pop("sub_attention_mask", None) - sub_attention_mask = ( - sub_attention_mask if sub_attention_mask is not None else torch.ones_like(batch["mask_time_indices"]) - ) - percent_masked = num_losses / sub_attention_mask.sum() - - # forward - outputs = model(**batch) - - # divide loss by gradient accumulation steps since gradients - # are accumulated for multiple backward passes in PyTorch - loss = outputs.loss / args.gradient_accumulation_steps - accelerator.backward(loss) - - # make sure that `num_losses` is summed for distributed training - # and average gradients over losses of all devices - if accelerator.state.num_processes > 1: - num_losses = accelerator.gather_for_metrics(num_losses).sum() - gradient_multiplier = accelerator.state.num_processes / num_losses - multiply_grads(model.module.parameters(), gradient_multiplier) - else: - multiply_grads(model.parameters(), 1 / num_losses) - - # update step - if (step + 1) % args.gradient_accumulation_steps == 0 or step == len(train_dataloader) - 1: - # compute grad norm for monitoring - scale = ( - accelerator.scaler._scale.item() - if hasattr(accelerator, "scaler") and accelerator.scaler is not None - else 1 - ) - if accelerator.state.num_processes > 1: - grad_norm = get_grad_norm(model.module.parameters(), scale) - else: - grad_norm = get_grad_norm(model.parameters(), scale) - - # update parameters - optimizer.step() - optimizer.zero_grad() - - if not accelerator.optimizer_step_was_skipped: - lr_scheduler.step() - elif accelerator.is_local_main_process: - progress_bar.write( - f"Gradients have overflown - skipping update step... Updating gradient scale to {scale}..." - ) - - # update gumbel temperature - gumbel_temperature = max( - args.max_gumbel_temperature * args.gumbel_temperature_decay**completed_steps, - args.min_gumbel_temperature, - ) - if hasattr(model, "module"): - model.module.set_gumbel_temperature(gumbel_temperature) - else: - model.set_gumbel_temperature(gumbel_temperature) - - progress_bar.update(1) - completed_steps += 1 - - # 6. Log all results - if (step + 1) % (args.gradient_accumulation_steps * args.logging_steps) == 0: - loss.detach() - outputs.contrastive_loss.detach() - outputs.diversity_loss.detach() - - if accelerator.state.num_processes > 1: - loss = accelerator.gather_for_metrics(loss).sum() - outputs.contrastive_loss = accelerator.gather_for_metrics(outputs.contrastive_loss).sum() - outputs.diversity_loss = accelerator.gather_for_metrics(outputs.diversity_loss).sum() - percent_masked = accelerator.gather_for_metrics(percent_masked).sum() - - train_logs = { - "loss": (loss * args.gradient_accumulation_steps) / num_losses, - "constrast_loss": outputs.contrastive_loss / num_losses, - "div_loss": outputs.diversity_loss / num_losses, - "%_mask_idx": percent_masked / accelerator.num_processes, - "ppl": outputs.codevector_perplexity, - "lr": torch.tensor(optimizer.param_groups[0]["lr"]), - "temp": torch.tensor(gumbel_temperature), - "grad_norm": torch.tensor(grad_norm), - } - log_str = "" - for k, v in train_logs.items(): - log_str += f"| {k}: {v.item():.3e}" - - if accelerator.is_local_main_process: - progress_bar.write(log_str) - if is_wandb_available(): - wandb.log(train_logs) - - # save model every `args.saving_steps` steps - if (step + 1) % (args.gradient_accumulation_steps * args.saving_steps) == 0: - if (args.push_to_hub and epoch < args.num_train_epochs - 1) or args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - - if (args.push_to_hub and epoch < args.num_train_epochs - 1) and accelerator.is_main_process: - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - # if completed steps > `args.max_train_steps` stop - if completed_steps >= args.max_train_steps: - break - - # 7. Validate! - model.eval() - - # init logs - val_logs = { - "val_loss": 0, - "val_contrastive_loss": 0, - "val_diversity_loss": 0, - "val_num_losses": 0, - } - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - batch.pop("sub_attention_mask", None) - outputs = model(**batch) - - val_logs["val_loss"] += outputs.loss - val_logs["val_contrastive_loss"] += outputs.contrastive_loss - val_logs["val_diversity_loss"] += outputs.diversity_loss - val_logs["val_num_losses"] += batch["mask_time_indices"].sum() - - # sum over devices in multi-processing - if accelerator.num_processes > 1: - val_logs = {k: accelerator.gather_for_metrics(v).sum() for k, v in val_logs.items()} - - val_logs = {k: v / val_logs["val_num_losses"] for k, v in val_logs.items()} - - log_str = "" - for k, v in val_logs.items(): - log_str += f"| {k}: {v.item():.3e}" - - if accelerator.is_local_main_process: - progress_bar.write(log_str) - if is_wandb_available(): - wandb.log(val_logs) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/speech-recognition/README.md b/examples/pytorch/speech-recognition/README.md deleted file mode 100644 index 704b725076f0..000000000000 --- a/examples/pytorch/speech-recognition/README.md +++ /dev/null @@ -1,608 +0,0 @@ - - -# Automatic Speech Recognition Examples - -## Table of Contents - -- [Automatic Speech Recognition with CTC](#connectionist-temporal-classification) - - [Single GPU example](#single-gpu-ctc) - - [Multi GPU example](#multi-gpu-ctc) - - [Examples](#examples-ctc) - - [TIMIT](#timit-ctc) - - [Librispeech](#librispeech-ctc) - - [Common Voice](#common-voice-ctc) - - [Multilingual Librispeech](#multilingual-librispeech-ctc) -- [Automatic Speech Recognition with CTC and Adapter Layers](#connectionist-temporal-classification-with-adapters) - - [Massive Multilingual Speech (MMS)](#mms-model) - - [Examples](#examples-ctc-adapter) - - [Common Voice](#common-voice-ctc-adapter) -- [Automatic Speech Recognition with Sequence-to-Sequence](#sequence-to-sequence) - - [Whisper Model](#whisper-model) - - [Speech-Encoder-Decoder Model](#warm-started-speech-encoder-decoder-model) - - [Examples](#examples-seq2seq) - - [Librispeech](#librispeech-seq2seq) - -## Connectionist Temporal Classification - -The script [`run_speech_recognition_ctc.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/speech-recognition/run_speech_recognition_ctc.py) can be used to fine-tune any pretrained [Connectionist Temporal Classification Model](https://huggingface.co/docs/transformers/main/en/model_doc/auto#transformers.AutoModelForCTC) for automatic speech -recognition on one of the [official speech recognition datasets](https://huggingface.co/datasets?task_ids=task_ids:automatic-speech-recognition) or a custom dataset. - -Speech recognition models that have been pretrained in unsupervised fashion on audio data alone, *e.g.* [Wav2Vec2](https://huggingface.co/transformers/main/model_doc/wav2vec2.html), [HuBERT](https://huggingface.co/transformers/main/model_doc/hubert.html), [XLSR-Wav2Vec2](https://huggingface.co/transformers/main/model_doc/xlsr_wav2vec2.html), have shown to require only -very little annotated data to yield good performance on automatic speech recognition datasets. - -In the script [`run_speech_recognition_ctc`], we first create a vocabulary from all unique characters of both the training data and evaluation data. Then, we preprocesses the speech recognition dataset, which includes correct resampling, normalization and padding. Finally, the pretrained speech recognition model is fine-tuned on the annotated speech recognition datasets using CTC loss. - ---- -**NOTE** - -If you encounter problems with data preprocessing by setting `--preprocessing_num_workers` > 1, -you might want to set the environment variable `OMP_NUM_THREADS` to 1 as follows: - -```bash -OMP_NUM_THREADS=1 python run_speech_recognition_ctc ... -``` - -If the environment variable is not set, the training script might freeze, *i.e.* see: https://github.com/pytorch/audio/issues/1021#issuecomment-726915239 - ---- - -### Single GPU CTC - -The following command shows how to fine-tune [XLSR-Wav2Vec2](https://huggingface.co/transformers/main/model_doc/xlsr_wav2vec2.html) on [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice) using a single GPU in half-precision. - -```bash -python run_speech_recognition_ctc.py \ - --dataset_name="mozilla-foundation/common_voice_17_0" \ - --model_name_or_path="facebook/wav2vec2-large-xlsr-53" \ - --dataset_config_name="tr" \ - --output_dir="./wav2vec2-common_voice-tr-demo" \ - --num_train_epochs="15" \ - --per_device_train_batch_size="16" \ - --gradient_accumulation_steps="2" \ - --learning_rate="3e-4" \ - --warmup_steps="500" \ - --eval_strategy="steps" \ - --text_column_name="sentence" \ - --length_column_name="input_length" \ - --save_steps="400" \ - --eval_steps="100" \ - --layerdrop="0.0" \ - --save_total_limit="3" \ - --freeze_feature_encoder \ - --gradient_checkpointing \ - --chars_to_ignore , ? . ! - \; \: \" “ % ‘ ” � \ - --fp16 \ - --train_sampling_strategy group_by_length \ - --push_to_hub \ - --do_train --do_eval -``` - -On a single V100 GPU, this script should run in *ca.* 1 hour 20 minutes and yield a CTC loss of **0.39** and word error rate -of **0.35**. - -### Multi GPU CTC - -The following command shows how to fine-tune [XLSR-Wav2Vec2](https://huggingface.co/transformers/main/model_doc/xlsr_wav2vec2.html) on [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice) using 8 GPUs in half-precision. - -```bash -torchrun \ - --nproc_per_node 8 run_speech_recognition_ctc.py \ - --dataset_name="mozilla-foundation/common_voice_17_0" \ - --model_name_or_path="facebook/wav2vec2-large-xlsr-53" \ - --dataset_config_name="tr" \ - --output_dir="./wav2vec2-common_voice-tr-demo-dist" \ - --num_train_epochs="15" \ - --per_device_train_batch_size="4" \ - --learning_rate="3e-4" \ - --warmup_steps="500" \ - --eval_strategy="steps" \ - --text_column_name="sentence" \ - --length_column_name="input_length" \ - --save_steps="400" \ - --eval_steps="100" \ - --logging_steps="1" \ - --layerdrop="0.0" \ - --save_total_limit="3" \ - --freeze_feature_encoder \ - --gradient_checkpointing \ - --chars_to_ignore , ? . ! - \; \: \" “ % ‘ ” � \ - --fp16 \ - --train_sampling_strategy group_by_length \ - --push_to_hub \ - --do_train --do_eval -``` - -On 8 V100 GPUs, this script should run in *ca.* 18 minutes and yield a CTC loss of **0.39** and word error rate -of **0.36**. - - -### Multi GPU CTC with Dataset Streaming - -The following command shows how to use [Dataset Streaming mode](https://huggingface.co/docs/datasets/dataset_streaming) -to fine-tune [XLS-R](https://huggingface.co/transformers/main/model_doc/xls_r.html) -on [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice) using 4 GPUs in half-precision. - -Streaming mode imposes several constraints on training: -1. We need to construct a tokenizer beforehand and define it via `--tokenizer_name_or_path`. -2. `--num_train_epochs` has to be replaced by `--max_steps`. Similarly, all other epoch-based arguments have to be -replaced by step-based ones. -3. Full dataset shuffling on each epoch is not possible, since we don't have the whole dataset available at once. -However, the `--shuffle_buffer_size` argument controls how many examples we can pre-download before shuffling them. - - -```bash -**torchrun \ - --nproc_per_node 4 run_speech_recognition_ctc_streaming.py \ - --dataset_name="mozilla-foundation/common_voice_17_0" \ - --model_name_or_path="facebook/wav2vec2-xls-r-300m" \ - --tokenizer_name_or_path="anton-l/wav2vec2-tokenizer-turkish" \ - --dataset_config_name="tr" \ - --train_split_name="train+validation" \ - --eval_split_name="test" \ - --output_dir="wav2vec2-xls-r-common_voice-tr-ft" \ - --max_steps="5000" \ - --per_device_train_batch_size="8" \ - --gradient_accumulation_steps="2" \ - --learning_rate="5e-4" \ - --warmup_steps="500" \ - --eval_strategy="steps" \ - --text_column_name="sentence" \ - --save_steps="500" \ - --eval_steps="500" \ - --logging_steps="1" \ - --layerdrop="0.0" \ - --eval_metrics wer cer \ - --save_total_limit="1" \ - --mask_time_prob="0.3" \ - --mask_time_length="10" \ - --mask_feature_prob="0.1" \ - --mask_feature_length="64" \ - --freeze_feature_encoder \ - --chars_to_ignore , ? . ! - \; \: \" “ % ‘ ” � \ - --max_duration_in_seconds="20" \ - --shuffle_buffer_size="500" \ - --fp16 \ - --push_to_hub \ - --do_train --do_eval \ - --gradient_checkpointing** -``` - -On 4 V100 GPUs, this script should run in *ca.* 3h 31min and yield a CTC loss of **0.35** and word error rate -of **0.29**. - -### Examples CTC - -The following tables present a couple of example runs on the most popular speech-recognition datasets. -The presented performances are by no means optimal as no hyper-parameter tuning was done. Nevertheless, -they can serve as a baseline to improve upon. - - -#### TIMIT CTC - -- [TIMIT](https://huggingface.co/datasets/timit-asr/timit_asr) - -| Dataset | Dataset Config | Pretrained Model | Word error rate on eval | Phoneme error rate on eval | GPU setup | Training time | Fine-tuned Model & Logs | Command to reproduce | -|-------|------------------------------|-------------|---------------|---------------|----------------------|-------------| -------------| ------- | -| [TIMIT](https://huggingface.co/datasets/timit-asr/timit_asr)| - | [wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base) | 0.21 | - | 1 GPU TITAN RTX | 32min | [here](https://huggingface.co/patrickvonplaten/wav2vec2-base-timit-fine-tuned) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-base-timit-fine-tuned/blob/main/run.sh) | -| [TIMIT](https://huggingface.co/datasets/timit-asr/timit_asr)| - | [wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base) | 0.21 | - | 1 GPU TITAN RTX | 32min | [here](https://huggingface.co/patrickvonplaten/wav2vec2-base-timit-fine-tuned) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-base-timit-fine-tuned/blob/main/run.sh) | -| [TIMIT](https://huggingface.co/datasets/timit-asr/timit_asr)| - | [unispeech-large-1500h-cv](https://huggingface.co/microsoft/unispeech-large-1500h-cv) | 0.22 | - | 1 GPU TITAN RTX | 35min | [here](https://huggingface.co/patrickvonplaten/unispeech-large-1500h-cv-timit) | [run.sh](https://huggingface.co/patrickvonplaten/unispeech-large-1500h-cv-timit/blob/main/run.sh) | -| [TIMIT](https://huggingface.co/datasets/timit-asr/timit_asr)| - | [asapp/sew-mid-100k](https://huggingface.co/asapp/sew-mid-100k) | 0.30 | - | 1 GPU TITAN RTX | 28min | [here](https://huggingface.co/patrickvonplaten/sew-small-100k-timit) | [run.sh](https://huggingface.co/patrickvonplaten/sew-small-100k-timit/blob/main/run.sh) | -| [TIMIT](https://huggingface.co/datasets/timit-asr/timit_asr)| - | [ntu-spml/distilhubert](https://huggingface.co/ntu-spml/distilhubert) | 0.68 | - | 1 GPU TITAN RTX | 26min | [here](https://huggingface.co/patrickvonplaten/distilhubert-timit) | [run.sh](https://huggingface.co/patrickvonplaten/distilhubert-timit/blob/main/run.sh) | - - -#### Librispeech CTC - -- [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr) - -| Dataset | Dataset Config | Pretrained Model | Word error rate on eval | Phoneme error rate on eval | GPU setup | Training time | Fine-tuned Model & Logs | Command to reproduce | -|-------|------------------------------|-------------|---------------|---------------|----------------------|-------------| -------------| ------- | -| [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr)| `"clean"` - `"train.100"` | [microsoft/wavlm-large](https://huggingface.co/microsoft/wavlm-large) | 0.049 | - | 8 GPU V100 | 1h30min | [here](https://huggingface.co/patrickvonplaten/wavlm-libri-clean-100h-large) | [run.sh](https://huggingface.co/patrickvonplaten/wavlm-libri-clean-100h-large/blob/main/run.sh) | -| [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr)| `"clean"` - `"train.100"` | [microsoft/wavlm-base-plus](https://huggingface.co/microsoft/wavlm-base-plus) | 0.068 | - | 8 GPU V100 | 1h30min | [here](https://huggingface.co/patrickvonplaten/wavlm-libri-clean-100h-base-plus) | [run.sh](https://huggingface.co/patrickvonplaten/wavlm-libri-clean-100h-base-plus/blob/main/run.sh) | -| [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr)| `"clean"` - `"train.100"` | [facebook/wav2vec2-large-lv60](https://huggingface.co/facebook/wav2vec2-large-lv60) | 0.042 | - | 8 GPU V100 | 1h30min | [here](https://huggingface.co/patrickvonplaten/wav2vec2-librispeech-clean-100h-demo-dist) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-librispeech-clean-100h-demo-dist/blob/main/run.sh) | -| [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr)| `"clean"` - `"train.100"` | [facebook/wav2vec2-large-lv60](https://huggingface.co/facebook/wav2vec2-large-lv60) | 0.042 | - | 8 GPU V100 | 1h30min | [here](https://huggingface.co/patrickvonplaten/wav2vec2-librispeech-clean-100h-demo-dist) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-librispeech-clean-100h-demo-dist/blob/main/run.sh) | -| [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr)| `"clean"` - `"train.100"` | [facebook/hubert-large-ll60k](https://huggingface.co/facebook/hubert-large-ll60k) | 0.088 | - | 8 GPU V100 | 1h30min | [here](https://huggingface.co/patrickvonplaten/hubert-librispeech-clean-100h-demo-dist) | [run.sh](https://huggingface.co/patrickvonplaten/hubert-librispeech-clean-100h-demo-dist/blob/main/run.sh) | -| [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr)| `"clean"` - `"train.100"` | [asapp/sew-mid-100k](https://huggingface.co/asapp/sew-mid-100k) | 0.167 | | 8 GPU V100 | 54min | [here](https://huggingface.co/patrickvonplaten/sew-mid-100k-librispeech-clean-100h-ft) | [run.sh](https://huggingface.co/patrickvonplaten/sew-mid-100k-librispeech-clean-100h-ft/blob/main/run.sh) | - - -#### Common Voice CTC - -- [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice) - -| Dataset | Dataset Config | Pretrained Model | Word error rate on eval | Phoneme error rate on eval | GPU setup | Training time | Fine-tuned Model & Logs | Command to reproduce | -|-------|------------------------------|-------------|---------------|---------------|----------------------|-------------| -------------| ------- | -| [Common Voice](https://huggingface.co/datasets/mozilla-foundation/common_voice_3_0)| `"tr"` | [facebook/wav2vec2-large-xls-r-300m](https://huggingface.co/facebook/wav2vec2-xls-r-300m) | - | 0.099 | 8 GPU V100 | 23min | [here](https://huggingface.co/patrickvonplaten/xls-r-300m-tr-phoneme) | [run.sh](https://huggingface.co/patrickvonplaten/xls-r-300m-tr-phoneme/blob/main/run.sh) | -| [Common Voice](https://huggingface.co/datasets/mozilla-foundation/common_voice_3_0)| `"it"` | [facebook/wav2vec2-large-xls-r-300m](https://huggingface.co/facebook/wav2vec2-xls-r-300m) | - | 0.077 | 8 GPU V100 | 23min | [here](https://huggingface.co/patrickvonplaten/xls-r-300m-it-phoneme) | [run.sh](https://huggingface.co/patrickvonplaten/xls-r-300m-it-phoneme/blob/main/run.sh) | -| [Common Voice](https://huggingface.co/datasets/mozilla-foundation/common_voice_3_0)| `"sv-SE"` | [facebook/wav2vec2-large-xls-r-300m](https://huggingface.co/facebook/wav2vec2-xls-r-300m) | - | 0.099 | 8 GPU V100 | 23min | [here](https://huggingface.co/patrickvonplaten/xls-r-300m-sv-phoneme) | [run.sh](https://huggingface.co/patrickvonplaten/xls-r-300m-sv-phoneme/blob/main/run.sh) | -| [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice)| `"tr"` | [facebook/wav2vec2-large-xlsr-53](https://huggingface.co/facebook/wav2vec2-large-xlsr-53) | 0.36 | - | 8 GPU V100 | 18min | [here](https://huggingface.co/patrickvonplaten/wav2vec2-common_voice-tr-demo-dist) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-common_voice-tr-demo-dist/blob/main/run_dist.sh) | -| [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice)| `"tr"` | [facebook/wav2vec2-large-xlsr-53](https://huggingface.co/facebook/wav2vec2-large-xlsr-53) | 0.31 | - | 8 GPU V100 | 1h05 | [here](https://huggingface.co/patrickvonplaten/wav2vec2-large-xlsr-53-common_voice-tr-ft) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-large-xlsr-53-common_voice-tr-ft/blob/main/run.sh) | -| [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice)| `"tr"` | [facebook/wav2vec2-large-xlsr-53](https://huggingface.co/facebook/wav2vec2-large-xlsr-53) | 0.35 | - | 1 GPU V100 | 1h20min | [here](https://huggingface.co/patrickvonplaten/wav2vec2-common_voice-tr-demo) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-common_voice-tr-demo/blob/main/run.sh) | -| [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice)| `"tr"` | [facebook/wav2vec2-xls-r-300m](https://huggingface.co/facebook/wav2vec2-xls-r-300m) | 0.31 | - | 8 GPU V100 | 1h05 | [here](https://huggingface.co/patrickvonplaten/wav2vec2-large-xls-r-300m-common_voice-tr-ft) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-large-xls-r-300m-common_voice-tr-ft/blob/main/run.sh) | -| [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice)| `"tr"` | [facebook/wav2vec2-xls-r-1b](https://huggingface.co/facebook/wav2vec2-xls-r-1b) | 0.21 | - | 2 GPU Titan 24 GB RAM | 15h10 | [here](https://huggingface.co/patrickvonplaten/wav2vec2-xls-r-1b-common_voice-tr-ft) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-large-xls-r-1b-common_voice-tr-ft/blob/main/run.sh) | -| [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice)| `"tr"` in streaming mode | [facebook/wav2vec2-xls-r-300m](https://huggingface.co/facebook/wav2vec2-xls-r-300m) | 0.29 | - | 4 GPU V100 | 3h31 | [here](https://huggingface.co/anton-l/wav2vec2-xls-r-common_voice-tr-ft-stream) | [run.sh](https://huggingface.co/anton-l/wav2vec2-xls-r-common_voice-tr-ft-stream/blob/main/run.sh) | - - -#### Multilingual Librispeech CTC - -- [Multilingual Librispeech](https://huggingface.co/datasets/facebook/multilingual_librispeech) - -| Dataset | Dataset Config | Pretrained Model | Word error rate on eval | Phoneme error rate on eval | GPU setup | Training time | Fine-tuned Model & Logs | Command to reproduce | -|-------|------------------------------|-------------|---------------|---------------|----------------------|-------------| -------------| ------- | -| [Multilingual Librispeech](https://huggingface.co/datasets/facebook/multilingual_librispeech)| `"german"` | [facebook/wav2vec2-large-xlsr-53](https://huggingface.co/facebook/wav2vec2-large-xlsr-53) | 0.13 | - | 1 GPU Titan 24 GB RAM | 15h04 | [here](https://huggingface.co/patrickvonplaten/wav2vec2-xlsr-53-300m-mls-german-ft) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-xlsr-53-300m-mls-german-ft/blob/main/run.sh) | -| [Multilingual Librispeech](https://huggingface.co/datasets/facebook/multilingual_librispeech)| `"german"` | [facebook/wav2vec2-xls-r-300m](https://huggingface.co/facebook/wav2vec2-xls-r-300m) | 0.15 | - | 1 GPU Titan 24 GB RAM | 15h04 | [here](https://huggingface.co/patrickvonplaten/wav2vec2-300m-mls-german-ft) | [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-300m-mls-german-ft/blob/main/run.sh) | - -## Connectionist Temporal Classification With Adapters - -The script [`run_speech_recognition_ctc_adapter.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/speech-recognition/run_speech_recognition_ctc_adapter.py) can be used to fine-tune adapter layers for [Wav2Vec2-like models like MMS](https://huggingface.co/docs/transformers/main/en/model_doc/mms) for automatic speech recognition. - -### MMS Model - -The [Massive Multilingual Speech (MMS) model](https://huggingface.co/facebook/mms-1b-all) has been pre-trained and fine-tuned -on 1000+ languages. The model makes use of adapter attention layers to fine-tune only a small part -of the model on a specific language. The model already comes with fine-tuned adapter layers for 1000+ languages and -can be used for inference for 1000+ languages out of the box. - -However, for improved performance or more specific use cases one can re-initialize the adapter weights, freeze all -other weights and fine-tune them on a specific dataset as shown in the [example below](#examples-ctc-adapter). - -Note that the adapter weights include low dimensional linear layers for every attention block as well as the final language -model head layers. - -### Examples CTC Adapter - -In the following we will look at how one can fine-tune adapter weights for any of the -[MMS CTC checkpoints](https://huggingface.co/models?pipeline_tag=automatic-speech-recognition&other=mms&sort=downloads) in less than 1 hour. - -#### Common Voice CTC Adapter - -As in the examples [above](#examples-ctc), we fine-tune on Common Voice's 6 dataset in Turkish as an example. -Contrary to [`run_speech_recognition_ctc.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/speech-recognition/run_speech_recognition_ctc.py) before there is a `--target_language` which has to be defined to state for which -language or concept the adapter layers shall be trained. The adapter weights will then -accordingly be called `adapter.{/wav2vec2-2-bart-base -cd wav2vec2-2-bart-base -``` - -Next, run the following script **inside** the just cloned repo: - -```python -from transformers import SpeechEncoderDecoderModel, AutoFeatureExtractor, AutoTokenizer, Wav2Vec2Processor - -# checkpoints to leverage -encoder_id = "facebook/wav2vec2-base" -decoder_id = "facebook/bart-base" - -# load and save speech-encoder-decoder model -# set some hyper-parameters for training and evaluation -model = SpeechEncoderDecoderModel.from_encoder_decoder_pretrained(encoder_id, decoder_id, encoder_add_adapter=True, encoder_feat_proj_dropout=0.0, encoder_layerdrop=0.0, max_length=200, num_beams=5) -model.config.decoder_start_token_id = model.decoder.config.bos_token_id -model.config.pad_token_id = model.decoder.config.pad_token_id -model.config.eos_token_id = model.decoder.config.eos_token_id -model.save_pretrained("./") - -# load and save processor -feature_extractor = AutoFeatureExtractor.from_pretrained(encoder_id) -tokenizer = AutoTokenizer.from_pretrained(decoder_id) -processor = Wav2Vec2Processor(feature_extractor, tokenizer) -processor.save_pretrained("./") -``` - -Finally, we can upload all files: -```bash -git lfs install -git add . && git commit -m "upload model files" && git push -``` - -and link the official `run_speech_recognition_seq2seq.py` script to the folder: - -```bash -ln -s $(realpath /examples/pytorch/speech-recognition/run_speech_recognition_seq2seq.py) ./ -``` - -Note that we have added a randomly initialized _adapter layer_ to `wav2vec2-base` with the argument -`encoder_add_adapter=True`. This adapter sub-samples the output sequence of -`wav2vec2-base` along the time dimension. By default, a single -output vector of `wav2vec2-base` has a receptive field of *ca.* 25ms (*cf.* -Section *4.2* of the [official Wav2Vec2 paper](https://huggingface.co/papers/2006.11477)), which represents a little less a single character. On the other hand, BART -makes use of a sentence-piece tokenizer as an input processor, so that a single -hidden vector of `bart-base` represents *ca.* 4 characters. To better align the -receptive field of the *Wav2Vec2* output vectors with *BART*'s hidden-states in the cross-attention -mechanism, we further subsample *Wav2Vec2*'s output by a factor of 8 by -adding a convolution-based adapter. - -Having warm-started the speech-encoder-decoder model under `/wav2vec2-2-bart`, we can now fine-tune it on the task of speech recognition. - -In the script [`run_speech_recognition_seq2seq`], we load the warm-started model, -feature extractor, and tokenizer, process a speech recognition dataset, -and subsequently make use of the [`Seq2SeqTrainer`](https://huggingface.co/docs/transformers/main/en/main_classes/trainer#transformers.Seq2SeqTrainer) to train our system. -Note that it is important to align the target transcriptions with the decoder's vocabulary. For example, the [`Librispeech`](https://huggingface.co/datasets/openslr/librispeech_asr) dataset only contains capitalized letters in the transcriptions, -whereas BART was pretrained mostly on normalized text. Thus, it is recommended to add the argument -`--do_lower_case` to the fine-tuning script when using a warm-started `SpeechEncoderDecoderModel`. -The model is fine-tuned on the standard cross-entropy language modeling -loss for sequence-to-sequence (just like *T5* or *BART* in natural language processing). - ---- -**NOTE** - -If you encounter problems with data preprocessing by setting `--preprocessing_num_workers` > 1, -you might want to set the environment variable `OMP_NUM_THREADS` to 1 as follows: - -```bash -OMP_NUM_THREADS=1 python run_speech_recognition_ctc ... -``` - -If the environment variable is not set, the training script might freeze, *i.e.* see: https://github.com/pytorch/audio/issues/1021#issuecomment-726915239. - ---- - -#### Single GPU Seq2Seq - -The following command shows how to fine-tune [XLSR-Wav2Vec2](https://huggingface.co/transformers/main/model_doc/xlsr_wav2vec2.html) on [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice) using a single GPU in half-precision. - -```bash -python run_speech_recognition_seq2seq.py \ - --dataset_name="openslr/librispeech_asr" \ - --model_name_or_path="./" \ - --dataset_config_name="clean" \ - --train_split_name="train.100" \ - --eval_split_name="validation" \ - --output_dir="./" \ - --preprocessing_num_workers="16" \ - --length_column_name="input_length" \ - --num_train_epochs="5" \ - --per_device_train_batch_size="8" \ - --per_device_eval_batch_size="8" \ - --gradient_accumulation_steps="8" \ - --learning_rate="3e-4" \ - --warmup_steps="400" \ - --eval_strategy="steps" \ - --text_column_name="text" \ - --save_steps="400" \ - --eval_steps="400" \ - --logging_steps="10" \ - --save_total_limit="1" \ - --freeze_feature_encoder \ - --gradient_checkpointing \ - --fp16 \ - --train_sampling_strategy group_by_length \ - --predict_with_generate \ - --generation_max_length="40" \ - --generation_num_beams="1" \ - --do_train --do_eval \ - --do_lower_case -``` - -On a single V100 GPU, this script should run in *ca.* 5 hours and yield a -cross-entropy loss of **0.405** and word error rate of **0.0728**. - -#### Multi GPU Seq2Seq - -The following command shows how to fine-tune [XLSR-Wav2Vec2](https://huggingface.co/transformers/main/model_doc/xlsr_wav2vec2.html) on [Common Voice](https://huggingface.co/datasets/legacy-datasets/common_voice) using 8 GPUs in half-precision. - -```bash -torchrun \ - --nproc_per_node 8 run_speech_recognition_seq2seq.py \ - --dataset_name="openslr/librispeech_asr" \ - --model_name_or_path="./" \ - --dataset_config_name="clean" \ - --train_split_name="train.100" \ - --eval_split_name="validation" \ - --output_dir="./" \ - --preprocessing_num_workers="16" \ - --length_column_name="input_length" \ - --num_train_epochs="5" \ - --per_device_train_batch_size="8" \ - --per_device_eval_batch_size="8" \ - --gradient_accumulation_steps="1" \ - --learning_rate="3e-4" \ - --warmup_steps="400" \ - --eval_strategy="steps" \ - --text_column_name="text" \ - --save_steps="400" \ - --eval_steps="400" \ - --logging_steps="10" \ - --save_total_limit="1" \ - --freeze_feature_encoder \ - --gradient_checkpointing \ - --fp16 \ - --train_sampling_strategy group_by_length \ - --predict_with_generate \ - --do_train --do_eval \ - --do_lower_case -``` - -On 8 V100 GPUs, this script should run in *ca.* 45 minutes and yield a cross-entropy loss of **0.405** and word error rate of **0.0728** - -### Examples Seq2Seq - -#### Librispeech Seq2Seq - -- [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr) - -| Dataset | Dataset Config | Pretrained Model | Word error rate on eval | Phoneme error rate on eval | GPU setup | Training time | Fine-tuned Model & Logs | Command to reproduce | -|----------------------------------------------------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------|----------------------------|------------|---------------|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr) | `"clean"` - `"train.100"` | [facebook/wav2vec2-base](https://huggingface.co/facebook/wav2vec2-base) and [facebook/bart-base](https://huggingface.co/facebook/bart-base) | 0.0728 | - | 8 GPU V100 | 45min | [here](https://huggingface.co/patrickvonplaten/wav2vec2-2-bart-base) | [create_model.py](https://huggingface.co/patrickvonplaten/wav2vec2-2-bart-base/blob/main/create_model.py) & [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-2-bart-base/blob/main/run_librispeech.sh) | -| [Librispeech](https://huggingface.co/datasets/openslr/librispeech_asr) | `"clean"` - `"train.100"` | [facebook/wav2vec2-large-lv60](https://huggingface.co/facebook/wav2vec2-large-lv60) and [facebook/bart-large](https://huggingface.co/facebook/bart-large) | 0.0486 | - | 8 GPU V100 | 1h20min | [here](https://huggingface.co/patrickvonplaten/wav2vec2-2-bart-large) | [create_model.py](https://huggingface.co/patrickvonplaten/wav2vec2-2-bart-large/blob/main/create_model.py) & [run.sh](https://huggingface.co/patrickvonplaten/wav2vec2-2-bart-large/blob/main/run_librispeech.sh) | diff --git a/examples/pytorch/speech-recognition/requirements.txt b/examples/pytorch/speech-recognition/requirements.txt deleted file mode 100644 index 4137ea02ad76..000000000000 --- a/examples/pytorch/speech-recognition/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -datasets[audio] >= 1.18.0 -torch >= 1.5 -torchaudio -librosa -jiwer -evaluate diff --git a/examples/pytorch/speech-recognition/run_speech_recognition_ctc.py b/examples/pytorch/speech-recognition/run_speech_recognition_ctc.py deleted file mode 100755 index aa63dcbe11fe..000000000000 --- a/examples/pytorch/speech-recognition/run_speech_recognition_ctc.py +++ /dev/null @@ -1,813 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "datasets[audio] >= 1.18.0", -# "torch >= 1.5", -# "torchaudio", -# "librosa", -# "jiwer", -# "evaluate", -# ] -# /// - -"""Fine-tuning a 🤗 Transformers CTC model for automatic speech recognition""" - -import functools -import json -import logging -import os -import re -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -import torch -from datasets import DatasetDict, load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoFeatureExtractor, - AutoModelForCTC, - AutoProcessor, - AutoTokenizer, - HfArgumentParser, - Trainer, - TrainingArguments, - set_seed, -) -from transformers.trainer_utils import is_main_process -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version( - "datasets>=1.18.0", - "To fix: pip install -r examples/pytorch/speech-recognition/requirements.txt", -) - - -logger = logging.getLogger(__name__) - - -def list_field(default=None, metadata=None): - return field(default_factory=lambda: default, metadata=metadata) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - tokenizer_name_or_path: str | None = field( - default=None, - metadata={"help": "Path to pretrained tokenizer or tokenizer identifier from huggingface.co/models"}, - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - freeze_feature_encoder: bool = field( - default=True, - metadata={"help": "Whether to freeze the feature encoder layers of the model."}, - ) - attention_dropout: float = field( - default=0.0, - metadata={"help": "The dropout ratio for the attention probabilities."}, - ) - activation_dropout: float = field( - default=0.0, - metadata={"help": "The dropout ratio for activations inside the fully connected layer."}, - ) - feat_proj_dropout: float = field(default=0.0, metadata={"help": "The dropout ratio for the projected features."}) - hidden_dropout: float = field( - default=0.0, - metadata={ - "help": "The dropout probability for all fully connected layers in the embeddings, encoder, and pooler." - }, - ) - final_dropout: float = field( - default=0.0, - metadata={"help": "The dropout probability for the final projection layer."}, - ) - mask_time_prob: float = field( - default=0.05, - metadata={ - "help": ( - "Probability of each feature vector along the time axis to be chosen as the start of the vector " - "span to be masked. Approximately ``mask_time_prob * sequence_length // mask_time_length`` feature " - "vectors will be masked along the time axis." - ) - }, - ) - mask_time_length: int = field( - default=10, - metadata={"help": "Length of vector span to mask along the time axis."}, - ) - mask_feature_prob: float = field( - default=0.0, - metadata={ - "help": ( - "Probability of each feature vector along the feature axis to be chosen as the start of the vectorspan" - " to be masked. Approximately ``mask_feature_prob * sequence_length // mask_feature_length`` feature" - " bins will be masked along the time axis." - ) - }, - ) - mask_feature_length: int = field( - default=10, - metadata={"help": "Length of vector span to mask along the feature axis."}, - ) - layerdrop: float = field(default=0.0, metadata={"help": "The LayerDrop probability."}) - ctc_loss_reduction: str | None = field( - default="mean", - metadata={"help": "The way the ctc loss should be reduced. Should be one of 'mean' or 'sum'."}, - ) - ctc_zero_infinity: bool | None = field( - default=False, - metadata={ - "help": "Whether to zero infinite losses and the associated gradients of `torch.nn.CTCLoss`. Infinite losses mainly" - " occur when the inputs are too short to be aligned to the targets." - }, - ) - add_adapter: bool | None = field( - default=False, - metadata={ - "help": "Whether a convolutional attention network should be stacked on top of the Wav2Vec2Bert Encoder. Can be very" - "useful to downsample the output length." - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - - Using `HfArgumentParser` we can turn this class - into argparse arguments to be able to specify them on - the command line. - """ - - dataset_name: str = field( - metadata={"help": "Path or name of the dataset (cf `load_dataset` method of the Datasets library)."} - ) - dataset_config_name: str = field( - default=None, - metadata={ - "help": "The configuration name of the dataset to use (cf `load_dataset` method of the Datasets library)." - }, - ) - train_split_name: str = field( - default="train+validation", - metadata={ - "help": ( - "The name of the training data set split to use (via the datasets library). Defaults to " - "'train+validation'" - ) - }, - ) - eval_split_name: str = field( - default="test", - metadata={ - "help": "The name of the evaluation data set split to use (via the datasets library). Defaults to 'test'" - }, - ) - audio_column_name: str = field( - default="audio", - metadata={"help": "The name of the dataset column containing the audio data. Defaults to 'audio'"}, - ) - text_column_name: str = field( - default="text", - metadata={"help": "The name of the dataset column containing the text data. Defaults to 'text'"}, - ) - overwrite_cache: bool = field( - default=False, - metadata={"help": "Overwrite the cached preprocessed datasets or not."}, - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of validation examples to this " - "value if set." - ) - }, - ) - chars_to_ignore: list[str] | None = list_field( - default=None, - metadata={"help": "A list of characters to remove from the transcripts."}, - ) - eval_metrics: list[str] = list_field( - default=["wer"], - metadata={"help": "A list of metrics the model should be evaluated on. E.g. `'wer cer'`"}, - ) - max_duration_in_seconds: float = field( - default=20.0, - metadata={ - "help": ( - "Filter audio files that are longer than `max_duration_in_seconds` seconds to" - " 'max_duration_in_seconds`" - ) - }, - ) - min_duration_in_seconds: float = field( - default=0.0, - metadata={"help": "Filter audio files that are shorter than `min_duration_in_seconds` seconds"}, - ) - preprocessing_only: bool = field( - default=False, - metadata={ - "help": ( - "Whether to only do data preprocessing and skip training. This is especially useful when data" - " preprocessing errors out in distributed training due to timeout. In this case, one should run the" - " preprocessing in a non-distributed setup with `preprocessing_only=True` so that the cached datasets" - " can consequently be loaded in distributed training" - ) - }, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - unk_token: str = field( - default="[UNK]", - metadata={"help": "The unk token for the tokenizer"}, - ) - pad_token: str = field( - default="[PAD]", - metadata={"help": "The padding token for the tokenizer"}, - ) - word_delimiter_token: str = field( - default="|", - metadata={"help": "The word delimiter token for the tokenizer"}, - ) - phoneme_language: str | None = field( - default=None, - metadata={ - "help": ( - "The target language that should be used be" - " passed to the tokenizer for tokenization. Note that" - " this is only relevant if the model classifies the" - " input audio to a sequence of phoneme sequences." - ) - }, - ) - - -@dataclass -class DataCollatorCTCWithPadding: - """ - Data collator that will dynamically pad the inputs received. - Args: - processor (:class:`~transformers.AutoProcessor`) - The processor used for processing the data. - padding (:obj:`bool`, :obj:`str` or :class:`~transformers.tokenization_utils_base.PaddingStrategy`, `optional`, defaults to :obj:`True`): - Select a strategy to pad the returned sequences (according to the model's padding side and padding index) - among: - * :obj:`True` or :obj:`'longest'`: Pad to the longest sequence in the batch (or no padding if only a single - sequence if provided). - * :obj:`'max_length'`: Pad to a maximum length specified with the argument :obj:`max_length` or to the - maximum acceptable input length for the model if that argument is not provided. - * :obj:`False` or :obj:`'do_not_pad'` (default): No padding (i.e., can output a batch with sequences of - different lengths). - max_length (:obj:`int`, `optional`): - Maximum length of the ``input_values`` of the returned list and optionally padding length (see above). - max_length_labels (:obj:`int`, `optional`): - Maximum length of the ``labels`` returned list and optionally padding length (see above). - pad_to_multiple_of (:obj:`int`, `optional`): - If set will pad the sequence to a multiple of the provided value. - This is especially useful to enable the use of Tensor Cores on NVIDIA hardware with compute capability >= - 7.5 (Volta). - """ - - processor: AutoProcessor - padding: bool | str = "longest" - pad_to_multiple_of: int | None = None - pad_to_multiple_of_labels: int | None = None - feature_extractor_input_name: str | None = "input_values" - - def __call__(self, features: list[dict[str, list[int] | torch.Tensor]]) -> dict[str, torch.Tensor]: - # split inputs and labels since they have to be of different lengths and need - # different padding methods - input_features = [ - {self.feature_extractor_input_name: feature[self.feature_extractor_input_name]} for feature in features - ] - label_features = [{"input_ids": feature["labels"]} for feature in features] - - batch = self.processor.pad( - input_features, - padding=self.padding, - pad_to_multiple_of=self.pad_to_multiple_of, - return_tensors="pt", - ) - - labels_batch = self.processor.pad( - labels=label_features, - padding=self.padding, - pad_to_multiple_of=self.pad_to_multiple_of_labels, - return_tensors="pt", - ) - - # replace padding with -100 to ignore loss correctly - labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100) - - batch["labels"] = labels - if "attention_mask" in batch: - batch["attention_mask"] = batch["attention_mask"].to(torch.long) - - return batch - - -def create_vocabulary_from_data( - datasets: DatasetDict, - word_delimiter_token: str | None = None, - unk_token: str | None = None, - pad_token: str | None = None, -): - # Given training and test labels create vocabulary - def extract_all_chars(batch): - all_text = " ".join(batch["target_text"]) - vocab = list(set(all_text)) - return {"vocab": [vocab], "all_text": [all_text]} - - vocabs = datasets.map( - extract_all_chars, - batched=True, - batch_size=-1, - keep_in_memory=True, - remove_columns=datasets["train"].column_names, - ) - - # take union of all unique characters in each dataset - vocab_set = functools.reduce( - lambda vocab_1, vocab_2: set(vocab_1["vocab"][0]) | set(vocab_2["vocab"][0]), - vocabs.values(), - ) - - vocab_dict = {v: k for k, v in enumerate(sorted(vocab_set))} - - # replace white space with delimiter token - if word_delimiter_token is not None: - vocab_dict[word_delimiter_token] = vocab_dict[" "] - del vocab_dict[" "] - - # add unk and pad token - if unk_token is not None: - vocab_dict[unk_token] = len(vocab_dict) - - if pad_token is not None: - vocab_dict[pad_token] = len(vocab_dict) - - return vocab_dict - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - logger.setLevel(logging.INFO if is_main_process(training_args.local_process_index) else logging.WARN) - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - # Set the verbosity to info of the Transformers logger (on main process only): - if is_main_process(training_args.local_process_index): - transformers.utils.logging.set_verbosity_info() - logger.info("Training/evaluation parameters %s", training_args) - - # Set seed before initializing model. - set_seed(training_args.seed) - - # 1. First, let's load the dataset - raw_datasets = DatasetDict() - - if training_args.do_train: - raw_datasets["train"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=data_args.train_split_name, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - if data_args.audio_column_name not in raw_datasets["train"].column_names: - raise ValueError( - f"--audio_column_name '{data_args.audio_column_name}' not found in dataset '{data_args.dataset_name}'." - " Make sure to set `--audio_column_name` to the correct audio column - one of" - f" {', '.join(raw_datasets['train'].column_names)}." - ) - - if data_args.text_column_name not in raw_datasets["train"].column_names: - raise ValueError( - f"--text_column_name {data_args.text_column_name} not found in dataset '{data_args.dataset_name}'. " - "Make sure to set `--text_column_name` to the correct text column - one of " - f"{', '.join(raw_datasets['train'].column_names)}." - ) - - if data_args.max_train_samples is not None: - raw_datasets["train"] = raw_datasets["train"].select(range(data_args.max_train_samples)) - - if training_args.do_eval: - raw_datasets["eval"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=data_args.eval_split_name, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - if data_args.max_eval_samples is not None: - raw_datasets["eval"] = raw_datasets["eval"].select(range(data_args.max_eval_samples)) - - # 2. We remove some special characters from the datasets - # that make training complicated and do not help in transcribing the speech - # E.g. characters, such as `,` and `.` do not really have an acoustic characteristic - # that could be easily picked up by the model - chars_to_ignore_regex = ( - f"[{''.join(data_args.chars_to_ignore)}]" if data_args.chars_to_ignore is not None else None - ) - text_column_name = data_args.text_column_name - - def remove_special_characters(batch): - if chars_to_ignore_regex is not None: - batch["target_text"] = re.sub(chars_to_ignore_regex, "", batch[text_column_name]).lower() + " " - else: - batch["target_text"] = batch[text_column_name].lower() + " " - return batch - - with training_args.main_process_first(desc="dataset map special characters removal"): - raw_datasets = raw_datasets.map( - remove_special_characters, - remove_columns=[text_column_name], - desc="remove special characters from datasets", - ) - - # save special tokens for tokenizer - word_delimiter_token = data_args.word_delimiter_token - unk_token = data_args.unk_token - pad_token = data_args.pad_token - - # 3. Next, let's load the config as we might need it to create - # the tokenizer - # load config - config = AutoConfig.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - # 4. Next, if no tokenizer file is defined, - # we create the vocabulary of the model by extracting all unique characters from - # the training and evaluation datasets - # We need to make sure that only first rank saves vocabulary - # make sure all processes wait until vocab is created - tokenizer_name_or_path = model_args.tokenizer_name_or_path - tokenizer_kwargs = {} - if tokenizer_name_or_path is None: - # save vocab in training output dir - tokenizer_name_or_path = training_args.output_dir - - vocab_file = os.path.join(tokenizer_name_or_path, "vocab.json") - - with training_args.main_process_first(): - if os.path.isfile(vocab_file): - try: - os.remove(vocab_file) - except OSError: - # in shared file-systems it might be the case that - # two processes try to delete the vocab file at the some time - pass - - with training_args.main_process_first(desc="dataset map vocabulary creation"): - if not os.path.isfile(vocab_file): - os.makedirs(tokenizer_name_or_path, exist_ok=True) - vocab_dict = create_vocabulary_from_data( - raw_datasets, - word_delimiter_token=word_delimiter_token, - unk_token=unk_token, - pad_token=pad_token, - ) - - # save vocab dict to be loaded into tokenizer - with open(vocab_file, "w", encoding="utf-8") as file: - json.dump(vocab_dict, file) - - tokenizer_kwargs = { - "config": config, - "tokenizer_type": config.model_type, - "unk_token": unk_token, - "pad_token": pad_token, - "word_delimiter_token": word_delimiter_token, - } - - # 5. Now we can instantiate the feature extractor, tokenizer and model - # Note for distributed training, the .from_pretrained methods guarantee that only - # one local process can concurrently download model & vocab. - - # load feature_extractor and tokenizer - tokenizer = AutoTokenizer.from_pretrained( - tokenizer_name_or_path, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - **tokenizer_kwargs, - ) - feature_extractor = AutoFeatureExtractor.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - # adapt config - config.update( - { - "feat_proj_dropout": model_args.feat_proj_dropout, - "attention_dropout": model_args.attention_dropout, - "hidden_dropout": model_args.hidden_dropout, - "final_dropout": model_args.final_dropout, - "mask_time_prob": model_args.mask_time_prob, - "mask_time_length": model_args.mask_time_length, - "mask_feature_prob": model_args.mask_feature_prob, - "mask_feature_length": model_args.mask_feature_length, - "gradient_checkpointing": training_args.gradient_checkpointing, - "layerdrop": model_args.layerdrop, - "ctc_loss_reduction": model_args.ctc_loss_reduction, - "ctc_zero_infinity": model_args.ctc_zero_infinity, - "pad_token_id": tokenizer.pad_token_id, - "vocab_size": len(tokenizer), - "activation_dropout": model_args.activation_dropout, - "add_adapter": model_args.add_adapter, - } - ) - - # create model - model = AutoModelForCTC.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - config=config, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - # freeze encoder - if model_args.freeze_feature_encoder: - model.freeze_feature_encoder() - - # 6. Now we preprocess the datasets including loading the audio, resampling and normalization - # Thankfully, `datasets` takes care of automatically loading and resampling the audio, - # so that we just need to set the correct target sampling rate and normalize the input - # via the `feature_extractor` - - # make sure that dataset decodes audio with correct sampling rate - dataset_sampling_rate = next(iter(raw_datasets.values())).features[data_args.audio_column_name].sampling_rate - if dataset_sampling_rate != feature_extractor.sampling_rate: - raw_datasets = raw_datasets.cast_column( - data_args.audio_column_name, - datasets.features.Audio(sampling_rate=feature_extractor.sampling_rate), - ) - - # derive max & min input length for sample rate & max duration - max_input_length = data_args.max_duration_in_seconds * feature_extractor.sampling_rate - min_input_length = data_args.min_duration_in_seconds * feature_extractor.sampling_rate - audio_column_name = data_args.audio_column_name - num_workers = data_args.preprocessing_num_workers - feature_extractor_input_name = feature_extractor.model_input_names[0] - - # `phoneme_language` is only relevant if the model is fine-tuned on phoneme classification - phoneme_language = data_args.phoneme_language - - # Preprocessing the datasets. - # We need to read the audio files as arrays and tokenize the targets. - def prepare_dataset(batch): - # load audio - sample = batch[audio_column_name] - - inputs = feature_extractor(sample["array"], sampling_rate=sample["sampling_rate"]) - batch[feature_extractor_input_name] = getattr(inputs, feature_extractor_input_name)[0] - # take length of raw audio waveform - batch["input_length"] = len(sample["array"].squeeze()) - - # encode targets - additional_kwargs = {} - if phoneme_language is not None: - additional_kwargs["phonemizer_lang"] = phoneme_language - - batch["labels"] = tokenizer(batch["target_text"], **additional_kwargs).input_ids - return batch - - with training_args.main_process_first(desc="dataset map preprocessing"): - vectorized_datasets = raw_datasets.map( - prepare_dataset, - remove_columns=next(iter(raw_datasets.values())).column_names, - num_proc=num_workers, - desc="preprocess datasets", - ) - - def is_audio_in_length_range(length): - return length > min_input_length and length < max_input_length - - # filter data that is shorter than min_input_length - vectorized_datasets = vectorized_datasets.filter( - is_audio_in_length_range, - num_proc=num_workers, - input_columns=["input_length"], - ) - - # 7. Next, we can prepare the training. - # Let's use word error rate (WER) as our evaluation metric, - # instantiate a data collator and the trainer - - # Define evaluation metrics during training, *i.e.* word error rate, character error rate - eval_metrics = {metric: evaluate.load(metric, cache_dir=model_args.cache_dir) for metric in data_args.eval_metrics} - - # for large datasets it is advised to run the preprocessing on a - # single machine first with ``args.preprocessing_only`` since there will mostly likely - # be a timeout when running the script in distributed mode. - # In a second step ``args.preprocessing_only`` can then be set to `False` to load the - # cached dataset - if data_args.preprocessing_only: - logger.info(f"Data preprocessing finished. Files cached at {vectorized_datasets.cache_files}") - return - - # For languages like Chinese with large vocabulary size, we need to discard logits - # and only keep the argmax, otherwise we run out of memory during evaluation. - def preprocess_logits_for_metrics(logits, labels): - pred_ids = torch.argmax(logits, dim=-1) - return pred_ids, labels - - def compute_metrics(pred): - pred_ids = pred.predictions[0] - pred.label_ids[pred.label_ids == -100] = tokenizer.pad_token_id - - pred_str = tokenizer.batch_decode(pred_ids) - # we do not want to group tokens when computing the metrics - label_str = tokenizer.batch_decode(pred.label_ids, group_tokens=False) - - metrics = {k: v.compute(predictions=pred_str, references=label_str) for k, v in eval_metrics.items()} - - return metrics - - # Now save everything to be able to create a single processor later - # make sure all processes wait until data is saved - with training_args.main_process_first(): - # only the main process saves them - if is_main_process(training_args.local_process_index): - # save feature extractor, tokenizer and config - feature_extractor.save_pretrained(training_args.output_dir) - tokenizer.save_pretrained(training_args.output_dir) - config.save_pretrained(training_args.output_dir) - - processor = AutoProcessor.from_pretrained(training_args.output_dir) - - # Instantiate custom data collator - data_collator = DataCollatorCTCWithPadding( - processor=processor, feature_extractor_input_name=feature_extractor_input_name - ) - - # Initialize Trainer - trainer = Trainer( - model=model, - data_collator=data_collator, - args=training_args, - compute_metrics=compute_metrics, - train_dataset=vectorized_datasets["train"] if training_args.do_train else None, - eval_dataset=vectorized_datasets["eval"] if training_args.do_eval else None, - processing_class=processor, - preprocess_logits_for_metrics=preprocess_logits_for_metrics, - ) - - # 8. Finally, we can start training - - # Training - if training_args.do_train: - # use last checkpoint if exist - if os.path.isdir(model_args.model_name_or_path): - checkpoint = model_args.model_name_or_path - else: - checkpoint = None - - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples - if data_args.max_train_samples is not None - else len(vectorized_datasets["train"]) - ) - metrics["train_samples"] = min(max_train_samples, len(vectorized_datasets["train"])) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - results = {} - if training_args.do_eval: - logger.info("*** Evaluate ***") - metrics = trainer.evaluate() - max_eval_samples = ( - data_args.max_eval_samples if data_args.max_eval_samples is not None else len(vectorized_datasets["eval"]) - ) - metrics["eval_samples"] = min(max_eval_samples, len(vectorized_datasets["eval"])) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Write model card and (optionally) push to hub - config_name = data_args.dataset_config_name if data_args.dataset_config_name is not None else "na" - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "tasks": "automatic-speech-recognition", - "tags": ["automatic-speech-recognition", data_args.dataset_name], - "dataset_args": ( - f"Config: {config_name}, Training split: {data_args.train_split_name}, Eval split:" - f" {data_args.eval_split_name}" - ), - "dataset": f"{data_args.dataset_name.upper()} - {config_name.upper()}", - } - if "common_voice" in data_args.dataset_name: - kwargs["language"] = config_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - return results - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/speech-recognition/run_speech_recognition_ctc_adapter.py b/examples/pytorch/speech-recognition/run_speech_recognition_ctc_adapter.py deleted file mode 100755 index 561c2413a017..000000000000 --- a/examples/pytorch/speech-recognition/run_speech_recognition_ctc_adapter.py +++ /dev/null @@ -1,811 +0,0 @@ -#!/usr/bin/env python -# Copyright 2023 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "datasets[audio] >= 1.18.0", -# "torch >= 1.5", -# "torchaudio", -# "librosa", -# "jiwer", -# "evaluate", -# ] -# /// - -"""Fine-tuning a 🤗 Transformers CTC adapter model for automatic speech recognition""" - -import functools -import json -import logging -import os -import re -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -import numpy as np -import torch -from datasets import DatasetDict, load_dataset -from safetensors.torch import save_file as safe_save_file - -import transformers -from transformers import ( - AutoConfig, - AutoFeatureExtractor, - AutoModelForCTC, - AutoProcessor, - AutoTokenizer, - HfArgumentParser, - Trainer, - TrainingArguments, - set_seed, -) -from transformers.models.wav2vec2.modeling_wav2vec2 import WAV2VEC2_ADAPTER_SAFE_FILE -from transformers.trainer_utils import is_main_process -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version( - "datasets>=1.18.0", - "To fix: pip install -r examples/pytorch/speech-recognition/requirements.txt", -) - - -logger = logging.getLogger(__name__) - - -def list_field(default=None, metadata=None): - return field(default_factory=lambda: default, metadata=metadata) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - tokenizer_name_or_path: str | None = field( - default=None, - metadata={"help": "Path to pretrained tokenizer or tokenizer identifier from huggingface.co/models"}, - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - final_dropout: float = field( - default=0.0, - metadata={"help": "The dropout probability for the final projection layer."}, - ) - mask_time_prob: float = field( - default=0.05, - metadata={ - "help": ( - "Probability of each feature vector along the time axis to be chosen as the start of the vector " - "span to be masked. Approximately ``mask_time_prob * sequence_length // mask_time_length`` feature " - "vectors will be masked along the time axis." - ) - }, - ) - mask_time_length: int = field( - default=10, - metadata={"help": "Length of vector span to mask along the time axis."}, - ) - mask_feature_prob: float = field( - default=0.0, - metadata={ - "help": ( - "Probability of each feature vector along the feature axis to be chosen as the start of the vectorspan" - " to be masked. Approximately ``mask_feature_prob * sequence_length // mask_feature_length`` feature" - " bins will be masked along the time axis." - ) - }, - ) - mask_feature_length: int = field( - default=10, - metadata={"help": "Length of vector span to mask along the feature axis."}, - ) - layerdrop: float = field(default=0.0, metadata={"help": "The LayerDrop probability."}) - ctc_loss_reduction: str | None = field( - default="mean", - metadata={"help": "The way the ctc loss should be reduced. Should be one of 'mean' or 'sum'."}, - ) - adapter_attn_dim: int = field( - default=16, - metadata={ - "help": "The hidden dimension of the adapter layers that will be randomly initialized and trained. The higher the dimension, the more capacity is given to the adapter weights. Note that only the adapter weights are fine-tuned." - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - - Using `HfArgumentParser` we can turn this class - into argparse arguments to be able to specify them on - the command line. - """ - - dataset_name: str = field( - metadata={"help": "Path or name of the dataset (cf `load_dataset` method of the Datasets library)."} - ) - target_language: str = field( - metadata={ - "help": ( - "The target language on which the adapter attention layers" - " should be trained on in ISO 693-3 code, e.g. `tur` for Turkish" - " Wav2Vec2's MMS ISO codes can be looked up here: https://dl.fbaipublicfiles.com/mms/misc/language_coverage_mms.html" - " If you are not training the adapter layers on a language, simply choose" - " another acronym that fits your data." - ) - }, - ) - dataset_config_name: str = field( - default=None, - metadata={ - "help": "The configuration name of the dataset to use (cf `load_dataset` method of the Datasets library)." - }, - ) - train_split_name: str = field( - default="train+validation", - metadata={ - "help": ( - "The name of the training data set split to use (via the datasets library). Defaults to " - "'train+validation'" - ) - }, - ) - eval_split_name: str = field( - default="test", - metadata={ - "help": "The name of the evaluation data set split to use (via the datasets library). Defaults to 'test'" - }, - ) - audio_column_name: str = field( - default="audio", - metadata={"help": "The name of the dataset column containing the audio data. Defaults to 'audio'"}, - ) - text_column_name: str = field( - default="text", - metadata={"help": "The name of the dataset column containing the text data. Defaults to 'text'"}, - ) - overwrite_cache: bool = field( - default=False, - metadata={"help": "Overwrite the cached preprocessed datasets or not."}, - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of validation examples to this " - "value if set." - ) - }, - ) - chars_to_ignore: list[str] | None = list_field( - default=None, - metadata={"help": "A list of characters to remove from the transcripts."}, - ) - eval_metrics: list[str] = list_field( - default=["wer"], - metadata={"help": "A list of metrics the model should be evaluated on. E.g. `'wer cer'`"}, - ) - max_duration_in_seconds: float = field( - default=20.0, - metadata={ - "help": ( - "Filter audio files that are longer than `max_duration_in_seconds` seconds to" - " 'max_duration_in_seconds`" - ) - }, - ) - min_duration_in_seconds: float = field( - default=0.0, - metadata={"help": "Filter audio files that are shorter than `min_duration_in_seconds` seconds"}, - ) - preprocessing_only: bool = field( - default=False, - metadata={ - "help": ( - "Whether to only do data preprocessing and skip training. This is especially useful when data" - " preprocessing errors out in distributed training due to timeout. In this case, one should run the" - " preprocessing in a non-distributed setup with `preprocessing_only=True` so that the cached datasets" - " can consequently be loaded in distributed training" - ) - }, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - unk_token: str = field( - default="[UNK]", - metadata={"help": "The unk token for the tokenizer"}, - ) - pad_token: str = field( - default="[PAD]", - metadata={"help": "The padding token for the tokenizer"}, - ) - word_delimiter_token: str = field( - default="|", - metadata={"help": "The word delimiter token for the tokenizer"}, - ) - overwrite_lang_vocab: bool = field( - default=False, - metadata={"help": ("If :obj:`True`, will overwrite existing `target_language` vocabulary of tokenizer.")}, - ) - - -@dataclass -class DataCollatorCTCWithPadding: - """ - Data collator that will dynamically pad the inputs received. - Args: - processor (:class:`~transformers.AutoProcessor`) - The processor used for processing the data. - padding (:obj:`bool`, :obj:`str` or :class:`~transformers.tokenization_utils_base.PaddingStrategy`, `optional`, defaults to :obj:`True`): - Select a strategy to pad the returned sequences (according to the model's padding side and padding index) - among: - * :obj:`True` or :obj:`'longest'`: Pad to the longest sequence in the batch (or no padding if only a single - sequence if provided). - * :obj:`'max_length'`: Pad to a maximum length specified with the argument :obj:`max_length` or to the - maximum acceptable input length for the model if that argument is not provided. - * :obj:`False` or :obj:`'do_not_pad'` (default): No padding (i.e., can output a batch with sequences of - different lengths). - max_length (:obj:`int`, `optional`): - Maximum length of the ``input_values`` of the returned list and optionally padding length (see above). - max_length_labels (:obj:`int`, `optional`): - Maximum length of the ``labels`` returned list and optionally padding length (see above). - pad_to_multiple_of (:obj:`int`, `optional`): - If set will pad the sequence to a multiple of the provided value. - This is especially useful to enable the use of Tensor Cores on NVIDIA hardware with compute capability >= - 7.5 (Volta). - """ - - processor: AutoProcessor - padding: bool | str = "longest" - pad_to_multiple_of: int | None = None - pad_to_multiple_of_labels: int | None = None - - def __call__(self, features: list[dict[str, list[int] | torch.Tensor]]) -> dict[str, torch.Tensor]: - # split inputs and labels since they have to be of different lengths and need - # different padding methods - input_features = [{"input_values": feature["input_values"]} for feature in features] - label_features = [{"input_ids": feature["labels"]} for feature in features] - - batch = self.processor.pad( - input_features, - padding=self.padding, - pad_to_multiple_of=self.pad_to_multiple_of, - return_tensors="pt", - ) - - labels_batch = self.processor.pad( - labels=label_features, - padding=self.padding, - pad_to_multiple_of=self.pad_to_multiple_of_labels, - return_tensors="pt", - ) - - # replace padding with -100 to ignore loss correctly - labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100) - - batch["labels"] = labels - if "attention_mask" in batch: - batch["attention_mask"] = batch["attention_mask"].to(torch.long) - - return batch - - -def create_vocabulary_from_data( - datasets: DatasetDict, - word_delimiter_token: str | None = None, - unk_token: str | None = None, - pad_token: str | None = None, -): - # Given training and test labels create vocabulary - def extract_all_chars(batch): - all_text = " ".join(batch["target_text"]) - vocab = list(set(all_text)) - return {"vocab": [vocab], "all_text": [all_text]} - - vocabs = datasets.map( - extract_all_chars, - batched=True, - batch_size=-1, - keep_in_memory=True, - remove_columns=datasets["train"].column_names, - ) - - # take union of all unique characters in each dataset - vocab_set = functools.reduce( - lambda vocab_1, vocab_2: set(vocab_1["vocab"][0]) | set(vocab_2["vocab"][0]), - vocabs.values(), - ) - - vocab_dict = {v: k for k, v in enumerate(sorted(vocab_set))} - - # replace white space with delimiter token - if word_delimiter_token is not None: - vocab_dict[word_delimiter_token] = vocab_dict[" "] - del vocab_dict[" "] - - # add unk and pad token - if unk_token is not None: - vocab_dict[unk_token] = len(vocab_dict) - - if pad_token is not None: - vocab_dict[pad_token] = len(vocab_dict) - - return vocab_dict - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - logger.setLevel(logging.INFO if is_main_process(training_args.local_process_index) else logging.WARN) - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - # Set the verbosity to info of the Transformers logger (on main process only): - if is_main_process(training_args.local_process_index): - transformers.utils.logging.set_verbosity_info() - logger.info("Training/evaluation parameters %s", training_args) - - # Set seed before initializing model. - set_seed(training_args.seed) - - # 1. First, let's load the dataset - raw_datasets = DatasetDict() - - if training_args.do_train: - raw_datasets["train"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=data_args.train_split_name, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - if data_args.audio_column_name not in raw_datasets["train"].column_names: - raise ValueError( - f"--audio_column_name '{data_args.audio_column_name}' not found in dataset '{data_args.dataset_name}'." - " Make sure to set `--audio_column_name` to the correct audio column - one of" - f" {', '.join(raw_datasets['train'].column_names)}." - ) - - if data_args.text_column_name not in raw_datasets["train"].column_names: - raise ValueError( - f"--text_column_name {data_args.text_column_name} not found in dataset '{data_args.dataset_name}'. " - "Make sure to set `--text_column_name` to the correct text column - one of " - f"{', '.join(raw_datasets['train'].column_names)}." - ) - - if data_args.max_train_samples is not None: - raw_datasets["train"] = raw_datasets["train"].select(range(data_args.max_train_samples)) - - if training_args.do_eval: - raw_datasets["eval"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=data_args.eval_split_name, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - if data_args.max_eval_samples is not None: - raw_datasets["eval"] = raw_datasets["eval"].select(range(data_args.max_eval_samples)) - - # 2. We remove some special characters from the datasets - # that make training complicated and do not help in transcribing the speech - # E.g. characters, such as `,` and `.` do not really have an acoustic characteristic - # that could be easily picked up by the model - chars_to_ignore_regex = ( - f"[{''.join(data_args.chars_to_ignore)}]" if data_args.chars_to_ignore is not None else None - ) - text_column_name = data_args.text_column_name - - def remove_special_characters(batch): - if chars_to_ignore_regex is not None: - batch["target_text"] = re.sub(chars_to_ignore_regex, "", batch[text_column_name]).lower() + " " - else: - batch["target_text"] = batch[text_column_name].lower() + " " - return batch - - with training_args.main_process_first(desc="dataset map special characters removal"): - raw_datasets = raw_datasets.map( - remove_special_characters, - remove_columns=[text_column_name], - desc="remove special characters from datasets", - ) - - # save special tokens for tokenizer - word_delimiter_token = data_args.word_delimiter_token - unk_token = data_args.unk_token - pad_token = data_args.pad_token - - # 3. Next, let's load the config as we might need it to create - # the tokenizer - # load config - config = AutoConfig.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - # 4. Next, if no tokenizer file is defined, - # we create the vocabulary of the model by extracting all unique characters from - # the training and evaluation datasets - # We need to make sure that only first rank saves vocabulary - # make sure all processes wait until vocab is created - tokenizer_name_or_path = model_args.tokenizer_name_or_path - tokenizer_kwargs = {} - - vocab_dict = {} - if tokenizer_name_or_path is not None: - # load vocabulary of other adapter languages so that new language can be appended - tokenizer = AutoTokenizer.from_pretrained( - tokenizer_name_or_path, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - vocab_dict = tokenizer.vocab.copy() - if tokenizer.target_lang is None: - raise ValueError("Make sure to load a multi-lingual tokenizer with a set target language.") - - if data_args.target_language in tokenizer.vocab and not data_args.overwrite_lang_vocab: - logger.info( - "Adapter language already exists." - " Skipping vocabulary creating. If you want to create a new vocabulary" - f" for {data_args.target_language} make sure to add '--overwrite_lang_vocab'" - ) - else: - tokenizer_name_or_path = None - - if tokenizer_name_or_path is None: - # save vocab in training output dir - tokenizer_name_or_path = training_args.output_dir - - vocab_file = os.path.join(tokenizer_name_or_path, "vocab.json") - - with training_args.main_process_first(): - if os.path.isfile(vocab_file): - try: - os.remove(vocab_file) - except OSError: - # in shared file-systems it might be the case that - # two processes try to delete the vocab file at the some time - pass - - with training_args.main_process_first(desc="dataset map vocabulary creation"): - if not os.path.isfile(vocab_file): - os.makedirs(tokenizer_name_or_path, exist_ok=True) - lang_dict = create_vocabulary_from_data( - raw_datasets, - word_delimiter_token=word_delimiter_token, - unk_token=unk_token, - pad_token=pad_token, - ) - - # if we doing adapter language training, save - # vocab with adapter language - if data_args.target_language is not None: - vocab_dict[data_args.target_language] = lang_dict - - # save vocab dict to be loaded into tokenizer - with open(vocab_file, "w", encoding="utf-8") as file: - json.dump(vocab_dict, file) - - tokenizer_kwargs = { - "config": config, - "tokenizer_type": config.model_type, - "unk_token": unk_token, - "pad_token": pad_token, - "word_delimiter_token": word_delimiter_token, - "target_lang": data_args.target_language, - } - - # 5. Now we can instantiate the feature extractor, tokenizer and model - # Note for distributed training, the .from_pretrained methods guarantee that only - # one local process can concurrently download model & vocab. - - # load feature_extractor and tokenizer - tokenizer = AutoTokenizer.from_pretrained( - tokenizer_name_or_path, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - **tokenizer_kwargs, - ) - feature_extractor = AutoFeatureExtractor.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ) - - # adapt config - config.update( - { - "final_dropout": model_args.final_dropout, - "mask_time_prob": model_args.mask_time_prob, - "mask_time_length": model_args.mask_time_length, - "mask_feature_prob": model_args.mask_feature_prob, - "mask_feature_length": model_args.mask_feature_length, - "gradient_checkpointing": training_args.gradient_checkpointing, - "layerdrop": model_args.layerdrop, - "ctc_loss_reduction": model_args.ctc_loss_reduction, - "pad_token_id": tokenizer.pad_token_id, - "vocab_size": len(tokenizer), - "adapter_attn_dim": model_args.adapter_attn_dim, - } - ) - - # create model - model = AutoModelForCTC.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - config=config, - token=data_args.token, - trust_remote_code=data_args.trust_remote_code, - ignore_mismatched_sizes=True, - ) - - # if attn adapter is defined, freeze all non-adapter weights - if model.config.adapter_attn_dim is not None: - model.init_adapter_layers() - # first we freeze the whole base model - model.freeze_base_model() - - # next we unfreeze all adapter layers - adapter_weights = model._get_adapters() - for param in adapter_weights.values(): - param.requires_grad = True - - # 6. Now we preprocess the datasets including loading the audio, resampling and normalization - # Thankfully, `datasets` takes care of automatically loading and resampling the audio, - # so that we just need to set the correct target sampling rate and normalize the input - # via the `feature_extractor` - - # make sure that dataset decodes audio with correct sampling rate - dataset_sampling_rate = next(iter(raw_datasets.values())).features[data_args.audio_column_name].sampling_rate - if dataset_sampling_rate != feature_extractor.sampling_rate: - raw_datasets = raw_datasets.cast_column( - data_args.audio_column_name, - datasets.features.Audio(sampling_rate=feature_extractor.sampling_rate), - ) - - # derive max & min input length for sample rate & max duration - max_input_length = data_args.max_duration_in_seconds * feature_extractor.sampling_rate - min_input_length = data_args.min_duration_in_seconds * feature_extractor.sampling_rate - audio_column_name = data_args.audio_column_name - num_workers = data_args.preprocessing_num_workers - - # Preprocessing the datasets. - # We need to read the audio files as arrays and tokenize the targets. - def prepare_dataset(batch): - # load audio - sample = batch[audio_column_name] - - inputs = feature_extractor(sample["array"], sampling_rate=sample["sampling_rate"]) - batch["input_values"] = inputs.input_values[0] - batch["input_length"] = len(batch["input_values"]) - - # encode targets - batch["labels"] = tokenizer(batch["target_text"]).input_ids - return batch - - with training_args.main_process_first(desc="dataset map preprocessing"): - vectorized_datasets = raw_datasets.map( - prepare_dataset, - remove_columns=next(iter(raw_datasets.values())).column_names, - num_proc=num_workers, - desc="preprocess datasets", - ) - - def is_audio_in_length_range(length): - return length > min_input_length and length < max_input_length - - # filter data that is shorter than min_input_length - vectorized_datasets = vectorized_datasets.filter( - is_audio_in_length_range, - num_proc=num_workers, - input_columns=["input_length"], - ) - - # 7. Next, we can prepare the training. - # Let's use word error rate (WER) as our evaluation metric, - # instantiate a data collator and the trainer - - # Define evaluation metrics during training, *i.e.* word error rate, character error rate - eval_metrics = {metric: evaluate.load(metric, cache_dir=model_args.cache_dir) for metric in data_args.eval_metrics} - - # for large datasets it is advised to run the preprocessing on a - # single machine first with ``args.preprocessing_only`` since there will mostly likely - # be a timeout when running the script in distributed mode. - # In a second step ``args.preprocessing_only`` can then be set to `False` to load the - # cached dataset - if data_args.preprocessing_only: - logger.info(f"Data preprocessing finished. Files cached at {vectorized_datasets.cache_files}") - return - - def compute_metrics(pred): - pred_logits = pred.predictions - pred_ids = np.argmax(pred_logits, axis=-1) - - pred.label_ids[pred.label_ids == -100] = tokenizer.pad_token_id - - pred_str = tokenizer.batch_decode(pred_ids) - # we do not want to group tokens when computing the metrics - label_str = tokenizer.batch_decode(pred.label_ids, group_tokens=False) - - metrics = {k: v.compute(predictions=pred_str, references=label_str) for k, v in eval_metrics.items()} - - return metrics - - # Now save everything to be able to create a single processor later - # make sure all processes wait until data is saved - with training_args.main_process_first(): - # only the main process saves them - if is_main_process(training_args.local_process_index): - # save feature extractor, tokenizer and config - feature_extractor.save_pretrained(training_args.output_dir) - tokenizer.save_pretrained(training_args.output_dir) - config.save_pretrained(training_args.output_dir) - - processor = AutoProcessor.from_pretrained(training_args.output_dir) - - # Instantiate custom data collator - data_collator = DataCollatorCTCWithPadding(processor=processor) - - # Initialize Trainer - trainer = Trainer( - model=model, - data_collator=data_collator, - args=training_args, - compute_metrics=compute_metrics, - train_dataset=vectorized_datasets["train"] if training_args.do_train else None, - eval_dataset=vectorized_datasets["eval"] if training_args.do_eval else None, - processing_class=processor, - ) - - # 8. Finally, we can start training - - # Training - if training_args.do_train: - # use last checkpoint if exist - if os.path.isdir(model_args.model_name_or_path): - checkpoint = model_args.model_name_or_path - else: - checkpoint = None - - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() - - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples - if data_args.max_train_samples is not None - else len(vectorized_datasets["train"]) - ) - metrics["train_samples"] = min(max_train_samples, len(vectorized_datasets["train"])) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - results = {} - if training_args.do_eval: - logger.info("*** Evaluate ***") - metrics = trainer.evaluate() - max_eval_samples = ( - data_args.max_eval_samples if data_args.max_eval_samples is not None else len(vectorized_datasets["eval"]) - ) - metrics["eval_samples"] = min(max_eval_samples, len(vectorized_datasets["eval"])) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Write model card and (optionally) push to hub - config_name = data_args.dataset_config_name if data_args.dataset_config_name is not None else "na" - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "tasks": "automatic-speech-recognition", - "tags": ["automatic-speech-recognition", data_args.dataset_name, "mms"], - "dataset_args": ( - f"Config: {config_name}, Training split: {data_args.train_split_name}, Eval split:" - f" {data_args.eval_split_name}" - ), - "dataset": f"{data_args.dataset_name.upper()} - {config_name.upper()}", - } - if "common_voice" in data_args.dataset_name: - kwargs["language"] = config_name - - # make sure that adapter weights are saved separately - adapter_file = WAV2VEC2_ADAPTER_SAFE_FILE.format(data_args.target_language) - adapter_file = os.path.join(training_args.output_dir, adapter_file) - logger.info(f"Saving adapter weights under {adapter_file}...") - safe_save_file(model._get_adapters(), adapter_file, metadata={"format": "pt"}) - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - return results - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/speech-recognition/run_speech_recognition_seq2seq.py b/examples/pytorch/speech-recognition/run_speech_recognition_seq2seq.py deleted file mode 100755 index 346851d71b75..000000000000 --- a/examples/pytorch/speech-recognition/run_speech_recognition_seq2seq.py +++ /dev/null @@ -1,603 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "datasets[audio] >= 1.18.0", -# "torch >= 1.5", -# "torchaudio", -# "librosa", -# "jiwer", -# "evaluate", -# ] -# /// - -""" -Fine-tuning the library models for sequence to sequence speech recognition. -""" -# You can also adapt this script on your own sequence to sequence speech -# recognition task. Pointers for this are left as comments. - -import logging -import os -import sys -from dataclasses import dataclass, field -from typing import Any - -import datasets -import evaluate -import torch -from datasets import DatasetDict, load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoModelForSpeechSeq2Seq, - AutoProcessor, - HfArgumentParser, - Seq2SeqTrainer, - Seq2SeqTrainingArguments, - set_seed, -) -from transformers.trainer_utils import is_main_process -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version( - "datasets>=1.18.0", - "To fix: pip install -r examples/pytorch/speech-recognition/requirements.txt", -) - -logger = logging.getLogger(__name__) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, - metadata={"help": "Pretrained config name or path if not the same as model_name"}, - ) - tokenizer_name: str | None = field( - default=None, - metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"}, - ) - feature_extractor_name: str | None = field( - default=None, - metadata={"help": "feature extractor name or path if not the same as model_name"}, - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - freeze_feature_encoder: bool = field( - default=True, - metadata={"help": "Whether to freeze the feature encoder layers of the model."}, - ) - freeze_encoder: bool = field( - default=False, - metadata={"help": "Whether to freeze the entire encoder of the seq2seq model."}, - ) - apply_spec_augment: bool = field( - default=False, - metadata={ - "help": "Whether to apply *SpecAugment* data augmentation to the input features. This is currently only relevant for Wav2Vec2, HuBERT, WavLM and Whisper models." - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - dataset_name: str = field( - metadata={"help": "Path or name of the dataset (cf `load_dataset` method of the Datasets library)."} - ) - dataset_config_name: str = field( - default=None, - metadata={ - "help": "The configuration name of the dataset to use (cf `load_dataset` method of the Datasets library)." - }, - ) - overwrite_cache: bool = field( - default=False, - metadata={"help": "Overwrite the cached training and evaluation sets"}, - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - audio_column_name: str = field( - default="audio", - metadata={"help": "The name of the dataset column containing the audio data. Defaults to 'audio'"}, - ) - text_column_name: str = field( - default="text", - metadata={"help": "The name of the dataset column containing the text data. Defaults to 'text'"}, - ) - max_duration_in_seconds: float = field( - default=20.0, - metadata={ - "help": ( - "Truncate audio files that are longer than `max_duration_in_seconds` seconds to" - " 'max_duration_in_seconds`" - ) - }, - ) - min_duration_in_seconds: float = field( - default=0.0, - metadata={"help": "Filter audio files that are shorter than `min_duration_in_seconds` seconds"}, - ) - preprocessing_only: bool = field( - default=False, - metadata={ - "help": ( - "Whether to only do data preprocessing and skip training. This is especially useful when data" - " preprocessing errors out in distributed training due to timeout. In this case, one should run the" - " preprocessing in a non-distributed setup with `preprocessing_only=True` so that the cached datasets" - " can consequently be loaded in distributed training" - ) - }, - ) - train_split_name: str = field( - default="train", - metadata={ - "help": "The name of the training data set split to use (via the datasets library). Defaults to 'train'" - }, - ) - eval_split_name: str = field( - default="test", - metadata={ - "help": "The name of the training data set split to use (via the datasets library). Defaults to 'train'" - }, - ) - do_lower_case: bool = field( - default=True, - metadata={"help": "Whether the target text should be lower cased."}, - ) - language: str = field( - default=None, - metadata={ - "help": ( - "Language for multilingual fine-tuning. This argument should be set for multilingual fine-tuning " - "only. For English speech recognition, it should be set to `None`." - ) - }, - ) - task: str = field( - default="transcribe", - metadata={"help": "Task, either `transcribe` for speech recognition or `translate` for speech translation."}, - ) - - -@dataclass -class DataCollatorSpeechSeq2SeqWithPadding: - """ - Data collator that will dynamically pad the inputs received. - Args: - processor ([`WhisperProcessor`]) - The processor used for processing the data. - decoder_start_token_id (`int`) - The begin-of-sentence of the decoder. - forward_attention_mask (`bool`) - Whether to return attention_mask. - """ - - processor: Any - decoder_start_token_id: int - forward_attention_mask: bool - - def __call__(self, features: list[dict[str, list[int] | torch.Tensor]]) -> dict[str, torch.Tensor]: - # split inputs and labels since they have to be of different lengths and need - # different padding methods - model_input_name = self.processor.model_input_names[0] - input_features = [{model_input_name: feature[model_input_name]} for feature in features] - label_features = [{"input_ids": feature["labels"]} for feature in features] - - batch = self.processor.feature_extractor.pad(input_features, return_tensors="pt") - - if self.forward_attention_mask: - batch["attention_mask"] = torch.LongTensor([feature["attention_mask"] for feature in features]) - - labels_batch = self.processor.tokenizer.pad(label_features, return_tensors="pt") - - # replace padding with -100 to ignore loss correctly - labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100) - - # if bos token is appended in previous tokenization step, - # cut bos token here as it's append later anyways - if (labels[:, 0] == self.decoder_start_token_id).all().cpu().item(): - labels = labels[:, 1:] - - batch["labels"] = labels - - return batch - - -def main(): - # 1. Parse input arguments - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, Seq2SeqTrainingArguments)) - - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # 2. Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - logger.setLevel(logging.INFO if is_main_process(training_args.local_process_index) else logging.WARN) - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set the verbosity to info of the Transformers logger (on main process only): - if is_main_process(training_args.local_process_index): - transformers.utils.logging.set_verbosity_info() - logger.info("Training/evaluation parameters %s", training_args) - - # Set seed before initializing model. - set_seed(training_args.seed) - - # 4. Load dataset - raw_datasets = DatasetDict() - - if training_args.do_train: - raw_datasets["train"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=data_args.train_split_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - if training_args.do_eval: - raw_datasets["eval"] = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - split=data_args.eval_split_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - if data_args.audio_column_name not in next(iter(raw_datasets.values())).column_names: - raise ValueError( - f"--audio_column_name '{data_args.audio_column_name}' not found in dataset '{data_args.dataset_name}'. " - "Make sure to set `--audio_column_name` to the correct audio column - one of " - f"{', '.join(next(iter(raw_datasets.values())).column_names)}." - ) - - if data_args.text_column_name not in next(iter(raw_datasets.values())).column_names: - raise ValueError( - f"--text_column_name {data_args.text_column_name} not found in dataset '{data_args.dataset_name}'. " - "Make sure to set `--text_column_name` to the correct text column - one of " - f"{', '.join(next(iter(raw_datasets.values())).column_names)}." - ) - - # 5. Load pretrained model, tokenizer, and feature extractor - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - config = AutoConfig.from_pretrained( - (model_args.config_name if model_args.config_name else model_args.model_name_or_path), - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # SpecAugment for whisper models - if getattr(config, "model_type", None) == "whisper": - config.update({"apply_spec_augment": model_args.apply_spec_augment}) - - processor = AutoProcessor.from_pretrained( - model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForSpeechSeq2Seq.from_pretrained( - model_args.model_name_or_path, - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - if model.config.decoder_start_token_id is None: - raise ValueError("Make sure that `config.decoder_start_token_id` is correctly defined") - - if model_args.freeze_feature_encoder: - model.freeze_feature_encoder() - - if model_args.freeze_encoder: - model.freeze_encoder() - model.model.encoder.gradient_checkpointing = False - - if hasattr(model.generation_config, "is_multilingual") and model.generation_config.is_multilingual: - # We only need to set the language and task ids in a multilingual setting - processor.tokenizer.set_prefix_tokens(language=data_args.language, task=data_args.task) - model.generation_config.language = data_args.language - model.generation_config.task = data_args.task - elif data_args.language is not None: - raise ValueError( - "Setting language token for an English-only checkpoint is not permitted. The language argument should " - "only be set for multilingual checkpoints." - ) - - model.generation_config.forced_decoder_ids = None - model.config.forced_decoder_ids = None - - # 6. Resample speech dataset if necessary - dataset_sampling_rate = next(iter(raw_datasets.values())).features[data_args.audio_column_name].sampling_rate - if dataset_sampling_rate != processor.feature_extractor.sampling_rate: - raw_datasets = raw_datasets.cast_column( - data_args.audio_column_name, - datasets.features.Audio(sampling_rate=processor.feature_extractor.sampling_rate), - ) - - # 7. Preprocessing the datasets. - # We need to read the audio files as arrays and tokenize the targets. - max_input_length = data_args.max_duration_in_seconds * processor.feature_extractor.sampling_rate - min_input_length = data_args.min_duration_in_seconds * processor.feature_extractor.sampling_rate - audio_column_name = data_args.audio_column_name - num_workers = data_args.preprocessing_num_workers - text_column_name = data_args.text_column_name - model_input_name = processor.feature_extractor.model_input_names[0] - do_lower_case = data_args.do_lower_case - # if SpecAugment is used for whisper models, return attention_mask to guide the mask along time axis - forward_attention_mask = ( - getattr(config, "model_type", None) == "whisper" - and getattr(config, "apply_spec_augment", False) - and getattr(config, "mask_time_prob", 0) > 0 - ) - - if data_args.max_train_samples is not None: - raw_datasets["train"] = raw_datasets["train"].select(range(data_args.max_train_samples)) - - if data_args.max_eval_samples is not None: - raw_datasets["eval"] = raw_datasets["eval"].select(range(data_args.max_eval_samples)) - - def prepare_dataset(batch): - # process audio - sample = batch[audio_column_name] - inputs = processor.feature_extractor( - sample["array"], - sampling_rate=sample["sampling_rate"], - return_attention_mask=forward_attention_mask, - ) - # process audio length - batch[model_input_name] = inputs.get(model_input_name)[0] - batch["input_length"] = len(sample["array"]) - if forward_attention_mask: - batch["attention_mask"] = inputs.get("attention_mask")[0] - - # process targets - input_str = batch[text_column_name].lower() if do_lower_case else batch[text_column_name] - batch["labels"] = processor.tokenizer(input_str).input_ids - return batch - - with training_args.main_process_first(desc="dataset map pre-processing"): - vectorized_datasets = raw_datasets.map( - prepare_dataset, - remove_columns=next(iter(raw_datasets.values())).column_names, - num_proc=data_args.preprocessing_num_workers, - desc="preprocess train dataset", - ) - - # filter data that is shorter than min_input_length or longer than - # max_input_length - def is_audio_in_length_range(length): - return length > min_input_length and length < max_input_length - - vectorized_datasets = vectorized_datasets.filter( - is_audio_in_length_range, - num_proc=num_workers, - input_columns=["input_length"], - ) - - # for large datasets it is advised to run the preprocessing on a - # single machine first with `args.preprocessing_only` since there will mostly likely - # be a timeout when running the script in distributed mode. - # In a second step `args.preprocessing_only` can then be set to `False` to load the - # cached dataset - if data_args.preprocessing_only: - cache = {k: v.cache_files for k, v in vectorized_datasets.items()} - logger.info(f"Data preprocessing finished. Files cached at {cache}.") - return - - # 8. Load Metric - metric = evaluate.load("wer", cache_dir=model_args.cache_dir) - - def compute_metrics(pred): - pred_ids = pred.predictions - - pred.label_ids[pred.label_ids == -100] = processor.tokenizer.pad_token_id - - pred_str = processor.tokenizer.batch_decode(pred_ids, skip_special_tokens=True) - # we do not want to group tokens when computing the metrics - label_str = processor.tokenizer.batch_decode(pred.label_ids, skip_special_tokens=True) - - wer = metric.compute(predictions=pred_str, references=label_str) - - return {"wer": wer} - - # 9. Create a single speech processor - # make sure all processes wait until data is saved - with training_args.main_process_first(): - # only the main process saves them - if is_main_process(training_args.local_process_index): - config.save_pretrained(training_args.output_dir) - - # 10. Define data collator - data_collator = DataCollatorSpeechSeq2SeqWithPadding( - processor=processor, - decoder_start_token_id=model.config.decoder_start_token_id, - forward_attention_mask=forward_attention_mask, - ) - - # 11. Initialize Trainer - trainer = Seq2SeqTrainer( - model=model, - args=training_args, - train_dataset=vectorized_datasets["train"] if training_args.do_train else None, - eval_dataset=vectorized_datasets["eval"] if training_args.do_eval else None, - processing_class=processor.feature_extractor, - data_collator=data_collator, - compute_metrics=(compute_metrics if training_args.predict_with_generate else None), - ) - - # 12. Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the feature extractor too for easy upload - - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples - if data_args.max_train_samples is not None - else len(vectorized_datasets["train"]) - ) - metrics["train_samples"] = min(max_train_samples, len(vectorized_datasets["train"])) - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # 13. Evaluation - results = {} - if training_args.do_eval: - logger.info("*** Evaluate ***") - metrics = trainer.evaluate( - metric_key_prefix="eval", - max_length=training_args.generation_max_length, - num_beams=training_args.generation_num_beams, - ) - max_eval_samples = ( - data_args.max_eval_samples if data_args.max_eval_samples is not None else len(vectorized_datasets["eval"]) - ) - metrics["eval_samples"] = min(max_eval_samples, len(vectorized_datasets["eval"])) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # 14. Write Training Stats - kwargs = { - "finetuned_from": model_args.model_name_or_path, - "tasks": "automatic-speech-recognition", - } - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - return results - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/summarization/README.md b/examples/pytorch/summarization/README.md deleted file mode 100644 index d82809ffe99b..000000000000 --- a/examples/pytorch/summarization/README.md +++ /dev/null @@ -1,194 +0,0 @@ - - -## Summarization - -This directory contains examples for finetuning and evaluating transformers on summarization tasks. -Please tag @patil-suraj with any issues/unexpected behaviors, or send a PR! -For deprecated `bertabs` instructions, see https://github.com/huggingface/transformers-research-projects/blob/main/bertabs/README.md. -For the old `finetune_trainer.py` and related utils, see [`examples/legacy/seq2seq`](https://github.com/huggingface/transformers/blob/main/examples/legacy/seq2seq). - -### Supported Architectures - -- `BartForConditionalGeneration` -- `FSMTForConditionalGeneration` (translation only) -- `MBartForConditionalGeneration` -- `MarianMTModel` -- `PegasusForConditionalGeneration` -- `T5ForConditionalGeneration` -- `MT5ForConditionalGeneration` - -`run_summarization.py` is a lightweight example of how to download and preprocess a dataset from the [🤗 Datasets](https://github.com/huggingface/datasets) library or use your own files (jsonlines or csv), then fine-tune one of the architectures above on it. - -For custom datasets in `jsonlines` format please see: https://huggingface.co/docs/datasets/loading_datasets#json-files -and you also will find examples of these below. - -## With Trainer - -Here is an example on a summarization task: -```bash -python run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --dataset_name abisee/cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -Only T5 models `google-t5/t5-small`, `google-t5/t5-base`, `google-t5/t5-large`, `google-t5/t5-3b` and `google-t5/t5-11b` must use an additional argument: `--source_prefix "summarize: "`. - -We used CNN/DailyMail dataset in this example as `google-t5/t5-small` was trained on it and one can get good scores even when pre-training with a very small sample. - -Extreme Summarization (XSum) Dataset is another commonly used dataset for the task of summarization. To use it replace `--dataset_name abisee/cnn_dailymail --dataset_config "3.0.0"` with `--dataset_name EdinburghNLP/xsum`. - -And here is how you would use it on your own files, after adjusting the values for the arguments -`--train_file`, `--validation_file`, `--text_column` and `--summary_column` to match your setup: - -```bash -python run_summarization.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --train_file path_to_csv_or_jsonlines_file \ - --validation_file path_to_csv_or_jsonlines_file \ - --source_prefix "summarize: " \ - --output_dir /tmp/tst-summarization \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -The task of summarization supports custom CSV and JSONLINES formats. - -#### Custom CSV Files - -If it's a csv file the training and validation files should have a column for the inputs texts and a column for the summaries. - -If the csv file has just two columns as in the following example: - -```csv -text,summary -"I'm sitting here in a boring room. It's just another rainy Sunday afternoon. I'm wasting my time I got nothing to do. I'm hanging around I'm waiting for you. But nothing ever happens. And I wonder","I'm sitting in a room where I'm waiting for something to happen" -"I see trees so green, red roses too. I see them bloom for me and you. And I think to myself what a wonderful world. I see skies so blue and clouds so white. The bright blessed day, the dark sacred night. And I think to myself what a wonderful world.","I'm a gardener and I'm a big fan of flowers." -"Christmas time is here. Happiness and cheer. Fun for all that children call. Their favorite time of the year. Snowflakes in the air. Carols everywhere. Olden times and ancient rhymes. Of love and dreams to share","It's that time of year again." -``` - -The first column is assumed to be for `text` and the second is for summary. - -If the csv file has multiple columns, you can then specify the names of the columns to use: - -```bash - --text_column text_column_name \ - --summary_column summary_column_name \ -``` - -For example if the columns were: - -```csv -id,date,text,summary -``` - -and you wanted to select only `text` and `summary`, then you'd pass these additional arguments: - -```bash - --text_column text \ - --summary_column summary \ -``` - -#### Custom JSONLINES Files - -The second supported format is jsonlines. Here is an example of a jsonlines custom data file. - - -```json -{"text": "I'm sitting here in a boring room. It's just another rainy Sunday afternoon. I'm wasting my time I got nothing to do. I'm hanging around I'm waiting for you. But nothing ever happens. And I wonder", "summary": "I'm sitting in a room where I'm waiting for something to happen"} -{"text": "I see trees so green, red roses too. I see them bloom for me and you. And I think to myself what a wonderful world. I see skies so blue and clouds so white. The bright blessed day, the dark sacred night. And I think to myself what a wonderful world.", "summary": "I'm a gardener and I'm a big fan of flowers."} -{"text": "Christmas time is here. Happiness and cheer. Fun for all that children call. Their favorite time of the year. Snowflakes in the air. Carols everywhere. Olden times and ancient rhymes. Of love and dreams to share", "summary": "It's that time of year again."} -``` - -Same as with the CSV files, by default the first value will be used as the text record and the second as the summary record. Therefore you can use any key names for the entries, in this example `text` and `summary` were used. - -And as with the CSV files, you can specify which values to select from the file, by explicitly specifying the corresponding key names. In our example this again would be: - -```bash - --text_column text \ - --summary_column summary \ -``` - -## With Accelerate - -Based on the script [`run_summarization_no_trainer.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/summarization/run_summarization_no_trainer.py). - -Like `run_summarization.py`, this script allows you to fine-tune any of the models supported on a -summarization task, the main difference is that this -script exposes the bare training loop, to allow you to quickly experiment and add any customization you would like. - -It offers less options than the script with `Trainer` (for instance you can easily change the options for the optimizer -or the dataloaders directly in the script) but still run in a distributed setup, on TPU and supports mixed precision by -the mean of the [🤗 `Accelerate`](https://github.com/huggingface/accelerate) library. You can use the script normally -after installing it: - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -then - -```bash -python run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name abisee/cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -You can then use your usual launchers to run in it in a distributed environment, but the easiest way is to run - -```bash -accelerate config -``` - -and reply to the questions asked. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -accelerate launch run_summarization_no_trainer.py \ - --model_name_or_path google-t5/t5-small \ - --dataset_name abisee/cnn_dailymail \ - --dataset_config "3.0.0" \ - --source_prefix "summarize: " \ - --output_dir ~/tmp/tst-summarization -``` - -This command is the same and will work for: - -- a CPU-only setup -- a setup with one GPU -- a distributed training with several GPUs (single or multi node) -- a training on TPUs - -Note that this library is in alpha release so your feedback is more than welcome if you encounter any problem using it. diff --git a/examples/pytorch/summarization/requirements.txt b/examples/pytorch/summarization/requirements.txt deleted file mode 100644 index 8db3440bebad..000000000000 --- a/examples/pytorch/summarization/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -accelerate >= 0.12.0 -datasets >= 1.8.0 -sentencepiece != 0.1.92 -protobuf -rouge-score -nltk >= 3.9 -py7zr -torch >= 1.3 -evaluate diff --git a/examples/pytorch/summarization/run_summarization.py b/examples/pytorch/summarization/run_summarization.py deleted file mode 100755 index 4400e6ac4e9f..000000000000 --- a/examples/pytorch/summarization/run_summarization.py +++ /dev/null @@ -1,769 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "datasets >= 1.8.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "rouge-score", -# "nltk >= 3.9", -# "py7zr", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -""" -Fine-tuning the library models for sequence to sequence. -""" -# You can also adapt this script on your own sequence to sequence task. Pointers for this are left as comments. - -import logging -import os -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -import nltk # Here to have a nice missing dependency error message early on -import numpy as np -from datasets import load_dataset -from filelock import FileLock -from huggingface_hub import is_offline_mode - -import transformers -from transformers import ( - AutoConfig, - AutoModelForSeq2SeqLM, - AutoTokenizer, - DataCollatorForSeq2Seq, - HfArgumentParser, - MBart50Tokenizer, - MBart50TokenizerFast, - MBartTokenizer, - MBartTokenizerFast, - Seq2SeqTrainer, - Seq2SeqTrainingArguments, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/summarization/requirements.txt") - -logger = logging.getLogger(__name__) - -# NLTK 3.9 replaced the pickled punkt data with punkt_tab, which is what sent_tokenize loads -try: - nltk.data.find("tokenizers/punkt_tab") -except (LookupError, OSError): - if is_offline_mode(): - raise LookupError( - "Offline mode: run this script without TRANSFORMERS_OFFLINE first to download nltk data files" - ) - with FileLock(".lock") as lock: - nltk.download("punkt_tab", quiet=True) - -# A list of all multilingual tokenizer which require lang attribute. -MULTILINGUAL_TOKENIZERS = [MBartTokenizer, MBartTokenizerFast, MBart50Tokenizer, MBart50TokenizerFast] - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - resize_position_embeddings: bool | None = field( - default=None, - metadata={ - "help": ( - "Whether to automatically resize the position embeddings if `max_source_length` exceeds " - "the model's position embeddings." - ) - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - lang: str | None = field(default=None, metadata={"help": "Language id for summarization."}) - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - text_column: str | None = field( - default=None, - metadata={"help": "The name of the column in the datasets containing the full texts (for summarization)."}, - ) - summary_column: str | None = field( - default=None, - metadata={"help": "The name of the column in the datasets containing the summaries (for summarization)."}, - ) - train_file: str | None = field( - default=None, metadata={"help": "The input training data file (a jsonlines or csv file)."} - ) - validation_file: str | None = field( - default=None, - metadata={ - "help": ( - "An optional input evaluation data file to evaluate the metrics (rouge) on (a jsonlines or csv file)." - ) - }, - ) - test_file: str | None = field( - default=None, - metadata={ - "help": "An optional input test data file to evaluate the metrics (rouge) on (a jsonlines or csv file)." - }, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_source_length: int | None = field( - default=1024, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - max_target_length: int | None = field( - default=128, - metadata={ - "help": ( - "The maximum total sequence length for target text after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - val_max_target_length: int | None = field( - default=None, - metadata={ - "help": ( - "The maximum total sequence length for validation target text after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded. Will default to `max_target_length`. " - "This argument is also used to override the ``max_length`` param of ``model.generate``, which is used " - "during ``evaluate`` and ``predict``." - ) - }, - ) - pad_to_max_length: bool = field( - default=False, - metadata={ - "help": ( - "Whether to pad all samples to model maximum sentence length. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch. More " - "efficient on GPU but very bad for TPU." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - num_beams: int | None = field( - default=1, - metadata={ - "help": ( - "Number of beams to use for evaluation. This argument will be passed to ``model.generate``, " - "which is used during ``evaluate`` and ``predict``." - ) - }, - ) - ignore_pad_token_for_loss: bool = field( - default=True, - metadata={ - "help": "Whether to ignore the tokens corresponding to padded labels in the loss computation or not." - }, - ) - source_prefix: str | None = field( - default=None, metadata={"help": "A prefix to add before every source text (useful for T5 models)."} - ) - - forced_bos_token: str | None = field( - default=None, - metadata={ - "help": ( - "The token to force as the first generated token after the decoder_start_token_id. " - "Useful for multilingual models like mBART where the first generated token" - "needs to be the target language token (Usually it is the target language token)" - ) - }, - ) - - def __post_init__(self): - if ( - self.dataset_name is None - and self.train_file is None - and self.validation_file is None - and self.test_file is None - ): - raise ValueError("Need either a dataset name or a training, validation, or test file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - if self.test_file is not None: - extension = self.test_file.split(".")[-1] - assert extension in ["csv", "json"], "`test_file` should be a csv or a json file." - if self.val_max_target_length is None: - self.val_max_target_length = self.max_target_length - - -summarization_name_mapping = { - "amazon_reviews_multi": ("review_body", "review_title"), - "big_patent": ("description", "abstract"), - "cnn_dailymail": ("article", "highlights"), - "orange_sum": ("text", "summary"), - "pn_summary": ("article", "summary"), - "psc": ("extract_text", "summary_text"), - "samsum": ("dialogue", "summary"), - "thaisum": ("body", "summary"), - "xglue": ("news_body", "news_title"), - "xsum": ("document", "summary"), - "wiki_summary": ("article", "highlights"), - "multi_news": ("document", "summary"), -} - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, Seq2SeqTrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - if data_args.source_prefix is None and model_args.model_name_or_path in [ - "google-t5/t5-small", - "google-t5/t5-base", - "google-t5/t5-large", - "google-t5/t5-3b", - "google-t5/t5-11b", - ]: - logger.warning( - "You're running a t5 model but didn't provide a source prefix, which is the expected, e.g. with " - "`--source_prefix 'summarize: ' `" - ) - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files this script will use the first column for the full texts and the second column for the - # summaries (unless you specify column names for this with the `text_column` and `summary_column` arguments). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - if data_args.test_file is not None: - data_files["test"] = data_args.test_file - extension = data_args.test_file.split(".")[-1] - raw_datasets = load_dataset( - extension, - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForSeq2SeqLM.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - if model.config.decoder_start_token_id is None and isinstance(tokenizer, (MBartTokenizer, MBartTokenizerFast)): - if isinstance(tokenizer, MBartTokenizer): - model.config.decoder_start_token_id = tokenizer.lang_code_to_id[data_args.lang] - else: - model.config.decoder_start_token_id = tokenizer.convert_tokens_to_ids(data_args.lang) - - if model.config.decoder_start_token_id is None: - raise ValueError("Make sure that `config.decoder_start_token_id` is correctly defined") - - if ( - hasattr(model.config, "max_position_embeddings") - and model.config.max_position_embeddings < data_args.max_source_length - ): - if model_args.resize_position_embeddings is None: - logger.warning( - "Increasing the model's number of position embedding vectors from" - f" {model.config.max_position_embeddings} to {data_args.max_source_length}." - ) - model.resize_position_embeddings(data_args.max_source_length) - elif model_args.resize_position_embeddings: - model.resize_position_embeddings(data_args.max_source_length) - else: - raise ValueError( - f"`--max_source_length` is set to {data_args.max_source_length}, but the model only has" - f" {model.config.max_position_embeddings} position encodings. Consider either reducing" - f" `--max_source_length` to {model.config.max_position_embeddings} or to automatically resize the" - " model's position encodings by passing `--resize_position_embeddings`." - ) - - prefix = data_args.source_prefix if data_args.source_prefix is not None else "" - - # Preprocessing the datasets. - # We need to tokenize inputs and targets. - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - column_names = raw_datasets["train"].column_names - elif training_args.do_eval: - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - column_names = raw_datasets["validation"].column_names - elif training_args.do_predict: - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - column_names = raw_datasets["test"].column_names - else: - logger.info("There is nothing to do. Please pass `do_train`, `do_eval` and/or `do_predict`.") - return - - if isinstance(tokenizer, tuple(MULTILINGUAL_TOKENIZERS)): - assert data_args.lang is not None, ( - f"{tokenizer.__class__.__name__} is a multilingual tokenizer which requires --lang argument" - ) - - tokenizer.src_lang = data_args.lang - tokenizer.tgt_lang = data_args.lang - - # For multilingual translation models like mBART-50 and M2M100 we need to force the target language token - # as the first generated token. We ask the user to explicitly provide this as --forced_bos_token argument. - forced_bos_token_id = ( - tokenizer.lang_code_to_id[data_args.forced_bos_token] if data_args.forced_bos_token is not None else None - ) - model.config.forced_bos_token_id = forced_bos_token_id - - # Get the column names for input/target. - dataset_columns = summarization_name_mapping.get(data_args.dataset_name) - if data_args.text_column is None: - text_column = dataset_columns[0] if dataset_columns is not None else column_names[0] - else: - text_column = data_args.text_column - if text_column not in column_names: - raise ValueError( - f"--text_column' value '{data_args.text_column}' needs to be one of: {', '.join(column_names)}" - ) - if data_args.summary_column is None: - summary_column = dataset_columns[1] if dataset_columns is not None else column_names[1] - else: - summary_column = data_args.summary_column - if summary_column not in column_names: - raise ValueError( - f"--summary_column' value '{data_args.summary_column}' needs to be one of: {', '.join(column_names)}" - ) - - # Temporarily set max_target_length for training. - max_target_length = data_args.max_target_length - padding = "max_length" if data_args.pad_to_max_length else False - - if training_args.label_smoothing_factor > 0 and not hasattr(model, "prepare_decoder_input_ids_from_labels"): - logger.warning( - "label_smoothing is enabled but the `prepare_decoder_input_ids_from_labels` method is not defined for " - f"`{model.__class__.__name__}`. This will lead to loss being calculated twice and will take up more memory" - ) - - def preprocess_function(examples): - # remove pairs where at least one record is None - - inputs, targets = [], [] - for i in range(len(examples[text_column])): - if examples[text_column][i] and examples[summary_column][i]: - inputs.append(examples[text_column][i]) - targets.append(examples[summary_column][i]) - - inputs = [prefix + inp for inp in inputs] - model_inputs = tokenizer(inputs, max_length=data_args.max_source_length, padding=padding, truncation=True) - - # Tokenize targets with the `text_target` keyword argument - labels = tokenizer(text_target=targets, max_length=max_target_length, padding=padding, truncation=True) - - # If we are padding here, replace all tokenizer.pad_token_id in the labels by -100 when we want to ignore - # padding in the loss. - if padding == "max_length" and data_args.ignore_pad_token_for_loss: - labels["input_ids"] = [ - [(l if l != tokenizer.pad_token_id else -100) for l in label] for label in labels["input_ids"] - ] - - model_inputs["labels"] = labels["input_ids"] - return model_inputs - - if training_args.do_train: - train_dataset = raw_datasets["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - with training_args.main_process_first(desc="train dataset map pre-processing"): - train_dataset = train_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - - if training_args.do_eval: - max_target_length = data_args.val_max_target_length - eval_dataset = raw_datasets["validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - with training_args.main_process_first(desc="validation dataset map pre-processing"): - eval_dataset = eval_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - - if training_args.do_predict: - max_target_length = data_args.val_max_target_length - predict_dataset = raw_datasets["test"] - if data_args.max_predict_samples is not None: - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - with training_args.main_process_first(desc="prediction dataset map pre-processing"): - predict_dataset = predict_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - - # Data collator - label_pad_token_id = -100 if data_args.ignore_pad_token_for_loss else tokenizer.pad_token_id - data_collator = DataCollatorForSeq2Seq( - tokenizer, - model=model, - label_pad_token_id=label_pad_token_id, - pad_to_multiple_of=8 if training_args.fp16 else None, - ) - - # Metric - metric = evaluate.load("rouge", cache_dir=model_args.cache_dir) - - def postprocess_text(preds, labels): - preds = [pred.strip() for pred in preds] - labels = [label.strip() for label in labels] - - # rougeLSum expects newline after each sentence - preds = ["\n".join(nltk.sent_tokenize(pred)) for pred in preds] - labels = ["\n".join(nltk.sent_tokenize(label)) for label in labels] - - return preds, labels - - def compute_metrics(eval_preds): - preds, labels = eval_preds - if isinstance(preds, tuple): - preds = preds[0] - # Replace -100s used for padding as we can't decode them - preds = np.where(preds != -100, preds, tokenizer.pad_token_id) - decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True) - labels = np.where(labels != -100, labels, tokenizer.pad_token_id) - decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) - - # Some simple post-processing - decoded_preds, decoded_labels = postprocess_text(decoded_preds, decoded_labels) - - result = metric.compute(predictions=decoded_preds, references=decoded_labels, use_stemmer=True) - result = {k: round(v * 100, 4) for k, v in result.items()} - prediction_lens = [np.count_nonzero(pred != tokenizer.pad_token_id) for pred in preds] - result["gen_len"] = np.mean(prediction_lens) - return result - - # Override the decoding parameters of Seq2SeqTrainer - training_args.generation_max_length = ( - training_args.generation_max_length - if training_args.generation_max_length is not None - else data_args.val_max_target_length - ) - training_args.generation_num_beams = ( - data_args.num_beams if data_args.num_beams is not None else training_args.generation_num_beams - ) - - # Initialize our Trainer - trainer = Seq2SeqTrainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - processing_class=tokenizer, - data_collator=data_collator, - compute_metrics=compute_metrics if training_args.predict_with_generate else None, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - results = {} - if training_args.do_eval: - logger.info("*** Evaluate ***") - if isinstance(eval_dataset, dict): - metrics = {} - for eval_ds_name, eval_ds in eval_dataset.items(): - dataset_metrics = trainer.evaluate(eval_dataset=eval_ds, metric_key_prefix=f"eval_{eval_ds_name}") - metrics.update(dataset_metrics) - else: - metrics = trainer.evaluate(metric_key_prefix="eval") - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - if training_args.do_predict: - logger.info("*** Predict ***") - - predict_results = trainer.predict(predict_dataset, metric_key_prefix="predict") - metrics = predict_results.metrics - max_predict_samples = ( - data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset) - ) - metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset)) - - trainer.log_metrics("predict", metrics) - trainer.save_metrics("predict", metrics) - - if trainer.is_world_process_zero(): - if training_args.predict_with_generate: - predictions = predict_results.predictions - predictions = np.where(predictions != -100, predictions, tokenizer.pad_token_id) - predictions = tokenizer.batch_decode( - predictions, skip_special_tokens=True, clean_up_tokenization_spaces=True - ) - predictions = [pred.strip() for pred in predictions] - output_prediction_file = os.path.join(training_args.output_dir, "generated_predictions.txt") - with open(output_prediction_file, "w", encoding="utf-8") as writer: - writer.write("\n".join(predictions)) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "summarization"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if data_args.lang is not None: - kwargs["language"] = data_args.lang - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - return results - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/summarization/run_summarization_no_trainer.py b/examples/pytorch/summarization/run_summarization_no_trainer.py deleted file mode 100644 index 662b67aa3b32..000000000000 --- a/examples/pytorch/summarization/run_summarization_no_trainer.py +++ /dev/null @@ -1,814 +0,0 @@ -#!/usr/bin/env python -# Copyright The HuggingFace Team and The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "datasets >= 1.8.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "rouge-score", -# "nltk >= 3.9", -# "py7zr", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -""" -Fine-tuning a 🤗 Transformers model on summarization. -""" -# You can also adapt this script on your own summarization task. Pointers for this are left as comments. - -import argparse -import json -import logging -import math -import os -import random -from pathlib import Path - -import datasets -import evaluate -import nltk -import numpy as np -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from filelock import FileLock -from huggingface_hub import HfApi, is_offline_mode -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_MAPPING, - AutoConfig, - AutoModelForSeq2SeqLM, - AutoTokenizer, - DataCollatorForSeq2Seq, - SchedulerType, - get_scheduler, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/summarization/requirements.txt") - -# You should update this to your particular problem to have better documentation of `model_type` -MODEL_CONFIG_CLASSES = list(MODEL_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - -# NLTK 3.9 replaced the pickled punkt data with punkt_tab, which is what sent_tokenize loads -try: - nltk.data.find("tokenizers/punkt_tab") -except (LookupError, OSError): - if is_offline_mode(): - raise LookupError( - "Offline mode: run this script without TRANSFORMERS_OFFLINE first to download nltk data files" - ) - with FileLock(".lock") as lock: - nltk.download("punkt_tab", quiet=True) - -summarization_name_mapping = { - "amazon_reviews_multi": ("review_body", "review_title"), - "big_patent": ("description", "abstract"), - "cnn_dailymail": ("article", "highlights"), - "orange_sum": ("text", "summary"), - "pn_summary": ("article", "summary"), - "psc": ("extract_text", "summary_text"), - "samsum": ("dialogue", "summary"), - "thaisum": ("body", "summary"), - "xglue": ("news_body", "news_title"), - "xsum": ("document", "summary"), - "wiki_summary": ("article", "highlights"), -} - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a summarization task") - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv or a json file containing the training data." - ) - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv or a json file containing the validation data." - ) - parser.add_argument( - "--ignore_pad_token_for_loss", - type=bool, - default=True, - help="Whether to ignore the tokens corresponding to padded labels in the loss computation or not.", - ) - parser.add_argument( - "--max_source_length", - type=int, - default=1024, - help=( - "The maximum total input sequence length after " - "tokenization.Sequences longer than this will be truncated, sequences shorter will be padded." - ), - ) - parser.add_argument( - "--source_prefix", - type=str, - default=None, - help="A prefix to add before every source text (useful for T5 models).", - ) - parser.add_argument( - "--preprocessing_num_workers", - type=int, - default=None, - help="The number of processes to use for the preprocessing.", - ) - parser.add_argument( - "--overwrite_cache", action="store_true", help="Overwrite the cached training and evaluation sets" - ) - parser.add_argument( - "--max_target_length", - type=int, - default=128, - help=( - "The maximum total sequence length for target text after " - "tokenization. Sequences longer than this will be truncated, sequences shorter will be padded. " - "during ``evaluate`` and ``predict``." - ), - ) - parser.add_argument( - "--val_max_target_length", - type=int, - default=None, - help=( - "The maximum total sequence length for validation " - "target text after tokenization.Sequences longer than this will be truncated, sequences shorter will be " - "padded. Will default to `max_target_length`.This argument is also used to override the ``max_length`` " - "param of ``model.generate``, which is used during ``evaluate`` and ``predict``." - ), - ) - parser.add_argument( - "--num_beams", - type=int, - default=None, - help=( - "Number of beams to use for evaluation. This argument will be " - "passed to ``model.generate``, which is used during ``evaluate`` and ``predict``." - ), - ) - parser.add_argument( - "--pad_to_max_length", - action="store_true", - help="If passed, pad all samples to `max_length`. Otherwise, dynamic padding is used.", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=False, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--tokenizer_name", - type=str, - default=None, - help="Pretrained tokenizer name or path if not the same as model_name", - ) - parser.add_argument( - "--text_column", - type=str, - default=None, - help="The name of the column in the datasets containing the full texts (for summarization).", - ) - parser.add_argument( - "--summary_column", - type=str, - default=None, - help="The name of the column in the datasets containing the summaries (for summarization).", - ) - parser.add_argument( - "--use_slow_tokenizer", - action="store_true", - help="If passed, will use a slow tokenizer (not backed by the Hugging Face Tokenizers library).", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument( - "--model_type", - type=str, - default=None, - help="Model type to use if training from scratch.", - choices=MODEL_TYPES, - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - if args.dataset_name is None and args.train_file is None and args.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator_log_kwargs = {} - - if args.with_tracking: - accelerator_log_kwargs["log_with"] = args.report_to - accelerator_log_kwargs["project_dir"] = args.output_dir - - accelerator = Accelerator(gradient_accumulation_steps=args.gradient_accumulation_steps, **accelerator_log_kwargs) - if args.source_prefix is None and args.model_name_or_path in [ - "google-t5/t5-small", - "google-t5/t5-base", - "google-t5/t5-large", - "google-t5/t5-3b", - "google-t5/t5-11b", - ]: - logger.warning( - "You're running a t5 model but didn't provide a source prefix, which is the expected, e.g. with " - "`--source_prefix 'summarize: ' `" - ) - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - else: - data_files = {} - if args.train_file is not None: - data_files["train"] = args.train_file - extension = args.train_file.split(".")[-1] - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.validation_file.split(".")[-1] - raw_datasets = load_dataset(extension, data_files=data_files) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - if args.config_name: - config = AutoConfig.from_pretrained(args.config_name, trust_remote_code=args.trust_remote_code) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained(args.model_name_or_path, trust_remote_code=args.trust_remote_code) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - - if args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained( - args.tokenizer_name, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - elif args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained( - args.model_name_or_path, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if args.model_name_or_path: - model = AutoModelForSeq2SeqLM.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForSeq2SeqLM.from_config(config, trust_remote_code=args.trust_remote_code) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - if model.config.decoder_start_token_id is None: - raise ValueError("Make sure that `config.decoder_start_token_id` is correctly defined") - - prefix = args.source_prefix if args.source_prefix is not None else "" - - # Preprocessing the datasets. - # First we tokenize all the texts. - column_names = raw_datasets["train"].column_names - - # Get the column names for input/target. - dataset_columns = summarization_name_mapping.get(args.dataset_name) - if args.text_column is None: - text_column = dataset_columns[0] if dataset_columns is not None else column_names[0] - else: - text_column = args.text_column - if text_column not in column_names: - raise ValueError( - f"--text_column' value '{args.text_column}' needs to be one of: {', '.join(column_names)}" - ) - if args.summary_column is None: - summary_column = dataset_columns[1] if dataset_columns is not None else column_names[1] - else: - summary_column = args.summary_column - if summary_column not in column_names: - raise ValueError( - f"--summary_column' value '{args.summary_column}' needs to be one of: {', '.join(column_names)}" - ) - - if args.val_max_target_length is None: - args.val_max_target_length = args.max_target_length - - # Temporarily set max_target_length for training. - max_target_length = args.max_target_length - padding = "max_length" if args.pad_to_max_length else False - - def preprocess_function(examples): - inputs = examples[text_column] - targets = examples[summary_column] - inputs = [prefix + inp for inp in inputs] - model_inputs = tokenizer(inputs, max_length=args.max_source_length, padding=padding, truncation=True) - - # Tokenize targets with the `text_target` keyword argument - labels = tokenizer(text_target=targets, max_length=max_target_length, padding=padding, truncation=True) - - # If we are padding here, replace all tokenizer.pad_token_id in the labels by -100 when we want to ignore - # padding in the loss. - if padding == "max_length" and args.ignore_pad_token_for_loss: - labels["input_ids"] = [ - [(l if l != tokenizer.pad_token_id else -100) for l in label] for label in labels["input_ids"] - ] - - model_inputs["labels"] = labels["input_ids"] - return model_inputs - - with accelerator.main_process_first(): - train_dataset = raw_datasets["train"].map( - preprocess_function, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - - # Temporarily set max_target_length for validation. - max_target_length = args.val_max_target_length - eval_dataset = raw_datasets["validation"].map( - preprocess_function, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 1): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - label_pad_token_id = -100 if args.ignore_pad_token_for_loss else tokenizer.pad_token_id - if accelerator.mixed_precision == "fp8": - pad_to_multiple_of = 16 - elif accelerator.mixed_precision != "no": - pad_to_multiple_of = 8 - else: - pad_to_multiple_of = None - data_collator = DataCollatorForSeq2Seq( - tokenizer, - model=model, - label_pad_token_id=label_pad_token_id, - pad_to_multiple_of=pad_to_multiple_of, - ) - - def postprocess_text(preds, labels): - preds = [pred.strip() for pred in preds] - labels = [label.strip() for label in labels] - - # rougeLSum expects newline after each sentence - preds = ["\n".join(nltk.sent_tokenize(pred)) for pred in preds] - labels = ["\n".join(nltk.sent_tokenize(label)) for label in labels] - - return preds, labels - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader(eval_dataset, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - no_decay = ["bias", "LayerNorm.weight", "layer_norm.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": args.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, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps * accelerator.num_processes, - num_training_steps=args.max_train_steps - if overrode_max_train_steps - else args.max_train_steps * accelerator.num_processes, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("summarization_no_trainer", experiment_config) - - # Metric - metric = evaluate.load("rouge") - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - with accelerator.accumulate(model): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - accelerator.backward(loss) - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - - # Checks if the accelerator has performed an optimization step behind the scenes - if accelerator.sync_gradients: - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if completed_steps >= args.max_train_steps: - break - - model.eval() - - gen_kwargs = { - "max_length": args.val_max_target_length, - "num_beams": args.num_beams, - } - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - generated_tokens = accelerator.unwrap_model(model).generate( - batch["input_ids"], - attention_mask=batch["attention_mask"], - **gen_kwargs, - ) - - generated_tokens = accelerator.pad_across_processes( - generated_tokens, dim=1, pad_index=tokenizer.pad_token_id - ) - labels = batch["labels"] - if not args.pad_to_max_length: - # If we did not pad to max length, we need to pad the labels too - labels = accelerator.pad_across_processes(batch["labels"], dim=1, pad_index=tokenizer.pad_token_id) - - generated_tokens, labels = accelerator.gather_for_metrics((generated_tokens, labels)) - generated_tokens = generated_tokens.cpu().numpy() - labels = labels.cpu().numpy() - - if args.ignore_pad_token_for_loss: - # Replace -100 in the labels as we can't decode them. - labels = np.where(labels != -100, labels, tokenizer.pad_token_id) - if isinstance(generated_tokens, tuple): - generated_tokens = generated_tokens[0] - decoded_preds = tokenizer.batch_decode(generated_tokens, skip_special_tokens=True) - decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) - - decoded_preds, decoded_labels = postprocess_text(decoded_preds, decoded_labels) - metric.add_batch( - predictions=decoded_preds, - references=decoded_labels, - ) - result = metric.compute(use_stemmer=True) - result = {k: round(v * 100, 4) for k, v in result.items()} - - logger.info(result) - - if args.with_tracking: - result["train_loss"] = total_loss.item() / len(train_dataloader) - result["epoch"] = epoch - result["step"] = completed_steps - accelerator.log(result, step=completed_steps) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - all_results = {f"eval_{k}": v for k, v in result.items()} - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump(all_results, f) - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/test_accelerate_examples.py b/examples/pytorch/test_accelerate_examples.py deleted file mode 100644 index be974576d234..000000000000 --- a/examples/pytorch/test_accelerate_examples.py +++ /dev/null @@ -1,386 +0,0 @@ -# Copyright 2018 HuggingFace Inc.. -# -# 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 argparse -import json -import logging -import os -import shutil -import sys -import tempfile -import unittest -from unittest import mock - -from accelerate.utils import write_basic_config - -from transformers.testing_utils import ( - TestCasePlus, - backend_device_count, - run_command, - slow, - torch_device, -) - - -logging.basicConfig(level=logging.DEBUG) - -logger = logging.getLogger() - - -def get_setup_file(): - parser = argparse.ArgumentParser() - parser.add_argument("-f") - args = parser.parse_args() - return args.f - - -def get_results(output_dir): - results = {} - path = os.path.join(output_dir, "all_results.json") - if os.path.exists(path): - with open(path, encoding="utf-8") as f: - results = json.load(f) - else: - raise ValueError(f"can't find {path}") - return results - - -stream_handler = logging.StreamHandler(sys.stdout) -logger.addHandler(stream_handler) - - -class ExamplesTestsNoTrainer(TestCasePlus): - @classmethod - def setUpClass(cls): - # Write Accelerate config, will pick up on CPU, GPU, and multi-GPU - cls.tmpdir = tempfile.mkdtemp() - cls.configPath = os.path.join(cls.tmpdir, "default_config.yml") - write_basic_config(save_location=cls.configPath) - cls._launch_args = ["accelerate", "launch", "--config_file", cls.configPath] - - @classmethod - def tearDownClass(cls): - shutil.rmtree(cls.tmpdir) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_glue_no_trainer(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/text-classification/run_glue_no_trainer.py - --model_name_or_path distilbert/distilbert-base-uncased - --output_dir {tmp_dir} - --train_file ./tests/fixtures/tests_samples/MRPC/train.csv - --validation_file ./tests/fixtures/tests_samples/MRPC/dev.csv - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --learning_rate=1e-4 - --seed=42 - --num_warmup_steps=2 - --checkpointing_steps epoch - --with_tracking - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_accuracy"], 0.75) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "epoch_0"))) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "glue_no_trainer"))) - - @unittest.skip("Zach is working on this.") - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_clm_no_trainer(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/language-modeling/run_clm_no_trainer.py - --model_name_or_path distilbert/distilgpt2 - --train_file ./tests/fixtures/sample_text.txt - --validation_file ./tests/fixtures/sample_text.txt - --block_size 128 - --per_device_train_batch_size 5 - --per_device_eval_batch_size 5 - --num_train_epochs 2 - --output_dir {tmp_dir} - --checkpointing_steps epoch - --with_tracking - """.split() - - if backend_device_count(torch_device) > 1: - # Skipping because there are not enough batches to train the model + would need a drop_last to work. - return - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertLess(result["perplexity"], 100) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "epoch_0"))) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "clm_no_trainer"))) - - @unittest.skip("Zach is working on this.") - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_mlm_no_trainer(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/language-modeling/run_mlm_no_trainer.py - --model_name_or_path distilbert/distilroberta-base - --train_file ./tests/fixtures/sample_text.txt - --validation_file ./tests/fixtures/sample_text.txt - --output_dir {tmp_dir} - --num_train_epochs=1 - --checkpointing_steps epoch - --with_tracking - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertLess(result["perplexity"], 42) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "epoch_0"))) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "mlm_no_trainer"))) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_ner_no_trainer(self): - # with so little data distributed training needs more epochs to get the score on par with 0/1 gpu - epochs = 7 if backend_device_count(torch_device) > 1 else 2 - - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/token-classification/run_ner_no_trainer.py - --model_name_or_path google-bert/bert-base-uncased - --train_file tests/fixtures/tests_samples/conll/sample.json - --validation_file tests/fixtures/tests_samples/conll/sample.json - --output_dir {tmp_dir} - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=2 - --num_train_epochs={epochs} - --seed 7 - --checkpointing_steps epoch - --with_tracking - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_accuracy"], 0.75) - self.assertLess(result["train_loss"], 0.6) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "epoch_0"))) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "ner_no_trainer"))) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_squad_no_trainer(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/question-answering/run_qa_no_trainer.py - --model_name_or_path google-bert/bert-base-uncased - --version_2_with_negative - --train_file tests/fixtures/tests_samples/SQUAD/sample.json - --validation_file tests/fixtures/tests_samples/SQUAD/sample.json - --output_dir {tmp_dir} - --seed=42 - --max_train_steps=10 - --num_warmup_steps=2 - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --checkpointing_steps epoch - --with_tracking - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - # Because we use --version_2_with_negative the testing script uses SQuAD v2 metrics. - self.assertGreaterEqual(result["eval_f1"], 28) - self.assertGreaterEqual(result["eval_exact"], 28) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "epoch_0"))) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "qa_no_trainer"))) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_swag_no_trainer(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/multiple-choice/run_swag_no_trainer.py - --model_name_or_path google-bert/bert-base-uncased - --train_file tests/fixtures/tests_samples/swag/sample.json - --validation_file tests/fixtures/tests_samples/swag/sample.json - --output_dir {tmp_dir} - --max_train_steps=20 - --num_warmup_steps=2 - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --with_tracking - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_accuracy"], 0.8) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "swag_no_trainer"))) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_summarization_no_trainer(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/summarization/run_summarization_no_trainer.py - --model_name_or_path google-t5/t5-small - --train_file tests/fixtures/tests_samples/xsum/sample.json - --validation_file tests/fixtures/tests_samples/xsum/sample.json - --output_dir {tmp_dir} - --max_train_steps=50 - --num_warmup_steps=8 - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --checkpointing_steps epoch - --with_tracking - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_rouge1"], 10) - self.assertGreaterEqual(result["eval_rouge2"], 2) - self.assertGreaterEqual(result["eval_rougeL"], 7) - self.assertGreaterEqual(result["eval_rougeLsum"], 7) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "epoch_0"))) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "summarization_no_trainer"))) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_translation_no_trainer(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/translation/run_translation_no_trainer.py - --model_name_or_path sshleifer/student_marian_en_ro_6_1 - --source_lang en - --target_lang ro - --train_file tests/fixtures/tests_samples/wmt16/sample.json - --validation_file tests/fixtures/tests_samples/wmt16/sample.json - --output_dir {tmp_dir} - --max_train_steps=50 - --num_warmup_steps=8 - --num_beams=6 - --learning_rate=3e-3 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --source_lang en_XX - --target_lang ro_RO - --checkpointing_steps epoch - --with_tracking - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_bleu"], 30) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "epoch_0"))) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "translation_no_trainer"))) - - @slow - def test_run_semantic_segmentation_no_trainer(self): - stream_handler = logging.StreamHandler(sys.stdout) - logger.addHandler(stream_handler) - - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/semantic-segmentation/run_semantic_segmentation_no_trainer.py - --dataset_name huggingface/semantic-segmentation-test-sample - --output_dir {tmp_dir} - --max_train_steps=10 - --num_warmup_steps=2 - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --checkpointing_steps epoch - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_overall_accuracy"], 0.10) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_image_classification_no_trainer(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/image-classification/run_image_classification_no_trainer.py - --model_name_or_path google/vit-base-patch16-224-in21k - --dataset_name hf-internal-testing/cats_vs_dogs_sample - --learning_rate 1e-4 - --per_device_train_batch_size 2 - --per_device_eval_batch_size 1 - --max_train_steps 2 - --train_val_split 0.1 - --seed 42 - --output_dir {tmp_dir} - --with_tracking - --checkpointing_steps 1 - --label_column_name labels - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - # The base model scores a 25% - self.assertGreaterEqual(result["eval_accuracy"], 0.4) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "step_1"))) - self.assertTrue(os.path.exists(os.path.join(tmp_dir, "image_classification_no_trainer"))) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_object_detection_no_trainer(self): - stream_handler = logging.StreamHandler(sys.stdout) - logger.addHandler(stream_handler) - - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/object-detection/run_object_detection_no_trainer.py - --model_name_or_path qubvel-hf/detr-resnet-50-finetuned-10k-cppe5 - --dataset_name qubvel-hf/cppe-5-sample - --output_dir {tmp_dir} - --max_train_steps=10 - --num_warmup_steps=2 - --learning_rate=1e-6 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --checkpointing_steps epoch - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertGreaterEqual(result["test_map"], 0.10) - - @slow - @mock.patch.dict(os.environ, {"WANDB_MODE": "offline", "DVCLIVE_TEST": "true"}) - def test_run_instance_segmentation_no_trainer(self): - stream_handler = logging.StreamHandler(sys.stdout) - logger.addHandler(stream_handler) - - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - {self.examples_dir}/pytorch/instance-segmentation/run_instance_segmentation_no_trainer.py - --model_name_or_path qubvel-hf/finetune-instance-segmentation-ade20k-mini-mask2former - --output_dir {tmp_dir} - --dataset_name qubvel-hf/ade20k-nano - --do_reduce_labels - --image_height 256 - --image_width 256 - --num_train_epochs 1 - --per_device_train_batch_size 2 - --per_device_eval_batch_size 1 - --seed 1234 - """.split() - - run_command(self._launch_args + testargs) - result = get_results(tmp_dir) - self.assertGreaterEqual(result["test_map"], 0.1) diff --git a/examples/pytorch/test_pytorch_examples.py b/examples/pytorch/test_pytorch_examples.py deleted file mode 100644 index f21d5f60c51a..000000000000 --- a/examples/pytorch/test_pytorch_examples.py +++ /dev/null @@ -1,714 +0,0 @@ -# Copyright 2018 HuggingFace Inc.. -# -# 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 -import logging -import os -import sys -import tempfile -from unittest.mock import patch - -import torch -from test_memory_cleanup_mixin import MemoryCleanupMixin - -from transformers import ( - AutoTokenizer, - BertConfig, - BertForMultipleChoice, - GPT2Config, - GPT2LMHeadModel, - ViTMAEForPreTraining, - Wav2Vec2ForPreTraining, -) -from transformers.testing_utils import ( - CaptureLogger, - TestCasePlus, - backend_device_count, - is_torch_fp16_available_on_device, - slow, - torch_device, -) - - -SRC_DIRS = [ - os.path.join(os.path.dirname(__file__), dirname) - for dirname in [ - "text-generation", - "text-classification", - "token-classification", - "language-modeling", - "multiple-choice", - "question-answering", - "summarization", - "translation", - "image-classification", - "speech-recognition", - "audio-classification", - "speech-pretraining", - "image-pretraining", - "semantic-segmentation", - "object-detection", - "instance-segmentation", - ] -] -sys.path.extend(SRC_DIRS) - - -if SRC_DIRS is not None: - import run_audio_classification - import run_clm - import run_generation - import run_glue - import run_image_classification - import run_instance_segmentation - import run_mae - import run_mlm - import run_ner - import run_object_detection - import run_qa as run_squad - import run_semantic_segmentation - import run_seq2seq_qa as run_squad_seq2seq - import run_speech_recognition_ctc - import run_speech_recognition_ctc_adapter - import run_speech_recognition_seq2seq - import run_summarization - import run_swag - import run_translation - import run_wav2vec2_pretraining_no_trainer - - -logging.basicConfig(level=logging.DEBUG) - -logger = logging.getLogger() - - -def get_results(output_dir): - results = {} - path = os.path.join(output_dir, "all_results.json") - if os.path.exists(path): - with open(path, encoding="utf-8") as f: - results = json.load(f) - else: - raise ValueError(f"can't find {path}") - return results - - -stream_handler = logging.StreamHandler(sys.stdout) -logger.addHandler(stream_handler) - - -class ExamplesTests(MemoryCleanupMixin, TestCasePlus): - # Tests do training — gradients are required. - run_under_no_grad = False - - def test_run_glue(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_glue.py - --model_name_or_path hf-internal-testing/tiny-random-bert - --output_dir {tmp_dir} - --train_file ./tests/fixtures/tests_samples/MRPC/train.csv - --validation_file ./tests/fixtures/tests_samples/MRPC/dev.csv - --do_train - --do_eval - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --learning_rate=5e-3 - --max_steps=30 - --warmup_steps=2 - --seed=42 - --max_seq_length=128 - --dataloader_num_workers=0 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_glue.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_accuracy"], 0.75) - - def test_run_clm(self): - tmp_dir = self.get_auto_remove_tmp_dir() - - if backend_device_count(torch_device) > 1: - # Skipping because there are not enough batches to train the model + would need a drop_last to work. - return - - # Create a tiny GPT-2 from config to avoid downloading distilgpt2 (82M params). - # Fixed seed gives reproducible init; 25 epochs + lr=1e-2 lets it memorize the tiny - # sample_text.txt fixture (33 lines) to achieve perplexity < 100. - with tempfile.TemporaryDirectory() as model_dir: - torch.manual_seed(42) - GPT2LMHeadModel( - GPT2Config(vocab_size=50257, n_embd=32, n_layer=2, n_head=2, n_positions=512) - ).save_pretrained(model_dir) - AutoTokenizer.from_pretrained("sshleifer/tiny-gpt2").save_pretrained(model_dir) - - testargs = f""" - run_clm.py - --model_name_or_path {model_dir} - --train_file ./tests/fixtures/sample_text.txt - --validation_file ./tests/fixtures/sample_text.txt - --do_train - --do_eval - --block_size 128 - --per_device_train_batch_size 5 - --per_device_eval_batch_size 5 - --num_train_epochs 25 - --learning_rate 1e-2 - --output_dir {tmp_dir} - """.split() - - if torch_device == "cpu": - testargs.append("--use_cpu") - - with patch.object(sys, "argv", testargs): - run_clm.main() - result = get_results(tmp_dir) - self.assertLess(result["perplexity"], 100) - - def test_run_clm_config_overrides(self): - # test that config_overrides works, despite the misleading dumps of default un-updated - # config via tokenizer - - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_clm.py - --model_type gpt2 - --tokenizer_name openai-community/gpt2 - --train_file ./tests/fixtures/sample_text.txt - --output_dir {tmp_dir} - --config_overrides n_embd=10,n_head=2 - """.split() - - if torch_device == "cpu": - testargs.append("--use_cpu") - - logger = run_clm.logger - with patch.object(sys, "argv", testargs): - with CaptureLogger(logger) as cl: - run_clm.main() - - self.assertIn('"n_embd": 10', cl.out) - self.assertIn('"n_head": 2', cl.out) - - def test_run_mlm(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_mlm.py - --model_name_or_path hf-internal-testing/tiny-random-bert - --train_file ./tests/fixtures/sample_text.txt - --validation_file ./tests/fixtures/sample_text.txt - --output_dir {tmp_dir} - --do_train - --do_eval - --prediction_loss_only - --num_train_epochs=20 - --learning_rate=5e-3 - --dataloader_num_workers=0 - --seed=42 - """.split() - - if torch_device == "cpu": - testargs.append("--use_cpu") - - with patch.object(sys, "argv", testargs): - run_mlm.main() - result = get_results(tmp_dir) - self.assertLess(result["perplexity"], 100) - - def test_run_ner(self): - # with so little data distributed training needs more epochs to get the score on par with 0/1 gpu - epochs = 14 if backend_device_count(torch_device) > 1 else 10 - - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_ner.py - --model_name_or_path hf-internal-testing/tiny-random-bert - --train_file tests/fixtures/tests_samples/conll/sample.json - --validation_file tests/fixtures/tests_samples/conll/sample.json - --output_dir {tmp_dir} - --do_train - --do_eval - --warmup_steps=2 - --learning_rate=5e-3 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=2 - --num_train_epochs={epochs} - --seed 7 - --ignore_mismatched_sizes True - """.split() - - if torch_device == "cpu": - testargs.append("--use_cpu") - - with patch.object(sys, "argv", testargs): - run_ner.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_accuracy"], 0.75) - self.assertLess(result["eval_loss"], 1.0) - - def test_run_squad(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_qa.py - --model_name_or_path hf-internal-testing/tiny-random-bert - --version_2_with_negative - --train_file tests/fixtures/tests_samples/SQUAD/sample.json - --validation_file tests/fixtures/tests_samples/SQUAD/sample.json - --output_dir {tmp_dir} - --max_steps=30 - --warmup_steps=2 - --do_train - --do_eval - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - """.split() - - with patch.object(sys, "argv", testargs): - run_squad.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_f1"], 30) - self.assertGreaterEqual(result["eval_exact"], 30) - - def test_run_squad_seq2seq(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_seq2seq_qa.py - --model_name_or_path sshleifer/t5-tinier-random - --context_column context - --question_column question - --answer_column answers - --version_2_with_negative - --train_file tests/fixtures/tests_samples/SQUAD/sample.json - --validation_file tests/fixtures/tests_samples/SQUAD/sample.json - --output_dir {tmp_dir} - --max_steps=30 - --warmup_steps=2 - --do_train - --do_eval - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --predict_with_generate - """.split() - - with patch.object(sys, "argv", testargs): - run_squad_seq2seq.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_f1"], 30) - self.assertGreaterEqual(result["eval_exact"], 30) - - def test_run_swag(self): - tmp_dir = self.get_auto_remove_tmp_dir() - # Create a tiny BertForMultipleChoice from config to avoid downloading a large model - # and to ensure the classifier head has the correct shape ([1, hidden_size]). - # Fixed seed guarantees reproducible weight init so accuracy is deterministic. - with tempfile.TemporaryDirectory() as model_dir: - torch.manual_seed(42) - config = BertConfig( - vocab_size=1000, - hidden_size=32, - num_hidden_layers=5, - num_attention_heads=4, - intermediate_size=37, - ) - BertForMultipleChoice(config).save_pretrained(model_dir) - AutoTokenizer.from_pretrained("hf-internal-testing/tiny-random-bert").save_pretrained(model_dir) - - testargs = f""" - run_swag.py - --model_name_or_path {model_dir} - --train_file tests/fixtures/tests_samples/swag/sample.json - --validation_file tests/fixtures/tests_samples/swag/sample.json - --output_dir {tmp_dir} - --max_steps=30 - --warmup_steps=2 - --do_train - --do_eval - --learning_rate=5e-3 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - """.split() - - with patch.object(sys, "argv", testargs): - run_swag.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_accuracy"], 0.8) - - def test_generation(self): - testargs = ["run_generation.py", "--prompt=Hello", "--length=10", "--seed=42"] - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - model_type, model_name = ( - "--model_type=gpt2", - "--model_name_or_path=sshleifer/tiny-gpt2", - ) - with patch.object(sys, "argv", testargs + [model_type, model_name]): - result = run_generation.main() - self.assertGreaterEqual(len(result[0]), 10) - - @slow - def test_run_summarization(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_summarization.py - --model_name_or_path google-t5/t5-small - --train_file tests/fixtures/tests_samples/xsum/sample.json - --validation_file tests/fixtures/tests_samples/xsum/sample.json - --output_dir {tmp_dir} - --max_steps=50 - --warmup_steps=8 - --do_train - --do_eval - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --predict_with_generate - """.split() - - with patch.object(sys, "argv", testargs): - run_summarization.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_rouge1"], 10) - self.assertGreaterEqual(result["eval_rouge2"], 2) - self.assertGreaterEqual(result["eval_rougeL"], 7) - self.assertGreaterEqual(result["eval_rougeLsum"], 7) - - @slow - def test_run_translation(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_translation.py - --model_name_or_path sshleifer/student_marian_en_ro_6_1 - --source_lang en - --target_lang ro - --train_file tests/fixtures/tests_samples/wmt16/sample.json - --validation_file tests/fixtures/tests_samples/wmt16/sample.json - --output_dir {tmp_dir} - --max_steps=50 - --warmup_steps=8 - --do_train - --do_eval - --learning_rate=3e-3 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --predict_with_generate - --source_lang en_XX - --target_lang ro_RO - --max_source_length 512 - """.split() - - with patch.object(sys, "argv", testargs): - run_translation.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_bleu"], 30) - - @slow - def test_run_image_classification(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_image_classification.py - --output_dir {tmp_dir} - --model_name_or_path google/vit-base-patch16-224-in21k - --dataset_name hf-internal-testing/cats_vs_dogs_sample - --do_train - --do_eval - --learning_rate 1e-4 - --per_device_train_batch_size 2 - --per_device_eval_batch_size 1 - --remove_unused_columns False - --dataloader_num_workers 0 - --metric_for_best_model accuracy - --max_steps 10 - --train_val_split 0.1 - --seed 42 - --label_column_name labels - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_image_classification.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_accuracy"], 0.8) - - @slow - def test_run_speech_recognition_ctc(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_speech_recognition_ctc.py - --output_dir {tmp_dir} - --model_name_or_path hf-internal-testing/tiny-random-wav2vec2 - --dataset_name hf-internal-testing/librispeech_asr_dummy - --dataset_config_name clean - --train_split_name validation - --eval_split_name validation - --do_train - --do_eval - --learning_rate 1e-4 - --per_device_train_batch_size 2 - --per_device_eval_batch_size 1 - --remove_unused_columns False - --preprocessing_num_workers 0 - --max_steps 10 - --seed 42 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_speech_recognition_ctc.main() - result = get_results(tmp_dir) - self.assertLess(result["eval_loss"], result["train_loss"]) - - def test_run_speech_recognition_ctc_adapter(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_speech_recognition_ctc_adapter.py - --output_dir {tmp_dir} - --model_name_or_path hf-internal-testing/tiny-random-wav2vec2 - --dataset_name hf-internal-testing/librispeech_asr_dummy - --dataset_config_name clean - --train_split_name validation - --eval_split_name validation - --do_train - --do_eval - --learning_rate 1e-4 - --per_device_train_batch_size 2 - --per_device_eval_batch_size 1 - --remove_unused_columns False - --preprocessing_num_workers 0 - --max_steps 10 - --max_duration_in_seconds 3.0 - --min_duration_in_seconds 0.0 - --target_language tur - --seed 42 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_speech_recognition_ctc_adapter.main() - result = get_results(tmp_dir) - self.assertTrue(os.path.isfile(os.path.join(tmp_dir, "./adapter.tur.safetensors"))) - self.assertLess(result["eval_loss"], result["train_loss"]) - - def test_run_speech_recognition_seq2seq(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_speech_recognition_seq2seq.py - --output_dir {tmp_dir} - --model_name_or_path hf-internal-testing/tiny-random-speech-encoder-decoder - --dataset_name hf-internal-testing/librispeech_asr_dummy - --dataset_config_name clean - --train_split_name validation - --eval_split_name validation - --do_train - --do_eval - --learning_rate 1e-4 - --per_device_train_batch_size 2 - --per_device_eval_batch_size 4 - --remove_unused_columns False - --preprocessing_num_workers 0 - --max_steps 10 - --max_duration_in_seconds 3.0 - --min_duration_in_seconds 0.0 - --seed 42 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_speech_recognition_seq2seq.main() - result = get_results(tmp_dir) - self.assertLess(result["eval_loss"], result["train_loss"]) - - def test_run_audio_classification(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_audio_classification.py - --output_dir {tmp_dir} - --model_name_or_path hf-internal-testing/tiny-random-wav2vec2 - --dataset_name anton-l/superb_demo - --dataset_config_name ks - --train_split_name test - --eval_split_name test - --audio_column_name audio - --label_column_name label - --do_train - --do_eval - --learning_rate 1e-4 - --per_device_train_batch_size 2 - --per_device_eval_batch_size 1 - --remove_unused_columns False - --num_train_epochs 10 - --max_steps 50 - --seed 42 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_audio_classification.main() - result = get_results(tmp_dir) - self.assertLess(result["eval_loss"], result["train_loss"]) - - def test_run_wav2vec2_pretraining(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_wav2vec2_pretraining_no_trainer.py - --output_dir {tmp_dir} - --model_name_or_path hf-internal-testing/tiny-random-wav2vec2 - --dataset_name hf-internal-testing/librispeech_asr_dummy - --dataset_config_names clean - --dataset_split_names validation - --learning_rate 1e-4 - --per_device_train_batch_size 4 - --per_device_eval_batch_size 4 - --preprocessing_num_workers 0 - --max_train_steps 2 - --validation_split_percentage 5 - --seed 42 - --max_duration_in_seconds 1.0 - --min_duration_in_seconds 0.5 - """.split() - - with patch.object(sys, "argv", testargs): - run_wav2vec2_pretraining_no_trainer.main() - model = Wav2Vec2ForPreTraining.from_pretrained(tmp_dir) - self.assertIsNotNone(model) - - def test_run_vit_mae_pretraining(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_mae.py - --output_dir {tmp_dir} - --dataset_name hf-internal-testing/cats_vs_dogs_sample - --do_train - --do_eval - --learning_rate 1e-4 - --per_device_train_batch_size 2 - --per_device_eval_batch_size 1 - --remove_unused_columns False - --dataloader_num_workers 0 - --metric_for_best_model accuracy - --max_steps 10 - --train_val_split 0.1 - --seed 42 - --config_overrides hidden_size=32,intermediate_size=64,num_hidden_layers=2,num_attention_heads=2,decoder_hidden_size=32,decoder_intermediate_size=64,decoder_num_hidden_layers=2,decoder_num_attention_heads=2 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_mae.main() - model = ViTMAEForPreTraining.from_pretrained(tmp_dir) - self.assertIsNotNone(model) - - @slow - def test_run_semantic_segmentation(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_semantic_segmentation.py - --output_dir {tmp_dir} - --dataset_name huggingface/semantic-segmentation-test-sample - --do_train - --do_eval - --remove_unused_columns False - --max_steps 10 - --learning_rate=2e-4 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --seed 32 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_semantic_segmentation.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["eval_overall_accuracy"], 0.1) - - @slow - @patch.dict(os.environ, {"WANDB_DISABLED": "true"}) - def test_run_object_detection(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_object_detection.py - --model_name_or_path qubvel-hf/detr-resnet-50-finetuned-10k-cppe5 - --output_dir {tmp_dir} - --dataset_name qubvel-hf/cppe-5-sample - --do_train - --do_eval - --remove_unused_columns False - --eval_do_concat_batches False - --max_steps 10 - --learning_rate=1e-6 - --per_device_train_batch_size=2 - --per_device_eval_batch_size=1 - --seed 32 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_object_detection.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["test_map"], 0.1) - - @slow - @patch.dict(os.environ, {"WANDB_DISABLED": "true"}) - def test_run_instance_segmentation(self): - tmp_dir = self.get_auto_remove_tmp_dir() - testargs = f""" - run_instance_segmentation.py - --model_name_or_path qubvel-hf/finetune-instance-segmentation-ade20k-mini-mask2former - --output_dir {tmp_dir} - --dataset_name qubvel-hf/ade20k-nano - --do_reduce_labels - --image_height 256 - --image_width 256 - --do_train - --num_train_epochs 1 - --learning_rate 1e-5 - --lr_scheduler_type constant - --per_device_train_batch_size 2 - --per_device_eval_batch_size 1 - --do_eval - --eval_strategy epoch - --seed 32 - """.split() - - if is_torch_fp16_available_on_device(torch_device): - testargs.append("--fp16") - - with patch.object(sys, "argv", testargs): - run_instance_segmentation.main() - result = get_results(tmp_dir) - self.assertGreaterEqual(result["test_map"], 0.1) diff --git a/examples/pytorch/text-classification/README.md b/examples/pytorch/text-classification/README.md deleted file mode 100644 index fe029a542e1f..000000000000 --- a/examples/pytorch/text-classification/README.md +++ /dev/null @@ -1,251 +0,0 @@ - - -# Text classification examples - -## GLUE tasks - -Based on the script [`run_glue.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/text-classification/run_glue.py). - -Fine-tuning the library models for sequence classification on the GLUE benchmark: [General Language Understanding -Evaluation](https://gluebenchmark.com/). This script can fine-tune any of the models on the [hub](https://huggingface.co/models) -and can also be used for a dataset hosted on our [hub](https://huggingface.co/datasets) or your own data in a csv or a JSON file -(the script might need some tweaks in that case, refer to the comments inside for help). - -GLUE is made up of a total of 9 different tasks. Here is how to run the script on one of them: - -```bash -export TASK_NAME=mrpc - -python run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --do_train \ - --do_eval \ - --max_seq_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ -``` - -where task name can be one of cola, sst2, mrpc, stsb, qqp, mnli, qnli, rte, wnli. - -We get the following results on the dev set of the benchmark with the previous commands (with an exception for MRPC and -WNLI which are tiny and where we used 5 epochs instead of 3). Trainings are seeded so you should obtain the same -results with PyTorch 1.6.0 (and close results with different versions), training times are given for information (a -single Titan RTX was used): - -| Task | Metric | Result | Training time | -|-------|------------------------------|-------------|---------------| -| CoLA | Matthews corr | 56.53 | 3:17 | -| SST-2 | Accuracy | 92.32 | 26:06 | -| MRPC | F1/Accuracy | 88.85/84.07 | 2:21 | -| STS-B | Pearson/Spearman corr. | 88.64/88.48 | 2:13 | -| QQP | Accuracy/F1 | 90.71/87.49 | 2:22:26 | -| MNLI | Matched acc./Mismatched acc. | 83.91/84.10 | 2:35:23 | -| QNLI | Accuracy | 90.66 | 40:57 | -| RTE | Accuracy | 65.70 | 57 | -| WNLI | Accuracy | 56.34 | 24 | - -Some of these results are significantly different from the ones reported on the test set of GLUE benchmark on the -website. For QQP and WNLI, please refer to [FAQ #12](https://gluebenchmark.com/faq) on the website. - -The following example fine-tunes BERT on the `imdb` dataset hosted on our [hub](https://huggingface.co/datasets): - -```bash -python run_glue.py \ - --model_name_or_path google-bert/bert-base-cased \ - --dataset_name stanfordnlp/imdb \ - --do_train \ - --do_predict \ - --max_seq_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/imdb/ -``` - -> If your model classification head dimensions do not fit the number of labels in the dataset, you can specify `--ignore_mismatched_sizes` to adapt it. - -## Text classification -As an alternative, we can use the script [`run_classification.py`](./run_classification.py) to fine-tune models on a single/multi-label classification task. - -The following example fine-tunes BERT on the [`dbpedia_14`](https://huggingface.co/datasets/fancyzhx/dbpedia_14) dataset. -We can specify the metric, the label column and also choose which text columns to use jointly for classification. -```bash -dataset="fancyzhx/dbpedia_14" -python run_classification.py \ - --model_name_or_path google-bert/bert-base-uncased \ - --dataset_name ${dataset} \ - --shuffle_train_dataset \ - --metric_name accuracy \ - --text_column_name "title,content" \ - --text_column_delimiter "\n" \ - --label_column_name label \ - --do_train \ - --do_eval \ - --max_seq_length 512 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 1 \ - --max_train_samples 20000 \ - --max_eval_samples 5000 \ - --output_dir /tmp/dbpedia_14/ -``` -Training on 20,000 samples for 1 epoch results in an accuracy of around 0.97. Remove `--max_train_samples` and `--max_eval_samples` to train and evaluate on the full dataset. - -The following is a multi-label classification example. It fine-tunes BERT on the `reuters21578` dataset hosted on our [hub](https://huggingface.co/datasets/ucirvine/reuters21578): -```bash -dataset="ucirvine/reuters21578" -subset="ModApte" -python run_classification.py \ - --model_name_or_path google-bert/bert-base-uncased \ - --dataset_name ${dataset} \ - --dataset_config_name ${subset} \ - --shuffle_train_dataset \ - --remove_splits "unused" \ - --metric_name f1 \ - --text_column_name text \ - --label_column_name topics \ - --do_train \ - --do_eval \ - --max_seq_length 512 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 15 \ - --output_dir /tmp/${dataset}_${subset}/ -``` - It results in a Micro F1 score of around 0.82 without any text and label filtering. Note that you have to explicitly remove the "unused" split from the dataset, since it is not used for classification. - -### Mixed precision training - -If you have a GPU with mixed precision capabilities (architecture Pascal or more recent), you can use mixed precision -training with PyTorch 1.6.0 or latest. Just add the flag `--fp16` to your command launching one of the scripts mentioned above! - -Using mixed precision training usually results in 2x-speedup for training with the same final results: - -| Task | Metric | Result | Training time | Result (FP16) | Training time (FP16) | -|-------|------------------------------|-------------|---------------|---------------|----------------------| -| CoLA | Matthews corr | 56.53 | 3:17 | 56.78 | 1:41 | -| SST-2 | Accuracy | 92.32 | 26:06 | 91.74 | 13:11 | -| MRPC | F1/Accuracy | 88.85/84.07 | 2:21 | 88.12/83.58 | 1:10 | -| STS-B | Pearson/Spearman corr. | 88.64/88.48 | 2:13 | 88.71/88.55 | 1:08 | -| QQP | Accuracy/F1 | 90.71/87.49 | 2:22:26 | 90.67/87.43 | 1:11:54 | -| MNLI | Matched acc./Mismatched acc. | 83.91/84.10 | 2:35:23 | 84.04/84.06 | 1:17:06 | -| QNLI | Accuracy | 90.66 | 40:57 | 90.96 | 20:16 | -| RTE | Accuracy | 65.70 | 57 | 65.34 | 29 | -| WNLI | Accuracy | 56.34 | 24 | 56.34 | 12 | - - -## PyTorch version, no Trainer - -Based on the script [`run_glue_no_trainer.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/text-classification/run_glue_no_trainer.py). - -Like `run_glue.py`, this script allows you to fine-tune any of the models on the [hub](https://huggingface.co/models) on a -text classification task, either a GLUE task or your own data in a csv or a JSON file. The main difference is that this -script exposes the bare training loop, to allow you to quickly experiment and add any customization you would like. - -It offers less options than the script with `Trainer` (for instance you can easily change the options for the optimizer -or the dataloaders directly in the script) but still run in a distributed setup, on TPU and supports mixed precision by -the mean of the [🤗 `Accelerate`](https://github.com/huggingface/accelerate) library. You can use the script normally -after installing it: - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -then - -```bash -export TASK_NAME=mrpc - -python run_glue_no_trainer.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --max_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ -``` - -You can then use your usual launchers to run in it in a distributed environment, but the easiest way is to run - -```bash -accelerate config -``` - -and reply to the questions asked. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -export TASK_NAME=mrpc - -accelerate launch run_glue_no_trainer.py \ - --model_name_or_path google-bert/bert-base-cased \ - --task_name $TASK_NAME \ - --max_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ -``` - -This command is the same and will work for: - -- a CPU-only setup -- a setup with one GPU -- a distributed training with several GPUs (single or multi node) -- a training on TPUs - -Note that this library is in alpha release so your feedback is more than welcome if you encounter any problem using it. - -## XNLI - -Based on the script [`run_xnli.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/text-classification/run_xnli.py). - -[XNLI](https://cims.nyu.edu/~sbowman/xnli/) is a crowd-sourced dataset based on [MultiNLI](https://cims.nyu.edu/~sbowman/multinli/). It is an evaluation benchmark for cross-lingual text representations. Pairs of text are labeled with textual entailment annotations for 15 different languages (including both high-resource language such as English and low-resource languages such as Swahili). - -#### Fine-tuning on XNLI - -This example code fine-tunes mBERT (multi-lingual BERT) on the XNLI dataset. It runs in 106 mins on a single tesla V100 16GB. - -```bash -python run_xnli.py \ - --model_name_or_path google-bert/bert-base-multilingual-cased \ - --language de \ - --train_language en \ - --do_train \ - --do_eval \ - --per_device_train_batch_size 32 \ - --learning_rate 5e-5 \ - --num_train_epochs 2.0 \ - --max_seq_length 128 \ - --output_dir /tmp/debug_xnli/ \ - --save_steps -1 -``` - -Training with the previously defined hyper-parameters yields the following results on the **test** set: - -```bash -acc = 0.7093812375249501 -``` diff --git a/examples/pytorch/text-classification/requirements.txt b/examples/pytorch/text-classification/requirements.txt deleted file mode 100644 index 19090ab12477..000000000000 --- a/examples/pytorch/text-classification/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -accelerate >= 0.12.0 -datasets >= 1.8.0 -sentencepiece != 0.1.92 -scipy -scikit-learn -protobuf -torch >= 1.3 -evaluate \ No newline at end of file diff --git a/examples/pytorch/text-classification/run_classification.py b/examples/pytorch/text-classification/run_classification.py deleted file mode 100755 index 28c5fea9ac02..000000000000 --- a/examples/pytorch/text-classification/run_classification.py +++ /dev/null @@ -1,746 +0,0 @@ -#!/usr/bin/env python -# Copyright 2020 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "datasets >= 1.8.0", -# "sentencepiece != 0.1.92", -# "scipy", -# "scikit-learn", -# "protobuf", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -"""Finetuning the library models for text classification.""" -# You can also adapt this script on your own text classification task. Pointers for this are left as comments. - -import logging -import os -import random -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -import numpy as np -from datasets import Value, load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoModelForSequenceClassification, - AutoTokenizer, - DataCollatorWithPadding, - EvalPrediction, - HfArgumentParser, - Trainer, - TrainingArguments, - default_data_collator, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/text-classification/requirements.txt") - - -logger = logging.getLogger(__name__) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - - Using `HfArgumentParser` we can turn this class - into argparse arguments to be able to specify them on - the command line. - """ - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - do_regression: bool = field( - default=None, - metadata={ - "help": "Whether to do regression instead of classification. If None, will be inferred from the dataset." - }, - ) - text_column_names: str | None = field( - default=None, - metadata={ - "help": ( - "The name of the text column in the input dataset or a CSV/JSON file. " - 'If not specified, will use the "sentence" column for single/multi-label classification task.' - ) - }, - ) - text_column_delimiter: str | None = field( - default=" ", metadata={"help": "The delimiter to use to join text columns into a single sentence."} - ) - train_split_name: str | None = field( - default=None, - metadata={ - "help": 'The name of the train split in the input dataset. If not specified, will use the "train" split when do_train is enabled' - }, - ) - validation_split_name: str | None = field( - default=None, - metadata={ - "help": 'The name of the validation split in the input dataset. If not specified, will use the "validation" split when do_eval is enabled' - }, - ) - test_split_name: str | None = field( - default=None, - metadata={ - "help": 'The name of the test split in the input dataset. If not specified, will use the "test" split when do_predict is enabled' - }, - ) - remove_splits: str | None = field( - default=None, - metadata={"help": "The splits to remove from the dataset. Multiple splits should be separated by commas."}, - ) - remove_columns: str | None = field( - default=None, - metadata={"help": "The columns to remove from the dataset. Multiple columns should be separated by commas."}, - ) - label_column_name: str | None = field( - default=None, - metadata={ - "help": ( - "The name of the label column in the input dataset or a CSV/JSON file. " - 'If not specified, will use the "label" column for single/multi-label classification task' - ) - }, - ) - max_seq_length: int = field( - default=128, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached preprocessed datasets or not."} - ) - pad_to_max_length: bool = field( - default=True, - metadata={ - "help": ( - "Whether to pad all samples to `max_seq_length`. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch." - ) - }, - ) - shuffle_train_dataset: bool = field( - default=False, metadata={"help": "Whether to shuffle the train dataset or not."} - ) - shuffle_seed: int = field( - default=42, metadata={"help": "Random seed that will be used to shuffle the train dataset."} - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - metric_name: str | None = field(default=None, metadata={"help": "The metric to use for evaluation."}) - train_file: str | None = field( - default=None, metadata={"help": "A csv or a json file containing the training data."} - ) - validation_file: str | None = field( - default=None, metadata={"help": "A csv or a json file containing the validation data."} - ) - test_file: str | None = field(default=None, metadata={"help": "A csv or a json file containing the test data."}) - - def __post_init__(self): - if self.dataset_name is None: - if self.train_file is None or self.validation_file is None: - raise ValueError(" training/validation file or a dataset name.") - - train_extension = self.train_file.split(".")[-1] - assert train_extension in ["csv", "json"], "`train_file` should be a csv or a json file." - validation_extension = self.validation_file.split(".")[-1] - assert validation_extension == train_extension, ( - "`validation_file` should have the same extension (csv or json) as `train_file`." - ) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - ignore_mismatched_sizes: bool = field( - default=False, - metadata={"help": "Will enable to load a pretrained model whose head dimensions are different."}, - ) - - -def get_label_list(raw_dataset, split="train") -> list[str]: - """Get the list of labels from a multi-label dataset""" - - if isinstance(raw_dataset[split]["label"][0], list): - label_list = [label for sample in raw_dataset[split]["label"] for label in sample] - label_list = list(set(label_list)) - else: - label_list = raw_dataset[split].unique("label") - # we will treat the label list as a list of string instead of int, consistent with model.config.label2id - label_list = [str(label) for label in label_list] - return label_list - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON training and evaluation files, or specify a dataset name - # to load from huggingface/datasets. In ether case, you can specify a the key of the column(s) containing the text and - # the key of the column containing the label. If multiple columns are specified for the text, they will be joined together - # for the actual text value. - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - # Try print some info about the dataset - logger.info(f"Dataset loaded: {raw_datasets}") - logger.info(raw_datasets) - else: - # Loading a dataset from your local files. - # CSV/JSON training and evaluation files are needed. - data_files = {"train": data_args.train_file, "validation": data_args.validation_file} - - # Get the test dataset: you can provide your own CSV/JSON test file - if training_args.do_predict: - if data_args.test_file is not None: - train_extension = data_args.train_file.split(".")[-1] - test_extension = data_args.test_file.split(".")[-1] - assert test_extension == train_extension, ( - "`test_file` should have the same extension (csv or json) as `train_file`." - ) - data_files["test"] = data_args.test_file - else: - raise ValueError("Need either a dataset name or a test file for `do_predict`.") - - for key in data_files: - logger.info(f"load a local file for {key}: {data_files[key]}") - - if data_args.train_file.endswith(".csv"): - # Loading a dataset from local csv files - raw_datasets = load_dataset( - "csv", - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - else: - # Loading a dataset from local json files - raw_datasets = load_dataset( - "json", - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - - # See more about loading any type of standard or custom dataset at - # https://huggingface.co/docs/datasets/loading_datasets. - - if data_args.remove_splits is not None: - for split in data_args.remove_splits.split(","): - logger.info(f"removing split {split}") - raw_datasets.pop(split) - - if data_args.train_split_name is not None: - logger.info(f"using {data_args.train_split_name} as train set") - raw_datasets["train"] = raw_datasets[data_args.train_split_name] - raw_datasets.pop(data_args.train_split_name) - - if data_args.validation_split_name is not None: - logger.info(f"using {data_args.validation_split_name} as validation set") - raw_datasets["validation"] = raw_datasets[data_args.validation_split_name] - raw_datasets.pop(data_args.validation_split_name) - - if data_args.test_split_name is not None: - logger.info(f"using {data_args.test_split_name} as test set") - raw_datasets["test"] = raw_datasets[data_args.test_split_name] - raw_datasets.pop(data_args.test_split_name) - - if data_args.remove_columns is not None: - for split in raw_datasets: - for column in data_args.remove_columns.split(","): - logger.info(f"removing column {column} from split {split}") - raw_datasets[split] = raw_datasets[split].remove_columns(column) - - if data_args.label_column_name is not None and data_args.label_column_name != "label": - for key in raw_datasets: - raw_datasets[key] = raw_datasets[key].rename_column(data_args.label_column_name, "label") - - # Trying to have good defaults here, don't hesitate to tweak to your needs. - - is_regression = ( - raw_datasets["train"].features["label"].dtype in ["float32", "float64"] - if data_args.do_regression is None - else data_args.do_regression - ) - - is_multi_label = False - if is_regression: - label_list = None - num_labels = 1 - # regression requires float as label type, let's cast it if needed - for split in raw_datasets: - if raw_datasets[split].features["label"].dtype not in ["float32", "float64"]: - logger.warning( - f"Label type for {split} set to float32, was {raw_datasets[split].features['label'].dtype}" - ) - features = raw_datasets[split].features - features.update({"label": Value("float32")}) - try: - raw_datasets[split] = raw_datasets[split].cast(features) - except TypeError as error: - logger.error( - f"Unable to cast {split} set to float32, please check the labels are correct, or maybe try with --do_regression=False" - ) - raise error - - else: # classification - if raw_datasets["train"].features["label"].dtype == "list": # multi-label classification - is_multi_label = True - logger.info("Label type is list, doing multi-label classification") - # Trying to find the number of labels in a multi-label classification task - # We have to deal with common cases that labels appear in the training set but not in the validation/test set. - # So we build the label list from the union of labels in train/val/test. - label_list = get_label_list(raw_datasets, split="train") - for split in ["validation", "test"]: - if split in raw_datasets: - val_or_test_labels = get_label_list(raw_datasets, split=split) - diff = set(val_or_test_labels).difference(set(label_list)) - if len(diff) > 0: - # add the labels that appear in val/test but not in train, throw a warning - logger.warning( - f"Labels {diff} in {split} set but not in training set, adding them to the label list" - ) - label_list += list(diff) - # if label is -1, we throw a warning and remove it from the label list - for label in label_list: - if label == -1: - logger.warning("Label -1 found in label list, removing it.") - label_list.remove(label) - - label_list.sort() - num_labels = len(label_list) - if num_labels <= 1: - raise ValueError("You need more than one label to do classification.") - - # Load pretrained model and tokenizer - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - num_labels=num_labels, - finetuning_task="text-classification", - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - if is_regression: - config.problem_type = "regression" - logger.info("setting problem type to regression") - elif is_multi_label: - config.problem_type = "multi_label_classification" - logger.info("setting problem type to multi label classification") - else: - config.problem_type = "single_label_classification" - logger.info("setting problem type to single label classification") - - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForSequenceClassification.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ignore_mismatched_sizes=model_args.ignore_mismatched_sizes, - ) - - # Padding strategy - if data_args.pad_to_max_length: - padding = "max_length" - else: - # We will pad later, dynamically at batch creation, to the max sequence length in each batch - padding = False - - # for training ,we will update the config with label infos, - # if do_train is not set, we will use the label infos in the config - if training_args.do_train and not is_regression: # classification, training - label_to_id = {v: i for i, v in enumerate(label_list)} - # update config with label infos - if model.config.label2id != label_to_id: - logger.warning( - "The label2id key in the model config.json is not equal to the label2id key of this " - "run. You can ignore this if you are doing finetuning." - ) - model.config.label2id = label_to_id - model.config.id2label = {id: label for label, id in label_to_id.items()} - elif not is_regression: # classification, but not training - logger.info("using label infos in the model config") - logger.info(f"label2id: {model.config.label2id}") - label_to_id = model.config.label2id - else: # regression - label_to_id = None - - if data_args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({data_args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) - - def multi_labels_to_ids(labels: list[str]) -> list[float]: - ids = [0.0] * len(label_to_id) # BCELoss requires float as target type - for label in labels: - ids[label_to_id[label]] = 1.0 - return ids - - def preprocess_function(examples): - if data_args.text_column_names is not None: - text_column_names = data_args.text_column_names.split(",") - # join together text columns into "sentence" column - examples["sentence"] = examples[text_column_names[0]] - for column in text_column_names[1:]: - for i in range(len(examples[column])): - examples["sentence"][i] += data_args.text_column_delimiter + examples[column][i] - # Tokenize the texts - result = tokenizer(examples["sentence"], padding=padding, max_length=max_seq_length, truncation=True) - if label_to_id is not None and "label" in examples: - if is_multi_label: - result["label"] = [multi_labels_to_ids(l) for l in examples["label"]] - else: - result["label"] = [(label_to_id[str(l)] if l != -1 else -1) for l in examples["label"]] - return result - - # Running the preprocessing pipeline on all the datasets - with training_args.main_process_first(desc="dataset map pre-processing"): - raw_datasets = raw_datasets.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset.") - train_dataset = raw_datasets["train"] - if data_args.shuffle_train_dataset: - logger.info("Shuffling the training dataset") - train_dataset = train_dataset.shuffle(seed=data_args.shuffle_seed) - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - - if training_args.do_eval: - if "validation" not in raw_datasets and "validation_matched" not in raw_datasets: - if "test" not in raw_datasets and "test_matched" not in raw_datasets: - raise ValueError("--do_eval requires a validation or test dataset if validation is not defined.") - else: - logger.warning("Validation dataset not found. Falling back to test dataset for validation.") - eval_dataset = raw_datasets["test"] - else: - eval_dataset = raw_datasets["validation"] - - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - - if training_args.do_predict or data_args.test_file is not None: - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_dataset = raw_datasets["test"] - # remove label column if it exists - if data_args.max_predict_samples is not None: - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - - # Log a few random samples from the training set: - if training_args.do_train: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - if data_args.metric_name is not None: - metric = ( - evaluate.load(data_args.metric_name, config_name="multilabel", cache_dir=model_args.cache_dir) - if is_multi_label - else evaluate.load(data_args.metric_name, cache_dir=model_args.cache_dir) - ) - logger.info(f"Using metric {data_args.metric_name} for evaluation.") - else: - if is_regression: - metric = evaluate.load("mse", cache_dir=model_args.cache_dir) - logger.info("Using mean squared error (mse) as regression score, you can use --metric_name to overwrite.") - else: - if is_multi_label: - metric = evaluate.load("f1", config_name="multilabel", cache_dir=model_args.cache_dir) - logger.info( - "Using multilabel F1 for multi-label classification task, you can use --metric_name to overwrite." - ) - else: - metric = evaluate.load("accuracy", cache_dir=model_args.cache_dir) - logger.info("Using accuracy as classification score, you can use --metric_name to overwrite.") - - def compute_metrics(p: EvalPrediction): - preds = p.predictions[0] if isinstance(p.predictions, tuple) else p.predictions - if is_regression: - preds = np.squeeze(preds) - result = metric.compute(predictions=preds, references=p.label_ids) - elif is_multi_label: - preds = np.array([np.where(p > 0, 1, 0) for p in preds]) # convert logits to multi-hot encoding - # Micro F1 is commonly used in multi-label classification - result = metric.compute(predictions=preds, references=p.label_ids, average="micro") - else: - preds = np.argmax(preds, axis=1) - result = metric.compute(predictions=preds, references=p.label_ids) - if len(result) > 1: - result["combined_score"] = np.mean(list(result.values())).item() - return result - - # Data collator will default to DataCollatorWithPadding when the tokenizer is passed to Trainer, so we change it if - # we already did the padding. - if data_args.pad_to_max_length: - data_collator = default_data_collator - elif training_args.fp16: - data_collator = DataCollatorWithPadding(tokenizer, pad_to_multiple_of=8) - else: - data_collator = None - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - compute_metrics=compute_metrics, - processing_class=tokenizer, - data_collator=data_collator, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - trainer.save_model() # Saves the tokenizer too for easy upload - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - metrics = trainer.evaluate(eval_dataset=eval_dataset) - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - if training_args.do_predict: - logger.info("*** Predict ***") - # Removing the `label` columns if exists because it might contains -1 and Trainer won't like that. - if "label" in predict_dataset.features: - predict_dataset = predict_dataset.remove_columns("label") - predictions = trainer.predict(predict_dataset, metric_key_prefix="predict").predictions - if is_regression: - predictions = np.squeeze(predictions) - elif is_multi_label: - # Convert logits to multi-hot encoding. We compare the logits to 0 instead of 0.5, because the sigmoid is not applied. - # You can also pass `preprocess_logits_for_metrics=lambda logits, labels: nn.functional.sigmoid(logits)` to the Trainer - # and set p > 0.5 below (less efficient in this case) - predictions = np.array([np.where(p > 0, 1, 0) for p in predictions]) - else: - predictions = np.argmax(predictions, axis=1) - output_predict_file = os.path.join(training_args.output_dir, "predict_results.txt") - if trainer.is_world_process_zero(): - with open(output_predict_file, "w", encoding="utf-8") as writer: - logger.info("***** Predict results *****") - writer.write("index\tprediction\n") - for index, item in enumerate(predictions): - if is_regression: - writer.write(f"{index}\t{item:3.3f}\n") - elif is_multi_label: - # recover from multi-hot encoding - item = [label_list[i] for i in range(len(item)) if item[i] == 1] - writer.write(f"{index}\t{item}\n") - else: - item = label_list[item] - writer.write(f"{index}\t{item}\n") - logger.info(f"Predict results saved at {output_predict_file}") - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "text-classification"} - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/text-classification/run_glue.py b/examples/pytorch/text-classification/run_glue.py deleted file mode 100755 index 4713961076b3..000000000000 --- a/examples/pytorch/text-classification/run_glue.py +++ /dev/null @@ -1,652 +0,0 @@ -#!/usr/bin/env python -# Copyright 2020 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "datasets >= 1.8.0", -# "sentencepiece != 0.1.92", -# "scipy", -# "scikit-learn", -# "protobuf", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -"""Finetuning the library models for sequence classification on GLUE.""" -# You can also adapt this script on your own text classification task. Pointers for this are left as comments. - -import logging -import os -import random -import sys -from collections import Counter -from dataclasses import dataclass, field - -import datasets -import evaluate -import numpy as np -from datasets import Value, load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoModelForSequenceClassification, - AutoTokenizer, - DataCollatorWithPadding, - EvalPrediction, - HfArgumentParser, - PreTrainedConfig, - Trainer, - TrainingArguments, - default_data_collator, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/text-classification/requirements.txt") - -task_to_keys = { - "cola": ("sentence", None), - "mnli": ("premise", "hypothesis"), - "mrpc": ("sentence1", "sentence2"), - "qnli": ("question", "sentence"), - "qqp": ("question1", "question2"), - "rte": ("sentence1", "sentence2"), - "sst2": ("sentence", None), - "stsb": ("sentence1", "sentence2"), - "wnli": ("sentence1", "sentence2"), -} - -logger = logging.getLogger(__name__) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - - Using `HfArgumentParser` we can turn this class - into argparse arguments to be able to specify them on - the command line. - """ - - task_name: str | None = field( - default=None, - metadata={"help": "The name of the task to train on: " + ", ".join(task_to_keys.keys())}, - ) - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - max_seq_length: int = field( - default=128, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached preprocessed datasets or not."} - ) - pad_to_max_length: bool = field( - default=True, - metadata={ - "help": ( - "Whether to pad all samples to `max_seq_length`. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - train_file: str | None = field( - default=None, metadata={"help": "A csv or a json file containing the training data."} - ) - validation_file: str | None = field( - default=None, metadata={"help": "A csv or a json file containing the validation data."} - ) - test_file: str | None = field(default=None, metadata={"help": "A csv or a json file containing the test data."}) - - def __post_init__(self): - if self.task_name is not None: - self.task_name = self.task_name.lower() - if self.task_name not in task_to_keys: - raise ValueError("Unknown task, you should pick one in " + ",".join(task_to_keys.keys())) - elif self.dataset_name is not None: - pass - elif self.train_file is None or self.validation_file is None: - raise ValueError("Need either a GLUE task, a training/validation file or a dataset name.") - else: - train_extension = self.train_file.split(".")[-1] - assert train_extension in ["csv", "json"], "`train_file` should be a csv or a json file." - validation_extension = self.validation_file.split(".")[-1] - assert validation_extension == train_extension, ( - "`validation_file` should have the same extension (csv or json) as `train_file`." - ) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - ignore_mismatched_sizes: bool = field( - default=False, - metadata={"help": "Will enable to load a pretrained model whose head dimensions are different."}, - ) - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON training and evaluation files (see below) - # or specify a GLUE benchmark task (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use as labels the column called 'label' and as pair of sentences the - # sentences in columns called 'sentence1' and 'sentence2' if such column exists or the first two columns not named - # label if at least two columns are provided. - # - # If the CSVs/JSONs contain only one non-label column, the script does single sentence classification on this - # single column. You can easily tweak this behavior (see below) - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.task_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - "nyu-mll/glue", - data_args.task_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - elif data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - # Loading a dataset from your local files. - # CSV/JSON training and evaluation files are needed. - data_files = {"train": data_args.train_file, "validation": data_args.validation_file} - - # Get the test dataset: you can provide your own CSV/JSON test file (see below) - # when you use `do_predict` without specifying a GLUE benchmark task. - if training_args.do_predict: - if data_args.test_file is not None: - train_extension = data_args.train_file.split(".")[-1] - test_extension = data_args.test_file.split(".")[-1] - assert test_extension == train_extension, ( - "`test_file` should have the same extension (csv or json) as `train_file`." - ) - data_files["test"] = data_args.test_file - else: - raise ValueError("Need either a GLUE task or a test file for `do_predict`.") - - for key in data_files: - logger.info(f"load a local file for {key}: {data_files[key]}") - - if data_args.train_file.endswith(".csv"): - # Loading a dataset from local csv files - raw_datasets = load_dataset( - "csv", - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - else: - # Loading a dataset from local json files - raw_datasets = load_dataset( - "json", - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - # See more about loading any type of standard or custom dataset at - # https://huggingface.co/docs/datasets/loading_datasets. - - # With pandas>=3, text columns of CSV files are loaded as `large_string`, and `datasets.map` then casts the label - # ids computed below back to that type, so they end up as strings. Using `string` lets them be inferred as ints. - for split in raw_datasets: - if raw_datasets[split].features.get("label") == Value("large_string"): - raw_datasets[split] = raw_datasets[split].cast_column("label", Value("string")) - - # Labels - if data_args.task_name is not None: - is_regression = data_args.task_name == "stsb" - if not is_regression: - label_list = raw_datasets["train"].features["label"].names - num_labels = len(label_list) - else: - num_labels = 1 - else: - # Trying to have good defaults here, don't hesitate to tweak to your needs. - is_regression = raw_datasets["train"].features["label"].dtype in ["float32", "float64"] - if is_regression: - num_labels = 1 - else: - # A useful fast method: - # https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.unique - label_list = raw_datasets["train"].unique("label") - label_list.sort() # Let's sort it for determinism - num_labels = len(label_list) - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - num_labels=num_labels, - finetuning_task=data_args.task_name, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForSequenceClassification.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ignore_mismatched_sizes=model_args.ignore_mismatched_sizes, - ) - - # Preprocessing the raw_datasets - if data_args.task_name is not None: - sentence1_key, sentence2_key = task_to_keys[data_args.task_name] - else: - # Again, we try to have some nice defaults but don't hesitate to tweak to your use case. - non_label_column_names = [name for name in raw_datasets["train"].column_names if name != "label"] - if "sentence1" in non_label_column_names and "sentence2" in non_label_column_names: - sentence1_key, sentence2_key = "sentence1", "sentence2" - else: - if len(non_label_column_names) >= 2: - sentence1_key, sentence2_key = non_label_column_names[:2] - else: - sentence1_key, sentence2_key = non_label_column_names[0], None - - # Padding strategy - if data_args.pad_to_max_length: - padding = "max_length" - else: - # We will pad later, dynamically at batch creation, to the max sequence length in each batch - padding = False - - # Some models have set the order of the labels to use, so let's make sure we do use it. - label_to_id = None - if ( - model.config.label2id != PreTrainedConfig(num_labels=num_labels).label2id - and data_args.task_name is not None - and not is_regression - ): - # Some have all caps in their config, some don't. - label_name_to_id = {k.lower(): v for k, v in model.config.label2id.items()} - if sorted(label_name_to_id.keys()) == sorted(label_list): - label_to_id = {i: int(label_name_to_id[label_list[i]]) for i in range(num_labels)} - else: - logger.warning( - "Your model seems to have been trained with labels, but they don't match the dataset: " - f"model labels: {sorted(label_name_to_id.keys())}, dataset labels: {sorted(label_list)}." - "\nIgnoring the model labels as a result.", - ) - elif data_args.task_name is None and not is_regression: - label_to_id = {v: i for i, v in enumerate(label_list)} - - if label_to_id is not None: - model.config.label2id = label_to_id - model.config.id2label = {id: label for label, id in config.label2id.items()} - elif data_args.task_name is not None and not is_regression: - model.config.label2id = {l: i for i, l in enumerate(label_list)} - model.config.id2label = {id: label for label, id in config.label2id.items()} - - if data_args.max_seq_length > tokenizer.model_max_length: - logger.warning( - f"The max_seq_length passed ({data_args.max_seq_length}) is larger than the maximum length for the " - f"model ({tokenizer.model_max_length}). Using max_seq_length={tokenizer.model_max_length}." - ) - max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length) - - def preprocess_function(examples): - # Tokenize the texts - args = ( - (examples[sentence1_key],) if sentence2_key is None else (examples[sentence1_key], examples[sentence2_key]) - ) - result = tokenizer(*args, padding=padding, max_length=max_seq_length, truncation=True) - - # Map labels to IDs (not necessary for GLUE tasks) - if label_to_id is not None and "label" in examples: - result["label"] = [(label_to_id[l] if l != -1 else -1) for l in examples["label"]] - return result - - with training_args.main_process_first(desc="dataset map pre-processing"): - raw_datasets = raw_datasets.map( - preprocess_function, - batched=True, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - - def print_class_distribution(dataset, split_name): - label_counts = Counter(dataset["label"]) - total = sum(label_counts.values()) - logger.info(f"Class distribution in {split_name} set:") - for label, count in label_counts.items(): - logger.info(f" Label {label}: {count} ({count / total:.2%})") - - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - print_class_distribution(train_dataset, "train") - - if training_args.do_eval: - if "validation" not in raw_datasets and "validation_matched" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_dataset = raw_datasets["validation_matched" if data_args.task_name == "mnli" else "validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - print_class_distribution(eval_dataset, "validation") - - if training_args.do_predict or data_args.task_name is not None or data_args.test_file is not None: - if "test" not in raw_datasets and "test_matched" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_dataset = raw_datasets["test_matched" if data_args.task_name == "mnli" else "test"] - if data_args.max_predict_samples is not None: - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - print_class_distribution(predict_dataset, "test") - - # Log a few random samples from the training set: - if training_args.do_train: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # Get the metric function - if data_args.task_name is not None: - metric = evaluate.load("glue", data_args.task_name, cache_dir=model_args.cache_dir) - elif is_regression: - metric = evaluate.load("mse", cache_dir=model_args.cache_dir) - else: - metric = evaluate.load("accuracy", cache_dir=model_args.cache_dir) - - # You can define your custom compute_metrics function. It takes an `EvalPrediction` object (a namedtuple with a - # predictions and label_ids field) and has to return a dictionary string to float. - def compute_metrics(p: EvalPrediction): - preds = p.predictions[0] if isinstance(p.predictions, tuple) else p.predictions - labels = p.label_ids - if not training_args.eval_do_concat_batches: - preds = np.concatenate(preds, axis=0) - labels = np.concatenate(p.label_ids, axis=0) - preds = np.squeeze(preds) if is_regression else np.argmax(preds, axis=1) - result = metric.compute(predictions=preds, references=labels) - if len(result) > 1: - result["combined_score"] = np.mean(list(result.values())).item() - return result - - # Data collator will default to DataCollatorWithPadding when the tokenizer is passed to Trainer, so we change it if - # we already did the padding. - if data_args.pad_to_max_length: - data_collator = default_data_collator - elif training_args.fp16: - data_collator = DataCollatorWithPadding(tokenizer, pad_to_multiple_of=8) - else: - data_collator = None - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - compute_metrics=compute_metrics, - processing_class=tokenizer, - data_collator=data_collator, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.save_model() # Saves the tokenizer too for easy upload - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - - # Loop to handle MNLI double evaluation (matched, mis-matched) - tasks = [data_args.task_name] - eval_datasets = [eval_dataset] - if data_args.task_name == "mnli": - tasks.append("mnli-mm") - valid_mm_dataset = raw_datasets["validation_mismatched"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(valid_mm_dataset), data_args.max_eval_samples) - valid_mm_dataset = valid_mm_dataset.select(range(max_eval_samples)) - eval_datasets.append(valid_mm_dataset) - combined = {} - - for eval_dataset, task in zip(eval_datasets, tasks): - metrics = trainer.evaluate(eval_dataset=eval_dataset) - - max_eval_samples = ( - data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - ) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - if task == "mnli-mm": - metrics = {k + "_mm": v for k, v in metrics.items()} - if task is not None and "mnli" in task: - combined.update(metrics) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", combined if task is not None and "mnli" in task else metrics) - - if training_args.do_predict: - logger.info("*** Predict ***") - - # Loop to handle MNLI double evaluation (matched, mis-matched) - tasks = [data_args.task_name] - predict_datasets = [predict_dataset] - if data_args.task_name == "mnli": - tasks.append("mnli-mm") - predict_datasets.append(raw_datasets["test_mismatched"]) - - for predict_dataset, task in zip(predict_datasets, tasks): - # Removing the `label` columns because it contains -1 and Trainer won't like that. - predict_dataset = predict_dataset.remove_columns("label") - predictions = trainer.predict(predict_dataset, metric_key_prefix="predict").predictions - predictions = np.squeeze(predictions) if is_regression else np.argmax(predictions, axis=1) - - output_predict_file = os.path.join(training_args.output_dir, f"predict_results_{task}.txt") - if trainer.is_world_process_zero(): - with open(output_predict_file, "w", encoding="utf-8") as writer: - logger.info(f"***** Predict results {task} *****") - writer.write("index\tprediction\n") - for index, item in enumerate(predictions): - if is_regression: - writer.write(f"{index}\t{item:3.3f}\n") - else: - item = label_list[item] - writer.write(f"{index}\t{item}\n") - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "text-classification"} - if data_args.task_name is not None: - kwargs["language"] = "en" - kwargs["dataset_tags"] = "glue" - kwargs["dataset_args"] = data_args.task_name - kwargs["dataset"] = f"GLUE {data_args.task_name.upper()}" - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/text-classification/run_glue_no_trainer.py b/examples/pytorch/text-classification/run_glue_no_trainer.py deleted file mode 100644 index a97930340911..000000000000 --- a/examples/pytorch/text-classification/run_glue_no_trainer.py +++ /dev/null @@ -1,699 +0,0 @@ -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "datasets >= 1.8.0", -# "sentencepiece != 0.1.92", -# "scipy", -# "scikit-learn", -# "protobuf", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -"""Finetuning a 🤗 Transformers model for sequence classification on GLUE.""" - -import argparse -import json -import logging -import math -import os -import random -from pathlib import Path - -import datasets -import evaluate -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - AutoConfig, - AutoModelForSequenceClassification, - AutoTokenizer, - DataCollatorWithPadding, - PreTrainedConfig, - SchedulerType, - default_data_collator, - get_scheduler, -) -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/text-classification/requirements.txt") - -task_to_keys = { - "cola": ("sentence", None), - "mnli": ("premise", "hypothesis"), - "mrpc": ("sentence1", "sentence2"), - "qnli": ("question", "sentence"), - "qqp": ("question1", "question2"), - "rte": ("sentence1", "sentence2"), - "sst2": ("sentence", None), - "stsb": ("sentence1", "sentence2"), - "wnli": ("sentence1", "sentence2"), -} - - -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a text classification task") - parser.add_argument( - "--task_name", - type=str, - default=None, - help="The name of the glue task to train on.", - choices=list(task_to_keys.keys()), - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv or a json file containing the training data." - ) - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv or a json file containing the validation data." - ) - parser.add_argument( - "--max_length", - type=int, - default=128, - help=( - "The maximum total input sequence length after tokenization. Sequences longer than this will be truncated," - " sequences shorter will be padded if `--pad_to_max_length` is passed." - ), - ) - parser.add_argument( - "--pad_to_max_length", - action="store_true", - help="If passed, pad all samples to `max_length`. Otherwise, dynamic padding is used.", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=True, - ) - parser.add_argument( - "--use_slow_tokenizer", - action="store_true", - help="If passed, will use a slow tokenizer (not backed by the Hugging Face Tokenizers library).", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - type=bool, - default=False, - help=( - "Whether or not to allow for custom models defined on the Hub in their own modeling files. This option " - "should only be set to `True` for repositories you trust and in which you have read the code, as it will " - "execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - parser.add_argument( - "--ignore_mismatched_sizes", - action="store_true", - help="Whether or not to enable to load a pretrained model whose head dimensions are different.", - ) - args = parser.parse_args() - - # Sanity checks - if args.task_name is None and args.train_file is None and args.validation_file is None: - raise ValueError("Need either a task name or a training/validation file.") - else: - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator = ( - Accelerator(log_with=args.report_to, project_dir=args.output_dir) if args.with_tracking else Accelerator() - ) - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON training and evaluation files (see below) - # or specify a GLUE benchmark task (the dataset will be downloaded automatically from the datasets Hub). - - # For CSV/JSON files, this script will use as labels the column called 'label' and as pair of sentences the - # sentences in columns called 'sentence1' and 'sentence2' if such column exists or the first two columns not named - # label if at least two columns are provided. - - # If the CSVs/JSONs contain only one non-label column, the script does single sentence classification on this - # single column. You can easily tweak this behavior (see below) - - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.task_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset("nyu-mll/glue", args.task_name) - else: - # Loading the dataset from local csv or json file. - data_files = {} - if args.train_file is not None: - data_files["train"] = args.train_file - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = (args.train_file if args.train_file is not None else args.validation_file).split(".")[-1] - raw_datasets = load_dataset(extension, data_files=data_files) - # See more about loading any type of standard or custom dataset at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Labels - if args.task_name is not None: - is_regression = args.task_name == "stsb" - if not is_regression: - label_list = raw_datasets["train"].features["label"].names - num_labels = len(label_list) - else: - num_labels = 1 - else: - # Trying to have good defaults here, don't hesitate to tweak to your needs. - is_regression = raw_datasets["train"].features["label"].dtype in ["float32", "float64"] - if is_regression: - num_labels = 1 - else: - # A useful fast method: - # https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.unique - label_list = raw_datasets["train"].unique("label") - label_list.sort() # Let's sort it for determinism - num_labels = len(label_list) - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - args.model_name_or_path, - num_labels=num_labels, - finetuning_task=args.task_name, - trust_remote_code=args.trust_remote_code, - ) - tokenizer = AutoTokenizer.from_pretrained( - args.model_name_or_path, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - if tokenizer.pad_token is None: - tokenizer.pad_token = tokenizer.eos_token - config.pad_token_id = tokenizer.pad_token_id - model = AutoModelForSequenceClassification.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - ignore_mismatched_sizes=args.ignore_mismatched_sizes, - trust_remote_code=args.trust_remote_code, - ) - - # Preprocessing the datasets - if args.task_name is not None: - sentence1_key, sentence2_key = task_to_keys[args.task_name] - else: - # Again, we try to have some nice defaults but don't hesitate to tweak to your use case. - non_label_column_names = [name for name in raw_datasets["train"].column_names if name != "label"] - if "sentence1" in non_label_column_names and "sentence2" in non_label_column_names: - sentence1_key, sentence2_key = "sentence1", "sentence2" - else: - if len(non_label_column_names) >= 2: - sentence1_key, sentence2_key = non_label_column_names[:2] - else: - sentence1_key, sentence2_key = non_label_column_names[0], None - - # Some models have set the order of the labels to use, so let's make sure we do use it. - label_to_id = None - if ( - model.config.label2id != PreTrainedConfig(num_labels=num_labels).label2id - and args.task_name is not None - and not is_regression - ): - # Some have all caps in their config, some don't. - label_name_to_id = {k.lower(): v for k, v in model.config.label2id.items()} - if sorted(label_name_to_id.keys()) == sorted(label_list): - logger.info( - f"The configuration of the model provided the following label correspondence: {label_name_to_id}. " - "Using it!" - ) - label_to_id = {i: label_name_to_id[label_list[i]] for i in range(num_labels)} - else: - logger.warning( - "Your model seems to have been trained with labels, but they don't match the dataset: " - f"model labels: {sorted(label_name_to_id.keys())}, dataset labels: {sorted(label_list)}." - "\nIgnoring the model labels as a result.", - ) - elif args.task_name is None and not is_regression: - label_to_id = {v: i for i, v in enumerate(label_list)} - - if label_to_id is not None: - model.config.label2id = label_to_id - model.config.id2label = {id: label for label, id in config.label2id.items()} - elif args.task_name is not None and not is_regression: - model.config.label2id = {l: i for i, l in enumerate(label_list)} - model.config.id2label = {id: label for label, id in config.label2id.items()} - - padding = "max_length" if args.pad_to_max_length else False - - def preprocess_function(examples): - # Tokenize the texts - texts = ( - (examples[sentence1_key],) if sentence2_key is None else (examples[sentence1_key], examples[sentence2_key]) - ) - result = tokenizer(*texts, padding=padding, max_length=args.max_length, truncation=True) - - if "label" in examples: - if label_to_id is not None: - # Map labels to IDs (not necessary for GLUE tasks) - result["labels"] = [label_to_id[l] for l in examples["label"]] - else: - # In all cases, rename the column to labels because the model will expect that. - result["labels"] = examples["label"] - return result - - with accelerator.main_process_first(): - processed_datasets = raw_datasets.map( - preprocess_function, - batched=True, - remove_columns=raw_datasets["train"].column_names, - desc="Running tokenizer on dataset", - ) - - train_dataset = processed_datasets["train"] - eval_dataset = processed_datasets["validation_matched" if args.task_name == "mnli" else "validation"] - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # DataLoaders creation: - if args.pad_to_max_length: - # If padding was already done ot max length, we use the default data collator that will just convert everything - # to tensors. - data_collator = default_data_collator - else: - # Otherwise, `DataCollatorWithPadding` will apply dynamic padding for us (by padding to the maximum length of - # the samples passed). When using mixed precision, we add `pad_to_multiple_of=8` to pad all tensors to multiple - # of 8s, which will enable the use of Tensor Cores on NVIDIA hardware with compute capability >= 7.5 (Volta). - # For fp8, we pad to multiple of 16. - if accelerator.mixed_precision == "fp8": - pad_to_multiple_of = 16 - elif accelerator.mixed_precision != "no": - pad_to_multiple_of = 8 - else: - pad_to_multiple_of = None - data_collator = DataCollatorWithPadding(tokenizer, pad_to_multiple_of=pad_to_multiple_of) - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader(eval_dataset, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps, - num_training_steps=args.max_train_steps, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("glue_no_trainer", experiment_config) - - # Get the metric function - if args.task_name is not None: - metric = evaluate.load("glue", args.task_name) - else: - metric = evaluate.load("accuracy") - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - loss = loss / args.gradient_accumulation_steps - accelerator.backward(loss) - if step % args.gradient_accumulation_steps == 0 or step == len(train_dataloader) - 1: - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if completed_steps >= args.max_train_steps: - break - - model.eval() - samples_seen = 0 - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - predictions = outputs.logits.argmax(dim=-1) if not is_regression else outputs.logits.squeeze() - predictions, references = accelerator.gather((predictions, batch["labels"])) - # If we are in a multiprocess environment, the last batch has duplicates - if accelerator.num_processes > 1: - if step == len(eval_dataloader) - 1: - predictions = predictions[: len(eval_dataloader.dataset) - samples_seen] - references = references[: len(eval_dataloader.dataset) - samples_seen] - else: - samples_seen += references.shape[0] - metric.add_batch( - predictions=predictions, - references=references, - ) - - eval_metric = metric.compute() - logger.info(f"epoch {epoch}: {eval_metric}") - - if args.with_tracking: - accelerator.log( - { - "accuracy" if args.task_name is not None else "glue": eval_metric, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.task_name == "mnli": - # Final evaluation on mismatched validation set - eval_dataset = processed_datasets["validation_mismatched"] - eval_dataloader = DataLoader( - eval_dataset, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size - ) - eval_dataloader = accelerator.prepare(eval_dataloader) - - model.eval() - for step, batch in enumerate(eval_dataloader): - outputs = model(**batch) - predictions = outputs.logits.argmax(dim=-1) - metric.add_batch( - predictions=accelerator.gather(predictions), - references=accelerator.gather(batch["labels"]), - ) - - eval_metric = metric.compute() - logger.info(f"mnli-mm: {eval_metric}") - - if args.output_dir is not None: - all_results = {f"eval_{k}": v for k, v in eval_metric.items()} - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump(all_results, f) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/text-classification/run_xnli.py b/examples/pytorch/text-classification/run_xnli.py deleted file mode 100755 index af6e47a5b457..000000000000 --- a/examples/pytorch/text-classification/run_xnli.py +++ /dev/null @@ -1,448 +0,0 @@ -#!/usr/bin/env python -# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team. -# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "datasets >= 1.8.0", -# "sentencepiece != 0.1.92", -# "scipy", -# "scikit-learn", -# "protobuf", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -"""Finetuning multi-lingual models on XNLI (e.g. Bert, DistilBERT, XLM). -Adapted from `examples/text-classification/run_glue.py`""" - -import logging -import os -import random -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -import numpy as np -from datasets import load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoModelForSequenceClassification, - AutoTokenizer, - DataCollatorWithPadding, - EvalPrediction, - HfArgumentParser, - Trainer, - TrainingArguments, - default_data_collator, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/text-classification/requirements.txt") - -logger = logging.getLogger(__name__) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - - Using `HfArgumentParser` we can turn this class - into argparse arguments to be able to specify them on - the command line. - """ - - max_seq_length: int | None = field( - default=128, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached preprocessed datasets or not."} - ) - pad_to_max_length: bool = field( - default=True, - metadata={ - "help": ( - "Whether to pad all samples to `max_seq_length`. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - default=None, metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - language: str = field( - default=None, metadata={"help": "Evaluation language. Also train language if `train_language` is set to None."} - ) - train_language: str | None = field( - default=None, metadata={"help": "Train language if it is different from the evaluation language."} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - do_lower_case: bool | None = field( - default=False, - metadata={"help": "arg to indicate if tokenizer should do lower case in AutoTokenizer.from_pretrained()"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether or not to allow for custom models defined on the Hub in their own modeling files. This option " - "should only be set to `True` for repositories you trust and in which you have read the code, as it will " - "execute code present on the Hub on your local machine." - ) - }, - ) - ignore_mismatched_sizes: bool = field( - default=False, - metadata={"help": "Will enable to load a pretrained model whose head dimensions are different."}, - ) - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # In distributed training, the load_dataset function guarantees that only one local process can concurrently - # download the dataset. - # Downloading and loading xnli dataset from the hub. - if training_args.do_train: - if model_args.train_language is None: - train_dataset = load_dataset( - "facebook/xnli", - model_args.language, - split="train", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - else: - train_dataset = load_dataset( - "facebook/xnli", - model_args.train_language, - split="train", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - label_list = train_dataset.features["label"].names - - if training_args.do_eval: - eval_dataset = load_dataset( - "facebook/xnli", - model_args.language, - split="validation", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - label_list = eval_dataset.features["label"].names - - if training_args.do_predict: - predict_dataset = load_dataset( - "facebook/xnli", - model_args.language, - split="test", - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - label_list = predict_dataset.features["label"].names - - # Labels - num_labels = len(label_list) - - # Load pretrained model and tokenizer - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - num_labels=num_labels, - id2label={str(i): label for i, label in enumerate(label_list)}, - label2id={label: i for i, label in enumerate(label_list)}, - finetuning_task="xnli", - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - do_lower_case=model_args.do_lower_case, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForSequenceClassification.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ignore_mismatched_sizes=model_args.ignore_mismatched_sizes, - ) - - # Preprocessing the datasets - # Padding strategy - if data_args.pad_to_max_length: - padding = "max_length" - else: - # We will pad later, dynamically at batch creation, to the max sequence length in each batch - padding = False - - def preprocess_function(examples): - # Tokenize the texts - return tokenizer( - examples["premise"], - examples["hypothesis"], - padding=padding, - max_length=data_args.max_seq_length, - truncation=True, - ) - - if training_args.do_train: - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - with training_args.main_process_first(desc="train dataset map pre-processing"): - train_dataset = train_dataset.map( - preprocess_function, - batched=True, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - if training_args.do_eval: - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - with training_args.main_process_first(desc="validation dataset map pre-processing"): - eval_dataset = eval_dataset.map( - preprocess_function, - batched=True, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - - if training_args.do_predict: - if data_args.max_predict_samples is not None: - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - with training_args.main_process_first(desc="prediction dataset map pre-processing"): - predict_dataset = predict_dataset.map( - preprocess_function, - batched=True, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - - # Get the metric function - metric = evaluate.load("xnli", cache_dir=model_args.cache_dir) - - # You can define your custom compute_metrics function. It takes an `EvalPrediction` object (a namedtuple with a - # predictions and label_ids field) and has to return a dictionary string to float. - def compute_metrics(p: EvalPrediction): - preds = p.predictions[0] if isinstance(p.predictions, tuple) else p.predictions - preds = np.argmax(preds, axis=1) - return metric.compute(predictions=preds, references=p.label_ids) - - # Data collator will default to DataCollatorWithPadding, so we change it if we already did the padding. - if data_args.pad_to_max_length: - data_collator = default_data_collator - elif training_args.fp16: - data_collator = DataCollatorWithPadding(tokenizer, pad_to_multiple_of=8) - else: - data_collator = None - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - compute_metrics=compute_metrics, - processing_class=tokenizer, - data_collator=data_collator, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.save_model() # Saves the tokenizer too for easy upload - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - metrics = trainer.evaluate(eval_dataset=eval_dataset) - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Prediction - if training_args.do_predict: - logger.info("*** Predict ***") - predictions, labels, metrics = trainer.predict(predict_dataset, metric_key_prefix="predict") - - max_predict_samples = ( - data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset) - ) - metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset)) - - trainer.log_metrics("predict", metrics) - trainer.save_metrics("predict", metrics) - - predictions = np.argmax(predictions, axis=1) - output_predict_file = os.path.join(training_args.output_dir, "predictions.txt") - if trainer.is_world_process_zero(): - with open(output_predict_file, "w", encoding="utf-8") as writer: - writer.write("index\tprediction\n") - for index, item in enumerate(predictions): - item = label_list[item] - writer.write(f"{index}\t{item}\n") - - trainer.end() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/text-generation/README.md b/examples/pytorch/text-generation/README.md deleted file mode 100644 index b96bcd92241c..000000000000 --- a/examples/pytorch/text-generation/README.md +++ /dev/null @@ -1,31 +0,0 @@ - - -## Language generation - -Based on the script [`run_generation.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/text-generation/run_generation.py). - -Conditional text generation using the auto-regressive models of the library: GPT, GPT-2, GPT-J, Transformer-XL, XLNet, CTRL, BLOOM, LLAMA, OPT. -A similar script is used for our official demo [Write With Transformer](https://transformer.huggingface.co), where you -can try out the different models available in the library. - -Example usage: - -```bash -python run_generation.py \ - --model_type=gpt2 \ - --model_name_or_path=openai-community/gpt2 -``` diff --git a/examples/pytorch/text-generation/requirements.txt b/examples/pytorch/text-generation/requirements.txt deleted file mode 100644 index 324a8cfb1c29..000000000000 --- a/examples/pytorch/text-generation/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -accelerate >= 0.21.0 -sentencepiece != 0.1.92 -protobuf -torch >= 1.3 diff --git a/examples/pytorch/text-generation/run_generation.py b/examples/pytorch/text-generation/run_generation.py deleted file mode 100755 index 9d9477f8f099..000000000000 --- a/examples/pytorch/text-generation/run_generation.py +++ /dev/null @@ -1,448 +0,0 @@ -#!/usr/bin/env python -# Copyright 2018 Google AI, Google Brain and Carnegie Mellon University Authors and the HuggingFace Inc. team. -# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.21.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "torch >= 1.3", -# ] -# /// - -"""Conditional text generation with the auto-regressive models of the library (GPT/GPT-2/CTRL/Transformer-XL/XLNet)""" - -import argparse -import inspect -import logging - -import torch -from accelerate import PartialState -from accelerate.utils import set_seed - -from transformers import ( - AutoTokenizer, - BloomForCausalLM, - CTRLLMHeadModel, - CTRLTokenizer, - GenerationMixin, - GPT2LMHeadModel, - GPT2Tokenizer, - GPTJForCausalLM, - LlamaForCausalLM, - OpenAIGPTLMHeadModel, - OpenAIGPTTokenizer, - OPTForCausalLM, - XLMTokenizer, - XLMWithLMHeadModel, - XLNetLMHeadModel, - XLNetTokenizer, -) -from transformers.modeling_outputs import CausalLMOutputWithPast - - -logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, -) -logger = logging.getLogger(__name__) - -MAX_LENGTH = 10000 # Hardcoded max length to avoid infinite loop - -MODEL_CLASSES = { - "gpt2": (GPT2LMHeadModel, GPT2Tokenizer), - "ctrl": (CTRLLMHeadModel, CTRLTokenizer), - "openai-gpt": (OpenAIGPTLMHeadModel, OpenAIGPTTokenizer), - "xlnet": (XLNetLMHeadModel, XLNetTokenizer), - "xlm": (XLMWithLMHeadModel, XLMTokenizer), - "gptj": (GPTJForCausalLM, AutoTokenizer), - "bloom": (BloomForCausalLM, AutoTokenizer), - "llama": (LlamaForCausalLM, AutoTokenizer), - "opt": (OPTForCausalLM, GPT2Tokenizer), -} - -# Padding text to help Transformer-XL and XLNet with short prompts as proposed by Aman Rusia -# in https://github.com/rusiaaman/XLNet-gen#methodology -# and https://medium.com/@amanrusia/xlnet-speaks-comparison-to-gpt-2-ea1a4e9ba39e -PREFIX = """In 1991, the remains of Russian Tsar Nicholas II and his family -(except for Alexei and Maria) are discovered. -The voice of Nicholas's young son, Tsarevich Alexei Nikolaevich, narrates the -remainder of the story. 1883 Western Siberia, -a young Grigori Rasputin is asked by his father and a group of men to perform magic. -Rasputin has a vision and denounces one of the men as a horse thief. Although his -father initially slaps him for making such an accusation, Rasputin watches as the -man is chased outside and beaten. Twenty years later, Rasputin sees a vision of -the Virgin Mary, prompting him to become a priest. Rasputin quickly becomes famous, -with people, even a bishop, begging for his blessing. """ - - -# -# Functions to prepare models' input -# - - -def prepare_ctrl_input(args, _, tokenizer, prompt_text): - if args.temperature > 0.7: - logger.info("CTRL typically works better with lower temperatures (and lower top_k).") - - encoded_prompt = tokenizer.encode(prompt_text, add_special_tokens=False) - if not any(encoded_prompt[0] == x for x in tokenizer.control_codes.values()): - logger.info("WARNING! You are not starting your generation from a control code so you won't get good results") - return prompt_text - - -def prepare_xlm_input(args, model, tokenizer, prompt_text): - # kwargs = {"language": None, "mask_token_id": None} - - # Set the language - use_lang_emb = hasattr(model.config, "use_lang_emb") and model.config.use_lang_emb - if hasattr(model.config, "lang2id") and use_lang_emb: - available_languages = model.config.lang2id.keys() - if args.xlm_language in available_languages: - language = args.xlm_language - else: - language = None - while language not in available_languages: - language = input("Using XLM. Select language in " + str(list(available_languages)) + " >>> ") - - model.config.lang_id = model.config.lang2id[language] - # kwargs["language"] = tokenizer.lang2id[language] - - # TODO fix mask_token_id setup when configurations will be synchronized between models and tokenizers - # XLM masked-language modeling (MLM) models need masked token - # is_xlm_mlm = "mlm" in args.model_name_or_path - # if is_xlm_mlm: - # kwargs["mask_token_id"] = tokenizer.mask_token_id - - return prompt_text - - -def prepare_xlnet_input(args, _, tokenizer, prompt_text): - prefix = args.prefix if args.prefix else args.padding_text if args.padding_text else PREFIX - prompt_text = prefix + prompt_text - return prompt_text - - -def prepare_transfoxl_input(args, _, tokenizer, prompt_text): - prefix = args.prefix if args.prefix else args.padding_text if args.padding_text else PREFIX - prompt_text = prefix + prompt_text - return prompt_text - - -PREPROCESSING_FUNCTIONS = { - "ctrl": prepare_ctrl_input, - "xlm": prepare_xlm_input, - "xlnet": prepare_xlnet_input, - "transfo-xl": prepare_transfoxl_input, -} - - -def adjust_length_to_model(length, max_sequence_length): - if length < 0 and max_sequence_length > 0: - length = max_sequence_length - elif 0 < max_sequence_length < length: - length = max_sequence_length # No generation bigger than model size - elif length < 0: - length = MAX_LENGTH # avoid infinite loop - return length - - -def sparse_model_config(model_config): - embedding_size = None - if hasattr(model_config, "hidden_size"): - embedding_size = model_config.hidden_size - elif hasattr(model_config, "n_embed"): - embedding_size = model_config.n_embed - elif hasattr(model_config, "n_embd"): - embedding_size = model_config.n_embd - - num_head = None - if hasattr(model_config, "num_attention_heads"): - num_head = model_config.num_attention_heads - elif hasattr(model_config, "n_head"): - num_head = model_config.n_head - - if embedding_size is None or num_head is None or num_head == 0: - raise ValueError("Check the model config") - - num_embedding_size_per_head = int(embedding_size / num_head) - if hasattr(model_config, "n_layer"): - num_layer = model_config.n_layer - elif hasattr(model_config, "num_hidden_layers"): - num_layer = model_config.num_hidden_layers - else: - raise ValueError("Number of hidden layers couldn't be determined from the model config") - - return num_layer, num_head, num_embedding_size_per_head - - -def generate_past_key_values(model, batch_size, seq_len): - num_block_layers, num_attention_heads, num_embedding_size_per_head = sparse_model_config(model.config) - if model.config.model_type == "bloom": - past_key_values = tuple( - ( - torch.empty(int(num_attention_heads * batch_size), num_embedding_size_per_head, seq_len) - .to(model.dtype) - .to(model.device), - torch.empty(int(num_attention_heads * batch_size), seq_len, num_embedding_size_per_head) - .to(model.dtype) - .to(model.device), - ) - for _ in range(num_block_layers) - ) - else: - past_key_values = tuple( - ( - torch.empty(batch_size, num_attention_heads, seq_len, num_embedding_size_per_head) - .to(model.dtype) - .to(model.device), - torch.empty(batch_size, num_attention_heads, seq_len, num_embedding_size_per_head) - .to(model.dtype) - .to(model.device), - ) - for _ in range(num_block_layers) - ) - return past_key_values - - -def prepare_jit_inputs(inputs, model, tokenizer): - batch_size = len(inputs) - dummy_input = tokenizer.batch_encode_plus(inputs, return_tensors="pt") - dummy_input = dummy_input.to(model.device) - if model.config.use_cache: - dummy_input["past_key_values"] = generate_past_key_values(model, batch_size, 1) - dummy_input["attention_mask"] = torch.cat( - [ - torch.zeros(dummy_input["attention_mask"].shape[0], 1) - .to(dummy_input["attention_mask"].dtype) - .to(model.device), - dummy_input["attention_mask"], - ], - -1, - ) - return dummy_input - - -class _ModelFallbackWrapper(GenerationMixin): - __slots__ = ("_optimized", "_default") - - def __init__(self, optimized, default): - self._optimized = optimized - self._default = default - - def __call__(self, *args, **kwargs): - if kwargs["past_key_values"] is None and self._default.config.use_cache: - kwargs["past_key_values"] = generate_past_key_values(self._default, kwargs["input_ids"].shape[0], 0) - kwargs.pop("position_ids", None) - for k in list(kwargs.keys()): - if kwargs[k] is None or isinstance(kwargs[k], bool): - kwargs.pop(k) - outputs = self._optimized(**kwargs) - lm_logits = outputs[0] - past_key_values = outputs[1] - fixed_output = CausalLMOutputWithPast( - loss=None, - logits=lm_logits, - past_key_values=past_key_values, - hidden_states=None, - attentions=None, - ) - return fixed_output - - def __getattr__(self, item): - return getattr(self._default, item) - - def prepare_inputs_for_generation( - self, input_ids, past_key_values=None, inputs_embeds=None, use_cache=None, **kwargs - ): - return self._default.prepare_inputs_for_generation( - input_ids, past_key_values=past_key_values, inputs_embeds=inputs_embeds, use_cache=use_cache, **kwargs - ) - - def _reorder_cache( - self, past_key_values: tuple[tuple[torch.Tensor]], beam_idx: torch.Tensor - ) -> tuple[tuple[torch.Tensor]]: - """ - This function is used to re-order the `past_key_values` cache if [`~PretrainedModel.beam_search`] or - [`~PretrainedModel.beam_sample`] is called. This is required to match `past_key_values` with the correct - beam_idx at every generation step. - """ - return self._default._reorder_cache(past_key_values, beam_idx) - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--model_type", - default=None, - type=str, - required=True, - help="Model type selected in the list: " + ", ".join(MODEL_CLASSES.keys()), - ) - parser.add_argument( - "--model_name_or_path", - default=None, - type=str, - required=True, - help="Path to pre-trained model or shortcut name selected in the list: " + ", ".join(MODEL_CLASSES.keys()), - ) - - parser.add_argument("--prompt", type=str, default="") - parser.add_argument("--length", type=int, default=20) - parser.add_argument("--stop_token", type=str, default=None, help="Token at which text generation is stopped") - - parser.add_argument( - "--temperature", - type=float, - default=1.0, - help="temperature of 1.0 has no effect, lower tend toward greedy sampling", - ) - parser.add_argument( - "--repetition_penalty", type=float, default=1.0, help="primarily useful for CTRL model; in that case, use 1.2" - ) - parser.add_argument("--k", type=int, default=0) - parser.add_argument("--p", type=float, default=0.9) - - parser.add_argument("--prefix", type=str, default="", help="Text added prior to input.") - parser.add_argument("--padding_text", type=str, default="", help="Deprecated, the use of `--prefix` is preferred.") - parser.add_argument("--xlm_language", type=str, default="", help="Optional language when used with the XLM model.") - - parser.add_argument("--seed", type=int, default=42, help="random seed for initialization") - parser.add_argument( - "--use_cpu", - action="store_true", - help="Whether or not to use cpu. If set to False, we will use gpu/npu or mps device if available", - ) - parser.add_argument("--num_return_sequences", type=int, default=1, help="The number of samples to generate.") - parser.add_argument( - "--fp16", - action="store_true", - help="Whether to use 16-bit (mixed) precision instead of 32-bit", - ) - parser.add_argument("--jit", action="store_true", help="Whether or not to use jit trace to accelerate inference") - args = parser.parse_args() - - # Initialize the distributed state. - distributed_state = PartialState(cpu=args.use_cpu) - - logger.warning(f"device: {distributed_state.device}, 16-bits inference: {args.fp16}") - - if args.seed is not None: - set_seed(args.seed) - - # Initialize the model and tokenizer - try: - args.model_type = args.model_type.lower() - model_class, tokenizer_class = MODEL_CLASSES[args.model_type] - except KeyError: - raise KeyError("the model {} you specified is not supported. You are welcome to add it and open a PR :)") - - tokenizer = tokenizer_class.from_pretrained(args.model_name_or_path) - if tokenizer.pad_token is None: - tokenizer.pad_token = tokenizer.eos_token - model = model_class.from_pretrained(args.model_name_or_path) - - # Set the model to the right device - model.to(distributed_state.device) - - if args.fp16: - model.half() - max_seq_length = getattr(model.config, "max_position_embeddings", 0) - args.length = adjust_length_to_model(args.length, max_sequence_length=max_seq_length) - logger.info(args) - - prompt_text = args.prompt if args.prompt else input("Model prompt >>> ") - - # Different models need different input formatting and/or extra arguments - requires_preprocessing = args.model_type in PREPROCESSING_FUNCTIONS - if requires_preprocessing: - prepare_input = PREPROCESSING_FUNCTIONS.get(args.model_type) - preprocessed_prompt_text = prepare_input(args, model, tokenizer, prompt_text) - - tokenizer_kwargs = {} - - encoded_prompt = tokenizer.encode( - preprocessed_prompt_text, add_special_tokens=False, return_tensors="pt", **tokenizer_kwargs - ) - else: - prefix = args.prefix if args.prefix else args.padding_text - encoded_prompt = tokenizer.encode(prefix + prompt_text, add_special_tokens=False, return_tensors="pt") - encoded_prompt = encoded_prompt.to(distributed_state.device) - - if encoded_prompt.size()[-1] == 0: - input_ids = None - else: - input_ids = encoded_prompt - - if args.jit: - jit_input_texts = ["enable jit"] - jit_inputs = prepare_jit_inputs(jit_input_texts, model, tokenizer) - torch._C._jit_set_texpr_fuser_enabled(False) - model.config.return_dict = False - if hasattr(model, "forward"): - sig = inspect.signature(model.forward) - else: - sig = inspect.signature(model.__call__) - jit_inputs = tuple(jit_inputs[key] for key in sig.parameters if jit_inputs.get(key, None) is not None) - traced_model = torch.jit.trace(model, jit_inputs, strict=False) - traced_model = torch.jit.freeze(traced_model.eval()) - traced_model(*jit_inputs) - traced_model(*jit_inputs) - - model = _ModelFallbackWrapper(traced_model, model) - - output_sequences = model.generate( - input_ids=input_ids, - max_length=args.length + len(encoded_prompt[0]), - temperature=args.temperature, - top_k=args.k, - top_p=args.p, - repetition_penalty=args.repetition_penalty, - do_sample=True, - num_return_sequences=args.num_return_sequences, - ) - - # Remove the batch dimension when returning multiple sequences - if len(output_sequences.shape) > 2: - output_sequences.squeeze_() - - generated_sequences = [] - - for generated_sequence_idx, generated_sequence in enumerate(output_sequences): - print(f"=== GENERATED SEQUENCE {generated_sequence_idx + 1} ===") - generated_sequence = generated_sequence.tolist() - - # Decode text - text = tokenizer.decode(generated_sequence, clean_up_tokenization_spaces=True) - - # Remove all text after the stop token - text = text[: text.find(args.stop_token) if args.stop_token else None] - - # Add the prompt at the beginning of the sequence. Remove the excess text that was used for pre-processing - total_sequence = ( - prompt_text + text[len(tokenizer.decode(encoded_prompt[0], clean_up_tokenization_spaces=True)) :] - ) - - generated_sequences.append(total_sequence) - print(total_sequence) - - return generated_sequences - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/token-classification/README.md b/examples/pytorch/token-classification/README.md deleted file mode 100644 index b4db0ba8dfad..000000000000 --- a/examples/pytorch/token-classification/README.md +++ /dev/null @@ -1,146 +0,0 @@ - - -# Token classification - -## PyTorch version - -Fine-tuning the library models for token classification task such as Named Entity Recognition (NER), Parts-of-speech -tagging (POS) or phrase extraction (CHUNKS). The main script `run_ner.py` leverages the 🤗 Datasets library and the Trainer API. You can easily -customize it to your needs if you need extra processing on your datasets. - -It will either run on a datasets hosted on our [hub](https://huggingface.co/datasets) or with your own text files for -training and validation, you might just need to add some tweaks in the data preprocessing. - -### Using your own data - -If you use your own data, the script expects the following format of the data - - -```bash -{ - "chunk_tags": [11, 12, 12, 21, 13, 11, 11, 21, 13, 11, 12, 13, 11, 21, 22, 11, 12, 17, 11, 21, 17, 11, 12, 12, 21, 22, 22, 13, 11, 0], - "id": "0", - "ner_tags": [0, 3, 4, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - "pos_tags": [12, 22, 22, 38, 15, 22, 28, 38, 15, 16, 21, 35, 24, 35, 37, 16, 21, 15, 24, 41, 15, 16, 21, 21, 20, 37, 40, 35, 21, 7], - "tokens": ["The", "European", "Commission", "said", "on", "Thursday", "it", "disagreed", "with", "German", "advice", "to", "consumers", "to", "shun", "British", "lamb", "until", "scientists", "determine", "whether", "mad", "cow", "disease", "can", "be", "transmitted", "to", "sheep", "."] -} -``` - -The following example fine-tunes BERT on CoNLL-2003: - -```bash -python run_ner.py \ - --model_name_or_path google-bert/bert-base-uncased \ - --dataset_name tomaarsen/conll2003 \ - --output_dir /tmp/test-ner \ - --do_train \ - --do_eval -``` - -or just can just run the bash script `run.sh`. - -To run on your own training and validation files, use the following command: - -```bash -python run_ner.py \ - --model_name_or_path google-bert/bert-base-uncased \ - --train_file path_to_train_file \ - --validation_file path_to_validation_file \ - --output_dir /tmp/test-ner \ - --do_train \ - --do_eval -``` - -**Note:** This script only works with models that have a fast tokenizer (backed by the 🤗 Tokenizers library) as it -uses special features of those tokenizers. You can check if your favorite model has a fast tokenizer in -[this table](https://huggingface.co/transformers/index.html#supported-frameworks), if it doesn't you can still use the old version -of the script. - -> If your model classification head dimensions do not fit the number of labels in the dataset, you can specify `--ignore_mismatched_sizes` to adapt it. - -## Old version of the script - -You can find the old version of the PyTorch script [here](https://github.com/huggingface/transformers/blob/main/examples/legacy/token-classification/run_ner.py). - -## Pytorch version, no Trainer - -Based on the script [run_ner_no_trainer.py](https://github.com/huggingface/transformers/blob/main/examples/pytorch/token-classification/run_ner_no_trainer.py). - -Like `run_ner.py`, this script allows you to fine-tune any of the models on the [hub](https://huggingface.co/models) on a -token classification task, either NER, POS or CHUNKS tasks or your own data in a csv or a JSON file. The main difference is that this -script exposes the bare training loop, to allow you to quickly experiment and add any customization you would like. - -It offers less options than the script with `Trainer` (for instance you can easily change the options for the optimizer -or the dataloaders directly in the script) but still run in a distributed setup, on TPU and supports mixed precision by -the mean of the [🤗 `Accelerate`](https://github.com/huggingface/accelerate) library. You can use the script normally -after installing it: - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -then - -```bash -export TASK_NAME=ner - -python run_ner_no_trainer.py \ - --model_name_or_path google-bert/bert-base-cased \ - --dataset_name tomaarsen/conll2003 \ - --task_name $TASK_NAME \ - --max_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ -``` - -You can then use your usual launchers to run in it in a distributed environment, but the easiest way is to run - -```bash -accelerate config -``` - -and reply to the questions asked. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -export TASK_NAME=ner - -accelerate launch run_ner_no_trainer.py \ - --model_name_or_path google-bert/bert-base-cased \ - --dataset_name tomaarsen/conll2003 \ - --task_name $TASK_NAME \ - --max_length 128 \ - --per_device_train_batch_size 32 \ - --learning_rate 2e-5 \ - --num_train_epochs 3 \ - --output_dir /tmp/$TASK_NAME/ -``` - -This command is the same and will work for: - -- a CPU-only setup -- a setup with one GPU -- a distributed training with several GPUs (single or multi node) -- a training on TPUs - -Note that this library is in alpha release so your feedback is more than welcome if you encounter any problem using it. diff --git a/examples/pytorch/token-classification/requirements.txt b/examples/pytorch/token-classification/requirements.txt deleted file mode 100644 index 53740bf4e81a..000000000000 --- a/examples/pytorch/token-classification/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -accelerate >= 0.12.0 -seqeval -datasets >= 1.8.0 -torch >= 1.3 -evaluate \ No newline at end of file diff --git a/examples/pytorch/token-classification/run.sh b/examples/pytorch/token-classification/run.sh deleted file mode 100755 index 81e2557bf11e..000000000000 --- a/examples/pytorch/token-classification/run.sh +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -python3 run_ner.py \ - --model_name_or_path bert-base-uncased \ - --dataset_name tomaarsen/conll2003 \ - --output_dir /tmp/test-ner \ - --do_train \ - --do_eval diff --git a/examples/pytorch/token-classification/run_ner.py b/examples/pytorch/token-classification/run_ner.py deleted file mode 100755 index 0138d5b6fed1..000000000000 --- a/examples/pytorch/token-classification/run_ner.py +++ /dev/null @@ -1,643 +0,0 @@ -#!/usr/bin/env python -# Copyright 2020 The HuggingFace Team All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "seqeval", -# "datasets >= 1.8.0", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -""" -Fine-tuning the library models for token classification. -""" -# You can also adapt this script on your own token classification task and datasets. Pointers for this are left as -# comments. - -import logging -import os -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -import numpy as np -from datasets import ClassLabel, load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoModelForTokenClassification, - AutoTokenizer, - DataCollatorForTokenClassification, - HfArgumentParser, - PreTrainedConfig, - Trainer, - TrainingArguments, - set_seed, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/token-classification/requirements.txt") - -logger = logging.getLogger(__name__) - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where do you want to store the pretrained models downloaded from huggingface.co"}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - ignore_mismatched_sizes: bool = field( - default=False, - metadata={"help": "Will enable to load a pretrained model whose head dimensions are different."}, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - task_name: str | None = field(default="ner", metadata={"help": "The name of the task (ner, pos...)."}) - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_file: str | None = field( - default=None, metadata={"help": "The input training data file (a csv or JSON file)."} - ) - validation_file: str | None = field( - default=None, - metadata={"help": "An optional input evaluation data file to evaluate on (a csv or JSON file)."}, - ) - test_file: str | None = field( - default=None, - metadata={"help": "An optional input test data file to predict on (a csv or JSON file)."}, - ) - text_column_name: str | None = field( - default=None, metadata={"help": "The column name of text to input in the file (a csv or JSON file)."} - ) - label_column_name: str | None = field( - default=None, metadata={"help": "The column name of label to input in the file (a csv or JSON file)."} - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_seq_length: int = field( - default=None, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. If set, sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - pad_to_max_length: bool = field( - default=False, - metadata={ - "help": ( - "Whether to pad all samples to model maximum sentence length. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch. More " - "efficient on GPU but very bad for TPU." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - label_all_tokens: bool = field( - default=False, - metadata={ - "help": ( - "Whether to put the label for one word on all tokens of generated by that word or just on the " - "one (in which case the other tokens will have a padding index)." - ) - }, - ) - return_entity_level_metrics: bool = field( - default=False, - metadata={"help": "Whether to return all the entity levels during evaluation or just the overall ones."}, - ) - - def __post_init__(self): - if self.dataset_name is None and self.train_file is None and self.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - else: - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - self.task_name = self.task_name.lower() - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - if data_args.test_file is not None: - data_files["test"] = data_args.test_file - extension = data_args.test_file.split(".")[-1] - raw_datasets = load_dataset(extension, data_files=data_files, cache_dir=model_args.cache_dir) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - if training_args.do_train: - column_names = raw_datasets["train"].column_names - features = raw_datasets["train"].features - else: - column_names = raw_datasets["validation"].column_names - features = raw_datasets["validation"].features - - if data_args.text_column_name is not None: - text_column_name = data_args.text_column_name - elif "tokens" in column_names: - text_column_name = "tokens" - else: - text_column_name = column_names[0] - - if data_args.label_column_name is not None: - label_column_name = data_args.label_column_name - elif f"{data_args.task_name}_tags" in column_names: - label_column_name = f"{data_args.task_name}_tags" - else: - label_column_name = column_names[1] - - # In the event the labels are not a `Sequence[ClassLabel]`, we will need to go through the dataset to get the - # unique labels. - def get_label_list(labels): - unique_labels = set() - for label in labels: - unique_labels = unique_labels | set(label) - label_list = list(unique_labels) - label_list.sort() - return label_list - - # If the labels are of type ClassLabel, they are already integers and we have the map stored somewhere. - # Otherwise, we have to get the list of labels manually. - labels_are_int = isinstance(features[label_column_name].feature, ClassLabel) - if labels_are_int: - label_list = features[label_column_name].feature.names - label_to_id = {i: i for i in range(len(label_list))} - else: - label_list = get_label_list(raw_datasets["train"][label_column_name]) - label_to_id = {l: i for i, l in enumerate(label_list)} - - num_labels = len(label_list) - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - num_labels=num_labels, - finetuning_task=data_args.task_name, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - tokenizer_name_or_path = model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path - if config.model_type in {"bloom", "gpt2", "roberta", "deberta"}: - tokenizer = AutoTokenizer.from_pretrained( - tokenizer_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=True, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - add_prefix_space=True, - ) - else: - tokenizer = AutoTokenizer.from_pretrained( - tokenizer_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=True, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - model = AutoModelForTokenClassification.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ignore_mismatched_sizes=model_args.ignore_mismatched_sizes, - ) - - # Tokenizer check: this script requires a fast tokenizer. - # Check if tokenizer has _tokenizer attribute (from tokenizers library) or is_fast property - if not (hasattr(tokenizer, "_tokenizer") or getattr(tokenizer, "is_fast", False)): - raise TypeError( - "This example script only works for models that have a fast tokenizer. Check out the big table of models at" - " https://huggingface.co/transformers/index.html#supported-frameworks to find the model types that meet" - " this requirement" - ) - - # Model has labels -> use them. - if model.config.label2id != PreTrainedConfig(num_labels=num_labels).label2id: - if sorted(model.config.label2id.keys()) == sorted(label_list): - # Reorganize `label_list` to match the ordering of the model. - if labels_are_int: - label_to_id = {i: int(model.config.label2id[l]) for i, l in enumerate(label_list)} - label_list = [model.config.id2label[i] for i in range(num_labels)] - else: - label_list = [model.config.id2label[i] for i in range(num_labels)] - label_to_id = {l: i for i, l in enumerate(label_list)} - else: - logger.warning( - "Your model seems to have been trained with labels, but they don't match the dataset: " - f"model labels: {sorted(model.config.label2id.keys())}, dataset labels:" - f" {sorted(label_list)}.\nIgnoring the model labels as a result.", - ) - - # Set the correspondences label/ID inside the model config - model.config.label2id = {l: i for i, l in enumerate(label_list)} - model.config.id2label = dict(enumerate(label_list)) - - # Map that sends B-Xxx label to its I-Xxx counterpart - b_to_i_label = [] - for idx, label in enumerate(label_list): - if label.startswith("B-") and label.replace("B-", "I-") in label_list: - b_to_i_label.append(label_list.index(label.replace("B-", "I-"))) - else: - b_to_i_label.append(idx) - - # Preprocessing the dataset - # Padding strategy - padding = "max_length" if data_args.pad_to_max_length else False - - # Tokenize all texts and align the labels with them. - def tokenize_and_align_labels(examples): - tokenized_inputs = tokenizer( - examples[text_column_name], - padding=padding, - truncation=True, - max_length=data_args.max_seq_length, - # We use this argument because the texts in our dataset are lists of words (with a label for each word). - is_split_into_words=True, - ) - labels = [] - for i, label in enumerate(examples[label_column_name]): - word_ids = tokenized_inputs.word_ids(batch_index=i) - previous_word_idx = None - label_ids = [] - for word_idx in word_ids: - # Special tokens have a word id that is None. We set the label to -100 so they are automatically - # ignored in the loss function. - if word_idx is None: - label_ids.append(-100) - # We set the label for the first token of each word. - elif word_idx != previous_word_idx: - label_ids.append(label_to_id[label[word_idx]]) - # For the other tokens in a word, we set the label to either the current label or -100, depending on - # the label_all_tokens flag. - else: - if data_args.label_all_tokens: - label_ids.append(b_to_i_label[label_to_id[label[word_idx]]]) - else: - label_ids.append(-100) - previous_word_idx = word_idx - - labels.append(label_ids) - tokenized_inputs["labels"] = labels - return tokenized_inputs - - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - with training_args.main_process_first(desc="train dataset map pre-processing"): - train_dataset = train_dataset.map( - tokenize_and_align_labels, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - - if training_args.do_eval: - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_dataset = raw_datasets["validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - with training_args.main_process_first(desc="validation dataset map pre-processing"): - eval_dataset = eval_dataset.map( - tokenize_and_align_labels, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - - if training_args.do_predict: - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_dataset = raw_datasets["test"] - if data_args.max_predict_samples is not None: - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - with training_args.main_process_first(desc="prediction dataset map pre-processing"): - predict_dataset = predict_dataset.map( - tokenize_and_align_labels, - batched=True, - num_proc=data_args.preprocessing_num_workers, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - - # Data collator - data_collator = DataCollatorForTokenClassification(tokenizer, pad_to_multiple_of=8 if training_args.fp16 else None) - - # Metrics - metric = evaluate.load("seqeval", cache_dir=model_args.cache_dir) - - def compute_metrics(p): - predictions, labels = p - if not training_args.eval_do_concat_batches: - predictions = np.hstack(predictions) - labels = np.hstack(labels) - predictions = np.argmax(predictions, axis=2) - - # Remove ignored index (special tokens) - true_predictions = [ - [label_list[p] for (p, l) in zip(prediction, label) if l != -100] - for prediction, label in zip(predictions, labels) - ] - true_labels = [ - [label_list[l] for (p, l) in zip(prediction, label) if l != -100] - for prediction, label in zip(predictions, labels) - ] - - results = metric.compute(predictions=true_predictions, references=true_labels) - if data_args.return_entity_level_metrics: - # Unpack nested dictionaries - final_results = {} - for key, value in results.items(): - if isinstance(value, dict): - for n, v in value.items(): - final_results[f"{key}_{n}"] = v - else: - final_results[key] = value - return final_results - else: - return { - "precision": results["overall_precision"], - "recall": results["overall_recall"], - "f1": results["overall_f1"], - "accuracy": results["overall_accuracy"], - } - - # Initialize our Trainer - trainer = Trainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - processing_class=tokenizer, - data_collator=data_collator, - compute_metrics=compute_metrics, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - metrics = train_result.metrics - trainer.save_model() # Saves the tokenizer too for easy upload - - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - if training_args.do_eval: - logger.info("*** Evaluate ***") - - metrics = trainer.evaluate() - - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - # Predict - if training_args.do_predict: - logger.info("*** Predict ***") - - predictions, labels, metrics = trainer.predict(predict_dataset, metric_key_prefix="predict") - predictions = np.argmax(predictions, axis=2) - - # Remove ignored index (special tokens) - true_predictions = [ - [label_list[p] for (p, l) in zip(prediction, label) if l != -100] - for prediction, label in zip(predictions, labels) - ] - - trainer.log_metrics("predict", metrics) - trainer.save_metrics("predict", metrics) - - # Save predictions - output_predictions_file = os.path.join(training_args.output_dir, "predictions.txt") - if trainer.is_world_process_zero(): - with open(output_predictions_file, "w", encoding="utf-8") as writer: - writer.writelines(" ".join(prediction) + "\n" for prediction in true_predictions) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "token-classification"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/token-classification/run_ner_no_trainer.py b/examples/pytorch/token-classification/run_ner_no_trainer.py deleted file mode 100755 index da9d7978a6f3..000000000000 --- a/examples/pytorch/token-classification/run_ner_no_trainer.py +++ /dev/null @@ -1,842 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "seqeval", -# "datasets >= 1.8.0", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -""" -Fine-tuning a 🤗 Transformers model on token classification tasks (NER, POS, CHUNKS) relying on the accelerate library -without using a Trainer. -""" - -import argparse -import json -import logging -import math -import os -import random -from pathlib import Path - -import datasets -import evaluate -import numpy as np -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import ClassLabel, load_dataset -from huggingface_hub import HfApi -from torch import nn -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_MAPPING, - AutoConfig, - AutoModelForTokenClassification, - AutoTokenizer, - DataCollatorForTokenClassification, - PreTrainedConfig, - SchedulerType, - default_data_collator, - get_scheduler, -) -from transformers.trainer_pt_utils import get_parameter_names -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/token-classification/requirements.txt") - -# You should update this to your particular problem to have better documentation of `model_type` -MODEL_CONFIG_CLASSES = list(MODEL_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -def parse_args(): - parser = argparse.ArgumentParser( - description="Finetune a transformers model on a text classification task (NER) with accelerate library" - ) - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv or a json file containing the training data." - ) - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv or a json file containing the validation data." - ) - parser.add_argument( - "--text_column_name", - type=str, - default=None, - help="The column name of text to input in the file (a csv or JSON file).", - ) - parser.add_argument( - "--label_column_name", - type=str, - default=None, - help="The column name of label to input in the file (a csv or JSON file).", - ) - parser.add_argument( - "--max_length", - type=int, - default=128, - help=( - "The maximum total input sequence length after tokenization. Sequences longer than this will be truncated," - " sequences shorter will be padded if `--pad_to_max_length` is passed." - ), - ) - parser.add_argument( - "--pad_to_max_length", - action="store_true", - help="If passed, pad all samples to `max_length`. Otherwise, dynamic padding is used.", - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=False, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--tokenizer_name", - type=str, - default=None, - help="Pretrained tokenizer name or path if not the same as model_name", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument( - "--model_type", - type=str, - default=None, - help="Model type to use if training from scratch.", - choices=MODEL_TYPES, - ) - parser.add_argument( - "--label_all_tokens", - action="store_true", - help="Setting labels of all special tokens to -100 and thus PyTorch will ignore them.", - ) - parser.add_argument( - "--return_entity_level_metrics", - action="store_true", - help="Indication whether entity level metrics are to be returner.", - ) - parser.add_argument( - "--task_name", - type=str, - default="ner", - choices=["ner", "pos", "chunk"], - help="The name of the task.", - ) - parser.add_argument( - "--debug", - action="store_true", - help="Activate debug mode and run training only with a subset of data.", - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - parser.add_argument( - "--ignore_mismatched_sizes", - action="store_true", - help="Whether or not to enable to load a pretrained model whose head dimensions are different.", - ) - args = parser.parse_args() - - # Sanity checks - if args.task_name is None and args.train_file is None and args.validation_file is None: - raise ValueError("Need either a task name or a training/validation file.") - else: - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - return args - - -def main(): - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator = ( - Accelerator(log_with=args.report_to, project_dir=args.output_dir) if args.with_tracking else Accelerator() - ) - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets for token classification task available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'tokens' or the first column if no column called - # 'tokens' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - else: - data_files = {} - if args.train_file is not None: - data_files["train"] = args.train_file - extension = args.train_file.split(".")[-1] - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.validation_file.split(".")[-1] - raw_datasets = load_dataset(extension, data_files=data_files) - # Trim a number of training examples - if args.debug: - for split in raw_datasets: - raw_datasets[split] = raw_datasets[split].select(range(100)) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - if raw_datasets["train"] is not None: - column_names = raw_datasets["train"].column_names - features = raw_datasets["train"].features - else: - column_names = raw_datasets["validation"].column_names - features = raw_datasets["validation"].features - - if args.text_column_name is not None: - text_column_name = args.text_column_name - elif "tokens" in column_names: - text_column_name = "tokens" - else: - text_column_name = column_names[0] - - if args.label_column_name is not None: - label_column_name = args.label_column_name - elif f"{args.task_name}_tags" in column_names: - label_column_name = f"{args.task_name}_tags" - else: - label_column_name = column_names[1] - - # In the event the labels are not a `Sequence[ClassLabel]`, we will need to go through the dataset to get the - # unique labels. - def get_label_list(labels): - unique_labels = set() - for label in labels: - unique_labels = unique_labels | set(label) - label_list = list(unique_labels) - label_list.sort() - return label_list - - # If the labels are of type ClassLabel, they are already integers and we have the map stored somewhere. - # Otherwise, we have to get the list of labels manually. - labels_are_int = isinstance(features[label_column_name].feature, ClassLabel) - if labels_are_int: - label_list = features[label_column_name].feature.names - label_to_id = {i: i for i in range(len(label_list))} - else: - label_list = get_label_list(raw_datasets["train"][label_column_name]) - label_to_id = {l: i for i, l in enumerate(label_list)} - - num_labels = len(label_list) - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - if args.config_name: - config = AutoConfig.from_pretrained( - args.config_name, num_labels=num_labels, trust_remote_code=args.trust_remote_code - ) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained( - args.model_name_or_path, num_labels=num_labels, trust_remote_code=args.trust_remote_code - ) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - - tokenizer_name_or_path = args.tokenizer_name if args.tokenizer_name else args.model_name_or_path - if not tokenizer_name_or_path: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if config.model_type in {"bloom", "gpt2", "roberta"}: - tokenizer = AutoTokenizer.from_pretrained( - tokenizer_name_or_path, use_fast=True, add_prefix_space=True, trust_remote_code=args.trust_remote_code - ) - else: - tokenizer = AutoTokenizer.from_pretrained( - tokenizer_name_or_path, use_fast=True, trust_remote_code=args.trust_remote_code - ) - - if args.model_name_or_path: - model = AutoModelForTokenClassification.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - ignore_mismatched_sizes=args.ignore_mismatched_sizes, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForTokenClassification.from_config(config, trust_remote_code=args.trust_remote_code) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Model has labels -> use them. - if model.config.label2id != PreTrainedConfig(num_labels=num_labels).label2id: - if sorted(model.config.label2id.keys()) == sorted(label_list): - # Reorganize `label_list` to match the ordering of the model. - if labels_are_int: - label_to_id = {i: int(model.config.label2id[l]) for i, l in enumerate(label_list)} - label_list = [model.config.id2label[i] for i in range(num_labels)] - else: - label_list = [model.config.id2label[i] for i in range(num_labels)] - label_to_id = {l: i for i, l in enumerate(label_list)} - else: - logger.warning( - "Your model seems to have been trained with labels, but they don't match the dataset: " - f"model labels: {sorted(model.config.label2id.keys())}, dataset labels:" - f" {sorted(label_list)}.\nIgnoring the model labels as a result.", - ) - - # Set the correspondences label/ID inside the model config - model.config.label2id = {l: i for i, l in enumerate(label_list)} - model.config.id2label = dict(enumerate(label_list)) - - # Map that sends B-Xxx label to its I-Xxx counterpart - b_to_i_label = [] - for idx, label in enumerate(label_list): - if label.startswith("B-") and label.replace("B-", "I-") in label_list: - b_to_i_label.append(label_list.index(label.replace("B-", "I-"))) - else: - b_to_i_label.append(idx) - - # Preprocessing the datasets. - # First we tokenize all the texts. - padding = "max_length" if args.pad_to_max_length else False - - # Tokenize all texts and align the labels with them. - - def tokenize_and_align_labels(examples): - tokenized_inputs = tokenizer( - examples[text_column_name], - max_length=args.max_length, - padding=padding, - truncation=True, - # We use this argument because the texts in our dataset are lists of words (with a label for each word). - is_split_into_words=True, - ) - - labels = [] - for i, label in enumerate(examples[label_column_name]): - word_ids = tokenized_inputs.word_ids(batch_index=i) - previous_word_idx = None - label_ids = [] - for word_idx in word_ids: - # Special tokens have a word id that is None. We set the label to -100 so they are automatically - # ignored in the loss function. - if word_idx is None: - label_ids.append(-100) - # We set the label for the first token of each word. - elif word_idx != previous_word_idx: - label_ids.append(label_to_id[label[word_idx]]) - # For the other tokens in a word, we set the label to either the current label or -100, depending on - # the label_all_tokens flag. - else: - if args.label_all_tokens: - label_ids.append(b_to_i_label[label_to_id[label[word_idx]]]) - else: - label_ids.append(-100) - previous_word_idx = word_idx - - labels.append(label_ids) - tokenized_inputs["labels"] = labels - return tokenized_inputs - - with accelerator.main_process_first(): - processed_raw_datasets = raw_datasets.map( - tokenize_and_align_labels, - batched=True, - remove_columns=raw_datasets["train"].column_names, - desc="Running tokenizer on dataset", - ) - - train_dataset = processed_raw_datasets["train"] - eval_dataset = processed_raw_datasets["validation"] - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # DataLoaders creation: - if args.pad_to_max_length: - # If padding was already done ot max length, we use the default data collator that will just convert everything - # to tensors. - data_collator = default_data_collator - else: - # Otherwise, `DataCollatorForTokenClassification` will apply dynamic padding for us (by padding to the maximum length of - # the samples passed). When using mixed precision, we add `pad_to_multiple_of=8` to pad all tensors to multiple - # of 8s, which will enable the use of Tensor Cores on NVIDIA hardware with compute capability >= 7.5 (Volta). - # For fp8, we pad to multiple of 16. - if accelerator.mixed_precision == "fp8": - pad_to_multiple_of = 16 - elif accelerator.mixed_precision != "no": - pad_to_multiple_of = 8 - else: - pad_to_multiple_of = None - data_collator = DataCollatorForTokenClassification(tokenizer, pad_to_multiple_of=pad_to_multiple_of) - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader(eval_dataset, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - forbidden_name_patterns = [r"bias", r"layernorm", r"rmsnorm", r"(?:^|\.)norm(?:$|\.)", r"_norm(?:$|\.)"] - decay_parameters = get_parameter_names(model, [nn.LayerNorm], forbidden_layer_names=forbidden_name_patterns) - optimizer_grouped_parameters = [ - { - "params": [p for n, p in model.named_parameters() if n in decay_parameters and p.requires_grad], - "weight_decay": args.weight_decay, - }, - { - "params": [p for n, p in model.named_parameters() if n not in decay_parameters and p.requires_grad], - "weight_decay": 0.0, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Use the device given by the `accelerator` object. - device = accelerator.device - model.to(device) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps, - num_training_steps=args.max_train_steps, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # The trackers initializes automatically on the main process. - if args.with_tracking: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("ner_no_trainer", experiment_config) - - # Metrics - metric = evaluate.load("seqeval") - - def get_labels(predictions, references): - # Transform predictions and references tensos to numpy arrays - if device.type == "cpu": - y_pred = predictions.detach().clone().numpy() - y_true = references.detach().clone().numpy() - else: - y_pred = predictions.detach().cpu().clone().numpy() - y_true = references.detach().cpu().clone().numpy() - - # Remove ignored index (special tokens) - true_predictions = [ - [label_list[p] for (p, l) in zip(pred, gold_label) if l != -100] - for pred, gold_label in zip(y_pred, y_true) - ] - true_labels = [ - [label_list[l] for (p, l) in zip(pred, gold_label) if l != -100] - for pred, gold_label in zip(y_pred, y_true) - ] - return true_predictions, true_labels - - def compute_metrics(): - results = metric.compute() - if args.return_entity_level_metrics: - # Unpack nested dictionaries - final_results = {} - for key, value in results.items(): - if isinstance(value, dict): - for n, v in value.items(): - final_results[f"{key}_{n}"] = v - else: - final_results[key] = value - return final_results - else: - return { - "precision": results["overall_precision"], - "recall": results["overall_recall"], - "f1": results["overall_f1"], - "accuracy": results["overall_accuracy"], - } - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - loss = loss / args.gradient_accumulation_steps - accelerator.backward(loss) - if step % args.gradient_accumulation_steps == 0 or step == len(train_dataloader) - 1: - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if completed_steps >= args.max_train_steps: - break - - model.eval() - samples_seen = 0 - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - outputs = model(**batch) - predictions = outputs.logits.argmax(dim=-1) - labels = batch["labels"] - if not args.pad_to_max_length: # necessary to pad predictions and labels for being gathered - predictions = accelerator.pad_across_processes(predictions, dim=1, pad_index=-100) - labels = accelerator.pad_across_processes(labels, dim=1, pad_index=-100) - predictions_gathered, labels_gathered = accelerator.gather((predictions, labels)) - # If we are in a multiprocess environment, the last batch has duplicates - if accelerator.num_processes > 1: - if step == len(eval_dataloader) - 1: - predictions_gathered = predictions_gathered[: len(eval_dataloader.dataset) - samples_seen] - labels_gathered = labels_gathered[: len(eval_dataloader.dataset) - samples_seen] - else: - samples_seen += labels_gathered.shape[0] - preds, refs = get_labels(predictions_gathered, labels_gathered) - metric.add_batch( - predictions=preds, - references=refs, - ) # predictions and preferences are expected to be a nested list of labels, not label_ids - - eval_metric = compute_metrics() - accelerator.print(f"epoch {epoch}:", eval_metric) - if args.with_tracking: - accelerator.log( - { - "seqeval": eval_metric, - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - all_results = {f"eval_{k}": v for k, v in eval_metric.items()} - if args.with_tracking: - all_results.update({"train_loss": total_loss.item() / len(train_dataloader)}) - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - # Convert all float64 & int64 type numbers to float & int for json serialization - for key, value in all_results.items(): - if isinstance(value, np.float64): - all_results[key] = float(value) - elif isinstance(value, np.int64): - all_results[key] = int(value) - json.dump(all_results, f) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/token-classification/run_no_trainer.sh b/examples/pytorch/token-classification/run_no_trainer.sh deleted file mode 100755 index 8987e92cffbf..000000000000 --- a/examples/pytorch/token-classification/run_no_trainer.sh +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -accelerate launch run_ner_no_trainer.py \ - --model_name_or_path bert-base-uncased \ - --dataset_name tomaarsen/conll2003 \ - --output_dir /tmp/test-ner \ - --pad_to_max_length \ - --task_name ner \ - --return_entity_level_metrics diff --git a/examples/pytorch/translation/README.md b/examples/pytorch/translation/README.md deleted file mode 100644 index 2cb7c5eb86e0..000000000000 --- a/examples/pytorch/translation/README.md +++ /dev/null @@ -1,206 +0,0 @@ - - -## Translation - -This directory contains examples for finetuning and evaluating transformers on translation tasks. -Please tag @patil-suraj with any issues/unexpected behaviors, or send a PR! -For deprecated `bertabs` instructions, see https://github.com/huggingface/transformers-research-projects/blob/main/bertabs/README.md. -For the old `finetune_trainer.py` and related utils, see [`examples/legacy/seq2seq`](https://github.com/huggingface/transformers/blob/main/examples/legacy/seq2seq). - -### Supported Architectures - -- `BartForConditionalGeneration` -- `FSMTForConditionalGeneration` (translation only) -- `MBartForConditionalGeneration` -- `MarianMTModel` -- `PegasusForConditionalGeneration` -- `T5ForConditionalGeneration` -- `MT5ForConditionalGeneration` - -`run_translation.py` is a lightweight examples of how to download and preprocess a dataset from the [🤗 Datasets](https://github.com/huggingface/datasets) library or use your own files (jsonlines or csv), then fine-tune one of the architectures above on it. - -For custom datasets in `jsonlines` format please see: https://huggingface.co/docs/datasets/loading_datasets#json-files -and you also will find examples of these below. - - -## With Trainer - -Here is an example of a translation fine-tuning with a MarianMT model: - -```bash -python run_translation.py \ - --model_name_or_path Helsinki-NLP/opus-mt-en-ro \ - --do_train \ - --do_eval \ - --source_lang en \ - --target_lang ro \ - --dataset_name wmt/wmt16 \ - --dataset_config_name ro-en \ - --output_dir /tmp/tst-translation \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -MBart and some T5 models require special handling. - -T5 models `google-t5/t5-small`, `google-t5/t5-base`, `google-t5/t5-large`, `google-t5/t5-3b` and `google-t5/t5-11b` must use an additional argument: `--source_prefix "translate {source_lang} to {target_lang}"`. For example: - -```bash -python run_translation.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --source_lang en \ - --target_lang ro \ - --source_prefix "translate English to Romanian: " \ - --dataset_name wmt/wmt16 \ - --dataset_config_name ro-en \ - --output_dir /tmp/tst-translation \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -If you get a terrible BLEU score, make sure that you didn't forget to use the `--source_prefix` argument. - -For the aforementioned group of T5 models it's important to remember that if you switch to a different language pair, make sure to adjust the source and target values in all 3 language-specific command line argument: `--source_lang`, `--target_lang` and `--source_prefix`. - -MBart models require a different format for `--source_lang` and `--target_lang` values, e.g. instead of `en` it expects `en_XX`, for `ro` it expects `ro_RO`. The full MBart specification for language codes can be found [here](https://huggingface.co/facebook/mbart-large-cc25). For example: - -```bash -python run_translation.py \ - --model_name_or_path facebook/mbart-large-en-ro \ - --do_train \ - --do_eval \ - --dataset_name wmt/wmt16 \ - --dataset_config_name ro-en \ - --source_lang en_XX \ - --target_lang ro_RO \ - --output_dir /tmp/tst-translation \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate - ``` - -And here is how you would use the translation finetuning on your own files, after adjusting the -values for the arguments `--train_file`, `--validation_file` to match your setup: - -```bash -python run_translation.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --source_lang en \ - --target_lang ro \ - --source_prefix "translate English to Romanian: " \ - --dataset_name wmt/wmt16 \ - --dataset_config_name ro-en \ - --train_file path_to_jsonlines_file \ - --validation_file path_to_jsonlines_file \ - --output_dir /tmp/tst-translation \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate -``` - -The task of translation supports only custom JSONLINES files, with each line being a dictionary with a key `"translation"` and its value another dictionary whose keys is the language pair. For example: - -```json -{ "translation": { "en": "Others have dismissed him as a joke.", "ro": "Alții l-au numit o glumă." } } -{ "translation": { "en": "And some are holding out for an implosion.", "ro": "Iar alții așteaptă implozia." } } -``` -Here the languages are Romanian (`ro`) and English (`en`). - -If you want to use a pre-processed dataset that leads to high BLEU scores, but for the `en-de` language pair, you can use `--dataset_name stas/wmt14-en-de-pre-processed`, as following: - -```bash -python run_translation.py \ - --model_name_or_path google-t5/t5-small \ - --do_train \ - --do_eval \ - --source_lang en \ - --target_lang de \ - --source_prefix "translate English to German: " \ - --dataset_name stas/wmt14-en-de-pre-processed \ - --output_dir /tmp/tst-translation \ - --per_device_train_batch_size=4 \ - --per_device_eval_batch_size=4 \ - --predict_with_generate - ``` - -## With Accelerate - -Based on the script [`run_translation_no_trainer.py`](https://github.com/huggingface/transformers/blob/main/examples/pytorch/translation/run_translation_no_trainer.py). - -Like `run_translation.py`, this script allows you to fine-tune any of the models supported on a -translation task, the main difference is that this -script exposes the bare training loop, to allow you to quickly experiment and add any customization you would like. - -It offers less options than the script with `Trainer` (for instance you can easily change the options for the optimizer -or the dataloaders directly in the script) but still run in a distributed setup, on TPU and supports mixed precision by -the mean of the [🤗 `Accelerate`](https://github.com/huggingface/accelerate) library. You can use the script normally -after installing it: - -```bash -pip install git+https://github.com/huggingface/accelerate -``` - -then - -```bash -python run_translation_no_trainer.py \ - --model_name_or_path Helsinki-NLP/opus-mt-en-ro \ - --source_lang en \ - --target_lang ro \ - --dataset_name wmt/wmt16 \ - --dataset_config_name ro-en \ - --output_dir ~/tmp/tst-translation -``` - -You can then use your usual launchers to run in it in a distributed environment, but the easiest way is to run - -```bash -accelerate config -``` - -and reply to the questions asked. Then - -```bash -accelerate test -``` - -that will check everything is ready for training. Finally, you can launch training with - -```bash -accelerate launch run_translation_no_trainer.py \ - --model_name_or_path Helsinki-NLP/opus-mt-en-ro \ - --source_lang en \ - --target_lang ro \ - --dataset_name wmt/wmt16 \ - --dataset_config_name ro-en \ - --output_dir ~/tmp/tst-translation -``` - -This command is the same and will work for: - -- a CPU-only setup -- a setup with one GPU -- a distributed training with several GPUs (single or multi node) -- a training on TPUs - -Note that this library is in alpha release so your feedback is more than welcome if you encounter any problem using it. diff --git a/examples/pytorch/translation/requirements.txt b/examples/pytorch/translation/requirements.txt deleted file mode 100644 index 9c9257430c06..000000000000 --- a/examples/pytorch/translation/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -accelerate >= 0.12.0 -datasets >= 1.8.0 -sentencepiece != 0.1.92 -protobuf -sacrebleu >= 1.4.12 -py7zr -torch >= 1.3 -evaluate \ No newline at end of file diff --git a/examples/pytorch/translation/run_translation.py b/examples/pytorch/translation/run_translation.py deleted file mode 100755 index 2c0574e48af0..000000000000 --- a/examples/pytorch/translation/run_translation.py +++ /dev/null @@ -1,693 +0,0 @@ -#!/usr/bin/env python -# Copyright The HuggingFace Team and The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "datasets >= 1.8.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "sacrebleu >= 1.4.12", -# "py7zr", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -""" -Fine-tuning the library models for sequence to sequence. -""" -# You can also adapt this script on your own sequence to sequence task. Pointers for this are left as comments. - -import logging -import os -import sys -from dataclasses import dataclass, field - -import datasets -import evaluate -import numpy as np -from datasets import load_dataset - -import transformers -from transformers import ( - AutoConfig, - AutoModelForSeq2SeqLM, - AutoTokenizer, - DataCollatorForSeq2Seq, - HfArgumentParser, - M2M100Tokenizer, - MBart50Tokenizer, - MBart50TokenizerFast, - MBartTokenizer, - MBartTokenizerFast, - Seq2SeqTrainer, - Seq2SeqTrainingArguments, - default_data_collator, - set_seed, -) -from transformers.tokenization_utils_sentencepiece import SentencePieceBackend -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/translation/requirements.txt") - -logger = logging.getLogger(__name__) - -# A list of all multilingual tokenizer which require src_lang and tgt_lang attributes. -MULTILINGUAL_TOKENIZERS = [MBartTokenizer, MBartTokenizerFast, MBart50Tokenizer, MBart50TokenizerFast, M2M100Tokenizer] - - -@dataclass -class ModelArguments: - """ - Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. - """ - - model_name_or_path: str = field( - metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} - ) - config_name: str | None = field( - default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"} - ) - tokenizer_name: str | None = field( - default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"} - ) - cache_dir: str | None = field( - default=None, - metadata={"help": "Where to store the pretrained models downloaded from huggingface.co"}, - ) - use_fast_tokenizer: bool = field( - default=True, - metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."}, - ) - model_revision: str = field( - default="main", - metadata={"help": "The specific model version to use (can be a branch name, tag name or commit id)."}, - ) - token: str = field( - default=None, - metadata={ - "help": ( - "The token to use as HTTP bearer authorization for remote files. If not specified, will use the token " - "generated when running `hf auth login` (stored in `~/.huggingface`)." - ) - }, - ) - trust_remote_code: bool = field( - default=False, - metadata={ - "help": ( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ) - }, - ) - - -@dataclass -class DataTrainingArguments: - """ - Arguments pertaining to what data we are going to input our model for training and eval. - """ - - source_lang: str = field(default=None, metadata={"help": "Source language id for translation."}) - target_lang: str = field(default=None, metadata={"help": "Target language id for translation."}) - - dataset_name: str | None = field( - default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."} - ) - dataset_config_name: str | None = field( - default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."} - ) - train_file: str | None = field(default=None, metadata={"help": "The input training data file (a jsonlines)."}) - validation_file: str | None = field( - default=None, - metadata={ - "help": "An optional input evaluation data file to evaluate the metrics (sacrebleu) on a jsonlines file." - }, - ) - test_file: str | None = field( - default=None, - metadata={"help": "An optional input test data file to evaluate the metrics (sacrebleu) on a jsonlines file."}, - ) - overwrite_cache: bool = field( - default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} - ) - preprocessing_num_workers: int | None = field( - default=None, - metadata={"help": "The number of processes to use for the preprocessing."}, - ) - max_source_length: int | None = field( - default=1024, - metadata={ - "help": ( - "The maximum total input sequence length after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - max_target_length: int | None = field( - default=128, - metadata={ - "help": ( - "The maximum total sequence length for target text after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded." - ) - }, - ) - val_max_target_length: int | None = field( - default=None, - metadata={ - "help": ( - "The maximum total sequence length for validation target text after tokenization. Sequences longer " - "than this will be truncated, sequences shorter will be padded. Will default to `max_target_length`. " - "This argument is also used to override the ``max_length`` param of ``model.generate``, which is used " - "during ``evaluate`` and ``predict``." - ) - }, - ) - pad_to_max_length: bool = field( - default=False, - metadata={ - "help": ( - "Whether to pad all samples to model maximum sentence length. " - "If False, will pad the samples dynamically when batching to the maximum length in the batch. More " - "efficient on GPU but very bad for TPU." - ) - }, - ) - max_train_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of training examples to this " - "value if set." - ) - }, - ) - max_eval_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of evaluation examples to this " - "value if set." - ) - }, - ) - max_predict_samples: int | None = field( - default=None, - metadata={ - "help": ( - "For debugging purposes or quicker training, truncate the number of prediction examples to this " - "value if set." - ) - }, - ) - num_beams: int | None = field( - default=1, - metadata={ - "help": ( - "Number of beams to use for evaluation. This argument will be passed to ``model.generate``, " - "which is used during ``evaluate`` and ``predict``." - ) - }, - ) - ignore_pad_token_for_loss: bool = field( - default=True, - metadata={ - "help": "Whether to ignore the tokens corresponding to padded labels in the loss computation or not." - }, - ) - source_prefix: str | None = field( - default=None, metadata={"help": "A prefix to add before every source text (useful for T5 models)."} - ) - forced_bos_token: str | None = field( - default=None, - metadata={ - "help": ( - "The token to force as the first generated token after the :obj:`decoder_start_token_id`.Useful for" - " multilingual models like :doc:`mBART <../model_doc/mbart>` where the first generated token needs to" - " be the target language token.(Usually it is the target language token)" - ) - }, - ) - - def __post_init__(self): - if self.dataset_name is None and self.train_file is None and self.validation_file is None: - raise ValueError("Need either a dataset name or a training/validation file.") - elif self.source_lang is None or self.target_lang is None: - raise ValueError("Need to specify the source language and the target language.") - - # accepting both json and jsonl file extensions, as - # many jsonlines files actually have a .json extension - valid_extensions = ["json", "jsonl"] - - if self.train_file is not None: - extension = self.train_file.split(".")[-1] - assert extension in valid_extensions, "`train_file` should be a jsonlines file." - if self.validation_file is not None: - extension = self.validation_file.split(".")[-1] - assert extension in valid_extensions, "`validation_file` should be a jsonlines file." - if self.val_max_target_length is None: - self.val_max_target_length = self.max_target_length - - -def main(): - # See all possible arguments in src/transformers/training_args.py - # or by passing the --help flag to this script. - # We now keep distinct sets of args, for a cleaner separation of concerns. - - parser = HfArgumentParser((ModelArguments, DataTrainingArguments, Seq2SeqTrainingArguments)) - if len(sys.argv) == 2 and sys.argv[1].endswith(".json"): - # If we pass only one argument to the script and it's the path to a json file, - # let's parse it to get our arguments. - model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1])) - else: - model_args, data_args, training_args = parser.parse_args_into_dataclasses() - - # Setup logging - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - handlers=[logging.StreamHandler(sys.stdout)], - ) - - if training_args.should_log: - # The default of training_args.log_level is passive, so we set log level at info here to have that default. - transformers.utils.logging.set_verbosity_info() - - log_level = training_args.get_process_log_level() - logger.setLevel(log_level) - datasets.utils.logging.set_verbosity(log_level) - transformers.utils.logging.set_verbosity(log_level) - transformers.utils.logging.enable_default_handler() - transformers.utils.logging.enable_explicit_format() - - # Log on each process the small summary: - logger.warning( - f"Process rank: {training_args.local_process_index}, device: {training_args.device}, n_gpu: {training_args.n_gpu}, " - + f"distributed training: {training_args.parallel_mode.value == 'distributed'}, 16-bits training: {training_args.fp16}" - ) - logger.info(f"Training/evaluation parameters {training_args}") - - if data_args.source_prefix is None and model_args.model_name_or_path in [ - "google-t5/t5-small", - "google-t5/t5-base", - "google-t5/t5-large", - "google-t5/t5-3b", - "google-t5/t5-11b", - ]: - logger.warning( - "You're running a t5 model but didn't provide a source prefix, which is expected, e.g. with " - "`--source_prefix 'translate English to German: ' `" - ) - - # Set seed before initializing model. - set_seed(training_args.seed) - - # Get the datasets: you can either provide your own JSON training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For translation, only JSON files are supported, with one field named "translation" containing two keys for the - # source and target languages (unless you adapt what follows). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if data_args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - data_args.dataset_name, - data_args.dataset_config_name, - cache_dir=model_args.cache_dir, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - else: - data_files = {} - if data_args.train_file is not None: - data_files["train"] = data_args.train_file - extension = data_args.train_file.split(".")[-1] - if data_args.validation_file is not None: - data_files["validation"] = data_args.validation_file - extension = data_args.validation_file.split(".")[-1] - if data_args.test_file is not None: - data_files["test"] = data_args.test_file - extension = data_args.test_file.split(".")[-1] - if extension == "jsonl": - builder_name = "json" # the "json" builder reads both .json and .jsonl files - else: - builder_name = extension # e.g. "parquet" - raw_datasets = load_dataset( - builder_name, - data_files=data_files, - cache_dir=model_args.cache_dir, - token=model_args.token, - ) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading. - - # Load pretrained model and tokenizer - # - # Distributed training: - # The .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - config = AutoConfig.from_pretrained( - model_args.config_name if model_args.config_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - tokenizer = AutoTokenizer.from_pretrained( - model_args.tokenizer_name if model_args.tokenizer_name else model_args.model_name_or_path, - cache_dir=model_args.cache_dir, - use_fast=model_args.use_fast_tokenizer, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - model = AutoModelForSeq2SeqLM.from_pretrained( - model_args.model_name_or_path, - from_tf=bool(".ckpt" in model_args.model_name_or_path), - config=config, - cache_dir=model_args.cache_dir, - revision=model_args.model_revision, - token=model_args.token, - trust_remote_code=model_args.trust_remote_code, - ) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Set decoder_start_token_id - if model.config.decoder_start_token_id is None and isinstance( - tokenizer, (MBartTokenizer, MBartTokenizerFast, SentencePieceBackend) - ): - if isinstance(tokenizer, MBartTokenizer): - model.config.decoder_start_token_id = tokenizer.lang_code_to_id[data_args.target_lang] - else: - model.config.decoder_start_token_id = tokenizer.convert_tokens_to_ids(data_args.target_lang) - - if model.config.decoder_start_token_id is None: - raise ValueError("Make sure that `config.decoder_start_token_id` is correctly defined") - - prefix = data_args.source_prefix if data_args.source_prefix is not None else "" - - # Preprocessing the datasets. - # We need to tokenize inputs and targets. - if training_args.do_train: - column_names = raw_datasets["train"].column_names - elif training_args.do_eval: - column_names = raw_datasets["validation"].column_names - elif training_args.do_predict: - column_names = raw_datasets["test"].column_names - else: - logger.info("There is nothing to do. Please pass `do_train`, `do_eval` and/or `do_predict`.") - return - - # For translation we set the codes of our source and target languages (only useful for mBART, the others will - # ignore those attributes). - if isinstance(tokenizer, tuple(MULTILINGUAL_TOKENIZERS)): - assert data_args.target_lang is not None and data_args.source_lang is not None, ( - f"{tokenizer.__class__.__name__} is a multilingual tokenizer which requires --source_lang and " - "--target_lang arguments." - ) - - tokenizer.src_lang = data_args.source_lang - tokenizer.tgt_lang = data_args.target_lang - - # For multilingual translation models like mBART-50 and M2M100 we need to force the target language token - # as the first generated token. We ask the user to explicitly provide this as --forced_bos_token argument. - forced_bos_token_id = ( - tokenizer.lang_code_to_id[data_args.forced_bos_token] if data_args.forced_bos_token is not None else None - ) - model.config.forced_bos_token_id = forced_bos_token_id - - # Get the language codes for input/target. - source_lang = data_args.source_lang.split("_")[0] - target_lang = data_args.target_lang.split("_")[0] - - # Check the whether the source target length fits in the model, if it has absolute positional embeddings - if ( - hasattr(model.config, "max_position_embeddings") - and not hasattr(model.config, "relative_attention_max_distance") - and model.config.max_position_embeddings < data_args.max_source_length - ): - raise ValueError( - f"`--max_source_length` is set to {data_args.max_source_length}, but the model only has" - f" {model.config.max_position_embeddings} position encodings. Consider either reducing" - f" `--max_source_length` to {model.config.max_position_embeddings} or using a model with larger position " - "embeddings" - ) - - # Temporarily set max_target_length for training. - max_target_length = data_args.max_target_length - padding = "max_length" if data_args.pad_to_max_length else False - - if training_args.label_smoothing_factor > 0 and not hasattr(model, "prepare_decoder_input_ids_from_labels"): - logger.warning( - "label_smoothing is enabled but the `prepare_decoder_input_ids_from_labels` method is not defined for " - f"`{model.__class__.__name__}`. This will lead to loss being calculated twice and will take up more memory" - ) - - def preprocess_function(examples): - inputs = [ex[source_lang] for ex in examples["translation"]] - targets = [ex[target_lang] for ex in examples["translation"]] - inputs = [prefix + inp for inp in inputs] - model_inputs = tokenizer(inputs, max_length=data_args.max_source_length, padding=padding, truncation=True) - - # Tokenize targets with the `text_target` keyword argument - labels = tokenizer(text_target=targets, max_length=max_target_length, padding=padding, truncation=True) - - # If we are padding here, replace all tokenizer.pad_token_id in the labels by -100 when we want to ignore - # padding in the loss. - if padding == "max_length" and data_args.ignore_pad_token_for_loss: - labels["input_ids"] = [ - [(l if l != tokenizer.pad_token_id else -100) for l in label] for label in labels["input_ids"] - ] - - model_inputs["labels"] = labels["input_ids"] - return model_inputs - - if training_args.do_train: - if "train" not in raw_datasets: - raise ValueError("--do_train requires a train dataset") - train_dataset = raw_datasets["train"] - if data_args.max_train_samples is not None: - max_train_samples = min(len(train_dataset), data_args.max_train_samples) - train_dataset = train_dataset.select(range(max_train_samples)) - with training_args.main_process_first(desc="train dataset map pre-processing"): - train_dataset = train_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on train dataset", - ) - - if training_args.do_eval: - max_target_length = data_args.val_max_target_length - if "validation" not in raw_datasets: - raise ValueError("--do_eval requires a validation dataset") - eval_dataset = raw_datasets["validation"] - if data_args.max_eval_samples is not None: - max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples) - eval_dataset = eval_dataset.select(range(max_eval_samples)) - with training_args.main_process_first(desc="validation dataset map pre-processing"): - eval_dataset = eval_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on validation dataset", - ) - - if training_args.do_predict: - max_target_length = data_args.val_max_target_length - if "test" not in raw_datasets: - raise ValueError("--do_predict requires a test dataset") - predict_dataset = raw_datasets["test"] - if data_args.max_predict_samples is not None: - max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples) - predict_dataset = predict_dataset.select(range(max_predict_samples)) - with training_args.main_process_first(desc="prediction dataset map pre-processing"): - predict_dataset = predict_dataset.map( - preprocess_function, - batched=True, - num_proc=data_args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not data_args.overwrite_cache, - desc="Running tokenizer on prediction dataset", - ) - - # Data collator - label_pad_token_id = -100 if data_args.ignore_pad_token_for_loss else tokenizer.pad_token_id - if data_args.pad_to_max_length: - data_collator = default_data_collator - else: - data_collator = DataCollatorForSeq2Seq( - tokenizer, - model=model, - label_pad_token_id=label_pad_token_id, - pad_to_multiple_of=8 if training_args.fp16 else None, - ) - - # Metric - metric = evaluate.load("sacrebleu", cache_dir=model_args.cache_dir) - - def postprocess_text(preds, labels): - preds = [pred.strip() for pred in preds] - labels = [[label.strip()] for label in labels] - - return preds, labels - - def compute_metrics(eval_preds): - preds, labels = eval_preds - if isinstance(preds, tuple): - preds = preds[0] - # Replace -100s used for padding as we can't decode them - preds = np.where(preds != -100, preds, tokenizer.pad_token_id) - decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True) - labels = np.where(labels != -100, labels, tokenizer.pad_token_id) - decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) - - # Some simple post-processing - decoded_preds, decoded_labels = postprocess_text(decoded_preds, decoded_labels) - - result = metric.compute(predictions=decoded_preds, references=decoded_labels) - result = {"bleu": result["score"]} - - prediction_lens = [np.count_nonzero(pred != tokenizer.pad_token_id) for pred in preds] - result["gen_len"] = np.mean(prediction_lens) - result = {k: round(v, 4) for k, v in result.items()} - return result - - # Initialize our Trainer - trainer = Seq2SeqTrainer( - model=model, - args=training_args, - train_dataset=train_dataset if training_args.do_train else None, - eval_dataset=eval_dataset if training_args.do_eval else None, - processing_class=tokenizer, - data_collator=data_collator, - compute_metrics=compute_metrics if training_args.predict_with_generate else None, - ) - - # Training - if training_args.do_train: - checkpoint = None - if training_args.resume_from_checkpoint is not None: - checkpoint = training_args.resume_from_checkpoint - train_result = trainer.train(resume_from_checkpoint=checkpoint) - trainer.save_model() # Saves the tokenizer too for easy upload - - metrics = train_result.metrics - max_train_samples = ( - data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset) - ) - metrics["train_samples"] = min(max_train_samples, len(train_dataset)) - - trainer.log_metrics("train", metrics) - trainer.save_metrics("train", metrics) - trainer.save_state() - - # Evaluation - results = {} - max_length = ( - training_args.generation_max_length - if training_args.generation_max_length is not None - else data_args.val_max_target_length - ) - num_beams = data_args.num_beams if data_args.num_beams is not None else training_args.generation_num_beams - if training_args.do_eval: - logger.info("*** Evaluate ***") - - metrics = trainer.evaluate(max_length=max_length, num_beams=num_beams, metric_key_prefix="eval") - max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset) - metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset)) - - trainer.log_metrics("eval", metrics) - trainer.save_metrics("eval", metrics) - - if training_args.do_predict: - logger.info("*** Predict ***") - - predict_results = trainer.predict( - predict_dataset, metric_key_prefix="predict", max_length=max_length, num_beams=num_beams - ) - metrics = predict_results.metrics - max_predict_samples = ( - data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset) - ) - metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset)) - - trainer.log_metrics("predict", metrics) - trainer.save_metrics("predict", metrics) - - if trainer.is_world_process_zero(): - if training_args.predict_with_generate: - predictions = predict_results.predictions - predictions = np.where(predictions != -100, predictions, tokenizer.pad_token_id) - predictions = tokenizer.batch_decode( - predictions, skip_special_tokens=True, clean_up_tokenization_spaces=True - ) - predictions = [pred.strip() for pred in predictions] - output_prediction_file = os.path.join(training_args.output_dir, "generated_predictions.txt") - with open(output_prediction_file, "w", encoding="utf-8") as writer: - writer.write("\n".join(predictions)) - - kwargs = {"finetuned_from": model_args.model_name_or_path, "tasks": "translation"} - if data_args.dataset_name is not None: - kwargs["dataset_tags"] = data_args.dataset_name - if data_args.dataset_config_name is not None: - kwargs["dataset_args"] = data_args.dataset_config_name - kwargs["dataset"] = f"{data_args.dataset_name} {data_args.dataset_config_name}" - else: - kwargs["dataset"] = data_args.dataset_name - - languages = [l for l in [data_args.source_lang, data_args.target_lang] if l is not None] - if len(languages) > 0: - kwargs["language"] = languages - - if training_args.push_to_hub: - trainer.push_to_hub(**kwargs) - else: - trainer.create_model_card(**kwargs) - - trainer.end() - - return results - - -def _mp_fn(index): - # For xla_spawn (TPUs) - main() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/translation/run_translation_no_trainer.py b/examples/pytorch/translation/run_translation_no_trainer.py deleted file mode 100644 index 701c5ccb2d2e..000000000000 --- a/examples/pytorch/translation/run_translation_no_trainer.py +++ /dev/null @@ -1,800 +0,0 @@ -#!/usr/bin/env python -# Copyright The HuggingFace Team and The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# /// script -# dependencies = [ -# "transformers @ git+https://github.com/huggingface/transformers.git", -# "accelerate >= 0.12.0", -# "datasets >= 1.8.0", -# "sentencepiece != 0.1.92", -# "protobuf", -# "sacrebleu >= 1.4.12", -# "py7zr", -# "torch >= 1.3", -# "evaluate", -# ] -# /// - -""" -Fine-tuning a 🤗 Transformers model on text translation. -""" -# You can also adapt this script on your own text translation task. Pointers for this are left as comments. - -import argparse -import json -import logging -import math -import os -import random -from pathlib import Path - -import datasets -import evaluate -import numpy as np -import torch -from accelerate import Accelerator -from accelerate.logging import get_logger -from accelerate.utils import set_seed -from datasets import load_dataset -from huggingface_hub import HfApi -from torch.utils.data import DataLoader -from tqdm.auto import tqdm - -import transformers -from transformers import ( - CONFIG_MAPPING, - MODEL_MAPPING, - AutoConfig, - AutoModelForSeq2SeqLM, - AutoTokenizer, - DataCollatorForSeq2Seq, - MBartTokenizer, - MBartTokenizerFast, - SchedulerType, - default_data_collator, - get_scheduler, -) -from transformers.utils import check_min_version -from transformers.utils.versions import require_version - - -# Will error if the minimal version of Transformers is not installed. Remove at your own risks. -check_min_version("4.57.0.dev0") - -logger = get_logger(__name__) -require_version("datasets>=1.8.0", "To fix: pip install -r examples/pytorch/translation/requirements.txt") - -# You should update this to your particular problem to have better documentation of `model_type` -MODEL_CONFIG_CLASSES = list(MODEL_MAPPING.keys()) -MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES) - - -# Parsing input arguments -def parse_args(): - parser = argparse.ArgumentParser(description="Finetune a transformers model on a text classification task") - parser.add_argument( - "--dataset_name", - type=str, - default=None, - help="The name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--predict_with_generate", - type=bool, - default=True, - help="", - ) - parser.add_argument( - "--dataset_config_name", - type=str, - default=None, - help="The configuration name of the dataset to use (via the datasets library).", - ) - parser.add_argument( - "--train_file", type=str, default=None, help="A csv or a json file containing the training data." - ) - - parser.add_argument( - "--num_beams", - type=int, - default=None, - help=( - "Number of beams to use for evaluation. This argument will be " - "passed to ``model.generate``, which is used during ``evaluate`` and ``predict``." - ), - ) - - parser.add_argument( - "--max_source_length", - type=int, - default=1024, - help=( - "The maximum total input sequence length after " - "tokenization.Sequences longer than this will be truncated, sequences shorter will be padded." - ), - ) - parser.add_argument( - "--max_target_length", - type=int, - default=128, - help=( - "The maximum total sequence length for target text after " - "tokenization. Sequences longer than this will be truncated, sequences shorter will be padded " - "during ``evaluate`` and ``predict``." - ), - ) - parser.add_argument( - "--val_max_target_length", - type=int, - default=None, - help=( - "The maximum total sequence length for validation " - "target text after tokenization.Sequences longer than this will be truncated, sequences shorter will be " - "padded. Will default to `max_target_length`.This argument is also used to override the ``max_length`` " - "param of ``model.generate``, which is used during ``evaluate`` and ``predict``." - ), - ) - parser.add_argument( - "--pad_to_max_length", - type=bool, - default=False, - help=( - "Whether to pad all samples to model maximum sentence " - "length. If False, will pad the samples dynamically when batching to the maximum length in the batch. More " - "efficient on GPU but very bad for TPU." - ), - ) - parser.add_argument( - "--validation_file", type=str, default=None, help="A csv or a json file containing the validation data." - ) - parser.add_argument( - "--ignore_pad_token_for_loss", - type=bool, - default=True, - help="Whether to ignore the tokens corresponding to padded labels in the loss computation or not.", - ) - parser.add_argument("--source_lang", type=str, default=None, help="Source language id for translation.") - parser.add_argument("--target_lang", type=str, default=None, help="Target language id for translation.") - parser.add_argument( - "--source_prefix", - type=str, - default=None, - help="A prefix to add before every source text (useful for T5 models).", - ) - parser.add_argument( - "--preprocessing_num_workers", - type=int, - default=None, - help="The number of processes to use for the preprocessing.", - ) - parser.add_argument( - "--overwrite_cache", action="store_true", help="Overwrite the cached training and evaluation sets" - ) - parser.add_argument( - "--max_length", - type=int, - default=128, - help=( - "The maximum total input sequence length after tokenization. Sequences longer than this will be truncated," - " sequences shorter will be padded if `--pad_to_max_length` is passed." - ), - ) - parser.add_argument( - "--model_name_or_path", - type=str, - help="Path to pretrained model or model identifier from huggingface.co/models.", - required=False, - ) - parser.add_argument( - "--config_name", - type=str, - default=None, - help="Pretrained config name or path if not the same as model_name", - ) - parser.add_argument( - "--tokenizer_name", - type=str, - default=None, - help="Pretrained tokenizer name or path if not the same as model_name", - ) - parser.add_argument( - "--use_slow_tokenizer", - action="store_true", - help="If passed, will use a slow tokenizer (not backed by the Hugging Face Tokenizers library).", - ) - parser.add_argument( - "--per_device_train_batch_size", - type=int, - default=8, - help="Batch size (per device) for the training dataloader.", - ) - parser.add_argument( - "--per_device_eval_batch_size", - type=int, - default=8, - help="Batch size (per device) for the evaluation dataloader.", - ) - parser.add_argument( - "--learning_rate", - type=float, - default=5e-5, - help="Initial learning rate (after the potential warmup period) to use.", - ) - parser.add_argument("--weight_decay", type=float, default=0.0, help="Weight decay to use.") - parser.add_argument("--num_train_epochs", type=int, default=3, help="Total number of training epochs to perform.") - parser.add_argument( - "--max_train_steps", - type=int, - default=None, - help="Total number of training steps to perform. If provided, overrides num_train_epochs.", - ) - parser.add_argument( - "--gradient_accumulation_steps", - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.", - ) - parser.add_argument( - "--lr_scheduler_type", - type=SchedulerType, - default="linear", - help="The scheduler type to use.", - choices=["linear", "cosine", "cosine_with_restarts", "polynomial", "constant", "constant_with_warmup"], - ) - parser.add_argument( - "--num_warmup_steps", type=int, default=0, help="Number of steps for the warmup in the lr scheduler." - ) - parser.add_argument("--output_dir", type=str, default=None, help="Where to store the final model.") - parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") - parser.add_argument( - "--model_type", - type=str, - default=None, - help="Model type to use if training from scratch.", - choices=MODEL_TYPES, - ) - parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") - parser.add_argument( - "--hub_model_id", type=str, help="The name of the repository to keep in sync with the local `output_dir`." - ) - parser.add_argument("--hub_token", type=str, help="The token to use to push to the Model Hub.") - parser.add_argument( - "--trust_remote_code", - action="store_true", - help=( - "Whether to trust the execution of code from datasets/models defined on the Hub." - " This option should only be set to `True` for repositories you trust and in which you have read the" - " code, as it will execute code present on the Hub on your local machine." - ), - ) - parser.add_argument( - "--checkpointing_steps", - type=str, - default=None, - help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch.", - ) - parser.add_argument( - "--resume_from_checkpoint", - type=str, - default=None, - help="If the training should continue from a checkpoint folder.", - ) - parser.add_argument( - "--with_tracking", - action="store_true", - help="Whether to enable experiment trackers for logging.", - ) - parser.add_argument( - "--report_to", - type=str, - default="all", - help=( - 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`,' - ' `"wandb"`, `"comet_ml"` and `"clearml"`. Use `"all"` (default) to report to all integrations. ' - "Only applicable when `--with_tracking` is passed." - ), - ) - args = parser.parse_args() - - # Sanity checks - - if args.dataset_name is None and args.train_file is None and args.validation_file is None: - raise ValueError("Need either a task name or a training/validation file.") - - if args.train_file is not None: - extension = args.train_file.split(".")[-1] - assert extension in ["csv", "json"], "`train_file` should be a csv or a json file." - if args.validation_file is not None: - extension = args.validation_file.split(".")[-1] - assert extension in ["csv", "json"], "`validation_file` should be a csv or a json file." - - if args.push_to_hub: - assert args.output_dir is not None, "Need an `output_dir` to create a repo when `--push_to_hub` is passed." - - return args - - -def main(): - # Parse the arguments - args = parse_args() - - # Initialize the accelerator. We will let the accelerator handle device placement for us in this example. - # If we're using tracking, we also need to initialize it here and it will by default pick up all supported trackers - # in the environment - accelerator = ( - Accelerator(log_with=args.report_to, project_dir=args.output_dir) if args.with_tracking else Accelerator() - ) - - # Make one log on every process with the configuration for debugging. - logging.basicConfig( - format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", - datefmt="%m/%d/%Y %H:%M:%S", - level=logging.INFO, - ) - logger.info(accelerator.state, main_process_only=False) - if accelerator.is_local_main_process: - datasets.utils.logging.set_verbosity_warning() - transformers.utils.logging.set_verbosity_info() - else: - datasets.utils.logging.set_verbosity_error() - transformers.utils.logging.set_verbosity_error() - - # If passed along, set the training seed now. - if args.seed is not None: - set_seed(args.seed) - - # Handle the repository creation - if accelerator.is_main_process: - if args.push_to_hub: - # Retrieve of infer repo_name - repo_name = args.hub_model_id - if repo_name is None: - repo_name = Path(args.output_dir).absolute().name - # Create repo and retrieve repo_id - api = HfApi() - repo_id = api.create_repo(repo_name, exist_ok=True, token=args.hub_token).repo_id - - with open(os.path.join(args.output_dir, ".gitignore"), "w+", encoding="utf-8") as gitignore: - if "step_*" not in gitignore: - gitignore.write("step_*\n") - if "epoch_*" not in gitignore: - gitignore.write("epoch_*\n") - elif args.output_dir is not None: - os.makedirs(args.output_dir, exist_ok=True) - accelerator.wait_for_everyone() - - # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below) - # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/ - # (the dataset will be downloaded automatically from the datasets Hub). - # - # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called - # 'text' is found. You can easily tweak this behavior (see below). - # - # In distributed training, the load_dataset function guarantee that only one local process can concurrently - # download the dataset. - if args.dataset_name is not None: - # Downloading and loading a dataset from the hub. - raw_datasets = load_dataset( - args.dataset_name, args.dataset_config_name, trust_remote_code=args.trust_remote_code - ) - else: - data_files = {} - if args.train_file is not None: - data_files["train"] = args.train_file - extension = args.train_file.split(".")[-1] - if args.validation_file is not None: - data_files["validation"] = args.validation_file - extension = args.validation_file.split(".")[-1] - raw_datasets = load_dataset(extension, data_files=data_files) - # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at - # https://huggingface.co/docs/datasets/loading_datasets. - - # Load pretrained model and tokenizer - # - # In distributed training, the .from_pretrained methods guarantee that only one local process can concurrently - # download model & vocab. - if args.config_name: - config = AutoConfig.from_pretrained(args.config_name, trust_remote_code=args.trust_remote_code) - elif args.model_name_or_path: - config = AutoConfig.from_pretrained(args.model_name_or_path, trust_remote_code=args.trust_remote_code) - else: - config = CONFIG_MAPPING[args.model_type]() - logger.warning("You are instantiating a new config instance from scratch.") - - if args.tokenizer_name: - tokenizer = AutoTokenizer.from_pretrained( - args.tokenizer_name, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - elif args.model_name_or_path: - tokenizer = AutoTokenizer.from_pretrained( - args.model_name_or_path, use_fast=not args.use_slow_tokenizer, trust_remote_code=args.trust_remote_code - ) - else: - raise ValueError( - "You are instantiating a new tokenizer from scratch. This is not supported by this script. " - "You can do it from another script, save it, and load it from here, using --tokenizer_name." - ) - - if args.model_name_or_path: - model = AutoModelForSeq2SeqLM.from_pretrained( - args.model_name_or_path, - from_tf=bool(".ckpt" in args.model_name_or_path), - config=config, - trust_remote_code=args.trust_remote_code, - ) - else: - logger.info("Training new model from scratch") - model = AutoModelForSeq2SeqLM.from_config(config, trust_remote_code=args.trust_remote_code) - - # We resize the embeddings only when necessary to avoid index errors. If you are creating a model from scratch - # on a small vocab and want a smaller embedding size, remove this test. - embedding_size = model.get_input_embeddings().weight.shape[0] - if len(tokenizer) > embedding_size: - model.resize_token_embeddings(len(tokenizer)) - - # Set decoder_start_token_id - if model.config.decoder_start_token_id is None and isinstance(tokenizer, (MBartTokenizer, MBartTokenizerFast)): - assert args.target_lang is not None and args.source_lang is not None, ( - "mBart requires --target_lang and --source_lang" - ) - if isinstance(tokenizer, MBartTokenizer): - model.config.decoder_start_token_id = tokenizer.lang_code_to_id[args.target_lang] - else: - model.config.decoder_start_token_id = tokenizer.convert_tokens_to_ids(args.target_lang) - - if model.config.decoder_start_token_id is None: - raise ValueError("Make sure that `config.decoder_start_token_id` is correctly defined") - - prefix = args.source_prefix if args.source_prefix is not None else "" - - # Preprocessing the datasets. - # First we tokenize all the texts. - column_names = raw_datasets["train"].column_names - - # For translation we set the codes of our source and target languages (only useful for mBART, the others will - # ignore those attributes). - if isinstance(tokenizer, (MBartTokenizer, MBartTokenizerFast)): - if args.source_lang is not None: - tokenizer.src_lang = args.source_lang - if args.target_lang is not None: - tokenizer.tgt_lang = args.target_lang - - # Get the language codes for input/target. - source_lang = args.source_lang.split("_")[0] - target_lang = args.target_lang.split("_")[0] - - padding = "max_length" if args.pad_to_max_length else False - - # Temporarily set max_target_length for training. - max_target_length = args.max_target_length - padding = "max_length" if args.pad_to_max_length else False - - def preprocess_function(examples): - inputs = [ex[source_lang] for ex in examples["translation"]] - targets = [ex[target_lang] for ex in examples["translation"]] - inputs = [prefix + inp for inp in inputs] - model_inputs = tokenizer(inputs, max_length=args.max_source_length, padding=padding, truncation=True) - - # Tokenize targets with the `text_target` keyword argument - labels = tokenizer(text_target=targets, max_length=max_target_length, padding=padding, truncation=True) - - # If we are padding here, replace all tokenizer.pad_token_id in the labels by -100 when we want to ignore - # padding in the loss. - if padding == "max_length" and args.ignore_pad_token_for_loss: - labels["input_ids"] = [ - [(l if l != tokenizer.pad_token_id else -100) for l in label] for label in labels["input_ids"] - ] - - model_inputs["labels"] = labels["input_ids"] - return model_inputs - - with accelerator.main_process_first(): - processed_datasets = raw_datasets.map( - preprocess_function, - batched=True, - num_proc=args.preprocessing_num_workers, - remove_columns=column_names, - load_from_cache_file=not args.overwrite_cache, - desc="Running tokenizer on dataset", - ) - - train_dataset = processed_datasets["train"] - eval_dataset = processed_datasets["validation"] - - # Log a few random samples from the training set: - for index in random.sample(range(len(train_dataset)), 3): - logger.info(f"Sample {index} of the training set: {train_dataset[index]}.") - - # DataLoaders creation: - label_pad_token_id = -100 if args.ignore_pad_token_for_loss else tokenizer.pad_token_id - if args.pad_to_max_length: - # If padding was already done ot max length, we use the default data collator that will just convert everything - # to tensors. - data_collator = default_data_collator - else: - # Otherwise, `DataCollatorWithPadding` will apply dynamic padding for us (by padding to the maximum length of - # the samples passed). When using mixed precision, we add `pad_to_multiple_of=8` to pad all tensors to multiple - # of 8s, which will enable the use of Tensor Cores on NVIDIA hardware with compute capability >= 7.5 (Volta). - # For fp8, we pad to multiple of 16. - if accelerator.mixed_precision == "fp8": - pad_to_multiple_of = 16 - elif accelerator.mixed_precision != "no": - pad_to_multiple_of = 8 - else: - pad_to_multiple_of = None - data_collator = DataCollatorForSeq2Seq( - tokenizer, - model=model, - label_pad_token_id=label_pad_token_id, - pad_to_multiple_of=pad_to_multiple_of, - ) - - train_dataloader = DataLoader( - train_dataset, shuffle=True, collate_fn=data_collator, batch_size=args.per_device_train_batch_size - ) - eval_dataloader = DataLoader(eval_dataset, collate_fn=data_collator, batch_size=args.per_device_eval_batch_size) - - # Optimizer - # Split weights in two groups, one with weight decay and the other not. - no_decay = ["bias", "LayerNorm.weight", "layer_norm.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": args.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, - }, - ] - optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.learning_rate) - - # Scheduler and math around the number of training steps. - overrode_max_train_steps = False - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if args.max_train_steps is None: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - overrode_max_train_steps = True - - lr_scheduler = get_scheduler( - name=args.lr_scheduler_type, - optimizer=optimizer, - num_warmup_steps=args.num_warmup_steps, - num_training_steps=args.max_train_steps, - ) - - # Prepare everything with our `accelerator`. - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) - - # We need to recalculate our total training steps as the size of the training dataloader may have changed. - num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) - if overrode_max_train_steps: - args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch - # Afterwards we recalculate our number of training epochs - args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) - # Figure out how many steps we should save the Accelerator states - checkpointing_steps = args.checkpointing_steps - if checkpointing_steps is not None and checkpointing_steps.isdigit(): - checkpointing_steps = int(checkpointing_steps) - - # We need to initialize the trackers we use, and also store our configuration. - # We initialize the trackers only on main process because `accelerator.log` - # only logs on main process and we don't want empty logs/runs on other processes. - if args.with_tracking: - if accelerator.is_main_process: - experiment_config = vars(args) - # TensorBoard cannot log Enums, need the raw value - experiment_config["lr_scheduler_type"] = experiment_config["lr_scheduler_type"].value - accelerator.init_trackers("translation_no_trainer", experiment_config) - - metric = evaluate.load("sacrebleu") - - def postprocess_text(preds, labels): - preds = [pred.strip() for pred in preds] - labels = [[label.strip()] for label in labels] - - return preds, labels - - # Train! - total_batch_size = args.per_device_train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps - - logger.info("***** Running training *****") - logger.info(f" Num examples = {len(train_dataset)}") - logger.info(f" Num Epochs = {args.num_train_epochs}") - logger.info(f" Instantaneous batch size per device = {args.per_device_train_batch_size}") - logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") - logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") - logger.info(f" Total optimization steps = {args.max_train_steps}") - # Only show the progress bar once on each machine. - progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process) - completed_steps = 0 - starting_epoch = 0 - - # Potentially load in the weights and states from a previous save - if args.resume_from_checkpoint: - if args.resume_from_checkpoint is not None or args.resume_from_checkpoint != "": - checkpoint_path = args.resume_from_checkpoint - path = os.path.basename(args.resume_from_checkpoint) - else: - # Get the most recent checkpoint - dirs = [f.name for f in os.scandir(os.getcwd()) if f.is_dir()] - dirs.sort(key=os.path.getctime) - path = dirs[-1] # Sorts folders by date modified, most recent checkpoint is the last - checkpoint_path = path - path = os.path.basename(checkpoint_path) - - accelerator.print(f"Resumed from checkpoint: {checkpoint_path}") - accelerator.load_state(checkpoint_path) - # Extract `epoch_{i}` or `step_{i}` - training_difference = os.path.splitext(path)[0] - - if "epoch" in training_difference: - starting_epoch = int(training_difference.replace("epoch_", "")) + 1 - resume_step = None - completed_steps = starting_epoch * num_update_steps_per_epoch - else: - # need to multiply `gradient_accumulation_steps` to reflect real steps - resume_step = int(training_difference.replace("step_", "")) * args.gradient_accumulation_steps - starting_epoch = resume_step // len(train_dataloader) - completed_steps = resume_step // args.gradient_accumulation_steps - resume_step -= starting_epoch * len(train_dataloader) - - # update the progress_bar if load from checkpoint - progress_bar.update(completed_steps) - - for epoch in range(starting_epoch, args.num_train_epochs): - model.train() - if args.with_tracking: - total_loss = 0 - if args.resume_from_checkpoint and epoch == starting_epoch and resume_step is not None: - # We skip the first `n` batches in the dataloader when resuming from a checkpoint - active_dataloader = accelerator.skip_first_batches(train_dataloader, resume_step) - else: - active_dataloader = train_dataloader - for step, batch in enumerate(active_dataloader): - outputs = model(**batch) - loss = outputs.loss - # We keep track of the loss at each epoch - if args.with_tracking: - total_loss += loss.detach().float() - loss = loss / args.gradient_accumulation_steps - accelerator.backward(loss) - if step % args.gradient_accumulation_steps == 0 or step == len(train_dataloader) - 1: - optimizer.step() - lr_scheduler.step() - optimizer.zero_grad() - progress_bar.update(1) - completed_steps += 1 - - if isinstance(checkpointing_steps, int): - if completed_steps % checkpointing_steps == 0 and accelerator.sync_gradients: - output_dir = f"step_{completed_steps}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if completed_steps >= args.max_train_steps: - break - - model.eval() - - if args.val_max_target_length is None: - args.val_max_target_length = args.max_target_length - - gen_kwargs = { - "max_length": args.val_max_target_length if args is not None else config.max_length, - "num_beams": args.num_beams, - } - samples_seen = 0 - for step, batch in enumerate(eval_dataloader): - with torch.no_grad(): - generated_tokens = accelerator.unwrap_model(model).generate( - batch["input_ids"], - attention_mask=batch["attention_mask"], - **gen_kwargs, - ) - - generated_tokens = accelerator.pad_across_processes( - generated_tokens, dim=1, pad_index=tokenizer.pad_token_id - ) - labels = batch["labels"] - if not args.pad_to_max_length: - # If we did not pad to max length, we need to pad the labels too - labels = accelerator.pad_across_processes(batch["labels"], dim=1, pad_index=tokenizer.pad_token_id) - - generated_tokens = accelerator.gather(generated_tokens).cpu().numpy() - labels = accelerator.gather(labels).cpu().numpy() - - if args.ignore_pad_token_for_loss: - # Replace -100 in the labels as we can't decode them. - labels = np.where(labels != -100, labels, tokenizer.pad_token_id) - - decoded_preds = tokenizer.batch_decode(generated_tokens, skip_special_tokens=True) - decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) - - decoded_preds, decoded_labels = postprocess_text(decoded_preds, decoded_labels) - - # If we are in a multiprocess environment, the last batch has duplicates - if accelerator.num_processes > 1: - if step == len(eval_dataloader) - 1: - decoded_preds = decoded_preds[: len(eval_dataloader.dataset) - samples_seen] - decoded_labels = decoded_labels[: len(eval_dataloader.dataset) - samples_seen] - else: - samples_seen += len(decoded_labels) - - metric.add_batch(predictions=decoded_preds, references=decoded_labels) - eval_metric = metric.compute() - logger.info({"bleu": eval_metric["score"]}) - - if args.with_tracking: - accelerator.log( - { - "bleu": eval_metric["score"], - "train_loss": total_loss.item() / len(train_dataloader), - "epoch": epoch, - "step": completed_steps, - }, - step=completed_steps, - ) - - if args.push_to_hub and epoch < args.num_train_epochs - 1: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - api.upload_folder( - commit_message=f"Training in progress epoch {epoch}", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - - if args.checkpointing_steps == "epoch": - output_dir = f"epoch_{epoch}" - if args.output_dir is not None: - output_dir = os.path.join(args.output_dir, output_dir) - accelerator.save_state(output_dir) - - if args.output_dir is not None: - accelerator.wait_for_everyone() - unwrapped_model = accelerator.unwrap_model(model) - unwrapped_model.save_pretrained( - args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save - ) - if accelerator.is_main_process: - tokenizer.save_pretrained(args.output_dir) - if args.push_to_hub: - api.upload_folder( - commit_message="End of training", - folder_path=args.output_dir, - repo_id=repo_id, - repo_type="model", - token=args.hub_token, - ) - with open(os.path.join(args.output_dir, "all_results.json"), "w", encoding="utf-8") as f: - json.dump({"eval_bleu": eval_metric["score"]}, f) - - accelerator.wait_for_everyone() - accelerator.end_training() - - -if __name__ == "__main__": - main() diff --git a/examples/pytorch/xla_spawn.py b/examples/pytorch/xla_spawn.py deleted file mode 100644 index 70fad50df2df..000000000000 --- a/examples/pytorch/xla_spawn.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2020 The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -A simple launcher script for TPU training - -Inspired by https://github.com/pytorch/pytorch/blob/master/torch/distributed/launch.py - -:: - >>> python xla_spawn.py --num_cores=NUM_CORES_YOU_HAVE - YOUR_TRAINING_SCRIPT.py (--arg1 --arg2 --arg3 and all other - arguments of your training script) - -""" - -import importlib -import sys -from argparse import REMAINDER, ArgumentParser -from pathlib import Path - -import torch_xla.distributed.xla_multiprocessing as xmp - - -def parse_args(): - """ - Helper function parsing the command line options - @retval ArgumentParser - """ - parser = ArgumentParser( - description=( - "PyTorch TPU distributed training launch helper utility that will spawn up multiple distributed processes" - ) - ) - - # Optional arguments for the launch helper - parser.add_argument("--num_cores", type=int, default=1, help="Number of TPU cores to use (1 or 8).") - - # positional - parser.add_argument( - "training_script", - type=str, - help=( - "The full path to the single TPU training " - "program/script to be launched in parallel, " - "followed by all the arguments for the " - "training script" - ), - ) - - # rest from the training program - parser.add_argument("training_script_args", nargs=REMAINDER) - - return parser.parse_args() - - -def main(): - args = parse_args() - - # Import training_script as a module. - script_fpath = Path(args.training_script) - sys.path.append(str(script_fpath.parent.resolve())) - mod_name = script_fpath.stem - mod = importlib.import_module(mod_name) - - # Patch sys.argv - sys.argv = [args.training_script] + args.training_script_args - - xmp.spawn(mod._mp_fn, args=(), nprocs=args.num_cores) - - -if __name__ == "__main__": - main() diff --git a/examples/research_projects/README.md b/examples/research_projects/README.md deleted file mode 100644 index e8a0ecd8c4e9..000000000000 --- a/examples/research_projects/README.md +++ /dev/null @@ -1,20 +0,0 @@ - - -# Research projects - -This directory previously contained various research projects using 🤗 Transformers. They have been moved -to a separate repo, so you can now find them at https://github.com/huggingface/transformers-research-projects/ diff --git a/examples/run_on_remote.py b/examples/run_on_remote.py deleted file mode 100644 index 2baf1d1a032a..000000000000 --- a/examples/run_on_remote.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# Copyright 2021 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import argparse -import shlex - -import runhouse as rh - - -if __name__ == "__main__": - # Refer to https://runhouse-docs.readthedocs-hosted.com/en/latest/api/python/cluster.html#hardware-setup for cloud access - # setup instructions, if using on-demand hardware - - # If user passes --user --host --key_path , fill them in as BYO cluster - # If user passes --instance --provider , fill them in as on-demand cluster - # Throw an error if user passes both BYO and on-demand cluster args - # Otherwise, use default values - parser = argparse.ArgumentParser() - parser.add_argument("--user", type=str, default="ubuntu") - parser.add_argument("--host", type=str, default="localhost") - parser.add_argument("--key_path", type=str, default=None) - parser.add_argument("--instance", type=str, default="V100:1") - parser.add_argument("--provider", type=str, default="cheapest") - parser.add_argument("--use_spot", type=bool, default=False) - parser.add_argument("--example", type=str, default="pytorch/text-generation/run_generation.py") - args, unknown = parser.parse_known_args() - if args.host != "localhost": - if args.instance != "V100:1" or args.provider != "cheapest": - raise ValueError("Cannot specify both BYO and on-demand cluster args") - cluster = rh.cluster( - name="rh-cluster", ips=[args.host], ssh_creds={"ssh_user": args.user, "ssh_private_key": args.key_path} - ) - else: - cluster = rh.cluster( - name="rh-cluster", instance_type=args.instance, provider=args.provider, use_spot=args.use_spot - ) - example_dir = args.example.rsplit("/", 1)[0] - - # Set up remote environment - cluster.install_packages(["pip:./"]) # Installs transformers from local source - # Note transformers is copied into the home directory on the remote machine, so we can install from there - cluster.run([f"pip install -r transformers/examples/{example_dir}/requirements.txt"]) - cluster.run(["pip install torch --upgrade --extra-index-url https://download.pytorch.org/whl/cu117"]) - - # Run example. You can bypass the CLI wrapper and paste your own code here. - cluster.run([f"python transformers/examples/{args.example} {shlex.join(unknown)}"]) - - # Alternatively, we can just import and run a training function (especially if there's no wrapper CLI): - # from my_script... import train - # reqs = ['pip:./', 'torch', 'datasets', 'accelerate', 'evaluate', 'tqdm', 'scipy', 'scikit-learn', 'tensorboard'] - # launch_train_gpu = rh.function(fn=train, - # system=gpu, - # reqs=reqs, - # name='train_bert_glue') - # - # We can pass in arguments just like we would to a function: - # launch_train_gpu(num_epochs = 3, lr = 2e-5, seed = 42, batch_size = 16 - # stream_logs=True) diff --git a/examples/training/distributed_training.py b/examples/training/distributed_training.py deleted file mode 100644 index af19106a8276..000000000000 --- a/examples/training/distributed_training.py +++ /dev/null @@ -1,113 +0,0 @@ -import argparse -import os - -import torch -import torch.distributed as dist - - -# Environment variables set by torch.distributed.launch -LOCAL_RANK = int(os.environ["LOCAL_RANK"]) -WORLD_SIZE = int(os.environ["WORLD_SIZE"]) -WORLD_RANK = int(os.environ["RANK"]) - -LOCAL_RANK = int(os.environ["OMPI_COMM_WORLD_LOCAL_RANK"]) -WORLD_SIZE = int(os.environ["OMPI_COMM_WORLD_SIZE"]) -WORLD_RANK = int(os.environ["OMPI_COMM_WORLD_RANK"]) - - -def run(backend): - tensor = torch.zeros(1) - # Need to put tensor on a GPU device for nccl backend - if backend == "nccl": - device = torch.device(f"cuda:{LOCAL_RANK}") - tensor = tensor.to(device) - - if WORLD_RANK == 0: - for rank_recv in range(1, WORLD_SIZE): - dist.send(tensor=tensor, dst=rank_recv) - print(f"worker_{0} sent data to Rank {rank_recv}\n") - else: - dist.recv(tensor=tensor, src=0) - print(f"worker_{WORLD_RANK} has received data from rank {0}\n") - - -def init_processes(backend): - dist.init_process_group(backend, rank=WORLD_RANK, world_size=WORLD_SIZE) - run(backend) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument( - "--local_rank", type=int, help="Local rank. Necessary for using the torch.distributed.launch utility." - ) - parser.add_argument("--backend", type=str, default="nccl", choices=["nccl", "gloo"]) - args = parser.parse_args() - - init_processes(backend=args.backend) - -"""" -python-m torch.distributed.launch \ ---nproc_per_node=2 --nnodes=2 --node_rank=0 \ -test_compile.py - -python3 -m torch.distributed.launch \ ---nproc_per_node=2 --nnodes=2 --node_rank=1 \ ---master_addr=104.171.200.62 --master_port=1234 \ -main.py \ ---backend=nccl --use_syn --batch_size=8192 --arch=resnet152 - - - -mpirun -np 4 \ --H 104.171.200.62:2,104.171.200.182:2 \ --x MASTER_ADDR=104.171.200.62 \ --x MASTER_PORT=1234 \ --x PATH \ --bind-to none -map-by slot \ --mca pml ob1 -mca btl ^openib \ -python3 main.py -""" - - -"""" -You need a host file with the name of hosts. -for example I have arthur@ip-26-0-162-46 and arthur@ip-26-0-162-239 - -________ -hostfile -ip-26-0-162-46 slots=8 -ip-26-0-162-239 slots=8 -________ - -mpirun --hostfile hostfile -np 16 \ - --bind-to none --map-by slot \ - -x MASTER_ADDR= \ - -x MASTER_PORT=29500 \ - -x NCCL_DEBUG=INFO \ - -x NCCL_SOCKET_IFNAME=^lo,docker0 \ - -x CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ - python your_script.py --backend nccl - - -to get the master IP you need to do a few things: -hostname -I | awk '{print $1}' - - -Use `ping ip-26-0-162-46` to check if connected - -26.0.162.46 - -mpirun --hostfile hostfile -np 16 \ - --bind-to none --map-by slot \ - -x MASTER_ADDR=26.0.162.46 \ - -x MASTER_PORT=29500 \ - -x NCCL_DEBUG=INFO \ - -x NCCL_SOCKET_IFNAME=^lo,docker0 \ - -x CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ - python your_script.py --backend nccl - - -mpirun --hostfile hostfile -np 2 -x NCCL_DEBUG=INFO python -c "import os;print(os.environ['OMPI_COMM_WORLD_LOCAL_RANK'])" -b 8 -e 128M -f 2 -g 1 -to test your setup -""" diff --git a/i18n/README_ar.md b/i18n/README_ar.md index dfb757db9d13..dbf45cb2f001 100644 --- a/i18n/README_ar.md +++ b/i18n/README_ar.md @@ -244,7 +244,6 @@ limitations under the License. - ليست هذه المكتبة عبارة عن مجموعة أدوات من الصناديق المكونة للشبكات العصبية. لم يتم إعادة صياغة التعليمات البرمجية في ملفات النموذج باستخدام تجريدات إضافية عن قصد، بحيث يمكن للباحثين إجراء حلقات تكرار سريعة على كل من النماذج دون الغوص في تجريدات/ملفات إضافية. - لا يُقصد بواجهة برمجة التطبيقات (API) للتدريب العمل على أي نموذج ولكنه مُستَهدف للعمل مع النماذج التي توفرها المكتبة. للحلقات العامة للتعلم الآلي، يجب استخدام مكتبة أخرى (ربما، [تسريع](https://huggingface.co/docs/accelerate)). -- في حين أننا نسعى جاهدين لتقديم أكبر عدد ممكن من حالات الاستخدام، فإن البرامج النصية الموجودة في مجلد [الأمثلة](https://github.com/huggingface/transformers/tree/main/examples) الخاص بنا هي مجرد أمثلة. من المتوقع ألا تعمل هذه البرامج النصية خارج الصندوق على مشكلتك المحددة وأنه سيُطلب منك تغيير بضع أسطر من التعليمات البرمجية لتكييفها مع احتياجاتك. ## التثبيت @@ -291,7 +290,7 @@ conda install conda-forge::transformers للتحقق مما إذا كان لكل نموذج تنفيذ في Flax أو PyTorch أو TensorFlow، أو كان لديه مُعلم مرفق مدعوم من مكتبة 🤗 Tokenizers، يرجى الرجوع إلى [هذا الجدول](https://huggingface.co/docs/transformers/index#supported-frameworks). -تم اختبار هذه التطبيقات على العديد من مجموعات البيانات (راجع البرامج النصية المثالية) ويجب أن تتطابق مع أداء التنفيذ الأصلي. يمكنك العثور على مزيد من التفاصيل حول الأداء في قسم الأمثلة من [الوثائق](https://github.com/huggingface/transformers/tree/main/examples). +تم اختبار هذه التطبيقات على العديد من مجموعات البيانات ويجب أن تتطابق مع أداء التنفيذ الأصلي. ## تعلم المزيد @@ -302,7 +301,6 @@ conda install conda-forge::transformers | [ملخص المهام](https://huggingface.co/docs/transformers/task_summary) | المهام التي يدعمها 🤗 Transformers | | [برنامج تعليمي لمعالجة مسبقة](https://huggingface.co/docs/transformers/preprocessing) | استخدام فئة `Tokenizer` لإعداد البيانات للنماذج | | [التدريب والضبط الدقيق](https://huggingface.co/docs/transformers/training) | استخدام النماذج التي يوفرها 🤗 Transformers في حلقة تدريب PyTorch/TensorFlow وواجهة برمجة تطبيقات `Trainer` | -| [جولة سريعة: البرامج النصية للضبط الدقيق/الاستخدام](https://github.com/huggingface/transformers/tree/main/examples) | البرامج النصية المثالية للضبط الدقيق للنماذج على مجموعة واسعة من المهام | | [مشاركة النماذج وتحميلها](https://huggingface.co/docs/transformers/model_sharing) | تحميل ومشاركة نماذجك المضبوطة بدقة مع المجتمع | ## الاستشهاد diff --git a/i18n/README_bn.md b/i18n/README_bn.md index 2bfb9b28d2dc..bcda25cd56b6 100644 --- a/i18n/README_bn.md +++ b/i18n/README_bn.md @@ -244,7 +244,6 @@ pipeline( * এই লাইব্রেরি নিউরাল নেটওয়ার্কের জন্য ব্লক-মডিউল টুলবক্স নয়। মডেল ফাইলের কোডে অতিরিক্ত অ্যাবস্ট্র্যাকশন intentionally করা হয়নি, যাতে গবেষকরা দ্রুত প্রতিটি মডেলের উপর কাজ করতে পারে কোনো অতিরিক্ত ফাইল বা স্তরে না গিয়ে। * ট্রেইনিং API মূলত Transformers-এর PyTorch মডেলের সাথে কাজ করার জন্য অপটিমাইজ করা হয়েছে। সাধারণ মেশিন লার্নিং লুপের জন্য, [Accelerate](https://huggingface.co/docs/accelerate) এর মতো অন্য লাইব্রেরি ব্যবহার করা উচিত। -* [উদাহরণ স্ক্রিপ্টগুলো](https://github.com/huggingface/transformers/tree/main/examples) শুধু *উদাহরণ*। এগুলো সরাসরি আপনার ব্যবহারের ক্ষেত্রে কাজ নাও করতে পারে, তাই কোড সামঞ্জস্য করতে হতে পারে। ## Transformers দিয়ে ১০০টি প্রজেক্ট diff --git a/i18n/README_de.md b/i18n/README_de.md index 8017d491c7d3..533e3f2583a1 100644 --- a/i18n/README_de.md +++ b/i18n/README_de.md @@ -245,7 +245,6 @@ Das Modell selbst ist ein reguläres [PyTorch `nn.Module`](https://pytorch.org/d - Diese Bibliothek ist kein modularer Werkzeugkasten mit Bausteinen für neuronale Netze. Der Code in den Modelldateien ist absichtlich nicht mit zusätzlichen Abstraktionen refaktorisiert, sodass Forscher schnell mit jedem der Modelle iterieren können, ohne sich in zusätzliche Abstraktionen/Dateien vertiefen zu müssen. - Die Trainings-API ist nicht dafür gedacht, mit beliebigen Modellen zu funktionieren, sondern ist für die Verwendung mit den von der Bibliothek bereitgestellten Modellen optimiert. Für generische Trainingsschleifen von maschinellem Lernen sollten Sie eine andere Bibliothek verwenden (möglicherweise [Accelerate](https://huggingface.co/docs/accelerate)). -- Auch wenn wir bestrebt sind, so viele Anwendungsfälle wie möglich zu veranschaulichen, sind die Beispielskripte in unserem [`examples`](./examples) Ordner genau das: Beispiele. Es ist davon auszugehen, dass sie nicht sofort auf Ihr spezielles Problem anwendbar sind und einige Codezeilen geändert werden müssen, um sie für Ihre Bedürfnisse anzupassen. ## Installation @@ -291,7 +290,7 @@ Aktuelle Anzahl der Checkpoints: ![](https://img.shields.io/endpoint?url=https:/ Um zu überprüfen, ob jedes Modell eine Implementierung in Flax, PyTorch oder TensorFlow hat oder über einen zugehörigen Tokenizer verfügt, der von der 🤗 Tokenizers-Bibliothek unterstützt wird, schauen Sie auf [diese Tabelle](https://huggingface.co/docs/transformers/index#supported-frameworks). -Diese Implementierungen wurden mit mehreren Datensätzen getestet (siehe Beispielskripte) und sollten den Leistungen der ursprünglichen Implementierungen entsprechen. Weitere Details zur Leistung finden Sie im Abschnitt der Beispiele in der [Dokumentation](https://github.com/huggingface/transformers/tree/main/examples). +Diese Implementierungen wurden mit mehreren Datensätzen getestet und sollten den Leistungen der ursprünglichen Implementierungen entsprechen. ## Mehr erfahren @@ -301,7 +300,6 @@ Diese Implementierungen wurden mit mehreren Datensätzen getestet (siehe Beispie | [Zusammenfassung der Aufgaben](https://huggingface.co/docs/transformers/task_summary) | Von 🤗 Transformers unterstützte Aufgaben | | [Vorverarbeitungs-Tutorial](https://huggingface.co/docs/transformers/preprocessing) | Verwendung der `Tokenizer`-Klasse zur Vorverarbeitung der Daten für die Modelle | | [Training und Feintuning](https://huggingface.co/docs/transformers/training) | Verwendung der von 🤗 Transformers bereitgestellten Modelle in einer PyTorch-/TensorFlow-Trainingsschleife und der `Trainer`-API | -| [Schnelleinstieg: Feintuning/Anwendungsskripte](https://github.com/huggingface/transformers/tree/main/examples) | Beispielskripte für das Feintuning von Modellen für eine breite Palette von Aufgaben | | [Modellfreigabe und -upload](https://huggingface.co/docs/transformers/model_sharing) | Laden Sie Ihre feingetunten Modelle hoch und teilen Sie sie mit der Community | ## Zitation diff --git a/i18n/README_es.md b/i18n/README_es.md index 4bd124a182be..253ecea2dff7 100644 --- a/i18n/README_es.md +++ b/i18n/README_es.md @@ -226,7 +226,6 @@ El modelo en si es un [Pytorch `nn.Module`](https://pytorch.org/docs/stable/nn.h - Esta biblioteca no es una caja de herramientas modular de bloques de construcción para redes neuronales. El código en los archivos del modelo no se refactoriza con abstracciones adicionales a propósito, de modo que los investigadores puedan iterar rápidamente en cada uno de los modelos sin sumergirse en abstracciones/archivos adicionales. - La API de entrenamiento no está diseñada para funcionar en ningún modelo, pero está optimizada para funcionar con los modelos proporcionados por la biblioteca. Para bucles genéricos de aprendizaje automático, debe usar otra biblioteca (posiblemente, [Accelerate](https://huggingface.co/docs/accelerate)). -- Si bien nos esforzamos por presentar tantos casos de uso como sea posible, los scripts en nuestra [carpeta de ejemplos](https://github.com/huggingface/transformers/tree/main/examples) son solo eso: ejemplos. Se espera que no funcionen de forma inmediata en su problema específico y que deba cambiar algunas líneas de código para adaptarlas a sus necesidades. ## Instalación @@ -273,7 +272,7 @@ Número actual de puntos de control: ![](https://img.shields.io/endpoint?url=htt Para comprobar si cada modelo tiene una implementación en Flax, PyTorch o TensorFlow, o tiene un tokenizador asociado respaldado por la librería 🤗 Tokenizers, ve a [esta tabla](https://huggingface.co/docs/transformers/index#supported-frameworks). -Estas implementaciones se han probado en varios conjuntos de datos (consulte los scripts de ejemplo) y deberían coincidir con el rendimiento de las implementaciones originales. Puede encontrar más detalles sobre el rendimiento en la sección Examples de la [documentación](https://github.com/huggingface/transformers/tree/main/examples). +Estas implementaciones se han probado en varios conjuntos de datos y deberían coincidir con el rendimiento de las implementaciones originales. ## Aprender más @@ -284,7 +283,6 @@ Estas implementaciones se han probado en varios conjuntos de datos (consulte los | [Resumen de tareas](https://huggingface.co/docs/transformers/task_summary) | Tareas soportadas 🤗 Transformers | | [Tutorial de preprocesamiento](https://huggingface.co/docs/transformers/preprocessing) | Usando la clase `Tokenizer` para preparar datos para los modelos | | [Entrenamiento y puesta a punto](https://huggingface.co/docs/transformers/training) | Usando los modelos aportados por 🤗 Transformers en un bucle de entreno de PyTorch/TensorFlow y la API de `Trainer` | -| [Recorrido rápido: secuencias de comandos de ajuste/uso](https://github.com/huggingface/transformers/tree/main/examples) | Scripts de ejemplo para ajustar modelos en una amplia gama de tareas | | [Compartir y subir modelos](https://huggingface.co/docs/transformers/model_sharing) | Carga y comparte tus modelos perfeccionados con la comunidad | | [Migración](https://huggingface.co/docs/transformers/migration) | Migra a 🤗 Transformers desde `pytorch-transformers` o `pytorch-pretrained-bert` | diff --git a/i18n/README_fa.md b/i18n/README_fa.md index c3c17b52c48e..20bab3ec776f 100644 --- a/i18n/README_fa.md +++ b/i18n/README_fa.md @@ -236,7 +236,6 @@ pipeline( - این کتابخانه یک جعبه‌ابزار ماژولار برای شبکه‌های عصبی عمومی نیست؛ کدهای مدل‌ها عمداً برای محققان کمتر انتزاعی شده‌اند. - رابط آموزش (Training API) بهینه‌سازی شده برای مدل‌های Transformers است. برای حلقه‌های عمومی یادگیری ماشین، بهتر است از کتابخانه‌هایی مانند [Accelerate](https://huggingface.co/docs/accelerate) استفاده کنید. -- [اسکریپت‌های نمونه](https://github.com/huggingface/transformers/tree/main/examples) ممکن است برای موارد استفاده خاص شما نیاز به تغییر و سازگاری داشته باشند. ## ۱۰۰ پروژه با استفاده از Transformers diff --git a/i18n/README_fr.md b/i18n/README_fr.md index 3e511f142b8d..eebf3bbe4c33 100644 --- a/i18n/README_fr.md +++ b/i18n/README_fr.md @@ -242,7 +242,6 @@ Le modèle lui-même est un module [`nn.Module` PyTorch](https://pytorch.org/doc - Cette bibliothèque n'est pas une boîte à outils modulaire de blocs de construction pour les réseaux neuronaux. Le code dans les fichiers de modèle n'est pas refactorisé avec des abstractions supplémentaires à dessein, afin que les chercheurs puissent itérer rapidement sur chacun des modèles sans plonger dans des abstractions/fichiers supplémentaires. - L'API d'entraînement n'est pas destinée à fonctionner avec n'importe quel modèle, mais elle est optimisée pour fonctionner avec les modèles fournis par la bibliothèque. Pour des boucles génériques d'apprentissage automatique, vous devriez utiliser une autre bibliothèque (éventuellement, [Accelerate](https://huggingface.co/docs/accelerate)). -- Bien que nous nous efforcions de présenter autant de cas d'utilisation que possible, les scripts de notre [dossier d'exemples](https://github.com/huggingface/transformers/tree/main/examples) ne sont que cela : des exemples. Il est prévu qu'ils ne fonctionnent pas immédiatement sur votre problème spécifique et que vous devrez probablement modifier quelques lignes de code pour les adapter à vos besoins. ## Installation @@ -289,7 +288,7 @@ Nombre actuel de points de contrôle : ![](https://img.shields.io/endpoint?url=h Pour vérifier si chaque modèle a une implémentation en Flax, PyTorch ou TensorFlow, ou s'il a un tokenizer associé pris en charge par la bibliothèque 🤗 Tokenizers, consultez [ce tableau](https://huggingface.co/docs/transformers/index#supported-frameworks). -Ces implémentations ont été testées sur plusieurs ensembles de données (voir les scripts d'exemple) et devraient correspondre aux performances des implémentations originales. Vous pouvez trouver plus de détails sur les performances dans la section Exemples de la [documentation](https://github.com/huggingface/transformers/tree/main/examples). +Ces implémentations ont été testées sur plusieurs ensembles de données et devraient correspondre aux performances des implémentations originales. ## En savoir plus @@ -299,7 +298,6 @@ Ces implémentations ont été testées sur plusieurs ensembles de données (voi | [Résumé des tâches](https://huggingface.co/docs/transformers/task_summary) | Tâches prises en charge par les 🤗 Transformers | | [Tutoriel de prétraitement](https://huggingface.co/docs/transformers/preprocessing) | Utilisation de la classe `Tokenizer` pour préparer les données pour les modèles | | [Entraînement et ajustement fin](https://huggingface.co/docs/transformers/training) | Utilisation des modèles fournis par les 🤗 Transformers dans une boucle d'entraînement PyTorch/TensorFlow et de l'API `Trainer` | -| [Tour rapide : Scripts d'ajustement fin/d'utilisation](https://github.com/huggingface/transformers/tree/main/examples) | Scripts d'exemple pour ajuster finement les modèles sur une large gamme de tâches | | [Partage et téléversement de modèles](https://huggingface.co/docs/transformers/model_sharing) | Téléchargez et partagez vos modèles ajustés avec la communauté | ## Citation diff --git a/i18n/README_hd.md b/i18n/README_hd.md index 4d16912fb2f8..ff3b999c4581 100644 --- a/i18n/README_hd.md +++ b/i18n/README_hd.md @@ -202,7 +202,6 @@ checkpoint: जाँच बिंदु - यह लाइब्रेरी मॉड्यूलर न्यूरल नेटवर्क टूलबॉक्स नहीं है। मॉडल फ़ाइल में कोड जानबूझकर अल्पविकसित है, बिना अतिरिक्त सार इनकैप्सुलेशन के, ताकि शोधकर्ता अमूर्तता और फ़ाइल जंपिंग में शामिल हुए जल्दी से पुनरावृति कर सकें। - `ट्रेनर` एपीआई किसी भी मॉडल के साथ संगत नहीं है, यह केवल इस पुस्तकालय के मॉडल के लिए अनुकूलित है। यदि आप सामान्य मशीन लर्निंग के लिए उपयुक्त प्रशिक्षण लूप कार्यान्वयन की तलाश में हैं, तो कहीं और देखें। -- हमारे सर्वोत्तम प्रयासों के बावजूद, [उदाहरण निर्देशिका](https://github.com/huggingface/transformers/tree/main/examples) में स्क्रिप्ट केवल उपयोग के मामले हैं। आपकी विशिष्ट समस्या के लिए, वे जरूरी नहीं कि बॉक्स से बाहर काम करें, और आपको कोड की कुछ पंक्तियों को सूट करने की आवश्यकता हो सकती है। ## स्थापित करना @@ -247,7 +246,7 @@ conda install conda-forge::transformers यह जांचने के लिए कि क्या किसी मॉडल में पहले से ही Flax, PyTorch या TensorFlow का कार्यान्वयन है, या यदि उसके पास Tokenizers लाइब्रेरी में संबंधित टोकन है, तो [यह तालिका](https://huggingface.co/docs/transformers/index#supported) देखें। -फ्रेमवर्क)। -इन कार्यान्वयनों का परीक्षण कई डेटासेट पर किया गया है (देखें केस स्क्रिप्ट का उपयोग करें) और वैनिला कार्यान्वयन के लिए तुलनात्मक रूप से प्रदर्शन करना चाहिए। आप उपयोग के मामले के दस्तावेज़ [इस अनुभाग](https://huggingface.co/docs/transformers/examples) में व्यवहार का विवरण पढ़ सकते हैं। +इन कार्यान्वयनों का परीक्षण कई डेटासेट पर किया गया है और वैनिला कार्यान्वयन के लिए तुलनात्मक रूप से प्रदर्शन करना चाहिए। ## अधिक समझें @@ -258,7 +257,6 @@ conda install conda-forge::transformers | [कार्य सारांश](https://huggingface.co/docs/transformers/task_summary) | ट्रांसफॉर्मर समर्थित कार्य | | [प्रीप्रोसेसिंग ट्यूटोरियल](https://huggingface.co/docs/transformers/preprocessing) | मॉडल के लिए डेटा तैयार करने के लिए `टोकनाइज़र` का उपयोग करना | | [प्रशिक्षण और फाइन-ट्यूनिंग](https://huggingface.co/docs/transformers/training) | PyTorch/TensorFlow के ट्रेनिंग लूप या `ट्रेनर` API में ट्रांसफॉर्मर द्वारा दिए गए मॉडल का उपयोग करें | -| [क्विक स्टार्ट: ट्वीकिंग एंड यूज़ केस स्क्रिप्ट्स](https://github.com/huggingface/transformers/tree/main/examples) | विभिन्न कार्यों के लिए केस स्क्रिप्ट का उपयोग करें | | [मॉडल साझा करना और अपलोड करना](https://huggingface.co/docs/transformers/model_sharing) | समुदाय के साथ अपने फाइन टूनड मॉडल अपलोड और साझा करें | | [माइग्रेशन](https://huggingface.co/docs/transformers/migration) | `पाइटोरच-ट्रांसफॉर्मर्स` या `पाइटोरच-प्रीट्रेनड-बर्ट` से ट्रांसफॉर्मर में माइग्रेट करना | diff --git a/i18n/README_it.md b/i18n/README_it.md index f0dd78cb64c7..04e6bb786a24 100644 --- a/i18n/README_it.md +++ b/i18n/README_it.md @@ -246,7 +246,6 @@ pipeline( - Questa libreria non è un toolbox modulare di blocchi costitutivi per reti neurali. Il codice nei file dei modelli non è stato rifattorizzato con ulteriori astrazioni di proposito, in modo che i ricercatori possano iterare rapidamente su ciascuno dei modelli senza dover approfondire ulteriori astrazioni/file. - L'API di addestramento è ottimizzata per funzionare con i modelli PyTorch forniti da Transformers. Per i loop generici di machine learning, è necessario utilizzare un'altra libreria come [Accelerate](https://huggingface.co/docs/accelerate). -- Gli [script di esempio](https://github.com/huggingface/transformers/tree/main/examples) sono solo *esempi*. Potrebbero non funzionare immediatamente nel vostro caso specifico e potrebbe essere necessario adattare il codice affinché funzioni. ## 100 progetti che usano Transformers diff --git a/i18n/README_ja.md b/i18n/README_ja.md index b611f0e846b9..ad4dd8583652 100644 --- a/i18n/README_ja.md +++ b/i18n/README_ja.md @@ -275,7 +275,6 @@ pipeline( - このライブラリは、ニューラルネットのためのビルディングブロックのモジュール式ツールボックスではありません。モデルファイルのコードは、研究者が追加の抽象化/ファイルに飛び込むことなく、各モデルを素早く反復できるように、意図的に追加の抽象化でリファクタリングされていません。 - 学習APIはTransformersが提供するPyTorchモデルで動作するように最適化されています。一般的な機械学習のループには、[Accelerate](https://huggingface.co/docs/accelerate)のような別のライブラリを使用する必要があります。 -- [example scripts](https://github.com/huggingface/transformers/tree/main/examples)にあるスクリプトはあくまで*例*です。あなたの特定の問題に対してすぐに動作するわけではなく、あなたのニーズに合わせるためにコードを適応させる必要があるでしょう。 ## Transformersを使用している100のプロジェクト diff --git a/i18n/README_ko.md b/i18n/README_ko.md index 54d93b03a53f..937bdcc1dae0 100644 --- a/i18n/README_ko.md +++ b/i18n/README_ko.md @@ -241,7 +241,6 @@ Transformers에 달린 100,000개의 별을 축하하기 위해, 우리는 커 - 이 라이브러리는 신경망 블록을 만들기 위한 모듈이 아닙니다. 연구자들이 여러 파일을 살펴보지 않고 바로 각 모델을 사용할 수 있도록, 모델 파일 코드의 추상화 수준을 적정하게 유지했습니다. - 학습 API는 모든 모델에 적용할 수 있도록 만들어지진 않았지만, 라이브러리가 제공하는 모델들에 적용할 수 있도록 최적화되었습니다. 일반적인 머신 러닝을 위해선, 다른 라이브러리를 사용하세요(예를 들면, [Accelerate](https://huggingface.co/docs/accelerate/index)). -- 가능한 많은 사용 예시를 보여드리고 싶어서, [예시 폴더](https://github.com/huggingface/transformers/tree/main/examples)의 스크립트를 준비했습니다. 이 스크립트들을 수정 없이 특정한 문제에 바로 적용하지 못할 수 있습니다. 필요에 맞게 일부 코드를 수정해야 할 수 있습니다. ## 설치 @@ -288,7 +287,7 @@ Flax, PyTorch, TensorFlow 설치 페이지에서 이들을 conda로 설치하는 각 모델이 Flax, PyTorch, TensorFlow으로 구현되었는지 또는 🤗 Tokenizers 라이브러리가 지원하는 토크나이저를 사용하는지 확인하려면, [이 표](https://huggingface.co/docs/transformers/ko/index#supported-framework)를 확인하세요. -이 구현은 여러 데이터로 검증되었고 (예시 스크립트를 참고하세요) 오리지널 구현의 성능과 같아야 합니다. [도큐먼트](https://github.com/huggingface/transformers/tree/main/examples)의 Examples 섹션에서 성능에 대한 자세한 설명을 확인할 수 있습니다. +이 구현은 여러 데이터로 검증되었고 오리지널 구현의 성능과 같아야 합니다. ## 더 알아보기 @@ -298,7 +297,6 @@ Flax, PyTorch, TensorFlow 설치 페이지에서 이들을 conda로 설치하는 | [과제 요약](https://huggingface.co/docs/transformers/ko/task_summary) | 🤗 Transformers가 지원하는 과제들 | | [전처리 튜토리얼](https://huggingface.co/docs/transformers/ko/preprocessing) | `Tokenizer` 클래스를 이용해 모델을 위한 데이터 준비하기 | | [학습과 파인 튜닝](https://huggingface.co/docs/transformers/ko/training) | 🤗 Transformers가 제공하는 모델 PyTorch/TensorFlow 학습 과정과 `Trainer` API에서 사용하기 | -| [퀵 투어: 파인 튜닝/사용 스크립트](https://github.com/huggingface/transformers/tree/main/examples) | 다양한 과제에서 모델을 파인 튜닝하는 예시 스크립트 | | [모델 공유 및 업로드](https://huggingface.co/docs/transformers/ko/model_sharing) | 커뮤니티에 파인 튜닝된 모델을 업로드 및 공유하기 | ## 인용 diff --git a/i18n/README_pt-br.md b/i18n/README_pt-br.md index e3e59f31373d..377c05ebe6a5 100644 --- a/i18n/README_pt-br.md +++ b/i18n/README_pt-br.md @@ -252,7 +252,6 @@ O modelo em si é um [Pytorch `nn.Module`](https://pytorch.org/docs/stable/nn.ht - Esta biblioteca não é uma caixa de ferramentas modular para construir redes neurais. O código nos arquivos do modelo não é refatorado com abstrações adicionais de propósito, para que os pesquisadores possam iterar rapidamente em cada um dos modelos sem se aprofundar em abstrações/arquivos adicionais. - A API de treinamento não é projetada para funcionar com qualquer modelo, mas é otimizada para funcionar com os modelos fornecidos pela biblioteca. Para loops de aprendizado de máquina genéricos, você deve usar outra biblioteca (possivelmente, [Accelerate](https://huggingface.co/docs/accelerate)). -- Embora nos esforcemos para apresentar o maior número possível de casos de uso, os scripts em nossa [pasta de exemplos](https://github.com/huggingface/transformers/tree/main/examples) são apenas isso: exemplos. É esperado que eles não funcionem prontos para uso em seu problema específico e que seja necessário modificar algumas linhas de código para adaptá-los às suas necessidades. @@ -300,7 +299,7 @@ Número atual de pontos de verificação: ![](https://img.shields.io/endpoint?ur Para verificar se cada modelo tem uma implementação em Flax, PyTorch ou TensorFlow, ou possui um tokenizador associado com a biblioteca 🤗 Tokenizers, consulte [esta tabela](https://huggingface.co/docs/transformers/index#supported-frameworks). -Essas implementações foram testadas em vários conjuntos de dados (veja os scripts de exemplo) e devem corresponder ao desempenho das implementações originais. Você pode encontrar mais detalhes sobre o desempenho na seção de Exemplos da [documentação](https://github.com/huggingface/transformers/tree/main/examples). +Essas implementações foram testadas em vários conjuntos de dados e devem corresponder ao desempenho das implementações originais. ## Saiba mais @@ -311,7 +310,6 @@ Essas implementações foram testadas em vários conjuntos de dados (veja os scr | [Resumo de Tarefas](https://huggingface.co/docs/transformers/task_summary) | Tarefas suportadas pelo 🤗 Transformers | | [Tutorial de Pré-processamento](https://huggingface.co/docs/transformers/preprocessing) | Usando a classe `Tokenizer` para preparar dados para os modelos | | [Treinamento e Ajuste Fino](https://huggingface.co/docs/transformers/training) | Usando os modelos fornecidos pelo 🤗 Transformers em um loop de treinamento PyTorch/TensorFlow e a API `Trainer` | -| [Tour Rápido: Scripts de Ajuste Fino/Utilização](https://github.com/huggingface/transformers/tree/main/examples) | Scripts de exemplo para ajuste fino de modelos em uma ampla gama de tarefas | | [Compartilhamento e Envio de Modelos](https://huggingface.co/docs/transformers/model_sharing) | Envie e compartilhe seus modelos ajustados com a comunidade | ## Citação diff --git a/i18n/README_ro.md b/i18n/README_ro.md index f6a40aaad410..2c8d93a95707 100644 --- a/i18n/README_ro.md +++ b/i18n/README_ro.md @@ -241,7 +241,6 @@ pipeline( - Această bibliotecă nu este un toolbox de block-uri pentru construirea rețelelor neuronale. Codul din fișierele modelelor nu este refactorizat cu mai multă abstractizare pentru ca cercetătorii să poată utiliza rapid fiecare dintre modele fără să aibă de-a face cu fișiere/abstractizări adiționale. - API-ul de antrenare este optimizat pentru utilizarea cu modele PyTorch oferite de Transformers. Pentru loop-uri generice de machine learning, utilizează o bibliotecă precum [Accelerate](https://huggingface.co/docs/accelerate). -- [Script-urile de exemplu](https://github.com/huggingface/transformers/tree/main/examples) sunt doar *exemple*. S-ar putea ca acestea să nu funcționeze în toate cazurile și va trebui să adaptezi codul pentru ca acestea să funcționeze. ## 100 de proiecte folosind Transformers diff --git a/i18n/README_ru.md b/i18n/README_ru.md index f0196add47e8..f2a8e847f315 100644 --- a/i18n/README_ru.md +++ b/i18n/README_ru.md @@ -243,7 +243,6 @@ Hugging Face Hub. Мы хотим, чтобы Transformers позволил ра - Данная библиотека не является модульным набором строительных блоков для нейронных сетей. Код в файлах моделей специально не рефакторится дополнительными абстракциями, чтобы исследователи могли быстро итеративно работать с каждой из моделей, не погружаясь в дополнительные абстракции/файлы. - API обучения не предназначен для работы с любой моделью, а оптимизирован для работы с моделями, предоставляемыми библиотекой. Для работы с общими циклами машинного обучения следует использовать другую библиотеку (возможно, [Accelerate](https://huggingface.co/docs/accelerate)). -- Несмотря на то, что мы стремимся представить как можно больше примеров использования, скрипты в нашей папке [примеров](https://github.com/huggingface/transformers/tree/main/examples) являются именно примерами. Предполагается, что они не будут работать "из коробки" для решения вашей конкретной задачи, и вам придется изменить несколько строк кода, чтобы адаптировать их под свои нужды. ## Установка @@ -290,7 +289,7 @@ conda install conda-forge::transformers Чтобы проверить, есть ли у каждой модели реализация на Flax, PyTorch или TensorFlow, или связанный с ней токенизатор, поддерживаемый библиотекой 🤗 Tokenizers, обратитесь к [этой таблице](https://huggingface.co/docs/transformers/index#supported-frameworks). -Эти реализации были протестированы на нескольких наборах данных (см. примеры скриптов) и должны соответствовать производительности оригинальных реализаций. Более подробную информацию о производительности можно найти в разделе "Примеры" [документации](https://github.com/huggingface/transformers/tree/main/examples). +Эти реализации были протестированы на нескольких наборах данных и должны соответствовать производительности оригинальных реализаций. ## Изучи больше @@ -301,7 +300,6 @@ conda install conda-forge::transformers | [Краткие описания задач](https://huggingface.co/docs/transformers/task_summary) | Задачи поддерживаются 🤗 Transformers | | [Пособие по предварительной обработке](https://huggingface.co/docs/transformers/preprocessing) | Использование класса `Tokenizer` для подготовки данных для моделей | | [Обучение и доработка](https://huggingface.co/docs/transformers/training) | Использование моделей, предоставляемых 🤗 Transformers, в цикле обучения PyTorch/TensorFlow и API `Trainer`. | -| [Быстрый тур: Тонкая настройка/скрипты использования](https://github.com/huggingface/transformers/tree/main/examples) | Примеры скриптов для тонкой настройки моделей на широком спектре задач | | [Совместное использование и загрузка моделей](https://huggingface.co/docs/transformers/model_sharing) | Загружайте и делитесь с сообществом своими доработанными моделями | ## Цитирование diff --git a/i18n/README_te.md b/i18n/README_te.md index 70bc241962c9..d819cfe84c3d 100644 --- a/i18n/README_te.md +++ b/i18n/README_te.md @@ -245,7 +245,6 @@ limitations under the License. - ఈ లైబ్రరీ న్యూరల్ నెట్‌ల కోసం బిల్డింగ్ బ్లాక్‌ల మాడ్యులర్ టూల్‌బాక్స్ కాదు. మోడల్ ఫైల్‌లలోని కోడ్ ఉద్దేశపూర్వకంగా అదనపు సంగ్రహణలతో రీఫ్యాక్టరింగ్ చేయబడదు, తద్వారా పరిశోధకులు అదనపు సంగ్రహణలు/ఫైళ్లలోకి ప్రవేశించకుండా ప్రతి మోడల్‌పై త్వరగా మళ్లించగలరు. - శిక్షణ API ఏ మోడల్‌లో పని చేయడానికి ఉద్దేశించబడలేదు కానీ లైబ్రరీ అందించిన మోడల్‌లతో పని చేయడానికి ఆప్టిమైజ్ చేయబడింది. సాధారణ మెషిన్ లెర్నింగ్ లూప్‌ల కోసం, మీరు మరొక లైబ్రరీని ఉపయోగించాలి (బహుశా, [Accelerate](https://huggingface.co/docs/accelerate)). -- మేము వీలైనన్ని ఎక్కువ వినియోగ సందర్భాలను ప్రదర్శించడానికి ప్రయత్నిస్తున్నప్పుడు, మా [ఉదాహరణల ఫోల్డర్](https://github.com/huggingface/transformers/tree/main/examples)లోని స్క్రిప్ట్‌లు కేవలం: ఉదాహరణలు. మీ నిర్దిష్ట సమస్యపై అవి పని చేయవు మరియు వాటిని మీ అవసరాలకు అనుగుణంగా మార్చుకోవడానికి మీరు కొన్ని కోడ్ లైన్‌లను మార్చవలసి ఉంటుంది. ## సంస్థాపన @@ -290,7 +289,7 @@ Flax, PyTorch లేదా TensorFlow యొక్క ఇన్‌స్టా 🤗 ట్రాన్స్‌ఫార్మర్లు ప్రస్తుతం కింది ఆర్కిటెక్చర్‌లను అందజేస్తున్నాయి: వాటిలో ప్రతి ఒక్కటి ఉన్నత స్థాయి సారాంశం కోసం [ఇక్కడ](https://huggingface.co/docs/transformers/model_summary) చూడండి. -ఈ అమలులు అనేక డేటాసెట్‌లలో పరీక్షించబడ్డాయి (ఉదాహరణ స్క్రిప్ట్‌లను చూడండి) మరియు అసలైన అమలుల పనితీరుతో సరిపోలాలి. మీరు [డాక్యుమెంటేషన్](https://github.com/huggingface/transformers/tree/main/examples) యొక్క ఉదాహరణల విభాగంలో పనితీరుపై మరిన్ని వివరాలను కనుగొనవచ్చు. +ఈ అమలులు అనేక డేటాసెట్‌లలో పరీక్షించబడ్డాయి మరియు అసలైన అమలుల పనితీరుతో సరిపోలాలి. ## ఇంకా నేర్చుకో @@ -300,7 +299,6 @@ Flax, PyTorch లేదా TensorFlow యొక్క ఇన్‌స్టా | [టాస్క్ సారాంశం](https://huggingface.co/docs/transformers/task_summary) | 🤗 ట్రాన్స్‌ఫార్మర్‌ల ద్వారా సపోర్ట్ చేయబడిన విధులు | | [ప్రీప్రాసెసింగ్ ట్యుటోరియల్](https://huggingface.co/docs/transformers/preprocessing) | మోడల్‌ల కోసం డేటాను సిద్ధం చేయడానికి `Tokenizer` క్లాస్‌ని ఉపయోగించడం | | [ట్రైనింగ్ మరియు ఫైన్-ట్యూనింగ్](https://huggingface.co/docs/transformers/training) | PyTorch/TensorFlow ట్రైనింగ్ లూప్ మరియు `Trainer` APIలో 🤗 ట్రాన్స్‌ఫార్మర్లు అందించిన మోడల్‌లను ఉపయోగించడం | -| [త్వరిత పర్యటన: ఫైన్-ట్యూనింగ్/యూసేజ్ స్క్రిప్ట్‌లు](https://github.com/huggingface/transformers/tree/main/examples) | విస్తృత శ్రేణి టాస్క్‌లపై ఫైన్-ట్యూనింగ్ మోడల్స్ కోసం ఉదాహరణ స్క్రిప్ట్‌లు | | [మోడల్ భాగస్వామ్యం మరియు అప్‌లోడ్ చేయడం](https://huggingface.co/docs/transformers/model_sharing) | కమ్యూనిటీతో మీ ఫైన్-ట్యూన్డ్ మోడల్‌లను అప్‌లోడ్ చేయండి మరియు భాగస్వామ్యం చేయండి | ## అనులేఖనం diff --git a/i18n/README_tr.md b/i18n/README_tr.md index ab90083df76a..e61ad900fb6f 100644 --- a/i18n/README_tr.md +++ b/i18n/README_tr.md @@ -240,7 +240,6 @@ pipeline( - Bu kütüphane, sinir ağları için yapı taşlarından oluşan modüler bir araç kutusu değildir. Model dosyalarındaki kod, araştırmacıların ek soyutlamalara/dosyalara dalmadan her bir model üzerinde hızlıca yineleme yapabilmesi için kasıtlı olarak ek soyutlamalarla yeniden düzenlenmemiştir. - Eğitim API'si, Transformers tarafından sağlanan PyTorch modelleriyle çalışmak üzere optimize edilmiştir. Genel amaçlı makine öğrenimi döngüleri için [Accelerate](https://huggingface.co/docs/accelerate) gibi başka bir kütüphane kullanmalısınız. -- [Örnek kodlar](https://github.com/huggingface/transformers/tree/main/examples) yalnızca *örnektir*. Sizin özel kullanım durumunuzda doğrudan çalışmayabilir ve çalışması için kodu uyarlamanız gerekebilir. ## Transformers kullanan 100 proje diff --git a/i18n/README_ur.md b/i18n/README_ur.md index 2e7e8919f61a..3c8aad97eb2a 100644 --- a/i18n/README_ur.md +++ b/i18n/README_ur.md @@ -258,7 +258,6 @@ limitations under the License. - یہ لائبریری نیورل نیٹس کے لیے بلڈنگ بلاکس کا ماڈیولر ٹول باکس نہیں ہے۔ ماڈل فائلز میں موجود کوڈ جان بوجھ کر اضافی ایبسٹریکشنز کے ساتھ دوبارہ ترتیب نہیں دیا گیا ہے، تاکہ محققین بغیر اضافی ایبسٹریکشنز/فائلوں میں گئے ہوئے جلدی سے ہر ماڈل پر کام کر سکیں۔ - تربیتی API کا مقصد کسی بھی ماڈل پر کام کرنے کے لیے نہیں ہے بلکہ یہ لائبریری کے فراہم کردہ ماڈلز کے ساتھ کام کرنے کے لیے بہتر بنایا گیا ہے۔ عام مشین لرننگ لوپس کے لیے، آپ کو دوسری لائبریری (ممکنہ طور پر [Accelerate](https://huggingface.co/docs/accelerate)) استعمال کرنی چاہیے۔ -- حالانکہ ہم جتنا ممکن ہو زیادہ سے زیادہ استعمال کے کیسز پیش کرنے کی کوشش کرتے ہیں، ہمارے [مثالوں کے فولڈر](https://github.com/huggingface/transformers/tree/main/examples) میں موجود اسکرپٹس صرف یہی ہیں: مثالیں۔ یہ توقع کی جاتی ہے کہ یہ آپ کے مخصوص مسئلے پر فوراً کام نہیں کریں گی اور آپ کو اپنی ضروریات کے مطابق کوڈ کی کچھ لائنیں تبدیل کرنی پڑیں گی۔ ### انسٹالیشن @@ -305,7 +304,7 @@ Flax، PyTorch، یا TensorFlow کو conda کے ساتھ انسٹال کرنے یہ چیک کرنے کے لیے کہ ہر ماڈل کی Flax، PyTorch یا TensorFlow میں کوئی عملداری ہے یا 🤗 Tokenizers لائبریری کے ذریعہ سپورٹ کردہ ٹوکنائزر کے ساتھ ہے، [اس جدول](https://huggingface.co/docs/transformers/index#supported-frameworks) کا حوالہ لیں۔ -یہ عملداری مختلف ڈیٹا سیٹس پر ٹیسٹ کی گئی ہیں (مثال کے اسکرپٹس دیکھیں) اور اصل عملداری کی کارکردگی کے ہم آہنگ ہونی چاہئیں۔ آپ کو کارکردگی کی مزید تفصیلات [دستاویزات](https://github.com/huggingface/transformers/tree/main/examples) کے مثالوں کے سیکشن میں مل سکتی ہیں۔ +یہ عملداری مختلف ڈیٹا سیٹس پر ٹیسٹ کی گئی ہیں اور اصل عملداری کی کارکردگی کے ہم آہنگ ہونی چاہئیں۔ ## مزید معلومات حاصل کریں @@ -316,7 +315,6 @@ Flax، PyTorch، یا TensorFlow کو conda کے ساتھ انسٹال کرنے | [ٹاسک کا خلاصہ](https://huggingface.co/docs/transformers/task_summary) | 🤗 Transformers کے ذریعہ سپورٹ کردہ ٹاسک | | [پری پروسیسنگ ٹیوٹوریل](https://huggingface.co/docs/transformers/preprocessing) | ماڈلز کے لیے ڈیٹا تیار کرنے کے لیے `Tokenizer` کلاس کا استعمال | | [ٹریننگ اور فائن ٹیوننگ](https://huggingface.co/docs/transformers/training) | PyTorch/TensorFlow ٹریننگ لوپ میں 🤗 Transformers کی طرف سے فراہم کردہ ماڈلز کا استعمال اور `Trainer` API | -| [تیز دورہ: فائن ٹیوننگ/استعمال کے اسکرپٹس](https://github.com/huggingface/transformers/tree/main/examples) | مختلف قسم کے ٹاسک پر ماڈلز کو فائن ٹیون کرنے کے لیے مثال کے اسکرپٹس | | [ماڈل کا اشتراک اور اپ لوڈ کرنا](https://huggingface.co/docs/transformers/model_sharing) | اپنی فائن ٹیون کردہ ماڈلز کو کمیونٹی کے ساتھ اپ لوڈ اور شیئر کریں | ## استشہاد diff --git a/i18n/README_vi.md b/i18n/README_vi.md index 5922cd03a893..323a51cff3fa 100644 --- a/i18n/README_vi.md +++ b/i18n/README_vi.md @@ -244,7 +244,6 @@ Chính mô hình là một [Pytorch `nn.Module`](https://pytorch.org/docs/stable - Thư viện này không phải là một bộ công cụ modul cho các khối xây dựng mạng neural. Mã trong các tệp mô hình không được tái cấu trúc với các trừu tượng bổ sung một cách cố ý, để các nhà nghiên cứu có thể lặp nhanh trên từng mô hình mà không cần đào sâu vào các trừu tượng/tệp bổ sung. - API huấn luyện không được thiết kế để hoạt động trên bất kỳ mô hình nào, mà được tối ưu hóa để hoạt động với các mô hình được cung cấp bởi thư viện. Đối với vòng lặp học máy chung, bạn nên sử dụng một thư viện khác (có thể là [Accelerate](https://huggingface.co/docs/accelerate)). -- Mặc dù chúng tôi cố gắng trình bày càng nhiều trường hợp sử dụng càng tốt, nhưng các tập lệnh trong thư mục [examples](https://github.com/huggingface/transformers/tree/main/examples) chỉ là ví dụ. Dự kiến rằng chúng sẽ không hoạt động ngay tức khắc trên vấn đề cụ thể của bạn và bạn sẽ phải thay đổi một số dòng mã để thích nghi với nhu cầu của bạn. ## Cài đặt @@ -291,7 +290,7 @@ Số lượng điểm kiểm tra hiện tại: ![](https://img.shields.io/endpoi Để kiểm tra xem mỗi mô hình có một phiên bản thực hiện trong Flax, PyTorch hoặc TensorFlow, hoặc có một tokenizer liên quan được hỗ trợ bởi thư viện 🤗 Tokenizers, vui lòng tham khảo [bảng này](https://huggingface.co/docs/transformers/index#supported-frameworks). -Những phiên bản này đã được kiểm tra trên một số tập dữ liệu (xem các tập lệnh ví dụ) và nên tương đương với hiệu suất của các phiên bản gốc. Bạn có thể tìm thấy thêm thông tin về hiệu suất trong phần Ví dụ của [tài liệu](https://github.com/huggingface/transformers/tree/main/examples). +Những phiên bản này đã được kiểm tra trên một số tập dữ liệu và nên tương đương với hiệu suất của các phiên bản gốc. ## Tìm hiểu thêm @@ -302,7 +301,6 @@ Những phiên bản này đã được kiểm tra trên một số tập dữ l | [Tóm tắt nhiệm vụ](https://huggingface.co/docs/transformers/task_summary) | Các nhiệm vụ được hỗ trợ bởi 🤗 Transformers | | [Hướng dẫn tiền xử lý](https://huggingface.co/docs/transformers/preprocessing) | Sử dụng lớp `Tokenizer` để chuẩn bị dữ liệu cho các mô hình | | [Huấn luyện và điều chỉnh](https://huggingface.co/docs/transformers/training) | Sử dụng các mô hình được cung cấp bởi 🤗 Transformers trong vòng lặp huấn luyện PyTorch/TensorFlow và API `Trainer` | -| [Hướng dẫn nhanh: Điều chỉnh/sử dụng các kịch bản](https://github.com/huggingface/transformers/tree/main/examples) | Các kịch bản ví dụ để điều chỉnh mô hình trên nhiều nhiệm vụ khác nhau | | [Chia sẻ và tải lên mô hình](https://huggingface.co/docs/transformers/model_sharing) | Tải lên và chia sẻ các mô hình đã điều chỉnh của bạn với cộng đồng | ## Trích dẫn diff --git a/i18n/README_zh-hans.md b/i18n/README_zh-hans.md index 23ec83969f9a..eefdd7f2cb71 100644 --- a/i18n/README_zh-hans.md +++ b/i18n/README_zh-hans.md @@ -265,7 +265,6 @@ pipeline( - 该库不是一个可自由拼搭的神经网络模块化工具箱。模型文件中的代码刻意减少额外抽象,以便研究者能快速在各个模型上迭代,而无需深入更多抽象或文件跳转。 - 训练 API 优化用于 Transformers 提供的 PyTorch 模型。若需要通用的机器学习训练循环,请使用其它库,如 [Accelerate](https://huggingface.co/docs/accelerate)。 -- [示例脚本](https://github.com/huggingface/transformers/tree/main/examples)只是「示例」。它们不一定能直接适配你的具体用例,需要你进行必要的改动。 ## 100 个使用 Transformers 的项目 diff --git a/i18n/README_zh-hant.md b/i18n/README_zh-hant.md index b49617baf457..b13ee2a6c784 100644 --- a/i18n/README_zh-hant.md +++ b/i18n/README_zh-hant.md @@ -240,7 +240,6 @@ pipeline( - 本函式庫並非一個用於建構神經網路的模組化工具箱。模型檔案中的程式碼為了讓研究人員能快速在模型上迭代,而沒有進行過度的抽象重構,避免了深入額外的抽象層/檔案。 - 訓練 API 針對 Transformers 提供的 PyTorch 模型進行了最佳化。對於通用的機器學習迴圈,您應該使用像 [Accelerate](https://huggingface.co/docs/accelerate) 這樣的其他函式庫。 -- [範例指令稿](https://github.com/huggingface/transformers/tree/main/examples)僅僅是*範例*。它們不一定能在您的特定用例上開箱即用,您可能需要修改程式碼才能使其正常運作。 ## 100個使用 Transformers 的專案 diff --git a/setup.py b/setup.py index fc56c13653af..d5d80e920519 100644 --- a/setup.py +++ b/setup.py @@ -79,8 +79,6 @@ "datasets>=2.15.0", # We need either this pin or pyarrow<21.0.0 "deepspeed>=0.9.3", "diffusers==0.35.2", # Needed for VibeVoice TTS integration tests - "dill<0.3.5", - "evaluate>=0.4.6", "faiss-cpu", "fastapi", "filelock", @@ -121,16 +119,11 @@ "regex>=2025.10.22", "rhoknp>=1.1.0,<1.3.1", "rjieba", - "rouge-score!=0.0.7,!=0.0.8,!=0.1,!=0.1.1", "ruff==0.14.10", # When bumping `transformers-mlinter`, sync repo-local rule overrides from # `utils/rules.toml` back into the released package. "transformers-mlinter==0.1.5", "ty==0.0.20", - # `sacrebleu` not used in `transformers`. However, it is needed in several tests, when a test calls - # `evaluate.load("sacrebleu")`. This metric is used in the examples that we use to test the `Trainer` with, in the - # `Trainer` tests (see references to `run_translation.py`). - "sacrebleu>=1.4.12,<2.0.0", "sacremoses", "safetensors>=0.8.0", "sagemaker>=2.31.0", @@ -222,16 +215,12 @@ def deps_list(*pkgs): "timeout-decorator", "parameterized", "psutil", - "dill", "diffusers", # Needed for VibeVoice TTS integration tests - "evaluate", - "rouge-score", "nltk", "sacremoses", "rjieba", "beautifulsoup4", "tensorboard", - "sacrebleu", # needed in trainer tests, see references to `run_translation.py` "filelock", # filesystem locks, e.g., to prevent parallel downloads ) + extras["docs"] diff --git a/src/transformers/dependency_versions_table.py b/src/transformers/dependency_versions_table.py index 91429504eac2..0ed9d02e2fcc 100644 --- a/src/transformers/dependency_versions_table.py +++ b/src/transformers/dependency_versions_table.py @@ -11,8 +11,6 @@ "datasets": "datasets>=2.15.0", "deepspeed": "deepspeed>=0.9.3", "diffusers": "diffusers==0.35.2", - "dill": "dill<0.3.5", - "evaluate": "evaluate>=0.4.6", "faiss-cpu": "faiss-cpu", "fastapi": "fastapi", "filelock": "filelock", @@ -53,11 +51,9 @@ "regex": "regex>=2025.10.22", "rhoknp": "rhoknp>=1.1.0,<1.3.1", "rjieba": "rjieba", - "rouge-score": "rouge-score!=0.0.7,!=0.0.8,!=0.1,!=0.1.1", "ruff": "ruff==0.14.10", "transformers-mlinter": "transformers-mlinter==0.1.5", "ty": "ty==0.0.20", - "sacrebleu": "sacrebleu>=1.4.12,<2.0.0", "sacremoses": "sacremoses", "safetensors": "safetensors>=0.8.0", "sagemaker": "sagemaker>=2.31.0", diff --git a/src/transformers/models/deit/modeling_deit.py b/src/transformers/models/deit/modeling_deit.py index 3bc5cd69e5cb..aa6a586eb08a 100644 --- a/src/transformers/models/deit/modeling_deit.py +++ b/src/transformers/models/deit/modeling_deit.py @@ -402,13 +402,6 @@ def forward( @auto_docstring( custom_intro=""" DeiT Model with a decoder on top for masked image modeling, as proposed in [SimMIM](https://huggingface.co/papers/2111.09886). - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) class DeiTForMaskedImageModeling(DeiTPreTrainedModel): diff --git a/src/transformers/models/focalnet/modeling_focalnet.py b/src/transformers/models/focalnet/modeling_focalnet.py index 27038f206f8c..edd9d4377f35 100644 --- a/src/transformers/models/focalnet/modeling_focalnet.py +++ b/src/transformers/models/focalnet/modeling_focalnet.py @@ -670,13 +670,6 @@ def forward( FocalNet Model with a decoder on top for masked image modeling. This follows the same implementation as in [SimMIM](https://huggingface.co/papers/2111.09886). - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) class FocalNetForMaskedImageModeling(FocalNetPreTrainedModel): diff --git a/src/transformers/models/hiera/modeling_hiera.py b/src/transformers/models/hiera/modeling_hiera.py index 7ebc67dbccba..d588f5c5770e 100644 --- a/src/transformers/models/hiera/modeling_hiera.py +++ b/src/transformers/models/hiera/modeling_hiera.py @@ -1058,13 +1058,6 @@ def forward(self, feature_maps: list[torch.Tensor]) -> torch.Tensor: @auto_docstring( custom_intro=""" The Hiera Model transformer with the decoder on top for self-supervised pre-training. - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) class HieraForPreTraining(HieraPreTrainedModel): diff --git a/src/transformers/models/swin/modeling_swin.py b/src/transformers/models/swin/modeling_swin.py index 14525c194830..ab51ec1b5986 100644 --- a/src/transformers/models/swin/modeling_swin.py +++ b/src/transformers/models/swin/modeling_swin.py @@ -892,13 +892,6 @@ def forward( @auto_docstring( custom_intro=""" Swin Model with a decoder on top for masked image modeling, as proposed in [SimMIM](https://huggingface.co/papers/2111.09886). - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) class SwinForMaskedImageModeling(SwinPreTrainedModel): diff --git a/src/transformers/models/swin/modular_swin.py b/src/transformers/models/swin/modular_swin.py index 3d077ee501ca..8a0d9330bbd4 100644 --- a/src/transformers/models/swin/modular_swin.py +++ b/src/transformers/models/swin/modular_swin.py @@ -851,13 +851,6 @@ def forward( @auto_docstring( custom_intro=""" Swin Model with a decoder on top for masked image modeling, as proposed in [SimMIM](https://huggingface.co/papers/2111.09886). - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) class SwinForMaskedImageModeling(SwinPreTrainedModel): diff --git a/src/transformers/models/swinv2/modeling_swinv2.py b/src/transformers/models/swinv2/modeling_swinv2.py index 472bcc6ded6f..315b28b28740 100644 --- a/src/transformers/models/swinv2/modeling_swinv2.py +++ b/src/transformers/models/swinv2/modeling_swinv2.py @@ -975,13 +975,6 @@ def forward( custom_intro=""" Swinv2 Model with a decoder on top for masked image modeling, as proposed in [SimMIM](https://huggingface.co/papers/2111.09886). - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) # Todo - Refactor as part of vision refactor. Copied from transformers.models.swin.modeling_swin.SwinForMaskedImageModeling with swin->swinv2, base-simmim-window6-192->tiny-patch4-window8-256,SWIN->SWINV2,Swin->Swinv2,192->256 diff --git a/src/transformers/models/timm_wrapper/image_processing_timm_wrapper.py b/src/transformers/models/timm_wrapper/image_processing_timm_wrapper.py index 05c0694026ab..20119d85ec2b 100644 --- a/src/transformers/models/timm_wrapper/image_processing_timm_wrapper.py +++ b/src/transformers/models/timm_wrapper/image_processing_timm_wrapper.py @@ -61,7 +61,7 @@ def __init__( self.data_config = timm.data.resolve_data_config(pretrained_cfg, model=None, verbose=False) self.val_transforms = timm.data.create_transform(**self.data_config, is_training=False) - # useful for training, see examples/pytorch/image-classification/run_image_classification.py + # useful for training self.train_transforms = timm.data.create_transform(**self.data_config, is_training=True) # If `ToTensor` is in the transforms, then the input should be numpy array or PIL image. diff --git a/src/transformers/models/vit/modeling_vit.py b/src/transformers/models/vit/modeling_vit.py index 1587fdb1d655..4ce496436d3b 100644 --- a/src/transformers/models/vit/modeling_vit.py +++ b/src/transformers/models/vit/modeling_vit.py @@ -391,13 +391,6 @@ def forward( @auto_docstring( custom_intro=""" ViT Model with a decoder on top for masked image modeling, as proposed in [SimMIM](https://huggingface.co/papers/2111.09886). - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) class ViTForMaskedImageModeling(ViTPreTrainedModel): diff --git a/src/transformers/models/vit_mae/modeling_vit_mae.py b/src/transformers/models/vit_mae/modeling_vit_mae.py index a248efd63ca0..d652c0a5ec4c 100755 --- a/src/transformers/models/vit_mae/modeling_vit_mae.py +++ b/src/transformers/models/vit_mae/modeling_vit_mae.py @@ -686,13 +686,6 @@ def forward( @auto_docstring( custom_intro=""" The ViTMAE Model transformer with the decoder on top for self-supervised pre-training. - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) class ViTMAEForPreTraining(ViTMAEPreTrainedModel): diff --git a/src/transformers/models/vit_mae/modular_vit_mae.py b/src/transformers/models/vit_mae/modular_vit_mae.py index 28859be4bc94..9ebf4c227083 100644 --- a/src/transformers/models/vit_mae/modular_vit_mae.py +++ b/src/transformers/models/vit_mae/modular_vit_mae.py @@ -493,13 +493,6 @@ def forward( @auto_docstring( custom_intro=""" The ViTMAE Model transformer with the decoder on top for self-supervised pre-training. - - - - Note that we provide a script to pre-train this model on custom data in our [examples - directory](https://github.com/huggingface/transformers/tree/main/examples/pytorch/image-pretraining). - - """ ) class ViTMAEForPreTraining(ViTMAEPreTrainedModel): diff --git a/src/transformers/testing_utils.py b/src/transformers/testing_utils.py index e1766a8b2d75..8a612199a217 100644 --- a/src/transformers/testing_utils.py +++ b/src/transformers/testing_utils.py @@ -2588,7 +2588,7 @@ def mockenv_context(*remove, **update): # --- pytest conf functions --- # -# to avoid multiple invocation from tests/conftest.py and examples/conftest.py - make sure it's called only once +# to avoid multiple invocation if several conftest.py files call it - make sure it's called only once pytest_opt_registered = {} diff --git a/src/transformers/training_args.py b/src/transformers/training_args.py index 30c836773cc0..6d4596e01793 100644 --- a/src/transformers/training_args.py +++ b/src/transformers/training_args.py @@ -738,21 +738,17 @@ class TrainingArguments: do_train (`bool`, *optional*, defaults to `False`): Whether to run training or not. This argument is not directly used by [`Trainer`], it's intended to be used - by your training/evaluation scripts instead. See the [example - scripts](https://github.com/huggingface/transformers/tree/main/examples) for more details. + by your training/evaluation scripts instead. do_eval (`bool`, *optional*): Whether to run evaluation on the validation set or not. Will be set to `True` if `eval_strategy` is different from `"no"`. This argument is not directly used by [`Trainer`], it's intended to be used by your - training/evaluation scripts instead. See the [example - scripts](https://github.com/huggingface/transformers/tree/main/examples) for more details. + training/evaluation scripts instead. do_predict (`bool`, *optional*, defaults to `False`): Whether to run predictions on the test set or not. This argument is not directly used by [`Trainer`], it's - intended to be used by your training/evaluation scripts instead. See the [example - scripts](https://github.com/huggingface/transformers/tree/main/examples) for more details. + intended to be used by your training/evaluation scripts instead. resume_from_checkpoint (`str`, *optional*): The path to a folder with a valid checkpoint for your model. This argument is not directly used by - [`Trainer`], it's intended to be used by your training/evaluation scripts instead. See the [example - scripts](https://github.com/huggingface/transformers/tree/main/examples) for more details. + [`Trainer`], it's intended to be used by your training/evaluation scripts instead. """ # Fields that accept dict values via CLI as JSON strings (e.g., '{"key": "value"}'). diff --git a/tests/fixtures/tests_samples/MRPC/dev.csv b/tests/fixtures/tests_samples/MRPC/dev.csv deleted file mode 100644 index 96beccda96d7..000000000000 --- a/tests/fixtures/tests_samples/MRPC/dev.csv +++ /dev/null @@ -1,7 +0,0 @@ -label,sentence1,sentence2 -equivalent,He said the foodservice pie business doesn 't fit the company 's long-term growth strategy .,""" The foodservice pie business does not fit our long-term growth strategy ." -not_equivalent,Magnarelli said Racicot hated the Iraqi regime and looked forward to using his long years of training in the war .,"His wife said he was "" 100 percent behind George Bush "" and looked forward to using his years of training in the war ." -not_equivalent,"The dollar was at 116.92 yen against the yen , flat on the session , and at 1.2891 against the Swiss franc , also flat .","The dollar was at 116.78 yen JPY = , virtually flat on the session , and at 1.2871 against the Swiss franc CHF = , down 0.1 percent ." -equivalent,The AFL-CIO is waiting until October to decide if it will endorse a candidate .,The AFL-CIO announced Wednesday that it will decide in October whether to endorse a candidate before the primaries . -not_equivalent,No dates have been set for the civil or the criminal trial .,"No dates have been set for the criminal or civil cases , but Shanley has pleaded not guilty ." -equivalent,Wal-Mart said it would check all of its million-plus domestic workers to ensure they were legally employed .,It has also said it would review all of its domestic employees more than 1 million to ensure they have legal status . diff --git a/tests/fixtures/tests_samples/MRPC/dev.tsv b/tests/fixtures/tests_samples/MRPC/dev.tsv deleted file mode 100644 index 5b814856c63f..000000000000 --- a/tests/fixtures/tests_samples/MRPC/dev.tsv +++ /dev/null @@ -1,7 +0,0 @@ -Quality #1 ID #2 ID #1 String #2 String -1 1355540 1355592 He said the foodservice pie business doesn 't fit the company 's long-term growth strategy . " The foodservice pie business does not fit our long-term growth strategy . -0 2029631 2029565 Magnarelli said Racicot hated the Iraqi regime and looked forward to using his long years of training in the war . His wife said he was " 100 percent behind George Bush " and looked forward to using his years of training in the war . -0 487993 487952 The dollar was at 116.92 yen against the yen , flat on the session , and at 1.2891 against the Swiss franc , also flat . The dollar was at 116.78 yen JPY = , virtually flat on the session , and at 1.2871 against the Swiss franc CHF = , down 0.1 percent . -1 1989515 1989458 The AFL-CIO is waiting until October to decide if it will endorse a candidate . The AFL-CIO announced Wednesday that it will decide in October whether to endorse a candidate before the primaries . -0 1783137 1782659 No dates have been set for the civil or the criminal trial . No dates have been set for the criminal or civil cases , but Shanley has pleaded not guilty . -1 3039165 3039036 Wal-Mart said it would check all of its million-plus domestic workers to ensure they were legally employed . It has also said it would review all of its domestic employees more than 1 million to ensure they have legal status . diff --git a/tests/fixtures/tests_samples/MRPC/train.csv b/tests/fixtures/tests_samples/MRPC/train.csv deleted file mode 100644 index 96beccda96d7..000000000000 --- a/tests/fixtures/tests_samples/MRPC/train.csv +++ /dev/null @@ -1,7 +0,0 @@ -label,sentence1,sentence2 -equivalent,He said the foodservice pie business doesn 't fit the company 's long-term growth strategy .,""" The foodservice pie business does not fit our long-term growth strategy ." -not_equivalent,Magnarelli said Racicot hated the Iraqi regime and looked forward to using his long years of training in the war .,"His wife said he was "" 100 percent behind George Bush "" and looked forward to using his years of training in the war ." -not_equivalent,"The dollar was at 116.92 yen against the yen , flat on the session , and at 1.2891 against the Swiss franc , also flat .","The dollar was at 116.78 yen JPY = , virtually flat on the session , and at 1.2871 against the Swiss franc CHF = , down 0.1 percent ." -equivalent,The AFL-CIO is waiting until October to decide if it will endorse a candidate .,The AFL-CIO announced Wednesday that it will decide in October whether to endorse a candidate before the primaries . -not_equivalent,No dates have been set for the civil or the criminal trial .,"No dates have been set for the criminal or civil cases , but Shanley has pleaded not guilty ." -equivalent,Wal-Mart said it would check all of its million-plus domestic workers to ensure they were legally employed .,It has also said it would review all of its domestic employees more than 1 million to ensure they have legal status . diff --git a/tests/fixtures/tests_samples/MRPC/train.tsv b/tests/fixtures/tests_samples/MRPC/train.tsv deleted file mode 100644 index 5b814856c63f..000000000000 --- a/tests/fixtures/tests_samples/MRPC/train.tsv +++ /dev/null @@ -1,7 +0,0 @@ -Quality #1 ID #2 ID #1 String #2 String -1 1355540 1355592 He said the foodservice pie business doesn 't fit the company 's long-term growth strategy . " The foodservice pie business does not fit our long-term growth strategy . -0 2029631 2029565 Magnarelli said Racicot hated the Iraqi regime and looked forward to using his long years of training in the war . His wife said he was " 100 percent behind George Bush " and looked forward to using his years of training in the war . -0 487993 487952 The dollar was at 116.92 yen against the yen , flat on the session , and at 1.2891 against the Swiss franc , also flat . The dollar was at 116.78 yen JPY = , virtually flat on the session , and at 1.2871 against the Swiss franc CHF = , down 0.1 percent . -1 1989515 1989458 The AFL-CIO is waiting until October to decide if it will endorse a candidate . The AFL-CIO announced Wednesday that it will decide in October whether to endorse a candidate before the primaries . -0 1783137 1782659 No dates have been set for the civil or the criminal trial . No dates have been set for the criminal or civil cases , but Shanley has pleaded not guilty . -1 3039165 3039036 Wal-Mart said it would check all of its million-plus domestic workers to ensure they were legally employed . It has also said it would review all of its domestic employees more than 1 million to ensure they have legal status . diff --git a/tests/fixtures/tests_samples/conll/sample.json b/tests/fixtures/tests_samples/conll/sample.json deleted file mode 100644 index 0bc42a92fe8c..000000000000 --- a/tests/fixtures/tests_samples/conll/sample.json +++ /dev/null @@ -1,10 +0,0 @@ -{"words": ["He", "was", "the", "27th", "pitcher", "used", "by", "the", "Angels", "this", "season", ",", "tying", "a", "major-league", "record", "."], "ner": ["O", "O", "O", "O", "O", "O", "O", "O", "B-ORG", "O", "O", "O", "O", "O", "O", "O", "O"]} -{"words": ["CHICAGO", "AT", "ATLANTA"], "ner": ["B-ORG", "O", "B-LOC"]} -{"words": ["President", "Bill", "Clinton", "earlier", "this", "month", "invoked", "special", "powers", "to", "appoint", "Fowler", "during", "the", "congressional", "recess", "because", "the", "Senate", "delayed", "confirming", "his", "nomination", "."], "ner": ["O", "B-PER", "I-PER", "O", "O", "O", "O", "O", "O", "O", "O", "B-PER", "O", "O", "O", "O", "O", "O", "B-ORG", "O", "O", "O", "O", "O"]} -{"words": ["goals", "for", ",", "goals", "against", ",", "points", ")", "."], "ner": ["O", "O", "O", "O", "O", "O", "O", "O", "O"]} -{"words": ["\"", "It", "is", "one", "step", "short", "of", "an", "emergency", "situation", ",", "\"", "a", "police", "spokesman", "said", "via", "telephone", "from", "a", "command", "post", "in", "the", "bush", "."], "ner": ["O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]} -{"words": ["U.S.", "Ambassador", "Myles", "Frechette", "applauded", "the", "move", ",", "saying", "it", "could", "prompt", "the", "Clinton", "administration", "to", "remove", "Colombia", "from", "a", "list", "of", "outcast", "nations", "that", "have", "failed", "to", "cooperate", "in", "U.S.", "counternarcotics", "efforts", "."], "ner": ["B-LOC", "O", "B-PER", "I-PER", "O", "O", "O", "O", "O", "O", "O", "O", "O", "B-PER", "O", "O", "O", "B-LOC", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "B-LOC", "O", "O", "O"]} -{"words": ["Halftime"], "ner": ["O"]} -{"words": ["It", "has", "manufacturing", "plants", "in", "San", "Diego", ";", "Creedmoor", ",", "N.C.", ";", "Hampshire", ",", "England", ";", "and", "Tijuana", ",", "Mexico", ",", "and", "distributes", "its", "prodcuts", "in", "more", "than", "120", "countries", "."], "ner": ["O", "O", "O", "O", "O", "B-LOC", "I-LOC", "O", "B-LOC", "O", "B-LOC", "O", "B-LOC", "O", "B-LOC", "O", "O", "B-LOC", "O", "B-LOC", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]} -{"words": ["Scotland", "manager", "Craig", "Brown", "said", "on", "Thursday", ":", "\"", "I", "'ve", "watched", "Duncan", "Ferguson", "in", "action", "twice", "recently", "and", "he", "'s", "bang", "in", "form", "."], "ner": ["B-LOC", "O", "B-PER", "I-PER", "O", "O", "O", "O", "O", "O", "O", "O", "B-PER", "I-PER", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]} -{"words": ["Clinton", "flew", "in", "by", "helicopter", "from", "Michigan", "City", ",", "Indiana", ",", "after", "ending", "a", "four-day", ",", "559-mile", "trip", "aboard", "a", "campaign", "train", "from", "Washington", "."], "ner": ["B-PER", "O", "O", "O", "O", "O", "B-LOC", "I-LOC", "O", "B-LOC", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "O", "B-LOC", "O"]} \ No newline at end of file diff --git a/tests/fixtures/tests_samples/swag/sample.json b/tests/fixtures/tests_samples/swag/sample.json deleted file mode 100644 index d00ad8d184e3..000000000000 --- a/tests/fixtures/tests_samples/swag/sample.json +++ /dev/null @@ -1,10 +0,0 @@ -{"ending0": "passes by walking down the street playing their instruments.", "ending1": "has heard approaching them.", "ending2": "arrives and they're outside dancing and asleep.", "ending3": "turns the lead singer watches the performance.", "label": 0, "sent1": "Members of the procession walk down the street holding small horn brass instruments.", "sent2": "A drum line"} -{"ending0": "are playing ping pong and celebrating one left each in quick.", "ending1": "wait slowly towards the cadets.", "ending2": "continues to play as well along the crowd along with the band being interviewed.", "ending3": "continue to play marching, interspersed.", "label": 3, "sent1": "A drum line passes by walking down the street playing their instruments.", "sent2": "Members of the procession"} -{"ending0": "pay the other coaches to cheer as people this chatter dips in lawn sheets.", "ending1": "walk down the street holding small horn brass instruments.", "ending2": "is seen in the background.", "ending3": "are talking a couple of people playing a game of tug of war.", "label": 1, "sent1": "A group of members in green uniforms walks waving flags.", "sent2": "Members of the procession"} -{"ending0": "are playing ping pong and celebrating one left each in quick.", "ending1": "wait slowly towards the cadets.", "ending2": "makes a square call and ends by jumping down into snowy streets where fans begin to take their positions.", "ending3": "play and go back and forth hitting the drums while the audience claps for them.", "label": 3, "sent1": "A drum line passes by walking down the street playing their instruments.", "sent2": "Members of the procession"} -{"ending0": "finishes the song and lowers the instrument.", "ending1": "hits the saxophone and demonstrates how to properly use the racquet.", "ending2": "finishes massage the instrument again and continues.", "ending3": "continues dancing while the man gore the music outside while drums.", "label": 0, "sent1": "The person plays a song on the violin.", "sent2": "The man"} -{"ending0": "finishes playing then marches their tenderly.", "ending1": "walks in frame and rubs on his hands, and then walks into a room.", "ending2": "continues playing guitar while moving from the camera.", "ending3": "plays a song on the violin.", "label": 3, "sent1": "The person holds up the violin to his chin and gets ready.", "sent2": "The person"} -{"ending0": "examines the instrument in his hand.", "ending1": "stops playing the drums and waves over the other boys.", "ending2": "lights the cigarette and sticks his head in.", "ending3": "drags off the vacuum.", "label": 0, "sent1": "A person retrieves an instrument from a closet.", "sent2": "The man"} -{"ending0": "studies a picture of the man playing the violin.", "ending1": "holds up the violin to his chin and gets ready.", "ending2": "stops to speak to the camera again.", "ending3": "puts his arm around the man and backs away.", "label": 1, "sent1": "The man examines the instrument in his hand.", "sent2": "The person"} -{"ending0": "hands her another phone.", "ending1": "takes the drink, then holds it.", "ending2": "looks off then looks at someone.", "ending3": "stares blearily down at the floor.", "label": 3, "sent1": "Someone walks over to the radio.", "sent2": "Someone"} -{"ending0": "looks off then looks at someone.", "ending1": "hands her another phone.", "ending2": "takes the drink, then holds it.", "ending3": "turns on a monitor.", "label": 3, "sent1": "Someone walks over to the radio.", "sent2": "Someone"} diff --git a/tests/fixtures/tests_samples/wmt16/sample.json b/tests/fixtures/tests_samples/wmt16/sample.json deleted file mode 100644 index 8c0e47b0648a..000000000000 --- a/tests/fixtures/tests_samples/wmt16/sample.json +++ /dev/null @@ -1,10 +0,0 @@ -{"translation": {"en": "Membership of Parliament: see Minutes", "ro": "Componenţa Parlamentului: a se vedea procesul-verbal"}} -{"translation": {"en": "Approval of Minutes of previous sitting: see Minutes", "ro": "Aprobarea procesului-verbal al şedinţei precedente: a se vedea procesul-verbal"}} -{"translation": {"en": "Membership of Parliament: see Minutes", "ro": "Componenţa Parlamentului: a se vedea procesul-verbal"}} -{"translation": {"en": "Verification of credentials: see Minutes", "ro": "Verificarea prerogativelor: a se vedea procesul-verbal"}} -{"translation": {"en": "Documents received: see Minutes", "ro": "Depunere de documente: a se vedea procesul-verbal"}} -{"translation": {"en": "Written statements and oral questions (tabling): see Minutes", "ro": "Declaraţii scrise şi întrebări orale (depunere): consultaţi procesul-verbal"}} -{"translation": {"en": "Petitions: see Minutes", "ro": "Petiţii: a se vedea procesul-verbal"}} -{"translation": {"en": "Texts of agreements forwarded by the Council: see Minutes", "ro": "Transmiterea de către Consiliu a textelor acordurilor: a se vedea procesul-verbal"}} -{"translation": {"en": "Action taken on Parliament's resolutions: see Minutes", "ro": "Cursul dat rezoluţiilor Parlamentului: a se vedea procesul-verbal"}} -{"translation": {"en": "Agenda for next sitting: see Minutes", "ro": "Ordinea de zi a următoarei şedinţe: a se vedea procesul-verbal"}} diff --git a/tests/fixtures/tests_samples/wmt_en_ro/test.json b/tests/fixtures/tests_samples/wmt_en_ro/test.json deleted file mode 100644 index 2841b1b6aab9..000000000000 --- a/tests/fixtures/tests_samples/wmt_en_ro/test.json +++ /dev/null @@ -1,20 +0,0 @@ -{ "translation": { "en": "UN Chief Says There Is No Military Solution in Syria Secretary-General Ban Ki-moon says his response to Russia's stepped up military support for Syria is that \"there is no military solution\" to the nearly five-year conflict and more weapons will only worsen the violence and misery for millions of people. The U.N. chief again urged all parties, including the divided U.N. Security Council, to unite and support inclusive negotiations to find a political solution. Ban told a news conference Wednesday that he plans to meet with foreign ministers of the five permanent council nations - the U.S., Russia, China, Britain and France - on the sidelines of the General Assembly's ministerial session later this month to discuss Syria.", "ro": "Șeful ONU declară că nu există soluții militare în Siria Secretarul General Ban Ki-moon afirmă că răspunsul său la suportul militar al Rusiei pentru Siria este că „nu există o soluție militară” la conflictul care durează de aproape cinci ani iar mai multe arme nu ar face decât să agraveze violența și suferința a milioane de oameni. Șeful ONU a solicitat din nou tuturor părților, inclusiv Consiliului de securitate ONU divizat să se unifice și să susțină negocierile pentru a găsi o soluție politică. Ban a declarat miercuri în cadrul unei conferințe că intenționează să se întâlnească luna aceasta cu miniștrii de externe din cinci țări permanent prezente în consiliu - SUA, Rusia, China, Anglia și Franța - pe marginea sesiunii ministeriale a Adunării Generale pentru a discuta despre Siria." } } -{ "translation": { "en": "He expressed regret that divisions in the council and among the Syrian people and regional powers \"made this situation unsolvable.\" Ban urged the five permanent members to show the solidarity and unity they did in achieving an Iran nuclear deal in addressing the Syria crisis. 8 Poll Numbers That Show Donald Trump Is For Real Some have tried to label him a flip-flopper. Others have dismissed him as a joke. And some are holding out for an implosion. But no matter how some Republicans are trying to drag Donald Trump down from atop the polls, it hasn't worked (yet).", "ro": "Ban și-a exprimat regretul că divizările în consiliu și între poporul sirian și puterile regionale „au făcut această situație de nerezolvat”. Ban le-a cerut celor cinci membri permanenți să dea dovadă de solidaritatea și unitatea arătate atunci când au reușit să încheie un acord referitor la armele nucleare ale Iranului, abordând astfel criza din Siria. 8 cifre din sondaje care arată că Donald Trump are șanse reale Unii au încercat să îl eticheteze ca politician „flip-flop”. Alții l-au numit o glumă. Iar alții așteaptă implozia. Însă indiferent de modul în care unii republicani încearcă să îl dărâme pe Donald Trump din vârful sondajelor, nu a funcționat (încă)." } } -{ "translation": { "en": "Ten of the last 11 national polls have shown Donald Trump's lead at double digits, and some are starting to ask seriously what it means for the real estate mogul's nomination chances. Of course, it's still early in the election cycle. None of this is to say that Trump is likely to win the Republican nomination. Pundits point out that at this time in 2011, Rick Perry's lead was giving way to a rising Herman Cain, neither of whom won even one state in the nomination process. And there are many reasons he would struggle in a general election. But outside groups like Jeb Bush's Super PAC and the economic conservative group Club for Growth are recognizing Trump's staying power and beginning to unload their dollars to topple him.", "ro": "Zece din ultimele 11 sondaje naționale au arătat că Donald Trump conduce cu un procent din două cifre iar unele voci încep să se întrebe serios ce înseamnă acest lucru pentru șansele de numire ale mogulului imobiliar. Desigur, este încă prematur. Nimic din toate acestea nu spune că Trump va câștiga cursa pentru nominalizarea republicanilor. Pundits arată că, în aceeași perioadă a anului 2011, avansul lui Rick Perry îi făcea loc lui Herman Cain în sondaje, dar niciunul dintre ei nu a câștigat în vreun stat în cursa de nominalizare. Iar motivele pentru care s-ar lupta din greu la alegerile generale sunt numeroase. Însă grupurile din exterior precum Super PAC al lui Jeb Bush și grupul conservator economic Club for Growth admit puterea lui Trump și încep să îl susțină cu bani." } } -{ "translation": { "en": "Here are some recent poll numbers that suggest that the real estate mogul isn't just a passing phase: Trump's favorability ratings have turned 180 degrees. Right before Donald Trump announced his candidacy in mid-June, a Monmouth University poll showed only two in 10 Republicans had a positive view of the real estate mogul. By mid-July, it was 40 percent. In early August, it was 52 percent. Now, six in 10 Republicans have a favorable view of Donald Trump. Roughly three in 10 say they have a negative view. And these numbers hold up in early states. A Quinnipiac poll in Iowa last week found that 60 percent of Republicans there had a favorable view of Trump.", "ro": "În continuare vă prezentăm câteva cifre din sondaje recente care sugerează că mogulul imobiliar nu este doar ceva trecător: Cifrele care indică susținerea față de Trump s-au întors la 180 grade. Chiar înainte ca Donald Trump să își anunțe candidatura, la mijlocul lui iunie, un sondaj realizat de Universitatea din Monmouth arăta că doar doi din 10 republicani aveau o părere pozitivă despre mogulul imobiliar. Până la mijlocul lui iulie, procentul a urcat la 40%. La începutul lui august, era 52%. În prezent, șase din 10 republicani au o părere favorabilă despre Donald Trump. Aproximativ trei din 10 declară că au o părere negativă. Aceste cifre se mențin. Un sondaj realizat săptămâna trecută de Quinnipiac în Iowa a concluzionat că 60% dintre republicanii din regiune au o părere favorabilă despre Trump." } } -{ "translation": { "en": "Two-thirds of GOP voters would be happy with Trump as the nominee. In a CNN/ORC poll last week, 67 percent of Republicans said they would be either \"enthusiastic\" or \"satisfied\" if Trump were the nominee. Only two in 10 say they would be \"upset\" if he were the nominee. Only Ben Carson generates roughly the same level of enthusiasm as Trump (43 percent say they would be \"enthusiastic\" vs. 40 percent who say the same of Trump). The next closest in enthusiasm? Marco Rubio with only 21 percent.", "ro": "Două treimi dintre alegătorii GOP ar fi fericiți dacă Trump ar câștiga cursa pentru nominalizare. Într-un sondaj realizat săptămâna trecută de CNN/ORC, 67% dintre republicani au declarat că ar fi „entuziasmați” sau „mulțumiți” dacă Trump ar câștiga cursa pentru nominalizare. Doar doi din 10 declară că ar fi „supărați” dacă Trump ar câștiga cursa pentru nominalizare. Doar Ben Carson generează aproximativ același nivel de entuziasm ca Trump (43% declară că ar fi „entuziasmați” față de 40% care declară același lucru despre Trump). Cel mai aproape în ceea ce privește entuziasmul? Marco Rubio, cu doar 21%." } } -{ "translation": { "en": "On the flip side, 47 percent of Republican voters say they would be \"dissatisfied\" or \"upset\" if establishment favorite Jeb Bush becomes the nominee. A majority of Republicans don't see Trump's temperament as a problem. While Donald Trump has been widely criticized for his bombast and insults, 52 percent of leaned Republican voters nationwide think that the real estate mogul has the right temperament to be president, according to Monday's ABC News/Washington Post poll. The same number holds in the first-in-the-nation caucus state of Iowa, where the same 52 percent of Republicans think he has the personality to be commander in chief, according to Quinnipiac last week.", "ro": "De partea cealaltă, 47% dintre alegătorii republicani afirmă că ar fi „nemulțumiți” sau „supărați” dacă favoritul Jeb Bush câștigă cursa pentru nominalizare. Majoritatea republicanilor nu consideră temperamentul lui Trump o problemă. Deși Donald Trump a fost puternic criticat pentru insultele aduse și stilul său bombastic, 52% dintre alegătorii republicani la nivel național consideră că mogulul imobiliar are temperamentul potrivit pentru a fi președinte, conform sondajului realizat luni de ABC News/Washington Post. Regăsim aceleași cifre în statul Iowa, unde tot 52% dintre republicani cred că Trump are personalitatea potrivită pentru a fi conducător, conform sondajului realizat săptămâna trecută de Quinnipiac." } } -{ "translation": { "en": "Still, 44 percent think he doesn't have the personality to serve effectively, and almost six in 10 independents say his temperament does not belong in the White House, according to ABC/Post. Republican voters are getting used to the idea. When they put on their pundit hats, Republican voters think Trump is for real. When asked who is most likely to win the GOP nomination, four in 10 said Trump was the best bet, according to a CNN/ORC poll out last week. That's a change from when four in 10 placed their money on Jeb Bush in late July. Full disclosure: GOP voters haven't had the clearest crystal ball in the past.", "ro": "Totuși, 44% sunt de părere că nu are personalitatea necesară pentru a acționa eficient și aproape șase din 10 independenți afirmă că temperamentul său nu are ce căuta la Casa Albă, conform ABC/Post. Alegătorii republicani se obișnuiesc cu ideea. Atunci când iau atitudinea de intelectuali, alegătorii republicani consideră că Trump este autentic. Conform unui sondaj realizat săptămâna trecută de CNN/ORC, la întrebarea cine are cele mai multe șanse să câștige cursa pentru nominalizare GOP, patru din 10 au declarat că Trump. Situația s-a schimbat față de finalul lui iulie, când patru din 10 ar fi pariat pe Jeb Bush. Informare completă: în trecut, alegătorii GOP nu au citit foarte bine viitorul." } } -{ "translation": { "en": "At this time last cycle, four in 10 Republicans picked Rick Perry to win the nomination, vs. only 28 percent for eventual nominee Mitt Romney. Still, it shows that a plurality of GOP voters see Trump's campaign as plausible. Even if Republicans rallied around another candidate, Trump still beats almost everyone. Some pundits point out that the splintered field is likely contributing to Trump's lead, while anti-Trump support is be spread diffusely among more than a dozen other candidates. But a Monmouth University poll in early September shows that, in a hypothetical head-to-head matchup between Trump and most other Republican candidates, Trump almost always garners majority support.", "ro": "În aceeași perioadă a ultimelor alegeri, patru din 10 republicani l-au ales pe Rick Perry în cursa pentru nominalizare, față de doar 28% pentru Mitt Romney. Însă, aceste cifre arată că majoritatea alegătorilor GOP consideră plauzibilă campania lui Trump. Chiar dacă republicanii sau repliat spre un alt candidat. Trump încă se află în fruntea tuturor. Unele voci spun că situația divizată va contribui probabil la victoria lui Trump, în timp ce susținerea contra lui Trump se va împărți la mai mult de doisprezece candidați. Însă un sondaj derulat la începutul lui septembrie de Universitatea din Monmouth arată că, în situația ipotetică a unei colaborări între Trump și majoritatea celorlalți candidați republicani, aproape întotdeauna Trump va beneficia de susținerea majoritară." } } -{ "translation": { "en": "He leads Carly Fiorina by 13 points, Marco Rubio by 14 points, Walker by 15 points, Jeb Bush by 19 points, and, finally, Rand Paul, John Kasich and Chris Christie by 33 points each. He's in a dead heat with Ted Cruz. The only candidate who beats him? Ben Carson would lead the businessman by a wide 19 points in a hypothetical head-to-head. A bare majority of Donald Trump's supporters say they've made up their minds. A new CBS/NYT poll out on Tuesday shows that just more than half of voters who support Trump say they have locked in their votes. Obviously, a lot can happen to change that, and no one can really say they would never change their mind.", "ro": "Trump se află la distanță de 13 puncte de Carly Fiorina, la 14 puncte de Marco Rubio, la 15 puncte de Walker, la 19 puncte de Jeb Bush și, în cele din urmă, la câte 33 de puncte față de Rand Paul, John Kasich și Chris Christie. Este aproape la egalitate cu Ted Cruz. Singurul candidat care îl învinge? Ben Carson l-ar învinge pe omul de afaceri cu 19 puncte într-o confruntare ipotetică de unu la unu. Majoritatea susținătorilor lui Donald Trump declară că s-au decis. Un nou sondaj realizat marți de CBS/NYT arată că peste jumătate dintre alegătorii care îl susțin pe Trump declară că nu își schimbă opțiunea de vot. Evident, se pot întâmpla multe în acest sens și nimeni nu poate spune că aceștia nu se vor răzgândi niciodată." } } -{ "translation": { "en": "46 percent said they are leaving the door open to switching candidates. Still, Trump's strongest competition at the moment is from fellow outsider neurosurgeon Ben Carson, but voters who say they have made up their minds are twice as likely to go for Trump. Six in 10 Republicans say they agree with Trump on immigration. Even since Donald Trump called immigrants from Mexico \"rapists\" in his campaign announcement speech two months ago, immigration has been front and center in the 2016 conversation. Some are worried that Trump's bombast will drive crucial Hispanic voters away from the Republican Party and damage rebranding efforts.", "ro": "46% afirmă că lasă portița deschisă posibilității de a-și schimba opțiunea. Cu toate acestea, cel mai important adversar al lui Trump este în prezent neurochirurgul Ben Carson, însă este de două ori mai probabil ca alegătorii care declară că s-au decis să voteze cu Trump. Șase din 10 republicani afirmă că sunt de acord cu Trump în problema imigrării. De când Donald Trump i-a numit pe imigranții din Mexic „violatori” în discursul de deschidere a campaniei sale, în urmă cu două luni, imigrarea a fost subiectul central în campania pentru 2016. Unii sunt îngrijorați că stilul bombastic al lui Trump va duce la o scindare între alegătorii hispanici importanți și Partidul Republican și va prejudicia eforturile de rebranding." } } -{ "translation": { "en": "But according to Monday's new ABC/Post poll, six in 10 Republicans say they agree with Trump on immigration issues. So as long as immigration remains in the spotlight, it seems Donald Trump will remain too. Frustration with government is climbing to new highs. Donald Trump and Ben Carson now account for roughly half of the support from Republican voters, largely due to their outsider status. Six in 10 Republicans in Monday's new ABC/Post poll say they want a political outsider over someone with government experience. And they are angry at Washington, too.", "ro": "Însă, conform sondajului realizat luni de ABC/Post, șase din 10 republicani afirmă că sunt de acord cu Trump în problema imigrării. Așa că, se pare că atâta timp cât problema imigrării rămâne în lumina reflectoarelor, la fel va rămâne și Doland Trump. Frustrarea față de autorități atinge noi culmi. Donald Trump și Ben Carson sunt acum susținuți de aproape jumătate dintre alegătorii republicani, în mare parte datorită statutului lor de outsideri. Conform sondajului realizat luni de ABC/Post, șase din 10 republicani afirmă că preferă un outsider politic în detrimentul cuiva cu experiență în guvernare. Oamenii sunt de asemenea supărați pe autoritățile de la Washington." } } -{ "translation": { "en": "A Des Moines Register/Bloomberg poll in Iowa from two weeks ago shows that three in four Iowa Republicans are frustrated with Republicans in Congress, with 54 percent \"unsatisfied\" and 21 percent \"mad as hell.\" Jeremy Corbyn to make debut at Prime Minister's Questions Since his election, Mr Corbyn's debut at PMQs has been keenly awaited New Labour leader Jeremy Corbyn is to make his debut at Prime Minister's Questions later, taking on David Cameron for the first time.", "ro": "Un sondaj derulat în urmă cu două săptămâni în Iowa de către Des Moines Register/Bloomberg arată că trei din patru republicani din Iowa sunt frustrați de prestația republicanilor din COngres, 54% declarându-se „nemulțumiți” iar 21% „nervoși la culme”. Jeremy Corbyn își face debutul la Prime Minister's Questions Încă de la alegerea sa, debutul domnului Corbyn la PMQs a fost îndelung așteptat Noul lider al Partidului Laburist, Jeremy Corbyn, își va face mai târziu debutul la Prime Minister's Questions, confruntându-se pentru prima dată cu David Cameron." } } -{ "translation": { "en": "Mr Corbyn will rise to ask the first of his six allotted questions shortly after midday, with his performance likely to be closely scrutinised by the media and Labour MPs. He has called for \"less theatre and more facts\" at the weekly showpiece. He has also said he could skip some sessions, leaving them to colleagues. The encounter will be the first parliamentary test of Mr Corbyn's leadership, coming after his appointment of a shadow cabinet and his speech to the TUC annual congress on Tuesday.", "ro": "Dl Corbyn va adresa primele dintre cele șase întrebări la care are dreptul la scurt timp după prânz; prestația sa va fi probabil analizată îndeaproape de mass-media și parlamentarii laburiști. În cadrul aparițiilor săptămânale, el a cerut „mai puțin teatru și mai multe fapte”. A declarat de asemenea că poate renunța la câteva participări și că le cedează colegilor săi. Confruntarea va fi primul test parlamentar al Dl Corbyn în poziție de lider, venind după ce a numit un „cabinet fantomă” și după discursul pe care l-a ținut marți la congresul anual TUC." } } -{ "translation": { "en": "Meanwhile, the Labour leader's decision to stand in silence during the singing of the national anthem at a service on Tuesday to mark the 75th anniversary of the Battle of Britain has attracted criticism from a number of Tory MPs and is the focus of several front page stories in the newspapers. Mr Corbyn's decision not to sing the national anthem has attracted attention A spokesman for Mr Corbyn said he had \"stood in respectful silence\" and did recognise the \"heroism of the Royal Air Force in the Battle of Britain.\"", "ro": "Între timp, decizia liderului Partidului laburist de a păstra tăcerea la rostirea imnului național în cadrul unei slujbe ținute marți cu ocazia aniversării a 75 de ani de la Bătălia Angliei a atras critici din partea unor parlamentari conservatori și a ținut prima pagină a ziarelor. Decizia domnului Corbyn de a nu cânta imnul național a atras atenția Un purtător de cuvânt al Dl Corbyn a declarat că acesta „a păstrat tăcerea în mod respectuos” și a recunoscut „eroismul Forțelor aeriene britanice în Bătălia Angliei.”" } } -{ "translation": { "en": "But a member of Mr Corbyn's shadow cabinet, Owen Smith, told BBC Two's Newsnight programme he would have advised the Labour leader to sing the national anthem \"irrespective\" of his belief that the monarchy should be abolished. Nearly a dozen shadow ministers have refused to serve in Mr Corbyn's top team, citing differences over the economy, defence and foreign affairs, while less than a sixth of the parliamentary party originally backed him as leader. BBC political correspondent Robin Brant says policy differences are also \"stacking up\" within Labour following Mr Corbyn's appointment over its position on the European Union and the government's cap on benefits.", "ro": "Însă un membru al cabinetului fantomă al Dl Corbyn, Owen Smith, a declarat pentru emisiunea Two's Newsnight transmisă de BBC că i-ar fi recomandat liderului laburist să cânte imnul național „indiferent” de credința sa că monarhia ar trebui abolită. În jur de doisprezece miniștri din cabinetul fantomă au refuzat să facă parte din echipa de frunte a Dl Corbyn, argumentând prin diferențe de opinie legate de economie, apărare și externe, în timp ce mai puțin de o șesime din partidul parlamentar l-a susținut ca lider. Corespondentul politic al BBC, Robin Brant, declară că diferențele de politică „se cumulează” în Partidul Laburist după numirea domnului Corbyn referitor la poziția sa față de Uniunea Europeană și limita de beneficii." } } -{ "translation": { "en": "Mr Corbyn told the TUC conference Labour was putting forward amendments to remove the whole idea of a cap altogether. Hours later Mr Smith, the shadow work and pensions secretary, said the party was \"very clear\" that it was only opposing government plans to reduce the level of cap from £26,000 to £23,000. Mr Corbyn will be the fifth Labour leader that David Cameron has faced across the despatch box over the past decade since he became Tory leader. The Labour leader, who has promised a different approach to politics, says he has \"crowd sourced\" ideas for questions to ask Mr Cameron and has been given more than 30,000 suggestions.", "ro": "Dl Corbyn a declarat la conferința TUC că Partidul Laburist va aduce modificări prin care se va elimina integral ideea limitării. Câteva ore mai târziu, Dl Smith, Ministrul Muncii și Pensiilor, a declarat că partidul „este foarte clar” în opoziția exclusivă față de planurile guvernului de a reduce nivelul „cap” de la 26.000 lire la 23.000 lire. Dl Corbyn va fi al cincilea lider laburist cu care se confruntă David Cameron la tribună în ultimul deceniu, de când a preluat conducerea Partidului Conservator. Liderul laburist, care a promis o abordare diferită a politicii, spune că are idei „din surse externe” pentru întrebări pe care să i le adreseze Domnului Cameron și că a primit peste 30.000 de sugestii." } } -{ "translation": { "en": "The Islington North MP has said PMQs is too confrontational and that he will refrain from both \"repartee\" and trading barbs, instead vowing to focus on serious issues such as poverty, inequality and the challenges facing young people. Mr Corbyn has said that Angela Eagle, the shadow business secretary, will deputise for him at PMQs when he does not attend - for instance when Mr Cameron is travelling abroad. He has also floated the idea of allowing other colleagues to take the floor on occasion, saying he had approached the Commons Speaker John Bercow to discuss the issue.", "ro": "Parlamentarul Islington North a afirmat că PMQs implică un nivel de confruntare prea înalt și că se va abține de la replici și atacuri, angajându-se să se concentreze în schimb pe probleme serioase precum sărăcia, inegalitatea și provocările cu care se confruntă tinerii. Dl Corbyn a declarat că Angela Eagle, Ministrul de finanțe, îi va ține locul la PMQs atunci când el nu poate participa - de exemplu atunci când Dl Cameron se deplasează în străinătate. A exprimat de asemenea ideea că va permite altor colegi să ia cuvântul ocazional, spunând că l-a abordat pe Președintele Camerei Deputaților, John Bercow, pentru a discuta acest aspect." } } -{ "translation": { "en": "When he became leader in 2005, Mr Cameron said he wanted to move away from the \"Punch and Judy\" style of politics often associated with PMQs but admitted some years later that he had failed. Since it was first televised in 1990, PMQs has been seen as a key barometer of a leader's judgement, their command of the Commons and their standing among their fellow MPs although critics have argued it has become a caricature and is in need of far-reaching reforms. 'Shot in Joburg': Homeless youth trained as photographers Downtown Johannesburg is a tough place to be homeless.", "ro": "În 2005, când a preluat conducerea, Dl Cameron a declarat că dorește să renunțe la stilul politic „Punch and Judy” asociat adesea cu PMQs însă a recunoscut câțiva ani mai târziu că nu a reușit în demersul său. De la prima transmisie, în 1990, PMQs a fost considerată un barometru cheie al raționamentului unui lider, al modului în care acesta conduce Camera Deputaților și a poziției sale în rândul colegilor parlamentari, deși criticii afirmă a ca devenit o caricatură și că are nevoie de o reformare profundă. „Cadru în Joburg”: Tineri fără adăpost beneficiază de cursuri de fotografie Este dificil să fii un om fără adăpost în Johannesburg." } } -{ "translation": { "en": "But one group of former street children have found a way to learn a skill and make a living. \"I was shot in Joburg\" is a non-profit studio that teaches homeless youngsters how to take photographs of their neighbourhood and make a profit from it. BBC News went to meet one of the project's first graduates. JD Sports boss says higher wages could hurt expansion JD Sports Executive Chairman Peter Cowgill says a higher minimum wage for UK workers could mean \"more spending power in the pockets of potential consumers.\" But that spending power is unlikely to outweigh the higher labour costs at his firm, he says.", "ro": "Însă un grup de oameni care au trăit pe străzi în copilărie au găsit un mod de a învăța o meserie și de a-și câștiga traiul. „I was shot în Joburg” este un studio non-profit care îi învață pe tinerii fără adăpost să facă fotografii ale zonelor în care trăiesc și să câștige bani din asta. BBC News s-a întâlnit cu unul dintre primii absolvenți ai proiectului. Șeful JD Sports spune că salariile mai mari ar putea dăuna extinderii Președintele JD Sports, Peter Cowgill, declară că o creștere a salariului minim în Marea Britanie ar putea însemna „o putere de cumpărare mai mare în buzunarele potențialilor consumatori.” Este însă puțin probabil ca respectiva putere de cumpărare să depășească costurile mai mari pentru forța de muncă în cadrul firmei, afirmă el." } } -{ "translation": { "en": "The costs could hit JD Sports' expansion plans, he added, which could mean fewer extra jobs. Thanasi Kokkinakis backed by Tennis Australia president Steve Healy Thanasi Kokkinakis deserves kudos rather than criticism for his behaviour. Thanasi Kokkinakis has been the collateral damage in the recent storm around his friend Nick Kyrgios and deserves kudos rather than criticism for his own behaviour, according to Tennis Australia president Steve Healy.", "ro": "Costurile ar putea avea impact asupra planurilor de extindere ale JD Sports, a adăugat el, ceea ce ar putea însemna mai puține locuri de muncă noi. Thanasi Kokkinakis susținut de președintele Tennis Australia, Steve Healy Thanasi Kokkinakis ar merita să fie lăudat și nu criticat pentru comportamentul său. Thanasi Kokkinakis a fost victimă colaterală în „furtuna” creată în jurul prietenului său, Nick Kyrgios, iar comportamentul său merită mai degrabă cuvinte de laudă și nu critică, în opinia președintelui Tennis Australia, Steve Healy." } } diff --git a/tests/fixtures/tests_samples/wmt_en_ro/train.json b/tests/fixtures/tests_samples/wmt_en_ro/train.json deleted file mode 100644 index 269d5156c23e..000000000000 --- a/tests/fixtures/tests_samples/wmt_en_ro/train.json +++ /dev/null @@ -1,11 +0,0 @@ -{ "translation": { "en": "Corrections to votes and voting intentions: see Minutes Assignment conferred on a Member: see Minutes Membership of committees and delegations: see Minutes Decisions concerning certain documents: see Minutes Forwarding of texts adopted during the sitting: see Minutes Dates for next sittings: see Minutes", "ro": "Corectările voturilor şi intenţiile de vot: a se vedea procesul-verbal Misiune încredinţată unui deputat: consultaţi procesul-verbal Componenţa comisiilor şi a delegaţiilor: a se vedea procesul-verbal Decizii privind anumite documente: a se vedea procesul-verbal Transmiterea textelor adoptate în cursul prezentei şedinţe: a se vedea procesul-verbal Calendarul următoarelor şedinţe: a se vedea procesul-verbal" } } -{ "translation": { "en": "Membership of Parliament: see Minutes Approval of Minutes of previous sitting: see Minutes Membership of Parliament: see Minutes Verification of credentials: see Minutes Documents received: see Minutes Written statements and oral questions (tabling): see Minutes Petitions: see Minutes Texts of agreements forwarded by the Council: see Minutes Action taken on Parliament's resolutions: see Minutes Agenda for next sitting: see Minutes Closure of sitting (The sitting was closed at 7.45 p.m.)", "ro": "Componenţa Parlamentului: a se vedea procesul-verbal Aprobarea procesului-verbal al şedinţei precedente: a se vedea procesul-verbal Componenţa Parlamentului: a se vedea procesul-verbal Verificarea prerogativelor: a se vedea procesul-verbal Depunere de documente: a se vedea procesul-verbal Declaraţii scrise şi întrebări orale (depunere): consultaţi procesul-verbal Petiţii: a se vedea procesul-verbal Transmiterea de către Consiliu a textelor acordurilor: a se vedea procesul-verbal Cursul dat rezoluţiilor Parlamentului: a se vedea procesul-verbal Ordinea de zi a următoarei şedinţe: a se vedea procesul-verbal Ridicarea şedinţei (Se levanta la sesión a las 19.45 horas)" } } -{ "translation": { "en": "Election of Vice-Presidents of the European Parliament (deadline for submitting nominations): see Minutes (The sitting was suspended at 12.40 p.m. and resumed at 3.00 p.m.) Election of Quaestors of the European Parliament (deadline for submitting nominations): see Minutes (The sitting was suspended at 3.25 p.m. and resumed at 6.00 p.m.) Agenda for next sitting: see Minutes Closure of sitting (The sitting was closed at 6.15 p.m.) Opening of the sitting (The sitting was opened at 9.35 a.m.) Documents received: see Minutes Approval of Minutes of previous sitting: see Minutes Membership of Parliament: see Minutes", "ro": "Alegerea vicepreşedinţilor Parlamentului European (termenul de depunere a candidaturilor): consultaţi procesul-verbal (Die Sitzung wird um 12.40 Uhr unterbrochen und um 15.00 Uhr wiederaufgenommen). Alegerea chestorilor Parlamentului European (termenul de depunere a candidaturilor): consultaţi procesul-verbal (Die Sitzung wird um 15.25 Uhr unterbrochen und um 18.00 Uhr wiederaufgenommen). Ordinea de zi a următoarei şedinţe: a se vedea procesul-verbal Ridicarea şedinţei (Die Sitzung wird um 18.15 Uhr geschlossen.) Deschiderea şedinţei (Die Sitzung wird um 9.35 Uhr eröffnet.) Depunerea documentelor: a se vedea procesul-verbal Aprobarea procesului-verbal al şedinţei precedente: a se vedea procesul-verbal Componenţa Parlamentului: a se vedea procesul-verbal" } } -{ "translation": { "en": "Membership of committees (deadline for tabling amendments): see Minutes (The sitting was suspended at 7 p.m. and resumed at 9 p.m.) Agenda for next sitting: see Minutes Closure of sitting (The sitting was suspended at 23.25 p.m.) Documents received: see Minutes Communication of Council common positions: see Minutes (The sitting was suspended at 11.35 a.m. and resumed for voting time at noon) Approval of Minutes of previous sitting: see Minutes Committee of Inquiry into the crisis of the Equitable Life Assurance Society (extension of mandate): see Minutes", "ro": "Componenţa comisiilor (termenul de depunere a amendamentelor): consultaţi procesul-verbal (La seduta, sospesa alle 19.00, è ripresa alle 21.00) Ordinea de zi a următoarei şedinţe: a se vedea procesul-verbal Ridicarea şedinţei (Die Sitzung wird um 23.25 Uhr geschlossen.) Depunerea documentelor: a se vedea procesul-verbal Comunicarea poziţiilor comune ale Parlamentului: a se vedea procesul-verbal (La séance, suspendue à 11h35 dans l'attente de l'Heure des votes, est reprise à midi) Aprobarea procesului-verbal al şedinţei precedente: a se vedea procesul-verbal Comisia de anchetă privind criza societăţii de asigurări \"Equitable Life” (prelungirea mandatului): consultaţi procesul-verbal" } } -{ "translation": { "en": "Announcement by the President: see Minutes 1. Membership of committees (vote) 2. Amendment of the ACP-EC Partnership Agreement (vote) 4. Certification of train drivers operating locomotives and trains on the railway system in the Community (vote) 6. Law applicable to non-contractual obligations (\"ROME II\") (vote) 8. Seventh and eighth annual reports on arms exports (vote) Corrections to votes and voting intentions: see Minutes Membership of committees and delegations: see Minutes Request for waiver of parliamentary immunity: see Minutes Decisions concerning certain documents: see Minutes", "ro": "Comunicarea Preşedintelui: consultaţi procesul-verbal 1. Componenţa comisiilor (vot) 2. Modificarea Acordului de parteneriat ACP-CE (\"Acordul de la Cotonou”) (vot) 4. Certificarea mecanicilor de locomotivă care conduc locomotive şi trenuri în sistemul feroviar comunitar (vot) 6. Legea aplicabilă obligaţiilor necontractuale (\"Roma II”) (vot) 8. Al şaptelea şi al optulea raport anual privind exportul de armament (vot) Corectările voturilor şi intenţiile de vot: a se vedea procesul-verbal Componenţa comisiilor şi a delegaţiilor: a se vedea procesul-verbal Cerere de ridicare a imunităţii parlamentare: consultaţi procesul-verbal Decizii privind anumite documente: a se vedea procesul-verbal" } } -{ "translation": { "en": "Written statements for entry", "ro": "Declaraţii scrise înscrise" } } -{ "translation": { "en": "Written statements for entry in the register (Rule 116): see Minutes Forwarding of texts adopted during the sitting: see Minutes Dates for next sittings: see Minutes Adjournment of the session I declare the session of the European Parliament adjourned. (The sitting was closed at 1 p.m.) Approval of Minutes of previous sitting: see Minutes Membership of Parliament: see Minutes Request for the defence of parliamentary immunity: see Minutes Appointments to committees (proposal by the Conference of Presidents): see Minutes Documents received: see Minutes Texts of agreements forwarded by the Council: see Minutes", "ro": "Declaraţii scrise înscrise în registru (articolul 116 din Regulamentul de procedură): a se vedea procesul-verbal Transmiterea textelor adoptate în cursul prezentei şedinţe: a se vedea procesul-verbal Calendarul următoarelor şedinţe: a se vedea procesul-verbal Întreruperea sesiunii Dichiaro interrotta la sessione del Parlamento europeo. (La seduta è tolta alle 13.00) Aprobarea procesului-verbal al şedinţei precedente: a se vedea procesul-verbal Componenţa Parlamentului: a se vedea procesul-verbal Cerere de apărare a imunităţii parlamentare: consultaţi procesul-verbal Numiri în comisii (propunerea Conferinţei preşedinţilor): consultaţi procesul-verbal Depunerea documentelor: a se vedea procesul-verbal Transmiterea de către Consiliu a textelor acordurilor: a se vedea procesul-verbal" } } -{ "translation": { "en": "Action taken on Parliament's resolutions: see Minutes Oral questions and written statements (tabling): see Minutes Written statements (Rule 116): see Minutes Agenda: see Minutes 1. Appointments to parliamentary committees (vote): see Minutes Voting time Agenda for next sitting: see Minutes Closure of sitting (The sitting was closed at 12 midnight) Opening of the sitting (The sitting was opened at 09.05) Documents received: see Minutes Approval of Minutes of previous sitting: see Minutes 1. Protection of passengers against displaced luggage (vote) 2.", "ro": "Continuări ale rezoluţiilor Parlamentului: consultaţi procesul-verbal Declaraţii scrise şi întrebări orale (depunere): consultaţi procesul-verbal Declaraţii scrise (articolul 116 din Regulamentul de procedură) Ordinea de zi: a se vedea procesul-verbal 1. Numiri în comisiile parlamentare (vot): consultaţi procesul-verbal Timpul afectat votului Ordinea de zi a următoarei şedinţe: a se vedea procesul-verbal Ridicarea şedinţei (La seduta è tolta alle 24.00) Deschiderea şedinţei (The sitting was opened at 09.05) Depunerea documentelor: a se vedea procesul-verbal Aprobarea procesului-verbal al şedinţei precedente: a se vedea procesul-verbal 1. Protecţia pasagerilor împotriva deplasării bagajelor (vot) 2." } } -{ "translation": { "en": "Approval of motor vehicles with regard to the forward field of vision of the driver (vote) 3. EC-Korea Agreement on scientific and technological cooperation (vote) 4. Mainstreaming sustainability in development cooperation policies (vote) 5. Draft Amending Budget No 1/2007 (vote) 7. EC-Gabon Fisheries Partnership (vote) 10. Limitation periods in cross-border disputes involving personal injuries and fatal accidents (vote) 12. Strategy for a strengthened partnership with the Pacific Islands (vote) 13. The European private company statute (vote) That concludes the vote.", "ro": "Omologarea vehiculelor cu motor cu privire la câmpul de vizibilitate înainte al conducătorului auto (vot) 3. Acordul CE-Coreea de cooperare ştiinţifică şi tehnologică (vot) 4. Integrarea durabilităţii în politicile de cooperare pentru dezvoltare (vot) 5. Proiect de buget rectificativ nr.1/2007 (vot) 7. Acordul de parteneriat în domeniul pescuitului între Comunitatea Europeană şi Republica Gaboneză (vot) 10. Termenele de prescripţie aplicabile în cadrul litigiilor transfrontaliere cu privire la vătămările corporale şi accidentele mortale (vot) 12. Relaţiile UE cu insulele din Pacific: Strategie pentru un parteneriat consolidat (vot) 13. Statutul societăţii private europene (vot) Damit ist die Abstimmungsstunde beendet." } } -{ "translation": { "en": "Corrections to votes and voting intentions: see Minutes Assignment conferred on a Member: see Minutes Membership of committees and delegations: see Minutes Decisions concerning certain documents: see Minutes Forwarding of texts adopted during the sitting: see Minutes Dates for next sittings: see Minutes", "ro": "Corectările voturilor şi intenţiile de vot: a se vedea procesul-verbal Misiune încredinţată unui deputat: consultaţi procesul-verbal Componenţa comisiilor şi a delegaţiilor: a se vedea procesul-verbal Decizii privind anumite documente: a se vedea procesul-verbal Transmiterea textelor adoptate în cursul prezentei şedinţe: a se vedea procesul-verbal Calendarul următoarelor şedinţe: a se vedea procesul-verbal" } } -{ "translation": { "en": "Written statements for entry", "ro": "Declaraţii scrise înscrise" } } diff --git a/tests/fixtures/tests_samples/wmt_en_ro/val.json b/tests/fixtures/tests_samples/wmt_en_ro/val.json deleted file mode 100644 index 22cdd68ecd1c..000000000000 --- a/tests/fixtures/tests_samples/wmt_en_ro/val.json +++ /dev/null @@ -1,16 +0,0 @@ -{ "translation": { "en": "Brazil's Former Presidential Chief-of-Staff to Stand Trial A federal judge on Tuesday accepted the charges filed against Brazil's former presidential chief of staff for his alleged involvement in a massive corruption scheme at state-owned oil company Petrobras. The federal prosecutor's office said Jose Dirceu will face trial on the corruption, racketeering and money laundering charges filed earlier this month. Fourteen other people will also be tried, including Joao Vaccari Neto, the former treasurer of Brazil's governing Workers' Party and Renato de Souza Duque, Petrobras' former head of corporate services.", "ro": "Fostul șef al cabinetului prezidențial brazilian este adus în fața instanței Marți, un judecător federal a acceptat acuzațiile aduse împotriva fostului șef al cabinetului prezidențial brazilian pentru presupusa implicare a acestuia într-o schemă masivă de corupție privind compania petrolieră de stat Petrobras. Biroul procurorului federal a declarat că Jose Dirceu va fi trimis în judecată pentru acuzațiile de corupție, înșelătorie și spălare de bani aduse în această lună. Alte paisprezece persoane vor fi judecate, printre acestea numărându-se Joao Vaccari Neto, fostul trezorier al Partidului Muncitorilor, aflat la putere în Brazilia, și Renato de Souza Duque, fostul președinte al serviciilor pentru întreprinderi ale Petrobras." } } -{ "translation": { "en": "Dirceu is the most senior member of the ruling Workers' Party to be taken into custody in connection with the scheme. Dirceu served as former President Luiz Inacio Lula da Silva's chief of staff between 2003 and 2005. He was arrested early August in his home, where he already was under house arrest serving an 11-year sentence for his involvement in a cash-for-votes scheme in Congress more than 10 years ago. Prosecutors have said that Dirceu masterminded the kickback scheme at Petrobras, accepted bribes while in office and continued to receive payments from contractors after he was jailed in late 2013 for the vote-buying scandal.", "ro": "Dirceu este cel mai vechi membru al Partidului Muncitorilor aflat la guvernare luat în custodie pentru legăturile cu această schemă. Dirceu a servit ca șef de cabinet al fostului președinte Luiz Inacio Lula da Silva între 2003 și 2005. A fost arestat la începutul lui august de acasă, unde deja se afla sub arest la domiciliu, cu o pedeapsă de 11 ani pentru implicarea într-o schemă de cumpărare a voturilor în Congres cu peste 10 ani în urmă. Procurorii au declarat că Dirceu a dezvoltat schema de luare de mită de la Petrobras, a acceptat mită în timp ce se afla în funcție și a continuat să primească plăți de la antreprenori după ce a fost închis la sfârșitul lui 2013 pentru scandalul voturilor cumpărate." } } -{ "translation": { "en": "According to prosecutors, the scheme at Petrobras involved roughly $2 billion in bribes and other illegal funds. Some of that money was allegedly funneled back to campaign coffers of the ruling party and its allies. It also allegedly included the payment of bribes to Petrobras executives in return for inflated contracts. 'Miraculous' recovery for Peshawar massacre schoolboy A teenager paralysed after being shot four times in Pakistan's deadliest terror attack has made a \"miraculous\" recovery following treatment in the UK. Muhammad Ibrahim Khan, 13, had been told by doctors in Pakistan that he would never walk again.", "ro": "Conform procurorilor, schema de la Petrobras a implicat aproximativ 2 miliarde de dolari sub formă de mită și alte fonduri ilegale. O parte din acei bani s-ar fi întors în fondul de campanie al partidului aflat la guvernare și al aliaților acestora. De asemenea, ar fi inclus mită către directorii Petrobras în schimbul unor contracte umflate. Recuperarea „miraculoasă” a unui elev supraviețuitor al masacrului de la Peshawar Un adolescent paralizat după ce fusese împușcat de patru ori în cel mai cumplit atac terorist din Pakistan a reușit o recuperare „miraculoasă” după ce a urmat un tratament în Regatul Unit. Lui Mohamed Ibrahim Khan, în vârstă de 13 ani, doctorii din Pakistan îi spuseseră că nu va mai putea să meargă niciodată." } } -{ "translation": { "en": "At least 140 people, mostly children, were killed when gunmen stormed Peshawar's Army Public School last December. Muhammad, who arrived in London last month for surgery, is being discharged from hospital later. Exactly nine months ago, on an ordinary Tuesday morning, Muhammad sat in his first aid class listening to his teachers intently. At the same time seven gunmen disguised in security uniforms were entering the Army Public School. They were strapped with explosives and had one simple mission in mind: Kill every man, woman and child they came across. \"I can't forget what happened that day,\" Muhammad says with a severe stare.", "ro": "Cel puțin 140 de persoane, majoritatea copii, au fost ucise când bărbați înarmați au atacat școala publică a armatei din Peshawar în luna decembrie a anului trecut. Mohamed, care a sosit la Londra luna trecută pentru operație, va fi externat mai târziu din spital. Exact cu nouă luni în urmă, într-o dimineață obișnuită de marți, Mohamed stătea la ora de primul ajutor și își asculta atent profesorii. Chiar atunci, șapte bărbați înarmați deghizați în uniformele agenților de pază intrau în școala publică a armatei. Purtau centuri cu explozivi și aveau de îndeplinit o misiune simplă: să îi ucidă pe toți bărbații, femeile și copiii care le ieșeau în cale. „Nu pot uita ce s-a întâmplat în acea zi”, spune Mohamed cu o privire aspră." } } -{ "translation": { "en": "We were sitting in the auditorium, we were asking questions... and then we heard heavy gunfire outside. The terrorists moved inside and they started killing - our teacher was burned alive. Muhammad described pulling four other pupils out of the auditorium as the carnage unfolded. He said he then heard his friend, Hamza calling to him. He said, 'oh brother save me'. I held his hand. That's when I was shot in the back, and he was shot in the head. Most of the people killed in the attack were pupils Hamza died in Muhammad's arms. Muhammad recalled blacking out after that, and the next thing he knew he was in a hospital bed, paralysed from the waist down.", "ro": "Stăteam în amfiteatru, puneam întrebări... apoi am auzit focuri de armă afară. Teroriștii au intrat înăuntru și au început să ucidă. Profesorul nostru a fost ars de viu. Mohamed descrie cum a scos patru elevi din amfiteatru în timp ce se desfășura carnagiul. Apoi spune că și-a auzit prietenul, pe Hamza, strigându-l. Spunea „oh, frate, salvează-mă”. L-am ținut de mână. Atunci eu am fost împușcat în spate, iar el în cap. Cei mai mulți dintre cei uciși în atac erau elevi Hamza a murit în brațele lui Mohamed. Mohamed își amintește că imediat după asta a leșinat și că următorul lucru pe care l-a știut a fost că se afla pe un pat de spital, paralizat de la brâu în jos." } } -{ "translation": { "en": "Doctors in Peshawar in northern Pakistan, and then Rawalpindi, close to the capital, told his family there was no treatment, and he would never walk again. \"Seeing him I felt like my soul had left my body,\" says Muhammad's father, Sher Khan Those nine months were the hardest in my life. But Mr Khan and his wife, Sherbano, refused to believe that their cricket-mad son would never be able to use his legs again. They campaigned, and appealed for help on Pakistani TV, gaining the support of high profile people such as cricketer turned politician Imran Khan.", "ro": "Doctorii din Peshawar din nordul Pakistanului, apoi cei din Rawalpindi, aproape de capitală, i-au spus familiei sale că nu exista tratament și că nu va mai putea merge niciodată. „Când l-am văzut, am simțit cum îmi iese sufletul”, spune Sher Khan, tatăl lui Mohamed. Acele nouă luni au fost cele mai grele din viața mea. Însă Khan și soția lui, Sherbano, au refuzat să creadă că fiul lor atât de pasionat de crichet nu-și va mai putea folosi vreodată picioarele. Au făcut o campanie și au cerut ajutor de la televiziunea pakistaneză, atrăgând sprijinul unor oameni faimoși precum Imran Khan, jucător de crichet devenit politician." } } -{ "translation": { "en": "Finally, they were able to raise the funds to bring Muhammad to the UK and provide him with treatment at London's private Harley Street Clinic. Consultant neurosurgeon Irfan Malik described Muhammad as \"terrified\" when he first arrived at the hospital. \"He'd spent the last [few] months lying on a bed, unable to move side to side,\" says Mr Malik. He was weak, he had a pressure sore on his back. He wasn't in great shape. A vertebra at the base of Muhammad's spine was destroyed Muhammad was shot in his shoulder, his hip, and his back during the attack, damaging his lower spine - leading to paralysis.", "ro": "Într-un final, au reușit să strângă fonduri pentru a-l duce pe Mohamed în Regatul Unit și a-i oferi tratament la clinica privată Harley Street din Londra. Neurochirurgul consultant Irfan Malik l-a descris pe Mohamed drept „înspăimântat” când acesta a ajuns la spital. „Își petrecuse ultimele [câteva] luni zăcând în pat, fără să se poată mișca de pe o parte pe alta, spune Malik. Era slăbit, se pusese multă presiune pe spatele lui. Nu era într-o formă prea bună. O vertebră de la baza coloanei vertebrale a lui Mohamed fusese distrusă Mohamed fusese împușcat în umăr, în șold și în spate în timpul atacului, iar coloana vertebrală inferioară îi fusese distrusă, ducând la paralizie." } } -{ "translation": { "en": "But during six hours of surgery, Mr Malik and his team were able to reattach nerve endings and reconstruct the damaged part of the spine. Even Mr Malik was surprised at what happened next. Exactly one week after the surgery Muhammad stood up and started taking steps and walking. We were not expecting to get that sort of excellent result. That was miraculous,\" he says. Less than two weeks after his operation, Muhammad is ready to leave hospital and start the long road to recovery. Muhammad has defied the odds and started to walk again He says he wants to build his strength and continue his education in the UK. But he says he is determined to return to Pakistan, join the army and help fight terrorism.", "ro": "Însă, în timpul unei operații care a durat șase ore, Malik și echipa lui au reușit să lege din nou terminațiile nervoase și să reconstruiască partea distrusă a coloanei. Chiar și Malik a fost surprins de ceea ce s-a întâmplat în continuare. Exact la o săptămână după operație, Mohamed s-a ridicat și a început să facă pași și să meargă. Nu ne așteptam la un rezultat atât de bun. A fost un miracol”, spune acesta. În mai puțin de două săptămâni de la operație, Mohamed este gata să părăsească spitalul și să înceapă procesul lung de recuperare. Mohamed a sfidat soarta și a început să meargă din nou Vrea să devină puternic și să își continue studiile în Regatul Unit. Însă este hotărât să revină în Pakistan, să se înroleze în armată și să lupte împotriva terorismului." } } -{ "translation": { "en": "\"I feel like I have a second chance at life,\" he says as he shows off pictures he's drawn of guns scribbled out next to school books and pens Muhammad grows physically stronger every day but the psychological trauma he continues to endure is unimaginable. \"My anger is not diminishing\" he says. In my school little kids were killed. What was their crime? His mother, wiping a tear from her eye, caressed his head and said: \"I can see my son walking again.\" He'll be able to get on with his normal life. 'Super Voice' 4G service from Three offers better signal Three is making use of a lower frequency 4G spectrum that can travel more widely", "ro": "„Simt că am încă o șansă la viață” spune el, arătând imaginile cu arme desenate de el lângă manuale școlare și stilouri Fizic, Mohamed devine tot mai puternic în fiecare zi, însă trauma psihologică prin care trece și acum este de neimaginat. „Furia mea nu a scăzut”, mărturisește el. În școala mea au fost uciși copii mici. Ce crimă au comis ei? Mama lui își șterge o lacrimă, îl mângâie pe creștet și spune: „Îmi văd fiul mergând din nou”. Va putea să-și continue firesc viața. Serviciul 4G „Super Voice” de la Three oferă semnal mai bun Three folosește un spectru 4G cu o frecvență mai joasă, care poate acoperi o zonă mai extinsă" } } -{ "translation": { "en": "Mobile phone provider Three has launched a UK service it says will improve reception inside buildings and in rural black spots. Its 4G Super Voice enables customers to make calls and send texts using a lower frequency spectrum. Other networks are looking into introducing the technology, known as Voice Over Long-Term Evolution (VoLTE). It currently works on only the Samsung Galaxy S5, but recent iPhone handsets will be added in the coming months. Three said up to 5.5 million customers would have access to the service by 2017.", "ro": "Furnizorul de telefonie mobilă Three a lansat în Regatul Unit un serviciu despre care spune că va îmbunătăți recepția în interiorul clădirilor și în zonele rurale fără semnal. Serviciul 4G Super Voice le permite clienților să efectueze apeluri și să trimită mesaje text folosind un spectru cu o frecvență mai joasă. Și alte rețele intenționează să introducă aceeași tehnologie, cunoscută ca „Voice Over Long-Term Evolution (VoLTE)”. Aceasta funcționează momentan doar cu Samsung Galaxy S5, însă telefoanele iPhone recente vor beneficia de ea în lunile următoare. Three menționează că până la 5,5 milioane de clienți vor avea acces la serviciu până în 2017." } } -{ "translation": { "en": "Chief technology officer Bryn Jones said: \"By the end of the year, one million of our customers will have access to better indoor coverage and be able to use their phones in more places than ever before.\" Stars prepare for panto season Pantomime season is big business for theatres up and down the UK, with many getting ready for this year's season now. Some of the biggest names in showbusiness now take part in the yuletide theatre. Matthew Kelly and Hayley Mills will be appearing in Cinderella - one as an ugly sister, the other as fairy godmother. They reveal their panto secrets to BBC Breakfast. Steven Wilson: 'If I don't do anything, I feel this creeping guilt'", "ro": "Responsabilul șef pentru tehnologie, Bryn Jones a declarat: „Până la sfârșitul anului, un milion dintre clienții noștri vor avea acces la o acoperire mai bună în interior și își vor putea folosi telefoanele în mai multe locuri ca până acum”. Vedetele se pregătesc pentru stagiunea de pantomimă Stagiunea de pantomimă este foarte importantă pentru teatrele din tot Regatul Unit, multe dintre ele pregătindu-se acum pentru stagiunea din acest an. Acum, la teatrul de Crăciun participă unele dintre numele cele mai mari din showbusiness. Matthew Kelly și Hayley Mills vor apărea în Cenușăreasa - primul în rolul uneia dintre surorile rele, iar a doua în rolul zânei. Aceștia dezvăluie secretele pantomimei lor la BBC Breakfast. Steven Wilson: „Dacă nu fac nimic, mă simt vinovat”" } } -{ "translation": { "en": "Steven Wilson was recently the big winner at the Progressive Music Awards Steven Wilson is often dubbed the hardest working musician in the world of progressive rock. The multi-talented musician won three prizes at this month's Progressive Music Awards in London, including album of the year for Hand. The Guardian's five-star review called it \"a smart, soulful and immersive work of art.\" Since the 1980s, Wilson has been the driving force in a number of musical projects, the best known of which is the rock band Porcupine Tree. Now, ahead of two sell-out shows at the Royal Albert Hall, Wilson is releasing a vinyl-only double LP, Transience, to showcase the \"more accessible\" side of his solo output.", "ro": "Steven Wilson a fost desemnat recent drept marele câștigător al Progressive Music Awards Steven Wilson a fost numit de multe ori drept cel mai muncitor muzician din lumea rockului progresiv. Talentatul muzician a câștigat trei premii la Progressive Music Awards, care a avut loc luna aceasta la Londra, printre care și premiul pentru cel mai bun album al anului pentru Hand. În recenzia sa de cinci stele, The Guardian a numit albumul „o operă de artă inteligentă, expresivă și captivantă”. Încă din anii 1980, Wilson este motorul mai multor proiecte muzicale, cel mai cunoscut dintre acestea fiind trupa de rock Porcupine Tree. Acum, înainte de două spectacole cu casa închisă la Royal Albert Hall, Wilson lansează un dublu LP doar în format vinil, Transience, pentru a arăta latura „mai accesibilă” a activității sale solo." } } -{ "translation": { "en": "He tells the BBC about his love of vinyl, his busy schedule and explains how comic actor Matt Berry came to be his support act. What does vinyl mean to you? I grew up at the very tail end of the vinyl era, and at the time, I remember, we couldn't wait for CD to come along because vinyl was so frustrating. You would buy the record, take it home, and it would have a scratch, and you would have to take it back again. I love CDs, and for some kinds of music - classical for example - it is better than vinyl. But the problem with the CD and digital downloads is that there's nothing you can really cherish or treasure. Owning vinyl is like having a beautiful painting hanging in your living room.", "ro": "A povestit pentru BBC despre dragostea lui pentru viniluri și despre programul său încărcat și a explicat cum a ajuns actorul de comedie Matt Berry să îi deschidă spectacolele. Ce înseamnă vinil pentru tine? Am crescut chiar în perioada de sfârșit a erei vinilurilor și îmi amintesc că atunci abia așteptam apariția CD-ului, căci vinilul era atât de enervant. Cumpărai un disc, mergeai cu el acasă, avea o zgârietură și trebuia să îl aduci înapoi. Iubesc CD-urile, iar pentru anumite tipuri de muzică, de exemplu cea clasică, sunt mai bune decât vinilurile. Însă problema cu CD-urile și cu descărcările digitale este aceea că nu mai există nimic pe care să îl prețuiești cu adevărat. Să ai un vinil e ca și cum ai avea un tablou frumos agățat în sufragerie." } } -{ "translation": { "en": "It's something you can hold, pore over the lyrics and immerse yourself in the art work. I thought it was just a nostalgic thing, but it can't be if kids too young to remember vinyl are enjoying that kind of experience. Do you have a piece of vinyl that you treasure? The truth is I got rid of 100% of my vinyl in the 90s. All the vinyl I have is re-bought. I started off from the perspective that I wanted to recreate the collection I had when I was 15, but it's gone beyond that. The first record which I persuaded my parents to buy for me was Electric Light Orchestra's Out of the Blue.", "ro": "E ceva ce poți ține în mână, în timp ce te lași absorbit de versuri și copleșit de actul artistic. Am crezut că e doar o chestie nostalgică, însă nu are cum să fie așa dacă unor puști prea tineri să-și amintească de viniluri le place acest gen de experiență. Ai vreun vinil la care ții în mod special? Recunosc că am scăpat de toate vinilurile în anii '90. Toate vinilurile pe care le am sunt cumpărate din nou. Am pornit de la ideea de a reface colecția pe care o aveam la 15 ani, însă am trecut de limita aceea. Primul disc pe care mi-am convins părinții să mi-l cumpere a fost Out of the Blue de la Electric Light Orchestra." } } -{ "translation": { "en": "If I still had my original copy, it would have sentimental value, but, alas, it's in a charity shop somewhere. Steven Wilson hopes the album will be a doorway for potential new fans Why release your new compilation Transience on vinyl? It was originally conceived as an idea for Record Store Day, but we missed the boat on that. My record company had suggested I put together some of my shorter, more accessible songs. I got a bit obsessed by the idea to make something like \"an introduction to Steven Wilson,\" and I was committed to it being a vinyl-only release. Anyone who buys the vinyl does also get a high-resolution download.", "ro": "Dacă aș mai fi avut încă exemplarul inițial, acesta ar fi avut valoare sentimentală, însă, din păcate, se află pe undeva printr-un magazin de caritate. Steven Wilson speră că albumul va fi o poartă către posibili fani noi De ce ți-ai lansat noua compilație Transience pe vinil? Aceasta a fost concepută inițial ca idee pentru Ziua magazinelor de discuri, însă am ratat ocazia. Casa mea de discuri sugerase să adun câteva dintre melodiile mele mai scurte și mai accesibile. Am ajuns să fiu ușor obsedat de ideea de a face ceva gen „introducere în muzica lui Steven Wilson” și am ținut neapărat ca proiectul să fie lansat doar pe vinil. Cine cumpără vinilul primește, de asemenea, și o variantă descărcată la rezoluție înaltă." } } -{ "translation": { "en": "Do you have a concern that the album won't show your work in a true light?", "ro": "Ești îngrijorat că albumul nu va arăta muzica ta în adevărata ei lumină?" } } diff --git a/tests/fixtures/tests_samples/xsum/sample.json b/tests/fixtures/tests_samples/xsum/sample.json deleted file mode 100644 index ea6e8a8bb8f6..000000000000 --- a/tests/fixtures/tests_samples/xsum/sample.json +++ /dev/null @@ -1,10 +0,0 @@ -{"document": "The warning begins at 22:00 GMT on Saturday and ends at 10:00 on Sunday.\nThe ice could lead to difficult driving conditions on untreated roads and slippery conditions on pavements, the weather service warned.\nOnly the southernmost counties and parts of the most westerly counties are expected to escape.\nCounties expected to be affected are Carmarthenshire, Powys, Ceredigion, Pembrokeshire, Denbighshire, Gwynedd, Wrexham, Conwy, Flintshire, Anglesey, Monmouthshire, Blaenau Gwent, Caerphilly, Merthyr Tydfil, Neath Port Talbot, Rhondda Cynon Taff and Torfaen.", "summary": "The Met Office has issued a yellow weather warning for ice across most of Wales."} -{"document": "You can see highlights of Sunderland v Arsenal on Match of the Day at 22:20 BST on Saturday on BBC One and the BBC Sport website.\nStoke and West Ham, for example, have started to climb away from the relegation zone but the biggest worry for Sunderland fans is that their side do not look remotely capable of doing the same.\nI know the Black Cats have got out of trouble before having found themselves in a similar situation but this time, after picking up only two points from their first nine games, things look really desperate for the only top-flight team without a win.\nAt least one element of their struggles seems to be self-inflicted, with everyone at the club feeling sorry for themselves - and not just because they have lost some players to injury and conceded some costly late goals.\nThere is a negative feeling about the place with the manager David Moyes and his players talking about how they have gone backwards since last season, when they should be searching for any kind of spark that could change things around.\nFrom the outside, looking at the way they play and their lack of creativity, it is hard to see what that spark might be or what could fundamentally change under Moyes until the January transfer window opens.\nIf they can get one win under their belt then they will get a bit of belief back but, the longer this winless run goes on, the more negativity there will be.\nMedia playback is not supported on this device\nSunderland finished last season on a high under Sam Allardyce, with a run of just one defeat in their last 11 games securing their safety.\nIn the space of five months, all of that confidence and momentum seems to have been sucked out of the club, despite them effectively having the same group of players who, not so long ago, looked inspired.\nThat is not all down to Moyes, but he has to take some responsibility for it.\nI am yet to see a defined style of play from Sunderland since he took charge at the end of July.\nThat is in contrast to Allardyce's time as manager, when they were resolute and difficult to beat and, at the end of his stint at the Stadium of Light, also played with a purpose when they went forward.\nOff the pitch, Moyes has not helped himself much either.\nThere was no need for him to be so pessimistic when he came out after the second game of the season and announced they would be in a relegation fight, which did not send out the right message to his players or the fans.\nWhen he took charge, he had actually started out by being unrealistically positive - talking about Sunderland becoming a club that regularly finished in the top half of the Premier League - but his expectations went downhill very quickly.\nI know you can argue that he has been proved right, because Sunderland are now battling the drop, but it meant there was a cloud over from them almost as soon as the season had started.\nIt seems to be a case that if you stop Jermain Defoe, you stop Sunderland. His statistics stand up well in comparison to last season, but the rest of their team are not doing enough in attack.\nThey were reliant on Defoe last season too, but others did chip in - in their first nine league games of 2015-16, five players found the net. This time around, only Defoe and Patrick van Aanholt have scored in the same period.\nIt is going to be a massive struggle for them to stay up from the position they are now in anyway, but they badly need a win and quickly. I don't see it coming at home to Arsenal on Saturday, though.\nDo they even look capable of holding out for a draw against the Gunners, the way another struggling team Middlesbrough did at Emirates Stadium last weekend? No.\nIf you struggle to make chances and score goals, as Sunderland do, that puts more pressure on your defence because you know if you concede then you are in big trouble.\nAnd the Black Cats have problems at the back as well - their only clean sheet in 12 matches under Moyes was against League One side Shrewsbury Town in the EFL Cup.\nIt does not bode well against an Arsenal side that are averaging more than two goals a game this season.\nIt is hard to find any positives from Sunderland's situation but at least they have not been cut adrift at the bottom - yet.\nUnless they win soon, that could happen. I think Hull are also in for a very tough season but when I look at the other two teams immediately above them, Boro and Swansea, they definitely have more about them than the Black Cats do.\nMedia playback is not supported on this device\nChanging manager has clearly not helped Sunderland and comparisons with his predecessor do not help Moyes much either.\nYou cannot tell me that, if Allardyce was still in charge, Sunderland would have only picked up two points so far. It just would not have happened.\nMoyes replaced him relatively late in the summer, which is difficult in itself, but he can only complain about the things that have gone against him up to a point. He should be doing much better than he is.\nHe is still the manager and he is capable of turning things around, so it is right there is no suggestion of him getting the sack.\nBut that will not last forever. This industry is results-driven and Moyes' results are not good enough.\nThat clearly has to change soon and, looking at Sunderland's next few fixtures, the one that stands out as a must-win is their home game against Hull on 19 November.\nIf they fail to beat Arsenal and Bournemouth, then the visit of the Tigers will be the game to define Moyes' tenure. If Sunderland are still without a win after that, things will become extremely difficult for him.\nChris Sutton was speaking to BBC Sport's Chris Bevan.", "summary": "We are exactly a quarter of the way through the Premier League season and some teams at the bottom of the table seem to be turning things around after making a bad start."} -{"document": "The win keeps the Candystripes two points behind leaders Dundalk who won 2-0 away to Shamrock Rovers.\nFormer Plymouth striker Patterson scored his sixth goal of the season in the 14th minute at the Brandywell.\nHe shot into an empty net after the ball broke to him when keeper Dean Delany thwarted Barry McNamee.\nKurtis Byrne should have netted a speedy equaliser but the son of former Celtic player Paul Byrne completely missed his kick in front of goal.\nThat was the one big scare for Kenny Shiels' men on a night when both keepers had a quiet night.\nDerry City have won six and drawn two in the eight games they have played since losing to Finn Harps on the first day of the season.", "summary": "Rory Patterson's early goal proved enough to give second-placed Derry City a home victory over Bohemians in Friday night's Premier Division clash."} -{"document": "The centre-right coalition led by Mr Passos Coelho won the most seats in the election on 4 October.\nBut Socialist leader Antonio Costa has been working to build a coalition with far-left parties.\nMany believe that Mr Passos Coelho will fail to pass the test of a vote of no confidence in Portugal's parliament.\nPresident Anibal Cavaco Silva would then be expected to ask the left to form a government.\nThere are fears that weeks of uncertainty could harm Portugal's economic recovery, more than a year after it exited the strict terms of its €78bn (£57bn) international bailout.\nEU officials have threatened to take action against Portugal for missing a 15 October deadline to present its draft 2016 budget.\nPortugal is still running one of the highest budget deficits in the eurozone.\n12%\nof the workforce is unemployed\n20%\nof people live below the poverty line\n485,000 emigrated from Portugal between 2011 and 2014\n125% debt to GDP - the second highest rate in the European Union\nMr Passos Coelho's Social Democrats have promised to present a budget, but the two left-wing parties campaigned strongly against his outgoing government's record of harsh austerity.\nThe Left Bloc is seen as allied to the anti-austerity Syriza party in Greece, which for months tried to renegotiate the terms of Greece's eurozone bailout.\nPortugal's Communist Party is regarded as anti-euro and anti-Nato, although it is thought to have moderated its eurozone policies in recent weeks.\nIf Mr Costa's Socialists are eventually chosen to lead a left-wing coalition, it would be the first time since the fall of Portugal's dictatorship in 1974 that a right-wing president appointed a government backed by communists.\nAfter his re-appointment as prime minister leading a right-of-centre coalition, Pedro Passos Coelho has 10 days to appoint ministers and secure parliamentary approval.\nThat may prove impossible, since his coalition lost its majority in the 4 October election and the Socialists have pledged to reject his programme if their talks with other parties succeed.\nTogether, the Socialists, Left Bloc and Communist Party have a majority. All wanted the president to appoint Mr Costa - arguing that anything else was a waste of time.\nIf Mr Passos Coelho does fail, the president could then appoint Mr Costa or keep the incumbent on as caretaker.\nFresh legislative elections may only take place from June, after voters have elected a new president early next year.", "summary": "The Portuguese president has invited incumbent Prime Minister Pedro Passos Coelho to form the next government, despite him having lost his majority."} -{"document": "Nev Edwards scored an early try for Sale, before Castres' Florian Vialelle went over, but Julien Dumora's penalty put the hosts 10-7 ahead at the break.\nJoe Ford sent over a penalty before Castres' Marc-Antoine Rallier and Sales' Will Addison were sin-binned.\nJulien Caminati's late attempt to stop Charlie Ingall saw Sale awarded the decisive penalty try.\nThe win moves the English Premiership side to within one point of Pool Two leaders Newport Gwent Dragons after three games.\nSale got off to the ideal start, Edwards sprinting away for the game's opening points from an Andrei Ostrikov kick, but Castres heaped the pressure on in search of a reply, which came through Vialelle on eight minutes.\nSharks flanker Magnus Lund was forced off with a head injury before the television match official denied Castres a second try, with replays showing that the Sharks defence did enough to force full-back Caminati into touch.\nFord had a chance to put Sale ahead again, but his penalty on 27 minutes drifted wide. Dumora, however, made no mistake soon after, slotting over to give the French side the lead on 33 minutes.\nA combination of probing grubber kicks and scrappy play eventually led to Ford teeing up his second penalty attempt, with the fly-half this time booting the three points to make it 10-10.\nRallier's yellow card following a scuffle saw Ford opt for the posts soon after, but he was off target again before Sales' one-man advantage was lost as Addison was sin-binned.\nSharks pushed for the breakthrough as Ingall went close to touching down, and the video referee eventually gave the penalty try after deciding that Caminati's attempt to stop the winger was illegal.\nCastres: Caminati; Martial, Vialelle, Combezou, Decrop; Dumora, Dupont; Taumoepeau, Rallier, Montes; Samson, Moreaux, Caballero, Diarra, Beattie.\nReplacements: Beziat, Tichit, Martinez, Desroche, Babillot, Fontaine, Lamerat, Seron.\nSale: Arscott; Edwards, Addison, Jennings, Ingall; Ford, Mitchell, Lewis-Roberts, Briggs, Mujati, Mills, Ostrikov, Lund, Seymour (capt), Easter.\nReplacements: Taylor, Flynn, Parker, Beaumont, Neild, Jeffers, James, Haley.\nReferee: David Wilkinson (Ireland)", "summary": "A late penalty try gave Sale victory over Castres at Stade Pierre-Antoine in their European Challenge Cup clash."} -{"document": "The 33-year-old was released by Norwich this summer after five years at the club, during which time he made 75 Canaries first-team appearances.\nTurner also had spells on loan at Fulham and Sheffield Wednesday during his time at Carrow Road.\nIn total, the centre-back has made 436 senior career appearances for eight different clubs.\nFind all the latest football transfers on our dedicated page.", "summary": "League One side Southend United have signed former Hull and Norwich defender Michael Turner on a one-year deal."} -{"document": "United contacted St Johnstone this week with a view to speaking to 52-year-old Wright about the job but this approach was rejected by the Saints board.\nThe Tannadice club - bottom of the Premiership - are seeking to replace Jackie McNamara, who left last month.\nDave Bowman took the first team for Saturday's loss to Partick Thistle.\nThe Tangerines have won only once this season and prop up the table with five points from 10 games.\nFormer Northern Ireland goalkeeper Wright, who replaced Steve Lomas at McDiarmid Park in 2013, led St Johnstone to Scottish Cup success in his first season in charge.\nHe has also secured two successive top-six finishes for the Perth side and previously managed in his homeland.", "summary": "St Johnstone boss Tommy Wright is no longer under consideration for the Dundee United manager's job, BBC Scotland has learned."} -{"document": "Media playback is unsupported on your device\n2 November 2014 Last updated at 17:20 GMT\nHomes and businesses were damaged in the storm, but weather experts were not able to confirm it was a tornado.\nNavtej Johal reports.", "summary": "Residents in Coalville in Leicestershire are cleaning up after high winds hit the town."} -{"document": "5 August 2015 Last updated at 06:36 BST\nShe's now 84 and has been telling Newsround the inspiring story of her life before and after that devastating and world-changing event.\nThis animation contains some sad moments that you might find upsetting.\nYou can find out more about what happened in Hiroshima here.\nWatch 'Hiroshima: A Newsround Special' - Thursday 6 August at 5.30pm on the CBBC channel and on the Newsround website.", "summary": "Bun Hashizume was 14 years old and lived in Hiroshima, in Japan, when a nuclear bomb was dropped on the city 70 years ago, at the end of World War Two."} -{"document": "But what has been your moment of the year?\nFrom Ben Stokes' 258 off 198 balls against South Africa to Stuart Broad's 6-17 against the same opponents, and Alastair Cook being the first Englishman to reach 10,000 Test runs, there are lots of highlights.\nOr perhaps you revelled in Australia being skittled for just 85? Or the dog that invaded the pitch at Vizag?\nThe cricket brains of BBC Sport and BBC Radio 5 live asked you to rank your top 10, and your shortlist will be revealed on Tuesday's Tuffers and Vaughan Cricket Show (20:30 GMT, BBC Radio 5 live and online).\nVotes will no longer count but you can still pick your top 10 and share with friends.\nWhat are your top 10 cricketing moments from this year?", "summary": "It's been topsy-turvy for the England side but eventful and entertaining nonetheless."} diff --git a/tests/repo_utils/test_tests_fetcher.py b/tests/repo_utils/test_tests_fetcher.py index 76219008b031..ee9f26dda5eb 100644 --- a/tests/repo_utils/test_tests_fetcher.py +++ b/tests/repo_utils/test_tests_fetcher.py @@ -45,7 +45,6 @@ get_repo_utils_tests, get_tree_starting_at, infer_tests_to_run, - init_test_examples_dependencies, parse_commit_message, print_tree_deps_of, should_run_conftest_tests, @@ -155,18 +154,7 @@ def create_tmp_repo(tmp_dir, models=None): f"from transformers import {cls}Config, {cls}Model\nfrom ...test_modeling_common import ModelTesterMixin\n\ncode" ) - example_dir = tmp_dir / "examples" - example_dir.mkdir(exist_ok=True) - framework_dir = example_dir / "pytorch" - framework_dir.mkdir(exist_ok=True) - with open(framework_dir / "test_pytorch_examples.py", "w", encoding="utf-8") as f: - f.write("""test_args = "run_glue.py"\n""") - glue_dir = framework_dir / "text-classification" - glue_dir.mkdir(exist_ok=True) - with open(glue_dir / "run_glue.py", "w", encoding="utf-8") as f: - f.write("from transformers import BertModel\n\ncode") - - repo.index.add(["examples", "src", "tests"]) + repo.index.add(["src", "tests"]) repo.index.commit("Initial commit") if "main" not in repo.heads: repo.create_head("main") @@ -183,14 +171,12 @@ def patch_transformer_repo_path(new_folder): """ old_repo_path = tests_fetcher.PATH_TO_REPO tests_fetcher.PATH_TO_REPO = Path(new_folder).resolve() - tests_fetcher.PATH_TO_EXAMPLES = tests_fetcher.PATH_TO_REPO / "examples" tests_fetcher.PATH_TO_TRANSFORMERS = tests_fetcher.PATH_TO_REPO / "src/transformers" tests_fetcher.PATH_TO_TESTS = tests_fetcher.PATH_TO_REPO / "tests" try: yield finally: tests_fetcher.PATH_TO_REPO = old_repo_path - tests_fetcher.PATH_TO_EXAMPLES = tests_fetcher.PATH_TO_REPO / "examples" tests_fetcher.PATH_TO_TRANSFORMERS = tests_fetcher.PATH_TO_REPO / "src/transformers" tests_fetcher.PATH_TO_TESTS = tests_fetcher.PATH_TO_REPO / "tests" @@ -525,17 +511,6 @@ def test_get_module_dependencies(self): with patch_transformer_repo_path(tmp_folder): assert get_module_dependencies(BERT_MODELING_FILE) == expected_bert_dependencies - # Test with an example - create_tmp_repo(tmp_folder) - - expected_example_dependencies = ["src/transformers/models/bert/modeling_bert.py"] - - with patch_transformer_repo_path(tmp_folder): - assert ( - get_module_dependencies("examples/pytorch/text-classification/run_glue.py") - == expected_example_dependencies - ) - def test_create_reverse_dependency_tree(self): with tempfile.TemporaryDirectory() as tmp_folder: tmp_folder = Path(tmp_folder) @@ -621,28 +596,6 @@ def test_print_tree_deps_of(self): assert cs.out.strip() in [expected_std_out, expected_std_out_2] - def test_init_test_examples_dependencies(self): - with tempfile.TemporaryDirectory() as tmp_folder: - tmp_folder = Path(tmp_folder).resolve() - create_tmp_repo(tmp_folder) - - expected_example_deps = { - "examples/pytorch/test_pytorch_examples.py": [ - "examples/pytorch/text-classification/run_glue.py", - "examples/pytorch/test_pytorch_examples.py", - ], - } - - expected_examples = { - "examples/pytorch/test_pytorch_examples.py", - "examples/pytorch/text-classification/run_glue.py", - } - - with patch_transformer_repo_path(tmp_folder): - example_deps, all_examples = init_test_examples_dependencies() - assert example_deps == expected_example_deps - assert {str(f.relative_to(tmp_folder)) for f in all_examples} == expected_examples - def test_create_reverse_dependency_map(self): with tempfile.TemporaryDirectory() as tmp_folder: tmp_folder = Path(tmp_folder) @@ -655,8 +608,6 @@ def test_create_reverse_dependency_map(self): "src/transformers/__init__.py", "src/transformers/models/bert/__init__.py", "tests/models/bert/test_modeling_bert.py", - "examples/pytorch/test_pytorch_examples.py", - "examples/pytorch/text-classification/run_glue.py", } assert set(reverse_map["src/transformers/models/bert/modeling_bert.py"]) == expected_bert_deps @@ -672,8 +623,6 @@ def test_create_reverse_dependency_map(self): "src/transformers/modeling_utils.py", "tests/test_modeling_common.py", "tests/models/bert/test_modeling_bert.py", - "examples/pytorch/test_pytorch_examples.py", - "examples/pytorch/text-classification/run_glue.py", } assert set(reverse_map["src/transformers/__init__.py"]) == expected_init_deps @@ -682,8 +631,6 @@ def test_create_reverse_dependency_map(self): "src/transformers/models/bert/configuration_bert.py", "src/transformers/models/bert/modeling_bert.py", "tests/models/bert/test_modeling_bert.py", - "examples/pytorch/test_pytorch_examples.py", - "examples/pytorch/text-classification/run_glue.py", } assert set(reverse_map["src/transformers/models/bert/__init__.py"]) == expected_init_deps @@ -698,8 +645,6 @@ def test_create_reverse_dependency_map(self): "src/transformers/models/bert/configuration_bert.py", "src/transformers/models/bert/modeling_bert.py", "tests/models/bert/test_modeling_bert.py", - "examples/pytorch/test_pytorch_examples.py", - "examples/pytorch/text-classification/run_glue.py", } assert set(reverse_map["src/transformers/models/bert/__init__.py"]) == expected_init_deps @@ -774,19 +719,12 @@ def test_infer_tests_to_run(self): commit_changes("src/transformers/models/bert/modeling_bert.py", BERT_MODEL_FILE_NEW_CODE, repo) - example_tests = { - "examples/pytorch/test_pytorch_examples.py", - } - with patch_transformer_repo_path(tmp_folder): infer_tests_to_run(tmp_folder / "test-output.txt", diff_with_last_commit=True) with open(tmp_folder / "test-output.txt", encoding="utf-8") as f: tests_to_run = f.read() - with open(tmp_folder / "examples_test_list.txt", encoding="utf-8") as f: - example_tests_to_run = f.read() assert tests_to_run == "tests/models/bert/test_modeling_bert.py" - assert set(example_tests_to_run.split(" ")) == example_tests # Fake a new model addition repo = create_tmp_repo(tmp_folder, models=models) @@ -823,8 +761,6 @@ def test_infer_tests_to_run(self): infer_tests_to_run(tmp_folder / "test-output.txt") with open(tmp_folder / "test-output.txt", encoding="utf-8") as f: tests_to_run = f.read() - with open(tmp_folder / "examples_test_list.txt", encoding="utf-8") as f: - example_tests_to_run = f.read() expected_tests = { "tests/models/bert/test_modeling_bert.py", @@ -833,19 +769,15 @@ def test_infer_tests_to_run(self): "tests/test_modeling_common.py", } assert set(tests_to_run.split(" ")) == expected_tests - assert set(example_tests_to_run.split(" ")) == example_tests with patch_transformer_repo_path(tmp_folder): infer_tests_to_run(tmp_folder / "test-output.txt") with open(tmp_folder / "test-output.txt", encoding="utf-8") as f: tests_to_run = f.read() - with open(tmp_folder / "examples_test_list.txt", encoding="utf-8") as f: - example_tests_to_run = f.read() expected_tests = [f"tests/models/{name}/test_modeling_{name}.py" for name in models + ["t5"]] expected_tests = set(expected_tests + ["tests/test_modeling_common.py"]) assert set(tests_to_run.split(" ")) == expected_tests - assert set(example_tests_to_run.split(" ")) == example_tests @unittest.skip("Broken for now TODO @ArthurZucker") def test_infer_tests_to_run_with_test_modifs(self): @@ -867,42 +799,6 @@ def test_infer_tests_to_run_with_test_modifs(self): assert tests_to_run == "tests/models/bert/test_modeling_bert.py" - @unittest.skip("Broken for now TODO @ArthurZucker") - def test_infer_tests_to_run_with_examples_modifs(self): - with tempfile.TemporaryDirectory() as tmp_folder: - tmp_folder = Path(tmp_folder) - models = ["bert", "gpt2"] - repo = create_tmp_repo(tmp_folder, models=models) - - # Modification in one example trigger the corresponding test - commit_changes( - "examples/pytorch/text-classification/run_glue.py", - "from transformers import BertModeln\n\ncode1", - repo, - ) - - with patch_transformer_repo_path(tmp_folder): - infer_tests_to_run(tmp_folder / "test-output.txt", diff_with_last_commit=True) - with open(tmp_folder / "examples_test_list.txt", encoding="utf-8") as f: - example_tests_to_run = f.read() - - assert example_tests_to_run == "examples/pytorch/test_pytorch_examples.py" - - # Modification in one test example file trigger that test - repo = create_tmp_repo(tmp_folder, models=models) - commit_changes( - "examples/pytorch/test_pytorch_examples.py", - """test_args = "run_glue.py"\nmore_code""", - repo, - ) - - with patch_transformer_repo_path(tmp_folder): - infer_tests_to_run(tmp_folder / "test-output.txt", diff_with_last_commit=True) - with open(tmp_folder / "examples_test_list.txt", encoding="utf-8") as f: - example_tests_to_run = f.read() - - assert example_tests_to_run == "examples/pytorch/test_pytorch_examples.py" - def test_parse_commit_message(self): assert parse_commit_message("Normal commit") == {"skip": False, "no_filter": False, "test_all": False} diff --git a/tests/sagemaker/scripts/pytorch/run_ddp.py b/tests/sagemaker/scripts/pytorch/run_ddp.py deleted file mode 100644 index 474285841b0d..000000000000 --- a/tests/sagemaker/scripts/pytorch/run_ddp.py +++ /dev/null @@ -1,52 +0,0 @@ -import json -import logging -import os -import subprocess -from argparse import ArgumentParser - - -logger = logging.getLogger(__name__) - - -def parse_args(): - parser = ArgumentParser() - parsed, unknown = parser.parse_known_args() - for arg in unknown: - if arg.startswith(("-", "--")): - parser.add_argument(arg.split("=")[0]) - - return parser.parse_args() - - -def main(): - args = parse_args() - port = 8888 - num_gpus = int(os.environ["SM_NUM_GPUS"]) - hosts = json.loads(os.environ["SM_HOSTS"]) - num_nodes = len(hosts) - current_host = os.environ["SM_CURRENT_HOST"] - rank = hosts.index(current_host) - os.environ["NCCL_DEBUG"] = "INFO" - - if num_nodes > 1: - cmd = f"""python -m torch.distributed.launch \ - --nnodes={num_nodes} \ - --node_rank={rank} \ - --nproc_per_node={num_gpus} \ - --master_addr={hosts[0]} \ - --master_port={port} \ - ./run_glue.py \ - {"".join([f" --{parameter} {value}" for parameter, value in args.__dict__.items()])}""" - else: - cmd = f"""python -m torch.distributed.launch \ - --nproc_per_node={num_gpus} \ - ./run_glue.py \ - {"".join([f" --{parameter} {value}" for parameter, value in args.__dict__.items()])}""" - try: - subprocess.run(cmd, shell=True) - except Exception as e: - logger.info(e) - - -if __name__ == "__main__": - main() diff --git a/tests/sagemaker/test_multi_node_data_parallel.py b/tests/sagemaker/test_multi_node_data_parallel.py deleted file mode 100644 index a537be890a5d..000000000000 --- a/tests/sagemaker/test_multi_node_data_parallel.py +++ /dev/null @@ -1,99 +0,0 @@ -import json -import os -import subprocess -import unittest -from ast import literal_eval - -import pytest -from parameterized import parameterized, parameterized_class - -from . import is_sagemaker_available - - -if is_sagemaker_available(): - from sagemaker import Session, TrainingJobAnalytics - from sagemaker.huggingface import HuggingFace - - -@pytest.mark.skipif( - literal_eval(os.getenv("TEST_SAGEMAKER", "False")) is not True, - reason="Skipping test because should only be run when releasing minor transformers version", -) -@pytest.mark.usefixtures("sm_env") -@parameterized_class( - [ - { - "script": "run_glue.py", - "model_name_or_path": "distilbert/distilbert-base-cased", - "instance_type": "ml.p3.16xlarge", - "results": {"train_runtime": 650, "eval_accuracy": 0.7, "eval_loss": 0.6}, - }, - { - "script": "run_ddp.py", - "model_name_or_path": "distilbert/distilbert-base-cased", - "instance_type": "ml.p3.16xlarge", - "results": {"train_runtime": 600, "eval_accuracy": 0.7, "eval_loss": 0.6}, - }, - ] -) -class MultiNodeTest(unittest.TestCase): - def setUp(self): - subprocess.run( - f"cp ./examples/pytorch/text-classification/run_glue.py {self.env.test_path}/run_glue.py".split(), - encoding="utf-8", - check=True, - ) - assert hasattr(self, "env") - - def create_estimator(self, instance_count): - job_name = f"{self.env.base_job_name}-{instance_count}-{'ddp' if 'ddp' in self.script else 'smd'}" - # distributed data settings - distribution = {"smdistributed": {"dataparallel": {"enabled": True}}} if self.script != "run_ddp.py" else None - - # creates estimator - return HuggingFace( - entry_point=self.script, - source_dir=self.env.test_path, - role=self.env.role, - image_uri=self.env.image_uri, - base_job_name=job_name, - instance_count=instance_count, - instance_type=self.instance_type, - debugger_hook_config=False, - hyperparameters={**self.env.distributed_hyperparameters, "model_name_or_path": self.model_name_or_path}, - metric_definitions=self.env.metric_definitions, - distribution=distribution, - py_version="py36", - ) - - def save_results_as_csv(self, job_name): - TrainingJobAnalytics(job_name).export_csv(f"{self.env.test_path}/{job_name}_metrics.csv") - - # @parameterized.expand([(2,), (4,),]) - @parameterized.expand([(2,)]) - def test_script(self, instance_count): - # create estimator - estimator = self.create_estimator(instance_count) - - # run training - estimator.fit() - - # result dataframe - result_metrics_df = TrainingJobAnalytics(estimator.latest_training_job.name).dataframe() - - # extract kpis - eval_accuracy = list(result_metrics_df[result_metrics_df.metric_name == "eval_accuracy"]["value"]) - eval_loss = list(result_metrics_df[result_metrics_df.metric_name == "eval_loss"]["value"]) - # get train time from SageMaker job, this includes starting, preprocessing, stopping - train_runtime = ( - Session().describe_training_job(estimator.latest_training_job.name).get("TrainingTimeInSeconds", 999999) - ) - - # assert kpis - assert train_runtime <= self.results["train_runtime"] - assert all(t >= self.results["eval_accuracy"] for t in eval_accuracy) - assert all(t <= self.results["eval_loss"] for t in eval_loss) - - # dump tests result into json file to share in PR - with open(f"{estimator.latest_training_job.name}.json", "w", encoding="utf-8") as outfile: - json.dump({"train_time": train_runtime, "eval_accuracy": eval_accuracy, "eval_loss": eval_loss}, outfile) diff --git a/tests/sagemaker/test_multi_node_model_parallel.py b/tests/sagemaker/test_multi_node_model_parallel.py index d5ed6145a38c..76cd0648dcda 100644 --- a/tests/sagemaker/test_multi_node_model_parallel.py +++ b/tests/sagemaker/test_multi_node_model_parallel.py @@ -1,6 +1,5 @@ import json import os -import subprocess import unittest from ast import literal_eval @@ -28,21 +27,10 @@ "instance_type": "ml.p3dn.24xlarge", "results": {"train_runtime": 1600, "eval_accuracy": 0.3, "eval_loss": 1.2}, }, - { - "script": "run_glue.py", - "model_name_or_path": "FacebookAI/roberta-large", - "instance_type": "ml.p3dn.24xlarge", - "results": {"train_runtime": 1600, "eval_accuracy": 0.3, "eval_loss": 1.2}, - }, ] ) class MultiNodeTest(unittest.TestCase): def setUp(self): - subprocess.run( - f"cp ./examples/pytorch/text-classification/run_glue.py {self.env.test_path}/run_glue.py".split(), - encoding="utf-8", - check=True, - ) assert hasattr(self, "env") def create_estimator(self, instance_count): @@ -65,14 +53,13 @@ def create_estimator(self, instance_count): distribution = {"smdistributed": {"modelparallel": smp_options}, "mpi": mpi_options} - name_extension = "trainer" if self.script == "run_glue.py" else "smtrainer" # creates estimator return HuggingFace( entry_point=self.script, source_dir=self.env.test_path, role=self.env.role, image_uri=self.env.image_uri, - base_job_name=f"{self.env.base_job_name}-{instance_count}-smp-{name_extension}", + base_job_name=f"{self.env.base_job_name}-{instance_count}-smp-smtrainer", instance_count=instance_count, instance_type=self.instance_type, debugger_hook_config=False, diff --git a/tests/sagemaker/test_single_node_gpu.py b/tests/sagemaker/test_single_node_gpu.py deleted file mode 100644 index 8b3e828995e6..000000000000 --- a/tests/sagemaker/test_single_node_gpu.py +++ /dev/null @@ -1,86 +0,0 @@ -import json -import os -import subprocess -import unittest -from ast import literal_eval - -import pytest -from parameterized import parameterized_class - -from . import is_sagemaker_available - - -if is_sagemaker_available(): - from sagemaker import Session, TrainingJobAnalytics - from sagemaker.huggingface import HuggingFace - - -@pytest.mark.skipif( - literal_eval(os.getenv("TEST_SAGEMAKER", "False")) is not True, - reason="Skipping test because should only be run when releasing minor transformers version", -) -@pytest.mark.usefixtures("sm_env") -@parameterized_class( - [ - { - "script": "run_glue.py", - "model_name_or_path": "distilbert/distilbert-base-cased", - "instance_type": "ml.g4dn.xlarge", - "results": {"train_runtime": 650, "eval_accuracy": 0.6, "eval_loss": 0.9}, - }, - ] -) -class SingleNodeTest(unittest.TestCase): - def setUp(self): - subprocess.run( - f"cp ./examples/pytorch/text-classification/run_glue.py {self.env.test_path}/run_glue.py".split(), - encoding="utf-8", - check=True, - ) - assert hasattr(self, "env") - - def create_estimator(self, instance_count=1): - # creates estimator - return HuggingFace( - entry_point=self.script, - source_dir=self.env.test_path, - role=self.env.role, - image_uri=self.env.image_uri, - base_job_name=f"{self.env.base_job_name}-single", - instance_count=instance_count, - instance_type=self.instance_type, - debugger_hook_config=False, - hyperparameters={**self.env.hyperparameters, "model_name_or_path": self.model_name_or_path}, - metric_definitions=self.env.metric_definitions, - py_version="py36", - ) - - def save_results_as_csv(self, job_name): - TrainingJobAnalytics(job_name).export_csv(f"{self.env.test_path}/{job_name}_metrics.csv") - - def test_glue(self): - # create estimator - estimator = self.create_estimator() - - # run training - estimator.fit() - - # result dataframe - result_metrics_df = TrainingJobAnalytics(estimator.latest_training_job.name).dataframe() - - # extract kpis - eval_accuracy = list(result_metrics_df[result_metrics_df.metric_name == "eval_accuracy"]["value"]) - eval_loss = list(result_metrics_df[result_metrics_df.metric_name == "eval_loss"]["value"]) - # get train time from SageMaker job, this includes starting, preprocessing, stopping - train_runtime = ( - Session().describe_training_job(estimator.latest_training_job.name).get("TrainingTimeInSeconds", 999999) - ) - - # assert kpis - assert train_runtime <= self.results["train_runtime"] - assert all(t >= self.results["eval_accuracy"] for t in eval_accuracy) - assert all(t <= self.results["eval_loss"] for t in eval_loss) - - # dump tests result into json file to share in PR - with open(f"{estimator.latest_training_job.name}.json", "w", encoding="utf-8") as outfile: - json.dump({"train_time": train_runtime, "eval_accuracy": eval_accuracy, "eval_loss": eval_loss}, outfile) diff --git a/tests/trainer/distributed/scripts/vit_feature_extractor.json b/tests/trainer/distributed/scripts/vit_feature_extractor.json deleted file mode 100644 index e73176d74e12..000000000000 --- a/tests/trainer/distributed/scripts/vit_feature_extractor.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "image_processor_type": "ViTImageProcessor", - "size": 30 -} diff --git a/tests/trainer/distributed/test_trainer_distributed_deepspeed.py b/tests/trainer/distributed/test_trainer_distributed_deepspeed.py index 3c1ebce6cb84..7a002004d315 100644 --- a/tests/trainer/distributed/test_trainer_distributed_deepspeed.py +++ b/tests/trainer/distributed/test_trainer_distributed_deepspeed.py @@ -23,7 +23,6 @@ import itertools import json import os -import subprocess import unittest from copy import deepcopy from functools import partial @@ -45,7 +44,6 @@ TestCasePlus, backend_device_count, execute_subprocess_async, - get_tests_dir, get_torch_dist_unique_port, mockenv_context, read_json_file, @@ -1065,8 +1063,7 @@ class TestTrainerDistributedDeepSpeedCommon(DeepSpeedCommandsMixin, TrainerDistr """ Distributed DeepSpeed tests using ``accelerate launch``. - Some tests use a simple training script (train.py), others use example - scripts (run_translation.py, run_clm.py) for broader integration coverage. + Some tests use a simple training script (train.py). """ # ------------------------------------------------------------------- @@ -1579,128 +1576,3 @@ def test_zero3_load_registered_buffers(self): self.assertEqual(buf.item(), -42.0, f"{name} was not loaded from checkpoint") elif "layer_scalar" in name: self.assertEqual(buf.item(), 0.5, f"{name} was not loaded from checkpoint") - - -# --------------------------------------------------------------------------- -# Model Zoo — test many architectures with DeepSpeed + zero_to_fp32 recovery -# --------------------------------------------------------------------------- - -_ZOO_MODELS = { - "albert": "hf-internal-testing/tiny-albert", - "bart": "sshleifer/bart-tiny-random", - "bert": "hf-internal-testing/tiny-bert", - "bigbird_pegasus": "hf-internal-testing/tiny-random-bigbird_pegasus", - "blenderbot": "hf-internal-testing/tiny-random-blenderbot", - "bloom": "bigscience/bigscience-small-testing", - "deberta": "hf-internal-testing/tiny-random-deberta", - "deberta-v2": "hf-internal-testing/tiny-random-deberta-v2", - "distilbert": "sshleifer/tiny-distilbert-base-cased", - "electra": "hf-internal-testing/tiny-electra", - "funnel": "hf-internal-testing/tiny-random-funnel", - "gpt2": GPT2_TINY, - "gpt_neo": "hf-internal-testing/tiny-random-gpt_neo", - "gptj": GPTJ_TINY, - "layoutlm": "hf-internal-testing/tiny-layoutlm", - "led": "hf-internal-testing/tiny-random-led", - "longformer": "hf-internal-testing/tiny-random-longformer", - "m2m_100": "stas/tiny-m2m_100", - "mobilebert": "hf-internal-testing/tiny-random-mobilebert", - "mpnet": "hf-internal-testing/tiny-random-mpnet", - "prophetnet": "hf-internal-testing/tiny-random-prophetnet", - "roberta": "sshleifer/tiny-distilroberta-base", - "squeezebert": "hf-internal-testing/tiny-random-squeezebert", - "t5": T5_TINY, - "t5_v1": "hf-internal-testing/tiny-random-t5-v1.1", - "vit": "hf-internal-testing/tiny-random-vit", - "xlm-roberta": "hf-internal-testing/tiny-xlm-roberta", - "xlnet": "sshleifer/tiny-xlnet-base-cased", -} - -_ZOO_FIXTURE_DIR = get_tests_dir("fixtures") -_ZOO_SAMPLES_DIR = f"{_ZOO_FIXTURE_DIR}/tests_samples" -_ZOO_SCRIPTS_DIR = f"{os.path.join(os.path.dirname(get_tests_dir()))}/examples/pytorch" -_ZOO_VIT_FEATURE_EXTRACTOR = os.path.join(SCRIPTS_DIR, "vit_feature_extractor.json") - - -def _make_zoo_tasks(): - """Build {task_model: (script, script_args)} for each task/model combo.""" - tasks2models = { - "trans": ["bart", "m2m_100", "t5", "t5_v1"], - "clm": ["bigbird_pegasus", "blenderbot", "bloom", "gpt2", "gpt_neo", "gptj", "xlm-roberta", "prophetnet"], - "mlm": ["albert", "deberta", "deberta-v2", "distilbert", "electra", "layoutlm"], - "qa": ["led", "longformer", "mobilebert", "mpnet", "roberta", "squeezebert"], - "clas": ["bert", "xlnet"], - "img_clas": ["vit"], - } - - # task -> (script_path, task-specific args) - task_defs = { - "trans": ( - f"{_ZOO_SCRIPTS_DIR}/translation/run_translation.py", - f"--train_file {_ZOO_SAMPLES_DIR}/wmt_en_ro/train.json --source_lang en --target_lang ro " - f"--max_source_length 12 --max_target_length 12".split(), - ), - "clm": ( - f"{_ZOO_SCRIPTS_DIR}/language-modeling/run_clm.py", - f"--train_file {_ZOO_FIXTURE_DIR}/sample_text.txt --block_size 8".split(), - ), - "mlm": ( - f"{_ZOO_SCRIPTS_DIR}/language-modeling/run_mlm.py", - f"--train_file {_ZOO_FIXTURE_DIR}/sample_text.txt".split(), - ), - "qa": ( - f"{_ZOO_SCRIPTS_DIR}/question-answering/run_qa.py", - f"--train_file {_ZOO_SAMPLES_DIR}/SQUAD/sample.json".split(), - ), - "clas": ( - f"{_ZOO_SCRIPTS_DIR}/text-classification/run_glue.py", - f"--train_file {_ZOO_SAMPLES_DIR}/MRPC/train.csv --max_seq_length 12 --task_name MRPC".split(), - ), - "img_clas": ( - f"{_ZOO_SCRIPTS_DIR}/image-classification/run_image_classification.py", - f"--dataset_name hf-internal-testing/cats_vs_dogs_sample --remove_unused_columns False " - f"--max_steps 10 --image_processor_name {_ZOO_VIT_FEATURE_EXTRACTOR} " - f"--label_column_name labels".split(), - ), - } - - common_args = "--do_train --max_train_samples 4 --per_device_train_batch_size 2 --num_train_epochs 1 --fp16 --save_steps 1".split() - - result = {} - for task, models in tasks2models.items(): - script, task_args = task_defs[task] - for model in models: - model_args = ["--model_name_or_path", _ZOO_MODELS[model]] - result[f"{task}_{model}"] = (script, task_args + model_args + common_args) - - return result - - -_zoo_tasks = _make_zoo_tasks() -_zoo_params = list(itertools.product(stages, _zoo_tasks.keys())) - - -@slow -@require_deepspeed -@require_torch_accelerator -class TestDeepSpeedModelZoo(DeepSpeedCommandsMixin, TestCasePlus): - """Test many model architectures with DeepSpeed (fp16 mixed precision) via example scripts + zero_to_fp32 recovery.""" - - @parameterized.expand(_zoo_params, name_func=_parameterized_custom_name_func) - def test_zero_to_fp32(self, stage, task): - script, script_args = _zoo_tasks[task] - output_dir = self.get_auto_remove_tmp_dir() - - # 1. Train and save a checkpoint - cmd = self.get_accelerate_cmd( - script, - config_file=DS_CONFIGS[stage], - script_args=script_args + ["--output_dir", output_dir], - ) - execute_subprocess_async(cmd, env=self.get_env()) - - # 2. Recover FP32 weights from the ZeRO checkpoint - chkpt_dir = f"{output_dir}/checkpoint-1" - recovered_model_path = f"{chkpt_dir}/out.bin" - subprocess.check_call(f"{chkpt_dir}/zero_to_fp32.py {chkpt_dir} {recovered_model_path}", shell=True) - assert os.path.exists(recovered_model_path), f"{recovered_model_path} was not found" diff --git a/tests/trainer/test_trainer.py b/tests/trainer/test_trainer.py index d47c38db7485..df3f389e0a05 100644 --- a/tests/trainer/test_trainer.py +++ b/tests/trainer/test_trainer.py @@ -18,7 +18,6 @@ """ import math -import os import tempfile from functools import partial @@ -56,10 +55,8 @@ LoggingLevel, TestCasePlus, backend_device_count, - execute_subprocess_async, require_bitsandbytes, require_liger_kernel, - require_non_hpu, require_peft, require_torch, require_torch_accelerator, @@ -69,8 +66,6 @@ require_torch_multi_accelerator, require_torch_non_multi_accelerator, require_torch_tf32, - run_first, - slow, torch_device, ) from transformers.trainer_utils import align_special_tokens @@ -1274,52 +1269,6 @@ def test_use_liger_kernel_custom_config_trainer(self): class TrainerIntegrationTest(TestCasePlus): """Integration tests: compatibility, and e2e.""" - @slow - @run_first - @require_non_hpu - @require_torch_multi_accelerator - def test_end_to_end_example(self): - # Tests that `translation.py` will run without issues - script_path = os.path.abspath( - os.path.join( - os.path.dirname(__file__), "..", "..", "examples", "pytorch", "translation", "run_translation.py" - ) - ) - - with tempfile.TemporaryDirectory() as tmpdir: - command = [ - "accelerate", - "launch", - script_path, - "--model_name_or_path", - "google-t5/t5-small", - "--per_device_train_batch_size", - "1", - "--output_dir", - tmpdir, - "--do_train", - "--max_train_samples", - "64", - "--num_train_epochs", - "1", - "--dataset_name", - "wmt16", - "--dataset_config", - "ro-en", - "--source_lang", - "en", - "--target_lang", - "ro", - "--do_predict", - "--max_predict_samples", - "64", - "--predict_with_generate", - "--ddp_timeout", - "60", - ] - execute_subprocess_async(command) - # successful return here == success - any errors would have caused an error or a timeout in the sub-call - def test_special_token_alignment(self): """ Tests that special token changes in the tokenizer result in model configs updates when using the trainer, to diff --git a/tests/trainer/test_trainer_checkpointing.py b/tests/trainer/test_trainer_checkpointing.py index 042219ec7ad7..61e066e0c595 100644 --- a/tests/trainer/test_trainer_checkpointing.py +++ b/tests/trainer/test_trainer_checkpointing.py @@ -27,7 +27,6 @@ import shutil import signal import subprocess -import sys import tempfile import unittest from pathlib import Path @@ -65,9 +64,7 @@ get_torch_dist_unique_port, is_staging_test, mockenv_context, - require_accelerate, require_deepspeed, - require_non_hpu, require_peft, require_tensorboard, require_torch, @@ -640,41 +637,28 @@ def setUp(self): self.n_epochs = args.num_train_epochs self.batch_size = args.train_batch_size - @slow - @require_non_hpu - @require_accelerate - @require_torch_non_multi_accelerator def test_auto_batch_size_finder(self): - if torch.cuda.is_available(): - torch.backends.cudnn.deterministic = True + train_dataset = RegressionDataset(length=128) + model = RegressionRandomPreTrainedModel(RegressionModelConfig(a=0, b=2)) - SRC_DIR = os.path.abspath( - os.path.join(os.path.dirname(__file__), "..", "..", "examples", "pytorch", "text-classification") - ) - sys.path.append(SRC_DIR) - import run_glue + def make_trainer(auto_find_batch_size): + args = RegressionTrainingArguments( + self.get_auto_remove_tmp_dir(), + max_steps=2, + save_strategy="no", + per_device_train_batch_size=16, + auto_find_batch_size=auto_find_batch_size, + ) + return Trainer(model, args, train_dataset=train_dataset, callbacks=[MockCudaOOMCallback()]) - with tempfile.TemporaryDirectory() as tmpdir: - testargs = f""" - run_glue.py - --model_name_or_path distilbert/distilbert-base-uncased - --task_name mrpc - --do_train - --do_eval - --max_seq_len 128 - --per_device_train_batch_size 4096 - --learning_rate 2e-5 - --num_train_epochs 1 - --output_dir {tmpdir} - --auto_find_batch_size 0 - """.split() - with self.assertRaises(RuntimeError): - with patch.object(sys, "argv", testargs): - run_glue.main() - - testargs[-1] = "1" - with patch.object(sys, "argv", testargs): - run_glue.main() + # Without the finder, the OOM reaches the user + with self.assertRaisesRegex(RuntimeError, "CUDA out of memory"): + make_trainer(auto_find_batch_size=False).train() + + # With it, training shrinks the batch size until it fits + trainer = make_trainer(auto_find_batch_size=True) + trainer.train() + self.assertLess(trainer._train_batch_size, 16) @require_deepspeed @require_torch_non_multi_accelerator diff --git a/tests/trainer/test_trainer_seq2seq.py b/tests/trainer/test_trainer_seq2seq.py index de16a4fad027..956d1cf33dbf 100644 --- a/tests/trainer/test_trainer_seq2seq.py +++ b/tests/trainer/test_trainer_seq2seq.py @@ -12,10 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import sys -from pathlib import Path -from unittest.mock import patch from transformers import ( AutoModelForSeq2SeqLM, @@ -29,20 +25,11 @@ T5Tokenizer, ) from transformers.testing_utils import ( - ExtendSysPath, TestCasePlus, - backend_device_count, - execute_subprocess_async, - get_torch_dist_unique_port, - require_bitsandbytes, require_sentencepiece, require_torch, - require_torch_multi_accelerator, - require_torch_non_multi_accelerator, slow, - torch_device, ) -from transformers.trainer_callback import TrainerState from transformers.trainer_utils import set_seed from transformers.utils import is_datasets_available, is_torch_available @@ -55,8 +42,6 @@ set_seed(42) -MARIAN_MODEL = "sshleifer/student_marian_en_ro_6_1" -MBART_TINY = "sshleifer/tiny-mbart" @require_sentencepiece @@ -241,173 +226,3 @@ def test_bad_generation_config_fail_early(self): compute_metrics=lambda x: {"samples": x[0].shape[0]}, ) self.assertIn("Fix these issues to train your model", str(exc.exception)) - - -@require_torch -class TestTranslationExample(TestCasePlus): - """Tests for the run_translation.py example script (seq2seq training via CLI).""" - - @classmethod - def setUpClass(cls): - super().setUpClass() - examples_dir = Path(__file__).resolve().parents[2] / "examples" / "pytorch" / "translation" - with ExtendSysPath(str(examples_dir)): - from run_translation import main as _main - - cls._run_translation_main = staticmethod(_main) - - def _run_translation( - self, - distributed=False, - extra_args_str=None, - predict_with_generate=True, - do_train=True, - do_eval=True, - do_predict=True, - n_gpus_to_use=None, - ): - data_dir = self.test_file_dir / "../fixtures/tests_samples/wmt_en_ro" - output_dir = self.get_auto_remove_tmp_dir() - args = f""" - --model_name_or_path {MBART_TINY} - --train_file {data_dir}/train.json - --validation_file {data_dir}/val.json - --test_file {data_dir}/test.json - --output_dir {output_dir} - --max_train_samples 8 - --max_source_length 12 - --max_target_length 12 - --do_train - --num_train_epochs 1 - --per_device_train_batch_size 4 - --learning_rate 3e-3 - --warmup_steps 8 - --logging_steps 0 - --logging_strategy no - --save_steps 1 - --train_sampling_strategy group_by_length - --label_smoothing_factor 0.1 - --target_lang ro_RO - --source_lang en_XX - --report_to none - """.split() - - if do_eval: - args += """ - --do_eval - --per_device_eval_batch_size 4 - --max_eval_samples 8 - --val_max_target_length 12 - --eval_strategy steps - --eval_steps 1 - """.split() - - if do_predict: - args += ["--do_predict"] - - if predict_with_generate: - args += ["--predict_with_generate"] - - if do_train: - args += ["--optim", "adafactor"] - - if extra_args_str is not None: - args += extra_args_str.split() - - if distributed: - if n_gpus_to_use is None: - n_gpus_to_use = backend_device_count(torch_device) - master_port = get_torch_dist_unique_port() - distributed_args = f""" - -m torch.distributed.run - --nproc_per_node={n_gpus_to_use} - --master_port={master_port} - {self.examples_dir_str}/pytorch/translation/run_translation.py - """.split() - cmd = [sys.executable] + distributed_args + args - execute_subprocess_async(cmd, env=self.get_env()) - else: - testargs = ["run_translation.py"] + args - with patch.object(sys, "argv", testargs): - self._run_translation_main() - - return output_dir - - @require_torch_non_multi_accelerator - def test_run_seq2seq_no_dist(self): - output_dir = self._run_translation() - logs = TrainerState.load_from_json(os.path.join(output_dir, "trainer_state.json")).log_history - eval_metrics = [log for log in logs if "eval_loss" in log] - first_step_stats = eval_metrics[0] - assert "eval_bleu" in first_step_stats - - @require_torch_multi_accelerator - def test_run_seq2seq_dp(self): - output_dir = self._run_translation(distributed=False) - logs = TrainerState.load_from_json(os.path.join(output_dir, "trainer_state.json")).log_history - eval_metrics = [log for log in logs if "eval_loss" in log] - first_step_stats = eval_metrics[0] - assert "eval_bleu" in first_step_stats - - @require_torch_multi_accelerator - def test_run_seq2seq_ddp(self): - output_dir = self._run_translation(distributed=True) - logs = TrainerState.load_from_json(os.path.join(output_dir, "trainer_state.json")).log_history - eval_metrics = [log for log in logs if "eval_loss" in log] - first_step_stats = eval_metrics[0] - assert "eval_bleu" in first_step_stats - - @slow - def test_run_seq2seq_slow(self): - output_dir = self._run_translation( - extra_args_str=f"--model_name_or_path {MARIAN_MODEL} --learning_rate 3e-4 --num_train_epochs 10 --max_source_length 128 --max_target_length 128 --eval_steps 2 --save_steps 2", - ) - logs = TrainerState.load_from_json(os.path.join(output_dir, "trainer_state.json")).log_history - eval_metrics = [log for log in logs if "eval_loss" in log] - first_step_stats = eval_metrics[0] - last_step_stats = eval_metrics[-1] - assert first_step_stats["eval_loss"] > last_step_stats["eval_loss"], "model learned nothing" - assert isinstance(last_step_stats["eval_bleu"], float) - contents = {os.path.basename(p) for p in os.listdir(output_dir)} - assert "generated_predictions.txt" in contents - assert "predict_results.json" in contents - - @slow - @require_bitsandbytes - def test_run_seq2seq_bnb(self): - from transformers.training_args import OptimizerNames - - def train_and_return_metrics(optim: str) -> tuple[int, float]: - output_dir = self._run_translation( - distributed=True, - extra_args_str=f"--skip_memory_metrics 0 --model_name_or_path {MARIAN_MODEL} --learning_rate 3e-4 --num_train_epochs 1 --optim {optim} --max_source_length 128 --max_target_length 128", - do_eval=False, - do_predict=False, - n_gpus_to_use=1, - ) - logs = TrainerState.load_from_json(Path(output_dir, "trainer_state.json")).log_history - gpu_peak_mem_mb = int(logs[0]["train_mem_gpu_peaked_delta"] / 2**20) - gpu_alloc_mem_mb = int(logs[0]["train_mem_gpu_alloc_delta"] / 2**20) - loss = logs[0]["train_loss"] - return gpu_peak_mem_mb, gpu_alloc_mem_mb, loss - - gpu_peak_mem_orig, gpu_alloc_mem_orig, loss_orig = train_and_return_metrics(OptimizerNames.ADAMW_TORCH.value) - gpu_peak_mem_bnb, gpu_alloc_mem_bnb, loss_bnb = train_and_return_metrics(OptimizerNames.ADAMW_BNB.value) - - gpu_alloc_mem_diff = gpu_alloc_mem_orig - gpu_alloc_mem_bnb - gpu_total_mem_orig = gpu_peak_mem_orig + gpu_alloc_mem_orig - gpu_total_mem_bnb = gpu_peak_mem_bnb + gpu_alloc_mem_bnb - gpu_total_mem_diff = gpu_total_mem_orig - gpu_total_mem_bnb - - expected_savings = 120 - self.assertGreater( - gpu_alloc_mem_diff, - expected_savings, - f"should use ~150MB less alloc gpu memory with BNB, but got diff={gpu_alloc_mem_diff}MB", - ) - self.assertGreater( - gpu_total_mem_diff, - expected_savings, - f"should use ~150MB less total gpu memory with BNB, but got diff={gpu_total_mem_diff}MB", - ) - self.assertAlmostEqual(loss_orig, loss_bnb, 5, f"loss should be the same: {loss_orig} vs {loss_bnb}") diff --git a/utils/not_doctested.txt b/utils/not_doctested.txt index f8c9b8f9f6d8..b678b0931c05 100644 --- a/utils/not_doctested.txt +++ b/utils/not_doctested.txt @@ -249,7 +249,6 @@ docs/source/en/perplexity.md docs/source/en/philosophy.md docs/source/en/pipeline_webserver.md docs/source/en/pr_checks.md -docs/source/en/run_scripts.md docs/source/en/serialization.md docs/source/en/tasks/asr.md docs/source/en/tasks/audio_classification.md diff --git a/utils/notification_service.py b/utils/notification_service.py index 2f100e8e61d2..8b9189d51dab 100644 --- a/utils/notification_service.py +++ b/utils/notification_service.py @@ -37,7 +37,6 @@ "run_models_gpu": "Models", "run_trainer_and_fsdp_gpu": "Trainer & DDP & FSDP", "run_pipelines_torch_gpu": "PyTorch pipelines", - "run_examples_gpu": "Examples directory", "run_torch_cuda_extensions_gpu": "DeepSpeed", "run_quantization_torch_gpu": "Quantization", "run_kernels_gpu": "Kernels", @@ -48,7 +47,6 @@ "Models": "model", "Trainer & DDP & FSDP": "trainer_and_fsdp", "PyTorch pipelines": "torch_pipeline", - "Examples directory": "example", "DeepSpeed": "deepspeed", "Quantization": "quantization", "Kernels": "kernels", @@ -1358,13 +1356,11 @@ def pop_default(l: list[Any], i: int, default: Any) -> Any: # Additional runs additional_files = { "PyTorch pipelines": "run_pipelines_torch_gpu_test_reports", - "Examples directory": "run_examples_gpu_test_reports", "DeepSpeed": "run_torch_cuda_extensions_gpu_test_reports", "Kernels": "run_kernels_gpu_test_reports", } if ci_event in ["push", "Nightly CI"] or ci_event.startswith("Past CI"): - del additional_files["Examples directory"] del additional_files["PyTorch pipelines"] elif ci_event.startswith("Scheduled CI (AMD)"): del additional_files["DeepSpeed"] diff --git a/utils/tests_fetcher.py b/utils/tests_fetcher.py index 826b9ab177a2..d5264d401934 100644 --- a/utils/tests_fetcher.py +++ b/utils/tests_fetcher.py @@ -67,7 +67,6 @@ PATH_TO_REPO = Path(__file__).parent.parent.resolve() -PATH_TO_EXAMPLES = PATH_TO_REPO / "examples" PATH_TO_TRANSFORMERS = PATH_TO_REPO / "src/transformers" PATH_TO_TESTS = PATH_TO_REPO / "tests" @@ -851,38 +850,6 @@ def print_tree_deps_of(module, all_edges=None): print(line[0]) -def init_test_examples_dependencies() -> tuple[dict[str, list[str]], list[str]]: - """ - The test examples do not import from the examples (which are just scripts, not modules) so we need some extra - care initializing the dependency map, which is the goal of this function. It initializes the dependency map for - example files by linking each example to the example test file for the example folder. - - Returns: - `Tuple[Dict[str, List[str]], List[str]]`: A tuple with two elements: the initialized dependency map which is a - dict test example file to list of example files potentially tested by that test file, and the list of all - example files (to avoid recomputing it later). - """ - test_example_deps = {} - all_examples = [] - - test_files = list((PATH_TO_EXAMPLES / "pytorch").glob("test_*.py")) - all_examples.extend(test_files) - # Remove the files at the root of examples/pytorch since they are not proper examples (they are either utils - # or example test files). - examples = [f for f in (PATH_TO_EXAMPLES / "pytorch").glob("**/*.py") if f.parent != PATH_TO_EXAMPLES / "pytorch"] - all_examples.extend(examples) - for test_file in test_files: - with open(test_file, "r", encoding="utf-8") as f: - content = f.read() - # Map all examples to the test files found in examples/pytorch. - test_example_deps[str(test_file.relative_to(PATH_TO_REPO))] = [ - str(e.relative_to(PATH_TO_REPO)) for e in examples if e.name in content - ] - # Also map the test files to themselves. - test_example_deps[str(test_file.relative_to(PATH_TO_REPO))].append(str(test_file.relative_to(PATH_TO_REPO))) - return test_example_deps, all_examples - - def create_reverse_dependency_map() -> dict[str, list[str]]: """ Create the dependency map from module/test filename to the list of modules/tests that depend on it recursively. @@ -894,16 +861,13 @@ def create_reverse_dependency_map() -> dict[str, list[str]]: """ cache = {} - # Start from the example deps init. - example_deps, examples = init_test_examples_dependencies() - # Add all modules and all tests to all examples + # Add all modules and all tests all_modules = list(PATH_TO_TRANSFORMERS.glob("**/*.py")) all_modules = [x for x in all_modules if not ("models" in x.parts and x.parts[-1].startswith("convert_"))] - all_modules += list(PATH_TO_TESTS.glob("**/*.py")) + examples + all_modules += list(PATH_TO_TESTS.glob("**/*.py")) all_modules = [str(mod.relative_to(PATH_TO_REPO)) for mod in all_modules] # Compute the direct dependencies of all modules. direct_deps = {m: get_module_dependencies(m, cache=cache) for m in all_modules} - direct_deps.update(example_deps) # This recurses the dependencies something_changed = True @@ -963,16 +927,8 @@ def create_module_to_test_map(reverse_map: dict[str, list[str]] | None = None) - if reverse_map is None: reverse_map = create_reverse_dependency_map() - # Utility that tells us if a given file is a test (taking test examples into account) - def is_test(fname): - if fname.startswith("tests"): - return True - if fname.startswith("examples") and fname.split(os.path.sep)[-1].startswith("test"): - return True - return False - # Build the test map - test_map = {module: [f for f in deps if is_test(f)] for module, deps in reverse_map.items()} + test_map = {module: [f for f in deps if f.startswith("tests")] for module, deps in reverse_map.items()} return test_map @@ -1050,7 +1006,6 @@ def infer_tests_to_run(output_file: str, diff_with_last_commit: bool = False, te The path where to store the summary of the test fetcher analysis. Other files will be stored in the same folder: - - examples_test_list.txt: The list of examples tests to run. - test_repo_utils.txt: Will indicate if the repo utils tests should be run or not. - doctest_list.txt: The list of doctests to run. @@ -1082,9 +1037,7 @@ def infer_tests_to_run(output_file: str, diff_with_last_commit: bool = False, te or len(model_impacted) >= NUM_MODELS_TO_TRIGGER_FULL_CI or commit_flags["test_all"] ): - test_files_to_run = glob.glob("tests/**/test_**.py", recursive=True) + glob.glob( - "examples/**/*.py", recursive=True - ) + test_files_to_run = glob.glob("tests/**/test_**.py", recursive=True) if len(model_impacted) >= NUM_MODELS_TO_TRIGGER_FULL_CI: print( f"More than {NUM_MODELS_TO_TRIGGER_FULL_CI - 1} models are impacted. CI is configured to test everything." @@ -1185,7 +1138,6 @@ def parse_commit_message(commit_message: str) -> dict[str, bool]: "tests_generate": r"(tests/models/.*/test_modeling_.*|tests/generation/test_.*\.py)", "tests_tokenization": r"tests/(?:models/.*/test_tokenization.*|test_tokenization_mistral_common\.py)", "tests_processors": r"tests/models/.*/test_(?!(?:modeling_|tokenization_)).*", # takes feature extractors, image processors, processors - "examples_torch": r"examples/pytorch/.*test_.*", "tests_exotic_models": r"tests/models/.*(?=layoutlmv|nat|deta|udop|nougat).*", "tests_custom_tokenizers": r"tests/models/.*/test_tokenization_(?=bert_japanese|openai|clip).*", # conftest tests exercise the test runner (repo-root conftest.py); they share the