Jannah Theme License is not validated, Go to the theme options page to validate the license, You need a single license for each domain name.
تقنية وتكنولوجيا

كيفية تفسير GPT2-Small. التفسير الآلي على… | بواسطة شويانغ شيانغ


إمكانية التفسير الآلي للتنبؤ بالرموز المتكررة

نحو علم البيانات

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

في منشور المدونة هذا، سأحاول إزالة الغموض عن GPT2-small باستخدام قابلية التفسير الآلي في حالة بسيطة: التنبؤ بالرموز المتكررة.

الأدوات الرياضية التقليدية لشرح نماذج التعلم الآلي ليست مناسبة تمامًا لنماذج اللغة.

خذ بعين الاعتبار SHAP، وهي أداة مفيدة لشرح نماذج التعلم الآلي. إنه بارع في تحديد الميزة التي أثرت بشكل كبير على التنبؤ بالنبيذ عالي الجودة. ومع ذلك، من المهم أن تتذكر أن نماذج اللغة تقوم بالتنبؤات على مستوى الرمز المميز، بينما يتم حساب قيم SHAP في الغالب على مستوى الميزة، مما يجعلها غير مناسبة للرموز المميزة.

علاوة على ذلك، تحتوي نماذج اللغة (LLMs) على العديد من المعلمات والمدخلات، مما يخلق مساحة عالية الأبعاد. يعد حساب قيم SHAP مكلفًا حتى في المساحات منخفضة الأبعاد، بل وأكثر من ذلك في الفضاء عالي الأبعاد للماجستير في القانون.

وعلى الرغم من تحمل التكاليف الحسابية المرتفعة، فإن التفسيرات التي تقدمها SHAP يمكن أن تكون سطحية. على سبيل المثال، معرفة أن مصطلح “الخزاف” هو الأكثر تأثيرًا على التنبؤ بالمخرجات نظرًا للذكر السابق لـ “هاري” لا يوفر الكثير من المعرفة. إنه يتركنا غير متأكدين بشأن جزء النموذج أو الآلية المحددة المسؤولة عن مثل هذا التنبؤ.

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

سوف نستخدم GPT2-small لمهمة بسيطة: التنبؤ بسلسلة من الرموز المميزة المتكررة. المكتبة التي سنستخدمها هي TransformerLens، والتي تم تصميمها لقابلية التفسير الآلي لنماذج اللغة ذات النمط GPT-2.

gpt2_small: HookedTransformer = HookedTransformer.from_pretrained("gpt2-small")

نستخدم الكود أعلاه لتحميل نموذج GPT2-Small والتنبؤ بالرموز المميزة على تسلسل تم إنشاؤه بواسطة وظيفة محددة. يتضمن هذا التسلسل تسلسلين متطابقين من الرموز المميزة، متبوعين بـ bos_token. على سبيل المثال، “ABCDABCD” + bos_token عندما يكون seq_len هو 3. للتوضيح، نشير إلى التسلسل من البداية إلى seq_len باعتباره النصف الأول، والتسلسل المتبقي، باستثناء bos_token، باعتباره النصف الثاني.

def generate_repeated_tokens(
model: HookedTransformer, seq_len: int, batch: int = 1
) -> Int[Tensor, "batch full_seq_len"]:
'''
Generates a sequence of repeated random tokens

Outputs are:
rep_tokens: [batch, 1+2*seq_len]
'''
bos_token = (t.ones(batch, 1) * model.tokenizer.bos_token_id).long() # generate bos token for each batch

rep_tokens_half = t.randint(0, model.cfg.d_vocab, (batch, seq_len), dtype=t.int64)
rep_tokens = t.cat([bos_token,rep_tokens_half,rep_tokens_half], dim=-1).to(device)
return rep_tokens

عندما نسمح للنموذج بالعمل على الرمز المميز الذي تم إنشاؤه، نجد ملاحظة مثيرة للاهتمام: أداء النموذج أفضل بكثير في النصف الثاني من التسلسل مقارنة بالنصف الأول. يتم قياس ذلك من خلال احتمالات السجل على الرموز الصحيحة. على وجه الدقة، الأداء في النصف الأول هو -13.898، في حين أن الأداء في النصف الثاني هو -0.644.

صورة للمؤلف: تسجيل الدخول على الرموز الصحيحة

