Transformers documentation

استراتيجيات التوليد

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

استراتيجيات التوليد

تُحدِّد استراتيجية فك التشفير كيفية اختيار النموذج للرمز التالي الذي سيتم توليده. توجد أنواع عديدة من استراتيجيات فك التشفير، ويؤثر اختيار الاستراتيجية المناسبة بشكل كبير على جودة النص المولَّد.

ستساعدك هذه الدليل على فهم استراتيجيات فك الترميز المختلفة المتاحة في Transformers وكيفية استخدامها ومتى.

طرق فك الترميز الأساسية

هذه طرق فك ترميز راسخة، وينبغي أن تكون نقطة انطلاقك لمهام توليد النص.

البحث الجشع

يُعدّ البحث الطمّاع (Greedy search) استراتيجية فكّ الترميز الافتراضية. فهو يختار الرمز الأكثر احتمالاً في كل خطوة. ما لم يُحدَّد ذلك في GenerationConfig، فإن هذه الاستراتيجية تولّد حداً أقصى قدره 20 رمزاً جديداً.

يعمل البحث الطمّاع بشكل جيد للمهام ذات المخرجات القصيرة نسبيًا حيث لا تُعدّ الإبداعية أولوية. ومع ذلك، يفشل عند توليد تسلسلات أطول لأنه يبدأ في تكرار نفسه.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to default length because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=20)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that provides a suite of tools and services for building, deploying, and maintaining natural language processing'

العينة

التعيّن، أو التعيّن متعدد الحدود، يختار رمزًا بشكل عشوائي بناءً على توزيع الاحتمالات على كامل مفردات النموذج (على عكس أكثر الرموز احتمالًا، كما في البحث الجشع). وهذا يعني أن كل رمز ذي احتمال غير صفري لديه فرصة ليتم اختياره. تقلل استراتيجيات التعيّن من التكرار ويمكنها توليد مخرجات أكثر إبداعًا وتنوعًا.

فعّل العينة متعددة الحدود باستخدام do_sample=True وnum_beams=1.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, do_sample=True, num_beams=1)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company 🤗\nWe are open-source and believe that open-source is the best way to build technology. Our mission is to make AI accessible to everyone, and we believe that open-source is the best way to achieve that.'

البحث الشعاعي

يحافظ بحث الحزمة (Beam search) على تتبع عدة تسلسلات مولّدة (حزم) في كل خطوة زمنية. بعد عدد معين من الخطوات، يختار التسلسل الذي يتمتع بأعلى إجمالي للاحتمالية. على عكس البحث الجشع، يمكن لهذه الاستراتيجية أن «تتطلع إلى الأمام» وتختار تسلسلاً يتمتع باحتمالية أعلى بشكل إجمالي حتى لو كانت الرموز الأولية ذات احتمالية أقل. وهو الأنسب للمهام المرتبطة بالمدخلات، مثل وصف صورة أو التعرف على الكلام. يمكنك أيضاً استخدام do_sample=True مع بحث الحزمة لأخذ عينات في كل خطوة، لكن بحث الحزمة سيظل يقصّ التسلسلات ذات الاحتمالية المنخفضة بشكل جشع بين الخطوات.

اطّلع على أداة عرض البحث الحزّامي لمعرفة كيفية عمل البحث الحزّامي.

فعّل البحث الشعاعي باستخدام معامل num_beams (يجب أن يكون أكبر من 1 وإلا كان مكافئًا للبحث الطمعي).

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, num_beams=2)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
"['Hugging Face is an open-source company that develops and maintains the Hugging Face platform, which is a collection of tools and libraries for building and deploying natural language processing (NLP) models. Hugging Face was founded in 2018 by Thomas Wolf']"

طرق التوليد المخصصة

تُمكّن طرق التوليد المخصصة من سلوكيات متخصصة مثل:

  • تسمح للنموذج بمواصلة التفكير إذا كان غير متأكد؛
  • تراجع عن التوليد إذا علق النموذج؛
  • التعامل مع الرموز الخاصة من خلال منطق مخصص؛
  • استخدام ذاكرات KV متخصصة؛

نُمكّن من استخدام طرق توليد مخصصة عبر مستودعات النماذج، بافتراض وسم نموذج محدد وهيكل ملفات (انظر الفرع أدناه). هذه الميزة امتداد لـ كود النمذجة المخصص، وكما هو الحال مع ذلك، تتطلب تعيين trust_remote_code=True.

إذا احتوى مستودع النموذج على طريقة توليد مخصصة، فإن أسهل طريقة لتجربتها هي تحميل النموذج والتوليد باستخدامه:

from transformers import AutoModelForCausalLM, AutoTokenizer

# `transformers-community/custom_generate_example` holds a copy of `Qwen/Qwen2.5-0.5B-Instruct`, but
# with custom generation code -> calling `generate` uses the custom generation method!
tokenizer = AutoTokenizer.from_pretrained("transformers-community/custom_generate_example")
model = AutoModelForCausalLM.from_pretrained(
    "transformers-community/custom_generate_example", device_map="auto", trust_remote_code=True
)

inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# The custom generation method is a minimal greedy decoding implementation. It also prints a custom message at run time.
gen_out = model.generate(**inputs)
# you should now see its custom message, "✨ using a custom generation method ✨"
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True))
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'

تمتلك مستودعات النماذج التي تتضمن طرق توليد مخصصة خاصية مميزة: يمكن تحميل طريقة التوليد الخاصة بها من أي نموذج عبر حجة custom_generate في generate(). وهذا يعني أن أي شخص يمكنه إنشاء ومشاركة طريقة توليده المخصصة لتعمل محتملاً مع أي نموذج من نماذج Transformers، دون الحاجة إلى تثبيت المستخدمين لحزم Python إضافية.

from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", device_map="auto")

inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# `custom_generate` replaces the original `generate` by the custom generation method defined in
# `transformers-community/custom_generate_example`
gen_out = model.generate(**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True)
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True)[0])
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'

يجب عليك قراءة ملف README.md الخاص بالمستودع الذي يحتوي على استراتيجية التوليد المخصصة لمعرفة ما إذا كانت هناك اختلافات في الحُجج الجديدة ونوع المخرجات، إن وُجدت. وإلا، يمكنك افتراض أنه يعمل بنفس طريقة الطريقة الأساسية generate().

يمكنك العثور على جميع طرق التوليد المخصصة من خلال البحث عن وسمها المخصص، custom_generate.

خذ مستودع transformers-community/custom_generate_example على Hub كمثال. ينص README.md على أنه يحتوي على معامل إدخال إضافي، left_padding، يضيف عددًا من رموز الحشو قبل الاستعلام.

gen_out = model.generate(
    **inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True, left_padding=5
)
print(tokenizer.batch_decode(gen_out)[0])
'<|endoftext|><|endoftext|><|endoftext|><|endoftext|><|endoftext|>The quick brown fox jumps over the lazy dog.\n\nThe sentence "The quick'

إذا كانت الطريقة المخصصة تتضمن متطلبات Python مثبتة لا يستوفيها بيئتك، فستظهر لك استثناءً يتعلق بمتطلبات مفقودة. على سبيل المثال، يحتوي transformers-community/custom_generate_bad_requirements على مجموعة مستحيلة من المتطلبات معرّفة في ملف custom_generate/requirements.txt الخاص به، وستظهر لك رسالة الخطأ أدناه إذا حاولت تشغيله.

ImportError: Missing requirements in your local environment for `transformers-community/custom_generate_bad_requirements`:
foo (installed: None)
bar==0.0.0 (installed: None)
torch>=99.0 (installed: 2.6.0)

سيؤدي تحديث متطلبات Python الخاصة بك وفقًا لذلك إلى إزالة رسالة الخطأ هذه.

إنشاء طريقة توليد مخصصة

لإنشاء طريقة توليد جديدة، عليك إنشاء مستودع Model جديد ودفع بعض الملفات إليه.

  1. النموذج الذي صممت منهجية التوليد الخاصة بك بناءً عليه.
  2. custom_generate/generate.py، والذي يحتوي على جميع منطق طريقة التوليد المخصصة الخاصة بك.
  3. custom_generate/requirements.txt، يُستخدم لإضافة متطلبات بايثون جديدة بشكل اختياري و/أو لتثبيت إصدارات محددة بشكل صحيح لاستخدام طريقتك.
  4. README.md، حيث يجب عليك إضافة وسم custom_generate وتوثيق أي اختلافات في الحُجج الجديدة أو أنواع المخرجات لطريقتك المخصصة هنا.

بعد إضافة جميع الملفات المطلوبة، يجب أن يبدو مستودعك على النحو التالي

your_repo/
├── README.md          # include the 'custom_generate' tag
├── config.json
├── ...
└── custom_generate/
    ├── generate.py
    └── requirements.txt

إضافة النموذج الأساسي

