تخطَّ إلى المحتوى
3/30الفصل 3 من 30

إلى أسفل الوادي: Gradient Descent والخطوتان اللتان يتخطاهما الجميع

احسب الحدّ الأعلى الدقيق لمعدل التعلّم، ثم شاهد بحثًا قسريًا عبر 3,600 اتجاه يعيد اكتشاف gradient دون أن يُخبر به.

في هذه الصفحة

انتهى الفصل السابق عند وادٍ.

ليس واديًا مجازيًا: بل منحنى فعلي، loss مرسوم مقابل معامل واحد، يهبط ثم يعود إلى الصعود. ولم تُختر loss تحته لأنها مرتّبة — بل اشتُقت من عبارة عن الضجيج في القياسات، وخرج الخطأ التربيعي من الطرف الآخر نتيجةً لا اصطلاحًا.

إذًا لدينا تضاريس لها قاع، ولدينا سبب للاعتقاد بأن القاع هو المكان الصحيح. ما لا نملكه هو طريقة للوصول إليه.

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

  • لماذا علامة الطرح. التحديث يطرح gradient. كل درس يكتبها؛ وقليل جدًا يشرح لماذا يكون gradient هو الاتجاه الذي يصعد إلى أعلى، وهي الحقيقة الوحيدة التي تجعل علامة الطرح أكثر من فعل إيمان.
  • ما حجم الخطوة. «الكبيرة جدًا تتباعد، والصغيرة جدًا بطيئة» عبارة صحيحة وعديمة الفائدة. هناك رقم دقيق، يمكن حسابه من loss، وهذا الفصل يحسبه مرتين — مرة لقطع مكافئ بسيط ومرة للبيانات الفعلية.

الإعداد، ولماذا لا يمكنك البحث فقط

رابط إلى القسم: الإعداد، ولماذا لا يمكنك البحث فقط

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

belt.pyPYTHON
import numpy as np

WIDTH  = np.array([18.0, 19.5, 20.2, 21.0, 24.0, 25.5, 23.0, 26.0])
WEIGHT = np.array([47.0, 52.0, 49.0, 55.0, 61.0, 66.0, 70.0, 58.0])

x = WIDTH  - WIDTH.mean()      # 22.15 mm
y = WEIGHT - WEIGHT.mean()     # 57.25 g

القياسات متمركزة، تمامًا كما في الفصل 1 ولسبب سيعود بعائد كبير قبل نهاية هذا الفصل. النموذج خط، y^=ax+b\hat{y} = a x + b، وloss هي متوسط الخطأ التربيعي الذي اشتقه الفصل السابق:

L(a,b)=1ni=1n(axi+byi)2L(a, b) = \frac{1}{n} \sum_{i=1}^{n} \left(a x_i + b - y_i\right)^2

معاملان. لماذا لا نجرب قيمًا كثيرة فقط؟ لنفعل ذلك فعلًا — شبكة من a=0a = 0 إلى 55 ومن b=5b = -5 إلى 55، بخطوات قدرها 0.010.01:

TEXT
grid 501 x 1001 = 501,501 evaluations in 3.67 s
  best found: a = 2.1000, b = -0.0000, L = 24.592450

نصف مليون تقييم لتثبيت رقمين حتى منزلتين عشريتين — وتلك الثانية هي زمن حائط على جهاز واحد، لذلك قد تقع إعادة التشغيل في أي مكان بين ثلاث وست؛ عدد التقييمات والحد الأدنى هما الجزء القابل لإعادة الإنتاج. Gradient descent، في نهاية هذا الفصل، يحصل على أربع منازل عشرية في ثماني خطوات وعلى إجابة float64 كاملة في ست وثلاثين.

لكن السرعة ليست الحجة، وهذه هي النقطة التي تحسم الدورة كلها. يكلف بحث الشبكة kPk^P تقييمًا من أجل PP معاملات عند kk قيم لكل منها. ومع ألف قيمة لكل محور:

النموذجالمعاملاتتقييمات الشبكة
هذا الخط210610^{6}
شبكة XOR في الفصل 59102710^{27}
شبكة صغيرة متعددة الطبقات20,0001060,00010^{60{,}000}

الصف الثالث ليس رقمًا كبيرًا، بل رقم بلا معنى — هناك تقريبًا 108010^{80} ذرة في الكون المرصود. البحث لا يصبح أبطأ مع نمو النماذج؛ بل يتوقف عن الوجود. كل ما يلي موجود بسبب ذلك الجدول.

ثبّت b=0b = 0 للحظة حتى يكون هناك معامل واحد ومنحنى واحد، وهي الصورة التي تركك معها الفصل السابق. خذ نقطة عليه، a=1a = 1، واسأل: إذا أزحت aa مقدارًا صغيرًا hh، فكم تتحرك loss لكل وحدة إزاحة؟

L(a+h)L(a)h\frac{L(a + h) - L(a)}{h}

هذه النسبة هي ارتفاع على امتداد — ميل الخط المستقيم المار بنقطتين على المنحنى. كلما صغر hh، انزلقت النقطتان معًا وصار الخط مماسًا. ميله هو المشتقة L(a)L'(a): معدل تغيّر loss لكل وحدة تغيّر في aa. ليست تقريبًا لشيء، وليست كمية متناهية الصغر. إنها حد لنسب عادية.

يستحق الأمر تشغيله، لأن الأرقام تقول شيئًا لا يقوله التعريف:

slope.pyPYTHON
def loss1(a):
    return np.mean((a * x - y) ** 2)