يمكننا أيضًا حساب دقة التنبؤ، والتي يتم تعريفها على أنها نسبة الرموز المميزة المتوقعة بشكل صحيح (تلك المطابقة للرموز المميزة التي تم إنشاؤها) إلى إجمالي عدد الرموز المميزة. دقة تسلسل النصف الأول هي 0.0، وهو أمر غير مفاجئ لأننا نعمل مع رموز عشوائية تفتقر إلى المعنى الفعلي. وفي الوقت نفسه، بلغت دقة الشوط الثاني 0.93، متفوقة بشكل ملحوظ على النصف الأول.

العثور على رئيس التعريفي

يمكن تفسير الملاحظة أعلاه بوجود دائرة تحريضية. هذه دائرة تقوم بمسح التسلسل بحثًا عن مثيلات سابقة للرمز الحالي، وتحدد الرمز المميز الذي تبعه سابقًا، وتتنبأ بتكرار نفس التسلسل. على سبيل المثال، إذا واجه “A”، فإنه يبحث عن “A” السابق أو رمز مميز مشابه جدًا لـ “A” في مساحة التضمين، ويحدد الرمز المميز التالي “B”، ثم يتنبأ بالرمز المميز التالي بعد “A” ” ليكون “B” أو رمزًا مميزًا مشابهًا جدًا لـ “B” في مساحة التضمين.

الصورة من قبل المؤلف: الدائرة التعريفي

يمكن تقسيم عملية التنبؤ هذه إلى خطوتين:

  1. حدد نفس الرمز المميز السابق (أو ما شابه). يجب على كل رمز مميز في النصف الثاني من التسلسل “الانتباه” إلى أماكن الرمز المميز “seq_len” قبله. على سبيل المثال، يجب أن ينتبه “A” في الموضع 4 إلى “A” في الموضع 1 إذا كان “seq_len” هو 3. يمكننا أن نطلق على رأس الانتباه الذي يقوم بهذه المهمة “رأس الحث“.
  2. حدد الرمز المميز التالي “B”. هذه هي عملية نسخ المعلومات من الرمز المميز السابق (على سبيل المثال، ‘A’) إلى الرمز المميز التالي (على سبيل المثال، ‘B’). سيتم استخدام هذه المعلومات “لإعادة إنتاج” “B” عندما يظهر “A” مرة أخرى. يمكننا أن نطلق على رأس الانتباه الذي يقوم بهذه المهمة “رأس الرمز السابق“.

يشكل هذان الرأسان دائرة تحريضية كاملة. لاحظ أنه في بعض الأحيان يستخدم مصطلح “رأس الحث” أيضًا لوصف “دائرة الحث” بأكملها. لمزيد من المقدمة عن دائرة الحث، أوصي بشدة بمقال التعلم في السياق ورأس الحث الذي يعد تحفة فنية!

الآن دعونا نتعرف على رأس الانتباه والرأس السابق في GPT2-small.

يتم استخدام الكود التالي للعثور على رأس الحث. أولاً، نقوم بتشغيل النموذج بـ 30 دفعة. بعد ذلك، نحسب القيمة المتوسطة للقطر مع إزاحة seq_len في مصفوفة نمط الانتباه. تتيح لنا هذه الطريقة قياس درجة الاهتمام التي يوليها الرمز المميز الحالي للرمز الذي يظهر seq_len مسبقًا.

def induction_score_hook(
pattern: Float[Tensor, "batch head_index dest_pos source_pos"],
hook: HookPoint,
):
'''
Calculates the induction score, and stores it in the [layer, head] position of the `induction_score_store` tensor.
'''
induction_stripe = pattern.diagonal(dim1=-2, dim2=-1, offset=1-seq_len) # src_pos, des_pos, one position right from seq_len
induction_score = einops.reduce(induction_stripe, "batch head_index position -> head_index", "mean")
induction_score_store[hook.layer(), :] = induction_score

seq_len = 50
batch = 30
rep_tokens_30 = generate_repeated_tokens(gpt2_small, seq_len, batch)
induction_score_store = t.zeros((gpt2_small.cfg.n_layers, gpt2_small.cfg.n_heads), device=gpt2_small.cfg.device)

rep_tokens_30,
return_type=None,
pattern_hook_names_filter,
induction_score_hook
)]
)

الآن، دعونا نتفحص درجات التعريفي. سنلاحظ أن بعض الرؤوس، مثل تلك الموجودة في الطبقة 5 والرأس 5، تتمتع بدرجة تحريض عالية تبلغ 0.91.

الصورة من قبل المؤلف: عشرات الرأس التعريفي

