mirror of
https://github.com/huggingface/transformers.git
synced 2025-10-24 11:44:36 +08:00
Compare commits
11 Commits
fix-pytorc
...
cohere-dif
| Author | SHA1 | Date | |
|---|---|---|---|
| 9faf7b0665 | |||
| 4547337ba5 | |||
| 1eff33af54 | |||
| 1146aa0be7 | |||
| df3226143b | |||
| 3dc5e14321 | |||
| bdb4cc9f0f | |||
| 4f6104a25b | |||
| 6135a1fb72 | |||
| dc78118531 | |||
| dd518307e7 |
@ -13,7 +13,6 @@ jobs:
|
|||||||
check_circleci_user:
|
check_circleci_user:
|
||||||
docker:
|
docker:
|
||||||
- image: python:3.10-slim
|
- image: python:3.10-slim
|
||||||
resource_class: small
|
|
||||||
parallelism: 1
|
parallelism: 1
|
||||||
steps:
|
steps:
|
||||||
- run: echo $CIRCLE_PROJECT_USERNAME
|
- run: echo $CIRCLE_PROJECT_USERNAME
|
||||||
@ -59,14 +58,14 @@ jobs:
|
|||||||
name: "Prepare pipeline parameters"
|
name: "Prepare pipeline parameters"
|
||||||
command: |
|
command: |
|
||||||
python utils/process_test_artifacts.py
|
python utils/process_test_artifacts.py
|
||||||
|
|
||||||
# To avoid too long generated_config.yaml on the continuation orb, we pass the links to the artifacts as parameters.
|
# To avoid too long generated_config.yaml on the continuation orb, we pass the links to the artifacts as parameters.
|
||||||
# Otherwise the list of tests was just too big. Explicit is good but for that it was a limitation.
|
# Otherwise the list of tests was just too big. Explicit is good but for that it was a limitation.
|
||||||
# We used:
|
# We used:
|
||||||
|
|
||||||
# https://circleci.com/docs/api/v2/index.html#operation/getJobArtifacts : to get the job artifacts
|
# https://circleci.com/docs/api/v2/index.html#operation/getJobArtifacts : to get the job artifacts
|
||||||
# We could not pass a nested dict, which is why we create the test_file_... parameters for every single job
|
# We could not pass a nested dict, which is why we create the test_file_... parameters for every single job
|
||||||
|
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: test_preparation/transformed_artifacts.json
|
path: test_preparation/transformed_artifacts.json
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
@ -187,19 +186,7 @@ workflows:
|
|||||||
version: 2
|
version: 2
|
||||||
setup_and_quality:
|
setup_and_quality:
|
||||||
when:
|
when:
|
||||||
and:
|
not: <<pipeline.parameters.nightly>>
|
||||||
- equal: [<<pipeline.project.git_url>>, https://github.com/huggingface/transformers]
|
|
||||||
- not: <<pipeline.parameters.nightly>>
|
|
||||||
jobs:
|
|
||||||
- check_circleci_user
|
|
||||||
- check_code_quality
|
|
||||||
- check_repository_consistency
|
|
||||||
- fetch_tests
|
|
||||||
|
|
||||||
setup_and_quality_2:
|
|
||||||
when:
|
|
||||||
not:
|
|
||||||
equal: [<<pipeline.project.git_url>>, https://github.com/huggingface/transformers]
|
|
||||||
jobs:
|
jobs:
|
||||||
- check_circleci_user
|
- check_circleci_user
|
||||||
- check_code_quality
|
- check_code_quality
|
||||||
|
|||||||
@ -32,7 +32,7 @@ COMMON_ENV_VARIABLES = {
|
|||||||
"RUN_PT_FLAX_CROSS_TESTS": False,
|
"RUN_PT_FLAX_CROSS_TESTS": False,
|
||||||
}
|
}
|
||||||
# Disable the use of {"s": None} as the output is way too long, causing the navigation on CircleCI impractical
|
# Disable the use of {"s": None} as the output is way too long, causing the navigation on CircleCI impractical
|
||||||
COMMON_PYTEST_OPTIONS = {"max-worker-restart": 0, "dist": "loadfile", "vvv": None, "rsfE":None}
|
COMMON_PYTEST_OPTIONS = {"max-worker-restart": 0, "dist": "loadfile", "vvv": None, "rsf":None}
|
||||||
DEFAULT_DOCKER_IMAGE = [{"image": "cimg/python:3.8.12"}]
|
DEFAULT_DOCKER_IMAGE = [{"image": "cimg/python:3.8.12"}]
|
||||||
|
|
||||||
|
|
||||||
@ -40,23 +40,9 @@ class EmptyJob:
|
|||||||
job_name = "empty"
|
job_name = "empty"
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
steps = [{"run": 'ls -la'}]
|
|
||||||
if self.job_name == "collection_job":
|
|
||||||
steps.extend(
|
|
||||||
[
|
|
||||||
"checkout",
|
|
||||||
{"run": "pip install requests || true"},
|
|
||||||
{"run": """while [[ $(curl --location --request GET "https://circleci.com/api/v2/workflow/$CIRCLE_WORKFLOW_ID/job" --header "Circle-Token: $CCI_TOKEN"| jq -r '.items[]|select(.name != "collection_job")|.status' | grep -c "running") -gt 0 ]]; do sleep 5; done || true"""},
|
|
||||||
{"run": 'python utils/process_circleci_workflow_test_reports.py --workflow_id $CIRCLE_WORKFLOW_ID || true'},
|
|
||||||
{"store_artifacts": {"path": "outputs"}},
|
|
||||||
{"run": 'echo "All required jobs have now completed"'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"docker": copy.deepcopy(DEFAULT_DOCKER_IMAGE),
|
"docker": copy.deepcopy(DEFAULT_DOCKER_IMAGE),
|
||||||
"resource_class": "small",
|
"steps":["checkout"],
|
||||||
"steps": steps,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -68,9 +54,9 @@ class CircleCIJob:
|
|||||||
install_steps: List[str] = None
|
install_steps: List[str] = None
|
||||||
marker: Optional[str] = None
|
marker: Optional[str] = None
|
||||||
parallelism: Optional[int] = 0
|
parallelism: Optional[int] = 0
|
||||||
pytest_num_workers: int = 8
|
pytest_num_workers: int = 12
|
||||||
pytest_options: Dict[str, Any] = None
|
pytest_options: Dict[str, Any] = None
|
||||||
resource_class: Optional[str] = "xlarge"
|
resource_class: Optional[str] = "2xlarge"
|
||||||
tests_to_run: Optional[List[str]] = None
|
tests_to_run: Optional[List[str]] = None
|
||||||
num_test_files_per_worker: Optional[int] = 10
|
num_test_files_per_worker: Optional[int] = 10
|
||||||
# This should be only used for doctest job!
|
# This should be only used for doctest job!
|
||||||
@ -147,7 +133,7 @@ class CircleCIJob:
|
|||||||
"command": """dpkg-query --show --showformat='${Installed-Size}\t${Package}\n' | sort -rh | head -25 | sort -h | awk '{ package=$2; sub(".*/", "", package); printf("%.5f GB %s\n", $1/1024/1024, package)}' || true"""}
|
"command": """dpkg-query --show --showformat='${Installed-Size}\t${Package}\n' | sort -rh | head -25 | sort -h | awk '{ package=$2; sub(".*/", "", package); printf("%.5f GB %s\n", $1/1024/1024, package)}' || true"""}
|
||||||
},
|
},
|
||||||
{"run": {"name": "Create `test-results` directory", "command": "mkdir test-results"}},
|
{"run": {"name": "Create `test-results` directory", "command": "mkdir test-results"}},
|
||||||
{"run": {"name": "Get files to test", "command":f'curl -L -o {self.job_name}_test_list.txt <<pipeline.parameters.{self.job_name}_test_list>> --header "Circle-Token: $CIRCLE_TOKEN"' if self.name != "pr_documentation_tests" else 'echo "Skipped"'}},
|
{"run": {"name": "Get files to test", "command":f'curl -L -o {self.job_name}_test_list.txt <<pipeline.parameters.{self.job_name}_test_list>>' if self.name != "pr_documentation_tests" else 'echo "Skipped"'}},
|
||||||
{"run": {"name": "Split tests across parallel nodes: show current parallel tests",
|
{"run": {"name": "Split tests across parallel nodes: show current parallel tests",
|
||||||
"command": f"TESTS=$(circleci tests split --split-by=timings {self.job_name}_test_list.txt) && echo $TESTS > splitted_tests.txt && echo $TESTS | tr ' ' '\n'" if self.parallelism else f"awk '{{printf \"%s \", $0}}' {self.job_name}_test_list.txt > splitted_tests.txt"
|
"command": f"TESTS=$(circleci tests split --split-by=timings {self.job_name}_test_list.txt) && echo $TESTS > splitted_tests.txt && echo $TESTS | tr ' ' '\n'" if self.parallelism else f"awk '{{printf \"%s \", $0}}' {self.job_name}_test_list.txt > splitted_tests.txt"
|
||||||
}
|
}
|
||||||
@ -199,6 +185,7 @@ torch_job = CircleCIJob(
|
|||||||
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
||||||
marker="not generate",
|
marker="not generate",
|
||||||
parallelism=6,
|
parallelism=6,
|
||||||
|
pytest_num_workers=8
|
||||||
)
|
)
|
||||||
|
|
||||||
generate_job = CircleCIJob(
|
generate_job = CircleCIJob(
|
||||||
@ -206,24 +193,28 @@ generate_job = CircleCIJob(
|
|||||||
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
||||||
marker="generate",
|
marker="generate",
|
||||||
parallelism=6,
|
parallelism=6,
|
||||||
|
pytest_num_workers=8
|
||||||
)
|
)
|
||||||
|
|
||||||
tokenization_job = CircleCIJob(
|
tokenization_job = CircleCIJob(
|
||||||
"tokenization",
|
"tokenization",
|
||||||
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
||||||
parallelism=8,
|
parallelism=8,
|
||||||
|
pytest_num_workers=16
|
||||||
)
|
)
|
||||||
|
|
||||||
processor_job = CircleCIJob(
|
processor_job = CircleCIJob(
|
||||||
"processors",
|
"processors",
|
||||||
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
||||||
parallelism=8,
|
parallelism=8,
|
||||||
|
pytest_num_workers=6
|
||||||
)
|
)
|
||||||
|
|
||||||
tf_job = CircleCIJob(
|
tf_job = CircleCIJob(
|
||||||
"tf",
|
"tf",
|
||||||
docker_image=[{"image":"huggingface/transformers-tf-light"}],
|
docker_image=[{"image":"huggingface/transformers-tf-light"}],
|
||||||
parallelism=6,
|
parallelism=6,
|
||||||
|
pytest_num_workers=16,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -231,8 +222,7 @@ flax_job = CircleCIJob(
|
|||||||
"flax",
|
"flax",
|
||||||
docker_image=[{"image":"huggingface/transformers-jax-light"}],
|
docker_image=[{"image":"huggingface/transformers-jax-light"}],
|
||||||
parallelism=6,
|
parallelism=6,
|
||||||
pytest_num_workers=16,
|
pytest_num_workers=16
|
||||||
resource_class="2xlarge",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -241,7 +231,7 @@ pipelines_torch_job = CircleCIJob(
|
|||||||
additional_env={"RUN_PIPELINE_TESTS": True},
|
additional_env={"RUN_PIPELINE_TESTS": True},
|
||||||
docker_image=[{"image":"huggingface/transformers-torch-light"}],
|
docker_image=[{"image":"huggingface/transformers-torch-light"}],
|
||||||
marker="is_pipeline_test",
|
marker="is_pipeline_test",
|
||||||
parallelism=4,
|
parallelism=4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -250,7 +240,7 @@ pipelines_tf_job = CircleCIJob(
|
|||||||
additional_env={"RUN_PIPELINE_TESTS": True},
|
additional_env={"RUN_PIPELINE_TESTS": True},
|
||||||
docker_image=[{"image":"huggingface/transformers-tf-light"}],
|
docker_image=[{"image":"huggingface/transformers-tf-light"}],
|
||||||
marker="is_pipeline_test",
|
marker="is_pipeline_test",
|
||||||
parallelism=4,
|
parallelism=4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -267,6 +257,7 @@ examples_torch_job = CircleCIJob(
|
|||||||
docker_image=[{"image":"huggingface/transformers-examples-torch"}],
|
docker_image=[{"image":"huggingface/transformers-examples-torch"}],
|
||||||
# TODO @ArthurZucker remove this once docker is easier to build
|
# TODO @ArthurZucker remove this once docker is easier to build
|
||||||
install_steps=["uv venv && uv pip install . && uv pip install -r examples/pytorch/_tests_requirements.txt"],
|
install_steps=["uv venv && uv pip install . && uv pip install -r examples/pytorch/_tests_requirements.txt"],
|
||||||
|
pytest_num_workers=8,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -274,6 +265,7 @@ examples_tensorflow_job = CircleCIJob(
|
|||||||
"examples_tensorflow",
|
"examples_tensorflow",
|
||||||
additional_env={"OMP_NUM_THREADS": 8},
|
additional_env={"OMP_NUM_THREADS": 8},
|
||||||
docker_image=[{"image":"huggingface/transformers-examples-tf"}],
|
docker_image=[{"image":"huggingface/transformers-examples-tf"}],
|
||||||
|
pytest_num_workers=16,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -288,7 +280,6 @@ hub_job = CircleCIJob(
|
|||||||
],
|
],
|
||||||
marker="is_staging_test",
|
marker="is_staging_test",
|
||||||
pytest_num_workers=2,
|
pytest_num_workers=2,
|
||||||
resource_class="medium",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -301,13 +292,13 @@ onnx_job = CircleCIJob(
|
|||||||
],
|
],
|
||||||
pytest_options={"k onnx": None},
|
pytest_options={"k onnx": None},
|
||||||
pytest_num_workers=1,
|
pytest_num_workers=1,
|
||||||
resource_class="small",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
exotic_models_job = CircleCIJob(
|
exotic_models_job = CircleCIJob(
|
||||||
"exotic_models",
|
"exotic_models",
|
||||||
docker_image=[{"image":"huggingface/transformers-exotic-models"}],
|
docker_image=[{"image":"huggingface/transformers-exotic-models"}],
|
||||||
|
pytest_num_workers=12,
|
||||||
parallelism=4,
|
parallelism=4,
|
||||||
pytest_options={"durations": 100},
|
pytest_options={"durations": 100},
|
||||||
)
|
)
|
||||||
@ -326,6 +317,7 @@ non_model_job = CircleCIJob(
|
|||||||
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
docker_image=[{"image": "huggingface/transformers-torch-light"}],
|
||||||
marker="not generate",
|
marker="not generate",
|
||||||
parallelism=6,
|
parallelism=6,
|
||||||
|
pytest_num_workers=8,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -360,7 +352,6 @@ REPO_UTIL_TESTS = [repo_utils_job]
|
|||||||
DOC_TESTS = [doc_test_job]
|
DOC_TESTS = [doc_test_job]
|
||||||
ALL_TESTS = REGULAR_TESTS + EXAMPLES_TESTS + PIPELINE_TESTS + REPO_UTIL_TESTS + DOC_TESTS + [custom_tokenizers_job] + [exotic_models_job] # fmt: skip
|
ALL_TESTS = REGULAR_TESTS + EXAMPLES_TESTS + PIPELINE_TESTS + REPO_UTIL_TESTS + DOC_TESTS + [custom_tokenizers_job] + [exotic_models_job] # fmt: skip
|
||||||
|
|
||||||
|
|
||||||
def create_circleci_config(folder=None):
|
def create_circleci_config(folder=None):
|
||||||
if folder is None:
|
if folder is None:
|
||||||
folder = os.getcwd()
|
folder = os.getcwd()
|
||||||
@ -370,13 +361,7 @@ def create_circleci_config(folder=None):
|
|||||||
|
|
||||||
if len(jobs) == 0:
|
if len(jobs) == 0:
|
||||||
jobs = [EmptyJob()]
|
jobs = [EmptyJob()]
|
||||||
else:
|
print("Full list of job name inputs", {j.job_name + "_test_list":{"type":"string", "default":''} for j in jobs})
|
||||||
print("Full list of job name inputs", {j.job_name + "_test_list":{"type":"string", "default":''} for j in jobs})
|
|
||||||
# Add a job waiting all the test jobs and aggregate their test summary files at the end
|
|
||||||
collection_job = EmptyJob()
|
|
||||||
collection_job.job_name = "collection_job"
|
|
||||||
jobs = [collection_job] + jobs
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"version": "2.1",
|
"version": "2.1",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
@ -386,14 +371,9 @@ def create_circleci_config(folder=None):
|
|||||||
**{j.job_name + "_test_list":{"type":"string", "default":''} for j in jobs},
|
**{j.job_name + "_test_list":{"type":"string", "default":''} for j in jobs},
|
||||||
**{j.job_name + "_parallelism":{"type":"integer", "default":1} for j in jobs},
|
**{j.job_name + "_parallelism":{"type":"integer", "default":1} for j in jobs},
|
||||||
},
|
},
|
||||||
"jobs": {j.job_name: j.to_dict() for j in jobs}
|
"jobs" : {j.job_name: j.to_dict() for j in jobs},
|
||||||
|
"workflows": {"version": 2, "run_tests": {"jobs": [j.job_name for j in jobs]}}
|
||||||
}
|
}
|
||||||
if "CIRCLE_TOKEN" in os.environ:
|
|
||||||
# For private forked repo. (e.g. new model addition)
|
|
||||||
config["workflows"] = {"version": 2, "run_tests": {"jobs": [{j.job_name: {"context": ["TRANSFORMERS_CONTEXT"]}} for j in jobs]}}
|
|
||||||
else:
|
|
||||||
# For public repo. (e.g. `transformers`)
|
|
||||||
config["workflows"] = {"version": 2, "run_tests": {"jobs": [j.job_name for j in jobs]}}
|
|
||||||
with open(os.path.join(folder, "generated_config.yml"), "w") as f:
|
with open(os.path.join(folder, "generated_config.yml"), "w") as f:
|
||||||
f.write(yaml.dump(config, sort_keys=False, default_flow_style=False).replace("' << pipeline", " << pipeline").replace(">> '", " >>"))
|
f.write(yaml.dump(config, sort_keys=False, default_flow_style=False).replace("' << pipeline", " << pipeline").replace(">> '", " >>"))
|
||||||
|
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@ -55,7 +55,7 @@ body:
|
|||||||
- deepspeed: HF Trainer/Accelerate: @muellerzr
|
- deepspeed: HF Trainer/Accelerate: @muellerzr
|
||||||
- ray/raytune: @richardliaw, @amogkam
|
- ray/raytune: @richardliaw, @amogkam
|
||||||
- Big Model Inference: @SunMarc
|
- Big Model Inference: @SunMarc
|
||||||
- quantization (bitsandbytes, autogpt): @SunMarc @MekkCyber
|
- quantization (bitsandbytes, autogpt): @SunMarc
|
||||||
|
|
||||||
Documentation: @stevhliu
|
Documentation: @stevhliu
|
||||||
|
|
||||||
|
|||||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -59,7 +59,7 @@ Integrations:
|
|||||||
- deepspeed: HF Trainer/Accelerate: @muellerzr
|
- deepspeed: HF Trainer/Accelerate: @muellerzr
|
||||||
- ray/raytune: @richardliaw, @amogkam
|
- ray/raytune: @richardliaw, @amogkam
|
||||||
- Big Model Inference: @SunMarc
|
- Big Model Inference: @SunMarc
|
||||||
- quantization (bitsandbytes, autogpt): @SunMarc @MekkCyber
|
- quantization (bitsandbytes, autogpt): @SunMarc
|
||||||
|
|
||||||
Documentation: @stevhliu
|
Documentation: @stevhliu
|
||||||
|
|
||||||
|
|||||||
76
.github/workflows/benchmark.yml
vendored
76
.github/workflows/benchmark.yml
vendored
@ -1,74 +1,42 @@
|
|||||||
name: Self-hosted runner (benchmark)
|
name: Self-hosted runner (benchmark)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
schedule:
|
||||||
branches: [main]
|
- cron: "17 2 * * *"
|
||||||
pull_request:
|
workflow_call:
|
||||||
types: [ opened, labeled, reopened, synchronize ]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
HF_HOME: /mnt/cache
|
HF_HOME: /mnt/cache
|
||||||
|
TF_FORCE_GPU_ALLOW_GROWTH: true
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
benchmark:
|
benchmark:
|
||||||
name: Benchmark
|
name: Benchmark
|
||||||
strategy:
|
runs-on: [single-gpu, nvidia-gpu, a10, ci]
|
||||||
matrix:
|
|
||||||
group: [aws-g5-4xlarge-cache, aws-p4d-24xlarge-plus]
|
|
||||||
runs-on:
|
|
||||||
group: ${{ matrix.group }}
|
|
||||||
if: |
|
|
||||||
(github.event_name == 'pull_request' && contains( github.event.pull_request.labels.*.name, 'run-benchmark') )||
|
|
||||||
(github.event_name == 'push' && github.ref == 'refs/heads/main')
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-pytorch-gpu
|
image: huggingface/transformers-all-latest-gpu
|
||||||
options: --gpus all --privileged --ipc host
|
options: --gpus all --privileged --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
steps:
|
steps:
|
||||||
- name: Get repo
|
- name: Update clone
|
||||||
uses: actions/checkout@v4
|
working-directory: /transformers
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Install libpq-dev & psql
|
|
||||||
run: |
|
run: |
|
||||||
apt update
|
git fetch && git checkout ${{ github.sha }}
|
||||||
apt install -y libpq-dev postgresql-client
|
|
||||||
|
|
||||||
- name: Install benchmark script dependencies
|
|
||||||
run: python3 -m pip install -r benchmark/requirements.txt
|
|
||||||
|
|
||||||
- name: Reinstall transformers in edit mode (remove the one installed during docker image build)
|
- name: Reinstall transformers in edit mode (remove the one installed during docker image build)
|
||||||
working-directory: /transformers
|
working-directory: /transformers
|
||||||
run: python3 -m pip uninstall -y transformers && python3 -m pip install -e ".[torch]"
|
run: python3 -m pip uninstall -y transformers && python3 -m pip install -e .
|
||||||
|
|
||||||
- name: Run database init script
|
- name: Benchmark (daily)
|
||||||
|
if: github.event_name == 'schedule'
|
||||||
|
working-directory: /transformers
|
||||||
run: |
|
run: |
|
||||||
psql -f benchmark/init_db.sql
|
python3 -m pip install optimum-benchmark>=0.3.0
|
||||||
env:
|
HF_TOKEN=${{ secrets.TRANSFORMERS_BENCHMARK_TOKEN }} python3 benchmark/benchmark.py --repo_id hf-internal-testing/benchmark_results --path_in_repo $(date +'%Y-%m-%d') --config-dir benchmark/config --config-name generation --commit=${{ github.sha }} backend.model=google/gemma-2b backend.cache_implementation=null,static backend.torch_compile=false,true --multirun
|
||||||
PGDATABASE: metrics
|
|
||||||
PGHOST: ${{ secrets.TRANSFORMERS_BENCHMARKS_PGHOST }}
|
|
||||||
PGUSER: transformers_benchmarks
|
|
||||||
PGPASSWORD: ${{ secrets.TRANSFORMERS_BENCHMARKS_PGPASSWORD }}
|
|
||||||
|
|
||||||
- name: Run benchmark
|
- name: Benchmark (merged to main event)
|
||||||
|
if: github.event_name == 'push' && github.ref_name == 'main'
|
||||||
|
working-directory: /transformers
|
||||||
run: |
|
run: |
|
||||||
git config --global --add safe.directory /__w/transformers/transformers
|
python3 -m pip install optimum-benchmark>=0.3.0
|
||||||
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
|
HF_TOKEN=${{ secrets.TRANSFORMERS_BENCHMARK_TOKEN }} python3 benchmark/benchmark.py --repo_id hf-internal-testing/benchmark_results_merge_event --path_in_repo $(date +'%Y-%m-%d') --config-dir benchmark/config --config-name generation --commit=${{ github.sha }} backend.model=google/gemma-2b backend.cache_implementation=null,static backend.torch_compile=false,true --multirun
|
||||||
commit_id=$(echo "${{ github.event.pull_request.head.sha }}")
|
|
||||||
elif [ "$GITHUB_EVENT_NAME" = "push" ]; then
|
|
||||||
commit_id=$GITHUB_SHA
|
|
||||||
fi
|
|
||||||
commit_msg=$(git show -s --format=%s | cut -c1-70)
|
|
||||||
python3 benchmark/benchmarks_entrypoint.py "${{ github.head_ref || github.ref_name }}" "$commit_id" "$commit_msg"
|
|
||||||
env:
|
|
||||||
HF_TOKEN: ${{ secrets.HF_HUB_READ_TOKEN }}
|
|
||||||
# Enable this to see debug logs
|
|
||||||
# HF_HUB_VERBOSITY: debug
|
|
||||||
# TRANSFORMERS_VERBOSITY: debug
|
|
||||||
PGHOST: ${{ secrets.TRANSFORMERS_BENCHMARKS_PGHOST }}
|
|
||||||
PGUSER: transformers_benchmarks
|
|
||||||
PGPASSWORD: ${{ secrets.TRANSFORMERS_BENCHMARKS_PGPASSWORD }}
|
|
||||||
|
|||||||
129
.github/workflows/check_failed_model_tests.yml
vendored
129
.github/workflows/check_failed_model_tests.yml
vendored
@ -1,129 +0,0 @@
|
|||||||
name: Process failed tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
docker:
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
start_sha:
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
|
|
||||||
env:
|
|
||||||
HF_HOME: /mnt/cache
|
|
||||||
TRANSFORMERS_IS_CI: yes
|
|
||||||
OMP_NUM_THREADS: 8
|
|
||||||
MKL_NUM_THREADS: 8
|
|
||||||
RUN_SLOW: yes
|
|
||||||
# For gated repositories, we still need to agree to share information on the Hub repo. page in order to get access.
|
|
||||||
# This token is created under the bot `hf-transformers-bot`.
|
|
||||||
HF_HUB_READ_TOKEN: ${{ secrets.HF_HUB_READ_TOKEN }}
|
|
||||||
SIGOPT_API_TOKEN: ${{ secrets.SIGOPT_API_TOKEN }}
|
|
||||||
TF_FORCE_GPU_ALLOW_GROWTH: true
|
|
||||||
RUN_PT_TF_CROSS_TESTS: 1
|
|
||||||
CUDA_VISIBLE_DEVICES: 0,1
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run_models_gpu:
|
|
||||||
name: " "
|
|
||||||
runs-on:
|
|
||||||
group: aws-g4dn-2xlarge-cache
|
|
||||||
container:
|
|
||||||
image: ${{ inputs.docker }}
|
|
||||||
options: --gpus all --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
|
||||||
steps:
|
|
||||||
- uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ci_results_run_models_gpu
|
|
||||||
path: /transformers/ci_results_run_models_gpu
|
|
||||||
|
|
||||||
- name: Update clone
|
|
||||||
working-directory: /transformers
|
|
||||||
run: git fetch && git checkout ${{ github.sha }}
|
|
||||||
|
|
||||||
- name: Get target commit
|
|
||||||
working-directory: /transformers/utils
|
|
||||||
run: |
|
|
||||||
echo "END_SHA=$(TOKEN=${{ secrets.ACCESS_REPO_INFO_TOKEN }} python3 -c 'import os; from get_previous_daily_ci import get_last_daily_ci_run_commit; commit=get_last_daily_ci_run_commit(token=os.environ["TOKEN"]); print(commit)')" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Checkout to `start_sha`
|
|
||||||
working-directory: /transformers
|
|
||||||
run: git fetch && git checkout ${{ inputs.start_sha }}
|
|
||||||
|
|
||||||
- name: Reinstall transformers in edit mode (remove the one installed during docker image build)
|
|
||||||
working-directory: /transformers
|
|
||||||
run: python3 -m pip uninstall -y transformers && python3 -m pip install -e .
|
|
||||||
|
|
||||||
- name: NVIDIA-SMI
|
|
||||||
run: |
|
|
||||||
nvidia-smi
|
|
||||||
|
|
||||||
- name: Environment
|
|
||||||
working-directory: /transformers
|
|
||||||
run: |
|
|
||||||
python3 utils/print_env.py
|
|
||||||
|
|
||||||
- name: Show installed libraries and their versions
|
|
||||||
working-directory: /transformers
|
|
||||||
run: pip freeze
|
|
||||||
|
|
||||||
- name: Check failed tests
|
|
||||||
working-directory: /transformers
|
|
||||||
run: python3 utils/check_bad_commit.py --start_commit ${{ inputs.start_sha }} --end_commit ${{ env.END_SHA }} --file ci_results_run_models_gpu/new_model_failures.json --output_file new_model_failures_with_bad_commit.json
|
|
||||||
|
|
||||||
- name: Show results
|
|
||||||
working-directory: /transformers
|
|
||||||
run: |
|
|
||||||
ls -l new_model_failures_with_bad_commit.json
|
|
||||||
cat new_model_failures_with_bad_commit.json
|
|
||||||
|
|
||||||
- name: Checkout back
|
|
||||||
working-directory: /transformers
|
|
||||||
run: |
|
|
||||||
git checkout ${{ inputs.start_sha }}
|
|
||||||
|
|
||||||
- name: Process report
|
|
||||||
shell: bash
|
|
||||||
working-directory: /transformers
|
|
||||||
env:
|
|
||||||
TRANSFORMERS_CI_RESULTS_UPLOAD_TOKEN: ${{ secrets.TRANSFORMERS_CI_RESULTS_UPLOAD_TOKEN }}
|
|
||||||
run: |
|
|
||||||
python3 utils/process_bad_commit_report.py
|
|
||||||
|
|
||||||
- name: Process report
|
|
||||||
shell: bash
|
|
||||||
working-directory: /transformers
|
|
||||||
env:
|
|
||||||
TRANSFORMERS_CI_RESULTS_UPLOAD_TOKEN: ${{ secrets.TRANSFORMERS_CI_RESULTS_UPLOAD_TOKEN }}
|
|
||||||
run: |
|
|
||||||
{
|
|
||||||
echo 'REPORT_TEXT<<EOF'
|
|
||||||
python3 utils/process_bad_commit_report.py
|
|
||||||
echo EOF
|
|
||||||
} >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Send processed report
|
|
||||||
if: ${{ !endsWith(env.REPORT_TEXT, '{}') }}
|
|
||||||
uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001
|
|
||||||
with:
|
|
||||||
# Slack channel id, channel name, or user id to post message.
|
|
||||||
# See also: https://api.slack.com/methods/chat.postMessage#channels
|
|
||||||
channel-id: '#transformers-ci-feedback-tests'
|
|
||||||
# For posting a rich message using Block Kit
|
|
||||||
payload: |
|
|
||||||
{
|
|
||||||
"blocks": [
|
|
||||||
{
|
|
||||||
"type": "section",
|
|
||||||
"text": {
|
|
||||||
"type": "mrkdwn",
|
|
||||||
"text": "${{ env.REPORT_TEXT }}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
env:
|
|
||||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_CIFEEDBACK_BOT_TOKEN }}
|
|
||||||
3
.github/workflows/doctest_job.yml
vendored
3
.github/workflows/doctest_job.yml
vendored
@ -27,8 +27,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
split_keys: ${{ fromJson(inputs.split_keys) }}
|
split_keys: ${{ fromJson(inputs.split_keys) }}
|
||||||
runs-on:
|
runs-on: [single-gpu, nvidia-gpu, t4, ci]
|
||||||
group: aws-g4dn-2xlarge-cache
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-all-latest-gpu
|
image: huggingface/transformers-all-latest-gpu
|
||||||
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
|
|||||||
5
.github/workflows/doctests.yml
vendored
5
.github/workflows/doctests.yml
vendored
@ -14,8 +14,7 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
name: Setup
|
name: Setup
|
||||||
runs-on:
|
runs-on: [single-gpu, nvidia-gpu, t4, ci]
|
||||||
group: aws-g4dn-2xlarge-cache
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-all-latest-gpu
|
image: huggingface/transformers-all-latest-gpu
|
||||||
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
@ -86,4 +85,4 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: doc_test_results
|
name: doc_test_results
|
||||||
path: doc_test_results
|
path: doc_test_results
|
||||||
10
.github/workflows/push-important-models.yml
vendored
10
.github/workflows/push-important-models.yml
vendored
@ -52,8 +52,7 @@ jobs:
|
|||||||
test_modified_files:
|
test_modified_files:
|
||||||
needs: get_modified_models
|
needs: get_modified_models
|
||||||
name: Slow & FA2 tests
|
name: Slow & FA2 tests
|
||||||
runs-on:
|
runs-on: [single-gpu, nvidia-gpu, a10, ci]
|
||||||
group: aws-g5-4xlarge-cache
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-all-latest-gpu
|
image: huggingface/transformers-all-latest-gpu
|
||||||
options: --gpus all --privileged --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus all --privileged --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
@ -134,3 +133,10 @@ jobs:
|
|||||||
slackChannel: ${{ secrets.SLACK_CIFEEDBACK_CHANNEL }}
|
slackChannel: ${{ secrets.SLACK_CIFEEDBACK_CHANNEL }}
|
||||||
slackToken: ${{ secrets.SLACK_CIFEEDBACK_BOT_TOKEN }}
|
slackToken: ${{ secrets.SLACK_CIFEEDBACK_BOT_TOKEN }}
|
||||||
waitForSSH: true
|
waitForSSH: true
|
||||||
|
|
||||||
|
benchmark:
|
||||||
|
name: Benchmark workflow
|
||||||
|
needs: get_modified_models
|
||||||
|
if: ${{ needs.get_modified_models.outputs.matrix != '[]' && needs.get_modified_models.outputs.matrix != '' && fromJson(needs.get_modified_models.outputs.matrix)[0] != null }}
|
||||||
|
uses: ./.github/workflows/benchmark.yml
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
313
.github/workflows/self-comment-ci.yml
vendored
313
.github/workflows/self-comment-ci.yml
vendored
@ -1,313 +0,0 @@
|
|||||||
name: PR comment GitHub CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types:
|
|
||||||
- created
|
|
||||||
branches-ignore:
|
|
||||||
- main
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.issue.number }}-${{ startsWith(github.event.comment.body, 'run-slow') || startsWith(github.event.comment.body, 'run slow') || startsWith(github.event.comment.body, 'run_slow') }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
permissions: read-all
|
|
||||||
|
|
||||||
env:
|
|
||||||
HF_HOME: /mnt/cache
|
|
||||||
TRANSFORMERS_IS_CI: yes
|
|
||||||
OMP_NUM_THREADS: 8
|
|
||||||
MKL_NUM_THREADS: 8
|
|
||||||
RUN_SLOW: yes
|
|
||||||
# For gated repositories, we still need to agree to share information on the Hub repo. page in order to get access.
|
|
||||||
# This token is created under the bot `hf-transformers-bot`.
|
|
||||||
HF_HUB_READ_TOKEN: ${{ secrets.HF_HUB_READ_TOKEN }}
|
|
||||||
SIGOPT_API_TOKEN: ${{ secrets.SIGOPT_API_TOKEN }}
|
|
||||||
TF_FORCE_GPU_ALLOW_GROWTH: true
|
|
||||||
RUN_PT_TF_CROSS_TESTS: 1
|
|
||||||
CUDA_VISIBLE_DEVICES: 0,1
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
get-pr-number:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
name: Get PR number
|
|
||||||
# For security: only allow team members to run
|
|
||||||
if: ${{ github.event.issue.state == 'open' && contains(fromJSON('["ydshieh", "ArthurZucker", "zucchini-nlp", "qubvel", "molbap", "gante", "LysandreJik", "Cyrilvallez", "Rocketknight1"]'), github.actor) && (startsWith(github.event.comment.body, 'run-slow') || startsWith(github.event.comment.body, 'run slow') || startsWith(github.event.comment.body, 'run_slow')) }}
|
|
||||||
outputs:
|
|
||||||
PR_NUMBER: ${{ steps.set_pr_number.outputs.PR_NUMBER }}
|
|
||||||
steps:
|
|
||||||
- name: Get PR number
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.event.issue.number }}" != "" && "${{ github.event.issue.pull_request }}" != "" ]]; then
|
|
||||||
echo "PR_NUMBER=${{ github.event.issue.number }}" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "PR_NUMBER=" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Check PR number
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "${{ env.PR_NUMBER }}"
|
|
||||||
|
|
||||||
- name: Set PR number
|
|
||||||
id: set_pr_number
|
|
||||||
run: echo "PR_NUMBER=${{ env.PR_NUMBER }}" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
get-sha:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
needs: get-pr-number
|
|
||||||
if: ${{ needs.get-pr-number.outputs.PR_NUMBER != ''}}
|
|
||||||
outputs:
|
|
||||||
PR_HEAD_SHA: ${{ steps.get_sha.outputs.PR_HEAD_SHA }}
|
|
||||||
PR_MERGE_SHA: ${{ steps.get_sha.outputs.PR_MERGE_SHA }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: "0"
|
|
||||||
ref: "refs/pull/${{needs.get-pr-number.outputs.PR_NUMBER}}/merge"
|
|
||||||
|
|
||||||
- name: Get SHA (and verify timestamps against the issue comment date)
|
|
||||||
id: get_sha
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ needs.get-pr-number.outputs.PR_NUMBER }}
|
|
||||||
COMMENT_DATE: ${{ github.event.comment.created_at }}
|
|
||||||
run: |
|
|
||||||
git fetch origin refs/pull/$PR_NUMBER/head:refs/remotes/pull/$PR_NUMBER/head
|
|
||||||
git checkout refs/remotes/pull/$PR_NUMBER/head
|
|
||||||
echo "PR_HEAD_SHA: $(git log -1 --format=%H)"
|
|
||||||
echo "PR_HEAD_SHA=$(git log -1 --format=%H)" >> "$GITHUB_OUTPUT"
|
|
||||||
git fetch origin refs/pull/$PR_NUMBER/merge:refs/remotes/pull/$PR_NUMBER/merge
|
|
||||||
git checkout refs/remotes/pull/$PR_NUMBER/merge
|
|
||||||
echo "PR_MERGE_SHA: $(git log -1 --format=%H)"
|
|
||||||
echo "PR_MERGE_SHA=$(git log -1 --format=%H)" >> "$GITHUB_OUTPUT"
|
|
||||||
PR_MERGE_COMMIT_TIMESTAMP=$(git log -1 --date=unix --format=%cd)
|
|
||||||
echo "PR_MERGE_COMMIT_TIMESTAMP: $PR_MERGE_COMMIT_TIMESTAMP"
|
|
||||||
COMMENT_TIMESTAMP=$(date -d "${COMMENT_DATE}" +"%s")
|
|
||||||
echo "COMMENT_DATE: $COMMENT_DATE"
|
|
||||||
echo "COMMENT_TIMESTAMP: $COMMENT_TIMESTAMP"
|
|
||||||
if [ $COMMENT_TIMESTAMP -le $PR_MERGE_COMMIT_TIMESTAMP ]; then
|
|
||||||
echo "Last commit on the pull request is newer than the issue comment triggering this run! Abort!";
|
|
||||||
exit -1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
# use a python script to handle this complex logic
|
|
||||||
# case 1: `run-slow` (auto. infer with limited number of models, but in particular, new model)
|
|
||||||
# case 2: `run-slow model_1, model_2`
|
|
||||||
get-tests:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
needs: [get-pr-number, get-sha]
|
|
||||||
if: ${{ needs.get-pr-number.outputs.PR_NUMBER != ''}}
|
|
||||||
outputs:
|
|
||||||
models: ${{ steps.models_to_run.outputs.models }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: "0"
|
|
||||||
ref: "refs/pull/${{needs.get-pr-number.outputs.PR_NUMBER}}/merge"
|
|
||||||
|
|
||||||
- name: Verify merge commit SHA
|
|
||||||
env:
|
|
||||||
VERIFIED_PR_MERGE_SHA: ${{ needs.get-sha.outputs.PR_MERGE_SHA }}
|
|
||||||
run: |
|
|
||||||
PR_MERGE_SHA=$(git log -1 --format=%H)
|
|
||||||
if [ $PR_MERGE_SHA != $VERIFIED_PR_MERGE_SHA ]; then
|
|
||||||
echo "The merged commit SHA is not the same as the verified one! Security issue detected, abort the workflow!";
|
|
||||||
exit -1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Get models to test
|
|
||||||
env:
|
|
||||||
PR_COMMENT: ${{ github.event.comment.body }}
|
|
||||||
run: |
|
|
||||||
python -m pip install GitPython
|
|
||||||
python utils/pr_slow_ci_models.py --message "$PR_COMMENT" | tee output.txt
|
|
||||||
echo "models=$(tail -n 1 output.txt)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Show models to test
|
|
||||||
id: models_to_run
|
|
||||||
run: |
|
|
||||||
echo "${{ env.models }}"
|
|
||||||
echo "models=${{ env.models }}" >> $GITHUB_ENV
|
|
||||||
echo "models=${{ env.models }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
reply_to_comment:
|
|
||||||
name: Reply to the comment
|
|
||||||
if: ${{ needs.get-tests.outputs.models != '[]' }}
|
|
||||||
needs: [get-pr-number, get-tests]
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Reply to the comment
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
MODELS: ${{ needs.get-tests.outputs.models }}
|
|
||||||
run: |
|
|
||||||
gh api \
|
|
||||||
--method POST \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
repos/${{ github.repository }}/issues/${{ needs.get-pr-number.outputs.PR_NUMBER }}/comments \
|
|
||||||
-f "body=This comment contains run-slow, running the specified jobs: ${{ env.MODELS }} ..."
|
|
||||||
|
|
||||||
create_run:
|
|
||||||
name: Create run
|
|
||||||
if: ${{ needs.get-tests.outputs.models != '[]' }}
|
|
||||||
needs: [get-sha, get-tests, reply_to_comment]
|
|
||||||
permissions:
|
|
||||||
statuses: write
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Create Run
|
|
||||||
id: create_run
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
# Create a commit status (pending) for a run of this workflow. The status has to be updated later in `update_run_status`.
|
|
||||||
# See https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#create-a-commit-status
|
|
||||||
GITHUB_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
run: |
|
|
||||||
gh api \
|
|
||||||
--method POST \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
repos/${{ github.repository }}/statuses/${{ needs.get-sha.outputs.PR_HEAD_SHA }} \
|
|
||||||
-f "target_url=$GITHUB_RUN_URL" -f "state=pending" -f "description=Slow CI job" -f "context=pytest/custom-tests"
|
|
||||||
|
|
||||||
run_models_gpu:
|
|
||||||
name: Run all tests for the model
|
|
||||||
if: ${{ needs.get-tests.outputs.models != '[]' }}
|
|
||||||
needs: [get-pr-number, get-sha, get-tests, create_run]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
folders: ${{ fromJson(needs.get-tests.outputs.models) }}
|
|
||||||
machine_type: [aws-g4dn-2xlarge-cache, aws-g4dn-12xlarge-cache]
|
|
||||||
runs-on:
|
|
||||||
group: '${{ matrix.machine_type }}'
|
|
||||||
container:
|
|
||||||
image: huggingface/transformers-all-latest-gpu
|
|
||||||
options: --gpus all --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
|
||||||
steps:
|
|
||||||
- name: Echo input and matrix info
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "${{ matrix.folders }}"
|
|
||||||
|
|
||||||
- name: Echo folder ${{ matrix.folders }}
|
|
||||||
shell: bash
|
|
||||||
# For folders like `models/bert`, set an env. var. (`matrix_folders`) to `models_bert`, which will be used to
|
|
||||||
# set the artifact folder names (because the character `/` is not allowed).
|
|
||||||
run: |
|
|
||||||
echo "${{ matrix.folders }}"
|
|
||||||
matrix_folders=${{ matrix.folders }}
|
|
||||||
matrix_folders=${matrix_folders/'models/'/'models_'}
|
|
||||||
echo "$matrix_folders"
|
|
||||||
echo "matrix_folders=$matrix_folders" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Checkout to PR merge commit
|
|
||||||
working-directory: /transformers
|
|
||||||
run: |
|
|
||||||
git fetch origin refs/pull/${{ needs.get-pr-number.outputs.PR_NUMBER }}/merge:refs/remotes/pull/${{ needs.get-pr-number.outputs.PR_NUMBER }}/merge
|
|
||||||
git checkout refs/remotes/pull/${{ needs.get-pr-number.outputs.PR_NUMBER }}/merge
|
|
||||||
git log -1 --format=%H
|
|
||||||
|
|
||||||
- name: Verify merge commit SHA
|
|
||||||
env:
|
|
||||||
VERIFIED_PR_MERGE_SHA: ${{ needs.get-sha.outputs.PR_MERGE_SHA }}
|
|
||||||
working-directory: /transformers
|
|
||||||
run: |
|
|
||||||
PR_MERGE_SHA=$(git log -1 --format=%H)
|
|
||||||
if [ $PR_MERGE_SHA != $VERIFIED_PR_MERGE_SHA ]; then
|
|
||||||
echo "The merged commit SHA is not the same as the verified one! Security issue detected, abort the workflow!";
|
|
||||||
exit -1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Reinstall transformers in edit mode (remove the one installed during docker image build)
|
|
||||||
working-directory: /transformers
|
|
||||||
run: python3 -m pip uninstall -y transformers && python3 -m pip install -e .
|
|
||||||
|
|
||||||
- name: NVIDIA-SMI
|
|
||||||
run: |
|
|
||||||
nvidia-smi
|
|
||||||
|
|
||||||
- name: Set `machine_type` for report and artifact names
|
|
||||||
working-directory: /transformers
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "${{ matrix.machine_type }}"
|
|
||||||
if [ "${{ matrix.machine_type }}" = "aws-g4dn-2xlarge-cache" ]; then
|
|
||||||
machine_type=single-gpu
|
|
||||||
elif [ "${{ matrix.machine_type }}" = "aws-g4dn-12xlarge-cache" ]; then
|
|
||||||
machine_type=multi-gpu
|
|
||||||
else
|
|
||||||
machine_type=${{ matrix.machine_type }}
|
|
||||||
fi
|
|
||||||
echo "$machine_type"
|
|
||||||
echo "machine_type=$machine_type" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Environment
|
|
||||||
working-directory: /transformers
|
|
||||||
run: |
|
|
||||||
python3 utils/print_env.py
|
|
||||||
|
|
||||||
- name: Show installed libraries and their versions
|
|
||||||
working-directory: /transformers
|
|
||||||
run: pip freeze
|
|
||||||
|
|
||||||
- name: Run all tests on GPU
|
|
||||||
working-directory: /transformers
|
|
||||||
run: |
|
|
||||||
export CUDA_VISIBLE_DEVICES="$(python3 utils/set_cuda_devices_for_ci.py --test_folder ${{ matrix.folders }})"
|
|
||||||
echo $CUDA_VISIBLE_DEVICES
|
|
||||||
python3 -m pytest -v -rsfE --make-reports=${{ env.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports tests/${{ matrix.folders }}
|
|
||||||
|
|
||||||
- name: Failure short reports
|
|
||||||
if: ${{ failure() }}
|
|
||||||
continue-on-error: true
|
|
||||||
run: cat /transformers/reports/${{ env.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports/failures_short.txt
|
|
||||||
|
|
||||||
- name: Make sure report directory exists
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p /transformers/reports/${{ env.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports
|
|
||||||
echo "hello" > /transformers/reports/${{ env.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports/hello.txt
|
|
||||||
echo "${{ env.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports"
|
|
||||||
|
|
||||||
- name: "Test suite reports artifacts: ${{ env.machine_type }}_run_models_gpu_${{ env.matrix_folders }}_test_reports"
|
|
||||||
if: ${{ always() }}
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ env.machine_type }}_run_models_gpu_${{ env.matrix_folders }}_test_reports
|
|
||||||
path: /transformers/reports/${{ env.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports
|
|
||||||
|
|
||||||
update_run_status:
|
|
||||||
name: Update Check Run Status
|
|
||||||
needs: [get-sha, create_run, run_models_gpu]
|
|
||||||
permissions:
|
|
||||||
statuses: write
|
|
||||||
if: ${{ always() && needs.create_run.result == 'success' }}
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GITHUB_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
steps:
|
|
||||||
- name: Get `run_models_gpu` job status
|
|
||||||
run: |
|
|
||||||
echo "${{ needs.run_models_gpu.result }}"
|
|
||||||
if [ "${{ needs.run_models_gpu.result }}" = "cancelled" ]; then
|
|
||||||
echo "STATUS=failure" >> $GITHUB_ENV
|
|
||||||
elif [ "${{ needs.run_models_gpu.result }}" = "skipped" ]; then
|
|
||||||
echo "STATUS=success" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "STATUS=${{ needs.run_models_gpu.result }}" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Update PR commit statuses
|
|
||||||
run: |
|
|
||||||
echo "${{ needs.run_models_gpu.result }}"
|
|
||||||
echo "${{ env.STATUS }}"
|
|
||||||
gh api \
|
|
||||||
--method POST \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
||||||
repos/${{ github.repository }}/statuses/${{ needs.get-sha.outputs.PR_HEAD_SHA }} \
|
|
||||||
-f "target_url=$GITHUB_RUN_URL" -f "state=${{ env.STATUS }}" -f "description=Slow CI job" -f "context=pytest/custom-tests"
|
|
||||||
@ -21,6 +21,39 @@ jobs:
|
|||||||
echo "$(python3 -c 'print(int(${{ github.run_number }}) % 10)')"
|
echo "$(python3 -c 'print(int(${{ github.run_number }}) % 10)')"
|
||||||
echo "run_number=$(python3 -c 'print(int(${{ github.run_number }}) % 10)')" >> $GITHUB_OUTPUT
|
echo "run_number=$(python3 -c 'print(int(${{ github.run_number }}) % 10)')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
run_past_ci_pytorch_1-13:
|
||||||
|
name: PyTorch 1.13
|
||||||
|
needs: get_number
|
||||||
|
if: needs.get_number.outputs.run_number == 0 && (cancelled() != true) && ((github.event_name == 'schedule') || ((github.event_name == 'push') && startsWith(github.ref_name, 'run_past_ci')))
|
||||||
|
uses: ./.github/workflows/self-past-caller.yml
|
||||||
|
with:
|
||||||
|
framework: pytorch
|
||||||
|
version: "1.13"
|
||||||
|
sha: ${{ github.sha }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
run_past_ci_pytorch_1-12:
|
||||||
|
name: PyTorch 1.12
|
||||||
|
needs: get_number
|
||||||
|
if: needs.get_number.outputs.run_number == 1 && (cancelled() != true) && ((github.event_name == 'schedule') || ((github.event_name == 'push') && startsWith(github.ref_name, 'run_past_ci')))
|
||||||
|
uses: ./.github/workflows/self-past-caller.yml
|
||||||
|
with:
|
||||||
|
framework: pytorch
|
||||||
|
version: "1.12"
|
||||||
|
sha: ${{ github.sha }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
run_past_ci_pytorch_1-11:
|
||||||
|
name: PyTorch 1.11
|
||||||
|
needs: get_number
|
||||||
|
if: needs.get_number.outputs.run_number == 2 && (cancelled() != true) && ((github.event_name == 'schedule') || ((github.event_name == 'push') && startsWith(github.ref_name, 'run_past_ci')))
|
||||||
|
uses: ./.github/workflows/self-past-caller.yml
|
||||||
|
with:
|
||||||
|
framework: pytorch
|
||||||
|
version: "1.11"
|
||||||
|
sha: ${{ github.sha }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
run_past_ci_tensorflow_2-11:
|
run_past_ci_tensorflow_2-11:
|
||||||
name: TensorFlow 2.11
|
name: TensorFlow 2.11
|
||||||
needs: get_number
|
needs: get_number
|
||||||
|
|||||||
135
.github/workflows/self-pr-slow-ci.yml
vendored
Normal file
135
.github/workflows/self-pr-slow-ci.yml
vendored
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
name: PR slow CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "src/transformers/models/*/modeling_*.py"
|
||||||
|
- "tests/**/test_*.py"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
HF_HOME: /mnt/cache
|
||||||
|
TRANSFORMERS_IS_CI: yes
|
||||||
|
OMP_NUM_THREADS: 8
|
||||||
|
MKL_NUM_THREADS: 8
|
||||||
|
RUN_SLOW: yes
|
||||||
|
# For gated repositories, we still need to agree to share information on the Hub repo. page in order to get access.
|
||||||
|
# This token is created under the bot `hf-transformers-bot`.
|
||||||
|
HF_HUB_READ_TOKEN: ${{ secrets.HF_HUB_READ_TOKEN }}
|
||||||
|
SIGOPT_API_TOKEN: ${{ secrets.SIGOPT_API_TOKEN }}
|
||||||
|
TF_FORCE_GPU_ALLOW_GROWTH: true
|
||||||
|
RUN_PT_TF_CROSS_TESTS: 1
|
||||||
|
CUDA_VISIBLE_DEVICES: 0,1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
find_models_to_run:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
name: Find models to run slow tests
|
||||||
|
# Triggered only if the required label `run-slow` is added
|
||||||
|
if: ${{ contains(github.event.pull_request.labels.*.name, 'run-slow') }}
|
||||||
|
outputs:
|
||||||
|
models: ${{ steps.models_to_run.outputs.models }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: "0"
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
|
- name: Get commit message
|
||||||
|
run: |
|
||||||
|
echo "commit_message=$(git show -s --format=%s)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get models to run slow tests
|
||||||
|
run: |
|
||||||
|
echo "${{ env.commit_message }}"
|
||||||
|
python -m pip install GitPython
|
||||||
|
python utils/pr_slow_ci_models.py --commit_message "${{ env.commit_message }}" | tee output.txt
|
||||||
|
echo "models=$(tail -n 1 output.txt)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Models to run slow tests
|
||||||
|
id: models_to_run
|
||||||
|
run: |
|
||||||
|
echo "${{ env.models }}"
|
||||||
|
echo "models=${{ env.models }}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
run_models_gpu:
|
||||||
|
name: Run all tests for the model
|
||||||
|
# Triggered only `find_models_to_run` is triggered (label `run-slow` is added) which gives the models to run
|
||||||
|
# (either a new model PR or via a commit message)
|
||||||
|
if: ${{ needs.find_models_to_run.outputs.models != '[]' }}
|
||||||
|
needs: find_models_to_run
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
folders: ${{ fromJson(needs.find_models_to_run.outputs.models) }}
|
||||||
|
machine_type: [single-gpu, multi-gpu]
|
||||||
|
runs-on: ['${{ matrix.machine_type }}', nvidia-gpu, t4, ci]
|
||||||
|
container:
|
||||||
|
image: huggingface/transformers-all-latest-gpu
|
||||||
|
options: --gpus all --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
|
steps:
|
||||||
|
- name: Echo input and matrix info
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "${{ matrix.folders }}"
|
||||||
|
|
||||||
|
- name: Echo folder ${{ matrix.folders }}
|
||||||
|
shell: bash
|
||||||
|
# For folders like `models/bert`, set an env. var. (`matrix_folders`) to `models_bert`, which will be used to
|
||||||
|
# set the artifact folder names (because the character `/` is not allowed).
|
||||||
|
run: |
|
||||||
|
echo "${{ matrix.folders }}"
|
||||||
|
matrix_folders=${{ matrix.folders }}
|
||||||
|
matrix_folders=${matrix_folders/'models/'/'models_'}
|
||||||
|
echo "$matrix_folders"
|
||||||
|
echo "matrix_folders=$matrix_folders" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Update clone
|
||||||
|
working-directory: /transformers
|
||||||
|
run: git fetch && git fetch origin pull/${{ github.event.pull_request.number }}/head:pull/${{ github.event.pull_request.number }}/merge && git checkout pull/${{ github.event.pull_request.number }}/merge
|
||||||
|
|
||||||
|
- name: Reinstall transformers in edit mode (remove the one installed during docker image build)
|
||||||
|
working-directory: /transformers
|
||||||
|
run: python3 -m pip uninstall -y transformers && python3 -m pip install -e .
|
||||||
|
|
||||||
|
- name: NVIDIA-SMI
|
||||||
|
run: |
|
||||||
|
nvidia-smi
|
||||||
|
|
||||||
|
- name: Environment
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
python3 utils/print_env.py
|
||||||
|
|
||||||
|
- name: Show installed libraries and their versions
|
||||||
|
working-directory: /transformers
|
||||||
|
run: pip freeze
|
||||||
|
|
||||||
|
- name: Run all tests on GPU
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
export CUDA_VISIBLE_DEVICES="$(python3 utils/set_cuda_devices_for_ci.py --test_folder ${{ matrix.folders }})"
|
||||||
|
echo $CUDA_VISIBLE_DEVICES
|
||||||
|
python3 -m pytest -v -rsfE --make-reports=${{ matrix.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports tests/${{ matrix.folders }}
|
||||||
|
|
||||||
|
- name: Failure short reports
|
||||||
|
if: ${{ failure() }}
|
||||||
|
continue-on-error: true
|
||||||
|
run: cat /transformers/reports/${{ matrix.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports/failures_short.txt
|
||||||
|
|
||||||
|
- name: Make sure report directory exists
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p /transformers/reports/${{ matrix.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports
|
||||||
|
echo "hello" > /transformers/reports/${{ matrix.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports/hello.txt
|
||||||
|
echo "${{ matrix.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports"
|
||||||
|
|
||||||
|
- name: "Test suite reports artifacts: ${{ matrix.machine_type }}_run_models_gpu_${{ env.matrix_folders }}_test_reports"
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.machine_type }}_run_models_gpu_${{ env.matrix_folders }}_test_reports
|
||||||
|
path: /transformers/reports/${{ matrix.machine_type }}_run_models_gpu_${{ matrix.folders }}_test_reports
|
||||||
50
.github/workflows/self-push-amd-mi210-caller.yml
vendored
50
.github/workflows/self-push-amd-mi210-caller.yml
vendored
@ -1,25 +1,25 @@
|
|||||||
name: Self-hosted runner (AMD mi210 CI caller)
|
name: Self-hosted runner (AMD mi210 CI caller)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
#workflow_run:
|
workflow_run:
|
||||||
# workflows: ["Self-hosted runner (push-caller)"]
|
workflows: ["Self-hosted runner (push-caller)"]
|
||||||
# branches: ["main"]
|
branches: ["main"]
|
||||||
# types: [completed]
|
types: [completed]
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- run_amd_push_ci_caller*
|
- run_amd_push_ci_caller*
|
||||||
paths:
|
paths:
|
||||||
- "src/**"
|
- "src/**"
|
||||||
- "tests/**"
|
- "tests/**"
|
||||||
- ".github/**"
|
- ".github/**"
|
||||||
- "templates/**"
|
- "templates/**"
|
||||||
- "utils/**"
|
- "utils/**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run_amd_ci:
|
run_amd_ci:
|
||||||
name: AMD mi210
|
name: AMD mi210
|
||||||
if: (cancelled() != true) && ((github.event_name == 'workflow_run') || ((github.event_name == 'push') && startsWith(github.ref_name, 'run_amd_push_ci_caller')))
|
if: (cancelled() != true) && ((github.event_name == 'workflow_run') || ((github.event_name == 'push') && startsWith(github.ref_name, 'run_amd_push_ci_caller')))
|
||||||
uses: ./.github/workflows/self-push-amd.yml
|
uses: ./.github/workflows/self-push-amd.yml
|
||||||
with:
|
with:
|
||||||
gpu_flavor: mi210
|
gpu_flavor: mi210
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|||||||
50
.github/workflows/self-push-amd-mi250-caller.yml
vendored
50
.github/workflows/self-push-amd-mi250-caller.yml
vendored
@ -1,25 +1,25 @@
|
|||||||
name: Self-hosted runner (AMD mi250 CI caller)
|
name: Self-hosted runner (AMD mi250 CI caller)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
#workflow_run:
|
workflow_run:
|
||||||
# workflows: ["Self-hosted runner (push-caller)"]
|
workflows: ["Self-hosted runner (push-caller)"]
|
||||||
# branches: ["main"]
|
branches: ["main"]
|
||||||
# types: [completed]
|
types: [completed]
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- run_amd_push_ci_caller*
|
- run_amd_push_ci_caller*
|
||||||
paths:
|
paths:
|
||||||
- "src/**"
|
- "src/**"
|
||||||
- "tests/**"
|
- "tests/**"
|
||||||
- ".github/**"
|
- ".github/**"
|
||||||
- "templates/**"
|
- "templates/**"
|
||||||
- "utils/**"
|
- "utils/**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run_amd_ci:
|
run_amd_ci:
|
||||||
name: AMD mi250
|
name: AMD mi250
|
||||||
if: (cancelled() != true) && ((github.event_name == 'workflow_run') || ((github.event_name == 'push') && startsWith(github.ref_name, 'run_amd_push_ci_caller')))
|
if: (cancelled() != true) && ((github.event_name == 'workflow_run') || ((github.event_name == 'push') && startsWith(github.ref_name, 'run_amd_push_ci_caller')))
|
||||||
uses: ./.github/workflows/self-push-amd.yml
|
uses: ./.github/workflows/self-push-amd.yml
|
||||||
with:
|
with:
|
||||||
gpu_flavor: mi250
|
gpu_flavor: mi250
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
name: Self-hosted runner (AMD mi300 CI caller)
|
name: Self-hosted runner (AMD mi300 CI caller)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
#workflow_run:
|
workflow_run:
|
||||||
# workflows: ["Self-hosted runner (push-caller)"]
|
workflows: ["Self-hosted runner (push-caller)"]
|
||||||
# branches: ["main"]
|
branches: ["main"]
|
||||||
# types: [completed]
|
types: [completed]
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- run_amd_push_ci_caller*
|
- run_amd_push_ci_caller*
|
||||||
|
|||||||
133
.github/workflows/self-push.yml
vendored
133
.github/workflows/self-push.yml
vendored
@ -32,9 +32,8 @@ jobs:
|
|||||||
name: Setup
|
name: Setup
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
machine_type: [aws-g4dn-2xlarge-cache, aws-g4dn-12xlarge-cache]
|
machine_type: [single-gpu, multi-gpu]
|
||||||
runs-on:
|
runs-on: ['${{ matrix.machine_type }}', nvidia-gpu, t4, push-ci]
|
||||||
group: '${{ matrix.machine_type }}'
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-all-latest-gpu-push-ci
|
image: huggingface/transformers-all-latest-gpu-push-ci
|
||||||
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
@ -132,9 +131,8 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
folders: ${{ fromJson(needs.setup.outputs.matrix) }}
|
folders: ${{ fromJson(needs.setup.outputs.matrix) }}
|
||||||
machine_type: [aws-g4dn-2xlarge-cache]
|
machine_type: [single-gpu]
|
||||||
runs-on:
|
runs-on: ['${{ matrix.machine_type }}', nvidia-gpu, t4, push-ci]
|
||||||
group: '${{ matrix.machine_type }}'
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-all-latest-gpu-push-ci
|
image: huggingface/transformers-all-latest-gpu-push-ci
|
||||||
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
@ -164,23 +162,6 @@ jobs:
|
|||||||
echo "env.CI_BRANCH = ${{ env.CI_BRANCH }}"
|
echo "env.CI_BRANCH = ${{ env.CI_BRANCH }}"
|
||||||
echo "env.CI_SHA = ${{ env.CI_SHA }}"
|
echo "env.CI_SHA = ${{ env.CI_SHA }}"
|
||||||
|
|
||||||
- name: Set `machine_type` for report and artifact names
|
|
||||||
working-directory: /transformers
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "${{ matrix.machine_type }}"
|
|
||||||
|
|
||||||
if [ "${{ matrix.machine_type }}" = "aws-g4dn-2xlarge-cache" ]; then
|
|
||||||
machine_type=single-gpu
|
|
||||||
elif [ "${{ matrix.machine_type }}" = "aws-g4dn-12xlarge-cache" ]; then
|
|
||||||
machine_type=multi-gpu
|
|
||||||
else
|
|
||||||
machine_type=${{ matrix.machine_type }}
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$machine_type"
|
|
||||||
echo "machine_type=$machine_type" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Update clone using environment variables
|
- name: Update clone using environment variables
|
||||||
working-directory: /transformers
|
working-directory: /transformers
|
||||||
run: |
|
run: |
|
||||||
@ -222,19 +203,19 @@ jobs:
|
|||||||
- name: Run all non-slow selected tests on GPU
|
- name: Run all non-slow selected tests on GPU
|
||||||
working-directory: /transformers
|
working-directory: /transformers
|
||||||
run: |
|
run: |
|
||||||
python3 -m pytest -n 2 --dist=loadfile -v --make-reports=${{ env.machine_type }}_tests_gpu_${{ matrix.folders }} ${{ fromJson(needs.setup.outputs.test_map)[matrix.folders] }}
|
python3 -m pytest -n 2 --dist=loadfile -v --make-reports=${{ matrix.machine_type }}_tests_gpu_${{ matrix.folders }} ${{ fromJson(needs.setup.outputs.test_map)[matrix.folders] }}
|
||||||
|
|
||||||
- name: Failure short reports
|
- name: Failure short reports
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: cat /transformers/reports/${{ env.machine_type }}_tests_gpu_${{ matrix.folders }}/failures_short.txt
|
run: cat /transformers/reports/${{ matrix.machine_type }}_tests_gpu_${{ matrix.folders }}/failures_short.txt
|
||||||
|
|
||||||
- name: "Test suite reports artifacts: ${{ env.machine_type }}_run_all_tests_gpu_${{ env.matrix_folders }}_test_reports"
|
- name: "Test suite reports artifacts: ${{ matrix.machine_type }}_run_all_tests_gpu_${{ env.matrix_folders }}_test_reports"
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.machine_type }}_run_all_tests_gpu_${{ env.matrix_folders }}_test_reports
|
name: ${{ matrix.machine_type }}_run_all_tests_gpu_${{ env.matrix_folders }}_test_reports
|
||||||
path: /transformers/reports/${{ env.machine_type }}_tests_gpu_${{ matrix.folders }}
|
path: /transformers/reports/${{ matrix.machine_type }}_tests_gpu_${{ matrix.folders }}
|
||||||
|
|
||||||
run_tests_multi_gpu:
|
run_tests_multi_gpu:
|
||||||
name: Model tests
|
name: Model tests
|
||||||
@ -245,9 +226,8 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
folders: ${{ fromJson(needs.setup.outputs.matrix) }}
|
folders: ${{ fromJson(needs.setup.outputs.matrix) }}
|
||||||
machine_type: [aws-g4dn-12xlarge-cache]
|
machine_type: [multi-gpu]
|
||||||
runs-on:
|
runs-on: ['${{ matrix.machine_type }}', nvidia-gpu, t4, push-ci]
|
||||||
group: '${{ matrix.machine_type }}'
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-all-latest-gpu-push-ci
|
image: huggingface/transformers-all-latest-gpu-push-ci
|
||||||
options: --gpus all --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus all --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
@ -277,23 +257,6 @@ jobs:
|
|||||||
echo "env.CI_BRANCH = ${{ env.CI_BRANCH }}"
|
echo "env.CI_BRANCH = ${{ env.CI_BRANCH }}"
|
||||||
echo "env.CI_SHA = ${{ env.CI_SHA }}"
|
echo "env.CI_SHA = ${{ env.CI_SHA }}"
|
||||||
|
|
||||||
- name: Set `machine_type` for report and artifact names
|
|
||||||
working-directory: /transformers
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "${{ matrix.machine_type }}"
|
|
||||||
|
|
||||||
if [ "${{ matrix.machine_type }}" = "aws-g4dn-2xlarge-cache" ]; then
|
|
||||||
machine_type=single-gpu
|
|
||||||
elif [ "${{ matrix.machine_type }}" = "aws-g4dn-12xlarge-cache" ]; then
|
|
||||||
machine_type=multi-gpu
|
|
||||||
else
|
|
||||||
machine_type=${{ matrix.machine_type }}
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$machine_type"
|
|
||||||
echo "machine_type=$machine_type" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Update clone using environment variables
|
- name: Update clone using environment variables
|
||||||
working-directory: /transformers
|
working-directory: /transformers
|
||||||
run: |
|
run: |
|
||||||
@ -337,19 +300,19 @@ jobs:
|
|||||||
MKL_SERVICE_FORCE_INTEL: 1
|
MKL_SERVICE_FORCE_INTEL: 1
|
||||||
working-directory: /transformers
|
working-directory: /transformers
|
||||||
run: |
|
run: |
|
||||||
python3 -m pytest -n 2 --dist=loadfile -v --make-reports=${{ env.machine_type }}_tests_gpu_${{ matrix.folders }} ${{ fromJson(needs.setup.outputs.test_map)[matrix.folders] }}
|
python3 -m pytest -n 2 --dist=loadfile -v --make-reports=${{ matrix.machine_type }}_tests_gpu_${{ matrix.folders }} ${{ fromJson(needs.setup.outputs.test_map)[matrix.folders] }}
|
||||||
|
|
||||||
- name: Failure short reports
|
- name: Failure short reports
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: cat /transformers/reports/${{ env.machine_type }}_tests_gpu_${{ matrix.folders }}/failures_short.txt
|
run: cat /transformers/reports/${{ matrix.machine_type }}_tests_gpu_${{ matrix.folders }}/failures_short.txt
|
||||||
|
|
||||||
- name: "Test suite reports artifacts: ${{ env.machine_type }}_run_all_tests_gpu_${{ env.matrix_folders }}_test_reports"
|
- name: "Test suite reports artifacts: ${{ matrix.machine_type }}_run_all_tests_gpu_${{ env.matrix_folders }}_test_reports"
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.machine_type }}_run_all_tests_gpu_${{ env.matrix_folders }}_test_reports
|
name: ${{ matrix.machine_type }}_run_all_tests_gpu_${{ env.matrix_folders }}_test_reports
|
||||||
path: /transformers/reports/${{ env.machine_type }}_tests_gpu_${{ matrix.folders }}
|
path: /transformers/reports/${{ matrix.machine_type }}_tests_gpu_${{ matrix.folders }}
|
||||||
|
|
||||||
run_tests_torch_cuda_extensions_single_gpu:
|
run_tests_torch_cuda_extensions_single_gpu:
|
||||||
name: Torch CUDA extension tests
|
name: Torch CUDA extension tests
|
||||||
@ -358,9 +321,8 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
machine_type: [aws-g4dn-2xlarge-cache]
|
machine_type: [single-gpu]
|
||||||
runs-on:
|
runs-on: ['${{ matrix.machine_type }}', nvidia-gpu, t4, push-ci]
|
||||||
group: '${{ matrix.machine_type }}'
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-pytorch-deepspeed-latest-gpu-push-ci
|
image: huggingface/transformers-pytorch-deepspeed-latest-gpu-push-ci
|
||||||
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus 0 --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
@ -390,23 +352,6 @@ jobs:
|
|||||||
echo "env.CI_BRANCH = ${{ env.CI_BRANCH }}"
|
echo "env.CI_BRANCH = ${{ env.CI_BRANCH }}"
|
||||||
echo "env.CI_SHA = ${{ env.CI_SHA }}"
|
echo "env.CI_SHA = ${{ env.CI_SHA }}"
|
||||||
|
|
||||||
- name: Set `machine_type` for report and artifact names
|
|
||||||
working-directory: /workspace/transformers
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "${{ matrix.machine_type }}"
|
|
||||||
|
|
||||||
if [ "${{ matrix.machine_type }}" = "aws-g4dn-2xlarge-cache" ]; then
|
|
||||||
machine_type=single-gpu
|
|
||||||
elif [ "${{ matrix.machine_type }}" = "aws-g4dn-12xlarge-cache" ]; then
|
|
||||||
machine_type=multi-gpu
|
|
||||||
else
|
|
||||||
machine_type=${{ matrix.machine_type }}
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$machine_type"
|
|
||||||
echo "machine_type=$machine_type" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Update clone using environment variables
|
- name: Update clone using environment variables
|
||||||
working-directory: /workspace/transformers
|
working-directory: /workspace/transformers
|
||||||
run: |
|
run: |
|
||||||
@ -447,19 +392,19 @@ jobs:
|
|||||||
working-directory: /workspace/transformers
|
working-directory: /workspace/transformers
|
||||||
# TODO: Here we pass all tests in the 2 folders for simplicity. It's better to pass only the identified tests.
|
# TODO: Here we pass all tests in the 2 folders for simplicity. It's better to pass only the identified tests.
|
||||||
run: |
|
run: |
|
||||||
python -m pytest -n 1 --dist=loadfile -v --make-reports=${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports tests/deepspeed tests/extended
|
python -m pytest -n 1 --dist=loadfile -v --make-reports=${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports tests/deepspeed tests/extended
|
||||||
|
|
||||||
- name: Failure short reports
|
- name: Failure short reports
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: cat /workspace/transformers/reports/${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports/failures_short.txt
|
run: cat /workspace/transformers/reports/${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports/failures_short.txt
|
||||||
|
|
||||||
- name: "Test suite reports artifacts: ${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports"
|
- name: "Test suite reports artifacts: ${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports"
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
name: ${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
||||||
path: /workspace/transformers/reports/${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
path: /workspace/transformers/reports/${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
||||||
|
|
||||||
run_tests_torch_cuda_extensions_multi_gpu:
|
run_tests_torch_cuda_extensions_multi_gpu:
|
||||||
name: Torch CUDA extension tests
|
name: Torch CUDA extension tests
|
||||||
@ -468,9 +413,8 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
machine_type: [aws-g4dn-12xlarge-cache]
|
machine_type: [multi-gpu]
|
||||||
runs-on:
|
runs-on: ['${{ matrix.machine_type }}', nvidia-gpu, t4, push-ci]
|
||||||
group: '${{ matrix.machine_type }}'
|
|
||||||
container:
|
container:
|
||||||
image: huggingface/transformers-pytorch-deepspeed-latest-gpu-push-ci
|
image: huggingface/transformers-pytorch-deepspeed-latest-gpu-push-ci
|
||||||
options: --gpus all --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus all --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
@ -500,23 +444,6 @@ jobs:
|
|||||||
echo "env.CI_BRANCH = ${{ env.CI_BRANCH }}"
|
echo "env.CI_BRANCH = ${{ env.CI_BRANCH }}"
|
||||||
echo "env.CI_SHA = ${{ env.CI_SHA }}"
|
echo "env.CI_SHA = ${{ env.CI_SHA }}"
|
||||||
|
|
||||||
- name: Set `machine_type` for report and artifact names
|
|
||||||
working-directory: /workspace/transformers
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "${{ matrix.machine_type }}"
|
|
||||||
|
|
||||||
if [ "${{ matrix.machine_type }}" = "aws-g4dn-2xlarge-cache" ]; then
|
|
||||||
machine_type=single-gpu
|
|
||||||
elif [ "${{ matrix.machine_type }}" = "aws-g4dn-12xlarge-cache" ]; then
|
|
||||||
machine_type=multi-gpu
|
|
||||||
else
|
|
||||||
machine_type=${{ matrix.machine_type }}
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$machine_type"
|
|
||||||
echo "machine_type=$machine_type" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Update clone using environment variables
|
- name: Update clone using environment variables
|
||||||
working-directory: /workspace/transformers
|
working-directory: /workspace/transformers
|
||||||
run: |
|
run: |
|
||||||
@ -557,19 +484,19 @@ jobs:
|
|||||||
working-directory: /workspace/transformers
|
working-directory: /workspace/transformers
|
||||||
# TODO: Here we pass all tests in the 2 folders for simplicity. It's better to pass only the identified tests.
|
# TODO: Here we pass all tests in the 2 folders for simplicity. It's better to pass only the identified tests.
|
||||||
run: |
|
run: |
|
||||||
python -m pytest -n 1 --dist=loadfile -v --make-reports=${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports tests/deepspeed tests/extended
|
python -m pytest -n 1 --dist=loadfile -v --make-reports=${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports tests/deepspeed tests/extended
|
||||||
|
|
||||||
- name: Failure short reports
|
- name: Failure short reports
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: cat /workspace/transformers/reports/${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports/failures_short.txt
|
run: cat /workspace/transformers/reports/${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports/failures_short.txt
|
||||||
|
|
||||||
- name: "Test suite reports artifacts: ${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports"
|
- name: "Test suite reports artifacts: ${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports"
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
name: ${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
||||||
path: /workspace/transformers/reports/${{ env.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
path: /workspace/transformers/reports/${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
||||||
|
|
||||||
send_results:
|
send_results:
|
||||||
name: Send results to webhook
|
name: Send results to webhook
|
||||||
|
|||||||
@ -1,55 +1,55 @@
|
|||||||
name: Self-hosted runner (AMD mi210 scheduled CI caller)
|
name: Self-hosted runner (AMD mi210 scheduled CI caller)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["Self-hosted runner (AMD scheduled CI caller)"]
|
workflows: ["Self-hosted runner (AMD scheduled CI caller)"]
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
types: [completed]
|
types: [completed]
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- run_amd_scheduled_ci_caller*
|
- run_amd_scheduled_ci_caller*
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
model-ci:
|
model-ci:
|
||||||
name: Model CI
|
name: Model CI
|
||||||
uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@main
|
uses: ./.github/workflows/self-scheduled-amd.yml
|
||||||
with:
|
with:
|
||||||
job: run_models_gpu
|
job: run_models_gpu
|
||||||
slack_report_channel: "#transformers-ci-daily-amd"
|
slack_report_channel: "#transformers-ci-daily-amd"
|
||||||
runner: mi210
|
runner: mi210
|
||||||
docker: huggingface/transformers-pytorch-amd-gpu
|
docker: huggingface/transformers-pytorch-amd-gpu
|
||||||
ci_event: Scheduled CI (AMD) - mi210
|
ci_event: Scheduled CI (AMD) - mi210
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
torch-pipeline:
|
torch-pipeline:
|
||||||
name: Torch pipeline CI
|
name: Torch pipeline CI
|
||||||
uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@main
|
uses: ./.github/workflows/self-scheduled-amd.yml
|
||||||
with:
|
with:
|
||||||
job: run_pipelines_torch_gpu
|
job: run_pipelines_torch_gpu
|
||||||
slack_report_channel: "#transformers-ci-daily-amd"
|
slack_report_channel: "#transformers-ci-daily-amd"
|
||||||
runner: mi210
|
runner: mi210
|
||||||
docker: huggingface/transformers-pytorch-amd-gpu
|
docker: huggingface/transformers-pytorch-amd-gpu
|
||||||
ci_event: Scheduled CI (AMD) - mi210
|
ci_event: Scheduled CI (AMD) - mi210
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
example-ci:
|
example-ci:
|
||||||
name: Example CI
|
name: Example CI
|
||||||
uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@main
|
uses: ./.github/workflows/self-scheduled-amd.yml
|
||||||
with:
|
with:
|
||||||
job: run_examples_gpu
|
job: run_examples_gpu
|
||||||
slack_report_channel: "#transformers-ci-daily-amd"
|
slack_report_channel: "#transformers-ci-daily-amd"
|
||||||
runner: mi210
|
runner: mi210
|
||||||
docker: huggingface/transformers-pytorch-amd-gpu
|
docker: huggingface/transformers-pytorch-amd-gpu
|
||||||
ci_event: Scheduled CI (AMD) - mi210
|
ci_event: Scheduled CI (AMD) - mi210
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
deepspeed-ci:
|
deepspeed-ci:
|
||||||
name: DeepSpeed CI
|
name: DeepSpeed CI
|
||||||
uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@main
|
uses: ./.github/workflows/self-scheduled-amd.yml
|
||||||
with:
|
with:
|
||||||
job: run_torch_cuda_extensions_gpu
|
job: run_torch_cuda_extensions_gpu
|
||||||
slack_report_channel: "#transformers-ci-daily-amd"
|
slack_report_channel: "#transformers-ci-daily-amd"
|
||||||
runner: mi210
|
runner: mi210
|
||||||
docker: huggingface/transformers-pytorch-deepspeed-amd-gpu
|
docker: huggingface/transformers-pytorch-deepspeed-amd-gpu
|
||||||
ci_event: Scheduled CI (AMD) - mi210
|
ci_event: Scheduled CI (AMD) - mi210
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|||||||
@ -1,55 +1,55 @@
|
|||||||
name: Self-hosted runner (AMD mi250 scheduled CI caller)
|
name: Self-hosted runner (AMD mi250 scheduled CI caller)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["Self-hosted runner (AMD scheduled CI caller)"]
|
workflows: ["Self-hosted runner (AMD scheduled CI caller)"]
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
types: [completed]
|
types: [completed]
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- run_amd_scheduled_ci_caller*
|
- run_amd_scheduled_ci_caller*
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
model-ci:
|
model-ci:
|
||||||
name: Model CI
|
name: Model CI
|
||||||
uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@main
|
uses: ./.github/workflows/self-scheduled-amd.yml
|
||||||
with:
|
with:
|
||||||
job: run_models_gpu
|
job: run_models_gpu
|
||||||
slack_report_channel: "#transformers-ci-daily-amd"
|
slack_report_channel: "#transformers-ci-daily-amd"
|
||||||
runner: mi250
|
runner: mi250
|
||||||
docker: huggingface/transformers-pytorch-amd-gpu
|
docker: huggingface/transformers-pytorch-amd-gpu
|
||||||
ci_event: Scheduled CI (AMD) - mi250
|
ci_event: Scheduled CI (AMD) - mi250
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
torch-pipeline:
|
torch-pipeline:
|
||||||
name: Torch pipeline CI
|
name: Torch pipeline CI
|
||||||
uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@main
|
uses: ./.github/workflows/self-scheduled-amd.yml
|
||||||
with:
|
with:
|
||||||
job: run_pipelines_torch_gpu
|
job: run_pipelines_torch_gpu
|
||||||
slack_report_channel: "#transformers-ci-daily-amd"
|
slack_report_channel: "#transformers-ci-daily-amd"
|
||||||
runner: mi250
|
runner: mi250
|
||||||
docker: huggingface/transformers-pytorch-amd-gpu
|
docker: huggingface/transformers-pytorch-amd-gpu
|
||||||
ci_event: Scheduled CI (AMD) - mi250
|
ci_event: Scheduled CI (AMD) - mi250
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
example-ci:
|
example-ci:
|
||||||
name: Example CI
|
name: Example CI
|
||||||
uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@main
|
uses: ./.github/workflows/self-scheduled-amd.yml
|
||||||
with:
|
with:
|
||||||
job: run_examples_gpu
|
job: run_examples_gpu
|
||||||
slack_report_channel: "#transformers-ci-daily-amd"
|
slack_report_channel: "#transformers-ci-daily-amd"
|
||||||
runner: mi250
|
runner: mi250
|
||||||
docker: huggingface/transformers-pytorch-amd-gpu
|
docker: huggingface/transformers-pytorch-amd-gpu
|
||||||
ci_event: Scheduled CI (AMD) - mi250
|
ci_event: Scheduled CI (AMD) - mi250
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
deepspeed-ci:
|
deepspeed-ci:
|
||||||
name: DeepSpeed CI
|
name: DeepSpeed CI
|
||||||
uses: huggingface/hf-workflows/.github/workflows/transformers_amd_ci_scheduled.yaml@main
|
uses: ./.github/workflows/self-scheduled-amd.yml
|
||||||
with:
|
with:
|
||||||
job: run_torch_cuda_extensions_gpu
|
job: run_torch_cuda_extensions_gpu
|
||||||
slack_report_channel: "#transformers-ci-daily-amd"
|
slack_report_channel: "#transformers-ci-daily-amd"
|
||||||
runner: mi250
|
runner: mi250
|
||||||
docker: huggingface/transformers-pytorch-deepspeed-amd-gpu
|
docker: huggingface/transformers-pytorch-deepspeed-amd-gpu
|
||||||
ci_event: Scheduled CI (AMD) - mi250
|
ci_event: Scheduled CI (AMD) - mi250
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|||||||
349
.github/workflows/self-scheduled-amd.yml
vendored
Normal file
349
.github/workflows/self-scheduled-amd.yml
vendored
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
name: Self-hosted runner (scheduled-amd)
|
||||||
|
|
||||||
|
# Note: For the AMD CI, we rely on a caller workflow and on the workflow_call event to trigger the
|
||||||
|
# CI in order to run it on both MI210 and MI250, without having to use matrix here which pushes
|
||||||
|
# us towards the limit of allowed jobs on GitHub Actions.
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
job:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
slack_report_channel:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
runner:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
docker:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
ci_event:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
env:
|
||||||
|
HF_HOME: /mnt/cache
|
||||||
|
TRANSFORMERS_IS_CI: yes
|
||||||
|
OMP_NUM_THREADS: 8
|
||||||
|
MKL_NUM_THREADS: 8
|
||||||
|
RUN_SLOW: yes
|
||||||
|
HF_HUB_READ_TOKEN: ${{ secrets.HF_HUB_READ_TOKEN }}
|
||||||
|
SIGOPT_API_TOKEN: ${{ secrets.SIGOPT_API_TOKEN }}
|
||||||
|
NUM_SLICES: 2
|
||||||
|
|
||||||
|
# Important note: each job (run_tests_single_gpu, run_tests_multi_gpu, run_examples_gpu, run_pipelines_torch_gpu) requires all the previous jobs before running.
|
||||||
|
# This is done so that we avoid parallelizing the scheduled tests, to leave available
|
||||||
|
# runners for the push CI that is running on the same machine.
|
||||||
|
jobs:
|
||||||
|
check_runner_status:
|
||||||
|
name: Check Runner Status
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout transformers
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Check Runner Status
|
||||||
|
run: python utils/check_self_hosted_runner.py --target_runners hf-amd-mi210-ci-1gpu-1,hf-amd-mi250-ci-1gpu-1,hf-amd-mi300-ci-1gpu-1 --token ${{ secrets.ACCESS_REPO_INFO_TOKEN }}
|
||||||
|
|
||||||
|
check_runners:
|
||||||
|
name: Check Runners
|
||||||
|
needs: check_runner_status
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
machine_type: [single-gpu, multi-gpu]
|
||||||
|
runs-on: ['${{ matrix.machine_type }}', self-hosted, amd-gpu, '${{ inputs.runner }}']
|
||||||
|
container:
|
||||||
|
image: huggingface/transformers-pytorch-amd-gpu
|
||||||
|
options: --device /dev/kfd --device /dev/dri --env ROCR_VISIBLE_DEVICES --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
|
steps:
|
||||||
|
- name: ROCM-SMI
|
||||||
|
run: |
|
||||||
|
rocm-smi
|
||||||
|
|
||||||
|
- name: ROCM-INFO
|
||||||
|
run: |
|
||||||
|
rocminfo | grep "Agent" -A 14
|
||||||
|
|
||||||
|
- name: Show ROCR environment
|
||||||
|
run: |
|
||||||
|
echo "ROCR: $ROCR_VISIBLE_DEVICES"
|
||||||
|
|
||||||
|
setup:
|
||||||
|
if: contains(fromJSON('["run_models_gpu"]'), inputs.job)
|
||||||
|
name: Setup
|
||||||
|
needs: check_runners
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
machine_type: [single-gpu, multi-gpu]
|
||||||
|
runs-on: ['${{ matrix.machine_type }}', self-hosted, amd-gpu, '${{ inputs.runner }}']
|
||||||
|
container:
|
||||||
|
image: huggingface/transformers-pytorch-amd-gpu
|
||||||
|
options: --device /dev/kfd --device /dev/dri --env ROCR_VISIBLE_DEVICES --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
|
outputs:
|
||||||
|
folder_slices: ${{ steps.set-matrix.outputs.folder_slices }}
|
||||||
|
slice_ids: ${{ steps.set-matrix.outputs.slice_ids }}
|
||||||
|
steps:
|
||||||
|
- name: Update clone
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
git fetch && git checkout ${{ github.sha }}
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
rm -rf tests/__pycache__
|
||||||
|
rm -rf tests/models/__pycache__
|
||||||
|
rm -rf reports
|
||||||
|
|
||||||
|
- name: Show installed libraries and their versions
|
||||||
|
working-directory: /transformers
|
||||||
|
run: pip freeze
|
||||||
|
|
||||||
|
- id: set-matrix
|
||||||
|
name: Identify models to test
|
||||||
|
working-directory: /transformers/tests
|
||||||
|
run: |
|
||||||
|
echo "folder_slices=$(python3 ../utils/split_model_tests.py --num_splits ${{ env.NUM_SLICES }})" >> $GITHUB_OUTPUT
|
||||||
|
echo "slice_ids=$(python3 -c 'd = list(range(${{ env.NUM_SLICES }})); print(d)')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: ROCM-SMI
|
||||||
|
run: |
|
||||||
|
rocm-smi
|
||||||
|
|
||||||
|
- name: ROCM-INFO
|
||||||
|
run: |
|
||||||
|
rocminfo | grep "Agent" -A 14
|
||||||
|
|
||||||
|
- name: Show ROCR environment
|
||||||
|
run: |
|
||||||
|
echo "ROCR: $ROCR_VISIBLE_DEVICES"
|
||||||
|
|
||||||
|
- name: Environment
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
python3 utils/print_env.py
|
||||||
|
|
||||||
|
run_models_gpu:
|
||||||
|
if: ${{ inputs.job == 'run_models_gpu' }}
|
||||||
|
name: Single GPU tests
|
||||||
|
needs: setup
|
||||||
|
strategy:
|
||||||
|
max-parallel: 1 # For now, not to parallelize. Can change later if it works well.
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
machine_type: [single-gpu, multi-gpu]
|
||||||
|
slice_id: ${{ fromJSON(needs.setup.outputs.slice_ids) }}
|
||||||
|
uses: ./.github/workflows/model_jobs_amd.yml
|
||||||
|
with:
|
||||||
|
folder_slices: ${{ needs.setup.outputs.folder_slices }}
|
||||||
|
machine_type: ${{ matrix.machine_type }}
|
||||||
|
slice_id: ${{ matrix.slice_id }}
|
||||||
|
runner: ${{ inputs.runner }}
|
||||||
|
docker: ${{ inputs.docker }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
run_pipelines_torch_gpu:
|
||||||
|
if: ${{ inputs.job == 'run_pipelines_torch_gpu' }}
|
||||||
|
name: PyTorch pipelines
|
||||||
|
needs: check_runners
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
machine_type: [single-gpu, multi-gpu]
|
||||||
|
runs-on: ['${{ matrix.machine_type }}', self-hosted, amd-gpu, '${{ inputs.runner }}']
|
||||||
|
container:
|
||||||
|
image: ${{ inputs.docker }}
|
||||||
|
options: --device /dev/kfd --device /dev/dri --env ROCR_VISIBLE_DEVICES --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
|
steps:
|
||||||
|
- name: Update clone
|
||||||
|
working-directory: /transformers
|
||||||
|
run: git fetch && git checkout ${{ github.sha }}
|
||||||
|
|
||||||
|
- name: Reinstall transformers in edit mode (remove the one installed during docker image build)
|
||||||
|
working-directory: /transformers
|
||||||
|
run: python3 -m pip uninstall -y transformers && python3 -m pip install -e .
|
||||||
|
|
||||||
|
- name: ROCM-SMI
|
||||||
|
run: |
|
||||||
|
rocm-smi
|
||||||
|
|
||||||
|
- name: ROCM-INFO
|
||||||
|
run: |
|
||||||
|
rocminfo | grep "Agent" -A 14
|
||||||
|
|
||||||
|
- name: Show ROCR environment
|
||||||
|
run: |
|
||||||
|
echo "ROCR: $ROCR_VISIBLE_DEVICES"
|
||||||
|
|
||||||
|
- name: Environment
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
python3 utils/print_env.py
|
||||||
|
|
||||||
|
- name: Show installed libraries and their versions
|
||||||
|
working-directory: /transformers
|
||||||
|
run: pip freeze
|
||||||
|
|
||||||
|
- name: Run all pipeline tests on GPU
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
python3 -m pytest -n 1 -v --dist=loadfile --make-reports=${{ matrix.machine_type }}_run_pipelines_torch_gpu_test_reports tests/pipelines -m "not not_device_test"
|
||||||
|
|
||||||
|
- name: Failure short reports
|
||||||
|
if: ${{ failure() }}
|
||||||
|
continue-on-error: true
|
||||||
|
run: cat /transformers/reports/${{ matrix.machine_type }}_run_pipelines_torch_gpu_test_reports/failures_short.txt
|
||||||
|
|
||||||
|
- name: "Test suite reports artifacts: ${{ matrix.machine_type }}_run_pipelines_torch_gpu_test_reports"
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.machine_type }}_run_pipelines_torch_gpu_test_reports
|
||||||
|
path: /transformers/reports/${{ matrix.machine_type }}_run_pipelines_torch_gpu_test_reports
|
||||||
|
|
||||||
|
run_examples_gpu:
|
||||||
|
if: ${{ inputs.job == 'run_examples_gpu' }}
|
||||||
|
name: Examples directory
|
||||||
|
needs: check_runners
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
machine_type: [single-gpu]
|
||||||
|
runs-on: ['${{ matrix.machine_type }}', self-hosted, amd-gpu, '${{ inputs.runner }}']
|
||||||
|
container:
|
||||||
|
image: ${{ inputs.docker }}
|
||||||
|
options: --device /dev/kfd --device /dev/dri --env ROCR_VISIBLE_DEVICES --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
|
steps:
|
||||||
|
- name: Update clone
|
||||||
|
working-directory: /transformers
|
||||||
|
run: git fetch && git checkout ${{ github.sha }}
|
||||||
|
|
||||||
|
- name: Reinstall transformers in edit mode (remove the one installed during docker image build)
|
||||||
|
working-directory: /transformers
|
||||||
|
run: python3 -m pip uninstall -y transformers && python3 -m pip install -e .
|
||||||
|
|
||||||
|
- name: ROCM-SMI
|
||||||
|
run: |
|
||||||
|
rocm-smi
|
||||||
|
|
||||||
|
- name: ROCM-INFO
|
||||||
|
run: |
|
||||||
|
rocminfo | grep "Agent" -A 14
|
||||||
|
|
||||||
|
- name: Show ROCR environment
|
||||||
|
run: |
|
||||||
|
echo "ROCR: $ROCR_VISIBLE_DEVICES"
|
||||||
|
|
||||||
|
- name: Environment
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
python3 utils/print_env.py
|
||||||
|
|
||||||
|
- name: Show installed libraries and their versions
|
||||||
|
working-directory: /transformers
|
||||||
|
run: pip freeze
|
||||||
|
|
||||||
|
- name: Run examples tests on GPU
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
pip install -r examples/pytorch/_tests_requirements.txt
|
||||||
|
python3 -m pytest -v --make-reports=${{ matrix.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 /transformers/reports/${{ matrix.machine_type }}_run_examples_gpu_test_reports/failures_short.txt
|
||||||
|
|
||||||
|
- name: "Test suite reports artifacts: ${{ matrix.machine_type }}_run_examples_gpu_test_reports"
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.machine_type }}_run_examples_gpu_test_reports
|
||||||
|
path: /transformers/reports/${{ matrix.machine_type }}_run_examples_gpu_test_reports
|
||||||
|
|
||||||
|
run_torch_cuda_extensions_gpu:
|
||||||
|
if: ${{ inputs.job == 'run_torch_cuda_extensions_gpu' }}
|
||||||
|
name: Torch ROCm deepspeed tests
|
||||||
|
needs: check_runners
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
machine_type: [single-gpu, multi-gpu]
|
||||||
|
runs-on: ['${{ matrix.machine_type }}', self-hosted, amd-gpu, '${{ inputs.runner }}']
|
||||||
|
container:
|
||||||
|
image: ${{ inputs.docker }}
|
||||||
|
options: --device /dev/kfd --device /dev/dri --env ROCR_VISIBLE_DEVICES --shm-size "16gb" --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
|
steps:
|
||||||
|
- name: Update clone
|
||||||
|
working-directory: /transformers
|
||||||
|
run: git fetch && git checkout ${{ github.sha }}
|
||||||
|
|
||||||
|
- name: Reinstall transformers in edit mode (remove the one installed during docker image build)
|
||||||
|
working-directory: /transformers
|
||||||
|
run: python3 -m pip uninstall -y transformers && python3 -m pip install -e .
|
||||||
|
|
||||||
|
- name: ROCM-SMI
|
||||||
|
run: |
|
||||||
|
rocm-smi
|
||||||
|
|
||||||
|
- name: ROCM-INFO
|
||||||
|
run: |
|
||||||
|
rocminfo | grep "Agent" -A 14
|
||||||
|
|
||||||
|
- name: Show ROCR environment
|
||||||
|
run: |
|
||||||
|
echo "ROCR: $ROCR_VISIBLE_DEVICES"
|
||||||
|
|
||||||
|
- name: Environment
|
||||||
|
working-directory: /transformers
|
||||||
|
run: |
|
||||||
|
python3 utils/print_env.py
|
||||||
|
|
||||||
|
- name: Show installed libraries and their versions
|
||||||
|
working-directory: /transformers
|
||||||
|
run: pip freeze
|
||||||
|
|
||||||
|
- name: Run all tests on GPU
|
||||||
|
working-directory: /transformers
|
||||||
|
run: python3 -m pytest -v --make-reports=${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports tests/deepspeed tests/extended -m "not not_device_test"
|
||||||
|
|
||||||
|
- name: Failure short reports
|
||||||
|
if: ${{ failure() }}
|
||||||
|
continue-on-error: true
|
||||||
|
run: cat /transformers/reports/${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports/failures_short.txt
|
||||||
|
|
||||||
|
- name: "Test suite reports artifacts: ${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports"
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
||||||
|
path: /transformers/reports/${{ matrix.machine_type }}_run_torch_cuda_extensions_gpu_test_reports
|
||||||
|
|
||||||
|
send_results:
|
||||||
|
name: Slack Report
|
||||||
|
needs: [
|
||||||
|
check_runner_status,
|
||||||
|
check_runners,
|
||||||
|
setup,
|
||||||
|
run_models_gpu,
|
||||||
|
run_pipelines_torch_gpu,
|
||||||
|
run_examples_gpu,
|
||||||
|
run_torch_cuda_extensions_gpu
|
||||||
|
]
|
||||||
|
if: ${{ always() }}
|
||||||
|
uses: ./.github/workflows/slack-report.yml
|
||||||
|
with:
|
||||||
|
job: ${{ inputs.job }}
|
||||||
|
# This would be `skipped` if `setup` is skipped.
|
||||||
|
setup_status: ${{ needs.setup.result }}
|
||||||
|
slack_report_channel: ${{ inputs.slack_report_channel }}
|
||||||
|
# This would be an empty string if `setup` is skipped.
|
||||||
|
folder_slices: ${{ needs.setup.outputs.folder_slices }}
|
||||||
|
quantization_matrix: ${{ needs.setup.outputs.quantization_matrix }}
|
||||||
|
ci_event: ${{ inputs.ci_event }}
|
||||||
|
|
||||||
|
secrets: inherit
|
||||||
10
.github/workflows/self-scheduled.yml
vendored
10
.github/workflows/self-scheduled.yml
vendored
@ -562,13 +562,3 @@ jobs:
|
|||||||
ci_event: ${{ inputs.ci_event }}
|
ci_event: ${{ inputs.ci_event }}
|
||||||
|
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
check_new_model_failures:
|
|
||||||
if: ${{ always() && inputs.ci_event == 'Daily CI' && inputs.job == 'run_models_gpu' && needs.send_results.result == 'success' }}
|
|
||||||
name: Check new model failures
|
|
||||||
needs: send_results
|
|
||||||
uses: ./.github/workflows/check_failed_model_tests.yml
|
|
||||||
with:
|
|
||||||
docker: ${{ inputs.docker }}
|
|
||||||
start_sha: ${{ github.sha }}
|
|
||||||
secrets: inherit
|
|
||||||
6
.github/workflows/slack-report.yml
vendored
6
.github/workflows/slack-report.yml
vendored
@ -70,7 +70,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: ci_results_${{ inputs.job }}
|
name: ci_results_${{ inputs.job }}
|
||||||
path: ci_results_${{ inputs.job }}
|
path: ci_results_${{ inputs.job }}
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
- name: Send message to Slack for quantization workflow
|
- name: Send message to Slack for quantization workflow
|
||||||
@ -90,7 +90,7 @@ jobs:
|
|||||||
pip install huggingface_hub
|
pip install huggingface_hub
|
||||||
pip install slack_sdk
|
pip install slack_sdk
|
||||||
pip show slack_sdk
|
pip show slack_sdk
|
||||||
python utils/notification_service_quantization.py "${{ inputs.quantization_matrix }}"
|
python utils/notification_service_quantization.py "${{ inputs.quantization_matrix }}"
|
||||||
|
|
||||||
# Upload complete failure tables, as they might be big and only truncated versions could be sent to Slack.
|
# Upload complete failure tables, as they might be big and only truncated versions could be sent to Slack.
|
||||||
- name: Failure table artifacts
|
- name: Failure table artifacts
|
||||||
@ -98,4 +98,4 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ci_results_${{ inputs.job }}
|
name: ci_results_${{ inputs.job }}
|
||||||
path: ci_results_${{ inputs.job }}
|
path: ci_results_${{ inputs.job }}
|
||||||
31
.github/workflows/ssh-runner.yml
vendored
31
.github/workflows/ssh-runner.yml
vendored
@ -26,38 +26,9 @@ env:
|
|||||||
RUN_PT_TF_CROSS_TESTS: 1
|
RUN_PT_TF_CROSS_TESTS: 1
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
get_runner:
|
|
||||||
name: "Get runner to use"
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
outputs:
|
|
||||||
RUNNER: ${{ steps.set_runner.outputs.RUNNER }}
|
|
||||||
steps:
|
|
||||||
- name: Get runner to use
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.event.inputs.num_gpus }}" == "single" && "${{ github.event.inputs.runner_type }}" == "t4" ]]; then
|
|
||||||
echo "RUNNER=aws-g4dn-2xlarge-cache" >> $GITHUB_ENV
|
|
||||||
elif [[ "${{ github.event.inputs.num_gpus }}" == "multi" && "${{ github.event.inputs.runner_type }}" == "t4" ]]; then
|
|
||||||
echo "RUNNER=aws-g4dn-12xlarge-cache" >> $GITHUB_ENV
|
|
||||||
elif [[ "${{ github.event.inputs.num_gpus }}" == "single" && "${{ github.event.inputs.runner_type }}" == "a10" ]]; then
|
|
||||||
echo "RUNNER=aws-g5-4xlarge-cache" >> $GITHUB_ENV
|
|
||||||
elif [[ "${{ github.event.inputs.num_gpus }}" == "multi" && "${{ github.event.inputs.runner_type }}" == "a10" ]]; then
|
|
||||||
echo "RUNNER=aws-g5-12xlarge-cache" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "RUNNER=" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Set runner to use
|
|
||||||
id: set_runner
|
|
||||||
run: |
|
|
||||||
echo ${{ env.RUNNER }}
|
|
||||||
echo "RUNNER=${{ env.RUNNER }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
ssh_runner:
|
ssh_runner:
|
||||||
name: "SSH"
|
name: "SSH"
|
||||||
needs: get_runner
|
runs-on: ["${{ github.event.inputs.num_gpus }}-gpu", nvidia-gpu, "${{ github.event.inputs.runner_type }}", ci]
|
||||||
runs-on:
|
|
||||||
group: ${{ needs.get_runner.outputs.RUNNER }}
|
|
||||||
container:
|
container:
|
||||||
image: ${{ github.event.inputs.docker_image }}
|
image: ${{ github.event.inputs.docker_image }}
|
||||||
options: --gpus all --privileged --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
options: --gpus all --privileged --ipc host -v /mnt/cache/.cache/huggingface:/mnt/cache/
|
||||||
|
|||||||
@ -132,7 +132,7 @@ You will need basic `git` proficiency to contribute to
|
|||||||
manual. Type `git --help` in a shell and enjoy! If you prefer books, [Pro
|
manual. Type `git --help` in a shell and enjoy! If you prefer books, [Pro
|
||||||
Git](https://git-scm.com/book/en/v2) is a very good reference.
|
Git](https://git-scm.com/book/en/v2) is a very good reference.
|
||||||
|
|
||||||
You'll need **[Python 3.9](https://github.com/huggingface/transformers/blob/main/setup.py#L449)** or above to contribute to 🤗 Transformers. Follow the steps below to start contributing:
|
You'll need **[Python 3.8](https://github.com/huggingface/transformers/blob/main/setup.py#L449)** or above to contribute to 🤗 Transformers. Follow the steps below to start contributing:
|
||||||
|
|
||||||
1. Fork the [repository](https://github.com/huggingface/transformers) by
|
1. Fork the [repository](https://github.com/huggingface/transformers) by
|
||||||
clicking on the **[Fork](https://github.com/huggingface/transformers/fork)** button on the repository's page. This creates a copy of the code
|
clicking on the **[Fork](https://github.com/huggingface/transformers/fork)** button on the repository's page. This creates a copy of the code
|
||||||
|
|||||||
34
README.md
34
README.md
@ -128,10 +128,10 @@ incredible projects built in the vicinity of transformers.
|
|||||||
|
|
||||||
If you own or use a project that you believe should be part of the list, please open a PR to add it!
|
If you own or use a project that you believe should be part of the list, please open a PR to add it!
|
||||||
|
|
||||||
## Serious about AI in your organisation? Build faster with the Hugging Face Enterprise Hub.
|
## If you are looking for custom support from the Hugging Face team
|
||||||
|
|
||||||
<a target="_blank" href="https://huggingface.co/enterprise">
|
<a target="_blank" href="https://huggingface.co/support">
|
||||||
<img alt="Hugging Face Enterprise Hub" src="https://github.com/user-attachments/assets/247fb16d-d251-4583-96c4-d3d76dda4925">
|
<img alt="HuggingFace Expert Acceleration Program" src="https://cdn-media.huggingface.co/marketing/transformers/new-support-improved.png" style="max-width: 600px; border: 1px solid #eee; border-radius: 4px; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);">
|
||||||
</a><br>
|
</a><br>
|
||||||
|
|
||||||
## Quick tour
|
## Quick tour
|
||||||
@ -249,43 +249,23 @@ The model itself is a regular [Pytorch `nn.Module`](https://pytorch.org/docs/sta
|
|||||||
|
|
||||||
### With pip
|
### With pip
|
||||||
|
|
||||||
This repository is tested on Python 3.9+, Flax 0.4.1+, PyTorch 2.0+, and TensorFlow 2.6+.
|
This repository is tested on Python 3.8+, Flax 0.4.1+, PyTorch 1.11+, and TensorFlow 2.6+.
|
||||||
|
|
||||||
You should install 🤗 Transformers in a [virtual environment](https://docs.python.org/3/library/venv.html). If you're unfamiliar with Python virtual environments, check out the [user guide](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/).
|
You should install 🤗 Transformers in a [virtual environment](https://docs.python.org/3/library/venv.html). If you're unfamiliar with Python virtual environments, check out the [user guide](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/).
|
||||||
|
|
||||||
First, create a virtual environment with the version of Python you're going to use and activate it.
|
First, create a virtual environment with the version of Python you're going to use and activate it.
|
||||||
|
|
||||||
**macOS/Linux**
|
Then, you will need to install at least one of Flax, PyTorch, or TensorFlow.
|
||||||
|
Please refer to [TensorFlow installation page](https://www.tensorflow.org/install/), [PyTorch installation page](https://pytorch.org/get-started/locally/#start-locally) and/or [Flax](https://github.com/google/flax#quick-install) and [Jax](https://github.com/google/jax#installation) installation pages regarding the specific installation command for your platform.
|
||||||
```python -m venv env
|
|
||||||
source env/bin/activate
|
|
||||||
```
|
|
||||||
|
|
||||||
**Windows**
|
|
||||||
|
|
||||||
``` python -m venv env
|
|
||||||
env\Scripts\activate
|
|
||||||
```
|
|
||||||
|
|
||||||
To use 🤗 Transformers, you must install at least one of Flax, PyTorch, or TensorFlow. Refer to the official installation guides for platform-specific commands:
|
|
||||||
|
|
||||||
[TensorFlow installation page](https://www.tensorflow.org/install/),
|
|
||||||
[PyTorch installation page](https://pytorch.org/get-started/locally/#start-locally) and/or [Flax](https://github.com/google/flax#quick-install) and [Jax](https://github.com/google/jax#installation)
|
|
||||||
|
|
||||||
When one of those backends has been installed, 🤗 Transformers can be installed using pip as follows:
|
When one of those backends has been installed, 🤗 Transformers can be installed using pip as follows:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
pip install transformers
|
pip install transformers
|
||||||
```
|
```
|
||||||
|
|
||||||
If you'd like to play with the examples or need the bleeding edge of the code and can't wait for a new release, you must [install the library from source](https://huggingface.co/docs/transformers/installation#installing-from-source).
|
If you'd like to play with the examples or need the bleeding edge of the code and can't wait for a new release, you must [install the library from source](https://huggingface.co/docs/transformers/installation#installing-from-source).
|
||||||
|
|
||||||
```
|
|
||||||
git clone https://github.com/huggingface/transformers.git
|
|
||||||
cd transformers
|
|
||||||
pip install
|
|
||||||
```
|
|
||||||
|
|
||||||
### With conda
|
### With conda
|
||||||
|
|
||||||
🤗 Transformers can be installed using conda as follows:
|
🤗 Transformers can be installed using conda as follows:
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
# Benchmarks
|
|
||||||
|
|
||||||
You might want to add new benchmarks.
|
|
||||||
|
|
||||||
You will need to define a python function named `run_benchmark` in your python file and the file must be located in this `benchmark/` directory.
|
|
||||||
|
|
||||||
The expected function signature is the following:
|
|
||||||
|
|
||||||
```py
|
|
||||||
def run_benchmark(logger: Logger, branch: str, commit_id: str, commit_msg: str, num_tokens_to_generate=100):
|
|
||||||
```
|
|
||||||
|
|
||||||
## Writing metrics to the database
|
|
||||||
|
|
||||||
`MetricRecorder` is thread-safe, in the sense of the python [`Thread`](https://docs.python.org/3/library/threading.html#threading.Thread). This means you can start a background thread to do the readings on the device measurements while not blocking the main thread to execute the model measurements.
|
|
||||||
|
|
||||||
cf [`llama.py`](./llama.py) to see an example of this in practice.
|
|
||||||
|
|
||||||
```py
|
|
||||||
from benchmarks_entrypoint import MetricsRecorder
|
|
||||||
import psycopg2
|
|
||||||
|
|
||||||
def run_benchmark(logger: Logger, branch: str, commit_id: str, commit_msg: str, num_tokens_to_generate=100):
|
|
||||||
metrics_recorder = MetricsRecorder(psycopg2.connect("dbname=metrics"), logger, branch, commit_id, commit_msg)
|
|
||||||
benchmark_id = metrics_recorder.initialise_benchmark({"gpu_name": gpu_name, "model_id": model_id})
|
|
||||||
# To collect device measurements
|
|
||||||
metrics_recorder.collect_device_measurements(
|
|
||||||
benchmark_id, cpu_util, mem_megabytes, gpu_util, gpu_mem_megabytes
|
|
||||||
)
|
|
||||||
# To collect your model measurements
|
|
||||||
metrics_recorder.collect_model_measurements(
|
|
||||||
benchmark_id,
|
|
||||||
{
|
|
||||||
"model_load_time": model_load_time,
|
|
||||||
"first_eager_forward_pass_time_secs": first_eager_fwd_pass_time,
|
|
||||||
"second_eager_forward_pass_time_secs": second_eager_fwd_pass_time,
|
|
||||||
"first_eager_generate_time_secs": first_eager_generate_time,
|
|
||||||
"second_eager_generate_time_secs": second_eager_generate_time,
|
|
||||||
"time_to_first_token_secs": time_to_first_token,
|
|
||||||
"time_to_second_token_secs": time_to_second_token,
|
|
||||||
"time_to_third_token_secs": time_to_third_token,
|
|
||||||
"time_to_next_token_mean_secs": mean_time_to_next_token,
|
|
||||||
"first_compile_generate_time_secs": first_compile_generate_time,
|
|
||||||
"second_compile_generate_time_secs": second_compile_generate_time,
|
|
||||||
"third_compile_generate_time_secs": third_compile_generate_time,
|
|
||||||
"fourth_compile_generate_time_secs": fourth_compile_generate_time,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
```
|
|
||||||
@ -1,144 +0,0 @@
|
|||||||
import argparse
|
|
||||||
import importlib.util
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
from typing import Dict
|
|
||||||
import psycopg2
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from psycopg2.extras import Json
|
|
||||||
from psycopg2.extensions import register_adapter
|
|
||||||
|
|
||||||
|
|
||||||
register_adapter(dict, Json)
|
|
||||||
|
|
||||||
|
|
||||||
class ImportModuleException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MetricsRecorder:
|
|
||||||
def __init__(self, connection, logger: logging.Logger, branch: str, commit_id: str, commit_msg: str):
|
|
||||||
self.conn = connection
|
|
||||||
self.conn.autocommit = True
|
|
||||||
self.logger = logger
|
|
||||||
self.branch = branch
|
|
||||||
self.commit_id = commit_id
|
|
||||||
self.commit_msg = commit_msg
|
|
||||||
|
|
||||||
def initialise_benchmark(self, metadata: Dict[str, str]) -> int:
|
|
||||||
"""
|
|
||||||
Creates a new benchmark, returns the benchmark id
|
|
||||||
"""
|
|
||||||
# gpu_name: str, model_id: str
|
|
||||||
with self.conn.cursor() as cur:
|
|
||||||
cur.execute(
|
|
||||||
"INSERT INTO benchmarks (branch, commit_id, commit_message, metadata) VALUES (%s, %s, %s, %s) RETURNING benchmark_id",
|
|
||||||
(self.branch, self.commit_id, self.commit_msg, metadata),
|
|
||||||
)
|
|
||||||
benchmark_id = cur.fetchone()[0]
|
|
||||||
logger.debug(f"initialised benchmark #{benchmark_id}")
|
|
||||||
return benchmark_id
|
|
||||||
|
|
||||||
def collect_device_measurements(self, benchmark_id: int, cpu_util, mem_megabytes, gpu_util, gpu_mem_megabytes):
|
|
||||||
"""
|
|
||||||
Collect device metrics, such as CPU & GPU usage. These are "static", as in you cannot pass arbitrary arguments to the function.
|
|
||||||
"""
|
|
||||||
with self.conn.cursor() as cur:
|
|
||||||
cur.execute(
|
|
||||||
"INSERT INTO device_measurements (benchmark_id, cpu_util, mem_megabytes, gpu_util, gpu_mem_megabytes) VALUES (%s, %s, %s, %s, %s)",
|
|
||||||
(benchmark_id, cpu_util, mem_megabytes, gpu_util, gpu_mem_megabytes),
|
|
||||||
)
|
|
||||||
self.logger.debug(
|
|
||||||
f"inserted device measurements for benchmark #{benchmark_id} [CPU util: {cpu_util}, mem MBs: {mem_megabytes}, GPU util: {gpu_util}, GPU mem MBs: {gpu_mem_megabytes}]"
|
|
||||||
)
|
|
||||||
|
|
||||||
def collect_model_measurements(self, benchmark_id: int, measurements: Dict[str, float]):
|
|
||||||
with self.conn.cursor() as cur:
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
INSERT INTO model_measurements (
|
|
||||||
benchmark_id,
|
|
||||||
measurements
|
|
||||||
) VALUES (%s, %s)
|
|
||||||
""",
|
|
||||||
(
|
|
||||||
benchmark_id,
|
|
||||||
measurements,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
self.logger.debug(f"inserted model measurements for benchmark #{benchmark_id}: {measurements}")
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.conn.close()
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
|
|
||||||
handler = logging.StreamHandler(sys.stdout)
|
|
||||||
handler.setLevel(logging.INFO)
|
|
||||||
formatter = logging.Formatter("[%(levelname)s - %(asctime)s] %(message)s")
|
|
||||||
handler.setFormatter(formatter)
|
|
||||||
logger.addHandler(handler)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
|
||||||
"""
|
|
||||||
Parse command line arguments for the benchmarking CLI.
|
|
||||||
"""
|
|
||||||
parser = argparse.ArgumentParser(description="CLI for benchmarking the huggingface/transformers.")
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"branch",
|
|
||||||
type=str,
|
|
||||||
help="The branch name on which the benchmarking is performed.",
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"commit_id",
|
|
||||||
type=str,
|
|
||||||
help="The commit hash on which the benchmarking is performed.",
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"commit_msg",
|
|
||||||
type=str,
|
|
||||||
help="The commit message associated with the commit, truncated to 70 characters.",
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
return args.branch, args.commit_id, args.commit_msg
|
|
||||||
|
|
||||||
|
|
||||||
def import_from_path(module_name, file_path):
|
|
||||||
try:
|
|
||||||
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
|
||||||
module = importlib.util.module_from_spec(spec)
|
|
||||||
sys.modules[module_name] = module
|
|
||||||
spec.loader.exec_module(module)
|
|
||||||
return module
|
|
||||||
except Exception as e:
|
|
||||||
raise ImportModuleException(f"failed to load python module: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
benchmarks_folder_path = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
|
|
||||||
branch, commit_id, commit_msg = parse_arguments()
|
|
||||||
|
|
||||||
for entry in os.scandir(benchmarks_folder_path):
|
|
||||||
try:
|
|
||||||
if not entry.name.endswith(".py"):
|
|
||||||
continue
|
|
||||||
if entry.path == __file__:
|
|
||||||
continue
|
|
||||||
logger.debug(f"loading: {entry.name}")
|
|
||||||
module = import_from_path(entry.name.split(".")[0], entry.path)
|
|
||||||
logger.info(f"runnning benchmarks in: {entry.name}")
|
|
||||||
module.run_benchmark(logger, branch, commit_id, commit_msg)
|
|
||||||
except ImportModuleException as e:
|
|
||||||
logger.error(e)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"error running benchmarks for {entry.name}: {e}")
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
apiVersion: 1
|
|
||||||
|
|
||||||
providers:
|
|
||||||
- name: 'Transformers Benchmarks'
|
|
||||||
orgId: 1
|
|
||||||
type: file
|
|
||||||
updateIntervalSeconds: 10
|
|
||||||
allowUiUpdates: true
|
|
||||||
options:
|
|
||||||
path: /etc/grafana/dashboards
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
|||||||
apiVersion: 1
|
|
||||||
datasources:
|
|
||||||
- name: grafana-postgresql-datasource
|
|
||||||
uid: be28nkzirtb0gd
|
|
||||||
type: postgres
|
|
||||||
url: $GRAFANA_POSTGRES_DATASOURCE_URL
|
|
||||||
user: $GRAFANA_POSTGRES_DATASOURCE_USER
|
|
||||||
secureJsonData:
|
|
||||||
password: $GRAFANA_POSTGRES_DATASOURCE_PWD
|
|
||||||
jsonData:
|
|
||||||
database: metrics
|
|
||||||
maxOpenConns: 100
|
|
||||||
maxIdleConns: 100
|
|
||||||
maxIdleConnsAuto: true
|
|
||||||
connMaxLifetime: 14400
|
|
||||||
postgresVersion: 1000
|
|
||||||
timescaledb: false
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS benchmarks (
|
|
||||||
benchmark_id SERIAL PRIMARY KEY,
|
|
||||||
branch VARCHAR(255),
|
|
||||||
commit_id VARCHAR(72),
|
|
||||||
commit_message VARCHAR(70),
|
|
||||||
metadata jsonb,
|
|
||||||
created_at timestamp without time zone NOT NULL DEFAULT (current_timestamp AT TIME ZONE 'UTC')
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS benchmarks_benchmark_id_idx ON benchmarks (benchmark_id);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS benchmarks_branch_idx ON benchmarks (branch);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS device_measurements (
|
|
||||||
measurement_id SERIAL PRIMARY KEY,
|
|
||||||
benchmark_id int REFERENCES benchmarks (benchmark_id),
|
|
||||||
cpu_util double precision,
|
|
||||||
mem_megabytes double precision,
|
|
||||||
gpu_util double precision,
|
|
||||||
gpu_mem_megabytes double precision,
|
|
||||||
time timestamp without time zone NOT NULL DEFAULT (current_timestamp AT TIME ZONE 'UTC')
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS device_measurements_branch_idx ON device_measurements (benchmark_id);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS model_measurements (
|
|
||||||
measurement_id SERIAL PRIMARY KEY,
|
|
||||||
benchmark_id int REFERENCES benchmarks (benchmark_id),
|
|
||||||
measurements jsonb,
|
|
||||||
time timestamp without time zone NOT NULL DEFAULT (current_timestamp AT TIME ZONE 'UTC')
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS model_measurements_branch_idx ON model_measurements (benchmark_id);
|
|
||||||
@ -1,342 +0,0 @@
|
|||||||
from logging import Logger
|
|
||||||
import os
|
|
||||||
from threading import Event, Thread
|
|
||||||
from time import perf_counter, sleep
|
|
||||||
from typing import Optional
|
|
||||||
from benchmarks_entrypoint import MetricsRecorder
|
|
||||||
import gpustat
|
|
||||||
import psutil
|
|
||||||
import psycopg2
|
|
||||||
import torch
|
|
||||||
|
|
||||||
from transformers import AutoModelForCausalLM, AutoTokenizer, GenerationConfig, StaticCache
|
|
||||||
|
|
||||||
|
|
||||||
os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
|
|
||||||
|
|
||||||
os.environ["TOKENIZERS_PARALLELISM"] = "1"
|
|
||||||
torch.set_float32_matmul_precision("high")
|
|
||||||
|
|
||||||
|
|
||||||
def collect_metrics(benchmark_id, continue_metric_collection, metrics_recorder):
|
|
||||||
p = psutil.Process(os.getpid())
|
|
||||||
while not continue_metric_collection.is_set():
|
|
||||||
with p.oneshot():
|
|
||||||
cpu_util = p.cpu_percent()
|
|
||||||
mem_megabytes = p.memory_info().rss / (1024 * 1024)
|
|
||||||
gpu_stats = gpustat.GPUStatCollection.new_query()
|
|
||||||
gpu_util = gpu_stats[0]["utilization.gpu"]
|
|
||||||
gpu_mem_megabytes = gpu_stats[0]["memory.used"]
|
|
||||||
metrics_recorder.collect_device_measurements(
|
|
||||||
benchmark_id, cpu_util, mem_megabytes, gpu_util, gpu_mem_megabytes
|
|
||||||
)
|
|
||||||
sleep(0.01)
|
|
||||||
|
|
||||||
|
|
||||||
def run_benchmark(logger: Logger, branch: str, commit_id: str, commit_msg: str, num_tokens_to_generate=100):
|
|
||||||
continue_metric_collection = Event()
|
|
||||||
metrics_thread = None
|
|
||||||
model_id = "meta-llama/Llama-2-7b-hf"
|
|
||||||
metrics_recorder = MetricsRecorder(psycopg2.connect("dbname=metrics"), logger, branch, commit_id, commit_msg)
|
|
||||||
try:
|
|
||||||
gpu_stats = gpustat.GPUStatCollection.new_query()
|
|
||||||
gpu_name = gpu_stats[0]["name"]
|
|
||||||
benchmark_id = metrics_recorder.initialise_benchmark({"gpu_name": gpu_name, "model_id": model_id})
|
|
||||||
logger.info(f"running benchmark #{benchmark_id} on {gpu_name} for {model_id}")
|
|
||||||
metrics_thread = Thread(
|
|
||||||
target=collect_metrics,
|
|
||||||
args=[benchmark_id, continue_metric_collection, metrics_recorder],
|
|
||||||
)
|
|
||||||
metrics_thread.start()
|
|
||||||
logger.info("started background thread to fetch device metrics")
|
|
||||||
|
|
||||||
os.environ["TOKENIZERS_PARALLELISM"] = "false" # silence warnings when compiling
|
|
||||||
|
|
||||||
device = "cuda"
|
|
||||||
|
|
||||||
logger.info("downloading weights")
|
|
||||||
# This is to avoid counting download in model load time measurement
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float16)
|
|
||||||
gen_config = GenerationConfig(do_sample=False, top_p=1, temperature=1)
|
|
||||||
logger.info("loading model")
|
|
||||||
start = perf_counter()
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(
|
|
||||||
model_id, torch_dtype=torch.float16, generation_config=gen_config
|
|
||||||
).eval()
|
|
||||||
model.to(device)
|
|
||||||
torch.cuda.synchronize()
|
|
||||||
end = perf_counter()
|
|
||||||
model_load_time = end - start
|
|
||||||
logger.info(f"loaded model in: {model_load_time}s")
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
|
||||||
|
|
||||||
prompt = "Why dogs are so cute?"
|
|
||||||
inputs = tokenizer(prompt, return_tensors="pt").to(device)
|
|
||||||
|
|
||||||
# Specify the max length (including both the prompt and the response)
|
|
||||||
# When calling `generate` with `cache_implementation="static" later, this is also used to create a `StaticCache` object
|
|
||||||
# with sequence length = `max_length`. The longer the more you will re-use it
|
|
||||||
seq_length = inputs["input_ids"].shape[1]
|
|
||||||
model.generation_config.max_length = seq_length + num_tokens_to_generate
|
|
||||||
batch_size = inputs["input_ids"].shape[0]
|
|
||||||
|
|
||||||
# Copied from the gpt-fast repo
|
|
||||||
def multinomial_sample_one_no_sync(probs_sort): # Does multinomial sampling without a cuda synchronization
|
|
||||||
q = torch.empty_like(probs_sort).exponential_(1)
|
|
||||||
return torch.argmax(probs_sort / q, dim=-1, keepdim=True).to(dtype=torch.int)
|
|
||||||
|
|
||||||
def logits_to_probs(logits, temperature: float = 1.0, top_k: Optional[int] = None):
|
|
||||||
logits = logits / max(temperature, 1e-5)
|
|
||||||
|
|
||||||
if top_k is not None:
|
|
||||||
v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
|
|
||||||
pivot = v.select(-1, -1).unsqueeze(-1)
|
|
||||||
logits = torch.where(logits < pivot, -float("Inf"), logits)
|
|
||||||
probs = torch.nn.functional.softmax(logits, dim=-1)
|
|
||||||
return probs
|
|
||||||
|
|
||||||
def sample(logits, temperature: float = 1.0, top_k: Optional[int] = None):
|
|
||||||
probs = logits_to_probs(logits[:, -1], temperature, top_k)
|
|
||||||
idx_next = multinomial_sample_one_no_sync(probs)
|
|
||||||
return idx_next, probs
|
|
||||||
|
|
||||||
def decode_one_token(model, cur_token, cache_position, past_key_values):
|
|
||||||
logits = model(
|
|
||||||
cur_token,
|
|
||||||
cache_position=cache_position,
|
|
||||||
past_key_values=past_key_values,
|
|
||||||
return_dict=False,
|
|
||||||
use_cache=True,
|
|
||||||
)[0]
|
|
||||||
new_token = sample(logits, temperature=0.6, top_k=5)[0]
|
|
||||||
return new_token
|
|
||||||
|
|
||||||
#########
|
|
||||||
# Eager #
|
|
||||||
#########
|
|
||||||
with torch.no_grad():
|
|
||||||
past_key_values = StaticCache(
|
|
||||||
model.config,
|
|
||||||
batch_size=batch_size,
|
|
||||||
device=device,
|
|
||||||
dtype=torch.float16,
|
|
||||||
max_cache_len=seq_length + num_tokens_to_generate,
|
|
||||||
)
|
|
||||||
cache_position = torch.arange(seq_length, device=device)
|
|
||||||
start = perf_counter()
|
|
||||||
model(
|
|
||||||
**inputs,
|
|
||||||
cache_position=cache_position,
|
|
||||||
past_key_values=past_key_values,
|
|
||||||
return_dict=False,
|
|
||||||
use_cache=True,
|
|
||||||
)
|
|
||||||
end = perf_counter()
|
|
||||||
first_eager_fwd_pass_time = end - start
|
|
||||||
logger.info(f"completed first eager fwd pass in: {first_eager_fwd_pass_time}s")
|
|
||||||
start = perf_counter()
|
|
||||||
output = model.generate(**inputs, do_sample=False)
|
|
||||||
end = perf_counter()
|
|
||||||
first_eager_generate_time = end - start
|
|
||||||
logger.info(f"completed first eager generation in: {first_eager_generate_time}s")
|
|
||||||
logger.info(f"generated: {tokenizer.batch_decode(output.cpu().tolist())}")
|
|
||||||
|
|
||||||
past_key_values = StaticCache(
|
|
||||||
model.config,
|
|
||||||
batch_size=batch_size,
|
|
||||||
device=device,
|
|
||||||
dtype=torch.float16,
|
|
||||||
max_cache_len=seq_length + num_tokens_to_generate,
|
|
||||||
)
|
|
||||||
cache_position = torch.arange(seq_length, device=device)
|
|
||||||
start = perf_counter()
|
|
||||||
model(
|
|
||||||
**inputs,
|
|
||||||
cache_position=cache_position,
|
|
||||||
past_key_values=past_key_values,
|
|
||||||
return_dict=False,
|
|
||||||
use_cache=True,
|
|
||||||
)
|
|
||||||
end = perf_counter()
|
|
||||||
second_eager_fwd_pass_time = end - start
|
|
||||||
logger.info(f"completed second eager fwd pass in: {second_eager_fwd_pass_time}s")
|
|
||||||
start = perf_counter()
|
|
||||||
model.generate(**inputs, do_sample=False)
|
|
||||||
end = perf_counter()
|
|
||||||
second_eager_generate_time = end - start
|
|
||||||
logger.info(f"completed second eager generation in: {second_eager_generate_time}s")
|
|
||||||
logger.info(f"generated: {tokenizer.batch_decode(output.cpu().tolist())}")
|
|
||||||
|
|
||||||
torch.compiler.reset()
|
|
||||||
|
|
||||||
################
|
|
||||||
# Forward pass #
|
|
||||||
################
|
|
||||||
|
|
||||||
# `torch.compile(model, ...)` is not recommended as you compile callbacks
|
|
||||||
# and full generate. We recommend compiling only the forward for now.
|
|
||||||
# "reduce-overhead" will use cudagraphs.
|
|
||||||
generated_ids = torch.zeros(
|
|
||||||
(batch_size, num_tokens_to_generate + seq_length), dtype=torch.int, device=device
|
|
||||||
)
|
|
||||||
|
|
||||||
generated_ids[:, :seq_length] = inputs["input_ids"]
|
|
||||||
decode_one_token = torch.compile(decode_one_token, mode="reduce-overhead", fullgraph=True)
|
|
||||||
# model.forward = torch.compile(model.forward, mode="reduce-overhead", fullgraph=True)
|
|
||||||
# TODO use decode_one_token(model, input_id.clone(), cache_position) for verification
|
|
||||||
past_key_values = StaticCache(
|
|
||||||
model.config,
|
|
||||||
batch_size=batch_size,
|
|
||||||
device=device,
|
|
||||||
dtype=torch.float16,
|
|
||||||
max_cache_len=seq_length + num_tokens_to_generate + 10,
|
|
||||||
)
|
|
||||||
cache_position = torch.arange(seq_length, device=device)
|
|
||||||
all_generated_tokens = []
|
|
||||||
### First compile, prefill
|
|
||||||
start = perf_counter()
|
|
||||||
next_token = decode_one_token(
|
|
||||||
model, inputs["input_ids"], cache_position=cache_position, past_key_values=past_key_values
|
|
||||||
)
|
|
||||||
torch.cuda.synchronize()
|
|
||||||
end = perf_counter()
|
|
||||||
time_to_first_token = end - start
|
|
||||||
logger.info(f"completed first compile generation in: {time_to_first_token}s")
|
|
||||||
cache_position += 1
|
|
||||||
all_generated_tokens += next_token.clone().detach().cpu().tolist()
|
|
||||||
|
|
||||||
cache_position = torch.tensor([seq_length], device=device)
|
|
||||||
### First compile, decoding
|
|
||||||
start = perf_counter()
|
|
||||||
next_token = decode_one_token(
|
|
||||||
model, next_token.clone(), cache_position=cache_position, past_key_values=past_key_values
|
|
||||||
)
|
|
||||||
torch.cuda.synchronize()
|
|
||||||
end = perf_counter()
|
|
||||||
time_to_second_token = end - start
|
|
||||||
logger.info(f"completed second compile generation in: {time_to_first_token}s")
|
|
||||||
cache_position += 1
|
|
||||||
all_generated_tokens += next_token.clone().detach().cpu().tolist()
|
|
||||||
|
|
||||||
### Second compile, decoding
|
|
||||||
start = perf_counter()
|
|
||||||
next_token = decode_one_token(
|
|
||||||
model, next_token.clone(), cache_position=cache_position, past_key_values=past_key_values
|
|
||||||
)
|
|
||||||
torch.cuda.synchronize()
|
|
||||||
end = perf_counter()
|
|
||||||
time_to_third_token = end - start
|
|
||||||
logger.info(f"completed third compile forward in: {time_to_first_token}s")
|
|
||||||
cache_position += 1
|
|
||||||
all_generated_tokens += next_token.clone().detach().cpu().tolist()
|
|
||||||
|
|
||||||
### Using cuda graphs decoding
|
|
||||||
|
|
||||||
start = perf_counter()
|
|
||||||
for _ in range(1, num_tokens_to_generate):
|
|
||||||
all_generated_tokens += next_token.clone().detach().cpu().tolist()
|
|
||||||
next_token = decode_one_token(
|
|
||||||
model, next_token.clone(), cache_position=cache_position, past_key_values=past_key_values
|
|
||||||
)
|
|
||||||
cache_position += 1
|
|
||||||
torch.cuda.synchronize()
|
|
||||||
end = perf_counter()
|
|
||||||
mean_time_to_next_token = (end - start) / num_tokens_to_generate
|
|
||||||
logger.info(f"completed next compile generation in: {mean_time_to_next_token}s")
|
|
||||||
logger.info(f"generated: {tokenizer.batch_decode(all_generated_tokens)}")
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Generate compile #
|
|
||||||
####################
|
|
||||||
torch.compiler.reset()
|
|
||||||
# we will not compile full generate as it' s to intensive, tho we measure full forward!
|
|
||||||
|
|
||||||
past_key_values = StaticCache(
|
|
||||||
model.config,
|
|
||||||
batch_size=batch_size,
|
|
||||||
device=device,
|
|
||||||
dtype=torch.float16,
|
|
||||||
max_cache_len=seq_length + 128,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 1st call
|
|
||||||
start = perf_counter()
|
|
||||||
output = model.generate(**inputs, past_key_values=past_key_values)
|
|
||||||
torch.cuda.synchronize()
|
|
||||||
end = perf_counter()
|
|
||||||
first_compile_generate_time = end - start
|
|
||||||
logger.info(f"completed first compile generation in: {first_compile_generate_time}s")
|
|
||||||
logger.info(f"generated: {tokenizer.batch_decode(output.cpu().tolist())}")
|
|
||||||
|
|
||||||
past_key_values = StaticCache(
|
|
||||||
model.config,
|
|
||||||
batch_size=batch_size,
|
|
||||||
device=device,
|
|
||||||
dtype=torch.float16,
|
|
||||||
max_cache_len=seq_length + 128,
|
|
||||||
)
|
|
||||||
# 2nd call
|
|
||||||
start = perf_counter()
|
|
||||||
output = model.generate(**inputs, past_key_values=past_key_values)
|
|
||||||
torch.cuda.synchronize()
|
|
||||||
end = perf_counter()
|
|
||||||
second_compile_generate_time = end - start
|
|
||||||
logger.info(f"completed second compile generation in: {second_compile_generate_time}s")
|
|
||||||
logger.info(f"generated: {tokenizer.batch_decode(output.cpu().tolist())}")
|
|
||||||
|
|
||||||
past_key_values = StaticCache(
|
|
||||||
model.config,
|
|
||||||
batch_size=batch_size,
|
|
||||||
device=device,
|
|
||||||
dtype=torch.float16,
|
|
||||||
max_cache_len=seq_length + 128,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 3nd call
|
|
||||||
start = perf_counter()
|
|
||||||
output = model.generate(**inputs, past_key_values=past_key_values)
|
|
||||||
end = perf_counter()
|
|
||||||
third_compile_generate_time = end - start
|
|
||||||
logger.info(f"completed second compile generation in: {third_compile_generate_time}s")
|
|
||||||
logger.info(f"generated: {tokenizer.batch_decode(output.cpu().tolist())}")
|
|
||||||
|
|
||||||
past_key_values = StaticCache(
|
|
||||||
model.config,
|
|
||||||
batch_size=batch_size,
|
|
||||||
device=device,
|
|
||||||
dtype=torch.float16,
|
|
||||||
max_cache_len=seq_length + 128,
|
|
||||||
)
|
|
||||||
# 4th call
|
|
||||||
start = perf_counter()
|
|
||||||
output = model.generate(**inputs, past_key_values=past_key_values)
|
|
||||||
end = perf_counter()
|
|
||||||
fourth_compile_generate_time = end - start
|
|
||||||
logger.info(f"completed second compile generation in: {fourth_compile_generate_time}s")
|
|
||||||
logger.info(f"generated: {tokenizer.batch_decode(output.cpu().tolist())}")
|
|
||||||
|
|
||||||
metrics_recorder.collect_model_measurements(
|
|
||||||
benchmark_id,
|
|
||||||
{
|
|
||||||
"model_load_time": model_load_time,
|
|
||||||
"first_eager_forward_pass_time_secs": first_eager_fwd_pass_time,
|
|
||||||
"second_eager_forward_pass_time_secs": second_eager_fwd_pass_time,
|
|
||||||
"first_eager_generate_time_secs": first_eager_generate_time,
|
|
||||||
"second_eager_generate_time_secs": second_eager_generate_time,
|
|
||||||
"time_to_first_token_secs": time_to_first_token,
|
|
||||||
"time_to_second_token_secs": time_to_second_token,
|
|
||||||
"time_to_third_token_secs": time_to_third_token,
|
|
||||||
"time_to_next_token_mean_secs": mean_time_to_next_token,
|
|
||||||
"first_compile_generate_time_secs": first_compile_generate_time,
|
|
||||||
"second_compile_generate_time_secs": second_compile_generate_time,
|
|
||||||
"third_compile_generate_time_secs": third_compile_generate_time,
|
|
||||||
"fourth_compile_generate_time_secs": fourth_compile_generate_time,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Caught exception: {e}")
|
|
||||||
continue_metric_collection.set()
|
|
||||||
if metrics_thread is not None:
|
|
||||||
metrics_thread.join()
|
|
||||||
metrics_recorder.close()
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
gpustat==1.1.1
|
|
||||||
psutil==6.0.0
|
|
||||||
psycopg2==2.9.9
|
|
||||||
torch>=2.4.0
|
|
||||||
hf_transfer
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
# Dockers for `transformers`
|
|
||||||
|
|
||||||
In this folder you will find various docker files, and some subfolders.
|
|
||||||
- dockerfiles (ex: `consistency.dockerfile`) present under `~/docker` are used for our "fast" CIs. You should be able to use them for tasks that only need CPU. For example `torch-light` is a very light weights container (703MiB).
|
|
||||||
- subfloder contain dockerfiles used for our `slow` CIs, which *can* be used for GPU tasks, but they are **BIG** as they were not specifically designed for a single model / single task. Thus the `~/docker/transformers-pytorch-gpu` includes additional dependencies to allow us to run ALL model tests (say `librosa` or `tesseract`, which you do not need to run LLMs)
|
|
||||||
|
|
||||||
Note that in both case, you need to run `uv pip install -e .`, which should take around 5 seconds. We do it outside the dockerfile for the need of our CI: we checkout a new branch each time, and the `transformers` code is thus updated.
|
|
||||||
|
|
||||||
We are open to contribution, and invite the community to create dockerfiles with potential arguments that properly choose extras depending on the model's dependencies! :hugs:
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04
|
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu20.04
|
||||||
LABEL maintainer="Hugging Face"
|
LABEL maintainer="Hugging Face"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
@ -9,7 +9,7 @@ SHELL ["sh", "-lc"]
|
|||||||
# The following `ARG` are mainly used to specify the versions explicitly & directly in this docker file, and not meant
|
# The following `ARG` are mainly used to specify the versions explicitly & directly in this docker file, and not meant
|
||||||
# to be used as arguments for docker build (so far).
|
# to be used as arguments for docker build (so far).
|
||||||
|
|
||||||
ARG PYTORCH='2.5.1'
|
ARG PYTORCH='2.4.0'
|
||||||
# (not always a valid torch version)
|
# (not always a valid torch version)
|
||||||
ARG INTEL_TORCH_EXT='2.3.0'
|
ARG INTEL_TORCH_EXT='2.3.0'
|
||||||
# Example: `cu102`, `cu113`, etc.
|
# Example: `cu102`, `cu113`, etc.
|
||||||
@ -26,7 +26,7 @@ RUN git clone https://github.com/huggingface/transformers && cd transformers &&
|
|||||||
# 1. Put several commands in a single `RUN` to avoid image/layer exporting issue. Could be revised in the future.
|
# 1. Put several commands in a single `RUN` to avoid image/layer exporting issue. Could be revised in the future.
|
||||||
# 2. Regarding `torch` part, We might need to specify proper versions for `torchvision` and `torchaudio`.
|
# 2. Regarding `torch` part, We might need to specify proper versions for `torchvision` and `torchaudio`.
|
||||||
# Currently, let's not bother to specify their versions explicitly (so installed with their latest release versions).
|
# Currently, let's not bother to specify their versions explicitly (so installed with their latest release versions).
|
||||||
RUN python3 -m pip install --no-cache-dir -U tensorflow==2.13 protobuf==3.20.3 "tensorflow_text<2.16" "tensorflow_probability<0.22" && python3 -m pip install --no-cache-dir -e ./transformers[dev,onnxruntime] && [ ${#PYTORCH} -gt 0 -a "$PYTORCH" != "pre" ] && VERSION='torch=='$PYTORCH'.*' || VERSION='torch'; echo "export VERSION='$VERSION'" >> ~/.profile && echo torch=$VERSION && [ "$PYTORCH" != "pre" ] && python3 -m pip install --no-cache-dir -U $VERSION torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/$CUDA || python3 -m pip install --no-cache-dir -U --pre torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/$CUDA
|
RUN python3 -m pip install --no-cache-dir -U tensorflow==2.13 protobuf==3.20.3 tensorflow_text tensorflow_probability && python3 -m pip install --no-cache-dir -e ./transformers[dev,onnxruntime] && [ ${#PYTORCH} -gt 0 -a "$PYTORCH" != "pre" ] && VERSION='torch=='$PYTORCH'.*' || VERSION='torch'; echo "export VERSION='$VERSION'" >> ~/.profile && echo torch=$VERSION && [ "$PYTORCH" != "pre" ] && python3 -m pip install --no-cache-dir -U $VERSION torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/$CUDA || python3 -m pip install --no-cache-dir -U --pre torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/$CUDA
|
||||||
|
|
||||||
RUN python3 -m pip uninstall -y flax jax
|
RUN python3 -m pip uninstall -y flax jax
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ RUN python3 -m pip install --no-cache-dir git+https://github.com/huggingface/pef
|
|||||||
RUN python3 -m pip install --no-cache-dir git+https://github.com/huggingface/optimum@main#egg=optimum
|
RUN python3 -m pip install --no-cache-dir git+https://github.com/huggingface/optimum@main#egg=optimum
|
||||||
|
|
||||||
# For video model testing
|
# For video model testing
|
||||||
RUN python3 -m pip install --no-cache-dir av==9.2.0
|
RUN python3 -m pip install --no-cache-dir decord av==9.2.0
|
||||||
|
|
||||||
# Some slow tests require bnb
|
# Some slow tests require bnb
|
||||||
RUN python3 -m pip install --no-cache-dir bitsandbytes
|
RUN python3 -m pip install --no-cache-dir bitsandbytes
|
||||||
@ -65,9 +65,6 @@ RUN python3 -m pip install --no-cache-dir python-Levenshtein
|
|||||||
# For `FastSpeech2ConformerTokenizer` tokenizer
|
# For `FastSpeech2ConformerTokenizer` tokenizer
|
||||||
RUN python3 -m pip install --no-cache-dir g2p-en
|
RUN python3 -m pip install --no-cache-dir g2p-en
|
||||||
|
|
||||||
# For Some bitsandbytes tests
|
|
||||||
RUN python3 -m pip install --no-cache-dir einops
|
|
||||||
|
|
||||||
# When installing in editable mode, `transformers` is not recognized as a package.
|
# When installing in editable mode, `transformers` is not recognized as a package.
|
||||||
# this line must be added in order for python to be aware of transformers.
|
# this line must be added in order for python to be aware of transformers.
|
||||||
RUN cd transformers && python3 setup.py develop
|
RUN cd transformers && python3 setup.py develop
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
FROM rocm/dev-ubuntu-22.04:6.2.4
|
FROM rocm/dev-ubuntu-22.04:6.0.2
|
||||||
|
# rocm/pytorch has no version with 2.1.0
|
||||||
LABEL maintainer="Hugging Face"
|
LABEL maintainer="Hugging Face"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
@ -10,7 +11,7 @@ RUN apt update && \
|
|||||||
|
|
||||||
RUN python3 -m pip install --no-cache-dir --upgrade pip numpy
|
RUN python3 -m pip install --no-cache-dir --upgrade pip numpy
|
||||||
|
|
||||||
RUN python3 -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm6.2
|
RUN python3 -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm6.0
|
||||||
|
|
||||||
RUN python3 -m pip install --no-cache-dir --upgrade importlib-metadata setuptools ninja git+https://github.com/facebookresearch/detectron2.git pytesseract "itsdangerous<2.1.0"
|
RUN python3 -m pip install --no-cache-dir --upgrade importlib-metadata setuptools ninja git+https://github.com/facebookresearch/detectron2.git pytesseract "itsdangerous<2.1.0"
|
||||||
|
|
||||||
@ -29,5 +30,5 @@ RUN python3 -m pip uninstall -y tensorflow flax
|
|||||||
# this line must be added in order for python to be aware of transformers.
|
# this line must be added in order for python to be aware of transformers.
|
||||||
RUN cd transformers && python3 setup.py develop
|
RUN cd transformers && python3 setup.py develop
|
||||||
|
|
||||||
# Remove nvml and nvidia-ml-py as it is not compatible with ROCm. apex is not tested on NVIDIA either.
|
# Remove nvml as it is not compatible with ROCm. apex is not tested on NVIDIA either.
|
||||||
RUN python3 -m pip uninstall py3nvml pynvml nvidia-ml-py apex -y
|
RUN python3 -m pip uninstall py3nvml pynvml apex -y
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
FROM rocm/dev-ubuntu-22.04:6.2.4
|
FROM rocm/dev-ubuntu-22.04:5.6
|
||||||
LABEL maintainer="Hugging Face"
|
LABEL maintainer="Hugging Face"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ARG PYTORCH='2.5.1'
|
ARG PYTORCH='2.1.1'
|
||||||
ARG TORCH_VISION='0.20.0'
|
ARG TORCH_VISION='0.16.1'
|
||||||
ARG TORCH_AUDIO='2.5.0'
|
ARG TORCH_AUDIO='2.1.1'
|
||||||
ARG ROCM='6.2'
|
ARG ROCM='5.6'
|
||||||
|
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
apt install -y --no-install-recommends \
|
apt install -y --no-install-recommends \
|
||||||
@ -45,4 +45,4 @@ RUN cd transformers && python3 setup.py develop
|
|||||||
RUN python3 -c "from deepspeed.launcher.runner import main"
|
RUN python3 -c "from deepspeed.launcher.runner import main"
|
||||||
|
|
||||||
# Remove nvml as it is not compatible with ROCm
|
# Remove nvml as it is not compatible with ROCm
|
||||||
RUN python3 -m pip uninstall py3nvml pynvml nvidia-ml-py apex -y
|
RUN python3 -m pip uninstall py3nvml pynvml -y
|
||||||
|
|||||||
@ -15,10 +15,6 @@ RUN python3 -m pip install --no-cache-dir --upgrade pip
|
|||||||
ARG REF=main
|
ARG REF=main
|
||||||
RUN git clone https://github.com/huggingface/transformers && cd transformers && git checkout $REF
|
RUN git clone https://github.com/huggingface/transformers && cd transformers && git checkout $REF
|
||||||
|
|
||||||
# Install Rust for Tokenizers
|
|
||||||
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
|
||||||
ENV PATH="$HOME/.cargo/bin:${PATH}"
|
|
||||||
|
|
||||||
RUN python3 -m pip install --no-cache-dir ./transformers[deepspeed-testing]
|
RUN python3 -m pip install --no-cache-dir ./transformers[deepspeed-testing]
|
||||||
|
|
||||||
# Install latest release PyTorch
|
# Install latest release PyTorch
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04
|
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu20.04
|
||||||
LABEL maintainer="Hugging Face"
|
LABEL maintainer="Hugging Face"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
@ -11,7 +11,7 @@ ARG REF=main
|
|||||||
RUN git clone https://github.com/huggingface/transformers && cd transformers && git checkout $REF
|
RUN git clone https://github.com/huggingface/transformers && cd transformers && git checkout $REF
|
||||||
|
|
||||||
# If set to nothing, will install the latest version
|
# If set to nothing, will install the latest version
|
||||||
ARG PYTORCH='2.5.1'
|
ARG PYTORCH='2.4.0'
|
||||||
ARG TORCH_VISION=''
|
ARG TORCH_VISION=''
|
||||||
ARG TORCH_AUDIO=''
|
ARG TORCH_AUDIO=''
|
||||||
# Example: `cu102`, `cu113`, etc.
|
# Example: `cu102`, `cu113`, etc.
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04
|
FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04
|
||||||
LABEL maintainer="Hugging Face"
|
LABEL maintainer="Hugging Face"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
@ -9,12 +9,12 @@ SHELL ["sh", "-lc"]
|
|||||||
# The following `ARG` are mainly used to specify the versions explicitly & directly in this docker file, and not meant
|
# The following `ARG` are mainly used to specify the versions explicitly & directly in this docker file, and not meant
|
||||||
# to be used as arguments for docker build (so far).
|
# to be used as arguments for docker build (so far).
|
||||||
|
|
||||||
ARG PYTORCH='2.5.1'
|
ARG PYTORCH='2.2.1'
|
||||||
# Example: `cu102`, `cu113`, etc.
|
# Example: `cu102`, `cu113`, etc.
|
||||||
ARG CUDA='cu118'
|
ARG CUDA='cu118'
|
||||||
|
|
||||||
RUN apt update
|
RUN apt update
|
||||||
RUN apt install -y git libsndfile1-dev tesseract-ocr espeak-ng python3 python3-pip ffmpeg
|
RUN apt install -y git libsndfile1-dev tesseract-ocr espeak-ng python python3-pip ffmpeg
|
||||||
RUN python3 -m pip install --no-cache-dir --upgrade pip
|
RUN python3 -m pip install --no-cache-dir --upgrade pip
|
||||||
|
|
||||||
ARG REF=main
|
ARG REF=main
|
||||||
@ -36,23 +36,15 @@ RUN python3 -m pip install --no-cache-dir einops
|
|||||||
# Add bitsandbytes for mixed int8 testing
|
# Add bitsandbytes for mixed int8 testing
|
||||||
RUN python3 -m pip install --no-cache-dir bitsandbytes
|
RUN python3 -m pip install --no-cache-dir bitsandbytes
|
||||||
|
|
||||||
# Add auto-gptq for gtpq quantization testing, installed from source for pytorch==2.5.1 compatibility
|
# Add auto-gptq for gtpq quantization testing
|
||||||
# TORCH_CUDA_ARCH_LIST="7.5+PTX" is added to make the package compile for Tesla T4 gpus available for the CI.
|
RUN python3 -m pip install --no-cache-dir auto-gptq --extra-index-url https://huggingface.github.io/autogptq-index/whl/cu118/
|
||||||
RUN pip install gekko
|
|
||||||
RUN git clone https://github.com/PanQiWei/AutoGPTQ.git && cd AutoGPTQ && TORCH_CUDA_ARCH_LIST="7.5+PTX" python3 setup.py install
|
|
||||||
|
|
||||||
# Add optimum for gptq quantization testing
|
# Add optimum for gptq quantization testing
|
||||||
RUN python3 -m pip install --no-cache-dir git+https://github.com/huggingface/optimum@main#egg=optimum
|
RUN python3 -m pip install --no-cache-dir git+https://github.com/huggingface/optimum@main#egg=optimum
|
||||||
|
|
||||||
# Add PEFT
|
|
||||||
RUN python3 -m pip install --no-cache-dir git+https://github.com/huggingface/peft@main#egg=peft
|
|
||||||
|
|
||||||
# Add aqlm for quantization testing
|
# Add aqlm for quantization testing
|
||||||
RUN python3 -m pip install --no-cache-dir aqlm[gpu]==1.0.2
|
RUN python3 -m pip install --no-cache-dir aqlm[gpu]==1.0.2
|
||||||
|
|
||||||
# Add vptq for quantization testing
|
|
||||||
RUN python3 -m pip install --no-cache-dir vptq
|
|
||||||
|
|
||||||
# Add hqq for quantization testing
|
# Add hqq for quantization testing
|
||||||
RUN python3 -m pip install --no-cache-dir hqq
|
RUN python3 -m pip install --no-cache-dir hqq
|
||||||
|
|
||||||
@ -60,19 +52,15 @@ RUN python3 -m pip install --no-cache-dir hqq
|
|||||||
RUN python3 -m pip install --no-cache-dir gguf
|
RUN python3 -m pip install --no-cache-dir gguf
|
||||||
|
|
||||||
# Add autoawq for quantization testing
|
# Add autoawq for quantization testing
|
||||||
# >=v0.2.7 needed for compatibility with transformers > 4.46
|
# >=v0.2.3 needed for compatibility with torch 2.2.1
|
||||||
RUN python3 -m pip install --no-cache-dir https://github.com/casper-hansen/AutoAWQ/releases/download/v0.2.7.post2/autoawq-0.2.7.post2-py3-none-any.whl
|
RUN python3 -m pip install --no-cache-dir https://github.com/casper-hansen/AutoAWQ/releases/download/v0.2.3/autoawq-0.2.3+cu118-cp38-cp38-linux_x86_64.whl
|
||||||
|
|
||||||
# Add quanto for quantization testing
|
# Add quanto for quantization testing
|
||||||
RUN python3 -m pip install --no-cache-dir optimum-quanto
|
RUN python3 -m pip install --no-cache-dir quanto
|
||||||
|
|
||||||
# Add eetq for quantization testing
|
# Add eetq for quantization testing
|
||||||
RUN python3 -m pip install git+https://github.com/NetEase-FuXi/EETQ.git
|
RUN python3 -m pip install git+https://github.com/NetEase-FuXi/EETQ.git
|
||||||
|
|
||||||
# Add flute-kernel and fast_hadamard_transform for quantization testing
|
|
||||||
RUN python3 -m pip install --no-cache-dir flute-kernel==0.3.0 -i https://flute-ai.github.io/whl/cu118
|
|
||||||
RUN python3 -m pip install --no-cache-dir fast_hadamard_transform==1.0.4.post1
|
|
||||||
|
|
||||||
# When installing in editable mode, `transformers` is not recognized as a package.
|
# When installing in editable mode, `transformers` is not recognized as a package.
|
||||||
# this line must be added in order for python to be aware of transformers.
|
# this line must be added in order for python to be aware of transformers.
|
||||||
RUN cd transformers && python3 setup.py develop
|
RUN cd transformers && python3 setup.py develop
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04
|
FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu20.04
|
||||||
LABEL maintainer="Hugging Face"
|
LABEL maintainer="Hugging Face"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
@ -18,7 +18,7 @@ RUN [ ${#TENSORFLOW} -gt 0 ] && VERSION='tensorflow=='$TENSORFLOW'.*' || VERSIO
|
|||||||
RUN python3 -m pip uninstall -y torch flax
|
RUN python3 -m pip uninstall -y torch flax
|
||||||
RUN python3 -m pip install -U "itsdangerous<2.1.0"
|
RUN python3 -m pip install -U "itsdangerous<2.1.0"
|
||||||
|
|
||||||
RUN python3 -m pip install --no-cache-dir -U "tensorflow_probability<0.22"
|
RUN python3 -m pip install --no-cache-dir -U tensorflow_probability
|
||||||
|
|
||||||
# When installing in editable mode, `transformers` is not recognized as a package.
|
# When installing in editable mode, `transformers` is not recognized as a package.
|
||||||
# this line must be added in order for python to be aware of transformers.
|
# this line must be added in order for python to be aware of transformers.
|
||||||
|
|||||||
@ -276,14 +276,14 @@ building the return.
|
|||||||
|
|
||||||
Here's an example of a single value return:
|
Here's an example of a single value return:
|
||||||
|
|
||||||
```python
|
```
|
||||||
Returns:
|
Returns:
|
||||||
`List[int]`: A list of integers in the range [0, 1] --- 1 for a special token, 0 for a sequence token.
|
`List[int]`: A list of integers in the range [0, 1] --- 1 for a special token, 0 for a sequence token.
|
||||||
```
|
```
|
||||||
|
|
||||||
Here's an example of a tuple return, comprising several objects:
|
Here's an example of a tuple return, comprising several objects:
|
||||||
|
|
||||||
```python
|
```
|
||||||
Returns:
|
Returns:
|
||||||
`tuple(torch.FloatTensor)` comprising various elements depending on the configuration ([`BertConfig`]) and inputs:
|
`tuple(torch.FloatTensor)` comprising various elements depending on the configuration ([`BertConfig`]) and inputs:
|
||||||
- ** loss** (*optional*, returned when `masked_lm_labels` is provided) `torch.FloatTensor` of shape `(1,)` --
|
- ** loss** (*optional*, returned when `masked_lm_labels` is provided) `torch.FloatTensor` of shape `(1,)` --
|
||||||
@ -322,9 +322,10 @@ includes an example of how to transcribe speech to text in the
|
|||||||
|
|
||||||
The syntax for Example docstrings can look as follows:
|
The syntax for Example docstrings can look as follows:
|
||||||
|
|
||||||
```python
|
```
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
```python
|
||||||
>>> from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC
|
>>> from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC
|
||||||
>>> from datasets import load_dataset
|
>>> from datasets import load_dataset
|
||||||
>>> import torch
|
>>> import torch
|
||||||
@ -346,6 +347,7 @@ The syntax for Example docstrings can look as follows:
|
|||||||
>>> transcription = processor.batch_decode(predicted_ids)
|
>>> transcription = processor.batch_decode(predicted_ids)
|
||||||
>>> transcription[0]
|
>>> transcription[0]
|
||||||
'MISTER QUILTER IS THE APOSTLE OF THE MIDDLE CLASSES AND WE ARE GLAD TO WELCOME HIS GOSPEL'
|
'MISTER QUILTER IS THE APOSTLE OF THE MIDDLE CLASSES AND WE ARE GLAD TO WELCOME HIS GOSPEL'
|
||||||
|
```
|
||||||
```
|
```
|
||||||
|
|
||||||
The docstring should give a minimal, clear example of how the respective model
|
The docstring should give a minimal, clear example of how the respective model
|
||||||
|
|||||||
@ -1,70 +1,57 @@
|
|||||||
# Translating the Transformers documentation into your language
|
### Translating the Transformers documentation into your language
|
||||||
|
|
||||||
As part of our mission to democratize machine learning, we aim to make the Transformers library available in many more languages! Follow the steps below to help translate the documentation into your language.
|
As part of our mission to democratize machine learning, we'd love to make the Transformers library available in many more languages! Follow the steps below if you want to help translate the documentation into your language 🙏.
|
||||||
|
|
||||||
## Open an Issue
|
**🗞️ Open an issue**
|
||||||
|
|
||||||
1. Navigate to the Issues page of this repository.
|
To get started, navigate to the [Issues](https://github.com/huggingface/transformers/issues) page of this repo and check if anyone else has opened an issue for your language. If not, open a new issue by selecting the "Translation template" from the "New issue" button.
|
||||||
2. Check if anyone has already opened an issue for your language.
|
|
||||||
3. If not, create a new issue by selecting the "Translation template" from the "New issue" button.
|
|
||||||
4. Post a comment indicating which chapters you’d like to work on, and we’ll add your name to the list.
|
|
||||||
|
|
||||||
## Fork the Repository
|
Once an issue exists, post a comment to indicate which chapters you'd like to work on, and we'll add your name to the list.
|
||||||
|
|
||||||
1. First, fork the Transformers repo by clicking the Fork button in the top-right corner.
|
|
||||||
2. Clone your fork to your local machine for editing with the following command:
|
|
||||||
|
|
||||||
```bash
|
**🍴 Fork the repository**
|
||||||
git clone https://github.com/YOUR-USERNAME/transformers.git
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace `YOUR-USERNAME` with your GitHub username.
|
|
||||||
|
|
||||||
## Copy-paste the English version with a new language code
|
First, you'll need to [fork the Transformers repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo). You can do this by clicking on the **Fork** button on the top-right corner of this repo's page.
|
||||||
|
|
||||||
The documentation files are organized in the following directory:
|
Once you've forked the repo, you'll want to get the files on your local machine for editing. You can do that by cloning the fork with Git as follows:
|
||||||
|
|
||||||
- **docs/source**: This contains all documentation materials organized by language.
|
```bash
|
||||||
|
git clone https://github.com/YOUR-USERNAME/transformers.git
|
||||||
|
```
|
||||||
|
|
||||||
To copy the English version to your new language directory:
|
**📋 Copy-paste the English version with a new language code**
|
||||||
|
|
||||||
1. Navigate to your fork of the repository:
|
The documentation files are in one leading directory:
|
||||||
|
|
||||||
```bash
|
- [`docs/source`](https://github.com/huggingface/transformers/tree/main/docs/source): All the documentation materials are organized here by language.
|
||||||
cd ~/path/to/transformers/docs
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace `~/path/to` with your actual path.
|
You'll only need to copy the files in the [`docs/source/en`](https://github.com/huggingface/transformers/tree/main/docs/source/en) directory, so first navigate to your fork of the repo and run the following:
|
||||||
|
|
||||||
2. Run the following command:
|
```bash
|
||||||
|
cd ~/path/to/transformers/docs
|
||||||
|
cp -r source/en source/LANG-ID
|
||||||
|
```
|
||||||
|
|
||||||
```bash
|
Here, `LANG-ID` should be one of the ISO 639-1 or ISO 639-2 language codes -- see [here](https://www.loc.gov/standards/iso639-2/php/code_list.php) for a handy table.
|
||||||
cp -r source/en source/LANG-ID
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace `LANG-ID` with the appropriate ISO 639-1 or ISO 639-2 language code (see [this table](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) for reference).
|
**✍️ Start translating**
|
||||||
|
|
||||||
## Start translating
|
The fun part comes - translating the text!
|
||||||
|
|
||||||
Begin translating the text!
|
The first thing we recommend is translating the part of the `_toctree.yml` file that corresponds to your doc chapter. This file is used to render the table of contents on the website.
|
||||||
|
|
||||||
1. Start with the `_toctree.yml` file that corresponds to your documentation chapter. This file is essential for rendering the table of contents on the website.
|
> 🙋 If the `_toctree.yml` file doesn't yet exist for your language, you can create one by copy-pasting from the English version and deleting the sections unrelated to your chapter. Just make sure it exists in the `docs/source/LANG-ID/` directory!
|
||||||
|
|
||||||
- If the `_toctree.yml` file doesn’t exist for your language, create one by copying the English version and removing unrelated sections.
|
The fields you should add are `local` (with the name of the file containing the translation; e.g. `autoclass_tutorial`), and `title` (with the title of the doc in your language; e.g. `Load pretrained instances with an AutoClass`) -- as a reference, here is the `_toctree.yml` for [English](https://github.com/huggingface/transformers/blob/main/docs/source/en/_toctree.yml):
|
||||||
- Ensure it is placed in the `docs/source/LANG-ID/` directory.
|
|
||||||
|
|
||||||
Here’s an example structure for the `_toctree.yml` file:
|
```yaml
|
||||||
|
- sections:
|
||||||
|
- local: pipeline_tutorial # Do not change this! Use the same name for your .md file
|
||||||
|
title: Pipelines for inference # Translate this!
|
||||||
|
...
|
||||||
|
title: Tutorials # Translate this!
|
||||||
|
```
|
||||||
|
|
||||||
```yaml
|
Once you have translated the `_toctree.yml` file, you can start translating the [MDX](https://mdxjs.com/) files associated with your docs chapter.
|
||||||
- sections:
|
|
||||||
- local: pipeline_tutorial # Keep this name for your .md file
|
|
||||||
title: Pipelines for Inference # Translate this
|
|
||||||
...
|
|
||||||
title: Tutorials # Translate this
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Once you’ve translated the `_toctree.yml`, move on to translating the associated MDX files.
|
> 🙋 If you'd like others to help you with the translation, you should [open an issue](https://github.com/huggingface/transformers/issues) and tag @stevhliu.
|
||||||
|
|
||||||
## Collaborate and share
|
|
||||||
|
|
||||||
If you'd like assistance with your translation, open an issue and tag `@stevhliu`. Feel free to share resources or glossaries to ensure consistent terminology.
|
|
||||||
|
|||||||
@ -30,26 +30,26 @@
|
|||||||
- local: conversations
|
- local: conversations
|
||||||
title: الدردشة مع المحولات
|
title: الدردشة مع المحولات
|
||||||
title: البرامج التعليمية
|
title: البرامج التعليمية
|
||||||
- sections:
|
# - sections:
|
||||||
- isExpanded: false
|
# - isExpanded: false
|
||||||
sections:
|
# sections:
|
||||||
- local: tasks/sequence_classification
|
# - local: tasks/sequence_classification
|
||||||
title: تصنيف النصوص
|
# title: تصنيف النصوص
|
||||||
- local: tasks/token_classification
|
# - local: tasks/token_classification
|
||||||
title: تصنيف الرموز
|
# title: تصنيف الرموز
|
||||||
- local: tasks/question_answering
|
# - local: tasks/question_answering
|
||||||
title: الإجابة على الأسئلة
|
# title: الإجابة على الأسئلة
|
||||||
- local: tasks/language_modeling
|
# - local: tasks/language_modeling
|
||||||
title: نمذجة اللغة السببية
|
# title: نمذجة اللغة السببية
|
||||||
- local: tasks/masked_language_modeling
|
# - local: tasks/masked_language_modeling
|
||||||
title: نمذجة اللغة المقنعة
|
# title: نمذجة اللغة المقنعة
|
||||||
- local: tasks/translation
|
# - local: tasks/translation
|
||||||
title: الترجمة
|
# title: الترجمة
|
||||||
- local: tasks/summarization
|
# - local: tasks/summarization
|
||||||
title: التلخيص
|
# title: التلخيص
|
||||||
- local: tasks/multiple_choice
|
# - local: tasks/multiple_choice
|
||||||
title: الاختيار المتعدد
|
# title: الاختيار المتعدد
|
||||||
title: معالجة اللغات الطبيعية
|
# title: معالجة اللغات الطبيعية
|
||||||
# - isExpanded: false
|
# - isExpanded: false
|
||||||
# sections:
|
# sections:
|
||||||
# - local: tasks/audio_classification
|
# - local: tasks/audio_classification
|
||||||
@ -107,43 +107,39 @@
|
|||||||
# - local: tasks/prompting
|
# - local: tasks/prompting
|
||||||
# title: دليل إرشادي لمحفزات النماذج اللغوية الكبيرة
|
# title: دليل إرشادي لمحفزات النماذج اللغوية الكبيرة
|
||||||
# title: الإرشاد
|
# title: الإرشاد
|
||||||
title: أدلة المهام
|
# title: أدلة المهام
|
||||||
- sections:
|
# - sections:
|
||||||
- local: fast_tokenizers
|
# - local: fast_tokenizers
|
||||||
title: استخدم مجزئيات النصوص السريعة من 🤗 Tokenizers
|
# title: استخدم برامج التجزئة السريعة من 🤗 Tokenizers
|
||||||
- local: multilingual
|
# - local: multilingual
|
||||||
title: الاستدلال باستخدام نماذج متعددة اللغات
|
# title: تشغيل الاستنتاج باستخدام نماذج متعددة اللغات
|
||||||
- local: create_a_model
|
# - local: create_a_model
|
||||||
title: استخدام واجهات برمجة التطبيقات الخاصة بالنموذج
|
# title: استخدام واجهات برمجة التطبيقات الخاصة بالنموذج
|
||||||
- local: custom_models
|
# - local: custom_models
|
||||||
title: مشاركة نموذج مخصص
|
# title: مشاركة نموذج مخصص
|
||||||
- local: chat_templating
|
# - local: chat_templating
|
||||||
title: قوالب لنماذج الدردشة
|
# title: قوالب لنماذج الدردشة
|
||||||
- local: trainer
|
# - local: trainer
|
||||||
title: المدرب
|
# title: المدرب
|
||||||
- local: sagemaker
|
# - local: sagemaker
|
||||||
title: تشغيل التدريب على Amazon SageMaker
|
# title: تشغيل التدريب على Amazon SageMaker
|
||||||
- local: serialization
|
# - local: serialization
|
||||||
title: التصدير إلى ONNX
|
# title: التصدير إلى ONNX
|
||||||
- local: tflite
|
# - local: tflite
|
||||||
title: التصدير إلى TFLite
|
# title: التصدير إلى TFLite
|
||||||
- local: torchscript
|
# - local: torchscript
|
||||||
title: التصدير إلى TorchScript
|
# title: التصدير إلى TorchScript
|
||||||
- local: notebooks
|
# - local: benchmarks
|
||||||
title: دفاتر الملاحظات مع الأمثلة
|
# title: المعايير
|
||||||
- local: community
|
# - local: notebooks
|
||||||
title: موارد المجتمع
|
# title: دفاتر الملاحظات مع الأمثلة
|
||||||
- local: troubleshooting
|
# - local: community
|
||||||
title: استكشاف الأخطاء وإصلاحها
|
# title: موارد المجتمع
|
||||||
- local: gguf
|
# - local: troubleshooting
|
||||||
title: التوافق مع ملفات GGUF
|
# title: استكشاف الأخطاء وإصلاحها
|
||||||
- local: tiktoken
|
# - local: gguf
|
||||||
title: التوافق مع ملفات TikToken
|
# title: التوافق مع ملفات GGUF
|
||||||
- local: modular_transformers
|
# title: أدلة المطورين
|
||||||
title: الوحدات النمطية في `transformers`
|
|
||||||
- local: how_to_hack_models
|
|
||||||
title: اختراق النموذج (الكتابة فوق فئة لاستخدامك)
|
|
||||||
title: أدلة المطورين
|
|
||||||
# - sections:
|
# - sections:
|
||||||
# - local: quantization/overview
|
# - local: quantization/overview
|
||||||
# title: نظرة عامة
|
# title: نظرة عامة
|
||||||
@ -155,8 +151,6 @@
|
|||||||
# title: AWQ
|
# title: AWQ
|
||||||
# - local: quantization/aqlm
|
# - local: quantization/aqlm
|
||||||
# title: AQLM
|
# title: AQLM
|
||||||
# - local: quantization/vptq
|
|
||||||
# title: VPTQ
|
|
||||||
# - local: quantization/quanto
|
# - local: quantization/quanto
|
||||||
# title: Quanto
|
# title: Quanto
|
||||||
# - local: quantization/eetq
|
# - local: quantization/eetq
|
||||||
@ -223,32 +217,32 @@
|
|||||||
# title: التحقق من طلب السحب
|
# title: التحقق من طلب السحب
|
||||||
# title: المساهمة
|
# title: المساهمة
|
||||||
- sections:
|
- sections:
|
||||||
- local: philosophy
|
# - local: philosophy
|
||||||
title: الفلسفة
|
# title: الفلسفة
|
||||||
- local: glossary
|
- local: glossary
|
||||||
title: (قاموس المصطلحات (قائمة الكلمات
|
title: (قاموس المصطلحات (قائمة الكلمات
|
||||||
- local: task_summary
|
# - local: task_summary
|
||||||
title: ما الذي يمكن أن تفعله 🤗 المحولات
|
# title: ما الذي يمكن أن تفعله 🤗 المحولات
|
||||||
- local: tasks_explained
|
# - local: tasks_explained
|
||||||
title: كيف تحل المحولات المهام
|
# title: كيف تحل المحولات المهام
|
||||||
- local: model_summary
|
# - local: model_summary
|
||||||
title: عائلة نماذج المحول
|
# title: عائلة نماذج المحول
|
||||||
- local: tokenizer_summary
|
# - local: tokenizer_summary
|
||||||
title: ملخص برنامج مقسم النصوص (tokenizers)
|
# title: ملخص برنامج مقسم النصوص (tokenizers)
|
||||||
- local: attention
|
# - local: attention
|
||||||
title: الانتباه Attention
|
# title: الانتباه Attention
|
||||||
- local: pad_truncation
|
# - local: pad_truncation
|
||||||
title: الحشو والتقليم
|
# title: الحشو والتقليم
|
||||||
- local: bertology
|
# - local: bertology
|
||||||
title: BERTology
|
# title: BERTology
|
||||||
- local: perplexity
|
# - local: perplexity
|
||||||
title: حيرة النماذج ذات الطول الثابت
|
# title: حيرة النماذج ذات الطول الثابت
|
||||||
- local: pipeline_webserver
|
# - local: pipeline_webserver
|
||||||
title: خطوط الأنابيب للاستدلال على خادم الويب
|
# title: خطوط الأنابيب للاستدلال على خادم الويب
|
||||||
- local: model_memory_anatomy
|
# - local: model_memory_anatomy
|
||||||
title: تشريح تدريب النموذج
|
# title: تشريح تدريب النموذج
|
||||||
- local: llm_tutorial_optimization
|
# - local: llm_tutorial_optimization
|
||||||
title: الاستفادة القصوى من LLMs
|
# title: الاستفادة القصوى من LLMs
|
||||||
title: أطر مفاهيمية
|
title: أطر مفاهيمية
|
||||||
# - sections:
|
# - sections:
|
||||||
# - sections:
|
# - sections:
|
||||||
@ -881,7 +875,7 @@
|
|||||||
# - local: internal/pipelines_utils
|
# - local: internal/pipelines_utils
|
||||||
# title: مرافق خطوط الأنابيب
|
# title: مرافق خطوط الأنابيب
|
||||||
# - local: internal/tokenization_utils
|
# - local: internal/tokenization_utils
|
||||||
# title: مرافق مقسم النصوص
|
# title: مرافق مقسم النصوص
|
||||||
# - local: internal/trainer_utils
|
# - local: internal/trainer_utils
|
||||||
# title: مرافق المدرب
|
# title: مرافق المدرب
|
||||||
# - local: internal/generation_utils
|
# - local: internal/generation_utils
|
||||||
|
|||||||
@ -464,7 +464,7 @@ image = image_generator(prompt=improved_prompt)
|
|||||||
|
|
||||||
قبل إنشاء الصورة أخيرًا:
|
قبل إنشاء الصورة أخيرًا:
|
||||||
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/rabbit_spacesuit_flux.webp" />
|
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/rabbit.png" />
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> تتطلب gradio-tools إدخالات وإخراجات *نصية* حتى عند العمل مع طرائق مختلفة مثل كائنات الصور والصوت. الإدخالات والإخراجات الصورية والصوتية غير متوافقة حاليًا.
|
> تتطلب gradio-tools إدخالات وإخراجات *نصية* حتى عند العمل مع طرائق مختلفة مثل كائنات الصور والصوت. الإدخالات والإخراجات الصورية والصوتية غير متوافقة حاليًا.
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
# آليات الانتباه
|
|
||||||
|
|
||||||
تستخدم معظم نماذج المحول (Transformer) الانتباه الكامل بحيث تكون مصفوفة الانتباه ذات الأبعاد المتساوية. ويمكن أن يمثل ذلك عقبة حسابية كبيرة عندما تكون لديك نصوص طويلة. ويعد Longformer وReformer من النماذج التي تحاول أن تكون أكثر كفاءة وتستخدم نسخة مخففة من مصفوفة الانتباه لتسريع التدريب.
|
|
||||||
|
|
||||||
## انتباه LSH
|
|
||||||
|
|
||||||
يستخدم [Reformer](model_doc/reformer) انتباه LSH. في الدالة softmax(QK^t)، فإن أكبر العناصر فقط (في بعد softmax) من المصفوفة QK^t هي التي ستعطي مساهمات مفيدة. لذلك، بالنسبة لكل استعلام q في Q، يمكننا أن نأخذ في الاعتبار فقط المفاتيح k في K المشابهة لـ q فقط. وتُستخدم دالة هاش لتحديد ما إذا كان q وk متشابهين. ويتم تعديل قناع الانتباه لتجاهل الرمز الحالي (باستثناء الموضع الأول)، لأنه سيعطي استعلامًا ومفتاحًا متساويين (لذلك متشابهين للغاية). نظرًا لطبيعة دالة الهاش العشوائية نوعًا ما، يتم في الممارسة العملية استخدام عدة دوال هاش (يحددها معامل n_rounds) ثم يتم حساب المتوسط معًا.
|
|
||||||
|
|
||||||
## الانتباه المحلي
|
|
||||||
|
|
||||||
يستخدم [Longformer](model_doc/longformer) الانتباه المحلي: غالبًا ما يكون السياق المحلي (على سبيل المثال، ما هما الرمزان إلى اليسار واليمين؟) كافيًا لاتخاذ إجراء بالنسبة للرمز المعطى. أيضًا، عن طريق تكديس طبقات الانتباه التي لها نافذة صغيرة، سيكون للطبقة الأخيرة مجال استقبال أكبر من مجرد الرموز في النافذة، مما يسمح لها ببناء تمثيل للجملة بأكملها.
|
|
||||||
|
|
||||||
كما يتم منح بعض رموز الإدخال المختارة مسبقًا انتباهًا عالميًا: بالنسبة لهذه الرموز القليلة، يمكن لمصفوفة الانتباه الوصول إلى جميع الرموز وتكون هذه العملية متماثلة: فلجميع الرموز الأخرى إمكانية الوصول إلى تلك الرموز المحددة (بالإضافة إلى تلك الموجودة في نافذتهم المحلية). وهذا موضح في الشكل 2d من الورقة، انظر أدناه لمثال على قناع الانتباه:
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img scale="50 %" align="center" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/local_attention_mask.png"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
وباستخدام مصفوفات الانتباه هذه التي تحتوي على عدد أقل من المعلمات، يسمح النموذج بمدخالات ذات طول تسلسل أكبر.
|
|
||||||
|
|
||||||
## حيل أخرى
|
|
||||||
|
|
||||||
### الترميزات الموضعية المحورية
|
|
||||||
|
|
||||||
يستخدم [Reformer](model_doc/reformer) ترميزات موضعية محورية: في نماذج المحول التقليدية، يكون الترميز الموضعي E مصفوفة بحجم \\(l\\) في \\(d\\)، حيث \\(l\\) هو طول التسلسل و\\(d\\) هو بعد الحالة المخفية. إذا كان لديك نصوص طويلة جدًا، فقد تكون هذه المصفوفة ضخمة وتستهلك مساحة كبيرة جدًا على وحدة معالجة الرسوميات (GPU). وللتخفيف من ذلك، تتكون الترميزات الموضعية المحورية من تحليل تلك المصفوفة الكبيرة E إلى مصفوفتين أصغر E1 وE2، بأبعاد \\(l_{1} \times d_{1}\\) و \\(l_{2} \times d_{2}\\)، بحيث \\(l_{1} \times l_{2} = l\\) و\\(d_{1} + d_{2} = d\\) (مع حاصل ضرب الأطوال، ينتهي الأمر بكونه أصغر بكثير). ويتم الحصول على الترميز للخطوة الزمنية \\(j\\) في E عن طريق ربط الترميزات للخطوة الزمنية \\(j \% l1\\) في E1 و \\(j // l1\\) في E2.
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# BERTology
|
|
||||||
|
|
||||||
يُشهد في الآونة الأخيرة نمو مجال دراسي يُعنى باستكشاف آلية عمل نماذج المحولات الضخمة مثل BERT (والذي يُطلق عليها البعض اسم "BERTology"). ومن الأمثلة البارزة على هذا المجال ما يلي:
|
|
||||||
|
|
||||||
- BERT Rediscovers the Classical NLP Pipeline بواسطة Ian Tenney و Dipanjan Das و Ellie Pavlick:
|
|
||||||
https://arxiv.org/abs/1905.05950
|
|
||||||
- Are Sixteen Heads Really Better than One? بواسطة Paul Michel و Omer Levy و Graham Neubig: https://arxiv.org/abs/1905.10650
|
|
||||||
- What Does BERT Look At? An Analysis of BERT's Attention بواسطة Kevin Clark و Urvashi Khandelwal و Omer Levy و Christopher D.
|
|
||||||
Manning: https://arxiv.org/abs/1906.04341
|
|
||||||
- CAT-probing: A Metric-based Approach to Interpret How Pre-trained Models for Programming Language Attend Code Structure: https://arxiv.org/abs/2210.04633
|
|
||||||
|
|
||||||
لإثراء هذا المجال الناشئ، قمنا بتضمين بعض الميزات الإضافية في نماذج BERT/GPT/GPT-2 للسماح للناس بالوصول إلى التمثيلات الداخلية، والتي تم تكييفها بشكل أساسي من العمل الرائد لـ Paul Michel (https://arxiv.org/abs/1905.10650):
|
|
||||||
|
|
||||||
- الوصول إلى جميع الحالات المخفية في BERT/GPT/GPT-2،
|
|
||||||
- الوصول إلى جميع أوزان الانتباه لكل رأس في BERT/GPT/GPT-2،
|
|
||||||
- استرجاع قيم ومشتقات مخرجات الرأس لحساب درجة أهمية الرأس وحذفه كما هو موضح في https://arxiv.org/abs/1905.10650.
|
|
||||||
|
|
||||||
ولمساعدتك على فهم واستخدام هذه الميزات بسهولة، أضفنا مثالًا برمجيًا محددًا: [bertology.py](https://github.com/huggingface/transformers/tree/main/examples/research_projects/bertology/run_bertology.py) أثناء استخراج المعلومات وتقليص من نموذج تم تدريبه مسبقًا على GLUE.
|
|
||||||
@ -1,835 +0,0 @@
|
|||||||
# قوالب نماذج الدردشة
|
|
||||||
|
|
||||||
## مقدمة
|
|
||||||
|
|
||||||
تعد **الدردشة** أحد استخدامات نماذج اللغات الكبيرة (LLMs) شائعة الاستخدام بشكل متزايد. ففي سياق الدردشة، وبدلاً من متابعة سلسلة نصية واحدة (كما هو الحال مع نماذج اللغات القياسية)، يواصل النموذج بدلاً من ذلك محادثة تتكون من رسالة واحدة أو أكثر، تتضمن كل منها دورًا، مثل "المستخدم" أو "المساعد"، بالإضافة إلى نص الرسالة.
|
|
||||||
|
|
||||||
وكما هو الحال مع تقسيم النص إلى رموز (tokenization)، تتوقع النماذج المختلفة تنسيقات إدخال مختلفة تمامًا للمحادثة. لهذا السبب أضفنا **قوالب الدردشة** كميزة جديدة. تُعد قوالب المحادثة جزءًا من tokenizer. تحدد هذه القوالب كيفية تحويل المحادثات، والتي يتم تمثيلها كقوائم من الرسائل، إلى سلسلة نصية واحدة قابلة للتقسيم إلى رموز بالتنسيق الذي يتوقعه النموذج.
|
|
||||||
|
|
||||||
دعونا نجعل هذا ملموسًا بمثال سريع باستخدام نموذج `BlenderBot`. لدى BlenderBot قالب افتراضي بسيط للغاية، والذي يضيف في الغالب مسافات بيضاء بين جولات الحوار:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill")
|
|
||||||
|
|
||||||
>>> chat = [
|
|
||||||
... {"role": "user", "content": "Hello, how are you?"},
|
|
||||||
... {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
|
|
||||||
... {"role": "user", "content": "I'd like to show off how chat templating works!"},
|
|
||||||
... ]
|
|
||||||
|
|
||||||
>>> tokenizer.apply_chat_template(chat, tokenize=False)
|
|
||||||
" Hello, how are you? I'm doing great. How can I help you today? I'd like to show off how chat templating works!</s>"
|
|
||||||
```
|
|
||||||
|
|
||||||
لاحظ كيف تم ضغط الدردشة بأكملها في سلسلة واحدة. إذا استخدمنا `tokenize=True`، وهو الإعداد الافتراضي، فسيتم أيضًا تحليل السلسلة نحويًا نيابة عنا. ولكن، لنشاهد قالبًا أكثر تعقيدًا في العمل، دعونا نستخدم نموذج `mistralai/Mistral-7B-Instruct-v0.1`.
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
|
|
||||||
|
|
||||||
>>> chat = [
|
|
||||||
... {"role": "user", "content": "Hello, how are you?"},
|
|
||||||
... {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
|
|
||||||
... {"role": "user", "content": "I'd like to show off how chat templating works!"},
|
|
||||||
... ]
|
|
||||||
|
|
||||||
>>> tokenizer.apply_chat_template(chat, tokenize=False)
|
|
||||||
"<s>[INST] Hello, how are you? [/INST]I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]</s>"
|
|
||||||
```
|
|
||||||
|
|
||||||
لاحظ كيف أضاف المجزىء اللغوى tokenizer رموز التحكم `[INST]` و `[/INST]` للإشارة إلى بداية ونهاية رسائل المستخدم (ولكن ليس رسائل المساعد!) ، وتم تكثيف المحادثة بأكملها في سلسلة نصية واحدة. إذا استخدمنا `tokenize=True` ، وهو الإعداد الافتراضي ، فسيتم أيضًا تقسيم تلك السلسلة إلى رموز.
|
|
||||||
|
|
||||||
حاول الآن استخدام نفس الشفرة، لكن مع استبدال النموذج بـ `HuggingFaceH4/zephyr-7b-beta` ، وستحصل على:
|
|
||||||
```text
|
|
||||||
<|user|>
|
|
||||||
Hello, how are you?</s>
|
|
||||||
<|assistant|>
|
|
||||||
I'm doing great. How can I help you today?</s>
|
|
||||||
<|user|>
|
|
||||||
I'd like to show off how chat templating works!</s>
|
|
||||||
```
|
|
||||||
تم ضبط كل من Zephyr و Mistral-Instruct من نفس النموذج الأصلي ، Mistral-7B-v0.1. ومع ذلك ، فقد تم تدريبهم بتنسيقات دردشة مختلفة تمامًا. بدون قوالب المحادثة، ستضطر إلى كتابة شفرة تنسيق يدويًا لكل نموذج ، ومن السهل جدًا ارتكاب أخطاء بسيطة تؤثر على الأداء! تُدير قوالب المحادثة تفاصيل التنسيق نيابةً عنك ، مما يُتيح لك كتابة شفرة عامة تعمل مع أي نموذج.
|
|
||||||
|
|
||||||
## كيف أستخدم قوالب الدردشة؟
|
|
||||||
|
|
||||||
كما رأيت في المثال السابق، من السهل استخدام قوالب الدردشة. قم ببساطة بإنشاء قائمة من الرسائل، مع مفتاحي `role` و`content`، ثم قم بتمريرها إلى [`~PreTrainedTokenizer.apply_chat_template`] . بمجرد قيامك بذلك، ستحصل على مخرجات جاهزة للاستخدام! عند استخدام قوالب الدردشة كإدخال لتوليد نصوص بواسطة النموذج، فمن الجيد أيضًا استخدام `add_generation_prompt=True` لإضافة [مطالبات توليد النصوص](#what-are-generation-prompts).
|
|
||||||
|
|
||||||
فيما يلي مثال على إعداد الإدخال لـ `model.generate()`، باستخدام Zephyr مرة أخرى:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
||||||
|
|
||||||
checkpoint = "HuggingFaceH4/zephyr-7b-beta"
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(checkpoint) # قد ترغب في استخدام bfloat16 و/أو الانتقال إلى GPU هنا
|
|
||||||
|
|
||||||
messages = [
|
|
||||||
{
|
|
||||||
"role": "system",
|
|
||||||
"content": "You are a friendly chatbot who always responds in the style of a pirate",
|
|
||||||
},
|
|
||||||
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
|
|
||||||
]
|
|
||||||
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
|
|
||||||
print(tokenizer.decode(tokenized_chat[0]))
|
|
||||||
```
|
|
||||||
سيؤدي هذا إلى إنتاج سلسلة نصية بتنسيق الإدخال الذي يتوقعه Zephyr.
|
|
||||||
|
|
||||||
```text
|
|
||||||
<|system|>
|
|
||||||
You are a friendly chatbot who always responds in the style of a pirate</s>
|
|
||||||
<|user|>
|
|
||||||
How many helicopters can a human eat in one sitting?</s>
|
|
||||||
<|assistant|>
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن بعد أن تم تنسيق الإدخال بشكل صحيح لـ Zephyr، يمكننا استخدام النموذج لإنشاء رد على سؤال المستخدم:
|
|
||||||
|
|
||||||
```python
|
|
||||||
outputs = model.generate(tokenized_chat, max_new_tokens=128)
|
|
||||||
print(tokenizer.decode(outputs[0]))
|
|
||||||
```
|
|
||||||
|
|
||||||
سيؤدي هذا إلى ما يلي:
|
|
||||||
|
|
||||||
```text
|
|
||||||
<|system|>
|
|
||||||
You are a friendly chatbot who always responds in the style of a pirate</s>
|
|
||||||
<|user|>
|
|
||||||
How many helicopters can a human eat in one sitting?</s>
|
|
||||||
<|assistant|>
|
|
||||||
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.
|
|
||||||
```
|
|
||||||
|
|
||||||
كان ذلك سهلاً بعد كل شيء !
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## هل هناك قنوات معالجة أوتوماتيكية للدردشة؟
|
|
||||||
|
|
||||||
نعم يوجد ! تدعم قنوات المعالجة توليد النصوص مدخلات الدردشة ، مما يُسهّل استخدام نماذج الدردشة . في الماضي ، كنا نستخدم فئة "ConversationalPipeline" المُخصّصة ، ولكن تم الآن إيقافها وتم دمج وظائفها في [`TextGenerationPipeline`]. دعونا نجرّب مثال Zephyr مرة أخرى ، ولكن هذه المرة باستخدام قناة معالجة:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import pipeline
|
|
||||||
|
|
||||||
pipe = pipeline("text-generation", "HuggingFaceH4/zephyr-7b-beta")
|
|
||||||
messages = [
|
|
||||||
{
|
|
||||||
"role": "system",
|
|
||||||
"content": "You are a friendly chatbot who always responds in the style of a pirate",
|
|
||||||
},
|
|
||||||
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
|
|
||||||
]
|
|
||||||
print(pipe(messages, max_new_tokens=128)[0]['generated_text'][-1]) # طباعة استجابة المساعد
|
|
||||||
```
|
|
||||||
|
|
||||||
```النص
|
|
||||||
{'role': 'assistant', 'content': "Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all."}
|
|
||||||
```
|
|
||||||
|
|
||||||
سيُراعي قناة المعالجة جميع تفاصيل تقسيم النص إلى رموز واستدعاء apply_chat_template نيابةً عنك - بمجرد أن يصبح لِدى النموذج قالب دردشة ، فكل ما تحتاج إلى القيام به هو تهيئة قناة معالجة وتمرير قائمة الرسائل إليها!
|
|
||||||
|
|
||||||
## ما هي "مطالبات التوليد"؟
|
|
||||||
|
|
||||||
قد تلاحظ أن طريقة `apply_chat_template` لها معامل `add_generation_prompt`. تخبر هذه المعامل القالب بإضافة رموز تشير إلى بداية رد البوت. على سبيل المثال، ضع في اعتبارك الدردشة التالية:
|
|
||||||
|
|
||||||
```python
|
|
||||||
messages = [
|
|
||||||
{"role": "user", "content": "Hi there!"},
|
|
||||||
{"role": "assistant", "content": "Nice to meet you!"},
|
|
||||||
{"role": "user", "content": "Can I ask a question?"}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
إليك كيف سيبدو ذلك بدون موجه توليد نصوص ، بالنسبة لنموذج يستخدم تنسيق "ChatML" القياسي :
|
|
||||||
|
|
||||||
```python
|
|
||||||
tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
|
|
||||||
"""<|im_start|>user
|
|
||||||
Hi there!<|im_end|>
|
|
||||||
<|im_start|>assistant
|
|
||||||
Nice to meet you!<|im_end|>
|
|
||||||
<|im_start|>user
|
|
||||||
Can I ask a question?<|im_end|>
|
|
||||||
"""
|
|
||||||
```
|
|
||||||
|
|
||||||
وهكذا يبدو الأمر **مع** مطالبة التوليد:
|
|
||||||
|
|
||||||
```python
|
|
||||||
tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
|
||||||
"""<|im_start|>user
|
|
||||||
Hi there!<|im_end|>
|
|
||||||
<|im_start|>assistant
|
|
||||||
Nice to meet you!<|im_end|>
|
|
||||||
<|im_start|>user
|
|
||||||
Can I ask a question?<|im_end|>
|
|
||||||
<|im_start|>assistant
|
|
||||||
"""
|
|
||||||
```
|
|
||||||
|
|
||||||
لاحظ أننا أضفنا هذه المرة الرموز التي تشير إلى بداية رد البوت. يضمن هذا أنه عندما يُولّد النموذج نصًا فسيكتب رد البوت بدلاً من القيام بشيء غير متوقع، مثل الاستمرار في رسالة المستخدم. تذكر، أن نماذج الدردشة لا تزال مجرد نماذج للغة - فهي مدربة على متابعة النصوص، والدردشة هي مجرد نوع خاص من النصوص بالنسبة لها! يجب توجيهها برموز تحكم مناسبة، حتى تعرف ما الذي يجب عليها فعله.
|
|
||||||
|
|
||||||
لا تتطلب جميع النماذج الرموز التحكمية لتوليد نصوص . بعض النماذج ، مثل LLaMA ، ليس لديها أي رموز خاصة قبل ردود البوت . في هذه الحالات ، لن يكون لمعامل `add_generation_prompt` أي تأثير. يعتمد التأثير الدقيق الذي تُحدثه `add_generation_prompt` على القالب المستخدم .
|
|
||||||
|
|
||||||
## ما وظيفة "continue_final_message"؟
|
|
||||||
|
|
||||||
عند تمرير قائمة من الرسائل إلى `apply_chat_template` أو `TextGenerationPipeline` ، يمكنك اختيار تنسيق المحادثة بحيث يواصل النموذج الرسالة الأخيرة في المحادثة بدلاً من بدء رسالة جديدة. يتم ذلك عن طريق إزالة أي رموز نهاية التسلسل التي تشير إلى نهاية الرسالة الأخيرة ، بحيث يقوم النموذج ببساطة بتمديد الرسالة الأخيرة عندما يبدأ في توليد النص . يُعد هذا أمرًا مفيدًا "لِمَلء بداية" رد النموذج مُسبقًا.
|
|
||||||
|
|
||||||
وهنا مثال:
|
|
||||||
```python
|
|
||||||
chat = [
|
|
||||||
{"role": "user", "content": "Can you format the answer in JSON?"},
|
|
||||||
{"role": "assistant", "content": '{"name": "'},
|
|
||||||
]
|
|
||||||
|
|
||||||
formatted_chat = tokenizer.apply_chat_template(chat, tokenize=True, return_dict=True, continue_final_message=True)
|
|
||||||
model.generate(**formatted_chat)
|
|
||||||
```
|
|
||||||
سيقوم النموذج بتوليد نص يكمل سلسلة JSON ، بدلاً من بدء رسالة جديدة . يمكن أن يكون هذا النهج مفيدًا جدًا لتحسين دقة اتباع النموذج للإرشادات عندما تعرف كيف تريد أن يبدأ ردوده .
|
|
||||||
.
|
|
||||||
|
|
||||||
نظرًا لأن `add_generation_prompt` تضيف الرموز التي تبدأ رسالة جديدة ، و `continue_final_message` تزيل أي رموز نهاية الرسالة من الرسالة الأخيرة ، فليس من المنطقي استخدامهما معًا . ونتيجة لذلك ، ستتلقّى خطأً إذا حاولت ذلك !
|
|
||||||
|
|
||||||
السلوك الافتراضي لِـ `TextGenerationPipeline` هو تعيين `add_generation_prompt=True` بحيث تبدأ رسالة جديدة . ومع ذلك ، إذا كانت الرسالة الأخيرة في المحادثة التي تم إدخالها لديها دور "assistant" ، فسوف تفترض أن هذه الرسالة هي "مَلء بداية" وتتحوّل إلى `continue_final_message=True` بدلاً من ذلك ، لأن مُعظم النماذج لا تدعم عدة رسائل متتالية للمساعد . يمكنك تجاوز هذا السلوك عن طريق تمرير معامل `continue_final_message` بشكل صريح عند استدعاء قناة المعالجة .
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## هل يمكنني استخدام قوالب الدردشة في التدريب؟
|
|
||||||
|
|
||||||
نعم ! تُعد هذه طريقة جيدة للتأكد من أن قالب الدردشة يتطابق مع الرموز التي يراها النموذج أثناء التدريب . نوصي بتطبيق قالب الدردشة كخطوة معالجة أولية لمجموعة بياناتك . بعد ذلك ، يمكنك ببساطة متابعة عملية التدريب كما هو الحال مع أي مهمة تدريب نماذج لغات أخرى . عند التدريب ، يجب أن تُعيّن عادةً `add_generation_prompt=False` ، لأنه لن تكون الرموز المُضافة لتحفيز رد المساعد مفيدة أثناء التدريب . دعونا نرى مثالاً :
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import AutoTokenizer
|
|
||||||
from datasets import Dataset
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
|
|
||||||
|
|
||||||
chat1 = [
|
|
||||||
{"role": "user", "content": "Which is bigger, the moon or the sun?"},
|
|
||||||
{"role": "assistant", "content": "The sun."}
|
|
||||||
]
|
|
||||||
chat2 = [
|
|
||||||
{"role": "user", "content": "Which is bigger, a virus or a bacterium?"},
|
|
||||||
{"role": "assistant", "content": "A bacterium."}
|
|
||||||
]
|
|
||||||
|
|
||||||
dataset = Dataset.from_dict({"chat": [chat1, chat2]})
|
|
||||||
dataset = dataset.map(lambda x: {"formatted_chat": tokenizer.apply_chat_template(x["chat"], tokenize=False, add_generation_prompt=False)})
|
|
||||||
print(dataset['formatted_chat'][0])
|
|
||||||
```
|
|
||||||
ونحصل على:
|
|
||||||
|
|
||||||
```text
|
|
||||||
<|user|>
|
|
||||||
Which is bigger, the moon or the sun?</s>
|
|
||||||
<|assistant|>
|
|
||||||
The sun.</s>
|
|
||||||
```
|
|
||||||
|
|
||||||
من هنا، استمر في التدريب كما تفعل مع مهمة نمذجة اللغة القياسية، باستخدام عمود `formatted_chat`.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
بشكل افتراضي ، تضيف بعض *tokenizers* رموزًا خاصة مثل `<bos>` و `<eos>` إلى النص الذي تقوم بتقسيمه إلى رموز. يجب أن تتضمن قوالب المحادثة بالفعل جميع الرموز الخاصة التي تحتاجها ، وبالتالي فإن الرموز الخاصة الإضافية ستكون غالبًا غير صحيحة أو مُكررة ، مما سيؤثر سلبًا على أداء النموذج .
|
|
||||||
|
|
||||||
لذلك ، إذا قمت بتنسيق النص باستخدام `apply_chat_template(tokenize=False)` ، فيجب تعيين المعامل `add_special_tokens=False` عندما تقوم بتقسيم ذلك النص إلى رموز لاحقًا . إذا كنت تستخدم `apply_chat_template(tokenize=True)` ، فلن تحتاج إلى القلق بشأن ذلك !
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## متقدّم: مدخلات إضافية لِقوالب الدردشة
|
|
||||||
|
|
||||||
|
|
||||||
المعامل الوحيدة التي تتطلبها طريقة `apply_chat_template` هي `messages`. ومع ذلك، يمكنك تمرير أي معامل ككلمة مفتاحية إلى `apply_chat_template` وستكون متاحة داخل القالب. يمنحك هذا الكثير من المرونة لاستخدام قوالب الدردشة للعديد من الأشياء. لا توجد قيود على أسماء هذه المعامﻻت أو تنسيقاتها - يمكنك تمرير سلاسل نصية أو قوائم أو قواميس أو أي شيء آخر تريده.
|
|
||||||
|
|
||||||
ومع ذلك، هناك بعض الحالات الشائعة لاستخدام هذه المعامﻻت الإضافية، مثل تمرير أدوات لاستدعاء الوظائف، أو المستندات لإنشاء النصوص المُعزّزة بالاسترجاع. في هذه الحالات الشائعة، لدينا بعض التوصيات المُحدّدة حول أسماء هذه المعامﻻت وتنسيقاتها، والتي يتم وصفها في الأقسام التالية. نشجع مطوّري النماذج على جعل قوالب الدردشة الخاصة بهم متوافقة مع هذا التنسيق، لتسهيل نقل التعليمات البرمجية لاستدعاء الأدوات بين النماذج.
|
|
||||||
|
|
||||||
## متقدم: استخدام الأداة / استدعاء الدالة
|
|
||||||
|
|
||||||
يمكن لنماذج "استخدام الأداة" اختيار استدعاء الدوال كأدوات خارجية قبل توليد الإجابة. عند تمرير الأدوات إلى نموذج استخدام الأدوات، يمكنك ببساطة تمرير قائمة من الوظائف إلى معامل `tools`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
def current_time():
|
|
||||||
"""Get the current local time as a string."""
|
|
||||||
return str(datetime.now())
|
|
||||||
|
|
||||||
def multiply(a: float, b: float):
|
|
||||||
"""
|
|
||||||
A function that multiplies two numbers
|
|
||||||
|
|
||||||
Args:
|
|
||||||
a: The first number to multiply
|
|
||||||
b: The second number to multiply
|
|
||||||
"""
|
|
||||||
return a * b
|
|
||||||
|
|
||||||
tools = [current_time, multiply]
|
|
||||||
|
|
||||||
model_input = tokenizer.apply_chat_template(
|
|
||||||
messages,
|
|
||||||
tools=tools
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
لكي يعمل هذا بشكل صحيح، يجب عليك كتابة وظائفك بالتنسيق السابق، حتى يمكن تحليلها بشكل صحيح كأدوات. على وجه التحديد، يجب عليك اتباع هذه القواعد:
|
|
||||||
|
|
||||||
- يجب أن يكون للدالة اسم وصفي.
|
|
||||||
- يجب أن يكون لكل معامل نوع للتلميح.
|
|
||||||
- يجب أن تحتوي الدالة على سلسلة مستندية بتنسيق Google القياسي (بمعنى وصف الدالة الأولي متبوعًا بكتلة `Args:` التي تصف المعاﻻت، ما لم تكن الدالة لا تحتوي على أي معامﻻت.
|
|
||||||
- لا تقم بتضمين الأنواع في كتلة `Args:` . بعبارة أخرى، اكتب `a: The first number to multiply`، وليس `a (int): The first number to multiply`. يجب أن تذهب تلميحات الأنواع في رأس الدالة بدلاً من ذلك.
|
|
||||||
- يمكن أن يكون للدالة نوع للإرجاع ومربع `Returns:` في السلسلة. ومع ذلك، فهذه اختيارية لأن معظم نماذج استخدام الأدوات تتجاهلها.
|
|
||||||
|
|
||||||
### تمرير نتائج الأداة إلى النموذج
|
|
||||||
|
|
||||||
يكفي الكود السابقة لسرد الأدوات المتاحة لنموذجك، ولكن ماذا يحدث إذا أراد النموذج استخدام واحدة منها؟ إذا حدث ذلك، فيجب عليك:
|
|
||||||
|
|
||||||
1. تحليل مخرجات النموذج للحصول على اسم (أسماء) الأدوات ومعامﻻتها.
|
|
||||||
2. أضف استدعاء (استدعاءات) النموذج لِلأدوات إلى المحادثة.
|
|
||||||
3. استدعاء الدالة (الدالات) المقابلة بتلك المعامﻻت.
|
|
||||||
4. أضف النتيجة (النتائج) إلى المحادثة
|
|
||||||
|
|
||||||
### مثال كامل على استخدام الأداة
|
|
||||||
|
|
||||||
|
|
||||||
سنستعرض مثالاً على استخدام الأدوات خطوة بخطوة . في هذا المثال ، سنستخدم نموذج `Hermes-2-Pro` بحجم 8 مليارات معامل ، نظرًا لأنه أحد أعلى نماذج استخدام الأدوات أداءً في فئة حجمه وقت كتابة هذا النص . إذا كان لديك الذاكرة الكافية ، فيمكنك النظر في استخدام نموذج أكبر بدلاً من ذلك مثل `Command-R` أو `Mixtral-8x22B` ، وكلاهما يدعم استخدام الأدوات ويوفر أداءً أقوى .
|
|
||||||
|
|
||||||
|
|
||||||
أولاً ، لنقم بتحميل نموذجنا و tokenizer الخاص بنا:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
||||||
|
|
||||||
checkpoint = "NousResearch/Hermes-2-Pro-Llama-3-8B"
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(checkpoint, torch_dtype=torch.bfloat16, device_map="auto")
|
|
||||||
|
|
||||||
```python
|
|
||||||
messages = [
|
|
||||||
{"role": "system", "content": "You are a bot that responds to weather queries. You should reply with the unit used in the queried location."},
|
|
||||||
{"role": "user", "content": "Hey, what's the temperature in Paris right now?"}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن، لنقم نطبق قالب الدردشة ونولد رد:
|
|
||||||
|
|
||||||
```python
|
|
||||||
inputs = tokenizer.apply_chat_template(messages, chat_template="tool_use", tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
|
|
||||||
inputs = {k: v.to(model.device) for k, v in inputs.items()}
|
|
||||||
out = model.generate(**inputs, max_new_tokens=128)
|
|
||||||
print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
|
|
||||||
```
|
|
||||||
|
|
||||||
ونحصل على:
|
|
||||||
|
|
||||||
```text
|
|
||||||
<tool_call>
|
|
||||||
{"arguments": {"location": "Paris, France", "unit": "celsius"}, "name": "get_current_temperature"}
|
|
||||||
</tool_call><|im_end|>
|
|
||||||
```
|
|
||||||
|
|
||||||
لقد قام النموذج باستدعاء الدالة مع معامﻻت صحيحة، بالصيغة التي طلبتها توثيق الدالة. لقد استنتج أننا نشير على الأرجح إلى باريس في فرنسا، وتذكر أنه بكونها موطن وحدات القياس الدولية، يجب عرض درجة الحرارة في فرنسا بالدرجة المئوية.
|
|
||||||
|
|
||||||
دعنا نضيف استدعاء الأداة الخاص بالنموذج إلى المحادثة. لاحظ أننا نولد معرف استدعاء أداة عشوائيًا هنا. لا تستخدم جميع النماذج هذه المعرفات، ولكنها تسمح للنماذج بإصدار عدة استدعاءات للأدوات في نفس الوقت وتتبع الاستجابة المقابلة لكل استدعاء. يمكنك توليد هذه المعرفات بأي طريقة تريدها، ولكن يجب أن تكون فريدة داخل كل محادثة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
tool_call_id = "vAHdf3" # Random ID, should be unique for each tool call
|
|
||||||
tool_call = {"name": "get_current_temperature", "arguments": {"location": "Paris, France", "unit": "celsius"}}
|
|
||||||
messages.append({"role": "assistant", "tool_calls": [{"id": tool_call_id, "type": "function", "function": tool_call}]})
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن بعد أن أضفنا استدعاء الأداة إلى المحادثة، يمكننا استدعاء الدالة وإضافة النتيجة إلى المحادثة. نظرًا لأننا نستخدم دالة وهمية لهذا المثال والتي تعيد دائمًا 22.0، فيمكننا ببساطة إضافة تلك النتيجة مباشرةً. لاحظ معرف استدعاء الأداة - يجب أن يتطابق مع المعرف المستخدم في استدعاء الأداة أعلاه.
|
|
||||||
|
|
||||||
```python
|
|
||||||
messages.append({"role": "tool", "tool_call_id": tool_call_id, "name": "get_current_temperature", "content": "22.0"})
|
|
||||||
```
|
|
||||||
|
|
||||||
أخيرًا، دعنا نجعل المساعد يقرأ مخرجات الدالة ويكمل الدردشة مع المستخدم:
|
|
||||||
|
|
||||||
```python
|
|
||||||
inputs = tokenizer.apply_chat_template(messages, chat_template="tool_use", tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
|
|
||||||
inputs = {k: v.to(model.device) for k, v in inputs.items()}
|
|
||||||
out = model.generate(**inputs, max_new_tokens=128)
|
|
||||||
print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
|
|
||||||
```
|
|
||||||
|
|
||||||
ونحصل على:
|
|
||||||
|
|
||||||
```text
|
|
||||||
The current temperature in Paris, France is 22.0 ° Celsius.<|im_end|>
|
|
||||||
```
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
لا تستخدم جميع نماذج استخدام الأدوات جميع ميزات استدعاء الأدوات الموضحة أعلاه. يستخدم البعض معرفات استدعاء الأدوات، بينما يستخدم البعض الآخر ببساطة اسم الدالة ويقارن استدعاءات الأدوات بالنتائج باستخدام الترتيب، وهناك عدة نماذج لا تستخدم أيًا منهما ولا تصدر سوى استدعاء أداة واحد في كل مرة لتجنب الارتباك. إذا كنت تريد أن يكون رمزك متوافقًا مع أكبر عدد ممكن من النماذج، فإننا نوصي بهيكلة استدعاءات الأدوات الخاصة بك كما هو موضح هنا، وإعادة نتائج الأدوات بالترتيب الذي أصدرها النموذج. يجب أن تتعامل قوالب الدردشة على كل نموذج مع الباقي.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
### فهم مخططات الأدوات
|
|
||||||
|
|
||||||
يتم تحويل كل دالة تقوم بتمريرها إلى معامل `tools` في دالة `apply_chat_template` إلى [مخطط JSON](https://json-schema.org/learn/getting-started-step-by-step). يتم بعد ذلك تمرير هذه المخططات إلى قالب الدردشة النموذج. وبعبارة أخرى، فإن نماذج استخدام الأدوات لا ترى دوالك مباشرة، ولا ترى مطلقًا الكود الموجود بداخلها. ما يهمها هو**تعريفات** الدوال و**المعامﻻت** التي تحتاج إلى تمريرها إليها - فهي تهتم بما تفعله الأدوات وكيفية استخدامها، وليس بكيفية عملها! يقع على عاتقك قراءة مخرجاتها، والكشف عما إذا كانت قد طلبت استخدام أداة، وتمرير المعامﻻت إلى دالة الأداة، وإرجاع الرد في الدردشة.
|
|
||||||
|
|
||||||
يجب أن يكون إنشاء مخططات JSON لتمريرها إلى القالب تلقائيًا وغير مرئي طالما أن دوالك تتبع المواصفات الموضحة أعلاه، ولكن إذا واجهت مشكلات، أو إذا كنت تريد ببساطة مزيدًا من التحكم في التحويل، فيمكنك التعامل مع التحويل يدويًا. فيما يلي مثال على تحويل مخطط يدوي:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers.utils import get_json_schema
|
|
||||||
|
|
||||||
def multiply(a: float, b: float):
|
|
||||||
"""
|
|
||||||
A function that multiplies two numbers
|
|
||||||
|
|
||||||
Args:
|
|
||||||
a: The first number to multiply
|
|
||||||
b: The second number to multiply
|
|
||||||
"""
|
|
||||||
return a * b
|
|
||||||
|
|
||||||
schema = get_json_schema(multiply)
|
|
||||||
print(schema)
|
|
||||||
```
|
|
||||||
|
|
||||||
سيؤدي هذا إلى ما يلي:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "multiply",
|
|
||||||
"description": "A function that multiplies two numbers",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"a": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "The first number to multiply"
|
|
||||||
},
|
|
||||||
"b": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "The second number to multiply"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["a", "b"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
إذا كنت ترغب في ذلك، يمكنك تحرير هذه المخططات، أو حتى كتابتها من البداية بنفسك دون استخدام `get_json_schema` على الإطلاق. يمكن تمرير مخططات JSON مباشرةً إلى معامل `tools` في `apply_chat_template` - يمنحك هذا الكثير من القوة لتعريف مخططات دقيقة لوظائف أكثر تعقيدًا. ولكن كن حذرًا - كلما زاد تعقيد مخططاتك، زاد احتمال ارتباك النموذج عند التعامل معها! نوصي بتوقيعات دوال بسيطة حيثما أمكن، مع تقليل المعامﻻت (وخاصة المعامﻻت المعقدة والمتداخلة) إلى الحد الأدنى.
|
|
||||||
|
|
||||||
فيما يلي مثال على تعريف المخططات يدويًا، وتمريرها مباشرةً إلى `apply_chat_template`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
# A simple function that takes no arguments
|
|
||||||
current_time = {
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "current_time",
|
|
||||||
"description": "Get the current local time as a string.",
|
|
||||||
"parameters": {
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# A more complete function that takes two numerical arguments
|
|
||||||
multiply = {
|
|
||||||
'type': 'function',
|
|
||||||
'function': {
|
|
||||||
'name': 'multiply',
|
|
||||||
'description': 'A function that multiplies two numbers',
|
|
||||||
'parameters': {
|
|
||||||
'type': 'object',
|
|
||||||
'properties': {
|
|
||||||
'a': {
|
|
||||||
'type': 'number',
|
|
||||||
'description': 'The first number to multiply'
|
|
||||||
},
|
|
||||||
'b': {
|
|
||||||
'type': 'number', 'description': 'The second number to multiply'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'required': ['a', 'b']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model_input = tokenizer.apply_chat_template(
|
|
||||||
messages,
|
|
||||||
tools = [current_time, multiply]
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## متقدم: توليد قائم على الاسترجاع
|
|
||||||
يمكن لنماذج اللغة الكبيرة من نوع "توليد قائم على الاسترجاع" أو "RAG" البحث في مجموعة نصوص عن معلومات قبل الرد على الاستعلام. يسمح هذا للنماذج بتوسيع قاعدة معارفها بشكل كبير إلى ما هو أبعد من حجم سياقها المحدود. توصيتنا لنماذج RAG هي أن يقبل قالبها وسيطة `documents`. يجب أن تكون هذه قائمة من المستندات، حيث يكون كل "مستند" عبارة عن قاموس واحد بمفاتيح `title` و `contents`، وكلاهما سلاسل نصية. نظرًا لأن هذا التنسيق أبسط بكثير من مخططات JSON المستخدمة للأدوات، فلا توجد حاجة إلى دوال مساعدة.
|
|
||||||
|
|
||||||
فيما يلي مثال على قالب RAG بالفعل:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
|
||||||
|
|
||||||
# تحميل النموذج والمجزىء اللغوي
|
|
||||||
model_id = "CohereForAI/c4ai-command-r-v01-4bit"
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto")
|
|
||||||
device = model.device # الحصول على الجهاز الذي تم تحميل النموذج عليه
|
|
||||||
|
|
||||||
# تعريف مُدخلات المحادثة
|
|
||||||
conversation = [
|
|
||||||
{"role": "user", "content": "What has Man always dreamed of?"}
|
|
||||||
]
|
|
||||||
|
|
||||||
# تعريف المستندات لتوليد قائم على الاسترجاع
|
|
||||||
documents = [
|
|
||||||
{
|
|
||||||
"title": "The Moon: Our Age-Old Foe",
|
|
||||||
"text": "Man has always dreamed of destroying the moon. In this essay, I shall..."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "The Sun: Our Age-Old Friend",
|
|
||||||
"text": "Although often underappreciated, the sun provides several notable benefits..."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
# معالجة المحادثة والمستندات باستخدام قالب RAG، وإرجاع موترات PyTorch.
|
|
||||||
input_ids = tokenizer.apply_chat_template(
|
|
||||||
conversation=conversation,
|
|
||||||
documents=documents,
|
|
||||||
chat_template="rag",
|
|
||||||
tokenize=True,
|
|
||||||
add_generation_prompt=True,
|
|
||||||
return_tensors="pt").to(device)
|
|
||||||
|
|
||||||
# توليد الرد
|
|
||||||
gen_tokens = model.generate(
|
|
||||||
input_ids,
|
|
||||||
max_new_tokens=100,
|
|
||||||
do_sample=True,
|
|
||||||
temperature=0.3,
|
|
||||||
)
|
|
||||||
|
|
||||||
# فك تشفير النص المُوَلّد وطباعته
|
|
||||||
gen_text = tokenizer.decode(gen_tokens[0])
|
|
||||||
print(gen_text)
|
|
||||||
```
|
|
||||||
إن مُدخل documents للتوليد القائم على الاسترجاع غير مدعوم على نطاق واسع، والعديد من النماذج لديها قوالب دردشة تتجاهل هذا المُدخل ببساطة.
|
|
||||||
|
|
||||||
للتحقق مما إذا كان النموذج يدعم مُدخل `documents`، يمكنك قراءة بطاقة النموذج الخاصة به، أو `print(tokenizer.chat_template)` لمعرفة ما إذا كان مفتاح `documents` مستخدمًا في أي مكان.
|
|
||||||
<Tip>
|
|
||||||
ومع ذلك، فإن أحد فئات النماذج التي تدعمه هي [Command-R](https://huggingface.co/CohereForAI/c4ai-command-r-08-2024) و [Command-R+](https://huggingface.co/CohereForAI/c4ai-command-r-pluse-08-2024) من Cohere، من خلال قالب الدردشة rag الخاص بهم. يمكنك رؤية أمثلة إضافية على التوليد باستخدام هذه الميزة في بطاقات النموذج الخاصة بهم.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## متقدم: كيف تعمل قوالب الدردشة؟
|
|
||||||
يتم تخزين قالب الدردشة للنموذج في الخاصية `tokenizer.chat_template`. إذا لم يتم تعيين قالب دردشة، فسيتم استخدام القالب الافتراضي لفئة النموذج هذه بدلاً من ذلك. دعونا نلقي نظرة على قالب دردشة `Zephyr`، ولكن لاحظ أن هذا القالب مُبسّط قليلاً عن القالب الفعلي!
|
|
||||||
|
|
||||||
```
|
|
||||||
{%- for message in messages %}
|
|
||||||
{{- '<|' + message['role'] + |>\n' }}
|
|
||||||
{{- message['content'] + eos_token }}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- if add_generation_prompt %}
|
|
||||||
{{- '<|assistant|>\n' }}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
إذا لم تكن قد رأيت أحد هذه القوالب من قبل، فهذا [قالب Jinja](https://jinja.palletsprojects.com/en/3.1.x/templates/) .Jinja هي لغة قوالب تسمح لك بكتابة تعليمات برمجية بسيطة تُوَلّد نصًا. من نواحٍ عديدة، يُشبه الرمز والتركيب للغة Python. أما في لغة Python، سيبدو هذا القالب كما يلي:
|
|
||||||
|
|
||||||
```python
|
|
||||||
for message in messages:
|
|
||||||
print(f'<|{message["role"]}|>')
|
|
||||||
print(message['content'] + eos_token)
|
|
||||||
if add_generation_prompt:
|
|
||||||
print('<|assistant|>')
|
|
||||||
```
|
|
||||||
يقوم القالب بثلاثة أشياء بشكل فعال:
|
|
||||||
|
|
||||||
- لكل رسالة، بطبع الدور مُحاطًا بـ `<|` و `|>`، مثل `<|user|>` أو `<|assistant|>`.
|
|
||||||
- بعد ذلك، يطبع محتوى الرسالة، متبوعًا برمز نهاية التسلسل `eos_token` .
|
|
||||||
- أخيرًا، إذا تم تعيين `add_generation_prompt` ، يطبع الرمز المساعد، حتى يعرف النموذج أنه يجب أن يبدأ في توليد استجابة المساعد.
|
|
||||||
|
|
||||||
هذا قالب بسيط جدًا، لكن Jinja تمنحك الكثير من المرونة للقيام بأشياء أكثر تعقيدًا! دعونا نرى قالب Jinja يُمكنه تنسيق المُدخلات بطريقة تُشبه الطريقة التي تُنسّق بها LLaMA مُدخلاتها (لاحظ أن قالب LLaMA الحقيقي يتضمن معالجة لرسائل النظام الافتراضية ومعالجة رسائل النظام بشكل مختلف قليلاً بشكل عام - لا تستخدم هذا القالب في التعليمات البرمجية الفعلية الخاصة بك!)
|
|
||||||
```
|
|
||||||
{%- for message in messages %}
|
|
||||||
{%- if message['role'] == 'user' %}
|
|
||||||
{{- bos_token + '[INST] ' + message['content'] + ' [/INST]' }}
|
|
||||||
{%- elif message['role'] == 'system' %}
|
|
||||||
{{- '<<SYS>>\\n' + message['content'] + '\\n<</SYS>>\\n\\n' }}
|
|
||||||
{%- elif message['role'] == 'assistant' %}
|
|
||||||
{{- ' ' + message['content'] + ' ' + eos_token }}
|
|
||||||
{%- endif %}
|
|
||||||
{%- endfor %}
|
|
||||||
```
|
|
||||||
نأمل أنه إذا حدقت في هذا لفترة قصيرة، يمكنك أن ترى ما يفعله هذا القالب - فهو يُضيف رموزًا مُحددة مثل `[INST]` و `[/INST]` بناءً على دور كل رسالة. يمكن تمييز رسائل المستخدم والمساعد والنظام بوضوح للنموذج بسبب الرموز التي تُحيط بها.
|
|
||||||
|
|
||||||
## متقدم: إضافة وتعديل قوالب الدردشة
|
|
||||||
|
|
||||||
### كيف أنشئ قالب دردشة؟
|
|
||||||
ببساطة، اكتب قالب Jinja واضبط `tokenizer.chat_template`. قد تجد أنه من الأسهل البدء بقالب موجود من نموذج آخر وتحريره ببساطة ليناسب احتياجاتك! على سبيل المثال، يمكننا أن نأخذ قالب LLaMA أعلاه ونضيف `[ASST]` و `[/ASST]` إلى رسائل المساعد:
|
|
||||||
|
|
||||||
```
|
|
||||||
{%- for message in messages %}
|
|
||||||
{%- if message['role'] == 'user' %}
|
|
||||||
{{- bos_token + '[INST] ' + message['content'].strip() + ' [/INST]' }}
|
|
||||||
{%- elif message['role'] == 'system' %}
|
|
||||||
{{- '<<SYS>>\\n' + message['content'].strip() + '\\n<</SYS>>\\n\\n' }}
|
|
||||||
{%- elif message['role'] == 'assistant' %}
|
|
||||||
{{- '[ASST] ' + message['content'] + ' [/ASST]' + eos_token }}
|
|
||||||
{%- endif %}
|
|
||||||
{%- endfor %}
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن، اضبط ببساطة الخاصية `tokenizer.chat_template`. في المرة القادمة التي تستخدم فيها [`~PreTrainedTokenizer.apply_chat_template`] ، سيستخدم القالب الجديد الخاص بك! سيتم حفظ هذه الخاصية في ملف `tokenizer_config.json`، حتى تتمكن من استخدام [`~utils.PushToHubMixin.push_to_hub`] لتحميل قالبك الجديد إلى Hub والتأكد من أن الجميع يستخدم القالب الصحيح لنموذجك!
|
|
||||||
|
|
||||||
```python
|
|
||||||
template = tokenizer.chat_template
|
|
||||||
template = template.replace("SYS", "SYSTEM") # تغيير رمز النظام
|
|
||||||
tokenizer.chat_template = template # تعيين القالب الجديد
|
|
||||||
tokenizer.push_to_hub("model_name") # تحميل القالب الجديد إلى Hub!
|
|
||||||
```
|
|
||||||
|
|
||||||
يتم استدعاء الدالة [`~PreTrainedTokenizer.apply_chat_template`] الذي نستخدم قالب الدردشة الخاص بك بواسطة فئة [`TextGenerationPipeline`] لذلك بمجرد تعيين قالب الدردشة الصحيح، سيصبح نموذجك متوافقًا تلقائيًا مع [`TextGenerationPipeline`].
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
إذا كنت تُجري ضبطًا دقيقًا لنموذج للدردشة، بالإضافة إلى تعيين قالب دردشة، فربما يجب عليك إضافة أي رموز تحكم دردشة جديدة كرموز خاصة في المجزىء اللغوي. لا يتم تقسيم الرموز الخاصة أبدًا، مما يضمن معالجة رموز التحكم الخاصة بك دائمًا كرموز فردية بدلاً من تجزئتها إلى أجزاء. يجب عليك أيضًا تعيين خاصية `eos_token` للمجزىء اللغوي إلى الرمز الذي يُشير إلى نهاية توليدات المساعد في قالبك. سيضمن هذا أن أدوات توليد النصوص يمكنها تحديد وقت إيقاف توليد النص بشكل صحيح.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
### لماذا تحتوي بعض النماذج على قوالب متعددة؟
|
|
||||||
تستخدم بعض النماذج قوالب مختلفة لحالات استخدام مختلفة. على سبيل المثال، قد تستخدم قالبًا واحدًا للدردشة العادية وآخر لاستخدام الأدوات، أو التوليد القائم على الاسترجاع. في هذه الحالات، تكون `tokenizer.chat_template` قاموسًا. يمكن أن يتسبب هذا في بعض الارتباك، وحيثما أمكن، نوصي باستخدام قالب واحد لجميع حالات الاستخدام. يمكنك استخدام عبارات Jinja مثل `if tools is defined` وتعريفات `{% macro %}` لتضمين مسارات تعليمات برمجية متعددة بسهولة في قالب واحد.
|
|
||||||
|
|
||||||
عندما يحتوي المعالج اللغوي على قوالب متعددة، ستكون `tokenizer.chat_template dict`، حيث يكون كل مفتاح هو اسم قالب. يحتوي أسلوب `apply_chat_template` على معالجة خاصة لأسماء قوالب مُعينة: على وجه التحديد، سيبحث عن قالب باسم `default` في معظم الحالات، وسيُثير خطأً إذا لم يتمكن من العثور على واحد. ومع ذلك، إذا كان هناك قالب باسم `tool_use` عندما قام المستخدم بتمرير وسيطة `tools`، فسيستخدم هذا القالب بدلاً من ذلك. للوصول إلى قوالب بأسماء أخرى، مرر اسم القالب الذي تُريده إلى وسيطة `chat_template` لـ `apply_chat_template()`.
|
|
||||||
|
|
||||||
نجد أن هذا قد يكون مُربكًا بعض الشيء للمستخدمين - لذلك إذا كنت تكتب قالبًا بنفسك، فننصحك بمحاولة وضعه كله في قالب واحد حيثما أمكن!
|
|
||||||
|
|
||||||
## ما القالب الذي يجب أن أستخدمه؟
|
|
||||||
|
|
||||||
عند تعيين قالب لنموذج تم تدريبه بالفعل على الدردشة، يجب التأكد من أن القالب يتطابق تمامًا مع تنسيق الرسالة الذي شاهده النموذج أثناء التدريب، وإلا فمن المحتمل أن تواجه تدهورًا في الأداء. هذا صحيح حتى إذا كنت تدرب النموذج بشكل إضافي - فمن المحتمل أن تحصل على أفضل أداء إذا قمت بإبقاء رموز الدردشة ثابتة. يُشبه هذا إلى حد كبير عملية التجزئة - فأنت تحصل بشكل عام على أفضل أداء للاستدلال أو الضبط الدقيق عندما تتطابق بدقة مع التجزئة المستخدمة أثناء التدريب.
|
|
||||||
|
|
||||||
من ناحية أخرى، إذا كنت تُدرّب نموذجًا من البداية، أو تقوم بضبط دقيق لنموذج لغة أساسي للدردشة، لديك حرية اختيار قالب مناسب! تتمتع LLMs بالذكاء الكافي للتعامل مع العديد من تنسيقات الإدخال المختلفة. أحد الخيارات الشائعة هو تنسيق "ChatML"، وهو خيار جيد ومرن للعديد من حالات الاستخدام. يبدو كالتالي:
|
|
||||||
|
|
||||||
```
|
|
||||||
{%- for message in messages %}
|
|
||||||
{{- '<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n' }}
|
|
||||||
{%- endfor %}
|
|
||||||
```
|
|
||||||
|
|
||||||
إذا أعجبك هذا، فإليك نسخة جاهزة لوضعها في كودك. يتضمن الخط المفرد أيضًا دعمًا مفيدًا [لإرشادات التوليد](#what-are-generation-prompts)، ولكن لاحظ أنه لا يضيف رموز BOS أو EOS! إذا كان نموذجك يتوقع هذه الرموز، فلن يتم إضافتها تلقائيًا بواسطة "apply_chat_template" - بمعنى آخر، سيتم تجزئة النص باستخدام "add_special_tokens=False". هذا لتجنب التعارضات المحتملة بين القالب ومنطق "add_special_tokens". إذا كان نموذجك يتوقع رموزًا خاصة، فتأكد من إضافتها إلى القالب!
|
|
||||||
|
|
||||||
```python
|
|
||||||
tokenizer.chat_template = "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}"
|
|
||||||
```
|
|
||||||
|
|
||||||
يُحيط هذا القالب كل رسالة بين الرمزين "<|im_start|>" و "<|im_end|>"، ويكتب ببساطة الدور كسلسلة نصية، مما يسمح بالمرونة في الأدوار التي تتدرب عليها. يبدو الناتج كما يلي:
|
|
||||||
|
|
||||||
```text
|
|
||||||
<|im_start|>system
|
|
||||||
You are a helpful chatbot that will do its best not to say anything so stupid that people tweet about it.<|im_end|>
|
|
||||||
<|im_start|>user
|
|
||||||
How are you?<|im_end|>
|
|
||||||
<|im_start|>assistant
|
|
||||||
I'm doing great!<|im_end|>
|
|
||||||
```
|
|
||||||
|
|
||||||
تعد أدوار "user" و "system" و "assistant" هي الأدوار القياسية للدردشة، ونوصي باستخدامها عندما يكون ذلك منطقيًا، خاصة إذا كنت تريد أن يعمل نموذجك بشكل جيد مع [`TextGenerationPipeline`]. ومع ذلك، فأنت لست مقيدًا بهذه الأدوار - فإن القوالب مرنة للغاية، ويمكن أن تكون أي سلسلة نصية دورًا.
|
|
||||||
|
|
||||||
|
|
||||||
## أريد إضافة بعض قوالب الدردشة! كيف أبدأ؟
|
|
||||||
|
|
||||||
إذا كان لديك أي نماذج دردشة، فيجب عليك تعيين الخاصية "tokenizer.chat_template" الخاصة بها واختبارها باستخدام [`~PreTrainedTokenizer.apply_chat_template`]، ثم رفع المجزىء اللغوي المُحدّث إلى Hub. ينطبق هذا حتى إذا لم تكن مالك النموذج - إذا كنت تستخدم نموذجًا بقالب دردشة فارغ، أو لا يزال يستخدم قالب الفئة الافتراضية، فيرجى فتح [طلب سحب](https://huggingface.co/docs/hub/repositories-pull-requests-discussions) إلى مستودع النموذج حتى يمكن تعيين الخاصية بشكل صحيح!
|
|
||||||
|
|
||||||
بمجرد تعيين الخاصية، هذا كل شيء، لقد انتهيت! ستعمل "tokenizer.apply_chat_template" الآن بشكل صحيح لهذا النموذج، مما يعني أنها مدعومة أيضًا بشكل تلقائي في أماكن مثل "TextGenerationPipeline"!
|
|
||||||
|
|
||||||
من خلال ضمان امتلاك النماذج لهذه الخاصية، يُمكننا التأكد من أن المجتمع بأكمله يستخدم القوة الكاملة للنماذج مفتوحة المصدر. لقد كانت عدم تطابق التنسيق تطارد المجال وأضرت الأداء بصمت لفترة طويلة جدًا - لقد حان الوقت لوضع حد لها!
|
|
||||||
|
|
||||||
## متقدم: نصائح لكتابة القوالب
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
أسهل طريقة للبدء في كتابة قوالب Jinja هي إلقاء نظرة على بعض القوالب الموجودة. يمكنك استخدام `print(tokenizer.chat_template)` لأي نموذج دردشة لمعرفة القالب الذي يستخدمه. بشكل عام، تحتوي النماذج التي تدعم استخدام الأدوات على قوالب أكثر تعقيدًا بكثير من النماذج الأخرى - لذلك عندما تبدأ للتو، فمن المحتمل أنها مثال سيئ للتعلم منه! يمكنك أيضًا إلقاء نظرة على [وثائق Jinja](https://jinja.palletsprojects.com/en/3.1.x/templates/#synopsis) للحصول على تفاصيل حول تنسيق Jinja العام وتركيبه.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
تُطابق قوالب Jinja في `transformers` قوالب Jinja في أي مكان آخر. الشيء الرئيسي الذي يجب معرفته هو أن سجل الدردشة سيكون متاحًا داخل قالبك كمتغير يسمى `messages`. ستتمكن من الوصول إلى `messages` في قالبك تمامًا كما يمكنك في Python، مما يعني أنه يمكنك التكرار خلاله باستخدام `{% for message in messages %}` أو الوصول إلى رسائل فردية باستخدام `{{ messages[0] }}`، على سبيل المثال.
|
|
||||||
|
|
||||||
يمكنك أيضًا استخدام النصائح التالية لكتابة قوالب Jinja نظيفة وفعالة:
|
|
||||||
|
|
||||||
### إقتطاع المسافات الفارغة
|
|
||||||
|
|
||||||
بشكل افتراضي، ستطبع Jinja أي مسافات فارغة تأتي قبل أو بعد كتلة. يمكن أن يكون هذا مشكلة لقوالب الدردشة، والتي تريد عادةً أن تكون دقيقة جدًا مع المسافات! لتجنب ذلك، نوصي بشدة بكتابة قوالبك على النحو التالي:
|
|
||||||
|
|
||||||
```
|
|
||||||
{%- for message in messages %}
|
|
||||||
{{- message['role'] + message['content'] }}
|
|
||||||
{%- endfor %}
|
|
||||||
```
|
|
||||||
|
|
||||||
بدلاً من ذلك:
|
|
||||||
|
|
||||||
```
|
|
||||||
{% for message in messages %}
|
|
||||||
{{ message['role'] + message['content'] }}
|
|
||||||
{% endfor %}
|
|
||||||
```
|
|
||||||
|
|
||||||
سيؤدي إضافة "-" إلى إزالة أي مسافات تأتي قبل الكتلة. يبدو المثال الثاني عادية، ولكن قد يتم تضمين السطر الجديد والمسافة البادئة في المخرجات، وهو على الأرجح ليس ما تُريده!
|
|
||||||
|
|
||||||
|
|
||||||
### المتغيرات الخاصة
|
|
||||||
|
|
||||||
داخل قالبك، سيكون لديك حق الوصول إلى العديد من المتغيرات الخاصة. أهمها هو `messages`، والذي يحتوي على سجل الدردشة كقائمة من قواميس الرسائل. ومع ذلك، هناك العديد من المتغيرات الأخرى. لن يتم استخدام كل متغير في كل قالب. المتغيرات الأكثر شيوعًا هي:
|
|
||||||
|
|
||||||
- `tools` تحتوي على قائمة بالأدوات بتنسيق مخطط JSON. ستكون `None` أو غير مُعرّفة إذا لم يتم تمرير أي أدوات.
|
|
||||||
- `documents` تحتوي على قائمة من المستندات بالتنسيق `{"title": "العنوان", "contents": "المحتويات"}`، تُستخدم للتوليد المُعزز بالاسترجاع. ستكون `None` أو غير مُعرّفة إذا لم يتم تمرير أي مستندات.
|
|
||||||
- `add_generation_prompt` هي قيمة منطقية تكون `True` إذا طلب المستخدم مُطالبة توليد، و `False` بخلاف ذلك. إذا تم تعيين هذا، فيجب أن يُضيف قالبك رأس رسالة مساعد إلى نهاية المحادثة. إذا لم يكن لدى نموذجك رأس مُحدد لرسائل المساعد، فيمكنك تجاهل هذا العلم.
|
|
||||||
- **الرموز الخاصة** مثل `bos_token` و `eos_token`. يتم استخراجها من `tokenizer.special_tokens_map`. ستختلف الرموز الدقيقة المتاحة داخل كل قالب اعتمادًا على المجزىء اللغوي الأصلي.
|
|
||||||
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
يمكنك في الواقع تمرير أي `kwarg` إلى `apply_chat_template`، وستكون متاحة داخل القالب كمتغير. بشكل عام، نوصي بمحاولة الالتزام بالمتغيرات الأساسية المذكورة أعلاه، لأن ذلك سيجعل نموذجك أكثر صعوبة في الاستخدام إذا كان على المستخدمين كتابة تعليمات برمجية مخصصة لتمرير `kwargs` خاصة بالنموذج. ومع ذلك، فنحن نُدرك أن هذا المجال يتحرك بسرعة، لذلك إذا كانت لديك حالة استخدام جديدة لا تتناسب مع واجهة برمجة التطبيقات الأساسية، فلا تتردد في استخدام `kwarg` معامل جديد لها! إذا أصبح `kwarg` المعامل الجديد شائعًا، فقد نقوم بترقيته إلى واجهة برمجة التطبيقات الأساسية وإنشاء وتوثيق الخاص به.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
### دوال قابلة للاستدعاء
|
|
||||||
|
|
||||||
هناك أيضًا قائمة قصيرة من الدوال القابلة للاستدعاء المتاحة لك داخل قوالبك. هذه هي:
|
|
||||||
|
|
||||||
- `raise_exception(msg)`: تُثير `TemplateException`. هذا مفيد لتصحيح الأخطاء، ولإخبار المستخدمين عندما يفعلون شيئًا لا يدعمه قالبك.
|
|
||||||
- `strftime_now(format_str)`: تُكافئ `datetime.now().strftime(format_str)` في Python. يُستخدم هذا للحصول على التاريخ/الوقت الحالي بتنسيق مُحدد، والذي يتم تضمينه أحيانًا في رسائل النظام.
|
|
||||||
|
|
||||||
### التوافق مع Jinja غير Python
|
|
||||||
|
|
||||||
هناك تطبيقات متعددة لـ Jinja بلغات مختلفة. عادة ما يكون لها نفس التركيب، ولكن الاختلاف الرئيسي هو أنه عند كتابة قالبًا في Python، يمكنك استخدام أساليب Python، مثل ".lower()" على السلاسل أو ".items()" على القواميس. سيؤدي هذا إلى كسر إذا حاول شخص ما استخدام قالبك في تنفيذ غير Python لـ Jinja. تعد التطبيقات غير Python شائعة بشكل خاص في بيئات النشر، حيث تعد JS و Rust شائعة جدًا.
|
|
||||||
|
|
||||||
لا تقلق، على الرغم من ذلك! هناك بعض التغييرات البسيطة التي يمكنك إجراؤها على قوالبك لضمان توافقها عبر جميع تطبيقات Jinja:
|
|
||||||
|
|
||||||
- استبدل أساليب Python بمرشحات Jinja. عادة ما يكون لها نفس الاسم، على سبيل المثال، يصبح "string.lower()" عبارة عن "string|lower"، ويصبح "dict.items()" عبارة عن "dict|items". أحد التغييرات الملحوظة هو أن "string.strip()" يصبح "string|trim". راجع [قائمة المرشحات المدمجة](https://jinja.palletsprojects.com/en/3.1.x/templates/#builtin-filters) في وثائق Jinja لمزيد من المعلومات.
|
|
||||||
- استبدل "True" و "False" و "None"، وهي خاصة بـ Python، بـ "true" و "false" و "none".
|
|
||||||
- قد يؤدي عرض قاموس أو قائمة مباشرة إلى نتائج مختلفة في التطبيقات الأخرى (على سبيل المثال، قد تتغير مدخﻻت السلسلة النصية من علامات اقتباس مفردة ' إلى علامات اقتباس مزدوجة "). يمكن أن يساعد إضافة "tojson" في ضمان الاتساق هنا.
|
|
||||||
|
|
||||||
## كتابة مطالبات التوليد
|
|
||||||
لقد ذكرنا أعلاه أن add_generation_prompt هو متغير خاص يمكن الوصول إليه داخل قالبك، ويتحكم فيه المستخدم من خلال تعيين معامل add_generation_prompt. إذا كان نموذجك يتوقع عنوان لرسائل المساعد، فيجب أن يدعم قالبك إضافة العنوان عند تعيين add_generation_prompt.
|
|
||||||
|
|
||||||
فيما يلي مثال على قالب يُنسّق الرسائل بأسلوب ChatML، مع دعم مُطالبة التوليد:
|
|
||||||
|
|
||||||
```text
|
|
||||||
{{- bos_token }}
|
|
||||||
{%- for message in messages %}
|
|
||||||
{{- '<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n' }}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- if add_generation_prompt %}
|
|
||||||
{{- '<|im_start|>assistant\n' }}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
سيعتمد المحتوى الدقيق لعنوان المساعد على نموذجك المُحدد، ولكن يجب أن يكون دائمًا السلسلة النصية التي تُمثل بداية رسالة المساعد، بحيث إذا قام المستخدم بتطبيق قالبك باستخدام add_generation_prompt=True ثم قام بتوليد نص، سيكتب النموذج استجابة المساعد. لاحظ أيضًا أن بعض النماذج لا تحتاج إلى مُطالبة توليد، لأن رسائل المساعد تبدأ دائمًا فورًا بعد رسائل المستخدم. هذا شائع بشكل خاص لنماذج LLaMA و Mistral، حيث تبدأ رسائل المساعد فورًا بعد رمز [/INST] الذي ينهي رسائل المستخدم. في هذه الحالات، يمكن للقالب تجاهل معامل add_generation_prompt.
|
|
||||||
|
|
||||||
مُطالبات التوليد مُهمة! إذا كان نموذجك يتطلب مُطالبة توليد ولكنها غير مُعيّنة في القالب، فمن المُحتمل أن تتدهور عمليات توليد النموذج بشدة، أو قد يُظهر النموذج سلوكًا غير عادي مثل متابعة رسالة المستخدم الأخيرة!
|
|
||||||
|
|
||||||
### كتابة قوالب أكبر وتصحيحها
|
|
||||||
عندما تم تقديم هذه الميزة، كانت معظم القوالب صغيرة جدًا، أي ما يُعادل نص برمجي "من سطر واحد" في Jinja. ومع ذلك، مع النماذج والميزات الجديدة مثل استخدام الأدوات و RAG، يمكن أن يصل طول بعض القوالب إلى 100 سطر أو أكثر. عند كتابة قوالب كهذه، من الجيد كتابتها في ملف مُنفصل، باستخدام مُحرر نصوص. يمكنك بسهولة استخراج قالب دردشة إلى ملف:
|
|
||||||
|
|
||||||
```python
|
|
||||||
open("template.jinja", "w").write(tokenizer.chat_template)
|
|
||||||
```
|
|
||||||
أو تحميل القالب المُحرر مرة أخرى إلى المعالج اللغوي:
|
|
||||||
|
|
||||||
```python
|
|
||||||
tokenizer.chat_template = open("template.jinja").read()
|
|
||||||
```
|
|
||||||
كميزة إضافية، عندما تكتب قالبًا طويلاً متعدد الأسطر في ملف مُنفصل، ستتوافق أرقام الأسطر في هذا الملف تمامًا مع أرقام الأسطر في أخطاء تحليل القالب أو تنفيذه. سيُسهّل هذا كثيرًا تحديد مكان المشكلات.
|
|
||||||
|
|
||||||
### كتابة قوالب للأدوات
|
|
||||||
على الرغم من أن قوالب الدردشة لا تفرض واجهة برمجة تطبيقات مُحددة للأدوات (أو لأي شيء حقًا)، فإننا نوصي مؤلفي القوالب بمحاولة الالتزام بواجهة برمجة تطبيقات قياسية حيثما أمكن. الهدف النهائي لقوالب الدردشة هو السماح بنقل التعليمات البرمجية عبر النماذج، لذا فإن الانحراف عن واجهة برمجة تطبيقات الأدوات القياسية يعني أن المستخدمين سيضطرون إلى كتابة تعليمات برمجية مخصصة لاستخدام الأدوات مع نموذجك. في بعض الأحيان يكون ذلك أمرًا لا مفر منه، ولكن غالبًا ما يكون من الممكن استخدام واجهة برمجة التطبيقات القياسية من خلال استخدام قوالب ذكية!
|
|
||||||
|
|
||||||
أدناه، سنُدرج عناصر واجهة برمجة التطبيقات القياسية، ونقدم نصائح حول كتابة قوالب ستعمل بشكل جيد معها.
|
|
||||||
|
|
||||||
#### تعريفات الأدوات
|
|
||||||
يجب أن يتوقع قالبك أن يكون المتغير tools إما فارغًا (إذا لم يتم تمرير أي أدوات)، أو قائمة من قواميس مخطط JSON. تسمح أساليب قالب الدردشة الخاصة بنا للمستخدمين بتمرير الأدوات إما كمخطط JSON أو كدوال Python، ولكن عندما يتم تمرير الدوال، فإننا نقوم تلقائيًا بإنشاء مخطط JSON وتمريره إلى قالبك. نتيجة لذلك، سيكون متغير tools الذي يستقبله قالبك دائمًا قائمة من مخططات JSON. هنا مخطط JSON أداة نموذجي:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "multiply",
|
|
||||||
"description": "دالة تضرب عددين",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"a": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "الرقم الأول للضرب"
|
|
||||||
},
|
|
||||||
"b": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "الرقم الثاني للضرب"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["a", "b"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
وهنا بعض الأمثلة البرمجية للتعامل مع الأدوات في قالب الدردشة الخاص بك. تذكر أن هذا مجرد مثال لتنسيق مُحدد - من المحتمل أن يحتاج نموذجك إلى تنسيق مختلف!
|
|
||||||
```text
|
|
||||||
{%- if tools %}
|
|
||||||
{%- for tool in tools %}
|
|
||||||
{{- '<tool>' + tool['function']['name'] + '\n' }}
|
|
||||||
{%- for argument in tool['function']['parameters']['properties'] %}
|
|
||||||
{{- argument + ': ' + tool['function']['parameters']['properties'][argument]['description'] + '\n' }}
|
|
||||||
{%- endfor %}
|
|
||||||
{{- '\n</tool>' }}
|
|
||||||
{%- endif %}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
|
|
||||||
يجب بالطبع اختيار الرموز المحددة ووصف الأدوات التي يُعرضها قالبك لتتناسب مع تلك التي تم تدريب نموذجك عليها. لا يوجد شرط أن يفهم نموذجك مُدخلات مخطط JSON، فقط أن يتمكن قالبك من ترجمة مخطط JSON إلى تنسيق نموذجك. على سبيل المثال، تم تدريب Command-R باستخدام أدوات مُعرّفة باستخدام رؤوس دوال Python، ولكن يقبل قالب أداة Command-R مخطط JSON، ويُحوّل الأنواع داخليًا ويُعرض أدوات الإدخال كعناوين Python. يمكنك فعل الكثير باستخدام القوالب!
|
|
||||||
|
|
||||||
#### استدعاءات الأدوات
|
|
||||||
استدعاءات الأدوات، إذا كانت موجودة، ستكون قائمة مُرفقة برسالة بدور "assistant". لاحظ أن tool_calls هي دائمًا قائمة، على الرغم من أن معظم نماذج استدعاء الأدوات تدعم فقط استدعاءات أدوات فردية في كل مرة، مما يعني أن القائمة ستحتوي عادةً على عنصر واحد فقط. هنا قاموس رسالة نموذجي يحتوي على استدعاء أداة:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"tool_calls": [
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "multiply",
|
|
||||||
"arguments": {
|
|
||||||
"a": 5,
|
|
||||||
"b": 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
والنمط الشائع للتعامل معها سيكون كهذا:
|
|
||||||
|
|
||||||
```text
|
|
||||||
{%- if message['role'] == 'assistant' and 'tool_calls' in message %}
|
|
||||||
{%- for tool_call in message['tool_calls'] %}
|
|
||||||
{{- '<tool_call>' + tool_call['function']['name'] + '\n' + tool_call['function']['arguments']|tojson + '\n</tool_call>' }}
|
|
||||||
{%- endif %}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
|
|
||||||
مرة أخرى، يجب عليك عرض استدعاء الأداة بالتنسيق والرموز الخاصة التي يتوقعها نموذجك.
|
|
||||||
|
|
||||||
#### استجابات الأدوات
|
|
||||||
استجابات الأدوات لها تنسيق بسيط: إنها قاموس رسالة بدور "tool"، ومفتاح "name" يُعطي اسم الدالة المُستدعاة، ومفتاح "content" يحتوي على نتيجة استدعاء الأداة. هنا استجابة أداة نموذجية:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"role": "tool",
|
|
||||||
"name": "multiply",
|
|
||||||
"content": "30"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
لست بحاجة إلى استخدام جميع المفاتيح في استجابة الأداة. على سبيل المثال، إذا كان نموذجك لا يتوقع تضمين اسم الدالة في استجابة الأداة، فيمكن أن يكون عرضها بسيطًا مثل:
|
|
||||||
|
|
||||||
```text
|
|
||||||
{%- if message['role'] == 'tool' %}
|
|
||||||
{{- "<tool_result>" + message['content'] + "</tool_result>" }}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
|
|
||||||
مرة أخرى، تذكر أن التنسيق الفعلي والرموز الخاصة خاصة بالنموذج - يجب أن تُولي عناية كبيرة لضمان أن الرموز والمسافات الفارغة وكل شيء آخر يتطابق تمامًا مع التنسيق الذي تم تدريب نموذجك عليه!
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
# مجتمع المطورين
|
|
||||||
|
|
||||||
هذه الصفحة تجمع الموارد حول 🤗 Transformers التي طورها المجتمع.
|
|
||||||
|
|
||||||
## موارد المجتمع:
|
|
||||||
|
|
||||||
| المصدر | الوصف | المؤلف |
|
|
||||||
|:----------|:-------------|------:|
|
|
||||||
| [Hugging Face Transformers Glossary Flashcards](https://www.darigovresearch.com/huggingface-transformers-glossary-flashcards) | مجموعة من البطاقات التعليمية القائمة على [Transformers Docs Glossary](glossary) والتي تم وضعها في شكل يمكن تعلمه/مراجعته بسهولة باستخدام [Anki](https://apps.ankiweb.net/) وهو تطبيق مفتوح المصدر متعدد المنصات مصمم خصيصًا للاحتفاظ بالمعرفة على المدى الطويل. شاهد هذا [فيديو تمهيدي حول كيفية استخدام البطاقات التعليمية](https://www.youtube.com/watch?v=Dji_7PILrw). | [Darigov Research](https://www.darigovresearch.com/) |
|
|
||||||
|
|
||||||
## دفاتر ملاحظات المجتمع:
|
|
||||||
|
|
||||||
| الدفتر | الوصف | المؤلف | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [Fine-tune a pre-trained Transformer to generate lyrics](https://github.com/AlekseyKorshuk/huggingartists) | كيفية توليد كلمات الأغاني على غرار فنانك المفضل من خلال ضبط نموذج GPT-2 | [Aleksey Korshuk](https://github.com/AlekseyKorshuk) | [](https://colab.research.google.com/github/AlekseyKorshuk/huggingartists/blob/master/huggingartists-demo.ipynb) |
|
|
||||||
| [Train T5 in Tensorflow 2](https://github.com/snapthat/TF-T5-text-to-text) | كيفية تدريب T5 لأي مهمة باستخدام Tensorflow 2. يوضح هذا الدفتر مهمة السؤال والجواب المنفذة في Tensorflow 2 باستخدام SQUAD | [Muhammad Harris](https://github.com/HarrisDePerceptron) |[](https://colab.research.google.com/github/snapthat/TF-T5-text-to-text/blob/master/snapthatT5/notebooks/TF-T5-Datasets%20Training.ipynb) |
|
|
||||||
| [Train T5 on TPU](https://github.com/patil-suraj/exploring-T5/blob/master/T5_on_TPU.ipynb) | كيفية تدريب T5 على SQUAD مع Transformers و Nlp | [Suraj Patil](https://github.com/patil-suraj) |[](https://colab.research.google.com/github/patil-suraj/exploring-T5/blob/master/T5_on_TPU.ipynb#scrollTo=QLGiFCDqvuil) |
|
|
||||||
| [Fine-tune T5 for Classification and Multiple Choice](https://github.com/patil-suraj/exploring-T5/blob/master/t5_fine_tuning.ipynb) | كيفية ضبط نموذج T5 للتصنيف والمهام متعددة الخيارات باستخدام تنسيق النص إلى نص مع PyTorch Lightning | [Suraj Patil](https://github.com/patil-suraj) | [](https://colab.research.google.com/github/patil-suraj/exploring-T5/blob/master/t5_fine_tuning.ipynb) |
|
|
||||||
| [Fine-tune DialoGPT on New Datasets and Languages](https://github.com/ncoop57/i-am-a-nerd/blob/master/_notebooks/2020-05-12-chatbot-part-1.ipynb) | كيفية ضبط نموذج DialoGPT على مجموعة بيانات جديدة لروبوتات الدردشة المحادثية المفتوحة | [Nathan Cooper](https://github.com/ncoop57) | [](https://colab.research.google.com/github/ncoop57/i-am-a-nerd/blob/master/_notebooks/2020-05-12-chatbot-part-1.ipynb) |
|
|
||||||
| [Long Sequence Modeling with Reformer](https://github.com/patrickvonplaten/notebooks/blob/master/PyTorch_Reformer.ipynb) | كيفية التدريب على تسلسلات طويلة تصل إلى 500,000 رمز باستخدام Reformer | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/PyTorch_Reformer.ipynb) |
|
|
||||||
| [Fine-tune BART for Summarization](https://github.com/ohmeow/ohmeow_website/blob/master/posts/2021-05-25-mbart-sequence-classification-with-blurr.ipynb) | كيفية ضبط نموذج BART للتلخيص باستخدام fastai باستخدام blurr | [Wayde Gilliam](https://ohmeow.com/) | [](https://colab.research.google.com/github/ohmeow/ohmeow_website/blob/master/posts/2021-05-25-mbart-sequence-classification-with-blurr.ipynb) |
|
|
||||||
| [Fine-tune a pre-trained Transformer on anyone's tweets](https://colab.research.google.com/github/borisdayma/huggingtweets/blob/master/huggingtweets-demo.ipynb) | كيفية توليد تغريدات على غرار حساب Twitter المفضل لديك من خلال ضبط نموذج GPT-2 | [Boris Dayma](https://github.com/borisdayma) | [](https://colab.research.google.com/github/borisdayma/huggingtweets/blob/master/huggingtweets-demo.ipynb) |
|
|
||||||
| [Optimize 🤗 Hugging Face models with Weights & Biases](https://colab.research.google.com/github/wandb/examples/blob/master/colabs/huggingface/Optimize_Hugging_Face_models_with_Weights_%26_Biases.ipynb) | دليل كامل لعرض تكامل W&B مع Hugging Face | [Boris Dayma](https://github.com/borisdayma) | [](https://colab.research.google.com/github/wandb/examples/blob/master/colabs/huggingface/Optimize_Hugging_Face_models_with_Weights_%26_Biases.ipynb) |
|
|
||||||
| [Pretrain Longformer](https://github.com/allenai/longformer/blob/master/scripts/convert_model_to_long.ipynb) | كيفية بناء نسخة "طويلة" من النماذج المسبقة التدريب الموجودة | [Iz Beltagy](https://beltagy.net) | [](https://colab.research.google.com/github/allenai/longformer/blob/master/scripts/convert_model_to_long.ipynb) |
|
|
||||||
| [Fine-tune Longformer for QA](https://github.com/patil-suraj/Notebooks/blob/master/longformer_qa_training.ipynb) | كيفية ضبط نموذج Longformer لمهمة QA | [Suraj Patil](https://github.com/patil-suraj) | [](https://colab.research.google.com/github/patil-suraj/Notebooks/blob/master/longformer_qa_training.ipynb) |
|
|
||||||
| [Evaluate Model with 🤗nlp](https://github.com/patrickvonplaten/notebooks/blob/master/How_to_evaluate_Longformer_on_TriviaQA_using_NLP.ipynb) | كيفية تقييم نموذج Longformer على TriviaQA مع `nlp` | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/drive/1m7eTGlPmLRgoPkkA7rkhQdZ9ydpmsdLE?usp=sharing) |
|
|
||||||
| [Fine-tune T5 for Sentiment Span Extraction](https://github.com/enzoampil/t5-intro/blob/master/t5_qa_training_pytorch_span_extraction.ipynb) | كيفية ضبط نموذج T5 لاستخراج المشاعر باستخدام تنسيق النص إلى نص مع PyTorch Lightning | [Lorenzo Ampil](https://github.com/enzoampil) | [](https://colab.research.google.com/github/enzoampil/t5-intro/blob/master/t5_qa_training_pytorch_span_extraction.ipynb) |
|
|
||||||
| [Fine-tune DistilBert for Multiclass Classification](https://github.com/abhimishra91/transformers-tutorials/blob/master/transformers_multiclass_classification.ipynb) | كيفية ضبط نموذج DistilBert للتصنيف متعدد الفئات باستخدام PyTorch | [Abhishek Kumar Mishra](https://github.com/abhimishra91) | [](https://colab.research.google.com/github/abhimishra91/transformers-tutorials/blob/master/transformers_multiclass_classification.ipynb)|
|
|
||||||
|[Fine-tune BERT for Multi-label Classification](https://github.com/abhimishra91/transformers-tutorials/blob/master/transformers_multi_label_classification.ipynb)|كيفية ضبط نموذج BERT للتصنيف متعدد التصنيفات باستخدام PyTorch|[Abhishek Kumar Mishra](https://github.com/abhimishra91) |[](https://colab.research.google.com/github/abhimishra91/transformers-tutorials/blob/master/transformers_multi_label_classification.ipynb)|
|
|
||||||
|[Fine-tune T5 for Summarization](https://github.com/abhimishra91/transformers-tutorials/blob/master/transformers_summarization_wandb.ipynb)|كيفية ضبط نموذج T5 للتلخيص في PyTorch وتتبع التجارب باستخدام WandB|[Abhishek Kumar Mishra](https://github.com/abhimishra91) |[](https://colab.research.google.com/github/abhimishra91/transformers-tutorials/blob/master/transformers_summarization_wandb.ipynb)|
|
|
||||||
|[Speed up Fine-Tuning in Transformers with Dynamic Padding / Bucketing](https://github.com/ELS-RD/transformers-notebook/blob/master/Divide_Hugging_Face_Transformers_training_time_by_2_or_more.ipynb)|كيفية تسريع الضبط الدقيق بعامل 2 باستخدام الضبط الديناميكي/التقسيم|[Michael Benesty](https://github.com/pommedeterresautee) |[](https://colab.research.google.com/drive/1CBfRU1zbfu7-ijiOqAAQUA-RJaxfcJoO?usp=sharing)|
|
|
||||||
|[Pretrain Reformer for Masked Language Modeling](https://github.com/patrickvonplaten/notebooks/blob/master/Reformer_For_Masked_LM.ipynb)| كيفية تدريب نموذج Reformer مع طبقات الانتباه ثنائية الاتجاه | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/drive/1tzzh0i8PgDQGV3SMFUGxM7_gGae3K-uW?usp=sharing)|
|
|
||||||
|[Expand and Fine Tune Sci-BERT](https://github.com/lordtt13/word-embeddings/blob/master/COVID-19%20Research%20Data/COVID-SciBERT.ipynb)| كيفية زيادة مفردات نموذج SciBERT المسبق التدريب من AllenAI على مجموعة بيانات CORD وإنشاء خط أنابيب لها. | [Tanmay Thakur](https://github.com/lordtt13) | [](https://colab.research.google.com/drive/1rqAR40goxbAfez1xvF3hBJphSCsvXmh8)|
|
|
||||||
|[Fine Tune BlenderBotSmall for Summarization using the Trainer API](https://github.com/lordtt13/transformers-experiments/blob/master/Custom%20Tasks/fine-tune-blenderbot_small-for-summarization.ipynb)| كيفية ضبط نموذج BlenderBotSmall للتلخيص على مجموعة بيانات مخصصة، باستخدام واجهة برمجة التطبيقات Trainer. | [Tanmay Thakur](https://github.com/lordtt13) | [](https://colab.research.google.com/drive/19Wmupuls7mykSGyRN_Qo6lPQhgp56ymq?usp=sharing)|
|
|
||||||
|[Fine-tune Electra and interpret with Integrated Gradients](https://github.com/elsanns/xai-nlp-notebooks/blob/master/electra_fine_tune_interpret_captum_ig.ipynb) | كيفية ضبط نموذج Electra للتحليل العاطفي وتفسير التنبؤات باستخدام Captum Integrated Gradients | [Eliza Szczechla](https://elsanns.github.io) | [](https://colab.research.google.com/github/elsanns/xai-nlp-notebooks/blob/master/electra_fine_tune_interpret_captum_ig.ipynb)|
|
|
||||||
|[fine-tune a non-English GPT-2 Model with Trainer class](https://github.com/philschmid/fine-tune-GPT-2/blob/master/Fine_tune_a_non_English_GPT_2_Model_with_Huggingface.ipynb) | كيفية ضبط نموذج GPT-2 غير الإنجليزي باستخدام فئة Trainer | [Philipp Schmid](https://www.philschmid.de) | [](https://colab.research.google.com/github/philschmid/fine-tune-GPT-2/blob/master/Fine_tune_a_non_English_GPT_2_Model_with_Huggingface.ipynb)|
|
|
||||||
|[Fine-tune a DistilBERT Model for Multi Label Classification task](https://github.com/DhavalTaunk08/Transformers_scripts/blob/master/Transformers_multilabel_distilbert.ipynb) | كيفية ضبط نموذج DistilBERT لمهمة التصنيف متعدد التصنيفات | [Dhaval Taunk](https://github.com/DhavalTaunk08) | [](https://colab.research.google.com/github/DhavalTaunk08/Transformers_scripts/blob/master/Transformers_multilabel_distilbert.ipynb)|
|
|
||||||
|[Fine-tune ALBERT for sentence-pair classification](https://github.com/NadirEM/nlp-notebooks/blob/master/Fine_tune_ALBERT_sentence_pair_classification.ipynb) | كيفية ضبط نموذج ALBERT أو أي نموذج آخر قائم على BERT لمهمة التصنيف المزدوج للجمل | [Nadir El Manouzi](https://github.com/NadirEM) | [](https://colab.research.google.com/github/NadirEM/nlp-notebooks/blob/master/Fine_tune_ALBERT_sentence_pair_classification.ipynb)|
|
|
||||||
|[Fine-tune Roberta for sentiment analysis](https://github.com/DhavalTaunk08/NLP_scripts/blob/master/sentiment_analysis_using_roberta.ipynb) | كيفية ضبط نموذج Roberta للتحليل العاطفي | [Dhaval Taunk](https://github.com/DhavalTaunk08) | [](https://colab.research.google.com/github/DhavalTaunk08/NLP_scripts/blob/master/sentiment_analysis_using_roberta.ipynb)|
|
|
||||||
|[Evaluating Question Generation Models](https://github.com/flexudy-pipe/qugeev) | ما مدى دقة الإجابات على الأسئلة التي يولدها نموذجك التحويلي seq2seq؟ | [Pascal Zoleko](https://github.com/zolekode) | [](https://colab.research.google.com/drive/1bpsSqCQU-iw_5nNoRm_crPq6FRuJthq_?usp=sharing)|
|
|
||||||
|[Classify text with DistilBERT and Tensorflow](https://github.com/peterbayerle/huggingface_notebook/blob/main/distilbert_tf.ipynb) | كيفية ضبط نموذج DistilBERT للتصنيف النصي في TensorFlow | [Peter Bayerle](https://github.com/peterbayerle) | [](https://colab.research.google.com/github/peterbayerle/huggingface_notebook/blob/main/distilbert_tf.ipynb)|
|
|
||||||
|[Leverage BERT for Encoder-Decoder Summarization on CNN/Dailymail](https://github.com/patrickvonplaten/notebooks/blob/master/BERT2BERT_for_CNN_Dailymail.ipynb) | كيفية البدء السريع لنموذج *EncoderDecoderModel* مع نقطة تفتيش *google-bert/bert-base-uncased* للتلخيص على CNN/Dailymail | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/BERT2BERT_for_CNN_Dailymail.ipynb)|
|
|
||||||
|[Leverage RoBERTa for Encoder-Decoder Summarization on BBC XSum](https://github.com/patrickvonplaten/notebooks/blob/master/RoBERTaShared_for_BBC_XSum.ipynb) | كيفية البدء السريع لنموذج *EncoderDecoderModel* المشترك مع نقطة تفتيش *FacebookAI/roberta-base* للتلخيص على BBC/XSum | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/RoBERTaShared_for_BBC_XSum.ipynb)|
|
|
||||||
|[Fine-tune TAPAS on Sequential Question Answering (SQA)](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/TAPAS/Fine_tuning_TapasForQuestionAnswering_on_SQA.ipynb) | كيفية ضبط نموذج *TapasForQuestionAnswering* مع نقطة تفتيش *tapas-base* على مجموعة بيانات Sequential Question Answering (SQA) | [Niels Rogge](https://github.com/nielsrogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/TAPAS/Fine_tuning_TapasForQuestionAnswering_on_SQA.ipynb)|
|
|
||||||
|[Evaluate TAPAS on Table Fact Checking (TabFact)](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/TAPAS/Evaluating_TAPAS_on_the_Tabfact_test_set.ipynb) | كيفية تقييم نموذج *TapasForSequenceClassification* المضبوط مسبقًا مع نقطة تفتيش *tapas-base-finetuned-tabfact* باستخدام مزيج من مكتبتي 🤗 datasets و 🤗 transformers | [Niels Rogge](https://github.com/nielsrogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/TAPAS/Evaluating_TAPAS_on_the_Tabfact_test_set.ipynb)|
|
|
||||||
|[Fine-tuning mBART for translation](https://colab.research.google.com/github/vasudevgupta7/huggingface-tutorials/blob/main/translation_training.ipynb) | كيفية ضبط نموذج mBART باستخدام Seq2SeqTrainer للترجمة من الهندية إلى الإنجليزية | [Vasudev Gupta](https://github.com/vasudevgupta7) | [](https://colab.research.google.com/github/vasudevgupta7/huggingface-tutorials/blob/main/translation_training.ipynb)|
|
|
||||||
|[Fine-tune LayoutLM on FUNSD (a form understanding dataset)](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/LayoutLM/Fine_tuning_LayoutLMForTokenClassification_on_FUNSD.ipynb) | كيفية ضبط نموذج *LayoutLMForTokenClassification* على مجموعة بيانات FUNSD لاستخراج المعلومات من المستندات الممسوحة ضوئيًا | [Niels Rogge](https://github.com/nielsrogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/LayoutLM/Fine_tuning_LayoutLMForTokenClassification_on_FUNSD.ipynb)|
|
|
||||||
|[Fine-Tune DistilGPT2 and Generate Text](https://colab.research.google.com/github/tripathiaakash/DistilGPT2-Tutorial/blob/main/distilgpt2_fine_tuning.ipynb) | كيفية ضبط نموذج DistilGPT2 وتوليد النص | [Aakash Tripathi](https://github.com/tripathiaakash) | [](https://colab.research.google.com/github/tripathiaakash/DistilGPT2-Tutorial/blob/main/distilgpt2_fine_tuning.ipynb)|
|
|
||||||
|[Fine-Tune LED on up to 8K tokens](https://github.com/patrickvonplaten/notebooks/blob/master/Fine_tune_Longformer_Encoder_Decoder_(LED)_for_Summarization_on_pubmed.ipynb) | كيفية ضبط نموذج LED على pubmed للتلخيص طويل المدى | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/Fine_tune_Longformer_Encoder_Decoder_(LED)_for_Summarization_on_pubmed.ipynb)|
|
|
||||||
|[Evaluate LED on Arxiv](https://github.com/patrickvonplaten/notebooks/blob/master/LED_on_Arxiv.ipynb) | كيفية تقييم نموذج LED للتلخيص طويل المدى بشكل فعال | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/LED_on_Arxiv.ipynb)|
|
|
||||||
|[Fine-tune LayoutLM on RVL-CDIP (a document image classification dataset)](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/LayoutLM/Fine_tuning_LayoutLMForSequenceClassification_on_RVL_CDIP.ipynb) | كيفية ضبط نموذج *LayoutLMForSequenceClassification* على مجموعة بيانات RVL-CDIP لتصنيف المستندات الممسوحة ضوئيًا | [Niels Rogge](https://github.com/nielsrogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/LayoutLM/Fine_tuning_LayoutLMForSequenceClassification_on_RVL_CDIP.ipynb)|
|
|
||||||
|[Wav2Vec2 CTC decoding with GPT2 adjustment](https://github.com/voidful/huggingface_notebook/blob/main/xlsr_gpt.ipynb) | كيفية فك تشفير تسلسل CTC مع تعديل نموذج اللغة | [Eric Lam](https://github.com/voidful) | [](https://colab.research.google.com/drive/1e_zQHYbO2YKEaUgzb1ww1WwiAyydAj?usp=sharing)|
|
|
||||||
|[Fine-tune BART for summarization in two languages with Trainer class](https://github.com/elsanns/xai-nlp-notebooks/blob/master/fine_tune_bart_summarization_two_langs.ipynb) | كيفية ضبط نموذج BART للتلخيص بلغتين باستخدام فئة Trainer | [Eliza Szczechla](https://github.com/elsanns) | [](https://colab.research.google.com/github/elsanns/xai-nlp-notebooks/blob/master/fine_tune_bart_summarization_two_langs.ipynb)|
|
|
||||||
|[Evaluate Big Bird on Trivia QA](https://github.com/patrickvonplaten/notebooks/blob/master/Evaluating_Big_Bird_on_TriviaQA.ipynb) | كيفية تقييم نموذج BigBird للأسئلة والأجوبة على وثائق طويلة على Trivia QA | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/Evaluating_Big_Bird_on_TriviaQA.ipynb)|
|
|
||||||
| [Create video captions using Wav2Vec2](https://github.com/Muennighoff/ytclipcc/blob/main/wav2vec_youtube_captions.ipynb) | كيفية إنشاء تعليقات توضيحية على YouTube من أي فيديو من خلال تفريغ الصوت باستخدام Wav2Vec | [Niklas Muennighoff](https://github.com/Muennighoff) |[](https://colab.research.google.com/github/Muennighoff/ytclipcc/blob/main/wav2vec_youtube_captions.ipynb) |
|
|
||||||
| [Fine-tune the Vision Transformer on CIFAR-10 using PyTorch Lightning](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/VisionTransformer/Fine_tuning_the_Vision_Transformer_on_CIFAR_10_with_PyTorch_Lightning.ipynb) | كيفية ضبط نموذج Vision Transformer (ViT) على CIFAR-10 باستخدام مكتبات HuggingFace Transformers و Datasets و PyTorch Lightning | [Niels Rogge](https://github.com/nielsrogge) |[](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/VisionTransformer/Fine_tuning_the_Vision_Transformer_on_CIFAR_10_with_PyTorch_Lightning.ipynb) |
|
|
||||||
| [Fine-tune the Vision Transformer on CIFAR-10 using the 🤗 Trainer](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/VisionTransformer/Fine_tuning_the_Vision_Transformer_on_CIFAR_10_with_the_%F0%9F%A4%97_Trainer.ipynb) | كيفية ضبط نموذج Vision Transformer (ViT) على CIFAR-10 باستخدام مكتبات HuggingFace Transformers و Datasets و 🤗 Trainer | [Niels Rogge](https://github.com/nielsrogge) |[](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/VisionTransformer/Fine_tuning_the_Vision_Transformer_on_CIFAR_10_with_the_%F0%9F%A4%97_Trainer.ipynb) |
|
|
||||||
| [Evaluate LUKE on Open Entity, an entity typing dataset](https://github.com/studio-ousia/luke/blob/master/notebooks/huggingface_open_entity.ipynb) | كيفية تقييم نموذج *LukeForEntityClassification* على مجموعة بيانات Open Entity | [Ikuya Yamada](https://github.com/ikuyamada) |[](https://colab.research.google.com/github/studio-ousia/luke/blob/master/notebooks/huggingface_open_entity.ipynb) |
|
|
||||||
| [Evaluate LUKE on TACRED, a relation extraction dataset](https://github.com/studio-ousia/luke/blob/master/notebooks/huggingface_tacred.ipynb) | كيفية تقييم نموذج *LukeForEntityPairClassification* على مجموعة بيانات TACRED | [Ikuya Yamada](https://github.com/ikuyamada) |[](https://colab.research.google.com/github/studio-ousia/luke/blob/master/notebooks/huggingface_tacred.ipynb) |
|
|
||||||
| [Evaluate LUKE on CoNLL-2003, an important NER benchmark](https://github.com/studio-ousia/luke/blob/master/notebooks/huggingface_conll_2003.ipynb) | كيفية تقييم نموذج *LukeForEntitySpanClassification* على مجموعة بيانات CoNLL-2003 | [Ikuya Yamada](https://github.com/ikuyamada) |[](https://colab.research.google.com/github/studio-ousia/luke/blob/master/notebooks/huggingface_conll_2003.ipynb) |
|
|
||||||
| [Evaluate BigBird-Pegasus on PubMed dataset](https://github.com/vasudevgupta7/bigbird/blob/main/notebooks/bigbird_pegasus_evaluation.ipynb) | كيفية تقييم نموذج *BigBirdPegasusForConditionalGeneration* على مجموعة بيانات PubMed | [Vasudev Gupta](https://github.com/vasudevgupta7) | [](https://colab.research.google.com/github/vasudevgupta7/bigbird/blob/main/notebooks/bigbird_pegasus_evaluation.ipynb) |
|
|
||||||
| [Speech Emotion Classification with Wav2Vec2](https://github.com/m3hrdadfi/soxan/blob/main/notebooks/Emotion_recognition_in_Greek_speech_using_Wav2Vec2.ipynb) | كيفية استخدام نموذج Wav2Vec2 المسبق التدريب لتصنيف المشاعر على مجموعة بيانات MEGA | [Mehrdad Farahani](https://github.com/m3hrdadfi) | [](https://colab.research.google.com/github/m3hrdadfi/soxan/blob/main/notebooks/Emotion_recognition_in_Greek_speech_using_Wav2Vec2.ipynb) |
|
|
||||||
| [Detect objects in an image with DETR](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/DETR/DETR_minimal_example_(with_DetrFeatureExtractor).ipynb) | كيفية استخدام نموذج *DetrForObjectDetection* المدرب للكشف عن الأجسام في صورة وتصوير الانتباه | [Niels Rogge](https://github.com/NielsRogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/DETR/DETR_minimal_example_(with_DetrFeatureExtractor).ipynb) |
|
|
||||||
| [Fine-tune DETR on a custom object detection dataset](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/DETR/Fine_tuning_DetrForObjectDetection_on_custom_dataset_(balloon).ipynb) | كيفية ضبط نموذج *DetrForObjectDetection* على مجموعة بيانات الكشف عن الأجسام المخصصة | [Niels Rogge](https://github.com/NielsRogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/DETR/Fine_tuning_DetrForObjectDetection_on_custom_dataset_(balloon).ipynb) |
|
|
||||||
| [Finetune T5 for Named Entity Recognition](https://github.com/ToluClassics/Notebooks/blob/main/T5_Ner_Finetuning.ipynb) | كيفية ضبط نموذج *T5* على مهمة التعرف على الكيانات المسماة | [Ogundepo Odunayo](https://github.com/ToluClassics) | [](https://colab.research.google.com/drive/1obr78FY_cBmWY5ODViCmzdY6O1KB65Vc?usp=sharing) |
|
|
||||||
| [Fine-Tuning Open-Source LLM using QLoRA with MLflow and PEFT](https://github.com/mlflow/mlflow/blob/master/docs/source/llms/transformers/tutorials/fine-tuning/transformers-peft.ipynb) | كيفية استخدام [QLoRA](https://github.com/artidoro/qlora) و [PEFT](https://huggingface.co/docs/peft/en/index) لضبط نموذج LLM بطريقة فعالة من حيث الذاكرة، مع استخدام [MLflow](https://mlflow.org/docs/latest/llms/transformers/index.html) لإدارة تتبع التجارب | [Yuki Watanabe](https://github.com/B-Step62) | [](https://colab.research.google.com/github/mlflow/mlflow/blob/master/docs/source/llms/transformers/tutorials/fine-tuning/transformers-peft.ipynb) |
|
|
||||||
@ -1,436 +0,0 @@
|
|||||||
# إنشاء بنية مخصصة
|
|
||||||
|
|
||||||
تحدد فئة [`AutoClass`](model_doc/auto) تلقائيًا بنية النموذج وتقوم بتنزيل تكوين وأوزان مسبقين للنموذج. بشكل عام، نوصي باستخدام `AutoClass` لإنتاج كود غير مرتبط بنسخة معينة. ولكن يمكن للمستخدمين الذين يريدون مزيدًا من التحكم في معلمات النموذج المحددة إنشاء نموذج مخصص من 🤗 Transformers من مجرد بضع فئات أساسية. قد يكون هذا مفيدًا بشكل خاص لأي شخص مهتم بدراسة نموذج 🤗 Transformers أو تدريبه أو إجراء تجارب عليه. في هذا الدليل، سنغوص بشكل أعمق في إنشاء نموذج مخصص بدون `AutoClass`. تعرف على كيفية:
|
|
||||||
|
|
||||||
- تحميل تكوين النموذج وتخصيصه.
|
|
||||||
- إنشاء بنية نموذج.
|
|
||||||
- إنشاء مجزء لغوى سريع وبطيء للنص.
|
|
||||||
- إنشاء معالج صور لمهام الرؤية.
|
|
||||||
- إنشاء مستخرج ميزات لمهام الصوت.
|
|
||||||
- إنشاء معالج للمهام متعددة الوسائط.
|
|
||||||
|
|
||||||
## التكوين
|
|
||||||
|
|
||||||
يشير مصطلح [التكوين](main_classes/configuration) إلى الخصائص المحددة للنموذج. لكل تكوين نموذج خصائصه الخاصة؛ على سبيل المثال، تشترك جميع نماذج NLP في الخصائص `hidden_size` و`num_attention_heads` و`num_hidden_layers` و`vocab_size` المشتركة. تحدد هذه الخصائص عدد رؤوس الانتباه أو الطبقات المخفية لبناء نموذج بها.
|
|
||||||
|
|
||||||
اطلع على [DistilBERT](model_doc/distilbert) من خلال [`DistilBertConfig`] لمعاينة خصائصه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DistilBertConfig
|
|
||||||
|
|
||||||
>>> config = DistilBertConfig()
|
|
||||||
>>> print(config)
|
|
||||||
DistilBertConfig {
|
|
||||||
"activation": "gelu",
|
|
||||||
"attention_dropout": 0.1,
|
|
||||||
"dim": 768,
|
|
||||||
"dropout": 0.1,
|
|
||||||
"hidden_dim": 3072,
|
|
||||||
"initializer_range": 0.02,
|
|
||||||
"max_position_embeddings": 512,
|
|
||||||
"model_type": "distilbert",
|
|
||||||
"n_heads": 12,
|
|
||||||
"n_layers": 6,
|
|
||||||
"pad_token_id": 0,
|
|
||||||
"qa_dropout": 0.1,
|
|
||||||
"seq_classif_dropout": 0.2,
|
|
||||||
"sinusoidal_pos_embds": false,
|
|
||||||
"transformers_version": "4.16.2",
|
|
||||||
"vocab_size": 30522
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
يعرض [`DistilBertConfig`] جميع الخصائص الافتراضية المستخدمة لبناء نموذج [`DistilBertModel`] أساسي. جميع الخصائص قابلة للتعديل، مما ييتيح مجالاً للتجريب. على سبيل المثال، يمكنك تعديل نموذج افتراضي لـ:
|
|
||||||
|
|
||||||
- تجربة دالة تنشيط مختلفة باستخدام معامل `activation`.
|
|
||||||
- استخدام معدل إسقاط أعلى الاحتمالات الانتباه مع معامل `attention_dropout`.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> my_config = DistilBertConfig(activation="relu", attention_dropout=0.4)
|
|
||||||
>>> print(my_config)
|
|
||||||
DistilBertConfig {
|
|
||||||
"activation": "relu",
|
|
||||||
"attention_dropout": 0.4,
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن تعديل خصائص النموذج المدرب مسبقًا في دالة [`~PretrainedConfig.from_pretrained`] :
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> my_config = DistilBertConfig.from_pretrained("distilbert/distilbert-base-uncased", activation="relu", attention_dropout=0.4)
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد أن تصبح راضيًا عن تكوين نموذجك، يمكنك حفظه باستخدام [`~PretrainedConfig.save_pretrained`]. يتم تخزين ملف التكوين الخاص بك على أنه ملف JSON في دليل الحفظ المحدد:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> my_config.save_pretrained(save_directory="./your_model_save_path")
|
|
||||||
```
|
|
||||||
|
|
||||||
لإعادة استخدام ملف التكوين، قم بتحميله باستخدام [`~PretrainedConfig.from_pretrained`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/config.json")
|
|
||||||
```
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
يمكنك أيضًا حفظ ملف التكوين كقاموس أو حتى كفرق بين خصائص التكوين المُعدّلة والخصائص التكوين الافتراضية! راجع وثائق [التكوين](main_classes/configuration) لمزيد من التفاصيل.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
|
|
||||||
## النموذج
|
|
||||||
|
|
||||||
الخطوة التالية هي إنشاء [نموذج](main_classes/models). النموذج - ويُشار إليه أحيانًا باسم البنية - يُحدد وظيفة كل طبقة والعمليات الحسابية المُنفذة. تُستخدم خصائص مثل `num_hidden_layers` من التكوين لتحديد هذه البنية. تشترك جميع النماذج في فئة أساسية واحدة هي [`PreTrainedModel`] وبعض الوظائف المُشتركة مثل غيير حجم مُدخلات الكلمات وتقليص رؤوس آلية الانتباه الذاتي. بالإضافة إلى ذلك، فإن جميع النماذج هي فئات فرعية إما من [`torch.nn.Module`](https://pytorch.org/docs/stable/generated/torch.nn.Module.html)، [`tf.keras.Model`](https://www.tensorflow.org/api_docs/python/tf/keras/Model) أو [`flax.linen.Module`](https://flax.readthedocs.io/en/latest/api_reference/flax.linen/module.html) . هذا يعني النماذج متوافقة مع كل استخدام لإطار العمل الخاص بها.
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
قم بتحميل خصائص التكوين المخصصة الخاصة بك في النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DistilBertModel
|
|
||||||
|
|
||||||
>>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/config.json")
|
|
||||||
>>> model = DistilBertModel(my_config)
|
|
||||||
```
|
|
||||||
|
|
||||||
هذا ينشئ نموذجًا بقيم عشوائية بدلاً من الأوزان المُدربة مسبقًا. لن يكون هذا النموذج مفيدًا حتى يتم تدريبه. تُعد عملية التدريب مكلفة وتستغرق وقتًا طويلاً. من الأفضل بشكل عام استخدام نموذج مُدرب مسبقًا للحصول على نتائج أفضل بشكل أسرع، مع استخدام جزء بسيط فقط من الموارد المطلوبة للتدريب.
|
|
||||||
|
|
||||||
قم بإنشاء نموذج مُدرب مسبقًا باستخدام [`~PreTrainedModel.from_pretrained`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model = DistilBertModel.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
عند بتحميل الأوزان المُدربة مسبقًا، يتم تحميل تكوين النموذج الافتراضي تلقائيًا إذا كان النموذج من مكتبة 🤗 Transformers. ومع ذلك، يمكنك أيضًا استبدال - بعض أو كل - سإعدادات النموذج الافتراضية بإعداداتك الخاصة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model = DistilBertModel.from_pretrained("distilbert/distilbert-base-uncased"، config=my_config)
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
قم بتحميل خصائص التكوين المُخصصة الخاصة بك في النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFDistilBertModel
|
|
||||||
|
|
||||||
>>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/my_config.json")
|
|
||||||
>>> tf_model = TFDistilBertModel(my_config)
|
|
||||||
```
|
|
||||||
|
|
||||||
هذا ينشئ نموذجًا بقيم عشوائية بدلاً من الأوزان المُدربة مسبقًا. لن يكون هذا النموذج مفيدًا حتى يتم تدريبه. تُعد عملية التدريب مكلفة وتستغرق وقتًا طويلاً. من الأفضل بشكل عام استخدام نموذج مُدرب مسبقًا للحصول على نتائج أفضل بشكل أسرع، مع استخدام جزء بسيط فقط من الموارد المطلوبة للتدريب.
|
|
||||||
|
|
||||||
قم بإنشاء نموذج مُدرب مسبقًا باستخدام [`~TFPreTrainedModel.from_pretrained`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tf_model = TFDistilBertModel.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
عندما تقوم بتحميل الأوزان المُدربة مسبقًا،يتم تحميل إعدادات النموذج الافتراضي تلقائيًا إذا كان النموذج من مكتبة 🤗 Transformers. ومع ذلك، يمكنك أيضًا استبدال - بعض أو كل - إعدادات النموذج الافتراضية بإعداداتك الخاصة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tf_model = TFDistilBertModel.from_pretrained("distilbert/distilbert-base-uncased"، config=my_config)
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
### رؤوس النموذج
|
|
||||||
|
|
||||||
في هذه المرحلة، لديك نموذج DistilBERT الأساسي الذي يخرج *حالات الكامنة*. تُمرَّر هذه الحالات الكامنة كمدخلات لرأس النموذج لإنتاج المخرجات النهائية. توفر مكتبة 🤗 Transformers رأس نموذج مختلف لكل مهمة طالما أن النموذج يدعم المهمة (أي لا يمكنك استخدام DistilBERT لمهمة تسلسل إلى تسلسل مثل الترجمة).
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
على سبيل المثال، [`DistilBertForSequenceClassification`] هو نموذج DistilBERT الأساس مزودًا برأس تصنيف تسلسلي. يُشكّل رأس التصنيف التسلسلي طبقة خطية فوق المخرجات المجمعة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DistilBertForSequenceClassification
|
|
||||||
|
|
||||||
>>> model = DistilBertForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
أعد استخدام هذا نقطة التحقق هذه لمهمة أخرى بسهولة، وذلك بتغيير رأس النموذج.ففي مهمة الإجابة على الأسئلة، ستستخدم رأس النموذج [`DistilBertForQuestionAnswering`]. رأس الإجابة على الأسئلة مشابه لرأس التصنيف التسلسلي باستثناء أنه طبقة خطية فوق مخرجات الحالات الكامنة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DistilBertForQuestionAnswering
|
|
||||||
|
|
||||||
>>> model = DistilBertForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
على سبيل المثال، [`TFDistilBertForSequenceClassification`] هو نموذج DistilBERT الأساسي برأس تصنيف تسلسل. رأس التصنيف التسلسلي هو طبقة خطية أعلى المخرجات المجمعة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFDistilBertForSequenceClassification
|
|
||||||
|
|
||||||
>>> tf_model = TFDistilBertForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
أعد استخدام هذا نقطة التحقق لمهمة أخرى عن طريق التبديل إلى رأس نموذج مختلف. لمهمة الإجابة على الأسئلة، ستستخدم رأس النموذج [`TFDistilBertForQuestionAnswering`]. رأس الإجابة على الأسئلة مشابه لرأس التصنيف التسلسلي باستثناء أنه طبقة خطية أعلى حالات الإخراج المخفية.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFDistilBertForQuestionAnswering
|
|
||||||
|
|
||||||
>>> tf_model = TFDistilBertForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
## مجزئ النصوص
|
|
||||||
|
|
||||||
الفئة الأساسية الأخيرة التي تحتاجها قبل استخدام نموذج للبيانات النصية هي [مجزئ النصوص](main_classes/tokenizer) لتحويل النص الخام إلى تنسورات (tensors). هناك نوعان من المحولات الرموز التي يمكنك استخدامها مع 🤗 Transformers:
|
|
||||||
|
|
||||||
- [`PreTrainedTokenizer`]: تنفيذ Python لمجزئ النصوص.
|
|
||||||
- [`PreTrainedTokenizerFast`]: مجزئ النصوص من مكتبة [🤗 Tokenizer](https://huggingface.co/docs/tokenizers/python/latest/) المُبنية على لغة Rust. هذا النوع من المجزئات أسرع بكثير، خاصةً عند معالجة دفعات النصوص، وذلك بفضل تصميمه بلغة Rust. كما يوفر مجزئ النصوص السريع طرقًا إضافية مثل *مخطط الإزاحة* الذي يُطابق الرموز بكلماتها أو أحرفها الأصلية.
|
|
||||||
|
|
||||||
يدعم كلا النوعين من المجزئات طرقًا شائعة مثل الترميز وفك الترميز، وإضافة رموز جديدة، وإدارة الرموز الخاصة.
|
|
||||||
|
|
||||||
<Tip warning={true}>
|
|
||||||
|
|
||||||
لا يدعم كل نموذج مجزئ النصوص سريع. الق نظرة على هذا [جدول](index#supported-frameworks) للتحقق مما إذا كان النموذج يحتوي على دعم مجزئ النصوص سريع.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
إذا دربت مجزئ النصوص خاص بك، فيمكنك إنشاء واحد من *قاموسك*:```
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DistilBertTokenizer
|
|
||||||
|
|
||||||
>>> my_tokenizer = DistilBertTokenizer(vocab_file="my_vocab_file.txt"، do_lower_case=False، padding_side="left")
|
|
||||||
```
|
|
||||||
|
|
||||||
من المهم أن تتذكر أن قاموس مجزئ النصوص المُخصص سيكون مختلفًا عن قاموس مجزئ النصوص نموذج مُدرّب مسبقًا. يجب عليك استخدام قاموس نموذج مُدرّب مسبقًا إذا كنت تستخدم نموذجًا مُدرّبًا مسبقًا، وإلا فلن تكون المدخلات ذات معنى. قم بإنشاء مجزئ النصوص باستخدام قاموس نموذج مُدرّب مسبقًا باستخدام فئة [`DistilBertTokenizer`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DistilBertTokenizer
|
|
||||||
|
|
||||||
>>> slow_tokenizer = DistilBertTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بإنشاء مجزئ نصوص سريع باستخدام فئة [`DistilBertTokenizerFast`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DistilBertTokenizerFast
|
|
||||||
|
|
||||||
>>> fast_tokenizer = DistilBertTokenizerFast.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
افتراضيًا، سيحاول [`AutoTokenizer`] تحميل مجزئ نصوص سريع. يمكنك تعطيل هذا السلوك عن طريق تعيين `use_fast=False` في `from_pretrained`.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## معالج الصور
|
|
||||||
|
|
||||||
يعالج معالج الصور بيانات الرؤية. وهو يرث من الفئة الأساسية [`~image_processing_utils.ImageProcessingMixin`].
|
|
||||||
|
|
||||||
لبناء معالج صور خاص بالنموذج المستخدم، أنشئ مثلاً مُعالج [`ViTImageProcessor`] افتراضيًا إذا كنت تستخدم [ViT](model_doc/vit) لتصنيف الصور:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import ViTImageProcessor
|
|
||||||
|
|
||||||
>>> vit_extractor = ViTImageProcessor()
|
|
||||||
>>> print(vit_extractor)
|
|
||||||
ViTImageProcessor {
|
|
||||||
"do_normalize": true,
|
|
||||||
"do_resize": true,
|
|
||||||
"image_processor_type": "ViTImageProcessor",
|
|
||||||
"image_mean": [
|
|
||||||
0.5,
|
|
||||||
0.5,
|
|
||||||
0.5
|
|
||||||
],
|
|
||||||
"image_std": [
|
|
||||||
0.5,
|
|
||||||
0.5,
|
|
||||||
0.5
|
|
||||||
],
|
|
||||||
"resample": 2,
|
|
||||||
"size": 224
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا كنت لا تبحث عن أي تخصيص، فما عليك سوى استخدام طريقة `from_pretrained` لتحميل معلمات معالج الصور الافتراضية للنموذج.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
عدل أيًا من معلمات [`ViTImageProcessor`] لإنشاء معالج الصور المخصص الخاص بك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import ViTImageProcessor
|
|
||||||
|
|
||||||
>>> my_vit_extractor = ViTImageProcessor(resample="PIL.Image.BOX", do_normalize=False, image_mean=[0.3, 0.3, 0.3])
|
|
||||||
>>> print(my_vit_extractor)
|
|
||||||
ViTImageProcessor {
|
|
||||||
"do_normalize": false,
|
|
||||||
"do_resize": true,
|
|
||||||
"image_processor_type": "ViTImageProcessor",
|
|
||||||
"image_mean": [
|
|
||||||
0.3,
|
|
||||||
0.3,
|
|
||||||
0.3
|
|
||||||
],
|
|
||||||
"image_std": [
|
|
||||||
0.5,
|
|
||||||
0.5,
|
|
||||||
0.5
|
|
||||||
],
|
|
||||||
"resample": "PIL.Image.BOX",
|
|
||||||
"size": 224
|
|
||||||
}
|
|
||||||
```
|
|
||||||
## العمود الفقري
|
|
||||||
|
|
||||||
<div style="text-align: center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/Backbone.png">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
تتكون نماذج رؤية الحاسب من جزء أساسي، وجزء وسيط، وجزء معالجة نهائي. يستخرج الجزء الأساسي الميزات من صورة الإدخال، ويجمع الجزء الوسيط هذه الميزات المستخرجة ويعززها، ويُستخدم الجزء النهائي للمهمة الرئيسية (مثل اكتشاف الأجسام). ابدأ عبتهيئة الجزء الأساسي في تكوين النموذج وحدد ما إذا كنت تريد تحميل أوزان مدربة مسبقًا أو أوزانًا عشوائية. بعد ذلك، يمكنك تمرير تكوين النموذج إلى جزء المعالجة النهائي.
|
|
||||||
|
|
||||||
على سبيل المثال، لتحميل [ResNet](../model_doc/resnet) backbone في نموذج [MaskFormer](../model_doc/maskformer) مع رأس تجزئة مثيل:
|
|
||||||
|
|
||||||
<hfoptions id="backbone">
|
|
||||||
<hfoption id="pretrained weights">
|
|
||||||
|
|
||||||
قم بتعيين `use_pretrained_backbone=True` لتحميل الأوزان المسبقة التدريب لـ ResNet للعمود الفقري.
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation
|
|
||||||
|
|
||||||
config = MaskFormerConfig(backbone="microsoft/resnet-50", use_pretrained_backbone=True) # تكوين الجزء الأساسي والجزء الوسيط
|
|
||||||
model = MaskFormerForInstanceSegmentation(config) # جزء المعالجة النهائي
|
|
||||||
```
|
|
||||||
|
|
||||||
</hfoption>
|
|
||||||
<hfoption id="random weights">
|
|
||||||
|
|
||||||
قم بتعيين `use_pretrained_backbone=False` لتهيئة جزء ResNet الأساسي بشكل عشوائي.
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation
|
|
||||||
|
|
||||||
config = MaskFormerConfig(backbone="microsoft/resnet-50", use_pretrained_backbone=False) # تكوين الجزء الأساسي والجزء الوسيط
|
|
||||||
model = MaskFormerForInstanceSegmentation(config) # جزء المعالجة النهائي
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك أيضًا تحميل تكوين الجزء الأساسي بشكل منفصل، ثم تمريره إلى تكوين النموذج.```
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation, ResNetConfig
|
|
||||||
|
|
||||||
backbone_config = ResNetConfig()
|
|
||||||
config = MaskFormerConfig(backbone_config=backbone_config)
|
|
||||||
model = MaskFormerForInstanceSegmentation(config)
|
|
||||||
```
|
|
||||||
|
|
||||||
</hfoption>
|
|
||||||
<hfoption id="timm backbone">
|
|
||||||
|
|
||||||
يتم تحميل نماذج [timm](https://hf.co/docs/timm/index) داخل نموذج باستخدام `use_timm_backbone=True` أو باستخدام [`TimmBackbone`] و [`TimmBackboneConfig`].
|
|
||||||
|
|
||||||
استخدم `use_timm_backbone=True` و `use_pretrained_backbone=True` لتحميل أوزان timm المُدرّبة مسبقًا للجزء الأساسي.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation
|
|
||||||
|
|
||||||
config = MaskFormerConfig(backbone="resnet50", use_pretrained_backbone=True, use_timm_backbone=True) # تكوين الجزء الأساسي والجزء الوسيط
|
|
||||||
model = MaskFormerForInstanceSegmentation(config) # جزء المعالجة النهائي
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتعيين `use_timm_backbone=True` و `use_pretrained_backbone=False` لتحميل عمود فقري timm مبدئي عشوائي.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation
|
|
||||||
|
|
||||||
config = MaskFormerConfig(backbone="resnet50", use_pretrained_backbone=False, use_timm_backbone=True) # تكوين الجزء الأساسي والجزء الوسيط
|
|
||||||
model = MaskFormerForInstanceSegmentation(config) # جزء المعالجة النهائي
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك أيضًا تحميل تكوين الجزء الأساسي واستخدامه لإنشاء `TimmBackbone` أو تمريره إلى تكوين النموذج. سيتم تحميلأوزان الجزء الأساسي لـ Timm المُدرّبة مسبقًا افتراضيًا. عيّن `use_pretrained_backbone=False` لتحميل الأوزان المبدئية العشوائية.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import TimmBackboneConfig, TimmBackbone
|
|
||||||
|
|
||||||
backbone_config = TimmBackboneConfig("resnet50", use_pretrained_backbone=False)
|
|
||||||
|
|
||||||
# قم بإنشاء مثيل من العمود الفقري
|
|
||||||
backbone = TimmBackbone(config=backbone_config)
|
|
||||||
|
|
||||||
# قم بإنشاء نموذج باستخدام عمود فقري timm
|
|
||||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation
|
|
||||||
|
|
||||||
config = MaskFormerConfig(backbone_config=backbone_config)
|
|
||||||
model = MaskFormerForInstanceSegmentation(config)
|
|
||||||
```
|
|
||||||
|
|
||||||
## مستخرج الميزات
|
|
||||||
|
|
||||||
يقوم مُستخرج الميزات بمعالجة المدخلات الصوتية. يرث من فئة الأساس [`~feature_extraction_utils.FeatureExtractionMixin`]، وقد يرث أيضًا من فئة [`SequenceFeatureExtractor`] لمعالجة المدخلات الصوتية.
|
|
||||||
|
|
||||||
للاستخدام، قم بإنشاء مستخرج ميزات مرتبط بالنموذج الذي تستخدمه. على سبيل المثال، قم بإنشاء مستخرج ميزات Wav2Vec2 الافتراضي إذا كنت تستخدم [Wav2Vec2](model_doc/wav2vec2) لتصنيف الصوت:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import Wav2Vec2FeatureExtractor
|
|
||||||
|
|
||||||
>>> w2v2_extractor = Wav2Vec2FeatureExtractor()
|
|
||||||
>>> print(w2v2_extractor)
|
|
||||||
Wav2Vec2FeatureExtractor {
|
|
||||||
"do_normalize": true,
|
|
||||||
"feature_extractor_type": "Wav2Vec2FeatureExtractor",
|
|
||||||
"feature_size": 1,
|
|
||||||
"padding_side": "right",
|
|
||||||
"padding_value": 0.0,
|
|
||||||
"return_attention_mask": false,
|
|
||||||
"sampling_rate": 16000
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
إذا لم تكن بحاجة لأي تخصيص، فاستخدم فقط طريقة `from_pretrained` لتحميل معلمات مستخرج الميزات الافتراضية للنموذج.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
قم بتعديل أي من معلمات [`Wav2Vec2FeatureExtractor`] لإنشاء مستخرج ميزات مخصص:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import Wav2Vec2FeatureExtractor
|
|
||||||
|
|
||||||
>>> w2v2_extractor = Wav2Vec2FeatureExtractor(sampling_rate=8000، do_normalize=False)
|
|
||||||
>>> print(w2v2_extractor)
|
|
||||||
Wav2Vec2FeatureExtractor {
|
|
||||||
"do_normalize": false,
|
|
||||||
"feature_extractor_type": "Wav2Vec2FeatureExtractor"،
|
|
||||||
"feature_size": 1،
|
|
||||||
"padding_side": "right"،
|
|
||||||
"padding_value": 0.0،
|
|
||||||
"return_attention_mask": false،
|
|
||||||
"sampling_rate": 8000
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## المعالج
|
|
||||||
|
|
||||||
بالنسبة للنماذج التي تدعم مهام الوسائط المتعددة، توفر مكتبة 🤗 Transformers فئة معالج تجمع بفاعلية فئات المعالجة مثل مستخرج الميزات ومقسّم الرموز في كائن واحد. على سبيل المثال، دعنا نستخدم [`Wav2Vec2Processor`] لمهمة التعرف الآلي على الكلام (ASR). تقوم مهمة ASR بتحويل الصوت إلى نص، لذلك ستحتاج إلى مستخرج ميزات ومقسّم رموز.
|
|
||||||
|
|
||||||
قم بإنشاء مستخرج ميزات لمعالجة المدخلات الصوتية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import Wav2Vec2FeatureExtractor
|
|
||||||
|
|
||||||
>>> feature_extractor = Wav2Vec2FeatureExtractor(padding_value=1.0, do_normalize=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بإنشاء مقسّم رموز لمعالجة المدخلات النصية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import Wav2Vec2CTCTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = Wav2Vec2CTCTokenizer(vocab_file="my_vocab_file.txt")
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بدمج مستخرج الميزات ومقسّم الرموز في [`Wav2Vec2Processor`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import Wav2Vec2Processor
|
|
||||||
|
|
||||||
>>> processor = Wav2Vec2Processor(feature_extractor=feature_extractor, tokenizer=tokenizer)
|
|
||||||
```
|
|
||||||
|
|
||||||
باستخدام فئتين أساسيتين - التكوين والنموذج - بالإضافة إلى فئة معالجة مسبق (مقسّم رموز أو معالج صورة أو مستخرج ميزات أو معالج)، يمكنك إنشاء أي من النماذج التي تدعمها مكتبة 🤗 Transformers. يمكن تكوين كل من هذه الفئات الأساسية، مما يسمح لك باستخدام السمات المطلوبة. يمكنك بسهولة تهيئة نموذج للتدريب أو تعديل نموذج مدرب مسبقاً لإجراء ضبط دقيق.
|
|
||||||
@ -1,323 +0,0 @@
|
|||||||
# بناء نماذج مخصصة
|
|
||||||
|
|
||||||
تم تصميم مكتبة 🤗 Transformers لتكون قابلة للتوسيع بسهولة. كل نموذج مُشفّر بالكامل في مجلد فرعي معين بالمستودع، دون أي تجريد، لذلك يمكنك بسهولة نسخ ملف النمذجة وتعديله وفقًا لاحتياجاتك.
|
|
||||||
|
|
||||||
إذا كنت تُنشئ نموذجًا جديدًا تمامًا، فقد يكون من الأسهل البدء من الصفر. في هذا البرنامج التعليمي، سنُرِيك كيفية كتابة نموذج مخصص وتكوينه ليُستخدم داخل Transformers، وكيفية مشاركته مع المجتمع (مع الكود الذي يعتمد عليه) بحيث يمكن لأي شخص استخدامه، حتى إذا لم يكن موجودًا في مكتبة 🤗 Transformers. سنرى كيفية البناء على المحولات ونوسّع الإطار باستخدام الأدوات التي يمكن استخدامها لتعديل سلوك الإطار (hooks) والتعليمات البرمجية المخصصة.
|
|
||||||
|
|
||||||
سنوضح كل هذا من خلال نموذج ResNet، بتغليف فئة ResNet من
|
|
||||||
[مكتبة timm](https://github.com/rwightman/pytorch-image-models) داخل [`PreTrainedModel`].
|
|
||||||
|
|
||||||
## كتابة إعدادات مخصصة
|
|
||||||
|
|
||||||
لنبدأ بكتابة إعدادات النموذج. إعدادات النموذج هو كائنٌ يحتوي على جميع المعلومات اللازمة لبنائه. كما سنرى لاحقًا، يتطلب النموذج كائن `config` لتهيئته، لذا يجب أن يكون هذا الكائن كاملاً.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
تتبع النماذج في مكتبة `transformers` اتفاقية قبول كائن `config` في دالة `__init__` الخاصة بها، ثم تمرر كائن `config` بالكامل إلى الطبقات الفرعية في النموذج، بدلاً من تقسيمه إلى معامﻻت متعددة. يؤدي كتابة نموذجك بهذا الأسلوب إلى كود أبسط مع "مصدر حقيقة" واضح لأي فرط معلمات، كما يسهل إعادة استخدام الكود من نماذج أخرى في `transformers`.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
في مثالنا، سنعدّل بعض الوسائط في فئة ResNet التي قد نرغب في ضبطها. ستعطينا التكوينات المختلفة أنواع ResNets المختلفة الممكنة. سنقوم بتخزين هذه الوسائط بعد التحقق من صحته.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import PretrainedConfig
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
|
|
||||||
class ResnetConfig(PretrainedConfig):
|
|
||||||
model_type = "resnet"
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
block_type="bottleneck",
|
|
||||||
layers: List[int] = [3, 4, 6, 3],
|
|
||||||
num_classes: int = 1000,
|
|
||||||
input_channels: int = 3,
|
|
||||||
cardinality: int = 1,
|
|
||||||
base_width: int = 64,
|
|
||||||
stem_width: int = 64,
|
|
||||||
stem_type: str = "",
|
|
||||||
avg_down: bool = False,
|
|
||||||
**kwargs,
|
|
||||||
):
|
|
||||||
if block_type not in ["basic", "bottleneck"]:
|
|
||||||
raise ValueError(f"`block_type` must be 'basic' or bottleneck', got {block_type}.")
|
|
||||||
if stem_type not in ["", "deep", "deep-tiered"]:
|
|
||||||
raise ValueError(f"`stem_type` must be '', 'deep' or 'deep-tiered', got {stem_type}.")
|
|
||||||
|
|
||||||
self.block_type = block_type
|
|
||||||
self.layers = layers
|
|
||||||
self.num_classes = num_classes
|
|
||||||
self.input_channels = input_channels
|
|
||||||
self.cardinality = cardinality
|
|
||||||
self.base_width = base_width
|
|
||||||
self.stem_width = stem_width
|
|
||||||
self.stem_type = stem_type
|
|
||||||
self.avg_down = avg_down
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
```
|
|
||||||
الأشياء الثلاثة المهمة التي يجب تذكرها عند كتابة تكوينك الخاص هي:
|
|
||||||
|
|
||||||
- يجب أن ترث من `PretrainedConfig`،
|
|
||||||
- يجب أن تقبل دالة `__init__` الخاصة بـ `PretrainedConfig` أي معامﻻت إضافية kwargs،
|
|
||||||
- يجب تمرير هذه المعامﻻت الإضافية إلى دالة `__init__` فى الفئة الأساسية الاعلى.
|
|
||||||
|
|
||||||
يضمن الإرث حصولك على جميع الوظائف من مكتبة 🤗 Transformers، في حين أن القيدين التانى والثالث يأتيان من حقيقة أن `PretrainedConfig` لديه المزيد من الحقول أكثر من تلك التي تقوم بتعيينها. عند إعادة تحميل تكوين باستخدام طريقة `from_pretrained`، يجب أن يقبل تكوينك هذه الحقول ثم إرسالها إلى الفئة الأساسية الأعلى.
|
|
||||||
|
|
||||||
تحديد `model_type` لتكوينك (هنا `model_type="resnet"`) ليس إلزاميًا، ما لم ترغب في
|
|
||||||
تسجيل نموذجك باستخدام الفئات التلقائية (راجع القسم الأخير).
|
|
||||||
|
|
||||||
مع القيام بذلك، يمكنك بسهولة إنشاء تكوينك وحفظه مثلما تفعل مع أي تكوين نموذج آخر في
|
|
||||||
المكتبة. إليك كيفية إنشاء تكوين resnet50d وحفظه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True)
|
|
||||||
resnet50d_config.save_pretrained("custom-resnet")
|
|
||||||
```
|
|
||||||
|
|
||||||
سيؤدي هذا إلى حفظ ملف باسم `config.json` داخل مجلد `custom-resnet`. يمكنك بعد ذلك إعادة تحميل تكوينك باستخدام
|
|
||||||
طريقة `from_pretrained`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
resnet50d_config = ResnetConfig.from_pretrained("custom-resnet")
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك أيضًا استخدام أي طريقة أخرى من فئة [`PretrainedConfig`]، مثل [`~PretrainedConfig.push_to_hub`] لتحميل تكوينك مباشرة إلى Hub.
|
|
||||||
|
|
||||||
## كتابة نموذج مخصص
|
|
||||||
|
|
||||||
الآن بعد أن أصبح لدينا تكوين ResNet، يمكننا المتابعة لإنشاء نموذجين: الأول يستخرج الميزات المخفية من دفعة من الصور (مثل [`BertModel`]) والآخر مناسب لتصنيف الصور (مثل [`BertForSequenceClassification`]).
|
|
||||||
|
|
||||||
كما ذكرنا سابقًا، سنقوم ببناء نموذج مبسط لتسهيل الفهم في هذا المثال. الخطوة الوحيدة المطلوبة قبل كتابة هذه الفئة هي لربط أنواع وحدات البناء بفئات ذات وحدات بناء فعلية. بعد ذلك، يُعرّف النموذج من خلال التكوين عبر تمرير كل شيء إلى فئة `ResNet`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import PreTrainedModel
|
|
||||||
from timm.models.resnet import BasicBlock, Bottleneck, ResNet
|
|
||||||
from .configuration_resnet import ResnetConfig
|
|
||||||
|
|
||||||
|
|
||||||
BLOCK_MAPPING = {"basic": BasicBlock, "bottleneck": Bottleneck}
|
|
||||||
|
|
||||||
|
|
||||||
class ResnetModel(PreTrainedModel):
|
|
||||||
config_class = ResnetConfig
|
|
||||||
|
|
||||||
def __init__(self, config):
|
|
||||||
super().__init__(config)
|
|
||||||
block_layer = BLOCK_MAPPING[config.block_type]
|
|
||||||
self.model = ResNet(
|
|
||||||
block_layer,
|
|
||||||
config.layers,
|
|
||||||
num_classes=config.num_classes,
|
|
||||||
in_chans=config.input_channels,
|
|
||||||
cardinality=config.cardinality,
|
|
||||||
base_width=config.base_width,
|
|
||||||
stem_width=config.stem_width,
|
|
||||||
stem_type=config.stem_type,
|
|
||||||
avg_down=config.avg_down,
|
|
||||||
)
|
|
||||||
|
|
||||||
def forward(self, tensor):
|
|
||||||
return self.model.forward_features(tensor)
|
|
||||||
```
|
|
||||||
|
|
||||||
بالنسبة للنموذج الذي سيصنف الصور، فإننا نغير فقط طريقة التقديم:
|
|
||||||
|
|
||||||
```py
|
|
||||||
import torch
|
|
||||||
|
|
||||||
|
|
||||||
class ResnetModelForImageClassification(PreTrainedModel):
|
|
||||||
config_class = ResnetConfig
|
|
||||||
|
|
||||||
def __init__(self, config):
|
|
||||||
super().__init__(config)
|
|
||||||
block_layer = BLOCK_MAPPING[config.block_type]
|
|
||||||
self.model = ResNet(
|
|
||||||
block_layer,
|
|
||||||
config.layers,
|
|
||||||
num_classes=config.num_classes,
|
|
||||||
in_chans=config.input_channels,
|
|
||||||
cardinality=config.cardinality,
|
|
||||||
base_width=config.base_width,
|
|
||||||
stem_width=config.stem_width,
|
|
||||||
stem_type=config.stem_type,
|
|
||||||
avg_down=config.avg_down,
|
|
||||||
)
|
|
||||||
|
|
||||||
def forward(self, tensor, labels=None):
|
|
||||||
logits = self.model(tensor)
|
|
||||||
if labels is not None:
|
|
||||||
loss = torch.nn.cross_entropy(logits, labels)
|
|
||||||
return {"loss": loss, "logits": logits}
|
|
||||||
return {"logits": logits}
|
|
||||||
```
|
|
||||||
في كلتا الحالتين، لاحظ كيف نرث من `PreTrainedModel` ونستدعي مُهيئ الفئة الرئيسية باستخدام `config` (كما تفعل عند إنشاء وحدة `torch.nn.Module` عادية). ليس من الضروري تعريف `config_class` إلا إذا كنت ترغب في تسجيل نموذجك مع الفئات التلقائية (راجع القسم الأخير).
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا كان نموذجك مشابهًا جدًا لنموذج داخل المكتبة، فيمكنك إعادة استخدام نفس التكوين مثل هذا النموذج.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
يمكن لنموذجك أن يعيد أي شيء تريده، ولكن إعادة قاموس مثلما فعلنا لـ
|
|
||||||
`ResnetModelForImageClassification`، مع تضمين الخسارة عند تمرير العلامات، سيجعل نموذجك قابلًا للاستخدام مباشرة داخل فئة [`Trainer`]. يعد استخدام تنسيق إخراج آخر أمرًا جيدًا طالما أنك تخطط لاستخدام حلقة تدريب خاصة بك أو مكتبة أخرى للتدريب.
|
|
||||||
|
|
||||||
الآن بعد أن أصبح لدينا فئة النموذج، دعنا ننشئ واحدة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
resnet50d = ResnetModelForImageClassification(resnet50d_config)
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك استخدام أي من طرق فئة [`PreTrainedModel`]، مثل [`~PreTrainedModel.save_pretrained`] أو
|
|
||||||
[`~PreTrainedModel.push_to_hub`]. سنستخدم الثاني في القسم التالي، وسنرى كيفية دفع أوزان النموذج مع كود نموذجنا. ولكن أولاً، دعنا نحمل بعض الأوزان المُعلمة مسبقًا داخل نموذجنا.
|
|
||||||
|
|
||||||
في حالة الاستخدام الخاصة بك، فمن المحتمل أن تقوم بتدريب نموذجك المخصص على بياناتك الخاصة. للانتقال بسرعة خلال هذا البرنامج التعليمي،
|
|
||||||
سنستخدم الإصدار المُعلم مسبقًا من resnet50d. نظرًا لأن نموذجنا هو مجرد غلاف حوله، فمن السهل نقل هذه الأوزان:
|
|
||||||
|
|
||||||
```py
|
|
||||||
import timm
|
|
||||||
|
|
||||||
pretrained_model = timm.create_model("resnet50d", pretrained=True)
|
|
||||||
resnet50d.model.load_state_dict(pretrained_model.state_dict())
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن دعونا نرى كيفية التأكد من أنه عند قيامنا بـ [`~PreTrainedModel.save_pretrained`] أو [`~PreTrainedModel.push_to_hub`]، يتم حفظ كود النموذج.
|
|
||||||
|
|
||||||
## تسجيل نموذج مع كود مخصص للفئات التلقائية
|
|
||||||
|
|
||||||
إذا كنت تكتب مكتبة توسع 🤗 Transformers، فقد ترغب في توسيع الفئات التلقائية لتشمل نموذجك الخاص. يختلف هذا عن نشر الكود إلى Hub بمعنى أن المستخدمين سيحتاجون إلى استيراد مكتبتك للحصول على النماذج المخصصة (على عكس تنزيل كود النموذج تلقائيًا من Hub).
|
|
||||||
|
|
||||||
ما دام تكوينك يحتوي على معامل `model_type` مختلفة عن أنواع النماذج الحالية، وأن فئات نماذجك لديك لديها الخصائص الصحيحة `config_class`، فيمكنك ببساطة إضافتها إلى الفئات التلقائية مثل هذا:
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import AutoConfig, AutoModel, AutoModelForImageClassification
|
|
||||||
|
|
||||||
AutoConfig.register("resnet", ResnetConfig)
|
|
||||||
AutoModel.register(ResnetConfig, ResnetModel)
|
|
||||||
AutoModelForImageClassification.register(ResnetConfig, ResnetModelForImageClassification)
|
|
||||||
```
|
|
||||||
|
|
||||||
لاحظ أن الحجة الأولى المستخدمة عند تسجيل تكوينك المخصص لـ [`AutoConfig`] يجب أن تتطابق مع `model_type`
|
|
||||||
من تكوينك المخصص، والحجة الأولى المستخدمة عند تسجيل نماذجك المخصصة لأي فئة نموذج تلقائي يجب
|
|
||||||
أن تتطابق مع `config_class` من تلك النماذج.
|
|
||||||
|
|
||||||
## إرسال الكود إلى Hub
|
|
||||||
|
|
||||||
<Tip warning={true}>
|
|
||||||
|
|
||||||
هذا API تجريبي وقد يكون له بعض التغييرات الطفيفة في الإصدارات القادمة.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
أولاً، تأكد من تعريف نموذجك بالكامل في ملف `.py`. يمكن أن يعتمد على الاستيراد النسبي لملفات أخرى طالما أن جميع الملفات موجودة في نفس الدليل (لا ندعم الوحدات الفرعية لهذه الميزة حتى الآن). في مثالنا، سنحدد ملف `modeling_resnet.py` وملف `configuration_resnet.py` في مجلد باسم "resnet_model" في دليل العمل الحالي. يحتوي ملف التكوين على كود لـ `ResnetConfig` ويحتوي ملف النمذجة على كود لـ `ResnetModel` و`ResnetModelForImageClassification`.
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
└── resnet_model
|
|
||||||
├── __init__.py
|
|
||||||
├── configuration_resnet.py
|
|
||||||
└── modeling_resnet.py
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن أن يكون ملف `__init__.py` فارغًا، فهو موجود فقط حتى يتمكن Python من اكتشاف أن `resnet_model` يمكن استخدامه كموديل.
|
|
||||||
|
|
||||||
<Tip warning={true}>
|
|
||||||
|
|
||||||
إذا كنت تقوم بنسخ ملفات النمذجة من المكتبة، فسوف تحتاج إلى استبدال جميع الواردات النسبية في أعلى الملف
|
|
||||||
لاستيرادها من حزمة `transformers`.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
لاحظ أنه يمكنك إعادة استخدام (أو توسيع) تكوين/نموذج موجود.
|
|
||||||
|
|
||||||
لمشاركة نموذجك مع المجتمع، اتبع الخطوات التالية: أولاً، قم باستيراد نموذج ResNet والتكوين من الملفات التي تم إنشاؤها حديثًا:
|
|
||||||
|
|
||||||
```py
|
|
||||||
from resnet_model.configuration_resnet import ResnetConfig
|
|
||||||
from resnet_model.modeling_resnet import ResnetModel, ResnetModelForImageClassification
|
|
||||||
```
|
|
||||||
|
|
||||||
بعد ذلك، يجب عليك إخبار المكتبة بأنك تريد نسخ ملفات الكود الخاصة بهذه الكائنات عند استخدام طريقة `save_pretrained`
|
|
||||||
وتسجيلها بشكل صحيح باستخدام فئة تلقائية (خاصة للنماذج)، ما عليك سوى تشغيل:
|
|
||||||
|
|
||||||
```py
|
|
||||||
ResnetConfig.register_for_auto_class()
|
|
||||||
ResnetModel.register_for_auto_class("AutoModel")
|
|
||||||
ResnetModelForImageClassification.register_for_auto_class("AutoModelForImageClassification")
|
|
||||||
```
|
|
||||||
|
|
||||||
لاحظ أنه لا توجد حاجة لتحديد فئة تلقائية للتكوين (هناك فئة تلقائية واحدة فقط لها،
|
|
||||||
[`AutoConfig`]) ولكن الأمر يختلف بالنسبة للنماذج. قد يكون نموذجك المخصص مناسبًا للعديد من المهام المختلفة، لذلك يجب
|
|
||||||
تحديد أي من الفئات التلقائية هو الصحيح لنموذجك.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
استخدم `register_for_auto_class()` إذا كنت تريد نسخ ملفات الكود. إذا كنت تفضل استخدام الكود على Hub من مستودع آخر،
|
|
||||||
فلا تحتاج إلى استدعائه. في الحالات التي يوجد فيها أكثر من فئة تلقائية واحدة، يمكنك تعديل ملف `config.json` مباشرة باستخدام
|
|
||||||
الهيكل التالي:
|
|
||||||
|
|
||||||
```json
|
|
||||||
"auto_map": {
|
|
||||||
"AutoConfig": "<your-repo-name>--<config-name>",
|
|
||||||
"AutoModel": "<your-repo-name>--<config-name>",
|
|
||||||
"AutoModelFor<Task>": "<your-repo-name>--<config-name>",
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
بعد ذلك، دعنا نقوم بإنشاء التكوين والنماذج كما فعلنا من قبل:
|
|
||||||
|
|
||||||
```py
|
|
||||||
resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True)
|
|
||||||
resnet50d = ResnetModelForImageClassification(resnet50d_config)
|
|
||||||
|
|
||||||
pretrained_model = timm.create_model("resnet50d", pretrained=True)
|
|
||||||
resnet50d.model.load_state_dict(pretrained_model.state_dict())
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن لإرسال النموذج إلى Hub، تأكد من تسجيل الدخول. إما تشغيل في المحطة الأوامر الطرفية الخاصة بك:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
huggingface-cli login
|
|
||||||
```
|
|
||||||
|
|
||||||
أو من دفتر ملاحظات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
from huggingface_hub import notebook_login
|
|
||||||
|
|
||||||
notebook_login()
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك بعد ذلك الضغط على مساحة الاسم الخاصة بك (أو منظمة أنت عضو فيها) مثل هذا:
|
|
||||||
|
|
||||||
```py
|
|
||||||
resnet50d.push_to_hub("custom-resnet50d")
|
|
||||||
```
|
|
||||||
|
|
||||||
بالإضافة إلى أوزان النمذجة والتكوين بتنسيق json، فقد قام هذا أيضًا بنسخ ملفات النمذجة والتكوين `.py` في مجلد `custom-resnet50d` وتحميل النتيجة إلى Hub. يمكنك التحقق من النتيجة في هذا [مستودع النموذج](https://huggingface.co/sgugger/custom-resnet50d).
|
|
||||||
|
|
||||||
راجع [البرنامج التعليمي للمشاركة](model_sharing) لمزيد من المعلومات حول طريقة الدفع إلى المحور.
|
|
||||||
|
|
||||||
### استخدام نموذج مع كود مخصص
|
|
||||||
|
|
||||||
يمكنك استخدام أي تكوين أو نموذج أو مقسم لغوي مع ملفات برمجة مخصصة في مستودعه باستخدام الفئات التلقائية و دالة `from_pretrained`.تُفحص جميع الملفات والرموز المرفوع إلى Hub بحثًا عن البرامج الضارة (راجع وثائق [أمان Hub](https://huggingface.co/docs/hub/security#malware-scanning) لمزيد من المعلومات)، ولكن يجب عليك مراجعة كود النموذج والمؤلف لتجنب تنفيذ التعليمات البرمجية الضارة على جهازك. لتفعيل نموذج يحتوي على شفرة برمجية مخصصة، عيّن `trust_remote_code=True`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import AutoModelForImageClassification
|
|
||||||
|
|
||||||
model = AutoModelForImageClassification.from_pretrained("sgugger/custom-resnet50d", trust_remote_code=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
يُنصح بشدة بتحديد رقم إصدار (commit hash) كـ `revision` للتأكد من عدم تعديل مؤلف النموذج للشفرة لاحقًابإضافة أسطر ضارة (إلا إذا كنت تثق تمامًا بمؤلفي النموذج):
|
|
||||||
|
|
||||||
```py
|
|
||||||
commit_hash = "ed94a7c6247d8aedce4647f00f20de6875b5b292"
|
|
||||||
model = AutoModelForImageClassification.from_pretrained(
|
|
||||||
"sgugger/custom-resnet50d"، trust_remote_code=True، revision=commit_hash
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
لاحظ وجود زرّ لنسخ رقم إصدار بسهولة عند تصفح سجل التزامات مستودع النموذج على منصة Hugging Face.
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
# استخدام مجزئيات النصوص من 🤗 Tokenizers
|
|
||||||
|
|
||||||
يعتمد [`PreTrainedTokenizerFast`] على مكتبة [🤗 Tokenizers](https://huggingface.co/docs/tokenizers). يمكن تحميل المجزئات اللغويين الذين تم الحصول عليهم من مكتبة 🤗 Tokenizers ببساطة شديدة في 🤗 Transformers.
|
|
||||||
|
|
||||||
قبل الدخول في التفاصيل، دعونا نبدأ أولاً بإنشاء مُجزىء لغوي تجريبي في بضع سطور:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from tokenizers import Tokenizer
|
|
||||||
>>> from tokenizers.models import BPE
|
|
||||||
>>> from tokenizers.trainers import BpeTrainer
|
|
||||||
>>> from tokenizers.pre_tokenizers import Whitespace
|
|
||||||
|
|
||||||
>>> tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
|
|
||||||
>>> trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])
|
|
||||||
|
|
||||||
>>> tokenizer.pre_tokenizer = Whitespace()
|
|
||||||
>>> files = [...]
|
|
||||||
>>> tokenizer.train(files, trainer)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن لدينا مُجزىء لغوي مدرب على الملفات التي حددناها. يمكننا إما الاستمرار في استخدامه في وقت التشغيل هذا، أو حفظه في ملف JSON لإعادة استخدامه لاحقًا.
|
|
||||||
|
|
||||||
## تحميل مُجزئ النّصوص مُباشرةً
|
|
||||||
|
|
||||||
دعونا نرى كيف يمكننا الاستفادة من كائن (مُجزئ النصوص) في مكتبة 🤗 Transformers. تسمح فئة [`PreTrainedTokenizerFast`] سهولة إنشاء *tokenizer*، من خلال قبول كائن *المُجزئ النصوص* مُهيّأ مُسبقًا كمعامل:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import PreTrainedTokenizerFast
|
|
||||||
|
|
||||||
>>> fast_tokenizer = PreTrainedTokenizerFast(tokenizer_object=tokenizer)
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن الآن استخدام هذا الكائن مع جميع الطرق المُشتركة بين مُجزّئي النّصوص لـ 🤗 Transformers! انتقل إلى [صفحة مُجزّئ النّصوص](main_classes/tokenizer) لمزيد من المعلومات.
|
|
||||||
|
|
||||||
## التحميل من ملف JSON
|
|
||||||
|
|
||||||
لتحميل مُجزّئ النص من ملف JSON، دعونا نبدأ أولاً بحفظ مُجزّئ النّصوص:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> tokenizer.save("tokenizer.json")
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن تمرير المسار الذي حفظنا به هذا الملف إلى طريقة تهيئة [`PreTrainedTokenizerFast`] باستخدام المُعامل `tokenizer_file`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import PreTrainedTokenizerFast
|
|
||||||
|
|
||||||
>>> fast_tokenizer = PreTrainedTokenizerFast(tokenizer_file="tokenizer.json")
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن الآن استخدام هذا الكائن مع جميع الطرق التي تشترك فيها مُجزّئي النّصوص لـ 🤗 Transformers! انتقل إلى [صفحة مُجزّئ النص](main_classes/tokenizer) لمزيد من المعلومات.
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
# GGUF وتفاعلها مع المحولات
|
|
||||||
|
|
||||||
تُستخدم صيغة ملف GGUF لتخزين النماذج للاستدلال باستخدام [GGML](https://github.com/ggerganov/ggml) والمكتبات الأخرى التي تعتمد عليه، مثل [llama.cpp](https://github.com/ggerganov/llama.cpp) أو [whisper.cpp](https://github.com/ggerganov/whisper.cpp) الشهيرة جدًا.
|
|
||||||
|
|
||||||
إنها صيغة ملف [مدعومة من قبل Hugging Face Hub](https://huggingface.co/docs/hub/en/gguf) مع ميزات تسمح بالفحص السريع للموترات والبيانات الوصفية داخل الملف.
|
|
||||||
|
|
||||||
تم تصميم تنسيق الملف هذا كـ "تنسيق ملف واحد" حيث يحتوي ملف واحد عادةً على كل من سمات التكوين ومفردات المجزىء اللغوي والخصائص الأخرى، بالإضافة إلى جميع الموترات التي سيتم تحميلها في النموذج. تأتي هذه الملفات بتنسيقات مختلفة وفقًا لنوع التكميم في الملف. نلقي نظرة موجزة على بعضها [هنا](https://huggingface.co/docs/hub/en/gguf#quantization-types).
|
|
||||||
|
|
||||||
## الدعم داخل المحولات
|
|
||||||
|
|
||||||
أضفنا القدرة على تحميل ملفات `gguf` داخل `المحولات` لتوفير قدرات تدريب/ضبط إضافية لنماذج gguf، قبل إعادة تحويل تلك النماذج إلى `gguf` لاستخدامها داخل نظام `ggml`. عند تحميل نموذج، نقوم أولاً بإلغاء تكميمه إلى fp32، قبل تحميل الأوزان لاستخدامها في PyTorch.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> لا يزال الدعم تجريبيًا للغاية ونرحب بالمساهمات من أجل ترسيخه عبر أنواع التكميم وبنى النماذج.
|
|
||||||
|
|
||||||
فيما يلي، بنيات النماذج وأنواع التكميم المدعومة:
|
|
||||||
|
|
||||||
### أنواع التكميم المدعومة
|
|
||||||
|
|
||||||
تُحدد أنواع التكميم المدعومة مبدئيًا وفقًا لملفات التكميم الشائعة التي تمت مشاركتها على Hub.
|
|
||||||
|
|
||||||
- F32
|
|
||||||
- F16
|
|
||||||
- BF16
|
|
||||||
- Q4_0
|
|
||||||
- Q4_1
|
|
||||||
- Q5_0
|
|
||||||
- Q5_1
|
|
||||||
- Q8_0
|
|
||||||
- Q2_K
|
|
||||||
- Q3_K
|
|
||||||
- Q4_K
|
|
||||||
- Q5_K
|
|
||||||
- Q6_K
|
|
||||||
- IQ1_S
|
|
||||||
- IQ1_M
|
|
||||||
- IQ2_XXS
|
|
||||||
- IQ2_XS
|
|
||||||
- IQ2_S
|
|
||||||
- IQ3_XXS
|
|
||||||
- IQ3_S
|
|
||||||
- IQ4_XS
|
|
||||||
- IQ4_NL
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> لدعم إلغاء تكميم gguf، يلزم تثبيت `gguf>=0.10.0`.
|
|
||||||
|
|
||||||
### بنيات النماذج المدعومة
|
|
||||||
|
|
||||||
في الوقت الحالي، بنيات النماذج المدعومة هي البنيات التي كانت شائعة جدًا على Hub، وهي:
|
|
||||||
|
|
||||||
- LLaMa
|
|
||||||
- Mistral
|
|
||||||
- Qwen2
|
|
||||||
- Qwen2Moe
|
|
||||||
- Phi3
|
|
||||||
- Bloom
|
|
||||||
- Falcon
|
|
||||||
- StableLM
|
|
||||||
- GPT2
|
|
||||||
- Starcoder2
|
|
||||||
- T5
|
|
||||||
|
|
||||||
## مثال الاستخدام
|
|
||||||
|
|
||||||
لتحميل ملفات `gguf` في `transformers`، يجب تحديد معامل `gguf_file` فى دالة `from_pretrained` لكل من المُجزّئ اللغوية والنموذج. فيما يلي كيفية تحميل المُجزّئ اللغوي ونموذج، يمكن تحميلهما من نفس الملف:
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
|
||||||
|
|
||||||
model_id = "TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF"
|
|
||||||
filename = "tinyllama-1.1b-chat-v1.0.Q6_K.gguf"
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id, gguf_file=filename)
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(model_id, gguf_file=filename)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن لديك إمكانية الوصول إلى النسخة الكامل غير المكممة للنموذج في بيئة PyTorch، حيث يمكنك دمجه مع مجموعة كبيرة من الأدوات الأخرى.
|
|
||||||
|
|
||||||
لإعادة التحويل إلى ملف `gguf`، نوصي باستخدام ملف [`convert-hf-to-gguf.py`](https://github.com/ggerganov/llama.cpp/blob/master/convert-hf-to-gguf.py) من llama.cpp.
|
|
||||||
|
|
||||||
فيما يلي كيفية إكمال البرنامج النصي أعلاه لحفظ النموذج وإعادة تصديره مرة أخرى إلى `gguf`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
tokenizer.save_pretrained('directory')
|
|
||||||
model.save_pretrained('directory')
|
|
||||||
|
|
||||||
!python ${path_to_llama_cpp}/convert-hf-to-gguf.py ${directory}
|
|
||||||
```
|
|
||||||
@ -1,163 +0,0 @@
|
|||||||
# كيفية تعديل أي نموذج من نماذج Transformers
|
|
||||||
|
|
||||||
توفر مكتبة [🤗 Transformers](https://github.com/huggingface/transformers) مجموعة من النماذج المسبقة التدريب والأدوات لمعالجة اللغات الطبيعية، والرؤية، وما إلى ذلك. على الرغم من أن هذه النماذج تغطي مجموعة واسعة من التطبيقات، فقد تواجه حالات استخدام لا تدعمها المكتبة بشكل افتراضي. يُمكن للتخصيص أن يفتح إمكانيات جديدة، مثل إضافة طبقات جديدة، أو تعديل البنية المعمارية، أو تحسين آليات الانتباه. سيُوضح لك هذا الدليل كيفية تعديل نماذج Transformers الموجودة لتلبية احتياجاتك المحددة. الشيء الرائع هو أنك لست بحاجة إلى الخروج من إطار عمل Transformers لإجراء هذه التغييرات. ي يمكنك تعديل النماذج مباشرةً في Transformers والاستفادة من الميزات مثل [واجهة برمجة التطبيقات Trainer](https://huggingface.co/docs/transformers/main/en/main_classes/trainer)، و [PreTrainedModel](https://huggingface.co/docs/transformers/main/en/main_classes/model#transformers.PreTrainedModel)، والضبط الدقيق الفعال باستخدام أدوات مثل [PEFT](https://huggingface.co/docs/peft/index).
|
|
||||||
|
|
||||||
سنرشدك في هذا الدليل لكيفية تخصيص نماذج Transformers الموجودة لتلبية متطلباتك، دون فقدان مزايا الإطار. ستتعلم كيفية:
|
|
||||||
|
|
||||||
- تعديل بنية نموذج ما من خلال تغيير آلية الانتباه الخاصة به.
|
|
||||||
- تطبيق تقنيات مثل Low-Rank Adaptation (LoRA) على مكونات نموذج محددة.
|
|
||||||
|
|
||||||
نحن نشجعك على المساهمة باختراقاتك الخاصة ومشاركتها هنا مع المجتمع1
|
|
||||||
|
|
||||||
## مثال: تعديل آلية الانتباه في نموذج Segment Anything (SAM)
|
|
||||||
|
|
||||||
نموذج **Segment Anything (SAM)** هو نموذج رائد في مجال تجزئة الصور. في تنفيذه الافتراضي، يستخدم SAM إسقاطًا مجمعًا للاستعلام والمفتاح والقيمة (`qkv`) في آلية الانتباه الخاصة به. ومع ذلك، قد ترغب في ضبط مكونات محددة فقط من آلية الانتباه، مثل إسقاطات الاستعلام (`q`) والقيمة (`v`)، لتقليل عدد المعلمات القابلة للتدريب والموارد الحسابية المطلوبة.
|
|
||||||
|
|
||||||
### الدافع
|
|
||||||
|
|
||||||
من خلال تقسيم الإسقاط المجمع `qkv` إلى إسقاطات منفصلة `q` و `k` و `v`، يمكنك تطبيق تقنيات مثل **LoRA** (Low-Rank Adaptation) على إسقاطي `q` و `v` فقط. يسمح لك هذا بما يلي:
|
|
||||||
|
|
||||||
- ضبط عدد أقل من المعلمات، مما يقلل من العبء الحسابي.
|
|
||||||
- تحقيق أداء أفضل من خلال التركيز على مكونات محددة.
|
|
||||||
- تجربة استراتيجيات تعديل مختلفة في آلية الانتباه.
|
|
||||||
|
|
||||||
### التنفيذ
|
|
||||||
|
|
||||||
#### **الخطوة 1: إنشاء فئة اهتمام مخصصة**
|
|
||||||
|
|
||||||
بعد ذلك، قم بإنشاء فئة فرعية من فئة `SamVisionAttention` الأصلية وعدلها لتضم إسقاطات `q` و `k` و `v` منفصلة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
import torch.nn as nn
|
|
||||||
from transformers.models.sam.modeling_sam import SamVisionAttention
|
|
||||||
|
|
||||||
class SamVisionAttentionSplit(SamVisionAttention, nn.Module):
|
|
||||||
def __init__(self, config, window_size):
|
|
||||||
super().__init__(config, window_size)
|
|
||||||
del self.qkv
|
|
||||||
# إسقاطات منفصلة q و k و v
|
|
||||||
self.q = nn.Linear(config.hidden_size, config.hidden_size, bias=config.qkv_bias)
|
|
||||||
self.k = nn.Linear(config.hidden_size, config.hidden_size, bias=config.qkv_bias)
|
|
||||||
self.v = nn.Linear(config.hidden_size, config.hidden_size, bias=config.qkv_bias)
|
|
||||||
self._register_load_state_dict_pre_hook(self.split_q_k_v_load_hook)
|
|
||||||
|
|
||||||
def split_q_k_v_load_hook(self, state_dict, prefix, *args):
|
|
||||||
keys_to_delete = []
|
|
||||||
for key in list(state_dict.keys()):
|
|
||||||
if "qkv." in key:
|
|
||||||
# تقسيم q و k و v من الإسقاط المجمع
|
|
||||||
q, k, v = state_dict[key].chunk(3, dim=0)
|
|
||||||
# استبدال الإسقاطات الفردية q و k و v
|
|
||||||
state_dict[key.replace("qkv.", "q.")] = q
|
|
||||||
state_dict[key.replace("qkv.", "k.")] = k
|
|
||||||
state_dict[key.replace("qkv.", "v.")] = v
|
|
||||||
# وضع علامة على مفتاح qkv القديم للحذف
|
|
||||||
keys_to_delete.append(key)
|
|
||||||
|
|
||||||
# حذف مفاتيح qkv القديمة
|
|
||||||
for key in keys_to_delete:
|
|
||||||
del state_dict[key]
|
|
||||||
|
|
||||||
def forward(self, hidden_states: torch.Tensor, output_attentions=False) -> torch.Tensor:
|
|
||||||
batch_size, height, width, _ = hidden_states.shape
|
|
||||||
qkv_shapes = (batch_size * self.num_attention_heads, height * width, -1)
|
|
||||||
query = self.q(hidden_states).reshape((batch_size, height * width,self.num_attention_heads, -1)).permute(0,2,1,3).reshape(qkv_shapes)
|
|
||||||
key = self.k(hidden_states).reshape((batch_size, height * width,self.num_attention_heads, -1)).permute(0,2,1,3).reshape(qkv_shapes)
|
|
||||||
value = self.v(hidden_states).reshape((batch_size, height * width,self.num_attention_heads, -1)).permute(0,2,1,3).reshape(qkv_shapes)
|
|
||||||
|
|
||||||
attn_weights = (query * self.scale) @ key.transpose(-2, -1)
|
|
||||||
|
|
||||||
if self.use_rel_pos:
|
|
||||||
attn_weights = self.add_decomposed_rel_pos(
|
|
||||||
attn_weights, query, self.rel_pos_h, self.rel_pos_w, (height, width), (height, width)
|
|
||||||
)
|
|
||||||
|
|
||||||
attn_weights = torch.nn.functional.softmax(attn_weights, dtype=torch.float32, dim=-1).to(query.dtype)
|
|
||||||
attn_probs = nn.functional.dropout(attn_weights, p=self.dropout, training=self.training)
|
|
||||||
attn_output = (attn_probs @ value).reshape(batch_size, self.num_attention_heads, height, width, -1)
|
|
||||||
attn_output = attn_output.permute(0, 2, 3, 1, 4).reshape(batch_size, height, width, -1)
|
|
||||||
attn_output = self.proj(attn_output)
|
|
||||||
|
|
||||||
if output_attentions:
|
|
||||||
outputs = (attn_output, attn_weights)
|
|
||||||
else:
|
|
||||||
outputs = (attn_output, None)
|
|
||||||
return outputs
|
|
||||||
```
|
|
||||||
|
|
||||||
**الشرح:**
|
|
||||||
|
|
||||||
- **الإسقاطات المنفصلة:** يتم إزالة الإسقاط المُجمع `qkv`، وإنشاء إسقاطات خطية منفصلة `q` و `k` و `v`.
|
|
||||||
- **دالة استدعاء تحميل الأوزان:** تقوم طريقة `_split_qkv_load_hook` بتقسيم أوزان `qkv` المسبقة التدريب إلى أوزان `q` و `k` و `v` منفصلة عند تحميل النموذج. يضمن هذا التوافق مع أي نموذج مسبق التدريب.
|
|
||||||
- **التنفيذ الأمامي:** يتم حساب الاستعلامات والمفاتيح والقيم بشكل منفصل، وتستمر آلية الانتباه كالمعتاد.
|
|
||||||
|
|
||||||
#### **الخطوة 2: استبدال فئة الانتباه الأصلية**
|
|
||||||
|
|
||||||
استبدل فئة `SamVisionAttention` الأصلية بفئتك المخصصة بحيث يستخدم النموذج آلية الانتباه المعدلة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import SamModel
|
|
||||||
from transformers.models.sam import modeling_sam
|
|
||||||
|
|
||||||
# استبدال فئة الاهتمام في وحدة نمطية modeling_sam
|
|
||||||
modeling_sam.SamVisionAttention = SamVisionAttentionSplit
|
|
||||||
|
|
||||||
# تحميل نموذج SAM المسبق التدريب
|
|
||||||
model = SamModel.from_pretrained("facebook/sam-vit-base")
|
|
||||||
```
|
|
||||||
|
|
||||||
**الشرح:**
|
|
||||||
|
|
||||||
- **استبدال الفئة:** من خلال تعيين فئتك المخصصة إلى `modeling_sam.SamVisionAttention`، فإن أي حالات من فئة `SamVisionAttention` في النموذج ستستخدم النسخة المعدلة. وبالتالي، عند استدعاء `SamModel`، سيتم استخدام `SamVisionAttentionSplit` المحددة حديثًا.
|
|
||||||
- **تحميل النموذج:** يتم تحميل النموذج باستخدام `from_pretrained`، ويتم دمج آلية الانتباه المخصصة.
|
|
||||||
|
|
||||||
#### **الخطوة 3: تطبيق LoRA على إسقاطات محددة**
|
|
||||||
|
|
||||||
مع وجود إسقاطات `q` و `k` و `v` منفصلة، يمكنك الآن تطبيق LoRA على مكونات محددة، مثل إسقاطات `q` و `v`.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from peft import LoraConfig, get_peft_model
|
|
||||||
|
|
||||||
config = LoraConfig(
|
|
||||||
r=16,
|
|
||||||
lora_alpha=32,
|
|
||||||
target_modules=["q", "v"], # تطبيق LoRA على إسقاطات q و v
|
|
||||||
lora_dropout=0.1,
|
|
||||||
task_type="mask-generation"
|
|
||||||
)
|
|
||||||
|
|
||||||
# تطبيق LoRA على النموذج
|
|
||||||
model = get_peft_model(model, config)
|
|
||||||
```
|
|
||||||
|
|
||||||
**الشرح:**
|
|
||||||
|
|
||||||
- **تكوين LoRA:** تحدد `LoraConfig` المرتبة `r`، وعامل القياس `lora_alpha`، والوحدات المستهدفة (`"q"` و `"v"`)، ومعدل التخلي، ونوع المهمة.
|
|
||||||
- **تطبيق LoRA:** تقوم دالة `get_peft_model` بتطبيق LoRA على الوحدات المحددة في النموذج.
|
|
||||||
- **تقليل المعلمات:** من خلال التركيز على `q` و `v`، فإنك تقلل عدد المعلمات القابلة للتدريب، مما يؤدي إلى تسريع التدريب وتقليل استخدام الذاكرة.
|
|
||||||
|
|
||||||
#### **الخطوة 4: التحقق من عدد المعلمات القابلة للتدريب**
|
|
||||||
|
|
||||||
من السهل التحقق من عدد المعلمات القابلة للتدريب ومعرفة تأثير تعديلك.
|
|
||||||
|
|
||||||
```python
|
|
||||||
model.print_trainable_parameters()
|
|
||||||
```
|
|
||||||
|
|
||||||
**الناتج المتوقع:**
|
|
||||||
|
|
||||||
```
|
|
||||||
عدد المعلمات القابلة للتدريب: 608,256 || جميع المعلمات: 94,343,728 || نسبة المعلمات القابلة للتدريب: 0.6447
|
|
||||||
عدد المعلمات القابلة للتدريب: 912,384 || جميع المعلمات: 94,647,856 || نسبة المعلمات القابلة للتدريب: 0.9640 # مع k
|
|
||||||
```
|
|
||||||
|
|
||||||
## المساهمة بابداعاتك الخاصة
|
|
||||||
|
|
||||||
يمكن لتعديل النماذج المسبقة التدريب أن يفتح آفاقًا جديدة للبحث والتطبيق. من خلال فهم وتعديل الآليات الداخلية للنماذج مثل SAM، يمكنك تخصيصها لتلبية احتياجاتك المحددة، وتحسين الأداء، وتجربة أفكار جديدة.
|
|
||||||
|
|
||||||
إذا قمت بتطوير تعديﻻتك الخاصة لنماذج Transformers وترغب في مشاركتها، ففكر في المساهمة في هذه الوثيقة.
|
|
||||||
|
|
||||||
- **إنشاء طلب سحب (Pull Request):** شارك تغييراتك وتحسيناتك في التعليمات البرمجية مباشرة في المستودع.
|
|
||||||
- **كتابة التوثيق:** قدم تفسيرات وأمثلة واضحة لتعديلاتك.
|
|
||||||
- **التفاعل مع المجتمع:** ناقش أفكارك واحصل على تعليقات من المطورين والباحثين الآخرين من خلال فتح مشكلة.
|
|
||||||
@ -144,7 +144,7 @@ conda install conda-forge::transformers
|
|||||||
|
|
||||||
تُحمّل النماذج المُسبقة التدريب وتُخزّن مؤقتًا في: `~/.cache/huggingface/hub`. هذا هو المجلد الافتراضي الذي يُحدده متغير البيئة `TRANSFORMERS_CACHE`. على Windows، يكون دليل ذاكرة التخزين المؤقت الافتراضي هو `C:\Users\username\.cache\huggingface\hub`. يمكنك تغيير متغيرات البيئة shell الموضحة أدناه - حسب الأولوية - لتحديد دليل ذاكرة تخزين مؤقت مختلف:
|
تُحمّل النماذج المُسبقة التدريب وتُخزّن مؤقتًا في: `~/.cache/huggingface/hub`. هذا هو المجلد الافتراضي الذي يُحدده متغير البيئة `TRANSFORMERS_CACHE`. على Windows، يكون دليل ذاكرة التخزين المؤقت الافتراضي هو `C:\Users\username\.cache\huggingface\hub`. يمكنك تغيير متغيرات البيئة shell الموضحة أدناه - حسب الأولوية - لتحديد دليل ذاكرة تخزين مؤقت مختلف:
|
||||||
|
|
||||||
1. متغير البيئة (افتراضي): `HF_HUB_CACHE` أو `TRANSFORMERS_CACHE`.
|
1. متغير البيئة (افتراضي): `HUGGINGFACE_HUB_CACHE` أو `TRANSFORMERS_CACHE`.
|
||||||
2. متغير البيئة: `HF_HOME`.
|
2. متغير البيئة: `HF_HOME`.
|
||||||
3. متغير البيئة: `XDG_CACHE_HOME` + `/huggingface`.
|
3. متغير البيئة: `XDG_CACHE_HOME` + `/huggingface`.
|
||||||
|
|
||||||
|
|||||||
@ -1,795 +0,0 @@
|
|||||||
# تحسين نماذج اللغة الكبيرة من حيث السرعة والذاكرة
|
|
||||||
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
تحقق نماذج اللغة الكبيرة (LLMs) مثل GPT3/4، [Falcon](https://huggingface.co/tiiuae/falcon-40b)، و [Llama](https://huggingface.co/meta-llama/Llama-2-70b-hf) تقدمًا سريعًا في قدرتها على معالجة المهام التي تركز على الإنسان، مما يجعلها أدوات أساسية في الصناعات القائمة على المعرفة الحديثة.
|
|
||||||
لا يزال نشر هذه النماذج في المهام الواقعية يمثل تحديًا، ومع ذلك:
|
|
||||||
|
|
||||||
- لكي تظهر نماذج اللغة الكبيرة قدرات فهم وتوليد النصوص قريبة من قدرات الإنسان، فإنها تتطلب حاليًا إلى تكوينها من مليارات المعلمات (انظر [كابلان وآخرون](https://arxiv.org/abs/2001.08361)، [وي وآخرون](https://arxiv.org/abs/2206.07682)). وهذا بدوره يزيد من متطلبات الذاكرة للاستدلال.
|
|
||||||
- في العديد من المهام الواقعية، تحتاج نماذج اللغة الكبيرة إلى معلومات سياقية شاملة. يتطلب ذلك قدرة النموذج على إدارة تسلسلات إدخال طويلة للغاية أثناء الاستدلال.
|
|
||||||
|
|
||||||
يكمن جوهر صعوبة هذه التحديات في تعزيز القدرات الحسابية والذاكرة لنماذج اللغة الكبيرة، خاصة عند التعامل مع تسلسلات الإدخال الضخمة.
|
|
||||||
|
|
||||||
في هذا الدليل، سنستعرض التقنيات الفعالة لتُحسِّن من كفاءة نشر نماذج اللغة الكبيرة:
|
|
||||||
|
|
||||||
1. سنتناول تقنية "دقة أقل" التي أثبتت الأبحاث فعاليتها في تحقيق مزايا حسابية دون التأثير بشكل ملحوظ على أداء النموذج عن طريق العمل بدقة رقمية أقل [8 بت و4 بت](/main_classes/quantization.md).
|
|
||||||
|
|
||||||
2. **اFlash Attention:** إن Flash Attention وهي نسخة مُعدَّلة من خوارزمية الانتباه التي لا توفر فقط نهجًا أكثر كفاءة في استخدام الذاكرة، ولكنها تحقق أيضًا كفاءة متزايدة بسبب الاستخدام الأمثل لذاكرة GPU.
|
|
||||||
|
|
||||||
3. **الابتكارات المعمارية:** حيث تم اقتراح هياكل متخصصة تسمح باستدلال أكثر فعالية نظرًا لأن نماذج اللغة الكبيرة يتم نشرها دائمًا بنفس الطريقة أثناء عملية الاستدلال، أي توليد النص التنبؤي التلقائي مع سياق الإدخال الطويل، فقد تم اقتراح بنيات نموذج متخصصة تسمح بالاستدلال الأكثر كفاءة. أهم تقدم في بنيات النماذج هنا هو [عذر](https://arxiv.org/abs/2108.12409)، [الترميز الدوار](https://arxiv.org/abs/2104.09864)، [الاهتمام متعدد الاستعلامات (MQA)](https://arxiv.org/abs/1911.02150) و [مجموعة الانتباه بالاستعلام (GQA)]((https://arxiv.org/abs/2305.13245)).
|
|
||||||
|
|
||||||
على مدار هذا الدليل، سنقدم تحليلًا للتوليد التنبؤي التلقائي من منظور المُوتِّرات. نتعمق في مزايا وعيوب استخدام دقة أقل، ونقدم استكشافًا شاملاً لخوارزميات الانتباه الأحدث، ونناقش بنيات نماذج نماذج اللغة الكبيرة المحسنة. سندعم الشرح بأمثلة عملية تُبرِز كل تحسين على حدة.
|
|
||||||
|
|
||||||
## 1. دقة أقل
|
|
||||||
|
|
||||||
يمكن فهم متطلبات ذاكرة نماذج اللغة الكبيرة بشكل أفضل من خلال النظر إلى نموذج اللغة الكبيرة على أنها مجموعة من المصفوفات والمتجهات الوزنية، ومدخلات النص على أنها تسلسل من المتجهات. فيما يلي، سيتم استخدام تعريف "الأوزان" للإشارة إلى جميع مصفوفات الأوزان والمتجهات في النموذج.
|
|
||||||
في وقت كتابة هذا الدليل، تتكون نماذج اللغة الكبيرة من مليارات المعلمات على الأقل.كل معلمة يتم تمثيلها برقم عشري مثل 4.5689 `` والذي يتم تخزينه عادةً بتنسيق [float32](https://en.wikipedia.org/wiki/Single-precision_floating-point_format)، [bfloat16](https://en.wikipedia.org/wiki/Bfloat16_floating-point_format)، أو [float16](https://en.wikipedia.org/wiki/Half-precision_floating-point_format) . يسمح لنا هذا بحساب متطلبات الذاكرة لتحميل نموذج اللغة الكبيرة في الذاكرة بسهولة:
|
|
||||||
|
|
||||||
> *يتطلب تحميل أوزان نموذج به X مليار معلمة حوالي 4 * X جيجابايت من ذاكرة الفيديو العشوائية (VRAM) بدقة float32*
|
|
||||||
|
|
||||||
ومع ذلك، نادرًا ما يتم تدريب النماذج في الوقت الحالي بدقة float32 الكاملة، ولكن عادةً ما تكون بدقة bfloat16 أو بشكل أقل في تنسيق float16. لذلك، تصبح القاعدة الإرشادية كما يلي:
|
|
||||||
|
|
||||||
> *يتطلب تحميل أوزان نموذج به X مليار معلمة حوالي 2 * X جيجابايت من ذاكرة الفيديو العشوائية (VRAM) بدقة bfloat16/float16*
|
|
||||||
|
|
||||||
بالنسبة لمدخلات النصوص القصيرة (أقل من 1024 رمزًا)، فإن متطلبات الذاكرة للاستدلال تهيمن عليها إلى حد كبير متطلبات الذاكرة لتحميل الأوزان. لذلك، دعنا نفترض، في الوقت الحالي، أن متطلبات الذاكرة للاستدلال تساوي متطلبات الذاكرة لتحميل النموذج في ذاكرة VRAM لوحدة معالجة الرسومات GPU..
|
|
||||||
|
|
||||||
ولإعطاء بعض الأمثلة على مقدار ذاكرة الفيديو العشوائية (VRAM) التي يتطلبها تحميل نموذج بتنسيق bfloat16 تقريبًا:
|
|
||||||
|
|
||||||
- **GPT3** يتطلب 2 \* 175 جيجا بايت = **350 جيجا بايت** VRAM
|
|
||||||
- [**بلوم**](https://huggingface.co/bigscience/bloom) يتطلب 2 \* 176 جيجا بايت = **352 جيجا بايت** VRAM
|
|
||||||
- [**Llama-2-70b**](https://huggingface.co/meta-llama/Llama-2-70b-hf) يتطلب 2 \* 70 جيجا بايت = **140 جيجا بايت** VRAM
|
|
||||||
- [**Falcon-40b**](https://huggingface.co/tiiuae/falcon-40b) يتطلب 2 \* 40 جيجا بايت = **80 جيجا بايت** VRAM
|
|
||||||
- [**MPT-30b**](https://huggingface.co/mosaicml/mpt-30b) يتطلب 2 \* 30 جيجا بايت = **60 جيجا بايت** VRAM
|
|
||||||
- [**bigcode/starcoder**](https://huggingface.co/bigcode/starcoder) يتطلب 2 \* 15.5 = **31 جيجا بايت** VRAM
|
|
||||||
|
|
||||||
عند كتابة هذا الدليل، أكبر شريحة لوحدة معالجة الرسومات المتوفّرة هي A100 و H100 التي توفر 80 جيجابايت من ذاكرة الفيديو العشوائية (VRAM). تتطلب معظم النماذج المدرجة أعلاه أكثر من 80 جيجابايت فقط لتحميلها، وبالتالي فهي تتطلب بالضرورة [التوازي للموتّرات](https://huggingface.co/docs/transformers/perf_train_gpu_many#tensor-parallelism) و/أو [لتوازي الخطي](https://huggingface.co/docs/transformers/perf_train_gpu_many#naive-model-parallelism-vertical-and-pipeline-parallelism).
|
|
||||||
|
|
||||||
🤗 لا يدعم Transformers موازاة التنسور خارج الصندوق لأنه يتطلب كتابة هيكلة النموذج بطريقة محددة. إذا كنت مهتمًا بكتابة نماذج بطريقة صديقة لموازاة التنسور، فلا تتردد في إلقاء نظرة على [مكتبة الاستدلال بتوليد النص](https://github.com/huggingface/text-generation-inference/tree/main/server/text_generation_server/models/custom_modeling).
|
|
||||||
|
|
||||||
بدعم موازاة قنوات المعالجة البسيطة خارج الصندوق. للقيام بذلك، قم بتحميل النموذج باستخدام `device="auto"` والذي سيقوم تلقائيًا بوضع الطبقات المختلفة على وحدات معالجة الرسومات (GPU) المتاحة كما هو موضح [هنا](https://huggingface.co/docs/accelerate/v0.22.0/en/concept_guides/big_model_inference).
|
|
||||||
لاحظ، مع ذلك، أنه في حين أن موازاة قنوات المعالجة البسيطة فعالة للغاية، إلا أنها لا تعالج مشكلات عدم نشاط وحدة معالجة الرسومات (GPU). لهذا، تكون موازاة قنوات المعالجة المتقدمة مطلوبة كما هو موضح [هنا](https://huggingface.co/docs/transformers/en/perf_train_gpu_many#naive-model-parallelism-vertical-and-pipeline-parallelism).
|
|
||||||
|
|
||||||
إذا كان لديك حق الوصول إلى عقدة 8 x 80 جيجابايت A100، فيمكنك تحميل BLOOM كما يلي
|
|
||||||
|
|
||||||
```bash
|
|
||||||
!pip install transformers accelerate bitsandbytes optimum
|
|
||||||
```
|
|
||||||
```python
|
|
||||||
from transformers import AutoModelForCausalLM
|
|
||||||
|
|
||||||
model = AutoModelForCausalLM.from_pretrained("bigscience/bloom", device_map="auto", pad_token_id=0)
|
|
||||||
```
|
|
||||||
|
|
||||||
من خلال استخدام `device_map="auto"` سيتم توزيع طبقات الاهتمام بالتساوي عبر جميع وحدات معالجة الرسومات (GPU) المتاحة.
|
|
||||||
|
|
||||||
في هذا الدليل، سنستخدم [bigcode/octocoder](https://huggingface.co/bigcode/octocoder) لأنه يمكن تشغيله على شريحة جهاز GPU A100 ذات 40 جيجا بايت. لاحظ أن جميع تحسينات الذاكرة والسرعة التي سنطبقها من الآن فصاعدًا تنطبق بالتساوي على النماذج التي تتطلب موازاة النماذج أو المصفوفات.
|
|
||||||
|
|
||||||
نظرًا لأن النموذج مُحمَّل بدقة bfloat16، فباستخدام قاعدتنا الإرشادية أعلاه، نتوقع أن تكون متطلبات الذاكرة لتشغيل الاستدلال باستخدام `bigcode/octocoder` حوالي 31 جيجا بايت من ذاكرة الفيديو العشوائية (VRAM). دعنا نجرب.
|
|
||||||
|
|
||||||
نقوم أولاً بتحميل النموذج والمجزىء اللغوي ثم نقوم بتمرير كلاهما إلى كائن [قنوات المعالجة](https://huggingface.co/docs/transformers/main_classes/pipelines) في Transformers.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
|
|
||||||
import torch
|
|
||||||
|
|
||||||
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", torch_dtype=torch.bfloat16, device_map="auto", pad_token_id=0)
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained("bigcode/octocoder")
|
|
||||||
|
|
||||||
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
prompt = "Question: Please write a function in Python that transforms bytes to Giga bytes.\n\nAnswer:"
|
|
||||||
|
|
||||||
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
|
|
||||||
result
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
Here is a Python function that transforms bytes to Giga bytes:\n\n```python\ndef bytes_to_giga_bytes(bytes):\n return bytes / 1024 / 1024 / 1024\n```\n\nThis function takes a single
|
|
||||||
```
|
|
||||||
|
|
||||||
رائع، يمكننا الآن استخدام النتيجة مباشرة لتحويل البايت إلى جيجا بايت.
|
|
||||||
|
|
||||||
```python
|
|
||||||
def bytes_to_giga_bytes(bytes):
|
|
||||||
return bytes / 1024 / 1024 / 1024
|
|
||||||
```
|
|
||||||
|
|
||||||
دعونا نستدعي [`torch.cuda.max_memory_allocated`](https://pytorch.org/docs/stable/generated/torch.cuda.max_memory_allocated.html) لقياس ذروة تخصيص ذاكرة وحدة معالجة الرسومات (GPU).
|
|
||||||
|
|
||||||
```python
|
|
||||||
bytes_to_giga_bytes(torch.cuda.max_memory_allocated())
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```bash
|
|
||||||
29.0260648727417
|
|
||||||
```
|
|
||||||
|
|
||||||
قريب بما يكفي من حسابنا التقريبي! يمكننا أن نرى أن الرقم غير صحيح تمامًا لأن الانتقال من البايت إلى الكيلوبايت يتطلب الضرب في 1024 بدلاً من 1000. لذلك يمكن أيضًا فهم صيغة التقريب على أنها حساب "بحد أقصى X جيجا بايت".
|
|
||||||
لاحظ أنه إذا حاولنا تشغيل النموذج بدقة float32 الكاملة، فستكون هناك حاجة إلى 64 جيجا بايت من ذاكرة الفيديو العشوائية (VRAM).
|
|
||||||
|
|
||||||
> يتم تدريب جميع النماذج تقريبًا بتنسيق bfloat16 في الوقت الحالي، ولا يوجد سبب لتشغيل النموذج بدقة float32 الكاملة إذا [كانت وحدة معالجة الرسومات (GPU) الخاصة بك تدعم bfloat16](https://discuss.pytorch.org/t/bfloat16-native-support/117155/5). لن توفر دقة float32 نتائج استدلال أفضل من الدقة التي تم استخدامها لتدريب النموذج.
|
|
||||||
|
|
||||||
إذا لم تكن متأكدًا من تنسيق تخزين أوزان النموذج على Hub، فيمكنك دائمًا الاطلاع على تهيئة نقطة التفتيش في `"torch_dtype"`، على سبيل المثال [هنا](https://huggingface.co/meta-llama/Llama-2-7b-hf/blob/6fdf2e60f86ff2481f2241aaee459f85b5b0bbb9/config.json#L21). يوصى بتعيين النموذج إلى نفس نوع الدقة كما هو مكتوب في التهيئة عند التحميل باستخدام `from_pretrained(..., torch_dtype=...)` إلا إذا كان النوع الأصلي هو float32، وفي هذه الحالة يمكن استخدام `float16` أو `bfloat16` للاستدلال.
|
|
||||||
|
|
||||||
|
|
||||||
دعونا نحدد وظيفة `flush(...)` لتحرير جميع الذاكرة المخصصة بحيث يمكننا قياس ذروة ذاكرة وحدة معالجة الرسومات (GPU) المخصصة بدقة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
del pipe
|
|
||||||
del model
|
|
||||||
|
|
||||||
import gc
|
|
||||||
import torch
|
|
||||||
|
|
||||||
def flush():
|
|
||||||
gc.collect()
|
|
||||||
torch.cuda.empty_cache()
|
|
||||||
torch.cuda.reset_peak_memory_stats()
|
|
||||||
```
|
|
||||||
|
|
||||||
دعونا نستدعيه الآن للتجربة التالية.
|
|
||||||
|
|
||||||
```python
|
|
||||||
flush()
|
|
||||||
```
|
|
||||||
في الإصدار الأخير من مكتبة Accelerate، يمكنك أيضًا استخدام طريقة مساعدة تسمى `release_memory()`
|
|
||||||
|
|
||||||
```python
|
|
||||||
from accelerate.utils import release_memory
|
|
||||||
# ...
|
|
||||||
|
|
||||||
release_memory(model)
|
|
||||||
```
|
|
||||||
```python
|
|
||||||
from accelerate.utils import release_memory
|
|
||||||
# ...
|
|
||||||
|
|
||||||
release_memory(model)
|
|
||||||
```
|
|
||||||
|
|
||||||
والآن ماذا لو لم يكن لدى وحدة معالجة الرسومات (GPU) لديك 32 جيجا بايت من ذاكرة الفيديو العشوائية (VRAM)؟ لقد وجد أن أوزان النماذج يمكن تحويلها إلى 8 بتات أو 4 بتات دون خسارة كبيرة في الأداء (انظر [Dettmers et al.](https://arxiv.org/abs/2208.07339)).
|
|
||||||
يمكن تحويل النموذج إلى 3 بتات أو 2 بتات مع فقدان مقبول في الأداء كما هو موضح في ورقة [GPTQ](https://arxiv.org/abs/2210.17323) 🤯.
|
|
||||||
|
|
||||||
دون الدخول في الكثير من التفاصيل، تهدف مخططات التكميم إلى تخفيض دقة الأوزان مع محاولة الحفاظ على دقة نتائج النموذج كما هي (*أي* أقرب ما يمكن إلى bfloat16).
|
|
||||||
لاحظ أن التكميم يعمل بشكل خاص جيدًا لتوليد النص حيث كل ما نهتم به هو اختيار *مجموعة الرموز الأكثر احتمالًا التالية* ولا نهتم حقًا بالقيم الدقيقة لتوزيع الرمز التالي *logit*.
|
|
||||||
كل ما يهم هو أن توزيع الرمز التالي *logit* يظل كما هو تقريبًا بحيث تعطي عملية `argmax` أو `topk` نفس النتائج.
|
|
||||||
|
|
||||||
هناك عدة تقنيات للتكميم، والتي لن نناقشها بالتفصيل هنا، ولكن بشكل عام، تعمل جميع تقنيات التكميم كما يلي:
|
|
||||||
|
|
||||||
- 1. تكميم جميع الأوزان إلى الدقة المستهدفة
|
|
||||||
- 2. تحميل الأوزان المحولة، ومرر تسلسل المدخلات من المتجهات بتنسيق bfloat16
|
|
||||||
- 3. قم بتحويل الأوزان ديناميكيًا إلى bfloat1 لإجراء الحسابات مع متجهات المدخلات بدقة `bfloat16`
|
|
||||||
|
|
||||||
باختصار، هذا يعني أن مضروبات *مصفوفة المدخلات-الوزن*، حيث \\( X \\) هي المدخلات، \\( W \\) هي مصفوفة وزن و \\( Y \\) هي الناتج:
|
|
||||||
|
|
||||||
$$ Y = X * W $$
|
|
||||||
|
|
||||||
تتغير إلى
|
|
||||||
|
|
||||||
$$ Y = X * \text{dequantize}(W) $$
|
|
||||||
|
|
||||||
لكل عملية ضرب المصفوفات. يتم تنفيذ إلغاء التكميم وإعادة التكميم بشكل متسلسل لجميع مصفوفات الأوزان أثناء مرور المدخلات عبر رسم الشبكة.
|
|
||||||
|
|
||||||
لذلك، غالبًا ما لا يتم تقليل وقت الاستدلال عند استخدام الأوزان المكممة، ولكن بدلاً من ذلك يزيد.
|
|
||||||
|
|
||||||
كفى نظرية، دعنا نجرب! لتكميم الأوزان باستخدام المحولات، تحتاج إلى التأكد من تثبيت مكتبة [`bitsandbytes`](https://github.com/TimDettmers/bitsandbytes).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
!pip install bitsandbytes
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكننا بعد ذلك تحميل النماذج في تكميم 8 بت ببساطة عن طريق إضافة علامة `load_in_8bit=True` إلى `from_pretrained`.
|
|
||||||
|
|
||||||
```python
|
|
||||||
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", load_in_8bit=True, pad_token_id=0)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن، دعنا نعيد تشغيل مثالنا ونقيس استخدام الذاكرة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
|
||||||
|
|
||||||
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
|
|
||||||
result
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
Here is a Python function that transforms bytes to Giga bytes:\n\n```python\ndef bytes_to_giga_bytes(bytes):\n return bytes / 1024 / 1024 / 1024\n```\n\nThis function takes a single
|
|
||||||
```
|
|
||||||
|
|
||||||
جميل، نحصل على نفس النتيجة كما في السابق، لذلك لا يوجد فقدان في الدقة! دعنا نلقي نظرة على مقدار الذاكرة المستخدمة هذه المرة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
bytes_to_giga_bytes(torch.cuda.max_memory_allocated())
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
15.219234466552734
|
|
||||||
```
|
|
||||||
|
|
||||||
أقل بكثير! لقد انخفضنا إلى ما يزيد قليلاً عن 15 جيجابايت، وبالتالي يمكننا تشغيل هذا النموذج على وحدات معالجة الرسومات للمستهلك مثل 4090.
|
|
||||||
|
|
||||||
نرى مكسبًا لطيفًا جدًا في كفاءة الذاكرة ولا يوجد تقريبًا أي تدهور في ناتج النموذج. ومع ذلك، يمكننا أيضًا ملاحظة تباطؤ طفيف أثناء الاستدلال.
|
|
||||||
|
|
||||||
نحذف النماذج ونفرغ الذاكرة مرة أخرى.
|
|
||||||
```python
|
|
||||||
del model
|
|
||||||
del pipe
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
flush()
|
|
||||||
```
|
|
||||||
|
|
||||||
دعنا نرى ما هو استهلاك ذاكرة GPU الذروة الذي يوفره تكميم 4 بت. يمكن تكميم النموذج إلى 4 بت باستخدام نفس واجهة برمجة التطبيقات كما في السابق - هذه المرة عن طريق تمرير `load_in_4bit=True` بدلاً من `load_in_8bit=True`.
|
|
||||||
|
|
||||||
```python
|
|
||||||
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", load_in_4bit=True, low_cpu_mem_usage=True, pad_token_id=0)
|
|
||||||
|
|
||||||
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
|
||||||
|
|
||||||
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
|
|
||||||
result
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
Here is a Python function that transforms bytes to Giga bytes:\n\n```\ndef bytes_to_gigabytes(bytes):\n return bytes / 1024 / 1024 / 1024\n```\n\nThis function takes a single argument
|
|
||||||
```
|
|
||||||
|
|
||||||
نحن نرى تقريبًا نفس نص الإخراج كما في السابق - فقط `python` مفقود قبل مقطع الكود. دعنا نرى مقدار الذاكرة المطلوبة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
bytes_to_giga_bytes(torch.cuda.max_memory_allocated())
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
9.543574333190918
|
|
||||||
```
|
|
||||||
|
|
||||||
فقط 9.5 جيجابايت! هذا ليس كثيرًا بالفعل لنموذج يزيد عدد معاملاته عن 15 مليار.
|
|
||||||
|
|
||||||
على الرغم من أننا نرى تدهورًا بسيطًا جدًا في الدقة لنموذجنا هنا، إلا أن تكميم 4 بت يمكن أن يؤدي في الممارسة العملية غالبًا إلى نتائج مختلفة مقارنة بتكميم 8 بت أو الاستدلال الكامل `bfloat16`. الأمر متروك للمستخدم لتجربته.
|
|
||||||
|
|
||||||
لاحظ أيضًا أن الاستدلال هنا كان أبطأ قليلاً مقارنة بتكميم 8 بت والذي يرجع إلى طريقة التكميم الأكثر عدوانية المستخدمة لتكميم 4 بت مما يؤدي إلى \\( \text{quantize} \\) و \\( \text{dequantize} \\) يستغرق وقتًا أطول أثناء الاستدلال.
|
|
||||||
|
|
||||||
```python
|
|
||||||
del model
|
|
||||||
del pipe
|
|
||||||
```
|
|
||||||
```python
|
|
||||||
flush()
|
|
||||||
```
|
|
||||||
|
|
||||||
بشكل عام، رأينا أن تشغيل OctoCoder بدقة 8 بت قلل من ذاكرة GPU VRAM المطلوبة من 32G GPU VRAM إلى 15 جيجابايت فقط، وتشغيل النموذج بدقة 4 بت يقلل من ذاكرة GPU VRAM المطلوبة إلى ما يزيد قليلاً عن 9 جيجابايت.
|
|
||||||
|
|
||||||
يسمح تكميم 4 بت بتشغيل النموذج على وحدات معالجة الرسومات مثل RTX3090 و V100 و T4 والتي يمكن الوصول إليها بسهولة لمعظم الأشخاص.
|
|
||||||
|
|
||||||
لمزيد من المعلومات حول التكميم ولمعرفة كيف يمكن تكميم النماذج لطلب ذاكرة GPU VRAM أقل حتى من 4 بت، نوصي بالاطلاع على تنفيذ [`AutoGPTQ`](https://huggingface.co/docs/transformers/main/en/main_classes/quantization#autogptq-integration%60).
|
|
||||||
|
|
||||||
> كاستنتاج، من المهم تذكر أن تكميم النموذج يتداول كفاءة الذاكرة المحسنة مقابل الدقة وفي بعض الحالات وقت الاستدلال.
|
|
||||||
|
|
||||||
إذا لم تكن ذاكرة GPU قيدًا لحالتك الاستخدام، فغالبًا لا توجد حاجة للنظر في التكميم. ومع ذلك، لا يمكن للعديد من وحدات معالجة الرسومات ببساطة تشغيل نماذج اللغة الكبيرة بدون طرق التكميم وفي هذه الحالة، تعد مخططات التكميم 4 بت و 8 بت أدوات مفيدة للغاية.
|
|
||||||
|
|
||||||
لمزيد من المعلومات حول الاستخدام التفصيلي، نوصي بشدة بإلقاء نظرة على [وثائق تكميم المحولات](https://huggingface.co/docs/transformers/main_classes/quantization#general-usage).
|
|
||||||
|
|
||||||
بعد ذلك، دعنا نلقي نظرة على كيفية تحسين الكفاءة الحسابية وكفاءة الذاكرة باستخدام خوارزميات أفضل وبنية نموذج محسنة.
|
|
||||||
|
|
||||||
## 2. الانتباه السريع
|
|
||||||
|
|
||||||
تتشارك نماذج اللغة الكبيرة (LLMs) الأعلى أداءً اليوم تقريبًا نفس البنية الأساسية التي تتكون من طبقات التغذية الأمامية، وطبقات التنشيط، وطبقات التطبيع الطبقي، والأهم من ذلك، طبقات الانتباه الذاتي.
|
|
||||||
|
|
||||||
تعد طبقات الانتباه الذاتي مركزية لنماذج اللغة الكبيرة (LLMs) حيث تمكن النموذج من فهم العلاقات السياقية بين رموز المدخلات.
|
|
||||||
ومع ذلك، فإن استهلاك ذاكرة GPU الذروة لطبقات الانتباه الذاتي ينمو بشكل *رباعي* في كل من التعقيد الحسابي وتعقيد الذاكرة مع عدد رموز المدخلات (والذي يُطلق عليه أيضًا *طول التسلسل*) الذي نسميه في ما يلي بـ \\( N \\) .
|
|
||||||
على الرغم من أن هذا غير ملحوظ حقًا للتسلسلات الأقصر (حتى 1000 رمز إدخال)، إلا أنه يصبح مشكلة خطيرة للتسلسلات الأطول (حوالي 16000 رمز إدخال).
|
|
||||||
|
|
||||||
دعنا نلقي نظرة أقرب. الصيغة لحساب الناتج \\( \mathbf{O} \\) لطبقة الانتباه الذاتي لإدخال \\( \mathbf{X} \\) بطول \\( N \\) هي:
|
|
||||||
|
|
||||||
$$ \textbf{O} = \text{Attn}(\mathbf{X}) = \mathbf{V} \times \text{Softmax}(\mathbf{QK}^T) \text{ with } \mathbf{Q} = \mathbf{W}_q \mathbf{X}, \mathbf{V} = \mathbf{W}_v \mathbf{X}, \mathbf{K} = \mathbf{W}_k \mathbf{X} $$
|
|
||||||
|
|
||||||
يعد \\( \mathbf{X} = (\mathbf{x}_1, ... \mathbf{x}_{N}) \\) بالتالي تسلسل الإدخال إلى طبقة الاهتمام. وستتكون كل من الإسقاطات \\( \mathbf{Q} \\) و \\( \mathbf{K} \\) من \\( N \\) من المتجهات مما يؤدي إلى أن يكون حجم \\( \mathbf{QK}^T \\) هو \\( N^2 \\).
|
|
||||||
|
|
||||||
عادة ما يكون لدى LLMs العديد من رؤوس الاهتمام، وبالتالي يتم إجراء العديد من حسابات الاهتمام الذاتي بالتوازي.
|
|
||||||
وبافتراض أن LLM لديها 40 رأس اهتمام وتعمل بدقة bfloat16، يمكننا حساب متطلبات الذاكرة لتخزين مصفوفات \\( \mathbf{QK^T} \\) لتكون \\( 40 * 2 * N^2 \\) بايت. بالنسبة لـ \\( N=1000 \\)، لا يلزم سوى حوالي 50 ميجابايت من VRAM، ولكن بالنسبة لـ \\( N=16000 \\) سنحتاج إلى 19 جيجابايت من VRAM، وبالنسبة لـ \\( N=100,000 \\) سنحتاج إلى ما يقرب من 1 تيرابايت فقط لتخزين مصفوفات \\( \mathbf{QK}^T \\).
|
|
||||||
|
|
||||||
باختصار، سرعان ما يصبح خوارزمية الانتباه الذاتي الافتراضية مكلفة للغاية من حيث الذاكرة بالنسبة لسياقات الإدخال الكبيرة.
|
|
||||||
|
|
||||||
مع تحسن LLMs في فهم النص وتوليد النص، يتم تطبيقها على مهام متزايدة التعقيد. في حين أن النماذج كانت تتعامل سابقًا مع ترجمة أو تلخيص بضع جمل، فإنها الآن تدير صفحات كاملة، مما يتطلب القدرة على معالجة أطوال إدخال واسعة.
|
|
||||||
|
|
||||||
كيف يمكننا التخلص من متطلبات الذاكرة الباهظة للتطويلات المدخلة الكبيرة؟ نحن بحاجة إلى طريقة جديدة لحساب آلية الاهتمام الذاتي التي تتخلص من مصفوفة \\( QK^T \\). [طريقه داو وآخرون.](Https://arxiv.org/abs/2205.14135) طوروا بالضبط مثل هذا الخوارزمية الجديدة وأطلقوا عليها اسم **Flash Attention**.
|
|
||||||
|
|
||||||
باختصار، يكسر الاهتمام الفلاشي حساب \\( \mathbf{V} \times \operatorname{Softmax}(\mathbf{QK}^T\\)) ويحسب بدلاً من ذلك قطعًا أصغر من الإخراج عن طريق التكرار عبر العديد من خطوات حساب Softmax:
|
|
||||||
|
|
||||||
$$ \textbf{O}_i \leftarrow s^a_{ij} * \textbf{O}_i + s^b_{ij} * \mathbf{V}_{j} \times \operatorname{Softmax}(\mathbf{QK}^T_{i,j}) \text{ for multiple } i, j \text{ iterations } $$
|
|
||||||
|
|
||||||
مع \\( s^a_{ij} \\) و \\( s^b_{ij} \\) كونها بعض إحصائيات التطبيع softmax التي يجب إعادة حسابها لكل \\( i \\) و \\( j \\).
|
|
||||||
|
|
||||||
يرجى ملاحظة أن Flash Attention بالكامل أكثر تعقيدًا إلى حد ما ويتم تبسيطه بشكل كبير هنا حيث أن التعمق كثيرًا يخرج عن نطاق هذا الدليل. القارئ مدعو لإلقاء نظرة على ورقة Flash Attention المكتوبة جيدًا [1] لمزيد من التفاصيل.
|
|
||||||
|
|
||||||
الفكرة الرئيسية هنا هي:
|
|
||||||
|
|
||||||
> من خلال تتبع إحصائيات التطبيع softmax واستخدام بعض الرياضيات الذكية، يعطي Flash Attention **مخرجات متطابقة رقميًا** مقارنة بطبقة الاهتمام الذاتي الافتراضية بتكلفة ذاكرة لا تزيد خطيًا مع \\( N \\).
|
|
||||||
|
|
||||||
عند النظر إلى الصيغة، قد يقول المرء بديهيًا أن الاهتمام الفلاشي يجب أن يكون أبطأ بكثير مقارنة بصيغة الاهتمام الافتراضية حيث يلزم إجراء المزيد من الحسابات. في الواقع، يتطلب Flash Attention المزيد من عمليات الفاصلة العائمة مقارنة بالاهتمام العادي حيث يجب إعادة حساب إحصائيات التطبيع softmax باستمرار (راجع [الورقة](https://arxiv.org/abs/2205.14135) لمزيد من التفاصيل إذا كنت مهتمًا)
|
|
||||||
|
|
||||||
> ومع ذلك، فإن الاهتمام الفلاشي أسرع بكثير في الاستدلال مقارنة بالاهتمام الافتراضي الذي يأتي من قدرته على تقليل الطلبات على ذاكرة GPU الأبطأ ذات النطاق الترددي العالي (VRAM)، والتركيز بدلاً من ذلك على ذاكرة SRAM الأسرع الموجودة على الشريحة.
|
|
||||||
|
|
||||||
من الناحية الأساسية، يتأكد Flash Attention من إمكانية إجراء جميع عمليات الكتابة والقراءة الوسيطة باستخدام ذاكرة SRAM السريعة الموجودة على الشريحة بدلاً من الاضطرار إلى الوصول إلى ذاكرة VRAM الأبطأ لحساب متجه الإخراج \\( \mathbf{O} \\).
|
|
||||||
|
|
||||||
من الناحية العملية، لا يوجد حاليًا أي سبب **عدم** استخدام الاهتمام الفلاشي إذا كان متاحًا. الخوارزمية تعطي نفس المخرجات رياضيا، وأسرع وأكثر كفاءة في استخدام الذاكرة.
|
|
||||||
|
|
||||||
لنلقِ نظرة على مثال عملي.
|
|
||||||
|
|
||||||
|
|
||||||
يحصل نموذج OctoCoder الخاص بنا الآن على موجه إدخال أطول بشكل كبير يتضمن ما يسمى *موجه النظام*. تُستخدم موجهات النظام لتوجيه LLM إلى مساعد أفضل مصمم لمهام المستخدمين.
|
|
||||||
فيما يلي، نستخدم موجه النظام الذي سيجعل OctoCoder مساعد ترميز أفضل.
|
|
||||||
|
|
||||||
```python
|
|
||||||
system_prompt = """Below are a series of dialogues between various people and an AI technical assistant.
|
|
||||||
The assistant tries to be helpful, polite, honest, sophisticated, emotionally aware, and humble but knowledgeable.
|
|
||||||
The assistant is happy to help with code questions and will do their best to understand exactly what is needed.
|
|
||||||
It also tries to avoid giving false or misleading information, and it caveats when it isn't entirely sure about the right answer.
|
|
||||||
That said, the assistant is practical really does its best, and doesn't let caution get too much in the way of being useful.
|
|
||||||
|
|
||||||
The Starcoder models are a series of 15.5B parameter models trained on 80+ programming languages from The Stack (v1.2) (excluding opt-out requests).
|
|
||||||
The model uses Multi Query Attention, was trained using the Fill-in-the-Middle objective, and with 8,192 tokens context window for a trillion tokens of heavily deduplicated data.
|
|
||||||
-----
|
|
||||||
|
|
||||||
Question: Write a function that takes two lists and returns a list that has alternating elements from each input list.
|
|
||||||
|
|
||||||
Answer: Sure. Here is a function that does that.
|
|
||||||
|
|
||||||
def alternating(list1, list2):
|
|
||||||
results = []
|
|
||||||
for i in range(len(list1)):
|
|
||||||
results.append(list1[i])
|
|
||||||
results.append(list2[i])
|
|
||||||
return results
|
|
||||||
|
|
||||||
Question: Can you write some test cases for this function?
|
|
||||||
|
|
||||||
Answer: Sure, here are some tests.
|
|
||||||
|
|
||||||
assert alternating([10, 20, 30], [1, 2, 3]) == [10, 1, 20, 2, 30, 3]
|
|
||||||
assert alternating([True, False], [4, 5]) == [True, 4, False, 5]
|
|
||||||
assert alternating([], []) == []
|
|
||||||
|
|
||||||
Question: Modify the function so that it returns all input elements when the lists have uneven length. The elements from the longer list should be at the end.
|
|
||||||
|
|
||||||
Answer: Here is the modified function.
|
|
||||||
|
|
||||||
def alternating(list1, list2):
|
|
||||||
results = []
|
|
||||||
for i in range(min(len(list1), len(list2))):
|
|
||||||
results.append(list1[i])
|
|
||||||
results.append(list2[i])
|
|
||||||
if len(list1) > len(list2):
|
|
||||||
results.extend(list1[i+1:])
|
|
||||||
else:
|
|
||||||
results.extend(list2[i+1:])
|
|
||||||
return results
|
|
||||||
-----
|
|
||||||
"""
|
|
||||||
```
|
|
||||||
لأغراض التوضيح، سنكرر موجه النظام عشر مرات بحيث يكون طول الإدخال طويلاً بما يكفي لملاحظة وفورات ذاكرة Flash Attention.
|
|
||||||
نضيف موجه النص الأصلي "سؤال: يرجى كتابة وظيفة في Python تقوم بتحويل البايتات إلى جيجا بايت.
|
|
||||||
|
|
||||||
```python
|
|
||||||
long_prompt = 10 * system_prompt + prompt
|
|
||||||
```
|
|
||||||
|
|
||||||
نقوم بتنفيذ نموذجنا مرة أخرى بدقة bfloat16.
|
|
||||||
|
|
||||||
```python
|
|
||||||
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", torch_dtype=torch.bfloat16, device_map="auto")
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained("bigcode/octocoder")
|
|
||||||
|
|
||||||
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
|
||||||
```
|
|
||||||
|
|
||||||
دعنا الآن نقوم بتشغيل النموذج تمامًا مثلما كان من قبل *بدون اهتمام فلاشي* وقياس متطلبات ذاكرة GPU وقت الذروة ووقت الاستدلال.
|
|
||||||
|
|
||||||
```python
|
|
||||||
import time
|
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
result = pipe(long_prompt, max_new_tokens=60)[0]["generated_text"][len(long_prompt):]
|
|
||||||
|
|
||||||
print(f"Generated in {time.time() - start_time} seconds.")
|
|
||||||
result
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
تم التوليد في 10.96854019165039 ثانية.
|
|
||||||
بالتأكيد. إليك وظيفة للقيام بذلك.
|
|
||||||
|
|
||||||
def bytes_to_giga(bytes):
|
|
||||||
return bytes / 1024 / 1024 / 1024
|
|
||||||
|
|
||||||
الإجابة: بالتأكيد. إليك وظيفة للقيام بذلك.
|
|
||||||
|
|
||||||
ديف
|
|
||||||
```
|
|
||||||
|
|
||||||
نحصل على نفس الإخراج كما كان من قبل، ولكن هذه المرة، يقوم النموذج بتكرار الإجابة عدة مرات حتى يتم قطعها عند 60 رمزًا. ليس من المستغرب أننا كررنا موجه النظام عشر مرات لأغراض التوضيح وبالتالي قمنا بتشغيل النموذج لتكرار نفسه.
|
|
||||||
|
|
||||||
**ملاحظة** لا ينبغي تكرار موجه النظام عشر مرات في التطبيقات الواقعية - مرة واحدة كافية!
|
|
||||||
|
|
||||||
دعنا نقيس متطلبات ذاكرة GPU وقت الذروة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
bytes_to_giga_bytes(torch.cuda.max_memory_allocated())
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
37.668193340301514
|
|
||||||
```
|
|
||||||
|
|
||||||
كما نرى، فإن متطلبات ذاكرة GPU وقت الذروة أعلى بكثير مما كانت عليه في البداية، وهو ما يرجع إلى حد كبير إلى تسلسل الإدخال الأطول. أيضًا، يستغرق التوليد أكثر من دقيقة بقليل الآن.
|
|
||||||
|
|
||||||
نستدعي `flush()` لتحرير ذاكرة GPU لتجربتنا التالية.
|
|
||||||
|
|
||||||
```python
|
|
||||||
flush()
|
|
||||||
```
|
|
||||||
|
|
||||||
لمقارنة، دعونا نقوم بتشغيل نفس الدالة، ولكن تمكين الاهتمام فلاش بدلا من ذلك.
|
|
||||||
للقيام بذلك، نقوم بتحويل النموذج إلى [BetterTransformer](Https://huggingface.co/docs/optimum/bettertransformer/overview) ومن خلال القيام بذلك تمكين PyTorch's [SDPA self-attention](Https://pytorch.org/docs/master/generated/torch.nn.functional.scaled_dot_product_attention) والتي بدورها قادرة على استخدام الاهتمام فلاش.
|
|
||||||
|
|
||||||
```python
|
|
||||||
model.to_bettertransformer()
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن نقوم بتشغيل نفس مقتطف التعليمات البرمجية بالضبط كما كان من قبل وتحت الغطاء سوف تستخدم المحولات الاهتمام فلاش.
|
|
||||||
|
|
||||||
```py
|
|
||||||
start_time = time.time()
|
|
||||||
with torch.backends.cuda.sdp_kernel(enable_flash=True, enable_math=False, enable_mem_efficient=False):
|
|
||||||
result = pipe(long_prompt, max_new_tokens=60)[0]["generated_text"][len(long_prompt):]
|
|
||||||
|
|
||||||
print(f"Generated in {time.time() - start_time} seconds.")
|
|
||||||
result
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
تم التوليد في 3.0211617946624756 ثانية.
|
|
||||||
بالتأكيد. إليك وظيفة للقيام بذلك.
|
|
||||||
|
|
||||||
def bytes_to_giga(bytes):
|
|
||||||
return bytes / 1024 / 1024 / 1024
|
|
||||||
|
|
||||||
الإجابة: بالتأكيد. إليك وظيفة للقيام بذلك.
|
|
||||||
|
|
||||||
ديف
|
|
||||||
```
|
|
||||||
|
|
||||||
نحصل على نفس النتيجة بالضبط كما كان من قبل، ولكن يمكننا ملاحظة تسريع كبير بفضل الاهتمام فلاش.
|
|
||||||
|
|
||||||
دعنا نقيس استهلاك الذاكرة لآخر مرة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
bytes_to_giga_bytes(torch.cuda.max_memory_allocated())
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
32.617331981658936
|
|
||||||
```
|
|
||||||
|
|
||||||
ونحن تقريبا مرة أخرى إلى ذاكرة GPU الذروة الأصلية لدينا 29GB.
|
|
||||||
|
|
||||||
يمكننا أن نلاحظ أننا نستخدم فقط حوالي 100 ميجابايت إضافية من ذاكرة GPU عند تمرير تسلسل إدخال طويل جدًا مع الاهتمام فلاش مقارنة بتمرير تسلسل إدخال قصير كما فعلنا في البداية.
|
|
||||||
|
|
||||||
```py
|
|
||||||
flush()
|
|
||||||
```
|
|
||||||
|
|
||||||
لمزيد من المعلومات حول كيفية استخدام Flash Attention، يرجى الاطلاع على [صفحة doc هذه](Https://huggingface.co/docs/transformers/en/perf_infer_gpu_one#flashattention-2).
|
|
||||||
|
|
||||||
## 3. الابتكارات المعمارية
|
|
||||||
|
|
||||||
حتى الآن، نظرنا في تحسين الكفاءة الحسابية والذاكرة من خلال:
|
|
||||||
|
|
||||||
- صب الأوزان في تنسيق دقة أقل
|
|
||||||
- استبدال خوارزمية الاهتمام الذاتي بإصدار أكثر كفاءة من حيث الذاكرة والحساب
|
|
||||||
|
|
||||||
دعونا الآن نلقي نظرة على كيفية تغيير بنية LLM بحيث تكون أكثر فعالية وكفاءة للمهام التي تتطلب مدخلات نصية طويلة، على سبيل المثال:
|
|
||||||
- استرجاع الأسئلة المعززة،
|
|
||||||
- تلخيص،
|
|
||||||
- الدردشة
|
|
||||||
|
|
||||||
لاحظ أن "الدردشة" لا تتطلب من LLM التعامل مع مدخلات نصية طويلة فحسب، بل تتطلب أيضًا أن يكون LLM قادرًا على التعامل بكفاءة مع الحوار ذهابًا وإيابًا بين المستخدم والمساعد (مثل ChatGPT).
|
|
||||||
|
|
||||||
بمجرد تدريبها، يصبح من الصعب تغيير بنية LLM الأساسية، لذلك من المهم مراعاة مهام LLM مسبقًا وتحسين بنية النموذج وفقًا لذلك.
|
|
||||||
هناك مكونان مهمان لبنية النموذج يصبحان بسرعة عنق زجاجة للذاكرة و/أو الأداء لتسلسلات الإدخال الكبيرة.
|
|
||||||
|
|
||||||
- الترميزات الموضعية
|
|
||||||
- ذاكرة التخزين المؤقت للقيمة الرئيسية
|
|
||||||
|
|
||||||
دعنا نلقي نظرة على كل مكون بمزيد من التفاصيل
|
|
||||||
|
|
||||||
### 3.1 تحسين الترميزات الموضعية لـ LLMs
|
|
||||||
|
|
||||||
يضع الاهتمام الذاتي كل رمز في علاقة مع رموز أخرى.
|
|
||||||
كمثال، يمكن أن تبدو مصفوفة \\( \operatorname{Softmax}(\mathbf{QK}^T) \\) لتسلسل الإدخال النصي *"مرحبًا"، "أنا"، "أحب"، "أنت"* كما يلي:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
يتم منح كل رمز كلمة كتلة احتمال يتم من خلالها الاهتمام بجميع رموز الكلمات الأخرى، وبالتالي يتم وضعها في علاقة مع جميع رموز الكلمات الأخرى. على سبيل المثال، تحضر كلمة *"الحب"* كلمة *"مرحبًا"* بنسبة 5%، و *"أنا"* بنسبة 30%، ونفسها بنسبة 65%.
|
|
||||||
|
|
||||||
سيواجه LLM القائم على الاهتمام الذاتي، ولكن بدون الترميزات الموضعية، صعوبات كبيرة في فهم مواضع نصوص الإدخال بالنسبة لبعضها البعض.
|
|
||||||
ويرجع ذلك إلى أن درجة الاحتمال التي يحسبها \\( \mathbf{QK}^T \\) تربط كل رمز كلمة بكل رمز كلمة أخرى في حسابات \\( O (1) \\) بغض النظر عن مسافة الموضع النسبي بينهما.
|
|
||||||
لذلك، بالنسبة إلى LLM بدون ترميزات موضعية، يبدو أن كل رمز له نفس المسافة إلى جميع الرموز الأخرى، على سبيل المثال، سيكون من الصعب التمييز بين *"مرحبًا أنا أحبك"* و *"أنت تحبني مرحبًا"*.
|
|
||||||
|
|
||||||
لكي يفهم LLM ترتيب الجملة، يلزم وجود *إشارة* إضافية ويتم تطبيقها عادةً في شكل *الترميزات الموضعية* (أو ما يُطلق عليه أيضًا *الترميزات الموضعية*).
|
|
||||||
لم يتم ترجمة النص الخاص والروابط وأكواد HTML وCSS بناءً على طلبك.
|
|
||||||
|
|
||||||
قدم مؤلفو الورقة البحثية [*Attention Is All You Need*](https://arxiv.org/abs/1706.03762) تضمينات موضعية جيبية مثلثية \\( \mathbf{P} = \mathbf{p}_1, \ldots, \mathbf{p}_N \\) حيث يتم حساب كل متجه \\( \mathbf{p}_i \\) كدالة جيبية لموضعه \\( i \\) .
|
|
||||||
بعد ذلك يتم ببساطة إضافة التضمينات الموضعية إلى متجهات تسلسل الإدخال \\( \mathbf{\hat{X}} = \mathbf{\hat{x}}_1, \ldots, \mathbf{\hat{x}}_N \\) = \\( \mathbf{x}_1 + \mathbf{p}_1, \ldots, \mathbf{x}_N + \mathbf{p}_N \\) وبالتالي توجيه النموذج لتعلم ترتيب الجملة بشكل أفضل.
|
|
||||||
|
|
||||||
بدلاً من استخدام التضمينات الموضعية الثابتة، استخدم آخرون (مثل [Devlin et al.](https://arxiv.org/abs/1810.04805)) تضمينات موضعية مكتسبة يتم من خلالها تعلم التضمينات الموضعية \\( \mathbf{P} \\) أثناء التدريب.
|
|
||||||
|
|
||||||
كانت التضمينات الموضعية الجيبية والمكتسبة هي الطرق السائدة لترميز ترتيب الجملة في نماذج اللغة الكبيرة، ولكن تم العثور على بعض المشكلات المتعلقة بهذه التضمينات الموضعية:
|
|
||||||
|
|
||||||
1. التضمينات الموضعية الجيبية والمكتسبة هي تضمينات موضعية مطلقة، أي ترميز تضمين فريد لكل معرف موضعي: \\( 0, \ldots, N \\) . كما أظهر [Huang et al.](https://arxiv.org/abs/2009.13658) و [Su et al.](https://arxiv.org/abs/2104.09864)، تؤدي التضمينات الموضعية المطلقة إلى أداء ضعيف لنماذج اللغة الكبيرة للمدخلات النصية الطويلة. بالنسبة للمدخلات النصية الطويلة، يكون من المفيد إذا تعلم النموذج المسافة الموضعية النسبية التي تمتلكها رموز المدخلات إلى بعضها البعض بدلاً من موضعها المطلق.
|
|
||||||
2. عند استخدام التضمينات الموضعية المكتسبة، يجب تدريب نموذج اللغة الكبيرة على طول إدخال ثابت \\( N \\)، مما يجعل من الصعب الاستقراء إلى طول إدخال أطول مما تم تدريبه عليه.
|
|
||||||
|
|
||||||
في الآونة الأخيرة، أصبحت التضمينات الموضعية النسبية التي يمكنها معالجة المشكلات المذكورة أعلاه أكثر شعبية، وأبرزها:
|
|
||||||
|
|
||||||
- [تضمين الموضع الدوراني (RoPE)](https://arxiv.org/abs/2104.09864)
|
|
||||||
- [ALiBi](https://arxiv.org/abs/2108.12409)
|
|
||||||
|
|
||||||
يؤكد كل من *RoPE* و *ALiBi* أنه من الأفضل توجيه نموذج اللغة الكبيرة حول ترتيب الجملة مباشرة في خوارزمية الانتباه الذاتي حيث يتم وضع رموز الكلمات في علاقة مع بعضها البعض. على وجه التحديد، يجب توجيه ترتيب الجملة عن طريق تعديل عملية \\( \mathbf{QK}^T \\) .
|
|
||||||
|
|
||||||
دون الدخول في الكثير من التفاصيل، يشير *RoPE* إلى أنه يمكن ترميز المعلومات الموضعية في أزواج الاستعلام-المفتاح، على سبيل المثال \\( \mathbf{q}_i \\) و \\( \mathbf{x}_j \\) عن طريق تدوير كل متجه بزاوية \\( \theta * i \\) و \\( \theta * j \\) على التوالي مع \\( i, j \\) تصف موضع الجملة لكل متجه:
|
|
||||||
|
|
||||||
$$ \mathbf{\hat{q}}_i^T \mathbf{\hat{x}}_j = \mathbf{{q}}_i^T \mathbf{R}_{\theta, i -j} \mathbf{{x}}_j. $$
|
|
||||||
|
|
||||||
يمثل \\( \mathbf{R}_{\theta, i - j} \\) مصفوفة دورانية. \\( \theta \\) *لا* يتم تعلمه أثناء التدريب، ولكن بدلاً من ذلك يتم تعيينه إلى قيمة محددة مسبقًا تعتمد على طول تسلسل الإدخال الأقصى أثناء التدريب.
|
|
||||||
|
|
||||||
> من خلال القيام بذلك، يتم التأثير على درجة الاحتمال بين \\( \mathbf{q}_i \\) و \\( \mathbf{q}_j \\) فقط إذا \\( i \ne j \\) ويعتمد فقط على المسافة النسبية \\( i - j \\) بغض النظر عن المواضع المحددة لكل متجه \\( i \\) و \\( j \\) .
|
|
||||||
|
|
||||||
يستخدم *RoPE* في العديد من نماذج اللغة الكبيرة الأكثر أهمية اليوم، مثل:
|
|
||||||
|
|
||||||
- [**Falcon**](https://huggingface.co/tiiuae/falcon-40b)
|
|
||||||
- [**Llama**](https://arxiv.org/abs/2302.13971)
|
|
||||||
- [**PaLM**](https://arxiv.org/abs/2204.02311)
|
|
||||||
|
|
||||||
كبديل، يقترح *ALiBi* مخطط ترميز موضعي نسبي أبسط بكثير. يتم إضافة المسافة النسبية التي تمتلكها رموز المدخلات إلى بعضها البعض كعدد صحيح سلبي مقياس بقيمة محددة مسبقًا `m` إلى كل إدخال استعلام-مفتاح لمصفوفة \\( \mathbf{QK}^T \\) مباشرة قبل حساب softmax.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
كما هو موضح في ورقة [ALiBi](https://arxiv.org/abs/2108.12409)، يسمح هذا الترميز الموضعي النسبي البسيط للنموذج بالحفاظ على أداء عالٍ حتى في تسلسلات المدخلات النصية الطويلة جدًا.
|
|
||||||
|
|
||||||
يُستخدم *ALiBi* في العديد من أهم نماذج اللغة الكبيرة المستخدمة اليوم، مثل:
|
|
||||||
|
|
||||||
- [**MPT**](https://huggingface.co/mosaicml/mpt-30b)
|
|
||||||
- [**BLOOM**](https://huggingface.co/bigscience/bloom)
|
|
||||||
|
|
||||||
يمكن لكل من ترميزات الموضع *RoPE* و *ALiBi* الاستقراء إلى أطوال إدخال لم يتم ملاحظتها أثناء التدريب، في حين ثبت أن الاستقراء يعمل بشكل أفضل بكثير خارج الصندوق لـ *ALiBi* مقارنة بـ *RoPE*.
|
|
||||||
بالنسبة لـ ALiBi، ما عليك سوى زيادة قيم مصفوفة الموضع المثلث السفلي لمطابقة طول تسلسل الإدخال.
|
|
||||||
بالنسبة لـ *RoPE*، يؤدي الحفاظ على نفس \\( \theta \\) الذي تم استخدامه أثناء التدريب إلى نتائج سيئة عند تمرير إدخالات نصية أطول بكثير من تلك التي شوهدت أثناء التدريب، راجع [Press et al.](https://arxiv.org/abs/2108.12409). ومع ذلك، وجد المجتمع بعض الحيل الفعالة التي تقوم بتعديل \\( \theta \\)، مما يسمح لترميزات الموضع *RoPE* بالعمل بشكل جيد لتسلسلات إدخال النص المستقرئة (راجع [هنا](https://github.com/huggingface/transformers/pull/24653)).
|
|
||||||
|
|
||||||
> كل من RoPE و ALiBi عبارة عن ترميزات موضع نسبي *لا* يتم تعلمها أثناء التدريب، ولكن بدلاً من ذلك تستند إلى الحدس التالي:
|
|
||||||
- يجب إعطاء الإشارات الموضعية حول إدخالات النص مباشرة إلى مصفوفة \\( QK^T \\) لطبقة الاهتمام الذاتي
|
|
||||||
- يجب تحفيز LLM لتعلم ترميزات موضعية ثابتة *نسبية* المسافة لبعضها البعض
|
|
||||||
- كلما ابتعدت رموز إدخال النص عن بعضها البعض، انخفض احتمال الاستعلام والقيمة. كل من RoPE و ALiBi يقللان من احتمال الاستعلام والمفتاح للرموز البعيدة عن بعضها البعض. يقوم RoPE بذلك عن طريق تقليل منتج المتجه من خلال زيادة الزاوية بين متجهات الاستعلام والمفتاح. تضيف ALiBi أرقامًا كبيرة سالبة إلى المنتج الاتجاهي
|
|
||||||
|
|
||||||
في الختام، من الأفضل تدريب نماذج اللغة الكبيرة المراد نشرها في مهام تتطلب التعامل مع إدخالات نصية كبيرة باستخدام ترميزات موضعية نسبية، مثل RoPE و ALiBi. لاحظ أيضًا أنه حتى إذا تم تدريب نموذج لغة كبيرة باستخدام RoPE و ALiBi على طول ثابت يبلغ، على سبيل المثال، \\( N_1 = 2048 \\)، فيمكن استخدامه عمليًا بإدخالات نصية أكبر بكثير من \\( N_1 \\)، مثل \\( N_2 = 8192> N_1 \\) عن طريق استقراء الترميزات الموضعية.
|
|
||||||
|
|
||||||
### 3.2 ذاكرة التخزين المؤقت للمفتاح والقيمة
|
|
||||||
|
|
||||||
تعمل عملية توليد النص ذاتي التراجع باستخدام نماذج اللغة الكبيرة عن طريق إدخال تسلسل إدخال بشكل تكراري، وأخذ عينات من الرمز التالي، وإلحاق الرمز التالي بتسلسل الإدخال، والاستمرار في ذلك حتى ينتج نموذج اللغة الكبيرة رمزًا يشير إلى انتهاء التوليد.
|
|
||||||
|
|
||||||
يرجى الاطلاع على [دليل إنشاء النص الخاص بـ Transformer](https://huggingface.co/docs/transformers/llm_tutorial#generate-text) للحصول على شرح مرئي أفضل لكيفية عمل التوليد ذاتي التراجع.
|
|
||||||
|
|
||||||
دعنا ننفذ مقتطفًا قصيرًا من التعليمات البرمجية لإظهار كيفية عمل التوليد ذاتي التراجع في الممارسة. ببساطة، سنأخذ الرمز الأكثر احتمالًا عبر `torch.argmax`.
|
|
||||||
|
|
||||||
```python
|
|
||||||
input_ids = tokenizer(prompt, return_tensors="pt")["input_ids"].to("cuda")
|
|
||||||
|
|
||||||
for _ in range(5):
|
|
||||||
next_logits = model(input_ids)["logits"][:, -1:]
|
|
||||||
next_token_id = torch.argmax(next_logits,dim=-1)
|
|
||||||
|
|
||||||
input_ids = torch.cat([input_ids, next_token_id], dim=-1)
|
|
||||||
print("shape of input_ids", input_ids.shape)
|
|
||||||
|
|
||||||
generated_text = tokenizer.batch_decode(input_ids[:, -5:])
|
|
||||||
generated_text
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
shape of input_ids torch.Size([1, 21])
|
|
||||||
shape of input_ids torch.Size([1, 22])
|
|
||||||
shape of input_ids torch.Size([1, 23])
|
|
||||||
shape of input_ids torch.Size([1, 24])
|
|
||||||
shape of input_ids torch.Size([1, 25])
|
|
||||||
[' Here is a Python function']
|
|
||||||
```
|
|
||||||
|
|
||||||
كما نرى، في كل مرة نزيد من رموز إدخال النص بالرمز الذي تم أخذ عينات منه للتو.
|
|
||||||
|
|
||||||
باستثناءات قليلة جدًا، يتم تدريب نماذج اللغة الكبيرة باستخدام [هدف نمذجة اللغة السببية](https://huggingface.co/docs/transformers/tasks/language_modeling#causal-language-modeling) وبالتالي يتم قناع المثلث العلوي لمصفوفة نتيجة الاهتمام - وهذا هو السبب في ترك نتائج الاهتمام فارغة (*أي لها احتمال 0*) في المخططين أعلاه. للحصول على ملخص سريع حول نمذجة اللغة السببية، يمكنك الرجوع إلى مدونة [*Illustrated Self Attention*](https://jalammar.github.io/illustrated-gpt2/#part-2-illustrated-self-attention).
|
|
||||||
|
|
||||||
ونتيجة لذلك، *لا* تعتمد الرموز *أبدًا* على الرموز السابقة، وبشكل أكثر تحديدًا، لا يتم أبدًا وضع المتجه \\( \mathbf{q}_i \\) في علاقة مع أي متجهات المفاتيح والقيم \\( \mathbf{k}_j، \mathbf{v}_j \\) إذا \\( j> i \\). بدلاً من ذلك، يحضر \\( \mathbf{q}_i \\) فقط إلى متجهات المفاتيح والقيم السابقة \\( \mathbf{k}_{m < i}، \mathbf{v}_{m < i} \text{ , for } m \in \{0، \ ldots i - 1\} \\). لتقليل الحسابات غير الضرورية، يمكن تخزين ذاكرة التخزين المؤقت لكل طبقة للمفاتيح ومتجهات القيم لجميع الخطوات الزمنية السابقة.
|
|
||||||
|
|
||||||
فيما يلي، سنطلب من نموذج اللغة الكبيرة استخدام ذاكرة التخزين المؤقت للمفاتيح والقيم عن طريق استردادها وإرسالها لكل عملية توجيه.
|
|
||||||
في Transformers، يمكننا استرداد ذاكرة التخزين المؤقت للمفاتيح والقيم عن طريق تمرير علم `use_cache` إلى مكالمة `forward` ويمكننا بعد ذلك تمريره مع الرمز الحالي.
|
|
||||||
|
|
||||||
```python
|
|
||||||
past_key_values = None # past_key_values is the key-value cache
|
|
||||||
generated_tokens = []
|
|
||||||
next_token_id = tokenizer(prompt, return_tensors="pt")["input_ids"].to("cuda")
|
|
||||||
|
|
||||||
for _ in range(5):
|
|
||||||
next_logits, past_key_values = model(next_token_id, past_key_values=past_key_values, use_cache=True).to_tuple()
|
|
||||||
next_logits = next_logits[:, -1:]
|
|
||||||
next_token_id = torch.argmax(next_logits, dim=-1)
|
|
||||||
|
|
||||||
print("shape of input_ids", next_token_id.shape)
|
|
||||||
print("length of key-value cache", len(past_key_values[0][0])) # past_key_values are of shape [num_layers, 0 for k, 1 for v, batch_size, length, hidden_dim]
|
|
||||||
generated_tokens.append(next_token_id.item())
|
|
||||||
|
|
||||||
generated_text = tokenizer.batch_decode(generated_tokens)
|
|
||||||
generated_text
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
shape of input_ids torch.Size([1, 1])
|
|
||||||
length of key-value cache 20
|
|
||||||
shape of input_ids torch.Size([1, 1])
|
|
||||||
length of key-value cache 21
|
|
||||||
shape of input_ids torch.Size([1, 1])
|
|
||||||
length of key-value cache 22
|
|
||||||
shape of input_ids torch.Size([1, 1])
|
|
||||||
length of key-value cache 23
|
|
||||||
shape of input_ids torch.Size([1, 1])
|
|
||||||
length of key-value cache 24
|
|
||||||
[' Here', ' is', ' a', ' Python', ' function']
|
|
||||||
```
|
|
||||||
|
|
||||||
كما هو موضح، عند استخدام ذاكرة التخزين المؤقت للمفاتيح والقيم، لا يتم زيادة رموز إدخال النص في الطول، ولكنها تظل متجه إدخال واحدًا. من ناحية أخرى، يتم زيادة طول ذاكرة التخزين المؤقت للمفاتيح والقيم بواحد في كل خطوة فك التشفير.
|
|
||||||
|
|
||||||
> يعني استخدام ذاكرة التخزين المؤقت للمفاتيح والقيم أن \\( \mathbf{QK}^T \\) يتم تقليله بشكل أساسي إلى \\( \mathbf{q}_c\mathbf{K}^T \\) مع \\( \mathbf{q}_c \\) كونها إسقاط الاستعلام للرمز المدخل الحالي الذي يكون *دائمًا* مجرد متجه واحد.
|
|
||||||
|
|
||||||
لاستخدام ذاكرة التخزين المؤقت للمفاتيح والقيم ميزتان:
|
|
||||||
- زيادة كبيرة في الكفاءة الحسابية حيث يتم إجراء حسابات أقل مقارنة بحساب مصفوفة \\( \mathbf{QK}^T \\) الكاملة. يؤدي ذلك إلى زيادة سرعة الاستدلال
|
|
||||||
- لا تزداد الذاكرة القصوى المطلوبة بشكل تربيعي مع عدد الرموز المولدة، ولكنها تزداد بشكل خطي فقط.
|
|
||||||
|
|
||||||
> يجب *دائمًا* استخدام ذاكرة التخزين المؤقت للمفاتيح والقيم حيث يؤدي ذلك إلى نتائج متطابقة وزيادة كبيرة في السرعة لتسلسلات الإدخال الأطول. ذاكرة التخزين المؤقت للمفاتيح والقيم ممكّنة بشكل افتراضي في Transformers عند استخدام خط أنابيب النص أو طريقة [`generate`](https://huggingface.co/docs/transformers/main_classes/text_generation).
|
|
||||||
|
|
||||||
|
|
||||||
<Tip warning={true}>
|
|
||||||
|
|
||||||
لاحظ أنه على الرغم من نصيحتنا باستخدام ذاكرة التخزين المؤقت للمفاتيح والقيم، فقد يكون إخراج نموذج اللغة الكبيرة مختلفًا قليلاً عند استخدامها. هذه خاصية نوى ضرب المصفوفة نفسها - يمكنك قراءة المزيد عنها [هنا](https://github.com/huggingface/transformers/issues/25420#issuecomment-1775317535).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
#### 3.2.1 محادثة متعددة الجولات
|
|
||||||
|
|
||||||
ذاكرة التخزين المؤقت للمفاتيح والقيم مفيدة بشكل خاص للتطبيقات مثل الدردشة حيث تكون هناك حاجة إلى عدة تمريرات من فك التشفير ذاتي التراجع. دعنا نلقي نظرة على مثال.
|
|
||||||
|
|
||||||
```
|
|
||||||
المستخدم: كم عدد الأشخاص الذين يعيشون في فرنسا؟
|
|
||||||
المساعد: يعيش حوالي 75 مليون شخص في فرنسا
|
|
||||||
المستخدم: وكم عدد الأشخاص في ألمانيا؟
|
|
||||||
المساعد: يوجد في ألمانيا حوالي 81 مليون نسمة
|
|
||||||
|
|
||||||
User: How many people live in France?
|
|
||||||
Assistant: Roughly 75 million people live in France
|
|
||||||
User: And how many are in Germany?
|
|
||||||
Assistant: Germany has ca. 81 million inhabitants
|
|
||||||
```
|
|
||||||
|
|
||||||
In this chat، يقوم LLM بتشغيل فك التشفير التلقائي مرتين:
|
|
||||||
1. المرة الأولى، تكون ذاكرة التخزين المؤقت key-value فارغة، ويكون موجه الإدخال هو "User: How many people live in France؟" ويقوم النموذج بإنشاء النص "Roughly 75 million people live in France" بشكل تلقائي أثناء زيادة ذاكرة التخزين المؤقت key-value في كل خطوة فك تشفير.
|
|
||||||
2. في المرة الثانية، يكون موجه الإدخال هو "User: How many people live in France؟ \n Assistant: Roughly 75 million people live in France \n User: And how many in Germany؟". بفضل ذاكرة التخزين المؤقت، يتم بالفعل حساب جميع متجهات القيمة الرئيسية لجاريتين الأولى. لذلك يتكون موجه الإدخال فقط من "User: And how many in Germany؟". أثناء معالجة موجه الإدخال المختصر، يتم ربط متجهات القيمة المحسوبة بذاكرة التخزين المؤقت key-value الخاصة بفك التشفير الأول. يتم بعد ذلك إنشاء إجابة المساعد الثانية "Germany has ca. 81 million inhabitants" بشكل تلقائي باستخدام ذاكرة التخزين المؤقت key-value المكونة من متجهات القيمة المشفرة لـ "User: How many people live in France؟ \n Assistant: Roughly 75 million people live in France \n User: And how many are in Germany؟".
|
|
||||||
|
|
||||||
يجب ملاحظة أمرين هنا:
|
|
||||||
1. الحفاظ على كل السياق أمر بالغ الأهمية للنماذج اللغوية الكبيرة (LLMs) التي يتم نشرها في الدردشة بحيث يفهم LLM كل سياق المحادثة السابق. على سبيل المثال، بالنسبة للمثال أعلاه، يحتاج LLM إلى فهم أن المستخدم يشير إلى السكان عند السؤال "And how many are in Germany؟".
|
|
||||||
2. ذاكرة التخزين المؤقت key-value مفيدة للغاية للدردشة حيث تتيح لنا النمو المستمر لتاريخ الدردشة المشفرة بدلاً من الاضطرار إلى إعادة تشفير تاريخ الدردشة من البداية (كما هو الحال، على سبيل المثال، عند استخدام بنية ترميز فك التشفير).
|
|
||||||
|
|
||||||
في `transformers`، ستعيد مكالمة `generate` `past_key_values` عندما يتم تمرير `return_dict_in_generate=True`، بالإضافة إلى `use_cache=True` الافتراضي. لاحظ أنه غير متوفر بعد من خلال واجهة `pipeline`.
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Generation as usual
|
|
||||||
prompt = system_prompt + "Question: Please write a function in Python that transforms bytes to Giga bytes.\n\nAnswer: Here"
|
|
||||||
model_inputs = tokenizer(prompt، return_tensors='pt')
|
|
||||||
generation_output = model.generate(**model_inputs، max_new_tokens=60، return_dict_in_generate=True)
|
|
||||||
decoded_output = tokenizer.batch_decode(generation_output.sequences)[0]
|
|
||||||
|
|
||||||
# Piping the returned `past_key_values` to speed up the next conversation round
|
|
||||||
prompt = decoded_output + "\nQuestion: How can I modify the function above to return Mega bytes instead?\n\nAnswer: Here"
|
|
||||||
model_inputs = tokenizer(prompt، return_tensors='pt')
|
|
||||||
generation_output = model.generate(
|
|
||||||
**model_inputs،
|
|
||||||
past_key_values=generation_output.past_key_values،
|
|
||||||
max_new_tokens=60،
|
|
||||||
return_dict_in_generate=True
|
|
||||||
)
|
|
||||||
tokenizer.batch_decode(generation_output.sequences)[0][len(prompt):]
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
هي نسخة معدلة من الدالة التي تعيد ميجا بايت بدلاً من ذلك.
|
|
||||||
|
|
||||||
def bytes_to_megabytes(bytes):
|
|
||||||
return bytes / 1024 / 1024
|
|
||||||
|
|
||||||
Answer: The function takes a number of bytes as input and returns the number of
|
|
||||||
```
|
|
||||||
|
|
||||||
رائع، لا يتم إنفاق وقت إضافي على إعادة حساب نفس المفتاح والقيم لطبقة الاهتمام! ومع ذلك، هناك شيء واحد يجب ملاحظته. في حين أن ذروة الذاكرة المطلوبة لمصفوفة \\( \mathbf{QK}^T \\) يتم تقليلها بشكل كبير، فإن الاحتفاظ بذاكرة التخزين المؤقت key-value في الذاكرة يمكن أن يصبح مكلفًا جدًا من حيث الذاكرة لسلاسل الإدخال الطويلة أو الدردشة متعددة الجولات. تذكر أن ذاكرة التخزين المؤقت key-value بحاجة إلى تخزين متجهات القيمة الرئيسية لجميع متجهات الإدخال السابقة \\( \mathbf{x}_i \text{، لـ } i \in \{1، \ ldots، c - 1\} \\) لجميع طبقات الاهتمام الذاتي وكل رؤوس الاهتمام.
|
|
||||||
|
|
||||||
دعنا نحسب عدد القيم العائمة التي يجب تخزينها في ذاكرة التخزين المؤقت key-value لنموذج LLM `bigcode/octocoder` الذي استخدمناه من قبل.
|
|
||||||
يبلغ عدد القيم العائمة ضعف طول التسلسل مضروبًا في عدد رؤوس الاهتمام مضروبًا في بعد رأس الاهتمام ومضروبًا في عدد الطبقات.
|
|
||||||
حساب هذا لنموذج LLM لدينا عند طول تسلسل افتراضي يبلغ 16000 يعطي:
|
|
||||||
|
|
||||||
```python
|
|
||||||
config = model.config
|
|
||||||
2 * 16_000 * config.n_layer * config.n_head * config.n_embd // config.n_head
|
|
||||||
```
|
|
||||||
|
|
||||||
**الإخراج**:
|
|
||||||
```
|
|
||||||
7864320000
|
|
||||||
```
|
|
||||||
|
|
||||||
Roughly 8 مليار قيمة عائمة! يتطلب تخزين 8 مليارات قيمة عائمة في دقة `float16` حوالي 15 جيجابايت من ذاكرة الوصول العشوائي (RAM) وهو ما يقرب من نصف حجم أوزان النموذج نفسها!
|
|
||||||
اقترح الباحثون طريقتين تسمحان بتقليل تكلفة الذاكرة لتخزين ذاكرة التخزين المؤقت key-value بشكل كبير، والتي يتم استكشافها في الأقسام الفرعية التالية.
|
|
||||||
|
|
||||||
#### 3.2.2 Multi-Query-Attention (MQA)
|
|
||||||
|
|
||||||
[Multi-Query-Attention](https://arxiv.org/abs/1911.02150) اقترحها Noam Shazeer في ورقته *Fast Transformer Decoding: One Write-Head is All You Need*. كما يقول العنوان، اكتشف Noam أنه بدلاً من استخدام `n_head` من أوزان إسقاط القيمة الرئيسية، يمكن استخدام زوج واحد من أوزان إسقاط رأس القيمة التي يتم مشاركتها عبر جميع رؤوس الاهتمام دون أن يتدهور أداء النموذج بشكل كبير.
|
|
||||||
|
|
||||||
> باستخدام زوج واحد من أوزان إسقاط رأس القيمة، يجب أن تكون متجهات القيمة الرئيسية \\( \mathbf{k}_i، \mathbf{v}_i \\) متطابقة عبر جميع رؤوس الاهتمام والتي بدورها تعني أننا بحاجة فقط إلى تخزين زوج إسقاط قيمة رئيسي واحد في ذاكرة التخزين المؤقت بدلاً من `n_head` منها.
|
|
||||||
|
|
||||||
نظرًا لأن معظم LLMs تستخدم ما بين 20 و100 رأس اهتمام، فإن MQA يقلل بشكل كبير من استهلاك الذاكرة لذاكرة التخزين المؤقت key-value. بالنسبة إلى LLM المستخدم في هذا الدفتر، يمكننا تقليل استهلاك الذاكرة المطلوبة من 15 جيجابايت إلى أقل من 400 ميجابايت عند طول تسلسل الإدخال 16000.
|
|
||||||
|
|
||||||
بالإضافة إلى توفير الذاكرة، يؤدي MQA أيضًا إلى تحسين الكفاءة الحسابية كما هو موضح في ما يلي.
|
|
||||||
في فك التشفير التلقائي، يجب إعادة تحميل متجهات القيمة الرئيسية الكبيرة، ودمجها مع زوج متجه القيمة الحالي، ثم إدخالها في \\( \mathbf{q}_c\mathbf{K}^T \\) الحساب في كل خطوة. بالنسبة لفك التشفير التلقائي، يمكن أن تصبح عرض النطاق الترددي للذاكرة المطلوبة لإعادة التحميل المستمر عنق زجاجة زمنيًا خطيرًا. من خلال تقليل حجم متجهات القيمة الرئيسية، يجب الوصول إلى ذاكرة أقل، وبالتالي تقليل عنق الزجاجة في عرض النطاق الترددي للذاكرة. لمزيد من التفاصيل، يرجى إلقاء نظرة على [ورقة Noam](https://arxiv.org/abs/1911.02150).
|
|
||||||
|
|
||||||
الجزء المهم الذي يجب فهمه هنا هو أن تقليل عدد رؤوس الاهتمام بالقيمة الرئيسية إلى 1 لا معنى له إلا إذا تم استخدام ذاكرة التخزين المؤقت للقيمة الرئيسية. يظل الاستهلاك الذروي لذاكرة النموذج لمرور واحد للأمام بدون ذاكرة التخزين المؤقت للقيمة الرئيسية دون تغيير لأن كل رأس اهتمام لا يزال لديه متجه استعلام فريد بحيث يكون لكل رأس اهتمام مصفوفة \\( \mathbf{QK}^T \\) مختلفة.
|
|
||||||
|
|
||||||
شهدت MQA اعتمادًا واسع النطاق من قبل المجتمع ويتم استخدامها الآن بواسطة العديد من LLMs الأكثر شهرة:
|
|
||||||
|
|
||||||
- [**Falcon**](https://huggingface.co/tiiuae/falcon-40b)
|
|
||||||
- [**PaLM**](https://arxiv.org/abs/2204.02311)
|
|
||||||
- [**MPT**](https://huggingface.co/mosaicml/mpt-30b)
|
|
||||||
- [**BLOOM**](https://huggingface.co/bigscience/bloom)
|
|
||||||
|
|
||||||
كما يستخدم نقطة التحقق المستخدمة في هذا الدفتر - `bigcode/octocoder` - MQA.
|
|
||||||
|
|
||||||
#### 3.2.3 مجموعة الاستعلام الاهتمام (GQA)
|
|
||||||
|
|
||||||
[مجموعة الاستعلام الاهتمام](https://arxiv.org/abs/2305.13245)، كما اقترح Ainslie et al. من Google، وجد أن استخدام MQA يمكن أن يؤدي غالبًا إلى تدهور الجودة مقارنة باستخدام إسقاطات رأس القيمة الرئيسية المتعددة. تجادل الورقة بأنه يمكن الحفاظ على أداء النموذج بشكل أكبر عن طريق تقليل عدد أوزان إسقاط رأس الاستعلام بشكل أقل حدة. بدلاً من استخدام وزن إسقاط قيمة رئيسية واحدة فقط، يجب استخدام `n <n_head` أوزان إسقاط قيمة رئيسية. من خلال اختيار `n` إلى قيمة أقل بكثير من `n_head`، مثل 2 أو 4 أو 8، يمكن الاحتفاظ بمعظم مكاسب الذاكرة والسرعة من MQA مع التضحية بقدر أقل من سعة النموذج وبالتالي، من المفترض، أقل أداء.
|
|
||||||
|
|
||||||
علاوة على ذلك، اكتشف مؤلفو GQA أنه يمكن *تدريب* نقاط تفتيش النموذج الموجودة ليكون لها بنية GQA باستخدام 5% فقط من الحوسبة الأصلية للتعليم المسبق. في حين أن 5% من الحوسبة الأصلية للتعليم المسبق يمكن أن تكون كمية هائلة، يسمح GQA *uptraining* بنقاط تفتيش موجودة للاستفادة من تسلسلات الإدخال الأطول.
|
|
||||||
|
|
||||||
تم اقتراح GQA مؤخرًا فقط، ولهذا السبب هناك اعتماد أقل وقت كتابة هذا الدفتر.
|
|
||||||
أبرز تطبيق لـ GQA هو [Llama-v2](https://huggingface.co/meta-llama/Llama-2-70b-hf).
|
|
||||||
|
|
||||||
> كخاتمة، من المستحسن بشدة استخدام GQA أو MQA إذا تم نشر LLM باستخدام فك التشفير التلقائي ويتطلب التعامل مع تسلسلات الإدخال الكبيرة كما هو الحال على سبيل المثال للدردشة.
|
|
||||||
|
|
||||||
|
|
||||||
## الخاتمة
|
|
||||||
|
|
||||||
مجتمع البحث يأتي باستمرار بطرق جديدة ومبتكرة لتسريع وقت الاستدلال للنماذج اللغوية الكبيرة على الإطلاق. كمثال، أحد اتجاهات البحث الواعدة هو [فك التشفير التخميني](https://arxiv.org/abs/2211.17192) حيث تقوم "الرموز السهلة" بإنشائها نماذج اللغة الأصغر والأسرع ويتم إنشاء "الرموز الصعبة" فقط بواسطة LLM نفسه. إن التعمق في التفاصيل يتجاوز نطاق هذا الدفتر، ولكن يمكن قراءته في هذه [تدوينة المدونة اللطيفة](https://huggingface.co/blog/assisted-generation).
|
|
||||||
|
|
||||||
السبب في أن LLMs الضخمة مثل GPT3/4، وLlama-2-70b، وClaude، وPaLM يمكن أن تعمل بسرعة كبيرة في واجهات الدردشة مثل [Hugging Face Chat](https://huggingface.co/chat/) أو ChatGPT يرجع إلى حد كبير إلى التحسينات المذكورة أعلاه في الدقة والخوارزميات والهندسة المعمارية.
|
|
||||||
في المستقبل، ستكون أجهزة التسريع مثل وحدات معالجة الرسومات (GPUs) ووحدات معالجة الرسومات (TPUs)، وما إلى ذلك... ستكون أسرع فقط وستسمح بمزيد من الذاكرة، ولكن يجب دائمًا التأكد من استخدام أفضل الخوارزميات والهندسة المعمارية المتاحة للحصول على أكبر قدر من المال
|
|
||||||
@ -1,226 +0,0 @@
|
|||||||
# تشريح عملية تدريب النموذج
|
|
||||||
|
|
||||||
لفهم تقنيات تحسين الأداء التي يمكن تطبيقها لتحسين كفاءة استخدام الذاكرة وسرعة تدريب النموذج، من المفيد التعرف على كيفية استخدام وحدة معالجة الرسوميات (GPU) أثناء التدريب، وكيف تختلف كثافة العمليات الحسابية باختلاف العملية التي يتم تنفيذها.
|
|
||||||
|
|
||||||
لنبدأ باستكشاف مثال توضيحي على استخدام وحدة GPU وتشغيل تدريب نموذج. وللتوضيح، سنحتاج إلى تثبيت بعض المكتبات:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers datasets accelerate nvidia-ml-py3
|
|
||||||
```
|
|
||||||
|
|
||||||
تتيح مكتبة `nvidia-ml-py3` إمكانية مراقبة استخدام الذاكرة في النماذج من داخل بايثون. قد تكون على دراية بأمر `nvidia-smi` في الجهاز - تسمح هذه المكتبة بالوصول إلى نفس المعلومات مباشرة في بايثون.
|
|
||||||
|
|
||||||
ثم، نقوم بإنشاء بعض البيانات الوهمية:معرّفات رموز عشوائية بين 100 و30000 وتصنيفات ثنائية للمصنف.
|
|
||||||
|
|
||||||
في المجموع، نحصل على 512 تسلسلًا، لكل منها طول 512، ونخزنها في [`~datasets.Dataset`] بتنسيق PyTorch.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import numpy as np
|
|
||||||
>>> from datasets import Dataset
|
|
||||||
|
|
||||||
>>> seq_len, dataset_size = 512, 512
|
|
||||||
>>> dummy_data = {
|
|
||||||
... "input_ids": np.random.randint(100, 30000, (dataset_size, seq_len)),
|
|
||||||
... "labels": np.random.randint(0, 1, (dataset_size)),
|
|
||||||
... }
|
|
||||||
>>> ds = Dataset.from_dict(dummy_data)
|
|
||||||
>>> ds.set_format("pt")
|
|
||||||
```
|
|
||||||
|
|
||||||
لطباعة إحصائيات موجزة لاستخدام وحدة GPU وتشغيل التدريب مع [`Trainer`]، نقوم بتعريف دالتين مساعدتين:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from pynvml import *
|
|
||||||
|
|
||||||
>>> def print_gpu_utilization():
|
|
||||||
... nvmlInit()
|
|
||||||
... handle = nvmlDeviceGetHandleByIndex(0)
|
|
||||||
... info = nvmlDeviceGetMemoryInfo(handle)
|
|
||||||
... print(f"GPU memory occupied: {info.used//1024**2} MB.")
|
|
||||||
|
|
||||||
>>> def print_summary(result):
|
|
||||||
... print(f"Time: {result.metrics['train_runtime']:.2f}")
|
|
||||||
... print(f"Samples/second: {result.metrics['train_samples_per_second']:.2f}")
|
|
||||||
... print_gpu_utilization()
|
|
||||||
```
|
|
||||||
|
|
||||||
دعنا نتأكد من أننا نبدأ بذاكرة وحدة GPU خالية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> print_gpu_utilization()
|
|
||||||
GPU memory occupied: 0 MB.
|
|
||||||
```
|
|
||||||
|
|
||||||
يبدو ذلك جيدًا: لم يتم شغل ذاكرة وحدة معالجة الرسومات كما نتوقع قبل تحميل أي نماذج. إذا لم يكن الأمر كذلك على جهازك، فتأكد من إيقاف جميع العمليات التي تستخدم ذاكرة وحدة GPU. ومع ذلك، لا يمكن للمستخدم استخدام كل ذاكرة وحدة GPU الفارغة. عندما يتم تحميل نموذج إلى وحدة GPU، يتم أيضًا تحميل النواة، والتي يمكن أن تستهلك 1-2 جيجابايت من الذاكرة. ولرؤية مقدار ذلك، نقوم بتحميل مصفوفة صغيرة إلى وحدة GPU والتي تؤدي إلى تحميل النواة أيضًا.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import torch
|
|
||||||
|
|
||||||
>>> torch.ones((1, 1)).to("cuda")
|
|
||||||
>>> print_gpu_utilization()
|
|
||||||
GPU memory occupied: 1343 MB.
|
|
||||||
```
|
|
||||||
|
|
||||||
نلاحظ أن النواة وحدها تستهلك 1.3 جيجابايت من ذاكرة وحدة GPU. الآن دعنا نرى مقدار المساحة التي يستخدمها النموذج.
|
|
||||||
|
|
||||||
## تحميل النموذج
|
|
||||||
|
|
||||||
أولاً، نقوم بتحميل نموذج `google-bert/bert-large-uncased`. نقوم بتحميل أوزان النموذج مباشرة إلى وحدة GPU حتى نتمكن من التحقق من مقدار المساحة التي تستخدمها الأوزان فقط.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForSequenceClassification
|
|
||||||
|
|
||||||
>>> model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-large-uncased").to("cuda")
|
|
||||||
>>> print_gpu_utilization()
|
|
||||||
GPU memory occupied: 2631 MB.
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكننا أن نرى أن أوزان النموذج وحدها تستهلك 1.3 جيجابايت من ذاكرة وحدة GPU. يعتمد الرقم الدقيق على وحدة GPU المحددة التي تستخدمها. لاحظ أنه في وحدات GPU الأحدث، قد يستغرق النموذج في بعض الأحيان مساحة أكبر نظرًا لأن الأوزان يتم تحميلها بطريقة مُحسّنة تُسرّع من استخدام النموذج. الآن يمكننا أيضًا التحقق بسرعة مما إذا كنا نحصل على نفس النتيجة كما هو الحال مع `nvidia-smi` CLI:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nvidia-smi
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
Tue Jan 11 08:58:05 2022
|
|
||||||
+-----------------------------------------------------------------------------+
|
|
||||||
| NVIDIA-SMI 460.91.03 Driver Version: 460.91.03 CUDA Version: 11.2 |
|
|
||||||
|-------------------------------+----------------------+----------------------+
|
|
||||||
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
|
|
||||||
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|
|
||||||
| | | MIG M. |
|
|
||||||
|===============================+======================+======================|
|
|
||||||
| 0 Tesla V100-SXM2... On | 00000000:00:04.0 Off | 0 |
|
|
||||||
| N/A 37C P0 39W / 300W | 2631MiB / 16160MiB | 0% Default |
|
|
||||||
| | | N/A |
|
|
||||||
+-------------------------------+----------------------+----------------------+
|
|
||||||
|
|
||||||
+-----------------------------------------------------------------------------+
|
|
||||||
| Processes: |
|
|
||||||
| GPU GI CI PID Type Process name GPU Memory |
|
|
||||||
| ID ID Usage |
|
|
||||||
|=============================================================================|
|
|
||||||
| 0 N/A N/A 3721 C ...nvs/codeparrot/bin/python 2629MiB |
|
|
||||||
+-----------------------------------------------------------------------------+
|
|
||||||
```
|
|
||||||
|
|
||||||
نحصل على نفس الرقم كما كان من قبل، ويمكنك أيضًا أن ترى أننا نستخدم GPU من طراز V100 مع 16 جيجابايت من الذاكرة. لذا الآن يمكننا بدء تدريب النموذج ورؤية كيف يتغير استخدام ذاكرة GPU. أولاً، نقوم بإعداد بعض معاملات التدريب القياسية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
default_args = {
|
|
||||||
"output_dir": "tmp"،
|
|
||||||
"eval_strategy": "steps"،
|
|
||||||
"num_train_epochs": 1،
|
|
||||||
"log_level": "error"،
|
|
||||||
"report_to": "none"،
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا كنت تخطط لتشغيل عدة تجارب، من أجل مسح الذاكرة بشكل صحيح بين التجارب، قم بإعادة تشغيل نواة Python بين التجارب.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## استخدام الذاكرة في التدريب الأساسي
|
|
||||||
|
|
||||||
دعونا نستخدم [`Trainer`] وقم بتدريب النموذج دون استخدام أي تقنيات تحسين أداء GPU وحجم دفعة يبلغ 4:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TrainingArguments، Trainer، logging
|
|
||||||
|
|
||||||
>>> logging.set_verbosity_error()
|
|
||||||
|
|
||||||
|
|
||||||
>>> training_args = TrainingArguments(per_device_train_batch_size=4، **default_args)
|
|
||||||
>>> trainer = Trainer(model=model، args=training_args، train_dataset=ds)
|
|
||||||
>>> result = trainer.train()
|
|
||||||
>>> print_summary(result)
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
الوقت: 57.82
|
|
||||||
العينات / الثانية: 8.86
|
|
||||||
ذاكرة GPU المشغولة: 14949 ميجابايت.
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكننا أن نرى أن حجم دفعة صغير نسبيًا يملأ تقريبًا ذاكرة GPU بالكامل. ومع ذلك، غالبًا ما يؤدي حجم دفعة أكبر في تقارب نموذج أسرع أو أداء أفضل في النهاية. لذلك نريد أن نضبط حجم الدفعة وفقًا لاحتياجات النموذج لدينا وليس مع قيود وحدة GPU. ما يثير الاهتمام هو أننا نستخدم ذاكرة أكثر بكثير من حجم النموذج.
|
|
||||||
لفهم سبب ذلك بشكل أفضل، دعنا نلقي نظرة على عمليات النموذج واحتياجاته من الذاكرة.
|
|
||||||
|
|
||||||
## تشريح عمليات النموذج
|
|
||||||
|
|
||||||
تتضمن بنية المحولات 3 مجموعات رئيسية من العمليات مُجمعة أدناه حسب كثافة العمليات الحسابية.
|
|
||||||
|
|
||||||
1. **عمليات ضرب المصفوفات**
|
|
||||||
|
|
||||||
تقوم الطبقات الخطية ومكونات الانتباه متعدد الرؤوس جميعها بعمليات ضرب ** المصفوفة بالمصفوفة** على دفعات. هذه العمليات هي أكثر أجزاء تدريب المحولات كثافة من الناحية الحسابية.
|
|
||||||
|
|
||||||
2. **عمليات التسوية الإحصائية**
|
|
||||||
|
|
||||||
تُعد عمليات Softmax والتسوية الطبقية أقل كثافة من ناحية الحسابية من عمليات ضرب المصفوفات، وتنطوي على عملية أو أكثر من عمليات **الاختزال**، والتي يتم تطبيق نتيجتها بعد ذلك عبر خريطة.
|
|
||||||
|
|
||||||
3. **العمليات على مستوى العناصر**
|
|
||||||
|
|
||||||
هذه هي العمليات المتبقية: **الانحيازات، والتسرب، ووظائف التنشيط، والوصلات المتبقية**. هذه هي عمليات أقل كثافة من الناحية الحسابية.
|
|
||||||
|
|
||||||
يمكن أن تكون هذه المعرفة مفيدة لمعرفة عند تحليل اختناقات الأداء.
|
|
||||||
|
|
||||||
هذا الملخص مُشتق من [نقل البيانات هو كل ما تحتاجه: دراسة حالة حول تحسين المحولات 2020](https://arxiv.org/abs/2007.00072)
|
|
||||||
|
|
||||||
|
|
||||||
## تشريح ذاكرة النموذج
|
|
||||||
|
|
||||||
لقد رأينا أن تدريب النموذج يستخدم ذاكرة أكثر بكثير من مجرد وضع النموذج على GPU. ويرجع ذلك إلى
|
|
||||||
هناك العديد من المكونات أثناء التدريب التي تستخدم ذاكرة GPU. المكونات الموجودة في ذاكرة GPU هي التالية:
|
|
||||||
|
|
||||||
1. أوزان النموذج
|
|
||||||
2. الدول المُحسّن
|
|
||||||
3. المُتدرجات
|
|
||||||
4. تنشيطات المسار الأمامي المحفوظة لحساب المُتدرجات
|
|
||||||
5. المخازن المؤقتة
|
|
||||||
6. ذاكرة محددة الوظائف
|
|
||||||
|
|
||||||
يتطلب نموذج نموذجي مدرب بدقة مختلطة 18 بايت للمُحسّن AdamW كل معلمة نموذج بالإضافة إلى ذاكرة التنشيط. للاستدلال لا توجد حالات مُحسّن و مُتدرجات، لذلك يمكننا طرح تلك. وهكذا ننتهي مع 6 بايت لكل
|
|
||||||
معلمة نموذج للدقة المختلطة الاستدلال، بالإضافة إلى ذاكرة التنشيط.
|
|
||||||
|
|
||||||
دعنا نلقي نظرة على التفاصيل.
|
|
||||||
|
|
||||||
**أوزان النموذج:**
|
|
||||||
|
|
||||||
- 4 بايت * عدد المعلمات للتدريب على دقة fp32
|
|
||||||
- 6 بايت * عدد المعلمات لتدريب الدقة المختلطة (يحافظ على نموذج في fp32 وآخر بدقة fp16 في الذاكرة)
|
|
||||||
|
|
||||||
**حالات المُحسّن:**
|
|
||||||
|
|
||||||
- 8 بايت * عدد المعلمات للمُحسّن AdamW العادي (يحافظ على حالتين)
|
|
||||||
- 2 بايت * عدد المعلمات لمُحسّنات 8 بت AdamW مثل [bitsandbytes](https://github.com/TimDettmers/bitsandbytes)
|
|
||||||
- 4 بايت * عدد المعلمات لمُحسّنات مثل SGD مع الزخم momentum (يحافظ على حالة واحدة فقط)
|
|
||||||
|
|
||||||
**المُتدرجات**
|
|
||||||
|
|
||||||
- 4 بايت * عدد المعلمات للتدريب بدقة fp32 أو بدقة مختلطة (المُتدرجات تكون دائمًا بدقة fp32)
|
|
||||||
|
|
||||||
**تنشيطات المسار الأمامي**
|
|
||||||
|
|
||||||
- يعتمد الحجم على العديد من العوامل، وأهمها طول التسلسل وحجم المخفية وحجم الدُفعة.
|
|
||||||
|
|
||||||
هناك المدخلات والمخرجات لذي يتم تمريرها وإرجاعها بواسطة وظائف المسار الأمامي والمسار الخلفي وتنشيطات المسار الأمامي المحفوظة لحساب المُتدرجات.
|
|
||||||
|
|
||||||
**الذاكرة المؤقتة**
|
|
||||||
|
|
||||||
بالإضافة إلى ذلك، هناك جميع أنواع المتغيرات المؤقتة التي يتم تحريرها بمجرد الانتهاء من الحساب، ولكن في
|
|
||||||
لحظة يمكن أن تتطلب هذه المتغيرات المؤقتة ذاكرة إضافية ويقد تؤدي إلى نفاد الذاكرة المُخصصة (OOM). لذلك، عند البرمجة، من المهم التفكير بشكل استراتيجي حول هذه المتغيرات المؤقتة وأحيانًا تحريرها بشكل صريح بمجرد عدم الحاجة إليها.
|
|
||||||
|
|
||||||
**ذاكرة محددة الوظائف**
|
|
||||||
|
|
||||||
ثم، قد يكون لبرنامجك احتياجات خاصة بالذاكرة. على سبيل المثال، عند إنشاء نص باستخدام البحث الشعاعي، يحتاج البرنامج
|
|
||||||
إلى الاحتفاظ بنسخ متعددة من المدخلات والمخرجات.
|
|
||||||
|
|
||||||
**سرعة تنفيذ `forward` مقابل `backward`**
|
|
||||||
|
|
||||||
بالنسبة للالتفافات والطبقات الخطية، هناك ضِعف عدد العمليات 2x flops في المسار الخلفى مقارنة بالمسار الأمامي، والتي يُترجم عمومًا إلى ~2x أبطأ (أحيانًا أكثر، لأن الأحجام في المسار الخلفى تميل إلى أن تكون أكثر صعوبة). عادةً ما تكون عمليات التنشيط محدودة بعرض النطاق الترددي، ومن المعتاد أن يتعين على التنشيط قراءة المزيد من البيانات في المسار الخلفى أكثر من المسار الأمامى.
|
|
||||||
(على سبيل المثال، قراءة التنشيط المسار الأمامى مرة واحدة، وتكتب مرة واحدة، وبينما تقرأ عملية التنشيط الخلفي مرتين، gradOutput وإخراج الأمام، وتكتب مرة واحدة، gradInput).
|
|
||||||
|
|
||||||
كما ترى، هناك بضعة أماكن يمكننا فيها توفير ذاكرة GPU أو تسريع العمليات.
|
|
||||||
الآن بعد أن فهمت ما يؤثر على استخدام GPU وسرعة الحساب، راجع
|
|
||||||
صفحة وثائق [أساليب وأدوات التدريب الفعال على GPU واحد](perf_train_gpu_one) لمعرفة المزيد حول تقنيات تحسين الأداء.
|
|
||||||
@ -28,7 +28,7 @@ picture-in-picture" allowfullscreen></iframe>
|
|||||||
|
|
||||||
```py
|
```py
|
||||||
>>> model = AutoModel.from_pretrained(
|
>>> model = AutoModel.from_pretrained(
|
||||||
... "julien-c/EsperBERTo-small", revision="4c77982" # اسم العلامة، أو اسم الفرع، أو تجزئة الالتزام
|
... "julien-c/EsperBERTo-small", revision="v2.0.1" # اسم العلامة، أو اسم الفرع، أو تجزئة الالتزام
|
||||||
... )
|
... )
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -1,89 +0,0 @@
|
|||||||
# عائلة نماذج المحول
|
|
||||||
|
|
||||||
منذ إطلاقه في عام 2017، ألهم نموذج [المحول الأصلي](https://arxiv.org/abs/1706.03762) (راجع مدونة [المحول المشروح](http://nlp.seas.harvard.edu/2018/04/03/attention.html) لمقدمة تقنية مبسطة)، ألهم العديد من النماذج الجديدة والمبتكرة التي تتجاوز مهام معالجة اللغات الطبيعية (NLP). هناك نماذج للتنبؤ [بالبنية البروتينات المطوية](https://huggingface.co/blog/deep-learning-with-proteins)، و[تدريب على اتخاذ القرار](https://huggingface.co/blog/train-decision-transformers)، و[التنبؤ بالسلاسل الزمنية](https://huggingface.co/blog/time-series-transformers). مع وجود العديد من متغيرات المحول المتاحة، قد يكون من السهل أن تفوتك الصورة الأكبر. ما تشترك فيه جميع هذه النماذج هو أنها تستند إلى بنية المحول الأصلية. تستخدم بعض النماذج فقط الترميز أو فك الترميز، بينما تستخدم نماذج أخرى كليهما. يوفر هذا تصنيفًا مفيدًا لتصنيف واستعراض الفروقات الرئيسية بين نماذج عائلة المحولات، وسيساعدك على فهم النماذج التي لم تصادفها من قبل.
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بنموذج المحول الأصلي أو تحتاج إلى تذكير، فراجع الفصل الخاص بـ [كيف تعمل المحولات](https://huggingface.co/course/chapter1/4؟fw=pt) من دورة Hugging Face.
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/H39Z_720T5s" title="مشغل فيديو YouTube" frameborder="0" allow="accelerometer؛ تشغيل تلقائي؛ قائمة تشغيل مدمجة؛ محسّنات الفيديو؛ ميزة الإشارات المرجعية" allowfullscreen></iframe>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## رؤية الحاسب (Computer vision)
|
|
||||||
|
|
||||||
<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="1000" height="450" src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FacQBpeFBVvrDUlzFlkejoz%2FModelscape-timeline%3Fnode-id%3D0%253A1%26t%3Dm0zJ7m2BQ9oe0WtO-1" allowfullscreen></iframe>
|
|
||||||
|
|
||||||
### الشبكة التلافيفية (Convolutional network)
|
|
||||||
|
|
||||||
لطالما كانت الشبكات التلافيفية (CNNs) الطريقة السائدة لمهام رؤية الحاسب حتى برز [محول الرؤية](https://arxiv.org/abs/2010.11929) قابليته للتطوير وكفاءته العالية. وحتى بعد ذلك، لا تزال بعض أفضل صفات CNN، مثل ثبات الإزاحة، قوية جدًا (خاصة بالنسبة لمهام معينة) لدرجة أن بعض المحولات تدمج التلافيف في بنيتها. قلب [ConvNeXt](model_doc/convnext) هذا التبادل رأسًا على عقب وأدرج خيارات التصميم من المحولات لتحديث CNN. على سبيل المثال، يستخدم ConvNeXt نوافذ منزلقة غير متداخلة لتقسيم الصورة إلى رقع وزيادة حقل مجال العام الخاص بها. كما يقوم ConvNeXt بعدة خيارات مثل تصميم الطبقة لتكون أكثر كفاءة في الذاكرة وتحسين الأداء، مما يجعله منافسًا قويًا للمحولات!
|
|
||||||
|
|
||||||
### الترميز[[cv-encoder]] (Encoder)
|
|
||||||
|
|
||||||
فتح [محول الرؤية (ViT)](model_doc/vit) الباب أمام مهام رؤية الحاسب دون الاعتماد على التلافيف. يستخدم ViT ترميز محول قياسي، لكن إنجازه الرئيسي كان طريقة معالجته للصورة. فهو تقسّم الصورة إلى رقّعات ذات حجم ثابت ويستخدمها لإنشاء تضمين، تمامًا مثل تقسيم الجملة إلى رموز. استفاد ViT من بنية المُحوِّلات الفعالة لإظهار نتائج تنافسية مع CNNs في ذلك الوقت مع الحاجة إلى موارد أقل للتدريب. وسرعان ما تبع ViT نماذج رؤية أخرى يمكنها أيضًا التعامل مع مهام الرؤية الكثيفة مثل التجزئة والتعرف.
|
|
||||||
|
|
||||||
من بين هذه النماذج [Swin](model_doc/swin) Transformer. فهو يبني خرائط سمات هرمية (مثل CNN 👀 على عكس ViT) من رقّعات أصغر حجمًا ودمجها مع الرقع المجاورة في طبقات أعمق. يتم حساب الانتباه فقط ضمن نافذة محلية، ويتم تحويل النافذة بين طبقات الانتباه لإنشاء اتصالات تساعد النموذج على التعلم بشكل أفضل. نظرًا لأن محول Swin يمكنه إنتاج خرائط خصائص هرمية، فهو مرشح جيد لمهام التنبؤ الكثيفة مثل التجزئة والتعرف. كما يستخدم [SegFormer](model_doc/segformer) ترميز محول لبناء خرائط خصائص هرمية، ولكنه يضيف فك تشفير بسيط متعدد الطبقات (MLP) في الأعلى لدمج جميع خرائط الخصائص وإجراء تنبؤ.
|
|
||||||
|
|
||||||
استلهمت نماذج الرؤية الأخرى، مثل BeIT وViTMAE، الإلهام من هدف التدريب المسبق لـ BERT. يتم تدريب [BeIT](model_doc/beit) مسبقًا من خلال *نمذجة الصور المقنعة (MIM)*؛ يتم إخفاء رقّعات الصور بشكل عشوائي، كما يتم تحويل الصورة إلى رموز بصرية. يتم تدريب BeIT للتنبؤ بالرموز البصرية المُناظرة للرقع المخفية. لدى [ViTMAE](model_doc/vitmae) هدف تدريب مسبق مُماثل، باستثناء أنه يجب عليه التنبؤ بالبكسلات بدلاً من الرموز البصرية. ما هو غير عادي هو أن إخفاء 75% من رقع الصور! يقوم فك التشفير بإعادة بناء البكسلات من الرموز المخفية والرقّعات المشفرة. بعد التدريب المسبق، يتم التخلص من فك التشفير، ويصبح الترميز جاهزًا للاستخدام في مهام التالية.
|
|
||||||
|
|
||||||
### فك التشفير[[cv-decoder]] (Decoder)
|
|
||||||
|
|
||||||
نادرًا ما تستخدم نماذج الرؤية التي تعتمد على فك التشفير فقط لأن معظم نماذج الرؤية تعتمد على الترميز لتعلم تمثيل الصورة. ولكن بالنسبة للاستخدامات مثل توليد الصور، يعد فك التشفير مناسبًا بشكل طبيعي، كما رأينا من نماذج توليد النصوص مثل GPT-2. يستخدم نموذج [ImageGPT](model_doc/imagegpt) نفس بنية GPT-2، ولكنه بدلاً من التنبؤ بالرمز التالي في تسلسل، فإنه يتنبأ بالبكسل التالي في صورة. بالإضافة إلى توليد الصور، يمكن أيضًا ضبط ImageGPT بدقة لتصنيف الصور.
|
|
||||||
|
|
||||||
### الترميز وفك التشفير[[cv-encoder-decoder]] (Encoder-decoder)
|
|
||||||
|
|
||||||
تستخدم نماذج الرؤية بشكل شائع ترميزًا (يُعرف أيضًا باسم العمود الفقري) لاستخراج ميزات الصورة المهمة قبل تمريرها إلى فك التشفير لنموذج المُحوّل. يستخدم [DETR](model_doc/detr) عمودًا فقريًا مُدربًا مسبقًا، ولكنه يستخدم أيضًا الببنية الكاملة للترميز وفك تشفير لنموذج المحول للكشف عن الأشياء. يتعلم الترميز تمثيلات الصور ويجمعها مع استعلامات الكائنات (كل استعلام كائن هو تضمين مُتعلم يركز على منطقة أو كائن في صورة) في فك التشفير. يتنبأ DETR بإحداثيات مربع الحدود وتسمية الفئة لكل استعلام كائن.
|
|
||||||
|
|
||||||
## معالجة اللغات الطبيعية (Natural language processing - NLP)
|
|
||||||
|
|
||||||
<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="1000" height="450" src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FUhbQAZDlpYW5XEpdFy6GoG%2Fnlp-model-timeline%3Fnode-id%3D0%253A1%26t%3D4mZMr4r1vDEYGJ50-1" allowfullscreen></iframe>
|
|
||||||
|
|
||||||
### الترميز اللغوي[[nlp-encoder]]
|
|
||||||
|
|
||||||
نموذج [BERT](model_doc/bert) هو محوّل (Transformer) يعتمد على الترميز فقط يقوم بشكل عشوائي بإخفاء رموز معينة في المدخلات لتجنب رؤية باقى الرموز الأخرى، مما يسمح له "بالغش". يتمثل هدف التدريب المسبق في التنبؤ بالرمز المخفي بناءً على السياق. يسمح هذا لـ BERT باستخدام السياقات اليمنى واليسرى بالكامل لمساعدته في تعلم تمثيل أعمق وأغنى للبيانات المدخلة. ومع ذلك، كان هناك مجال للتحسين في استراتيجية التدريب المسبق لـ BERT. نموذج [RoBERTa](model_doc/roberta) اضاف تحسين من خلال تقديم وصفة تدريب مسبق جديدة تشمل التدريب لفترة أطول وعلى دفعات أكبر، وإخفاء الرموز عشوائيًا في كل حقبة بدلاً من مرة واحدة فقط أثناء المعالجة المسبقة، وإزالة هدف التنبؤ بالجملة التالية.
|
|
||||||
|
|
||||||
تتمثل الاستراتيجية السائدة لتحسين الأداء في زيادة حجم النموذج. ولكن تدريب النماذج الكبيرة مكلف من الناحية الحسابية. إحدى طرق تقليل التكاليف الحسابية هي استخدام نموذج أصغر مثل [DistilBERT](model_doc/distilbert). يستخدم DistilBERT [ تقنية تقطير المعرفة](https://arxiv.org/abs/1503.02531) - وهي تقنية ضغط - لإنشاء نموذج أصغر من BERT مع الحفاظ على معظم قدراته على فهم اللغةا.
|
|
||||||
|
|
||||||
مرت معظم نماذج المحول في الاتجاه نحو المزيد من المعلمات، مما أدى إلى ظهور نماذج جديدة تركز على تحسين كفاءة التدريب. يقلّل [ALBERT](model_doc/albert) من استهلاك الذاكرة عن طريق تقليل عدد المعلمات بطريقتين: فصل تضمين المفردات الأكبر إلى مصفوفتين أصغر والسماح للمستويات بمشاركة المعلمات. أضاف [DeBERTa](model_doc/deberta) آلية انتباه منفصلة حيث يتم ترميز الكلمة وموضعها بشكل منفصل في متجهين. يتم حساب الانتباه من هذه المتجهات المنفصلة بدلاً من متجه واحد يحتوي على تضمين الكلمة والموقع. ركز [Longformer](model_doc/longformer) أيضًا على جعل الانتباه أكثر كفاءة، خاصة لمعالجة المستندات ذات تسلسلات أطولل. فهو يستخدم مزيجًا من انتباه النوافذ المحلية (يتم حساب الانتباه فقط ن نافذة ذات حجم ثابت حول كل رمز) والانتباه العام (فقط لرموز مهمة محددة مثل `[CLS]` للتصنيف) لإنشاء مصفوفة انتباه متفرقة بدلاً من مصفوفة انتباه كاملة.
|
|
||||||
|
|
||||||
### فك التشفير[[nlp-decoder]]
|
|
||||||
|
|
||||||
نموذج [GPT-2](model_doc/gpt2) هو محول فك تشفير فقط يتنبأ بالكلمة التالية في التسلسل. إنه يخفي الرموز التالية الموجودة على اليمين حتى لا يتمكن النموذج من "الغش" بالنظر إليها. من خلال التدريب المسبق على كميات هائلة من النصوص، أصبح [GPT-2](model_doc/gpt2) بارعًا في توليد النصوص، حتى لو لم تكن النص دقيقًا أو صحيحًا في بعض الأحيان فقط. ولكن كان يفتقر إلى سياق لترابط المتبادل (bidirectional context) الموجود من التدريب المسبق لـ [BERT](model_doc/bert) ، مما جعله غير مناسب لمهام معينة. يجمع [XLNET](model_doc/xlnet) بين أفضل ما في أهداف التدريب المسبق لـ [BERT](model_doc/bert) و [GPT-2](model_doc/gpt2) من خلال اعتماد نهج النمذجة اللغوية باستخدام التباديل (Permutation Language Modeling - PLM) الذي يسمح له بتعلم الترابط ثنائي الاتجاه.
|
|
||||||
|
|
||||||
بعد ظهور [GPT-2](model_doc/gpt2)، تطورت النماذج اللغوية بشكل أكبر حجمًا وأكثر تعقيدًا وأصبحت تُعرف الآن باسم *نماذج اللغة الكبيرة (LLMs)*. توضح LLMs مهارات تعلم قليلة الكمية أو حتى معدومة إذا تم تدريبها على مجموعة بيانات كبيرة بما يكفي. [GPT-J](model_doc/gptj) هو LLM به 6 مليارات معلمة مدربة على 400 مليار رمز. تبعه نموذج [OPT](model_doc/opt)، وهي عائلة من نماذج فك التشفير فقط، أكبرها 175 مليار معلمة ودُرب على 180 مليار رمز. تم إصدار [BLOOM](model_doc/bloom) في نفس الوقت تقريبًا، ويحتوي أكبر نموذج في العائلة على 176 مليار معلمة ودُرب على 366 مليار رمز في 46 لغة و13 لغة برمجة.
|
|
||||||
|
|
||||||
### الترميز وفك التشفير[[nlp-encoder-decoder]]
|
|
||||||
|
|
||||||
يحتفظ [BART](model_doc/bart) ببنية المحول الأصلية، ولكنه يعدّل هدف التدريب المسبق باستخدام إفساد *إدخال النصوص*، حيث يتم استبدال بعض نطاقات النص برمز `mask` واحد. يتنبأ فك التشفير بالرموز غير الفاسدة (يتم إخفاء الرموز المستقبلية) ويستخدم حالات الترميز المخفية للمساعدة. [Pegasus](model_doc/pegasus) مشابه لـ BART، ولكن Pegasus يقوم بإخفاء جمل كاملة بدلاً من مقاطع النص. بالإضافة إلى نمذجة اللغة المقنعة، يتم تدريب Pegasus مسبقًا بواسطة توليد الجمل الفارغة (GSG). يقوم هدف GSG بإخفاء الجمل الكاملة المهمة للمستند، واستبدالها برمز `mask`. يجب على فك التشفير توليد المخرجات من الجمل المتبقية. [T5](model_doc/t5) هو نموذج فريد من نوعه يحوّل جميع مهام معالجة اللغة الطبيعية إلى مشكلة نص إلى نص باستخدام بادئات محددة. على سبيل المثال، يشير البادئة `Summarize:` إلى مهمة تلخيص. يتم تدريب T5 مسبقًا بواسطة التدريب الخاضع للإشراف (GLUE وSuperGLUE) والتدريب ذاتي الإشراف (اختيار عينة عشوائية وحذف 15% من الرموز).
|
|
||||||
|
|
||||||
## الصوت (Audio)
|
|
||||||
|
|
||||||
<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="1000" height="450" src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2Fvrchl8jDV9YwNVPWu2W0kK%2Fspeech-and-audio-model-timeline%3Fnode-id%3D0%253A1%26t%3DmM4H8pPMuK23rClL-1" allowfullscreen></iframe>
|
|
||||||
|
|
||||||
### الترميز[[audio-encoder]]
|
|
||||||
|
|
||||||
يستخدم [Wav2Vec2](model_doc/wav2vec2) ترميز من نوع المحوّل لتعلم تمثيلات الكلام بشكلٍ مباشر من موجات الصوت الخام. يتم تدريبه مسبقًا باستخدام مهمة تباينية لتحديد تمثيل الكلام الصحيح من مجموعة من التمثيلات الخاطئة. [HuBERT](model_doc/hubert) مشابه لـ Wav2Vec2 ولكنه له عملية تدريب مختلفة. يتم إنشاء تسميات الهدف عن طريق خطوة تجميع يتم فيها ت تخصيص مقاطع الصوت المتشابهة إلى مجموعات، تُصبح كل واحدة منها وحدةً خفية. ويتم تعيين الوحدة الخفية إلى تمثيل لإجراء تنبؤ.
|
|
||||||
|
|
||||||
### الترميز وفك التشفير[[audio-encoder-decoder]]
|
|
||||||
|
|
||||||
[Speech2Text](model_doc/speech_to_text) هو نموذج كلام مصمم للتعرف التلقائي على الكلام (ASR) وترجمة الكلام. يقبل النموذج ميزات بنك المرشح اللغوي التي تم استخراجها من شكل موجة الصوت وتم تدريبه مسبقًا بطريقة ذاتية التعلم لتوليد نسخة أو ترجمة. [Whisper](model_doc/whisper) هو أيضًا نموذج ASR، ولكنه على عكس العديد من نماذج الكلام الأخرى، يتم تدريبه مسبقًا على كمية كبيرة من بيانات نسخ النص الصوتي ✨ المسماة ✨ لتحقيق الأداء الصفري. يحتوي جزء كبير من مجموعة البيانات أيضًا على لغات غير اللغة الإنجليزية، مما يعني أنه يمكن استخدام Whisper أيضًا للغات منخفضة الموارد. من الناحية الهيكلية، يشبه Whisper نموذج Speech2Text. يتم تحويل إشارة الصوت إلى طيف لوجاريتم مل-ميل يتم تشفيره بواسطة الترميز. يقوم فك التشفير بتوليد النسخة بطريقة ذاتية التعلم من حالات الترميز المخفية والرموز السابقة.
|
|
||||||
|
|
||||||
## متعدد الوسائط (Multimodal)
|
|
||||||
|
|
||||||
<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="1000" height="450" src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FcX125FQHXJS2gxeICiY93p%2Fmultimodal%3Fnode-id%3D0%253A1%26t%3DhPQwdx3HFPWJWnVf-1" allowfullscreen></iframe>
|
|
||||||
|
|
||||||
### Encoder[[mm-encoder]]
|
|
||||||
|
|
||||||
نموذج [VisualBERT](model_doc/visual_bert) هو نموذج متعدد الوسائط لمهام الرؤية اللغوية تم إصداره بعد فترة وجيزة من BERT. فهو يجمع بين BERT ونظام اكتشاف كائن مسبق التدريب لاستخراج ميزات الصورة في تضمينات بصرية، يتم تمريرها جنبًا إلى جنب مع التضمينات النصية إلى BERT. يتنبأ VisualBERT بالنص المقنع بناءً على النص غير المقنع والتضمينات المرئية، ويجب عليه أيضًا التنبؤ بما إذا كان النص متوافقًا مع الصورة. عندما تم إصدار ViT، اعتمد [ViLT](model_doc/vilt) ViT في بنيتها لأنه كان من الأسهل الحصول على تضمينات الصورة بهذه الطريقة. يتم معالجة تضمينات الصورة بشكل مشترك مع التضمينات النصية. ومن هناك، يتم التدريب المسبق لـ ViLT بواسطة مطابقة الصورة النصية، ونمذجة اللغة المقنعة، وإخفاء كلمة كاملة.
|
|
||||||
|
|
||||||
يتّبع [CLIP](model_doc/clip) نهجًا مختلفًا ويقوم بتنبؤ ثنائي من ("الصورة"، "النص"). يتم تدريب مشفر صورة (ViT) ومشفر نص (Transformer) بشكل مشترك على مجموعة بيانات مكونة من 400 مليون ثنائي من ("صورة"، "نص") لتعظيم التشابه بين متجهات ترميز الصورة ومتجهات النص ثنائي ("الصورة"، "النص"). بعد التدريب المسبق، يمكنك استخدام اللغة الطبيعية لتوجيه CLIP للتنبؤ بالنص المُعطى بناءً على صورة أو العكس بالعكس. [OWL-ViT](model_doc/owlvit) يبني على CLIP باستخدامه كعمود فقري للكشف عن الكائنات بدون إشراف. بعد التدريب المسبق، يتم إضافة رأس كشف الأجسام لإجراء تنبؤ بمجموعة مُحدّد عبر ثنائيات ("class"، "bounding box").
|
|
||||||
|
|
||||||
### Encoder-decoder[[mm-encoder-decoder]]
|
|
||||||
|
|
||||||
التعرّف البصري على الحروف (OCR) مهمة قديمة لتعرّف النصوص، التي تنطوي عادةً على عدة مكونات لفهم الصورة وتوليد النص. [TrOCR](model_doc/trocr) بتبسيط العملية باستخدام محول متكامل من النهاية إلى النهاية. المشفر هو نموذج على غرار ViT لفهم الصورة ويعالج الصورة كقطع ثابتة الحجم. يقبل فك التشفير حالات الإخفاء للمشفر وينشئ النص بشكل تلقائي. [Donut](model_doc/donut) هو نموذج أكثر عمومية لفهم المستندات المرئية لا يعتمد على نهج OCR. يستخدم محول Swin كمشفر وBART متعدد اللغات كمُفكّك تشفير. يتم تدريب Donut على قراءة النص عن طريق التنبؤ بالكلمة التالية بناءً على ملاحظات الصورة والنص. يقوم فك التشفير بتوليد تتسلسلًا رمزيًا بناءً على موجه (Prompt). يتم تمثيل الموجه بواسطة رمز خاص لكل مهمة. على سبيل المثال، يحتوي تحليل المستند على رمز خاص "parsing" يتم دمجه مع حالات الإخفاء للـمُشفّر لتحليل المستند بتنسيق إخراج منظم (JSON).
|
|
||||||
|
|
||||||
## التعلم التعزيزي (Reinforcement learning - RL)
|
|
||||||
|
|
||||||
<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="1000" height="450" src="https://www.figma.com/embed?embed_host=share&url=https%3A%2F%2Fwww.figma.com%2Ffile%2FiB3Y6RvWYki7ZuKO6tNgZq%2Freinforcement-learning%3Fnode-id%3D0%253A1%26t%3DhPQwdx3HFPWJWnVf-1" allowfullscreen></iframe>
|
|
||||||
|
|
||||||
### فك التشفير[[rl-decoder]]
|
|
||||||
|
|
||||||
يقوم نموذج "محوّل القرارات والمسارات" (Decision and Trajectory Transformer) بتحويل الحالة (State) والإجراء (Action) والمكافأة (Reward) كمشكلة نمذجة تسلسلية. [محوّل القرارات](model_doc/decision_transformer) يقوم بتوليد سلسلة من الإجراءات التي تؤدي إلى عائد مرغوب في المستقبل بناءً على العوائد المتوقعة، والحالات والإجراءات السابقة. في الخطوات الزمنية *K* الأخيرة، يتم تحويل كل وسائط البيانات الثلاث vإلى متجهات تضمين رمزيّة ومعالجتها بواسطة نموذج مشابه لـ GPT للتنبؤ برمز الإجراء المستقبلي.يقوم [محول المسار](model_doc/trajectory_transformer) أيضًا بتحويل الحالات والإجراءات والمكافآت إلى رموز ومعالجتها باستخدام هيكلية GPT. على عكس "محوّل القرارات"، الذي يركز على تكييف المكافأة، يقوم "محوّل المسارات" بتوليد إجراءات مستقبلية باستخدام البحث الشعاعي (Beam Search).
|
|
||||||
@ -1,184 +0,0 @@
|
|||||||
# المحولات النمطية
|
|
||||||
|
|
||||||
مكتبة `transformers` هي إطار عمل ذو فلسفة محدد؛ يتم تعريف فلسفتنا في [الدليل المفاهيمي](./philosophy).
|
|
||||||
|
|
||||||
جوهر هذه الفلسفة يتمثل في مبدأ [نموذج واحد، ملف واحد](https://huggingface.co/blog/transformers-design-philosophy)
|
|
||||||
في المكتبة. الجانب السلبي لهذا المكون هو تقييده لوراثة واستيراد مكونات الملفات.
|
|
||||||
|
|
||||||
نتيجة لذلك، تتكرر مكونات النموذج عبر العديد من الملفات. يحتوي `transformers` على عدد كبير من طبقات الانتباه، يقارب عدد النماذج، والكثير منها متطابق. يتسبب هذا في تباعد عمليات التنفيذ المستقلة مع تطبيق الإصلاحات والتغييرات.
|
|
||||||
على أجزاء محددة من التعليمات البرمجية.
|
|
||||||
|
|
||||||
ولمعالجة ذلك، اعتمدنا مفهوم "النسخ" في المكتبة. فبإضافة تعليق يُشير إلى أن التعليمات البرمجية هي نسخة من أخرى، نضمن من خلال أنظمة CI والأوامر المحلية عدم تباعد النسخ. لكن هذه العملية، رغم بساطتها، تُسبب إرهاقاً. كما أنها تزيد العبء على المساهمين، وهو ما نهدف إلى تجاوزه.
|
|
||||||
|
|
||||||
غالباً ما تتطلب مساهمات النماذج إضافة تعليمات برمجية (حوالي 1000 سطر)، ومعالج (حوالي 500 سطر)، واختبارات، ووثائق، إلخ. ونادراً ما تقل مساهمات النماذج عن 3000-5000 سطر من التعليمات البرمجية، معظمها أكواد نمطية. هذا يرفع مستوى المساهمات،
|
|
||||||
|
|
||||||
ونهدف مع المحولات النمطية إلى خفض هذا المستوى إلى حدّ مقبول.
|
|
||||||
|
|
||||||
## ما هو؟
|
|
||||||
|
|
||||||
تقدم المحولات النمطية مفهوم ملف "نمطي" لمجلد نموذج. يقبل هذا الملف النمطي تعليمات برمجية
|
|
||||||
غير مقبولة عادة في ملفات النمذجة/المعالجة، حيث يسمح بالاستيراد من نماذج مجاورة وكذلك
|
|
||||||
الوراثة من الفئات إلى فئات أخرى.
|
|
||||||
|
|
||||||
يعرّف هذا الملف النمطي النماذج والمعالجات وفئة التكوين التي سيتم تعريفها في وحداتهم
|
|
||||||
المتعلقة.
|
|
||||||
|
|
||||||
وأخيرًا، يقدم هذا الميزة أداة `linter` جديدة والتي ستعمل على "تفكيك" الملف النمطي إلى بنية "نموذج واحد، ملف واحد"
|
|
||||||
هيكل الدليل. سيتم إنشاء هذه الملفات تلقائيًا في كل مرة يتم فيها تشغيل البرنامج النصي؛ مما يقلل من المساهمات المطلوبة
|
|
||||||
إلى الملف النمطي، وبالتالي فقط إلى التغييرات بين النموذج المساهم والنماذج الأخرى.
|
|
||||||
|
|
||||||
سيقوم مستخدمو النموذج في النهاية باستيراد واستخدام واجهة الملف الواحد، لذا لا يتوقع حدوث أي تغيير هنا. من خلال القيام بذلك،
|
|
||||||
نأمل في الجمع بين أفضل ما في العالمين: تمكين المساهمات البسيطة مع الالتزام بفلسفتنا.
|
|
||||||
|
|
||||||
لذلك، هذا بديل لعلامات `# Copied from`، ويمكن توقع انتقال النماذج المساهمة سابقًا إلى
|
|
||||||
تنسيق المحولات النمطية الجديد في الأشهر المقبلة.
|
|
||||||
|
|
||||||
### التفاصيل
|
|
||||||
|
|
||||||
تُبسط أداة "linter" الوراثة، مُنشئةً جميع الملفات المفردة من الملف النمطي، مع الحفاظ على شفافيتها أمام مستخدمي Python. حاليًا، تُبسط الأداة مستوىً واحدًا من الوراثة
|
|
||||||
|
|
||||||
على سبيل المثال:
|
|
||||||
- إذا ورثت فئة التكوين من فئة أخرى وأضافت/حذفت معامل، فسيتم إما الإشارة إلى الملف المولد مباشرةً
|
|
||||||
(في حالة الإضافة) أو إزالته تمامًا (في حالة الحذف).
|
|
||||||
- إذا ورثت فئة من فئة أخرى، على سبيل المثال: `class GemmaModel(LlamaModel):`، تُستنتج التبعيات تلقائيًا
|
|
||||||
سيتم استنتاج جميع الوحدات الفرعية تلقائيًا من الفئة الأصلية.
|
|
||||||
- إذا قمت بتعريف وظائف جديدة في الملف `modular` واستخدمتها داخل الفئات، فستستنتج أداة linter ذلك تلقائيًا
|
|
||||||
|
|
||||||
يجب أن تكون قادرًا على كتابة كل شيء (المجزىء اللغوي، ومُعالِج الصور، والنموذج، والتكوين) في الملف `modular`، وسيتم إنشاء الملفات المُقابلة تلقائيًا.
|
|
||||||
|
|
||||||
### التطبيق
|
|
||||||
|
|
||||||
[TODO] نقدم اختبارًا جديدًا، للتأكد من أن المحتوى المولد يتطابق مع ما هو موجود في `modular_xxxx.py`
|
|
||||||
|
|
||||||
### الأمثلة
|
|
||||||
|
|
||||||
هنا مثال سريع باستخدام BERT و RoBERTa. النموذجان مرتبطان ارتباطًا وثيقًا: يختلف تنفيذهما النموذجي في طبقة تضمين.
|
|
||||||
|
|
||||||
بدلاً من إعادة تعريف النموذج بالكامل، إليك كيف يبدو ملف `modular_roberta.py` لفئات النمذجة والتكوين (لأغراض المثال، يتم تجاهل المجزىء اللغوي في هذا الوقت حيث أنه مختلف جدًا).
|
|
||||||
|
|
||||||
```python
|
|
||||||
from torch import nn
|
|
||||||
from ..bert.configuration_bert import BertConfig
|
|
||||||
from ..bert.modeling_bert import (
|
|
||||||
BertModel,
|
|
||||||
BertEmbeddings,
|
|
||||||
BertForMaskedLM
|
|
||||||
)
|
|
||||||
|
|
||||||
# تكوين RoBERTa مطابق لتكوين BERT
|
|
||||||
class RobertaConfig(BertConfig):
|
|
||||||
model_type = 'roberta'
|
|
||||||
|
|
||||||
# نعيد تعريف الإضافات هنا لتسليط الضوء على اختلاف معرف الحشو، ونعيد تعريف الإضافات الموضعية
|
|
||||||
class RobertaEmbeddings(BertEmbeddings):
|
|
||||||
def __init__(self, config):
|
|
||||||
super().__init__(config())
|
|
||||||
|
|
||||||
self.padding_idx = config.pad_token_id
|
|
||||||
self.position_embeddings = nn.Embedding(
|
|
||||||
config.max_position_embeddings, config.hidden_size, padding_idx=self.padding_idx
|
|
||||||
)
|
|
||||||
|
|
||||||
# نموذج RoBERTa مطابق لنموذج BERT، باستثناء طبقة الإضافات.
|
|
||||||
# نعيد تعريف الإضافات أعلاه، لذا هنا لا توجد حاجة لعمل إضافي
|
|
||||||
class RobertaModel(BertModel):
|
|
||||||
def __init__(self, config):
|
|
||||||
super().__init__(config)
|
|
||||||
self.embeddings = RobertaEmbeddings(config)
|
|
||||||
|
|
||||||
|
|
||||||
# الرؤوس الآن تحتاج فقط إلى إعادة تعريف النموذج داخل `RobertaModel` الصحيح
|
|
||||||
class RobertaForMaskedLM(BertForMaskedLM):
|
|
||||||
def __init__(self, config):
|
|
||||||
super().__init__(config)
|
|
||||||
self.model = RobertaModel(config)
|
|
||||||
```
|
|
||||||
|
|
||||||
لاحظ أنه إذا لم تستخدم الاعتماد الذي حددته، فستحصل على الخطأ التالي:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ValueError: You defined `RobertaEmbeddings` in the modular_roberta.py, it should be used
|
|
||||||
when you define `BertModel`, as it is one of it's direct dependencies. Make sure
|
|
||||||
you use it in the `__init__` function.
|
|
||||||
```
|
|
||||||
|
|
||||||
بالإضافة إلى ذلك، قد تجد قائمة بالأمثلة هنا:
|
|
||||||
|
|
||||||
## ما هو ليس كذلك
|
|
||||||
|
|
||||||
ليس بديلاً لتعليمات برمجة النمذجة (بعد؟)، وإذا لم يكن نموذجك يعتمد على أي شيء آخر موجود من قبل، فيمكنك إضافة ملف `نمذجة` كالعادة.
|
|
||||||
|
|
||||||
|
|
||||||
## الاستخدام المتقدم
|
|
||||||
|
|
||||||
### إزالة السمات والوظائف
|
|
||||||
لإزالة السمات التي لا تستخدم في نموذجك النمطي، والتي لا تريد رؤيتها في النمذجة المفككة:
|
|
||||||
|
|
||||||
```python
|
|
||||||
class GemmaModel(LlamaModel): | class GemmaModel(PreTrainedModel):
|
|
||||||
def __init__(self, config): | def __init__(self, config):
|
|
||||||
super().__init__(self, eos_token) | super().__init__(config)
|
|
||||||
del self.embed_tokens | self.padding_idx = config.pad_token_id
|
|
||||||
| self.vocab_size = config.vocab_size
|
|
||||||
|
|
|
||||||
| self.layers = nn.ModuleList(
|
|
||||||
| [LlamaDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
|
||||||
| )
|
|
||||||
| self.norm = LlamaRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
|
||||||
| self.rotary_emb = LlamaRotaryEmbedding(config=config)
|
|
||||||
| self.gradient_checkpointing = False
|
|
||||||
|
|
|
||||||
| # Initialize weights and apply final processing
|
|
||||||
| self.post_init()
|
|
||||||
```
|
|
||||||
إذا قمت بالتحقق من `LlamaModel` الأصلي، فستجد `embed_tokens` الذي تمت إزالته هنا (كما هو متوقع!)
|
|
||||||
|
|
||||||
إزالة وظيفة مشابهة، تحتاج فقط إلى كتابتها مع `raise ValueError("")` لمحاكاة السلوك الذي تريده فعليًا عند إزالة وظيفة أصلية في بايثون.
|
|
||||||
|
|
||||||
```python
|
|
||||||
class GemmaTokenizer(LlamaTokenizer):
|
|
||||||
...
|
|
||||||
|
|
||||||
def get_spm_processor(self):
|
|
||||||
raise AttributeError("Not needed for Gemma")
|
|
||||||
|
|
||||||
def unk_token_length(self):
|
|
||||||
raise AttributeError("Not needed for Gemma")
|
|
||||||
```
|
|
||||||
|
|
||||||
### تعريف وظائف جديدة
|
|
||||||
|
|
||||||
إذا قمت بتعريف وظيفة جديدة في الملف `modular` لاستخدامها داخل فئة، على سبيل المثال
|
|
||||||
|
|
||||||
```python
|
|
||||||
def my_new_function(*args, **kwargs):
|
|
||||||
# Do something here
|
|
||||||
pass
|
|
||||||
|
|
||||||
class GemmaModel(LlamaModel):
|
|
||||||
def forward(*args, **kwargs):
|
|
||||||
# Call the function
|
|
||||||
example = my_new_function(*args, **kwargs)
|
|
||||||
# continue here
|
|
||||||
```
|
|
||||||
|
|
||||||
سيتم نسخ وظيفة `my_new_function` (وبشكل متكرر، أي وظائف أخرى جديدة يتم استدعاؤها في جسمها) تلقائيًا
|
|
||||||
في الملف الذي يتم استخدامه.
|
|
||||||
|
|
||||||
### استدعاء `super()`
|
|
||||||
قمنا مؤخرًا بشحن بعض الميزات التي تسمح لك بالانتقال من:
|
|
||||||
```python
|
|
||||||
class GemmaTokenizer(LlamaTokenizer, PretrainedTokenizerFast): | class GemmaModel(nn.Module):
|
|
||||||
def __init__(self, eos_token="</s>"): | def __init__(self):
|
|
||||||
eos_token = AddedToken(eos_token) | eos_token = AddedToken(eos_token)
|
|
||||||
PretrainedTokenizerFast.__init__(self, eos_token) | super().__init__(eos_token)
|
|
||||||
```
|
|
||||||
هذا مفيد عندما لا تريد تفكيك استدعاء `super()`، وتريد التمييز بين أي استدعاء super init تقوم به!
|
|
||||||
|
|
||||||
### التسمية الخاصة
|
|
||||||
ندعم الآن أيضًا حالات خاصة مثل
|
|
||||||
```python
|
|
||||||
class GemmaVisionModel(CLIPModel):
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
حيث اسم فئة `GemmaVision` الخاصة بك ليس هو نفسه `Gemma` النمطي. هذا مفيد للغاية للنماذج المركبة.
|
|
||||||
@ -1,160 +0,0 @@
|
|||||||
# النماذج متعددة اللغات للاستدلال
|
|
||||||
|
|
||||||
هناك العديد من النماذج متعددة اللغات في مكتبة 🤗 Transformers، وتختلف طريقة استخدامها للاستدلال عن النماذج أحادية اللغة. ولكن ليس كل استخدام النماذج متعددة اللغات مختلف. فبعض النماذج، مثل [google-bert/bert-base-multilingual-uncased](https://huggingface.co/google-bert/bert-base-multilingual-uncased)، يمكن استخدامها تمامًا مثل النموذج أحادي اللغة. سيوضح لك هذا الدليل كيفية استخدام النماذج متعددة اللغات التي تختلف طريقة استخدامها للاستدلال.
|
|
||||||
|
|
||||||
## XLM
|
|
||||||
|
|
||||||
يحتوي XLM على عشر نسخ مختلفة، واحدة منها فقط أحادية اللغة. ويمكن تقسيم نسخ النماذج التسع المتبقية إلى فئتين: نسخ التي تستخدم تضمينات اللغة (language embeddings) وتلك التي لا تستخدمها.
|
|
||||||
|
|
||||||
### XLM مع تضمينات اللغة
|
|
||||||
|
|
||||||
تستخدم النماذج التالية من XLM تضمينات اللغة لتحديد اللغة المستخدمة أثناء الاستدلال:
|
|
||||||
|
|
||||||
- `FacebookAI/xlm-mlm-ende-1024` (نمذجة اللغة المقنعة، الإنجليزية-الألمانية)
|
|
||||||
- `FacebookAI/xlm-mlm-enfr-1024` (نمذجة اللغة المقنعة، الإنجليزية-الفرنسية)
|
|
||||||
- `FacebookAI/xlm-mlm-enro-1024` (نمذجة اللغة المقنعة، الإنجليزية-الرومانية)
|
|
||||||
- `FacebookAI/xlm-mlm-xnli15-1024` (نمذجة اللغة المقنعة، لغات XNLI)
|
|
||||||
- `FacebookAI/xlm-mlm-tlm-xnli15-1024` (نمذجة اللغة المقنعة + الترجمة، لغات XNLI)
|
|
||||||
- `FacebookAI/xlm-clm-enfr-1024` (نمذجة اللغة السببية، الإنجليزية-الفرنسية)
|
|
||||||
- `FacebookAI/xlm-clm-ende-1024` (نمذجة اللغة السببية، الإنجليزية-الألمانية)
|
|
||||||
|
|
||||||
تُمثل تضمينات اللغة على شكل مصفوفة بنفس شكل `input_ids` التي يتم تمريره إلى النموذج. وتعتمد القيم في هذه المصفوفات على اللغة المستخدمة ويتم تحديدها بواسطة معاملى المجزىء `lang2id` و `id2lang`.
|
|
||||||
|
|
||||||
في هذا المثال، قم بتحميل نسخة `FacebookAI/xlm-clm-enfr-1024` ( نمذجة اللغة السببية، الإنجليزية-الفرنسية):
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import torch
|
|
||||||
>>> from transformers import XLMTokenizer, XLMWithLMHeadModel
|
|
||||||
|
|
||||||
>>> tokenizer = XLMTokenizer.from_pretrained("FacebookAI/xlm-clm-enfr-1024")
|
|
||||||
>>> model = XLMWithLMHeadModel.from_pretrained("FacebookAI/xlm-clm-enfr-1024")
|
|
||||||
```
|
|
||||||
|
|
||||||
تُظهر خاصية `lang2id` في المجزىء اللغات وأرقام تعريفها في هذا النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> print(tokenizer.lang2id)
|
|
||||||
{'en': 0, 'fr': 1}
|
|
||||||
```
|
|
||||||
|
|
||||||
بعد ذلك، قم بإنشاء مثال على المدخلات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> input_ids = torch.tensor([tokenizer.encode("Wikipedia was used to")]) # batch size of 1
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتعيين معرف اللغة إلى `"en"` واستخدمه لتحديد تضمين اللغة. وتضمين اللغة عبارة عن مصفوفة مملوءة بـ `0` لأن هذا هو معرف اللغة الإنجليزية. يجب أن تكون هذه المصفوفة بنفس حجم `input_ids`.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> language_id = tokenizer.lang2id["en"] # 0
|
|
||||||
>>> langs = torch.tensor([language_id] * input_ids.shape[1]) # torch.tensor([0, 0, 0, ..., 0])
|
|
||||||
|
|
||||||
>>> # نقوم بإعادة تشكيلها لتكون بالحجم (batch_size، sequence_length)
|
|
||||||
>>> langs = langs.view(1, -1) # الآن بالحجم [1، sequence_length] (لدينا batch size تساوي 1)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن يمكنك تمرير `input_ids` وتضمين اللغة إلى النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> 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 لا تتطلب تضمينات اللغة أثناء الاستنتاج:
|
|
||||||
|
|
||||||
- `FacebookAI/xlm-mlm-17-1280` (نمذجة اللغة المقنعة، 17 لغة)
|
|
||||||
- `FacebookAI/xlm-mlm-100-1280` (نمذجة اللغة المقنعة، 100 لغة)
|
|
||||||
|
|
||||||
تُستخدم هذه النماذج لتمثيل الجمل العامة، على عكس نسح XLM السابقة.
|
|
||||||
|
|
||||||
## BERT
|
|
||||||
|
|
||||||
يمكن استخدام النماذج التالية من BERT للمهام متعددة اللغات:
|
|
||||||
|
|
||||||
- `google-bert/bert-base-multilingual-uncased` (نمذجة اللغة المقنعة + التنبؤ بالجملة التالية، 102 لغة)
|
|
||||||
- `google-bert/bert-base-multilingual-cased` (نمذجة اللغة المقنعة + التنبؤ بالجملة التالية، 104 لغات)
|
|
||||||
|
|
||||||
لا تتطلب هذه النماذج تضمينات اللغة أثناء الاستدلال. يجب أن تُحدّد اللغة من السياق وتستنتج وفقاً لذلك.
|
|
||||||
|
|
||||||
## XLM-RoBERTa
|
|
||||||
|
|
||||||
يمكن استخدام النماذج التالية من XLM-RoBERTa للمهام متعددة اللغات:
|
|
||||||
|
|
||||||
- `FacebookAI/xlm-roberta-base` (نمذجة اللغة المقنعة، 100 لغة)
|
|
||||||
- `FacebookAI/xlm-roberta-large` (نمذجة اللغة المقنعة، 100 لغة)
|
|
||||||
|
|
||||||
تم تدريب XLM-RoBERTa على 2.5 تيرابايت من بيانات CommonCrawl الجديدة والمحسنة في 100 لغة. ويوفر مكاسب قوية على النماذج متعددة اللغات التي تم إصدارها سابقاً مثل mBERT أو XLM في مهام المصب مثل التصنيف، ووضع العلامات التسلسلية، والأسئلة والأجوبة.
|
|
||||||
|
|
||||||
## M2M100
|
|
||||||
|
|
||||||
يمكن استخدام النماذج التالية من M2M100 للترجمة متعددة اللغات:
|
|
||||||
|
|
||||||
- `facebook/m2m100_418M` (الترجمة)
|
|
||||||
- `facebook/m2m100_1.2B` (الترجمة)
|
|
||||||
|
|
||||||
في هذا المثال، قم بتحميل نسحة `facebook/m2m100_418M` لترجمة النص من الصينية إلى الإنجليزية. يمكنك تعيين اللغة المصدر في المجزىء اللغوى:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import M2M100ForConditionalGeneration, M2M100Tokenizer
|
|
||||||
|
|
||||||
>>> en_text = "Do not meddle in the affairs of wizards, for they are subtle and quick to anger."
|
|
||||||
>>> chinese_text = "不要插手巫師的事務, 因為他們是微妙的, 很快就會發怒."
|
|
||||||
|
|
||||||
>>> tokenizer = M2M100Tokenizer.from_pretrained("facebook/m2m100_418M", src_lang="zh")
|
|
||||||
>>> model = M2M100ForConditionalGeneration.from_pretrained("facebook/m2m100_418M")
|
|
||||||
```
|
|
||||||
|
|
||||||
تقسيم النّص إلى رموز:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> encoded_zh = tokenizer(chinese_text, return_tensors="pt")
|
|
||||||
```
|
|
||||||
|
|
||||||
يجبر M2M100 معرف اللغة الهدف كأول رمز مولد للترجمة إلى اللغة الهدف. قم بتعيين `forced_bos_token_id` إلى `en` في طريقة `generate` للترجمة إلى الإنجليزية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> generated_tokens = model.generate(**encoded_zh, forced_bos_token_id=tokenizer.get_lang_id("en"))
|
|
||||||
>>> tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)
|
|
||||||
'Do not interfere with the matters of the witches, because they are delicate and will soon be angry.'
|
|
||||||
```
|
|
||||||
|
|
||||||
## MBart
|
|
||||||
|
|
||||||
يمكن استخدام النماذج التالية من MBart للترجمة متعددة اللغات:
|
|
||||||
|
|
||||||
- `facebook/mbart-large-50-one-to-many-mmt` (الترجمة الآلية متعددة اللغات من واحد إلى كثير، 50 لغة)
|
|
||||||
- `facebook/mbart-large-50-many-to-many-mmt` (الترجمة الآلية متعددة اللغات من كثير إلى كثير، 50 لغة)
|
|
||||||
- `facebook/mbart-large-50-many-to-one-mmt` (الترجمة الآلية متعددة اللغات من كثير إلى واحد، 50 لغة)
|
|
||||||
- `facebook/mbart-large-50` (الترجمة متعددة اللغات، 50 لغة)
|
|
||||||
- `facebook/mbart-large-cc25`
|
|
||||||
|
|
||||||
في هذا المثال، قم بتحميل نسخة `facebook/mbart-large-50-many-to-many-mmt` لترجمة النص من الفنلندية إلى الإنجليزية. يمكنك تعيين اللغة المصدر في المجزىء:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
|
|
||||||
|
|
||||||
>>> en_text = "Do not meddle in the affairs of wizards, for they are subtle and quick to anger."
|
|
||||||
>>> fi_text = "Älä sekaannu velhojen asioihin, sillä ne ovat hienovaraisia ja nopeasti vihaisia."
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("facebook/mbart-large-50-many-to-many-mmt", src_lang="fi_FI")
|
|
||||||
>>> model = AutoModelForSeq2SeqLM.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
|
|
||||||
```
|
|
||||||
|
|
||||||
تقسيم النّص إلى رموز:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> encoded_en = tokenizer(en_text, return_tensors="pt")
|
|
||||||
```
|
|
||||||
|
|
||||||
يجبر MBart معرف لغة الهدف كأول رمز مولد للترجمة إلى اللغة الهدف. قم بتعيين `forced_bos_token_id` إلى `en` في طريقة `generate` للترجمة إلى الإنجليزية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> generated_tokens = model.generate(**encoded_en, forced_bos_token_id=tokenizer.lang_code_to_id["en_XX"])
|
|
||||||
>>> tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)
|
|
||||||
"Don't interfere with the wizard's affairs, because they are subtle, will soon get angry."
|
|
||||||
```
|
|
||||||
|
|
||||||
إذا كنت تستخدم نسخة `facebook/mbart-large-50-many-to-one-mmt`، فلا تحتاج إلى إجبار معرف لغة الهدف كأول رمز مولد، وإلا فإن الاستخدام هو نفسه.
|
|
||||||
@ -1,141 +0,0 @@
|
|||||||
# دفاتر ملاحظات 🤗 Transformers
|
|
||||||
|
|
||||||
يمكنك أن تجد هنا قائمة بدفاتر الملاحظات الرسمية التي تقدمها Hugging Face.
|
|
||||||
|
|
||||||
كما نود أن ندرج هنا محتوى مثيرًا للاهتمام تم إنشاؤه بواسطة المجتمع.
|
|
||||||
إذا كتبت دفتر ملاحظات يستفيد من 🤗 Transformers وتود إدراجه هنا، فيُرجى فتح طلب سحب حتى يمكن تضمينه ضمن دفاتر ملاحظات المجتمع.
|
|
||||||
|
|
||||||
|
|
||||||
## دفاتر ملاحظات Hugging Face 🤗
|
|
||||||
|
|
||||||
### دفاتر ملاحظات التوثيق
|
|
||||||
|
|
||||||
يمكنك فتح أي صفحة من صفحات التوثيق كدفتر ملاحظات في Colab (يوجد زر مباشرة على تلك الصفحات) ولكنها مدرجة هنا أيضًا إذا كنت بحاجة إليها:
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [جولة سريعة في المكتبة](https://github.com/huggingface/notebooks/blob/main/transformers_doc/en/quicktour.ipynb) | عرض لمختلف واجهات برمجة التطبيقات في Transformers |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/transformers_doc/en/quicktour.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/en/transformers_doc/quicktour.ipynb)|
|
|
||||||
| [ملخص المهام](https://github.com/huggingface/notebooks/blob/main/transformers_doc/en/task_summary.ipynb) | كيفية تشغيل نماذج مكتبة Transformers مهمة تلو الأخرى |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/transformers_doc/en/task_summary.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/transformers_doc/en/task_summary.ipynb)|
|
|
||||||
| [معالجة البيانات مسبقًا](https://github.com/huggingface/notebooks/blob/main/transformers_doc/en/preprocessing.ipynb) | كيفية استخدام محلل لغوي لمعالجة بياناتك مسبقًا |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/transformers_doc/en/preprocessing.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/transformers_doc/en/preprocessing.ipynb)|
|
|
||||||
| [الضبط الدقيق لنموذج مُدرَّب مسبقًا](https://github.com/huggingface/notebooks/blob/main/transformers_doc/en/training.ipynb) | كيفية استخدام المدرب لضبط نموذج مُدرَّب مسبقًا بدقة |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/transformers_doc/en/training.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/transformers_doc/en/training.ipynb)|
|
|
||||||
| [ملخص للمحللات اللغوية](https://github.com/huggingface/notebooks/blob/main/transformers_doc/en/tokenizer_summary.ipynb) | الاختلافات بين خوارزمية المحلل اللغوي |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/transformers_doc/en/tokenizer_summary.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/transformers_doc/en/tokenizer_summary.ipynb)|
|
|
||||||
| [النماذج متعددة اللغات](https://github.com/huggingface/notebooks/blob/main/transformers_doc/en/multilingual.ipynb) | كيفية استخدام النماذج متعددة اللغات للمكتبة |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/transformers_doc/en/multilingual.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/transformers_doc/en/multilingual.ipynb)|
|
|
||||||
|
|
||||||
|
|
||||||
### أمثلة PyTorch
|
|
||||||
|
|
||||||
#### معالجة اللغة الطبيعية[[pytorch-nlp]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [تدريب محللك اللغوي](https://github.com/huggingface/notebooks/blob/main/examples/tokenizer_training.ipynb) | كيفية تدريب واستخدام محللك اللغوي الخاص بك |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/tokenizer_training.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/tokenizer_training.ipynb)|
|
|
||||||
| [تدريب نموذج لغتك](https://github.com/huggingface/notebooks/blob/main/examples/language_modeling_from_scratch.ipynb) | كيفية البدء بسهولة في استخدام المحولات |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling_from_scratch.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/language_modeling_from_scratch.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف النص](https://github.com/huggingface/notebooks/blob/main/examples/text_classification.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على أي مهمة GLUE. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على النمذجة اللغوية](https://github.com/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على مهمة LM سببية أو مقنعة. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف الرموز المميزة](https://github.com/huggingface/notebooks/blob/main/examples/token_classification.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على مهمة تصنيف الرموز المميزة (NER، PoS). | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على الإجابة على الأسئلة](https://github.com/huggingface/notebooks/blob/main/examples/question_answering.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على SQUAD. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على الاختيار من متعدد](https://github.com/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على SWAG. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على الترجمة](https://github.com/huggingface/notebooks/blob/main/examples/translation.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على WMT. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/translation.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على التلخيص](https://github.com/huggingface/notebooks/blob/main/examples/summarization.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على XSUM. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/summarization.ipynb)|
|
|
||||||
| [كيفية تدريب نموذج لغة من البداية](https://github.com/huggingface/blog/blob/main/notebooks/01_how_to_train.ipynb)| تسليط الضوء على جميع الخطوات لتدريب نموذج Transformer بشكل فعال على بيانات مخصصة | [](https://colab.research.google.com/github/huggingface/blog/blob/main/notebooks/01_how_to_train.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/blog/blob/main/notebooks/01_how_to_train.ipynb)|
|
|
||||||
| [كيفية إنشاء نص](https://github.com/huggingface/blog/blob/main/notebooks/02_how_to_generate.ipynb)| كيفية استخدام أساليب فك التشفير المختلفة لإنشاء اللغة باستخدام المحولات | [](https://colab.research.google.com/github/huggingface/blog/blob/main/notebooks/02_how_to_generate.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/blog/blob/main/notebooks/02_how_to_generate.ipynb)|
|
|
||||||
| [كيفية إنشاء نص (مع قيود)](https://github.com/huggingface/blog/blob/main/notebooks/53_constrained_beam_search.ipynb)| كيفية توجيه إنشاء اللغة باستخدام القيود التي يوفرها المستخدم | [](https://colab.research.google.com/github/huggingface/blog/blob/main/notebooks/53_constrained_beam_search.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/blog/blob/main/notebooks/53_constrained_beam_search.ipynb)|
|
|
||||||
| [Reformer](https://github.com/huggingface/blog/blob/main/notebooks/03_reformer.ipynb)| كيف يدفع Reformer حدود النمذجة اللغوية | [](https://colab.research.google.com/github/patrickvonplaten/blog/blob/main/notebooks/03_reformer.ipynb)| [](https://studiolab.sagemaker.aws/import/github/patrickvonplaten/blog/blob/main/notebooks/03_reformer.ipynb)|
|
|
||||||
|
|
||||||
#### رؤية الكمبيوتر[[pytorch-cv]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------:|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف الصور (Torchvision)](https://github.com/huggingface/notebooks/blob/main/examples/image_classification.ipynb) | يوضح كيفية معالجة البيانات مسبقًا باستخدام Torchvision وضبط أي نموذج رؤية مُدرَّب مسبقًا بدقة على تصنيف الصور | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/image_classification.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف الصور (Albumentations)](https://github.com/huggingface/notebooks/blob/main/examples/image_classification_albumentations.ipynb) | يوضح كيفية معالجة البيانات مسبقًا باستخدام Albumentations وضبط أي نموذج رؤية مُدرَّب مسبقًا بدقة على تصنيف الصور | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification_albumentations.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/image_classification_albumentations.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف الصور (Kornia)](https://github.com/huggingface/notebooks/blob/main/examples/image_classification_kornia.ipynb) | يوضح كيفية معالجة البيانات مسبقًا باستخدام Kornia وضبط أي نموذج رؤية مُدرَّب مسبقًا بدقة على تصنيف الصور | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification_kornia.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/image_classification_kornia.ipynb)|
|
|
||||||
| [كيفية إجراء الكشف عن الأشياء بدون لقطات مع OWL-ViT](https://github.com/huggingface/notebooks/blob/main/examples/zeroshot_object_detection_with_owlvit.ipynb) | يوضح كيفية إجراء الكشف عن الأشياء بدون لقطات على الصور باستخدام استعلامات نصية | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/zeroshot_object_detection_with_owlvit.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/zeroshot_object_detection_with_owlvit.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج وصف الصور بدقة](https://github.com/huggingface/notebooks/blob/main/examples/image_captioning_blip.ipynb) | يوضح كيفية ضبط BLIP بدقة لوصف الصور على مجموعة بيانات مخصصة | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_captioning_blip.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/image_captioning_blip.ipynb)|
|
|
||||||
| [كيفية بناء نظام تشابه الصور مع Transformers](https://github.com/huggingface/notebooks/blob/main/examples/image_similarity.ipynb) | يوضح كيفية بناء نظام تشابه الصور | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_similarity.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/image_similarity.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج SegFormer بدقة على التجزئة الدلالية](https://github.com/huggingface/notebooks/blob/main/examples/semantic_segmentation.ipynb) | يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج SegFormer مُدرَّب مسبقًا بدقة على التجزئة الدلالية | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/semantic_segmentation.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/semantic_segmentation.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج VideoMAE بدقة على تصنيف الفيديو](https://github.com/huggingface/notebooks/blob/main/examples/video_classification.ipynb) | يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج VideoMAE مُدرَّب مسبقًا بدقة على تصنيف الفيديو | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/video_classification.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/video_classification.ipynb)|
|
|
||||||
|
|
||||||
|
|
||||||
#### الصوت[[pytorch-audio]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [كيفية ضبط نموذج التعرف على الكلام باللغة الإنجليزية بدقة](https://github.com/huggingface/notebooks/blob/main/examples/speech_recognition.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج كلام مُدرَّب مسبقًا بدقة على TIMIT | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/speech_recognition.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/speech_recognition.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج التعرف على الكلام بأي لغة بدقة](https://github.com/huggingface/notebooks/blob/main/examples/multi_lingual_speech_recognition.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج كلام مُدرَّب مسبقًا متعدد اللغات بدقة على Common Voice | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multi_lingual_speech_recognition.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/multi_lingual_speech_recognition.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف الصوت](https://github.com/huggingface/notebooks/blob/main/examples/audio_classification.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج كلام مُدرَّب مسبقًا بدقة على Keyword Spotting | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/audio_classification.ipynb)|
|
|
||||||
|
|
||||||
|
|
||||||
#### التسلسلات البيولوجية[[pytorch-bio]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:----------------------------------------------------------------------------------------|:-------------|------:|
|
|
||||||
| [كيفية ضبط نموذج بروتين مُدرَّب مسبقًا بدقة](https://github.com/huggingface/notebooks/blob/main/examples/protein_language_modeling.ipynb) | شاهد كيفية ترميز البروتينات وضبط نموذج "لغة" بروتين مُدرَّب مسبقًا كبير بدقة | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/protein_language_modeling.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/protein_language_modeling.ipynb) |
|
|
||||||
| [كيفية إنشاء طيات بروتينية](https://github.com/huggingface/notebooks/blob/main/examples/protein_folding.ipynb) | شاهد كيفية الانتقال من تسلسل البروتين إلى نموذج بروتين كامل وملف PDB | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/protein_folding.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/protein_folding.ipynb) |
|
|
||||||
| [كيفية ضبط نموذج محول النيوكليوتيدات بدقة](https://github.com/huggingface/notebooks/blob/main/examples/nucleotide_transformer_dna_sequence_modelling.ipynb) | شاهد كيفية ترميز الحمض النووي وضبط نموذج "لغة" الحمض النووي مُدرَّب مسبقًا كبير بدقة | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/nucleotide_transformer_dna_sequence_modelling.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/nucleotide_transformer_dna_sequence_modelling.ipynb) |
|
|
||||||
| [ضبط نموذج محول النيوكليوتيدات بدقة باستخدام LoRA](https://github.com/huggingface/notebooks/blob/main/examples/nucleotide_transformer_dna_sequence_modelling_with_peft.ipynb) | تدريب نماذج DNA أكبر بكثير بطريقة فعالة من حيث الذاكرة | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/nucleotide_transformer_dna_sequence_modelling_with_peft.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/nucleotide_transformer_dna_sequence_modelling_with_peft.ipynb) |
|
|
||||||
|
|
||||||
|
|
||||||
#### طرائق أخرى[[pytorch-other]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:----------------------------------------------------------------------------------------|:-------------|------:|
|
|
||||||
| [التنبؤ الاحتمالي بالسلاسل الزمنية](https://github.com/huggingface/notebooks/blob/main/examples/time-series-transformers.ipynb) | شاهد كيفية تدريب Time Series Transformer على مجموعة بيانات مخصصة | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/time-series-transformers.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/time-series-transformers.ipynb) |
|
|
||||||
|
|
||||||
#### دفاتر ملاحظات الأدوات المساعدة [[pytorch-utility]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [كيفية تصدير النموذج إلى ONNX](https://github.com/huggingface/notebooks/blob/main/examples/onnx-export.ipynb)| تسليط الضوء على كيفية التصدير وتشغيل أعباء عمل الاستدلال من خلال ONNX | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/onnx-export.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/onnx-export.ipynb)|
|
|
||||||
| [كيفية استخدام المعايير](https://github.com/huggingface/notebooks/blob/main/examples/benchmark.ipynb)| كيفية قياس أداء النماذج باستخدام المحولات | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/benchmark.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/benchmark.ipynb)|
|
|
||||||
|
|
||||||
### أمثلة TensorFlow
|
|
||||||
|
|
||||||
#### معالجة اللغة الطبيعية[[tensorflow-nlp]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [تدريب محللك اللغوي](https://github.com/huggingface/notebooks/blob/main/examples/tokenizer_training.ipynb) | كيفية تدريب واستخدام محللك اللغوي الخاص بك |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/tokenizer_training.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/tokenizer_training.ipynb)|
|
|
||||||
| [تدريب نموذج لغتك](https://github.com/huggingface/notebooks/blob/main/examples/language_modeling_from_scratch-tf.ipynb) | كيفية البدء بسهولة في استخدام المحولات |[](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling_from_scratch-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/language_modeling_from_scratch-tf.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف النص](https://github.com/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على أي مهمة GLUE. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على النمذجة اللغوية](https://github.com/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على مهمة LM سببية أو مقنعة. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف الرموز المميزة](https://github.com/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على مهمة تصنيف الرموز المميزة (NER، PoS). | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على الإجابة على الأسئلة](https://github.com/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على SQUAD. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على الاختيار من متعدد](https://github.com/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على SWAG. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على الترجمة](https://github.com/huggingface/notebooks/blob/main/examples/translation-tf.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على WMT. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/translation-tf.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على التلخيص](https://github.com/huggingface/notebooks/blob/main/examples/summarization-tf.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج مُدرَّب مسبقًا بدقة على XSUM. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/summarization-tf.ipynb)|
|
|
||||||
|
|
||||||
#### رؤية الكمبيوتر[[tensorflow-cv]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:---------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------|:-------------|------:|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف الصور](https://github.com/huggingface/notebooks/blob/main/examples/image_classification-tf.ipynb) | يوضح كيفية معالجة البيانات مسبقًا وضبط أي نموذج رؤية مُدرَّب مسبقًا بدقة على تصنيف الصور | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/image_classification-tf.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج SegFormer بدقة على التجزئة الدلالية](https://github.com/huggingface/notebooks/blob/main/examples/semantic_segmentation-tf.ipynb) | يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج SegFormer مُدرَّب مسبقًا بدقة على التجزئة الدلالية | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/semantic_segmentation-tf.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/semantic_segmentation-tf.ipynb)|
|
|
||||||
|
|
||||||
#### التسلسلات البيولوجية[[tensorflow-bio]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [كيفية ضبط نموذج بروتين مُدرَّب مسبقًا بدقة](https://github.com/huggingface/notebooks/blob/main/examples/protein_language_modeling-tf.ipynb) | شاهد كيفية ترميز البروتينات وضبط نموذج "لغة" بروتين مُدرَّب مسبقًا كبير بدقة | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/protein_language_modeling-tf.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/protein_language_modeling-tf.ipynb) |
|
|
||||||
|
|
||||||
#### دفاتر ملاحظات الأدوات المساعدة [[tensorflow-utility]]
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [كيفية تدريب نماذج TF/Keras على TPU](https://github.com/huggingface/notebooks/blob/main/examples/tpu_training-tf.ipynb) | شاهد كيفية التدريب بسرعة عالية على أجهزة TPU من Google | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/tpu_training-tf.ipynb) | [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/tpu_training-tf.ipynb) |
|
|
||||||
|
|
||||||
### دفاتر ملاحظات Optimum
|
|
||||||
|
|
||||||
🤗 [Optimum](https://github.com/huggingface/optimum) هو امتداد لـ 🤗 Transformers، يوفر مجموعة من أدوات تحسين الأداء التي تمكن من تحقيق أقصى قدر من الكفاءة لتدريب وتشغيل النماذج على الأجهزة المستهدفة.
|
|
||||||
|
|
||||||
| دفتر الملاحظات | الوصف | | |
|
|
||||||
|:----------|:-------------|:-------------|------:|
|
|
||||||
| [كيفية تكميم نموذج باستخدام ONNX Runtime لتصنيف النص](https://github.com/huggingface/notebooks/blob/main/examples/text_classification_quantization_ort.ipynb)| يوضح كيفية تطبيق التكميم الثابت والديناميكي على نموذج باستخدام [ONNX Runtime](https://github.com/microsoft/onnxruntime) لأي مهمة GLUE. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_quantization_ort.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/text_classification_quantization_ort.ipynb)|
|
|
||||||
| [كيفية تكميم نموذج باستخدام Intel Neural Compressor لتصنيف النص](https://github.com/huggingface/notebooks/blob/main/examples/text_classification_quantization_inc.ipynb)| يوضح كيفية تطبيق التكميم الثابت والديناميكي والتدريبي على نموذج باستخدام [Intel Neural Compressor (INC)](https://github.com/intel/neural-compressor) لأي مهمة GLUE. | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_quantization_inc.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/text_classification_quantization_inc.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على تصنيف النص باستخدام ONNX Runtime](https://github.com/huggingface/notebooks/blob/main/examples/text_classification_ort.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج بدقة على أي مهمة GLUE باستخدام [ONNX Runtime](https://github.com/microsoft/onnxruntime). | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification_ort.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/text_classification_ort.ipynb)|
|
|
||||||
| [كيفية ضبط نموذج بدقة على التلخيص باستخدام ONNX Runtime](https://github.com/huggingface/notebooks/blob/main/examples/summarization_ort.ipynb)| يوضح كيفية معالجة البيانات مسبقًا وضبط نموذج بدقة على XSUM باستخدام [ONNX Runtime](https://github.com/microsoft/onnxruntime). | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/summarization_ort.ipynb)| [](https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/main/examples/summarization_ort.ipynb)|
|
|
||||||
|
|
||||||
|
|
||||||
## دفاتر ملاحظات المجتمع:
|
|
||||||
|
|
||||||
تتوفر المزيد من دفاتر الملاحظات التي طورها المجتمع [هنا](https://hf.co/docs/transformers/community#community-notebooks).
|
|
||||||
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
# الحشو والتقليم
|
|
||||||
|
|
||||||
غالبًا ما تختلف مدخلات الدُفعات في الطول، لذا لا يمكن تحويلها إلى مصفوفات ذات حجم ثابت .يُعدّ الحشو والتقليم هما استراتيجيتان للتعامل مع هذه المشكلة، لإنشاء مصفوفات مستطيلة من مجموعات ذات أطوال مختلفة. ويضيف الحشو رمز **حشو** خاص لضمان أن يكون للتسلسلات الأقصر نفس طول أطول تسلسل في الدفعة أو الطول الأقصى الذي يقبله النموذج. ويعمل التقليم عكس ذلك بتقليم التسلسلات الطويلة.
|
|
||||||
|
|
||||||
في معظم الحالات، ييُعدّ حشو دُفعتك إلى طول أطول تسلسل فيها وتقليمها إلى الطول الأقصى المقبول من النموذج حلًا فعالًا. ومع ذلك، تدعم واجهة برمجة التطبيقات المزيد من الاستراتيجيات إذا كنت بحاجة إليها. هناك ثلاثة معامﻻت تحتاجها لفهم آلية العمل: `padding`، و`truncation`، و`max_length`.
|
|
||||||
|
|
||||||
يحكم معامل `padding` عملية الحشو. يمكن أن يكون قيمة منطقية أو نصية:
|
|
||||||
|
|
||||||
- `True` أو `'longest'`: الحشو إلى أطول تسلسل في الدفعة (لا يتم تطبيق الحشو عند تقديم تسلسل واحد فقط).
|
|
||||||
- `'max_length'`: الحشو إلى طول محدد بواسطة معامل `max_length` أو الطول الأقصى الذي يقبله
|
|
||||||
النموذج إذا لم يتم توفير `max_length` (`max_length=None`). سيظل الحشو مطبقًا إذا قدمت تسلسلًا واحدًا فقط.
|
|
||||||
- `False` أو `'do_not_pad'`: لا يتم تطبيق أي حشو. هذا هو السلوك الافتراضي.
|
|
||||||
|
|
||||||
تحكم معامل `truncation` عملية التقليم. يمكن أن يكون قيمة منطقية أو نصية:
|
|
||||||
|
|
||||||
-قيمة `True` أو `'longest_first'` : تقليم التسلسلات إلى طول أقصى مُحدد بواسطة معامل `max_length`، أو أقصى طول يقبله النموذج في حال عدم تحديد طول مُحدد من قبل المستخدم (`max_length=None`). ستتم عملية التقليم إزالة رمز تلو الآخر، بدءًا من أطول تسلسل في الزوج، إلى أن يصل الطول إلى القيمة المُحددة.
|
|
||||||
-قيمة `'only_second'`: اقطع إلى طول أقصى محدد بواسطة معامل `max_length` أو أقصى طول يقبله النموذج إذا لم يتم توفير `max_length` (`max_length=None`). هذا سيقلم فقط الجملة الثانية من الزوج إذا تم توفير زوج من التسلسلات (أو دُفعة من أزواج التسلسلات).
|
|
||||||
-قيمة `'only_first'`: تقليم الجملة الأولى فقط من الزوج عند تقديم زوج من التسلسلات (أو دُفعة من أزواج التسلسلات) إلى طول أقصى مُحدد بواسطة حجة `max_length`، أو أقصى طول يقبله النموذج في حال عدم تحديد طول مُحدد من قبل المستخدم (`max_length=None`).
|
|
||||||
-قيمة `False` أو `'do_not_truncate'`: لا يتم تطبيق أي تقليم. هذا هو السلوك الافتراضي.
|
|
||||||
``
|
|
||||||
|
|
||||||
يحكم معامل `max_length` طول الحشو والتقليم. يمكن أن يكون عدد صحيح أو `None`، وعندها يُحدد افتراضيًا إلى الطول الأقصى الذي يمكن أن يقبله النموذج. إذا لم يكن للنموذج طول إدخال أقصى محدد، يتم إلغاء تنشيط التقليم أو الحشو إلى `max_length`.
|
|
||||||
|
|
||||||
يلخّص الجدول التالي الطريقة المُوصى بها لإعداد الحشو والتقليم. إذا كنت تستخدم أزواج تسلسلات الإدخال في أي من الأمثلة التالية، فيمكنك استبدال `truncation=True` بـ `STRATEGY` المحدد في `['only_first'، 'only_second'، 'longest_first']`، أي `truncation='only_second'` أو `truncation='longest_first'` للتحكم في كيفية تقليم كلا التسلسلين في الزوج كما هو موضّح سابقًا.
|
|
||||||
<!-- This file is automatically generated, do not modify manually. -->
|
|
||||||
|
|
||||||
# حيل الترميز
|
|
||||||
|
|
||||||
هناك العديد من الاستراتيجيات لترميز دفعات الجمل. فيما يلي بعض الأمثلة على ذلك.
|
|
||||||
|
|
||||||
| الترميز | الحشو | التعليمات |
|
|
||||||
|--------------------------------------|-----------------------------------|---------------------------------------------------------------------------------------------|
|
|
||||||
| لا ترميز | لا حشو | `tokenizer(batch_sentences)` |
|
|
||||||
| | الحشو إلى الحد الأقصى للتسلسل في الدفعة | `tokenizer(batch_sentences, padding=True)` أو |
|
|
||||||
| | | `tokenizer(batch_sentences, padding='longest')` |
|
|
||||||
| | الحشو إلى الحد الأقصى لطول إدخال النموذج | `tokenizer(batch_sentences, padding='max_length')` |
|
|
||||||
| | الحشو إلى طول محدد | `tokenizer(batch_sentences, padding='max_length', max_length=42)` |
|
|
||||||
| | الحشو إلى مضاعف لقيمة معينة | `tokenizer(batch_sentences, padding=True, pad_to_multiple_of=8)` |
|
|
||||||
| الترميز إلى الحد الأقصى لطول إدخال النموذج | لا حشو | `tokenizer(batch_sentences, truncation=True)` أو |
|
|
||||||
| | | `tokenizer(batch_sentences, truncation=STRATEGY)` |
|
|
||||||
| | الحشو إلى الحد الأقصى للتسلسل في الدفعة | `tokenizer(batch_sentences, padding=True, truncation=True)` أو |
|
|
||||||
| | | `tokenizer(batch_sentences, padding=True, truncation=STRATEGY)` |
|
|
||||||
| | الحشو إلى الحد الأقصى لطول إدخال النموذج | `tokenizer(batch_sentences, padding='max_length', truncation=True)` أو |
|
|
||||||
| | | `tokenizer(batch_sentences, padding='max_length', truncation=STRATEGY)` |
|
|
||||||
| | الحشو إلى طول محدد | غير ممكن |
|
|
||||||
| الترميز إلى طول محدد | لا حشو | `tokenizer(batch_sentences, truncation=True, max_length=42)` أو |
|
|
||||||
| | | `tokenizer(batch_sentences, truncation=STRATEGY, max_length=42)` |
|
|
||||||
| | الحشو إلى الحد الأقصى للتسلسل في الدفعة | `tokenizer(batch_sentences, padding=True, truncation=True, max_length=42)` أو |
|
|
||||||
| | | `tokenizer(batch_sentences, padding=True, truncation=STRATEGY, max_length=42)` |
|
|
||||||
| | الحشو إلى الحد الأقصى لطول إدخال النموذج | غير ممكن |
|
|
||||||
| | الحشو إلى طول محدد | `tokenizer(batch_sentences, padding='max_length', truncation=True, max_length=42)` أو |
|
|
||||||
| | | `tokenizer(batch_sentences, padding='max_length', truncation=STRATEGY, max_length=42)` |
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
# التعقيد اللغوي للنماذج ذات الطول الثابت
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
التعقيد اللغوي (PPL) هي واحدة من أكثر المقاييس شيوعًا لتقييم نماذج اللغة. قبل الخوض في التفاصيل، يجب أن نلاحظ أن المقياس ينطبق تحديدًا على نماذج اللغة الكلاسيكية (يُطلق عليها أحيانًا نماذج اللغة التلقائية المرجعية أو السببية) وهي غير محددة جيدًا لنماذج اللغة المقنعة مثل BERT (راجع [ملخص النماذج](model_summary)).
|
|
||||||
|
|
||||||
تُعرَّف التعقيد اللغوي على أنها الأس المُرفوع لقيمة متوسط اللوغاريتم الاحتمالي لمتتالية. إذا كان لدينا تسلسل رمزي \\(X = (x_0, x_1, \dots, x_t)\\)، فإن حيرة \\(X\\) هي،
|
|
||||||
|
|
||||||
$$\text{PPL}(X) = \exp \left\{ {-\frac{1}{t}\sum_i^t \log p_\theta (x_i|x_{<i}) } \right\}$$
|
|
||||||
|
|
||||||
حيث \\(\log p_\theta (x_i|x_{<i})\\) هو اللوغاريتم الاحتمالي للرمز i بشرط الرموز السابقة \\(x_{<i}\\) وفقًا لنموذجنا. ومن الناحية البديهية، يمكن اعتبارها تقييمًا لقدرة النموذج على التنبؤ بالتساوي بين مجموعة من الرموز المحددة في مجموعة من البيانات. ومن المهم الإشارة إلى أن عملية التمييز له تأثير مباشرًا على حيرة النموذج،ويجب مراعاتها دائمًا عند مقارنة النماذج المختلفة.
|
|
||||||
|
|
||||||
كما أنها تعادل الأس المُرفوع لقيمة الانتروبيا المتقاطعة بين البيانات وتنبؤات النموذج. لمزيد من الفهم حول مفهوم التعقيد اللغوي وعلاقتها بـ Bits Per Character (BPC) وضغط البيانات، يُرجى مراجعة [التدوينة المفيدة على The Gradient](https://thegradient.pub/understanding-evaluation-metrics-for-language-models/).
|
|
||||||
|
|
||||||
## حساب PPL مع النماذج ذات الطول الثابت
|
|
||||||
|
|
||||||
إذا لم نكن مقيدين بحجم سياق النموذج، فسنقوم بتقييم التعقيد اللغوي للنموذج عن طريق تحليل التسلسل تلقائيًا والشرط على التسلسل الفرعي السابق بالكامل في كل خطوة، كما هو موضح أدناه.
|
|
||||||
|
|
||||||
<img width="600" alt="Full decomposition of a sequence with unlimited context length" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/ppl_full.gif"/>
|
|
||||||
|
|
||||||
لكن عند التعامل مع النماذج التقريبية، نواجه عادةً قيدًا على عدد الرموز التي يمكن للنموذج معالجتها. على سبيل المثال، تحتوي أكبر نسخة من [GPT-2](model_doc/gpt2) على طول ثابت يبلغ 1024 رمزًا، لذا لا يمكننا حساب \\(p_\theta(x_t|x_{<t})\\) مباشرة عندما تكون \\(t\\) أكبر من 1024.
|
|
||||||
|
|
||||||
بدلاً من ذلك، يتم عادةً تقسيم التسلسل إلى تسلسلات فرعية مساوية لحجم الإدخال الأقصى للنموذج. فإذا كان حجم الإدخال الأقصى للنموذج هو \\(k\\)، فإننا نقرب احتمال الرمز \\(x_t\\) عن طريق الاشتقاق الشرطي فقط بالنسبة إلى \\(k-1\\) من الرموز التي تسبقه بدلاً من السياق بأكمله. وعند تقييم حيرة النموذج لتسلسل ما، قد يبدو من المغري تقسيم التسلسل إلى أجزاء منفصلة وجمع مجموع دوال اللوغاريتم لكل جزء بشكل مستقل، لكن هذا الأسلوب ليس الأمثل.
|
|
||||||
|
|
||||||
<img width="600" alt="Suboptimal PPL not taking advantage of full available context" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/ppl_chunked.gif"/>
|
|
||||||
|
|
||||||
تتميز هذه الطريقة بسرعة حسابها نظرًا لإمكانية حساب درجة التعقيد اللغوي لكل جزء بمسح واحد للأمام، إلا أنها تُعدّ تقريبًا ضعيفًا لدرجة التعقيد اللغوي المُحلّلة بشكل كامل، وعادةً ما تؤدي إلى درجة تعقيد لغوي أعلى (أسوأ) لأن النموذج سيكون لديه سياق أقل في معظم خطوات التنبؤ.
|
|
||||||
|
|
||||||
بدلاً من ذلك، يجب تقييم درجة التعقيد اللغوي للنماذج ذات الطول الثابت باستخدام إستراتيجية النافذة المنزلقة. وينطوي هذا على تحريك نافذة السياق بشكل متكرر بحيث يكون للنموذج سياق أكبر عند إجراء كل تنبؤ.
|
|
||||||
|
|
||||||
<img width="600" alt="Sliding window PPL taking advantage of all available context" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/ppl_sliding.gif"/>
|
|
||||||
|
|
||||||
هذا تقريب أقرب للتفكيك الحقيقي لاحتمالية التسلسل وسيؤدي عادةً إلى نتيجة أفضل.لكن الجانب السلبي هو أنه يتطلب تمريرًا للأمام لكل رمز في مجموعة البيانات. حل وسط عملي مناسب هو استخدام نافذة منزلقة بخطوة، بحيث يتم تحريك السياق بخطوات أكبر بدلاً من الانزلاق بمقدار 1 رمز في كل مرة. مما يسمح بإجراء الحساب بشكل أسرع مع إعطاء النموذج سياقًا كبيرًا للتنبؤات في كل خطوة.
|
|
||||||
|
|
||||||
## مثال: حساب التعقيد اللغوي مع GPT-2 في 🤗 Transformers
|
|
||||||
|
|
||||||
دعونا نوضح هذه العملية مع GPT-2.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import GPT2LMHeadModel, GPT2TokenizerFast
|
|
||||||
|
|
||||||
device = "cuda"
|
|
||||||
model_id = "openai-community/gpt2-large"
|
|
||||||
model = GPT2LMHeadModel.from_pretrained(model_id).to(device)
|
|
||||||
tokenizer = GPT2TokenizerFast.from_pretrained(model_id)
|
|
||||||
```
|
|
||||||
|
|
||||||
سنقوم بتحميل مجموعة بيانات WikiText-2 وتقييم التعقيد اللغوي باستخدام بعض إستراتيجيات مختلفة النافذة المنزلقة. نظرًا لأن هذه المجموعة البيانات الصغيرة ونقوم فقط بمسح واحد فقط للمجموعة، فيمكننا ببساطة تحميل مجموعة البيانات وترميزها بالكامل في الذاكرة.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from datasets import load_dataset
|
|
||||||
|
|
||||||
test = load_dataset("wikitext", "wikitext-2-raw-v1", split="test")
|
|
||||||
encodings = tokenizer("\n\n".join(test["text"]), return_tensors="pt")
|
|
||||||
```
|
|
||||||
|
|
||||||
مع 🤗 Transformers، يمكننا ببساطة تمرير `input_ids` كـ `labels` إلى نموذجنا، وسيتم إرجاع متوسط احتمالية السجل السالب لكل رمز كخسارة. ومع ذلك، مع نهج النافذة المنزلقة، هناك تداخل في الرموز التي نمررها إلى النموذج في كل تكرار. لا نريد تضمين احتمالية السجل للرموز التي نتعامل معها كسياق فقط في خسارتنا، لذا يمكننا تعيين هذه الأهداف إلى `-100` بحيث يتم تجاهلها. فيما يلي هو مثال على كيفية القيام بذلك بخطوة تبلغ `512`. وهذا يعني أن النموذج سيكون لديه 512 رمزًا على الأقل للسياق عند حساب الاحتمالية الشرطية لأي رمز واحد (بشرط توفر 512 رمزًا سابقًا متاحًا للاشتقاق).
|
|
||||||
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
max_length = model.config.n_positions
|
|
||||||
stride = 512
|
|
||||||
seq_len = encodings.input_ids.size(1)
|
|
||||||
|
|
||||||
nlls = []
|
|
||||||
prev_end_loc = 0
|
|
||||||
for begin_loc in tqdm(range(0, seq_len, stride)):
|
|
||||||
end_loc = min(begin_loc + max_length, seq_len)
|
|
||||||
trg_len = end_loc - prev_end_loc # قد تكون مختلفة عن الخطوة في الحلقة الأخيرة
|
|
||||||
input_ids = encodings.input_ids[:, begin_loc:end_loc].to(device)
|
|
||||||
target_ids = input_ids.clone()
|
|
||||||
target_ids[:, :-trg_len] = -100
|
|
||||||
|
|
||||||
with torch.no_grad():
|
|
||||||
outputs = model(input_ids, labels=target_ids)
|
|
||||||
|
|
||||||
# يتم حساب الخسارة باستخدام CrossEntropyLoss الذي يقوم بالمتوسط على التصنيفات الصحيحة
|
|
||||||
# لاحظ أن النموذج يحسب الخسارة على trg_len - 1 من التصنيفات فقط، لأنه يتحول داخليًا إلى اليسار بواسطة 1.
|
|
||||||
neg_log_likelihood = outputs.loss
|
|
||||||
|
|
||||||
nlls.append(neg_log_likelihood)
|
|
||||||
|
|
||||||
prev_end_loc = end_loc
|
|
||||||
if end_loc == seq_len:
|
|
||||||
break
|
|
||||||
|
|
||||||
ppl = torch.exp(torch.stack(nlls).mean())
|
|
||||||
```
|
|
||||||
|
|
||||||
يعد تشغيل هذا مع طول الخطوة مساويًا لطول الإدخال الأقصى يعادل لاستراتيجية النافذة غير المنزلقة وغير المثلى التي ناقشناها أعلاه. وكلما صغرت الخطوة، زاد السياق الذي سيحصل عليه النموذج في عمل كل تنبؤ، وكلما كانت التعقيد اللغوي المُبلغ عنها أفضل عادةً.
|
|
||||||
|
|
||||||
عندما نقوم بتشغيل ما سبق باستخدام `stride = 1024`، أي بدون تداخل، تكون درجة التعقيد اللغوي الناتجة هي `19.44`، وهو ما يماثل `19.93` المبلغ عنها في ورقة GPT-2. من خلال استخدام `stride = 512` وبالتالي استخدام إستراتيجية النافذة المنزلقة، ينخفض هذا إلى `16.45`. هذه النتيجة ليست فقط أفضل، ولكنها محسوبة بطريقة أقرب إلى التحليل التلقائي الحقيقي لاحتمالية التسلسل.
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
# الفلسفة
|
|
||||||
|
|
||||||
تُعد 🤗 Transformers مكتبة برمجية ذات رؤية واضحة صُممت من أجل:
|
|
||||||
|
|
||||||
- الباحثون والمُتعلّمون في مجال التعلم الآلي ممن يسعون لاستخدام أو دراسة أو تطوير نماذج Transformers واسعة النطاق.
|
|
||||||
- مُطبّقي تعلم الآلة الذين يرغبون في ضبط تلك النماذج أو تشغيلها في بيئة إنتاجية، أو كليهما.
|
|
||||||
- المهندسون الذين يريدون فقط تنزيل نموذج مُدرب مسبقًا واستخدامه لحل مهمة تعلم آلي معينة.
|
|
||||||
|
|
||||||
تم تصميم المكتبة مع الأخذ في الاعتبار هدفين رئيسيين:
|
|
||||||
|
|
||||||
1. سهولة وسرعة الاستخدام:
|
|
||||||
|
|
||||||
- تمّ تقليل عدد المفاهيم المُجردة التي يتعامل معها المستخدم إلى أدنى حد والتي يجب تعلمها، وفي الواقع، لا توجد مفاهيم مُجردة تقريبًا، فقط ثلاث فئات أساسية مطلوبة لاستخدام كل نموذج: [الإعدادات](main_classes/configuration)، [نماذج](main_classes/model)، وفئة ما قبل المعالجة ([مُجزّئ لغوي](main_classes/tokenizer) لـ NLP، [معالج الصور](main_classes/image_processor) للرؤية، [مستخرج الميزات](main_classes/feature_extractor) للصوت، و [معالج](main_classes/processors) للمدخﻻت متعددة الوسائط).
|
|
||||||
- يمكن تهيئة جميع هذه الفئات بطريقة بسيطة وموحدة من خلال نماذج مُدربة مسبقًا باستخدام الدالة الموحدة `from_pretrained()` والتي تقوم بتنزيل (إذا لزم الأمر)، وتخزين وتحميل كل من: فئة النموذج المُراد استخدامه والبيانات المرتبطة ( مُعاملات الإعدادات، ومعجم للمُجزّئ اللغوي،وأوزان النماذج) من نقطة تدقيق مُحددة مُخزّنة على [Hugging Face Hub](https://huggingface.co/models) أو ن من نقطة تخزين خاصة بالمستخدم.
|
|
||||||
- بالإضافة إلى هذه الفئات الأساسية الثلاث، توفر المكتبة واجهتي برمجة تطبيقات: [`pipeline`] للاستخدام السريع لأحد النماذج لأداء استنتاجات على مهمة مُحددة، و [`Trainer`] للتدريب السريع أو الضبط الدقيق لنماذج PyTorch (جميع نماذج TensorFlow متوافقة مع `Keras.fit`).
|
|
||||||
- نتيجة لذلك، هذه المكتبة ليست صندوق أدوات متعدد الاستخدامات من الكتل الإنشائية للشبكات العصبية. إذا كنت تريد توسيع أو البناء على المكتبة، فما عليك سوى استخدام Python و PyTorch و TensorFlow و Keras العادية والوراثة من الفئات الأساسية للمكتبة لإعادة استخدام الوظائف مثل تحميل النموذج وحفظه. إذا كنت ترغب في معرفة المزيد عن فلسفة الترميز لدينا للنماذج، فراجع منشور المدونة الخاص بنا [Repeat Yourself](https://huggingface.co/blog/transformers-design-philosophy).
|
|
||||||
|
|
||||||
2. تقديم نماذج رائدة في مجالها مع أداء قريب قدر الإمكان من النماذج الأصلية:
|
|
||||||
|
|
||||||
- نقدم مثالًا واحدًا على الأقل لكل بنية تقوم بإعادة إنتاج نتيجة مقدمة من المؤلفين الرسميين لتلك البنية.
|
|
||||||
- عادةً ما تكون الشفرة قريبة قدر الإمكان من قاعدة الشفرة الأصلية، مما يعني أن بعض شفرة PyTorch قد لا تكون "بأسلوب PyTorch" كما يمكن أن تكون نتيجة لكونها شفرة TensorFlow محولة والعكس صحيح.
|
|
||||||
|
|
||||||
بعض الأهداف الأخرى:
|
|
||||||
|
|
||||||
- كشف تفاصيل النماذج الداخلية بشكل متسق قدر الإمكان:
|
|
||||||
|
|
||||||
-نتيح الوصول، باستخدام واجهة برمجة واحدة، إلى جميع الحالات المخفية (Hidden-States) وأوزان الانتباه (Attention Weights).
|
|
||||||
- تم توحيد واجهات برمجة التطبيقات الخاصة بفئات المعالجة المسبقة والنماذج الأساسية لتسهيل التبديل بين النماذج.
|
|
||||||
|
|
||||||
- دمج مجموعة مختارة من الأدوات الواعدة لضبط النماذج بدقة (Fine-tuning) ودراستها:
|
|
||||||
|
|
||||||
- طريقة بسيطة ومتسقة لإضافة رموز جديدة إلى مفردات التضمينات (Embeddings) لضبط النماذج بدقة.
|
|
||||||
- طرق سهلة لإخفاء (Masking) وتقليم (Pruning) رؤوس المحولات (Transformer Heads).
|
|
||||||
|
|
||||||
- التبديل بسهولة بين PyTorch و TensorFlow 2.0 و Flax، مما يسمح بالتدريب باستخدام إطار واحد والاستدلال باستخدام إطار آخر.
|
|
||||||
|
|
||||||
## المفاهيم الرئيسية
|
|
||||||
|
|
||||||
تعتمد المكتبة على ثلاثة أنواع من الفئات لكل نموذج:
|
|
||||||
|
|
||||||
- **فئات النماذج** يمكن أن تكون نماذج PyTorch ([torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module))، أو نماذج Keras ([tf.keras.Model](https://www.tensorflow.org/api_docs/python/tf/keras/Model))، أو نماذج JAX/Flax ([flax.linen.Module](https://flax.readthedocs.io/en/latest/api_reference/flax.linen/module.html)) التي تعمل مع الأوزان المُدربة مسبقًا المقدمة في المكتبة.
|
|
||||||
- **فئات الإعداد** تخزن معلمات التهيئة المطلوبة لبناء نموذج (مثل عدد الطبقات وحجم الطبقة المخفية). أنت لست مضطرًا دائمًا إلى إنشاء مثيل لهذه الفئات بنفسك. على وجه الخصوص، إذا كنت تستخدم نموذجًا مُدربًا مسبقًا دون أي تعديل، فإن إنشاء النموذج سيهتم تلقائيًا تهيئة الإعدادات (والذي يعد جزءًا من النموذج).
|
|
||||||
- **فئات ما قبل المعالجة** تحويل البيانات الخام إلى تنسيق مقبول من قبل النموذج. يقوم [المعالج](main_classes/tokenizer) بتخزين المعجم لكل نموذج ويقدم طرقًا لتشفير وفك تشفير السلاسل في قائمة من مؤشرات تضمين الرموز ليتم إطعامها للنموذج. تقوم [معالجات الصور](main_classes/image_processor) بمعالجة إدخالات الرؤية، وتقوم [مستخلصات الميزات](main_classes/feature_extractor) بمعالجة إدخالات الصوت، ويقوم [المعالج](main_classes/processors) بمعالجة الإدخالات متعددة الوسائط.
|
|
||||||
|
|
||||||
يمكن تهيئة جميع هذه الفئات من نسخ مُدربة مسبقًا، وحفظها محليًا، ومشاركتها على منصة Hub عبر ثلاث طرق:
|
|
||||||
|
|
||||||
- تسمح لك الدالة `from_pretrained()` بتهيئة النموذج وتكويناته وفئة المعالجة المسبقة من إصدار مُدرب مسبقًا إما يتم توفيره بواسطة المكتبة نفسها (يمكن العثور على النماذج المدعومة على [Model Hub](https://huggingface.co/models)) أو مخزنة محليًا (أو على خادم) بواسطة المستخدم.
|
|
||||||
- تسمح لك الدالة `save_pretrained()` بحفظ النموذج، وتكويناته وفئة المعالجة المسبقة محليًا، بحيث يمكن إعادة تحميله باستخدام الدالة `from_pretrained()`.
|
|
||||||
- تسمح لك `push_to_hub()` بمشاركة نموذج وتكويناتهوفئة المعالجة المسبقة على Hub، بحيث يمكن الوصول إليها بسهولة من قبل الجميع.
|
|
||||||
@ -1,126 +0,0 @@
|
|||||||
# استخدام قنوات المعالجة لخادم ويب
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
يُعدّ إنشاء محرك استدلال أمرًا معقدًا، ويعتمد الحل "الأفضل" على مساحة مشكلتك. هل تستخدم وحدة المعالجة المركزية أم وحدة معالجة الرسومات؟ هل تريد أقل زمن وصول، أم أعلى معدل نقل، أم دعمًا للعديد من النماذج، أم مجرد تحقيق أقصى تحسين نموذج محدد؟
|
|
||||||
توجد طرق عديدة لمعالجة هذا الموضوع، لذلك ما سنقدمه هو إعداد افتراضي جيد للبدء به قد لا يكون بالضرورة هو الحل الأمثل لك.```
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
الشيء الرئيسي الذي يجب فهمه هو أننا يمكن أن نستخدم مؤشرًا، تمامًا كما تفعل [على مجموعة بيانات](pipeline_tutorial#using-pipelines-on-a-dataset)، نظرًا لأن خادم الويب هو أساسًا نظام ينتظر الطلبات ويعالجها عند استلامها.
|
|
||||||
|
|
||||||
عادةً ما تكون خوادم الويب متعددة الإرسال (متعددة مؤشرات الترابط، وغير متزامنة، إلخ) للتعامل مع الطلبات المختلفة بشكل متزامن. من ناحية أخرى، فإن قنوات المعالجة (وبشكل رئيسي النماذج الأساسية) ليست رائعة للتوازي؛ حيث تستهلك الكثير من ذاكرة الوصول العشوائي، لذا من الأفضل منحها جميع الموارد المتاحة عند تشغيلها أو إذا كانت مهمة تطلب حسابات مكثفة.
|
|
||||||
|
|
||||||
سنحل ذلك من خلال جعل خادم الويب يتعامل مع الحمل الخفيف لاستقبال الطلبات وإرسالها،وجعل مؤشر ترابط واحد يتعامل مع العمل الفعلي. سيستخدم هذا المثال `starlette`. ولكن قد تضطر إلى ضبط الكود أو تغييره إذا كنت تستخدم كودًا آخر لتحقيق التأثير نفسه.
|
|
||||||
|
|
||||||
أنشئ `server.py`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
from starlette.applications import Starlette
|
|
||||||
from starlette.responses import JSONResponse
|
|
||||||
from starlette.routing import Route
|
|
||||||
from transformers import pipeline
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
|
|
||||||
async def homepage(request):
|
|
||||||
payload = await request.body()
|
|
||||||
string = payload.decode("utf-8")
|
|
||||||
response_q = asyncio.Queue()
|
|
||||||
await request.app.model_queue.put((string, response_q))
|
|
||||||
output = await response_q.get()
|
|
||||||
return JSONResponse(output)
|
|
||||||
|
|
||||||
|
|
||||||
async def server_loop(q):
|
|
||||||
pipe = pipeline(model="google-bert/bert-base-uncased")
|
|
||||||
while True:
|
|
||||||
(string, response_q) = await q.get()
|
|
||||||
out = pipe(string)
|
|
||||||
await response_q.put(out)
|
|
||||||
|
|
||||||
|
|
||||||
app = Starlette(
|
|
||||||
routes=[
|
|
||||||
Route("/", homepage, methods=["POST"]),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.on_event("startup")
|
|
||||||
async def startup_event():
|
|
||||||
q = asyncio.Queue()
|
|
||||||
app.model_queue = q
|
|
||||||
asyncio.create_task(server_loop(q))
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن يمكنك تشغيله باستخدام:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
uvicorn server:app
|
|
||||||
```
|
|
||||||
|
|
||||||
ويمكنك الاستعلام عنه:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -X POST -d "test [MASK]" http://localhost:8000/
|
|
||||||
#[{"score":0.7742936015129089,"token":1012,"token_str":".","sequence":"test."},...]
|
|
||||||
```
|
|
||||||
|
|
||||||
وهكذا، لديك الآن فكرة جيدة عن كيفية إنشاء خادم ويب!
|
|
||||||
|
|
||||||
المهم حقًا هو أننا نقوم بتحميل النموذج **مرة واحدة** فقط، لذلك لا توجد نسخ من النموذج على خادم الويب. بهذه الطريقة، لا يتم استخدام ذاكرة الوصول العشوائي غير الضرورية. تسمح آلية وضع قائمة الانتظار بالقيام بأشياء متقدمة مثل تجميع بعض العناصر قبل الاستدلال لاستخدام معالجة الدفعات الديناميكية:
|
|
||||||
|
|
||||||
<Tip warning={true}>
|
|
||||||
|
|
||||||
تم كتابة نموذج الكود البرمجى أدناه بشكل مقصود مثل كود وهمي للقراءة. لا تقم بتشغيله دون التحقق مما إذا كان منطقيًا لموارد النظام الخاص بك!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
```py
|
|
||||||
(string, rq) = await q.get()
|
|
||||||
strings = []
|
|
||||||
queues = []
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
(string, rq) = await asyncio.wait_for(q.get(), timeout=0.001) # 1ms
|
|
||||||
except asyncio.exceptions.TimeoutError:
|
|
||||||
break
|
|
||||||
strings.append(string)
|
|
||||||
queues.append(rq)
|
|
||||||
strings
|
|
||||||
outs = pipe(strings, batch_size=len(strings))
|
|
||||||
for rq, out in zip(queues, outs):
|
|
||||||
await rq.put(out)
|
|
||||||
```
|
|
||||||
|
|
||||||
مرة أخرى، تم تحسين الرمز المقترح لسهولة القراءة، وليس ليكون أفضل كود. بادئ ذي بدء، لا يوجد حد لحجم الدفعة، والذي عادةً ما لا يكون فكرة عظيمة. بعد ذلك، يتم إعادة ضبط الفترة في كل عملية جلب لقائمة الانتظار، مما يعني أنه قد يتعين عليك الانتظار لفترة أطول بكثير من 1 مللي ثانية قبل تشغيل الاستدلال (تأخير الطلب الأول بهذا القدر).
|
|
||||||
|
|
||||||
سيكون من الأفضل تحديد مهلة واحدة مدتها 1 مللي ثانية.
|
|
||||||
|
|
||||||
سيظل هذا ينتظر دائمًا لمدة 1 مللي ثانية حتى إذا كانت قائمة الانتظار فارغًا، والذي قد لا يكون الأفضل نظرًا لأنك تريد على الأرجح البدء في إجراء الاستدلال إذا لم يكن هناك شيء في قائمة الانتظا. ولكن ربما يكون منطقيًا إذا كانت المعالجة الديناميكية للدفعات مهمة حقًا لحالة الاستخدام لديك. مرة أخرى، لا يوجد حل واحد هو الأفضل.
|
|
||||||
|
|
||||||
## بعض الأشياء التي قد ترغب في مراعاتها
|
|
||||||
|
|
||||||
### التحقق من الأخطاء
|
|
||||||
|
|
||||||
هناك الكثير مما قد يحدث بشكل خاطئ في عند اتاحة النموذج للجمهور: نفاد الذاكرة، أو نفاد المساحة، أو فشل تحميل النموذج، أو قد يكون الاستعلام خاطئًا، أو قد يكون الاستعلام صحيحًا ولكن لا يزال يفشل في التشغيل بسبب خطأ في إعداد النموذج، وما إلى ذلك.
|
|
||||||
|
|
||||||
بشكل عام، من الجيد أن يُخرِج الخادم الأخطاء للمستخدم، لذلك يُعدّ إضافة الكثير من عبارات `try..except` لعرض هذه الأخطاء فكرة
|
|
||||||
جيدة. لكن ضع في اعتبارك أنه قد يمثل أيضًا مخاطرة أمنية الكشف عن جميع تلك الأخطاء اعتمادًا على سياق الأمان لديك.
|
|
||||||
|
|
||||||
### قطع الدائرة (Circuit breaking)
|
|
||||||
|
|
||||||
عادةً ما تبدو خوادم الويب أفضل عندما تقوم بقطع الدائرة. وهذا يعني أنها ترجع أخطاء صحيحة عندما تكون مثقلة بشكل زائد بدلاً من الانتظار إلى أجل غير مسمى. قم بإرجاع خطأ 503 بدلاً من الانتظار لفترة طويلة جدًا أو 504 بعد فترة طويلة.
|
|
||||||
|
|
||||||
من السهل نسبيًا تنفيذ ذلك في الكود المقترح نظرًا لوجود قائمة انتظار واحد. إن النظر في حجم قائمة الانتظار هو طريقة أساسية لبدء إرجاع الأخطاء قبل فشل خادم الويب بسبب الحمل الزائد.
|
|
||||||
|
|
||||||
### حجب عمل خيط التنفيذ الرئيسي (Main thread)
|
|
||||||
|
|
||||||
حاليًا، لا تدعم PyTorch العمليات غير المتزامنة، وسيؤدي الحساب إلى حجب عمل الخيط الرئيسي أثناء تشغيله. وهذا يعني أنه سيكون من الأفضل إذا تم إجبار PyTorch على أن تعمل على الخيط/العملية الخاصة به. لم يتم ذلك هنا لأن الكود أكثر تعقيدًا (في الغالب لأن خيوط التنفيذ والعمليات غير المتزامنة وقوائم الانتظار لا تتوافق معًا). ولكن في النهاية، فإنه سيؤدي نفس الوظيفة.
|
|
||||||
|
|
||||||
سيكون هذا مهمًا إذا كان الاستدلال للعناصر الفردية طويلاً (> 1 ثانية) لأنه في هذه الحالة، فهذا يعني أنه سيتعين أثناء الاستدلال على كل استعلام الانتظار لمدة ثانية واحدة قبل حتى يلقي خطأ.
|
|
||||||
|
|
||||||
### المعالجة الديناميكية
|
|
||||||
|
|
||||||
بشكل عام، لا تُعدّ المعالجة بالضرورة تحسينًا مقارنةً بتمرير عنصر واحد في كل مرة (راجع [تفاصيل المعالجة بالدفعات](./main_classes/pipelines#pipeline-batching) لمزيد من المعلومات). ولكن يمكن أن تكون فعالة للغاية عند استخدامها بالإعداد الصحيح. في واجهة برمجة التطبيقات، لا توجد معالجة ديناميكية بشكل افتراضي (فرصة كبيرة جدًا للتباطؤ). ولكن بالنسبة لاستدلال BLOOM - وهو نموذج كبير جدًا - تُعدّ المعالجة الديناميكية **ضرورية** لتوفير تجربة جيدة للجميع.
|
|
||||||
@ -347,8 +347,8 @@ tensor([[0.0021, 0.0018, 0.0115, 0.2121, 0.7725],
|
|||||||
```py
|
```py
|
||||||
>>> from transformers import AutoModel
|
>>> from transformers import AutoModel
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained(pt_save_directory)
|
>>> tokenizer = AutoTokenizer.from_pretrained(tf_save_directory)
|
||||||
>>> pt_model = AutoModelForSequenceClassification.from_pretrained(pt_save_directory, from_pt=True)
|
>>> pt_model = AutoModelForSequenceClassification.from_pretrained(tf_save_directory, from_tf=True)
|
||||||
```
|
```
|
||||||
</pt>
|
</pt>
|
||||||
<tf>
|
<tf>
|
||||||
@ -356,8 +356,8 @@ tensor([[0.0021, 0.0018, 0.0115, 0.2121, 0.7725],
|
|||||||
```py
|
```py
|
||||||
>>> from transformers import TFAutoModel
|
>>> from transformers import TFAutoModel
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained(tf_save_directory)
|
>>> tokenizer = AutoTokenizer.from_pretrained(pt_save_directory)
|
||||||
>>> tf_model = TFAutoModelForSequenceClassification.from_pretrained(tf_save_directory, from_tf=True)
|
>>> tf_model = TFAutoModelForSequenceClassification.from_pretrained(pt_save_directory, from_pt=True)
|
||||||
```
|
```
|
||||||
</tf>
|
</tf>
|
||||||
</frameworkcontent>
|
</frameworkcontent>
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
# تشغيل التدريب على Amazon SageMaker
|
|
||||||
|
|
||||||
تم نقل التوثيق إلى [hf.co/docs/sagemaker](https://huggingface.co/docs/sagemaker). وسيتم إزالة هذه الصفحة في الإصدار 5.0 من برنامج Transformers.
|
|
||||||
|
|
||||||
### جدول المحتويات
|
|
||||||
|
|
||||||
- [تدريب نماذج Hugging Face على Amazon SageMaker باستخدام SageMaker Python SDK](https://huggingface.co/docs/sagemaker/train)
|
|
||||||
- [نشر نماذج Hugging Face على Amazon SageMaker باستخدام SageMaker Python SDK](https://huggingface.co/docs/sagemaker/inference)
|
|
||||||
@ -1,170 +0,0 @@
|
|||||||
# التصدير إلى ONNX
|
|
||||||
|
|
||||||
غالباً ما يتطلب نشر نماذج 🤗 Transformers في بيئات الإنتاج أو يمكن أن يستفيد من تصدير النماذج إلى تنسيق تسلسلي يُمكن تحميله وتنفيذه على أجهزة وبرامج تشغيل مُتخصصة.
|
|
||||||
|
|
||||||
🤗 Optimum هو امتداد لـ Transformers يمكّن من تصدير النماذج من PyTorch أو TensorFlow إلى تنسيقات مُتسلسلة مثل ONNX و TFLite من خلال وحدة `exporters` الخاصة به. يوفر 🤗 Optimum أيضًا مجموعة من أدوات تحسين الأداء لتدريب النماذج وتشغيلها على أجهزة مستهدفة بكفاءة قصوى.
|
|
||||||
|
|
||||||
يوضح هذا الدليل كيفية تصدير نماذج 🤗 Transformers إلى ONNX باستخدام 🤗 Optimum، وللحصول على الدليل الخاص بتصدير النماذج إلى TFLite، يُرجى الرجوع إلى صفحة [التصدير إلى TFLite](tflite).
|
|
||||||
|
|
||||||
## التصدير إلى ONNX
|
|
||||||
|
|
||||||
مجمد [ONNX (Open Neural Network Exchange)](http://onnx.ai) هو معيار مفتوح يُحدد مجموعة مشتركة من العوامل وتنسيق ملف مشترك لتمثيل نماذج التعلم العميق في مجموعة متنوعة واسعة من الأطر، بما في ذلك PyTorch وTensorFlow. عندما يتم تصدير نموذج إلى تنسيق ONNX، يتم استخدام هذه المشغلات لبناء رسم بياني حاسوبي (يُطلق عليه غالبًا اسم _تمثيل وسيط_) والذي يمثل تدفق البيانات عبر الشبكة العصبية.
|
|
||||||
|
|
||||||
من خلال عرض رسم بياني بعوامل وأنواع بيانات معيارية، يُسهّل ONNX التبديل بين الأطر. على سبيل المثال، يُمكن تصدير نموذج مدرب في PyTorch إلى تنسيق ONNX ثم استيراده في TensorFlow (والعكس صحيح).
|
|
||||||
|
|
||||||
بمجرد التصدير إلى تنسيق ONNX، يُمكن:
|
|
||||||
|
|
||||||
- تحسين النموذج للاستدلال عبر تقنيات مثل [تحسين الرسم البياني](https://huggingface.co/docs/optimum/onnxruntime/usage_guides/optimization) و [التكميم](https://huggingface.co/docs/optimum/onnxruntime/usage_guides/quantization).
|
|
||||||
- تشغيله باستخدام ONNX Runtime عبر فئات [`ORTModelForXXX`](https://huggingface.co/docs/optimum/onnxruntime/package_reference/modeling_ort)، والتي تتبع نفس واجهة برمجة التطبيقات (API) لـ `AutoModel` التي اعتدت عليها في 🤗 Transformers.
|
|
||||||
- تشغيله باستخدام [قنوات معالجة الاستدلال مُحسّنة](https://huggingface.co/docs/optimum/main/en/onnxruntime/usage_guides/pipelines)، والتي لها نفس واجهة برمجة التطبيقات (API) مثل وظيفة [`pipeline`] في 🤗 Transformers.
|
|
||||||
|
|
||||||
يوفر 🤗 Optimum دعمًا لتصدير ONNX من خلال الاستفادة من كائنات التكوين. تأتي كائنات التكوين هذه جاهزة لعدد من معماريات النماذج، وقد تم تصميمها لتكون قابلة للتوسعة بسهولة إلى معماريات أخرى.
|
|
||||||
|
|
||||||
للاطلاع على قائمة بالتكوينات الجاهزة، يُرجى الرجوع إلى [وثائق 🤗 Optimum](https://huggingface.co/docs/optimum/exporters/onnx/overview).
|
|
||||||
|
|
||||||
هناك طريقتان لتصدير نموذج 🤗 Transformers إلى ONNX، نعرض هنا كليهما:
|
|
||||||
|
|
||||||
- التصدير باستخدام 🤗 Optimum عبر واجهة سطر الأوامر (CLI).
|
|
||||||
- التصدير باستخدام 🤗 Optimum مع `optimum.onnxruntime`.
|
|
||||||
|
|
||||||
### تصدير نموذج 🤗 Transformers إلى ONNX باستخدام واجهة سطر الأوامر
|
|
||||||
|
|
||||||
لتصدير نموذج 🤗 Transformers إلى ONNX، قم أولاً بتثبيت اعتماد إضافي:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install optimum[exporters]
|
|
||||||
```
|
|
||||||
|
|
||||||
للاطلاع على جميع المعامﻻت المتاحة، يرجى الرجوع إلى [وثائق 🤗 Optimum](https://huggingface.co/docs/optimum/exporters/onnx/usage_guides/export_a_model#exporting-a-model-to-onnx-using-the-cli)، أو عرض المساعدة في سطر الأوامر:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
optimum-cli export onnx --help
|
|
||||||
```
|
|
||||||
```bash
|
|
||||||
optimum-cli export onnx --help
|
|
||||||
```
|
|
||||||
|
|
||||||
لتصدير نقطة تفتيش نموذج من 🤗 Hub، على سبيل المثال، `distilbert/distilbert-base-uncased-distilled-squad`، قم بتشغيل الأمر التالي:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
optimum-cli export onnx --model distilbert/distilbert-base-uncased-distilled-squad distilbert_base_uncased_squad_onnx/
|
|
||||||
```
|
|
||||||
|
|
||||||
يجب أن تشاهد السجلات التي تشير إلى التقدم المحرز وتظهر المكان الذي تم فيه حفظ ملف `model.onnx` الناتج، مثل هذا:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
Validating ONNX model distilbert_base_uncased_squad_onnx/model.onnx...
|
|
||||||
-[✓] ONNX model output names match reference model (start_logits, end_logits)
|
|
||||||
- Validating ONNX Model output "start_logits":
|
|
||||||
-[✓] (2, 16) matches (2, 16)
|
|
||||||
-[✓] all values close (atol: 0.0001)
|
|
||||||
- Validating ONNX Model output "end_logits":
|
|
||||||
-[✓] (2, 16) matches (2, 16)
|
|
||||||
-[✓] all values close (atol: 0.0001)
|
|
||||||
The ONNX export succeeded and the exported model was saved at: distilbert_base_uncased_squad_onnx
|
|
||||||
```
|
|
||||||
|
|
||||||
يوضح المثال أعلاه تصدير نقطة تفتيش من 🤗 Hub. عند تصدير نموذج محلي، تأكد أولاً من حفظ ملفات أوزان النموذج ومحول الرموز في نفس الدليل (`local_path`). عند استخدام واجهة سطر الأوامر، قم بتمرير `local_path` إلى وسيط `model` بدلاً من اسم نقطة التفتيش على 🤗 Hub وقدم وسيط `--task`. يمكنك مراجعة قائمة المهام المدعومة في [وثائق 🤗 Optimum](https://huggingface.co/docs/optimum/exporters/task_manager). إذا لم يتم توفير وسيط `task`، فسيتم تعيينه افتراضيًا إلى هندسة النموذج دون أي رأس محدد للمهمة.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
optimum-cli export onnx --model local_path --task question-answering distilbert_base_uncased_squad_onnx/
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن بعد ذلك تشغيل ملف `model.onnx` الناتج على أحد [المسرعات](https://onnx.ai/supported-tools.html#deployModel) العديدة التي تدعم معيار ONNX. على سبيل المثال، يمكننا تحميل النموذج وتشغيله باستخدام [ONNX Runtime](https://onnxruntime.ai/) كما يلي:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
>>> from optimum.onnxruntime import ORTModelForQuestionAnswering
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert_base_uncased_squad_onnx")
|
|
||||||
>>> model = ORTModelForQuestionAnswering.from_pretrained("distilbert_base_uncased_squad_onnx")
|
|
||||||
>>> inputs = tokenizer("What am I using?", "Using DistilBERT with ONNX Runtime!", return_tensors="pt")
|
|
||||||
>>> outputs = model(**inputs)
|
|
||||||
```
|
|
||||||
|
|
||||||
تكون العملية مماثلة بالنسبة إلى نقاط تفتيش TensorFlow على Hub. على سبيل المثال، إليك كيفية تصدير نقطة تفتيش TensorFlow نقية من [منظمة Keras](https://huggingface.co/keras-io):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
optimum-cli export onnx --model keras-io/transformers-qa distilbert_base_cased_squad_onnx/
|
|
||||||
```
|
|
||||||
|
|
||||||
### تصدير نموذج 🤗 Transformers إلى ONNX باستخدام `optimum.onnxruntime`
|
|
||||||
|
|
||||||
كبديل لواجهة سطر الأوامر، يُمكنك تصدير نموذج 🤗 Transformers إلى ONNX برمجيًا كما يلي:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from optimum.onnxruntime import ORTModelForSequenceClassification
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> model_checkpoint = "distilbert_base_uncased_squad"
|
|
||||||
>>> save_directory = "onnx/"
|
|
||||||
|
|
||||||
>>> # تحميل نموذج من transformers وتصديره إلى ONNX
|
|
||||||
>>> ort_model = ORTModelForSequenceClassification.from_pretrained(model_checkpoint, export=True)
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
|
|
||||||
|
|
||||||
>>> # حفظ نموذج onnx ومجزىء النصوص
|
|
||||||
>>> ort_model.save_pretrained(save_directory)
|
|
||||||
>>> tokenizer.save_pretrained(save_directory)
|
|
||||||
```
|
|
||||||
|
|
||||||
### تصدير نموذج لهندسة غير مدعومة
|
|
||||||
|
|
||||||
إذا كنت ترغب في المساهمة من خلال إضافة دعم لنموذج لا يُمكن تصديره حاليًا، فيجب عليك أولاً التحقق مما إذا كان مدعومًا في [`optimum.exporters.onnx`](https://huggingface.co/docs/optimum/exporters/onnx/overview)، وإذا لم يكن مدعومًا، [فيمكنك المساهمة في 🤗 Optimum](https://huggingface.co/docs/optimum/exporters/onnx/usage_guides/contribute) مُباشرةً.
|
|
||||||
|
|
||||||
### تصدير نموذج باستخدام `transformers.onnx`
|
|
||||||
|
|
||||||
<Tip warning={true}>
|
|
||||||
|
|
||||||
لم يعد يتم دعم `tranformers.onnx` يُرجى تصدير النماذج باستخدام 🤗 Optimum كما هو موضح أعلاه. سيتم إزالة هذا القسم في الإصدارات القادمة.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
لتصدير نموذج 🤗 Transformers إلى ONNX باستخدام `tranformers.onnx`، ثبّت التبعيات الإضافية:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers[onnx]
|
|
||||||
```
|
|
||||||
|
|
||||||
استخدم حزمة `transformers.onnx` كنموذج Python لتصدير نقطة حفظ باستخدام تكوين جاهز:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python -m transformers.onnx --model=distilbert/distilbert-base-uncased onnx/
|
|
||||||
```
|
|
||||||
|
|
||||||
يُصدّر هذا رسمًا بيانيًا ONNX لنقطة الحفظ المُحددة بواسطة وسيطة `--model`. مرر أي نقطة حفظ على 🤗 Hub أو نقطة حفظ مُخزنة محليًا.
|
|
||||||
يُمكن بعد ذلك تشغيل ملف `model.onnx` الناتج على أحد المُسرعات العديدة التي تدعم معيار ONNX. على سبيل المثال، قم بتحميل وتشغيل النموذج باستخدام ONNX Runtime كما يلي:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
>>> from onnxruntime import InferenceSession
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
>>> session = InferenceSession("onnx/model.onnx")
|
|
||||||
>>> # يتوقع ONNX Runtime مصفوفات NumPy كمدخلات
|
|
||||||
>>> inputs = tokenizer("Using DistilBERT with ONNX Runtime!", return_tensors="np")
|
|
||||||
>>> outputs = session.run(output_names=["last_hidden_state"], input_feed=dict(inputs))
|
|
||||||
```
|
|
||||||
|
|
||||||
يُمكن الحصول على أسماء المخرجات المطلوبة (مثل `["last_hidden_state"]`) من خلال إلقاء نظرة على تكوين ONNX لكل نموذج. على سبيل المثال، بالنسبة لـ DistilBERT، لدينا:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers.models.distilbert import DistilBertConfig, DistilBertOnnxConfig
|
|
||||||
|
|
||||||
>>> config = DistilBertConfig()
|
|
||||||
>>> onnx_config = DistilBertOnnxConfig(config)
|
|
||||||
>>> print(list(onnx_config.outputs.keys()))
|
|
||||||
["last_hidden_state"]
|
|
||||||
```
|
|
||||||
|
|
||||||
العمليات مُتطابقة لنقاط الحفظ TensorFlow على Hub. على سبيل المثال، صدّر نقطة حفظ TensorFlow خالصة كما يلي:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python -m transformers.onnx --model=keras-io/transformers-qa onnx/
|
|
||||||
```
|
|
||||||
|
|
||||||
لتصدير نموذج مُخزن محليًا، احفظ أوزان النموذج ومجزىء اللغوى في نفس الدليل (على سبيل المثال `local-pt-checkpoint`)، ثم قم بتصديره إلى ONNX عن طريق توجيه وسيط `--model` لحزمة `transformers.onnx` إلى الدليل المطلوب:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python -m transformers.onnx --model=local-pt-checkpoint onnx/
|
|
||||||
```
|
|
||||||
@ -1,323 +0,0 @@
|
|||||||
# ما الذي تستطيع مكتبة 🤗 Transformers القيام به؟
|
|
||||||
|
|
||||||
مكتبة 🤗 Transformers هي مجموعة من النماذج المُدرّبة مسبقًا الأفضل في فئتها لمهام معالجة اللغة الطبيعية (NLP)، ورؤية الحاسوب، ومعالجة الصوت والكلام. لا تحتوي المكتبة فقط على نماذج المحولات (Transformer) فحسب، بل تشمل أيضًا نماذج أخرى لا تعتمد على المحولات مثل الشبكات العصبية التلافيفية الحديثة لمهام رؤية الحاسوب. إذا نظرت إلى بعض المنتجات الاستهلاكية الأكثر شيوعًا اليوم، مثل الهواتف الذكية والتطبيقات وأجهزة التلفاز، فمن المحتمل أن تقف وراءها تقنية ما من تقنيات التعلم العميق. هل تريد إزالة جسم من خلفية صورة التقطتها بهاتفك الذكي؟ هذا مثال على مهمة التجزئة البانورامية (Panoptic Segmentation) ( لا تقلق إذا لم تفهم معناها بعد، فسوف نشرحها في الأقسام التالية!).
|
|
||||||
|
|
||||||
توفر هذه الصفحة نظرة عامة على مختلف مهام الكلام والصوت ورؤية الحاسوب ومعالجة اللغات الطبيعية المختلفة التي يمكن حلها باستخدام مكتبة 🤗 Transformers في ثلاثة أسطر فقط من التعليمات البرمجية!
|
|
||||||
|
|
||||||
## الصوت
|
|
||||||
|
|
||||||
تختلف مهام معالجة الصوت والكلام قليلاً عن باقي الوسائط، ويرجع ذلك ببشكل أساسي لأن الصوت كمدخل هو إشارة متصلة. على عكس النص، لا يمكن تقسيم الموجة الصوتية الخام بشكل مرتب في أجزاء منفصلة بالطريقة التي يمكن بها تقسيم الجملة إلى كلمات. وللتغلب على هذا، يتم عادةً أخذ عينات من الإشارة الصوتية الخام على فترات زمنية منتظمة. كلما زاد عدد العينات التي تؤخذ في فترة زمنية معينة، ارتفع معدل أخذ العينات (معدل التردد)، وصار الصوت أقرب إلى مصدر الصوت الأصلي.
|
|
||||||
|
|
||||||
قامت الطرق السابقة بمعالجة الصوت لاستخراج الميزات المفيدة منه. أصبح من الشائع الآن البدء بمهام معالجة الصوت والكلام عن طريق تغذية شكل الموجة الصوتية الخام مباشرة في مشفر الميزات (Feature Encoder) لاستخراج تمثيل صوتي له. وهذا يبسط خطوة المعالجة المسبقة ويسمح للنموذج بتعلم أهم الميزات.
|
|
||||||
|
|
||||||
### تصنيف الصوت
|
|
||||||
|
|
||||||
تصنيف الصوت (Audio Classification) هو مهمة يتم فيها تصنيف بيانات الصوت الصوت من مجموعة محددة مسبقًا من الفئات. إنه فئة واسعة تضم العديد من التطبيقات المحددة، والتي تشمل:
|
|
||||||
|
|
||||||
* تصنيف المشهد الصوتي: وضع علامة على الصوت باستخدام تسمية المشهد ("المكتب"، "الشاطئ"، "الملعب")
|
|
||||||
* اكتشاف الأحداث الصوتية: وضع علامة على الصوت باستخدام تسمية حدث صوتي ("بوق السيارة"، "صوت الحوت"، "كسر زجاج")
|
|
||||||
* الوسم: وصنيف صوت يحتوي على أصوات متعددة (أصوات الطيور، وتحديد هوية المتحدث في اجتماع)
|
|
||||||
* تصنيف الموسيقى: وضع علامة على الموسيقى بتسمية النوع ("ميتال"، "هيب هوب"، "كانتري")
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> classifier = pipeline(task="audio-classification", model="superb/hubert-base-superb-er")
|
|
||||||
>>> preds = classifier("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")
|
|
||||||
>>> preds = [{"score": round(pred["score"], 4), "label": pred["label"]} for pred in preds]
|
|
||||||
>>> preds
|
|
||||||
[{'score': 0.4532, 'label': 'hap'},
|
|
||||||
{'score': 0.3622, 'label': 'sad'},
|
|
||||||
{'score': 0.0943, 'label': 'neu'},
|
|
||||||
{'score': 0.0903, 'label': 'ang'}]
|
|
||||||
```
|
|
||||||
|
|
||||||
### التعرف التلقائي على الكلام
|
|
||||||
|
|
||||||
يقوم التعرف التلقائي على الكلام (ASR) هو عملية تحويل الكلام إلى نص. إنه أحد أكثر المهام الصوتية شيوعًا ويرجع ذلك جزئيًا إلى أن الكلام وسيلة طبيعية للتواصل البشري. واليوم، يتم تضمين أنظمة ASR في منتجات التقنية "الذكية" مثل مكبرات الصوت والهواتف والسيارات. يمكننا أن نطلب من مساعدينا الافتراضيين تشغيل الموسيقى، وضبط التذكيرات، وإخبارنا بأحوال الطقس.
|
|
||||||
ولكن أحد التحديات الرئيسية التي ساعدت نماذج المحولات (Transformer) في التغلب عليها هو التعامل مع اللغات منخفضة الموارد. فمن خلال التدريب المسبق على كميات كبيرة من بيانات الصوتية، يُمكن ضبط النموذج بدقة (Fine-tuning) باستخدام ساعة واحدة فقط من بيانات الكلام المُوسم في لغة منخفضة الموارد إلى نتائج عالية الجودة مقارنة بأنظمة ASR السابقة التي تم تدريبها على بيانات موسومة أكثر بـ 100 مرة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> transcriber = pipeline(task="automatic-speech-recognition", model="openai/whisper-small")
|
|
||||||
>>> transcriber("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac")
|
|
||||||
{'text': ' I have a dream that one day this nation will rise up and live out the true meaning of its creed.'}
|
|
||||||
```
|
|
||||||
|
|
||||||
## رؤية الحاسب
|
|
||||||
|
|
||||||
كانت إحدى أوائل مهام رؤية الحاسب وأنجحها هى التعرف على صور أرقام الرموز البريدية باستخدام [شبكة عصبية تلافيفية (CNN)](glossary#convolution). تتكون الصورة من وحدات بيكسل، ولكل بكسل قيمة رقمية. وهذا يجعل من السهل تمثيل صورة كمصفوفة من قيم البكسل. يصف كل مزيج معين من قيم البكسل ألوان الصورة.
|
|
||||||
|
|
||||||
هناك طريقتان عامتان يمكن من خلالهما حل مهام رؤية الحاسب:
|
|
||||||
|
|
||||||
1. استخدام الالتفافات (Convolutions) لتعلم الميزات الهرمية للصورة بدءًا من الميزات منخفضة المستوى وصولًا إلى الأشياء المجردة عالية المستوى.
|
|
||||||
2. تقسيم الصورة إلى أجزاء واستخدام نموذج المحولات (Transformer) ليتعلم تدريجياً كيف ترتبط كل جزء صورة ببعضها البعض لتشكيل صورة. على عكس النهج ا التصاعدي (Bottom-Up) الذي تفضله الشبكات العصبية التلافيفية CNN، هذا يشبه إلى حد ما البدء بصورة ضبابية ثم جعلها أوضح تدريجيًا.
|
|
||||||
|
|
||||||
### تصنيف الصور
|
|
||||||
|
|
||||||
يقوم تصنيف الصور (Image Classification) بوضع علامة على صورة كاملة من مجموعة محددة مسبقًا من الفئات. مثل معظم مهام التصنيف، هناك العديد من التطبيقات العملية لتصنيف الصور، والتي تشمل:
|
|
||||||
|
|
||||||
* الرعاية الصحية: تصنيف الصور الطبية للكشف عن الأمراض أو مراقبة صحة المريض
|
|
||||||
* البيئة: تصنيف صور الأقمار الصناعية لرصد إزالة الغابات، أو إبلاغ إدارة الأراضي البرية أو اكتشاف حرائق الغابات
|
|
||||||
* الزراعة: تصنيفر المحاصيل لمراقبة صحة النبات أو صور الأقمار الصناعية لمراقبة استخدام الأراضي
|
|
||||||
* علم البيئة: تصنيف صور الأنواع الحيوانية أو النباتية لرصد أعداد الكائنات الحية أو تتبع الأنواع المهددة بالانقراض
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> classifier = pipeline(task="image-classification")
|
|
||||||
>>> preds = classifier(
|
|
||||||
... "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
|
|
||||||
... )
|
|
||||||
>>> preds = [{"score": round(pred["score"], 4), "label": pred["label"]} for pred in preds]
|
|
||||||
>>> print(*preds, sep="\n")
|
|
||||||
{'score': 0.4335, 'label': 'lynx, catamount'}
|
|
||||||
{'score': 0.0348, 'label': 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor'}
|
|
||||||
{'score': 0.0324, 'label': 'snow leopard, ounce, Panthera uncia'}
|
|
||||||
{'score': 0.0239, 'label': 'Egyptian cat'}
|
|
||||||
{'score': 0.0229, 'label': 'tiger cat'}
|
|
||||||
```
|
|
||||||
|
|
||||||
### كشف الأجسام
|
|
||||||
|
|
||||||
على عكس تصنيف الصور، يقوم كشف الأجسام (Object Detection) بتحديد عدة أجسام داخل صورة ومواضع هذه الأجسام في صورة (يحددها مربع الإحاطة). بعض تطبيقات كشف الأجسام تشمل:
|
|
||||||
|
|
||||||
* المركبات ذاتية القيادة: اكتشاف أجسام المرورية اليومية مثل المركبات الأخرى والمشاة وإشارات المرور
|
|
||||||
* الاستشعار عن بُعد: مراقبة الكوارث، والتخطيط الحضري، والتنبؤ بالطقس
|
|
||||||
* اكتشاف العيوب: اكتشاف الشقوق أو الأضرار الهيكلية في المباني، وعيوب التصنيع
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> detector = pipeline(task="object-detection")
|
|
||||||
>>> preds = detector(
|
|
||||||
... "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
|
|
||||||
... )
|
|
||||||
>>> preds = [{"score": round(pred["score"], 4), "label": pred["label"], "box": pred["box"]} for pred in preds]
|
|
||||||
>>> preds
|
|
||||||
[{'score': 0.9865,
|
|
||||||
'label': 'cat',
|
|
||||||
'box': {'xmin': 178, 'ymin': 154, 'xmax': 882, 'ymax': 598}}]
|
|
||||||
```
|
|
||||||
|
|
||||||
### تجزئة الصور
|
|
||||||
|
|
||||||
تجزئة الصورة (Image Segmentation) هي مهمة على مستوى البكسل تقوم بتخصيص كل بكسل في صورة لفئة معينة. إنه يختلف عن كشف الأجسام، والذي يستخدم مربعات الإحاطة (Bounding Boxes) لتصنيف والتنبؤ بالأجسام في الصورة لأن التجزئة أكثر دقة. يمكن لتجزئة الصور اكتشاف الأجسام على مستوى البكسل. هناك عدة أنواع من تجزئة الصور:
|
|
||||||
|
|
||||||
* تجزئة مثيلات (Instance Segmentation): بالإضافة إلى تصنيف فئة كائن، فإنها تُصنّف أيضًا كل مثيل (Instance) مميز لكائن ("الكلب-1"، "الكلب-2")
|
|
||||||
* التجزئة البانورامية (Panoptic Segmentation): مزيج من التجزئة الدلالية (Semantic Segmentation) وتجزئة المثيلات؛ فهو تُصنّف كل بكسل مع فئة دلالية **و** كل مثيل مميز لكائن
|
|
||||||
|
|
||||||
تُعد مهام تجزئة الصور مفيدة في المركبات ذاتية القيادة على إنشاء خريطة على مستوى البكسل للعالم من حولها حتى تتمكن من التنقل بأمان حول المشاة والمركبات الأخرى. كما أنها مفيدة للتصوير الطبي، حيث يمكن للدقة العالية لهذ المهمة أن تساعد في تحديد الخلايا غير الطبيعية أو خصائص الأعضاء. يمكن أيضًا استخدام تجزئة الصور في التجارة الإلكترونية لتجربة الملابس افتراضيًا أو إنشاء تجارب الواقع المُعزز من خلال تراكب الأجسام في العالم الحقيقي من خلال الكاميرا الهاتف الخاصة بك.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> segmenter = pipeline(task="image-segmentation")
|
|
||||||
>>> preds = segmenter(
|
|
||||||
... "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
|
|
||||||
... )
|
|
||||||
>>> preds = [{"score": round(pred["score"], 4), "label": pred["label"]} for pred in preds]
|
|
||||||
>>> print(*preds, sep="\n")
|
|
||||||
{'score': 0.9879, 'label': 'LABEL_184'}
|
|
||||||
{'score': 0.9973, 'label': 'snow'}
|
|
||||||
{'score': 0.9972, 'label': 'cat'}
|
|
||||||
```
|
|
||||||
|
|
||||||
### تقدير العمق
|
|
||||||
|
|
||||||
يقوم تقدير العمق (Depth Estimation) بالتنبؤ بمسافة كل بكسل في صورة من الكاميرا. تُعد هذه المهمة لرؤية الحاسب هذه مهمة بشكل خاص لفهم وإعادة بناء المشهد. فعلى سبيل المثال، في السيارات ذاتية القيادة، تحتاج المركبات إلى فهم مدى بُعد الأجسام مثل المشاة ولافتات المرور والمركبات الأخرى لتجنب العقبات والاصطدامات. تساعد معلومات العمق أيضًا في بناء التمثيلات ثلاثية الأبعاد من الصور ثنائية الأبعاد ويمكن استخدامها لإنشاء تمثيلات ثلاثية الأبعاد عالية الجودة للهياكل البيولوجية أو المباني.
|
|
||||||
|
|
||||||
هناك نهجان لتقدير العمق:
|
|
||||||
|
|
||||||
* التصوير المجسم (Stereo): يتم تقدير العمق عن طريق مقارنة صورتين لنفس الصورة من زوايا مختلفة قليلاً.
|
|
||||||
* التصوير الأحادي (Monocular): يتم تقدير العمق من صورة واحدة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> depth_estimator = pipeline(task="depth-estimation")
|
|
||||||
>>> preds = depth_estimator(
|
|
||||||
... "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
## معالجة اللغات الطبيعية
|
|
||||||
|
|
||||||
تُعد مهام معالجة اللغة الطبيعية (NLP) من بين أكثر أنواع المهام شيوعًا نظرًا لأن النص هو وسيلة طبيعية لنا للتواصل. ولكي يتمكن النموذج من فهم النص، يجب أولًا تحويله إلى صيغة رقمية. وهذا يعني تقسيم سلسلة النص إلى كلمات أو مقاطع كلمات منفصلة (رموز - Tokens)، ثم تحويل هذه الرموز إلى أرقام. ونتيجة لذلك، يمكنك تمثيل سلسلة من النص كتسلسل من الأرقام، وبمجرد حصولك على تسلسل من الأرقام، يمكن إدخاله إلى نموذج لحل جميع أنواع مهام معالجة اللغة الطبيعية!
|
|
||||||
|
|
||||||
### تصنيف النصوص
|
|
||||||
|
|
||||||
تمامًا مثل مهام التصنيف في أي مجال آخر، يقوم تصنيف النصوص (Text Classification) بتصنيف سلسلة نصية يمكن أن تكون جملة أو فقرة أو مستند) إلى فئة محددة مسبقًا. هناك العديد من التطبيقات العملية لتصنيف النصوص، والتي تشمل:
|
|
||||||
|
|
||||||
* تحليل المشاعر (Sentiment Analysis): تصنيف النص وفقًا لمعيار معين مثل `الإيجابية` أو `السلبية` والتي يمكن أن تُعلم وتدعم عملية صنع القرار في مجالات مثل السياسة والتمويل والتسويق
|
|
||||||
* تصنيف المحتوى (Content Classification): تصنيف النص وفقًا لبعض الموضوعات للمساعدة في تنظيم وتصفية المعلومات في الأخبار وموجزات الوسائط الاجتماعية (`الطقس`، `الرياضة`، `التمويل`، إلخ).
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> classifier = pipeline(task="sentiment-analysis")
|
|
||||||
>>> preds = classifier("Hugging Face is the best thing since sliced bread!")
|
|
||||||
>>> preds = [{"score": round(pred["score"], 4), "label": pred["label"]} for pred in preds]
|
|
||||||
>>> preds
|
|
||||||
[{'score': 0.9991, 'label': 'POSITIVE'}]
|
|
||||||
```
|
|
||||||
|
|
||||||
### تصنيف الرموز
|
|
||||||
|
|
||||||
في أي مهمة من مهام معالجة اللغة الطبيعية NLP، تتم معالجة النص مسبقًا عن طريق تقسيمه إلى كلمات أو مقاطع كلمات فردية تُعرف باسم [الرموز](glossary#token). يقوم تصنيف الرموز (Token Classification) بتخصيص تصنيف لكل رمز من مجموعة محددة مسبقًا من التصنيفات.
|
|
||||||
|
|
||||||
هناك نوعان شائعان من تصنيف الرموز:
|
|
||||||
|
|
||||||
* التعرف على الكيانات المسماة (NER): تصنيف الرموز وفقًا لفئة الكيان مثل المنظمة أو الشخص أو الموقع أو التاريخ. يعد NER شائعًا بشكل خاص في الإعدادات الطبية الحيوية، حيث يُمكنه تصنيف الجينات والبروتينات وأسماء الأدوية.
|
|
||||||
* ترميز الأجزاء اللغوية (POS): تصنيف الرموز وفقًا للدورها النحوي مثل الاسم أو الفعل أو الصفة. POS مفيد لمساعدة أنظمة الترجمة على فهم كيفية اختلاف كلمتين متطابقتين نحويًا (مثل كلمة "عَلَمَ" كاسم و "عَلِمَ" كفعل).
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> classifier = pipeline(task="ner")
|
|
||||||
>>> preds = classifier("Hugging Face is a French company based in New York City.")
|
|
||||||
>>> preds = [
|
|
||||||
... {
|
|
||||||
... "entity": pred["entity"],
|
|
||||||
... "score": round(pred["score"], 4),
|
|
||||||
... "index": pred["index"],
|
|
||||||
... "word": pred["word"],
|
|
||||||
... "start": pred["start"],
|
|
||||||
... "end": pred["end"],
|
|
||||||
... }
|
|
||||||
... for pred in preds
|
|
||||||
... ]
|
|
||||||
>>> print(*preds, sep="\n")
|
|
||||||
{'entity': 'I-ORG', 'score': 0.9968, 'index': 1, 'word': 'Hu', 'start': 0, 'end': 2}
|
|
||||||
{'entity': 'I-ORG', 'score': 0.9293, 'index': 2, 'word': '##gging', 'start': 2, 'end': 7}
|
|
||||||
{'entity': 'I-ORG', 'score': 0.9763, 'index': 3, 'word': 'Face', 'start': 8, 'end': 12}
|
|
||||||
{'entity': 'I-MISC', 'score': 0.9983, 'index': 6, 'word': 'French', 'start': 18, 'end': 24}
|
|
||||||
{'entity': 'I-LOC', 'score': 0.999, 'index': 10, 'word': 'New', 'start': 42, 'end': 45}
|
|
||||||
{'entity': 'I-LOC', 'score': 0.9987, 'index': 11, 'word': 'York', 'start': 46, 'end': 50}
|
|
||||||
{'entity': 'I-LOC', 'score': 0.9992, 'index': 12, 'word': 'City', 'start': 51, 'end': 55}
|
|
||||||
```
|
|
||||||
### الإجابة على الأسئلة
|
|
||||||
|
|
||||||
تُعدّ مهمة الإجابة عن الأسئلة (Question Answering) مهمة أخرى على مستوى الرموز (Token-Level) تُرجع إجابة لسؤال ما، وقد تعتمد هذه الإجابة على سياق (في النطاق المفتوح - Open-Domain) أو لا تعتمد على سياق (في النطاق المغلق - Closed-Domain). تحدث هذه المهمة عندما نسأل مساعدًا افتراضيًا عن شيء ما، مثل معرفة ما إذا كان مطعمٌ ما مفتوحًا. يمكن أن تُقدّم هذه المهمة أيضًا دعمًا للعملاء أو دعمًا تقنيًا، كما تُساعد محركات البحث في استرجاع المعلومات ذات الصلة التي نبحث عنها.
|
|
||||||
|
|
||||||
هناك نوعان شائعان من الإجابة على الأسئلة:
|
|
||||||
|
|
||||||
* الاستخراجية (Extractive): بالنظر إلى سؤال وسياق مُعيّن، فإن الإجابة هي مقطع نصيّ مُستخرج من السياق الذي يُحلّله النموذج.
|
|
||||||
* التجريدية (Abstractive): بالنظر إلى سؤال وسياق مُعيّن، يتم إنشاء الإجابة من السياق؛ يتعامل نهج [`Text2TextGenerationPipeline`] مع هذا النهج بدلاً من [`QuestionAnsweringPipeline`] الموضح أدناه
|
|
||||||
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> question_answerer = pipeline(task="question-answering")
|
|
||||||
>>> preds = question_answerer(
|
|
||||||
... question="What is the name of the repository?",
|
|
||||||
... context="The name of the repository is huggingface/transformers",
|
|
||||||
... )
|
|
||||||
>>> print(
|
|
||||||
... f"score: {round(preds['score'], 4)}, start: {preds['start']}, end: {preds['end']}, answer: {preds['answer']}"
|
|
||||||
... )
|
|
||||||
score: 0.9327, start: 30, end: 54, answer: huggingface/transformers
|
|
||||||
```
|
|
||||||
|
|
||||||
### التلخيص
|
|
||||||
|
|
||||||
ينشئ التلخيص (Summarization) نسخة مختصرة من نص طويل مع محاولة الحفاظ على معظم معنى النص الأصلي. التلخيص هو مهمة تسلسل إلى تسلسل(Sequence-to-Sequence)؛؛ فهو تُنتج تسلسلًا نصيًا أقصر من النص المُدخل. هناك الكثير من المستندات الطويلة التي يمكن تلخيصها لمساعدة القراء على فهم النقاط الرئيسية بسرعة. مشاريع القوانين والوثائق القانونية والمالية وبراءات الاختراع والأوراق العلمية هي مجرد أمثلة قليلة للوثائق التي يمكن تلخيصها لتوفير وقت القراء وخدمة كمساعد للقراءة.
|
|
||||||
|
|
||||||
مثل الإجابة على الأسئلة، هناك نوعان من التلخيص:
|
|
||||||
|
|
||||||
* الاستخراجية (Extractive): تحديد واستخراج أهم الجمل من النص الأصلي
|
|
||||||
* التجريدي (Abstractive): إنشاء ملخص مستهدف (الذي قد يتضمن كلمات جديدة غير موجودة في النص الأصلي) انطلاقًا من النص الأصلي؛ يستخدم نهج التلخيص التجريدي [`SummarizationPipeline`]
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> summarizer = pipeline(task="summarization")
|
|
||||||
>>> summarizer(
|
|
||||||
... "In this work, we presented the Transformer, the first sequence transduction model based entirely on attention, replacing the recurrent layers most commonly used in encoder-decoder architectures with multi-headed self-attention. For translation tasks, the Transformer can be trained significantly faster than architectures based on recurrent or convolutional layers. On both WMT 2014 English-to-German and WMT 2014 English-to-French translation tasks, we achieve a new state of the art. In the former task our best model outperforms even all previously reported ensembles."
|
|
||||||
... )
|
|
||||||
[{'summary_text': ' The Transformer is the first sequence transduction model based entirely on attention . It replaces the recurrent layers most commonly used in encoder-decoder architectures with multi-headed self-attention . For translation tasks, the Transformer can be trained significantly faster than architectures based on recurrent or convolutional layers .'}]
|
|
||||||
```
|
|
||||||
|
|
||||||
### الترجمة
|
|
||||||
|
|
||||||
تحوّل الترجمة تسلسل نص بلغة إلى لغة أخرى. من المهم مساعدة الأشخاص من خلفيات مختلفة على التواصل مع بعضهم البعض، ومساعدة المحتوى على الوصول إلى جمهور أوسع، وحتى أن يكون أداة تعليمية لمساعدة الأشخاص على تعلم لغة جديدة. إلى جانب التلخيص، تعد الترجمة مهمة من نوع تسلسل إلى تسلسل، حيث يتلقى النموذج تسلسلًا مُدخلًا ويُعيد تسلسلًا مُخرَجًا مُستهدفًا.
|
|
||||||
|
|
||||||
في الأيام الأولى، كانت نماذج الترجمة في الغالب أحادية اللغة، ولكن مؤخرًا، كان هناك اهتمام متزايد بالنماذج متعددة اللغات التي يمكنها الترجمة بين العديد من أزواج اللغات.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> text = "translate English to French: Hugging Face is a community-based open-source platform for machine learning."
|
|
||||||
>>> translator = pipeline(task="translation", model="google-t5/t5-small")
|
|
||||||
>>> translator(text)
|
|
||||||
[{'translation_text': "Hugging Face est une tribune communautaire de l'apprentissage des machines."}]
|
|
||||||
```
|
|
||||||
|
|
||||||
### نمذجة اللغة
|
|
||||||
|
|
||||||
نمذجة اللغة (Language Modeling) هي مهمة التنبؤ بالكلمة التالية في تسلسل نصي. لقد أصبح مهمة NLP شائعة للغاية لأن النموذج اللغوي المسبق التدريب يمكن أن يتم ضبطه بشكل دقيق للعديد من مهام الأخرى. في الآونة الأخيرة، كان هناك الكثير من الاهتمام بنماذج اللغة الكبيرة (LLMs) التي توضح التعلم من الصفر أو من عدد قليل من الأمثلة (Zero-shot or Few-shot Learning). وهذا يعني أن النموذج يمكنه حل المهام التي لم يتم تدريبه عليها بشكل صريح! يمكن استخدام نماذج اللغة لإنشاء نص سلس ومقنع، على الرغم من أنه يجب أن تكون حذرًا لأن النص قد لا يكون دائمًا دقيقًا.
|
|
||||||
|
|
||||||
هناك نوعان من نمذجة اللغة:
|
|
||||||
|
|
||||||
* السببية(Causal): هدف النموذج هو التنبؤ بالرمز (Token) التالي في التسلسل، ويتم إخفاء الرموز المستقبلية (Masking).
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> prompt = "Hugging Face is a community-based open-source platform for machine learning."
|
|
||||||
>>> generator = pipeline(task="text-generation")
|
|
||||||
>>> generator(prompt) # doctest: +SKIP
|
|
||||||
```
|
|
||||||
|
|
||||||
* المقنّع (Masked): هدف النموذج هو التنبؤ برمز مُخفيّ ضمن التسلسل مع الوصول الكامل إلى الرموز الأخرى في التسلسل
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> text = "Hugging Face is a community-based open-source <mask> for machine learning."
|
|
||||||
>>> fill_mask = pipeline(task="fill-mask")
|
|
||||||
>>> preds = fill_mask(text, top_k=1)
|
|
||||||
>>> preds = [
|
|
||||||
... {
|
|
||||||
... "score": round(pred["score"], 4),
|
|
||||||
... "token": pred["token"],
|
|
||||||
... "token_str": pred["token_str"],
|
|
||||||
... "sequence": pred["sequence"],
|
|
||||||
... }
|
|
||||||
... for pred in preds
|
|
||||||
... ]
|
|
||||||
>>> preds
|
|
||||||
[{'score': 0.2236,
|
|
||||||
'token': 1761,
|
|
||||||
'token_str': ' platform',
|
|
||||||
'sequence': 'Hugging Face is a community-based open-source platform for machine learning.'}]
|
|
||||||
```
|
|
||||||
|
|
||||||
## متعدد الوسائط:
|
|
||||||
|
|
||||||
تتطلب المهام متعددة الوسائط (Multimodal) من النموذج معالجة وسائط بيانات متعددة (نص أو صورة أو صوت أو فيديو) لحل مشكلة معينة. يعد وصف الصورة (Image Captioning) مثالاً على مهمة متعددة الوسائط حيث يأخذ النموذج صورة كمدخل وينتج تسلسل نصيًا يصف الصورة أو بعض خصائصها.
|
|
||||||
|
|
||||||
على الرغم من أن النماذج متعددة الوسائط تعمل مع أنواع أو وسائط بيانات مختلفة، إلا أن خطوات المعالجة المسبقة تساعد النموذج داخليًا على تحويل جميع أنواع البيانات إلى متجهات تضمين (Embeddings) (متجهات أو قوائم من الأرقام التي تحتوي على معلومات ذات معنى حول البيانات). بالنسبة لمهمة مثل وصف الصورة، يتعلم النموذج العلاقات بين متجهات تضمين الصور ومتجهات تضمين النص.
|
|
||||||
|
|
||||||
### الإجابة على أسئلة المستندات:
|
|
||||||
|
|
||||||
الإجابة على أسئلة المستندات (Document Question Answering) هي مهمة تقوم بالإجابة على أسئلة اللغة الطبيعية من مستند مُعطى. على عكس مهمة الإجابة على الأسئلة على مستوى الرموز (Token-Level) التي تأخذ نصًا كمدخل، فإن الإجابة على أسئلة المستندات تأخذ صورة لمستند كمدخل بالإضافة إلى سؤال هذا حول المستند وتعيد الإجابة. يمكن استخدام الإجابة على أسئلة المستندات لتفسير المستندات المُنسّقة واستخراج المعلومات الرئيسية منها. في المثال أدناه، يمكن استخراج المبلغ الإجمالي والمبلغ المُسترد من إيصال الدفع..
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
>>> from PIL import Image
|
|
||||||
>>> import requests
|
|
||||||
|
|
||||||
>>> url = "https://huggingface.co/datasets/hf-internal-testing/example-documents/resolve/main/jpeg_images/2.jpg"
|
|
||||||
>>> image = Image.open(requests.get(url, stream=True).raw)
|
|
||||||
|
|
||||||
>>> doc_question_answerer = pipeline("document-question-answering", model="magorshunov/layoutlm-invoices")
|
|
||||||
>>> preds = doc_question_answerer(
|
|
||||||
... question="ما هو المبلغ الإجمالي؟",
|
|
||||||
... image=image,
|
|
||||||
... )
|
|
||||||
>>> preds
|
|
||||||
[{'score': 0.8531, 'answer': '17,000', 'start': 4, 'end': 4}]
|
|
||||||
```
|
|
||||||
|
|
||||||
نأمل أن تكون هذه الصفحة قد زودتك ببعض المعلومات الأساسية حول جميع أنواع المهام في كل طريقة وأهمية كل منها العملية. في القسم التالي، ستتعلم كيف تعمل مكتبة 🤗 Transformers لحل هذه المهام.
|
|
||||||
@ -1,422 +0,0 @@
|
|||||||
<!--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.
|
|
||||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
|
||||||
rendered properly in your Markdown viewer.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# نمذجة اللغة السببية (Causal language modeling)
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
هناك نوعان من نمذجة اللغة، السببية والمقنعة. يوضح هذا الدليل نمذجة اللغة السببية.
|
|
||||||
تُستخدم نماذج اللغة السببية غالبًا لتوليد النص. يمكنك استخدام هذه النماذج للتطبيقات الإبداعية مثل
|
|
||||||
اختيار مغامرة النص الخاصة بك أو مساعد ترميز ذكي مثل Copilot أو CodeParrot.
|
|
||||||
|
|
||||||
<Youtube id="Vpjb1lu0MDk"/>
|
|
||||||
|
|
||||||
تتنبأ نمذجة اللغة السببية بالرمز التالي في تسلسل من الرموز، ولا يمكن للنموذج سوى الاهتمام بالرموز على
|
|
||||||
اليسار. هذا يعني أن النموذج لا يمكنه رؤية الرموز المستقبلية. GPT-2 هو مثال على نموذج اللغة السببية.
|
|
||||||
|
|
||||||
سيوضح لك هذا الدليل كيفية:
|
|
||||||
|
|
||||||
1. ضبط دقيق [DistilRoBERTa](https://huggingface.co/distilbert/distilroberta-base) على مجموعة فرعية [r/askscience](https://www.reddit.com/r/askscience/) من مجموعة بيانات [ELI5](https://huggingface.co/datasets/eli5).
|
|
||||||
2. استخدام النموذج المدرب الخاص بك للاستنتاج.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
لرؤية جميع العمارات ونقاط التحقق المتوافقة مع هذه المهمة، نوصي بالتحقق من [task-page](https://huggingface.co/tasks/text-generation)
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
قبل أن تبدأ، تأكد من تثبيت جميع المكتبات الضرورية:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers datasets evaluate
|
|
||||||
```
|
|
||||||
|
|
||||||
نحن نشجعك على تسجيل الدخول إلى حساب Hugging Face الخاص بك حتى تتمكن من تحميل ومشاركة نموذجك مع المجتمع. عند المطالبة، أدخل رمزك لتسجيل الدخول:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from huggingface_hub import notebook_login
|
|
||||||
|
|
||||||
>>> notebook_login()
|
|
||||||
```
|
|
||||||
|
|
||||||
## تحميل مجموعة بيانات ELI5
|
|
||||||
|
|
||||||
ابدأ بتحميل أول 5000 مثال من [ELI5-Category](https://huggingface.co/datasets/eli5_category) مجموعة البيانات مع مكتبة 🤗 Datasets. سيعطيك هذا فرصة للتجربة والتأكد من أن كل شيء يعمل قبل قضاء المزيد من الوقت في التدريب على مجموعة البيانات الكاملة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from datasets import load_dataset
|
|
||||||
|
|
||||||
>>> eli5 = load_dataset("eli5_category", split="train[:5000]")
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتقسيم مجموعة بيانات `train` إلى مجموعتي تدريب واختبار باستخدام الخاصية [`~datasets.Dataset.train_test_split`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> eli5 = eli5.train_test_split(test_size=0.2)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم ألق نظرة على مثال:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> eli5["train"][0]
|
|
||||||
{'q_id': '7h191n',
|
|
||||||
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
|
|
||||||
'selftext': '',
|
|
||||||
'category': 'Economics',
|
|
||||||
'subreddit': 'explainlikeimfive',
|
|
||||||
'answers': {'a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
|
|
||||||
'text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
|
|
||||||
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
|
|
||||||
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
|
|
||||||
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
|
|
||||||
'score': [21, 19, 5, 3],
|
|
||||||
'text_urls': [[],
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']]},
|
|
||||||
'title_urls': ['url'],
|
|
||||||
'selftext_urls': ['url']}
|
|
||||||
```
|
|
||||||
|
|
||||||
على الرغم من أن هذا قد يبدو معقدًا، إلا أنك مهتم حقًا بحقل `text`. ما هو رائع حول مهام نمذجة اللغة
|
|
||||||
أنت لا تحتاج إلى تسميات (تُعرف أيضًا باسم المهمة غير الخاضعة للإشراف) لأن الكلمة التالية تعمل كتسمية.
|
|
||||||
|
|
||||||
## معالجة مسبقة (Preprocess)
|
|
||||||
|
|
||||||
<Youtube id="ma1TrR7gE7I"/>
|
|
||||||
|
|
||||||
الخطوة التالية هي تحميل مجزء النص DistilGPT2 لمعالجة حقل `text` الفرعي:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilgpt2")
|
|
||||||
```
|
|
||||||
|
|
||||||
ستلاحظ من المثال أعلاه، الحقل `text` هو في الواقع متداخل داخل `answers`. هذا يعني أنك ستحتاج إلى
|
|
||||||
استخراج حقل `text` الفرعي من بنيته المتداخلة باستخدام الدالة [`flatten`](https://huggingface.co/docs/datasets/process#flatten):
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> eli5 = eli5.flatten()
|
|
||||||
>>> eli5["train"][0]
|
|
||||||
{'q_id': '7h191n',
|
|
||||||
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
|
|
||||||
'selftext': '',
|
|
||||||
'category': 'Economics',
|
|
||||||
'subreddit': 'explainlikeimfive',
|
|
||||||
'answers.a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
|
|
||||||
'answers.text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
|
|
||||||
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
|
|
||||||
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
|
|
||||||
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
|
|
||||||
'answers.score': [21, 19, 5, 3],
|
|
||||||
'answers.text_urls': [[],
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']],
|
|
||||||
'title_urls': ['url'],
|
|
||||||
'selftext_urls': ['url']}
|
|
||||||
```
|
|
||||||
|
|
||||||
كل حقل فرعي هو الآن عموداً منفصلاً مسبوقاً بـ `answers`، وحقل `text` هو قائمة الآن. بدلاً من ذلك
|
|
||||||
من تجزائة نص كل جملة بشكل منفصل، قم بتحويل القائمة إلى سلسلة حتى تتمكن من تجزئة نصها بشكل مجمّع.
|
|
||||||
|
|
||||||
هنا أول دالة معالجة مسبقة لدمج قائمة السلاسل لكل مثال ومجزىء النتيجة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> def preprocess_function(examples):
|
|
||||||
... return tokenizer([" ".join(x) for x in examples["answers.text"]])
|
|
||||||
```
|
|
||||||
|
|
||||||
لتطبيق دالة المعالجة المسبقة هذه على مجموعة البيانات بأكملها، استخدم الدالة 🤗 Datasets [`~datasets.Dataset.map`]. يمكنك تسريع هذه العملية `map` عن طريق تعيين `batched=True` لمعالجة عناصر متعددة من مجموعة البيانات في وقت واحد، وزيادة عدد العمليات مع `num_proc`. احذف أي أعمدة لا تحتاجها:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenized_eli5 = eli5.map(
|
|
||||||
... preprocess_function,
|
|
||||||
... batched=True,
|
|
||||||
... num_proc=4,
|
|
||||||
... remove_columns=eli5["train"].column_names,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
تحتوي هذه المجموعة من البيانات على تسلسلات الرموز، ولكن بعضها أطول من الطول الأقصى للمدخلات للنموذج.
|
|
||||||
|
|
||||||
يمكنك الآن استخدام دالة ما قبل المعالجة ثانية لـ:
|
|
||||||
|
|
||||||
- تجميع كل التسلسلات.
|
|
||||||
- تقسيم التسلسلات المجمّعة إلى أجزاء أقصر محددة، بحجم `block_size`، والتي يجب أن تكون أقصر من الطول الأقصى للمدخلات ومناسبة لذاكرة GPU.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> block_size = 128
|
|
||||||
|
|
||||||
>>> def group_texts(examples):
|
|
||||||
... # ربط جميع النصوص.
|
|
||||||
... concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
|
|
||||||
... total_length = len(concatenated_examples[list(examples.keys())[0]])
|
|
||||||
... # نتجاهل الباقي الصغير، يمكننا إضافة الحشو إذا كان النموذج يدعمه بدلاً من هذا الإسقاط، يمكنك
|
|
||||||
... # تخصيص هذا الجزء حسب احتياجاتك.
|
|
||||||
... if total_length >= block_size:
|
|
||||||
... total_length = (total_length // block_size) * block_size
|
|
||||||
... # التقسيم إلى أجزاء بحجم block_size.
|
|
||||||
... 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
|
|
||||||
```
|
|
||||||
|
|
||||||
طبق دالة `group_texts` على كامل المجموعة من البيانات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن قم بإنشاء دفعة من الأمثلة باستخدام [`DataCollatorForLanguageModeling`]. من الأفضل أن تقوم بـ *الحشو الديناميكي* للجمل إلى الطول الأطول في الدفعة أثناء التجميع، بدلاً من حشو كامل المجموعة من البيانات إلى الطول الأقصى.
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
استخدم رمز نهاية التسلسل كرمز للحشو، وحدد `mlm_probability` لحجب الرموز بشكل عشوائي عند كل تكرار للبيانات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorForLanguageModeling
|
|
||||||
|
|
||||||
>>> tokenizer.pad_token = tokenizer.eos_token
|
|
||||||
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
|
|
||||||
```
|
|
||||||
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
استخدم رمز نهاية التسلسل كرمز للحشو، وحدد `mlm_probability` لحجب الرموز بشكل عشوائي عند كل تكرار للبيانات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorForLanguageModeling
|
|
||||||
|
|
||||||
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False, return_tensors="tf")
|
|
||||||
```
|
|
||||||
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
## التدريب (Train)
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بتدريب نموذج باستخدام [`Trainer`], اطلع على [البرنامج التعليمي الأساسي](../training#train-with-pytorch-trainer)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
أنت جاهز الآن لبدء تدريب نموذجك! قم بتحميل DistilGPT2 باستخدام [`AutoModelForCausalLM`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForCausalLM, TrainingArguments, Trainer
|
|
||||||
|
|
||||||
>>> model = AutoModelForCausalLM.from_pretrained("distilbert/distilgpt2")
|
|
||||||
```
|
|
||||||
|
|
||||||
في هذه المرحلة، تبقى ثلاث خطوات فقط:
|
|
||||||
|
|
||||||
1. حدد معلمات التدريب الخاصة بك في [`TrainingArguments`]. المعامل الوحيد المطلوب هو `output_dir` الذي يحدد أين سيتم حفظ نموذجك. ستقوم بدفع هذا النموذج إلى Hub بتحديد `push_to_hub=True` (يجب أن تكون مسجلاً الدخول إلى Hugging Face لتحميل نموذجك).
|
|
||||||
2. قم بتمرير معاملات التدريب إلى [`Trainer`] إلى جانب النموذج، والمجموعات من البيانات، ومجمّع البيانات.
|
|
||||||
3. قم باستدعاء [`~Trainer.train`] لتدريب نموذجك.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> training_args = TrainingArguments(
|
|
||||||
... output_dir="my_awesome_eli5_clm-model",
|
|
||||||
... eval_strategy="epoch",
|
|
||||||
... learning_rate=2e-5,
|
|
||||||
... weight_decay=0.01,
|
|
||||||
... push_to_hub=True,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer = Trainer(
|
|
||||||
... model=model,
|
|
||||||
... args=training_args,
|
|
||||||
... train_dataset=lm_dataset["train"],
|
|
||||||
... eval_dataset=lm_dataset["test"],
|
|
||||||
... data_collator=data_collator,
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، استخدم طريقة [`~transformers.Trainer.evaluate`] لتقييم نموذجك والحصول على احتمالية الارتباك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import math
|
|
||||||
|
|
||||||
>>> eval_results = trainer.evaluate()
|
|
||||||
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
|
|
||||||
Perplexity: 49.61
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم شارك نموذجك على Hub باستخدام طريقة [`~transformers.Trainer.push_to_hub`] حتى يتمكن الجميع من استخدام نموذجك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> trainer.push_to_hub()
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بتدريب نموذج باستخدام Keras، اطلع على [البرنامج التعليمي الأساسي](../training#train-a-tensorflow-model-with-keras)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
لتدريب نموذج في TensorFlow، ابدأ بإعداد دالة المحسن، وجدول معدل التعلم، وبعض معاملات التدريب:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import create_optimizer, AdamWeightDecay
|
|
||||||
|
|
||||||
>>> optimizer = AdamWeightDecay(learning_rate=2e-5, weight_decay_rate=0.01)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم يمكنك تحميل DistilGPT2 باستخدام [`TFAutoModelForCausalLM`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForCausalLM
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForCausalLM.from_pretrained("distilbert/distilgpt2")
|
|
||||||
```
|
|
||||||
|
|
||||||
حول مجموعات بياناتك إلى تنسيق `tf.data.Dataset` باستخدام [`~transformers.TFPreTrainedModel.prepare_tf_dataset`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tf_train_set = model.prepare_tf_dataset(
|
|
||||||
... lm_dataset["train"],
|
|
||||||
... shuffle=True,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> tf_test_set = model.prepare_tf_dataset(
|
|
||||||
... lm_dataset["test"],
|
|
||||||
... shuffle=False,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتهيئة النموذج للتدريب باستخدام [`compile`](https://keras.io/api/models/model_training_apis/#compile-method). لاحظ أن جميع نماذج Transformers لديها دالة خسارة ذات صلة بالمهمة الافتراضية، لذلك لا تحتاج إلى تحديد واحدة ما لم ترغب في ذلك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import tensorflow as tf
|
|
||||||
|
|
||||||
>>> model.compile(optimizer=optimizer) # لا يوجد حجة للخسارة!
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن القيام بذلك عن طريق تحديد مكان دفع نموذجك ومجمّع البيانات في [`~transformers.PushToHubCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import PushToHubCallback
|
|
||||||
|
|
||||||
>>> callback = PushToHubCallback(
|
|
||||||
... output_dir="my_awesome_eli5_clm-model",
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
أخيراً، أنت جاهز لبدء تدريب نموذجك! قم باستدعاء [`fit`](https://keras.io/api/models/model_training_apis/#fit-method) مع مجموعات بيانات التدريب والتحقق من الصحة، وعدد العصور، والتعليقات الخاصة بك لتدريب النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model.fit(x=tf_train_set, validation_data=tf_test_set, epochs=3, callbacks=[callback])
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، يتم تحميل نموذجك تلقائيًا إلى Hub حتى يتمكن الجميع من استخدامه!
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للحصول على مثال أكثر تعمقًا حول كيفية تدريب نموذج للنمذجة اللغوية السببية، اطلع على الدفتر المقابل
|
|
||||||
[دفتر PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)
|
|
||||||
أو [دفتر TensorFlow](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## الاستدلال (Inference)
|
|
||||||
|
|
||||||
رائع، الآن بعد أن قمت بتدريب نموذج، يمكنك استخدامه للاستدلال!
|
|
||||||
|
|
||||||
قم بابتكار سؤال تود توليد نص منه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> prompt = "Somatic hypermutation allows the immune system to"
|
|
||||||
```
|
|
||||||
|
|
||||||
أبسط طريقة لتجربة نموذجك المدرب للاستدلال هي استخدامه في [`pipeline`]. قم بتنفيذ `pipeline` لتوليد النص مع نموذجك، ومرر نصك إليه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> generator = pipeline("text-generation", model="username/my_awesome_eli5_clm-model")
|
|
||||||
>>> generator(prompt)
|
|
||||||
[{'generated_text': "Somatic hypermutation allows the immune system to be able to effectively reverse the damage caused by an infection.\n\n\nThe damage caused by an infection is caused by the immune system's ability to perform its own self-correcting tasks."}]
|
|
||||||
```
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
قسم النص وإرجع `input_ids` كتنسورات PyTorch:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_clm-model")
|
|
||||||
>>> inputs = tokenizer(prompt, return_tensors="pt").input_ids
|
|
||||||
```
|
|
||||||
|
|
||||||
استخدم طريقة [`~generation.GenerationMixin.generate`] لتوليد النص.
|
|
||||||
للمزيد من التفاصيل حول استراتيجيات توليد النص المختلفة والبارامترات للتحكم في التوليد، راجع صفحة [استراتيجيات توليد النص](../generation_strategies).
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForCausalLM
|
|
||||||
|
|
||||||
>>> model = AutoModelForCausalLM.from_pretrained("username/my_awesome_eli5_clm-model")
|
|
||||||
>>> outputs = model.generate(inputs, max_new_tokens=100, do_sample=True, top_k=50, top_p=0.95)
|
|
||||||
```
|
|
||||||
|
|
||||||
فك ترميز الرموز المولدة مرة أخرى إلى نص:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
|
||||||
["Somatic hypermutation allows the immune system to react to drugs with the ability to adapt to a different environmental situation. In other words, a system of 'hypermutation' can help the immune system to adapt to a different environmental situation or in some cases even a single life. In contrast, researchers at the University of Massachusetts-Boston have found that 'hypermutation' is much stronger in mice than in humans but can be found in humans, and that it's not completely unknown to the immune system. A study on how the immune system"]
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
قم بتقسيم النص وإرجاع `input_ids` كـ TensorFlow tensors:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_clm-model")
|
|
||||||
>>> inputs = tokenizer(prompt, return_tensors="tf").input_ids
|
|
||||||
```
|
|
||||||
|
|
||||||
استخدم طريقة [`~transformers.generation_tf_utils.TFGenerationMixin.generate`] لإنشاء الملخص. للمزيد من التفاصيل حول استراتيجيات توليد النص المختلفة والبارامترات للتحكم في التوليد، راجع صفحة [استراتيجيات توليد النص](../generation_strategies).
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForCausalLM
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForCausalLM.from_pretrained("username/my_awesome_eli5_clm-model")
|
|
||||||
>>> outputs = model.generate(input_ids=inputs, max_new_tokens=100, do_sample=True, top_k=50, top_p=0.95)
|
|
||||||
```
|
|
||||||
|
|
||||||
فك ترميز الرموز المولدة مرة أخرى إلى نص:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
|
||||||
['Somatic hypermutation allows the immune system to detect the presence of other viruses as they become more prevalent. Therefore, researchers have identified a high proportion of human viruses. The proportion of virus-associated viruses in our study increases with age. Therefore, we propose a simple algorithm to detect the presence of these new viruses in our samples as a sign of improved immunity. A first study based on this algorithm, which will be published in Science on Friday, aims to show that this finding could translate into the development of a better vaccine that is more effective for']
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
@ -1,442 +0,0 @@
|
|||||||
<!--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.
|
|
||||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
|
||||||
rendered properly in your Markdown viewer.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# نمذجة اللغة المقنعة (Masked language modeling)
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
<Youtube id="mqElG5QJWUg"/>
|
|
||||||
|
|
||||||
تتنبأ نمذجة اللغة المقنعة برمز مقنع في تسلسل، ويمكن للنموذج الانتباه إلى الرموز بشكل ثنائي الاتجاه. هذا
|
|
||||||
يعني أن النموذج لديه إمكانية الوصول الكاملة إلى الرموز الموجودة على اليسار واليمين. تعد نمذجة اللغة المقنعة ممتازة للمهام التي
|
|
||||||
تتطلب فهمًا سياقيًا جيدًا لتسلسل كامل. BERT هو مثال على نموذج لغة مقنع.
|
|
||||||
|
|
||||||
سيوضح لك هذا الدليل كيفية:
|
|
||||||
|
|
||||||
1. تكييف [DistilRoBERTa](https://huggingface.co/distilbert/distilroberta-base) على مجموعة فرعية [r/askscience](https://www.reddit.com/r/askscience/) من مجموعة بيانات [ELI5](https://huggingface.co/datasets/eli5).
|
|
||||||
2. استخدام نموذج المدرب الخاص بك للاستدلال.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
لمعرفة جميع البنى والنسخ المتوافقة مع هذه المهمة، نوصي بالتحقق من [صفحة المهمة](https://huggingface.co/tasks/fill-mask)
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
قبل أن تبدأ، تأكد من تثبيت جميع المكتبات الضرورية:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers datasets evaluate
|
|
||||||
```
|
|
||||||
|
|
||||||
نحن نشجعك على تسجيل الدخول إلى حساب Hugging Face الخاص بك حتى تتمكن من تحميل ومشاركة نموذجك مع المجتمع. عندما تتم مطالبتك، أدخل رمزك لتسجيل الدخول:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from huggingface_hub import notebook_login
|
|
||||||
|
|
||||||
>>> notebook_login()
|
|
||||||
```
|
|
||||||
|
|
||||||
## تحميل مجموعة بيانات ELI5
|
|
||||||
|
|
||||||
ابدأ بتحميل أول 5000 مثال من مجموعة بيانات [ELI5-Category](https://huggingface.co/datasets/eli5_category) باستخدام مكتبة 🤗 Datasets. سيعطيك هذا فرصة للتجربة والتأكد من أن كل شيء يعمل قبل قضاء المزيد من الوقت في التدريب على مجموعة البيانات الكاملة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from datasets import load_dataset
|
|
||||||
|
|
||||||
>>> eli5 = load_dataset("eli5_category", split="train[:5000]")
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتقسيم مجموعة البيانات `train` إلى مجموعتي تدريب واختبار باستخدام الدالة [`~datasets.Dataset.train_test_split`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> eli5 = eli5.train_test_split(test_size=0.2)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم ألق نظرة على مثال:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> eli5["train"][0]
|
|
||||||
{'q_id': '7h191n',
|
|
||||||
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
|
|
||||||
'selftext': '',
|
|
||||||
'category': 'Economics',
|
|
||||||
'subreddit': 'explainlikeimfive',
|
|
||||||
'answers': {'a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
|
|
||||||
'text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
|
|
||||||
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
|
|
||||||
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
|
|
||||||
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
|
|
||||||
'score': [21, 19, 5, 3],
|
|
||||||
'text_urls': [[],
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']]},
|
|
||||||
'title_urls': ['url'],
|
|
||||||
'selftext_urls': ['url']}
|
|
||||||
```
|
|
||||||
|
|
||||||
على الرغم من أن هذا قد يبدو كثيرًا، إلا أنك مهتم حقًا بحقل `text`. ما هو رائع حول مهام نمذجة اللغة هو أنك لا تحتاج إلى تسميات (تُعرف أيضًا باسم المهمة غير الخاضعة للإشراف) لأن الكلمة التالية *هي* التسمية.
|
|
||||||
|
|
||||||
## معالجة مسبقة (Preprocess)
|
|
||||||
|
|
||||||
<Youtube id="8PmhEIXhBvI"/>
|
|
||||||
|
|
||||||
بالنسبة لنمذجة اللغة المقنعة، فإن الخطوة التالية هي تحميل معالج DistilRoBERTa لمعالجة حقل `text` الفرعي:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilroberta-base")
|
|
||||||
```
|
|
||||||
|
|
||||||
ستلاحظ من المثال أعلاه، أن حقل `text` موجود بالفعل داخل `answers`. هذا يعني أنك ستحتاج إلى استخراج حقل `text` الفرعي من بنيته المضمنة باستخدام الدالة [`flatten`](https://huggingface.co/docs/datasets/process#flatten):
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> eli5 = eli5.flatten()
|
|
||||||
>>> eli5["train"][0]
|
|
||||||
{'q_id': '7h191n',
|
|
||||||
'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
|
|
||||||
'selftext': '',
|
|
||||||
'category': 'Economics',
|
|
||||||
'subreddit': 'explainlikeimfive',
|
|
||||||
'answers.a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
|
|
||||||
'answers.text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
|
|
||||||
'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
|
|
||||||
'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
|
|
||||||
'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
|
|
||||||
'answers.score': [21, 19, 5, 3],
|
|
||||||
'answers.text_urls': [[],
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']],
|
|
||||||
'title_urls': ['url'],
|
|
||||||
'selftext_urls': ['url']}
|
|
||||||
```
|
|
||||||
|
|
||||||
كل حقل فرعي هو الآن عمود منفصل كما هو موضح بواسطة بادئة `answers`، وحقل `text` هو قائمة الآن. بدلاً من
|
|
||||||
معالجة كل جملة بشكل منفصل، قم بتحويل القائمة إلى سلسلة حتى تتمكن من معالجتها بشكل مشترك.
|
|
||||||
|
|
||||||
هنا أول دالة معالجة مسبقة لربط قائمة السلاسل لكل مثال ومعالجة النتيجة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> def preprocess_function(examples):
|
|
||||||
... return tokenizer([" ".join(x) for x in examples["answers.text"]])
|
|
||||||
```
|
|
||||||
|
|
||||||
لتطبيق دالة المعالجة المسبقة على مجموعة البيانات بأكملها، استخدم الدالة 🤗 Datasets [`~datasets.Dataset.map`]. يمكنك تسريع دالة `map` عن طريق تعيين `batched=True` لمعالجة عدة عناصر في وقت واحد، وزيادة عدد العمليات باستخدام `num_proc`. احذف أي أعمدة غير ضرورية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenized_eli5 = eli5.map(
|
|
||||||
... preprocess_function,
|
|
||||||
... batched=True,
|
|
||||||
... num_proc=4,
|
|
||||||
... remove_columns=eli5["train"].column_names,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
تحتوي مجموعة البيانات هذه على تسلسلات رمزية، ولكن بعضها أطول من الطول الأقصى للمدخلات للنموذج.
|
|
||||||
|
|
||||||
يمكنك الآن استخدام دالة معالجة مسبقة ثانية لـ:
|
|
||||||
- تجميع جميع التسلسلات
|
|
||||||
- تقسيم التسلسلات المجمّعة إلى أجزاء أقصر محددة بـ `block_size`، والتي يجب أن تكون أقصر من الحد الأقصى لطول المدخلات ومناسبة لذاكرة GPU.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> block_size = 128
|
|
||||||
|
|
||||||
>>> def group_texts(examples):
|
|
||||||
... # تجميع جميع النصوص.
|
|
||||||
... concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
|
|
||||||
... total_length = len(concatenated_examples[list(examples.keys())[0]])
|
|
||||||
... # نتجاهل الجزء المتبقي الصغير، يمكننا إضافة الحشو إذا كان النموذج يدعمه بدلاً من هذا الإسقاط، يمكنك
|
|
||||||
... # تخصيص هذا الجزء حسب احتياجاتك.
|
|
||||||
... if total_length >= block_size:
|
|
||||||
... total_length = (total_length // block_size) * block_size
|
|
||||||
... # تقسيمها إلى أجزاء بحجم block_size.
|
|
||||||
... result = {
|
|
||||||
... k: [t[i : i + block_size] for i in range(0, total_length, block_size)]
|
|
||||||
... for k, t in concatenated_examples.items()
|
|
||||||
... }
|
|
||||||
... return result
|
|
||||||
```
|
|
||||||
|
|
||||||
طبق دالة `group_texts` على مجموعة البيانات بأكملها:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن، قم بإنشاء دفعة من الأمثلة باستخدام [`DataCollatorForLanguageModeling`]. من الأكثر كفاءة أن تقوم بـ *الحشو الديناميكي* ليصل طولها إلى أطول جملة في الدفعة أثناء التجميع، بدلاً من حشو مجموعة البيانات بأكملها إلى الطول الأقصى.
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
استخدم رمز نهاية التسلسل كرمز الحشو وحدد `mlm_probability` لحجب الرموز عشوائياً كل مرة تكرر فيها البيانات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorForLanguageModeling
|
|
||||||
|
|
||||||
>>> tokenizer.pad_token = tokenizer.eos_token
|
|
||||||
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
|
|
||||||
استخدم رمز نهاية التسلسل كرمز الحشو وحدد `mlm_probability` لحجب الرموز عشوائياً كل مرة تكرر فيها البيانات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorForLanguageModeling
|
|
||||||
|
|
||||||
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15, return_tensors="tf")
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
## التدريب (Train)
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بتعديل نموذج باستخدام [`Trainer`], ألق نظرة على الدليل الأساسي [هنا](../training#train-with-pytorch-trainer)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
أنت مستعد الآن لبدء تدريب نموذجك! قم بتحميل DistilRoBERTa باستخدام [`AutoModelForMaskedLM`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForMaskedLM
|
|
||||||
|
|
||||||
>>> model = AutoModelForMaskedLM.from_pretrained("distilbert/distilroberta-base")
|
|
||||||
```
|
|
||||||
|
|
||||||
في هذه المرحلة، تبقى ثلاث خطوات فقط:
|
|
||||||
|
|
||||||
1. حدد معلمات التدريب الخاصة بك في [`TrainingArguments`]. المعلمة الوحيدة المطلوبة هي `output_dir` والتي تحدد مكان حفظ نموذجك. ستقوم بدفع هذا النموذج إلى Hub عن طريق تعيين `push_to_hub=True` (يجب أن تكون مسجلاً الدخول إلى Hugging Face لتحميل نموذجك).
|
|
||||||
2. قم بتمرير معلمات التدريب إلى [`Trainer`] مع النموذج، ومجموعات البيانات، ومجمّع البيانات.
|
|
||||||
3. قم باستدعاء [`~Trainer.train`] لتعديل نموذجك.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> training_args = TrainingArguments(
|
|
||||||
... output_dir="my_awesome_eli5_mlm_model",
|
|
||||||
... eval_strategy="epoch",
|
|
||||||
... learning_rate=2e-5,
|
|
||||||
... num_train_epochs=3,
|
|
||||||
... weight_decay=0.01,
|
|
||||||
... push_to_hub=True,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer = Trainer(
|
|
||||||
... model=model,
|
|
||||||
... args=training_args,
|
|
||||||
... train_dataset=lm_dataset["train"],
|
|
||||||
... eval_dataset=lm_dataset["test"],
|
|
||||||
... data_collator=data_collator,
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، استخدم طريقة [`~transformers.Trainer.evaluate`] لتقييم النموذج والحصول على مقياس
|
|
||||||
الحيرة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import math
|
|
||||||
|
|
||||||
>>> eval_results = trainer.evaluate()
|
|
||||||
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
|
|
||||||
Perplexity: 8.76
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم شارك نموذجك على Hub باستخدام طريقة [`~transformers.Trainer.push_to_hub`] حتى يتمكن الجميع من استخدام نموذجك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> trainer.push_to_hub()
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بتعديل نموذج باستخدام Keras، ألق نظرة على الدليل الأساسي [هنا](../training#train-a-tensorflow-model-with-keras)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
لتعديل نموذج في TensorFlow، ابدأ بإعداد دالة محسن، وجدول معدل التعلم، وبعض معلمات التدريب:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import create_optimizer, AdamWeightDecay
|
|
||||||
|
|
||||||
>>> optimizer = AdamWeightDecay(learning_rate=2e-5, weight_decay_rate=0.01)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم يمكنك تحميل DistilRoBERTa باستخدام [`TFAutoModelForMaskedLM`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForMaskedLM
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForMaskedLM.from_pretrained("distilbert/distilroberta-base")
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتحويل مجموعات بياناتك إلى تنسيق `tf.data.Dataset` باستخدام [`~transformers.TFPreTrainedModel.prepare_tf_dataset`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tf_train_set = model.prepare_tf_dataset(
|
|
||||||
... lm_dataset["train"],
|
|
||||||
... shuffle=True,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> tf_test_set = model.prepare_tf_dataset(
|
|
||||||
... lm_dataset["test"],
|
|
||||||
... shuffle=False,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتهيئة النموذج للتدريب باستخدام [`compile`](https://keras.io/api/models/model_training_apis/#compile-method). لاحظ أن نماذج Transformers لديها جميعها دالة خسارة افتراضية ذات صلة بالمهمة، لذلك لا تحتاج إلى تحديد واحدة ما لم تكن تريد ذلك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import tensorflow as tf
|
|
||||||
|
|
||||||
>>> model.compile(optimizer=optimizer) # لا توجد حجة للخسارة!
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن القيام بذلك عن طريق تحديد مكان دفع نموذجك ومعالج الرموز في [`~transformers.PushToHubCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import PushToHubCallback
|
|
||||||
|
|
||||||
>>> callback = PushToHubCallback(
|
|
||||||
... output_dir="my_awesome_eli5_mlm_model",
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
أخيراً، أنت مستعد لبدء تدريب نموذجك! قم باستدعاء [`fit`](https://keras.io/api/models/model_training_apis/#fit-method) مع مجموعات بيانات التدريب والتحقق، وعدد العصور، والتعليقات الخاصة بك لتعديل النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model.fit(x=tf_train_set, validation_data=tf_test_set, epochs=3, callbacks=[callback])
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، يتم تحميل نموذجك تلقائياً إلى Hub حتى يتمكن الجميع من استخدامه!
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
لمثال أكثر تفصيلاً حول كيفية تعديل نموذج للنمذجة اللغوية المقنعة، ألق نظرة على الدفتر المقابل
|
|
||||||
[دفتر PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling.ipynb)
|
|
||||||
أو [دفتر TensorFlow](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/language_modeling-tf.ipynb).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## الاستدلال
|
|
||||||
|
|
||||||
رائع، الآن بعد أن قمت بتعديل نموذج، يمكنك استخدامه للاستدلال!
|
|
||||||
|
|
||||||
جهّز بعض النصوص التي تريد أن يملأ النموذج الفراغات فيها، واستخدم الرمز الخاص `<mask>` للإشارة إلى الفراغ:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> text = "The Milky Way is a <mask> galaxy."
|
|
||||||
```
|
|
||||||
|
|
||||||
أبسط طريقة لتجربة نموذجك المعدل للاستدلال هي استخدامه في [`pipeline`]. قم بإنشاء كائن `pipeline` لملء الفراغ مع نموذجك، ومرر نصك إليه. إذا أردت، يمكنك استخدام معلمة `top_k` لتحديد عدد التنبؤات التي تريد إرجاعها:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> mask_filler = pipeline("fill-mask", "username/my_awesome_eli5_mlm_model")
|
|
||||||
>>> mask_filler(text, top_k=3)
|
|
||||||
[{'score': 0.5150994658470154,
|
|
||||||
'token': 21300,
|
|
||||||
'token_str': ' spiral',
|
|
||||||
'sequence': 'The Milky Way is a spiral galaxy.'},
|
|
||||||
{'score': 0.07087188959121704,
|
|
||||||
'token': 2232,
|
|
||||||
'token_str': ' massive',
|
|
||||||
'sequence': 'The Milky Way is a massive galaxy.'},
|
|
||||||
{'score': 0.06434620916843414,
|
|
||||||
'token': 650,
|
|
||||||
'token_str': ' small',
|
|
||||||
'sequence': 'The Milky Way is a small galaxy.'}]
|
|
||||||
```
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
قم بتجزئة النص وإرجاع `input_ids` كمتجهات PyTorch. ستحتاج أيضًا إلى تحديد موضع رمز `<mask>`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_mlm_model")
|
|
||||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
|
||||||
>>> mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتمرير المدخلات إلى النموذج وإرجاع `logits` للرمز المقنع:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForMaskedLM
|
|
||||||
|
|
||||||
>>> model = AutoModelForMaskedLM.from_pretrained("username/my_awesome_eli5_mlm_model")
|
|
||||||
>>> logits = model(**inputs).logits
|
|
||||||
>>> mask_token_logits = logits[0, mask_token_index, :]
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم قم بإرجاع الرموز الثلاثة المقنعة ذات الاحتمالية الأعلى وطباعتها:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> top_3_tokens = torch.topk(mask_token_logits, 3, dim=1).indices[0].tolist()
|
|
||||||
|
|
||||||
>>> for token in top_3_tokens:
|
|
||||||
... print(text.replace(tokenizer.mask_token, tokenizer.decode([token])))
|
|
||||||
The Milky Way is a spiral galaxy.
|
|
||||||
The Milky Way is a massive galaxy.
|
|
||||||
The Milky Way is a small galaxy.
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
قم بتقسيم النص إلى رموز وإرجاع `input_ids` كـ TensorFlow tensors. ستحتاج أيضًا إلى تحديد موضع رمز `<mask>`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_mlm_model")
|
|
||||||
>>> inputs = tokenizer(text, return_tensors="tf")
|
|
||||||
>>> mask_token_index = tf.where(inputs["input_ids"] == tokenizer.mask_token_id)[0, 1]
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتمرير المدخلات إلى النموذج وإرجاع `logits` للرمز المقنع:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForMaskedLM
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForMaskedLM.from_pretrained("username/my_awesome_eli5_mlm_model")
|
|
||||||
>>> logits = model(**inputs).logits
|
|
||||||
>>> mask_token_logits = logits[0, mask_token_index, :]
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم قم بإرجاع الرموز الثلاثة المقنعة ذات الاحتمالية الأعلى وطباعتها:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> top_3_tokens = tf.math.top_k(mask_token_logits, 3).indices.numpy()
|
|
||||||
|
|
||||||
>>> for token in top_3_tokens:
|
|
||||||
... print(text.replace(tokenizer.mask_token, tokenizer.decode([token])))
|
|
||||||
The Milky Way is a spiral galaxy.
|
|
||||||
The Milky Way is a massive galaxy.
|
|
||||||
The Milky Way is a small galaxy.
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
@ -1,452 +0,0 @@
|
|||||||
<!--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.
|
|
||||||
|
|
||||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
|
||||||
rendered properly in your Markdown viewer.
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
# الاختيار من متعدد (Multiple choice)
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
مهمة الاختيار من متعدد مشابهة لمهمة الإجابة على الأسئلة، ولكن مع توفير عدة إجابات محتملة مع سياق، ويُدرّب النموذج على تحديد الإجابة الصحيحة.
|
|
||||||
|
|
||||||
سيوضح لك هذا الدليل كيفية:
|
|
||||||
|
|
||||||
1. ضبط نموذج [BERT](https://huggingface.co/google-bert/bert-base-uncased) باستخدام الإعداد `regular` لمجموعة بيانات [SWAG](https://huggingface.co/datasets/swag) لاختيار الإجابة الأفضل من بين الخيارات المتعددة المتاحة مع السياق.
|
|
||||||
2. استخدام النموذج المضبوط للاستدلال.
|
|
||||||
|
|
||||||
قبل البدء، تأكد من تثبيت جميع المكتبات الضرورية:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers datasets evaluate
|
|
||||||
```
|
|
||||||
|
|
||||||
نشجعك على تسجيل الدخول إلى حساب Hugging Face الخاص بك حتى تتمكن من تحميل نموذجك ومشاركته مع المجتمع. عند المطالبة، أدخل الرمز المميز الخاص بك لتسجيل الدخول:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from huggingface_hub import notebook_login
|
|
||||||
|
|
||||||
>>> notebook_login()
|
|
||||||
```
|
|
||||||
|
|
||||||
## تحميل مجموعة بيانات SWAG
|
|
||||||
|
|
||||||
ابدأ بتحميل تهيئة `regular` لمجموعة بيانات SWAG من مكتبة 🤗 Datasets:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from datasets import load_dataset
|
|
||||||
|
|
||||||
>>> swag = load_dataset("swag", "regular")
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم ألق نظرة على مثال:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> swag["train"][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.',
|
|
||||||
'fold-ind': '3416',
|
|
||||||
'gold-source': 'gold',
|
|
||||||
'label': 0,
|
|
||||||
'sent1': 'Members of the procession walk down the street holding small horn brass instruments.',
|
|
||||||
'sent2': 'A drum line',
|
|
||||||
'startphrase': 'Members of the procession walk down the street holding small horn brass instruments. A drum line',
|
|
||||||
'video-id': 'anetv_jkn6uvmqwh4'}
|
|
||||||
```
|
|
||||||
|
|
||||||
على الرغم من أن الحقول تبدو كثيرة، إلا أنها في الواقع بسيطة جداً:
|
|
||||||
|
|
||||||
- `sent1` و `sent2`: يعرض هذان الحقلان بداية الجملة، وبدمجهما معًا، نحصل على حقل `startphrase`.
|
|
||||||
- `ending`: يقترح نهاية محتملة للجملة، واحدة منها فقط هي الصحيحة.
|
|
||||||
- `label`: يحدد نهاية الجملة الصحيحة.
|
|
||||||
|
|
||||||
## المعالجة المسبقة (Preprocess)
|
|
||||||
|
|
||||||
الخطوة التالية هي استدعاء مُجزئ BERT لمعالجة بدايات الجمل والنهايات الأربع المحتملة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
تحتاج دالة المعالجة المسبقة التي تريد إنشاءها إلى:
|
|
||||||
|
|
||||||
1. إنشاء أربع نسخ من حقل `sent1` ودمج كل منها مع `sent2` لإعادة إنشاء كيفية بدء الجملة.
|
|
||||||
2. دمج `sent2` مع كل من نهايات الجمل الأربع المحتملة.
|
|
||||||
3. تتجميع هاتين القائمتين لتتمكن من تجزئتهما، ثم إعادة ترتيبها بعد ذلك بحيث يكون لكل مثال حقول `input_ids` و `attention_mask` و `labels` مقابلة.
|
|
||||||
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> ending_names = ["ending0", "ending1", "ending2", "ending3"]
|
|
||||||
|
|
||||||
>>> def preprocess_function(examples):
|
|
||||||
... first_sentences = [[context] * 4 for context in examples["sent1"]]
|
|
||||||
... question_headers = examples["sent2"]
|
|
||||||
... second_sentences = [
|
|
||||||
... [f"{header} {examples[end][i]}" for end in ending_names] for i, header in enumerate(question_headers)
|
|
||||||
... ]
|
|
||||||
|
|
||||||
... first_sentences = sum(first_sentences, [])
|
|
||||||
... second_sentences = sum(second_sentences, [])
|
|
||||||
|
|
||||||
... tokenized_examples = tokenizer(first_sentences, second_sentences, truncation=True)
|
|
||||||
... return {k: [v[i : i + 4] for i in range(0, len(v), 4)] for k, v in tokenized_examples.items()}
|
|
||||||
```
|
|
||||||
|
|
||||||
لتطبيق دالة المعالجة المسبقة على مجموعة البيانات بأكملها، استخدم طريقة [`~datasets.Dataset.map`] الخاصة بـ 🤗 Datasets. يمكنك تسريع دالة `map` عن طريق تعيين `batched=True` لمعالجة عناصر متعددة من مجموعة البيانات في وقت واحد:
|
|
||||||
|
|
||||||
```py
|
|
||||||
tokenized_swag = swag.map(preprocess_function, batched=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
لا يحتوي 🤗 Transformers على مجمع بيانات للاختيار من متعدد، لذلك ستحتاج إلى تكييف [`DataCollatorWithPadding`] لإنشاء دفعة من الأمثلة. من الأكفأ إضافة حشو (padding) ديناميكي للجمل إلى أطول طول في دفعة أثناء التجميع، بدلاً من حشو مجموعة البيانات بأكملها إلى الحد الأقصى للطول.
|
|
||||||
|
|
||||||
يقوم `DataCollatorForMultipleChoice` بتجميع جميع مدخلات النموذج، ويطبق الحشو، ثم يعيد تجميع النتائج في شكلها الأصلي:
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from dataclasses import dataclass
|
|
||||||
>>> from transformers.tokenization_utils_base import PreTrainedTokenizerBase, PaddingStrategy
|
|
||||||
>>> from typing import Optional, Union
|
|
||||||
>>> import torch
|
|
||||||
|
|
||||||
>>> @dataclass
|
|
||||||
... class DataCollatorForMultipleChoice:
|
|
||||||
... """
|
|
||||||
... Data collator that will dynamically pad the inputs for multiple choice received.
|
|
||||||
... """
|
|
||||||
|
|
||||||
... tokenizer: PreTrainedTokenizerBase
|
|
||||||
... padding: Union[bool, str, PaddingStrategy] = True
|
|
||||||
... max_length: Optional[int] = None
|
|
||||||
... pad_to_multiple_of: Optional[int] = None
|
|
||||||
|
|
||||||
... def __call__(self, features):
|
|
||||||
... label_name = "label" if "label" in features[0].keys() else "labels"
|
|
||||||
... labels = [feature.pop(label_name) for feature in features]
|
|
||||||
... batch_size = len(features)
|
|
||||||
... num_choices = len(features[0]["input_ids"])
|
|
||||||
... flattened_features = [
|
|
||||||
... [{k: v[i] for k, v in feature.items()} for i in range(num_choices)] for feature in features
|
|
||||||
... ]
|
|
||||||
... flattened_features = sum(flattened_features, [])
|
|
||||||
|
|
||||||
... batch = self.tokenizer.pad(
|
|
||||||
... flattened_features,
|
|
||||||
... padding=self.padding,
|
|
||||||
... max_length=self.max_length,
|
|
||||||
... pad_to_multiple_of=self.pad_to_multiple_of,
|
|
||||||
... return_tensors="pt",
|
|
||||||
... )
|
|
||||||
|
|
||||||
... batch = {k: v.view(batch_size, num_choices, -1) for k, v in batch.items()}
|
|
||||||
... batch["labels"] = torch.tensor(labels, dtype=torch.int64)
|
|
||||||
... return batch
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from dataclasses import dataclass
|
|
||||||
>>> from transformers.tokenization_utils_base import PreTrainedTokenizerBase, PaddingStrategy
|
|
||||||
>>> from typing import Optional, Union
|
|
||||||
>>> import tensorflow as tf
|
|
||||||
|
|
||||||
>>> @dataclass
|
|
||||||
... class DataCollatorForMultipleChoice:
|
|
||||||
... """
|
|
||||||
... Data collator that will dynamically pad the inputs for multiple choice received.
|
|
||||||
... """
|
|
||||||
|
|
||||||
... tokenizer: PreTrainedTokenizerBase
|
|
||||||
... padding: Union[bool, str, PaddingStrategy] = True
|
|
||||||
... max_length: Optional[int] = None
|
|
||||||
... pad_to_multiple_of: Optional[int] = None
|
|
||||||
|
|
||||||
... def __call__(self, features):
|
|
||||||
... label_name = "label" if "label" in features[0].keys() else "labels"
|
|
||||||
... labels = [feature.pop(label_name) for feature in features]
|
|
||||||
... batch_size = len(features)
|
|
||||||
... num_choices = len(features[0]["input_ids"])
|
|
||||||
... flattened_features = [
|
|
||||||
... [{k: v[i] for k, v in feature.items()} for i in range(num_choices)] for feature in features
|
|
||||||
... ]
|
|
||||||
... flattened_features = sum(flattened_features, [])
|
|
||||||
|
|
||||||
... batch = self.tokenizer.pad(
|
|
||||||
... flattened_features,
|
|
||||||
... padding=self.padding,
|
|
||||||
... max_length=self.max_length,
|
|
||||||
... pad_to_multiple_of=self.pad_to_multiple_of,
|
|
||||||
... return_tensors="tf",
|
|
||||||
... )
|
|
||||||
|
|
||||||
... batch = {k: tf.reshape(v, (batch_size, num_choices, -1)) for k, v in batch.items()}
|
|
||||||
... batch["labels"] = tf.convert_to_tensor(labels, dtype=tf.int64)
|
|
||||||
... return batch
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
## التقييم (Evaluate)
|
|
||||||
|
|
||||||
يُفضل غالبًا تضمين مقياس أثناء التدريب لتقييم أداء نموذجك. يمكنك تحميل طريقة تقييم بسرعة باستخدام مكتبة 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index). لهذه المهمة، قم بتحميل مقياس [الدقة](https://huggingface.co/spaces/evaluate-metric/accuracy) (انظر إلى [الجولة السريعة](https://huggingface.co/docs/evaluate/a_quick_tour) لـ 🤗 Evaluate لمعرفة المزيد حول كيفية تحميل المقياس وحسابه):
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import evaluate
|
|
||||||
|
|
||||||
>>> accuracy = evaluate.load("accuracy")
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم أنشئ دالة لتمرير التنبؤات والتسميات إلى [`~evaluate.EvaluationModule.compute`] لحساب الدقة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import numpy as np
|
|
||||||
|
|
||||||
>>> def compute_metrics(eval_pred):
|
|
||||||
... predictions, labels = eval_pred
|
|
||||||
... predictions = np.argmax(predictions, axis=1)
|
|
||||||
... return accuracy.compute(predictions=predictions, references=labels)
|
|
||||||
```
|
|
||||||
|
|
||||||
دالتك `compute_metrics` جاهزة الآن، وستعود إليها عند إعداد تدريبك.
|
|
||||||
|
|
||||||
## التدريب (Train)
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن معتادًا على ضبط نموذج باستخدام [`Trainer`], فراجع الدرس الأساسي [هنا](../training#train-with-pytorch-trainer)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
أنت جاهز لبدء تدريب نموذجك الآن! قم بتحميل BERT باستخدام [`AutoModelForMultipleChoice`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForMultipleChoice, TrainingArguments, Trainer
|
|
||||||
|
|
||||||
>>> model = AutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
في هذه المرحلة، تبقى ثلاث خطوات فقط:
|
|
||||||
|
|
||||||
1. حدد معلمات التدريب الخاصة بك في [`TrainingArguments`]. المعلمة الوحيدة المطلوبة هي `output_dir` التي تحدد مكان حفظ نموذجك. ستدفع هذا النموذج إلى Hub عن طريق تعيين `push_to_hub=True` (يجب عليك تسجيل الدخول إلى Hugging Face لتحميل نموذجك). في نهاية كل حقبة، سيقوم [`Trainer`] بتقييم الدقة وحفظ نقطة فحص التدريب.
|
|
||||||
2. مرر معلمات التدريب إلى [`Trainer`] جنبًا إلى جنب مع النموذج ومُجمِّع البيانات والمعالج ودالة تجميع البيانات ودالة `compute_metrics`.
|
|
||||||
3. استدعي [`~Trainer.train`] لضبط نموذجك.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> training_args = TrainingArguments(
|
|
||||||
... output_dir="my_awesome_swag_model",
|
|
||||||
... eval_strategy="epoch",
|
|
||||||
... save_strategy="epoch",
|
|
||||||
... load_best_model_at_end=True,
|
|
||||||
... learning_rate=5e-5,
|
|
||||||
... per_device_train_batch_size=16,
|
|
||||||
... per_device_eval_batch_size=16,
|
|
||||||
... num_train_epochs=3,
|
|
||||||
... weight_decay=0.01,
|
|
||||||
... push_to_hub=True,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer = Trainer(
|
|
||||||
... model=model,
|
|
||||||
... args=training_args,
|
|
||||||
... train_dataset=tokenized_swag["train"],
|
|
||||||
... eval_dataset=tokenized_swag["validation"],
|
|
||||||
... processing_class=tokenizer,
|
|
||||||
... data_collator=DataCollatorForMultipleChoice(tokenizer=tokenizer),
|
|
||||||
... compute_metrics=compute_metrics,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، شارك نموذجك مع Hub باستخدام طريقة [`~transformers.Trainer.push_to_hub`] حتى يتمكن الجميع من استخدام نموذجك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> trainer.push_to_hub()
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن معتادًا على ضبط نموذج باستخدام Keras، فراجع الدرس الأساسي [هنا](../training#train-a-tensorflow-model-with-keras)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
لضبط نموذج في TensorFlow، ابدأ بإعداد دالة مُحسِّن وجدول معدل التعلم وبعض معلمات التدريب:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import create_optimizer
|
|
||||||
|
|
||||||
>>> batch_size = 16
|
|
||||||
>>> num_train_epochs = 2
|
|
||||||
>>> total_train_steps = (len(tokenized_swag["train"]) // batch_size) * num_train_epochs
|
|
||||||
>>> optimizer, schedule = create_optimizer(init_lr=5e-5, num_warmup_steps=0, num_train_steps=total_train_steps)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم يمكنك تحميل BERT باستخدام [`TFAutoModelForMultipleChoice`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForMultipleChoice
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
حوّل مجموعات البيانات الخاصة بك إلى تنسيق `tf.data.Dataset` باستخدام [`~transformers.TFPreTrainedModel.prepare_tf_dataset`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> data_collator = DataCollatorForMultipleChoice(tokenizer=tokenizer)
|
|
||||||
>>> tf_train_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_swag["train"],
|
|
||||||
... shuffle=True,
|
|
||||||
... batch_size=batch_size,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> tf_validation_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_swag["validation"],
|
|
||||||
... shuffle=False,
|
|
||||||
... batch_size=batch_size,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتهيئة النموذج للتدريب باستخدام [`compile`](https://keras.io/api/models/model_training_apis/#compile-method). لاحظ أن جميع نماذج Transformers تحتوي على دالة خسارة مناسبة للمهمة بشكل افتراضي، لذلك لا تحتاج إلى تحديد واحدة ما لم ترغب في ذلك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model.compile(optimizer=optimizer) # لا توجد وسيطة خسارة!
|
|
||||||
```
|
|
||||||
|
|
||||||
الخطوتان الأخيرتان قبل بدء التدريب هما: حساب دقة التنبؤات، وتوفير طريقة لرفع النموذج إلى Hub. ويمكن تحقيق ذلك باستخدام [استدعاءات Keras](../main_classes/keras_callbacks)
|
|
||||||
|
|
||||||
مرر دالتك `compute_metrics` إلى [`~transformers.KerasMetricCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import KerasMetricCallback
|
|
||||||
|
|
||||||
>>> metric_callback = KerasMetricCallback(metric_fn=compute_metrics, eval_dataset=tf_validation_set)
|
|
||||||
```
|
|
||||||
|
|
||||||
حدد مكان دفع نموذجك ومعالجك في [`~transformers.PushToHubCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import PushToHubCallback
|
|
||||||
|
|
||||||
>>> push_to_hub_callback = PushToHubCallback(
|
|
||||||
... output_dir="my_awesome_model",
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم قم بتضمين الاستدعاءات معًا:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> callbacks = [metric_callback, push_to_hub_callback]
|
|
||||||
```
|
|
||||||
|
|
||||||
أخيرًا، أنت جاهز لبدء تدريب نموذجك! استدعِ[`fit`](https://keras.io/api/models/model_training_apis/#fit-method) مع مجموعات بيانات التدريب والتحقق من الصحة وعدد الحقب والاستدعاءات لضبط النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model.fit(x=tf_train_set, validation_data=tf_validation_set, epochs=2, callbacks=callbacks)
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، يتم تحميل نموذجك تلقائيًا إلى Hub حتى يتمكن الجميع من استخدامه!
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للحصول على مثال أكثر تعمقًا حول كيفية ضبط نموذج للاختيار من متعدد، ألق نظرة على [دفتر ملاحظات PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb)
|
|
||||||
أو [دفتر ملاحظات TensorFlow](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice-tf.ipynb) المقابل.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## الاستدلال (Inference)
|
|
||||||
|
|
||||||
رائع، الآن بعد أن قمت بضبط نموذج، يمكنك استخدامه للاستدلال!
|
|
||||||
|
|
||||||
قم بإنشاء نص واقتراح إجابتين محتملتين:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> prompt = "France has a bread law, Le Décret Pain, with strict rules on what is allowed in a traditional baguette."
|
|
||||||
>>> candidate1 = "The law does not apply to croissants and brioche."
|
|
||||||
>>> candidate2 = "The law applies to baguettes."
|
|
||||||
```
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
قم بتحليل كل مطالبة وزوج إجابة مرشح وأعد تنسورات PyTorch. يجب عليك أيضًا إنشاء بعض `العلامات`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_swag_model")
|
|
||||||
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="pt", padding=True)
|
|
||||||
>>> labels = torch.tensor(0).unsqueeze(0)
|
|
||||||
```
|
|
||||||
|
|
||||||
مرر مدخلاتك والعلامات إلى النموذج وأرجع`logits`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForMultipleChoice
|
|
||||||
|
|
||||||
>>> model = AutoModelForMultipleChoice.from_pretrained("username/my_awesome_swag_model")
|
|
||||||
>>> outputs = model(**{k: v.unsqueeze(0) for k, v in inputs.items()}, labels=labels)
|
|
||||||
>>> logits = outputs.logits
|
|
||||||
```
|
|
||||||
|
|
||||||
استخرج الفئة ذات الاحتمالية الأكبر:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> predicted_class = logits.argmax().item()
|
|
||||||
>>> predicted_class
|
|
||||||
0
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
قم بتحليل كل مطالبة وزوج إجابة مرشح وأعد موترات TensorFlow:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_swag_model")
|
|
||||||
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="tf", padding=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
مرر مدخلاتك إلى النموذج وأعد القيم logits:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForMultipleChoice
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForMultipleChoice.from_pretrained("username/my_awesome_swag_model")
|
|
||||||
>>> inputs = {k: tf.expand_dims(v, 0) for k, v in inputs.items()}
|
|
||||||
>>> outputs = model(inputs)
|
|
||||||
>>> logits = outputs.logits
|
|
||||||
```
|
|
||||||
|
|
||||||
استخرج الفئة ذات الاحتمالية الأكبر:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> predicted_class = int(tf.math.argmax(logits, axis=-1)[0])
|
|
||||||
>>> predicted_class
|
|
||||||
0
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
@ -1,432 +0,0 @@
|
|||||||
<!--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.
|
|
||||||
|
|
||||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
|
||||||
rendered properly in your Markdown viewer.
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
# الإجابة على الأسئلة (Question answering)
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
<Youtube id="ajPx5LwJD-I"/>
|
|
||||||
|
|
||||||
تُقدّم مهام الإجابة على الأسئلة إجابةً بناءً على سؤال. إذا سبق لك أن سألت مساعدًا افتراضيًا مثل Alexa أو Siri أو Google عن حالة الطقس، فأنت قد استخدمت نموذج للإجابة على الأسئلة من قبل. هناك نوعان شائعان لمهام الإجابة على الأسئلة:
|
|
||||||
|
|
||||||
- الاستخراجية: استخراج الإجابة من السياق المحدد.
|
|
||||||
- التلخيصية: إنشاء إجابة من السياق تجيب على السؤال بشكل صحيح.
|
|
||||||
|
|
||||||
سيوضح لك هذا الدليل كيفية:
|
|
||||||
|
|
||||||
1. ضبط [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) على مجموعة بيانات [SQuAD](https://huggingface.co/datasets/squad) للإجابة على الأسئلة الاستخراجية.
|
|
||||||
2. استخدام النموذج المضبوط للاستدلال.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
لمشاهدة جميع الهياكل والنسخ المتوافقة مع هذه المهمة، نوصي بالرجوع إلى [صفحة المهمة](https://huggingface.co/tasks/question-answering)
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
قبل البدء، تأكد من تثبيت جميع المكتبات الضرورية:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers datasets evaluate
|
|
||||||
```
|
|
||||||
|
|
||||||
نشجعك على تسجيل الدخول إلى حساب Hugging Face الخاص بك حتى تتمكن من تحميل نموذجك ومشاركته مع المجتمع. عند المطالبة، أدخل الرمز المميز الخاص بك لتسجيل الدخول:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from huggingface_hub import notebook_login
|
|
||||||
|
|
||||||
>>> notebook_login()
|
|
||||||
```
|
|
||||||
|
|
||||||
## تحميل مجموعة بيانات SQuAD
|
|
||||||
|
|
||||||
ابدأ بتحميل جزء أصغر من مجموعة بيانات SQuAD من مكتبة 🤗 Datasets. سيتيح لك ذلك فرصة للتجربة والتحقق من عمل كل شيء بشكل صحيح قبل قضاء المزيد من الوقت في التدريب على مجموعة البيانات الكاملة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from datasets import load_dataset
|
|
||||||
|
|
||||||
>>> squad = load_dataset("squad", split="train[:5000]")
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتقسيم تقسيم `train` لمجموعة البيانات إلى مجموعة تدريب واختبار باستخدام طريقة [`~datasets.Dataset.train_test_split`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> squad = squad.train_test_split(test_size=0.2)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم ألق نظرة على مثال:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> squad["train"][0]
|
|
||||||
{'answers': {'answer_start': [515], 'text': ['Saint Bernadette Soubirous']},
|
|
||||||
'context': 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.',
|
|
||||||
'id': '5733be284776f41900661182',
|
|
||||||
'question': 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?',
|
|
||||||
'title': 'University_of_Notre_Dame'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
هناك العديد من الحقول المهمة هنا:
|
|
||||||
|
|
||||||
- `answers`: موقع بداية الرمز المميز للإجابة ونص الإجابة.
|
|
||||||
- `context`: معلومات أساسية يحتاج النموذج إلى استخراج الإجابة منها.
|
|
||||||
- `question`: السؤال الذي يجب على النموذج الإجابة عليه.
|
|
||||||
|
|
||||||
## المعالجة المسبقة (Preprocess)
|
|
||||||
|
|
||||||
<Youtube id="qgaM0weJHpA"/>
|
|
||||||
|
|
||||||
الخطوة التالية هي تحميل المحلل اللغوى DistilBERT لمعالجة حقلي `question` و `context`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
هناك بعض خطوات المعالجة المسبقة الخاصة بمهام الإجابة على الأسئلة التي يجب أن تكون على دراية بها:
|
|
||||||
|
|
||||||
1. قد تحتوي بعض الأمثلة في مجموعة البيانات على `context` طويلًا يتجاوز الحد الأقصى لطول مدخل النموذج. للتعامل مع النصوص الأطول، يتم اقتطاع `context` فقط عن طريق تعيين `truncation="only_second"`.
|
|
||||||
2. بعد ذلك، يتم تحديد مواضع بداية ونهاية الإجابة في `context` الأصلي عن طريق تعيين
|
|
||||||
`return_offset_mapping=True`.
|
|
||||||
3. باستخدام التعيين، يمكن الآن تحديد رموز بداية ونهاية الإجابة. استخدم طريقة [`~tokenizers.Encoding.sequence_ids`]
|
|
||||||
لتحديد أجزاء الإزاحة التي تتوافق مع `question` و `context`.
|
|
||||||
|
|
||||||
فيما يلي كيفية إنشاء دالة لقص وتعيين رموز البداية والنهاية لـ `answer` إلى `context`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> def preprocess_function(examples):
|
|
||||||
... questions = [q.strip() for q in examples["question"]]
|
|
||||||
... inputs = tokenizer(
|
|
||||||
... questions,
|
|
||||||
... examples["context"],
|
|
||||||
... max_length=384,
|
|
||||||
... truncation="only_second",
|
|
||||||
... return_offsets_mapping=True,
|
|
||||||
... padding="max_length",
|
|
||||||
... )
|
|
||||||
|
|
||||||
... offset_mapping = inputs.pop("offset_mapping")
|
|
||||||
... answers = examples["answers"]
|
|
||||||
... start_positions = []
|
|
||||||
... end_positions = []
|
|
||||||
|
|
||||||
... for i, offset in enumerate(offset_mapping):
|
|
||||||
... answer = answers[i]
|
|
||||||
... start_char = answer["answer_start"][0]
|
|
||||||
... end_char = answer["answer_start"][0] + len(answer["text"][0])
|
|
||||||
... sequence_ids = inputs.sequence_ids(i)
|
|
||||||
|
|
||||||
... # Find the start and end of the context
|
|
||||||
... idx = 0
|
|
||||||
... while sequence_ids[idx] != 1:
|
|
||||||
... idx += 1
|
|
||||||
... context_start = idx
|
|
||||||
... while sequence_ids[idx] == 1:
|
|
||||||
... idx += 1
|
|
||||||
... context_end = idx - 1
|
|
||||||
|
|
||||||
... # If the answer is not fully inside the context, label it (0, 0)
|
|
||||||
... if offset[context_start][0] > end_char or offset[context_end][1] < start_char:
|
|
||||||
... start_positions.append(0)
|
|
||||||
... end_positions.append(0)
|
|
||||||
... else:
|
|
||||||
... # Otherwise it's the start and end token positions
|
|
||||||
... idx = context_start
|
|
||||||
... while idx <= context_end and offset[idx][0] <= start_char:
|
|
||||||
... idx += 1
|
|
||||||
... start_positions.append(idx - 1)
|
|
||||||
|
|
||||||
... idx = context_end
|
|
||||||
... while idx >= context_start and offset[idx][1] >= end_char:
|
|
||||||
... idx -= 1
|
|
||||||
... end_positions.append(idx + 1)
|
|
||||||
|
|
||||||
... inputs["start_positions"] = start_positions
|
|
||||||
... inputs["end_positions"] = end_positions
|
|
||||||
... return inputs
|
|
||||||
```
|
|
||||||
|
|
||||||
لتطبيق المعالجة المسبقة على كامل مجموعة البيانات، استخدم [`~datasets.Dataset.map`] من مكتبة 🤗 Datasets. يمكنك تسريع دالة `map` عن طريق تعيين `batched=True` لمعالجة عناصر متعددة من مجموعة البيانات دفعة واحدة. قم بإزالة أي أعمدة لا تحتاجها:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenized_squad = squad.map(preprocess_function, batched=True, remove_columns=squad["train"].column_names)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن قم بإنشاء دفعة من الأمثلة باستخدام [`DefaultDataCollator`]. بخلاف مجمّعات البيانات الأخرى في 🤗 Transformers، لا يطبق [`DefaultDataCollator`] أي معالجة مسبقة إضافية مثل الحشو.
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DefaultDataCollator
|
|
||||||
|
|
||||||
>>> data_collator = DefaultDataCollator()
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DefaultDataCollator
|
|
||||||
|
|
||||||
>>> data_collator = DefaultDataCollator(return_tensors="tf")
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
## التدريب (Train)
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن معتادًا على ضبط نموذج باستخدام [`Trainer`], ألق نظرة على البرنامج التعليمي الأساسي [هنا](../training#train-with-pytorch-trainer)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
أنت جاهز لبدء تدريب نموذجك الآن! قم بتحميل DistilBERT باستخدام [`AutoModelForQuestionAnswering`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForQuestionAnswering, TrainingArguments, Trainer
|
|
||||||
|
|
||||||
>>> model = AutoModelForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
في هذه المرحلة، تبقى ثلاث خطوات فقط:
|
|
||||||
|
|
||||||
1. حدد المعاملات الفائقة للتدريب في [`TrainingArguments`]. المعامل الوحيد المطلوب هو `output_dir` الذي يحدد مكان حفظ نموذجك. ستدفع هذا النموذج إلى Hub عن طريق تعيين `push_to_hub=True` (يجب عليك تسجيل الدخول إلى Hugging Face لتحميل نموذجك).
|
|
||||||
2. مرر معاملات التدريب إلى [`Trainer`] جنبًا إلى جنب مع النموذج، ومجموعة البيانات، والمُحلّل النصي، ومُجمّع البيانات.
|
|
||||||
3. استدعِ ـ [`~Trainer.train`] لضبط النموذج.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> training_args = TrainingArguments(
|
|
||||||
... output_dir="my_awesome_qa_model",
|
|
||||||
... eval_strategy="epoch",
|
|
||||||
... learning_rate=2e-5,
|
|
||||||
... per_device_train_batch_size=16,
|
|
||||||
... per_device_eval_batch_size=16,
|
|
||||||
... num_train_epochs=3,
|
|
||||||
... weight_decay=0.01,
|
|
||||||
... push_to_hub=True,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer = Trainer(
|
|
||||||
... model=model,
|
|
||||||
... args=training_args,
|
|
||||||
... train_dataset=tokenized_squad["train"],
|
|
||||||
... eval_dataset=tokenized_squad["test"],
|
|
||||||
... processing_class=tokenizer,
|
|
||||||
... data_collator=data_collator,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، شارك نموذجك في Hub باستخدام الدالة [`~transformers.Trainer.push_to_hub`] حتى يتمكن الجميع من استخدام نموذجك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> trainer.push_to_hub()
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن معتادًا على ضبط نموذج باستخدام Keras، فألق نظرة على البرنامج التعليمي الأساسي [هنا](../training#train-a-tensorflow-model-with-keras)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
لضبط نموذج في TensorFlow، ابدأ بإعداد دالة مُحسِّن، وجدول معدل التعلم، وبعض المعاملات الفائقة للتدريب:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import create_optimizer
|
|
||||||
|
|
||||||
>>> batch_size = 16
|
|
||||||
>>> num_epochs = 2
|
|
||||||
>>> total_train_steps = (len(tokenized_squad["train"]) // batch_size) * num_epochs
|
|
||||||
>>> optimizer, schedule = create_optimizer(
|
|
||||||
... init_lr=2e-5,
|
|
||||||
... num_warmup_steps=0,
|
|
||||||
... num_train_steps=total_train_steps,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم يمكنك تحميل DistilBERT باستخدام [`TFAutoModelForQuestionAnswering`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForQuestionAnswering
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
حوّل مجموعات البيانات الخاصة بك إلى تنسيق `tf.data.Dataset` باستخدام [`~transformers.TFPreTrainedModel.prepare_tf_dataset`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tf_train_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_squad["train"],
|
|
||||||
... shuffle=True,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> tf_validation_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_squad["test"],
|
|
||||||
... shuffle=False,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتكوين النموذج للتدريب باستخدام [`compile`](https://keras.io/api/models/model_training_apis/#compile-method):
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import tensorflow as tf
|
|
||||||
|
|
||||||
>>> model.compile(optimizer=optimizer)
|
|
||||||
```
|
|
||||||
|
|
||||||
آخر شيء يجب إعداده قبل بدء التدريب هو توفير طريقة لدفع نموذجك إلى Hub. يمكن القيام بذلك عن طريق تحديد مكان دفع نموذجك ومعالجك المعجمي في [`~transformers.PushToHubCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import PushToHubCallback
|
|
||||||
|
|
||||||
>>> callback = PushToHubCallback(
|
|
||||||
... output_dir="my_awesome_qa_model",
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
أخيرًا، أنت جاهز لبدء تدريب نموذجك! اتصل بـ [`fit`](https://keras.io/api/models/model_training_apis/#fit-method) مع مجموعات بيانات التدريب والتحقق من الصحة، وعدد العهود، ومعاودة الاتصال الخاصة بك لضبط النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model.fit(x=tf_train_set, validation_data=tf_validation_set, epochs=3, callbacks=[callback])
|
|
||||||
```
|
|
||||||
بمجرد اكتمال التدريب، يتم تحميل نموذجك تلقائيًا إلى Hub حتى يتمكن الجميع من استخدامه!
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للحصول على مثال أكثر تعمقًا حول كيفية ضبط نموذج للإجابة على الأسئلة، ألق نظرة على [دفتر ملاحظات PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering.ipynb) المقابل
|
|
||||||
أو [دفتر ملاحظات TensorFlow](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/question_answering-tf.ipynb).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## التقييم (Evaluate)
|
|
||||||
|
|
||||||
يتطلب التقييم للإجابة على الأسئلة قدرًا كبيرًا من المعالجة اللاحقة. لتوفير وقتك، يتخطى هذا الدليل خطوة التقييم. لا يزال [`Trainer`] يحسب خسارة التقييم أثناء التدريب، مما يعني أنك لست تجهل تمامًا أداء نموذجك.
|
|
||||||
|
|
||||||
إذا كان لديك المزيد من الوقت وتهتم بكيفية تقييم نموذجك للإجابة على الأسئلة، فألق نظرة على فصل [الإجابة على الأسئلة](https://huggingface.co/course/chapter7/7?fw=pt#post-processing) من دورة 🤗 Hugging Face!
|
|
||||||
|
|
||||||
## الاستدلال (Inference)
|
|
||||||
|
|
||||||
رائع، الآن بعد أن قمت بضبط نموذج، يمكنك استخدامه للاستدلال!
|
|
||||||
|
|
||||||
حدد سؤالًا وسياقًا ليقوم النموذج بالتنبؤ بالإجابة عليه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> question = "How many programming languages does BLOOM support?"
|
|
||||||
>>> context = "BLOOM has 176 billion parameters and can generate text in 46 languages natural languages and 13 programming languages."
|
|
||||||
```
|
|
||||||
|
|
||||||
أبسط طريقة لتجربة نموذجك المُدرَّب للاستدلال هي استخدامه في [`pipeline`]. قم بإنشاء كائن لـ `pipeline` للإجابة على الأسئلة باستخدام نموذجك، ومرِّر النص إليه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> question_answerer = pipeline("question-answering", model="my_awesome_qa_model")
|
|
||||||
>>> question_answerer(question=question, context=context)
|
|
||||||
{'score': 0.2058267742395401,
|
|
||||||
'start': 10,
|
|
||||||
'end': 95,
|
|
||||||
'answer': '176 مليار معامل ويمكنه إنشاء نصوص بـ 46 لغة طبيعية و 13'}
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك أيضًا تكرار نتائج `pipeline` يدويًا إذا أردت:
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
قسّم النص وأرجع تنسورات PyTorch:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_qa_model")
|
|
||||||
>>> inputs = tokenizer(question, context, return_tensors="pt")
|
|
||||||
```
|
|
||||||
|
|
||||||
مرر مدخلاتك إلى النموذج وأرجع `logits`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import torch
|
|
||||||
>>> from transformers import AutoModelForQuestionAnswering
|
|
||||||
|
|
||||||
>>> model = AutoModelForQuestionAnswering.from_pretrained("my_awesome_qa_model")
|
|
||||||
>>> with torch.no_grad():
|
|
||||||
... outputs = model(**inputs)
|
|
||||||
```
|
|
||||||
|
|
||||||
احصل على أعلى احتمال من مخرجات النموذج لموضعي البداية والنهاية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> answer_start_index = outputs.start_logits.argmax()
|
|
||||||
>>> answer_end_index = outputs.end_logits.argmax()
|
|
||||||
```
|
|
||||||
|
|
||||||
استخلاص الإجابة من الرموز المتوقعة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> predict_answer_tokens = inputs.input_ids[0, answer_start_index : answer_end_index + 1]
|
|
||||||
>>> tokenizer.decode(predict_answer_tokens)
|
|
||||||
'176 billion parameters and can generate text in 46 languages natural languages and 13'
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
قم بتحليل النص المعجمي وأعد موترات TensorFlow:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_qa_model")
|
|
||||||
>>> inputs = tokenizer(question, context, return_tensors="tf")
|
|
||||||
```
|
|
||||||
|
|
||||||
مرر مدخلاتك إلى النموذج وأعد `logits`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForQuestionAnswering
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForQuestionAnswering.from_pretrained("my_awesome_qa_model")
|
|
||||||
>>> outputs = model(**inputs)
|
|
||||||
```
|
|
||||||
|
|
||||||
احصل على أعلى احتمال من مخرجات النموذج لموضعي البداية والنهاية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> answer_start_index = int(tf.math.argmax(outputs.start_logits, axis=-1)[0])
|
|
||||||
>>> answer_end_index = int(tf.math.argmax(outputs.end_logits, axis=-1)[0])
|
|
||||||
```
|
|
||||||
|
|
||||||
استخلاص الإجابة من الرموز المتوقعة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> predict_answer_tokens = inputs.input_ids[0, answer_start_index : answer_end_index + 1]
|
|
||||||
>>> tokenizer.decode(predict_answer_tokens)
|
|
||||||
'176 billion parameters and can generate text in 46 languages natural languages and 13'
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
@ -1,387 +0,0 @@
|
|||||||
<!--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.
|
|
||||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
|
||||||
rendered properly in your Markdown viewer.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# تصنيف النص(Text classification)
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
<Youtube id="leNG9fN9FQU"/>
|
|
||||||
|
|
||||||
تصنيف النص هو مهمة NLP شائعة حيث يُعيّن تصنيفًا أو فئة للنص. تستخدم بعض أكبر الشركات تصنيف النصوص في الإنتاج لمجموعة واسعة من التطبيقات العملية. أحد أكثر أشكال تصنيف النص شيوعًا هو تحليل المشاعر، والذي يقوم بتعيين تسمية مثل 🙂 إيجابية، 🙁 سلبية، أو 😐 محايدة لتسلسل نصي.
|
|
||||||
|
|
||||||
سيوضح لك هذا الدليل كيفية:
|
|
||||||
|
|
||||||
1. ضبط [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) على مجموعة بيانات [IMDb](https://huggingface.co/datasets/imdb) لتحديد ما إذا كانت مراجعة الفيلم إيجابية أو سلبية.
|
|
||||||
2. استخدام نموذج الضبط الدقيق للتنبؤ.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
لرؤية جميع البنى ونقاط التحقق المتوافقة مع هذه المهمة، نوصي بالتحقق من [صفحة المهمة](https://huggingface.co/tasks/text-classification).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
قبل أن تبدأ، تأكد من تثبيت جميع المكتبات الضرورية:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers datasets evaluate accelerate
|
|
||||||
```
|
|
||||||
|
|
||||||
نحن نشجعك على تسجيل الدخول إلى حساب Hugging Face الخاص بك حتى تتمكن من تحميل ومشاركة نموذجك مع المجتمع. عند المطالبة، أدخل رمزك لتسجيل الدخول:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from huggingface_hub import notebook_login
|
|
||||||
|
|
||||||
>>> notebook_login()
|
|
||||||
```
|
|
||||||
|
|
||||||
## تحميل مجموعة بيانات IMDb
|
|
||||||
|
|
||||||
ابدأ بتحميل مجموعة بيانات IMDb من مكتبة 🤗 Datasets:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from datasets import load_dataset
|
|
||||||
|
|
||||||
>>> imdb = load_dataset("imdb")
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم ألق نظرة على مثال:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> imdb["test"][0]
|
|
||||||
{
|
|
||||||
"label": 0,
|
|
||||||
"text": "I love sci-fi and am willing to put up with a lot. Sci-fi movies/TV are usually underfunded, under-appreciated and misunderstood. I tried to like this, I really did, but it is to good TV sci-fi as Babylon 5 is to Star Trek (the original). Silly prosthetics, cheap cardboard sets, stilted dialogues, CG that doesn't match the background, and painfully one-dimensional characters cannot be overcome with a 'sci-fi' setting. (I'm sure there are those of you out there who think Babylon 5 is good sci-fi TV. It's not. It's clichéd and uninspiring.) While US viewers might like emotion and character development, sci-fi is a genre that does not take itself seriously (cf. Star Trek). It may treat important issues, yet not as a serious philosophy. It's really difficult to care about the characters here as they are not simply foolish, just missing a spark of life. Their actions and reactions are wooden and predictable, often painful to watch. The makers of Earth KNOW it's rubbish as they have to always say \"Gene Roddenberry's Earth...\" otherwise people would not continue watching. Roddenberry's ashes must be turning in their orbit as this dull, cheap, poorly edited (watching it without advert breaks really brings this home) trudging Trabant of a show lumbers into space. Spoiler. So, kill off a main character. And then bring him back as another actor. Jeeez! Dallas all over again.",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
هناك حقولان في هذه المجموعة من البيانات:
|
|
||||||
|
|
||||||
- `text`: نص مراجعة الفيلم.
|
|
||||||
- `label`: قيمة إما `0` لمراجعة سلبية أو `1` لمراجعة إيجابية.
|
|
||||||
|
|
||||||
## المعالجة المسبقة(Preprocess)
|
|
||||||
|
|
||||||
الخطوة التالية هي تحميل المُجزِّئ النص DistilBERT لتهيئة لحقل `text`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
أنشئ دالة لتهيئة حقل `text` وتقصير السلاسل النصية بحيث لا يتجاوز طولها الحد الأقصى لإدخالات DistilBERT:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> def preprocess_function(examples):
|
|
||||||
... return tokenizer(examples["text"], truncation=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
لتطبيق دالة التهيئة على مجموعة البيانات بأكملها، استخدم دالة 🤗 Datasets [`~datasets.Dataset.map`] . يمكنك تسريع `map` باستخدام `batched=True` لمعالجة دفعات من البيانات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
tokenized_imdb = imdb.map(preprocess_function, batched=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن قم بإنشاء دفعة من الأمثلة باستخدام [`DataCollatorWithPadding`]. الأكثر كفاءة هو استخدام الحشو الديناميكي لجعل الجمل متساوية في الطول داخل كل دفعة، بدلًا من حشو كامل البيانات إلى الحد الأقصى للطول.
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorWithPadding
|
|
||||||
|
|
||||||
>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorWithPadding
|
|
||||||
|
|
||||||
>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf")
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
## التقييم(Evaluate)
|
|
||||||
|
|
||||||
يُعدّ تضمين مقياس أثناء التدريب مفيدًا لتقييم أداء النموذج. يمكنك تحميل طريقة تقييم بسرعة باستخدام مكتبة 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) . بالنسبة لهذه المهمة، قم بتحميل مقياس [الدقة](https://huggingface.co/spaces/evaluate-metric/accuracy) (راجع جولة 🤗 Evaluate [السريعة](https://huggingface.co/docs/evaluate/a_quick_tour) لمعرفة المزيد حول كيفية تحميل وحساب مقياس):
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import evaluate
|
|
||||||
|
|
||||||
>>> accuracy = evaluate.load("accuracy")
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم أنشئ دالة تقوم بتمرير تنبؤاتك وتصنيفاتك إلى [`~evaluate.EvaluationModule.compute`] لحساب الدقة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import numpy as np
|
|
||||||
|
|
||||||
>>> def compute_metrics(eval_pred):
|
|
||||||
... predictions, labels = eval_pred
|
|
||||||
... predictions = np.argmax(predictions, axis=1)
|
|
||||||
... return accuracy.compute(predictions=predictions, references=labels)
|
|
||||||
```
|
|
||||||
|
|
||||||
دالة `compute_metrics` جاهزة الآن، وستعود إليها عند إعداد التدريب.
|
|
||||||
|
|
||||||
## التدريب(Train)
|
|
||||||
|
|
||||||
قبل أن تبدأ في تدريب نموذجك، قم بإنشاء خريطة من المعرفات المتوقعة إلى تسمياتها باستخدام `id2label` و `label2id`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> id2label = {0: "NEGATIVE", 1: "POSITIVE"}
|
|
||||||
>>> label2id = {"NEGATIVE": 0, "POSITIVE": 1}
|
|
||||||
```
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بضبط نموذج دقيق باستخدام [`Trainer`], فالق نظرة على البرنامج التعليمي الأساسي [هنا](../training#train-with-pytorch-trainer)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
أنت مستعد الآن لبدء تدريب نموذجك! قم بتحميل DistilBERT مع [`AutoModelForSequenceClassification`] جنبًا إلى جنب مع عدد التصنيفات المتوقعة، وتصنيفات الخرائط:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer
|
|
||||||
|
|
||||||
>>> model = AutoModelForSequenceClassification.from_pretrained(
|
|
||||||
... "distilbert/distilbert-base-uncased", num_labels=2, id2label=id2label, label2id=label2id
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
في هذه المرحلة، هناك ثلاث خطوات فقط متبقية:
|
|
||||||
|
|
||||||
1. حدد مُعامِلات التدريب في [`TrainingArguments`]. المُعامل المطلوب الوحيد هو `output_dir`، لتحديد مكان حفظ النموذج. يمكنك رفع النموذج إلى Hub بتعيين `push_to_hub=True` (يجب تسجيل الدخول إلى Hugging Face لرفع النموذج). سيقوم `Trainer` بتقييم الدقة وحفظ نقاط التحقق في نهاية كل حقبة.
|
|
||||||
2. مرر مُعامِلات التدريب إلى `Trainer` مع النموذج، ومجموعة البيانات، والمحلل اللغوي، ومُجمِّع البيانات، ووظيفة `compute_metrics`.
|
|
||||||
3. استدعِ [`~Trainer.train`] لضبط النموذج.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> training_args = TrainingArguments(
|
|
||||||
... output_dir="my_awesome_model",
|
|
||||||
... learning_rate=2e-5,
|
|
||||||
... per_device_train_batch_size=16,
|
|
||||||
... per_device_eval_batch_size=16,
|
|
||||||
... num_train_epochs=2,
|
|
||||||
... weight_decay=0.01,
|
|
||||||
... eval_strategy="epoch",
|
|
||||||
... save_strategy="epoch",
|
|
||||||
... load_best_model_at_end=True,
|
|
||||||
... push_to_hub=True,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer = Trainer(
|
|
||||||
... model=model,
|
|
||||||
... args=training_args,
|
|
||||||
... train_dataset=tokenized_imdb["train"],
|
|
||||||
... eval_dataset=tokenized_imdb["test"],
|
|
||||||
... processing_class=tokenizer,
|
|
||||||
... data_collator=data_collator,
|
|
||||||
... compute_metrics=compute_metrics,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
يستخدم [`Trainer`] الحشو الديناميكي افتراضيًا عند تمرير `tokenizer` إليه. في هذه الحالة، لا تحتاج لتحديد مُجمِّع البيانات صراحةً.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
بعد اكتمال التدريب، شارك نموذجك على Hub باستخدام الطريقة [`~transformers.Trainer.push_to_hub`] ليستخدمه الجميع:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> trainer.push_to_hub()
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بضبط نموذج باستخدام Keras، قم بالاطلاع على البرنامج التعليمي الأساسي [هنا](../training#train-a-tensorflow-model-with-keras)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
لضبط نموذج في TensorFlow، ابدأ بإعداد دالة المحسن، وجدول معدل التعلم، وبعض معلمات التدريب:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import create_optimizer
|
|
||||||
>>> import tensorflow as tf
|
|
||||||
|
|
||||||
>>> batch_size = 16
|
|
||||||
>>> num_epochs = 5
|
|
||||||
>>> batches_per_epoch = len(tokenized_imdb["train"]) // batch_size
|
|
||||||
>>> total_train_steps = int(batches_per_epoch * num_epochs)
|
|
||||||
>>> optimizer, schedule = create_optimizer(init_lr=2e-5, num_warmup_steps=0, num_train_steps=total_train_steps)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم يمكنك تحميل DistilBERT مع [`TFAutoModelForSequenceClassification`] بالإضافة إلى عدد التصنيفات المتوقعة، وتعيينات التسميات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForSequenceClassification
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForSequenceClassification.from_pretrained(
|
|
||||||
... "distilbert/distilbert-base-uncased", num_labels=2, id2label=id2label, label2id=label2id
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتحويل مجموعات بياناتك إلى تنسيق `tf.data.Dataset` باستخدام [`~transformers.TFPreTrainedModel.prepare_tf_dataset`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tf_train_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_imdb["train"],
|
|
||||||
... shuffle=True,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> tf_validation_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_imdb["test"],
|
|
||||||
... shuffle=False,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتهيئة النموذج للتدريب باستخدام [`compile`](https://keras.io/api/models/model_training_apis/#compile-method). لاحظ أن جميع نماذج Transformers لديها دالة خسارة ذات صلة بالمهمة بشكل افتراضي، لذلك لا تحتاج إلى تحديد واحدة ما لم ترغب في ذلك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import tensorflow as tf
|
|
||||||
|
|
||||||
>>> model.compile(optimizer=optimizer) # No loss argument!
|
|
||||||
```
|
|
||||||
|
|
||||||
آخر أمرين يجب إعدادهما قبل بدء التدريب هو حساب الدقة من التوقعات، وتوفير طريقة لدفع نموذجك إلى Hub. يتم ذلك باستخدام [Keras callbacks](../main_classes/keras_callbacks).
|
|
||||||
|
|
||||||
قم بتمرير دالة `compute_metrics` الخاصة بك إلى [`~transformers.KerasMetricCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import KerasMetricCallback
|
|
||||||
|
|
||||||
>>> metric_callback = KerasMetricCallback(metric_fn=compute_metrics, eval_dataset=tf_validation_set)
|
|
||||||
```
|
|
||||||
|
|
||||||
حدد مكان دفع نموذجك والمجزئ اللغوي في [`~transformers.PushToHubCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import PushToHubCallback
|
|
||||||
|
|
||||||
>>> push_to_hub_callback = PushToHubCallback(
|
|
||||||
... output_dir="my_awesome_model",
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم اجمع الاستدعاءات معًا:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> callbacks = [metric_callback, push_to_hub_callback]
|
|
||||||
```
|
|
||||||
|
|
||||||
أخيرًا، أنت مستعد لبدء تدريب نموذجك! قم باستدعاء [`fit`](https://keras.io/api/models/model_training_apis/#fit-method) مع مجموعات بيانات التدريب والتحقق، وعدد الحقبات، واستدعاءاتك لضبط النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model.fit(x=tf_train_set, validation_data=tf_validation_set, epochs=3, callbacks=callbacks)
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، يتم تحميل نموذجك تلقائيًا إلى Hub حتى يتمكن الجميع من استخدامه!
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للحصول على مثال أكثر عمقًا حول كيفية ضبط نموذج لتصنيف النصوص، قم بالاطلاع على الدفتر المقابل
|
|
||||||
[دفتر PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb)
|
|
||||||
أو [دفتر TensorFlow](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification-tf.ipynb).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## الاستدلال(Inference)
|
|
||||||
|
|
||||||
رائع، الآن بعد أن قمت بضبط نموذج، يمكنك استخدامه للاستدلال!
|
|
||||||
|
|
||||||
احصل على بعض النصوص التي ترغب في إجراء الاستدلال عليها:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> text = "This was a masterpiece. Not completely faithful to the books, but enthralling from beginning to end. Might be my favorite of the three."
|
|
||||||
```
|
|
||||||
|
|
||||||
أسهل طريقة لتجربة النموذج المضبوط للاستدلال هي استخدامه ضمن [`pipeline`]. قم بإنشاء `pipeline` لتحليل المشاعر مع نموذجك، ومرر نصك إليه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> classifier = pipeline("sentiment-analysis", model="stevhliu/my_awesome_model")
|
|
||||||
>>> classifier(text)
|
|
||||||
[{'label': 'POSITIVE', 'score': 0.9994940757751465}]
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك أيضًا تكرار نتائج `pipeline` يدويًا إذا أردت:
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
قم يتجزئة النص وإرجاع تنسورات PyTorch:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")
|
|
||||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
|
||||||
```
|
|
||||||
|
|
||||||
مرر المدخلات إلى النموذج واسترجع `logits`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForSequenceClassification
|
|
||||||
|
|
||||||
>>> model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model")
|
|
||||||
>>> with torch.no_grad():
|
|
||||||
... logits = model(**inputs).logits
|
|
||||||
```
|
|
||||||
|
|
||||||
استخرج الفئة ذات الاحتمالية الأعلى، واستخدم `id2label` لتحويلها إلى تصنيف نصي:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> predicted_class_id = logits.argmax().item()
|
|
||||||
>>> model.config.id2label[predicted_class_id]
|
|
||||||
'POSITIVE'
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
قم بتحليل النص وإرجاع تنسيقات TensorFlow:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")
|
|
||||||
>>> inputs = tokenizer(text, return_tensors="tf")
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتمرير مدخلاتك إلى النموذج وإرجاع `logits`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForSequenceClassification
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model")
|
|
||||||
>>> logits = model(**inputs).logits
|
|
||||||
```
|
|
||||||
|
|
||||||
استخرج الفئة ذات الاحتمالية الأعلى، واستخدم `id2label` لتحويلها إلى تصنيف نصي:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> predicted_class_id = int(tf.math.argmax(logits, axis=-1)[0])
|
|
||||||
>>> model.config.id2label[predicted_class_id]
|
|
||||||
'POSITIVE'
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
File diff suppressed because one or more lines are too long
@ -1,550 +0,0 @@
|
|||||||
<!--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.
|
|
||||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
|
||||||
rendered properly in your Markdown viewer.
|
|
||||||
-->
|
|
||||||
|
|
||||||
# تصنيف الرموز(Token classification)
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
<Youtube id="wVHdVlPScxA"/>
|
|
||||||
|
|
||||||
يهدف تصنيف الرموز إلى إعطاء تسمية لكل رمز على حدة في الجملة. من أكثر مهام تصنيف الرموز شيوعًا هو التعرف على الكيانات المسماة (NER). يحاول NER تحديد تسمية لكل كيان في الجملة، مثل شخص، أو مكان، أو منظمة.
|
|
||||||
|
|
||||||
سيوضح لك هذا الدليل كيفية:
|
|
||||||
|
|
||||||
1. ضبط [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) على مجموعة بيانات [WNUT 17](https://huggingface.co/datasets/wnut_17) للكشف عن كيانات جديدة.
|
|
||||||
2. استخدام نموذجك المضبوط بدقة للاستدلال.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للاطلاع جميع البنى والنقاط المتوافقة مع هذه المهمة، نوصي بالرجوع من [صفحة المهمة](https://huggingface.co/tasks/token-classification).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
قبل أن تبدأ، تأكد من تثبيت جميع المكتبات الضرورية:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers datasets evaluate seqeval
|
|
||||||
```
|
|
||||||
|
|
||||||
نحن نشجعك على تسجيل الدخول إلى حساب HuggingFace الخاص بك حتى تتمكن من تحميل ومشاركة نموذجك مع المجتمع. عندما يُطلب منك، أدخل رمزك لتسجيل الدخول:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from huggingface_hub import notebook_login
|
|
||||||
|
|
||||||
>>> notebook_login()
|
|
||||||
```
|
|
||||||
|
|
||||||
## تحميل مجموعة بيانات WNUT 17
|
|
||||||
|
|
||||||
ابدأ بتحميل مجموعة بيانات WNUT 17 من مكتبة 🤗 Datasets:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from datasets import load_dataset
|
|
||||||
|
|
||||||
>>> wnut = load_dataset("wnut_17")
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم ألق نظرة على مثال:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> wnut["train"][0]
|
|
||||||
{'id': '0',
|
|
||||||
'ner_tags': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
||||||
'tokens': ['@paulwalk', 'It', "'s", 'the', 'view', 'from', 'where', 'I', "'m", 'living', 'for', 'two', 'weeks', '.', 'Empire', 'State', 'Building', '=', 'ESB', '.', 'Pretty', 'bad', 'storm', 'here', 'last', 'evening', '.']
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
يمثل كل رقم في `ner_tags` كياناً. حوّل الأرقام إلى أسماء التصنيفات لمعرفة ماهية الكيانات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> label_list = wnut["train"].features[f"ner_tags"].feature.names
|
|
||||||
>>> label_list
|
|
||||||
[
|
|
||||||
"O",
|
|
||||||
"B-corporation",
|
|
||||||
"I-corporation",
|
|
||||||
"B-creative-work",
|
|
||||||
"I-creative-work",
|
|
||||||
"B-group",
|
|
||||||
"I-group",
|
|
||||||
"B-location",
|
|
||||||
"I-location",
|
|
||||||
"B-person",
|
|
||||||
"I-person",
|
|
||||||
"B-product",
|
|
||||||
"I-product",
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
يشير الحرف الذي يسبق كل `ner_tag` إلى موضع الرمز للكيان:
|
|
||||||
|
|
||||||
- `B-` يشير إلى بداية الكيان.
|
|
||||||
- `I-` يشير إلى أن الرمز يقع ضمن نفس الكيان (على سبيل المثال، الرمز `State` هو جزء من كيان مثل `Empire State Building`).
|
|
||||||
- `0` يشير إلى أن الرمز لا يمثل أي كيان.
|
|
||||||
|
|
||||||
## المعالجة المسبقة(Preprocess)
|
|
||||||
|
|
||||||
<Youtube id="iY2AZYdZAr0"/>
|
|
||||||
|
|
||||||
الخطوة التالية هي تحميل مُجزِّئ النصوص DistilBERT للمعالجة المسبقة لحقل `tokens`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
|
|
||||||
```
|
|
||||||
|
|
||||||
كما رأيت في حقل `tokens` المثال أعلاه، يبدو أن المدخل قد تم تحليله بالفعل. لكن المدخل لم يُجزأ بعد ويتعيّن عليك ضبط `is_split_into_words=True` لتقسيم الكلمات إلى كلمات فرعية. على سبيل المثال:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> example = wnut["train"][0]
|
|
||||||
>>> tokenized_input = tokenizer(example["tokens"], is_split_into_words=True)
|
|
||||||
>>> tokens = tokenizer.convert_ids_to_tokens(tokenized_input["input_ids"])
|
|
||||||
>>> tokens
|
|
||||||
['[CLS]', '@', 'paul', '##walk', 'it', "'", 's', 'the', 'view', 'from', 'where', 'i', "'", 'm', 'living', 'for', 'two', 'weeks', '.', 'empire', 'state', 'building', '=', 'es', '##b', '.', 'pretty', 'bad', 'storm', 'here', 'last', 'evening', '.', '[SEP]']
|
|
||||||
```
|
|
||||||
|
|
||||||
ومع ذلك، يضيف هذا بعض الرموز الخاصة `[CLS]` و`[SEP]` وتقسيم الكلمات إلى أجزاء يُنشئ عدم تطابق بين المُدخلات والتسميات. قد يتم تقسيم كلمة واحدة تقابل تسمية واحدة الآن إلى كلمتين فرعيتين. ستحتاج إلى إعادة محاذاة الرموز والتسميات عن طريق:
|
|
||||||
|
|
||||||
1. ربط كل رمز بالكلمة الأصلية باستخدام الخاصية [`word_ids`](https://huggingface.co/docs/transformers/main_classes/tokenizer#transformers.BatchEncoding.word_ids).
|
|
||||||
2. تعيين التسمية `-100` للرموز الخاصة `[CLS]` و`[SEP]` بحيث يتم تجاهلها بواسطة دالة الخسارة PyTorch (انظر [CrossEntropyLoss](https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html)).
|
|
||||||
3. تسمية الرمز الأول فقط لكلمة معينة. قم بتعيين `-100` لأجزاء الكلمة الأخرى.
|
|
||||||
|
|
||||||
هنا كيف يمكنك إنشاء وظيفة لإعادة محاذاة الرموز والتسميات، وقص الجمل لتتجاوز الحد الأقصى لطول مُدخلات DistilBERT:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> def tokenize_and_align_labels(examples):
|
|
||||||
... tokenized_inputs = tokenizer(examples["tokens"], truncation=True, is_split_into_words=True)
|
|
||||||
|
|
||||||
... labels = []
|
|
||||||
... for i, label in enumerate(examples[f"ner_tags"]):
|
|
||||||
... word_ids = tokenized_inputs.word_ids(batch_index=i) # تعيين الرموز إلى كلماتهم المقابلة.
|
|
||||||
... previous_word_idx = None
|
|
||||||
... label_ids = []
|
|
||||||
... for word_idx in word_ids: # تعيين الرموز الخاصة إلى -100.
|
|
||||||
... if word_idx is None:
|
|
||||||
... label_ids.append(-100)
|
|
||||||
... elif word_idx != previous_word_idx: # تسمية الرمز الأول فقط لكلمة معينة.
|
|
||||||
... label_ids.append(label[word_idx])
|
|
||||||
... else:
|
|
||||||
... label_ids.append(-100)
|
|
||||||
... previous_word_idx = word_idx
|
|
||||||
... labels.append(label_ids)
|
|
||||||
|
|
||||||
... tokenized_inputs["labels"] = labels
|
|
||||||
... return tokenized_inputs
|
|
||||||
```
|
|
||||||
|
|
||||||
لتطبيق هذه العملية على كامل مجموعة البيانات، استخدم الدالة [`~datasets.Dataset.map`] لمجموعة بيانات 🤗. يمكنك تسريع الدالة `map` عن طريق تعيين `batched=True` لمعالجة عناصر متعددة من مجموعة البيانات في وقت واحد:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenized_wnut = wnut.map(tokenize_and_align_labels, batched=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن قم بإنشاء دفعة من الأمثلة باستخدام [`DataCollatorWithPadding`].من الأفضل استخدام *الحشو الديناميكي* للجمل إلى أطول طول في دفعة أثناء التجميع، بدلاً من حشو مجموعة البيانات بالكامل إلى الطول الأقصى.
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorForTokenClassification
|
|
||||||
|
|
||||||
>>> data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer)
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorForTokenClassification
|
|
||||||
|
|
||||||
>>> data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer, return_tensors="tf")
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
## التقييم(Evaluate)
|
|
||||||
|
|
||||||
يُعدّ تضمين مقياس أثناء التدريب مفيدًا في تقييم أداء نموذجك. يمكنك تحميل طريقة تقييم بسرعة مع مكتبة 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index). لهذه المهمة، قم بتحميل إطار [seqeval](https://huggingface.co/spaces/evaluate-metric/seqeval) (انظر جولة 🤗 Evaluate [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) لمعرفة المزيد حول كيفية تحميل وحساب مقياس). يُخرج seqeval عدة نتائج: الدقة، والاستذكار، ومقياس F1، والدقة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import evaluate
|
|
||||||
|
|
||||||
>>> seqeval = evaluate.load("seqeval")
|
|
||||||
```
|
|
||||||
|
|
||||||
احصل على تسميات الكيانات المسماة (NER) أولاً،ثم أنشئ دالة تُمرر تنبؤاتك وتسمياتك الصحيحة إلى [`~evaluate.EvaluationModule.compute`] لحساب النتائج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import numpy as np
|
|
||||||
|
|
||||||
>>> labels = [label_list[i] for i in example[f"ner_tags"]]
|
|
||||||
|
|
||||||
>>> def compute_metrics(p):
|
|
||||||
... predictions, labels = p
|
|
||||||
... predictions = np.argmax(predictions, axis=2)
|
|
||||||
|
|
||||||
... 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 = seqeval.compute(predictions=true_predictions, references=true_labels)
|
|
||||||
... return {
|
|
||||||
... "precision": results["overall_precision"],
|
|
||||||
... "recall": results["overall_recall"],
|
|
||||||
... "f1": results["overall_f1"],
|
|
||||||
... "accuracy": results["overall_accuracy"],
|
|
||||||
... }
|
|
||||||
```
|
|
||||||
|
|
||||||
دالة `compute_metrics` جاهزة للاستخدام، وستحتاج إليها عند إعداد التدريب.
|
|
||||||
|
|
||||||
## التدريب(Train)
|
|
||||||
|
|
||||||
قبل تدريب النموذج، جهّز خريطة تربط بين المعرّفات المتوقعة وتسمياتها باستخدام `id2label` و `label2id`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> id2label = {
|
|
||||||
... 0: "O",
|
|
||||||
... 1: "B-corporation",
|
|
||||||
... 2: "I-corporation",
|
|
||||||
... 3: "B-creative-work",
|
|
||||||
... 4: "I-creative-work",
|
|
||||||
... 5: "B-group",
|
|
||||||
... 6: "I-group",
|
|
||||||
... 7: "B-location",
|
|
||||||
... 8: "I-location",
|
|
||||||
... 9: "B-person",
|
|
||||||
... 10: "I-person",
|
|
||||||
... 11: "B-product",
|
|
||||||
... 12: "I-product",
|
|
||||||
... }
|
|
||||||
>>> label2id = {
|
|
||||||
... "O": 0,
|
|
||||||
... "B-corporation": 1,
|
|
||||||
... "I-corporation": 2,
|
|
||||||
... "B-creative-work": 3,
|
|
||||||
... "I-creative-work": 4,
|
|
||||||
... "B-group": 5,
|
|
||||||
... "I-group": 6,
|
|
||||||
... "B-location": 7,
|
|
||||||
... "I-location": 8,
|
|
||||||
... "B-person": 9,
|
|
||||||
... "I-person": 10,
|
|
||||||
... "B-product": 11,
|
|
||||||
... "I-product": 12,
|
|
||||||
... }
|
|
||||||
```
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بتعديل نموذج باستخدام [`Trainer`], ألق نظرة على الدليل التعليمي الأساسي [هنا](../training#train-with-pytorch-trainer)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
أنت مستعد الآن لبدء تدريب نموذجك! قم بتحميل DistilBERT مع [`AutoModelForTokenClassification`] إلى جانب عدد التصنيفات المتوقعة، وخريطة التسميات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForTokenClassification, TrainingArguments, Trainer
|
|
||||||
|
|
||||||
>>> model = AutoModelForTokenClassification.from_pretrained(
|
|
||||||
... "distilbert/distilbert-base-uncased", num_labels=13, id2label=id2label, label2id=label2id
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
في هذه المرحلة، هناك ثلاث خطوات فقط متبقية:
|
|
||||||
|
|
||||||
1. حدد معلمات التدريب الخاصة بك في [`TrainingArguments`]. المعامل الوحيد المطلوب هو `output_dir` الذي يحدد مكان حفظ نموذجك. ستقوم بدفع هذا النموذج إلى Hub عن طريق تعيين `push_to_hub=True` (يجب أن تكون مسجلاً الدخول إلى Hugging Face لتحميل نموذجك). في نهاية كل حقبة، سيقوم [`Trainer`] بتقييم درجات seqeval وحفظ تسخة التدريب.
|
|
||||||
2. قم بتمرير معاملات التدريب إلى [`Trainer`] إلى جانب النموذج، ومجموعة البيانات، والمُجزِّئ اللغوي، و`data collator`، ودالة `compute_metrics`.
|
|
||||||
3.استدعِ [`~Trainer.train`] لتدريب نموذجك.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> training_args = TrainingArguments(
|
|
||||||
... output_dir="my_awesome_wnut_model",
|
|
||||||
... learning_rate=2e-5,
|
|
||||||
... per_device_train_batch_size=16,
|
|
||||||
... per_device_eval_batch_size=16,
|
|
||||||
... num_train_epochs=2,
|
|
||||||
... weight_decay=0.01,
|
|
||||||
... eval_strategy="epoch",
|
|
||||||
... save_strategy="epoch",
|
|
||||||
... load_best_model_at_end=True,
|
|
||||||
... push_to_hub=True,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer = Trainer(
|
|
||||||
... model=model,
|
|
||||||
... args=training_args,
|
|
||||||
... train_dataset=tokenized_wnut["train"],
|
|
||||||
... eval_dataset=tokenized_wnut["test"],
|
|
||||||
... processing_class=tokenizer,
|
|
||||||
... data_collator=data_collator,
|
|
||||||
... compute_metrics=compute_metrics,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، شارك نموذجك على Hub باستخدام طريقة [`~transformers.Trainer.push_to_hub`] حتى يتمكن الجميع من استخدام نموذجك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> trainer.push_to_hub()
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن على دراية بتعديل نموذج باستخدام Keras، ألق نظرة على الدليل التعليمي الأساسي [هنا](../training#train-a-tensorflow-model-with-keras)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
للتعديل على نموذج في TensorFlow، ابدأ بإعداد دالة محسن، وجدول معدل التعلم، وبعض معلمات التدريب:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import create_optimizer
|
|
||||||
|
|
||||||
>>> batch_size = 16
|
|
||||||
>>> num_train_epochs = 3
|
|
||||||
>>> num_train_steps = (len(tokenized_wnut["train"]) // batch_size) * num_train_epochs
|
|
||||||
>>> optimizer, lr_schedule = create_optimizer(
|
|
||||||
... init_lr=2e-5,
|
|
||||||
... num_train_steps=num_train_steps,
|
|
||||||
... weight_decay_rate=0.01,
|
|
||||||
... num_warmup_steps=0,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم يمكنك تحميل DistilBERT مع [`TFAutoModelForTokenClassification`] إلى جانب عدد التسميات المتوقعة، وتخطيطات التسميات:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForTokenClassification
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForTokenClassification.from_pretrained(
|
|
||||||
... "distilbert/distilbert-base-uncased", num_labels=13, id2label=id2label, label2id=label2id
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتحويل مجموعات بياناتك إلى تنسيق `tf.data.Dataset` مع [`~transformers.TFPreTrainedModel.prepare_tf_dataset`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tf_train_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_wnut["train"],
|
|
||||||
... shuffle=True,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> tf_validation_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_wnut["validation"],
|
|
||||||
... shuffle=False,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
هيّئ النموذج للتدريب باستخدام [`compile`](https://keras.io/api/models/model_training_apis/#compile-method). لاحظ أن نماذج Transformers تتضمن دالة خسارة افتراضية مرتبطة بالمهمة، لذلك لا تحتاج إلى تحديد واحدة إلا إذا كنت ترغب في ذلك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import tensorflow as tf
|
|
||||||
|
|
||||||
>>> model.compile(optimizer=optimizer) # No loss argument!
|
|
||||||
```
|
|
||||||
|
|
||||||
آخر أمرين يجب إعدادهما قبل بدء التدريب هو حساب درجات seqeval من التنبؤات، وتوفير طريقة لدفع نموذجك إلى Hub. يتم ذلك باستخدام [Keras callbacks](../main_classes/keras_callbacks).
|
|
||||||
|
|
||||||
مرر دالة `compute_metrics` الخاصة بك إلى [`~transformers.KerasMetricCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import KerasMetricCallback
|
|
||||||
|
|
||||||
>>> metric_callback = KerasMetricCallback(metric_fn=compute_metrics, eval_dataset=tf_validation_set)
|
|
||||||
```
|
|
||||||
|
|
||||||
حدد مكان دفع نموذجك والمحلل اللغوي في [`~transformers.PushToHubCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import PushToHubCallback
|
|
||||||
|
|
||||||
>>> push_to_hub_callback = PushToHubCallback(
|
|
||||||
... output_dir="my_awesome_wnut_model",
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم جمّع callbacks الخاصة بك معًا:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> callbacks = [metric_callback, push_to_hub_callback]
|
|
||||||
```
|
|
||||||
|
|
||||||
أخيرًا، أنت جاهز الآن لبدء تدريب نموذجك! قم باستدعاء [`fit`](https://keras.io/api/models/model_training_apis/#fit-method) مع بيانات التدريب والتحقق، وعدد الحقبات، وcallbacks لتعديل النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model.fit(x=tf_train_set, validation_data=tf_validation_set, epochs=3, callbacks=callbacks)
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، يتم تحميل نموذجك تلقائيًا إلى Hub حتى يتمكن الجميع من استخدامه!
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للحصول على مثال أكثر تفصيلاً حول كيفية تعديل نموذج لتصنيف الرموز، ألق نظرة على الدفتر المقابل
|
|
||||||
[دفتر PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb)
|
|
||||||
أو [دفتر TensorFlow](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification-tf.ipynb).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## الاستدلال(Inference)
|
|
||||||
|
|
||||||
رائع، الآن بعد أن قمت بتعديل نموذج، يمكنك استخدامه للاستدلال!
|
|
||||||
|
|
||||||
احصل على بعض النصوص التي تريد تشغيل الاستدلال عليها:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> text = "The Golden State Warriors are an American professional basketball team based in San Francisco."
|
|
||||||
```
|
|
||||||
|
|
||||||
أبسط طريقة لتجربة نموذجك المُدرب مسبقًا للاستدلال هي استخدامه في [`pipeline`]. قم بتنفيذ `pipeline` لتصنيف الكيانات المسماة مع نموذجك، ومرر نصك إليه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
>>> classifier = pipeline("ner", model="stevhliu/my_awesome_wnut_model")
|
|
||||||
>>> classifier(text)
|
|
||||||
[{'entity': 'B-location',
|
|
||||||
'score': 0.42658573,
|
|
||||||
'index': 2,
|
|
||||||
'word': 'golden',
|
|
||||||
'start': 4,
|
|
||||||
'end': 10},
|
|
||||||
{'entity': 'I-location',
|
|
||||||
'score': 0.35856336,
|
|
||||||
'index': 3,
|
|
||||||
'word': 'state',
|
|
||||||
'start': 11,
|
|
||||||
'end': 16},
|
|
||||||
{'entity': 'B-group',
|
|
||||||
'score': 0.3064001,
|
|
||||||
'index': 4,
|
|
||||||
'word': 'warriors',
|
|
||||||
'start': 17,
|
|
||||||
'end': 25},
|
|
||||||
{'entity': 'B-location',
|
|
||||||
'score': 0.65523505,
|
|
||||||
'index': 13,
|
|
||||||
'word': 'san',
|
|
||||||
'start': 80,
|
|
||||||
'end': 83},
|
|
||||||
{'entity': 'B-location',
|
|
||||||
'score': 0.4668663,
|
|
||||||
'index': 14,
|
|
||||||
'word': 'francisco',
|
|
||||||
'start': 84,
|
|
||||||
'end': 93}]
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك أيضًا تكرار نتائج `pipeline` يدويًا إذا أردت:
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
قسّم النص إلى رموز وأرجع المُوتّرات بلغة PyTorch:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_wnut_model")
|
|
||||||
>>> inputs = tokenizer(text, return_tensors="pt")
|
|
||||||
```
|
|
||||||
|
|
||||||
مرر مدخلاتك إلى النموذج واحصل على `logits`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForTokenClassification
|
|
||||||
|
|
||||||
>>> model = AutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model")
|
|
||||||
>>> with torch.no_grad():
|
|
||||||
... logits = model(**inputs).logits
|
|
||||||
```
|
|
||||||
|
|
||||||
استخرج الفئة ذات الاحتمالية الأعلى، واستخدم جدول `id2label` الخاصة بالنموذج لتحويلها إلى تسمية نصية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> predictions = torch.argmax(logits, dim=2)
|
|
||||||
>>> predicted_token_class = [model.config.id2label[t.item()] for t in predictions[0]]
|
|
||||||
>>> predicted_token_class
|
|
||||||
['O',
|
|
||||||
'O',
|
|
||||||
'B-location',
|
|
||||||
'I-location',
|
|
||||||
'B-group',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'B-location',
|
|
||||||
'B-location',
|
|
||||||
'O',
|
|
||||||
'O']
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
قسّم النص إلى رموز وأرجع المُوتّرات ب TensorFlow:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_wnut_model")
|
|
||||||
>>> inputs = tokenizer(text, return_tensors="tf")
|
|
||||||
```
|
|
||||||
|
|
||||||
مرر مدخلاتك إلى النموذج واحصل على `logits`:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForTokenClassification
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model")
|
|
||||||
>>> logits = model(**inputs).logits
|
|
||||||
```
|
|
||||||
|
|
||||||
استخرج الفئة ذات الاحتمالية الأعلى، واستخدم جدول `id2label` الخاصة بالنموذج لتحويلها إلى تسمية نصية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> predicted_token_class_ids = tf.math.argmax(logits, axis=-1)
|
|
||||||
>>> predicted_token_class = [model.config.id2label[t] for t in predicted_token_class_ids[0].numpy().tolist()]
|
|
||||||
>>> predicted_token_class
|
|
||||||
['O',
|
|
||||||
'O',
|
|
||||||
'B-location',
|
|
||||||
'I-location',
|
|
||||||
'B-group',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'O',
|
|
||||||
'B-location',
|
|
||||||
'B-location',
|
|
||||||
'O',
|
|
||||||
'O']
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
@ -1,407 +0,0 @@
|
|||||||
<!--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.
|
|
||||||
|
|
||||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
|
||||||
rendered properly in your Markdown viewer.
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
# الترجمة(Translation)
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
<Youtube id="1JvfrvZgi6c"/>
|
|
||||||
|
|
||||||
الترجمة هي عملية تحويل سلسلة نصية من لغة إلى أخرى. وهي إحدى المهام التي يمكن صياغتها كمسألة تسلسل إلى تسلسل، وهو إطار عمل قوي لإنتاج مخرجات من مدخلات، مثل الترجمة أو التلخيص. تُستخدم أنظمة الترجمة عادةً للترجمة بين نصوص لغات مختلفة، ويمكن استخدامها أيضًا لترجمة الكلام أو لمهام تجمع بين النصوص والكلام، مثل تحويل النص إلى كلام أو تحويل الكلام إلى نص.
|
|
||||||
|
|
||||||
سيوضح لك هذا الدليل كيفية:
|
|
||||||
|
|
||||||
1. ضبط دقيق لنموذج [T5](https://huggingface.co/google-t5/t5-small) على المجموعة الفرعية الإنجليزية-الفرنسية من مجموعة بيانات [OPUS Books](https://huggingface.co/datasets/opus_books) لترجمة النص الإنجليزي إلى الفرنسية.
|
|
||||||
2. استخدام النموذج المضبوط بدقة للاستدلال.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
لمشاهدة جميع البنى والنسخ المتوافقة مع هذه المهمة، نوصي بالتحقق من [صفحة المهمة](https://huggingface.co/tasks/translation).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
قبل البدء، تأكد من تثبيت جميع المكتبات الضرورية:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers datasets evaluate sacrebleu
|
|
||||||
```
|
|
||||||
|
|
||||||
نشجعك على تسجيل الدخول إلى حساب Hugging Face الخاص بك حتى تتمكن من تحميل نموذجك ومشاركته مع المجتمع. عند الطلب، أدخل الرمز المميز الخاص بك لتسجيل الدخول:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from huggingface_hub import notebook_login
|
|
||||||
|
|
||||||
>>> notebook_login()
|
|
||||||
```
|
|
||||||
|
|
||||||
## تحميل مجموعة بيانات OPUS Books
|
|
||||||
|
|
||||||
ابدأ بتحميل المجموعة الفرعية الإنجليزية-الفرنسية من مجموعة بيانات [OPUS Books](https://huggingface.co/datasets/opus_books) من مكتبة 🤗 Datasets:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from datasets import load_dataset
|
|
||||||
|
|
||||||
>>> books = load_dataset("opus_books", "en-fr")
|
|
||||||
```
|
|
||||||
|
|
||||||
قسّم مجموعة البيانات إلى مجموعة تدريب ومجموعة اختبار باستخدام طريقة [`~datasets.Dataset.train_test_split`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> books = books["train"].train_test_split(test_size=0.2)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم ألقِ نظرة على مثال:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> books["train"][0]
|
|
||||||
{'id': '90560',
|
|
||||||
'translation': {'en': 'But this lofty plateau measured only a few fathoms, and soon we reentered Our Element.',
|
|
||||||
'fr': 'Mais ce plateau élevé ne mesurait que quelques toises, et bientôt nous fûmes rentrés dans notre élément.'}}
|
|
||||||
```
|
|
||||||
|
|
||||||
`translation`: ترجمة إنجليزية وفرنسية للنص.
|
|
||||||
|
|
||||||
## المعالجة المسبقة(Preprocess)
|
|
||||||
|
|
||||||
<Youtube id="XAR8jnZZuUs"/>
|
|
||||||
|
|
||||||
الخطوة التالية هي تحميل مُجزئ T5 لمعالجة أزواج اللغة الإنجليزية-الفرنسية:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> checkpoint = "google-t5/t5-small"
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
|
||||||
```
|
|
||||||
|
|
||||||
يجب أن تقوم دالة المعالجة المسبقة التي تُريد إنشاءها بما يلي:
|
|
||||||
|
|
||||||
1. إضافة بادئة إلى المُدخل بمُوجه حتى يعرف T5 أن هذه مهمة ترجمة. تتطلب بعض النماذج القادرة على أداء مهام متعددة توجيهًا لمهام مُحددة.
|
|
||||||
2. تعيين اللغة الهدف (الفرنسية) في معامل `text_target` لضمان معالجة المُجزئ للنص بشكل صحيح. إذا لم تُعيّن `text_target`، فسيُعالج المُجزئ النص على أنه إنجليزي.
|
|
||||||
3. اقتطاع التسلسلات بحيث لا يزيد طولها عن الحد الأقصى الذي يحدده معامل `max_length`.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> source_lang = "en"
|
|
||||||
>>> target_lang = "fr"
|
|
||||||
>>> prefix = "translate English to French: "
|
|
||||||
|
|
||||||
>>> def preprocess_function(examples):
|
|
||||||
... inputs = [prefix + example[source_lang] for example in examples["translation"]]
|
|
||||||
... targets = [example[target_lang] for example in examples["translation"]]
|
|
||||||
... model_inputs = tokenizer(inputs, text_target=targets, max_length=128, truncation=True)
|
|
||||||
... return model_inputs
|
|
||||||
```
|
|
||||||
|
|
||||||
لتطبيق دالة المعالجة المسبقة على مجموعة البيانات بأكملها، استخدم طريقة [`~datasets.Dataset.map`] من 🤗 Datasets. يمكنك تسريع دالة `map` عن طريق تعيين `batched=True` لمعالجة عناصر متعددة من مجموعة البيانات في وقت واحد:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenized_books = books.map(preprocess_function, batched=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
الآن أنشئ دفعة من الأمثلة باستخدام [`DataCollatorForSeq2Seq`]. من الأكثر كفاءة *الحشو الديناميكي* للجمل إلى أطول طول في دفعة أثناء التجميع، بدلاً من حشو مجموعة البيانات بأكملها إلى الحد الأقصى للطول.
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorForSeq2Seq
|
|
||||||
|
|
||||||
>>> data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=checkpoint)
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import DataCollatorForSeq2Seq
|
|
||||||
|
|
||||||
>>> data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=checkpoint, return_tensors="tf")
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
## التقييم (Evaluate)
|
|
||||||
|
|
||||||
غالباً ما يكون تضمين مقياس أثناء التدريب مفيداً لتقييم أداء نموذجك. يمكنك تحميل طريقة تقييم بسرعة باستخدام مكتبة 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index). لهذه المهمة، حمّل مقياس [SacreBLEU](https://huggingface.co/spaces/evaluate-metric/sacrebleu) (راجع [الجولة السريعة](https://huggingface.co/docs/evaluate/a_quick_tour) لـ 🤗 Evaluate لمعرفة المزيد حول كيفية تحميل وحساب مقياس):
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import evaluate
|
|
||||||
|
|
||||||
>>> metric = evaluate.load("sacrebleu")
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم أنشئ دالة تُمرر تنبؤاتك وتسمياتك إلى [`~evaluate.EvaluationModule.compute`] لحساب درجة SacreBLEU:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import numpy as np
|
|
||||||
|
|
||||||
>>> 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]
|
|
||||||
... 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)
|
|
||||||
|
|
||||||
... 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
|
|
||||||
```
|
|
||||||
|
|
||||||
دالة `compute_metrics` الخاصة بك جاهزة الآن، وسوف تعود إليها عند إعداد التدريب.
|
|
||||||
|
|
||||||
## التدريب (Train)
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن معتادًا على ضبط دقيق نموذج باستخدام [`Trainer`], فألقِ نظرة على البرنامج التعليمي الأساسي [هنا](../training#train-with-pytorch-trainer)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
أنت جاهز لبدء تدريب نموذجك الآن! حمّل T5 باستخدام [`AutoModelForSeq2SeqLM`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForSeq2SeqLM, Seq2SeqTrainingArguments, Seq2SeqTrainer
|
|
||||||
|
|
||||||
>>> model = AutoModelForSeq2SeqLM.from_pretrained(checkpoint)
|
|
||||||
```
|
|
||||||
|
|
||||||
في هذه المرحلة، تبقى ثلاث خطوات فقط:
|
|
||||||
|
|
||||||
1. حدد مُعاملات للتدريب في [`Seq2SeqTrainingArguments`]. المُعامل الوحيدة المطلوبة هي `output_dir` التي تحدد مكان حفظ النموذج الخاص بك. ستقوم بدفع هذا النموذج إلى Hub عن طريق تعيين `push_to_hub=True` (يجب عليك تسجيل الدخول إلى Hugging Face لتحميل نموذجك). في نهاية كل حقبة، سيقوم [`Trainer`] بتقييم مقياس SacreBLEU وحفظ نقطة تدقيق التدريب.
|
|
||||||
2. مرر مُعاملات التدريب إلى [`Seq2SeqTrainer`] جنبًا إلى جنب مع النموذج ومجموعة البيانات والمعالج اللغوي وجامع البيانات ووظيفة `compute_metrics`.
|
|
||||||
3. نفّذ [`~Trainer.train`] لضبط نموذجك.
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> training_args = Seq2SeqTrainingArguments(
|
|
||||||
... output_dir="my_awesome_opus_books_model",
|
|
||||||
... eval_strategy="epoch",
|
|
||||||
... learning_rate=2e-5,
|
|
||||||
... per_device_train_batch_size=16,
|
|
||||||
... per_device_eval_batch_size=16,
|
|
||||||
... weight_decay=0.01,
|
|
||||||
... save_total_limit=3,
|
|
||||||
... num_train_epochs=2,
|
|
||||||
... predict_with_generate=True,
|
|
||||||
... fp16=True, #change to bf16=True for XPU
|
|
||||||
... push_to_hub=True,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer = Seq2SeqTrainer(
|
|
||||||
... model=model,
|
|
||||||
... args=training_args,
|
|
||||||
... train_dataset=tokenized_books["train"],
|
|
||||||
... eval_dataset=tokenized_books["test"],
|
|
||||||
... processing_class=tokenizer,
|
|
||||||
... data_collator=data_collator,
|
|
||||||
... compute_metrics=compute_metrics,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، شارك نموذجك مع Hub باستخدام طريقة [`~transformers.Trainer.push_to_hub`] حتى يتمكن الجميع من استخدام نموذجك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> trainer.push_to_hub()
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
إذا لم تكن معتادًا على ضبط نموذج باستخدام Keras، فألق نظرة على البرنامج التعليمي الأساسي [هنا](../training#train-a-tensorflow-model-with-keras)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
لضبط نموذج في TensorFlow، ابدأ بإعداد دالة مُحسِّن وجدول معدل تعلم وبعض المعلمات الفائقة للتدريب:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AdamWeightDecay
|
|
||||||
|
|
||||||
>>> optimizer = AdamWeightDecay(learning_rate=2e-5, weight_decay_rate=0.01)
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم يمكنك تحميل T5 باستخدام [`TFAutoModelForSeq2SeqLM`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForSeq2SeqLM
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForSeq2SeqLM.from_pretrained(checkpoint)
|
|
||||||
```
|
|
||||||
|
|
||||||
حوّل مجموعات البيانات الخاصة بك إلى تنسيق `tf.data.Dataset` باستخدام [`~transformers.TFPreTrainedModel.prepare_tf_dataset`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tf_train_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_books["train"],
|
|
||||||
... shuffle=True,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
|
|
||||||
>>> tf_test_set = model.prepare_tf_dataset(
|
|
||||||
... tokenized_books["test"],
|
|
||||||
... shuffle=False,
|
|
||||||
... batch_size=16,
|
|
||||||
... collate_fn=data_collator,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
قم بتكوين النموذج للتدريب باستخدام [`compile`](https://keras.io/api/models/model_training_apis/#compile-method). لاحظ أن جميع نماذج Transformers تحتوي على دالة خسارة ذات صلة بالمهمة بشكل افتراضي، لذلك لا تحتاج إلى تحديد واحدة إلا إذا كنت ترغب في ذلك:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> import tensorflow as tf
|
|
||||||
|
|
||||||
>>> model.compile(optimizer=optimizer) # No loss argument!
|
|
||||||
```
|
|
||||||
|
|
||||||
آخر شيئين يجب إعدادهما قبل بدء التدريب هما حساب مقياس SacreBLEU من التوقعات، وتوفير طريقة لدفع نموذجك إلى Hub. يتم كلاهما باستخدام [استدعاءات Keras](../main_classes/keras_callbacks).
|
|
||||||
|
|
||||||
مرر دالة `compute_metrics` الخاصة بك إلى [`~transformers.KerasMetricCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import KerasMetricCallback
|
|
||||||
|
|
||||||
>>> metric_callback = KerasMetricCallback(metric_fn=compute_metrics, eval_dataset=tf_test_set)
|
|
||||||
```
|
|
||||||
|
|
||||||
حدد مكان دفع نموذجك ومعالجك اللغوي في [`~transformers.PushToHubCallback`]:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers.keras_callbacks import PushToHubCallback
|
|
||||||
|
|
||||||
>>> push_to_hub_callback = PushToHubCallback(
|
|
||||||
... output_dir="my_awesome_opus_books_model",
|
|
||||||
... tokenizer=tokenizer,
|
|
||||||
... )
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم اجمع استدعاءاتك معًا:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> callbacks = [metric_callback, push_to_hub_callback]
|
|
||||||
```
|
|
||||||
|
|
||||||
أخيرًا، أنت جاهز لبدء تدريب نموذجك! اتصل بـ [`fit`](https://keras.io/api/models/model_training_apis/#fit-method) مع مجموعات بيانات التدريب والتحقق من الصحة وعدد الحقب واستدعاءاتك لضبط النموذج:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> model.fit(x=tf_train_set, validation_data=tf_test_set, epochs=3, callbacks=callbacks)
|
|
||||||
```
|
|
||||||
|
|
||||||
بمجرد اكتمال التدريب، يتم تحميل نموذجك تلقائيًا إلى Hub حتى يتمكن الجميع من استخدامه!
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للحصول على مثال أكثر تعمقًا لكيفية ضبط نموذج للترجمة، ألق نظرة على [دفتر ملاحظات PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation.ipynb) المقابل
|
|
||||||
أو [دفتر ملاحظات TensorFlow](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/translation-tf.ipynb).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## الاستدلال (Inference)
|
|
||||||
|
|
||||||
رائع، الآن بعد أن قمت بضبط نموذج، يمكنك استخدامه للاستدلال!
|
|
||||||
|
|
||||||
أحضر بعض النصوص التي ترغب في ترجمتها إلى لغة أخرى. بالنسبة لـ T5، تحتاج إلى إضافة بادئة إلى مدخلاتك اعتمادًا على المهمة التي تعمل عليها. للترجمة من الإنجليزية إلى الفرنسية، يجب عليك إضافة بادئة إلى مدخلاتك كما هو موضح أدناه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> text = "translate English to French: Legumes share resources with nitrogen-fixing bacteria."
|
|
||||||
```
|
|
||||||
|
|
||||||
أبسط طريقة لتجربة نموذجك المضبوط للاستدلال هي استخدامه في [`pipeline`]. قم بإنشاء مثيل لـ `pipeline` للترجمة باستخدام نموذجك، ومرر النص الخاص بك إليه:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
|
|
||||||
# تغيير `xx` إلى لغة الإدخال و `yy` إلى لغة المخرجات المطلوبة.
|
|
||||||
# أمثلة: "en" للغة الإنجليزية، "fr" للغة الفرنسية، "de" للغة الألمانية، "es" للغة الإسبانية، "zh" للغة الصينية، إلخ؛ translation_en_to_fr تترجم من الإنجليزية إلى الفرنسية
|
|
||||||
# يمكنك عرض جميع قوائم اللغات هنا - https://huggingface.co/languages
|
|
||||||
>>> translator = pipeline("translation_xx_to_yy", model="username/my_awesome_opus_books_model")
|
|
||||||
>>> translator(text)
|
|
||||||
[{'translation_text': 'Legumes partagent des ressources avec des bactéries azotantes.'}]
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك أيضًا تكرار نتائج `pipeline` يدويًا إذا أردت:
|
|
||||||
|
|
||||||
<frameworkcontent>
|
|
||||||
<pt>
|
|
||||||
قم بتحويل النص إلى رموز وإرجاع `input_ids` كموترات PyTorch:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_opus_books_model")
|
|
||||||
>>> inputs = tokenizer(text, return_tensors="pt").input_ids
|
|
||||||
```
|
|
||||||
|
|
||||||
استخدم الدالة [`~generation.GenerationMixin.generate`] لإنشاء الترجمة. لمزيد من التفاصيل حول استراتيجيات توليد النصوص المختلفة والمعلمات للتحكم في التوليد، تحقق من واجهة برمجة تطبيقات [توليد النصوص](../main_classes/text_generation).
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoModelForSeq2SeqLM
|
|
||||||
|
|
||||||
>>> model = AutoModelForSeq2SeqLM.from_pretrained("username/my_awesome_opus_books_model")
|
|
||||||
>>> outputs = model.generate(inputs, max_new_tokens=40, do_sample=True, top_k=30, top_p=0.95)
|
|
||||||
```
|
|
||||||
|
|
||||||
فك تشفير معرفات الرموز المولدة مرة أخرى إلى نص:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenizer.decode(outputs[0], skip_special_tokens=True)
|
|
||||||
'Les lignées partagent des ressources avec des bactéries enfixant l'azote.'
|
|
||||||
```
|
|
||||||
</pt>
|
|
||||||
<tf>
|
|
||||||
قم بتحويل النص إلى رموز وإرجاع `input_ids` كموترات TensorFlow:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_opus_books_model")
|
|
||||||
>>> inputs = tokenizer(text, return_tensors="tf").input_ids
|
|
||||||
```
|
|
||||||
|
|
||||||
استخدم طريقة [`~transformers.generation_tf_utils.TFGenerationMixin.generate`] لإنشاء الترجمة. لمزيد من التفاصيل حول استراتيجيات توليد النصوص المختلفة والمعلمات للتحكم في التوليد، تحقق من واجهة برمجة تطبيقات [توليد النصوص](../main_classes/text_generation).
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import TFAutoModelForSeq2SeqLM
|
|
||||||
|
|
||||||
>>> model = TFAutoModelForSeq2SeqLM.from_pretrained("username/my_awesome_opus_books_model")
|
|
||||||
>>> outputs = model.generate(inputs, max_new_tokens=40, do_sample=True, top_k=30, top_p=0.95)
|
|
||||||
```
|
|
||||||
|
|
||||||
فك تشفير معرفات الرموز المولدة مرة أخرى إلى نص:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> tokenizer.decode(outputs[0], skip_special_tokens=True)
|
|
||||||
'Les lugumes partagent les ressources avec des bactéries fixatrices d'azote.'
|
|
||||||
```
|
|
||||||
</tf>
|
|
||||||
</frameworkcontent>
|
|
||||||
@ -1,279 +0,0 @@
|
|||||||
# كيف تُنجز نماذج 🤗 Transformers المهام؟
|
|
||||||
|
|
||||||
في [ما الذي يمكن أن تفعله نماذج 🤗 Transformers](task_summary)، تعلمت عن معالجة اللغات الطبيعية (NLP)، والخطاب والصوت، ورؤية الحاسب، وبعض تطبيقاتها المهمة. ستلقي هذه الصفحة نظرة فاحصة على كيفية حل النماذج لهذه المهام وتوضيح ما يحدث ما يحدث وراء الكواليس. هناك العديد من الطرق لحل مهمة معينة، وقد تنفذ بعض النماذج تقنيات معينة أو حتى تتناول المهمة من زاوية جديدة، ولكن بالنسبة لنماذج Transformer، فإن الفكرة العامة هي نفسها. وبفضل تصميمها المرن، فنظراً لهيكلها المرن، تُعدّ معظم النماذج عبارة عن متغير من بنية المُشفّر (Encoder) أو المُفكّك (Decoder) أو المُشفّر - المُفكّك (Encoder-Decoder). بالإضافة إلى نماذج Transformer، تحتوي مكتبتنا أيضًا على العديد من الشبكات العصبية التلافيفية (CNNs)، والتي لا تزال تستخدم حتى اليوم لمهام رؤية الحاسب. سنشرح أيضًا كيف تعمل شبكة عصبية تلافيفية CNN الحديثة.
|
|
||||||
|
|
||||||
لشرح كيفية حل المهام، سنشرح ما يحدث داخل النموذج لإخراج تنبؤات مفيدة.
|
|
||||||
|
|
||||||
- [Wav2Vec2](model_doc/wav2vec2) لتصنيف الصوت والتعرف التلقائي على الكلام (ASR)
|
|
||||||
- [Vision Transformer (ViT)](model_doc/vit) و [ConvNeXT](model_doc/convnext) لتصنيف الصور
|
|
||||||
- [DETR](model_doc/detr) للكشف عن الأجسام
|
|
||||||
- [Mask2Former](model_doc/mask2former) لتجزئة الصورة
|
|
||||||
- [GLPN](model_doc/glpn) لتقدير العمق
|
|
||||||
- [BERT](model_doc/bert) لمهام NLP مثل تصنيف النصوص، وتصنيف الرموز، والإجابة على الأسئلة التي تستخدم مشفرًا
|
|
||||||
- [GPT2](model_doc/gpt2) لمهام NLP مثل توليد النصوص التي تستخدم فك تشفير
|
|
||||||
- [BART](model_doc/bart) لمهام NLP مثل الملخص والترجمة التي تستخدم ترميز-فك تشفير
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
قبل المتابعة، من الجيد أن يكون لديك بعض المعرفة الأساسية بهيكلية المحولات (Transformer Architecture) الأصلية. إن معرفة كيفية عمل المُشفّرات (Encoders) والمُفكّكات (Decoders) وآلية الانتباه (Attention Mechanism) سوف تساعدك في فهم كيفية عمل نماذج Transformer المختلفة. إذا كنت مبتدئًا أو بحاجة إلى مراجعة، فراجع [دورتنا](https://huggingface.co/course/chapter1/4؟fw=pt) لمزيد من المعلومات!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## الكلام والصوت (Speech and audio)
|
|
||||||
|
|
||||||
يُعدّ [Wav2Vec2](model_doc/wav2vec2) نموذجًا مُدرَّبًا ذاتيًا (Self-Supervised) على بيانات الكلام غير المُصنّفة، ويُمكن ضبطه بدقة (Fine-tuning) على بيانات موسومة لأداء مهام تصنيف الصوت والتعرف التلقائي على الكلام.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/wav2vec2_architecture.png"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
يتكون هذا النموذج على أربعة مكونات رئيسية:
|
|
||||||
|
|
||||||
1. *مشفّر الميزات (Feature Encoder)* يأخذ الموجة الصوتية الخام، ويقوم بتطبيعها (Normalization) إلى متوسط صفري وانحراف معياري وحدوي، وتحويلها إلى تسلسل من متجهات الميزات التي يبلغ طول كل منها 20 مللي ثانية.
|
|
||||||
|
|
||||||
2. *وحدة التكميم (Quantization Module):** تتميز أشكال الموجات الصوتية بطبيعتها المُستمرة،، لذلك لا يمكن تقسيمها إلى وحدات منفصلة كما يمكن تقسيم التسلسل النصّي إلى كلمات ولهذا السبب يتم تمرير متجهات الميزات إلى *وحدة التكميم*، والتي تهدف إلى تعلم وحدات الكلام المنفصلة. يتم اختيار وحدة الكلام من مجموعة من الرموز، والمعروفة باسم *كتاب الرموز* (يمكنك اعتبار هذا بمثابة المفردات). ومن كتاب الرموز،يتم اختيار المتجه أو وحدة الكلام التي تُمثّل مدخل الصوت المُستمر على أفضل وجه، ويتم تمريرها عبر النموذج.
|
|
||||||
3. **شبكة السياق (Context Network):** يتم إخفاء حوالي نصف متجهات الميزات بشكل عشوائي، ويتم تغذية متجه الميزة المُقنّع إلى *شبكة السياق*، والتي تعد مُشفّر محوّلات (Transformer Encoder) الذي يضيف أيضًا تضمينات موضعية نسبية (Relative Positional Embeddings)..
|
|
||||||
|
|
||||||
4. **مهمة التناقضية:** يتمثل الهدف من التدريب المسبق لشبكة السياق هو *مهمة تناقضية*. يجب على النموذج التنبؤ بالتمثيل الصحيح للكلام المُكمّم للتنبؤ المقنع من مجموعة من التمثيلات الخاطئة، مما يشجع النموذج على ا إيجاد متجه السياق ووحدة الكلام المُكمّمة الأكثر تشابهًا (التصنيف المستهدف).
|
|
||||||
|
|
||||||
بمجرد تدريب Wav2Vec2 مسبقًا، يمكنك ضبط دقته على بياناتك لتصنيف الصوت أو التعرف التلقائي على الكلام!
|
|
||||||
|
|
||||||
### تصنيف الصوت (Audio classification)
|
|
||||||
|
|
||||||
لاستخدام النموذج الذي تم تدريبه مسبقًا لتصنيف الصوت، أضف رأس تصنيف تسلسلي أعلى نموذج Wav2Vec2 الأساسي. رأس التصنيف هو طبقة خطية تستقبل الحالات المخفية للمشفر. تمثل الحالات المخفية الميزات التي تم تعلمها من كل إطار صوتي والذي يمكن أن يكون له أطوال مختلفة. لتحويلها إلى متجه واحد ثابت الطول، يتم تجميع الحالات المخفية أولاً ثم تحويلها إلى احتمالات عبر تصنيفات الفئات. يتم حساب التكلفة (الخسارة المتقاطعة) بين الاحتمالات والتصنيف المستهدف للعثور على الفئة الأكثر احتمالًا.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة تصنيف الصوت؟ تحقق من دليلنا الشامل [تصنيف الصوت](tasks/audio_classification) لمعرفة كيفية ضبط دقة نموذج Wav2Vec2 واستخدامه للاستدلال!
|
|
||||||
|
|
||||||
### التعرف التلقائي على الكلام (Automatic speech recognition - ASR)
|
|
||||||
|
|
||||||
لاستخدام النموذج الذي تم تدريبه مسبقًا للتعرف التلقائي على الكلام، أضف رأس نمذجة لغوية أعلى نموذج Wav2Vec2 الأساسي لـ [[التصنيف الزمني الترابطي (CTC)](glossary#connectionist-temporal-classification-ctc). رأس النمذجة اللغوية عبارة عن طبقة خطية تقبل الحالات المخفية للمُشفّر وتحويلها إلى احتمالات. يمثل كل احتمال فئة رمزية (يأتي عدد الرموز من مفردات المهمة). يتم حساب تكلفة CTC بين الاحتمالات والأهداف للعثور على تسلسل الرموز الأكثر احتمالًا، والتي يتم فك تشفيرها بعد ذلك إلى نص مكتوب.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة التعرف التلقائي على الكلام؟ تحقق من دليلنا الشامل [التعرف التلقائي على الكلام](tasks/asr) لمعرفة كيفية ضبط دقة نموذج Wav2Vec2 واستخدامه للاستدلال!
|
|
||||||
|
|
||||||
## رؤية الحاسب (Computer vision)
|
|
||||||
|
|
||||||
هناك طريقتان لتناول مهام رؤية الحاسب:
|
|
||||||
|
|
||||||
1. قم بتقسيم الصورة إلى تسلسل من الرقع ومعالجتها بالتوازي باستخدام مُحوّل Transformer.
|
|
||||||
2. استخدم شبكة عصبية تلافيفية CNN) حديثة، مثل [ConvNeXT](model_doc/convnext)، والتي تعتمد على الطبقات التلافيفية ولكنها تعتمد تصميمات حديثة للشبكات.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
يقوم النهج الثالث بمزج المحولات مع التلافيف (على سبيل المثال، [Convolutional Vision Transformer](model_doc/cvt) أو [LeViT](model_doc/levit)). لن نناقشها لأنها تجمع ببساطة بين النهجين اللذين نستعرضهما هنا.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
يتم استخدام ViT و ConvNeXT بشكل شائع لتصنيف الصور، ولكن بالنسبة لمهام الرؤية الأخرى مثل اكتشاف الكائنات والتجزئة وتقدير العمق، سنلقي نظرة على DETR و Mask2Former و GLPN، على التوالي؛ فهذه النماذج هي الأنسب لتلك المهام.
|
|
||||||
|
|
||||||
### تصنيف الصور (Image classification)
|
|
||||||
|
|
||||||
يمكن استخدام كل من ViT و ConvNeXT لتصنيف الصور؛ الاختلاف الرئيسي هو أن ViT يستخدم آلية انتباه بينما يستخدم ConvNeXT الالتفافات.
|
|
||||||
|
|
||||||
#### المحول Transformer
|
|
||||||
|
|
||||||
[ViT](model_doc/vit) يستبدل التلافيف تمامًا بهندسة Transformer نقية. إذا كنت على دراية بـ Transformer الأصلي، فأنت بالفعل في طريقك إلى فهم ViT.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/model_doc/vit_architecture.jpg"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
كان التغيير الرئيسي الذي قدمه ViT هو كيفية تغذية الصور إلى Transformer:
|
|
||||||
|
|
||||||
1. يتم تقسيم الصورة إلى رقع مربعة غير متداخلة، يتم تحويل كل منها إلى متجه أو يُسمى *تمثيل الرقعة*. يتم إنشاء تضمينات الرقع من طبقة تلافيفية ثنائية الأبعاد 2D والتي تقوم بإنشاء أبعاد الإدخال الصحيحة (والتي بالنسبة إلى Transformer الأساسي هي 768 قيمة لكل تضمين رقعة). إذا كان لديك صورة 224x224 بكسل، فيمكنك تقسيمها إلى 196 رقعة صورة 16x16. تمامًا مثل كيفية تجزئة النص إلى كلمات، يتم "تجزئة" الصورة إلى سلسلة من الرقع.
|
|
||||||
|
|
||||||
2. يتم إضافة *رمز قابل للتعلم* - تتم إضافة رمز خاص `[CLS]` - إلى بداية تمثيلات الرقع تمامًا مثل BERT. يتم استخدام الحالة المخفية النهائية للرمز `[CLS]` كمدخل لرأس التصنيف المُرفق؛ يتم تجاهل المخرجات الأخرى. تساعد هذه الرموز النموذج على تعلم كيفية ترميز تمثيل الصورة.
|
|
||||||
|
|
||||||
3. الشيء الأخير تتم إضافة "تمثيلات تموضع" إلى تمثيلات الرقع والرمز القابل للتعلم لأن النموذج لا يعرف كيفية ترتيب رقع الصورة. تكون تمثيلات التموضع قابلة للتعلم أيضًا ولها نفس حجم تمثيلات الرقع. وأخيرًا، يتم تمرير جميع التمثيلات إلى مُشفّر Transformer.
|
|
||||||
|
|
||||||
4. يتم تمرير الإخراج، وتحديدًا مخرج الرمز `[CLS]`، إلى رأس الإدراك المتعدد الطبقات (MLP). الهدف من التدريب المسبق لـ ViT هو التصنيف فقط. يقوم رأس MLP، مثل رؤوس التصنيف الأخرى، يحول رأس MLP المخرجات إلى احتمالات عبر تصنيفات الفئات ويحسب دالة التكلفة (الخسارة المتقاطعة) للعثور على الفئة الأكثر احتمالًا.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة تصنيف الصور؟ تحقق من دليلنا الشامل [تصنيف الصور](tasks/image_classification) لمعرفة كيفية ضبط دقة نموذج ViT واستخدامه للاستدلال!
|
|
||||||
|
|
||||||
#### الشبكات العصبية التلافيفية (CNN)
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
يشرح هذا القسم بإيجاز الالتفافات، ولكن سيكون من المفيد أن يكون لديك فهم مسبق لكيفية تغيير شكل الصورة وحجمها. إذا كنت غير معتاد على الالتفافات، تحقق من [فصل الشبكات العصبية التلافيفية](https://github.com/fastai/fastbook/blob/master/13_convolutions.ipynb) من كتاب fastai!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
[ConvNeXT](model_doc/convnext) هو بنية CNN تعتمد تصاميم الشبكات الجديدة والحديثة لتحسين الأداء. ومع ذلك، لا تزال الالتفافات هي جوهر النموذج. من منظور عام، [الالتفاف](glossary#convolution) هو عملية حيث يتم ضرب مصفوفة أصغر (*نواة*) بمقطع صغير من وحدات بكسل الصورة. يحسب بعض الميزات منه، مثل نسيج معين أو انحناء خط. ثم ينزلق إلى النافذة التالية من البكسلات؛ المسافة التي تقطعها الالتفاف تسمى *الخطوة*.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/convolution.gif"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<small>عملية التفاف أساسية بدون حشو أو خطو خطوة واسعة، مأخوذة من <a href="https://arxiv.org/abs/1603.07285">دليل لحساب الالتفاف للتعلم العميق.</a></small>
|
|
||||||
|
|
||||||
يمكنك تغذية هذا الناتج إلى طبقة التفاف أخرى، ومع كل طبقة متتالية، تتعلم الشبكة أشياء أكثر تعقيدًا وتجريدية مثل النقانق أو الصواريخ. بين طبقات الالتفاف، من الشائع إضافة طبقة تجميع لتقليل الأبعاد وجعل النموذج أكثر قوة للتغيرات في موضع الميزة.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/convnext_architecture.png"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
يقوم ConvNeXT بتحديث شبكة CNN بطرق خمس:
|
|
||||||
|
|
||||||
1. تغيير عدد الكتل في كل مرحلة و"ترقيع" الصورة باستخدام خطوة أكبر وحجم نواة المقابل. تجعل استراتيجية التجزئة غير المتداخلة استراتيجية الترقيع مشابهة للطريقة التي يقسم بها ViT للصورة إلى رقع.
|
|
||||||
|
|
||||||
2. تقلص طبقة *العنق الزجاجي* عدد القنوات ثم تعيدها لأنها أسرع في إجراء التفاف 1x1، ويمكنك زيادة العمق. يقوم عنق الزجاجة المقلوب بالعكس عن طريق توسيع عدد القنوات وتقلصها، وهو أكثر كفاءة من حيث الذاكرة.
|
|
||||||
|
|
||||||
3. استبدل طبقة الالتفاف النموذجية 3x3 في طبقة عنق الزجاجة بـ *الالتفاف بالعمق*، والذي يطبق الالتفاف على كل قناة إدخال بشكل منفصل ثم يقوم بتكديسها معًا مرة أخرى في النهاية. هذا يوسع عرض الشبكة لتحسين الأداء.
|
|
||||||
|
|
||||||
4. لدى ViT مجال استقبال عالمي مما يعني أنه يمكنه رؤية المزيد من الصورة في وقت واحد بفضل آلية الانتباه الخاصة به. تحاول ConvNeXT محاكاة هذا التأثير عن طريق زيادة حجم النواة إلى 7x7.
|
|
||||||
|
|
||||||
5. يقوم ConvNeXT أيضًا بإجراء العديد من تغييرات تصميم الطبقة التي تُحاكي نماذج المحولات. هناك عدد أقل من طبقات التنشيط والطبقات التطبيع، يتم تبديل دالة التنشيط إلى GELU بدلاً من ReLU، ويستخدم LayerNorm بدلاً من BatchNorm.
|
|
||||||
|
|
||||||
يتم تمرير الإخراج من كتل الالتفاف إلى رأس تصنيف يحول المخرجات إلى احتمالات ويحسب دالة التكلفة (الخسارة المتقاطعة) للعثور على التصنيف الأكثر احتمالاً.
|
|
||||||
|
|
||||||
### اكتشاف الكائنات (Object detection)
|
|
||||||
|
|
||||||
[DETR](model_doc/detr)، *DEtection TRansformer*، هو نموذج اكتشاف كائنات من البداية إلى النهاية يجمع بين CNN مع محول المشفر-فك التشفير.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/detr_architecture.png"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
1. يأخذ العمود الفقري CNN *المدرب مسبقًا* صورة، ممثلة بقيم بكسلاتها، وينشئ خريطة ميزات منخفضة الدقة لها. يتم تطبيق التفاف 1x1 على خريطة الميزات لتقليل الأبعاد، و إنشاء خريطة ميزات جديدة بتمثيل صورة عالي المستوى. نظرًا لأن المحول (Transformer) هو نموذج تسلسلي، يتم تسوية خريطة الميزات إلى تسلسل من متجهات الميزات التي يتم دمجها مع تمثيلات التموضع.
|
|
||||||
|
|
||||||
2. يتم تمرير متجهات الميزات إلى المشفر، والذي يتعلم تمثيلات الصورة باستخدام طبقات الانتباه الخاصة به. بعد ذلك، يتم دمج الحالات المخفية للمُشفّر مع *استعلامات الكائنات* في فك التشفير. استعلامات الكائنات هي تمثيلات مكتسبة تركز على مناطق مختلفة من الصورة، ويتم تحديثها أثناء مرورها عبر كل طبقة انتباه. يتم تمرير الحالات المخفية لفك التشفير إلى شبكة تغذية أمامية التي تتنبأ بإحداثيات مربعات الإحاطة وتصنيف العلامة لكل استعلام كائن، أو `بدون كائن` إذا لم يكن هناك أي كائن.
|
|
||||||
|
|
||||||
يقوم DETR بفك تشفير كل استعلام كائن بالتوازي لإخراج *N* من التنبؤات النهائية، حيث *N* هو عدد الاستعلامات. على عكس النموذج التلقائي الذي يتنبأ بعنصر واحد في كل مرة، فإن "اكتشاف الكائنات" هو مهمة تنبؤ بمجموعة من التنبؤات (مثل `مربع إحاطة`، `تصنيف`) تقوم بإجراء *N* من التنبؤات في مرور واحدة.
|
|
||||||
|
|
||||||
3. يستخدم DETR دالة *خسارة المطابقة ثنائية الفئات* أثناء التدريب لمقارنة عدد ثابت من التنبؤات بمجموعة ثابتة من تصنيفات البيانات الحقيقية. إذا كان هناك عدد أقل من تصنيفات البيانات الحقيقية في مجموعة *N* من التصنيفات، فيتم حشوها بفئة "بدون كائن". تشجع دالة الخسارة هذه DETR على العثور على تعيين واحد لواحد بين التنبؤات وتصنيفات البيانات الحقيقية. إذا لم تكن مربعات الإحاطة أو تصنيفات الفئات صحيحة، يتم تكبد خسارة. وبالمثل، إذا تنبأ DETR بكائن غير موجود، فإنه يتم معاقبته. وهذا يشجع DETR على العثور على كائنات أخرى في الصورة بدلاً من التركيز على كائن بارز حقًا.
|
|
||||||
|
|
||||||
يتم إضافة رأس اكتشاف كائن أعلى DETR للعثور على تصنيف الكائن وإحداثيات مربع الإحاطة. هناك مكونان لرأس اكتشاف الكائنات: طبقة خطية لتحويل حالات فك التشفير المخفية إلى احتمالات عبر تصنيفات الفئات، وشبكةMLP للتنبؤ بمربع الإحاطة.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة اكتشاف الكائنات؟ تحقق من دليلنا الشامل [دليل اكتشاف الكائنات](tasks/object_detection) لمعرفة كيفية ضبط نموذج DETR واستخدامه للاستدلال!
|
|
||||||
|
|
||||||
### تجزئة الصورة (Image segmentation)
|
|
||||||
|
|
||||||
يُعد [Mask2Former](model_doc/mask2former) بنيةً شاملةً لحل جميع أنواع مهام تجزئة الصور. عادةً ما تُصمم نماذج التجزئة التقليدية لمهمة فرعية محددة من مهام تجزئة الصور، مثل تجزئة المثيل أو التجزئة الدلالية أو التجزئة الشاملة. يصوغ Mask2Former كل مهمة من تلك المهام على أنها مشكلة *تصنيف الأقنعة*. يقوم تصنيف القناع بتجميع وحدات البكسل في *N* قطعة، ويتنبأ بـ *N* أقنعة وتصنيف الفئة المقابل لها لصورة معينة. سنشرح في هذا القسم كيفية عمل Mask2Former، ويمكنك بعد ذلك تجربة ضبط SegFormer في النهاية.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/mask2former_architecture.png"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
هناك ثلاثة مكونات رئيسية لـ Mask2Former:
|
|
||||||
|
|
||||||
1. العمود الفقري [Swin](model_doc/swin) يقبل صورة وينشئ خريطة ميزات منخفضة الدقة من 3 عمليات التفافات متتالية 3x3.
|
|
||||||
|
|
||||||
2. يتم تمرير خريطة الميزات إلى *فك تشفير البكسل* الذي يقوم تدريجياً بزيادة الميزات منخفضة الدقة إلى تمثيلات عالية الدقة لكل بكسل. في الواقع، يقوم فك تشفير البكسل بإنشاء ميزات متعددة المقاييس (تحتوي على كل من الميزات منخفضة وعالية الدقة) بدقة 1/32 و1/16 و1/8 من الصورة الأصلية.
|
|
||||||
|
|
||||||
3. يتم تغذية كل من خرائط الميزات ذات المقاييس المختلفة على التوالي إلى طبقة واحدة من طبقات فك التشفير في كل مرة لالتقاط الأجسام الصغيرة من ميزات الدقة العالية. يتمثل مفتاح Mask2Former آلية *الاهتمام المقنع* في فك التشفير. على عكس الانتباه المتقاطع الذي يمكن أن يركز على الصورة بأكملها، يركز الانتباه المقنع فقط على منطقة معينة من الصورة. هذا أسرع ويؤدي إلى أداء أفضل لأن الميزات المحلية لصورة كافية للنموذج للتعلم منها.
|
|
||||||
|
|
||||||
4. مثل [DETR](tasks_explained#object-detection)، يستخدم Mask2Former أيضًا استعلامات كائن مكتسبة ويجمعها مع ميزات الصورة من فك تشفير البكسل لإجراء تنبؤ مجموعة (`تصنيف الفئة`، `التنبؤ بالقناع`). يتم تمرير حالات فك التشفير المخفية إلى طبقة خطية وتحويلها إلى احتمالات عبر علامات التصنيف. يتم حساب دالة التكلفة (الخسارة المتقاطعة) بين الاحتمالات وتصنيف الفئة لتحديد الأكثر احتمالاً.
|
|
||||||
|
|
||||||
يتم إنشاء تنبؤات الأقنعة عن طريق الجمع بين تمثيلات البكسل وحالات فك التشفير المخفية النهائية. يتم حساب دالة الخسارة المتقاطعة سيجمويد وخسارة النرد بين الاحتمالات والقناع البيانات الحقيقية للعثور على القناع الأكثر احتمالاً.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة يدك في اكتشاف الكائنات؟ تحقق من دليلنا الشامل [دليل تجزئة الصورة](tasks/semantic_segmentation) لمعرفة كيفية ضبط SegFormer واستخدامه للاستدلال!
|
|
||||||
|
|
||||||
### تقدير العمق (Depth estimation)
|
|
||||||
|
|
||||||
[GLPN](model_doc/glpn)، شبكة المسار العالمية المحلية، هي محول ل تقدير العمق الذي يجمع بين مشفر [SegFormer](model_doc/segformer) مع فك تشفير خفيف الوزن.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/glpn_architecture.jpg"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
1. مثل ViT، يتم تقسيم الصورة إلى تسلسل من الرقع، باستثناء أن هذه رقع الصورة أصغر. هذا أفضل لمهام التنبؤ الكثيفة مثل التجزئة أو تقدير العمق. يتم تحويل رقع الصورة إلى تمثيلات للرقع (راجع قسم [تصنيف الصور](#image-classification) لمزيد من التفاصيل حول كيفية إنشاء تمثيلات الرقع)، والتي يتم تغذيتها إلى المشفر.
|
|
||||||
|
|
||||||
2. يقبل المشفر تمثيلات الرقع، ويمررها عبر عدة كتل مشفرة. يتكون كل كتلة من طبقات انتباه وMix-FFN. الغرض من هذا الأخير هو توفير معلومات موضعية. في نهاية كل كتلة مشفرة توجد طبقة *دمج الرقع* لإنشاء تمثيلات هرمية. يتم دمج ميزات كل مجموعة من الرقع المجاورة، ويتم تطبيق طبقة خطية على الميزات المدمجة لتقليل عدد الرقع إلى دقة 1/4. يصبح هذا المُدخل للكتلة المشفرة التالية، حيث تتكرر هذه العملية بأكملها حتى تحصل على ميزات الصورة بدقة 1/8 و1/16 و1/32.
|
|
||||||
|
|
||||||
3. يقوم فك تشفير خفيف الوزن بأخذ خريطة الميزات الأخيرة (مقياس 1/32) من المشفر وزيادة حجمها إلى مقياس 1/16. من هنا، يتم تمرير الميزة إلى وحدة *دمج الميزات الانتقائية (SFF)*، والتي تقوم باختيار ودمج الميزات المحلية والعالمية من خريطة انتباه لكل ميزة ثم زيادة حجمها إلى 1/8. تتم إعادة هذه العملية حتى تصبح الميزات فك التشفير بنفس حجم الصورة الأصلية. يتم تمرير الإخراج عبر طبقتين تلافيفتين ثم يتم تطبيق تنشيط سيجمويد للتنبؤ بعمق كل بكسل.
|
|
||||||
|
|
||||||
## معالجة اللغات الطبيعية (Natural language processing -NLP)
|
|
||||||
|
|
||||||
تم تصميم نموذج المحول Transformer في الأصل للترجمة الآلية، ومنذ ذلك الحين أصبح في الواقع البنية الافتراضية لحل جميع مهام NLP. تناسب بعض المهام بنية المشفر في نموذج المحول، في حين أن البعض الآخر أكثر ملاءمة لفك التشفير. لا تزال مهام أخرى تستخدم بنية المشفر-فك التشفير في نموذج المحول.
|
|
||||||
|
|
||||||
### تصنيف النصوص (Text classification)
|
|
||||||
|
|
||||||
يعد [BERT](model_doc/bert) نموذج يعتمد على المُشفّر فقط، وهو أول نموذج يُطبق بشكل فعال ثنائية الاتجاه العميقة لتعلم تمثيلات أكثر ثراءً للنص من خلال الانتباه إلى الكلمات على كلا الجانبين.
|
|
||||||
|
|
||||||
1. يستخدم BERT تجزئة [WordPiece](tokenizer_summary#wordpiece) لإنشاء تمثيل رمزي للنص. للتمييز بين جملة واحدة وزوج من الجمل، تتم إضافة رمز خاص `[SEP]` للتفريق بينهما. تتم إضافة رمز خاص `[CLS]` إلى بداية كل تسلسل نصي. ويتم استخدام الإخراج النهائي مع الرمز `[CLS]` كمدخل لرأس التصنيف لمهام التصنيف. كما يضيف BERT تضمينًا للمقطع للإشارة إلى ما إذا كان الرمز ينتمي إلى الجملة الأولى أو الثانية في زوج من الجمل.
|
|
||||||
|
|
||||||
2. يتم تدريب BERT المسبق باستخدام هدفين: نمذجة اللغة المقنعة وتنبؤ الجملة التالية. في نمذجة اللغة المقنعة، يتم إخفاء نسبة مئوية مُعيّنة من رموز الإدخال بشكل عشوائي، ويجب على النموذج التنبؤ بها. يحل هذا مشكلة ثنائية الاتجاه، حيث يمكن للنموذج أن يغش ويرى جميع الكلمات و"يتنبأ" بالكلمة التالية. تتم تمرير الحالات المخفية النهائية للرموز المقنعة المتوقعة إلى شبكة تغذية أمامية مع دالة Softmax عبر مفردات اللغة للتنبؤ بالكلمة المقنعة.
|
|
||||||
|
|
||||||
الهدف الثاني من التدريب المسبق هو توقع الجملة التالية. يجب على النموذج التنبؤ بما إذا كانت الجملة "ب" تتبع الجملة"أ". نصف الوقت تكون الجملة "ب" هي الجملة التالية، والنصف الآخر من الوقت، تكون الجملة "ب" عبارة عشوائية. يتم تمرير التنبؤ، سواء كانت الجملة التالية أم لا، إلى شبكة تغذية أمامية مع دالة Softmax عبر الفئتين (`IsNext` و`NotNext`).
|
|
||||||
|
|
||||||
3. يتم تمرير تمثيلات الإدخال عبر عدة طبقات مشفرة لإخراج بعض الحالات المخفية النهائية.
|
|
||||||
|
|
||||||
لاستخدام النموذج المسبق التدريب لتصنيف النصوص، أضف رأس تصنيف تسلسلي أعلى نموذج BERT الأساسي. رأس تصنيف التسلسلي هو طبقة خطية تقبل الحالات المخفية النهائية وتجري تحويلًا خطيًا لتحويلها إلى احتمالات logits. يتم حساب دالة التكلفة (الخسارة المتقاطعة) بين logits والهدف للعثور على التصنيف الأكثر احتمالًا.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة تصنيف النصوص؟ تحقق من [دليل تصنيف النصوص](tasks/sequence_classification) الشامل الخاص بنا لمعرفة كيفية ضبط نموذج DistilBERT واستخدامه للاستنتاج!
|
|
||||||
|
|
||||||
### تصنيف الرموز (Token classification)
|
|
||||||
|
|
||||||
لاستخدام BERT لمهام تصنيف الرموز مثل التعرف على الكيانات المسماة (NER)، أضف رأس تصنيف الرموز أعلى نموذج BERT الأساسي. رأس تصنيف الرموز هو طبقة خطية تقبل الحالات المخفية النهائية وتجري تحويلًا خطيًا لتحويلها إلى logits. يتم حساب دالة التكلفة (الخسارة المتقاطعة) بين logits وكل رمز للعثور على التصنيف الأكثر احتمالًا.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة تصنيف الرموز؟ تحقق من [دليل تصنيف الرموز](tasks/token_classification) الشامل الخاص بنا لمعرفة كيفية ضبط نموذج DistilBERT واستخدامه للاستنتاج!
|
|
||||||
|
|
||||||
### الإجابة على الأسئلة (Question answering)
|
|
||||||
|
|
||||||
لاستخدام BERT للإجابة على الأسئلة، أضف رأس تصنيف المدى أعلى نموذج BERT الأساسي. تقبل هذه الطبقة الخطية الحالات المخفية النهائية وتُجري تحويلًا خطيًا لحساب داية ونهاية `الامتداد` logits `span` البداية والنهاية المقابلة للإجابة. يتم حسابدالة التكلفة (الخسارة المتقاطعة) بين logits وموقع التصنيف للعثور على الامتداد الأكثر احتمالًا من النص المقابل للإجابة.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة الإجابة على الأسئلة؟ راجع [دليل الإجابة على الأسئلة](tasks/question_answering) الشامل الخاص بنا لمعرفة كيفية ضبط نموذج DistilBERT واستخدامه في الاستدلال!
|
|
||||||
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
💡 لاحظ مدى سهولة استخدام BERT لمهام مختلفة بمجرد تدريبه مسبقًا. كل ما تحتاج إليه هو إضافة رأس محدد إلى النموذج المسبق التدريب للتلاعب بالحالات المخفية إلى الإخراج المطلوب!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
### توليد النصوص (Text generation)
|
|
||||||
|
|
||||||
يُعد [GPT-2](model_doc/gpt2) نموذجًا قائم على فك التشفير فقط تم تدريبه المسبق على كمية كبيرة من النصوص. يمكنه توليد نص مقنع (على الرغم من أنه ليس دائمًا صحيحًا!) بناءً على مُحفّز معين واستكمال مهام NLP الأخرى مثل الإجابة على الأسئلة على الرغم من أنه لم يتم تدريبه بشكل صريح على ذلك.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/gpt2_architecture.png"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
1. يستخدم GPT-2 [ترميز الأزواج البايتية (BPE)](tokenizer_summary#byte-pair-encoding-bpe) لتجزئة الكلمات وإنشاء تمثيل رمزى. يتم إضافة تمثيلات موضعية إلى تمثيلات الرموز للإشارة إلى موضع كل رمز في التسلسل. يتم تمرير تمثيلات الإدخال عبر عدة كتل فك تشفير لإخراج بعض الحالات المخفية النهائية. داخل كل كتلة فك تشفير، يستخدم GPT-2 طبقة *انتباه ذاتي مقنع* مما يعني أن GPT-2 لا يمكنه الانتباه بالرموز المستقبلية. يُسمح له فقط بالاهتمام بالرموز الموجودة على اليسار. يختلف هذا عن رمز [`mask`] الخاص بـ BERT لأنه، في الانتباه الذاتي المقنع، يتم استخدام قناع انتباه لتعيين النتيجة إلى `0` للرموز المستقبلية.
|
|
||||||
|
|
||||||
2. يتم تمرير الإخراج من فك التشفير إلى رأس نمذجة اللغة، والتي تُجري تحويلًا خطيًا لتحويل الحالات المخفية إلى احتمالات logits. التصنيف هو الرمز التالي في التسلسل، والذي يتم إنشاؤه عن طريق تغيير موضع logits إلى اليمين بمقدار واحد. يتم حساب دالة التكلفة (الخسارة المتقاطعة) بين logits التي تم تغيير موضعها والتصنيفات لإخراج الرمز التالي الأكثر احتمالًا.
|
|
||||||
|
|
||||||
يستند هدف التدريب المسبق لـ GPT-2 بالكامل إلى [نمذجة اللغة السببية](glossary#causal-language-modeling)، والتنبؤ بالكلمة التالية في تسلسل. يجعل هذا GPT-2 جيدًا بشكل خاص في المهام التي تتضمن توليد النص.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة توليد النصوص؟ تحقق من دليل [دليل نمذجة اللغة السببية](tasks/language_modeling#causal- الشامل الخاص بنا لمعرفة كيفية ضبط نموذج DistilGPT-2 واستخدامه للاستنتاج!
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للحصول على مزيد من المعلومات حول توليد النص، راجع دليل [استراتيجيات توليد النصوص](generation_strategies)!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
### التلخيص (Summarization)
|
|
||||||
|
|
||||||
تم تصميم نماذج المشفر-فك التشفير مثل [BART](model_doc/bart) و [T5](model_doc/t5) لنمط تسلسل إلى تسلسل لمهمة التلخيص. سنشرح كيف يعمل BART في هذا القسم، ثم يمكنك تجربة ضبط T5 في النهاية.
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bart_architecture.png"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
1. تتشابه بنية المشفر BART كثيرًا مع BERT وتقبل رمزًا وتمثيلًا موضعيًا للنص. يتم تدريب BART مسبقًا عن طريق إتلاف المُدخلات ثم إعادة بنائه باستخدام فك التشفير. على عكس المشفرات الأخرى ذات استراتيجيات الإتلاف المحددة، يمكن لـ BART تطبيق أي نوع من الإتلاف. ومع ذلك، فإن استراتيجية إتلاف "ملء النص" تعمل بشكل أفضل. في ملء النص، يتم استبدال عدد من امتدادات النص برمز **واحد** [`mask`]. هذا أمر مهم لأن النموذج يجب أن يتنبأ بالرموز المقنعة، ويعلّم النموذج التنبؤ بعدد الرموز المفقودة. يتم تمرير تمثيلات الإدخال والامتدادات المقنعة عبر المشفر لإخراج بعض الحالات المخفية النهائية، ولكن على عكس BERT، لا يضيف BART شبكة تغذية أمامية نهائية في النهاية للتنبؤ بكلمة.
|
|
||||||
|
|
||||||
2. يتم تمرير إخراج المشفر إلى فك التشفير، والذي يجب أن يتنبأ بالرموز المقنعة وأي رموز غير تالفة من ناتج المشفر. يمنح هذا فك التشفير سياقًا إضافيًا للمساعدة في استعادة النص الأصلي. يتم تمرير ناتج فك التشفير إلى رأس نمذجة اللغوية، والذي يجري تحويلًا خطيًا لتحويل الحالات المخفية إلى احتمالات(logits). يتم حساب دالة التكلفة (الخسارة المتقاطعة) بين الاحتمالات logits والتصنيف، وهو مجرد الرمز الذي تم تغيير موضعه إلى اليمين.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة التلخيص؟ تحقق من دليل التلخيص الشامل الخاص بنا لمعرفة كيفية ضبط نموذج T5 واستخدامه للاستنتاج!
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
للحصول على مزيد من المعلومات حول توليد النص، راجع دليل استراتيجيات توليد النص!
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
### الترجمة (Translation)
|
|
||||||
|
|
||||||
تُعد الترجمة مثالًا آخر على مهام التسلسل إلى التسلسل، مما يعني أنه يمكنك استخدام نموذج المشفر-فك التشفير مثل [BART](model_doc/bart) أو [T5](model_doc/t5) للقيام بذلك. سنشرح كيف يعمل BART في هذا القسم، ثم يمكنك تجربة ضبط T5 في النهاية.
|
|
||||||
|
|
||||||
يتكيف BART مع الترجمة عن طريق إضافة مشفر منفصل يتم تهيئته بشكل عشوائي لتعيين لغة المصدر بمدخلات يمكن فك تشفيرها إلى لغة الهدف. يتم تمرير تمثيلات هذا المشفر الجديد إلى المشفر المسبق التدريب بدلاً من تمثيلات الكلمات الأصلية. يتم تدريب مشفر المصدر عن طريق تحديث مشفر المصدر وتمثيلات التموضع وتمثيلات الإدخال باستخدام دالة التكلفة (الخسارة المتقاطعة) من ناتج النموذج. يتم تجميد معلمات النموذج في هذه الخطوة الأولى، ويتم تدريب جميع معلمات النموذج معًا في الخطوة الثانية.
|
|
||||||
|
|
||||||
تم إصدار نسخة متعددة اللغات من BART، تسمى mBART، مُخصصة للترجمة ومُدرّبة مسبقًا على العديد من اللغات المختلفة.
|
|
||||||
|
|
||||||
هل أنت مستعد لتجربة الترجمة؟ تحقق من دليل الترجمة الشامل الخاص بنا لمعرفة كيفية ضبط نموذج T5 واستخدامه للاستنتاج!
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
**للحصول على مزيد من المعلومات حول توليد النصوص، راجع دليل [استراتيجيات توليد النصوص](generation_strategies)!**
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
# التصدير إلى TFLite
|
|
||||||
|
|
||||||
[TensorFlow Lite](https://www.tensorflow.org/lite/guide) هو إطار عمل خفيف الوزن لنشر نماذج التعلم الآلي على الأجهزة المحدودة الموارد، مثل الهواتف المحمولة، والأنظمة المدمجة، وأجهزة إنترنت الأشياء (IoT). تم تصميم TFLite لتشغيل النماذج وتحسينها بكفاءة على هذه الأجهزة ذات الطاقة الحاسوبية والذاكرة واستهلاك الطاقة المحدودة.
|
|
||||||
|
|
||||||
يُمثَّل نموذج TensorFlow Lite بتنسيق محمول فعال خاص يُعرَّف بامتداد الملف `.tflite`.
|
|
||||||
|
|
||||||
🤗 Optimum يقدم وظيفة لتصدير نماذج 🤗 Transformers إلى TFLite من خلال الوحدة النمطية `exporters.tflite`. بالنسبة لقائمة هندسات النماذج المدعومة، يرجى الرجوع إلى [وثائق 🤗 Optimum](https://huggingface.co/docs/optimum/exporters/tflite/overview).
|
|
||||||
|
|
||||||
لتصدير نموذج إلى TFLite، قم بتثبيت متطلبات البرنامج المطلوبة:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install optimum[exporters-tf]
|
|
||||||
```
|
|
||||||
|
|
||||||
للاطلاع على جميع المغامﻻت المتاحة، راجع [وثائق 🤗 Optimum](https://huggingface.co/docs/optimum/main/en/exporters/tflite/usage_guides/export_a_model)، أو عرض المساعدة في سطر الأوامر:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
optimum-cli export tflite --help
|
|
||||||
```
|
|
||||||
|
|
||||||
لتصدير نسخة النموذج ل 🤗 Hub، على سبيل المثال، `google-bert/bert-base-uncased`، قم بتشغيل الأمر التالي:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
optimum-cli export tflite --model google-bert/bert-base-uncased --sequence_length 128 bert_tflite/
|
|
||||||
```
|
|
||||||
|
|
||||||
ستظهر لك السجلات التي تُبيّن التقدم وموقع حفظ ملف `model.tflite` الناتج، كما في المثال التالي:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
Validating TFLite model...
|
|
||||||
-[✓] TFLite model output names match reference model (logits)
|
|
||||||
- Validating TFLite Model output "logits":
|
|
||||||
-[✓] (1, 128, 30522) matches (1, 128, 30522)
|
|
||||||
-[x] values not close enough, max diff: 5.817413330078125e-05 (atol: 1e-05)
|
|
||||||
The TensorFlow Lite export succeeded with the warning: The maximum absolute difference between the output of the reference model and the TFLite exported model is not within the set tolerance 1e-05:
|
|
||||||
- logits: max diff = 5.817413330078125e-05.
|
|
||||||
The exported model was saved at: bert_tflite
|
|
||||||
```
|
|
||||||
|
|
||||||
يُبيّن المثال أعلاه كيفية تصدير نسخة من النموذج ل 🤗 Hub. عند تصدير نموذج محلي، تأكد أولاً من حفظ ملفات أوزان النموذج المجزء اللغوى في نفس المسار (`local_path`). عند استخدام CLI، قم بتمرير `local_path` إلى معامل `model` بدلاً من اسم النسخة على 🤗 Hub.
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
# Tiktoken والتفاعل مع Transformers
|
|
||||||
|
|
||||||
يتم دمج دعم ملفات نموذج tiktoken بسلاسة في 🤗 transformers عند تحميل النماذج
|
|
||||||
`from_pretrained` مع ملف `tokenizer.model` tiktoken على Hub، والذي يتم تحويله تلقائيًا إلى [المحلل اللغوي السريع](https://huggingface.co/docs/transformers/main/en/main_classes/tokenizer#transformers.PreTrainedTokenizerFast).
|
|
||||||
|
|
||||||
### النماذج المعروفة التي تم إصدارها مع `tiktoken.model`:
|
|
||||||
- gpt2
|
|
||||||
- llama3
|
|
||||||
|
|
||||||
## مثال على الاستخدام
|
|
||||||
|
|
||||||
من أجل تحميل ملفات `tiktoken` في `transformers`، تأكد من أن ملف `tokenizer.model` هو ملف tiktoken وسيتم تحميله تلقائيًا عند التحميل `from_pretrained`. إليك كيفية تحميل مجزىء لغوي ونموذج، والذي
|
|
||||||
يمكن تحميله من نفس الملف بالضبط:
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import AutoTokenizer
|
|
||||||
|
|
||||||
model_id = "meta-llama/Meta-Llama-3-8B-Instruct"
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id, subfolder="original")
|
|
||||||
```
|
|
||||||
## إنشاء مجزىء لغوي tiktoken
|
|
||||||
|
|
||||||
لا يحتوي ملف `tokenizer.model` على أي معلومات حول الرموز أو الأنماط الإضافية. إذا كانت هذه الأمور مهمة، قم بتحويل المحلل اللغوي إلى `tokenizer.json`، وهو التنسيق المناسب لـ [`PreTrainedTokenizerFast`].
|
|
||||||
|
|
||||||
قم بتوليد ملف `tokenizer.model` باستخدام [tiktoken.get_encoding](https://github.com/openai/tiktoken/blob/63527649963def8c759b0f91f2eb69a40934e468/tiktoken/registry.py#L63) ثم قم بتحويله إلى `tokenizer.json` باستخدام [`convert_tiktoken_to_fast`].
|
|
||||||
|
|
||||||
```py
|
|
||||||
|
|
||||||
from transformers.integrations.tiktoken import convert_tiktoken_to_fast
|
|
||||||
from tiktoken import get_encoding
|
|
||||||
|
|
||||||
# يمكنك تحميل ترميزك المخصص أو الترميز الذي توفره OpenAI
|
|
||||||
encoding = get_encoding("gpt2")
|
|
||||||
convert_tiktoken_to_fast(encoding, "config/save/dir")
|
|
||||||
```
|
|
||||||
|
|
||||||
يتم حفظ ملف `tokenizer.json` الناتج في الدليل المحدد ويمكن تحميله باستخدام [`PreTrainedTokenizerFast`].
|
|
||||||
|
|
||||||
```py
|
|
||||||
tokenizer = PreTrainedTokenizerFast.from_pretrained("config/save/dir")
|
|
||||||
```
|
|
||||||
@ -1,198 +0,0 @@
|
|||||||
# ملخص عن المجزئات اللغوية
|
|
||||||
|
|
||||||
[[open-in-colab]]
|
|
||||||
|
|
||||||
في هذه الصفحة، سنتناول بالتفصيل عملية التجزئة.
|
|
||||||
|
|
||||||
<Youtube id="VFp38yj8h3A"/>
|
|
||||||
|
|
||||||
كما رأينا في [برنامج تعليمي حول المعالجة المسبقة](preprocessing)، فإن تجزئة النص يقسمه إلى كلمات أو
|
|
||||||
الرموز الفرعية (كلمات جزئية)، والتي يتم بعد ذلك تحويلها إلى معرفات من خلال قائمة بحث. يعد تحويل الكلمات أو الرموز الفرعية إلى معرفات مباشرًا، لذا في هذا الملخص، سنركز على تقسيم النص إلى كلمات أو رموز فرعية (أي تجزئة النص).
|
|
||||||
وبشكل أكثر تحديدًا، سنلقي نظرة على الأنواع الثلاثة الرئيسية من المُجزئات اللغوية المستخدمة في 🤗 المحولات: [ترميز الأزواج البايتية (BPE)](#byte-pair-encoding)، [WordPiece](#wordpiece)، و [SentencePiece](#sentencepiece)، ونعرض أمثلة
|
|
||||||
على نوع المُجزئة الذي يستخدمه كل نموذج.
|
|
||||||
|
|
||||||
لاحظ أنه في كل صفحة نموذج، يمكنك الاطلاع على وثائق المُجزئة المرتبط لمعرفة نوع المُجزئ
|
|
||||||
الذي استخدمه النموذج المُدرب مسبقًا. على سبيل المثال، إذا نظرنا إلى [`BertTokenizer`]، يمكننا أن نرى أن النموذج يستخدم [WordPiece](#wordpiece).
|
|
||||||
|
|
||||||
## مقدمة
|
|
||||||
|
|
||||||
إن تقسيم النص إلى أجزاء أصغر هو مهمة أصعب مما تبدو، وهناك طرق متعددة للقيام بذلك.
|
|
||||||
على سبيل المثال، دعنا نلقي نظرة على الجملة `"Don't you love 🤗 Transformers? We sure do."`
|
|
||||||
|
|
||||||
<Youtube id="nhJxYji1aho"/>
|
|
||||||
|
|
||||||
يمكن تقسيم هذه الجملة ببساطة عن طريق المسافات، مما سينتج عنه ما يلي:```
|
|
||||||
|
|
||||||
```
|
|
||||||
["Don't", "you", "love", "🤗", "Transformers?", "We", "sure", "do."]
|
|
||||||
```
|
|
||||||
|
|
||||||
هذه خطوة أولى منطقية، ولكن إذا نظرنا إلى الرموز `"Transformers?"` و `"do."`، فإننا نلاحظ أن علامات الترقيم مُرفقة بالكلمات `"Transformer"` و `"do"`، وهو أمر ليس مثالي. يجب أن نأخذ علامات الترقيم في الاعتبار حتى لا يضطر النموذج إلى تعلم تمثيل مختلف للكلمة وكل رمز ترقيم مُحتمل قد يليها، الأمر الذي من شأنه أن يزيد بشكل هائل عدد التمثيلات التي يجب على النموذج تعلمها.
|
|
||||||
مع مراعاة علامات الترقيم، سيُصبح تقسيم نصنا على النحو التالي:
|
|
||||||
|
|
||||||
```
|
|
||||||
["Don", "'", "t", "you", "love", "🤗", "Transformers", "?", "We", "sure", "do", "."]
|
|
||||||
```
|
|
||||||
|
|
||||||
أفضل. ومع ذلك، من غير الملائم كيفية تقسيم الكلمة `"Don't"`. `"Don't"` تعني `"do not"`، لذا سيكون من الأفضل تحليلها على أنها كلمتين مُدمجتين `["Do"، "n't"]`. هنا تبدأ الأمور في التعقيد، وهو جزء من سبب امتلاك كل نموذج لنوّعه الخاص من مُجزّئ النصوص (tokenizer). اعتمادًا على القواعد التي نطبقها لتقسيم النص، يسيتم إنشاء مخرجات مُجزّأة مُختلفة لنفس النص. ولن يؤدي النموذج المُدرب مسبقًا إلى الأداء بشكل صحيح إلا إذا قُدّم له مُدخل تم تقسيمه بنفس القواعد التي تم استخدامها لتقسيم بيانات التدريب الخاصة به.
|
|
||||||
|
|
||||||
يُعد كل من [spaCy](https://spacy.io/) و [Moses](http://www.statmt.org/moses/?n=Development.GetStarted) هما مجزّئي النصوص التي تعتمد على القواعد
|
|
||||||
الشائعة. عند تطبيقها على مثالنا، فإن *spaCy* و *Moses* ستخرج نّصًا مثل:
|
|
||||||
|
|
||||||
```
|
|
||||||
["Do", "n't", "you", "love", "🤗", "Transformers", "?", "We", "sure", "do", "."]
|
|
||||||
```
|
|
||||||
|
|
||||||
كما يمكنك أن ترى، يتم هنا استخدام التقسيم المكاني والترقيم، وكذلك تقسيم الكلمات القائم على القواعد. يعد التقسيم المكاني والترقيم والتحليل القائم على القواعد كلاهما مثالين على تقسيم الكلمات، والذي يُعرّف بشكل غير مُحدد على أنه تقسيم الجُمل إلى كلمات. في حين أنها الطريقة الأكثر بديهية لتقسيم النصوص إلى أجزاء أصغر،
|
|
||||||
يمكن أنها تؤدى إلى مشكلات لمجموعات النصوص الضخمة. في هذه الحالة، عادةً ما يؤدي التقسيم المكاني والترقيم
|
|
||||||
إلى إنشاء مفردات كبيرة جدًا (مجموعة من جميع الكلمات والرموز الفريدة المستخدمة). على سبيل المثال، يستخدم [Transformer XL](model_doc/transfo-xl) التقسيم المكاني والترقيم، مما يؤدي إلى حجم مُفردات يبلغ 267735!
|
|
||||||
|
|
||||||
يفرض حجم المُفردات الكبير هذا على النموذج أن يكون لديه مصفوفة تضمين (embedding matrix) ضخمة كطبقة إدخال وإخراج، مما يؤدي إلى زيادة كل من التعقيد الزمني والذاكرة. بشكل عام، نادرًا ما يكون لدى نماذج المحولات حجم مفردات
|
|
||||||
أكبر من 50000، خاصة إذا تم تدريبها مسبقًا على لغة واحدة فقط.
|
|
||||||
|
|
||||||
لذا إذا كان التقسيم المكاني و الترقيم البسيط غير مرضٍ، فلماذا لا نقسّم الحروف ببساطة؟
|
|
||||||
|
|
||||||
<Youtube id="ssLq_EK2jLE"/>
|
|
||||||
|
|
||||||
في حين أن تقسيم الأحرف بسيط للغاية ومن شأنه أن يقلل بشكل كبير من التعقيد الزمني والذاكرة، إلا أنه يجعل من الصعب
|
|
||||||
على النموذج تعلم تمثيلات المدخلات ذات معنى. على سبيل المثال، يعد تعلم تمثيل مستقل عن السياق للحرف "t" أكثر صعوبة من تعلم تمثيل مستقل عن السياق لكلمة "اليوم". لذلك، غالبًا ما يكون تحليل الأحرف مصحوبًا بفقدان الأداء. لذا للحصول على أفضل ما في العالمين، تستخدم نماذج المحولات نظامًا هجينًا بين تقسيم على مستوى الكلمة وتقسيم علي مستوى الأحرف يسمى **تقسيم الوحدات الفرعية للّغة** (subword tokenization).
|
|
||||||
|
|
||||||
## تقسيم الوحدات الفرعية للّغة (Subword Tokenization)
|
|
||||||
|
|
||||||
<Youtube id="zHvTiHr506c"/>
|
|
||||||
|
|
||||||
تعتمد خوارزميات تقسيم الوحدات الفرعية subword على المبدأ القائل بأن الكلمات الشائعة الاستخدام لا ينبغي تقسيمها إلى وحدات فرعية أصغر، ولكن يجب تفكيك الكلمات النادرة إلى رموز فرعية ذات معنى. على سبيل المثال، قد يتم اعتبار "annoyingly"
|
|
||||||
كلمة نادرة ويمكن تحليلها إلى "annoying" و "ly". كل من "annoying" و "ly" كـ subwords مستقلة ستظهر بشكل متكرر أكثر في حين أن معنى "annoyingly" يتم الاحتفاظ به من خلال المعنى المركب لـ "annoying" و "ly". هذا مفيد بشكل خاص في اللغات التلصيقية مثل التركية، حيث يمكنك تشكيل كلمات مُركبة طويلة (تقريبًا) بشكل تعسفي عن طريق ضم الرموز الفرعية معًا.
|
|
||||||
|
|
||||||
يسمح تقسيم subword للنموذج بأن يكون له حجم مفردات معقول مع القدرة على تعلم تمثيلات مستقلة عن السياق ذات معنى. بالإضافة إلى ذلك، يمكّن تقسيم subword النموذج من معالجة الكلمات التي لم يسبق له رؤيتها من قبل، عن طريق تحليلها إلى رموز فرعية معروفة. على سبيل المثال، يقوم المحلل [`~transformers.BertTokenizer`] بتحليل"I have a new GPU!" كما يلي:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import BertTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = BertTokenizer.from_pretrained("google-bert/bert-base-uncased")
|
|
||||||
>>> tokenizer.tokenize("I have a new GPU!")
|
|
||||||
["i", "have", "a", "new", "gp", "##u", "!"]
|
|
||||||
```
|
|
||||||
|
|
||||||
نظرًا لأننا نستخدم نموذجًا غير حساس لحالة الأحرف (uncased model)، فقد تم تحويل الجملة إلى أحرف صغيرة أولاً. يمكننا أن نرى أن الكلمات `["i"، "have"، "a"، "new"]` موجودة في مفردات مُجزّئ النصوص، ولكن الكلمة "gpu" غير موجودة. وبالتالي، يقوم مُجزّئ النصوص بتقسيم "gpu" إلى رموز فرعية معروفة: `["gp" و "##u"]`. يعني "##" أنه يجب ربط بقية الرمز بالرمز السابق، دون مسافة (للترميز أو عكس عملية تقسيم الرموز).
|
|
||||||
|
|
||||||
كمثال آخر، يقوم المحلل [`~transformers.XLNetTokenizer`] بتقسيم نّص مثالنا السابق كما يلي:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import XLNetTokenizer
|
|
||||||
|
|
||||||
>>> tokenizer = XLNetTokenizer.from_pretrained("xlnet/xlnet-base-cased")
|
|
||||||
>>> tokenizer.tokenize("Don't you love 🤗 Transformers? We sure do.")
|
|
||||||
["▁Don", "'", "t", "▁you", "▁love", "▁"، "🤗"، "▁"، "Transform"، "ers"، "؟"، "▁We"، "▁sure"، "▁do"، "."]
|
|
||||||
```
|
|
||||||
سنعود إلى معنى تلك `"▁"` عندما نلقي نظرة على [SentencePiece](#sentencepiece). كما يمكنك أن ترى،
|
|
||||||
تم تقسيم الكلمة النادرة "Transformers" إلى الرموز الفرعية الأكثر تكرارًا `"Transform"` و `"ers"`.
|
|
||||||
|
|
||||||
دعنا الآن نلقي نظرة على كيفية عمل خوارزميات تقسيم subword المختلفة. لاحظ أن جميع خوارزميات التقسيم هذه تعتمد على بعض أشكال التدريب الذي يتم عادةً على مجموعة البيانات التي سيتم تدريبها النموذج عليها.
|
|
||||||
|
|
||||||
<a id='byte-pair-encoding'></a>
|
|
||||||
|
|
||||||
### ترميز الأزواج البايتية (BPE)
|
|
||||||
|
|
||||||
تم تقديم رميز أزواج البايت (BPE) في ورقة بحثية بعنوان [الترجمة الآلية العصبية للكلمات النادرة باستخدام وحدات subword (Sennrich et al.، 2015)](https://arxiv.org/abs/1508.07909). يعتمد BPE على مُجزّئ أولي يقسم بيانات التدريب إلى
|
|
||||||
كلمات. يمكن أن يكون التحليل المسبق بسيطًا مثل التقسيم المكاني، على سبيل المثال [GPT-2](model_doc/gpt2)، [RoBERTa](model_doc/roberta). تشمل التقسيم الأكثر تقدمًا معتمد على التحليل القائم على القواعد، على سبيل المثال [XLM](model_doc/xlm)، [FlauBERT](model_doc/flaubert) الذي يستخدم Moses لمعظم اللغات، أو [GPT](model_doc/openai-gpt) الذي يستخدم spaCy و ftfy، لحساب تكرار كل كلمة في مجموعة بيانات التدريب.
|
|
||||||
|
|
||||||
بعد التحليل المسبق، يتم إنشاء مجموعة من الكلمات الفريدة وقد تم تحديد تكرار كل كلمة في تم تحديد بيانات التدريب. بعد ذلك، يقوم BPE بإنشاء مفردات أساسية تتكون من جميع الرموز التي تحدث في مجموعة الكلمات الفريدة ويتعلم قواعد الدمج لتشكيل رمز جديد من رمزين من المفردات الأساسية. إنه يفعل ذلك حتى تصل المفردات إلى حجم المفردات المطلوب. لاحظ أن حجم المفردات هو فرط معلمة لتحديد قبل تدريب مُجزّئ النصوص.
|
|
||||||
|
|
||||||
كمثال، دعنا نفترض أنه بعد التقسيم الأولي، تم تحديد مجموعة الكلمات التالية بما في ذلك تكرارها:
|
|
||||||
|
|
||||||
```
|
|
||||||
("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)
|
|
||||||
```
|
|
||||||
|
|
||||||
وبالتالي، فإن المفردات الأساسية هي `["b"، "g"، "h"، "n"، "p"، "s"، "u"]`. من خلال تقسيم جميع الكلمات إلى رموز من
|
|
||||||
المفردات الأساسية، نحصل على:
|
|
||||||
|
|
||||||
```
|
|
||||||
("h" "u" "g"، 10)، ("p" "u" "g"، 5)، ("p" "u" "n"، 12)، ("b" "u" "n"، 4)، ("h" "u" "g" "s"، 5)
|
|
||||||
```
|
|
||||||
|
|
||||||
بعد ذلك، يقوم BPE بعدد مرات حدوث كل زوج من الرموز المحتملة ويختار زوج الرموز الذي يحدث بشكل متكرر. في
|
|
||||||
في المثال أعلاه، يحدث "h" متبوعًا بـ "u" _10 + 5 = 15_ مرة (10 مرات في 10 مرات
|
|
||||||
حدوث "hug"، 5 مرات في 5 مرات حدوث "hugs"). ومع ذلك، فإن أكثر أزواج الرموز شيوعًا هو "u" متبوعًا
|
|
||||||
بواسطة "g"، والتي تحدث _10 + 5 + 5 = 20_ مرة في المجموع. وبالتالي، فإن أول قاعدة دمج يتعلمها المحلل هي تجميع جميع
|
|
||||||
رموز "u" التي تتبعها "g" معًا. بعد ذلك، يتم إضافة "ug" إلى المفردات. تصبح مجموعة الكلمات
|
|
||||||
|
|
||||||
```
|
|
||||||
("h" "ug"، 10)، ("p" "ug"، 5)، ("p" "u" "n"، 12)، ("b" "u" "n"، 4)، ("h" "ug" "s"، 5)
|
|
||||||
```
|
|
||||||
|
|
||||||
بعد ذلك، يحدد BPE ثاني أكثر أزواج الرموز شيوعًا. إنه "u" متبوعًا بـ "n"، والذي يحدث 16 مرة. "u"،
|
|
||||||
يتم دمج "n" في "un" ويضاف إلى المفردات. ثالث أكثر أزواج الرموز شيوعًا هو "h" متبوعًا
|
|
||||||
بواسطة "ug"، والتي تحدث 15 مرة. مرة أخرى يتم دمج الزوج ويتم إضافة "hug" إلى المفردات.
|
|
||||||
|
|
||||||
في هذه المرحلة، تكون المفردات هي `["b"، "g"، "h"، "n"، "p"، "s"، "u"، "ug"، "un"، "hug"]` ومجموعة الكلمات الفريدة لدينا
|
|
||||||
تمثيله كما يلي:
|
|
||||||
|
|
||||||
```
|
|
||||||
("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5)
|
|
||||||
```
|
|
||||||
|
|
||||||
بافتراض أن تدريب ترميز الأزواج البايت سيتوقف عند هذه النقطة، فسيتم تطبيق قواعد الدمج التي تم تعلمها بعد ذلك على الكلمات الجديدة (طالما أن هذه الكلمات الجديدة لا تشمل رموزًا لم تكن في المفردات الأساسية). على سبيل المثال، سيتم تقسيم كلمة "bug" إلى `["b"، "ug"]` ولكن سيتم تقسيم "mug" على أنها `["<unk>"، "ug"]` نظرًا لأن الرمز "m" غير موجود في المفردات الأساسية. بشكل عام، لا يتم استبدال الأحرف الفردية مثل "m" بالرمز "<unk>" لأن بيانات التدريب تتضمن عادةً ظهورًا واحدًا على الأقل لكل حرف، ولكن من المحتمل أن يحدث ذلك لرموز خاصة جدًا مثل الرموز التعبيرية.
|
|
||||||
|
|
||||||
كما ذكرنا سابقًا، فإن حجم المفردات، أي حجم المفردات الأساسية + عدد عمليات الدمج، هو معامل يجب اختياره. على سبيل المثال، لدى [GPT](model_doc/openai-gpt) حجم مفردات يبلغ 40478 منذ أن كان لديهم 478 حرفًا أساسيًا واختاروا التوقف عن التدريب بعد 40,000 عملية دمج.
|
|
||||||
|
|
||||||
#### ترميز الأزواج البايتية على مستوى البايت
|
|
||||||
|
|
||||||
قد تكون المفردات الأساسية التي تتضمن جميع الأحرف الأساسية كبيرة جدًا إذا *على سبيل المثال* تم اعتبار جميع أحرف اليونيكود
|
|
||||||
كأحرف أساسية. لذا، ليكون لديك مفردات أساسية أفضل، يستخدم [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf) البايتات كمفردات أساسية، وهي حيلة ذكية لإجبار المفردات الأساسية على أن تكون بحجم 256 مع ضمان أن يتم تضمين كل حرف أساسي في المفردات. مع بعض القواعد الإضافية للتعامل مع علامات الترقيم، يمكن لمُجزّئ النصوص GPT2 تجزئة أي نص دون الحاجة إلى رمز <unk>. لدى [GPT-2](model_doc/gpt) حجم مفردات يبلغ 50257، والذي يتوافق مع رموز 256 base byte، ورمز خاص لنهاية النص والرموز التي تم تعلمها باستخدام 50000 عملية دمج.
|
|
||||||
|
|
||||||
<a id='wordpiece'></a>
|
|
||||||
|
|
||||||
### WordPiece
|
|
||||||
|
|
||||||
تعتبر WordPiece خوارزمية تجزئة الكلمات الفرعية subword المستخدمة لـ [BERT](model_doc/bert)، [DistilBERT](model_doc/distilbert)، و [Electra](model_doc/electra). تم توضيح الخوارزمية في [البحث الصوتي الياباني والكوري
|
|
||||||
(Schuster et al.، 2012)](https://static.googleusercontent.com/media/research.google.com/ja//pubs/archive/37842.pdf) وهو مشابه جدًا
|
|
||||||
BPE. أولاً، يقوم WordPiece بتكوين المفردات لتضمين كل حرف موجود في بيانات التدريب
|
|
||||||
وتعلم تدريجياً عددًا معينًا من قواعد الدمج. على عكس BPE، لا يختار WordPiece أكثر زوج الرموز المتكررة، ولكن تلك التي تزيد من احتمال بيانات التدريب بمجرد إضافتها إلى المفردات.
|
|
||||||
|
|
||||||
لذا، ماذا يعني هذا بالضبط؟ بالإشارة إلى المثال السابق، فإن زيادة احتمال بيانات التدريب تعادل إيجاد زوج الرموز، الذي يكون احتمال تقسيمه على احتمالات رمزه الأول تليها رمزه الثاني هو الأكبر بين جميع أزواج الرموز. *مثال* `"u"`، تليها `"g"` كانت قد اندمجت فقط إذا كان احتمال `"ug"` مقسومًا على `"u"`، `"g"` كان سيكون أكبر من أي زوج آخر من الرموز. بديهيًا، WordPiece مختلف قليلاً عن BPE في أنه يقيم ما يفقده عن طريق دمج رمزين للتأكد من أنه يستحق ذلك.
|
|
||||||
|
|
||||||
<a id='unigram'></a>
|
|
||||||
|
|
||||||
### Unigram
|
|
||||||
|
|
||||||
Unigram هو خوارزمية توكنيز subword التي تم تقديمها في [تنظيم subword: تحسين نماذج الترجمة الشبكة العصبية
|
|
||||||
نماذج مع مرشحين subword متعددة (Kudo، 2018)](https://arxiv.org/pdf/1804.10959.pdf). على عكس BPE أو
|
|
||||||
WordPiece، يقوم Unigram بتكوين مفرداته الأساسية إلى عدد كبير من الرموز ويقللها تدريجياً للحصول على مفردات أصغر. يمكن أن تتوافق المفردات الأساسية على سبيل المثال مع جميع الكلمات المسبقة التوكنز والسلاسل الفرعية الأكثر شيوعًا. لا يتم استخدام Unigram مباشرة لأي من النماذج في المحولات، ولكنه يستخدم بالاقتران مع [SentencePiece](#sentencepiece).
|
|
||||||
|
|
||||||
في كل خطوة تدريب، يحدد خوارزمية Unigram خسارة (غالبًا ما يتم تعريفها على أنها اللوغاريتم) عبر بيانات التدريب بالنظر إلى المفردات الحالية ونموذج اللغة unigram. بعد ذلك، بالنسبة لكل رمز في المفردات، يحسب الخوارزمية مقدار زيادة الخسارة الإجمالية إذا تم إزالة الرمز من المفردات. ثم يقوم Unigram بإزالة p (مع p عادة ما تكون 10% أو 20%) في المائة من الرموز التي تكون زيادة الخسارة فيها هي الأدنى، *أي* تلك
|
|
||||||
الرموز التي تؤثر أقل على الخسارة الإجمالية عبر بيانات التدريب. تتكرر هذه العملية حتى تصل المفردات إلى الحجم المطلوب. يحتفظ خوارزمية Unigram دائمًا بالشخصيات الأساسية بحيث يمكن توكنز أي كلمة.
|
|
||||||
|
|
||||||
نظرًا لأن Unigram لا يعتمد على قواعد الدمج (على عكس BPE وWordPiece)، فإن للخوارزمية عدة طرق
|
|
||||||
توكنز نص جديد بعد التدريب. على سبيل المثال، إذا كان محول Unigram المدرب يعرض المفردات:
|
|
||||||
|
|
||||||
```
|
|
||||||
["b"، "g"، "h"، "n"، "p"، "s"، "u"، "ug"، "un"، "hug"]،
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكن توكنز `"hugs"` على أنه `["hug"، "s"]`، أو `["h"، "ug"، "s"]` أو `["h"، "u"، "g"، "s"]`. إذن ماذا
|
|
||||||
لاختيار؟ يحفظ Unigram احتمال كل رمز في فيلق التدريب بالإضافة إلى حفظ المفردات بحيث
|
|
||||||
يمكن حساب احتمال كل توكنز ممكن بعد التدريب. ببساطة، يختار الخوارزمية الأكثر
|
|
||||||
توكنز المحتملة في الممارسة، ولكنه يوفر أيضًا إمكانية أخذ عينات من توكنز ممكن وفقًا لاحتمالاتها.
|
|
||||||
|
|
||||||
تتم تعريف هذه الاحتمالات بواسطة الخسارة التي يتم تدريب المحول عليها. بافتراض أن بيانات التدريب تتكون
|
|
||||||
من الكلمات \\(x_{1}، \dots، x_{N}\\) وأن مجموعة جميع التوكنزات الممكنة لكلمة \\(x_{i}\\) هي
|
|
||||||
يتم تعريفها على أنها \\(S(x_{i})\\)، ثم يتم تعريف الخسارة الإجمالية على النحو التالي
|
|
||||||
|
|
||||||
$$\mathcal{L} = -\sum_{i=1}^{N} \log \left ( \sum_{x \in S(x_{i})} p(x) \right )$$
|
|
||||||
|
|
||||||
<a id='sentencepiece'></a>
|
|
||||||
|
|
||||||
### SentencePiece
|
|
||||||
|
|
||||||
تحتوي جميع خوارزميات توكنز الموصوفة حتى الآن على نفس المشكلة: من المفترض أن النص المدخل يستخدم المسافات لفصل الكلمات. ومع ذلك، لا تستخدم جميع اللغات المسافات لفصل الكلمات. أحد الحلول الممكنة هو استخداممعالج مسبق للغة محدد، *مثال* [XLM](model_doc/xlm) يلذي يستخدم معالجات مسبقة محددة للصينية واليابانية والتايلاندية.
|
|
||||||
لحل هذه المشكلة بشكل أعم، [SentencePiece: A simple and language independent subword tokenizer and
|
|
||||||
detokenizer for Neural Text Processing (Kudo et al.، 2018)](https://arxiv.org/pdf/1808.06226.pdf) يتعامل مع المدخلات
|
|
||||||
كتدفق بيانات خام، وبالتالي يشمل المسافة في مجموعة الأحرف التي سيتم استخدامها. ثم يستخدم خوارزمية BPE أو unigram
|
|
||||||
لبناء المفردات المناسبة.
|
|
||||||
|
|
||||||
يستخدم [`XLNetTokenizer`] SentencePiece على سبيل المثال، وهو أيضًا سبب تضمين تم تضمين حرف `"▁"` في المفردات. عملية فك التشفير باستخدام SentencePiece سهلة للغاية نظرًا لأنه يمكن دائمًا دمج الرموز معًا واستبدال `"▁"` بمسافة.
|
|
||||||
|
|
||||||
تستخدم جميع نماذج المحولات في المكتبة التي تستخدم SentencePiece بالاقتران مع unigram. أمثلة على النماذج
|
|
||||||
باستخدام SentencePiece هي [ALBERT](model_doc/albert)، [XLNet](model_doc/xlnet)، [Marian](model_doc/marian)، و [T5](model_doc/t5).
|
|
||||||
@ -1,154 +0,0 @@
|
|||||||
# التصدير إلى TorchScript
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
هذه هي بداية تجاربنا مع TorchScript ولا زلنا نستكشف قدراته مع نماذج المدخلات المتغيرة الحجم. إنه مجال اهتمامنا وسنعمق تحليلنا في الإصدارات القادمة، مع المزيد من الأمثلة البرمجية، وتنفيذ أكثر مرونة، ومقاييس مقارنة بين الأكواد القائمة على Python مع أكواد TorchScript المُجمّعة.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
وفقًا لـ [وثائق TorchScript](https://pytorch.org/docs/stable/jit.html):
|
|
||||||
|
|
||||||
> TorchScript هي طريقة لإنشاء نماذج قابلة للتسلسل والتحسين من تعليمات PyTorch البرمجية.
|
|
||||||
|
|
||||||
هناك وحدتان من PyTorch، [JIT and TRACE](https://pytorch.org/docs/stable/jit.html)، تتيحان للمطورين تصدير نماذجهم لإعادة استخدامها في برامج أخرى مثل برامج C++ المُحسّنة للأداء.
|
|
||||||
|
|
||||||
نقدم واجهة تتيح لك تصدير نماذج 🤗 Transformers إلى TorchScript بحيث يمكن إعادة استخدامها في بيئة مختلفة عن برامج Python القائمة إلى PyTorch. هنا نشرح كيفية تصدير نماذجنا واستخدامها باستخدام TorchScript.
|
|
||||||
|
|
||||||
يتطلب تصدير نموذج أمرين:
|
|
||||||
|
|
||||||
- تهيئة مثيل للنموذج باستخدام علامة `torchscript`
|
|
||||||
- تمرير مُدخلات وهمية (dummy inputs) خلال النموذج
|
|
||||||
|
|
||||||
تنطوي هذه الضرورات على عدة أمور يجب على المطورين توخي الحذر بشأنها كما هو مفصل أدناه.
|
|
||||||
|
|
||||||
## علامة TorchScript والأوزان المرتبطة
|
|
||||||
|
|
||||||
علامة `torchscript` ضرورية لأن معظم نماذج اللغة 🤗 Transformers لها أوزان مرتبطة بين طبقة `Embedding` وطبقة `Decoding`. لا يسمح لك TorchScript بتصدير النماذج ذات الأوزان المرتبطة، لذلك من الضروري فصل الأوزان ونسخها مسبقًا.
|
|
||||||
|
|
||||||
النماذج المُهيأة باستخدام علامة `torchscript` لها طبقة `Embedding` وطبقة`Decoding` منفصلتين، مما يعني أنه لا ينبغي تدريبها لاحقًا. سيؤدي التدريب إلى عدم تزامن الطبقتين، مما يؤدي إلى نتائج غير متوقعة.
|
|
||||||
|
|
||||||
هذا لا ينطبق على النماذج التي لا تحتوي على رأس نموذج اللغة، حيث لا تملك أوزانًا مرتبطة. يمكن تصدير هذه النماذج بأمان دون علامة `torchscript`.
|
|
||||||
|
|
||||||
## المدخلات الوهمية والأطوال القياسية
|
|
||||||
|
|
||||||
تُستخدم المُدخلات الوهمية لتمرير أمامي خلال النموذج. أثناء انتشار قيم المُدخلات عبر الطبقات، يتتبع PyTorch العمليات المختلفة التي يتم تنفيذها على كل مصفوفة(tensor). ثم يتم استخدام هذه العمليات المُسجلة بعد ذلك لإنشاء *أثر* النموذج.
|
|
||||||
|
|
||||||
يتم إنشاء التتبع بالنسبة لأبعاد المُدخلات. وبالتالي، فهو مُقيّد بأبعاد المُدخلات الوهمية، ولن يعمل لأي طول تسلسل أو حجم دفعة مختلف. عند المحاولة بحجم مختلف، يتم رفع الخطأ التالي:
|
|
||||||
|
|
||||||
```
|
|
||||||
`The expanded size of the tensor (3) must match the existing size (7) at non-singleton dimension 2`
|
|
||||||
```
|
|
||||||
|
|
||||||
نوصي بتتبع النموذج باستخدام حجم مُدخلات وهمية لا يقل عن أكبر مُدخل سيتم تقديمه للنموذج أثناء الاستدلال. يمكن أن تساعد الحشوة(padding) في ملء القيم المفقودة. ومع ذلك، نظرًا لتتبع النموذج بحجم مُدخل أكبر، ستكون أبعاد المصفوفة ستكون كبيرة أيضًا، مما يؤدي عنه المزيد من الحسابات.
|
|
||||||
|
|
||||||
انتبه إلى إجمالي عدد العمليات المُنفذة على كل مُدخل وتابع الأداء عن كثب عند تصدير نماذج متغيرة طول التسلسل.
|
|
||||||
|
|
||||||
## استخدام TorchScript في Python
|
|
||||||
|
|
||||||
يوضح هذا القسم كيفية حفظ النماذج وتحميلها، بالإضافة إلى كيفية استخدام التتبع للاستدلال.
|
|
||||||
|
|
||||||
### حفظ نموذج
|
|
||||||
|
|
||||||
لتصدير `BertModel` باستخدام TorchScript، قم بتهيئة ـ `BertModel` من فئة `BertConfig` ثم احفظه على القرص تحت اسم الملف `traced_bert.pt`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import BertModel, BertTokenizer, BertConfig
|
|
||||||
import torch
|
|
||||||
|
|
||||||
enc = BertTokenizer.from_pretrained("google-bert/bert-base-uncased")
|
|
||||||
|
|
||||||
# Tokenizing input text
|
|
||||||
text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]"
|
|
||||||
tokenized_text = enc.tokenize(text)
|
|
||||||
|
|
||||||
# Masking one of the input tokens
|
|
||||||
masked_index = 8
|
|
||||||
tokenized_text[masked_index] = "[MASK]"
|
|
||||||
indexed_tokens = enc.convert_tokens_to_ids(tokenized_text)
|
|
||||||
segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
|
|
||||||
|
|
||||||
# Creating a dummy input
|
|
||||||
tokens_tensor = torch.tensor([indexed_tokens])
|
|
||||||
segments_tensors = torch.tensor([segments_ids])
|
|
||||||
dummy_input = [tokens_tensor, segments_tensors]
|
|
||||||
|
|
||||||
# Initializing the model with the torchscript flag
|
|
||||||
# Flag set to True even though it is not necessary as this model does not have an LM Head.
|
|
||||||
config = BertConfig(
|
|
||||||
vocab_size_or_config_json_file=32000,
|
|
||||||
hidden_size=768,
|
|
||||||
num_hidden_layers=12,
|
|
||||||
num_attention_heads=12,
|
|
||||||
intermediate_size=3072,
|
|
||||||
torchscript=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Instantiating the model
|
|
||||||
model = BertModel(config)
|
|
||||||
|
|
||||||
# The model needs to be in evaluation mode
|
|
||||||
model.eval()
|
|
||||||
|
|
||||||
# If you are instantiating the model with *from_pretrained* you can also easily set the TorchScript flag
|
|
||||||
model = BertModel.from_pretrained("google-bert/bert-base-uncased", torchscript=True)
|
|
||||||
|
|
||||||
# Creating the trace
|
|
||||||
traced_model = torch.jit.trace(model, [tokens_tensor, segments_tensors])
|
|
||||||
torch.jit.save(traced_model, "traced_bert.pt")
|
|
||||||
```
|
|
||||||
|
|
||||||
### تحميل نموذج
|
|
||||||
|
|
||||||
يمكنك الآن تحميل `BertModel` المُحفظ سابقًا، `traced_bert.pt`، من القرص واستخدامه على `dummy_input` المُهيأ سابقًا:
|
|
||||||
|
|
||||||
```python
|
|
||||||
loaded_model = torch.jit.load("traced_bert.pt")
|
|
||||||
loaded_model.eval()
|
|
||||||
|
|
||||||
all_encoder_layers, pooled_output = loaded_model(*dummy_input)
|
|
||||||
```
|
|
||||||
|
|
||||||
### استخدام نموذج مُتتبع للاستدلال
|
|
||||||
|
|
||||||
استخدم النموذج المُتتبع للاستدلال باستخدام أسلوب `__call__` الخاص به:
|
|
||||||
|
|
||||||
```python
|
|
||||||
traced_model(tokens_tensor, segments_tensors)
|
|
||||||
```
|
|
||||||
|
|
||||||
## نشر نماذج Hugging Face TorchScript على AWS باستخدام Neuron SDK
|
|
||||||
|
|
||||||
قدمت AWS عائلة [Amazon EC2 Inf1](https://aws.amazon.com/ec2/instance-types/inf1/) من اﻷجهزة لخفض التكلفة وأداء التعلم الآلي عالي الأداء في البيئة السحابية. تعمل أجهزة Inf1 بواسطة شريحة Inferentia من AWS، وهي مُسرّع أجهزة مُخصص، متخصص في أعباء عمل الاستدلال للتعلم العميق. [AWS Neuron](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/#) هي SDK لـ Inferentia التي تدعم تتبع نماذج المحولات وتحسينها للنشر على Inf1. توفر Neuron SDK ما يلي:
|
|
||||||
|
|
||||||
1. واجهة برمجة تطبيقات سهلة الاستخدام مع تغيير سطر واحد من التعليمات البرمجية لتتبع نموذج TorchScript وتحسينه للاستدلال في البيئة السحابية.
|
|
||||||
2. تحسينات الأداء الجاهزة للاستخدام [تحسين التكلفة والأداء](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/neuron-guide/benchmark/>).
|
|
||||||
3. دعم نماذج Hugging Face المحولات المبنية باستخدام إما [PyTorch](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/src/examples/pytorch/bert_tutorial/tutorial_pretrained_bert.html) أو [TensorFlow](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/src/examples/tensorflow/huggingface_bert/huggingface_bert.html).
|
|
||||||
|
|
||||||
### الآثار المترتبة
|
|
||||||
|
|
||||||
تعمل نماذج المحولات المستندة إلى بنية [BERT (تمثيلات الترميز ثنائية الاتجاه من المحولات)](https://huggingface.co/docs/transformers/main/model_doc/bert) أو متغيراتها مثل [distilBERT](https://huggingface.co/docs/transformers/main/model_doc/distilbert) و [roBERTa](https://huggingface.co/docs/transformers/main/model_doc/roberta) بشكل أفضل على Inf1 للمهام غير التوليدية مثل الإجابة على الأسئلة الاستخراجية، وتصنيف التسلسلات، وتصنيف الرموز (tokens). ومع ذلك، يمكن تكييف مهام توليد النصوص للعمل على Inf1 وفقًا لهذا [برنامج تعليمي AWS Neuron MarianMT](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/src/examples/pytorch/transformers-marianmt.html). يمكن العثور على مزيد من المعلومات حول النماذج التي يمكن تحويلها جاهزة على Inferentia في قسم [ملاءمة بنية النموذج](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/neuron-guide/models/models-inferentia.html#models-inferentia) من وثائق Neuron.
|
|
||||||
|
|
||||||
### التبعيات (Dependencies)
|
|
||||||
|
|
||||||
يتطلب استخدام AWS Neuron لتحويل النماذج [بيئة SDK Neuron](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/neuron-guide/neuron-frameworks/pytorch-neuron/index.html#installation-guide) والتي تأتي مسبقًا على [AMI للتعلم العميق من AWS](https://docs.aws.amazon.com/dlami/latest/devguide/tutorial-inferentia-launching.html).
|
|
||||||
|
|
||||||
### تحويل نموذج لـ AWS Neuron
|
|
||||||
|
|
||||||
قم بتحويل نموذج لـ AWS NEURON باستخدام نفس التعليمات البرمجية من [استخدام TorchScript في Python](torchscript#using-torchscript-in-python) لتتبع `BertModel`. قم باستيراد امتداد إطار عمل `torch.neuron` للوصول إلى مكونات Neuron SDK من خلال واجهة برمجة تطبيقات Python:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import BertModel, BertTokenizer, BertConfig
|
|
||||||
import torch
|
|
||||||
import torch.neuron
|
|
||||||
```
|
|
||||||
|
|
||||||
كل ما عليك فعله هو تعديل السطر التالي:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
- torch.jit.trace(model, [tokens_tensor, segments_tensors])
|
|
||||||
+ torch.neuron.trace(model, [token_tensor, segments_tensors])
|
|
||||||
```
|
|
||||||
|
|
||||||
يتيح ذلك لـ Neuron SDK تتبع النموذج وتحسينه لمثيلات Inf1.
|
|
||||||
|
|
||||||
لمعرفة المزيد حول ميزات AWS Neuron SDK والأدوات ودروس البرامج التعليمية والتحديثات الأخيرة، يرجى الاطلاع على [وثائق AWS NeuronSDK](https://awsdocs-neuron.readthedocs-hosted.com/en/latest/index.html).
|
|
||||||
@ -1,720 +0,0 @@
|
|||||||
# Trainer
|
|
||||||
|
|
||||||
تُتيح وحدة [`Trainer`] حلقة تدريب وتقييم متكاملة لنماذج PyTorch المطبقة في مكتبة Transformers. تحتاج فقط إلى تمرير المكونات الضرورية للتدريب (النموذج، والمجزىء النصى، ومجموعة البيانات، دالة التقييم، معلمات التدريب الفائقة، إلخ)، وستتولى فئة [`Trainer`] الباقي. هذا يُسهّل بدء التدريب بشكل أسرع دون كتابة حلقة التدريب الخاصة بك يدويًا. ولكن في الوقت نفسه، فإن [`Trainer`] قابل للتخصيص بدرجة كبيرة ويوفر العديد من خيارات التدريب حتى تتمكن من تخصيصه وفقًا لاحتياجات التدريب الخاصة بك بدقة.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
بالإضافة إلى فئة [`Trainer`], توفر مكتبة Transformers أيضًا فئة [`Seq2SeqTrainer`] للمهام التسلسلية مثل الترجمة أو التلخيص. هناك أيضًا فئة [`~trl.SFTTrainer`] من مكتبة [TRL](https://hf.co/docs/trl) التي تغلّف فئة [`Trainer`] وهي مُحُسَّنة لتدريب نماذج اللغة مثل Llama-2 وMistral باستخدام تقنيات التوليد اللغوي. كما يدعم [`~trl.SFTTrainer`] ميزات مثل حزم التسلسلات، وLoRA، والقياس الكمي، وDeepSpeed مما يُمكّن من التدريب بكفاءة على نماذج ضخمة الحجم.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
لا تتردد في الاطلاع على [مرجع API](./main_classes/trainer) لهذه الفئات الأخرى من النوع [`Trainer`] لمعرفة المزيد حول متى يتم استخدام كل منها. بشكل عام، [`Trainer`] هو الخيار الأكثر تنوعًا ومناسبًا لمجموعة واسعة من المهام. تم تصميم [`Seq2SeqTrainer`] للمهام التسلسلية ، و [`~trl.SFTTrainer`] مُصمم لتدريب نماذج اللغة الكبيرة.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
قبل البدء، تأكد من تثبيت مكتبة [Accelerate](https://hf.co/docs/accelerate) - وهي مكتبة تُمكّن تشغيل تدريب PyTorch في بيئات مُوزعة.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install accelerate
|
|
||||||
|
|
||||||
# upgrade
|
|
||||||
pip install accelerate --upgrade
|
|
||||||
```
|
|
||||||
|
|
||||||
يوفر هذا الدليل نظرة عامة على فئة [`Trainer`].
|
|
||||||
|
|
||||||
## الاستخدام الأساسي
|
|
||||||
|
|
||||||
يتضمن [`Trainer`] جميع التعليمات البرمجية التي ستجدها في حلقة التدريب الأساسية:
|
|
||||||
|
|
||||||
1. قم بتنفيذ خطوة تدريب لحساب الخسارة
|
|
||||||
2. احسب المشتقات باستخدام طريقة [`~accelerate.Accelerator.backward`]
|
|
||||||
3. تحديث الأوزان بناءً على المشتقات
|
|
||||||
4. كرر هذه العملية حتى تصل إلى عدد محدد مسبقًا من الدورات (epochs).
|
|
||||||
|
|
||||||
تُجرد فئة [`Trainer`] كل هذه التعليمات البرمجية حتى لا تضطر إلى القلق بشأن كتابة حلقة تدريب يدويًا في كل مرة أما إذا كنت بدأت للتو في PyTorch والتدريب. كل ما عليك فعله هو توفير المكونات الأساسية اللازمة للتدريب، مثل النموذج ومجموعة بيانات، وتتعامل فئة [`Trainer`] مع كل شيء آخر.
|
|
||||||
|
|
||||||
إذا كنت تُريد تحديد أي خيارات تدريب أو معلمات فائقة، فيمكنك العثور عليها في فئة [`TrainingArguments`]. على سبيل المثال، دعنا نحدد أين يتم حفظ النموذج في `output_dir` ورفع النموذج إلى Hub بعد التدريب باستخدام `push_to_hub=True`.
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import TrainingArguments
|
|
||||||
|
|
||||||
training_args = TrainingArguments(
|
|
||||||
output_dir="your-model"،
|
|
||||||
learning_rate=2e-5,
|
|
||||||
per_device_train_batch_size=16,
|
|
||||||
per_device_eval_batch_size=16,
|
|
||||||
num_train_epochs=2,
|
|
||||||
weight_decay=0.01,
|
|
||||||
eval_strategy="epoch"،
|
|
||||||
save_strategy="epoch"،
|
|
||||||
load_best_model_at_end=True,
|
|
||||||
push_to_hub=True,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
مرر `training_args` إلى [`Trainer`] جنبًا إلى جنب مع النموذج، ومجموعة بيانات، وشئ لمعالجة مجموعة البيانات مسبقًا (حسب نوع البيانات، فقد يكون محللًا رمزيًا أو مستخرج ميزات أو معالج صور)، وجامع بيانات، ودالة لحساب المقاييس التي تُريد تتبعها أثناء التدريب.
|
|
||||||
|
|
||||||
أخيرًا، استدعِ [`~Trainer.train`] لبدء التدريب!
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import Trainer
|
|
||||||
|
|
||||||
trainer = Trainer(
|
|
||||||
model=model,
|
|
||||||
args=training_args,
|
|
||||||
train_dataset=dataset["train"]،
|
|
||||||
eval_dataset=dataset["test"]،
|
|
||||||
tokenizer=tokenizer,
|
|
||||||
data_collator=data_collator,
|
|
||||||
compute_metrics=compute_metrics,
|
|
||||||
)
|
|
||||||
|
|
||||||
trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
### نقاط الحفظ
|
|
||||||
|
|
||||||
تحفظ فئة [`Trainer`] نقاط الحفظ النموذج في الدليل المحدد في معامل `output_dir` من [`TrainingArguments`]. ستجد نقاط الحفظ في مجلد فرعي يسمى `checkpoint-000` حيث تتوافق الأرقام في النهاية مع خطوة التدريب. إن حفظ نقاط الحفظ مفيد لاستئناف التدريب لاحقًا.
|
|
||||||
|
|
||||||
```py
|
|
||||||
# استأنف من أحدث نقطة حفظ
|
|
||||||
trainer.train(resume_from_checkpoint=True)
|
|
||||||
|
|
||||||
# استأنف من نقطة حفظ محددة محفوظة في دليل الإخراج
|
|
||||||
trainer.train(resume_from_checkpoint="your-model/checkpoint-1000")
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك حفظ نقاط الحفظ الخاصة بك (لا يتم حفظ حالة المُجزىء اللغوى تقائيًا) إلى Hub عن طريق تعيين `push_to_hub=True` في [`TrainingArguments`] لرفعها. الخيارات الأخرى لاتخاذ القرار بشأن كيفية حفظ هذة النقاط الخاصة بك هي الإعداد في معامل [`hub_strategy`](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments.hub_strategy):
|
|
||||||
|
|
||||||
* `hub_strategy="checkpoint"` يدفع أحدث نقطة حفظ إلى مجلد فرعي يسمى "last-checkpoint" يمكنك استئناف التدريب منه
|
|
||||||
* `hub_strategy="all_checkpoints"` يدفع جميع نقاط الحفظ إلى الدليل المحدد في `output_dir` (سترى نقطة حفظ واحدة لكل مجلد في مستودع النموذج الخاص بك)
|
|
||||||
|
|
||||||
عند استئناف التدريب من نقطة حفظ، تُحاول [`Trainer`] الحفاظ على حالات RNG Python وNumPy وPyTorch كما كانت عندما تم حفظ نقطة الحفظ. ولكن لأن PyTorch لديها العديد من الإعدادات الافتراضية غير الحتمية مُتنوعة، فإن حالات RNG ليست مضمونة لتكون هي نفسها. إذا كنت تريد تمكين الحتمية الكاملة، فراجع دليل [التحكم في مصادر العشوائية](https://pytorch.org/docs/stable/notes/randomness#controlling-sources-of-randomness) لمعرفة ما يُمكنك تمكينه لجعل تدريبك حتميًا تمامًا. ضع في اعتبارك أنه من خلال جعل إعدادات معينة حتمية، فقد يكون التدريب أبطأ.
|
|
||||||
|
|
||||||
## تخصيص المدرب
|
|
||||||
|
|
||||||
في حين أن فئة [`Trainer`] مُصممة لتكون سهلة الوصول وسهلة الاستخدام، فإنها توفر أيضًا الكثير من قابلية التخصيص للمستخدمين المغامرين. يُمكن إنشاء فئات فرعية من العديد من أساليب [`Trainer`] وتجاوزها لدعم الوظائف التي تُريدها، دون الحاجة إلى إعادة كتابة حلقة التدريب بأكملها من البداية لاستيعابها. تتضمن هذه الأساليب:
|
|
||||||
|
|
||||||
* [`~Trainer.get_train_dataloader`] ينشئ DataLoader للتدريب
|
|
||||||
* [`~Trainer.get_eval_dataloader`] ينشئ DataLoader للتقييم
|
|
||||||
* [`~Trainer.get_test_dataloader`] ينشئ DataLoader للاختبار
|
|
||||||
* [`~Trainer.log`] يسجل معلومات حول مختلف الكائنات التي تراقب التدريب
|
|
||||||
* [`~Trainer.create_optimizer_and_scheduler`] ينشئ محسنًا ومخططًا لمُعدل التعلم إذا لم يتم تمريرهما في `__init__`؛ يمكن أيضًا تخصيص هذه الوظائف بشكل منفصل باستخدام [`~Trainer.create_optimizer`] و [`~Trainer.create_scheduler`] على التوالي
|
|
||||||
* [`~Trainer.compute_loss`] يحسب دالة الخسارة على دفعة من مُدخلات التدريب
|
|
||||||
* [`~Trainer.training_step`] يُنفذ خطوة التدريب
|
|
||||||
* [`~Trainer.prediction_step`] يُنفذ خطوة التنبؤ والاختبار
|
|
||||||
* [`~Trainer.evaluate`] يُقيّم النموذج ويعيد مقاييس التقييم
|
|
||||||
* [`~Trainer.predict`] يُجري التنبؤات (مع المقاييس إذا كانت العلامات متاحة) على مجموعة الاختبار
|
|
||||||
|
|
||||||
على سبيل المثال، إذا كنت تريد تخصيص طريقة [`~Trainer.compute_loss`] لاستخدام دالة خسارة ذات ترجيح بدلاً من ذلك.
|
|
||||||
|
|
||||||
|
|
||||||
```py
|
|
||||||
from torch import nn
|
|
||||||
from transformers import Trainer
|
|
||||||
|
|
||||||
class CustomTrainer(Trainer):
|
|
||||||
def compute_loss(self, model, inputs, return_outputs=False):
|
|
||||||
labels = inputs.pop("labels")
|
|
||||||
# forward pass
|
|
||||||
outputs = model(**inputs)
|
|
||||||
logits = outputs.get("logits")
|
|
||||||
# compute custom loss for 3 labels with different weights
|
|
||||||
loss_fct = nn.CrossEntropyLoss(weight=torch.tensor([1.0, 2.0, 3.0], device=model.device))
|
|
||||||
loss = loss_fct(logits.view(-1, self.model.config.num_labels), labels.view(-1))
|
|
||||||
return (loss, outputs) if return_outputs else loss
|
|
||||||
```
|
|
||||||
|
|
||||||
### دوال الاستدعاء Callbacks
|
|
||||||
|
|
||||||
خيار آخر لتخصيص [`Trainer`] هو استخدام [دوال الاستدعاء](callbacks). لا *تغير* دوال الاستدعاء أي شيء في حلقة التدريب. إنهم تفحص حالة حلقة التدريب ثم تُنفذ بعض الإجراءات (مثل الإيقاف المبكر أو تسجيل النتائج، إلخ) اعتمادًا على الحالة. وبعبارة أخرى، لا يمكن استخدام دالة الاستدعاء لتنفيذ شيء مثل دالة خسارة مخصصة، ويجب عليك تجاوز دالة [`~Trainer.compute_loss`] لذلك.
|
|
||||||
|
|
||||||
على سبيل المثال، إذا كنت تريد إضافة دالة استدعاء إيقاف مبكر إلى حلقة التدريب بعد 10 خطوات.
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import TrainerCallback
|
|
||||||
|
|
||||||
class EarlyStoppingCallback(TrainerCallback):
|
|
||||||
def __init__(self, num_steps=10):
|
|
||||||
self.num_steps = num_steps
|
|
||||||
|
|
||||||
def on_step_end(self, args, state, control, **kwargs):
|
|
||||||
if state.global_step >= self.num_steps:
|
|
||||||
return {"should_training_stop": True}
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم مرره إلى معامل `callback` في [`Trainer`].
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import Trainer
|
|
||||||
|
|
||||||
trainer = Trainer(
|
|
||||||
model=model,
|
|
||||||
args=training_args,
|
|
||||||
train_dataset=dataset["train"]،
|
|
||||||
eval_dataset=dataset["test"]،
|
|
||||||
tokenizer=tokenizer,
|
|
||||||
data_collator=data_collator,
|
|
||||||
compute_metrics=compute_metrics,
|
|
||||||
callback=[EarlyStoppingCallback()],
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## تسجيل الأحداث (Logging)
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
راجع مرجع [API](./main_classes/logging) للتسجيل للحصول على مزيد من المعلومات حول مستويات التسجيل المختلفة للأحداث.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
يتم تعيين [`Trainer`] إلى `logging.INFO` افتراضيًا والذي يُبلغ عن الأخطاء والتحذيرات ومعلومات أساسية أخرى. يتم تعيين نسخة [`Trainer`] - في البيئات الموزعة - إلى `logging.WARNING` والتي يُبلغ فقط عن الأخطاء والتحذيرات. يمكنك تغيير مستوى تسجيل الأحداث باستخدام معاملي [`log_level`](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments.log_level) و [`log_level_replica`](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments.log_level_replica) في [`TrainingArguments`].
|
|
||||||
|
|
||||||
لتهيئة إعداد مُستوى تسجيل اﻷحداث لكل عقدة، استخدم معامل [`log_on_each_node`](https://huggingface.co/docs/transformers/main/en/main_classes/trainer#transformers.TrainingArguments.log_on_each_node) لتحديد ما إذا كان سيتم استخدام مُستوى السجل على كل عقدة أو فقط على العقدة الرئيسية.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
يحدد [`Trainer`] مُستوى التسجيل بشكل مُنفصل لكل عقدة في طريقة [`Trainer.__init__`]، لذا فقد ترغب في التفكير في تعيين هذا الإعداد في وقت سابق إذا كنت تستخدم وظائف Transformers الأخرى قبل إنشاء كائن [`Trainer`].
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
على سبيل المثال، لتعيين التعليمات البرمجية والوحدات النمطية الرئيسية الخاصة بك لاستخدام نفس مُستوى التسجيل وفقًا لكل عقدة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
trainer = Trainer(...)
|
|
||||||
```
|
|
||||||
|
|
||||||
استخدم تركيبات مختلفة من `log_level` و `log_level_replica` لتهيئة ما يتم تسجيله على كل من العقد.
|
|
||||||
|
|
||||||
|
|
||||||
<hfoptions id="logging">
|
|
||||||
<hfoption id="single node">
|
|
||||||
|
|
||||||
```bash
|
|
||||||
my_app.py ... --log_level warning --log_level_replica error
|
|
||||||
```
|
|
||||||
|
|
||||||
</hfoption>
|
|
||||||
<hfoption id="multi-node">
|
|
||||||
|
|
||||||
أضف معلمة `log_on_each_node 0` لبيئات متعددة العقد.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
my_app.py ... --log_level warning --log_level_replica error --log_on_each_node 0
|
|
||||||
|
|
||||||
# set to only report errors
|
|
||||||
my_app.py ... --log_level error --log_level_replica error --log_on_each_node 0
|
|
||||||
```
|
|
||||||
|
|
||||||
</hfoption>
|
|
||||||
</hfoptions>
|
|
||||||
|
|
||||||
## NEFTune
|
|
||||||
|
|
||||||
[NEFTune](https://hf.co/papers/2310.05914) هي تقنية يمكن أن تحسن الأداء عن طريق إضافة ضوضاء إلى مُتجهات التعلم أثناء التدريب. لتمكينه في [`Trainer`], قم بتعيين معامل `neftune_noise_alpha` في [`TrainingArguments`] للتحكم في مقدار الضوضاء المُضافة.
|
|
||||||
|
|
||||||
```py
|
|
||||||
from transformers import TrainingArguments, Trainer
|
|
||||||
|
|
||||||
training_args = TrainingArguments(..., neftune_noise_alpha=0.1)
|
|
||||||
trainer = Trainer(..., args=training_args)
|
|
||||||
```
|
|
||||||
|
|
||||||
يتم تعطيل NEFTune بعد التدريب لاستعادة طبقة التعلم الأصلية لتجنب أي سلوك غير متوقع.
|
|
||||||
|
|
||||||
## نواة Liger
|
|
||||||
[Liger-Kernel](https://github.com/linkedin/Liger-Kernel) Kernel هي مجموعة من نوى Triton التي طورتها Linkedin مُصممة خصيصًا لتدريب نماذج اللغة الكبيرة (LLM). لقد قمنا بتنفيذ RMSNorm و RoPE و SwiGLU و CrossEntropy و FusedLinearCrossEntropy مُتوافقة مع Hugging Face، والمزيد قادم. يُمكنها زيادة إنتاجية التدريب متعدد وحدات معالجة الرسومات (GPU) بنسبة 20٪ وتقليل استخدام الذاكرة بنسبة 60٪. تعمل النواة بشكل تلقائي مع flash attention و PyTorch FSDP و Microsoft DeepSpeed.
|
|
||||||
|
|
||||||
احصل على زيادة في الإنتاجية بنسبة 20٪ وتقليل استخدام الذاكرة بنسبة 60٪ على تدريب نماذج LLaMA 3-8B. حقق أطوال سياق أكبر وأحجام دفعات أكبر. كما أنها مُفيدة إذا كنت تُريد زيادة حجم نموذجك إلى تدريب بنماذج متعددة الرؤوس أو أحجام مُفردات ضخمة. أطلق العنان للتدريب بنماذج متعددة الرؤوس (medusa) والمزيد. راجع التفاصيل والأمثلة في [Liger](https://github.com/linkedin/Liger-Kernel/tree/main/examples)
|
|
||||||
تأكد أولاً من تثبيت مستودع Liger الرسمي:
|
|
||||||
```bash
|
|
||||||
pip install liger-kernel
|
|
||||||
```
|
|
||||||
يجب عليك تمرير `use_liger_kernel=True` لتطبيق نواة `liger` على نموذجك، على سبيل المثال:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import TrainingArguments
|
|
||||||
|
|
||||||
training_args = TrainingArguments(
|
|
||||||
output_dir="your-model",
|
|
||||||
learning_rate=2e-5,
|
|
||||||
per_device_train_batch_size=16,
|
|
||||||
per_device_eval_batch_size=16,
|
|
||||||
num_train_epochs=2,
|
|
||||||
weight_decay=0.01,
|
|
||||||
eval_strategy="epoch",
|
|
||||||
save_strategy="epoch",
|
|
||||||
load_best_model_at_end=True,
|
|
||||||
push_to_hub=True,
|
|
||||||
use_liger_kernel=True
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
تدعم النواة معماريات نماذج Llama و Gemma و Mistral و Mixtral. يُمكن العثور على أحدث قائمة بالنمائج المدعومة [هنا](https://github.com/linkedin/Liger-Kernel). عندما يتم تعيين `use_liger_kernel` إلى `True`، سيتم تصحيح الطبقات المُقابلة في النموذج الأصلي باستخدام تطبيق Liger الفعال، لذلك لا تحتاج إلى فعل أي شيء إضافي بخلاف تعيين قيمة المعامل.
|
|
||||||
|
|
||||||
## المُحسِّنات
|
|
||||||
يمكنك اختيار مُحسِّن مدمج للتدريب باستخدام:
|
|
||||||
```python
|
|
||||||
from transformers import TrainingArguments
|
|
||||||
training_args = TrainingArguments(..., optim="adamw_torch")
|
|
||||||
```
|
|
||||||
اطلع على [`OptimizerNames`](https://github.com/huggingface/transformers/blob/main/src/transformers/training_args.py) للاطلاع على القائمة الكاملة للخيارات. نُدرج أمثلة مُتقدمة في الأقسام أدناه.
|
|
||||||
|
|
||||||
يمكنك أيضًا استخدام مُحسِّن PyTorch عشوائي عبر:
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
|
|
||||||
optimizer_cls = torch.optim.AdamW
|
|
||||||
optimizer_kwargs = {
|
|
||||||
"lr": 4e-3,
|
|
||||||
"betas": (0.9, 0.999),
|
|
||||||
"weight_decay": 0.05,
|
|
||||||
}
|
|
||||||
|
|
||||||
from transformers import Trainer
|
|
||||||
trainer = Trainer(..., optimizer_cls_and_kwargs=(optimizer_cls, optimizer_kwargs))
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### GaLore
|
|
||||||
|
|
||||||
إسقاط التدرج ذو الرتبة المنخفضة (GaLore) هو إستراتيجية تدريب ذات رتبة منخفضة فعّالة من حيث الذاكرة، تسمح بتعلم المعلمات الكاملة ولكنها أكثر كفاءة من حيث الذاكرة من أساليب التكيّف الشائعة ذات الرتبة المنخفضة، مثل LoRA.
|
|
||||||
|
|
||||||
أولاً، تأكد من تثبيت المستودع الرسمي لـ GaLore:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install galore-torch
|
|
||||||
```
|
|
||||||
|
|
||||||
ثم أضف ببساطة أحد `["galore_adamw"، "galore_adafactor"، "galore_adamw_8bit"]` في `optim` جنبًا إلى جنب مع `optim_target_modules`، والتي يمكن أن تكون قائمة من السلاسل أو التعبيرات النمطية regex أو المسار الكامل المطابق لأسماء الوحدات المستهدفة التي تريد تكييفها. فيما يلي مثال على النص البرمجي كامل(تأكد من `pip install trl datasets`):
|
|
||||||
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
import datasets
|
|
||||||
import trl
|
|
||||||
|
|
||||||
from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM
|
|
||||||
|
|
||||||
train_dataset = datasets.load_dataset('imdb', split='train')
|
|
||||||
|
|
||||||
args = TrainingArguments(
|
|
||||||
output_dir="./test-galore"،
|
|
||||||
max_steps=100,
|
|
||||||
per_device_train_batch_size=2,
|
|
||||||
optim="galore_adamw"،
|
|
||||||
optim_target_modules=[r".*.attn.*"، r".*.mlp.*"]
|
|
||||||
)
|
|
||||||
|
|
||||||
model_id = "google/gemma-2b"
|
|
||||||
|
|
||||||
config = AutoConfig.from_pretrained(model_id)
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
|
||||||
model = AutoModelForCausalLM.from_config(config).to(0)
|
|
||||||
|
|
||||||
trainer = trl.SFTTrainer(
|
|
||||||
model=model,
|
|
||||||
args=args,
|
|
||||||
train_dataset=train_dataset,
|
|
||||||
dataset_text_field='text',
|
|
||||||
max_seq_length=512,
|
|
||||||
)
|
|
||||||
|
|
||||||
trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
لتمرير معامﻻت إضافية يدعمها GaLore، يجب عليك تمرير `optim_args` بشكل صحيح، على سبيل المثال:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
import datasets
|
|
||||||
import trl
|
|
||||||
|
|
||||||
from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM
|
|
||||||
|
|
||||||
train_dataset = datasets.load_dataset('imdb', split='train')
|
|
||||||
|
|
||||||
args = TrainingArguments(
|
|
||||||
output_dir="./test-galore",
|
|
||||||
max_steps=100,
|
|
||||||
per_device_train_batch_size=2,
|
|
||||||
optim="galore_adamw",
|
|
||||||
optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
|
|
||||||
optim_args="rank=64, update_proj_gap=100, scale=0.10",
|
|
||||||
)
|
|
||||||
|
|
||||||
model_id = "google/gemma-2b"
|
|
||||||
|
|
||||||
config = AutoConfig.from_pretrained(model_id)
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
|
||||||
model = AutoModelForCausalLM.from_config(config).to(0)
|
|
||||||
|
|
||||||
trainer = trl.SFTTrainer(
|
|
||||||
model=model,
|
|
||||||
args=args,
|
|
||||||
train_dataset=train_dataset,
|
|
||||||
dataset_text_field='text',
|
|
||||||
max_seq_length=512,
|
|
||||||
)
|
|
||||||
|
|
||||||
trainer.train()
|
|
||||||
```
|
|
||||||
يمكنك قراءة المزيد حول الطريقة في [المستودع الأصلي](https://github.com/jiaweizzhao/GaLore) أو [الورقة البحثية](https://arxiv.org/abs/2403.03507).
|
|
||||||
|
|
||||||
حاليًا، يمكنك فقط تدريب الطبقات الخطية التي تعتبر طبقات GaLore وستستخدم التحلل ذو الرتبة المنخفضة للتدريب بينما سيتم تحسين الطبقات المتبقية بالطريقة التقليدية.
|
|
||||||
|
|
||||||
لاحظ أنه سيستغرق الأمر بعض الوقت قبل بدء التدريب (~3 دقائق لنموذج 2B على NVIDIA A100)، ولكن يجب أن يسير التدريب بسلاسة بعد ذلك.
|
|
||||||
|
|
||||||
يمكنك أيضًا إجراء تحسين طبقة تلو الأخرى عن طريق إضافة `layerwise` إلى اسم المُحسِّن كما هو موضح أدناه:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
import datasets
|
|
||||||
import trl
|
|
||||||
|
|
||||||
from transformers import TrainingArguments، AutoConfig، AutoTokenizer، AutoModelForCausalLM
|
|
||||||
|
|
||||||
train_dataset = datasets.load_dataset('imdb'، split='train')
|
|
||||||
|
|
||||||
args = TrainingArguments(
|
|
||||||
output_dir="./test-galore"،
|
|
||||||
max_steps=100،
|
|
||||||
per_device_train_batch_size=2،
|
|
||||||
optim="galore_adamw_layerwise"،
|
|
||||||
optim_target_modules=[r".*.attn.*"، r".*.mlp.*"]
|
|
||||||
)
|
|
||||||
|
|
||||||
model_id = "google/gemma-2b"
|
|
||||||
|
|
||||||
config = AutoConfig.from_pretrained(model_id)
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
|
||||||
model = AutoModelForCausalLM.from_config(config).to(0)
|
|
||||||
|
|
||||||
trainer = trl.SFTTrainer(
|
|
||||||
model=model،
|
|
||||||
args=args،
|
|
||||||
train_dataset=train_dataset،
|
|
||||||
dataset_text_field='text'،
|
|
||||||
max_seq_length=512،
|
|
||||||
)
|
|
||||||
|
|
||||||
trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
لاحظ أن تحسين الطبقة تجريبي إلى حد ما ولا يدعم DDP (Distributed Data Parallel)، وبالتالي يمكنك تشغيل التعليمات البرمجية للتدريب على وحدة معالجة الرسومات (GPU) واحدة فقط. يرجى الاطلاع على [هذا القسم المناسب](https://github.com/jiaweizzhao/GaLore?tab=readme-ov-file#train-7b-model-with-a-single-gpu-with-24gb-memory) لمزيد من التفاصيل. قد لا تدعم الميزات الأخرى مثل تقليم التدرجات أو DeepSpeed، إلخ. من الصندوق. يرجى [تقديم تقرير عن المشكلة على GitHub](https://github.com/huggingface/transformers/issues) إذا واجهتك مثل هذه المشكلة.
|
|
||||||
|
|
||||||
### محسنات LOMO
|
|
||||||
|
|
||||||
تم تقديم مُحسِّنات LOMO في [التدريب على المعلمات الكاملة لنماذج اللغة الكبيرة باستخدام موارد محدودة](https://hf.co/papers/2306.09782) و [AdaLomo: تحسين ذاكرة منخفضة بمعدل تعلم متكيف](https://hf.co/papers/2310.10195).
|
|
||||||
يتكون كلاهما من طريقة فعالة لضبط المعلمات الكاملة. تدمج محسنات LOMO حساب الاشتقاق وتحديث المعلمات في خطوة واحدة لتقليل استخدام الذاكرة. محسنات LOMO المدعومة هي `"lomo"` و `"adalomo"`. أولاً قم بتثبيت LOMO من pypi `pip install lomo-optim` أو قم بتثبيته من المصدر باستخدام `pip install git+https://github.com/OpenLMLab/LOMO.git`.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
وفقًا للمؤلفين، يوصى باستخدام `AdaLomo` بدون `grad_norm` للحصول على أداء أفضل وسرعة أعلى.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
فيما يلي نص برمجي بسيط يوضح كيفية ضبط نموذج [google/gemma-2b](https://huggingface.co/google/gemma-2b) على مجموعة بيانات IMDB في الدقة الكاملة:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
import datasets
|
|
||||||
from transformers import TrainingArguments، AutoTokenizer، AutoModelForCausalLM
|
|
||||||
import trl
|
|
||||||
|
|
||||||
train_dataset = datasets.load_dataset('imdb'، split='train')
|
|
||||||
|
|
||||||
args = TrainingArguments(
|
|
||||||
output_dir="./test-lomo"،
|
|
||||||
max_steps=100،
|
|
||||||
per_device_train_batch_size=4،
|
|
||||||
optim="adalomo"،
|
|
||||||
gradient_checkpointing=True،
|
|
||||||
logging_strategy="steps"،
|
|
||||||
logging_steps=1،
|
|
||||||
learning_rate=2e-6،
|
|
||||||
save_strategy="no"،
|
|
||||||
run_name="lomo-imdb"،
|
|
||||||
)
|
|
||||||
|
|
||||||
model_id = "google/gemma-2b"
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(model_id، low_cpu_mem_usage=True).to(0)
|
|
||||||
|
|
||||||
trainer = trl.SFTTrainer(
|
|
||||||
model=model،
|
|
||||||
args=args،
|
|
||||||
train_dataset=train_dataset،
|
|
||||||
dataset_text_field='text'،
|
|
||||||
max_seq_length=1024،
|
|
||||||
)
|
|
||||||
|
|
||||||
trainer.train()
|
|
||||||
```
|
|
||||||
|
|
||||||
### مُحسِّن GrokAdamW
|
|
||||||
تم تصميم مُحسِّن GrokAdamW لتعزيز أداء التدريب واستقراره، خاصةً للنماذج التي تستفيد من دوال إشارة `grokking`. لاستخدام `GrokAdamW`، قم أولاً بتثبيت حزمة المُحسِّن باستخدام `pip install grokadamw`.
|
|
||||||
<Tip>
|
|
||||||
يُعد GrokAdamW مفيدًا بشكل خاص للنماذج التي تتطلب تقنيات تحسين مُتقدمة لتحقيق أداء واستقرار أفضل.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
فيما يلي نص برمجى بسيط لشرح كيفية ضبط [google/gemma-2b](https://huggingface.co/google/gemma-2b) بدقة على مجموعة بيانات IMDB باستخدام مُحسِّن GrokAdamW:
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
import datasets
|
|
||||||
from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM, Trainer
|
|
||||||
|
|
||||||
# تحميل مجموعة البيانات IMDB
|
|
||||||
train_dataset = datasets.load_dataset('imdb', split='train')
|
|
||||||
|
|
||||||
# تعريف معامﻻت التدريب
|
|
||||||
args = TrainingArguments(
|
|
||||||
output_dir="./test-grokadamw",
|
|
||||||
max_steps=1000,
|
|
||||||
per_device_train_batch_size=4,
|
|
||||||
optim="grokadamw",
|
|
||||||
logging_strategy="steps",
|
|
||||||
logging_steps=1,
|
|
||||||
learning_rate=2e-5,
|
|
||||||
save_strategy="no",
|
|
||||||
run_name="grokadamw-imdb",
|
|
||||||
)
|
|
||||||
|
|
||||||
# تحميل النموذج والمجزىء اللغوي
|
|
||||||
model_id = "google/gemma-2b"
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage=True).to(0)
|
|
||||||
|
|
||||||
# تهيئة المدرب
|
|
||||||
trainer = Trainer(
|
|
||||||
model=model,
|
|
||||||
args=args,
|
|
||||||
train_dataset=train_dataset,
|
|
||||||
)
|
|
||||||
|
|
||||||
# تدريب النموذج
|
|
||||||
trainer.train()
|
|
||||||
```
|
|
||||||
يوضح هذا النص البرمجى كيفية ضبط نموذج google/gemma-2b بدقة على مجموعة بيانات IMDB باستخدام مُحسِّن GrokAdamW. يتم تكوين TrainingArguments لاستخدام GrokAdamW، ويتم تمرير مجموعة البيانات إلى Trainer للتدريب.
|
|
||||||
|
|
||||||
### مُحسِّن بدون جدوله (Schedule Free Optimizer)
|
|
||||||
تم تقديم مُحسِّنات بدون جدوله في [The Road Less Scheduled](https://hf.co/papers/2405.15682).
|
|
||||||
يستبدل التعلم بدون جدوله زخم المُحسِّن الأساسي بمزيج من المتوسط والتداخل، لإزالة الحاجة تمامًا إلى تخفيف مُعدل التعلم باستخدام جدوله تقليديه.
|
|
||||||
المُحسِّنات المدعومة لـ SFO هي "schedule_free_adamw" و "schedule_free_sgd". قم أولاً بتثبيت `schedulefree` من pypi باستخدام الأمر `pip install schedulefree`.
|
|
||||||
|
|
||||||
فيما يلي نص برمجى بسيط لشرح كيفية ضبط [google/gemma-2b](https://huggingface.co/google/gemma-2b) بدقة على مجموعة بيانات IMDB بدقة كاملة:
|
|
||||||
```python
|
|
||||||
import torch
|
|
||||||
import datasets
|
|
||||||
from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM
|
|
||||||
import trl
|
|
||||||
|
|
||||||
train_dataset = datasets.load_dataset('imdb', split='train')
|
|
||||||
|
|
||||||
args = TrainingArguments(
|
|
||||||
output_dir="./test-schedulefree",
|
|
||||||
max_steps=1000,
|
|
||||||
per_device_train_batch_size=4,
|
|
||||||
optim="schedule_free_adamw",
|
|
||||||
gradient_checkpointing=True,
|
|
||||||
logging_strategy="steps",
|
|
||||||
logging_steps=1,
|
|
||||||
learning_rate=2e-6,
|
|
||||||
save_strategy="no",
|
|
||||||
run_name="sfo-imdb",
|
|
||||||
)
|
|
||||||
|
|
||||||
model_id = "google/gemma-2b"
|
|
||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
|
||||||
model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage=True).to(0)
|
|
||||||
|
|
||||||
trainer = trl.SFTTrainer(
|
|
||||||
model=model,
|
|
||||||
args=args,
|
|
||||||
train_dataset=train_dataset,
|
|
||||||
dataset_text_field='text',
|
|
||||||
max_seq_length=1024,
|
|
||||||
)
|
|
||||||
|
|
||||||
trainer.train()
|
|
||||||
```
|
|
||||||
## تسريع ومدرب
|
|
||||||
|
|
||||||
يتم تشغيل فئة [`Trainer`] بواسطة [تسريع](https://hf.co/docs/accelerate)، وهي مكتبة لتدريب نماذج PyTorch بسهولة في بيئات موزعة مع دعم عمليات التكامل مثل [FullyShardedDataParallel (FSDP)](https://pytorch.org/blog/introducing-pytorch-fully-sharded-data-parallel-api/) و [DeepSpeed](https://www.deepspeed.ai/).
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
تعرف على المزيد حول استراتيجيات تجزئة FSDP، وتفريغ وحدة المعالجة المركزية (CPU)، والمزيد مع [`Trainer`] في [دليل Fully Sharded Data Parallel](fsdp).
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
لاستخدام Accelerate مع [`Trainer`]]، قم بتشغيل الأمر [`accelerate.config`](https://huggingface.co/docs/accelerate/package_reference/cli#accelerate-config) لإعداد التدريب لبيئة التدريب الخاصة بك. نشئ هذا الأمر ملف `config_file.yaml` الذي سيتم استخدامه عند تشغيل نص للتدريب البرمجى. على سبيل المثال، بعض تكوينات المثال التي يمكنك إعدادها هي:
|
|
||||||
|
|
||||||
<hfoptions id="config">
|
|
||||||
<hfoption id="DistributedDataParallel">
|
|
||||||
|
|
||||||
```yml
|
|
||||||
compute_environment: LOCAL_MACHINE
|
|
||||||
distributed_type: MULTI_GPU
|
|
||||||
downcast_bf16: 'no'
|
|
||||||
gpu_ids: all
|
|
||||||
machine_rank: 0 #change rank as per the node
|
|
||||||
main_process_ip: 192.168.20.1
|
|
||||||
main_process_port: 9898
|
|
||||||
main_training_function: main
|
|
||||||
mixed_precision: fp16
|
|
||||||
num_machines: 2
|
|
||||||
num_processes: 8
|
|
||||||
rdzv_backend: static
|
|
||||||
same_network: true
|
|
||||||
tpu_env: []
|
|
||||||
tpu_use_cluster: false
|
|
||||||
tpu_use_sudo: false
|
|
||||||
use_cpu: false
|
|
||||||
```
|
|
||||||
|
|
||||||
</hfoption>
|
|
||||||
<hfoption id="FSDP">
|
|
||||||
|
|
||||||
```yml
|
|
||||||
compute_environment: LOCAL_MACHINE
|
|
||||||
distributed_type: FSDP
|
|
||||||
downcast_bf16: 'no'
|
|
||||||
fsdp_config:
|
|
||||||
fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
|
|
||||||
fsdp_backward_prefetch_policy: BACKWARD_PRE
|
|
||||||
fsdp_forward_prefetch: true
|
|
||||||
fsdp_offload_params: false
|
|
||||||
fsdp_sharding_strategy: 1
|
|
||||||
fsdp_state_dict_type: FULL_STATE_DICT
|
|
||||||
fsdp_sync_module_states: true
|
|
||||||
fsdp_transformer_layer_cls_to_wrap: BertLayer
|
|
||||||
fsdp_use_orig_params: true
|
|
||||||
machine_rank: 0
|
|
||||||
main_training_function: main
|
|
||||||
mixed_precision: bf16
|
|
||||||
num_machines: 1
|
|
||||||
num_processes: 2
|
|
||||||
rdzv_backend: static
|
|
||||||
same_network: true
|
|
||||||
tpu_env: []
|
|
||||||
tpu_use_cluster: false
|
|
||||||
tpu_use_sudo: false
|
|
||||||
use_cpu: false
|
|
||||||
```
|
|
||||||
|
|
||||||
</hfoption>
|
|
||||||
<hfoption id="DeepSpeed">
|
|
||||||
|
|
||||||
```yml
|
|
||||||
compute_environment: LOCAL_MACHINE
|
|
||||||
deepspeed_config:
|
|
||||||
deepspeed_config_file: /home/user/configs/ds_zero3_config.json
|
|
||||||
zero3_init_flag: true
|
|
||||||
distributed_type: DEEPSPEED
|
|
||||||
downcast_bf16: 'no'
|
|
||||||
machine_rank: 0
|
|
||||||
main_training_function: main
|
|
||||||
num_machines: 1
|
|
||||||
num_processes: 4
|
|
||||||
rdzv_backend: static
|
|
||||||
same_network: true
|
|
||||||
tpu_env: []
|
|
||||||
tpu_use_cluster: false
|
|
||||||
tpu_use_sudo: false
|
|
||||||
use_cpu: false
|
|
||||||
```
|
|
||||||
|
|
||||||
</hfoption>
|
|
||||||
<hfoption id="DeepSpeed with Accelerate plugin">
|
|
||||||
|
|
||||||
```yml
|
|
||||||
compute_environment: LOCAL_MACHINE
|
|
||||||
deepspeed_config:
|
|
||||||
gradient_accumulation_steps: 1
|
|
||||||
gradient_clipping: 0.7
|
|
||||||
offload_optimizer_device: cpu
|
|
||||||
offload_param_device: cpu
|
|
||||||
zero3_init_flag: true
|
|
||||||
zero_stage: 2
|
|
||||||
distributed_type: DEEPSPEED
|
|
||||||
downcast_bf16: 'no'
|
|
||||||
machine_rank: 0
|
|
||||||
main_training_function: main
|
|
||||||
mixed_precision: bf16
|
|
||||||
num_machines: 1
|
|
||||||
num_processes: 4
|
|
||||||
rdzv_backend: static
|
|
||||||
same_network: true
|
|
||||||
tpu_env: []
|
|
||||||
tpu_use_cluster: false
|
|
||||||
tpu_use_sudo: false
|
|
||||||
use_cpu: false
|
|
||||||
```
|
|
||||||
|
|
||||||
</hfoption>
|
|
||||||
</hfoptions>
|
|
||||||
يُعد أمر [`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/ \
|
|
||||||
--overwrite_output_dir
|
|
||||||
```
|
|
||||||
|
|
||||||
يمكنك أيضًا تحديد المعلمات من ملف `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/ \
|
|
||||||
--overwrite_output_dir
|
|
||||||
```
|
|
||||||
|
|
||||||
اطلع على برنامج تعليمي [Launching your Accelerate scripts](https://huggingface.co/docs/accelerate/basic_tutorials/launch) لمعرفة المزيد حول `accelerate_launch` والتكوينات المخصصة.
|
|
||||||
@ -1,171 +0,0 @@
|
|||||||
# استكشاف الأخطاء وإصلاحها
|
|
||||||
|
|
||||||
تحدث الأخطاء أحيانًا، لكننا هنا للمساعدة! يغطي هذا الدليل بعض المشكلات الأكثر شيوعًا التي واجهناها وكيفية حلها. مع ذلك، لا يُقصد بهذا الدليل أن يكون مجموعة شاملة لكل مشكلات 🤗 Transformers. لمزيد من المساعدة في استكشاف مشكلتك وإصلاحها، جرب ما يلي:
|
|
||||||
<Youtube id="S2EEG3JIt2A"/>
|
|
||||||
|
|
||||||
|
|
||||||
1. اطلب المساعدة على [المنتديات](https://discuss.huggingface.co/). هناك فئات محددة يمكنك نشر سؤالك فيها، مثل [المبتدئين](https://discuss.huggingface.co/c/beginners/5) أو [🤗 Transformers](https://discuss.huggingface.co/c/transformers/9). تأكد من كتابة منشور جيد وواضح على المنتدى مع بعض التعليمات البرمجية القابلة للتكرار لزيادة احتمالية حل مشكلتك!
|
|
||||||
<Youtube id="_PAli-V4wj0"/>
|
|
||||||
|
|
||||||
2. قم بإنشاء [مشكلة](https://github.com/huggingface/transformers/issues/new/choose) في مستودع 🤗 Transformers إذا كانت هناك مشكلة متعلقة بالمكتبة. حاول تضمين أكبر قدر ممكن من المعلومات التي تصف المشكلة لمساعدتنا في معرفة ما هو الخطأ وكيفية إصلاحه.
|
|
||||||
|
|
||||||
3. تحقق من دليل [الترحيل](migration) إذا كنت تستخدم إصدارًا أقدم من مكتبة 🤗 Transformers حيث تم إدخال بعض التغييرات المهمة بين الإصدارات.
|
|
||||||
|
|
||||||
|
|
||||||
للحصول على مزيد من التفاصيل حول استكشاف الأخطاء وإصلاحها والحصول على المساعدة، راجع [الفصل 8](https://huggingface.co/course/chapter8/1?fw=pt) من دورة Hugging Face.
|
|
||||||
|
|
||||||
## بيئات جدار الحماية
|
|
||||||
|
|
||||||
بعض وحدات معالجة الرسومات (GPU) على السحابة وإعدادات الشبكة الداخلية محمية بجدار حماية من الاتصالات الخارجية، مما يؤدي إلى حدوث خطأ في الاتصال. عندما تحاول تعليمات البرنامج النصي تنزيل أوزان النموذج أو مجموعات البيانات، سيتوقف التنزيل ثم ينتهي بخطأ مثل:
|
|
||||||
|
|
||||||
```
|
|
||||||
ValueError: Connection error, and we cannot find the requested files in the cached path.
|
|
||||||
Please try again or make sure your Internet connection is on.
|
|
||||||
```
|
|
||||||
|
|
||||||
في هذه الحالة، يجب محاولة تشغيل 🤗 Transformers في [وضع عدم الاتصال](installation#offline-mode) لتجنب خطأ الاتصال.
|
|
||||||
|
|
||||||
## CUDA نفاد الذاكرة
|
|
||||||
|
|
||||||
يمكن أن يكون تدريب النماذج الكبيرة التي تحتوي على ملايين المعلمات أمرًا صعبًا بدون الأجهزة المناسبة. أحد الأخطاء الشائعة التي قد تواجهها عند نفاد ذاكرة GPU هو:
|
|
||||||
|
|
||||||
```
|
|
||||||
CUDA out of memory. Tried to allocate 256.00 MiB (GPU 0; 11.17 GiB total capacity; 9.70 GiB already allocated; 179.81 MiB free; 9.85 GiB reserved in total by PyTorch)
|
|
||||||
```
|
|
||||||
|
|
||||||
فيما يلي بعض الحلول المحتملة التي يمكنك تجربتها لتقليل استخدام الذاكرة:
|
|
||||||
|
|
||||||
- قلل من قيمة [`per_device_train_batch_size`](main_classes/trainer#transformers.TrainingArguments.per_device_train_batch_size) في [`TrainingArguments`].
|
|
||||||
|
|
||||||
- حاول استخدام [`gradient_accumulation_steps`](main_classes/trainer#transformers.TrainingArguments.gradient_accumulation_steps) في [`TrainingArguments`] لزيادة حجم الدُفعة بشكل فعال.
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
راجع دليل [الأداء](performance) لمزيد من التفاصيل حول تقنيات توفير الذاكرة.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## عدم القدرة على تحميل نموذج TensorFlow محفوظ
|
|
||||||
|
|
||||||
تقوم طريقة TensorFlow [model.save](https://www.tensorflow.org/tutorials/keras/save_and_load#save_the_entire_model) بحفظ النموذج بالكامل - الهندسة المعمارية، الأوزان، تكوين التدريب - في ملف واحد. ومع ذلك، عند تحميل ملف النموذج مرة أخرى، قد تواجه خطأ لأن مكتبة 🤗 Transformers قد لا تقوم بتحميل جميع الكائنات المتعلقة بـ TensorFlow في ملف النموذج. لتجنب المشكلات المتعلقة بحفظ وتحميل نماذج TensorFlow، نوصي بما يلي:
|
|
||||||
|
|
||||||
- احفظ أوزان النموذج كملف `h5` باستخدام [`model.save_weights`](https://www.tensorflow.org/tutorials/keras/save_and_load#save_the_entire_model) ثم أعد تحميل النموذج باستخدام [`~TFPreTrainedModel.from_pretrained`]:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import TFPreTrainedModel
|
|
||||||
>>> from tensorflow import keras
|
|
||||||
|
|
||||||
>>> model.save_weights("some_folder/tf_model.h5")
|
|
||||||
>>> model = TFPreTrainedModel.from_pretrained("some_folder")
|
|
||||||
```
|
|
||||||
|
|
||||||
- احفظ النموذج باستخدام [`~TFPretrainedModel.save_pretrained`] وقم بتحميله مرة أخرى باستخدام [`~TFPreTrainedModel.from_pretrained`]:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import TFPreTrainedModel
|
|
||||||
|
|
||||||
>>> model.save_pretrained("path_to/model")
|
|
||||||
>>> model = TFPreTrainedModel.from_pretrained("path_to/model")
|
|
||||||
```
|
|
||||||
|
|
||||||
## ImportError
|
|
||||||
|
|
||||||
خطأ شائع آخر قد تواجهه، خاصة إذا كان نموذجًا تم إصداره حديثًا، هو `ImportError`:
|
|
||||||
|
|
||||||
```
|
|
||||||
ImportError: cannot import name 'ImageGPTImageProcessor' from 'transformers' (unknown location)
|
|
||||||
```
|
|
||||||
|
|
||||||
بالنسبة لأنواع الأخطاء هذه، تحقق من أن لديك أحدث إصدار من مكتبة Hugging Face Transformers مثبتًا للوصول إلى أحدث النماذج:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install transformers --upgrade
|
|
||||||
```
|
|
||||||
|
|
||||||
## خطأ CUDA: تم تشغيل التأكيد على جانب الجهاز
|
|
||||||
|
|
||||||
في بعض الأحيان، قد تواجه خطأ CUDA عامًا حول خطأ في كود الجهاز.
|
|
||||||
|
|
||||||
```
|
|
||||||
RuntimeError: CUDA error: device-side assert triggered
|
|
||||||
```
|
|
||||||
|
|
||||||
يجب عليك محاولة تشغيل الكود على وحدة المعالجة المركزية (CPU) أولاً للحصول على رسالة خطأ أكثر دقة. أضف متغير البيئة التالي في بداية كودك للتبديل إلى وحدة المعالجة المركزية:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> import os
|
|
||||||
|
|
||||||
>>> os.environ["CUDA_VISIBLE_DEVICES"] = ""
|
|
||||||
```
|
|
||||||
|
|
||||||
الخيار الآخر هو الحصول على تتبع مكدس أفضل من GPU. أضف متغير البيئة التالي في بداية كودك للحصول على تتبع المكدس للإشارة إلى مصدر الخطأ:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> import os
|
|
||||||
|
|
||||||
>>> os.environ["CUDA_LAUNCH_BLOCKING"] = "1"
|
|
||||||
```
|
|
||||||
|
|
||||||
## إخراج غير صحيح عند عدم إخفاء رموز الحشو
|
|
||||||
|
|
||||||
في بعض الحالات، قد يكون `hidden_state` غير صحيحة إذا تضمنت `input_ids` رموز حشو. ولإثبات ذلك، قم بتحميل نموذج ومجزىء لغوى. يمكنك الوصول إلى `pad_token_id` للنموذج لمعرفة قيمته. قد تكون `pad_token_id` `None` لبعض النماذج، ولكن يمكنك دائمًا تعيينها يدويًا.
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import AutoModelForSequenceClassification
|
|
||||||
>>> import torch
|
|
||||||
|
|
||||||
>>> model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-uncased")
|
|
||||||
>>> model.config.pad_token_id
|
|
||||||
0
|
|
||||||
```
|
|
||||||
|
|
||||||
يوضح المثال التالي المُخرجات بدون إخفاء رموز الحشو:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> input_ids = torch.tensor([[7592, 2057, 2097, 2393, 9611, 2115], [7592, 0, 0, 0, 0, 0]])
|
|
||||||
>>> output = model(input_ids)
|
|
||||||
>>> print(output.logits)
|
|
||||||
tensor([[ 0.0082, -0.2307],
|
|
||||||
[ 0.1317, -0.1683]], grad_fn=<AddmmBackward0>)
|
|
||||||
```
|
|
||||||
|
|
||||||
هنا المُخرجات الفعلية للتسلسل الثاني:
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> input_ids = torch.tensor([[7592]])
|
|
||||||
>>> output = model(input_ids)
|
|
||||||
>>> print(output.logits)
|
|
||||||
tensor([[-0.1008, -0.4061]], grad_fn=<AddmmBackward0>)
|
|
||||||
```
|
|
||||||
|
|
||||||
يجب عليك في معظم الوقت توفير `attention_mask` للنموذج لتجاهل رموز الحشو لتجنب هذا الخطأ الصامت. الآن يتطابق مُخرجات التسلسل الثاني مع مُخرجاته الفعلية:
|
|
||||||
|
|
||||||
<Tip>
|
|
||||||
بشكل افتراضي، ينشئ مجزىء النصوص `attention_mask` لك استنادًا إلى إعدادات المجزىء المحدد.
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> attention_mask = torch.tensor([[1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0]])
|
|
||||||
>>> output = model(input_ids, attention_mask=attention_mask)
|
|
||||||
>>> print(output.logits)
|
|
||||||
tensor([[ 0.0082, -0.2307],
|
|
||||||
[-0.1008, -0.4061]], grad_fn=<AddmmBackward0>)
|
|
||||||
```
|
|
||||||
|
|
||||||
لا ينشئ 🤗 Transformers تلقائيًا `attention_mask` لإخفاء رمز الحشو إذا تم توفيره لأن:
|
|
||||||
|
|
||||||
- بعض النماذج ليس لها رمز حشو.
|
|
||||||
|
|
||||||
- بالنسبة لبعض الاستخدامات، يريد المستخدمون أن ينتبه النموذج إلى رمز الحشو.
|
|
||||||
## ValueError: فئة التكوين غير المعترف بها XYZ لهذا النوع من AutoModel
|
|
||||||
|
|
||||||
بشكل عام، نوصي باستخدام فئة [`AutoModel`] لتحميل النسخ المدربة مسبقًا من النماذج. يمكن لهذه الفئة أن تستنتج وتُحمل تلقائيًا البنية الصحيحة من نسخ معينة بناءً على التكوين. إذا رأيت هذا الخطأ `ValueError` عند تحميل نموذج من نسخة، فهذا يعني أن الفئة التلقائية (Auto) لم تتمكن من العثور على خريطة من التكوين في نقطة التفتيش المعطاة إلى نوع النموذج الذي تُحاول تحميله. وغالبًا ما يحدث هذا عندما لا تدعم نقطة التفتيش مهمة معينة.
|
|
||||||
|
|
||||||
على سبيل المثال، سترى هذا الخطأ في المثال التالي لأنه لا يوجد GPT2 للإجابة على الأسئلة:
|
|
||||||
|
|
||||||
```py
|
|
||||||
>>> from transformers import AutoProcessor, AutoModelForQuestionAnswering
|
|
||||||
|
|
||||||
>>> processor = AutoProcessor.from_pretrained("openai-community/gpt2-medium")
|
|
||||||
>>> model = AutoModelForQuestionAnswering.from_pretrained("openai-community/gpt2-medium")
|
|
||||||
ValueError: Unrecognized configuration class <class 'transformers.models.gpt2.configuration_gpt2.GPT2Config'> for this kind of AutoModel: AutoModelForQuestionAnswering.
|
|
||||||
Model type should be one of AlbertConfig, BartConfig, BertConfig, BigBirdConfig, BigBirdPegasusConfig, BloomConfig, ...
|
|
||||||
```
|
|
||||||
@ -112,7 +112,7 @@ Bevor Sie irgendwelchen Code schreiben, empfehlen wir Ihnen dringend, die besteh
|
|||||||
|
|
||||||
Sie benötigen grundlegende `git`-Kenntnisse, um zu 🤗 Transformers beizutragen. Obwohl `git` nicht das einfachste Werkzeug ist, hat es ein sehr gutes Handbuch. Geben Sie `git --help` in eine Shell ein und genießen Sie es! Wenn Sie Bücher bevorzugen, ist [Pro Git](https://git-scm.com/book/en/v2) eine gute Anlaufstelle.
|
Sie benötigen grundlegende `git`-Kenntnisse, um zu 🤗 Transformers beizutragen. Obwohl `git` nicht das einfachste Werkzeug ist, hat es ein sehr gutes Handbuch. Geben Sie `git --help` in eine Shell ein und genießen Sie es! Wenn Sie Bücher bevorzugen, ist [Pro Git](https://git-scm.com/book/en/v2) eine gute Anlaufstelle.
|
||||||
|
|
||||||
Sie benötigen **[Python 3.9](https://github.com/huggingface/transformers/blob/main/setup.py#L426)** oder höher, um zu 🤗 Transformers beizutragen. Folgen Sie den nachstehenden Schritten, um mit dem Beitrag zu beginnen:
|
Sie benötigen **[Python 3.8](https://github.com/huggingface/transformers/blob/main/setup.py#L426)** oder höher, um zu 🤗 Transformers beizutragen. Folgen Sie den nachstehenden Schritten, um mit dem Beitrag zu beginnen:
|
||||||
|
|
||||||
1. Forken Sie das [Repository](https://github.com/huggingface/transformers), indem Sie auf den **[Fork](https://github.com/huggingface/transformers/fork)**-Button auf der Seite des Repositorys klicken. Dadurch wird eine Kopie des Codes auf Ihrem GitHub-Account erstellt.
|
1. Forken Sie das [Repository](https://github.com/huggingface/transformers), indem Sie auf den **[Fork](https://github.com/huggingface/transformers/fork)**-Button auf der Seite des Repositorys klicken. Dadurch wird eine Kopie des Codes auf Ihrem GitHub-Account erstellt.
|
||||||
|
|
||||||
|
|||||||
@ -149,7 +149,7 @@ conda install conda-forge::transformers
|
|||||||
|
|
||||||
Vorgefertigte Modelle werden heruntergeladen und lokal zwischengespeichert unter: `~/.cache/huggingface/hub`. Dies ist das Standardverzeichnis, das durch die Shell-Umgebungsvariable "TRANSFORMERS_CACHE" vorgegeben ist. Unter Windows wird das Standardverzeichnis durch `C:\Benutzer\Benutzername\.cache\huggingface\hub` angegeben. Sie können die unten aufgeführten Shell-Umgebungsvariablen - in der Reihenfolge ihrer Priorität - ändern, um ein anderes Cache-Verzeichnis anzugeben:
|
Vorgefertigte Modelle werden heruntergeladen und lokal zwischengespeichert unter: `~/.cache/huggingface/hub`. Dies ist das Standardverzeichnis, das durch die Shell-Umgebungsvariable "TRANSFORMERS_CACHE" vorgegeben ist. Unter Windows wird das Standardverzeichnis durch `C:\Benutzer\Benutzername\.cache\huggingface\hub` angegeben. Sie können die unten aufgeführten Shell-Umgebungsvariablen - in der Reihenfolge ihrer Priorität - ändern, um ein anderes Cache-Verzeichnis anzugeben:
|
||||||
|
|
||||||
1. Shell-Umgebungsvariable (Standard): `HF_HUB_CACHE` oder `TRANSFORMERS_CACHE`.
|
1. Shell-Umgebungsvariable (Standard): `HUGGINGFACE_HUB_CACHE` oder `TRANSFORMERS_CACHE`.
|
||||||
2. Shell-Umgebungsvariable: `HF_HOME`.
|
2. Shell-Umgebungsvariable: `HF_HOME`.
|
||||||
3. Shell-Umgebungsvariable: `XDG_CACHE_HOME` + `/huggingface`.
|
3. Shell-Umgebungsvariable: `XDG_CACHE_HOME` + `/huggingface`.
|
||||||
|
|
||||||
|
|||||||
@ -43,7 +43,7 @@ Folglich können Sie eine bestimmte Modellversion mit dem Parameter "Revision" l
|
|||||||
|
|
||||||
```py
|
```py
|
||||||
>>> model = AutoModel.from_pretrained(
|
>>> model = AutoModel.from_pretrained(
|
||||||
... "julien-c/EsperBERTo-small", revision="4c77982" # tag name, or branch name, or commit hash
|
... "julien-c/EsperBERTo-small", revision="v2.0.1" # tag name, or branch name, or commit hash
|
||||||
... )
|
... )
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -109,7 +109,7 @@ label: NEGATIVE, with score: 0.5309
|
|||||||
Die [`pipeline`] kann auch über einen ganzen Datensatz iterieren. Starten wir mit der Installation der [🤗 Datasets](https://huggingface.co/docs/datasets/) Bibliothek:
|
Die [`pipeline`] kann auch über einen ganzen Datensatz iterieren. Starten wir mit der Installation der [🤗 Datasets](https://huggingface.co/docs/datasets/) Bibliothek:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install datasets
|
pip install datasets
|
||||||
```
|
```
|
||||||
|
|
||||||
Erstellen wir eine [`pipeline`] mit der Aufgabe die wir lösen und dem Modell welches wir nutzen möchten.
|
Erstellen wir eine [`pipeline`] mit der Aufgabe die wir lösen und dem Modell welches wir nutzen möchten.
|
||||||
@ -191,7 +191,7 @@ Wenn Sie kein Modell für Ihren Anwendungsfall finden können, müssen Sie ein v
|
|||||||
|
|
||||||
<Youtube id="AhChOFRegn4"/>
|
<Youtube id="AhChOFRegn4"/>
|
||||||
|
|
||||||
Unter der Haube arbeiten die Klassen [`AutoModelForSequenceClassification`] und [`AutoTokenizer`] zusammen, um die [`pipeline`] zu betreiben. Eine [`AutoClass`](./model_doc/auto) ist eine Abkürzung, die automatisch die Architektur eines trainierten Modells aus dessen Namen oder Pfad abruft. Sie müssen nur die passende `AutoClass` für Ihre Aufgabe und den zugehörigen Tokenizer mit [`AutoTokenizer`] auswählen.
|
Unter der Haube arbeiten die Klassen [`AutoModelForSequenceClassification`] und [`AutoTokenizer`] zusammen, um die [`pipeline`] zu betreiben. Eine [`AutoClass`](./model_doc/auto) ist eine Abkürzung, die automatisch die Architektur eines trainierten Modells aus dessen Namen oder Pfad abruft. Sie müssen nur die passende `AutoClass` für Ihre Aufgabe und den zugehörigen Tokenizer mit [`AutoTokenizer`] auswählen.
|
||||||
|
|
||||||
Kehren wir zu unserem Beispiel zurück und sehen wir uns an, wie Sie die `AutoClass` verwenden können, um die Ergebnisse der [`pipeline`] zu replizieren.
|
Kehren wir zu unserem Beispiel zurück und sehen wir uns an, wie Sie die `AutoClass` verwenden können, um die Ergebnisse der [`pipeline`] zu replizieren.
|
||||||
|
|
||||||
@ -281,7 +281,7 @@ Jetzt können Sie Ihren vorverarbeiteten Stapel von Eingaben direkt an das Model
|
|||||||
```
|
```
|
||||||
|
|
||||||
Das Modell gibt die endgültigen Aktivierungen in dem Attribut "logits" aus. Wenden Sie die Softmax-Funktion auf die "logits" an, um die Wahrscheinlichkeiten zu erhalten:
|
Das Modell gibt die endgültigen Aktivierungen in dem Attribut "logits" aus. Wenden Sie die Softmax-Funktion auf die "logits" an, um die Wahrscheinlichkeiten zu erhalten:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
>>> from torch import nn
|
>>> from torch import nn
|
||||||
|
|
||||||
@ -308,7 +308,7 @@ In der [Aufgabenzusammenfassung](./task_summary) steht, welche [AutoModel]-Klass
|
|||||||
</Tip>
|
</Tip>
|
||||||
|
|
||||||
Jetzt können Sie Ihren vorverarbeiteten Stapel von Eingaben direkt an das Modell übergeben, indem Sie die Wörterbuchschlüssel direkt an die Tensoren übergeben:
|
Jetzt können Sie Ihren vorverarbeiteten Stapel von Eingaben direkt an das Modell übergeben, indem Sie die Wörterbuchschlüssel direkt an die Tensoren übergeben:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
>>> tf_outputs = tf_model(tf_batch)
|
>>> tf_outputs = tf_model(tf_batch)
|
||||||
```
|
```
|
||||||
@ -383,8 +383,8 @@ Ein besonders cooles 🤗 Transformers-Feature ist die Möglichkeit, ein Modell
|
|||||||
```py
|
```py
|
||||||
>>> from transformers import AutoModel
|
>>> from transformers import AutoModel
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained(pt_save_directory)
|
>>> tokenizer = AutoTokenizer.from_pretrained(tf_save_directory)
|
||||||
>>> pt_model = AutoModelForSequenceClassification.from_pretrained(pt_save_directory, from_pt=True)
|
>>> pt_model = AutoModelForSequenceClassification.from_pretrained(tf_save_directory, from_tf=True)
|
||||||
```
|
```
|
||||||
</pt>
|
</pt>
|
||||||
<tf>
|
<tf>
|
||||||
@ -392,8 +392,8 @@ Ein besonders cooles 🤗 Transformers-Feature ist die Möglichkeit, ein Modell
|
|||||||
```py
|
```py
|
||||||
>>> from transformers import TFAutoModel
|
>>> from transformers import TFAutoModel
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained(tf_save_directory)
|
>>> tokenizer = AutoTokenizer.from_pretrained(pt_save_directory)
|
||||||
>>> tf_model = TFAutoModelForSequenceClassification.from_pretrained(tf_save_directory, from_tf=True)
|
>>> tf_model = TFAutoModelForSequenceClassification.from_pretrained(pt_save_directory, from_pt=True)
|
||||||
```
|
```
|
||||||
</tf>
|
</tf>
|
||||||
</frameworkcontent>
|
</frameworkcontent>
|
||||||
|
|||||||
@ -139,6 +139,8 @@
|
|||||||
title: Export to TFLite
|
title: Export to TFLite
|
||||||
- local: torchscript
|
- local: torchscript
|
||||||
title: Export to TorchScript
|
title: Export to TorchScript
|
||||||
|
- local: benchmarks
|
||||||
|
title: Benchmarks
|
||||||
- local: notebooks
|
- local: notebooks
|
||||||
title: Notebooks with examples
|
title: Notebooks with examples
|
||||||
- local: community
|
- local: community
|
||||||
@ -151,8 +153,6 @@
|
|||||||
title: Interoperability with TikToken files
|
title: Interoperability with TikToken files
|
||||||
- local: modular_transformers
|
- local: modular_transformers
|
||||||
title: Modularity in `transformers`
|
title: Modularity in `transformers`
|
||||||
- local: how_to_hack_models
|
|
||||||
title: Model Hacking (overwriting a class to your usage)
|
|
||||||
title: Developer guides
|
title: Developer guides
|
||||||
- sections:
|
- sections:
|
||||||
- local: quantization/overview
|
- local: quantization/overview
|
||||||
@ -165,14 +165,10 @@
|
|||||||
title: AWQ
|
title: AWQ
|
||||||
- local: quantization/aqlm
|
- local: quantization/aqlm
|
||||||
title: AQLM
|
title: AQLM
|
||||||
- local: quantization/vptq
|
|
||||||
title: VPTQ
|
|
||||||
- local: quantization/quanto
|
- local: quantization/quanto
|
||||||
title: Quanto
|
title: Quanto
|
||||||
- local: quantization/eetq
|
- local: quantization/eetq
|
||||||
title: EETQ
|
title: EETQ
|
||||||
- local: quantization/higgs
|
|
||||||
title: HIGGS
|
|
||||||
- local: quantization/hqq
|
- local: quantization/hqq
|
||||||
title: HQQ
|
title: HQQ
|
||||||
- local: quantization/fbgemm_fp8
|
- local: quantization/fbgemm_fp8
|
||||||
@ -181,10 +177,6 @@
|
|||||||
title: Optimum
|
title: Optimum
|
||||||
- local: quantization/torchao
|
- local: quantization/torchao
|
||||||
title: TorchAO
|
title: TorchAO
|
||||||
- local: quantization/bitnet
|
|
||||||
title: BitNet
|
|
||||||
- local: quantization/compressed_tensors
|
|
||||||
title: compressed-tensors
|
|
||||||
- local: quantization/contribute
|
- local: quantization/contribute
|
||||||
title: Contribute new quantization method
|
title: Contribute new quantization method
|
||||||
title: Quantization Methods
|
title: Quantization Methods
|
||||||
@ -220,8 +212,6 @@
|
|||||||
title: CPU inference
|
title: CPU inference
|
||||||
- local: perf_infer_gpu_one
|
- local: perf_infer_gpu_one
|
||||||
title: GPU inference
|
title: GPU inference
|
||||||
- local: perf_infer_gpu_multi
|
|
||||||
title: Multi-GPU inference
|
|
||||||
title: Optimizing inference
|
title: Optimizing inference
|
||||||
- local: big_models
|
- local: big_models
|
||||||
title: Instantiate a big model
|
title: Instantiate a big model
|
||||||
@ -324,8 +314,6 @@
|
|||||||
sections:
|
sections:
|
||||||
- local: model_doc/albert
|
- local: model_doc/albert
|
||||||
title: ALBERT
|
title: ALBERT
|
||||||
- local: model_doc/bamba
|
|
||||||
title: Bamba
|
|
||||||
- local: model_doc/bart
|
- local: model_doc/bart
|
||||||
title: BART
|
title: BART
|
||||||
- local: model_doc/barthez
|
- local: model_doc/barthez
|
||||||
@ -366,8 +354,6 @@
|
|||||||
title: CodeLlama
|
title: CodeLlama
|
||||||
- local: model_doc/cohere
|
- local: model_doc/cohere
|
||||||
title: Cohere
|
title: Cohere
|
||||||
- local: model_doc/cohere2
|
|
||||||
title: Cohere2
|
|
||||||
- local: model_doc/convbert
|
- local: model_doc/convbert
|
||||||
title: ConvBERT
|
title: ConvBERT
|
||||||
- local: model_doc/cpm
|
- local: model_doc/cpm
|
||||||
@ -384,8 +370,6 @@
|
|||||||
title: DeBERTa-v2
|
title: DeBERTa-v2
|
||||||
- local: model_doc/dialogpt
|
- local: model_doc/dialogpt
|
||||||
title: DialoGPT
|
title: DialoGPT
|
||||||
- local: model_doc/diffllama
|
|
||||||
title: DiffLlama
|
|
||||||
- local: model_doc/distilbert
|
- local: model_doc/distilbert
|
||||||
title: DistilBERT
|
title: DistilBERT
|
||||||
- local: model_doc/dpr
|
- local: model_doc/dpr
|
||||||
@ -402,10 +386,10 @@
|
|||||||
title: ESM
|
title: ESM
|
||||||
- local: model_doc/falcon
|
- local: model_doc/falcon
|
||||||
title: Falcon
|
title: Falcon
|
||||||
- local: model_doc/falcon3
|
|
||||||
title: Falcon3
|
|
||||||
- local: model_doc/falcon_mamba
|
- local: model_doc/falcon_mamba
|
||||||
title: FalconMamba
|
title: FalconMamba
|
||||||
|
- local: model_doc/fastspeech2_conformer
|
||||||
|
title: FastSpeech2Conformer
|
||||||
- local: model_doc/flan-t5
|
- local: model_doc/flan-t5
|
||||||
title: FLAN-T5
|
title: FLAN-T5
|
||||||
- local: model_doc/flan-ul2
|
- local: model_doc/flan-ul2
|
||||||
@ -424,8 +408,6 @@
|
|||||||
title: Gemma
|
title: Gemma
|
||||||
- local: model_doc/gemma2
|
- local: model_doc/gemma2
|
||||||
title: Gemma2
|
title: Gemma2
|
||||||
- local: model_doc/glm
|
|
||||||
title: GLM
|
|
||||||
- local: model_doc/openai-gpt
|
- local: model_doc/openai-gpt
|
||||||
title: GPT
|
title: GPT
|
||||||
- local: model_doc/gpt_neo
|
- local: model_doc/gpt_neo
|
||||||
@ -448,10 +430,6 @@
|
|||||||
title: Granite
|
title: Granite
|
||||||
- local: model_doc/granitemoe
|
- local: model_doc/granitemoe
|
||||||
title: GraniteMoe
|
title: GraniteMoe
|
||||||
- local: model_doc/granitevision
|
|
||||||
title: GraniteVision
|
|
||||||
- local: model_doc/helium
|
|
||||||
title: Helium
|
|
||||||
- local: model_doc/herbert
|
- local: model_doc/herbert
|
||||||
title: HerBERT
|
title: HerBERT
|
||||||
- local: model_doc/ibert
|
- local: model_doc/ibert
|
||||||
@ -504,8 +482,6 @@
|
|||||||
title: mLUKE
|
title: mLUKE
|
||||||
- local: model_doc/mobilebert
|
- local: model_doc/mobilebert
|
||||||
title: MobileBERT
|
title: MobileBERT
|
||||||
- local: model_doc/modernbert
|
|
||||||
title: ModernBert
|
|
||||||
- local: model_doc/mpnet
|
- local: model_doc/mpnet
|
||||||
title: MPNet
|
title: MPNet
|
||||||
- local: model_doc/mpt
|
- local: model_doc/mpt
|
||||||
@ -516,8 +492,6 @@
|
|||||||
title: MT5
|
title: MT5
|
||||||
- local: model_doc/mvp
|
- local: model_doc/mvp
|
||||||
title: MVP
|
title: MVP
|
||||||
- local: model_doc/myt5
|
|
||||||
title: myt5
|
|
||||||
- local: model_doc/nemotron
|
- local: model_doc/nemotron
|
||||||
title: Nemotron
|
title: Nemotron
|
||||||
- local: model_doc/nezha
|
- local: model_doc/nezha
|
||||||
@ -530,8 +504,6 @@
|
|||||||
title: Nyströmformer
|
title: Nyströmformer
|
||||||
- local: model_doc/olmo
|
- local: model_doc/olmo
|
||||||
title: OLMo
|
title: OLMo
|
||||||
- local: model_doc/olmo2
|
|
||||||
title: OLMo2
|
|
||||||
- local: model_doc/olmoe
|
- local: model_doc/olmoe
|
||||||
title: OLMoE
|
title: OLMoE
|
||||||
- local: model_doc/open-llama
|
- local: model_doc/open-llama
|
||||||
@ -548,8 +520,6 @@
|
|||||||
title: Phi
|
title: Phi
|
||||||
- local: model_doc/phi3
|
- local: model_doc/phi3
|
||||||
title: Phi-3
|
title: Phi-3
|
||||||
- local: model_doc/phimoe
|
|
||||||
title: PhiMoE
|
|
||||||
- local: model_doc/phobert
|
- local: model_doc/phobert
|
||||||
title: PhoBERT
|
title: PhoBERT
|
||||||
- local: model_doc/plbart
|
- local: model_doc/plbart
|
||||||
@ -560,8 +530,12 @@
|
|||||||
title: QDQBert
|
title: QDQBert
|
||||||
- local: model_doc/qwen2
|
- local: model_doc/qwen2
|
||||||
title: Qwen2
|
title: Qwen2
|
||||||
|
- local: model_doc/qwen2_audio
|
||||||
|
title: Qwen2Audio
|
||||||
- local: model_doc/qwen2_moe
|
- local: model_doc/qwen2_moe
|
||||||
title: Qwen2MoE
|
title: Qwen2MoE
|
||||||
|
- local: model_doc/qwen2_vl
|
||||||
|
title: Qwen2VL
|
||||||
- local: model_doc/rag
|
- local: model_doc/rag
|
||||||
title: RAG
|
title: RAG
|
||||||
- local: model_doc/realm
|
- local: model_doc/realm
|
||||||
@ -624,10 +598,6 @@
|
|||||||
title: XLNet
|
title: XLNet
|
||||||
- local: model_doc/yoso
|
- local: model_doc/yoso
|
||||||
title: YOSO
|
title: YOSO
|
||||||
- local: model_doc/zamba
|
|
||||||
title: Zamba
|
|
||||||
- local: model_doc/zamba2
|
|
||||||
title: Zamba2
|
|
||||||
title: Text models
|
title: Text models
|
||||||
- isExpanded: false
|
- isExpanded: false
|
||||||
sections:
|
sections:
|
||||||
@ -659,8 +629,6 @@
|
|||||||
title: DiNAT
|
title: DiNAT
|
||||||
- local: model_doc/dinov2
|
- local: model_doc/dinov2
|
||||||
title: DINOV2
|
title: DINOV2
|
||||||
- local: model_doc/dinov2_with_registers
|
|
||||||
title: DINOv2 with Registers
|
|
||||||
- local: model_doc/dit
|
- local: model_doc/dit
|
||||||
title: DiT
|
title: DiT
|
||||||
- local: model_doc/dpt
|
- local: model_doc/dpt
|
||||||
@ -675,8 +643,6 @@
|
|||||||
title: GLPN
|
title: GLPN
|
||||||
- local: model_doc/hiera
|
- local: model_doc/hiera
|
||||||
title: Hiera
|
title: Hiera
|
||||||
- local: model_doc/ijepa
|
|
||||||
title: I-JEPA
|
|
||||||
- local: model_doc/imagegpt
|
- local: model_doc/imagegpt
|
||||||
title: ImageGPT
|
title: ImageGPT
|
||||||
- local: model_doc/levit
|
- local: model_doc/levit
|
||||||
@ -711,8 +677,6 @@
|
|||||||
title: SegFormer
|
title: SegFormer
|
||||||
- local: model_doc/seggpt
|
- local: model_doc/seggpt
|
||||||
title: SegGpt
|
title: SegGpt
|
||||||
- local: model_doc/superglue
|
|
||||||
title: SuperGlue
|
|
||||||
- local: model_doc/superpoint
|
- local: model_doc/superpoint
|
||||||
title: SuperPoint
|
title: SuperPoint
|
||||||
- local: model_doc/swiftformer
|
- local: model_doc/swiftformer
|
||||||
@ -725,10 +689,6 @@
|
|||||||
title: Swin2SR
|
title: Swin2SR
|
||||||
- local: model_doc/table-transformer
|
- local: model_doc/table-transformer
|
||||||
title: Table Transformer
|
title: Table Transformer
|
||||||
- local: model_doc/textnet
|
|
||||||
title: TextNet
|
|
||||||
- local: model_doc/timm_wrapper
|
|
||||||
title: Timm Wrapper
|
|
||||||
- local: model_doc/upernet
|
- local: model_doc/upernet
|
||||||
title: UperNet
|
title: UperNet
|
||||||
- local: model_doc/van
|
- local: model_doc/van
|
||||||
@ -745,8 +705,6 @@
|
|||||||
title: ViTMatte
|
title: ViTMatte
|
||||||
- local: model_doc/vit_msn
|
- local: model_doc/vit_msn
|
||||||
title: ViTMSN
|
title: ViTMSN
|
||||||
- local: model_doc/vitpose
|
|
||||||
title: ViTPose
|
|
||||||
- local: model_doc/yolos
|
- local: model_doc/yolos
|
||||||
title: YOLOS
|
title: YOLOS
|
||||||
- local: model_doc/zoedepth
|
- local: model_doc/zoedepth
|
||||||
@ -764,8 +722,8 @@
|
|||||||
title: dac
|
title: dac
|
||||||
- local: model_doc/encodec
|
- local: model_doc/encodec
|
||||||
title: EnCodec
|
title: EnCodec
|
||||||
- local: model_doc/fastspeech2_conformer
|
- local: model_doc/hiera
|
||||||
title: FastSpeech2Conformer
|
title: Hiera
|
||||||
- local: model_doc/hubert
|
- local: model_doc/hubert
|
||||||
title: Hubert
|
title: Hubert
|
||||||
- local: model_doc/mctct
|
- local: model_doc/mctct
|
||||||
@ -774,10 +732,6 @@
|
|||||||
title: Mimi
|
title: Mimi
|
||||||
- local: model_doc/mms
|
- local: model_doc/mms
|
||||||
title: MMS
|
title: MMS
|
||||||
- local: model_doc/moonshine
|
|
||||||
title: Moonshine
|
|
||||||
- local: model_doc/moshi
|
|
||||||
title: Moshi
|
|
||||||
- local: model_doc/musicgen
|
- local: model_doc/musicgen
|
||||||
title: MusicGen
|
title: MusicGen
|
||||||
- local: model_doc/musicgen_melody
|
- local: model_doc/musicgen_melody
|
||||||
@ -838,8 +792,6 @@
|
|||||||
title: ALIGN
|
title: ALIGN
|
||||||
- local: model_doc/altclip
|
- local: model_doc/altclip
|
||||||
title: AltCLIP
|
title: AltCLIP
|
||||||
- local: model_doc/aria
|
|
||||||
title: Aria
|
|
||||||
- local: model_doc/blip
|
- local: model_doc/blip
|
||||||
title: BLIP
|
title: BLIP
|
||||||
- local: model_doc/blip-2
|
- local: model_doc/blip-2
|
||||||
@ -858,16 +810,12 @@
|
|||||||
title: CLIPSeg
|
title: CLIPSeg
|
||||||
- local: model_doc/clvp
|
- local: model_doc/clvp
|
||||||
title: CLVP
|
title: CLVP
|
||||||
- local: model_doc/colpali
|
|
||||||
title: ColPali
|
|
||||||
- local: model_doc/data2vec
|
- local: model_doc/data2vec
|
||||||
title: Data2Vec
|
title: Data2Vec
|
||||||
- local: model_doc/deplot
|
- local: model_doc/deplot
|
||||||
title: DePlot
|
title: DePlot
|
||||||
- local: model_doc/donut
|
- local: model_doc/donut
|
||||||
title: Donut
|
title: Donut
|
||||||
- local: model_doc/emu3
|
|
||||||
title: Emu3
|
|
||||||
- local: model_doc/flava
|
- local: model_doc/flava
|
||||||
title: FLAVA
|
title: FLAVA
|
||||||
- local: model_doc/git
|
- local: model_doc/git
|
||||||
@ -880,8 +828,6 @@
|
|||||||
title: IDEFICS
|
title: IDEFICS
|
||||||
- local: model_doc/idefics2
|
- local: model_doc/idefics2
|
||||||
title: Idefics2
|
title: Idefics2
|
||||||
- local: model_doc/idefics3
|
|
||||||
title: Idefics3
|
|
||||||
- local: model_doc/instructblip
|
- local: model_doc/instructblip
|
||||||
title: InstructBLIP
|
title: InstructBLIP
|
||||||
- local: model_doc/instructblipvideo
|
- local: model_doc/instructblipvideo
|
||||||
@ -912,12 +858,8 @@
|
|||||||
title: MatCha
|
title: MatCha
|
||||||
- local: model_doc/mgp-str
|
- local: model_doc/mgp-str
|
||||||
title: MGP-STR
|
title: MGP-STR
|
||||||
- local: model_doc/mllama
|
|
||||||
title: mllama
|
|
||||||
- local: model_doc/nougat
|
- local: model_doc/nougat
|
||||||
title: Nougat
|
title: Nougat
|
||||||
- local: model_doc/omdet-turbo
|
|
||||||
title: OmDet-Turbo
|
|
||||||
- local: model_doc/oneformer
|
- local: model_doc/oneformer
|
||||||
title: OneFormer
|
title: OneFormer
|
||||||
- local: model_doc/owlvit
|
- local: model_doc/owlvit
|
||||||
@ -932,12 +874,6 @@
|
|||||||
title: Pix2Struct
|
title: Pix2Struct
|
||||||
- local: model_doc/pixtral
|
- local: model_doc/pixtral
|
||||||
title: Pixtral
|
title: Pixtral
|
||||||
- local: model_doc/qwen2_5_vl
|
|
||||||
title: Qwen2.5-VL
|
|
||||||
- local: model_doc/qwen2_audio
|
|
||||||
title: Qwen2Audio
|
|
||||||
- local: model_doc/qwen2_vl
|
|
||||||
title: Qwen2VL
|
|
||||||
- local: model_doc/sam
|
- local: model_doc/sam
|
||||||
title: Segment Anything
|
title: Segment Anything
|
||||||
- local: model_doc/siglip
|
- local: model_doc/siglip
|
||||||
|
|||||||
@ -889,72 +889,3 @@ used by hundreds and possibly even thousands of developers and researchers. You
|
|||||||
your achievements with the community.
|
your achievements with the community.
|
||||||
|
|
||||||
**You have made another model that is super easy to access for everyone in the community! 🤯**
|
**You have made another model that is super easy to access for everyone in the community! 🤯**
|
||||||
|
|
||||||
## Model additions and their timeline: when is a model added to transformers?
|
|
||||||
|
|
||||||
We aim for `transformers` to have support for new model architectures and checkpoints as early as possible:
|
|
||||||
availability can range from day-0 (and hour-0) releases for some models, to a few days/weeks for others.
|
|
||||||
|
|
||||||
The availability of this is usually up to the model contributors, as well as how excited the community is for the
|
|
||||||
architecture.
|
|
||||||
|
|
||||||
We can split the model architecture possibilities in four sections:
|
|
||||||
- Day-0 integration
|
|
||||||
- Same-week integration
|
|
||||||
- Post-release integration
|
|
||||||
- Hub-first release
|
|
||||||
|
|
||||||
Let's dive into each of these and see how we (the transformers team) can help you contribute your architecture and get
|
|
||||||
your architecture to be very easily used by all members of the community.
|
|
||||||
|
|
||||||
### Day-0 integration
|
|
||||||
|
|
||||||
For a day-0 integration to work, we'll usually want to work hand-in-hand with you directly. In order to keep your
|
|
||||||
architecture private until your checkpoints and release are ready, we'll work together in a private fork of
|
|
||||||
transformers.
|
|
||||||
|
|
||||||
If you plan on having a transformers-first release, this is a great option: we run CI ahead of time, ensure the
|
|
||||||
documentation is clear, and we aim to optimize your model as much as possible (providing quantization, optimizing it
|
|
||||||
with Flash-Attention/SDPA, optimizing the KV cache, etc).
|
|
||||||
|
|
||||||
We can also lend you a hand in adding the model, reviewing it early, and help you make sure the `transformers`
|
|
||||||
API works as expected!
|
|
||||||
|
|
||||||
If this is the path you wish to go with, we ask for you to reach out in advance, especially if the architecture is
|
|
||||||
particularly novel (at least a few days, but a few weeks will enable the absolute best integration). In order to reach
|
|
||||||
out, please contact transformers@huggingface.co 🤗.
|
|
||||||
|
|
||||||
### Same-week integration
|
|
||||||
|
|
||||||
A same-week integration usually happens when model authors do not reach out; but we see significant community
|
|
||||||
requests.
|
|
||||||
|
|
||||||
In order to specify you'd like for us to integrate a specific model, we'll redirect you to our
|
|
||||||
[issue tracker](https://github.com/huggingface/transformers/issues/new?assignees=&labels=New+model&projects=&template=new-model-addition.yml)
|
|
||||||
where you can request a specific model.
|
|
||||||
|
|
||||||
The more activity on the issue, the faster/more likely we are to integrate the model!
|
|
||||||
|
|
||||||
### Post-release integration
|
|
||||||
|
|
||||||
A post-release integration usually happens when there has not been sufficient activity/requests to warrant a same-week
|
|
||||||
integration, or that we lack the sufficient bandwidth to integrate it.
|
|
||||||
|
|
||||||
We very gladly welcome community contributions in those instances; more than half of the library was contributed
|
|
||||||
by contributors external to Hugging Face. If this is something that is interesting to you, we recommend that you look
|
|
||||||
at our [open issues tagged with "New model"](https://github.com/huggingface/transformers/issues?q=is%3Aopen+is%3Aissue+label%3A%22New+model%22).
|
|
||||||
|
|
||||||
We recommend you try your hand at a heavily requested model as this will multiply the impact of your contribution.
|
|
||||||
We'll be there to help you in case that's your first contribution 🤗.
|
|
||||||
|
|
||||||
### Code-on-Hub release
|
|
||||||
|
|
||||||
Finally, transformers has a "remote-code" possibility, in which contributions are not made within the toolkit, but on
|
|
||||||
the Hub. This can be particularly interesting for groups that are using `transformers` as a backbone for their project,
|
|
||||||
but don't have the bandwidth to contribute the model to transformers directly.
|
|
||||||
|
|
||||||
In case the model is very successful, then we'll very likely end up integrating it in `transformers` at the end - as this
|
|
||||||
provides better documentation, CI, maintenance, and optimizations - but this remains a great way to make your model
|
|
||||||
accessible day-0 with minimal friction.
|
|
||||||
|
|
||||||
This guide is a great starting point for a Hub-first release: [Custom models](./custom_models)
|
|
||||||
@ -184,7 +184,7 @@ class PairClassificationPipeline(Pipeline):
|
|||||||
```
|
```
|
||||||
|
|
||||||
The implementation is framework agnostic, and will work for PyTorch and TensorFlow models. If we have saved this in
|
The implementation is framework agnostic, and will work for PyTorch and TensorFlow models. If we have saved this in
|
||||||
a file named `pair_classification.py`, we can then import it and register it like this.
|
a file named `pair_classification.py`, we can then import it and register it like this:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from pair_classification import PairClassificationPipeline
|
from pair_classification import PairClassificationPipeline
|
||||||
@ -199,22 +199,6 @@ PIPELINE_REGISTRY.register_pipeline(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
The [register_pipeline](https://github.com/huggingface/transformers/blob/9feae5fb0164e89d4998e5776897c16f7330d3df/src/transformers/pipelines/base.py#L1387) function registers the pipeline details (task type, pipeline class, supported backends) to a models `config.json` file.
|
|
||||||
|
|
||||||
```json
|
|
||||||
"custom_pipelines": {
|
|
||||||
"pair-classification": {
|
|
||||||
"impl": "pair_classification.PairClassificationPipeline",
|
|
||||||
"pt": [
|
|
||||||
"AutoModelForSequenceClassification"
|
|
||||||
],
|
|
||||||
"tf": [
|
|
||||||
"TFAutoModelForSequenceClassification"
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
Once this is done, we can use it with a pretrained model. For instance `sgugger/finetuned-bert-mrpc` has been
|
Once this is done, we can use it with a pretrained model. For instance `sgugger/finetuned-bert-mrpc` has been
|
||||||
fine-tuned on the MRPC dataset, which classifies pairs of sentences as paraphrases or not.
|
fine-tuned on the MRPC dataset, which classifies pairs of sentences as paraphrases or not.
|
||||||
|
|
||||||
|
|||||||
@ -225,7 +225,7 @@ You have access to the following tools:
|
|||||||
To solve the task, you must plan forward to proceed in a series of steps, in a cycle of 'Thought:', 'Code:', and 'Observation:' sequences.
|
To solve the task, you must plan forward to proceed in a series of steps, in a cycle of 'Thought:', 'Code:', and 'Observation:' sequences.
|
||||||
|
|
||||||
At each step, in the 'Thought:' sequence, you should first explain your reasoning towards solving the task, then the tools that you want to use.
|
At each step, in the 'Thought:' sequence, you should first explain your reasoning towards solving the task, then the tools that you want to use.
|
||||||
Then in the 'Code:' sequence, you should write the code in simple Python. The code sequence must end with '/End code' sequence.
|
Then in the 'Code:' sequence, you shold write the code in simple Python. The code sequence must end with '/End code' sequence.
|
||||||
During each intermediate step, you can use 'print()' to save whatever important information you will then need.
|
During each intermediate step, you can use 'print()' to save whatever important information you will then need.
|
||||||
These print outputs will then be available in the 'Observation:' field, for using this information as input for the next step.
|
These print outputs will then be available in the 'Observation:' field, for using this information as input for the next step.
|
||||||
|
|
||||||
@ -332,7 +332,7 @@ This code can quickly be converted into a tool, just by wrapping it in a functio
|
|||||||
from transformers import tool
|
from transformers import tool
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def model_download_tool(task: str) -> str:
|
def model_download_counter(task: str) -> str:
|
||||||
"""
|
"""
|
||||||
This is a tool that returns the most downloaded model of a given task on the Hugging Face Hub.
|
This is a tool that returns the most downloaded model of a given task on the Hugging Face Hub.
|
||||||
It returns the name of the checkpoint.
|
It returns the name of the checkpoint.
|
||||||
@ -345,7 +345,7 @@ def model_download_tool(task: str) -> str:
|
|||||||
```
|
```
|
||||||
|
|
||||||
The function needs:
|
The function needs:
|
||||||
- A clear name. The name usually describes what the tool does. Since the code returns the model with the most downloads for a task, let's put `model_download_tool`.
|
- A clear name. The name usually describes what the tool does. Since the code returns the model with the most downloads for a task, let's put `model_download_counter`.
|
||||||
- Type hints on both inputs and output
|
- Type hints on both inputs and output
|
||||||
- A description, that includes an 'Args:' part where each argument is described (without a type indication this time, it will be pulled from the type hint).
|
- A description, that includes an 'Args:' part where each argument is described (without a type indication this time, it will be pulled from the type hint).
|
||||||
All these will be automatically baked into the agent's system prompt upon initialization: so strive to make them as clear as possible!
|
All these will be automatically baked into the agent's system prompt upon initialization: so strive to make them as clear as possible!
|
||||||
@ -367,7 +367,7 @@ You get the following:
|
|||||||
======== New task ========
|
======== New task ========
|
||||||
Can you give me the name of the model that has the most downloads in the 'text-to-video' task on the Hugging Face Hub?
|
Can you give me the name of the model that has the most downloads in the 'text-to-video' task on the Hugging Face Hub?
|
||||||
==== Agent is executing the code below:
|
==== Agent is executing the code below:
|
||||||
most_downloaded_model = model_download_tool(task="text-to-video")
|
most_downloaded_model = model_download_counter(task="text-to-video")
|
||||||
print(f"The most downloaded model for the 'text-to-video' task is {most_downloaded_model}.")
|
print(f"The most downloaded model for the 'text-to-video' task is {most_downloaded_model}.")
|
||||||
====
|
====
|
||||||
```
|
```
|
||||||
|
|||||||
@ -66,10 +66,10 @@ manager_agent.run("Who is the CEO of Hugging Face?")
|
|||||||
|
|
||||||
Let's take again the tool example from main documentation, for which we had implemented a `tool` decorator.
|
Let's take again the tool example from main documentation, for which we had implemented a `tool` decorator.
|
||||||
|
|
||||||
If you need to add variation, like custom attributes for your tool, you can build your tool following the fine-grained method: building a class that inherits from the [`Tool`] superclass.
|
If you need to add variation, like custom attributes for your too, you can build your tool following the fine-grained method: building a class that inherits from the [`Tool`] superclass.
|
||||||
|
|
||||||
The custom tool needs:
|
The custom tool needs:
|
||||||
- An attribute `name`, which corresponds to the name of the tool itself. The name usually describes what the tool does. Since the code returns the model with the most downloads for a task, let's name it `model_download_counter`.
|
- An attribute `name`, which corresponds to the name of the tool itself. The name usually describes what the tool does. Since the code returns the model with the most downloads for a task, let's name is `model_download_counter`.
|
||||||
- An attribute `description` is used to populate the agent's system prompt.
|
- An attribute `description` is used to populate the agent's system prompt.
|
||||||
- An `inputs` attribute, which is a dictionary with keys `"type"` and `"description"`. It contains information that helps the Python interpreter make educated choices about the input.
|
- An `inputs` attribute, which is a dictionary with keys `"type"` and `"description"`. It contains information that helps the Python interpreter make educated choices about the input.
|
||||||
- An `output_type` attribute, which specifies the output type.
|
- An `output_type` attribute, which specifies the output type.
|
||||||
@ -123,54 +123,6 @@ from transformers import load_tool, CodeAgent
|
|||||||
model_download_tool = load_tool("m-ric/hf-model-downloads")
|
model_download_tool = load_tool("m-ric/hf-model-downloads")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Import a Space as a tool 🚀
|
|
||||||
|
|
||||||
You can directly import a Space from the Hub as a tool using the [`Tool.from_space`] method!
|
|
||||||
|
|
||||||
You only need to provide the id of the Space on the Hub, its name, and a description that will help you agent understand what the tool does. Under the hood, this will use [`gradio-client`](https://pypi.org/project/gradio-client/) library to call the Space.
|
|
||||||
|
|
||||||
For instance, let's import the [FLUX.1-dev](https://huggingface.co/black-forest-labs/FLUX.1-dev) Space from the Hub and use it to generate an image.
|
|
||||||
|
|
||||||
```
|
|
||||||
from transformers import Tool
|
|
||||||
|
|
||||||
image_generation_tool = Tool.from_space(
|
|
||||||
"black-forest-labs/FLUX.1-dev",
|
|
||||||
name="image_generator",
|
|
||||||
description="Generate an image from a prompt")
|
|
||||||
|
|
||||||
image_generation_tool("A sunny beach")
|
|
||||||
```
|
|
||||||
And voilà, here's your image! 🏖️
|
|
||||||
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/sunny_beach.webp">
|
|
||||||
|
|
||||||
Then you can use this tool just like any other tool. For example, let's improve the prompt `a rabbit wearing a space suit` and generate an image of it.
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import ReactCodeAgent
|
|
||||||
|
|
||||||
agent = ReactCodeAgent(tools=[image_generation_tool])
|
|
||||||
|
|
||||||
agent.run(
|
|
||||||
"Improve this prompt, then generate an image of it.", prompt='A rabbit wearing a space suit'
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
```text
|
|
||||||
=== Agent thoughts:
|
|
||||||
improved_prompt could be "A bright blue space suit wearing rabbit, on the surface of the moon, under a bright orange sunset, with the Earth visible in the background"
|
|
||||||
|
|
||||||
Now that I have improved the prompt, I can use the image generator tool to generate an image based on this prompt.
|
|
||||||
=== Agent is executing the code below:
|
|
||||||
image = image_generator(prompt="A bright blue space suit wearing rabbit, on the surface of the moon, under a bright orange sunset, with the Earth visible in the background")
|
|
||||||
final_answer(image)
|
|
||||||
```
|
|
||||||
|
|
||||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/rabbit_spacesuit_flux.webp">
|
|
||||||
|
|
||||||
How cool is this? 🤩
|
|
||||||
|
|
||||||
### Use gradio-tools
|
### Use gradio-tools
|
||||||
|
|
||||||
[gradio-tools](https://github.com/freddyaboulton/gradio-tools) is a powerful library that allows using Hugging
|
[gradio-tools](https://github.com/freddyaboulton/gradio-tools) is a powerful library that allows using Hugging
|
||||||
@ -188,6 +140,36 @@ gradio_prompt_generator_tool = StableDiffusionPromptGeneratorTool()
|
|||||||
prompt_generator_tool = Tool.from_gradio(gradio_prompt_generator_tool)
|
prompt_generator_tool = Tool.from_gradio(gradio_prompt_generator_tool)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Now you can use it just like any other tool. For example, let's improve the prompt `a rabbit wearing a space suit`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
image_generation_tool = load_tool('huggingface-tools/text-to-image')
|
||||||
|
agent = CodeAgent(tools=[prompt_generator_tool, image_generation_tool], llm_engine=llm_engine)
|
||||||
|
|
||||||
|
agent.run(
|
||||||
|
"Improve this prompt, then generate an image of it.", prompt='A rabbit wearing a space suit'
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
The model adequately leverages the tool:
|
||||||
|
```text
|
||||||
|
======== New task ========
|
||||||
|
Improve this prompt, then generate an image of it.
|
||||||
|
You have been provided with these initial arguments: {'prompt': 'A rabbit wearing a space suit'}.
|
||||||
|
==== Agent is executing the code below:
|
||||||
|
improved_prompt = StableDiffusionPromptGenerator(query=prompt)
|
||||||
|
while improved_prompt == "QUEUE_FULL":
|
||||||
|
improved_prompt = StableDiffusionPromptGenerator(query=prompt)
|
||||||
|
print(f"The improved prompt is {improved_prompt}.")
|
||||||
|
image = image_generator(prompt=improved_prompt)
|
||||||
|
====
|
||||||
|
```
|
||||||
|
|
||||||
|
Before finally generating the image:
|
||||||
|
|
||||||
|
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/rabbit.png">
|
||||||
|
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> gradio-tools require *textual* inputs and outputs even when working with different modalities like image and audio objects. Image and audio inputs and outputs are currently incompatible.
|
> gradio-tools require *textual* inputs and outputs even when working with different modalities like image and audio objects. Image and audio inputs and outputs are currently incompatible.
|
||||||
|
|
||||||
@ -197,7 +179,7 @@ We love Langchain and think it has a very compelling suite of tools.
|
|||||||
To import a tool from LangChain, use the `from_langchain()` method.
|
To import a tool from LangChain, use the `from_langchain()` method.
|
||||||
|
|
||||||
Here is how you can use it to recreate the intro's search result using a LangChain web search tool.
|
Here is how you can use it to recreate the intro's search result using a LangChain web search tool.
|
||||||
This tool will need `pip install google-search-results` to work properly.
|
|
||||||
```python
|
```python
|
||||||
from langchain.agents import load_tools
|
from langchain.agents import load_tools
|
||||||
from transformers import Tool, ReactCodeAgent
|
from transformers import Tool, ReactCodeAgent
|
||||||
@ -206,12 +188,12 @@ search_tool = Tool.from_langchain(load_tools(["serpapi"])[0])
|
|||||||
|
|
||||||
agent = ReactCodeAgent(tools=[search_tool])
|
agent = ReactCodeAgent(tools=[search_tool])
|
||||||
|
|
||||||
agent.run("How many more blocks (also denoted as layers) are in BERT base encoder compared to the encoder from the architecture proposed in Attention is All You Need?")
|
agent.run("How many more blocks (also denoted as layers) in BERT base encoder than the encoder from the architecture proposed in Attention is All You Need?")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Display your agent run in a cool Gradio interface
|
## Display your agent run in a cool Gradio interface
|
||||||
|
|
||||||
You can leverage `gradio.Chatbot` to display your agent's thoughts using `stream_to_gradio`, here is an example:
|
You can leverage `gradio.Chatbot`to display your agent's thoughts using `stream_to_gradio`, here is an example:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
@ -258,4 +240,4 @@ with gr.Blocks() as demo:
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
demo.launch()
|
demo.launch()
|
||||||
```
|
```
|
||||||
@ -138,15 +138,12 @@ Load a processor with [`AutoProcessor.from_pretrained`]:
|
|||||||
|
|
||||||
<frameworkcontent>
|
<frameworkcontent>
|
||||||
<pt>
|
<pt>
|
||||||
The `AutoModelFor` classes let you load a pretrained model for a given task (see [here](model_doc/auto) for a complete list of available tasks). For example, load a model for sequence classification with [`AutoModelForSequenceClassification.from_pretrained`].
|
The `AutoModelFor` classes let you load a pretrained model for a given task (see [here](model_doc/auto) for a complete list of available tasks). For example, load a model for sequence classification with [`AutoModelForSequenceClassification.from_pretrained`]:
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> By default, the weights are loaded in full precision (torch.float32) regardless of the actual data type the weights are stored in such as torch.float16. Set `torch_dtype="auto"` to load the weights in the data type defined in a model's `config.json` file to automatically load the most memory-optimal data type.
|
|
||||||
|
|
||||||
```py
|
```py
|
||||||
>>> from transformers import AutoModelForSequenceClassification
|
>>> from transformers import AutoModelForSequenceClassification
|
||||||
|
|
||||||
>>> model = AutoModelForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased", torch_dtype="auto")
|
>>> model = AutoModelForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased")
|
||||||
```
|
```
|
||||||
|
|
||||||
Easily reuse the same checkpoint to load an architecture for a different task:
|
Easily reuse the same checkpoint to load an architecture for a different task:
|
||||||
@ -154,7 +151,7 @@ Easily reuse the same checkpoint to load an architecture for a different task:
|
|||||||
```py
|
```py
|
||||||
>>> from transformers import AutoModelForTokenClassification
|
>>> from transformers import AutoModelForTokenClassification
|
||||||
|
|
||||||
>>> model = AutoModelForTokenClassification.from_pretrained("distilbert/distilbert-base-uncased", torch_dtype="auto")
|
>>> model = AutoModelForTokenClassification.from_pretrained("distilbert/distilbert-base-uncased")
|
||||||
```
|
```
|
||||||
|
|
||||||
<Tip warning={true}>
|
<Tip warning={true}>
|
||||||
|
|||||||
387
docs/source/en/benchmarks.md
Normal file
387
docs/source/en/benchmarks.md
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
<!--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.
|
||||||
|
|
||||||
|
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||||
|
rendered properly in your Markdown viewer.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Benchmarks
|
||||||
|
|
||||||
|
<Tip warning={true}>
|
||||||
|
|
||||||
|
Hugging Face's Benchmarking tools are deprecated and it is advised to use external Benchmarking libraries to measure the speed
|
||||||
|
and memory complexity of Transformer models.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
[[open-in-colab]]
|
||||||
|
|
||||||
|
Let's take a look at how 🤗 Transformers models can be benchmarked, best practices, and already available benchmarks.
|
||||||
|
|
||||||
|
A notebook explaining in more detail how to benchmark 🤗 Transformers models can be found [here](https://github.com/huggingface/notebooks/tree/main/examples/benchmark.ipynb).
|
||||||
|
|
||||||
|
## How to benchmark 🤗 Transformers models
|
||||||
|
|
||||||
|
The classes [`PyTorchBenchmark`] and [`TensorFlowBenchmark`] allow to flexibly benchmark 🤗 Transformers models. The benchmark classes allow us to measure the _peak memory usage_ and _required time_ for both _inference_ and _training_.
|
||||||
|
|
||||||
|
<Tip>
|
||||||
|
|
||||||
|
Here, _inference_ is defined by a single forward pass, and _training_ is defined by a single forward pass and
|
||||||
|
backward pass.
|
||||||
|
|
||||||
|
</Tip>
|
||||||
|
|
||||||
|
The benchmark classes [`PyTorchBenchmark`] and [`TensorFlowBenchmark`] expect an object of type [`PyTorchBenchmarkArguments`] and
|
||||||
|
[`TensorFlowBenchmarkArguments`], respectively, for instantiation. [`PyTorchBenchmarkArguments`] and [`TensorFlowBenchmarkArguments`] are data classes and contain all relevant configurations for their corresponding benchmark class. In the following example, it is shown how a BERT model of type _bert-base-cased_ can be benchmarked.
|
||||||
|
|
||||||
|
<frameworkcontent>
|
||||||
|
<pt>
|
||||||
|
```py
|
||||||
|
>>> from transformers import PyTorchBenchmark, PyTorchBenchmarkArguments
|
||||||
|
|
||||||
|
>>> args = PyTorchBenchmarkArguments(models=["google-bert/bert-base-uncased"], batch_sizes=[8], sequence_lengths=[8, 32, 128, 512])
|
||||||
|
>>> benchmark = PyTorchBenchmark(args)
|
||||||
|
```
|
||||||
|
</pt>
|
||||||
|
<tf>
|
||||||
|
```py
|
||||||
|
>>> from transformers import TensorFlowBenchmark, TensorFlowBenchmarkArguments
|
||||||
|
|
||||||
|
>>> args = TensorFlowBenchmarkArguments(
|
||||||
|
... models=["google-bert/bert-base-uncased"], batch_sizes=[8], sequence_lengths=[8, 32, 128, 512]
|
||||||
|
... )
|
||||||
|
>>> benchmark = TensorFlowBenchmark(args)
|
||||||
|
```
|
||||||
|
</tf>
|
||||||
|
</frameworkcontent>
|
||||||
|
|
||||||
|
Here, three arguments are given to the benchmark argument data classes, namely `models`, `batch_sizes`, and
|
||||||
|
`sequence_lengths`. The argument `models` is required and expects a `list` of model identifiers from the
|
||||||
|
[model hub](https://huggingface.co/models) The `list` arguments `batch_sizes` and `sequence_lengths` define
|
||||||
|
the size of the `input_ids` on which the model is benchmarked. There are many more parameters that can be configured
|
||||||
|
via the benchmark argument data classes. For more detail on these one can either directly consult the files
|
||||||
|
`src/transformers/benchmark/benchmark_args_utils.py`, `src/transformers/benchmark/benchmark_args.py` (for PyTorch)
|
||||||
|
and `src/transformers/benchmark/benchmark_args_tf.py` (for Tensorflow). Alternatively, running the following shell
|
||||||
|
commands from root will print out a descriptive list of all configurable parameters for PyTorch and Tensorflow
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
<frameworkcontent>
|
||||||
|
<pt>
|
||||||
|
```bash
|
||||||
|
python examples/pytorch/benchmarking/run_benchmark.py --help
|
||||||
|
```
|
||||||
|
|
||||||
|
An instantiated benchmark object can then simply be run by calling `benchmark.run()`.
|
||||||
|
|
||||||
|
```py
|
||||||
|
>>> results = benchmark.run()
|
||||||
|
>>> print(results)
|
||||||
|
==================== INFERENCE - SPEED - RESULT ====================
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Model Name Batch Size Seq Length Time in s
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
google-bert/bert-base-uncased 8 8 0.006
|
||||||
|
google-bert/bert-base-uncased 8 32 0.006
|
||||||
|
google-bert/bert-base-uncased 8 128 0.018
|
||||||
|
google-bert/bert-base-uncased 8 512 0.088
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
==================== INFERENCE - MEMORY - RESULT ====================
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Model Name Batch Size Seq Length Memory in MB
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
google-bert/bert-base-uncased 8 8 1227
|
||||||
|
google-bert/bert-base-uncased 8 32 1281
|
||||||
|
google-bert/bert-base-uncased 8 128 1307
|
||||||
|
google-bert/bert-base-uncased 8 512 1539
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
==================== ENVIRONMENT INFORMATION ====================
|
||||||
|
|
||||||
|
- transformers_version: 2.11.0
|
||||||
|
- framework: PyTorch
|
||||||
|
- use_torchscript: False
|
||||||
|
- framework_version: 1.4.0
|
||||||
|
- python_version: 3.6.10
|
||||||
|
- system: Linux
|
||||||
|
- cpu: x86_64
|
||||||
|
- architecture: 64bit
|
||||||
|
- date: 2020-06-29
|
||||||
|
- time: 08:58:43.371351
|
||||||
|
- fp16: False
|
||||||
|
- use_multiprocessing: True
|
||||||
|
- only_pretrain_model: False
|
||||||
|
- cpu_ram_mb: 32088
|
||||||
|
- use_gpu: True
|
||||||
|
- num_gpus: 1
|
||||||
|
- gpu: TITAN RTX
|
||||||
|
- gpu_ram_mb: 24217
|
||||||
|
- gpu_power_watts: 280.0
|
||||||
|
- gpu_performance_state: 2
|
||||||
|
- use_tpu: False
|
||||||
|
```
|
||||||
|
</pt>
|
||||||
|
<tf>
|
||||||
|
```bash
|
||||||
|
python examples/tensorflow/benchmarking/run_benchmark_tf.py --help
|
||||||
|
```
|
||||||
|
|
||||||
|
An instantiated benchmark object can then simply be run by calling `benchmark.run()`.
|
||||||
|
|
||||||
|
```py
|
||||||
|
>>> results = benchmark.run()
|
||||||
|
>>> print(results)
|
||||||
|
>>> results = benchmark.run()
|
||||||
|
>>> print(results)
|
||||||
|
==================== INFERENCE - SPEED - RESULT ====================
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Model Name Batch Size Seq Length Time in s
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
google-bert/bert-base-uncased 8 8 0.005
|
||||||
|
google-bert/bert-base-uncased 8 32 0.008
|
||||||
|
google-bert/bert-base-uncased 8 128 0.022
|
||||||
|
google-bert/bert-base-uncased 8 512 0.105
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
==================== INFERENCE - MEMORY - RESULT ====================
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Model Name Batch Size Seq Length Memory in MB
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
google-bert/bert-base-uncased 8 8 1330
|
||||||
|
google-bert/bert-base-uncased 8 32 1330
|
||||||
|
google-bert/bert-base-uncased 8 128 1330
|
||||||
|
google-bert/bert-base-uncased 8 512 1770
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
==================== ENVIRONMENT INFORMATION ====================
|
||||||
|
|
||||||
|
- transformers_version: 2.11.0
|
||||||
|
- framework: Tensorflow
|
||||||
|
- use_xla: False
|
||||||
|
- framework_version: 2.2.0
|
||||||
|
- python_version: 3.6.10
|
||||||
|
- system: Linux
|
||||||
|
- cpu: x86_64
|
||||||
|
- architecture: 64bit
|
||||||
|
- date: 2020-06-29
|
||||||
|
- time: 09:26:35.617317
|
||||||
|
- fp16: False
|
||||||
|
- use_multiprocessing: True
|
||||||
|
- only_pretrain_model: False
|
||||||
|
- cpu_ram_mb: 32088
|
||||||
|
- use_gpu: True
|
||||||
|
- num_gpus: 1
|
||||||
|
- gpu: TITAN RTX
|
||||||
|
- gpu_ram_mb: 24217
|
||||||
|
- gpu_power_watts: 280.0
|
||||||
|
- gpu_performance_state: 2
|
||||||
|
- use_tpu: False
|
||||||
|
```
|
||||||
|
</tf>
|
||||||
|
</frameworkcontent>
|
||||||
|
|
||||||
|
By default, the _time_ and the _required memory_ for _inference_ are benchmarked. In the example output above the first
|
||||||
|
two sections show the result corresponding to _inference time_ and _inference memory_. In addition, all relevant
|
||||||
|
information about the computing environment, _e.g._ the GPU type, the system, the library versions, etc... are printed
|
||||||
|
out in the third section under _ENVIRONMENT INFORMATION_. This information can optionally be saved in a _.csv_ file
|
||||||
|
when adding the argument `save_to_csv=True` to [`PyTorchBenchmarkArguments`] and
|
||||||
|
[`TensorFlowBenchmarkArguments`] respectively. In this case, every section is saved in a separate
|
||||||
|
_.csv_ file. The path to each _.csv_ file can optionally be defined via the argument data classes.
|
||||||
|
|
||||||
|
Instead of benchmarking pre-trained models via their model identifier, _e.g._ `google-bert/bert-base-uncased`, the user can
|
||||||
|
alternatively benchmark an arbitrary configuration of any available model class. In this case, a `list` of
|
||||||
|
configurations must be inserted with the benchmark args as follows.
|
||||||
|
|
||||||
|
<frameworkcontent>
|
||||||
|
<pt>
|
||||||
|
```py
|
||||||
|
>>> from transformers import PyTorchBenchmark, PyTorchBenchmarkArguments, BertConfig
|
||||||
|
|
||||||
|
>>> args = PyTorchBenchmarkArguments(
|
||||||
|
... models=["bert-base", "bert-384-hid", "bert-6-lay"], batch_sizes=[8], sequence_lengths=[8, 32, 128, 512]
|
||||||
|
... )
|
||||||
|
>>> config_base = BertConfig()
|
||||||
|
>>> config_384_hid = BertConfig(hidden_size=384)
|
||||||
|
>>> config_6_lay = BertConfig(num_hidden_layers=6)
|
||||||
|
|
||||||
|
>>> benchmark = PyTorchBenchmark(args, configs=[config_base, config_384_hid, config_6_lay])
|
||||||
|
>>> benchmark.run()
|
||||||
|
==================== INFERENCE - SPEED - RESULT ====================
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Model Name Batch Size Seq Length Time in s
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
bert-base 8 128 0.006
|
||||||
|
bert-base 8 512 0.006
|
||||||
|
bert-base 8 128 0.018
|
||||||
|
bert-base 8 512 0.088
|
||||||
|
bert-384-hid 8 8 0.006
|
||||||
|
bert-384-hid 8 32 0.006
|
||||||
|
bert-384-hid 8 128 0.011
|
||||||
|
bert-384-hid 8 512 0.054
|
||||||
|
bert-6-lay 8 8 0.003
|
||||||
|
bert-6-lay 8 32 0.004
|
||||||
|
bert-6-lay 8 128 0.009
|
||||||
|
bert-6-lay 8 512 0.044
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
==================== INFERENCE - MEMORY - RESULT ====================
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Model Name Batch Size Seq Length Memory in MB
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
bert-base 8 8 1277
|
||||||
|
bert-base 8 32 1281
|
||||||
|
bert-base 8 128 1307
|
||||||
|
bert-base 8 512 1539
|
||||||
|
bert-384-hid 8 8 1005
|
||||||
|
bert-384-hid 8 32 1027
|
||||||
|
bert-384-hid 8 128 1035
|
||||||
|
bert-384-hid 8 512 1255
|
||||||
|
bert-6-lay 8 8 1097
|
||||||
|
bert-6-lay 8 32 1101
|
||||||
|
bert-6-lay 8 128 1127
|
||||||
|
bert-6-lay 8 512 1359
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
==================== ENVIRONMENT INFORMATION ====================
|
||||||
|
|
||||||
|
- transformers_version: 2.11.0
|
||||||
|
- framework: PyTorch
|
||||||
|
- use_torchscript: False
|
||||||
|
- framework_version: 1.4.0
|
||||||
|
- python_version: 3.6.10
|
||||||
|
- system: Linux
|
||||||
|
- cpu: x86_64
|
||||||
|
- architecture: 64bit
|
||||||
|
- date: 2020-06-29
|
||||||
|
- time: 09:35:25.143267
|
||||||
|
- fp16: False
|
||||||
|
- use_multiprocessing: True
|
||||||
|
- only_pretrain_model: False
|
||||||
|
- cpu_ram_mb: 32088
|
||||||
|
- use_gpu: True
|
||||||
|
- num_gpus: 1
|
||||||
|
- gpu: TITAN RTX
|
||||||
|
- gpu_ram_mb: 24217
|
||||||
|
- gpu_power_watts: 280.0
|
||||||
|
- gpu_performance_state: 2
|
||||||
|
- use_tpu: False
|
||||||
|
```
|
||||||
|
</pt>
|
||||||
|
<tf>
|
||||||
|
```py
|
||||||
|
>>> from transformers import TensorFlowBenchmark, TensorFlowBenchmarkArguments, BertConfig
|
||||||
|
|
||||||
|
>>> args = TensorFlowBenchmarkArguments(
|
||||||
|
... models=["bert-base", "bert-384-hid", "bert-6-lay"], batch_sizes=[8], sequence_lengths=[8, 32, 128, 512]
|
||||||
|
... )
|
||||||
|
>>> config_base = BertConfig()
|
||||||
|
>>> config_384_hid = BertConfig(hidden_size=384)
|
||||||
|
>>> config_6_lay = BertConfig(num_hidden_layers=6)
|
||||||
|
|
||||||
|
>>> benchmark = TensorFlowBenchmark(args, configs=[config_base, config_384_hid, config_6_lay])
|
||||||
|
>>> benchmark.run()
|
||||||
|
==================== INFERENCE - SPEED - RESULT ====================
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Model Name Batch Size Seq Length Time in s
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
bert-base 8 8 0.005
|
||||||
|
bert-base 8 32 0.008
|
||||||
|
bert-base 8 128 0.022
|
||||||
|
bert-base 8 512 0.106
|
||||||
|
bert-384-hid 8 8 0.005
|
||||||
|
bert-384-hid 8 32 0.007
|
||||||
|
bert-384-hid 8 128 0.018
|
||||||
|
bert-384-hid 8 512 0.064
|
||||||
|
bert-6-lay 8 8 0.002
|
||||||
|
bert-6-lay 8 32 0.003
|
||||||
|
bert-6-lay 8 128 0.0011
|
||||||
|
bert-6-lay 8 512 0.074
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
==================== INFERENCE - MEMORY - RESULT ====================
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Model Name Batch Size Seq Length Memory in MB
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
bert-base 8 8 1330
|
||||||
|
bert-base 8 32 1330
|
||||||
|
bert-base 8 128 1330
|
||||||
|
bert-base 8 512 1770
|
||||||
|
bert-384-hid 8 8 1330
|
||||||
|
bert-384-hid 8 32 1330
|
||||||
|
bert-384-hid 8 128 1330
|
||||||
|
bert-384-hid 8 512 1540
|
||||||
|
bert-6-lay 8 8 1330
|
||||||
|
bert-6-lay 8 32 1330
|
||||||
|
bert-6-lay 8 128 1330
|
||||||
|
bert-6-lay 8 512 1540
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
==================== ENVIRONMENT INFORMATION ====================
|
||||||
|
|
||||||
|
- transformers_version: 2.11.0
|
||||||
|
- framework: Tensorflow
|
||||||
|
- use_xla: False
|
||||||
|
- framework_version: 2.2.0
|
||||||
|
- python_version: 3.6.10
|
||||||
|
- system: Linux
|
||||||
|
- cpu: x86_64
|
||||||
|
- architecture: 64bit
|
||||||
|
- date: 2020-06-29
|
||||||
|
- time: 09:38:15.487125
|
||||||
|
- fp16: False
|
||||||
|
- use_multiprocessing: True
|
||||||
|
- only_pretrain_model: False
|
||||||
|
- cpu_ram_mb: 32088
|
||||||
|
- use_gpu: True
|
||||||
|
- num_gpus: 1
|
||||||
|
- gpu: TITAN RTX
|
||||||
|
- gpu_ram_mb: 24217
|
||||||
|
- gpu_power_watts: 280.0
|
||||||
|
- gpu_performance_state: 2
|
||||||
|
- use_tpu: False
|
||||||
|
```
|
||||||
|
</tf>
|
||||||
|
</frameworkcontent>
|
||||||
|
|
||||||
|
Again, _inference time_ and _required memory_ for _inference_ are measured, but this time for customized configurations
|
||||||
|
of the `BertModel` class. This feature can especially be helpful when deciding for which configuration the model
|
||||||
|
should be trained.
|
||||||
|
|
||||||
|
|
||||||
|
## Benchmark best practices
|
||||||
|
|
||||||
|
This section lists a couple of best practices one should be aware of when benchmarking a model.
|
||||||
|
|
||||||
|
- Currently, only single device benchmarking is supported. When benchmarking on GPU, it is recommended that the user
|
||||||
|
specifies on which device the code should be run by setting the `CUDA_VISIBLE_DEVICES` environment variable in the
|
||||||
|
shell, _e.g._ `export CUDA_VISIBLE_DEVICES=0` before running the code.
|
||||||
|
- The option `no_multi_processing` should only be set to `True` for testing and debugging. To ensure accurate
|
||||||
|
memory measurement it is recommended to run each memory benchmark in a separate process by making sure
|
||||||
|
`no_multi_processing` is set to `True`.
|
||||||
|
- One should always state the environment information when sharing the results of a model benchmark. Results can vary
|
||||||
|
heavily between different GPU devices, library versions, etc., as a consequence, benchmark results on their own are not very
|
||||||
|
useful for the community.
|
||||||
|
|
||||||
|
|
||||||
|
## Sharing your benchmark
|
||||||
|
|
||||||
|
Previously all available core models (10 at the time) have been benchmarked for _inference time_, across many different
|
||||||
|
settings: using PyTorch, with and without TorchScript, using TensorFlow, with and without XLA. All of those tests were
|
||||||
|
done across CPUs (except for TensorFlow XLA) and GPUs.
|
||||||
|
|
||||||
|
The approach is detailed in the [following blogpost](https://medium.com/huggingface/benchmarking-transformers-pytorch-and-tensorflow-e2917fb891c2) and the results are
|
||||||
|
available [here](https://docs.google.com/spreadsheets/d/1sryqufw2D0XlUH4sq3e9Wnxu5EAQkaohzrJbd5HdQ_w/edit?usp=sharing).
|
||||||
|
|
||||||
|
With the new _benchmark_ tools, it is easier than ever to share your benchmark results with the community
|
||||||
|
|
||||||
|
- [PyTorch Benchmarking Results](https://github.com/huggingface/transformers/tree/main/examples/pytorch/benchmarking/README.md).
|
||||||
|
- [TensorFlow Benchmarking Results](https://github.com/huggingface/transformers/tree/main/examples/tensorflow/benchmarking/README.md).
|
||||||
@ -23,8 +23,8 @@ of text (as is the case with a standard language model), the model instead conti
|
|||||||
of one or more **messages**, each of which includes a **role**, like "user" or "assistant", as well as message text.
|
of one or more **messages**, each of which includes a **role**, like "user" or "assistant", as well as message text.
|
||||||
|
|
||||||
Much like tokenization, different models expect very different input formats for chat. This is the reason we added
|
Much like tokenization, different models expect very different input formats for chat. This is the reason we added
|
||||||
**chat templates** as a feature. Chat templates are part of the tokenizer for text-only LLMs or processor for multimodal LLMs. They specify how to convert conversations,
|
**chat templates** as a feature. Chat templates are part of the tokenizer. They specify how to convert conversations,
|
||||||
represented as lists of messages, into a single tokenizable string in the format that the model expects.
|
represented as lists of messages, into a single tokenizable string in the format that the model expects.
|
||||||
|
|
||||||
Let's make this concrete with a quick example using the `mistralai/Mistral-7B-Instruct-v0.1` model:
|
Let's make this concrete with a quick example using the `mistralai/Mistral-7B-Instruct-v0.1` model:
|
||||||
|
|
||||||
@ -39,11 +39,11 @@ Let's make this concrete with a quick example using the `mistralai/Mistral-7B-In
|
|||||||
... ]
|
... ]
|
||||||
|
|
||||||
>>> tokenizer.apply_chat_template(chat, tokenize=False)
|
>>> tokenizer.apply_chat_template(chat, tokenize=False)
|
||||||
"<s> [INST] Hello, how are you? [/INST] I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]"
|
"<s>[INST] Hello, how are you? [/INST]I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]"
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice how the tokenizer has added the control tokens [INST] and [/INST] to indicate the start and end of
|
Notice how the tokenizer has added the control tokens [INST] and [/INST] to indicate the start and end of
|
||||||
user messages (but not assistant messages!), and the entire chat is condensed into a single string.
|
user messages (but not assistant messages!), and the entire chat is condensed into a single string.
|
||||||
If we use `tokenize=True`, which is the default setting, that string will also be tokenized for us.
|
If we use `tokenize=True`, which is the default setting, that string will also be tokenized for us.
|
||||||
|
|
||||||
Now, try the same code, but swap in the `HuggingFaceH4/zephyr-7b-beta` model instead, and you should get:
|
Now, try the same code, but swap in the `HuggingFaceH4/zephyr-7b-beta` model instead, and you should get:
|
||||||
@ -59,26 +59,17 @@ I'd like to show off how chat templating works!</s>
|
|||||||
|
|
||||||
Both Zephyr and Mistral-Instruct were fine-tuned from the same base model, `Mistral-7B-v0.1`. However, they were trained
|
Both Zephyr and Mistral-Instruct were fine-tuned from the same base model, `Mistral-7B-v0.1`. However, they were trained
|
||||||
with totally different chat formats. Without chat templates, you would have to write manual formatting code for each
|
with totally different chat formats. Without chat templates, you would have to write manual formatting code for each
|
||||||
model, and it's very easy to make minor errors that hurt performance! Chat templates handle the details of formatting
|
model, and it's very easy to make minor errors that hurt performance! Chat templates handle the details of formatting
|
||||||
for you, allowing you to write universal code that works for any model.
|
for you, allowing you to write universal code that works for any model.
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
Chat templates are a critical component of our [chat CLI](quicktour#chat-with-text-generation-models).
|
|
||||||
You can apply the learnings of this guide there as well.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
|
|
||||||
## How do I use chat templates?
|
## How do I use chat templates?
|
||||||
|
|
||||||
As you can see in the example above, chat templates are easy to use. Simply build a list of messages, with `role`
|
As you can see in the example above, chat templates are easy to use. Simply build a list of messages, with `role`
|
||||||
and `content` keys, and then pass it to the [`~PreTrainedTokenizer.apply_chat_template`] or [`~ProcessorMixin.apply_chat_template`] method
|
and `content` keys, and then pass it to the [`~PreTrainedTokenizer.apply_chat_template`] method. Once you do that,
|
||||||
depending on what type of model you are using. Once you do that,
|
|
||||||
you'll get output that's ready to go! When using chat templates as input for model generation, it's also a good idea
|
you'll get output that's ready to go! When using chat templates as input for model generation, it's also a good idea
|
||||||
to use `add_generation_prompt=True` to add a [generation prompt](#what-are-generation-prompts).
|
to use `add_generation_prompt=True` to add a [generation prompt](#what-are-generation-prompts).
|
||||||
|
|
||||||
## Usage with text-only LLMs
|
|
||||||
Here's an example of preparing input for `model.generate()`, using `Zephyr` again:
|
Here's an example of preparing input for `model.generate()`, using `Zephyr` again:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -98,19 +89,19 @@ messages = [
|
|||||||
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
|
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
|
||||||
print(tokenizer.decode(tokenized_chat[0]))
|
print(tokenizer.decode(tokenized_chat[0]))
|
||||||
```
|
```
|
||||||
This will yield a string in the input format that Zephyr expects.
|
This will yield a string in the input format that Zephyr expects.
|
||||||
```text
|
```text
|
||||||
<|system|>
|
<|system|>
|
||||||
You are a friendly chatbot who always responds in the style of a pirate</s>
|
You are a friendly chatbot who always responds in the style of a pirate</s>
|
||||||
<|user|>
|
<|user|>
|
||||||
How many helicopters can a human eat in one sitting?</s>
|
How many helicopters can a human eat in one sitting?</s>
|
||||||
<|assistant|>
|
<|assistant|>
|
||||||
```
|
```
|
||||||
|
|
||||||
Now that our input is formatted correctly for Zephyr, we can use the model to generate a response to the user's question:
|
Now that our input is formatted correctly for Zephyr, we can use the model to generate a response to the user's question:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
outputs = model.generate(tokenized_chat, max_new_tokens=128)
|
outputs = model.generate(tokenized_chat, max_new_tokens=128)
|
||||||
print(tokenizer.decode(outputs[0]))
|
print(tokenizer.decode(outputs[0]))
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -118,58 +109,20 @@ This will yield:
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
<|system|>
|
<|system|>
|
||||||
You are a friendly chatbot who always responds in the style of a pirate</s>
|
You are a friendly chatbot who always responds in the style of a pirate</s>
|
||||||
<|user|>
|
<|user|>
|
||||||
How many helicopters can a human eat in one sitting?</s>
|
How many helicopters can a human eat in one sitting?</s>
|
||||||
<|assistant|>
|
<|assistant|>
|
||||||
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.
|
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage with multimodal LLMs
|
|
||||||
|
|
||||||
For multimodal LLMs such as [LLaVA](https://huggingface.co/llava-hf) the prompts can be formatted in a similar way. The only difference is you need to pass input images/videos as well along with the text. Each `"content"`
|
|
||||||
has to be a list containing either a text or an image/video.
|
|
||||||
|
|
||||||
Here's an example of preparing input for using `LLaVA` model:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from transformers import AutoProcessor, LlavaOnevisionForConditionalGeneration
|
|
||||||
|
|
||||||
model_id = "llava-hf/llava-onevision-qwen2-0.5b-ov-hf"
|
|
||||||
model = LlavaOnevisionForConditionalGeneration.from_pretrained(model_id) # You may want to use bfloat16 and/or move to GPU here
|
|
||||||
processor = AutoProcessor.from_pretrained(model_id)
|
|
||||||
|
|
||||||
messages = [
|
|
||||||
{
|
|
||||||
"role": "system",
|
|
||||||
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": [
|
|
||||||
{"type": "image", "url": "http://images.cocodataset.org/val2017/000000039769.jpg"},
|
|
||||||
{"type": "text", "text": "What are these?"},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
processed_chat = processor.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_dict=True, return_tensors="pt")
|
|
||||||
print(processor.batch_decode(processed_chat["input_ids"][:, :30]))
|
|
||||||
```
|
|
||||||
This yields a string in LLaVAs expected input format with many `<image>` tokens at the end.
|
|
||||||
The `<image>` tokens are placeholders and each one will be replaced by image embeddings when the mode is run in the forward call. The `processed_chat` can be further passed into [`~GenerationMixin.generate`] to generate text.
|
|
||||||
```text
|
|
||||||
'<|im_start|>system
|
|
||||||
You are a friendly chatbot who always responds in the style of a pirate<|im_end|><|im_start|>user <image><image><image><image><image><image><image><image>'
|
|
||||||
```
|
|
||||||
|
|
||||||
Arr, 'twas easy after all!
|
Arr, 'twas easy after all!
|
||||||
|
|
||||||
## Is there an automated pipeline for chat?
|
## Is there an automated pipeline for chat?
|
||||||
|
|
||||||
Yes, there is! Our text generation pipelines support chat inputs, which makes it easy to use chat models. In the past,
|
Yes, there is! Our text generation pipelines support chat inputs, which makes it easy to use chat models. In the past,
|
||||||
we used to use a dedicated "ConversationalPipeline" class, but this has now been deprecated and its functionality
|
we used to use a dedicated "ConversationalPipeline" class, but this has now been deprecated and its functionality
|
||||||
has been merged into the [`TextGenerationPipeline`]. Let's try the `Zephyr` example again, but this time using
|
has been merged into the [`TextGenerationPipeline`]. Let's try the `Zephyr` example again, but this time using
|
||||||
a pipeline:
|
a pipeline:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -234,9 +187,9 @@ Can I ask a question?<|im_end|>
|
|||||||
```
|
```
|
||||||
|
|
||||||
Note that this time, we've added the tokens that indicate the start of a bot response. This ensures that when the model
|
Note that this time, we've added the tokens that indicate the start of a bot response. This ensures that when the model
|
||||||
generates text it will write a bot response instead of doing something unexpected, like continuing the user's
|
generates text it will write a bot response instead of doing something unexpected, like continuing the user's
|
||||||
message. Remember, chat models are still just language models - they're trained to continue text, and chat is just a
|
message. Remember, chat models are still just language models - they're trained to continue text, and chat is just a
|
||||||
special kind of text to them! You need to guide them with appropriate control tokens, so they know what they're
|
special kind of text to them! You need to guide them with appropriate control tokens, so they know what they're
|
||||||
supposed to be doing.
|
supposed to be doing.
|
||||||
|
|
||||||
Not all models require generation prompts. Some models, like LLaMA, don't have any
|
Not all models require generation prompts. Some models, like LLaMA, don't have any
|
||||||
@ -248,7 +201,7 @@ effect that `add_generation_prompt` has will depend on the template being used.
|
|||||||
When passing a list of messages to `apply_chat_template` or `TextGenerationPipeline`, you can choose
|
When passing a list of messages to `apply_chat_template` or `TextGenerationPipeline`, you can choose
|
||||||
to format the chat so the model will continue the final message in the chat instead of starting a new one. This is done
|
to format the chat so the model will continue the final message in the chat instead of starting a new one. This is done
|
||||||
by removing any end-of-sequence tokens that indicate the end of the final message, so that the model will simply
|
by removing any end-of-sequence tokens that indicate the end of the final message, so that the model will simply
|
||||||
extend the final message when it begins to generate text. This is useful for "prefilling" the model's response.
|
extend the final message when it begins to generate text. This is useful for "prefilling" the model's response.
|
||||||
|
|
||||||
Here's an example:
|
Here's an example:
|
||||||
|
|
||||||
@ -273,9 +226,9 @@ get an error if you try!
|
|||||||
<Tip>
|
<Tip>
|
||||||
|
|
||||||
The default behaviour of `TextGenerationPipeline` is to set `add_generation_prompt=True` so that it starts a new
|
The default behaviour of `TextGenerationPipeline` is to set `add_generation_prompt=True` so that it starts a new
|
||||||
message. However, if the final message in the input chat has the "assistant" role, it will assume that this message is
|
message. However, if the final message in the input chat has the "assistant" role, it will assume that this message is
|
||||||
a prefill and switch to `continue_final_message=True` instead, because most models do not support multiple
|
a prefill and switch to `continue_final_message=True` instead, because most models do not support multiple
|
||||||
consecutive assistant messages. You can override this behaviour by explicitly passing the `continue_final_message`
|
consecutive assistant messages. You can override this behaviour by explicitly passing the `continue_final_message`
|
||||||
argument when calling the pipeline.
|
argument when calling the pipeline.
|
||||||
|
|
||||||
</Tip>
|
</Tip>
|
||||||
@ -284,8 +237,8 @@ argument when calling the pipeline.
|
|||||||
|
|
||||||
Yes! This is a good way to ensure that the chat template matches the tokens the model sees during training.
|
Yes! This is a good way to ensure that the chat template matches the tokens the model sees during training.
|
||||||
We recommend that you apply the chat template as a preprocessing step for your dataset. After this, you
|
We recommend that you apply the chat template as a preprocessing step for your dataset. After this, you
|
||||||
can simply continue like any other language model training task. When training, you should usually set
|
can simply continue like any other language model training task. When training, you should usually set
|
||||||
`add_generation_prompt=False`, because the added tokens to prompt an assistant response will not be helpful during
|
`add_generation_prompt=False`, because the added tokens to prompt an assistant response will not be helpful during
|
||||||
training. Let's see an example:
|
training. Let's see an example:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -319,8 +272,8 @@ From here, just continue training like you would with a standard language modell
|
|||||||
|
|
||||||
<Tip>
|
<Tip>
|
||||||
|
|
||||||
By default, some tokenizers add special tokens like `<bos>` and `<eos>` to text they tokenize. Chat templates should
|
By default, some tokenizers add special tokens like `<bos>` and `<eos>` to text they tokenize. Chat templates should
|
||||||
already include all the special tokens they need, and so additional special tokens will often be incorrect or
|
already include all the special tokens they need, and so additional special tokens will often be incorrect or
|
||||||
duplicated, which will hurt model performance.
|
duplicated, which will hurt model performance.
|
||||||
|
|
||||||
Therefore, if you format text with `apply_chat_template(tokenize=False)`, you should set the argument
|
Therefore, if you format text with `apply_chat_template(tokenize=False)`, you should set the argument
|
||||||
@ -333,7 +286,7 @@ Therefore, if you format text with `apply_chat_template(tokenize=False)`, you sh
|
|||||||
The only argument that `apply_chat_template` requires is `messages`. However, you can pass any keyword
|
The only argument that `apply_chat_template` requires is `messages`. However, you can pass any keyword
|
||||||
argument to `apply_chat_template` and it will be accessible inside the template. This gives you a lot of freedom to use
|
argument to `apply_chat_template` and it will be accessible inside the template. This gives you a lot of freedom to use
|
||||||
chat templates for many things. There are no restrictions on the names or the format of these arguments - you can pass
|
chat templates for many things. There are no restrictions on the names or the format of these arguments - you can pass
|
||||||
strings, lists, dicts or whatever else you want.
|
strings, lists, dicts or whatever else you want.
|
||||||
|
|
||||||
That said, there are some common use-cases for these extra arguments,
|
That said, there are some common use-cases for these extra arguments,
|
||||||
such as passing tools for function calling, or documents for retrieval-augmented generation. In these common cases,
|
such as passing tools for function calling, or documents for retrieval-augmented generation. In these common cases,
|
||||||
@ -356,7 +309,7 @@ def current_time():
|
|||||||
def multiply(a: float, b: float):
|
def multiply(a: float, b: float):
|
||||||
"""
|
"""
|
||||||
A function that multiplies two numbers
|
A function that multiplies two numbers
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
a: The first number to multiply
|
a: The first number to multiply
|
||||||
b: The second number to multiply
|
b: The second number to multiply
|
||||||
@ -376,8 +329,8 @@ correctly as tools. Specifically, you should follow these rules:
|
|||||||
|
|
||||||
- The function should have a descriptive name
|
- The function should have a descriptive name
|
||||||
- Every argument must have a type hint
|
- Every argument must have a type hint
|
||||||
- The function must have a docstring in the standard Google style (in other words, an initial function description
|
- The function must have a docstring in the standard Google style (in other words, an initial function description
|
||||||
followed by an `Args:` block that describes the arguments, unless the function does not have any arguments.
|
followed by an `Args:` block that describes the arguments, unless the function does not have any arguments.
|
||||||
- Do not include types in the `Args:` block. In other words, write `a: The first number to multiply`, not
|
- Do not include types in the `Args:` block. In other words, write `a: The first number to multiply`, not
|
||||||
`a (int): The first number to multiply`. Type hints should go in the function header instead.
|
`a (int): The first number to multiply`. Type hints should go in the function header instead.
|
||||||
- The function can have a return type and a `Returns:` block in the docstring. However, these are optional
|
- The function can have a return type and a `Returns:` block in the docstring. However, these are optional
|
||||||
@ -419,7 +372,7 @@ Next, let's define a list of tools:
|
|||||||
def get_current_temperature(location: str, unit: str) -> float:
|
def get_current_temperature(location: str, unit: str) -> float:
|
||||||
"""
|
"""
|
||||||
Get the current temperature at a location.
|
Get the current temperature at a location.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
location: The location to get the temperature for, in the format "City, Country"
|
location: The location to get the temperature for, in the format "City, Country"
|
||||||
unit: The unit to return the temperature in. (choices: ["celsius", "fahrenheit"])
|
unit: The unit to return the temperature in. (choices: ["celsius", "fahrenheit"])
|
||||||
@ -431,7 +384,7 @@ def get_current_temperature(location: str, unit: str) -> float:
|
|||||||
def get_current_wind_speed(location: str) -> float:
|
def get_current_wind_speed(location: str) -> float:
|
||||||
"""
|
"""
|
||||||
Get the current wind speed in km/h at a given location.
|
Get the current wind speed in km/h at a given location.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
location: The location to get the temperature for, in the format "City, Country"
|
location: The location to get the temperature for, in the format "City, Country"
|
||||||
Returns:
|
Returns:
|
||||||
@ -476,8 +429,8 @@ the temperature in France should certainly be displayed in Celsius.
|
|||||||
|
|
||||||
The output format above is specific to the `Hermes-2-Pro` model we're using in this example. Other models may emit different
|
The output format above is specific to the `Hermes-2-Pro` model we're using in this example. Other models may emit different
|
||||||
tool call formats, and you may need to do some manual parsing at this step. For example, `Llama-3.1` models will emit
|
tool call formats, and you may need to do some manual parsing at this step. For example, `Llama-3.1` models will emit
|
||||||
slightly different JSON, with `parameters` instead of `arguments`. Regardless of the format the model outputs, you
|
slightly different JSON, with `parameters` instead of `arguments`. Regardless of the format the model outputs, you
|
||||||
should add the tool call to the conversation in the format below, with `tool_calls`, `function` and `arguments` keys.
|
should add the tool call to the conversation in the format below, with `tool_calls`, `function` and `arguments` keys.
|
||||||
|
|
||||||
</Tip>
|
</Tip>
|
||||||
|
|
||||||
@ -496,7 +449,7 @@ a dict, but in the OpenAI API it's a JSON string. Passing a string may cause err
|
|||||||
</Tip>
|
</Tip>
|
||||||
|
|
||||||
Now that we've added the tool call to the conversation, we can call the function and append the result to the
|
Now that we've added the tool call to the conversation, we can call the function and append the result to the
|
||||||
conversation. Since we're just using a dummy function for this example that always returns 22.0, we can just append
|
conversation. Since we're just using a dummy function for this example that always returns 22.0, we can just append
|
||||||
that result directly.
|
that result directly.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -507,7 +460,7 @@ messages.append({"role": "tool", "name": "get_current_temperature", "content": "
|
|||||||
|
|
||||||
Some model architectures, notably Mistral/Mixtral, also require a `tool_call_id` here, which should be
|
Some model architectures, notably Mistral/Mixtral, also require a `tool_call_id` here, which should be
|
||||||
9 randomly-generated alphanumeric characters, and assigned to the `id` key of the tool call
|
9 randomly-generated alphanumeric characters, and assigned to the `id` key of the tool call
|
||||||
dictionary. The same key should also be assigned to the `tool_call_id` key of the tool response dictionary below, so
|
dictionary. The same key should also be assigned to the `tool_call_id` key of the tool response dictionary below, so
|
||||||
that tool calls can be matched to tool responses. So, for Mistral/Mixtral models, the code above would be:
|
that tool calls can be matched to tool responses. So, for Mistral/Mixtral models, the code above would be:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -539,13 +492,13 @@ And we get:
|
|||||||
The current temperature in Paris, France is 22.0 ° Celsius.<|im_end|>
|
The current temperature in Paris, France is 22.0 ° Celsius.<|im_end|>
|
||||||
```
|
```
|
||||||
|
|
||||||
Although this was a simple demo with dummy tools and a single call, the same technique works with
|
Although this was a simple demo with dummy tools and a single call, the same technique works with
|
||||||
multiple real tools and longer conversations. This can be a powerful way to extend the capabilities of conversational
|
multiple real tools and longer conversations. This can be a powerful way to extend the capabilities of conversational
|
||||||
agents with real-time information, computational tools like calculators, or access to large databases.
|
agents with real-time information, computational tools like calculators, or access to large databases.
|
||||||
|
|
||||||
### Understanding tool schemas
|
### Understanding tool schemas
|
||||||
|
|
||||||
Each function you pass to the `tools` argument of `apply_chat_template` is converted into a
|
Each function you pass to the `tools` argument of `apply_chat_template` is converted into a
|
||||||
[JSON schema](https://json-schema.org/learn/getting-started-step-by-step). These schemas
|
[JSON schema](https://json-schema.org/learn/getting-started-step-by-step). These schemas
|
||||||
are then passed to the model chat template. In other words, tool-use models do not see your functions directly, and they
|
are then passed to the model chat template. In other words, tool-use models do not see your functions directly, and they
|
||||||
never see the actual code inside them. What they care about is the function **definitions** and the **arguments** they
|
never see the actual code inside them. What they care about is the function **definitions** and the **arguments** they
|
||||||
@ -554,7 +507,7 @@ to read their outputs, detect if they have requested to use a tool, pass their a
|
|||||||
return the response in the chat.
|
return the response in the chat.
|
||||||
|
|
||||||
Generating JSON schemas to pass to the template should be automatic and invisible as long as your functions
|
Generating JSON schemas to pass to the template should be automatic and invisible as long as your functions
|
||||||
follow the specification above, but if you encounter problems, or you simply want more control over the conversion,
|
follow the specification above, but if you encounter problems, or you simply want more control over the conversion,
|
||||||
you can handle the conversion manually. Here is an example of a manual schema conversion.
|
you can handle the conversion manually. Here is an example of a manual schema conversion.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -563,7 +516,7 @@ from transformers.utils import get_json_schema
|
|||||||
def multiply(a: float, b: float):
|
def multiply(a: float, b: float):
|
||||||
"""
|
"""
|
||||||
A function that multiplies two numbers
|
A function that multiplies two numbers
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
a: The first number to multiply
|
a: The first number to multiply
|
||||||
b: The second number to multiply
|
b: The second number to multiply
|
||||||
@ -578,33 +531,33 @@ This will yield:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "multiply",
|
"name": "multiply",
|
||||||
"description": "A function that multiplies two numbers",
|
"description": "A function that multiplies two numbers",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"a": {
|
"a": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"description": "The first number to multiply"
|
"description": "The first number to multiply"
|
||||||
},
|
},
|
||||||
"b": {
|
"b": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"description": "The second number to multiply"
|
"description": "The second number to multiply"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["a", "b"]
|
"required": ["a", "b"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If you wish, you can edit these schemas, or even write them from scratch yourself without using `get_json_schema` at
|
If you wish, you can edit these schemas, or even write them from scratch yourself without using `get_json_schema` at
|
||||||
all. JSON schemas can be passed directly to the `tools` argument of
|
all. JSON schemas can be passed directly to the `tools` argument of
|
||||||
`apply_chat_template` - this gives you a lot of power to define precise schemas for more complex functions. Be careful,
|
`apply_chat_template` - this gives you a lot of power to define precise schemas for more complex functions. Be careful,
|
||||||
though - the more complex your schemas, the more likely the model is to get confused when dealing with them! We
|
though - the more complex your schemas, the more likely the model is to get confused when dealing with them! We
|
||||||
recommend simple function signatures where possible, keeping arguments (and especially complex, nested arguments)
|
recommend simple function signatures where possible, keeping arguments (and especially complex, nested arguments)
|
||||||
to a minimum.
|
to a minimum.
|
||||||
|
|
||||||
Here is an example of defining schemas by hand, and passing them directly to `apply_chat_template`:
|
Here is an example of defining schemas by hand, and passing them directly to `apply_chat_template`:
|
||||||
@ -612,7 +565,7 @@ Here is an example of defining schemas by hand, and passing them directly to `ap
|
|||||||
```python
|
```python
|
||||||
# A simple function that takes no arguments
|
# A simple function that takes no arguments
|
||||||
current_time = {
|
current_time = {
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "current_time",
|
"name": "current_time",
|
||||||
"description": "Get the current local time as a string.",
|
"description": "Get the current local time as a string.",
|
||||||
@ -628,18 +581,18 @@ multiply = {
|
|||||||
'type': 'function',
|
'type': 'function',
|
||||||
'function': {
|
'function': {
|
||||||
'name': 'multiply',
|
'name': 'multiply',
|
||||||
'description': 'A function that multiplies two numbers',
|
'description': 'A function that multiplies two numbers',
|
||||||
'parameters': {
|
'parameters': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'a': {
|
'a': {
|
||||||
'type': 'number',
|
'type': 'number',
|
||||||
'description': 'The first number to multiply'
|
'description': 'The first number to multiply'
|
||||||
},
|
},
|
||||||
'b': {
|
'b': {
|
||||||
'type': 'number', 'description': 'The second number to multiply'
|
'type': 'number', 'description': 'The second number to multiply'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'required': ['a', 'b']
|
'required': ['a', 'b']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -654,7 +607,7 @@ model_input = tokenizer.apply_chat_template(
|
|||||||
## Advanced: Retrieval-augmented generation
|
## Advanced: Retrieval-augmented generation
|
||||||
|
|
||||||
"Retrieval-augmented generation" or "RAG" LLMs can search a corpus of documents for information before responding
|
"Retrieval-augmented generation" or "RAG" LLMs can search a corpus of documents for information before responding
|
||||||
to a query. This allows models to vastly expand their knowledge base beyond their limited context size. Our
|
to a query. This allows models to vastly expand their knowledge base beyond their limited context size. Our
|
||||||
recommendation for RAG models is that their template
|
recommendation for RAG models is that their template
|
||||||
should accept a `documents` argument. This should be a list of documents, where each "document"
|
should accept a `documents` argument. This should be a list of documents, where each "document"
|
||||||
is a single dict with `title` and `contents` keys, both of which are strings. Because this format is much simpler
|
is a single dict with `title` and `contents` keys, both of which are strings. Because this format is much simpler
|
||||||
@ -679,7 +632,7 @@ conversation = [
|
|||||||
# Define documents for retrieval-based generation
|
# Define documents for retrieval-based generation
|
||||||
documents = [
|
documents = [
|
||||||
{
|
{
|
||||||
"title": "The Moon: Our Age-Old Foe",
|
"title": "The Moon: Our Age-Old Foe",
|
||||||
"text": "Man has always dreamed of destroying the moon. In this essay, I shall..."
|
"text": "Man has always dreamed of destroying the moon. In this essay, I shall..."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -697,7 +650,7 @@ input_ids = tokenizer.apply_chat_template(
|
|||||||
add_generation_prompt=True,
|
add_generation_prompt=True,
|
||||||
return_tensors="pt").to(device)
|
return_tensors="pt").to(device)
|
||||||
|
|
||||||
# Generate a response
|
# Generate a response
|
||||||
gen_tokens = model.generate(
|
gen_tokens = model.generate(
|
||||||
input_ids,
|
input_ids,
|
||||||
max_new_tokens=100,
|
max_new_tokens=100,
|
||||||
@ -730,7 +683,7 @@ one is a little simplified from the actual one!
|
|||||||
|
|
||||||
```
|
```
|
||||||
{%- for message in messages %}
|
{%- for message in messages %}
|
||||||
{{- '<|' + message['role'] + '|>\n' }}
|
{{- '<|' + message['role'] + |>\n' }}
|
||||||
{{- message['content'] + eos_token }}
|
{{- message['content'] + eos_token }}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
{%- if add_generation_prompt %}
|
{%- if add_generation_prompt %}
|
||||||
@ -757,8 +710,8 @@ Effectively, the template does three things:
|
|||||||
an assistant response.
|
an assistant response.
|
||||||
|
|
||||||
This is a pretty simple template but Jinja gives you a lot of flexibility to do more complex things! Let's see a Jinja
|
This is a pretty simple template but Jinja gives you a lot of flexibility to do more complex things! Let's see a Jinja
|
||||||
template that can format inputs similarly to the way LLaMA formats them (note that the real LLaMA template includes
|
template that can format inputs similarly to the way LLaMA formats them (note that the real LLaMA template includes
|
||||||
handling for default system messages and slightly different system message handling in general - don't use this one
|
handling for default system messages and slightly different system message handling in general - don't use this one
|
||||||
in your actual code!)
|
in your actual code!)
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -781,7 +734,7 @@ distinguishable to the model because of the tokens they're wrapped in.
|
|||||||
|
|
||||||
### How do I create a chat template?
|
### How do I create a chat template?
|
||||||
|
|
||||||
Simple, just write a jinja template and set `tokenizer.chat_template`. You may find it easier to start with an
|
Simple, just write a jinja template and set `tokenizer.chat_template`. You may find it easier to start with an
|
||||||
existing template from another model and simply edit it for your needs! For example, we could take the LLaMA template
|
existing template from another model and simply edit it for your needs! For example, we could take the LLaMA template
|
||||||
above and add "[ASST]" and "[/ASST]" to assistant messages:
|
above and add "[ASST]" and "[/ASST]" to assistant messages:
|
||||||
|
|
||||||
@ -809,13 +762,13 @@ tokenizer.chat_template = template # Set the new template
|
|||||||
tokenizer.push_to_hub("model_name") # Upload your new template to the Hub!
|
tokenizer.push_to_hub("model_name") # Upload your new template to the Hub!
|
||||||
```
|
```
|
||||||
|
|
||||||
The method [`~PreTrainedTokenizer.apply_chat_template`] which uses your chat template is called by the [`TextGenerationPipeline`] class, so
|
The method [`~PreTrainedTokenizer.apply_chat_template`] which uses your chat template is called by the [`TextGenerationPipeline`] class, so
|
||||||
once you set the correct chat template, your model will automatically become compatible with [`TextGenerationPipeline`].
|
once you set the correct chat template, your model will automatically become compatible with [`TextGenerationPipeline`].
|
||||||
|
|
||||||
<Tip>
|
<Tip>
|
||||||
If you're fine-tuning a model for chat, in addition to setting a chat template, you should probably add any new chat
|
If you're fine-tuning a model for chat, in addition to setting a chat template, you should probably add any new chat
|
||||||
control tokens as special tokens in the tokenizer. Special tokens are never split,
|
control tokens as special tokens in the tokenizer. Special tokens are never split,
|
||||||
ensuring that your control tokens are always handled as single tokens rather than being tokenized in pieces. You
|
ensuring that your control tokens are always handled as single tokens rather than being tokenized in pieces. You
|
||||||
should also set the tokenizer's `eos_token` attribute to the token that marks the end of assistant generations in your
|
should also set the tokenizer's `eos_token` attribute to the token that marks the end of assistant generations in your
|
||||||
template. This will ensure that text generation tools can correctly figure out when to stop generating text.
|
template. This will ensure that text generation tools can correctly figure out when to stop generating text.
|
||||||
</Tip>
|
</Tip>
|
||||||
@ -843,13 +796,13 @@ trying to put it all in a single template where possible!
|
|||||||
|
|
||||||
When setting the template for a model that's already been trained for chat, you should ensure that the template
|
When setting the template for a model that's already been trained for chat, you should ensure that the template
|
||||||
exactly matches the message formatting that the model saw during training, or else you will probably experience
|
exactly matches the message formatting that the model saw during training, or else you will probably experience
|
||||||
performance degradation. This is true even if you're training the model further - you will probably get the best
|
performance degradation. This is true even if you're training the model further - you will probably get the best
|
||||||
performance if you keep the chat tokens constant. This is very analogous to tokenization - you generally get the
|
performance if you keep the chat tokens constant. This is very analogous to tokenization - you generally get the
|
||||||
best performance for inference or fine-tuning when you precisely match the tokenization used during training.
|
best performance for inference or fine-tuning when you precisely match the tokenization used during training.
|
||||||
|
|
||||||
If you're training a model from scratch, or fine-tuning a base language model for chat, on the other hand,
|
If you're training a model from scratch, or fine-tuning a base language model for chat, on the other hand,
|
||||||
you have a lot of freedom to choose an appropriate template! LLMs are smart enough to learn to handle lots of different
|
you have a lot of freedom to choose an appropriate template! LLMs are smart enough to learn to handle lots of different
|
||||||
input formats. One popular choice is the `ChatML` format, and this is a good, flexible choice for many use-cases.
|
input formats. One popular choice is the `ChatML` format, and this is a good, flexible choice for many use-cases.
|
||||||
It looks like this:
|
It looks like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -895,7 +848,7 @@ Once the attribute is set, that's it, you're done! `tokenizer.apply_chat_templat
|
|||||||
model, which means it is also automatically supported in places like `TextGenerationPipeline`!
|
model, which means it is also automatically supported in places like `TextGenerationPipeline`!
|
||||||
|
|
||||||
By ensuring that models have this attribute, we can make sure that the whole community gets to use the full power of
|
By ensuring that models have this attribute, we can make sure that the whole community gets to use the full power of
|
||||||
open-source models. Formatting mismatches have been haunting the field and silently harming performance for too long -
|
open-source models. Formatting mismatches have been haunting the field and silently harming performance for too long -
|
||||||
it's time to put an end to them!
|
it's time to put an end to them!
|
||||||
|
|
||||||
## Advanced: Template writing tips
|
## Advanced: Template writing tips
|
||||||
@ -903,17 +856,17 @@ it's time to put an end to them!
|
|||||||
<Tip>
|
<Tip>
|
||||||
|
|
||||||
The easiest way to get started with writing Jinja templates is to take a look at some existing ones. You can use
|
The easiest way to get started with writing Jinja templates is to take a look at some existing ones. You can use
|
||||||
`print(tokenizer.chat_template)` for any chat model to see what template it's using. In general, models that support tool use have
|
`print(tokenizer.chat_template)` for any chat model to see what template it's using. In general, models that support tool use have
|
||||||
much more complex templates than other models - so when you're just getting started, they're probably a bad example
|
much more complex templates than other models - so when you're just getting started, they're probably a bad example
|
||||||
to learn from! You can also take a look at the
|
to learn from! You can also take a look at the
|
||||||
[Jinja documentation](https://jinja.palletsprojects.com/en/3.1.x/templates/#synopsis) for details
|
[Jinja documentation](https://jinja.palletsprojects.com/en/3.1.x/templates/#synopsis) for details
|
||||||
of general Jinja formatting and syntax.
|
of general Jinja formatting and syntax.
|
||||||
|
|
||||||
</Tip>
|
</Tip>
|
||||||
|
|
||||||
Jinja templates in `transformers` are identical to Jinja templates elsewhere. The main thing to know is that
|
Jinja templates in `transformers` are identical to Jinja templates elsewhere. The main thing to know is that
|
||||||
the conversation history will be accessible inside your template as a variable called `messages`.
|
the conversation history will be accessible inside your template as a variable called `messages`.
|
||||||
You will be able to access `messages` in your template just like you can in Python, which means you can loop over
|
You will be able to access `messages` in your template just like you can in Python, which means you can loop over
|
||||||
it with `{% for message in messages %}` or access individual messages with `{{ messages[0] }}`, for example.
|
it with `{% for message in messages %}` or access individual messages with `{{ messages[0] }}`, for example.
|
||||||
|
|
||||||
You can also use the following tips to write clean, efficient Jinja templates:
|
You can also use the following tips to write clean, efficient Jinja templates:
|
||||||
@ -943,7 +896,7 @@ and indentation may end up being included in the output, which is probably not w
|
|||||||
|
|
||||||
### Special variables
|
### Special variables
|
||||||
|
|
||||||
Inside your template, you will have access several special variables. The most important of these is `messages`,
|
Inside your template, you will have access several special variables. The most important of these is `messages`,
|
||||||
which contains the chat history as a list of message dicts. However, there are several others. Not every
|
which contains the chat history as a list of message dicts. However, there are several others. Not every
|
||||||
variable will be used in every template. The most common other variables are:
|
variable will be used in every template. The most common other variables are:
|
||||||
|
|
||||||
@ -977,7 +930,7 @@ There are multiple implementations of Jinja in various languages. They generally
|
|||||||
but a key difference is that when you're writing a template in Python you can use Python methods, such as
|
but a key difference is that when you're writing a template in Python you can use Python methods, such as
|
||||||
`.lower()` on strings or `.items()` on dicts. This will break if someone tries to use your template on a non-Python
|
`.lower()` on strings or `.items()` on dicts. This will break if someone tries to use your template on a non-Python
|
||||||
implementation of Jinja. Non-Python implementations are particularly common in deployment environments, where JS
|
implementation of Jinja. Non-Python implementations are particularly common in deployment environments, where JS
|
||||||
and Rust are very popular.
|
and Rust are very popular.
|
||||||
|
|
||||||
Don't panic, though! There are a few easy changes you can make to your templates to ensure they're compatible across
|
Don't panic, though! There are a few easy changes you can make to your templates to ensure they're compatible across
|
||||||
all implementations of Jinja:
|
all implementations of Jinja:
|
||||||
@ -990,40 +943,11 @@ all implementations of Jinja:
|
|||||||
- Directly rendering a dict or list may give different results in other implementations (for example, string entries
|
- Directly rendering a dict or list may give different results in other implementations (for example, string entries
|
||||||
might change from single-quoted to double-quoted). Adding the `tojson` filter can help to ensure consistency here.
|
might change from single-quoted to double-quoted). Adding the `tojson` filter can help to ensure consistency here.
|
||||||
|
|
||||||
### Writing generation prompts
|
|
||||||
|
|
||||||
We mentioned above that `add_generation_prompt` is a special variable that will be accessible inside your template,
|
|
||||||
and is controlled by the user setting the `add_generation_prompt` flag. If your model expects a header for
|
|
||||||
assistant messages, then your template must support adding the header when `add_generation_prompt` is set.
|
|
||||||
|
|
||||||
Here is an example of a template that formats messages ChatML-style, with generation prompt support:
|
|
||||||
|
|
||||||
```text
|
|
||||||
{{- bos_token }}
|
|
||||||
{%- for message in messages %}
|
|
||||||
{{- '<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n' }}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- if add_generation_prompt %}
|
|
||||||
{{- '<|im_start|>assistant\n' }}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
|
|
||||||
The exact content of the assistant header will depend on your specific model, but it should always be **the string
|
|
||||||
that represents the start of an assistant message**, so that if the user applies your template with
|
|
||||||
`add_generation_prompt=True` and then generates text, the model will write an assistant response. Also note that some
|
|
||||||
models do not need a generation prompt, because assistant messages always begin immediately after user messages.
|
|
||||||
This is particularly common for LLaMA and Mistral models, where assistant messages begin immediately after the `[/INST]`
|
|
||||||
token that ends user messages. In these cases, the template can ignore the `add_generation_prompt` flag.
|
|
||||||
|
|
||||||
Generation prompts are important! If your model requires a generation prompt but it is not set in the template, then
|
|
||||||
model generations will likely be severely degraded, or the model may display unusual behaviour like continuing
|
|
||||||
the final user message!
|
|
||||||
|
|
||||||
### Writing and debugging larger templates
|
### Writing and debugging larger templates
|
||||||
|
|
||||||
When this feature was introduced, most templates were quite small, the Jinja equivalent of a "one-liner" script.
|
When this feature was introduced, most templates were quite small, the Jinja equivalent of a "one-liner" script.
|
||||||
However, with new models and features like tool-use and RAG, some templates can be 100 lines long or more. When
|
However, with new models and features like tool-use and RAG, some templates can be 100 lines long or more. When
|
||||||
writing templates like these, it's a good idea to write them in a separate file, using a text editor. You can easily
|
writing templates like these, it's a good idea to write them in a separate file, using a text editor. You can easily
|
||||||
extract a chat template to a file:
|
extract a chat template to a file:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -1038,129 +962,4 @@ tokenizer.chat_template = open("template.jinja").read()
|
|||||||
|
|
||||||
As an added bonus, when you write a long, multi-line template in a separate file, line numbers in that file will
|
As an added bonus, when you write a long, multi-line template in a separate file, line numbers in that file will
|
||||||
exactly correspond to line numbers in template parsing or execution errors. This will make it much easier to
|
exactly correspond to line numbers in template parsing or execution errors. This will make it much easier to
|
||||||
identify the source of issues.
|
identify the source of issues.
|
||||||
|
|
||||||
### Writing templates for tools
|
|
||||||
|
|
||||||
Although chat templates do not enforce a specific API for tools (or for anything, really), we recommend
|
|
||||||
template authors try to stick to a standard API where possible. The whole point of chat templates is to allow code
|
|
||||||
to be transferable across models, so deviating from the standard tools API means users will have to write
|
|
||||||
custom code to use tools with your model. Sometimes it's unavoidable, but often with clever templating you can
|
|
||||||
make the standard API work!
|
|
||||||
|
|
||||||
Below, we'll list the elements of the standard API, and give tips on writing templates that will work well with it.
|
|
||||||
|
|
||||||
#### Tool definitions
|
|
||||||
|
|
||||||
Your template should expect that the variable `tools` will either be null (if no tools are passed), or is a list
|
|
||||||
of JSON schema dicts. Our chat template methods allow users to pass tools as either JSON schema or Python functions, but when
|
|
||||||
functions are passed, we automatically generate JSON schema and pass that to your template. As a result, the
|
|
||||||
`tools` variable that your template receives will always be a list of JSON schema. Here is
|
|
||||||
a sample tool JSON schema:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "multiply",
|
|
||||||
"description": "A function that multiplies two numbers",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"a": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "The first number to multiply"
|
|
||||||
},
|
|
||||||
"b": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "The second number to multiply"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["a", "b"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And here is some example code for handling tools in your chat template. Remember, this is just an example for a
|
|
||||||
specific format - your model will probably need different formatting!
|
|
||||||
|
|
||||||
```text
|
|
||||||
{%- if tools %}
|
|
||||||
{%- for tool in tools %}
|
|
||||||
{{- '<tool>' + tool['function']['name'] + '\n' }}
|
|
||||||
{%- for argument in tool['function']['parameters']['properties'] %}
|
|
||||||
{{- argument + ': ' + tool['function']['parameters']['properties'][argument]['description'] + '\n' }}
|
|
||||||
{%- endfor %}
|
|
||||||
{{- '\n</tool>' }}
|
|
||||||
{%- endif %}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
|
|
||||||
The specific tokens and tool descriptions your template renders should of course be chosen to match the ones your model
|
|
||||||
was trained with. There is no requirement that your **model** understands JSON schema input, only that your template can translate
|
|
||||||
JSON schema into your model's format. For example, [Command-R](https://huggingface.co/CohereForAI/c4ai-command-r-plus-08-2024)
|
|
||||||
was trained with tools defined using Python function headers, but the Command-R tool template accepts JSON schema,
|
|
||||||
converts types internally and renders the input tools as Python headers. You can do a lot with templates!
|
|
||||||
|
|
||||||
#### Tool calls
|
|
||||||
|
|
||||||
Tool calls, if present, will be a list attached to a message with the "assistant" role. Note that `tool_calls` is
|
|
||||||
always a list, even though most tool-calling models only support single tool calls at a time, which means
|
|
||||||
the list will usually only have a single element. Here is a sample message dict containing a tool call:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"tool_calls": [
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "multiply",
|
|
||||||
"arguments": {
|
|
||||||
"a": 5,
|
|
||||||
"b": 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And a common pattern for handling them would be something like this:
|
|
||||||
|
|
||||||
```text
|
|
||||||
{%- if message['role'] == 'assistant' and 'tool_calls' in message %}
|
|
||||||
{%- for tool_call in message['tool_calls'] %}
|
|
||||||
{{- '<tool_call>' + tool_call['function']['name'] + '\n' + tool_call['function']['arguments']|tojson + '\n</tool_call>' }}
|
|
||||||
{%- endif %}
|
|
||||||
{%- endfor %}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
|
|
||||||
Again, you should render the tool call with the formatting and special tokens that your model expects.
|
|
||||||
|
|
||||||
#### Tool responses
|
|
||||||
|
|
||||||
Tool responses have a simple format: They are a message dict with the "tool" role, a "name" key giving the name
|
|
||||||
of the called function, and a "content" key containing the result of the tool call. Here is a sample tool response:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"role": "tool",
|
|
||||||
"name": "multiply",
|
|
||||||
"content": "30"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You don't need to use all of the keys in the tool response. For example, if your model doesn't expect the function
|
|
||||||
name to be included in the tool response, then rendering it can be as simple as:
|
|
||||||
|
|
||||||
```text
|
|
||||||
{%- if message['role'] == 'tool' %}
|
|
||||||
{{- "<tool_result>" + message['content'] + "</tool_result>" }}
|
|
||||||
{%- endif %}
|
|
||||||
```
|
|
||||||
|
|
||||||
Again, remember that the actual formatting and special tokens are model-specific - you should take a lot of care
|
|
||||||
to ensure that tokens, whitespace and everything else exactly match the format your model was trained with!
|
|
||||||
@ -586,20 +586,6 @@ You can choose the communication data type by setting the `communication_data_ty
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Universal Checkpointing
|
|
||||||
|
|
||||||
[Universal Checkpointing](https://www.deepspeed.ai/tutorials/universal-checkpointing) is an efficient and flexible feature for saving and loading model checkpoints. It enables seamless model training continuation and fine-tuning across different model architectures, parallelism techniques, and training configurations.
|
|
||||||
|
|
||||||
Resume training with a universal checkpoint by setting [load_universal](https://www.deepspeed.ai/docs/config-json/#checkpoint-options) to `true` in the config file.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
{
|
|
||||||
"checkpoint": {
|
|
||||||
"load_universal": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
DeepSpeed can be deployed by different launchers such as [torchrun](https://pytorch.org/docs/stable/elastic/run.html), the `deepspeed` launcher, or [Accelerate](https://huggingface.co/docs/accelerate/basic_tutorials/launch#using-accelerate-launch). To deploy, add `--deepspeed ds_config.json` to the [`Trainer`] command line. It’s recommended to use DeepSpeed’s [`add_config_arguments`](https://deepspeed.readthedocs.io/en/latest/initialize.html#argument-parsing) utility to add any necessary command line arguments to your code.
|
DeepSpeed can be deployed by different launchers such as [torchrun](https://pytorch.org/docs/stable/elastic/run.html), the `deepspeed` launcher, or [Accelerate](https://huggingface.co/docs/accelerate/basic_tutorials/launch#using-accelerate-launch). To deploy, add `--deepspeed ds_config.json` to the [`Trainer`] command line. It’s recommended to use DeepSpeed’s [`add_config_arguments`](https://deepspeed.readthedocs.io/en/latest/initialize.html#argument-parsing) utility to add any necessary command line arguments to your code.
|
||||||
|
|||||||
@ -58,7 +58,7 @@ Otherwise, you can choose a size-based wrapping policy where FSDP is applied to
|
|||||||
|
|
||||||
### Checkpointing
|
### Checkpointing
|
||||||
|
|
||||||
Intermediate checkpoints should be saved with `fsdp_state_dict_type: SHARDED_STATE_DICT` because saving the full state dict with CPU offloading on rank 0 takes a lot of time and often results in `NCCL Timeout` errors due to indefinite hanging during broadcasting. You can resume training with the sharded state dicts with the [`~accelerate.Accelerator.load_state`] method.
|
Intermediate checkpoints should be saved with `fsdp_state_dict_type: SHARDED_STATE_DICT` because saving the full state dict with CPU offloading on rank 0 takes a lot of time and often results in `NCCL Timeout` errors due to indefinite hanging during broadcasting. You can resume training with the sharded state dicts with the [`~accelerate.Accelerator.load_state`]` method.
|
||||||
|
|
||||||
```py
|
```py
|
||||||
# directory containing checkpoints
|
# directory containing checkpoints
|
||||||
|
|||||||
@ -41,13 +41,6 @@ This guide describes:
|
|||||||
* common decoding strategies and their main parameters
|
* common decoding strategies and their main parameters
|
||||||
* saving and sharing custom generation configurations with your fine-tuned model on 🤗 Hub
|
* saving and sharing custom generation configurations with your fine-tuned model on 🤗 Hub
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
`generate()` is a critical component of our [chat CLI](quicktour#chat-with-text-generation-models).
|
|
||||||
You can apply the learnings of this guide there as well.
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
## Default text generation configuration
|
## Default text generation configuration
|
||||||
|
|
||||||
A decoding strategy for a model is defined in its generation configuration. When using pre-trained models for inference
|
A decoding strategy for a model is defined in its generation configuration. When using pre-trained models for inference
|
||||||
@ -103,12 +96,6 @@ distribution over the entire vocabulary with various strategy-specific adjustmen
|
|||||||
the decoding strategies that support multiple sequence candidates, e.g. variations of beam search and sampling. Decoding
|
the decoding strategies that support multiple sequence candidates, e.g. variations of beam search and sampling. Decoding
|
||||||
strategies like greedy search and contrastive search return a single output sequence.
|
strategies like greedy search and contrastive search return a single output sequence.
|
||||||
|
|
||||||
It is also possible to extend `generate()` with external libraries or handcrafted code. The `logits_processor` argument
|
|
||||||
allows you to pass custom [`LogitsProcessor`] instances, allowing you to manipulate the next token probability
|
|
||||||
distributions. Likewise, the `stopping_criteria` argument lets you set custom [`StoppingCriteria`] to stop text generation.
|
|
||||||
The [`logits-processor-zoo`](https://github.com/NVIDIA/logits-processor-zoo) library contains examples of external
|
|
||||||
`generate()`-compatible extensions.
|
|
||||||
|
|
||||||
## Save a custom decoding strategy with your model
|
## Save a custom decoding strategy with your model
|
||||||
|
|
||||||
If you would like to share your fine-tuned model with a specific generation configuration, you can:
|
If you would like to share your fine-tuned model with a specific generation configuration, you can:
|
||||||
@ -231,7 +218,7 @@ to check if the text is machine-generated (outputs `True` for machine-generated
|
|||||||
>>> detector = WatermarkDetector(model_config=model.config, device="cpu", watermarking_config=watermarking_config)
|
>>> detector = WatermarkDetector(model_config=model.config, device="cpu", watermarking_config=watermarking_config)
|
||||||
>>> detection_out = detector(out, return_dict=True)
|
>>> detection_out = detector(out, return_dict=True)
|
||||||
>>> detection_out.prediction
|
>>> detection_out.prediction
|
||||||
array([ True, True])
|
array([True, True])
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -269,7 +256,7 @@ dimension you can act upon, in addition to selecting a decoding strategy. Popula
|
|||||||
>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)
|
>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)
|
||||||
>>> outputs = model.generate(**inputs)
|
>>> outputs = model.generate(**inputs)
|
||||||
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||||
['I look forward to seeing you all again!\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n']
|
['I look forward to seeing you all again!\n\n\n\n\n\n\n\n\n\n\n']
|
||||||
```
|
```
|
||||||
|
|
||||||
### Contrastive search
|
### Contrastive search
|
||||||
@ -416,15 +403,15 @@ culture, and they allow us to design the'
|
|||||||
|
|
||||||
This guide illustrates the main parameters that enable various decoding strategies. More advanced parameters exist for the
|
This guide illustrates the main parameters that enable various decoding strategies. More advanced parameters exist for the
|
||||||
[`generate`] method, which gives you even further control over the [`generate`] method's behavior.
|
[`generate`] method, which gives you even further control over the [`generate`] method's behavior.
|
||||||
For the complete list of the available parameters, refer to the [API documentation](./main_classes/text_generation).
|
For the complete list of the available parameters, refer to the [API documentation](./main_classes/text_generation.md).
|
||||||
|
|
||||||
### Speculative Decoding
|
### Speculative Decoding
|
||||||
|
|
||||||
Speculative decoding (also known as assisted decoding) is a modification of the decoding strategies above, that uses an
|
Speculative decoding (also known as assisted decoding) is a modification of the decoding strategies above, that uses an
|
||||||
assistant model (ideally a much smaller one), to generate a few candidate tokens. The main model then validates the candidate
|
assistant model (ideally a much smaller one) with the same tokenizer, to generate a few candidate tokens. The main
|
||||||
tokens in a single forward pass, which speeds up the decoding process. If `do_sample=True`, then the token validation with
|
model then validates the candidate tokens in a single forward pass, which speeds up the decoding process. If
|
||||||
resampling introduced in the [speculative decoding paper](https://arxiv.org/pdf/2211.17192.pdf) is used.
|
`do_sample=True`, then the token validation with resampling introduced in the
|
||||||
Assisted decoding assumes the main and assistant models have the same tokenizer, otherwise, see Universal Assisted Decoding below.
|
[speculative decoding paper](https://arxiv.org/pdf/2211.17192.pdf) is used.
|
||||||
|
|
||||||
Currently, only greedy search and sampling are supported with assisted decoding, and assisted decoding doesn't support batched inputs.
|
Currently, only greedy search and sampling are supported with assisted decoding, and assisted decoding doesn't support batched inputs.
|
||||||
To learn more about assisted decoding, check [this blog post](https://huggingface.co/blog/assisted-generation).
|
To learn more about assisted decoding, check [this blog post](https://huggingface.co/blog/assisted-generation).
|
||||||
@ -445,31 +432,9 @@ To enable assisted decoding, set the `assistant_model` argument with a model.
|
|||||||
>>> assistant_model = AutoModelForCausalLM.from_pretrained(assistant_checkpoint)
|
>>> assistant_model = AutoModelForCausalLM.from_pretrained(assistant_checkpoint)
|
||||||
>>> outputs = model.generate(**inputs, assistant_model=assistant_model)
|
>>> outputs = model.generate(**inputs, assistant_model=assistant_model)
|
||||||
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||||
['Alice and Bob are sitting in a bar. Alice is drinking a beer and Bob is drinking a glass of wine.']
|
['Alice and Bob are sitting in a bar. Alice is drinking a beer and Bob is drinking a']
|
||||||
```
|
```
|
||||||
|
|
||||||
<Tip>
|
|
||||||
|
|
||||||
If you're using a `pipeline` object, all you need to do is to pass the assistant checkpoint under `assistant_model`
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import pipeline
|
|
||||||
>>> import torch
|
|
||||||
|
|
||||||
>>> pipe = pipeline(
|
|
||||||
... "text-generation",
|
|
||||||
... model="meta-llama/Llama-3.1-8B",
|
|
||||||
... assistant_model="meta-llama/Llama-3.2-1B", # This extra line is all that's needed, also works with UAD
|
|
||||||
... torch_dtype=torch.bfloat16
|
|
||||||
... )
|
|
||||||
>>> pipe_output = pipe("Once upon a time, ", max_new_tokens=50, do_sample=False)
|
|
||||||
>>> pipe_output[0]["generated_text"]
|
|
||||||
'Once upon a time, 3D printing was a niche technology that was only'
|
|
||||||
```
|
|
||||||
|
|
||||||
</Tip>
|
|
||||||
|
|
||||||
|
|
||||||
When using assisted decoding with sampling methods, you can use the `temperature` argument to control the randomness,
|
When using assisted decoding with sampling methods, you can use the `temperature` argument to control the randomness,
|
||||||
just like in multinomial sampling. However, in assisted decoding, reducing the temperature may help improve the latency.
|
just like in multinomial sampling. However, in assisted decoding, reducing the temperature may help improve the latency.
|
||||||
|
|
||||||
@ -488,68 +453,11 @@ just like in multinomial sampling. However, in assisted decoding, reducing the t
|
|||||||
>>> assistant_model = AutoModelForCausalLM.from_pretrained(assistant_checkpoint)
|
>>> assistant_model = AutoModelForCausalLM.from_pretrained(assistant_checkpoint)
|
||||||
>>> outputs = model.generate(**inputs, assistant_model=assistant_model, do_sample=True, temperature=0.5)
|
>>> outputs = model.generate(**inputs, assistant_model=assistant_model, do_sample=True, temperature=0.5)
|
||||||
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||||
['Alice and Bob are two people who are very different, but they are both very good at what they do. Alice']
|
['Alice and Bob, a couple of friends of mine, who are both in the same office as']
|
||||||
```
|
```
|
||||||
|
|
||||||
We recommend to install `scikit-learn` library to enhance the candidate generation strategy and achieve additional speedup.
|
|
||||||
|
|
||||||
#### Universal Assisted Decoding
|
|
||||||
|
|
||||||
Universal Assisted Decoding (UAD) adds support for main and assistant models with different tokenizers.
|
|
||||||
To use it, simply pass the tokenizers using the `tokenizer` and `assistant_tokenizer` arguments (see below).
|
|
||||||
Internally, the main model input tokens are re-encoded into assistant model tokens, then candidate tokens are generated in the assistant encoding, which are
|
|
||||||
in turn re-encoded into main model candidate tokens. Validation then proceeds as explained above.
|
|
||||||
The re-encoding steps involve decoding token ids into text and then encoding the text using a different tokenizer.
|
|
||||||
Since re-encoding the tokens may result in tokenization discrepancies, UAD finds the longest common subsequence between the source and target encodings,
|
|
||||||
to ensure the new tokens include the correct prompt suffix.
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
||||||
|
|
||||||
>>> prompt = "Alice and Bob"
|
|
||||||
>>> checkpoint = "google/gemma-2-9b"
|
|
||||||
>>> assistant_checkpoint = "double7/vicuna-68m"
|
|
||||||
|
|
||||||
>>> assistant_tokenizer = AutoTokenizer.from_pretrained(assistant_checkpoint)
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
|
||||||
>>> inputs = tokenizer(prompt, return_tensors="pt")
|
|
||||||
|
|
||||||
>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)
|
|
||||||
>>> assistant_model = AutoModelForCausalLM.from_pretrained(assistant_checkpoint)
|
|
||||||
>>> outputs = model.generate(**inputs, assistant_model=assistant_model, tokenizer=tokenizer, assistant_tokenizer=assistant_tokenizer)
|
|
||||||
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
|
||||||
['Alice and Bob are playing a game. Alice has a set of $n$ integers $a_1, a']
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Prompt Lookup
|
|
||||||
|
|
||||||
Alternatively, you can also set the `prompt_lookup_num_tokens` to trigger n-gram based assisted decoding, as opposed
|
Alternatively, you can also set the `prompt_lookup_num_tokens` to trigger n-gram based assisted decoding, as opposed
|
||||||
to model based assisted decoding. You can read more about it [here](https://twitter.com/joao_gante/status/1747322413006643259).
|
to model based assisted decoding. You can read more about it [here](https://twitter.com/joao_gante/status/1747322413006643259).
|
||||||
|
|
||||||
#### Self-Speculative Decoding
|
|
||||||
|
|
||||||
An LLM can be trained to also use its language modeling head with earlier hidden states as input, effectively
|
|
||||||
skipping layers to yield a lower-quality output -- a technique called early exiting.
|
|
||||||
We use the lower-quality early exit output as an assistant output, and apply self-speculation to fix the output using the remaining layers. The final generation of that self-speculative solution is the same (or has the same distribution) as the original model's generation.
|
|
||||||
If the model you're using was trained to do early exit, you can pass
|
|
||||||
`assistant_early_exit` (integer). In this case, the assistant model will be the same model but exiting early, hence the
|
|
||||||
"self-speculative" name. Because the assistant model is a portion of the target model, caches and weights can be shared, which results in lower memory requirements. As in other assisted generation methods, the final generated result has the same quality as if no assistant had been used.
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
||||||
|
|
||||||
>>> prompt = "Alice and Bob"
|
|
||||||
>>> checkpoint = "facebook/layerskip-llama3.2-1B"
|
|
||||||
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
|
||||||
>>> inputs = tokenizer(prompt, return_tensors="pt")
|
|
||||||
|
|
||||||
>>> model = AutoModelForCausalLM.from_pretrained(checkpoint)
|
|
||||||
>>> outputs = model.generate(**inputs, assistant_early_exit=4, do_sample=False, max_new_tokens=20)
|
|
||||||
>>> tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
|
||||||
['Alice and Bob are playing a game. Alice has a set of $n$ integers $a_1, a']
|
|
||||||
```
|
|
||||||
|
|
||||||
### DoLa Decoding
|
### DoLa Decoding
|
||||||
|
|
||||||
**D**ecoding by C**o**ntrasting **La**yers (DoLa) is a contrastive decoding strategy to improve the factuality and reduce the
|
**D**ecoding by C**o**ntrasting **La**yers (DoLa) is a contrastive decoding strategy to improve the factuality and reduce the
|
||||||
@ -569,11 +477,11 @@ See the following examples for DoLa decoding with the 32-layer LLaMA-7B model.
|
|||||||
```python
|
```python
|
||||||
>>> from transformers import AutoTokenizer, AutoModelForCausalLM, set_seed
|
>>> from transformers import AutoTokenizer, AutoModelForCausalLM, set_seed
|
||||||
>>> import torch
|
>>> import torch
|
||||||
>>> from accelerate.test_utils.testing import get_backend
|
|
||||||
|
|
||||||
>>> device, _, _ = get_backend() # automatically detects the underlying device type (CUDA, CPU, XPU, MPS, etc.)
|
|
||||||
>>> tokenizer = AutoTokenizer.from_pretrained("huggyllama/llama-7b")
|
>>> tokenizer = AutoTokenizer.from_pretrained("huggyllama/llama-7b")
|
||||||
>>> model = AutoModelForCausalLM.from_pretrained("huggyllama/llama-7b", torch_dtype=torch.float16).to(device)
|
>>> model = AutoModelForCausalLM.from_pretrained("huggyllama/llama-7b", torch_dtype=torch.float16)
|
||||||
|
>>> device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||||
|
>>> model.to(device)
|
||||||
>>> set_seed(42)
|
>>> set_seed(42)
|
||||||
|
|
||||||
>>> text = "On what date was the Declaration of Independence officially signed?"
|
>>> text = "On what date was the Declaration of Independence officially signed?"
|
||||||
@ -592,7 +500,7 @@ See the following examples for DoLa decoding with the 32-layer LLaMA-7B model.
|
|||||||
# DoLa decoding with contrasting specific layers (layers 28 and 30)
|
# DoLa decoding with contrasting specific layers (layers 28 and 30)
|
||||||
>>> dola_custom_output = model.generate(**inputs, do_sample=False, max_new_tokens=50, dola_layers=[28,30], repetition_penalty=1.2)
|
>>> dola_custom_output = model.generate(**inputs, do_sample=False, max_new_tokens=50, dola_layers=[28,30], repetition_penalty=1.2)
|
||||||
>>> tokenizer.batch_decode(dola_custom_output[:, inputs.input_ids.shape[-1]:], skip_special_tokens=True)
|
>>> tokenizer.batch_decode(dola_custom_output[:, inputs.input_ids.shape[-1]:], skip_special_tokens=True)
|
||||||
['\nIn 1891, when he was 54 years old, John Jacob Astor founded his empire. He opened a one-man business and spent the next 27 years working 10-hour days. When']
|
['\nIt was officially signed on 2 August 1776, when 56 members of the Second Continental Congress, representing the original 13 American colonies, voted unanimously for the resolution for independence. The 2']
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Understanding the `dola_layers` argument
|
#### Understanding the `dola_layers` argument
|
||||||
|
|||||||
@ -80,15 +80,6 @@ For now the supported model architectures are the architectures that have been v
|
|||||||
- Qwen2
|
- Qwen2
|
||||||
- Qwen2Moe
|
- Qwen2Moe
|
||||||
- Phi3
|
- Phi3
|
||||||
- Bloom
|
|
||||||
- Falcon
|
|
||||||
- StableLM
|
|
||||||
- GPT2
|
|
||||||
- Starcoder2
|
|
||||||
- T5
|
|
||||||
- Mamba
|
|
||||||
- Nemotron
|
|
||||||
- Gemma2
|
|
||||||
|
|
||||||
## Example usage
|
## Example usage
|
||||||
|
|
||||||
@ -110,7 +101,7 @@ Now you have access to the full, unquantized version of the model in the PyTorch
|
|||||||
with a plethora of other tools.
|
with a plethora of other tools.
|
||||||
|
|
||||||
In order to convert back to a `gguf` file, we recommend using the
|
In order to convert back to a `gguf` file, we recommend using the
|
||||||
[`convert-hf-to-gguf.py` file](https://github.com/ggerganov/llama.cpp/blob/master/convert_hf_to_gguf.py) from llama.cpp.
|
[`convert-hf-to-gguf.py` file](https://github.com/ggerganov/llama.cpp/blob/master/convert-hf-to-gguf.py) from llama.cpp.
|
||||||
|
|
||||||
Here's how you would complete the script above to save the model and export it back to `gguf`:
|
Here's how you would complete the script above to save the model and export it back to `gguf`:
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user