for h in [1.0, 1e-2, 1e-4, 1e-6, 1e-8, 1e-10, 1e-12, 1e-14]:
    q = (loss1(1.0 + h) - loss1(1.0)) / h
    print(f"h = {h:<8.0e}   slope estimate = {q:.10f}   error = {abs(q + 16.385):.3e}")
TEXT
h = 1e+00      slope estimate = -8.9400000000    error = 7.445e+00
h = 1e-02      slope estimate = -16.3105500000   error = 7.445e-02
h = 1e-04      slope estimate = -16.3842555001   error = 7.445e-04
h = 1e-06      slope estimate = -16.3849925556   error = 7.444e-06
h = 1e-08      slope estimate = -16.3850003787   error = 3.787e-07
h = 1e-10      slope estimate = -16.3850444324   error = 4.443e-05
h = 1e-12      slope estimate = -16.3851154866   error = 1.155e-04
h = 1e-14      slope estimate = -17.0530256582   error = 6.680e-01

يحدث شيئان هنا، وكلاهما أساسي.

الخطأ ليس متناسبًا بشكل مبهم مع hh — بل هو بالضبط 7.445h7.445\,h. اقسم hh على مئة، فينقسم الخطأ على مئة، إلى أربع خانات معنوية في كل مرة. ذلك الثابت ليس زينة: إنه نصف المشتقة الثانية لـ loss، وهو أول ظهور لفكرة بعد قسمين من الآن — أن المنحنى قرب نقطة يبدو كخط زائد تصحيح متناسب مع h2h^2.

ثم ينكسر النمط. تحت h=108h = 10^{-8} يصبح التقدير أسوأ، وعند 101410^{-14} يكون خاطئًا في الرقم الثاني. لم يحدث شيء رياضي؛ بل حدث صندوق الفاصلة العائمة من الفصل السابق. L(a+h)L(a+h) وL(a)L(a) يتفقان في أول عشرة أرقام، وطرحهما يدمّر تلك الأرقام، ثم القسمة على عدد صغير تضخم ما تبقى. هناك أفضل hh — هنا حول 10810^{-8}، تقريبًا الجذر التربيعي لـ machine epsilon — والذهاب إلى أصغر من ذلك ليس أكثر حذرًا، بل أقل. تذكّر ذلك؛ فدالة في نهاية هذا الفصل تعتمد عليه.

الميل الدقيق، من التفاضل لا من القياس، هو 16.385-16.385. لذا يمكننا التوقف عن القياس والبدء في الاشتقاق.

هذه هي الفكرة التي تُبنى عليها بقية الدورة، تُقال مرة واحدة بوضوح.

أن تركّب دالتين يعني أن تُدخل إحداهما في الأخرى: (fg)(x)=f(g(x))(f \circ g)(x) = f(g(x)). لا أكثر.

الشبكة العميقة ليست مثل تركيب. إنها تركيب. الطبقة دالة؛ وتكديس الطبقات هو تركيبها؛ و«العمق» هو عدد الدوال في السلسلة. عندما يبني الفصل 5 شبكة، فهو يبني f4f3f2f1f_4 \circ f_3 \circ f_2 \circ f_1 ولا شيء آخر. وهذا يعني أن أهم قاعدة تفاضل، لأغراضنا، هي التي تشتق تركيبًا:

ddxf(g(x))=f(g(x))g(x)\frac{d}{dx} f(g(x)) = f'(g(x)) \cdot g'(x)

المعدلات تتضاعف. إذا كان gg يتغير أسرع بثلاث مرات من xx، وكان ff يتغير أسرع بمرتين من gg، فإن ff يتغير أسرع بست مرات من xx. هذا هو المحتوى كله، ولهذا فإن إشارة تمر عائدة عبر عشر طبقات تُضرب في عشرة أرقام — ولهذا يقضي الفصل 6 قسمًا في ما يحدث عندما تكون تلك الأرقام كلها أقل قليلًا من واحد.

استخدمها على loss لدينا. اكتب الباقي ri=axi+byir_i = a x_i + b - y_i، بحيث L=1nri2L = \frac{1}{n}\sum r_i^2. كل rir_i يعتمد على aa عبر الدالة الداخلية axia x_i، ومشتقتها xix_i. قاعدة السلسلة، حدًا بحد:

La=1ni2rixi,Lb=1ni2ri1\frac{\partial L}{\partial a} = \frac{1}{n}\sum_i 2 r_i \cdot x_i, \qquad \frac{\partial L}{\partial b} = \frac{1}{n}\sum_i 2 r_i \cdot 1

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

L=(La, Lb)\nabla L = \left( \frac{\partial L}{\partial a},\ \frac{\partial L}{\partial b} \right)

عند النقطة (a,b)=(1,4)(a, b) = (1, 4) يكون ذلك المتجه (16.385, 8.0)(-16.385,\ 8.0). رقمان. السؤال هو ماذا يعنيان، وهذه أول خطوة يتخطاها الجميع.

Gradient متجه من الميول على طول المحاور. هذا كل ما أثبتناه. ليس بديهيًا — ولا ينبغي أن يكون بديهيًا — أن تجميعها في متجه ينتج شيئًا يشير إلى مكان محدد.

لذا عرّف الشيء الذي نريده فعلًا. اختر متجه وحدة u\mathbf{u}، أي اتجاهًا. المشتقة الاتجاهية هي معدل تغير loss وأنت تمشي في ذلك الاتجاه:

DuL=limh0L(θ+hu)L(θ)hD_{\mathbf{u}} L = \lim_{h \to 0} \frac{L(\boldsymbol{\theta} + h\mathbf{u}) - L(\boldsymbol{\theta})}{h}

تحوّل قاعدة السلسلة هذا إلى شيء قابل للحساب. المشي على طول u\mathbf{u} يغيّر aa بمعدل u1u_1 وbb بمعدل u2u_2، وتُجمع المساهمات:

DuL=Lau1+Lbu2=LuD_{\mathbf{u}} L = \frac{\partial L}{\partial a} u_1 + \frac{\partial L}{\partial b} u_2 = \nabla L \cdot \mathbf{u}

معدل التغير في أي اتجاه هو حاصل الضرب النقطي بين gradient وذلك الاتجاه. والآن الخلاصة، وهي سطر واحد من الهندسة. بكتابة الضرب النقطي مع الزاوية ϕ\phi بين المتجهين،

Lu=Lucosϕ=Lcosϕ\nabla L \cdot \mathbf{u} = \lVert \nabla L \rVert \, \lVert \mathbf{u} \rVert \cos\phi = \lVert \nabla L \rVert \cos\phi

لأن u\mathbf{u} طوله 1. الشيء الوحيد الذي تتحكم فيه هو cosϕ\cos\phi، وهو أكبر ما يكون عند ϕ=0\phi = 0 وأصغر ما يكون عند نصف دورة، ϕ=180\phi = 180 درجة. إذًا:

  • أشد صعود يكون على طول L\nabla L نفسه، والميل هناك يساوي بالضبط L\lVert \nabla L \rVert.
  • أشد نزول يكون على طول L-\nabla L، والميل هناك L-\lVert \nabla L \rVert.
  • عموديًا على gradient، لا تتغير loss إطلاقًا. ولهذا تقطع خطوط خريطة الكنتور gradient بزوايا قائمة.

هذه هي علامة الطرح. ليست اصطلاحًا، ولا قلب إشارة اختاره أحدهم: اتجاه أسرع نقصان هو gradient السالب لأن cosϕ\cos\phi يصغر عند نصف دورة، ولا سبب آخر.

وبما أن هذا ادعاء عن كل الاتجاهات، اختبره على كل الاتجاهات. خذ عينة من 3,600 اتجاه، واحد لكل عُشر درجة، وقِس كل واحد بإزاحة صغيرة:

directions.pyPYTHON
theta = np.array([1.0, 4.0])
g = grad(theta)
print("gradient      ", g)
print("its length    ", np.linalg.norm(g))
print("its angle     ", np.degrees(np.arctan2(g[1], g[0])) % 360, "degrees")

best = max(
    ((loss(theta + 1e-6 * u) - loss(theta - 1e-6 * u)) / 2e-6, np.degrees(ang))
    for ang, u in (
        (a, np.array([np.cos(a), np.sin(a)])) for a in np.arange(3600) * 2 * np.pi / 3600
    )
)
print("steepest slope", best[0], "at", best[1], "degrees")
TEXT
gradient       [-16.385   8.   ]
its length     18.23371122399386
its angle      153.97598928042032 degrees
steepest slope 18.233709624837502 at 154.0 degrees

بحث لا يعرف شيئًا عن gradients، عبر 3,600 اتجاه، يجد أشد صعود له عند 154.0 درجة — اتجاه gradient نفسه، ضمن دقة البحث البالغة 0.1 درجة. والميل الذي يجده هناك، 18.2337، هو طول gradient إلى ست خانات. النظرية ليست قصة عن معنى gradients؛ إنها حقيقة قابلة للقياس، وهذا هو القياس.

لماذا تساعد خطوة صغيرة إلى أسفل فعلًا

رابط إلى القسم: لماذا تساعد خطوة صغيرة إلى أسفل فعلًا

الآن الخطوة الثانية التي يتخطونها. نعرف أي طريق هو الأسفل. لا يلزم من ذلك أن المشي في ذلك الطريق يخفض loss، لأن «الأسفل» عبارة عن إزاحة متناهية الصغر، والخطوة ليست متناهية الصغر.

الجسر هو الخطية المحلية. قرب نقطة، تكون الدالة الملساء مماسها زائد تصحيح:

L(θ+δ)=L(θ)+Lδ+O(δ2)L(\boldsymbol{\theta} + \boldsymbol{\delta}) = L(\boldsymbol{\theta}) + \nabla L \cdot \boldsymbol{\delta} + O(\lVert\boldsymbol{\delta}\rVert^2)

هذا هو توسع تايلور من الرتبة الأولى. الجزء المهمل O(δ2)O(\lVert\boldsymbol{\delta}\rVert^2) هو التقوس — المصطلح نفسه الذي جعل تقدير جدول الميل يخطئ بالضبط بمقدار 7.445h7.445\,h. ضع فيه الخطوة التي ننوي أخذها، δ=ηL\boldsymbol{\delta} = -\eta \nabla L:

L(θηL)L(θ)ηL2L(\boldsymbol{\theta} - \eta \nabla L) \approx L(\boldsymbol{\theta}) - \eta \lVert \nabla L \rVert^2

تنخفض loss بمقدار ηL2\eta \lVert \nabla L \rVert^2. كل جزء من ذلك غير سالب، لذا الوعد حقيقي — من أجل η\eta صغير بما يكفي، لأن الحد المهمل ينمو مثل η2\eta^2 وسيبتلعه في النهاية. هذه هي النظرية كلها. إليك الوعد يتحقق، ثم ينكسر:

TEXT
eta = 0.2       promised    66.49364500   delivered   -16.01619240   ratio -0.240868
eta = 0.1       promised    33.24682250   delivered    12.61936315   ratio  0.379566
eta = 0.01      promised     3.32468225   delivered     3.11840766   ratio  0.937957
eta = 0.001     promised     0.33246822   delivered     0.33040548   ratio  0.993796
eta = 0.0001    promised     0.03324682   delivered     0.03322620   ratio  0.999380
eta = 1e-05     promised     0.00332468   delivered     0.00332448   ratio  0.999938

اقرأه من الأسفل. كلما صغر η\eta، اقترب الهبوط المنجز من الموعود — النسبة 0.99938، ثم 0.99994 — وهذا هو صحة مبرهنة تايلور. اقرأه من الأعلى، وعند η=0.2\eta = 0.2 يكون «الهبوط» المنجز سالب ستة عشر. الخطوة ذهبت إلى أسفل وloss صعدت.

إذًا قاعدة التحديث هي

θθηL(θ)\boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \nabla L(\boldsymbol{\theta})

وتأتي معها شرط لا يذكره أحد، وهو أن η\eta صغير بما يكفي. صغير بما يكفي مقارنةً بـ ماذا بالضبط؟ هذا هو القسم التالي.

ابدأ بأبسط وادٍ موجود، f(x)=x2f(x) = x^2، حيث f(x)=2xf'(x) = 2x. خطوة واحدة من gradient descent هي

xxη2x=x(12η)x \leftarrow x - \eta \cdot 2x = x\,(1 - 2\eta)

يُضرب الموضع في (12η)(1 - 2\eta) في كل خطوة. هذا متتالية هندسية، وللمتتاليات الهندسية قاعدة واحدة بالضبط: تنكمش عندما يكون المضاعِف أصغر من 1 بالقيمة المطلقة، وتنمو خلاف ذلك. لذا 12η<1\lvert 1 - 2\eta \rvert < 1، أي 0<η<10 < \eta < 1.

الحد يقع عند η=1\eta = 1 بالضبط. ليس «حوالي 1»، ولا «1 غالبًا كبير جدًا». عند η=1\eta = 1 يكون المضاعِف 1-1 وتظل النقطة ترتد بين xx وx-x إلى الأبد، لا تقترب ولا تهرب. تحته، تقارب؛ فوقه، تباعد. وينقسم المجال مرة أخرى عند η=0.5\eta = 0.5، حيث يغير المضاعِف إشارته: دونه يكون الاقتراب رتيبًا، وفوقه تتجاوز النقطة القاع وتتبادل الجانبين، وعند 0.50.5 بالضبط يكون المضاعِف 0 وخطوة واحدة تهبط على الحد الأدنى.

أربعة أنظمة من أربعة أسطر جبر. اذهب واعبر الحدود بنفسك:

عدد الخطوات: 14، والنهاية عند x = -0.0836.

عرض البيانات كجدول
خطوةxf(x)
0⁨-1.9000⁩⁨3.6100⁩
1⁨-1.5200⁩⁨2.3104⁩
2⁨-1.2160⁩⁨1.4787⁩
3⁨-0.9728⁩⁨0.9463⁩
4⁨-0.7782⁩⁨0.6057⁩
5⁨-0.6226⁩⁨0.3876⁩
6⁨-0.4981⁩⁨0.2481⁩
7⁨-0.3985⁩⁨0.1588⁩
8⁨-0.3188⁩⁨0.1016⁩
9⁨-0.2550⁩⁨0.0650⁩
10⁨-0.2040⁩⁨0.0416⁩
11⁨-0.1632⁩⁨0.0266⁩
12⁨-0.1306⁩⁨0.0170⁩
13⁨-0.1045⁩⁨0.0109⁩
14⁨-0.0836⁩⁨0.0070⁩
الانحدار التدرجي، تفاعلي

أربع عشرة خطوة بمعدل 0.1، من x=1.9x = -1.9، تنتهي عند 0.0836-0.0836. ارفع المعدل إلى 0.5 فتهبط الخطوة الأولى نفسها في القاع. ارفعه إلى 0.9 فينتهي عند 0.0836-0.0836 نفسها التي انتهى إليها 0.1 — المسافة نفسها، والأسلوب عكسي، لأن 12η\lvert 1 - 2\eta \rvert يساوي 0.8 في الحالتين — لكنه يصل إليها بالتعرج عبر الوادي بدل المشي نزولًا على جانب واحد.

والآن الحالة المثيرة:

عدد الخطوات: 14، والنهاية عند x = -1.9000.

عرض البيانات كجدول
خطوةxf(x)
0⁨-1.9000⁩⁨3.6100⁩
1⁨1.9000⁩⁨3.6100⁩
2⁨-1.9000⁩⁨3.6100⁩
3⁨1.9000⁩⁨3.6100⁩
4⁨-1.9000⁩⁨3.6100⁩
5⁨1.9000⁩⁨3.6100⁩
6⁨-1.9000⁩⁨3.6100⁩
7⁨1.9000⁩⁨3.6100⁩
8⁨-1.9000⁩⁨3.6100⁩
9⁨1.9000⁩⁨3.6100⁩
10⁨-1.9000⁩⁨3.6100⁩
11⁨1.9000⁩⁨3.6100⁩
12⁨-1.9000⁩⁨3.6100⁩
13⁨1.9000⁩⁨3.6100⁩
14⁨-1.9000⁩⁨3.6100⁩
الانحدار التدرجي، تفاعلي

