مرحلة التعلم الخاضع للإشراف
قبل أن يتمكن AlphaGo من اللعب الذاتي، كان يحتاج أولاً إلى "مشاهدة" كمية كبيرة من سجلات اللعب البشرية. تسمى هذه العملية التعلم الخاضع للإشراف.
من خلال تحليل 30 مليون موقف من اللعب البشري، حققت شبكة Policy Network في AlphaGo دقة تنبؤ 57% — قادرة على تخمين الحركة التالية لخبير بشري في أكثر من نصف الحالات.
قد لا يبدو هذا مثيراً للإعجاب، لكن بالنظر إلى أن كل موقف لديه في المتوسط 250 حركة قانونية، فهذا إنجاز مذهل.
لماذا نبدأ من سجلات اللعب البشرية؟
نقطة بداية التعلم
تخيل أنك تريد تعليم شخص لا يعرف شيئاً عن الجو. ماذا ستفعل؟
الخيار أ: الاستكشاف العشوائي
دعه يلعب عشوائياً، ليكتشف تدريجياً ما هي الحركة الجيدة
← كفاءة منخفضة جداً، قد لا يتعلم أبداً
الخيار ب: مشاهدة كيف يلعب الخبراء
دعه يشاهد كمية كبيرة من مباريات اللاعبين المحترفين، ويقلد طريقة لعبهم
← بعد وضع الأساس، يستكشف بنفسه
اختار AlphaGo الخيار ب. التعلم الخاضع للإشراف هو النسخة الرياضية من "مشاهدة كيف يلعب الخبراء".
قيمة سجلات اللعب البشرية
أمضى البشر آلاف السنين في تطوير نظرية الجو. كل هذه المعرفة مشفرة في سجلات اللعب:
- الجوسيكي (الأنماط الافتتاحية): طرق اللعب الافتتاحية التي تم التحقق منها على مدى فترة طويلة
- تكتيكات الوسط: حكمة التحول بين الهجوم والدفاع
- مهارات النهاية: جوهر حساب النقاط
- الرؤية الشاملة: حدس الحكم العام
يتيح التعلم الخاضع للإشراف لـ AlphaGo "وراثة" هذه الحكمة البشرية، دون الحاجة للتجربة من الصفر.
مصدر بيانات التدريب
KGS Go Server
جاءت بيانات تدريب AlphaGo بشكل رئيسي من KGS Go Server (المعروف أيضاً بـ Kiseido Go Server)، وهي منصة جو معروفة على الإنترنت.
خصائص KGS
| الخاصية | الوصف |
|---|---|
| المستخدمون | لاعبون هواة بشكل رئيسي، مع بعض المحترفين |
| نطاق القوة | من المبتدئين إلى المحترفين دان 9 |
| سجلات المباريات | سجلات SGF كاملة محفوظة |
| فترة النشاط | من 2000 حتى الآن |
لماذا اختيار KGS؟
- كمية بيانات كبيرة: ملايين سجلات اللعب
- تنسيق موحد: تنسيق SGF سهل التحليل
- علامات القوة: كل مستخدم له تصنيف
- التنوع: لاعبون بأساليب مختلفة
30 مليون موقف
من سجلات KGS، استخرجت DeepMind حوالي 30 مليون موقف:
البيانات الخام:
- حوالي 160,000 سجل لعب
- كل سجل حوالي 200 حركة
- مجموع ~32 مليون موقف
فلترة البيانات:
- فلترة مباريات اللاعبين ذوي الدان المنخفض
- فلترة المواقف من المباريات المستسلمة مبكراً
- في النهاية حوالي 30 مليون موقف عالي الجودة
تنسيق البيانات
كل عينة تدريب تتضمن:
{
"board_state": [[0, 1, 2, ...], ...], # لوحة 19×19
"features": [...], # 48 مستوى ميزة
"next_move": 123, # موقع اللعب البشري (0-360)
"game_result": 1, # 1=فوز الأسود، -1=فوز الأبيض
"player_rank": "5d", # دان اللاعب الذي لعب هذه الحركة
}
معالجة البيانات المسبقة
تحليل SGF
SGF (Smart Game Format) هو التنسيق القياسي لسجلات الجو:
(;GM[1]FF[4]CA[UTF-8]AP[CGoban:3]ST[2]
RU[Japanese]SZ[19]KM[6.50]
PW[White]PB[Black]
;B[pd];W[dd];B[pq];W[dp];B[qk];W[nc]...
)
يجب تحليل:
- حجم اللوحة (SZ[19])
- كل حركة (B[pd], W[dd]...)
- نتيجة المباراة (RE[B+2.5])
def parse_sgf(sgf_string):
"""تحليل سجل SGF"""
moves = []
# استخراج جميع الحركات
pattern = r';([BW])\[([a-s]{2})\]'
for match in re.finditer(pattern, sgf_string):
color = match.group(1) # 'B' or 'W'
coord = match.group(2) # 'pd', 'dd', etc.
# تحويل الإحداثيات
x = ord(coord[0]) - ord('a')
y = ord(coord[1]) - ord('a')
moves.append((color, x, y))
return moves
استخراج الميزات
لكل موقف، استخراج 48 مستوى ميزة (انظر تصميم ميزات المدخلات):
def extract_features(board, history, current_player):
"""استخراج 48 مستوى ميزة"""
features = np.zeros((48, 19, 19))
# مواقع الأحجار
features[0] = (board == 1) # الأحجار السوداء
features[1] = (board == 2) # الأحجار البيضاء
features[2] = (board == 0) # النقاط الفارغة
# السجل التاريخي
for i, hist in enumerate(history[:8]):
features[3+i] = (hist == 1)
features[11+i] = (hist == 2)
# الحريات، الأتاري، اللادر، إلخ...
# (التنفيذ المفصل محذوف)
return features
تعزيز البيانات
لوحة الجو لها 8 تماثلات (4 دورانات × 2 انعكاس). كل عينة أصلية يمكن أن تصبح 8:
الأصلي:
| ● |
دوران 90°:
| ● |
دوران 180°:
| ● |
دوران 270°:
| ● |
كل منها يُقلب أفقياً، للحصول على 8 عينات تدريب متكافئة
هذا يزيد بيانات التدريب الفعالة 8 مرات، مع ضمان أن الأنماط التي يتعلمها النموذج لا تعتمد على اتجاه معين.
def augment(state, action):
"""تعزيز التماثل الثماني"""
augmented = []
for rotation in [0, 1, 2, 3]: # 0, 90, 180, 270 درجة
rotated_state = np.rot90(state, rotation, axes=(1, 2))
rotated_action = rotate_action(action, rotation)
augmented.append((rotated_state, rotated_action))
# القلب الأفقي
flipped_state = np.flip(rotated_state, axis=2)
flipped_action = flip_action(rotated_action)
augmented.append((flipped_state, flipped_action))
return augmented
دالة الخسارة
خسارة الإنتروبيا المتقاطعة
يستخدم التعلم الخاضع للإشراف خسارة الإنتروبيا المتقاطعة (Cross-Entropy Loss) لتدريب شبكة Policy Network:
L(θ) = -Σ log p_θ(a | s)
حيث:
s: حالة اللوحةa: الموقع الذي لعب فيه الإنسان فعلياً (العلامة)p_θ(a | s): احتمال النموذج للتنبؤ بهذا الموقع
الفهم البديهي
خسارة الإنتروبيا المتقاطعة تقيس "الفجوة بين تنبؤ النموذج والعلامة":
| السيناريو | تنبؤ النموذج | الخسارة | الشرح |
|---|---|---|---|
| تنبؤ مثالي | احتمال a = 1.0 | 0 | الأفضل |
| واثق وصحيح | احتمال a = 0.9 | 0.1 | جيد جداً |
| غير متأكد لكن صحيح | احتمال a = 0.5 | 0.7 | مقبول |
| تنبؤ خاطئ | احتمال a = 0.1 | 2.3 | سيء جداً |
| خاطئ تماماً | احتمال a = 0.01 | 4.6 | الأسوأ |
دالة الخسارة تدفع النموذج لزيادة احتمال الموقع الصحيح.
المقارنة مع MSE
لماذا لا نستخدم متوسط مربع الخطأ (MSE)؟
# MSE:
loss_mse = (prediction - target)^2
# Cross-Entropy:
loss_ce = -log(prediction[target])
| الخاصية | MSE | الإنتروبيا المتقاطعة |
|---|---|---|
| نوع الهدف | انحدار (قيم مستمرة) | تصنيف (توزيع احتمالي) |
| سلوك التدرج | كلما زاد الخطأ، زاد التدرج | عند الخطأ الواثق، التدرج أكبر |
| السيناريو المناسب | شبكة Value | شبكة Policy |
مخرجات شبكة Policy Network هي توزيع احتمالي لـ 361 فئة، والإنتروبيا المتقاطعة هي الاختيار الطبيعي.
عملية التدريب
تكوين الأجهزة
استخدمت DeepMind موارد حوسبة كبيرة:
| المورد | العدد |
|---|---|
| GPU | 50 |
| وقت التدريب | حوالي 3 أسابيع |
| حجم الدفعة | 16 |
| إجمالي خطوات التدريب | ~340M |
المحسّن
استخدام النزول التدرجي العشوائي (SGD) + الزخم:
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.003, # معدل التعلم الأولي
momentum=0.9, # معامل الزخم
weight_decay=1e-4 # تنظيم L2
)
لماذا SGD بدلاً من Adam؟
في عام 2016، كان SGD + momentum لا يزال الخيار السائد لمهام الصور. في الواقع، وجدت الأبحاث اللاحقة (بما في ذلك KataGo) أن محسّنات نوع Adam قد تكون أفضل.
جدولة معدل التعلم
معدل التعلم يتناقص تدريجياً أثناء التدريب:
scheduler = torch.optim.lr_scheduler.StepLR(
optimizer,
step_size=80_000_000, # كل 80M خطوة
gamma=0.1 # معدل التعلم × 0.1
)
معدل التعلم:
0.003 ────────┐
└─────── 0.0003 ────────┐
└─────── 0.00003
80M خطوة 160M خطوة 240M خطوة
حلقة التدريب
def train_epoch(model, dataloader, optimizer):
model.train()
total_loss = 0
correct = 0
total = 0
for batch in dataloader:
states, actions = batch
# التمرير الأمامي
policy = model(states) # (batch, 361)
# حساب الخسارة
loss = F.cross_entropy(policy, actions)
# التمرير الخلفي
optimizer.zero_grad()
loss.backward()
optimizer.step()
# الإحصائيات
total_loss += loss.item()
predictions = policy.argmax(dim=1)
correct += (predictions == actions).sum().item()
total += actions.size(0)
accuracy = correct / total
avg_loss = total_loss / len(dataloader)
return avg_loss, accuracy
منحنى التدريب
عملية التدريب النموذجية:
الدقة
60% | ......**********
| ......*
50% | ......*
| ....*
40% | ..*
|..*
30% |*
+───────────────────────────────────── خطوات التدريب
0 100M 200M 300M 340M
الخسارة والدقة سترتفعان بسرعة، ثم تستقران.
تحليل النتائج
دقة 57%
بعد التدريب الكامل، حققت شبكة Policy Network دقة top-1 بنسبة 57.0%.
ما هي دقة top-1؟
التنبؤ: النموذج يخرج 361 احتمال
Top-1: الموقع ذو أعلى احتمال
الدقة: نسبة هذا الموقع يساوي الموقع الذي لعبه الإنسان فعلياً
57% تعني: النموذج لديه أكثر من نصف الفرصة لتخمين الحركة التالية للخبير البشري.
المقارنة مع برامج أخرى
| البرنامج | دقة Top-1 | الملاحظات |
|---|---|---|
| الاختيار العشوائي | 0.4% | خط الأساس |
| ميزات تقليدية + نموذج خطي | ~24% | مستوى 2008 |
| CNN ضحلة | ~44% | مستوى 2014 |
| شبكة Policy Network لـ AlphaGo | 57% | اختراق 2016 |
| AlphaGo Zero | ~60% | 2017 |
CNN العميقة من DeepMind تحسنت بـ 13 نقطة مئوية عن أفضل طريقة سابقة.
تقييم قوة اللعب
قوة اللعب باستخدام شبكة Policy Network وحدها (بدون بحث):
| التكوين | تصنيف Elo | المستوى التقريبي |
|---|---|---|
| أقوى تقليدي (Pachi) | ~2500 | هاوي دان 4-5 |
| شبكة SL Policy | ~2800 | هاوي دان 6-7 |
التعلم الخاضع للإشراف وحده وصل بالفعل إلى مستوى الهاوي المتقدم، وهذا كان اختراقاً كبيراً في 2016.
الدقة مقابل قوة اللعب
المثير للاهتمام أن الدقة وقوة اللعب ليست علاقة خطية:
الدقة: 44% → 57% (تحسن 13%)
Elo: ~2500 → ~2800 (تحسن ~300)
نسبة تحسن الدقة: 13% / 44% ≈ 30%
نسبة تحسن Elo: 300 / 2500 ≈ 12%
تحسن بسيط في الدقة قد يجلب تحسناً كبيراً في قوة اللعب، لأن:
- الاختيارات الصحيحة في المواقف الحرجة أكثر أهمية
- تجنب الأخطاء الواضحة أهم من لعب حركات جيدة إضافية
حدود التعلم الخاضع للإشراف
المشكلة 1: تأثير السقف
التعلم الخاضع للإشراف يمكنه فقط الوصول إلى "المستوى البشري"، لا يمكنه التجاوز:
هدف شبكة SL Policy: تقليد البشر
↓
إذا كان لدى البشر عادات خاطئة
↓
شبكة SL Policy ستتعلم أيضاً هذه الأخطاء
على سبيل المثال، إذا لم يلعب اللاعبون في بيانات التدريب "الحركة 37" غير التقليدية كثيراً، فإن شبكة SL Policy لن تتعلمها أيضاً.
المشكلة 2: عدم القدرة على التمييز بين الحركة الجيدة والسيئة
التعلم الخاضع للإشراف ينظر فقط إلى "ما لعبه الإنسان"، بغض النظر عما إذا كانت الحركة جيدة أم سيئة:
الموقف A: الإنسان لعب K10 (في الواقع حركة سيئة)
الموقف B: الإنسان لعب Q4 (حركة جيدة)
شبكة SL Policy تعاملهما بالتساوي، كلاهما يجب تعلمه
بيانات التدريب تتضمن مباريات لاعبين هواة، فيها الكثير من الأخطاء. شبكة SL Policy ستتعلم هذه الأخطاء.
المشكلة 3: نقص الاستكشاف
شبكة SL Policy تتعلم فقط الحركات المعروفة للبشر:
مجموعة الحركات البشرية: {A, B, C, D, E}
↓
شبكة SL Policy ستختار فقط من هذه الحركات
↓
قد توجد حركة أفضل F، لكنها لم تُكتشف أبداً
هذا هو الحد الأساسي للتعلم الخاضع للإشراف: يمكنه فقط تعلم ما هو موجود في بيانات التدريب.
الحل: التعلم المعزز
للتجاوز على البشر، قام AlphaGo بـ التعلم المعزز بعد التعلم الخاضع للإشراف:
شبكة SL Policy (مستوى بشري)
↓ اللعب الذاتي
شبكة RL Policy (تجاوز البشر)
انظر مقدمة في التعلم المعزز واللعب الذاتي للتفاصيل.
نقاط التنفيذ
كود التدريب الكامل
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
class GoDataset(Dataset):
def __init__(self, data_path):
# تحميل البيانات المعالجة مسبقاً
self.states = np.load(f"{data_path}/states.npy")
self.actions = np.load(f"{data_path}/actions.npy")
def __len__(self):
return len(self.states)
def __getitem__(self, idx):
state = torch.FloatTensor(self.states[idx])
action = torch.LongTensor([self.actions[idx]])[0]
return state, action
def train_policy_network():
# النموذج
model = PolicyNetwork(input_channels=48, num_filters=192, num_layers=12)
model = model.cuda()
# البيانات
dataset = GoDataset("data/kgs")
dataloader = DataLoader(
dataset, batch_size=16, shuffle=True, num_workers=4
)
# المحسّن
optimizer = optim.SGD(
model.parameters(),
lr=0.003,
momentum=0.9,
weight_decay=1e-4
)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=80_000_000, gamma=0.1)
# حلقة التدريب
best_accuracy = 0
for epoch in range(100):
model.train()
total_loss = 0
correct = 0
total = 0
for states, actions in dataloader:
states = states.cuda()
actions = actions.cuda()
# التمرير الأمامي
policy = model(states)
loss = nn.functional.cross_entropy(policy, actions)
# التمرير الخلفي
optimizer.zero_grad()
loss.backward()
optimizer.step()
scheduler.step()
# الإحصائيات
total_loss += loss.item()
predictions = policy.argmax(dim=1)
correct += (predictions == actions).sum().item()
total += actions.size(0)
accuracy = correct / total
print(f"Epoch {epoch}: Loss={total_loss/len(dataloader):.4f}, Acc={accuracy:.4f}")
# حفظ أفضل نموذج
if accuracy > best_accuracy:
best_accuracy = accuracy
torch.save(model.state_dict(), "best_policy.pth")
print(f"Best accuracy: {best_accuracy:.4f}")
كود التقييم
def evaluate_policy(model, test_dataloader):
model.eval()
correct_top1 = 0
correct_top5 = 0
total = 0
with torch.no_grad():
for states, actions in test_dataloader:
states = states.cuda()
actions = actions.cuda()
policy = model(states)
# دقة Top-1
top1_pred = policy.argmax(dim=1)
correct_top1 += (top1_pred == actions).sum().item()
# دقة Top-5
top5_pred = policy.topk(5, dim=1)[1]
for i, action in enumerate(actions):
if action in top5_pred[i]:
correct_top5 += 1
total += actions.size(0)
print(f"Top-1 Accuracy: {correct_top1/total:.4f}")
print(f"Top-5 Accuracy: {correct_top5/total:.4f}")
المشاكل الشائعة والحلول
| المشكلة | الأعراض | الحل |
|---|---|---|
| الإفراط في التعلم | دقة التدريب عالية، دقة الاختبار منخفضة | زيادة تعزيز البيانات، Dropout |
| تدريب غير مستقر | تقلب حاد في الخسارة | خفض معدل التعلم، زيادة حجم الدفعة |
| تقارب بطيء | الدقة تتوقف عن التحسن | ضبط معدل التعلم، فحص البيانات |
| نقص الذاكرة | خطأ OOM | تقليل حجم الدفعة، استخدام الدقة المختلطة |
مطابقة الرسوم المتحركة
المفاهيم الأساسية المذكورة في هذا المقال ومطابقتها لأرقام الرسوم المتحركة:
| الرقم | المفهوم | المقابلة الفيزيائية/الرياضية |
|---|---|---|
| D3 | التعلم الخاضع للإشراف | تقدير الإمكانية القصوى |
| D5 | خسارة الإنتروبيا المتقاطعة | تباعد KL |
| D6 | النزول التدرجي | التحسين |
| A6 | معالجة البيانات المسبقة | التطبيع |
قراءة موسعة
- المقال السابق: الشبكات العصبية الالتفافية ولعبة الجو — كيف تعالج الشبكات العصبية الالتفافية لوحة اللعب
- المقال التالي: مقدمة في التعلم المعزز — المفتاح لتجاوز البشر
- موضوع ذو صلة: تفاصيل شبكة Policy — تفاصيل بنية الشبكة
النقاط الرئيسية
- سجلات KGS هي مصدر بيانات التدريب: حوالي 30 مليون موقف عالي الجودة
- خسارة الإنتروبيا المتقاطعة تقود التعلم: تجعل النموذج يزيد احتمال الموقع الصحيح
- دقة 57% اختراق كبير: تفوق على أفضل طريقة سابقة بـ 13 نقطة مئوية
- تعزيز التماثل الثماني: زيادة فعالة لبيانات التدريب
- للتعلم الخاضع للإشراف سقف: لا يمكن تجاوز مستوى بيانات التدريب
التعلم الخاضع للإشراف هو "نقطة البداية" لـ AlphaGo — ورث حكمة الجو البشرية لآلاف السنين، مما وضع الأساس للتعلم المعزز اللاحق.
المراجع
- Silver, D., et al. (2016). "Mastering the game of Go with deep neural networks and tree search." Nature, 529, 484-489.
- Maddison, C. J., et al. (2014). "Move Evaluation in Go Using Deep Convolutional Neural Networks." arXiv:1412.6564.
- Clark, C., & Storkey, A. (2015). "Training Deep Convolutional Neural Networks to Play Go." ICML.
- KGS Game Archives: https://www.gokgs.com/archives.jsp