نقطة الانطلاق لطريقة التوليد المخصصة لديك هي مستودع نموذج تمامًا مثل أي مستودع آخر. يجب أن يكون النموذج الذي ستضيفه إلى هذا المستودع هو النموذج الذي صممت منهجيتك بناءً عليه، وهو مخصص ليكون جزءًا من زوج نموذج-توليد يعمل بشكل مستقل بذاته. عند تحميل النموذج الموجود في هذا المستودع، ستقوم طريقة التوليد المخصصة لديك بتجاوز generate. لا تقلق — لا يزال بإمكانك تحميل طريقة التوليد الخاصة بك مع أي نموذج آخر من Transformers، كما هو موضح في القسم أعلاه.

إذا كنت ترغب ببساطة في نسخ نموذج موجود، يمكنك

from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("source/model_repo")
model = AutoModelForCausalLM.from_pretrained("source/model_repo")
tokenizer.save_pretrained("your/generation_method", push_to_hub=True)
model.save_pretrained("your/generation_method", push_to_hub=True)

generate.py

هذا هو جوهر طريقة التوليد لديك. يجب أن تحتوي على طريقة باسم generate، ويجب أن تحتوي هذه الطريقة على معامل model كمعامل أول. model هو نموذج المثال، مما يعني أن لديك وصولاً إلى جميع الخصائص والطرق في النموذج، بما في ذلك تلك المعرفة في GenerationMixin (مثل طريقة generate الأساسية).

يجب وضع generate.py في مجلد باسم custom_generate، وليس في المستوى الجذري للمستودع. مسارات الملفات لهذه الميزة مبرمجة بشكل ثابت.

في الخلفية، عند استدعاء طريقة generate() الأساسية مع حجة custom_generate، فإنها أولاً تتحقق من متطلبات بايثون الخاصة بها (إن وُجدت)، ثم تحدد طريقة generate المخصصة في generate.py، وأخيراً تستدعي generate المخصصة. تُمرَّر جميع الحجج المستلمة وmodel إلى طريقة generate المخصصة الخاصة بك، باستثناء الحجج المستخدمة لتفعيل التوليد المخصص (trust_remote_code وcustom_generate).

هذا يعني أن generate الخاص بك يمكن أن يحتوي على مزيج من الحجج الأصلية والحجج المخصصة (إضافةً إلى نوع مخرجات مختلف) كما هو موضح أدناه.

import torch

def generate(model, input_ids, generation_config=None, left_padding=None, **kwargs):
    generation_config = generation_config or model.generation_config  # default to the model generation config
    cur_length = input_ids.shape[1]
    max_length = generation_config.max_length or cur_length + generation_config.max_new_tokens

    # Example of custom argument: add `left_padding` (integer) pad tokens before the prompt
    if left_padding is not None:
        if not isinstance(left_padding, int) or left_padding < 0:
            raise ValueError(f"left_padding must be an integer larger than 0, but is {left_padding}")

        pad_token = kwargs.pop("pad_token", None) or generation_config.pad_token_id or model.config.pad_token_id
        if pad_token is None:
            raise ValueError("pad_token is not defined")
        batch_size = input_ids.shape[0]
        pad_tensor = torch.full(size=(batch_size, left_padding), fill_value=pad_token).to(input_ids.device)
        input_ids = torch.cat((pad_tensor, input_ids), dim=1)
        cur_length = input_ids.shape[1]

    # Simple greedy decoding loop
    while cur_length < max_length:
        logits = model(input_ids).logits
        next_token_logits = logits[:, -1, :]
        next_tokens = torch.argmax(next_token_logits, dim=-1)
        input_ids = torch.cat((input_ids, next_tokens[:, None]), dim=-1)
        cur_length += 1

    return input_ids

اتبع الممارسات الموصى بها أدناه للتأكد من أن طريقة التوليد المخصصة تعمل كما هو متوقع.

  • لا تتردد في إعادة استخدام منطق التحقق من الصحة وتجهيز المدخلات الموجود في generate() الأصلية.
  • ثبّت إصدار transformers في المتطلبات إذا كنت تستخدم أي طريقة/خاصية خاصة في model.
  • فكّر في إضافة التحقق من النموذج، أو التحقق من المدخلات، أو حتى ملف اختبار منفصل لمساعدة المستخدمين على التأكد من صحة الكود الخاص بك في بيئتهم.

يمكن لطريقة generate المخصصة لديك استيراد الأكواد بشكل نسبي من مجلد custom_generate. على سبيل المثال، إذا كان لديك ملف utils.py، يمكنك استيراده على النحو التالي:

from .utils import some_function

يُؤمَن الاستيراد النسبي فقط من مجلد custom_generate على نفس المستوى. استيرادات المجلدات الأم/الأخ غير صالحة. كما يعمل الحجة custom_generate محليًا مع أي مجلد يحتوي على بنية custom_generate، وهو سير العمل الموصى به لتطوير طريقة التوليد المخصصة الخاصة بك.