على الحد تمامًا. أربع عشرة خطوة بمعدل 1، وتنتهي عند 1.9-1.9: بالضبط حيث بدأت، ولم تفعل شيئًا سوى الارتداد. إزاحة صغيرة أعلى فينمو الارتداد بدل أن يبقى ثابتًا؛ عند 1.2 يخرج عن المخطط في أربع خطوات. المعدل الكبير جدًا لا يتقارب ببطء. إنه لا يتقارب.

والآن القاعدة العامة، التي تخرج من الحجة نفسها. كان المضاعِف 12η1 - 2\eta في الحقيقة 1ηf1 - \eta f''، وقرب حد أدنى تكون لـ loss متعددة المعاملات قيمة كهذه في كل اتجاه — القيم الذاتية لمصفوفة المشتقات الثانية. يجب أن يكون كل اتجاه مستقرًا في وقت واحد، لذلك يحدَّد السقف بالأكبر:

η<2λmax\eta < \frac{2}{\lambda_{\max}}

بالنسبة إلى f(x)=x2f(x) = x^2، f=2f'' = 2، السقف 1، وهذا ما اشتققناه للتو. وبالنسبة إلى الحزام لدينا، مصفوفة المشتقات الثانية هي 2nAA\frac{2}{n} A^{\top} A حيث AA مصفوفة المدخلات ذات العمودين، وقيمها الذاتية 2 و14.89، لذا السقف هو 2/14.89=0.134322 / 14.89 = 0.13432. هذا تنبؤ بخمس خانات معنوية. اختبره:

TEXT
lr=0.1343    -> L =      24.5924
lr=0.13431   -> L =      24.5924
lr=0.13432   -> L =       4707.8       BLEW UP
lr=0.13433   -> L =  4.00452e+16       BLEW UP
lr=0.1344    -> L = 1.18229e+107       BLEW UP

خمس منازل عشرية من الاتفاق بين سطر من الجبر الخطي ومئة ألف تكرار من حلقة for.

وهنا يعود الفصل 1. كل ما سبق استخدم القياسات المتمركزة. شغّل الكود نفسه على المليمترات والغرامات الخام، فتكون القيم الذاتية 0.0298 و998.1 بدل 2 و14.89. ينهار السقف من 0.134 إلى 0.002004 — بالدقة نفسها، متقاربًا عند lr=0.002003 ومنفجرًا عند lr=0.002004.

أسوأ من السقف هو النسبة بين القيم الذاتية. يقيس عدد الشرط مدى ابتعاد الوادي عن الاستدارة: خندق طويل رفيع يفرض معدلًا صغيرًا بما يكفي للجدران الحادة، ثم يُمشى على أرض الخندق بذلك الزحف نفسه. ينتقل لدينا من 7.44 متمركزًا إلى 33,452 خامًا. ومع أفضل معدل تستطيع كل نسخة أخذه:

الميزاتعدد الشرطأفضل معدلالخطوات للوصول إلى ضمن 1% من optimum
متمركزة7.440.118410
مليمترات وغرامات خام33,4520.002003779,513

البيانات نفسها، والكود نفسه، والإجابة نفسها في النهاية — وثمانية آلاف ضعف من العمل، لأن أحدًا لم يطرح المتوسط. في الفصل 1 كلف الإغفال نفسه perceptron عاملًا قدره ستة آلاف في epochs، وكان التشخيص هناك هندسيًا: البيانات عائمة بعيدًا عن الأصل. إنها الهندسة نفسها هنا بزي optimization، ولهذا فإن تطبيع المدخلات ليس نصيحة نظافة بل حساب.1

لم يحتج أي شيء أعلاه إلى مكتبة. هذا هو optimizer كاملًا.

descent.pyPYTHON
def loss(theta):
    a, b = theta
    return np.mean((a * x + b - y) ** 2)


def grad(theta):
    a, b = theta
    residual = a * x + b - y
    return np.array([np.mean(2 * residual * x), np.mean(2 * residual)])


def descend(theta, lr, steps):
    theta = np.array(theta, dtype=float)
    for _ in range(steps):
        theta = theta - lr * grad(theta)   
    return theta


theta = descend([0.0, 0.0], lr=0.05, steps=60)
print(theta, loss(theta))
TEXT
[ 2.10040296e+00 -2.76445533e-15] 24.592448791134984

إجابة least-squares المغلقة لهذه النقاط الثماني هي a=2.100403a = 2.100403، b=0b = 0، مع loss قدرها 24.59244924.592449. وجدت الحلقة ذلك إلى ثماني خانات معنوية من دون أن تعرف أن صيغة مغلقة موجودة — وهذا مهم، لأنه من الفصل 5 فصاعدًا لن توجد واحدة.

المسار، لأن مشاهدته هي المقصود:

TEXT
   0 a=0.000000 b=0.000000 L=57.437500
   1 a=1.563750 b=0.000000 L=26.736582
   2 a=1.963288 b=-0.000000 L=24.732418
   5 a=2.098116 b=-0.000000 L=24.592488
  10 a=2.100400 b=-0.000000 L=24.592449
  60 a=2.100403 b=-0.000000 L=24.592449

تُقطع معظم المسافة في أول خطوتين، لأن gradient يكون أكبر عندما تكون أبعد ما تكون عن القاع، ثم يصغر مع الاقتراب. Gradient descent يبطئ تلقائيًا قرب حد أدنى. هذه ميزة، وهي أيضًا، في الفصل 6، مشكلة.