يمكننا أيضًا عرض نمط انتباه هذا الرأس. ستلاحظ وجود خط قطري واضح يصل إلى إزاحة seq_len.

الصورة من قبل المؤلف: الطبقة 5، نمط الانتباه للرأس 5

وبالمثل، يمكننا تحديد رأس الرمز المميز السابق. على سبيل المثال، تُظهر الطبقة 4 الرأس 11 نمطًا قويًا للرمز المميز السابق.

الصورة من قبل المؤلف: درجات رأس الرمز المميز السابقة

كيف تنسب طبقات MLP؟

دعونا نفكر في هذا السؤال: هل يتم احتساب طبقات MLP؟ نحن نعلم أن GPT2-Small يحتوي على طبقات الانتباه وطبقات MLP. للتحقيق في هذا، أقترح استخدام تقنية الاجتثاث.

يقوم الاستئصال، كما يوحي الاسم، بإزالة بعض مكونات النموذج بشكل منهجي ويلاحظ كيفية تغير الأداء نتيجة لذلك.

سوف نستبدل مخرجات طبقات MLP في النصف الثاني من التسلسل بتلك الموجودة في النصف الأول، ونلاحظ كيف يؤثر ذلك على دالة الخسارة النهائية. سنقوم بحساب الفرق بين الخسارة بعد استبدال مخرجات طبقة MLP والخسارة الأصلية لتسلسل النصف الثاني باستخدام الكود التالي.

def patch_residual_component(
residual_component,
hook,
pos,
cache,
):
residual_component[0,pos, :] = cache[hook.name][pos-seq_len, :]
return residual_component

ablation_scores = t.zeros((gpt2_small.cfg.n_layers, seq_len), device=gpt2_small.cfg.device)

gpt2_small.reset_hooks()
logits = gpt2_small(rep_tokens, return_type="logits")
loss_no_ablation = cross_entropy_loss(logits[:, seq_len: max_len],rep_tokens[:, seq_len: max_len])

for layer in tqdm(range(gpt2_small.cfg.n_layers)):
for position in range(seq_len, max_len):
hook_fn = functools.partial(patch_residual_component, pos=position, cache=rep_cache)
ablated_logits = gpt2_small.run_with_hooks(rep_tokens, fwd_hooks=[
(utils.get_act_name("mlp_out", layer), hook_fn)
])
loss = cross_entropy_loss(ablated_logits[:, seq_len: max_len], rep_tokens[:, seq_len: max_len])
ablation_scores[layer, position-seq_len] = loss - loss_no_ablation

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

الصورة من المؤلف: فقدان مختلف قبل وبعد استئصال طبقات mlp

نظرًا لأن طبقات MLP لا تساهم بشكل كبير في التنبؤ النهائي، يمكننا إنشاء دائرة تحريضية يدويًا باستخدام رأس الطبقة 5، الرأس 5، ورأس الطبقة 4، الرأس 11. تذكر أن هذه هي رأس الحث و رأس الرمز السابق. ونقوم بذلك عن طريق الكود التالي:

def K_comp_full_circuit(
model: HookedTransformer,
prev_token_layer_index: int,
ind_layer_index: int,
prev_token_head_index: int,
ind_head_index: int
) -> FactoredMatrix:
'''
Returns a (vocab, vocab)-size FactoredMatrix,
with the first dimension being the query side
and the second dimension being the key side (going via the previous token head)

'''
W_E = gpt2_small.W_E
W_Q = gpt2_small.W_Q[ind_layer_index, ind_head_index]
W_K = model.W_K[ind_layer_index, ind_head_index]
W_O = model.W_O[prev_token_layer_index, prev_token_head_index]
W_V = model.W_V[prev_token_layer_index, prev_token_head_index]

Q = W_E @ W_Q
K = W_E @ W_V @ W_O @ W_K
return FactoredMatrix(Q, K.T)

يؤدي حساب الدقة الأولى لهذه الدائرة إلى الحصول على قيمة 0.2283. وهذا أمر جيد جدًا بالنسبة لدائرة مبنية برأسين فقط!

للتنفيذ التفصيلي، يرجى مراجعة بلدي دفتر.


اكتشاف المزيد من موقع علم

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

زر الذهاب إلى الأعلى

اكتشاف المزيد من موقع علم

اشترك الآن للاستمرار في القراءة والحصول على حق الوصول إلى الأرشيف الكامل.

Continue reading