Transformers documentation

كيفية تعديل أي نموذج من نماذج Transformers

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

and get access to the augmented documentation experience

to get started

كيفية تعديل أي نموذج من نماذج Transformers

توفر مكتبة 🤗 Transformers مجموعة من النماذج المسبقة التدريب والأدوات لمعالجة اللغات الطبيعية، والرؤية، وما إلى ذلك. على الرغم من أن هذه النماذج تغطي مجموعة واسعة من التطبيقات، فقد تواجه حالات استخدام لا تدعمها المكتبة بشكل افتراضي. يُمكن للتخصيص أن يفتح إمكانيات جديدة، مثل إضافة طبقات جديدة، أو تعديل البنية المعمارية، أو تحسين آليات الانتباه. سيُوضح لك هذا الدليل كيفية تعديل نماذج Transformers الموجودة لتلبية احتياجاتك المحددة. الشيء الرائع هو أنك لست بحاجة إلى الخروج من إطار عمل Transformers لإجراء هذه التغييرات. ي يمكنك تعديل النماذج مباشرةً في Transformers والاستفادة من الميزات مثل واجهة برمجة التطبيقات Trainer، و PreTrainedModel، والضبط الدقيق الفعال باستخدام أدوات مثل PEFT.

سنرشدك في هذا الدليل لكيفية تخصيص نماذج 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 منفصلة.

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 الأصلية بفئتك المخصصة بحيث يستخدم النموذج آلية الانتباه المعدلة.

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.

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: التحقق من عدد المعلمات القابلة للتدريب

من السهل التحقق من عدد المعلمات القابلة للتدريب ومعرفة تأثير تعديلك.

model.print_trainable_parameters()

الناتج المتوقع:

عدد المعلمات القابلة للتدريب: 608,256 || جميع المعلمات: 94,343,728 || نسبة المعلمات القابلة للتدريب: 0.6447
عدد المعلمات القابلة للتدريب: 912,384 || جميع المعلمات: 94,647,856 || نسبة المعلمات القابلة للتدريب: 0.9640 # مع k

المساهمة بابداعاتك الخاصة

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

إذا قمت بتطوير تعديﻻتك الخاصة لنماذج Transformers وترغب في مشاركتها، ففكر في المساهمة في هذه الوثيقة.

  • إنشاء طلب سحب (Pull Request): شارك تغييراتك وتحسيناتك في التعليمات البرمجية مباشرة في المستودع.
  • كتابة التوثيق: قدم تفسيرات وأمثلة واضحة لتعديلاتك.
  • التفاعل مع المجتمع: ناقش أفكارك واحصل على تعليقات من المطورين والباحثين الآخرين من خلال فتح مشكلة.
< > Update on GitHub