في الحجة حتى الآن ثغرة. تتوقف الخطوة عندما L=0\nabla L = \mathbf{0}، وكنا نسمي ذلك «الحد الأدنى». النقطة ذات gradient صفر هي نقطة حرجة، وكونها حدًا أدنى ليس إلا إحدى طرق أن تكون كذلك:

  • حد أدنى محلي: صعود في كل اتجاه، لكن ربما ليس أدنى نقطة من هذا النوع في أي مكان؛
  • حد أقصى محلي: نزول في كل اتجاه؛
  • نقطة سرج: صعود في بعض الاتجاهات ونزول في أخرى. السطح f(x,y)=x2y2f(x,y) = x^2 - y^2 له f=(2x,2y)\nabla f = (2x, -2y)، وهو صفر عند الأصل، حيث تكون الدالة حدًا أدنى على محور xx وحدًا أقصى على محور yy في الوقت نفسه.

لا يستطيع gradient descent التمييز بينها، لأنه لا ينظر إلا إلى gradient، وgradient يساوي صفرًا عند الثلاثة.

للخط لدينا نقطة حرجة واحدة وهي الإجابة — loss خطأ تربيعي على نموذج خطي هي convex، وعاء واحد، وdescent عليها لا يمكن أن يفشل في إيجاد الحد الأدنى العالمي. هذه الخاصية لا تصمد عند الاصطدام بهذه الدورة. Loss الشبكة العصبية ليست convex، ومن الفصل 5 فصاعدًا لا يوجد شيء اسمه «الحد الأدنى»: هناك كثير منها، بأعماق مختلفة، وأي واحد تحصل عليه يعتمد على أين بدأت. هذه جملة واحدة وستبقى جملة واحدة، لأن النظرية كبيرة والنتيجة العملية صغيرة.

يمكنك رؤية النتيجة كلها على منحنى واحد. خذ f(x)=x44x22+x10f(x) = \tfrac{x^4}{4} - \tfrac{x^2}{2} + \tfrac{x}{10}، وله واديان بعمقين مختلفين:

TEXT
   x =  -1.046681   f(x) =  -0.352386   minimum
   x =   0.101031   f(x) =   0.005026   maximum
   x =   0.945649   f(x) =  -0.152639   minimum

عدد الخطوات: 40، والنهاية عند x = 0.9456.

عرض البيانات كجدول
خطوةxf(x)
0⁨0.1100⁩⁨0.0050⁩
1⁨0.1122⁩⁨0.0050⁩
2⁨0.1149⁩⁨0.0049⁩
3⁨0.1182⁩⁨0.0049⁩
4⁨0.1223⁩⁨0.0048⁩
5⁨0.1275⁩⁨0.0047⁩
6⁨0.1338⁩⁨0.0045⁩
7⁨0.1416⁩⁨0.0042⁩
8⁨0.1513⁩⁨0.0038⁩
9⁨0.1633⁩⁨0.0032⁩
10⁨0.1781⁩⁨0.0022⁩
11⁨0.1962⁩⁨0.0007⁩
12⁨0.2183⁩⁨-0.0014⁩
13⁨0.2453⁩⁨-0.0046⁩
14⁨0.2779⁩⁨-0.0093⁩
15⁨0.3170⁩⁨-0.0160⁩
16⁨0.3633⁩⁨-0.0253⁩
17⁨0.4172⁩⁨-0.0377⁩
18⁨0.4783⁩⁨-0.0535⁩
19⁨0.5455⁩⁨-0.0721⁩
20⁨0.6163⁩⁨-0.0922⁩
21⁨0.6869⁩⁨-0.1116⁩
22⁨0.7526⁩⁨-0.1277⁩
23⁨0.8092⁩⁨-0.1393⁩
24⁨0.8540⁩⁨-0.1463⁩
25⁨0.8868⁩⁨-0.1499⁩
26⁨0.9091⁩⁨-0.1516⁩
27⁨0.9236⁩⁨-0.1522⁩
28⁨0.9325⁩⁨-0.1525⁩
29⁨0.9379⁩⁨-0.1526⁩
30⁨0.9411⁩⁨-0.1526⁩
31⁨0.9430⁩⁨-0.1526⁩
32⁨0.9441⁩⁨-0.1526⁩
33⁨0.9448⁩⁨-0.1526⁩
34⁨0.9451⁩⁨-0.1526⁩
35⁨0.9454⁩⁨-0.1526⁩
36⁨0.9455⁩⁨-0.1526⁩
37⁨0.9455⁩⁨-0.1526⁩
38⁨0.9456⁩⁨-0.1526⁩
39⁨0.9456⁩⁨-0.1526⁩
40⁨0.9456⁩⁨-0.1526⁩
الانحدار التدرجي، تفاعلي

أربعون خطوة من x=0.11x = 0.11، تستقر عند 0.94560.9456 — الوادي الأقل عمقًا من الاثنين. الآن حرّك نقطة البداية درجة واحدة إلى اليسار، إلى 0.100.10. المعدل نفسه، والأربعون خطوة نفسها، وتستقر عند 1.0461-1.0461 بدلًا من ذلك، حيث loss أقل بمقدار 0.199747. خط تقسيم المياه هو الحدبة عند 0.1010310.101031، والفرق كله بين الإجابتين هو على أي جانب منها صادف أنك بدأت.