gen_out = model.generate(**inputs, custom_generate="path/to/local/dir", trust_remote_code=True)

تؤدي عملية تحميل مجلد محلي إلى تنفيذ custom_generate/generate.py الخاص به، لذا فهي تتطلب trust_remote_code=True تمامًا كما هو الحال مع مستودع Hub. لا تمرر trust_remote_code=True إلا للأكواد التي كتبتها أو راجعتها.

requirements.txt

يمكنك اختيارياً تحديد متطلبات بايثون إضافية في ملف requirements.txt داخل مجلد custom_generate. يتم التحقق من هذه المتطلبات وقت التشغيل، وسيتم طرح استثناء إذا كانت مفقودة، مما يدفع المستخدمين إلى تحديث بيئتهم وفقاً لذلك.

README.md

يصف ملف README.md في مستوى الجذر من مستودع النموذج عادةً النموذج الموجود فيه. ومع ذلك، بما أن تركيز المستودع هو طريقة التوليد المخصصة، فنحن نوصي بشدة بتحويل تركيزه نحو وصف طريقة التوليد المخصصة. بالإضافة إلى وصف الطريقة، نوصي بتوثيق أي اختلافات في المدخلات و/أو المخرجات مقارنةً بـ generate() الأصلية. وبهذه الطريقة، يمكن للمستخدمين التركيز على ما هو جديد، والاعتماد على وثائق Transformers للتفاصيل العامة للتنفيذ.

لزيادة قابلية الاكتشاف، ننصحك بشدة بإضافة وسم custom_generate إلى مستودعك. للقيام بذلك، يجب أن يبدو الجزء العلوي من ملف README.md لديك كما هو موضح في المثال أدناه. بعد دفع الملف، يجب أن ترى الوسم في مستودعك!

---
library_name: transformers
tags:
  - custom_generate
---

(your markdown content here)

الممارسات الموصى بها:

  • وثّق الفروق بين المدخلات والمخرجات في generate().
  • أضف أمثلة مكتفية ذاتياً لتسهيل التجارب السريعة.
  • صف المتطلبات غير الصارمة، مثل ما إذا كانت الطريقة تعمل بشكل جيد فقط مع عائلة معينة من النماذج.

إعادة استخدام إعداد مدخلات generate

إذا كنت تضيف حلقة فك ترميز جديدة، فقد ترغب في الحفاظ على إعداد المدخلات الموجود في generate (توسيع الدفعة، أقنعة الانتباه، معالجات اللوجيت، معايير التوقف، وما إلى ذلك). كما يمكنك تمرير دالة قابلة للاستدعاء إلى custom_generate لإعادة استخدام خط أنابيب الإعداد الكامل الخاص بـ generate() مع تجاوز حلقة فك الترميز فقط.

def custom_loop(model, input_ids, attention_mask, logits_processor, stopping_criteria, generation_config, **model_kwargs):
    next_tokens = input_ids
    while input_ids.shape[1] < stopping_criteria[0].max_length:
        logits = model(next_tokens, attention_mask=attention_mask, **model_kwargs).logits
        next_token_logits = logits_processor(input_ids, logits[:, -1, :])
        next_tokens = torch.argmax(next_token_logits, dim=-1)[:, None]
        input_ids = torch.cat((input_ids, next_tokens), dim=-1)
        attention_mask = torch.cat((attention_mask, torch.ones_like(next_tokens)), dim=-1)
    return input_ids

output = model.generate(
    **inputs,
    custom_generate=custom_loop,
    max_new_tokens=10,
)

إذا نشرت مستودع custom_generate، فإن تنفيذك لـgenerate يمكنه هو نفسه تعريف دالة قابلة للاستدعاء وتحويلها إلى model.generate(). يتيح لك ذلك تخصيص حلقة فك الترميز مع الاستفادة في الوقت نفسه من منطق تحضير المدخلات المدمج في Transformers.

العثور على طرق توليد مخصصة

يمكنك العثور على جميع طرق التوليد المخصصة من خلال البحث عن وسمها المخصص، custom_generate. بالإضافة إلى الوسم، نقوم بتحرير مجموعتين لطرق custom_generate:

الموارد

اقرأ منشور المدونة كيف تولّد النص: استخدام طرق فك الترميز المختلفة لتوليد اللغة مع Transformers للحصول على شرح لكيفية عمل استراتيجيات فك الترميز الشائعة.

Update on GitHub