الهبوط في الوادي الضحل أسوأ في loss بنسبة 56.7%، ولا تملك الخوارزمية طريقة لمعرفة ذلك، لأن كل اتجاه من داخل وادٍ هو صعود. لا إصلاح لهذا في gradient descent، ولن يأتي إصلاح. الموجود عمليًا هو أن الأمر أقل أهمية بكثير مما توحي به هذه الصورة — في الأبعاد العالية جدًا لشبكة حقيقية يتضح أن معظم النقاط الحرجة سروج لا مصائد،2 والفصل 5 يقيس كم مرة تعلق شبكة صغيرة فعلًا.

ينبغي أن يزعجك شيء واحد في grad أعلاه: إنه يجمع على مجموعة البيانات كلها في كل خطوة. ثمانية أجزاء لا شيء. مليون يعني مليون حساب gradient لتحريك المعاملات مرة واحدة.

المخرج هو أن gradient متوسط، ويمكن تقدير المتوسط من عينة. احسبه على حفنة عشوائية — minibatch — وخذ خطوة عليها. التقدير صاخب؛ لكنه أيضًا غير متحيز، ومئات الخطوات الصاخبة الرخيصة تتفوق على خطوة دقيقة واحدة مكلفة. على مئة ألف قطعة اصطناعية، مع عدّ gradients لكل مثال بدل الخطوات:

الطريقةالخطوات للوصول إلى ضمن 0.1% من optimumgradients لكل مثال
full batch7700,000
minibatch بحجم 321003,200
مثال واحد في كل مرة17,58017,580

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

Momentum هو الإصلاح الرخيص الآخر، وهو مصوّب مباشرة إلى الخندق. في وادٍ سيئ التكييف تتعرج الخطوات عبر الاتجاه الضيق بينما تزحف على الاتجاه الطويل. يحتفظ Momentum بمتوسط جارٍ لـ gradients الماضية، فتتلاشى المكونات المتذبذبة ويتراكم المكون المتسق:4

vβv+L(θ),θθηv\mathbf{v} \leftarrow \beta \mathbf{v} + \nabla L(\boldsymbol{\theta}), \qquad \boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \mathbf{v}

سطران إضافيان. على الحزام الخام غير المتمركز — عدد شرط 33,452، أسوأ حالة لدينا — عند أفضل معدل يمكن لـ descent العادي أخذه:

TEXT
momentum beta=0.0   ->    79,513 steps to 1%
momentum beta=0.9   ->     1,609 steps to 1%
momentum beta=0.99  ->       461 steps to 1%

عامل 172 مقابل سطرين من الكود. يحوّل الفصل 6 هذا إلى Adam؛ الآلية موجودة هنا بالفعل.

كل gradient في هذا الفصل اشتُق يدويًا، وبالتالي قد يكون خاطئًا. الإصلاح هو جدول الميل من البداية: قِس المشتقة عدديًا وقارن. استخدم الفرق المركزي، L(θ+h)L(θh)2h\frac{L(\theta+h) - L(\theta-h)}{2h}، لأنه يلغي حد الخطأ الرائد ويكون أدق بكثير عند hh نفسه.

gradcheck.pyPYTHON
def numeric_grad(f, theta, h=1e-5):
    theta = np.asarray(theta, dtype=float)
    out = np.zeros_like(theta)
    for i in range(theta.size):
        bump = np.zeros_like(theta)
        bump[i] = h
        out[i] = (f(theta + bump) - f(theta - bump)) / (2 * h)     
    return out


def gradcheck(f, df, theta, h=1e-5):
    analytic = np.asarray(df(theta), dtype=float)
    numeric = numeric_grad(f, theta, h)
    return np.max(np.abs(analytic - numeric) / np.maximum(1e-8, np.abs(analytic) + np.abs(numeric)))

الصيغة النسبية للمقارنة مهمة: فرق مطلق قدره 10410^{-4} كارثة على gradient حجمه 10310^{-3}، ولا يهم على واحد حجمه 10610^{6}.

TEXT
relative error: 1.8929136036763527e-11
with 2 dropped: 0.33333333331650744

السطر الأول هو gradient المشتق يدويًا أعلاه. الثاني هو الدالة نفسها مع ترك عامل 2 خارج مكون واحد — خطأ مطبعي من حرف واحد — ويمسكه الفحص فورًا. أي شيء تحت نحو 10710^{-7} هو اتفاق؛ وأي شيء فوق 10410^{-4} هو علة. احتفظ بهذه الدالة: يستخدمها الفصل 5 لتصحيح محرك automatic differentiation، وهي السبب الوحيد الذي يجعل العثور على gradient خاطئ ممكنًا أصلًا.

كل شيء في هذا الفصل استند إلى افتراض لم يُذكر قط: أنك تستطيع كتابة L/θ\partial L / \partial \theta.

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

الشبكةالعمليات في مشتقة جزئية واحدة
أربع وحدات مخفية، طبقة واحدة40
أربع وحدات مخفية، طبقتان301
أربع وحدات مخفية، ثلاث طبقات1,717

الصف الثالث شبكة ذات 57 معاملًا — شبكة صغيرة جدًا لدرجة أنها ستكون حاشية في الفصل 6 — وكتابة gradient لها يدويًا تعني نحو 97,869 عملية لمثال تدريب واحد. لا توجد صياغة رمزية تنقذ هذا. ما ينقذه هو ملاحظة أن قاعدة السلسلة المطبقة على تركيب تملك بنية هائلة، وأن الكميات الوسيطة نفسها تظهر مرارًا، وأن حسابها بالترتيب الصحيح يعطي كل المشتقات تقريبًا بثمن تمريرة أمامية واحدة. هذا هو الفصل 5.

لكن هناك مشكلة أصغر أولًا، وهي تنتظر فورًا.

لدينا الآن آلة ستتدحرج إلى أسفل على أي loss قابلة للاشتقاق. وجّهها إلى سؤال الحزام الأصلي — اقبل أو ارفض، هدفه 1 أو 0 — وضع sigmoid على الخرج حتى يتنبأ باحتمال، وقلّل الخطأ التربيعي. ستعمل. لكنها بالكاد ستتحرك عندما تكون أكثر خطأً، وgradient يشرح السبب:

الخرج zzالتنبؤالحقيقةgradient مع الخطأ التربيعيgradient مع cross-entropy
000.500012.5×1012.5 \times 10^{-1}5.0×1015.0 \times 10^{-1}
2-20.119211.850×1011.850 \times 10^{-1}8.808×1018.808 \times 10^{-1}
6-60.002514.921×1034.921 \times 10^{-3}9.975×1019.975 \times 10^{-1}
10-104.54×1054.54 \times 10^{-5}19.079×1059.079 \times 10^{-5}1.0001.000

نموذج مخطئ بثقة وبشكل كارثي — يتنبأ بـ 0.0000454 عندما تكون الإجابة 1 — ينتج gradient للخطأ التربيعي قدره 9×1059 \times 10^{-5}. لا فكرة لديه أنه في ورطة. العمود الآخر، من loss لم نشتقها بعد، يبلغ 1.0: أقصى إلحاح، بالضبط حيث يستحق.

وهذا يطرح السؤال الذي يبدأ به الفصل التالي. قال الفصل السابق إن loss افتراض عن الضجيج، وإن الخطأ التربيعي يفترض ضجيجًا Gaussian. ما نموذج الضجيج لإجابة نعم أو لا — وما loss التي تخرج عندما تُجري الاشتقاق نفسه عليها؟


الطريقة أقدم من كل هذه: وصفها Cauchy في مذكرة إلى Académie des Sciences عام 1847، كطريقة لحل أنظمة المعادلات بالمشي إلى أسفل على مجموع مربعات بواقيها. ومن المفيد أيضًا القراءة إلى جانب هذا الفصل: مقال Sebastian Ruder بعنوان An overview of gradient descent optimization algorithms (arXiv:1609.04747)، الذي يغطي momentum وصولًا إلى Adam في أربع عشرة صفحة سهلة القراءة؛ والفصل 3 من كتاب Nocedal وWright Numerical Optimization (الطبعة الثانية، Springer، 2006)، حيث تعطي المبرهنة 3.3 معدل تقارب steepest descent على دالة تربيعية بدلالة عدد الشرط — إنها النظرية وراء سبب أن التكييف يحدد عدد الخطوات، رغم أنها تعالج line search بدل سقف 2/λmax2/\lambda_{\max} ذي الخطوة الثابتة المقاس أعلاه، أو §5.8 و§7.1 من كتاب Deisenroth وFaisal وOng Mathematics for Machine Learning للمجال نفسه بأدوات أقل؛ و§6.1 من كتاب Prince Understanding Deep Learning و§4.3 من كتاب Goodfellow وBengio وCourville Deep Learning؛ وDive into Deep Learning §12.1–12.3، الذي يقدم تحليل minibatch بقياسات أكثر مما تتسع له المساحة هنا؛ والفصل 4 من كتاب Géron Hands-On Machine Learning (الطبعة الثالثة)، وهو المعالجة الأكثر عملية لمعدل التعلّم باعتباره شيئًا تضبطه بدل أن تشتقه. تضع ملاحظات MIT 6.390 gradient descent قبل التصنيف، كما تفعل هذه الدورة، وللسبب نفسه.

  1. LeCun, Y., Bottou, L., Orr, G. B. and Müller, K.-R. Efficient BackProp, in Neural Networks: Tricks of the Trade (Springer, 1998), pp. 9–50. يقدّم القسم 4.3 التوصية، ويقدّم القسم 5.1 الحجة المستخدمة في صندوق التفاصيل أعلاه: تمركز المدخلات وتحجيمها يغيران القيم الذاتية لمصفوفة المشتقات الثانية، وبالتالي عدد الخطوات، لا مجرد الراحة العددية.

  2. Dauphin, Y. N., Pascanu, R., Gulcehre, C., Cho, K., Ganguli, S. and Bengio, Y. Identifying and attacking the saddle point problem in high-dimensional non-convex optimization, arXiv:1406.2572 (2014). الحجة أن النقاط الحرجة في الأبعاد العالية تكون بأغلبية ساحقة سروجًا لا حدودًا دنيا محلية، لأن الحد الأدنى يتطلب أن ينحني كل واحد من آلاف الاتجاهات إلى أعلى في الوقت نفسه.

  3. Robbins, H. and Monro, S. A Stochastic Approximation Method. Annals of Mathematical Statistics 22(3), pp. 400–407 (1951). الورقة التي أثبتت أن تقديرًا صاخبًا لـ gradient يكفي، إذا كان حجم الخطوة ينكمش بالطريقة الصحيحة.

  4. Polyak, B. T. Some methods of speeding up the convergence of iteration methods. USSR Computational Mathematics and Mathematical Physics 4(5), pp. 1–17 (1964). طريقة الكرة الثقيلة، وهي تحديث momentum أعلاه، قبل اثنين وعشرين عامًا من وصول backpropagation إلى هذا المجال.

هل أنت مستعد لتترك الاختيار لـ LIA؟

ابنِ بكل نماذج الذكاء الاصطناعي في مكان واحد — ابدأ مجانًا اليوم.