🌐 Update translations via Co-op Translator
This commit is contained in:
parent
257d24b274
commit
a49308da3d
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ للقيم السلبية والإيجابية لعينات التدريب، على التوالي\n",
|
||||
" * $\\mathcal{M}$ - مجموعة الأمثلة التي تم تصنيفها بشكل خاطئ\n",
|
||||
" \n",
|
||||
"سنستخدم عملية **الانحدار التدريجي**. بدءًا بأوزان عشوائية أولية $\\mathbf{w}^{(0)}$، سنقوم بتعديل الأوزان في كل خطوة من خطوات التدريب باستخدام التدرج لـ $E$:\n",
|
||||
"سنستخدم عملية **الانحدار التدريجي**. بدءًا من أوزان عشوائية ابتدائية $\\mathbf{w}^{(0)}$، سنقوم بتعديل الأوزان في كل خطوة من خطوات التدريب باستخدام التدرج لـ $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -272,7 +272,20 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
":الآن دعونا نقوم بتشغيل التدريب على مجموعة البيانات الخاصة بنا\n"
|
||||
"**ملاحظة حول معدل التعلم**: يتحكم معامل `learning_rate` (القيمة الافتراضية `0.01`) في مقدار تعديل الأوزان خلال كل خطوة تدريب. يتم تنفيذ ذلك باستخدام صيغة تحديث الانحدار المتدرج:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- معدل تعلم أكبر (مثل `1.0`) يجعل الخوارزمية تتعلم بشكل أسرع ولكنه قد يتجاوز الحل الأمثل.\n",
|
||||
"- معدل تعلم أصغر (مثل `0.001`) يتعلم بشكل أبطأ ولكنه قد يتقارب بدقة أكبر.\n",
|
||||
"- يمكنك التجربة عن طريق استدعاء: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
":الآن دعنا نقوم بتشغيل التدريب على مجموعة البيانات الخاصة بنا\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"كما ترى، الدقة الأولية تكون حوالي 50%، لكنها ترتفع بسرعة إلى قيم أعلى قريبة من 90%.\n",
|
||||
"\n",
|
||||
"دعونا نتصور كيف يتم فصل الفئات. وظيفة التصنيف لدينا تبدو كالتالي $\\mathbf{w}^Tx$، وهي أكبر من 0 لفئة واحدة، وأقل من 0 للفئة الأخرى. وبالتالي، يتم تعريف خط الفصل بين الفئات بواسطة $\\mathbf{w}^Tx = 0$. وبما أن لدينا بعدين فقط $x_0$ و $x_1$، فإن معادلة الخط ستكون $w_0x_0+w_1x_1+w_2 = 0$ (تذكر أننا قمنا بتعريف بعد إضافي صراحةً $x_2=1$). دعونا نرسم هذا الخط:\n"
|
||||
"دعونا نتصور كيف يتم فصل الفئات. وظيفة التصنيف لدينا تبدو كالتالي $\\mathbf{w}^Tx$، وهي أكبر من 0 لفئة واحدة، وأقل من 0 للفئة الأخرى. وبالتالي، يتم تعريف خط الفصل بين الفئات بواسطة $\\mathbf{w}^Tx = 0$. وبما أن لدينا بعدين فقط $x_0$ و $x_1$، فإن معادلة الخط ستكون $w_0x_0+w_1x_1+w_2 = 0$ (تذكر أننا قمنا بتعريف بعد إضافي بشكل صريح $x_2=1$). دعونا نرسم هذا الخط:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## تجربة معدلات التعلم\n",
|
||||
"\n",
|
||||
"الآن دعونا نستكشف كيف تؤثر معدلات التعلم المختلفة على عملية التدريب. معدل التعلم يتحكم في حجم الخطوة في نزول التدرج - وهو معلمة فائقة الأهمية تؤثر على سرعة التقارب واستقرار العملية.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### تجربة تفاعلية لمعدل التعلم\n",
|
||||
"\n",
|
||||
"استخدم شريط التمرير أدناه لتجربة معدلات تعلم مختلفة بشكل تفاعلي ومشاهدة تأثيرها على حدود القرار:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -379,9 +505,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## تقييم على مجموعة البيانات الاختبارية\n",
|
||||
"## تقييم على مجموعة بيانات الاختبار\n",
|
||||
"\n",
|
||||
"في البداية، قمنا بفصل بعض البيانات لتكون في مجموعة البيانات الاختبارية. دعونا نرى مدى دقة المصنف الخاص بنا على هذه المجموعة. للقيام بذلك، نقوم أيضًا بتوسيع مجموعة البيانات الاختبارية بإضافة بُعد إضافي، ثم نضربها في مصفوفة الأوزان، ونتأكد من أن القيمة الناتجة تحمل نفس الإشارة مثل التصنيف (+1 أو -1). بعد ذلك، نجمع جميع القيم البوليانية ونقسمها على طول عينة الاختبار للحصول على الدقة:\n"
|
||||
"في البداية، قمنا بفصل بعض البيانات لتكون في مجموعة بيانات الاختبار. دعونا نرى مدى دقة المصنف الخاص بنا على هذه المجموعة. للقيام بذلك، نقوم أيضًا بتوسيع مجموعة بيانات الاختبار بإضافة بُعد إضافي، ثم نضربها في مصفوفة الأوزان، ونتأكد من أن القيمة الناتجة تحمل نفس الإشارة مثل التصنيف (+1 أو -1). بعد ذلك، نجمع جميع القيم المنطقية ونقسمها على طول عينة الاختبار للحصول على الدقة:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,7 +655,7 @@
|
|||
"source": [
|
||||
"## قيود بيرسيبترون\n",
|
||||
"\n",
|
||||
"كما رأيت أعلاه، بيرسيبترون هو **مصنف خطي**. يمكنه التمييز بين فئتين بشكل جيد إذا كانتا **قابلتين للفصل خطيًا**، أي يمكن فصلهما بخط مستقيم. خلاف ذلك، لن تتقارب عملية تدريب بيرسيبترون.\n",
|
||||
"كما رأيت أعلاه، فإن بيرسيبترون هو **مصنف خطي**. يمكنه التمييز بين فئتين بشكل جيد إذا كانتا **قابلتين للفصل خطيًا**، أي يمكن فصلهما بخط مستقيم. خلاف ذلك، لن تتقارب عملية تدريب بيرسيبترون.\n",
|
||||
"\n",
|
||||
"أحد الأمثلة الأكثر وضوحًا على مشكلة لا يمكن حلها بواسطة بيرسيبترون هي ما يُعرف بـ **مشكلة XOR**. نريد أن يتعلم بيرسيبترون وظيفة XOR المنطقية، والتي تحتوي على جدول الحقيقة التالي:\n",
|
||||
"\n",
|
||||
|
|
@ -538,7 +664,7 @@
|
|||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"دعونا نحاول القيام بذلك! سنقوم بملء جميع عينات التدريب الإيجابية والسلبية يدويًا، ثم نستدعي وظيفة التدريب التي قمنا بتعريفها أعلاه:\n"
|
||||
"دعونا نحاول القيام بذلك! سنقوم يدويًا بملء جميع عينات التدريب الإيجابية والسلبية، ثم نستدعي وظيفة التدريب التي قمنا بتعريفها أعلاه:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -617,7 +743,7 @@
|
|||
"\n",
|
||||
"جميع الأرقام ممثلة بصور رمادية بحجم 28x28 بكسل.\n",
|
||||
"\n",
|
||||
"> مجموعة بيانات MNIST متاحة كمنافسة تدريبية على [Kaggle](https://www.kaggle.com/c/digit-recognizer)، وهو موقع يستضيف مسابقات وفعاليات التعلم الآلي. بمجرد أن تتعلم كيفية تصنيف أرقام MNIST، يمكنك تقديم الحل الخاص بك إلى Kaggle لترى كيف يتم تقييمه بين المشاركين الآخرين.\n",
|
||||
"> مجموعة بيانات MNIST متاحة كمنافسة تدريبية على [Kaggle](https://www.kaggle.com/c/digit-recognizer)، وهو موقع يستضيف مسابقات ومنافسات التعلم الآلي. بمجرد أن تتعلم كيفية تصنيف أرقام MNIST، يمكنك تقديم حلك إلى Kaggle لترى كيف يتم تقييمه بين المشاركين الآخرين.\n",
|
||||
"\n",
|
||||
"نبدأ بتحميل مجموعة بيانات MNIST:\n"
|
||||
]
|
||||
|
|
@ -644,7 +770,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"لنقم الآن برسم مجموعة البيانات:\n"
|
||||
":الآن دعونا نرسم مجموعة البيانات\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"لأن بيرسيبترون هو مصنف ثنائي، سنقتصر مشكلتنا على التعرف على رقمين فقط. الدالة أدناه ستقوم بملء مصفوفات العينات الإيجابية والسلبية برقمين محددين (وستعرض أيضًا عينات من هذه الأرقام للتوضيح).\n"
|
||||
"لأن بيرسيبترون هو مصنف ثنائي، سنقتصر مشكلتنا على التعرف على رقمين فقط. الوظيفة أدناه ستقوم بملء مصفوفات العينات الإيجابية والسلبية برقمين محددين (وستعرض أيضًا عينات من هذه الأرقام للتوضيح).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -831,11 +957,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"يرجى ملاحظة كيف ترتفع الدقة إلى ما يقارب 100% بسرعة كبيرة.\n",
|
||||
"يرجى ملاحظة كيف ترتفع الدقة بسرعة لتصل إلى ما يقارب 100%.\n",
|
||||
"\n",
|
||||
"يرجى تحريك شريط التمرير إلى موقع ما قرب نهاية التدريب، وملاحظة مصفوفة الأوزان المرسومة على اليسار. ستساعدك هذه المصفوفة على فهم كيفية عمل البرسيبترون فعليًا. يمكنك رؤية القيم العالية للأوزان في منتصف الحقل، والتي تتوافق مع البكسلات التي تكون عادةً موجودة للرقم 1، والقيم السلبية المنخفضة على الجوانب، حيث توجد أجزاء من الرقم 0. لذلك، إذا كان الرقم المعروض على البرسيبترون هو في الواقع 1، فإن الجزء الأوسط منه سيتم ضربه بقيم عالية، مما ينتج عنه نتيجة إيجابية. وعلى العكس، عندما يلاحظ البرسيبترون الرقم 0، فإن البكسلات المقابلة سيتم ضربها بأرقام سلبية.\n",
|
||||
"يرجى تحريك شريط التمرير إلى موقع ما قرب نهاية التدريب، وملاحظة مصفوفة الأوزان المعروضة على اليسار. هذه المصفوفة ستساعدك على فهم كيفية عمل البرسيبترون. يمكنك رؤية قيم الأوزان العالية في منتصف المجال، والتي تتوافق مع البكسلات التي تكون عادة موجودة للرقم 1، وقيم سلبية منخفضة على الجوانب، حيث توجد أجزاء الرقم 0. لذا، إذا كان الرقم المعروض على البرسيبترون هو بالفعل 1، فإن الجزء الأوسط منه سيتم ضربه بقيم عالية، مما ينتج عنه نتيجة إيجابية. وعلى العكس، عندما يلاحظ البرسيبترون الرقم 0، سيتم ضرب البكسلات المقابلة بأرقام سلبية.\n",
|
||||
"\n",
|
||||
"> قد تلاحظ أنه إذا قدمنا للبرسيبترون الرقم 1 مع انحراف طفيف أفقيًا، بحيث تشغل بكسلاته المكان الذي توجد فيه الأجزاء الرأسية للرقم 0، فقد نحصل على نتيجة غير صحيحة. نظرًا لأن طبيعة مجموعة بيانات MNIST لدينا هي أن جميع الأرقام تكون متمركزة ومضبوطة بشكل صحيح، فإن البرسيبترون يعتمد على ذلك للتمييز بين الأرقام.\n",
|
||||
"> قد تلاحظ أنه إذا قدمنا للبرسيبترون الرقم 1 وهو منحرف قليلاً أفقيًا، بحيث تشغل بكسلاته المكان الذي توجد فيه الأجزاء العمودية للرقم 0، فقد نحصل على نتيجة غير صحيحة. نظرًا لأن طبيعة مجموعة بيانات MNIST هي أن جميع الأرقام تكون متمركزة وموضوعة بشكل صحيح، ويعتمد البرسيبترون على ذلك للتمييز بين الأرقام.\n",
|
||||
"\n",
|
||||
"الآن دعونا نجرب أرقامًا مختلفة:\n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"لسبب ما، الرقمين 2 و5 ليس من السهل فصلهما. على الرغم من أننا نحصل على دقة عالية نسبيًا (أكثر من 85%)، يمكننا بوضوح رؤية كيف يتوقف perceptron عن التعلم في مرحلة معينة.\n",
|
||||
"\n",
|
||||
"لفهم سبب حدوث ذلك، يمكننا محاولة استخدام [تحليل المكونات الرئيسية](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). إنها تقنية تعلم آلي تُستخدم لتقليل أبعاد مجموعة البيانات المدخلة، بطريقة تتيح الحصول على أفضل فصل بين الفئات.\n",
|
||||
"لفهم سبب حدوث ذلك، يمكننا محاولة استخدام [تحليل المكونات الرئيسية](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). إنها تقنية تعلم آلي تُستخدم لتقليل الأبعاد في مجموعة البيانات المدخلة، بطريقة تتيح الحصول على أفضل فصل بين الفئات.\n",
|
||||
"\n",
|
||||
"في حالتنا، تحتوي الصورة المدخلة على 784 بكسل (ميزات المدخلات)، ونريد استخدام PCA لتقليل عدد المعلمات إلى اثنتين فقط، حتى نتمكن من رسمهما على الرسم البياني. ستكون هاتان المعلمتان عبارة عن مزيج خطي من الميزات الأصلية، ويمكننا اعتبار هذه العملية بمثابة \"تدوير\" فضائنا الأصلي ذي الأبعاد الـ784 ومراقبة إسقاطه على فضاء ثنائي الأبعاد، حتى نحصل على أفضل رؤية تفصل بين الفئات.\n"
|
||||
"في حالتنا، تحتوي الصورة المدخلة على 784 بكسل (ميزات مدخلة)، ونريد استخدام PCA لتقليل عدد المعلمات إلى اثنتين فقط، حتى نتمكن من رسمهما على الرسم البياني. هاتان المعلمتان ستكونان مزيجًا خطيًا من الميزات الأصلية، ويمكننا اعتبار هذه العملية بمثابة \"تدوير\" فضائنا الأصلي ذي الأبعاد الـ784 ومراقبة إسقاطه على فضاء ثنائي الأبعاد، حتى نحصل على أفضل رؤية تفصل بين الفئات.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,15 +1155,15 @@
|
|||
"source": [
|
||||
"كما ترى، يمكن فصل الرقمين 0 و 1 بوضوح باستخدام خط مستقيم. يشير هذا إلى أنه في الفضاء الأصلي ذو الأبعاد الـ784، يمكن فصل النقاط التي تمثل الأرقام خطيًا أيضًا. أما في حالة الرقمين 2 و 5، فلا يمكننا العثور على إسقاط جيد يفصل بين الأرقام بوضوح، وبالتالي هناك بعض الحالات التي يحدث فيها تصنيف خاطئ.\n",
|
||||
"\n",
|
||||
"> لاحقًا في هذه الدورة، سنتعلم كيفية إنشاء مصنفات غير خطية باستخدام الشبكات العصبية، وكيفية التعامل مع مشكلة عدم محاذاة الأرقام بشكل صحيح. قريبًا جدًا سنحقق دقة تتجاوز 99% في تصنيف أرقام MNIST، مع تصنيفها إلى 10 فئات مختلفة.\n",
|
||||
"> لاحقًا في هذه الدورة، سنتعلم كيفية إنشاء مصنفات غير خطية باستخدام الشبكات العصبية، وكيفية التعامل مع مشكلة عدم محاذاة الأرقام بشكل صحيح. قريبًا جدًا سنصل إلى دقة تتجاوز 99% في تصنيف أرقام MNIST، مع تصنيفها إلى 10 فئات مختلفة.\n",
|
||||
"\n",
|
||||
"## النقاط الرئيسية\n",
|
||||
"\n",
|
||||
" * تعلمنا عن أبسط بنية للشبكات العصبية - وهي طبقة واحدة من بيرسيبترون.\n",
|
||||
" * قمنا بتنفيذ بيرسيبترون \"يدويًا\"، باستخدام إجراء تدريب بسيط يعتمد على الانحدار التدريجي.\n",
|
||||
" * على الرغم من بساطته، يمكن لبيرسيبترون ذو الطبقة الواحدة حل مشاكل معقدة نسبيًا مثل التعرف على الأرقام المكتوبة بخط اليد.\n",
|
||||
" * بيرسيبترون ذو الطبقة الواحدة هو مصنف خطي، وبالتالي يوفر نفس قوة التصنيف التي تقدمها الانحدار اللوجستي.\n",
|
||||
" * في فضاء العينات، يمكن لبيرسيبترون فصل فئتين من بيانات الإدخال باستخدام مستوى فوقي.\n"
|
||||
" * تعلمنا عن أبسط بنية للشبكات العصبية - وهي طبقة واحدة من الـ perceptron.\n",
|
||||
" * قمنا بتنفيذ perceptron \"يدويًا\"، باستخدام إجراء تدريب بسيط يعتمد على الانحدار التدريجي.\n",
|
||||
" * على الرغم من بساطته، يمكن لـ perceptron ذو الطبقة الواحدة حل مشاكل معقدة نسبيًا مثل التعرف على الأرقام المكتوبة بخط اليد.\n",
|
||||
" * الـ perceptron ذو الطبقة الواحدة هو مصنف خطي، وبالتالي يوفر نفس قوة التصنيف التي تقدمها الانحدار اللوجستي.\n",
|
||||
" * في فضاء العينات، يمكن لـ perceptron فصل فئتين من بيانات الإدخال باستخدام مستوى فائق.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**إخلاء المسؤولية**: \nتم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي [Co-op Translator](https://github.com/Azure/co-op-translator). بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الرسمي. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة ناتجة عن استخدام هذه الترجمة.\n"
|
||||
"\n---\n\n**إخلاء المسؤولية**: \nتم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي [Co-op Translator](https://github.com/Azure/co-op-translator). بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو معلومات غير دقيقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الرسمي. للحصول على معلومات حاسمة، يُوصى بالاستعانة بترجمة بشرية احترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة ناتجة عن استخدام هذه الترجمة.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:09:54+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:55:32+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "ar"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Примерен проблем\n",
|
||||
"\n",
|
||||
"За начало, нека разгледаме един примерен проблем, при който имаме две входни характеристики. Например, в медицината може да искаме да класифицираме туморите като доброкачествени или злокачествени, в зависимост от техния размер и възраст.\n",
|
||||
"За начало, нека разгледаме един примерен проблем, при който имаме два входни признака. Например, в медицината може да искаме да класифицираме туморите като доброкачествени или злокачествени, в зависимост от техния размер и възраст.\n",
|
||||
"\n",
|
||||
"Ще генерираме случайна класификационна база данни, използвайки функцията `make_classification` от библиотеката SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Въпреки това, една обща линейна моделна формула трябва да включва и отклонение (bias), т.е. идеално би трябвало да изчислим $y$ като $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. За да опростим модела си, можем да премахнем този термин за отклонение, като добавим още едно измерение към входните характеристики, което винаги е равно на 1:\n"
|
||||
"Въпреки това, общият линеен модел трябва да има и отклонение (bias), т.е. идеално би трябвало да изчислим $y$ като $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. За да опростим модела си, можем да премахнем този термин за отклонение, като добавим още едно измерение към нашите входни характеристики, което винаги е равно на 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -219,7 +219,7 @@
|
|||
"\n",
|
||||
"където $\\eta$ е **скорост на обучение**, а $\\tau\\in\\mathbb{N}$ - номер на итерацията.\n",
|
||||
"\n",
|
||||
"Нека дефинираме този алгоритъм на Python:\n"
|
||||
"Нека дефинираме този алгоритъм в Python:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Бележка за скоростта на обучение**: Параметърът `learning_rate` (по подразбиране `0.01`) контролира колко коригираме теглата по време на всяка стъпка на обучение. Това прилага формулата за обновяване чрез градиентен спуск:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- По-голяма скорост на обучение (например `1.0`) кара перцептрона да учи по-бързо, но може да пропусне оптималното решение\n",
|
||||
"- По-малка скорост на обучение (например `0.001`) учи по-бавно, но може да се сближи по-прецизно\n",
|
||||
"- Можете да експериментирате, като извикате: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Експериментиране с темповете на обучение\n",
|
||||
"\n",
|
||||
"Сега нека разгледаме как различните темпове на обучение влияят върху процеса на обучение. Темпът на обучение контролира размера на стъпката в градиентния спуск - ключов хиперпараметър, който влияе както на скоростта на сближаване, така и на стабилността.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Интерактивен експеримент с темпа на обучение\n",
|
||||
"\n",
|
||||
"Използвайте плъзгача по-долу, за да експериментирате интерактивно с различни темпове на обучение и да видите как те влияят на границата на решение:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Оценка върху тестовия набор от данни\n",
|
||||
"\n",
|
||||
"В началото отделихме част от данните за тестовия набор. Нека видим колко точен е нашият класификатор върху този тестов набор. За да направим това, разширяваме тестовия набор с допълнително измерение, умножаваме го с матрицата на теглата и се уверяваме, че получената стойност има същия знак като етикета (+1 или -1). След това събираме всички булеви стойности и ги делим на дължината на тестовата извадка, за да получим точността:\n"
|
||||
"В началото отделихме част от данните за тестовия набор. Нека видим колко точен е нашият класификатор върху този тестов набор. За да направим това, разширяваме тестовия набор с допълнително измерение, умножаваме по матрицата на теглата и се уверяваме, че получената стойност има същия знак като етикета (+1 или -1). След това събираме всички булеви стойности и ги делим на дължината на тестовата извадка, за да получим точността:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Както можете да видите от графиката по-горе, точността никога не надвишава 75%, защото е невъзможно да се начертае права линия така, че да се обхванат всички възможни примери правилно.\n",
|
||||
"Както можете да видите от графиката по-горе, точността никога не надвишава 75%, защото е невъзможно да се начертае права линия, която да обхване всички възможни примери правилно.\n",
|
||||
"\n",
|
||||
"Проблемът XOR е класически пример за ограниченията на перцептрона и беше посочен от Марвин Мински и Сиймур Пейпърт през 1969 г. в тяхната книга [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Това наблюдение ограничи изследванията в областта на невронните мрежи за почти 10 години, въпреки че - както ще видим в следващата секция на нашия курс - многослойните перцептрони са напълно способни да решават такива проблеми.\n",
|
||||
"Проблемът с XOR е класически пример за ограниченията на перцептрона и е посочен от Марвин Мински и Сиймур Пейпърт през 1969 г. в тяхната книга [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Това наблюдение ограничава изследванията в областта на невронните мрежи за почти 10 години, въпреки че - както ще видим в следващата секция на нашия курс - многослойните перцептрони са напълно способни да решават такива проблеми.\n",
|
||||
"\n",
|
||||
"## Сложен пример - MNIST\n",
|
||||
"\n",
|
||||
"Въпреки че перцептронът не може да реши проблема XOR, той може да решава много по-сложни задачи, като например разпознаване на ръкописни символи.\n",
|
||||
"Въпреки че перцептронът не може да реши проблема с XOR, той може да решава много по-сложни задачи, като например разпознаване на ръкописни символи.\n",
|
||||
"\n",
|
||||
"Един набор от данни, който често се използва при усвояване на машинното обучение, се нарича [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Той е създаден от Модифицирания Национален Институт за Стандарти и Технологии и съдържа тренировъчен набор от 60 000 ръкописни цифри, събрани от около 250 студенти и служители на института. Съществува и тестов набор от данни с 10 000 цифри, събрани от различни индивиди.\n",
|
||||
"Един набор от данни, който често се използва при усвояване на машинното обучение, се нарича [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Той е създаден от Модифицирания Национален Институт за Стандарти и Технологии и съдържа тренировъчен набор от 60 000 ръкописни цифри, събрани от около 250 студенти и служители на института. Има и тестов набор от данни с 10 000 цифри, събрани от различни индивиди.\n",
|
||||
"\n",
|
||||
"Всички цифри са представени чрез изображения в сиви тонове с размер 28x28 пиксела.\n",
|
||||
"\n",
|
||||
"> Наборът от данни MNIST е достъпен като тренировъчно състезание на [Kaggle](https://www.kaggle.com/c/digit-recognizer), сайт, който организира състезания и конкурси по машинно обучение. След като се научите да класифицирате цифрите от MNIST, можете да изпратите своето решение на Kaggle, за да видите как се оценява сред другите участници.\n",
|
||||
"> Наборът от данни MNIST е достъпен като тренировъчно състезание на [Kaggle](https://www.kaggle.com/c/digit-recognizer), сайт, който хоства състезания и конкурси за машинно обучение. След като научите как да класифицирате цифрите от MNIST, можете да изпратите своето решение на Kaggle, за да видите как се оценява сред другите участници.\n",
|
||||
"\n",
|
||||
"Започваме с зареждането на набора от данни MNIST:\n"
|
||||
]
|
||||
|
|
@ -831,13 +957,13 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Моля, обърнете внимание как точността се повишава до почти 100% много бързо.\n",
|
||||
"Моля, обърнете внимание как точността се повишава почти до 100% много бързо.\n",
|
||||
"\n",
|
||||
"Моля, преместете плъзгача към някоя позиция към края на обучението и наблюдавайте матрицата на теглата, изобразена отляво. Тази матрица ще ви позволи да разберете как всъщност работи перцептронът. Можете да видите високите стойности на теглата в средата на полето, които съответстват на пиксели, които обикновено присъстват за цифрата 1, и ниските отрицателни стойности отстрани, където се намират частите на цифрата 0. Така че, ако цифрата, представена на перцептрона, е всъщност 1, средната част от нея ще бъде умножена с високи стойности, което ще доведе до положителен резултат. Обратно, когато перцептронът наблюдава 0, съответните пиксели ще бъдат умножени с отрицателни числа.\n",
|
||||
"Моля, преместете плъзгача към някоя позиция към края на обучението и наблюдавайте матрицата на теглата, изобразена отляво. Тази матрица ще ви помогне да разберете как всъщност работи перцептронът. Можете да видите високите стойности на теглата в средата на полето, които съответстват на пикселите, които обикновено присъстват за цифрата 1, и ниските отрицателни стойности отстрани, където се намират части от цифрата 0. Така че, ако цифрата, представена на перцептрона, наистина е 1, средната част от нея ще бъде умножена с високи стойности, което ще произведе положителен резултат. Обратно, когато перцептронът наблюдава 0, съответните пиксели ще бъдат умножени с отрицателни числа.\n",
|
||||
"\n",
|
||||
"> Може да забележите, че ако дадем на нашия перцептрон цифра 1, леко изместена хоризонтално, така че нейните пиксели да заемат мястото, където се намират вертикалните части на 0, може да получим неправилен резултат. Тъй като природата на нашия MNIST набор от данни е такава, че всички цифри са центрирани и правилно позиционирани, перцептронът разчита на това, за да различава цифрите.\n",
|
||||
"> Може да забележите, че ако дадем на нашия перцептрон цифра 1, леко изместена хоризонтално, така че нейните пиксели да заемат мястото, където има вертикални части от цифрата 0, може да получим неправилен резултат. Тъй като природата на нашия MNIST набор от данни е такава, че всички цифри са центрирани и правилно позиционирани, перцептронът разчита на това, за да различава цифрите.\n",
|
||||
"\n",
|
||||
"Сега нека опитаме с различни цифри:\n"
|
||||
"Сега нека опитаме различни цифри:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -911,13 +1037,13 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Дискусия\n",
|
||||
"## Обсъждане\n",
|
||||
"\n",
|
||||
"По някаква причина, 2 и 5 не са толкова лесно разделими. Въпреки че постигаме сравнително висока точност (над 85%), ясно се вижда как перцептронът спира да учи в даден момент.\n",
|
||||
"\n",
|
||||
"За да разберем защо се случва това, можем да използваме [Анализ на главните компоненти](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Това е техника от машинното обучение, която се използва за намаляване на размерността на входния набор от данни, така че да се постигне най-добрата разделимост между класовете.\n",
|
||||
"За да разберем защо се случва това, можем да използваме [Анализ на главните компоненти](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Това е техника за машинно обучение, която се използва за намаляване на размерността на входния набор от данни, така че да се постигне най-добрата разделимост между класовете.\n",
|
||||
"\n",
|
||||
"В нашия случай, входното изображение има 784 пиксела (входни характеристики), и искаме да използваме PCA, за да намалим броя на параметрите само до 2, за да можем да ги изобразим на графика. Тези два параметъра ще бъдат линейна комбинация от оригиналните характеристики, и можем да разглеждаме този процес като \"завъртане\" на нашето оригинално пространство с 784 измерения и наблюдение на неговата проекция в двумерното пространство, докато получим най-добрия изглед, който разделя класовете.\n"
|
||||
"В нашия случай, входното изображение има 784 пиксела (входни характеристики), и искаме да използваме PCA, за да намалим броя на параметрите само до 2, за да можем да ги изобразим на графика. Тези два параметъра ще бъдат линейна комбинация от оригиналните характеристики, и можем да разглеждаме този процес като \"завъртане\" на нашето оригинално 784-мерно пространство и наблюдение на неговата проекция в 2D-пространството, докато получим най-добрия изглед, който разделя класовете.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,14 +1155,14 @@
|
|||
"source": [
|
||||
"Както можете да видите, 0 и 1 могат ясно да бъдат разделени с права линия. Това показва, че в оригиналното 784-мерно пространство точките, съответстващи на цифрите, също са линейно разделими. В случая с 2 и 5 не можем да намерим добра проекция, която да раздели цифрите ясно, и следователно има случаи на неправилна класификация.\n",
|
||||
"\n",
|
||||
"> По-късно в този курс ще научим как да създаваме нелинейни класификатори, използвайки невронни мрежи, и как да се справяме с проблема, когато цифрите не са правилно подравнени. Много скоро ще постигнем над 99% точност при класификация на цифри от MNIST, като ги класифицираме в 10 различни класа.\n",
|
||||
"> По-късно в този курс ще научим как да създаваме нелинейни класификатори с помощта на невронни мрежи и как да се справяме с проблема, когато цифрите не са правилно подравнени. Много скоро ще постигнем над 99% точност при класификация на цифри от MNIST, като ги класифицираме в 10 различни класа.\n",
|
||||
"\n",
|
||||
"## Основни изводи\n",
|
||||
"\n",
|
||||
" * Научихме за най-простата архитектура на невронна мрежа - еднослоен перцептрон.\n",
|
||||
" * Реализирахме перцептрона \"ръчно\", използвайки проста процедура за обучение, базирана на градиентен спуск.\n",
|
||||
" * Въпреки своята простота, еднослойният перцептрон може да решава сравнително сложни задачи за разпознаване на ръкописни цифри.\n",
|
||||
" * Еднослойният перцептрон е линеен класификатор и следователно предоставя същата класификационна мощност като логистичната регресия.\n",
|
||||
" * Реализирахме перцептрона \"ръчно\", използвайки прост тренировъчен процес, базиран на градиентен спуск.\n",
|
||||
" * Въпреки своята простота, еднослойният перцептрон може да решава доста сложни задачи за разпознаване на ръкописни цифри.\n",
|
||||
" * Еднослойният перцептрон е линеен класификатор и следователно предоставя същата класификационна мощ като логистичната регресия.\n",
|
||||
" * В пространството на примерите перцептронът може да разделя два класа входни данни, използвайки хиперплоскост.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Отказ от отговорност**: \nТози документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за недоразумения или погрешни интерпретации, произтичащи от използването на този превод.\n"
|
||||
"\n---\n\n**Отказ от отговорност**: \nТози документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за каквито и да е недоразумения или погрешни интерпретации, произтичащи от използването на този превод.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:45:40+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:33:52+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "bg"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## পারসেপট্রন\n",
|
||||
"## পার্সেপট্রন\n",
|
||||
"\n",
|
||||
"> এই নোটবুকটি [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners)-এর একটি অংশ। সম্পূর্ণ শিক্ষামূলক উপকরণের জন্য রিপোজিটরি পরিদর্শন করুন।\n",
|
||||
"\n",
|
||||
"যেমনটি আমরা আলোচনা করেছি, পারসেপট্রন আপনাকে **বাইনারি শ্রেণীবিভাজন সমস্যা** সমাধান করতে সাহায্য করে, অর্থাৎ ইনপুট উদাহরণগুলোকে দুটি শ্রেণীতে ভাগ করতে - আমরা এগুলোকে **পজিটিভ** এবং **নেগেটিভ** বলতে পারি।\n",
|
||||
"যেমনটি আমরা আলোচনা করেছি, পার্সেপট্রন আপনাকে **বাইনারি ক্লাসিফিকেশন সমস্যা** সমাধান করতে সাহায্য করে, অর্থাৎ ইনপুট উদাহরণগুলোকে দুটি শ্রেণিতে ভাগ করতে - আমরা এগুলোকে **পজিটিভ** এবং **নেগেটিভ** বলতে পারি।\n",
|
||||
"\n",
|
||||
"প্রথমে, চলুন কিছু প্রয়োজনীয় লাইব্রেরি ইমপোর্ট করি।\n"
|
||||
]
|
||||
|
|
@ -47,11 +47,11 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## টয় সমস্যা\n",
|
||||
"## খেলনা সমস্যা\n",
|
||||
"\n",
|
||||
"শুরুতে, চলুন একটি টয় সমস্যার সাথে শুরু করি, যেখানে আমাদের দুটি ইনপুট বৈশিষ্ট্য রয়েছে। উদাহরণস্বরূপ, চিকিৎসায় আমরা টিউমারগুলোকে সাইজ এবং বয়সের উপর ভিত্তি করে বেনাইন এবং ম্যালিগন্যান্ট হিসেবে শ্রেণীবদ্ধ করতে চাইতে পারি।\n",
|
||||
"শুরু করার জন্য, চলুন একটি খেলনা সমস্যার সাথে শুরু করি, যেখানে আমাদের দুটি ইনপুট বৈশিষ্ট্য রয়েছে। উদাহরণস্বরূপ, চিকিৎসায় আমরা টিউমারগুলিকে তার আকার এবং বয়সের উপর ভিত্তি করে সুশীল এবং ক্ষতিকারক শ্রেণিতে ভাগ করতে চাই।\n",
|
||||
"\n",
|
||||
"আমরা SciKit Learn লাইব্রেরির `make_classification` ফাংশন ব্যবহার করে একটি র্যান্ডম শ্রেণীবিন্যাস ডেটাসেট তৈরি করব:\n"
|
||||
"আমরা SciKit Learn লাইব্রেরির `make_classification` ফাংশন ব্যবহার করে একটি র্যান্ডম শ্রেণিবিন্যাস ডেটাসেট তৈরি করব:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## পারসেপট্রন\n",
|
||||
"\n",
|
||||
"যেহেতু পারসেপট্রন একটি বাইনারি ক্লাসিফায়ার, প্রতিটি ইনপুট ভেক্টর $x$ এর জন্য আমাদের পারসেপট্রনের আউটপুট হবে +1 অথবা -1, যা ক্লাসের উপর নির্ভর করবে। আউটপুট নিচের সূত্র ব্যবহার করে গণনা করা হবে:\n",
|
||||
"যেহেতু পারসেপট্রন একটি বাইনারি শ্রেণীবিভাজক, প্রতিটি ইনপুট ভেক্টর $x$ এর জন্য আমাদের পারসেপট্রনের আউটপুট হবে +1 বা -1, যা শ্রেণীর উপর নির্ভর করবে। আউটপুটটি নিম্নলিখিত সূত্র ব্যবহার করে গণনা করা হবে:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"তবে, একটি সাধারণ লিনিয়ার মডেলে একটি বায়াসও থাকা উচিত, অর্থাৎ আদর্শভাবে আমাদের $y$ গণনা করা উচিত $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ হিসেবে। আমাদের মডেলকে সহজ করার জন্য, আমরা এই বায়াস টার্মটি বাদ দিতে পারি যদি আমরা আমাদের ইনপুট ফিচারগুলিতে একটি অতিরিক্ত ডাইমেনশন যোগ করি, যার মান সবসময় 1 থাকে:\n"
|
||||
"তবে, একটি সাধারণ লিনিয়ার মডেলে একটি বায়াসও থাকা উচিত, অর্থাৎ আদর্শভাবে আমাদের $y$ গণনা করা উচিত $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ হিসাবে। আমাদের মডেলটি সহজ করার জন্য, আমরা আমাদের ইনপুট বৈশিষ্ট্যগুলিতে একটি অতিরিক্ত মাত্রা যোগ করে এই বায়াস টার্মটি বাদ দিতে পারি, যা সর্বদা 1 এর সমান:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -206,20 +206,20 @@
|
|||
"source": [
|
||||
"## প্রশিক্ষণ অ্যালগরিদম\n",
|
||||
"\n",
|
||||
"পার্সেপট্রন প্রশিক্ষণ করার জন্য, আমাদের এমন ওজন $\\mathbf{w}$ খুঁজে বের করতে হবে যা ত্রুটি কমাবে। ত্রুটি **পার্সেপট্রন ক্রাইটেরিয়া** ব্যবহার করে সংজ্ঞায়িত করা হয়:\n",
|
||||
"পার্সেপট্রন প্রশিক্ষণ করার জন্য, আমাদের এমন ওজন $\\mathbf{w}$ খুঁজে বের করতে হবে যা ত্রুটি কমাবে। ত্রুটি **পার্সেপট্রন ক্রাইটেরিয়া** ব্যবহার করে সংজ্ঞায়িত করা হয়:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ নেতিবাচক এবং ইতিবাচক প্রশিক্ষণ নমুনার জন্য যথাক্রমে\n",
|
||||
" * $\\mathcal{M}$ - ভুলভাবে শ্রেণীবদ্ধ উদাহরণগুলোর একটি সেট\n",
|
||||
" * $\\mathcal{M}$ - ভুলভাবে শ্রেণীবদ্ধ উদাহরণগুলোর সেট\n",
|
||||
" \n",
|
||||
"আমরা **গ্রেডিয়েন্ট ডিসেন্ট** প্রক্রিয়া ব্যবহার করব। কিছু প্রাথমিক র্যান্ডম ওজন $\\mathbf{w}^{(0)}$ দিয়ে শুরু করে, আমরা প্রতিটি প্রশিক্ষণ ধাপে $E$-এর গ্রেডিয়েন্ট ব্যবহার করে ওজন সমন্বয় করব:\n",
|
||||
"আমরা **গ্রেডিয়েন্ট ডিসেন্ট** প্রক্রিয়া ব্যবহার করব। প্রাথমিকভাবে কিছু র্যান্ডম ওজন $\\mathbf{w}^{(0)}$ দিয়ে শুরু করে, আমরা প্রশিক্ষণের প্রতিটি ধাপে $E$-এর গ্রেডিয়েন্ট ব্যবহার করে ওজন সামঞ্জস্য করব:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"যেখানে $\\eta$ হলো **শেখার হার**, এবং $\\tau\\in\\mathbb{N}$ - ইটারেশনের সংখ্যা।\n",
|
||||
"যেখানে $\\eta$ হল **লার্নিং রেট**, এবং $\\tau\\in\\mathbb{N}$ - ইটারেশনের সংখ্যা।\n",
|
||||
"\n",
|
||||
"চলুন এই অ্যালগরিদমটি Python-এ সংজ্ঞায়িত করি:\n"
|
||||
"চলুন এই অ্যালগরিদমটি পাইথনে সংজ্ঞায়িত করি:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**শিক্ষার হার সম্পর্কে নোট**: `learning_rate` প্যারামিটার (ডিফল্ট `0.01`) প্রতিটি প্রশিক্ষণ ধাপে ওজনগুলো কতটা পরিবর্তন করা হবে তা নিয়ন্ত্রণ করে। এটি গ্রেডিয়েন্ট ডিসেন্ট আপডেট সূত্রটি বাস্তবায়ন করে:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- বড় শিক্ষার হার (যেমন, `1.0`) পারসেপট্রনকে দ্রুত শিখতে সাহায্য করে, তবে এটি আদর্শ সমাধানকে অতিক্রম করতে পারে\n",
|
||||
"- ছোট শিক্ষার হার (যেমন, `0.001`) ধীরে শিখে, তবে এটি আরও সঠিকভাবে একত্রিত হতে পারে\n",
|
||||
"- আপনি পরীক্ষা করতে পারেন এইভাবে কল করে: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"যেমনটি দেখতে পাচ্ছেন, প্রাথমিক সঠিকতার হার প্রায় ৫০%, তবে এটি দ্রুত বৃদ্ধি পেয়ে প্রায় ৯০%-এর কাছাকাছি পৌঁছে যায়।\n",
|
||||
"যেমনটি দেখা যাচ্ছে, প্রাথমিক সঠিকতার হার প্রায় ৫০%, তবে এটি দ্রুত বৃদ্ধি পেয়ে ৯০%-এর কাছাকাছি উচ্চ মানে পৌঁছায়।\n",
|
||||
"\n",
|
||||
"এবার আমরা ক্লাসগুলো কীভাবে পৃথক করা হয়েছে তা চিত্রায়িত করি। আমাদের শ্রেণীবিন্যাস ফাংশন $\\mathbf{w}^Tx$ এর মতো দেখায়, এবং এটি একটি ক্লাসের জন্য ০-এর বেশি এবং অন্য ক্লাসের জন্য ০-এর নিচে থাকে। সুতরাং, ক্লাস পৃথককরণের রেখা $\\mathbf{w}^Tx = 0$ দ্বারা সংজ্ঞায়িত হয়। যেহেতু আমাদের মাত্র দুটি ডাইমেনশন $x_0$ এবং $x_1$ রয়েছে, রেখার সমীকরণ হবে $w_0x_0+w_1x_1+w_2 = 0$ (মনে রাখুন যে আমরা স্পষ্টভাবে একটি অতিরিক্ত ডাইমেনশন $x_2=1$ সংজ্ঞায়িত করেছি)। এবার আমরা এই রেখাটি চিত্রায়িত করি:\n"
|
||||
"চলুন দেখি কীভাবে শ্রেণিগুলি পৃথক করা হয়েছে। আমাদের শ্রেণিবিন্যাস ফাংশন $\\mathbf{w}^Tx$ এর মতো দেখায়, এবং এটি একটি শ্রেণির জন্য ০-এর বেশি এবং অন্যটির জন্য ০-এর নিচে থাকে। সুতরাং, শ্রেণি বিভাজন রেখাটি $\\mathbf{w}^Tx = 0$ দ্বারা সংজ্ঞায়িত হয়। যেহেতু আমাদের মাত্র দুটি মাত্রা $x_0$ এবং $x_1$ রয়েছে, রেখার সমীকরণ হবে $w_0x_0+w_1x_1+w_2 = 0$ (মনে রাখুন আমরা স্পষ্টভাবে একটি অতিরিক্ত মাত্রা $x_2=1$ সংজ্ঞায়িত করেছি)। চলুন এই রেখাটি প্লট করি:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## শেখার হার নিয়ে পরীক্ষা-নিরীক্ষা\n",
|
||||
"\n",
|
||||
"এখন চলুন দেখি কীভাবে বিভিন্ন শেখার হার প্রশিক্ষণ প্রক্রিয়াকে প্রভাবিত করে। শেখার হার গ্রেডিয়েন্ট ডিসেন্টে পদক্ষেপের আকার নিয়ন্ত্রণ করে - এটি একটি গুরুত্বপূর্ণ হাইপারপ্যারামিটার যা একত্রিত হওয়ার গতি এবং স্থিতিশীলতাকে প্রভাবিত করে।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### ইন্টারঅ্যাকটিভ লার্নিং রেট এক্সপেরিমেন্ট\n",
|
||||
"\n",
|
||||
"নীচের স্লাইডারটি ব্যবহার করে বিভিন্ন লার্নিং রেটের সাথে ইন্টারঅ্যাকটিভভাবে পরীক্ষা করুন এবং দেখুন কীভাবে এটি সিদ্ধান্ত সীমারেখাকে প্রভাবিত করে:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## টেস্ট ডেটাসেটে মূল্যায়ন\n",
|
||||
"\n",
|
||||
"শুরুতে, আমরা কিছু ডেটা টেস্ট ডেটাসেটের জন্য আলাদা করে রেখেছি। চলুন দেখি আমাদের ক্লাসিফায়ার এই টেস্ট ডেটাসেটে কতটা সঠিক। এটি করার জন্য, আমরা টেস্ট ডেটাসেটকে একটি অতিরিক্ত মাত্রা দিয়ে প্রসারিত করি, ওজন ম্যাট্রিক্স দ্বারা গুণ করি, এবং নিশ্চিত করি যে প্রাপ্ত মানটি লেবেলের মতো একই চিহ্ন (+1 বা -1) রয়েছে। এরপর আমরা সমস্ত বুলিয়ান মান যোগ করি এবং টেস্ট স্যাম্পলের দৈর্ঘ্য দ্বারা ভাগ করি, যাতে সঠিকতার মান পাওয়া যায়:\n"
|
||||
"শুরুতে, আমরা কিছু ডেটা টেস্ট ডেটাসেটের জন্য আলাদা করে রেখেছি। চলুন দেখি আমাদের ক্লাসিফায়ার এই টেস্ট ডেটাসেটে কতটা সঠিক। এটি করার জন্য, আমরা টেস্ট ডেটাসেটকে একটি অতিরিক্ত মাত্রা দিয়ে প্রসারিত করি, ওজন ম্যাট্রিক্স দ্বারা গুণ করি, এবং নিশ্চিত করি যে প্রাপ্ত মানটি লেবেলের মতো একই চিহ্ন (+1 বা -1) রয়েছে। এরপর আমরা সমস্ত বুলিয়ান মান যোগ করি এবং টেস্ট স্যাম্পলের দৈর্ঘ্য দিয়ে ভাগ করি, যাতে সঠিকতার মান পাওয়া যায়:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## প্রশিক্ষণ প্রক্রিয়া পর্যবেক্ষণ করা\n",
|
||||
"\n",
|
||||
"আমরা আগেও দেখেছি কীভাবে প্রশিক্ষণের সময় সঠিকতার হার কমে যায়। প্রশিক্ষণের সময় বিভাজন রেখাটি কীভাবে পরিবর্তিত হয় তা দেখা বেশ আকর্ষণীয় হবে। নিচের কোডটি সবকিছু এক গ্রাফে চিত্রিত করবে, এবং আপনি স্লাইডারটি সরিয়ে প্রশিক্ষণ প্রক্রিয়ার মধ্য দিয়ে \"সময় ভ্রমণ\" করতে পারবেন।\n"
|
||||
"আমরা আগেও দেখেছি কীভাবে প্রশিক্ষণের সময় সঠিকতার হার কমে যায়। প্রশিক্ষণের সময় বিভাজন রেখাটি কীভাবে পরিবর্তিত হয় তা দেখলে ভালো হয়। নিচের কোডটি সবকিছু এক গ্রাফে প্রদর্শন করবে, এবং আপনি স্লাইডারটি সরিয়ে প্রশিক্ষণ প্রক্রিয়ার মধ্য দিয়ে \"সময়ের ভ্রমণ\" করতে পারবেন।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,16 +655,16 @@
|
|||
"source": [
|
||||
"## পারসেপট্রনের সীমাবদ্ধতা\n",
|
||||
"\n",
|
||||
"যেমন আপনি উপরে দেখেছেন, পারসেপট্রন একটি **রৈখিক শ্রেণীবিভাজক**। এটি দুটি শ্রেণীর মধ্যে পার্থক্য করতে পারে যদি তারা **রৈখিকভাবে পৃথকযোগ্য** হয়, অর্থাৎ একটি সরল রেখা দ্বারা পৃথক করা যায়। অন্যথায়, পারসেপট্রনের প্রশিক্ষণ প্রক্রিয়া সঠিকভাবে সম্পন্ন হবে না।\n",
|
||||
"যেমন আপনি উপরে দেখেছেন, পারসেপট্রন একটি **লিনিয়ার ক্লাসিফায়ার**। এটি দুইটি শ্রেণীর মধ্যে পার্থক্য করতে পারে যদি তারা **লিনিয়ারলি সেপারেবল** হয়, অর্থাৎ একটি সরল রেখা দ্বারা পৃথক করা যায়। অন্যথায়, পারসেপট্রনের প্রশিক্ষণ প্রক্রিয়া সঠিকভাবে সম্পন্ন হবে না।\n",
|
||||
"\n",
|
||||
"পারসেপট্রন দ্বারা সমাধান করা যায় না এমন সমস্যার একটি সুস্পষ্ট উদাহরণ হল তথাকথিত **XOR সমস্যা**। আমরা চাই আমাদের পারসেপট্রন XOR বুলিয়ান ফাংশনটি শিখুক, যার সত্য টেবিল নিম্নরূপ:\n",
|
||||
"পারসেপট্রন দ্বারা সমাধান করা সম্ভব নয় এমন একটি সমস্যার সবচেয়ে স্পষ্ট উদাহরণ হলো **XOR সমস্যা**। আমরা চাই আমাদের পারসেপট্রন XOR বুলিয়ান ফাংশনটি শিখুক, যার সত্য টেবিল নিম্নরূপ:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"চলুন চেষ্টা করি! আমরা ম্যানুয়ালি সমস্ত পজিটিভ এবং নেগেটিভ প্রশিক্ষণ নমুনা পূরণ করব, তারপর আমাদের উপরে সংজ্ঞায়িত train ফাংশনটি কল করব:\n"
|
||||
"চলুন চেষ্টা করি! আমরা ম্যানুয়ালি সব পজিটিভ এবং নেগেটিভ প্রশিক্ষণ নমুনা পূরণ করব, তারপর আমাদের উপরে সংজ্ঞায়িত train ফাংশনটি কল করব:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -607,17 +733,17 @@
|
|||
"source": [
|
||||
"যেমনটি আপনি উপরের গ্রাফ থেকে দেখতে পাচ্ছেন, সঠিকতার হার কখনোই ৭৫% এর উপরে যায় না, কারণ এমন একটি সরল রেখা আঁকা অসম্ভব যা সমস্ত উদাহরণকে সঠিকভাবে আলাদা করতে পারে।\n",
|
||||
"\n",
|
||||
"XOR সমস্যা হলো পার্সেপট্রনের সীমাবদ্ধতার একটি ক্লাসিক উদাহরণ, এবং এটি ১৯৬৯ সালে মারভিন মিনস্কি এবং সেমুর প্যাপার্ট তাদের বই [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book))-এ উল্লেখ করেছিলেন। এই পর্যবেক্ষণ প্রায় ১০ বছর ধরে নিউরাল নেটওয়ার্ক গবেষণাকে সীমিত করেছিল, যদিও - এবং আমরা আমাদের কোর্সের পরবর্তী অংশে এটি দেখব - বহু-স্তরযুক্ত পার্সেপট্রন এমন সমস্যাগুলি সমাধান করতে পুরোপুরি সক্ষম।\n",
|
||||
"XOR সমস্যাটি পারসেপট্রনের সীমাবদ্ধতার একটি ক্লাসিক উদাহরণ, এবং এটি ১৯৬৯ সালে মারভিন মিনস্কি এবং সেমুর প্যাপার্ট তাদের বই [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book))-এ উল্লেখ করেছিলেন। এই পর্যবেক্ষণ প্রায় ১০ বছর ধরে নিউরাল নেটওয়ার্ক গবেষণাকে সীমিত করেছিল, যদিও - এবং আমরা আমাদের কোর্সের পরবর্তী অংশে এটি দেখব - বহু-স্তরযুক্ত পারসেপট্রন এমন সমস্যাগুলি সমাধান করতে পুরোপুরি সক্ষম।\n",
|
||||
"\n",
|
||||
"## জটিল উদাহরণ - MNIST\n",
|
||||
"\n",
|
||||
"যদিও পার্সেপট্রন XOR সমস্যাটি সমাধান করতে পারে না, এটি অনেক বেশি জটিল সমস্যাগুলি সমাধান করতে পারে, যেমন হাতে লেখা অক্ষর সনাক্তকরণ।\n",
|
||||
"যদিও পারসেপট্রন XOR সমস্যাটি সমাধান করতে পারে না, এটি আরও অনেক জটিল সমস্যার সমাধান করতে পারে, যেমন হাতে লেখা অক্ষর সনাক্তকরণ।\n",
|
||||
"\n",
|
||||
"যে ডেটাসেটটি মেশিন লার্নিং শিখতে প্রায়ই ব্যবহৃত হয় সেটি [MNIST](https://en.wikipedia.org/wiki/MNIST_database) নামে পরিচিত। এটি Modified National Institute of Standards and Technology দ্বারা তৈরি করা হয়েছে এবং এতে ৬০,০০০ হাতে লেখা সংখ্যার একটি প্রশিক্ষণ সেট রয়েছে, যা প্রায় ২৫০ জন ছাত্র এবং ইনস্টিটিউটের কর্মচারীদের কাছ থেকে সংগ্রহ করা হয়েছে। এছাড়াও, ১০,০০০ সংখ্যার একটি টেস্ট ডেটাসেট রয়েছে, যা বিভিন্ন ব্যক্তির কাছ থেকে সংগ্রহ করা হয়েছে।\n",
|
||||
"যে ডেটাসেটটি মেশিন লার্নিং শিখতে প্রায়ই ব্যবহৃত হয় সেটি [MNIST](https://en.wikipedia.org/wiki/MNIST_database) নামে পরিচিত। এটি মডিফাইড ন্যাশনাল ইনস্টিটিউট অফ স্ট্যান্ডার্ডস অ্যান্ড টেকনোলজি দ্বারা তৈরি করা হয়েছে এবং এতে ৬০,০০০ হাতে লেখা সংখ্যার একটি প্রশিক্ষণ সেট রয়েছে, যা প্রায় ২৫০ জন ছাত্র এবং ইনস্টিটিউটের কর্মচারীদের কাছ থেকে সংগ্রহ করা হয়েছে। এছাড়াও ১০,০০০ সংখ্যার একটি টেস্ট ডেটাসেট রয়েছে, যা বিভিন্ন ব্যক্তির কাছ থেকে সংগ্রহ করা হয়েছে।\n",
|
||||
"\n",
|
||||
"সব সংখ্যাগুলি ২৮x২৮ পিক্সেলের গ্রেস্কেল ইমেজ দ্বারা উপস্থাপিত।\n",
|
||||
"সব সংখ্যাগুলি ২৮x২৮ পিক্সেলের গ্রেস্কেল ইমেজ হিসেবে উপস্থাপিত।\n",
|
||||
"\n",
|
||||
"> MNIST ডেটাসেট [Kaggle](https://www.kaggle.com/c/digit-recognizer)-এ একটি প্রশিক্ষণ প্রতিযোগিতা হিসেবে উপলব্ধ, যা মেশিন লার্নিং প্রতিযোগিতা এবং কনটেস্টের জন্য একটি সাইট। একবার আপনি MNIST সংখ্যাগুলি শ্রেণীবদ্ধ করতে শিখে গেলে, আপনি আপনার সমাধান Kaggle-এ জমা দিতে পারেন এবং দেখতে পারেন এটি অন্যান্য অংশগ্রহণকারীদের মধ্যে কীভাবে রেট করা হয়।\n",
|
||||
"> MNIST ডেটাসেট [Kaggle](https://www.kaggle.com/c/digit-recognizer)-এ একটি প্রশিক্ষণ প্রতিযোগিতা হিসেবে উপলব্ধ, যা মেশিন লার্নিং প্রতিযোগিতা এবং কনটেস্ট হোস্ট করে। একবার আপনি MNIST সংখ্যাগুলি শ্রেণীবদ্ধ করতে শিখলে, আপনি আপনার সমাধান Kaggle-এ জমা দিতে পারেন এবং দেখতে পারেন এটি অন্যান্য অংশগ্রহণকারীদের মধ্যে কীভাবে রেট করা হয়।\n",
|
||||
"\n",
|
||||
"আমরা MNIST ডেটাসেট লোড করা দিয়ে শুরু করি:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"কারণ পারসেপট্রন একটি বাইনারি ক্লাসিফায়ার, আমরা আমাদের সমস্যাকে শুধুমাত্র দুটি সংখ্যা সনাক্ত করার মধ্যে সীমাবদ্ধ রাখব। নিচের ফাংশনটি দুটি প্রদত্ত সংখ্যার জন্য পজিটিভ এবং নেগেটিভ স্যাম্পল অ্যারে পূরণ করবে (এবং স্পষ্টতার জন্য সেই সংখ্যাগুলোর নমুনাও দেখাবে)।\n"
|
||||
"কারণ পারসেপট্রন একটি দ্বিমুখী শ্রেণীবিন্যাসকারী, আমরা আমাদের সমস্যাকে শুধুমাত্র দুটি সংখ্যা সনাক্ত করার মধ্যে সীমাবদ্ধ রাখব। নিচের ফাংশনটি দুটি প্রদত্ত সংখ্যার জন্য ইতিবাচক এবং নেতিবাচক নমুনার অ্যারে পূরণ করবে (এবং স্পষ্টতার জন্য সেই সংখ্যাগুলির নমুনাও দেখাবে)।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -831,11 +957,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"অনুগ্রহ করে লক্ষ্য করুন, কীভাবে নির্ভুলতা খুব দ্রুত প্রায় ১০০% পর্যন্ত পৌঁছে যায়।\n",
|
||||
"দয়া করে লক্ষ্য করুন, কীভাবে নির্ভুলতা খুব দ্রুত প্রায় ১০০% পর্যন্ত পৌঁছে যায়।\n",
|
||||
"\n",
|
||||
"অনুগ্রহ করে, ট্রেনিংয়ের শেষের দিকে স্লাইডারটি সরান এবং বাম দিকে প্রদর্শিত ওজন ম্যাট্রিক্সটি পর্যবেক্ষণ করুন। এই ম্যাট্রিক্সটি আপনাকে বুঝতে সাহায্য করবে কীভাবে পারসেপট্রন কার্যকরভাবে কাজ করে। আপনি দেখতে পাবেন ক্ষেত্রের মাঝখানে উচ্চ ওজন মান, যা সাধারণত সংখ্যা ১-এর জন্য উপস্থিত পিক্সেলগুলোর সাথে সম্পর্কিত, এবং পাশের দিকে নিম্ন নেতিবাচক মান, যেখানে সংখ্যা ০-এর অংশগুলো থাকে। সুতরাং, যদি পারসেপট্রনের কাছে প্রদর্শিত সংখ্যা আসলে ১ হয়, এর মাঝের অংশটি উচ্চ মান দ্বারা গুণিত হবে, যা একটি ইতিবাচক ফলাফল তৈরি করবে। অন্যদিকে, যখন পারসেপট্রন সংখ্যা ০ পর্যবেক্ষণ করে, সংশ্লিষ্ট পিক্সেলগুলো নেতিবাচক সংখ্যাগুলোর দ্বারা গুণিত হবে।\n",
|
||||
"অনুগ্রহ করে, ট্রেনিংয়ের শেষের দিকে স্লাইডারটি সরান এবং বাম দিকে প্রদর্শিত ওজন ম্যাট্রিক্সটি পর্যবেক্ষণ করুন। এই ম্যাট্রিক্সটি আপনাকে বুঝতে সাহায্য করবে যে পারসেপট্রন কীভাবে কাজ করে। আপনি ক্ষেত্রের মাঝখানে উচ্চ ওজন মান দেখতে পাবেন, যা সাধারণত সংখ্যা ১-এর জন্য উপস্থিত পিক্সেলের সাথে সম্পর্কিত, এবং পাশের দিকে নিম্ন নেতিবাচক মান, যেখানে সংখ্যা ০-এর অংশ থাকে। সুতরাং, যদি পারসেপট্রনকে প্রদত্ত সংখ্যা আসলেই ১ হয়, এর মাঝের অংশটি উচ্চ মান দ্বারা গুণিত হবে, যা একটি ইতিবাচক ফলাফল তৈরি করবে। অন্যদিকে, যখন পারসেপট্রন ০ পর্যবেক্ষণ করে, সংশ্লিষ্ট পিক্সেলগুলি নেতিবাচক সংখ্যার দ্বারা গুণিত হবে।\n",
|
||||
"\n",
|
||||
"> আপনি লক্ষ্য করতে পারেন যে যদি আমরা আমাদের পারসেপট্রনকে একটি সংখ্যা ১ দিই, যা সামান্য অনুভূমিকভাবে সরানো হয়েছে, যাতে এর পিক্সেলগুলো সেই স্থানে থাকে যেখানে ০-এর উল্লম্ব অংশগুলো থাকে, তাহলে আমরা ভুল ফলাফল পেতে পারি। যেহেতু আমাদের MNIST ডেটাসেটের প্রকৃতি এমন যে সমস্ত সংখ্যাগুলো কেন্দ্রীভূত এবং সঠিকভাবে অবস্থান করা থাকে, এবং পারসেপট্রন এই বৈশিষ্ট্যের উপর নির্ভর করে সংখ্যাগুলো পার্থক্য করতে।\n",
|
||||
"> আপনি লক্ষ্য করতে পারেন যে যদি আমরা আমাদের পারসেপট্রনকে একটি সংখ্যা ১ দিই যা সামান্য অনুভূমিকভাবে সরানো হয়েছে, যাতে এর পিক্সেলগুলি এমন জায়গা দখল করে যেখানে ০-এর উল্লম্ব অংশ রয়েছে, আমরা ভুল ফলাফল পেতে পারি। যেহেতু আমাদের MNIST ডেটাসেটের প্রকৃতি এমন যে সমস্ত সংখ্যা কেন্দ্রীভূত এবং সঠিকভাবে অবস্থান করা থাকে, এবং পারসেপট্রন এই বিষয়টির উপর নির্ভর করে সংখ্যাগুলি আলাদা করতে।\n",
|
||||
"\n",
|
||||
"এখন চলুন বিভিন্ন সংখ্যা চেষ্টা করি:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## আলোচনা\n",
|
||||
"\n",
|
||||
"কোনো কারণে, ২ এবং ৫ সংখ্যাগুলো সহজে আলাদা করা যায় না। যদিও আমরা তুলনামূলকভাবে উচ্চ সঠিকতা (৮৫% এর উপরে) পাই, তবুও স্পষ্টভাবে দেখা যায় যে, perceptron একটি নির্দিষ্ট পর্যায়ে গিয়ে শেখা বন্ধ করে দেয়।\n",
|
||||
"কোনো কারণে, ২ এবং ৫ সহজে আলাদা করা যায় না। যদিও আমরা তুলনামূলকভাবে উচ্চ নির্ভুলতা (৮৫% এর উপরে) পাই, তবুও স্পষ্টভাবে দেখা যায় যে, একটি পর্যায়ে গিয়ে পারসেপট্রন শেখা বন্ধ করে দেয়।\n",
|
||||
"\n",
|
||||
"এটি কেন ঘটে তা বোঝার জন্য আমরা [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) ব্যবহার করতে পারি। এটি একটি মেশিন লার্নিং পদ্ধতি যা ইনপুট ডেটাসেটের মাত্রা কমানোর জন্য ব্যবহৃত হয়, যাতে শ্রেণিগুলোর মধ্যে সর্বোত্তম আলাদা করার ক্ষমতা পাওয়া যায়।\n",
|
||||
"এটি কেন ঘটে তা বোঝার জন্য আমরা [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) ব্যবহার করতে পারি। এটি একটি মেশিন লার্নিং কৌশল যা ইনপুট ডেটাসেটের মাত্রা কমানোর জন্য ব্যবহৃত হয়, যাতে শ্রেণিগুলোর মধ্যে সর্বোত্তম পৃথকীকরণ পাওয়া যায়।\n",
|
||||
"\n",
|
||||
"আমাদের ক্ষেত্রে, একটি ইনপুট ইমেজে ৭৮৪টি পিক্সেল (ইনপুট ফিচার) থাকে, এবং আমরা PCA ব্যবহার করে প্যারামিটারের সংখ্যা মাত্র ২-এ কমাতে চাই, যাতে আমরা সেগুলো গ্রাফে প্লট করতে পারি। এই দুটি প্যারামিটার মূল ফিচারগুলোর একটি লিনিয়ার কম্বিনেশন হবে, এবং আমরা এই প্রক্রিয়াকে আমাদের মূল ৭৮৪-মাত্রিক স্পেসকে \"ঘোরানো\" এবং এটি ২-মাত্রিক স্পেসে প্রক্ষেপণ করার মতো দেখতে পারি, যতক্ষণ না আমরা শ্রেণিগুলোকে আলাদা করার জন্য সর্বোত্তম দৃশ্য পাই।\n"
|
||||
"আমাদের ক্ষেত্রে, একটি ইনপুট ইমেজে ৭৮৪টি পিক্সেল (ইনপুট ফিচার) থাকে, এবং আমরা PCA ব্যবহার করে প্যারামিটারের সংখ্যা মাত্র ২-এ কমাতে চাই, যাতে আমরা সেগুলো গ্রাফে প্লট করতে পারি। এই দুটি প্যারামিটার মূল ফিচারগুলোর একটি লিনিয়ার কম্বিনেশন হবে, এবং আমরা এই প্রক্রিয়াকে আমাদের মূল ৭৮৪-মাত্রিক স্থানকে \"ঘোরানো\" এবং তার প্রক্ষেপণকে ২-মাত্রিক স্থানে পর্যবেক্ষণ করার মতো দেখতে পারি, যতক্ষণ না আমরা শ্রেণিগুলোর মধ্যে সর্বোত্তম পৃথকীকরণ দেখতে পাই।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"যেমন আপনি দেখতে পাচ্ছেন, 0 এবং 1 একটি সরল রেখা দ্বারা স্পষ্টভাবে পৃথক করা যেতে পারে। এটি নির্দেশ করে যে মূল 784-ডাইমেনশনাল স্পেসে সংখ্যাগুলোর সাথে সম্পর্কিত বিন্দুগুলোও সরলরেখাভাবে পৃথকযোগ্য। কিন্তু 2 এবং 5 এর ক্ষেত্রে, আমরা এমন একটি ভালো প্রক্ষেপণ খুঁজে পাই না যা সংখ্যাগুলোকে স্পষ্টভাবে পৃথক করতে পারে, এবং এর ফলে কিছু ভুল শ্রেণিবিন্যাস ঘটে।\n",
|
||||
"যেমনটি দেখা যাচ্ছে, 0 এবং 1 একটি সরল রেখা দ্বারা স্পষ্টভাবে পৃথক করা যেতে পারে। এটি নির্দেশ করে যে মূল 784-ডাইমেনশনাল স্পেসে সংখ্যাগুলোর সাথে সম্পর্কিত বিন্দুগুলোও সরলরেখাভাবে পৃথকযোগ্য। কিন্তু 2 এবং 5 এর ক্ষেত্রে, এমন একটি ভালো প্রক্ষেপণ খুঁজে পাওয়া যায় না যা সংখ্যাগুলোকে স্পষ্টভাবে পৃথক করতে পারে, এবং এর ফলে কিছু ভুল শ্রেণিবিন্যাস ঘটে।\n",
|
||||
"\n",
|
||||
"> এই কোর্সে আমরা পরে শিখব কীভাবে Neural Networks ব্যবহার করে অ-রৈখিক শ্রেণিবিন্যাসকারী তৈরি করা যায় এবং কীভাবে সংখ্যাগুলো সঠিকভাবে সজ্জিত না থাকলে সেই সমস্যার সমাধান করা যায়। খুব শীঘ্রই আমরা MNIST সংখ্যাগুলোর শ্রেণিবিন্যাসে 99% এর উপরে সঠিকতা অর্জন করব, যেখানে আমরা তাদের 10টি ভিন্ন শ্রেণিতে শ্রেণিবদ্ধ করব।\n",
|
||||
"> এই কোর্সে আমরা শিখব কীভাবে Neural Networks ব্যবহার করে অ-রৈখিক শ্রেণিবিন্যাসকারী তৈরি করা যায় এবং কীভাবে সংখ্যাগুলো সঠিকভাবে সারিবদ্ধ না থাকার সমস্যার সমাধান করা যায়। খুব শীঘ্রই আমরা MNIST সংখ্যাগুলোর শ্রেণিবিন্যাসে 99% এর বেশি সঠিকতা অর্জন করব, যেখানে এগুলোকে 10টি ভিন্ন শ্রেণিতে শ্রেণিবদ্ধ করা হবে।\n",
|
||||
"\n",
|
||||
"## মূল বিষয়\n",
|
||||
"\n",
|
||||
" * আমরা সবচেয়ে সহজ Neural Network আর্কিটেকচার - এক-স্তরের Perceptron সম্পর্কে শিখেছি।\n",
|
||||
" * আমরা Gradient Descent ভিত্তিক একটি সহজ প্রশিক্ষণ পদ্ধতি ব্যবহার করে Perceptron \"নিজ হাতে\" বাস্তবায়ন করেছি।\n",
|
||||
" * সরলতার পরেও, এক-স্তরের Perceptron হাতে লেখা সংখ্যাগুলোর জটিল সমস্যাগুলো সমাধান করতে পারে।\n",
|
||||
" * এক-স্তরের Perceptron একটি রৈখিক শ্রেণিবিন্যাসকারী, এবং এটি Logistic Regression এর সমান শ্রেণিবিন্যাস ক্ষমতা প্রদান করে।\n",
|
||||
" * নমুনা স্পেসে, Perceptron Hyperplane ব্যবহার করে ইনপুট ডেটার দুটি শ্রেণি পৃথক করতে পারে।\n"
|
||||
" * আমরা সবচেয়ে সহজ নিউরাল নেটওয়ার্ক আর্কিটেকচার - এক-স্তর বিশিষ্ট পারসেপট্রন সম্পর্কে শিখেছি।\n",
|
||||
" * আমরা পারসেপট্রনকে \"নিজ হাতে\" বাস্তবায়ন করেছি, যেখানে গ্রেডিয়েন্ট ডিসেন্ট ভিত্তিক একটি সহজ প্রশিক্ষণ পদ্ধতি ব্যবহার করা হয়েছে।\n",
|
||||
" * সরলতার পরেও, এক-স্তর বিশিষ্ট পারসেপট্রন হাতে লেখা সংখ্যাগুলোর জটিল সমস্যাগুলো সমাধান করতে পারে।\n",
|
||||
" * এক-স্তর বিশিষ্ট পারসেপট্রন একটি রৈখিক শ্রেণিবিন্যাসকারী, এবং এটি লজিস্টিক রিগ্রেশনের সমান শ্রেণিবিন্যাস ক্ষমতা প্রদান করে।\n",
|
||||
" * নমুনা স্পেসে, পারসেপট্রন একটি হাইপারপ্লেন ব্যবহার করে ইনপুট ডেটার দুটি শ্রেণি পৃথক করতে পারে।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**অস্বীকৃতি**: \nএই নথিটি AI অনুবাদ পরিষেবা [Co-op Translator](https://github.com/Azure/co-op-translator) ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসাধ্য সঠিকতা নিশ্চিত করার চেষ্টা করি, তবে অনুগ্রহ করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। মূল ভাষায় থাকা নথিটিকে প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ সুপারিশ করা হয়। এই অনুবাদ ব্যবহারের ফলে কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যা হলে আমরা দায়বদ্ধ থাকব না।\n"
|
||||
"\n---\n\n**অস্বীকৃতি**: \nএই নথিটি AI অনুবাদ পরিষেবা [Co-op Translator](https://github.com/Azure/co-op-translator) ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসাধ্য সঠিকতার জন্য চেষ্টা করি, তবে অনুগ্রহ করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। মূল ভাষায় থাকা নথিটিকে প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ সুপারিশ করা হয়। এই অনুবাদ ব্যবহারের ফলে কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যা হলে আমরা দায়ী থাকব না।\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:19:42+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:06:12+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "bn"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ para amostras de treinamento negativas e positivas, respectivamente\n",
|
||||
" * $\\mathcal{M}$ - um conjunto de exemplos classificados incorretamente\n",
|
||||
" \n",
|
||||
"Usaremos o processo de **descida do gradiente**. Começando com alguns pesos iniciais aleatórios $\\mathbf{w}^{(0)}$, ajustaremos os pesos a cada etapa do treinamento usando o gradiente de $E$:\n",
|
||||
"Usaremos o processo de **descida do gradiente**. Começando com alguns pesos iniciais aleatórios $\\mathbf{w}^{(0)}$, ajustaremos os pesos em cada etapa do treinamento usando o gradiente de $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Nota sobre a Taxa de Aprendizado**: O parâmetro `learning_rate` (padrão `0.01`) controla o quanto ajustamos os pesos durante cada etapa de treinamento. Isso implementa a fórmula de atualização do gradiente descendente:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Uma taxa de aprendizado maior (por exemplo, `1.0`) faz o perceptron aprender mais rápido, mas pode ultrapassar a solução ideal\n",
|
||||
"- Uma taxa de aprendizado menor (por exemplo, `0.001`) aprende mais devagar, mas pode convergir com mais precisão\n",
|
||||
"- Você pode experimentar chamando: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Como você pode ver, a precisão inicial está em torno de 50%, mas rapidamente aumenta para valores mais altos, próximos de 90%.\n",
|
||||
"\n",
|
||||
"Vamos visualizar como as classes estão separadas. Nossa função de classificação tem a forma $\\mathbf{w}^Tx$, e ela é maior que 0 para uma classe e menor que 0 para outra. Assim, a linha de separação das classes é definida por $\\mathbf{w}^Tx = 0$. Como temos apenas duas dimensões $x_0$ e $x_1$, a equação da linha seria $w_0x_0+w_1x_1+w_2 = 0$ (lembre-se de que definimos explicitamente uma dimensão extra $x_2=1$). Vamos plotar essa linha:\n"
|
||||
"Vamos visualizar como as classes estão separadas. Nossa função de classificação tem a forma $\\mathbf{w}^Tx$, e ela é maior que 0 para uma classe e menor que 0 para outra. Assim, a linha de separação das classes é definida por $\\mathbf{w}^Tx = 0$. Como temos apenas duas dimensões, $x_0$ e $x_1$, a equação da linha seria $w_0x_0+w_1x_1+w_2 = 0$ (lembre-se de que definimos explicitamente uma dimensão extra $x_2=1$). Vamos plotar essa linha:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimentando com Taxas de Aprendizado\n",
|
||||
"\n",
|
||||
"Agora vamos explorar como diferentes taxas de aprendizado afetam o processo de treinamento. A taxa de aprendizado controla o tamanho do passo no gradiente descendente - um hiperparâmetro crucial que influencia tanto a velocidade de convergência quanto a estabilidade.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Experimento Interativo de Taxa de Aprendizado\n",
|
||||
"\n",
|
||||
"Use o controle deslizante abaixo para experimentar interativamente diferentes taxas de aprendizado e veja como elas afetam a fronteira de decisão:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -379,9 +505,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Avaliar no Conjunto de Dados de Teste\n",
|
||||
"## Avaliar no Conjunto de Teste\n",
|
||||
"\n",
|
||||
"No início, separamos alguns dados para o conjunto de teste. Vamos verificar quão preciso nosso classificador é nesse conjunto de teste. Para isso, expandimos o conjunto de teste com uma dimensão extra, multiplicamos pela matriz de pesos e garantimos que o valor obtido tenha o mesmo sinal que o rótulo (+1 ou -1). Em seguida, somamos todos os valores booleanos e dividimos pelo tamanho da amostra de teste para obter a precisão:\n"
|
||||
"No início, separamos alguns dados para o conjunto de teste. Vamos verificar quão preciso nosso classificador é nesse conjunto de teste. Para isso, também expandimos o conjunto de teste com uma dimensão extra, multiplicamos pela matriz de pesos e garantimos que o valor obtido tenha o mesmo sinal que o rótulo (+1 ou -1). Em seguida, somamos todos os valores booleanos e dividimos pelo tamanho da amostra de teste para obter a precisão:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -607,7 +733,7 @@
|
|||
"source": [
|
||||
"Como você pode ver no gráfico acima, a precisão nunca ultrapassa 75%, porque é impossível traçar uma linha reta de forma a acertar todos os exemplos possíveis.\n",
|
||||
"\n",
|
||||
"O problema XOR é um exemplo clássico das limitações do perceptron, e foi apontado por Marvin Minsky e Seymour Papert em 1969 no livro [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Essa observação limitou as pesquisas na área de redes neurais por quase 10 anos, embora - e veremos isso na próxima seção do nosso curso - perceptrons multicamadas sejam perfeitamente capazes de resolver tais problemas.\n",
|
||||
"O problema XOR é um exemplo clássico das limitações do perceptron, e foi apontado por Marvin Minsky e Seymour Papert em 1969 em seu livro [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Essa observação limitou as pesquisas na área de redes neurais por quase 10 anos, embora - e veremos isso na próxima seção do nosso curso - perceptrons multicamadas sejam perfeitamente capazes de resolver tais problemas.\n",
|
||||
"\n",
|
||||
"## Exemplo Complexo - MNIST\n",
|
||||
"\n",
|
||||
|
|
@ -615,9 +741,9 @@
|
|||
"\n",
|
||||
"Um conjunto de dados frequentemente utilizado para aprender sobre aprendizado de máquina é chamado [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Ele foi criado pelo Instituto Nacional de Padrões e Tecnologia Modificado e contém um conjunto de treinamento com 60.000 dígitos manuscritos, coletados de cerca de 250 estudantes e funcionários do instituto. Há também um conjunto de teste com 10.000 dígitos, coletados de diferentes indivíduos.\n",
|
||||
"\n",
|
||||
"Todos os dígitos são representados por imagens em escala de cinza com tamanho de 28x28 pixels.\n",
|
||||
"Todos os dígitos são representados por imagens em escala de cinza de tamanho 28x28 pixels.\n",
|
||||
"\n",
|
||||
"> O conjunto de dados MNIST está disponível como uma competição de treinamento no [Kaggle](https://www.kaggle.com/c/digit-recognizer), um site que hospeda competições e desafios de aprendizado de máquina. Assim que você aprender a classificar os dígitos do MNIST, pode enviar sua solução para o Kaggle e ver como ela é avaliada entre outros participantes.\n",
|
||||
"> O conjunto de dados MNIST está disponível como uma competição de treinamento no [Kaggle](https://www.kaggle.com/c/digit-recognizer), um site que hospeda competições e desafios de aprendizado de máquina. Assim que você aprender a classificar os dígitos do MNIST, pode enviar sua solução ao Kaggle para ver como ela é avaliada entre outros participantes.\n",
|
||||
"\n",
|
||||
"Começamos carregando o conjunto de dados MNIST:\n"
|
||||
]
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"Observe como a precisão aumenta rapidamente, chegando quase a 100%.\n",
|
||||
"\n",
|
||||
"Por favor, mova o controle deslizante para uma posição próxima ao final do treinamento e observe a matriz de pesos plotada à esquerda. Essa matriz permitirá que você entenda como o perceptron realmente funciona. Você pode ver os valores altos de peso no meio do campo, que correspondem a pixels geralmente presentes no dígito 1, e valores negativos baixos nas laterais, onde estão partes do dígito 0. Assim, se o dígito apresentado ao perceptron for de fato 1, a parte central será multiplicada por valores altos, produzindo um resultado positivo. Por outro lado, quando o perceptron observa o dígito 0, os pixels correspondentes serão multiplicados por números negativos.\n",
|
||||
"Por favor, mova o controle deslizante para uma posição próxima ao final do treinamento e observe a matriz de pesos plotada à esquerda. Essa matriz permitirá que você entenda como o perceptron realmente funciona. Você pode ver os valores altos de peso no meio do campo, que correspondem a pixels que geralmente estão presentes no dígito 1, e valores negativos baixos nas laterais, onde estão partes do dígito 0. Assim, se o dígito apresentado ao perceptron for de fato 1, a parte central será multiplicada por valores altos, produzindo um resultado positivo. Por outro lado, quando o perceptron observa o dígito 0, os pixels correspondentes serão multiplicados por números negativos.\n",
|
||||
"\n",
|
||||
"> Você pode notar que, se dermos ao perceptron um dígito 1 ligeiramente deslocado horizontalmente, de forma que seus pixels ocupem o lugar onde há partes verticais do dígito 0, podemos obter um resultado incorreto. Isso ocorre porque a natureza do nosso conjunto de dados MNIST é tal que todos os dígitos estão centralizados e posicionados corretamente, e o perceptron depende disso para distinguir entre os dígitos.\n",
|
||||
"> Você pode perceber que, se dermos ao perceptron um dígito 1 ligeiramente deslocado horizontalmente, de forma que seus pixels ocupem o lugar onde há partes verticais do dígito 0, podemos obter um resultado incorreto. Isso ocorre porque a natureza do nosso conjunto de dados MNIST é tal que todos os dígitos estão centralizados e posicionados corretamente, e o perceptron depende disso para distinguir entre os dígitos.\n",
|
||||
"\n",
|
||||
"Agora vamos tentar diferentes dígitos:\n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"Por algum motivo, 2 e 5 não são tão facilmente separáveis. Embora obtenhamos uma precisão relativamente alta (acima de 85%), podemos claramente observar como o perceptron para de aprender em determinado momento.\n",
|
||||
"\n",
|
||||
"Para entender por que isso acontece, podemos tentar usar a [Análise de Componentes Principais](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). É uma técnica de aprendizado de máquina usada para reduzir a dimensionalidade do conjunto de dados de entrada, de forma a obter a melhor separabilidade entre as classes.\n",
|
||||
"Para entender por que isso acontece, podemos tentar usar [Análise de Componentes Principais](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Trata-se de uma técnica de aprendizado de máquina usada para reduzir a dimensionalidade do conjunto de dados de entrada, de forma a obter a melhor separabilidade entre as classes.\n",
|
||||
"\n",
|
||||
"No nosso caso, uma imagem de entrada possui 784 pixels (características de entrada), e queremos usar PCA para reduzir o número de parâmetros para apenas 2, para que possamos plotá-los em um gráfico. Esses dois parâmetros seriam uma combinação linear das características originais, e podemos visualizar esse procedimento como uma \"rotação\" do nosso espaço original de 784 dimensões e observar sua projeção no espaço 2D, até obtermos a melhor visualização que separa as classes.\n"
|
||||
"No nosso caso, uma imagem de entrada possui 784 pixels (características de entrada), e queremos usar PCA para reduzir o número de parâmetros para apenas 2, de modo que possamos plotá-los em um gráfico. Esses dois parâmetros seriam uma combinação linear das características originais, e podemos visualizar esse procedimento como uma \"rotação\" do nosso espaço original de 784 dimensões e a observação de sua projeção no espaço 2D, até obtermos a melhor visualização que separa as classes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.\n"
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:24:48+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:11:51+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "br"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"Protože perceptron je binární klasifikátor, výstup našeho perceptronu pro každý vstupní vektor $x$ bude buď +1, nebo -1, v závislosti na třídě. Výstup bude vypočítán pomocí vzorce\n",
|
||||
"Protože perceptron je binární klasifikátor, výstup našeho perceptronu pro každý vstupní vektor $x$ bude buď +1, nebo -1, v závislosti na třídě. Výstup bude vypočítán podle vzorce\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ pro negativní a pozitivní trénovací vzorky\n",
|
||||
" * $\\mathcal{M}$ - množina špatně klasifikovaných příkladů\n",
|
||||
" \n",
|
||||
"Použijeme proces **gradientního sestupu**. Začneme s nějakými počátečními náhodnými váhami $\\mathbf{w}^{(0)}$ a na každém kroku trénování budeme váhy upravovat pomocí gradientu $E$:\n",
|
||||
"Použijeme proces **gradientního sestupu**. Začneme s nějakými počátečními náhodnými váhami $\\mathbf{w}^{(0)}$ a na každém kroku trénování upravíme váhy pomocí gradientu $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Poznámka k učící rychlosti**: Parametr `learning_rate` (výchozí hodnota `0.01`) určuje, jak moc upravujeme váhy během každého kroku trénování. Tento parametr implementuje aktualizační vzorec gradientního sestupu:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Vyšší učící rychlost (např. `1.0`) způsobí, že perceptron se učí rychleji, ale může přeskočit optimální řešení\n",
|
||||
"- Nižší učící rychlost (např. `0.001`) se učí pomaleji, ale může konvergovat přesněji\n",
|
||||
"- Můžete experimentovat zavoláním: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Jak vidíte, počáteční přesnost je kolem 50 %, ale rychle se zvyšuje na vyšší hodnoty blízké 90 %.\n",
|
||||
"Jak můžete vidět, počáteční přesnost je kolem 50 %, ale rychle se zvyšuje na vyšší hodnoty blízké 90 %.\n",
|
||||
"\n",
|
||||
"Pojďme si vizualizovat, jak jsou třídy odděleny. Naše klasifikační funkce vypadá jako $\\mathbf{w}^Tx$, a je větší než 0 pro jednu třídu, a menší než 0 pro druhou. Linie oddělující třídy je tedy definována jako $\\mathbf{w}^Tx = 0$. Protože máme pouze dvě dimenze $x_0$ a $x_1$, rovnice pro tuto linii bude $w_0x_0+w_1x_1+w_2 = 0$ (pamatujte, že jsme explicitně definovali další dimenzi $x_2=1$). Pojďme tuto linii vykreslit:\n"
|
||||
"Pojďme si vizualizovat, jak jsou třídy odděleny. Naše klasifikační funkce vypadá jako $\\mathbf{w}^Tx$, a je větší než 0 pro jednu třídu, a menší než 0 pro druhou. Tudíž je linie oddělující třídy definována jako $\\mathbf{w}^Tx = 0$. Protože máme pouze dvě dimenze $x_0$ a $x_1$, rovnice pro tuto linii by byla $w_0x_0+w_1x_1+w_2 = 0$ (pamatujte, že jsme explicitně definovali extra dimenzi $x_2=1$). Pojďme tuto linii vykreslit:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimentování s rychlostmi učení\n",
|
||||
"\n",
|
||||
"Teď se podíváme, jak různé rychlosti učení ovlivňují proces trénování. Rychlost učení určuje velikost kroku při gradientním sestupu – klíčový hyperparametr, který ovlivňuje jak rychlost konvergence, tak stabilitu.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktivní experiment s rychlostí učení\n",
|
||||
"\n",
|
||||
"Použijte posuvník níže k interaktivnímu experimentování s různými rychlostmi učení a podívejte se, jak ovlivňují rozhodovací hranici:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -379,9 +505,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Vyhodnocení na testovacím datovém souboru\n",
|
||||
"## Vyhodnocení na testovacím datasetu\n",
|
||||
"\n",
|
||||
"Na začátku jsme oddělili část dat pro testovací datový soubor. Podívejme se, jak přesný je náš klasifikátor na tomto testovacím datovém souboru. Abychom to zjistili, rozšíříme testovací datový soubor o další rozměr, vynásobíme maticí vah a ověříme, že získaná hodnota má stejný znaménko jako štítek (+1 nebo -1). Poté sečteme všechny hodnoty typu boolean a vydělíme délkou testovacího vzorku, abychom získali přesnost:\n"
|
||||
"Na začátku jsme oddělili část dat pro testovací dataset. Podívejme se, jak přesný je náš klasifikátor na tomto testovacím datasetu. Abychom to zjistili, rozšíříme testovací dataset o další rozměr, vynásobíme maticí vah a ověříme, že získaná hodnota má stejný znaménko jako štítek (+1 nebo -1). Poté sečteme všechny hodnoty typu boolean a vydělíme délkou testovacího vzorku, abychom získali přesnost:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Pozorování procesu tréninku\n",
|
||||
"\n",
|
||||
"Už jsme viděli, jak se přesnost během tréninku snižuje. Bylo by zajímavé sledovat, jak se během tréninku chová separační čára. Níže uvedený kód vše vizualizuje na jednom grafu, a měli byste být schopni posouvat jezdec, abyste mohli \"cestovat časem\" skrz proces tréninku.\n"
|
||||
"Už jsme viděli, jak se přesnost během tréninku snižuje. Bylo by zajímavé sledovat, jak se během tréninku chová separační čára. Níže uvedený kód vše zobrazí na jednom grafu, a budete moci posouvat jezdec, abyste \"cestovali časem\" skrz proces tréninku.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -538,7 +664,7 @@
|
|||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Pojďme to zkusit! Ručně vyplníme všechny pozitivní a negativní tréninkové vzorky a poté zavoláme naši trénovací funkci definovanou výše:\n"
|
||||
"Pojďme to zkusit! Ručně vyplníme všechny pozitivní a negativní tréninkové vzorky a poté zavoláme naši funkci train definovanou výše:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Jak můžete vidět z grafu výše, přesnost nikdy nepřekročí 75 %, protože není možné nakreslit přímku tak, aby správně klasifikovala všechny příklady.\n",
|
||||
"Jak můžete vidět z výše uvedeného grafu, přesnost nikdy nepřesáhne 75 %, protože není možné nakreslit přímku tak, aby správně pokryla všechny možné příklady.\n",
|
||||
"\n",
|
||||
"Problém XOR je klasickým příkladem omezení perceptronu, na který upozornili Marvin Minsky a Seymour Papert v roce 1969 ve své knize [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Toto zjištění omezilo výzkum v oblasti neuronových sítí téměř na 10 let, i když - jak uvidíme v další části našeho kurzu - vícevrstvé perceptrony jsou schopné takové problémy vyřešit.\n",
|
||||
"Problém XOR je klasickým příkladem omezení perceptronu, na který upozornili Marvin Minsky a Seymour Papert v roce 1969 ve své knize [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Toto zjištění omezilo výzkum v oblasti neuronových sítí téměř na 10 let, i když - jak uvidíme v další části našeho kurzu - vícevrstvé perceptrony jsou schopny takové problémy bez problémů řešit.\n",
|
||||
"\n",
|
||||
"## Složitý příklad - MNIST\n",
|
||||
"\n",
|
||||
"I když perceptron nedokáže vyřešit problém XOR, dokáže vyřešit mnohem složitější problémy, jako je rozpoznávání ručně psaných znaků.\n",
|
||||
"I když perceptron nedokáže vyřešit problém XOR, dokáže řešit mnohem složitější problémy, jako je například rozpoznávání ručně psaných znaků.\n",
|
||||
"\n",
|
||||
"Datová sada, která se často používá při osvojování strojového učení, se nazývá [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Byla vytvořena Modifikovaným národním institutem standardů a technologie a obsahuje trénovací sadu 60 000 ručně psaných číslic, sesbíraných od přibližně 250 studentů a zaměstnanců institutu. K dispozici je také testovací sada 10 000 číslic, sesbíraných od různých jednotlivců.\n",
|
||||
"Datová sada, která se často používá při zvládání strojového učení, se nazývá [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Byla vytvořena Modifikovaným národním institutem standardů a technologie a obsahuje trénovací sadu 60 000 ručně psaných číslic, sesbíraných od přibližně 250 studentů a zaměstnanců institutu. Existuje také testovací sada obsahující 10 000 číslic, sesbíraných od různých jednotlivců.\n",
|
||||
"\n",
|
||||
"Všechny číslice jsou reprezentovány jako šedotónové obrázky o velikosti 28x28 pixelů.\n",
|
||||
"Všechny číslice jsou reprezentovány obrázky v odstínech šedi o velikosti 28x28 pixelů.\n",
|
||||
"\n",
|
||||
"> Datová sada MNIST je dostupná jako tréninková soutěž na [Kaggle](https://www.kaggle.com/c/digit-recognizer), což je web, který hostí soutěže a výzvy v oblasti strojového učení. Jakmile se naučíte klasifikovat číslice z MNIST, můžete svůj výsledek odeslat na Kaggle a zjistit, jak je hodnocen mezi ostatními účastníky.\n",
|
||||
"> Datová sada MNIST je dostupná jako tréninková soutěž na [Kaggle](https://www.kaggle.com/c/digit-recognizer), což je webová stránka, která hostí soutěže a výzvy v oblasti strojového učení. Jakmile se naučíte klasifikovat číslice z MNIST, můžete své řešení odeslat na Kaggle a zjistit, jak je hodnoceno mezi ostatními účastníky.\n",
|
||||
"\n",
|
||||
"Začneme načtením datové sady MNIST:\n"
|
||||
]
|
||||
|
|
@ -644,7 +770,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Pojďme nyní vykreslit datovou sadu:\n"
|
||||
"Pojďme nyní vykreslit dataset:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,7 +959,7 @@
|
|||
"source": [
|
||||
"Všimněte si, jak přesnost velmi rychle stoupá téměř na 100 %.\n",
|
||||
"\n",
|
||||
"Prosím, posuňte posuvník na nějakou pozici směrem ke konci trénování a podívejte se na matici vah zobrazenou vlevo. Tato matice vám umožní pochopit, jak perceptron skutečně funguje. Můžete vidět vysoké hodnoty vah uprostřed pole, které odpovídají pixelům, jež jsou obvykle přítomny u číslice 1, a nízké negativní hodnoty po stranách, kde se nacházejí části číslice 0. Pokud je číslice předložená perceptronu skutečně 1, její střední část bude násobena vysokými hodnotami, což povede k pozitivnímu výsledku. Naopak, když perceptron pozoruje číslici 0, odpovídající pixely budou násobeny negativními čísly.\n",
|
||||
"Prosím, posuňte posuvník na nějakou pozici směrem ke konci trénování a sledujte matici vah zobrazenou vlevo. Tato matice vám umožní pochopit, jak perceptron skutečně funguje. Můžete vidět vysoké hodnoty vah uprostřed pole, které odpovídají pixelům, jež jsou typicky přítomné u číslice 1, a nízké negativní hodnoty po stranách, kde se nacházejí části číslice 0. Takže pokud je číslice předložená perceptronu skutečně 1, její střední část bude násobena vysokými hodnotami, což povede k pozitivnímu výsledku. Naopak, když perceptron pozoruje číslici 0, odpovídající pixely budou násobeny negativními čísly.\n",
|
||||
"\n",
|
||||
"> Můžete si všimnout, že pokud dáme našemu perceptronu číslici 1 mírně posunutou horizontálně, takže její pixely zaujmou místo, kde jsou vertikální části číslice 0, můžeme obdržet nesprávný výsledek. Vzhledem k tomu, že povaha našeho datasetu MNIST je taková, že všechny číslice jsou vycentrované a správně umístěné, perceptron na tom spoléhá při rozlišování mezi číslicemi.\n",
|
||||
"\n",
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"Z nějakého důvodu nejsou čísla 2 a 5 tak snadno oddělitelná. I když dosahujeme poměrně vysoké přesnosti (nad 85 %), je zřejmé, že perceptron v určitém bodě přestává učit.\n",
|
||||
"\n",
|
||||
"Abychom pochopili, proč k tomu dochází, můžeme zkusit použít [Analýzu hlavních komponent](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Jedná se o techniku strojového učení, která se používá ke snížení dimenzionality vstupního datového souboru tak, aby bylo dosaženo co nejlepšího oddělení mezi třídami.\n",
|
||||
"Abychom pochopili, proč k tomu dochází, můžeme použít [Analýzu hlavních komponent](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Jedná se o techniku strojového učení, která se používá ke snížení dimenzionality vstupního datového souboru tak, aby bylo dosaženo co nejlepší oddělitelnosti mezi třídami.\n",
|
||||
"\n",
|
||||
"V našem případě má vstupní obrázek 784 pixelů (vstupních prvků) a chceme použít PCA ke snížení počtu parametrů na pouhé 2, abychom je mohli vykreslit na grafu. Tyto dva parametry by byly lineární kombinací původních prvků a tento postup si můžeme představit jako „otáčení“ našeho původního 784-dimenzionálního prostoru a pozorování jeho projekce do našeho 2D prostoru, dokud nezískáme nejlepší pohled, který odděluje třídy.\n"
|
||||
"V našem případě má vstupní obrázek 784 pixelů (vstupních parametrů) a chceme použít PCA ke snížení počtu parametrů na pouhé 2, abychom je mohli zobrazit na grafu. Tyto dva parametry by byly lineární kombinací původních vlastností a tento postup si můžeme představit jako „otáčení“ našeho původního 784-dimenzionálního prostoru a pozorování jeho projekce do 2D prostoru, dokud nezískáme nejlepší pohled, který odděluje třídy.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,9 +1153,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Jak vidíte, 0 a 1 lze jasně oddělit přímkou. To naznačuje, že v původním 784-dimenzionálním prostoru jsou body odpovídající číslicím také lineárně oddělitelné. V případě číslic 2 a 5 však nelze najít vhodnou projekci, která by číslice jasně oddělila, a proto dochází k některým případům nesprávné klasifikace.\n",
|
||||
"Jak můžete vidět, 0 a 1 lze jasně oddělit přímkou. To naznačuje, že v původním 784-dimenzionálním prostoru jsou body odpovídající číslicím také lineárně oddělitelné. V případě 2 a 5 však nemůžeme najít vhodnou projekci, která by číslice jasně oddělila, a proto dochází k některým případům špatné klasifikace.\n",
|
||||
"\n",
|
||||
"> Později v tomto kurzu se naučíme, jak vytvořit nelineární klasifikátory pomocí neuronových sítí a jak řešit problém číslic, které nejsou správně zarovnané. Velmi brzy dosáhneme přesnosti nad 99 % při klasifikaci číslic MNIST, přičemž je budeme klasifikovat do 10 různých tříd.\n",
|
||||
"> Později v tomto kurzu se naučíme, jak vytvářet nelineární klasifikátory pomocí neuronových sítí a jak řešit problém číslic, které nejsou správně zarovnány. Velmi brzy dosáhneme přesnosti nad 99 % při klasifikaci číslic MNIST, přičemž je budeme klasifikovat do 10 různých tříd.\n",
|
||||
"\n",
|
||||
"## Shrnutí\n",
|
||||
"\n",
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Poděkování\n",
|
||||
"\n",
|
||||
"Tento notebook je součástí [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) a byl připraven [Dmitry Soshnikovem](http://soshnikov.com). Je inspirován workshopem o neuronových sítích v Microsoft Research Cambridge. Některé kódy a ilustrativní materiály pocházejí z prezentací [Katji Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthewa Johnsona](https://www.microsoft.com/en-us/research/people/matjoh/) a [Ryota Tomioky](https://www.microsoft.com/en-us/research/people/ryoto/), a také z repozitáře [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Tento notebook je součástí [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) a byl připraven [Dmitry Soshnikovem](http://soshnikov.com). Je inspirován workshopem o neuronových sítích v Microsoft Research Cambridge. Část kódu a ilustračních materiálů pochází z prezentací [Katji Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthewa Johnsona](https://www.microsoft.com/en-us/research/people/matjoh/) a [Ryota Tomioky](https://www.microsoft.com/en-us/research/people/ryoto/), a také z repozitáře [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Prohlášení**: \nTento dokument byl přeložen pomocí služby AI pro překlady [Co-op Translator](https://github.com/Azure/co-op-translator). I když se snažíme o přesnost, mějte prosím na paměti, že automatizované překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho původním jazyce by měl být považován za autoritativní zdroj. Pro důležité informace se doporučuje profesionální lidský překlad. Neodpovídáme za žádná nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu.\n"
|
||||
"\n---\n\n**Prohlášení**: \nTento dokument byl přeložen pomocí služby AI pro překlad [Co-op Translator](https://github.com/Azure/co-op-translator). I když se snažíme o přesnost, mějte prosím na paměti, že automatizované překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho původním jazyce by měl být považován za autoritativní zdroj. Pro důležité informace se doporučuje profesionální lidský překlad. Neodpovídáme za žádná nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:42:37+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:30:41+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "cs"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"Da perceptron er en binær klassifikator, vil output for hver inputvektor $x$ fra vores perceptron være enten +1 eller -1, afhængigt af klassen. Outputtet beregnes ved hjælp af formlen\n",
|
||||
"Da perceptron er en binær klassifikator, vil output for hver inputvektor $x$ fra vores perceptron enten være +1 eller -1, afhængigt af klassen. Outputtet beregnes ved hjælp af formlen\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ for henholdsvis negative og positive træningsprøver\n",
|
||||
" * $\\mathcal{M}$ - et sæt af forkert klassificerede eksempler\n",
|
||||
" \n",
|
||||
"Vi vil anvende processen **gradientnedstigning**. Med start i nogle tilfældige indledende vægte $\\mathbf{w}^{(0)}$ justerer vi vægtene ved hvert trin i træningen ved hjælp af gradienten af $E$:\n",
|
||||
"Vi vil anvende processen **gradient descent**. Startende med nogle tilfældige initialvægte $\\mathbf{w}^{(0)}$, justerer vi vægtene ved hvert trin i træningen ved hjælp af gradienten af $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Bemærk om læringsrate**: Parameteren `learning_rate` (standardværdi `0.01`) styrer, hvor meget vi justerer vægtene under hvert træningsskridt. Dette implementerer opdateringsformlen for gradientnedstigning:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- En større læringsrate (f.eks. `1.0`) får perceptronen til at lære hurtigere, men kan overskyde den optimale løsning\n",
|
||||
"- En mindre læringsrate (f.eks. `0.001`) lærer langsommere, men kan konvergere mere præcist\n",
|
||||
"- Du kan eksperimentere ved at kalde: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Eksperimentering med læringsrater\n",
|
||||
"\n",
|
||||
"Lad os nu undersøge, hvordan forskellige læringsrater påvirker træningsprocessen. Læringsraten styrer skridtlængden i gradientnedstigning - en vigtig hyperparameter, der påvirker både konvergenshastighed og stabilitet.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktivt Eksperiment med Læringsrate\n",
|
||||
"\n",
|
||||
"Brug skyderen nedenfor til interaktivt at eksperimentere med forskellige læringsrater og se, hvordan de påvirker beslutningsgrænsen:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -379,9 +505,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Evaluér på testdatasæt\n",
|
||||
"## Evaluér på Testdatasæt\n",
|
||||
"\n",
|
||||
"I starten har vi lagt noget data til side til testdatasættet. Lad os se, hvor præcis vores klassifikator er på dette testdatasæt. For at gøre dette udvider vi også testdatasættet med en ekstra dimension, multiplicerer med vægtsmatricen og sikrer, at den opnåede værdi har samme fortegn som etiketten (+1 eller -1). Derefter summerer vi alle boolske værdier og dividerer med længden af testprøven for at beregne nøjagtigheden:\n"
|
||||
"I starten har vi lagt noget data til side til testdatasættet. Lad os se, hvor præcis vores klassifikator er på dette testdatasæt. For at gøre dette udvider vi også testdatasættet med en ekstra dimension, multiplicerer med vægtsmatricen og sikrer, at den opnåede værdi har samme fortegn som etiketten (+1 eller -1). Derefter summerer vi alle boolske værdier og dividerer med længden af testprøven for at få nøjagtigheden:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Observering træningsprocessen\n",
|
||||
"\n",
|
||||
"Vi har tidligere set, hvordan nøjagtigheden falder under træningen. Det kunne være interessant at se, hvordan separationslinjen opfører sig under træningen. Koden nedenfor vil visualisere alt på én graf, og du bør kunne flytte skyderen for at \"rejse i tiden\" gennem træningsprocessen.\n"
|
||||
"Vi har tidligere set, hvordan nøjagtigheden falder under træningen. Det kunne være interessant at se, hvordan separationslinjen opfører sig under træningen. Koden nedenfor vil visualisere alt på én graf, og du vil kunne flytte skyderen for at \"rejse i tiden\" gennem træningsprocessen.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -605,17 +731,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Som du kan se på grafen ovenfor, går nøjagtigheden aldrig over 75 %, fordi det er umuligt at tegne en lige linje, der korrekt klassificerer alle eksempler.\n",
|
||||
"Som du kan se på grafen ovenfor, går nøjagtigheden aldrig over 75 %, fordi det er umuligt at tegne en lige linje, der kan klassificere alle eksempler korrekt.\n",
|
||||
"\n",
|
||||
"XOR-problemet er et klassisk eksempel på perceptronens begrænsninger, og det blev påpeget af Marvin Minsky og Seymour Papert i 1969 i deres bog [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Denne observation begrænsede forskningen inden for neurale netværk i næsten 10 år, selvom - og det vil vi se i den næste sektion af vores kursus - flerlagede perceptroner er fuldt ud i stand til at løse sådanne problemer.\n",
|
||||
"XOR-problemet er et klassisk eksempel på perceptronens begrænsninger, og det blev påpeget af Marvin Minsky og Seymour Papert i 1969 i deres bog [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Denne observation begrænsede forskningen inden for neurale netværk i næsten 10 år, selvom - og det vil vi se i næste afsnit af vores kursus - flerlagede perceptroner er fuldt ud i stand til at løse sådanne problemer.\n",
|
||||
"\n",
|
||||
"## Komplekst Eksempel - MNIST\n",
|
||||
"\n",
|
||||
"Selvom perceptronen ikke kan løse XOR-problemet, kan den løse mange mere komplekse problemer, såsom genkendelse af håndskrevne tegn.\n",
|
||||
"\n",
|
||||
"Et datasæt, der ofte bruges, når man lærer maskinlæring, kaldes [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Det er blevet oprettet af Modified National Institute of Standards and Technology og indeholder et træningssæt med 60.000 håndskrevne cifre, indsamlet fra omkring 250 studerende og ansatte på instituttet. Der er også et testdatasæt med 10.000 cifre, indsamlet fra forskellige personer.\n",
|
||||
"Et datasæt, der ofte bruges til at mestre maskinlæring, kaldes [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Det er blevet oprettet af Modified National Institute of Standards and Technology og indeholder et træningssæt med 60.000 håndskrevne cifre, indsamlet fra omkring 250 studerende og ansatte på instituttet. Der er også et testdatasæt med 10.000 cifre, indsamlet fra forskellige personer.\n",
|
||||
"\n",
|
||||
"Alle cifre er repræsenteret af gråtonede billeder med en størrelse på 28x28 pixels.\n",
|
||||
"Alle cifre er repræsenteret ved gråtonede billeder med en størrelse på 28x28 pixels.\n",
|
||||
"\n",
|
||||
"> MNIST-datasættet er tilgængeligt som en træningskonkurrence på [Kaggle](https://www.kaggle.com/c/digit-recognizer), en hjemmeside, der afholder konkurrencer og udfordringer inden for maskinlæring. Når du har lært at klassificere MNIST-cifre, kan du indsende din løsning til Kaggle for at se, hvordan den vurderes blandt andre deltagere.\n",
|
||||
"\n",
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"Bemærk, hvordan nøjagtigheden stiger til næsten 100% meget hurtigt.\n",
|
||||
"\n",
|
||||
"Flyt venligst skyderen til en position mod slutningen af træningen, og observer vægtmatricen, der er plottet til venstre. Denne matrix vil hjælpe dig med at forstå, hvordan perceptronen faktisk fungerer. Du kan se de høje vægtværdier i midten af feltet, som svarer til pixels, der typisk er til stede for tallet 1, og lave negative værdier ved siderne, hvor dele af tallet 0 er. Så hvis det tal, der præsenteres for perceptronen, faktisk er 1, vil midterdelen af det blive multipliceret med høje værdier, hvilket giver et positivt resultat. Omvendt, når perceptronen observerer 0, vil de tilsvarende pixels blive multipliceret med negative tal.\n",
|
||||
"Flyt venligst skyderen til en position mod slutningen af træningen, og observer vægtmatricen, der er plottet til venstre. Denne matrix vil hjælpe dig med at forstå, hvordan perceptronen faktisk fungerer. Du kan se de høje vægtværdier i midten af feltet, som svarer til pixels, der typisk er til stede for tallet 1, og lave negative værdier i siderne, hvor dele af tallet 0 er. Så hvis det tal, der præsenteres for perceptronen, faktisk er 1, vil den midterste del af det blive multipliceret med høje værdier, hvilket giver et positivt resultat. Omvendt, når perceptronen observerer 0, vil de tilsvarende pixels blive multipliceret med negative tal.\n",
|
||||
"\n",
|
||||
"> Du kan bemærke, at hvis vi giver vores perceptron et 1-tal, der er let forskudt horisontalt, så dets pixels optager det sted, hvor der er vertikale dele af 0, kan vi få et forkert resultat. Da naturen af vores MNIST-datasæt er sådan, at alle tal er centreret og korrekt positioneret, og perceptronen er afhængig af dette for at skelne mellem tallene.\n",
|
||||
"> Du kan bemærke, at hvis vi giver vores perceptron et tal 1, der er let forskudt horisontalt, så dets pixels optager det sted, hvor der er lodrette dele af 0, kan vi få et forkert resultat. Da naturen af vores MNIST-datasæt er sådan, at alle tal er centreret og korrekt positioneret, er perceptronen afhængig af dette for at skelne mellem tallene.\n",
|
||||
"\n",
|
||||
"Lad os nu prøve forskellige tal:\n"
|
||||
]
|
||||
|
|
@ -1027,9 +1153,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Som du kan se, kan 0 og 1 tydeligt adskilles med en lige linje. Dette indikerer, at punkterne, der svarer til cifre, også er lineært adskillelige i det oprindelige 784-dimensionelle rum. I tilfældet med 2 og 5 kan vi ikke finde en god projektion, der klart adskiller cifrene, og derfor opstår der nogle tilfælde af forkert klassifikation.\n",
|
||||
"Som du kan se, kan 0 og 1 tydeligt adskilles med en lige linje. Dette indikerer, at punkterne, der svarer til cifrene, også er lineært adskillelige i det oprindelige 784-dimensionelle rum. I tilfældet med 2 og 5 kan vi ikke finde en god projektion, der klart adskiller cifrene, og derfor opstår der nogle tilfælde af forkert klassifikation.\n",
|
||||
"\n",
|
||||
"> Senere i dette kursus vil vi lære, hvordan man opretter ikke-lineære klassifikatorer ved hjælp af neurale netværk, og hvordan man håndterer problemet med cifre, der ikke er korrekt justeret. Meget snart vil vi opnå over 99% nøjagtighed i MNIST-cifferklassifikation, mens vi klassificerer dem i 10 forskellige klasser.\n",
|
||||
"> Senere i dette kursus vil vi lære, hvordan man skaber ikke-lineære klassifikatorer ved hjælp af neurale netværk, og hvordan man håndterer problemet med cifre, der ikke er korrekt justeret. Meget snart vil vi opnå over 99% nøjagtighed i MNIST-cifferklassifikation, mens vi klassificerer dem i 10 forskellige klasser.\n",
|
||||
"\n",
|
||||
"## Vigtigste pointer\n",
|
||||
"\n",
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Ansvarsfraskrivelse**: \nDette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selvom vi bestræber os på at sikre nøjagtighed, skal det bemærkes, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi påtager os ikke ansvar for misforståelser eller fejltolkninger, der måtte opstå som følge af brugen af denne oversættelse.\n"
|
||||
"\n---\n\n**Ansvarsfraskrivelse**: \nDette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selvom vi bestræber os på nøjagtighed, skal det bemærkes, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi påtager os ikke ansvar for misforståelser eller fejltolkninger, der måtte opstå som følge af brugen af denne oversættelse.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:31:42+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:19:25+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "da"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,11 +154,11 @@
|
|||
"source": [
|
||||
"## Perzeptron\n",
|
||||
"\n",
|
||||
"Da der Perzeptron ein binärer Klassifikator ist, wird für jeden Eingabevektor $x$ die Ausgabe unseres Perzeptrons entweder +1 oder -1 sein, abhängig von der Klasse. Die Ausgabe wird mit der Formel berechnet:\n",
|
||||
"Da ein Perzeptron ein binärer Klassifikator ist, wird für jeden Eingabevektor $x$ die Ausgabe unseres Perzeptrons entweder +1 oder -1 sein, abhängig von der Klasse. Die Ausgabe wird mit der folgenden Formel berechnet:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"wobei $\\mathbf{w}$ ein Gewichtungsvektor ist und $f$ eine Stufenaktivierungsfunktion:\n",
|
||||
"wobei $\\mathbf{w}$ ein Gewichtungsvektor ist und $f$ eine Stufenaktivierungsfunktion ist:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Ein generisches lineares Modell sollte jedoch auch einen Bias enthalten, d.h. idealerweise sollten wir $y$ als $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ berechnen. Um unser Modell zu vereinfachen, können wir diesen Bias-Term eliminieren, indem wir eine zusätzliche Dimension zu unseren Eingabefeatures hinzufügen, die immer den Wert 1 hat:\n"
|
||||
"Ein generisches lineares Modell sollte jedoch auch einen Bias enthalten, d.h. idealerweise sollten wir $y$ als $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ berechnen. Um unser Modell zu vereinfachen, können wir diesen Bias-Term eliminieren, indem wir unseren Eingabefeatures eine weitere Dimension hinzufügen, die immer gleich 1 ist:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Hinweis zur Lernrate**: Der Parameter `learning_rate` (Standardwert `0.01`) steuert, wie stark die Gewichte bei jedem Trainingsschritt angepasst werden. Dies implementiert die Aktualisierungsformel des Gradientenabstiegs:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Eine größere Lernrate (z. B. `1.0`) lässt das Perzeptron schneller lernen, kann jedoch die optimale Lösung überschreiten\n",
|
||||
"- Eine kleinere Lernrate (z. B. `0.001`) lernt langsamer, kann aber präziser konvergieren\n",
|
||||
"- Sie können experimentieren, indem Sie Folgendes aufrufen: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimentieren mit Lernraten\n",
|
||||
"\n",
|
||||
"Lassen Sie uns nun untersuchen, wie verschiedene Lernraten den Trainingsprozess beeinflussen. Die Lernrate steuert die Schrittgröße im Gradientenabstieg – ein entscheidender Hyperparameter, der sowohl die Konvergenzgeschwindigkeit als auch die Stabilität beeinflusst.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktives Experiment zur Lernrate\n",
|
||||
"\n",
|
||||
"Nutzen Sie den Schieberegler unten, um interaktiv mit verschiedenen Lernraten zu experimentieren und zu sehen, wie sie die Entscheidungsgrenze beeinflussen:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Bewertung auf dem Testdatensatz\n",
|
||||
"\n",
|
||||
"Zu Beginn haben wir einige Daten für den Testdatensatz beiseitegelegt. Schauen wir uns an, wie genau unser Klassifikator auf diesem Testdatensatz ist. Dafür erweitern wir den Testdatensatz um eine zusätzliche Dimension, multiplizieren ihn mit der Gewichtsmatrix und stellen sicher, dass der erhaltene Wert dasselbe Vorzeichen wie das Label hat (+1 oder -1). Anschließend summieren wir alle booleschen Werte und teilen durch die Länge der Testprobe, um die Genauigkeit zu berechnen:\n"
|
||||
"Zu Beginn haben wir einige Daten für den Testdatensatz beiseitegelegt. Schauen wir uns an, wie genau unser Klassifikator auf diesem Testdatensatz ist. Dafür erweitern wir den Testdatensatz um eine zusätzliche Dimension, multiplizieren ihn mit der Gewichtsmatrix und stellen sicher, dass der erhaltene Wert das gleiche Vorzeichen wie das Label hat (+1 oder -1). Anschließend summieren wir alle booleschen Werte und teilen durch die Länge der Testprobe, um die Genauigkeit zu berechnen:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -531,14 +657,14 @@
|
|||
"\n",
|
||||
"Wie oben gezeigt, ist das Perzeptron ein **linearer Klassifikator**. Es kann zwei Klassen gut unterscheiden, wenn sie **linear trennbar** sind, d. h. durch eine gerade Linie getrennt werden können. Andernfalls wird der Trainingsprozess des Perzeptrons nicht konvergieren.\n",
|
||||
"\n",
|
||||
"Ein offensichtliches Beispiel für ein Problem, das von einem Perzeptron nicht gelöst werden kann, ist das sogenannte **XOR-Problem**. Wir möchten, dass unser Perzeptron die XOR-Logikfunktion lernt, die folgende Wahrheitstabelle hat:\n",
|
||||
"Ein offensichtliches Beispiel für ein Problem, das nicht durch ein Perzeptron gelöst werden kann, ist das sogenannte **XOR-Problem**. Wir möchten, dass unser Perzeptron die XOR-Boolesche Funktion lernt, die folgende Wahrheitstabelle hat:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Versuchen wir es! Wir werden alle positiven und negativen Trainingsbeispiele manuell einfügen und dann unsere oben definierte Trainingsfunktion aufrufen:\n"
|
||||
"Lassen Sie uns das ausprobieren! Wir werden alle positiven und negativen Trainingsbeispiele manuell einfügen und dann unsere oben definierte Trainingsfunktion aufrufen:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,7 +731,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Wie aus dem obigen Diagramm ersichtlich, überschreitet die Genauigkeit niemals 75 %, da es unmöglich ist, eine gerade Linie so zu ziehen, dass alle möglichen Beispiele korrekt erfasst werden.\n",
|
||||
"Wie aus dem obigen Diagramm ersichtlich, übersteigt die Genauigkeit niemals 75 %, da es unmöglich ist, eine gerade Linie so zu ziehen, dass alle möglichen Beispiele korrekt klassifiziert werden.\n",
|
||||
"\n",
|
||||
"Das XOR-Problem ist ein klassisches Beispiel für die Grenzen des Perzeptrons und wurde 1969 von Marvin Minsky und Seymour Papert in ihrem Buch [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) aufgezeigt. Diese Beobachtung schränkte die Forschung im Bereich der neuronalen Netze fast 10 Jahre lang ein, obwohl - und das werden wir im nächsten Abschnitt unseres Kurses sehen - mehrschichtige Perzeptrons solche Probleme problemlos lösen können.\n",
|
||||
"\n",
|
||||
|
|
@ -613,11 +739,11 @@
|
|||
"\n",
|
||||
"Auch wenn ein Perzeptron das XOR-Problem nicht lösen kann, ist es in der Lage, viele komplexere Probleme zu bewältigen, wie beispielsweise die Erkennung handgeschriebener Zeichen.\n",
|
||||
"\n",
|
||||
"Ein Datensatz, der häufig beim Erlernen von maschinellem Lernen verwendet wird, heißt [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Er wurde vom Modified National Institute of Standards and Technology erstellt und enthält einen Trainingssatz mit 60.000 handgeschriebenen Ziffern, die von etwa 250 Studenten und Mitarbeitern des Instituts gesammelt wurden. Es gibt auch einen Testdatensatz mit 10.000 Ziffern, die von verschiedenen Personen stammen.\n",
|
||||
"Ein Datensatz, der häufig verwendet wird, um maschinelles Lernen zu meistern, heißt [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Er wurde vom Modified National Institute of Standards and Technology erstellt und enthält einen Trainingssatz mit 60.000 handgeschriebenen Ziffern, die von etwa 250 Studenten und Mitarbeitern des Instituts gesammelt wurden. Es gibt auch einen Testdatensatz mit 10.000 Ziffern, die von verschiedenen Personen stammen.\n",
|
||||
"\n",
|
||||
"Alle Ziffern sind durch Graustufenbilder mit einer Größe von 28x28 Pixeln dargestellt.\n",
|
||||
"Alle Ziffern werden durch Graustufenbilder mit einer Größe von 28x28 Pixeln dargestellt.\n",
|
||||
"\n",
|
||||
"> Der MNIST-Datensatz ist als Trainingswettbewerb auf [Kaggle](https://www.kaggle.com/c/digit-recognizer) verfügbar, einer Plattform, die Wettbewerbe und Herausforderungen im Bereich maschinelles Lernen veranstaltet. Sobald Sie gelernt haben, wie man MNIST-Ziffern klassifiziert, können Sie Ihre Lösung bei Kaggle einreichen, um zu sehen, wie sie im Vergleich zu anderen Teilnehmern bewertet wird.\n",
|
||||
"> Der MNIST-Datensatz ist als Trainingswettbewerb auf [Kaggle](https://www.kaggle.com/c/digit-recognizer) verfügbar, einer Plattform, die Wettbewerbe und Herausforderungen im Bereich maschinelles Lernen ausrichtet. Sobald Sie gelernt haben, wie man MNIST-Ziffern klassifiziert, können Sie Ihre Lösung bei Kaggle einreichen, um zu sehen, wie sie im Vergleich zu anderen Teilnehmern bewertet wird.\n",
|
||||
"\n",
|
||||
"Wir beginnen mit dem Laden des MNIST-Datensatzes:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Da der Perzeptron ein binärer Klassifikator ist, werden wir unser Problem darauf beschränken, nur zwei Ziffern zu erkennen. Die folgende Funktion wird positive und negative Beispielarrays mit zwei gegebenen Ziffern füllen (und zur Verdeutlichung auch Beispiele dieser Ziffern anzeigen).\n"
|
||||
"Da der Perzeptron ein binärer Klassifikator ist, werden wir unser Problem darauf beschränken, nur zwei Ziffern zu erkennen. Die folgende Funktion wird positive und negative Beispielarrays mit zwei gegebenen Ziffern füllen (und wird auch Beispiele dieser Ziffern zur Verdeutlichung anzeigen).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -915,7 +1041,7 @@
|
|||
"\n",
|
||||
"Aus irgendeinem Grund sind 2 und 5 nicht so leicht voneinander zu trennen. Obwohl wir eine relativ hohe Genauigkeit (über 85 %) erreichen, können wir deutlich sehen, wie der Perzeptron irgendwann aufhört zu lernen.\n",
|
||||
"\n",
|
||||
"Um zu verstehen, warum das passiert, können wir versuchen, [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) zu verwenden. Dies ist eine Technik des maschinellen Lernens, die dazu dient, die Dimensionalität des Eingabedatensatzes zu reduzieren, um die bestmögliche Trennbarkeit zwischen den Klassen zu erreichen.\n",
|
||||
"Um zu verstehen, warum das passiert, können wir versuchen, [Principal Component Analysis](https://de.wikipedia.org/wiki/Hauptkomponentenanalyse) (PCA) zu verwenden. Dies ist eine Technik des maschinellen Lernens, die dazu dient, die Dimensionalität des Eingabedatensatzes zu reduzieren, um die bestmögliche Trennbarkeit zwischen den Klassen zu erreichen.\n",
|
||||
"\n",
|
||||
"In unserem Fall hat ein Eingabebild 784 Pixel (Eingabemerkmale), und wir möchten PCA verwenden, um die Anzahl der Parameter auf nur 2 zu reduzieren, damit wir sie auf einem Diagramm darstellen können. Diese beiden Parameter wären eine lineare Kombination der ursprünglichen Merkmale, und wir können diesen Vorgang als eine \"Rotation\" unseres ursprünglichen 784-dimensionalen Raums betrachten, bei der wir dessen Projektion auf unseren 2D-Raum beobachten, bis wir die beste Ansicht erhalten, die die Klassen trennt.\n"
|
||||
]
|
||||
|
|
@ -1029,12 +1155,12 @@
|
|||
"source": [
|
||||
"Wie Sie sehen können, können 0 und 1 klar durch eine gerade Linie getrennt werden. Dies zeigt, dass die Punkte, die den Ziffern im ursprünglichen 784-dimensionalen Raum entsprechen, ebenfalls linear trennbar sind. Im Fall von 2 und 5 können wir jedoch keine geeignete Projektion finden, die die Ziffern klar trennt, und daher gibt es einige Fälle von falscher Klassifikation.\n",
|
||||
"\n",
|
||||
"> Später in diesem Kurs werden wir lernen, wie man nicht-lineare Klassifikatoren mit neuronalen Netzwerken erstellt und wie man das Problem von Ziffern angeht, die nicht richtig ausgerichtet sind. Sehr bald werden wir eine Genauigkeit von über 99 % bei der MNIST-Ziffernklassifikation erreichen, während wir sie in 10 verschiedene Klassen einteilen.\n",
|
||||
"> Später in diesem Kurs werden wir lernen, wie man nicht-lineare Klassifikatoren mit neuronalen Netzwerken erstellt und wie man mit dem Problem umgeht, dass Ziffern nicht richtig ausgerichtet sind. Schon bald werden wir eine Genauigkeit von über 99 % bei der MNIST-Ziffernklassifikation erreichen, während wir sie in 10 verschiedene Klassen einteilen.\n",
|
||||
"\n",
|
||||
"## Fazit\n",
|
||||
"\n",
|
||||
" * Wir haben die einfachste Architektur eines neuronalen Netzwerks kennengelernt – den Ein-Schicht-Perzeptron.\n",
|
||||
" * Wir haben den Perzeptron „von Hand“ implementiert, mit einem einfachen Trainingsverfahren basierend auf Gradientenabstieg.\n",
|
||||
" * Wir haben den Perzeptron \"von Hand\" implementiert, mit einem einfachen Trainingsverfahren basierend auf Gradientenabstieg.\n",
|
||||
" * Trotz seiner Einfachheit kann der Ein-Schicht-Perzeptron recht komplexe Probleme der handschriftlichen Ziffernerkennung lösen.\n",
|
||||
" * Der Ein-Schicht-Perzeptron ist ein linearer Klassifikator und bietet daher die gleiche Klassifikationsleistung wie die logistische Regression.\n",
|
||||
" * Im Merkmalsraum kann der Perzeptron zwei Klassen von Eingabedaten mithilfe einer Hyperebene trennen.\n"
|
||||
|
|
@ -1046,7 +1172,7 @@
|
|||
"source": [
|
||||
"## Credits\n",
|
||||
"\n",
|
||||
"Dieses Notebook ist Teil des [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) und wurde von [Dmitry Soshnikov](http://soshnikov.com) erstellt. Es ist inspiriert von dem Neural Network Workshop bei Microsoft Research Cambridge. Einige Codebeispiele und Illustrationsmaterialien stammen aus Präsentationen von [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) und [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), sowie aus dem Repository [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Dieses Notebook ist Teil des [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) und wurde von [Dmitry Soshnikov](http://soshnikov.com) erstellt. Es ist inspiriert vom Neural Network Workshop bei Microsoft Research Cambridge. Einige Codebeispiele und Illustrationsmaterialien stammen aus Präsentationen von [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) und [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), sowie aus dem Repository [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:08:02+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:53:28+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "de"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Απλό Πρόβλημα\n",
|
||||
"## Πρόβλημα Παιχνιδιού\n",
|
||||
"\n",
|
||||
"Για αρχή, ας ξεκινήσουμε με ένα απλό πρόβλημα, όπου έχουμε δύο χαρακτηριστικά εισόδου. Για παράδειγμα, στην ιατρική μπορεί να θέλουμε να ταξινομήσουμε όγκους σε καλοήθεις και κακοήθεις, ανάλογα με το μέγεθος και την ηλικία τους.\n",
|
||||
"Ας ξεκινήσουμε με ένα απλό πρόβλημα, όπου έχουμε δύο χαρακτηριστικά εισόδου. Για παράδειγμα, στην ιατρική μπορεί να θέλουμε να ταξινομήσουμε όγκους σε καλοήθεις και κακοήθεις, ανάλογα με το μέγεθος και την ηλικία τους.\n",
|
||||
"\n",
|
||||
"Θα δημιουργήσουμε ένα τυχαίο σύνολο δεδομένων ταξινόμησης χρησιμοποιώντας τη συνάρτηση `make_classification` από τη βιβλιοθήκη SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -158,7 +158,7 @@
|
|||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"όπου $\\mathbf{w}$ είναι ένα διάνυσμα βαρών, και $f$ είναι μια βηματική συνάρτηση ενεργοποίησης:\n",
|
||||
"όπου $\\mathbf{w}$ είναι ένα διανυσματικό βάρος, και $f$ είναι μια συνάρτηση ενεργοποίησης βήματος:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Σημείωση για τον Ρυθμό Μάθησης**: Η παράμετρος `learning_rate` (προεπιλογή `0.01`) ελέγχει πόσο προσαρμόζουμε τα βάρη σε κάθε βήμα εκπαίδευσης. Αυτό υλοποιεί τον τύπο ενημέρωσης της μεθόδου gradient descent:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Ένας μεγαλύτερος ρυθμός μάθησης (π.χ., `1.0`) κάνει το perceptron να μαθαίνει πιο γρήγορα αλλά μπορεί να υπερβεί τη βέλτιστη λύση\n",
|
||||
"- Ένας μικρότερος ρυθμός μάθησης (π.χ., `0.001`) μαθαίνει πιο αργά αλλά μπορεί να συγκλίνει πιο ακριβώς\n",
|
||||
"- Μπορείτε να πειραματιστείτε καλώντας: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Όπως μπορείτε να δείτε, η αρχική ακρίβεια είναι περίπου 50%, αλλά αυξάνεται γρήγορα σε υψηλότερες τιμές κοντά στο 90%.\n",
|
||||
"\n",
|
||||
"Ας οπτικοποιήσουμε πώς διαχωρίζονται οι κατηγορίες. Η συνάρτηση ταξινόμησής μας μοιάζει με $\\mathbf{w}^Tx$, και είναι μεγαλύτερη από 0 για μία κατηγορία, ενώ είναι μικρότερη από 0 για την άλλη. Επομένως, η γραμμή διαχωρισμού των κατηγοριών ορίζεται από $\\mathbf{w}^Tx = 0$. Επειδή έχουμε μόνο δύο διαστάσεις $x_0$ και $x_1$, η εξίσωση για τη γραμμή θα είναι $w_0x_0+w_1x_1+w_2 = 0$ (θυμηθείτε ότι έχουμε ορίσει ρητά μία επιπλέον διάσταση $x_2=1$). Ας σχεδιάσουμε αυτή τη γραμμή:\n"
|
||||
"Ας οπτικοποιήσουμε πώς διαχωρίζονται οι κατηγορίες. Η συνάρτηση ταξινόμησης μας έχει τη μορφή $\\mathbf{w}^Tx$, και είναι μεγαλύτερη από 0 για μία κατηγορία, ενώ είναι μικρότερη από 0 για την άλλη. Επομένως, η γραμμή διαχωρισμού των κατηγοριών ορίζεται από $\\mathbf{w}^Tx = 0$. Επειδή έχουμε μόνο δύο διαστάσεις $x_0$ και $x_1$, η εξίσωση για τη γραμμή θα είναι $w_0x_0+w_1x_1+w_2 = 0$ (θυμηθείτε ότι έχουμε ορίσει ρητά μια επιπλέον διάσταση $x_2=1$). Ας σχεδιάσουμε αυτή τη γραμμή:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Πειραματισμός με Ρυθμούς Μάθησης\n",
|
||||
"\n",
|
||||
"Ας εξερευνήσουμε τώρα πώς οι διαφορετικοί ρυθμοί μάθησης επηρεάζουν τη διαδικασία εκπαίδευσης. Ο ρυθμός μάθησης ελέγχει το μέγεθος του βήματος στην κατάβαση κλίσης - μια κρίσιμη υπερπαράμετρος που επηρεάζει τόσο την ταχύτητα σύγκλισης όσο και τη σταθερότητα.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Διαδραστικό Πείραμα Ρυθμού Μάθησης\n",
|
||||
"\n",
|
||||
"Χρησιμοποιήστε τον παρακάτω ρυθμιστή για να πειραματιστείτε διαδραστικά με διαφορετικούς ρυθμούς μάθησης και δείτε πώς επηρεάζουν το όριο απόφασης:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Αξιολόγηση στο Σύνολο Δοκιμών\n",
|
||||
"\n",
|
||||
"Στην αρχή, έχουμε κρατήσει κάποια δεδομένα για το σύνολο δοκιμών. Ας δούμε πόσο ακριβής είναι ο ταξινομητής μας σε αυτό το σύνολο δοκιμών. Για να το κάνουμε αυτό, επεκτείνουμε επίσης το σύνολο δοκιμών με μια επιπλέον διάσταση, πολλαπλασιάζουμε με τον πίνακα βαρών και βεβαιωνόμαστε ότι η προκύπτουσα τιμή έχει το ίδιο πρόσημο με την ετικέτα (+1 ή -1). Στη συνέχεια, προσθέτουμε όλες τις λογικές τιμές και διαιρούμε με το μήκος του δείγματος δοκιμών, για να υπολογίσουμε την ακρίβεια:\n"
|
||||
"Στην αρχή, έχουμε κρατήσει κάποια δεδομένα για το σύνολο δοκιμών. Ας δούμε πόσο ακριβής είναι ο ταξινομητής μας σε αυτό το σύνολο δοκιμών. Για να το κάνουμε αυτό, επεκτείνουμε επίσης το σύνολο δοκιμών με μια επιπλέον διάσταση, πολλαπλασιάζουμε με τον πίνακα βαρών και βεβαιωνόμαστε ότι η προκύπτουσα τιμή έχει το ίδιο πρόσημο με την ετικέτα (+1 ή -1). Στη συνέχεια, προσθέτουμε όλες τις λογικές τιμές και διαιρούμε με το μέγεθος του δείγματος δοκιμών, για να υπολογίσουμε την ακρίβεια:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Παρακολούθηση της διαδικασίας εκπαίδευσης\n",
|
||||
"\n",
|
||||
"Έχουμε δει προηγουμένως πώς μειώνεται η ακρίβεια κατά τη διάρκεια της εκπαίδευσης. Θα ήταν ενδιαφέρον να δούμε πώς συμπεριφέρεται η γραμμή διαχωρισμού κατά τη διάρκεια της εκπαίδευσης. Ο παρακάτω κώδικας θα οπτικοποιήσει τα πάντα σε ένα γράφημα, και θα μπορείτε να μετακινήσετε τον δείκτη για να \"ταξιδέψετε στον χρόνο\" μέσα από τη διαδικασία εκπαίδευσης.\n"
|
||||
"Έχουμε δει προηγουμένως πώς μειώνεται η ακρίβεια κατά τη διάρκεια της εκπαίδευσης. Θα ήταν ενδιαφέρον να δούμε πώς συμπεριφέρεται η γραμμή διαχωρισμού κατά τη διάρκεια της εκπαίδευσης. Ο παρακάτω κώδικας θα οπτικοποιήσει τα πάντα σε ένα γράφημα, και θα μπορείτε να μετακινήσετε τον slider για να \"ταξιδέψετε στον χρόνο\" μέσα στη διαδικασία εκπαίδευσης.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -538,7 +664,7 @@
|
|||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Ας προσπαθήσουμε να το κάνουμε! Θα εισάγουμε χειροκίνητα όλα τα θετικά και αρνητικά δείγματα εκπαίδευσης και στη συνέχεια θα καλέσουμε τη συνάρτηση εκπαίδευσης που ορίσαμε παραπάνω:\n"
|
||||
"Ας προσπαθήσουμε να το κάνουμε! Θα γεμίσουμε χειροκίνητα όλα τα θετικά και αρνητικά δείγματα εκπαίδευσης και στη συνέχεια θα καλέσουμε τη συνάρτηση εκπαίδευσης που ορίσαμε παραπάνω:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,9 +731,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Όπως μπορείτε να δείτε από το παραπάνω γράφημα, η ακρίβεια δεν ξεπερνά ποτέ το 75%, επειδή είναι αδύνατο να σχεδιάσετε μια ευθεία γραμμή με τέτοιο τρόπο ώστε να καλύπτονται σωστά όλα τα πιθανά παραδείγματα.\n",
|
||||
"Όπως μπορείτε να δείτε από το παραπάνω γράφημα, η ακρίβεια δεν ξεπερνά ποτέ το 75%, επειδή είναι αδύνατο να σχεδιάσετε μια ευθεία γραμμή με τέτοιο τρόπο ώστε να καλύπτονται σωστά όλα τα παραδείγματα.\n",
|
||||
"\n",
|
||||
"Το πρόβλημα XOR είναι ένα κλασικό παράδειγμα των περιορισμών του perceptron, και επισημάνθηκε από τους Marvin Minsky και Seymour Papert το 1969 στο βιβλίο τους [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Αυτή η παρατήρηση περιόρισε την έρευνα στον τομέα των νευρωνικών δικτύων για σχεδόν 10 χρόνια, παρόλο που - όπως θα δούμε στην επόμενη ενότητα του μαθήματός μας - τα πολυεπίπεδα perceptrons είναι απολύτως ικανά να λύσουν τέτοια προβλήματα.\n",
|
||||
"Το πρόβλημα XOR είναι ένα κλασικό παράδειγμα των περιορισμών του perceptron, και επισημάνθηκε από τους Marvin Minsky και Seymour Papert το 1969 στο βιβλίο τους [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Αυτή η παρατήρηση περιόρισε την έρευνα στον τομέα των νευρωνικών δικτύων για σχεδόν 10 χρόνια, παρόλο που - και θα το δούμε στην επόμενη ενότητα του μαθήματός μας - τα perceptrons με πολλαπλά επίπεδα είναι απολύτως ικανά να λύσουν τέτοια προβλήματα.\n",
|
||||
"\n",
|
||||
"## Σύνθετο Παράδειγμα - MNIST\n",
|
||||
"\n",
|
||||
|
|
@ -615,9 +741,9 @@
|
|||
"\n",
|
||||
"Ένα σύνολο δεδομένων που χρησιμοποιείται συχνά για την εκμάθηση της μηχανικής μάθησης ονομάζεται [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Δημιουργήθηκε από το Modified National Institute of Standards and Technology και περιέχει ένα σύνολο εκπαίδευσης με 60.000 χειρόγραφους αριθμούς, που συλλέχθηκαν από περίπου 250 μαθητές και υπαλλήλους του ινστιτούτου. Υπάρχει επίσης ένα σύνολο δοκιμών με 10.000 αριθμούς, που συλλέχθηκαν από διαφορετικά άτομα.\n",
|
||||
"\n",
|
||||
"Όλοι οι αριθμοί αντιπροσωπεύονται από εικόνες σε κλίμακα του γκρι με μέγεθος 28x28 pixels.\n",
|
||||
"Όλοι οι αριθμοί αναπαρίστανται από εικόνες σε κλίμακα του γκρι, μεγέθους 28x28 pixels.\n",
|
||||
"\n",
|
||||
"> Το σύνολο δεδομένων MNIST είναι διαθέσιμο ως διαγωνισμός εκπαίδευσης στο [Kaggle](https://www.kaggle.com/c/digit-recognizer), έναν ιστότοπο που φιλοξενεί διαγωνισμούς και διαγωνισμούς μηχανικής μάθησης. Μόλις μάθετε πώς να ταξινομείτε τους αριθμούς MNIST, μπορείτε να υποβάλετε τη λύση σας στο Kaggle για να δείτε πώς αξιολογείται μεταξύ άλλων συμμετεχόντων.\n",
|
||||
"> Το σύνολο δεδομένων MNIST είναι διαθέσιμο ως διαγωνισμός εκπαίδευσης στο [Kaggle](https://www.kaggle.com/c/digit-recognizer), έναν ιστότοπο που φιλοξενεί διαγωνισμούς και προκλήσεις μηχανικής μάθησης. Μόλις μάθετε πώς να ταξινομείτε τους αριθμούς του MNIST, μπορείτε να υποβάλετε τη λύση σας στο Kaggle για να δείτε πώς αξιολογείται σε σύγκριση με άλλους συμμετέχοντες.\n",
|
||||
"\n",
|
||||
"Ξεκινάμε φορτώνοντας το σύνολο δεδομένων MNIST:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Επειδή ο perceptron είναι ένας δυαδικός ταξινομητής, θα περιορίσουμε το πρόβλημά μας στην αναγνώριση μόνο δύο ψηφίων. Η παρακάτω συνάρτηση θα γεμίσει τους πίνακες θετικών και αρνητικών δειγμάτων με δύο δεδομένα ψηφία (και θα δείξει επίσης δείγματα αυτών των ψηφίων για λόγους σαφήνειας).\n"
|
||||
"Επειδή ο perceptron είναι ένας δυαδικός ταξινομητής, θα περιορίσουμε το πρόβλημά μας στην αναγνώριση μόνο δύο ψηφίων. Η παρακάτω συνάρτηση θα γεμίσει τους πίνακες θετικών και αρνητικών δειγμάτων με δύο δεδομένα ψηφία (και θα δείξει επίσης δείγματα αυτών των ψηφίων για σαφήνεια).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,7 +959,7 @@
|
|||
"source": [
|
||||
"Λάβετε υπόψη ότι η ακρίβεια αυξάνεται σχεδόν στο 100% πολύ γρήγορα.\n",
|
||||
"\n",
|
||||
"Παρακαλώ, μετακινήστε τον slider σε κάποια θέση προς το τέλος της εκπαίδευσης και παρατηρήστε τον πίνακα βαρών που εμφανίζεται στα αριστερά. Αυτός ο πίνακας θα σας βοηθήσει να κατανοήσετε πώς λειτουργεί ο perceptron. Μπορείτε να δείτε τις υψηλές τιμές βαρών στο κέντρο του πεδίου, οι οποίες αντιστοιχούν σε pixels που συνήθως υπάρχουν για το ψηφίο 1, και χαμηλές αρνητικές τιμές στις πλευρές, όπου βρίσκονται μέρη του ψηφίου 0. Έτσι, αν το ψηφίο που παρουσιάζεται στον perceptron είναι πράγματι το 1, το κεντρικό μέρος του θα πολλαπλασιαστεί με υψηλές τιμές, παράγοντας θετικό αποτέλεσμα. Αντίθετα, όταν ο perceptron παρατηρεί το 0, τα αντίστοιχα pixels θα πολλαπλασιαστούν με αρνητικούς αριθμούς.\n",
|
||||
"Παρακαλώ, μετακινήστε τον slider σε κάποια θέση προς το τέλος της εκπαίδευσης και παρατηρήστε τον πίνακα βαρών που εμφανίζεται στα αριστερά. Αυτός ο πίνακας θα σας βοηθήσει να κατανοήσετε πώς λειτουργεί ο perceptron. Μπορείτε να δείτε τις υψηλές τιμές βαρών στο κέντρο του πεδίου, οι οποίες αντιστοιχούν σε pixels που συνήθως υπάρχουν για το ψηφίο 1, και χαμηλές αρνητικές τιμές στα πλάγια, όπου βρίσκονται μέρη του ψηφίου 0. Έτσι, αν το ψηφίο που παρουσιάζεται στον perceptron είναι πράγματι το 1, το κεντρικό μέρος του θα πολλαπλασιαστεί με υψηλές τιμές, παράγοντας θετικό αποτέλεσμα. Αντίθετα, όταν ο perceptron παρατηρεί το 0, τα αντίστοιχα pixels θα πολλαπλασιαστούν με αρνητικούς αριθμούς.\n",
|
||||
"\n",
|
||||
"> Μπορεί να παρατηρήσετε ότι αν δώσουμε στον perceptron ένα ψηφίο 1 ελαφρώς μετατοπισμένο οριζόντια, έτσι ώστε τα pixels του να καταλαμβάνουν τη θέση όπου υπάρχουν κάθετα μέρη του 0, μπορεί να λάβουμε λανθασμένο αποτέλεσμα. Επειδή η φύση του dataset MNIST είναι τέτοια που όλα τα ψηφία είναι κεντραρισμένα και τοποθετημένα σωστά, και ο perceptron βασίζεται σε αυτό για να διακρίνει τα ψηφία.\n",
|
||||
"\n",
|
||||
|
|
@ -917,7 +1043,7 @@
|
|||
"\n",
|
||||
"Για να κατανοήσουμε γιατί συμβαίνει αυτό, μπορούμε να χρησιμοποιήσουμε την [Ανάλυση Κύριων Συνιστωσών](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Πρόκειται για μια τεχνική μηχανικής μάθησης που χρησιμοποιείται για τη μείωση της διαστασιμότητας του συνόλου δεδομένων εισόδου, με τέτοιο τρόπο ώστε να επιτευχθεί ο καλύτερος δυνατός διαχωρισμός μεταξύ των κατηγοριών.\n",
|
||||
"\n",
|
||||
"Στην περίπτωσή μας, μια εικόνα εισόδου έχει 784 pixels (χαρακτηριστικά εισόδου), και θέλουμε να χρησιμοποιήσουμε το PCA για να μειώσουμε τον αριθμό των παραμέτρων σε μόλις 2, ώστε να μπορέσουμε να τους απεικονίσουμε σε ένα γράφημα. Αυτές οι δύο παράμετροι θα είναι γραμμικός συνδυασμός των αρχικών χαρακτηριστικών, και μπορούμε να δούμε αυτή τη διαδικασία ως \"περιστροφή\" του αρχικού μας χώρου των 784 διαστάσεων και την παρατήρηση της προβολής του στον δισδιάστατο χώρο μας, μέχρι να αποκτήσουμε την καλύτερη θέα που διαχωρίζει τις κατηγορίες.\n"
|
||||
"Στην περίπτωσή μας, μια εικόνα εισόδου έχει 784 pixels (χαρακτηριστικά εισόδου), και θέλουμε να χρησιμοποιήσουμε την PCA για να μειώσουμε τον αριθμό των παραμέτρων σε μόλις 2, ώστε να μπορέσουμε να τους απεικονίσουμε σε ένα γράφημα. Αυτές οι δύο παράμετροι θα είναι γραμμικός συνδυασμός των αρχικών χαρακτηριστικών, και μπορούμε να δούμε αυτή τη διαδικασία ως \"περιστροφή\" του αρχικού μας χώρου των 784 διαστάσεων και παρατήρηση της προβολής του στον δισδιάστατο χώρο, μέχρι να αποκτήσουμε την καλύτερη δυνατή προβολή που διαχωρίζει τις κατηγορίες.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,15 +1153,15 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Όπως μπορείτε να δείτε, το 0 και το 1 μπορούν να διαχωριστούν ξεκάθαρα με μια ευθεία γραμμή. Αυτό δείχνει ότι στον αρχικό χώρο των 784 διαστάσεων, τα σημεία που αντιστοιχούν στα ψηφία είναι επίσης γραμμικά διαχωρίσιμα. Στην περίπτωση του 2 και του 5, δεν μπορούμε να βρούμε την κατάλληλη προβολή που θα διαχωρίσει τα ψηφία ξεκάθαρα, και έτσι υπάρχουν ορισμένες περιπτώσεις λανθασμένης ταξινόμησης.\n",
|
||||
"Όπως μπορείτε να δείτε, το 0 και το 1 μπορούν να διαχωριστούν ξεκάθαρα με μια ευθεία γραμμή. Αυτό υποδεικνύει ότι στον αρχικό χώρο των 784 διαστάσεων, τα σημεία που αντιστοιχούν στα ψηφία είναι επίσης γραμμικά διαχωρίσιμα. Στην περίπτωση του 2 και του 5, δεν μπορούμε να βρούμε την κατάλληλη προβολή που θα διαχωρίσει τα ψηφία ξεκάθαρα, και έτσι υπάρχουν ορισμένες περιπτώσεις λανθασμένης ταξινόμησης.\n",
|
||||
"\n",
|
||||
"> Αργότερα σε αυτό το μάθημα θα μάθουμε πώς να δημιουργούμε μη γραμμικούς ταξινομητές χρησιμοποιώντας Νευρωνικά Δίκτυα, και πώς να αντιμετωπίζουμε το πρόβλημα των ψηφίων που δεν είναι σωστά ευθυγραμμισμένα. Πολύ σύντομα θα φτάσουμε πάνω από 99% ακρίβεια στην ταξινόμηση ψηφίων MNIST, ενώ θα τα ταξινομούμε σε 10 διαφορετικές κατηγορίες.\n",
|
||||
"\n",
|
||||
"## Συμπεράσματα\n",
|
||||
"\n",
|
||||
" * Μάθαμε για την απλούστερη αρχιτεκτονική νευρωνικού δικτύου - τον μονοστρωματικό perceptron.\n",
|
||||
" * Υλοποιήσαμε τον perceptron \"χειροκίνητα\", χρησιμοποιώντας μια απλή διαδικασία εκπαίδευσης βασισμένη στην κλίση.\n",
|
||||
" * Παρά την απλότητα, ο μονοστρωματικός perceptron μπορεί να λύσει αρκετά σύνθετα προβλήματα αναγνώρισης χειρόγραφων ψηφίων.\n",
|
||||
" * Υλοποιήσαμε τον perceptron \"χειροκίνητα\", χρησιμοποιώντας μια απλή διαδικασία εκπαίδευσης βασισμένη στην καθοδική κλίση.\n",
|
||||
" * Παρά την απλότητα του, ο μονοστρωματικός perceptron μπορεί να λύσει αρκετά σύνθετα προβλήματα αναγνώρισης χειρόγραφων ψηφίων.\n",
|
||||
" * Ο μονοστρωματικός perceptron είναι ένας γραμμικός ταξινομητής, και έτσι παρέχει την ίδια ταξινομική ισχύ όπως η λογιστική παλινδρόμηση.\n",
|
||||
" * Στον χώρο των δειγμάτων, ο perceptron μπορεί να διαχωρίσει δύο κατηγορίες δεδομένων εισόδου χρησιμοποιώντας υπερεπίπεδο.\n"
|
||||
]
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Αποποίηση ευθύνης**: \nΑυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία αυτόματης μετάφρασης [Co-op Translator](https://github.com/Azure/co-op-translator). Παρόλο που καταβάλλουμε προσπάθειες για ακρίβεια, παρακαλούμε να έχετε υπόψη ότι οι αυτόματες μεταφράσεις ενδέχεται να περιέχουν λάθη ή ανακρίβειες. Το πρωτότυπο έγγραφο στη μητρική του γλώσσα θα πρέπει να θεωρείται η αυθεντική πηγή. Για κρίσιμες πληροφορίες, συνιστάται επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για τυχόν παρεξηγήσεις ή εσφαλμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης.\n"
|
||||
"\n---\n\n**Αποποίηση ευθύνης**: \nΑυτό το έγγραφο έχει μεταφραστεί χρησιμοποιώντας την υπηρεσία μετάφρασης AI [Co-op Translator](https://github.com/Azure/co-op-translator). Παρόλο που καταβάλλουμε προσπάθειες για ακρίβεια, παρακαλούμε να έχετε υπόψη ότι οι αυτοματοποιημένες μεταφράσεις ενδέχεται να περιέχουν λάθη ή ανακρίβειες. Το πρωτότυπο έγγραφο στη μητρική του γλώσσα θα πρέπει να θεωρείται η αυθεντική πηγή. Για κρίσιμες πληροφορίες, συνιστάται επαγγελματική ανθρώπινη μετάφραση. Δεν φέρουμε ευθύνη για τυχόν παρεξηγήσεις ή εσφαλμένες ερμηνείες που προκύπτουν από τη χρήση αυτής της μετάφρασης.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:28:42+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:16:16+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "el"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"> This notebook is part of the [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Visit the repository for the complete set of learning materials.\n",
|
||||
"> This notebook is part of [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Visit the repository for the complete set of learning materials.\n",
|
||||
"\n",
|
||||
"As we discussed, a perceptron helps solve **binary classification problems**, meaning it classifies input examples into two categories, which we can refer to as **positive** and **negative**.\n",
|
||||
"As we discussed, a perceptron enables you to solve **binary classification problems**, meaning it classifies input examples into two categories—let's call them **positive** and **negative**.\n",
|
||||
"\n",
|
||||
"First, let's import some necessary libraries.\n"
|
||||
]
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ for negative and positive training samples, respectively\n",
|
||||
" * $\\mathcal{M}$ - the set of misclassified examples\n",
|
||||
" \n",
|
||||
"We will use the **gradient descent** method. Starting with some initial random weights $\\mathbf{w}^{(0)}$, we will update the weights at each step of training using the gradient of $E$:\n",
|
||||
"We will use the **gradient descent** method. Starting with some initial random weights $\\mathbf{w}^{(0)}$, we will update the weights at each step of the training process using the gradient of $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Note on Learning Rate**: The `learning_rate` parameter (default `0.01`) determines how much the weights are adjusted during each training step. It follows the gradient descent update formula:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- A higher learning rate (e.g., `1.0`) allows the perceptron to learn faster but might overshoot the optimal solution.\n",
|
||||
"- A lower learning rate (e.g., `0.001`) results in slower learning but may lead to more precise convergence.\n",
|
||||
"- You can test this by using: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"As you can see, the initial accuracy is approximately 50%, but it quickly improves to higher values, nearing 90%.\n",
|
||||
"\n",
|
||||
"Let's visualize how the classes are separated. Our classification function is represented as $\\mathbf{w}^Tx$, which is greater than 0 for one class and less than 0 for the other. Therefore, the class separation line is defined by $\\mathbf{w}^Tx = 0$. Since we are working with only two dimensions, $x_0$ and $x_1$, the equation for the line becomes $w_0x_0 + w_1x_1 + w_2 = 0$ (recall that we explicitly introduced an additional dimension $x_2 = 1$). Let's plot this line:\n"
|
||||
"Let’s visualize how the classes are separated. Our classification function is represented as $\\mathbf{w}^Tx$, which is greater than 0 for one class and less than 0 for the other. Therefore, the class separation line is defined by $\\mathbf{w}^Tx = 0$. Since we are working with only two dimensions, $x_0$ and $x_1$, the equation for the line becomes $w_0x_0 + w_1x_1 + w_2 = 0$ (recall that we explicitly added an extra dimension $x_2 = 1$). Let’s plot this line:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimenting with Learning Rates\n",
|
||||
"\n",
|
||||
"Now let's examine how various learning rates influence the training process. The learning rate determines the step size in gradient descent—a key hyperparameter that impacts both the speed of convergence and the stability of the process.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interactive Learning Rate Experiment\n",
|
||||
"\n",
|
||||
"Use the slider below to interactively experiment with different learning rates and observe how they influence the decision boundary:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Observing the training process\n",
|
||||
"\n",
|
||||
"We previously observed how accuracy decreases during training. It would be interesting to see how the decision boundary evolves during training. The code below will display everything on a single graph, allowing you to use the slider to \"time-travel\" through the training process.\n"
|
||||
"We have previously seen how accuracy decreases during training. It would be interesting to observe how the separation line changes during training. The code below will visualize everything on a single graph, allowing you to move the slider to \"time-travel\" through the training process.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -531,14 +657,14 @@
|
|||
"\n",
|
||||
"As mentioned earlier, the perceptron is a **linear classifier**. It performs well in distinguishing between two classes if they are **linearly separable**, meaning they can be divided by a straight line. However, if the classes are not linearly separable, the perceptron training process will fail to converge.\n",
|
||||
"\n",
|
||||
"A classic example of a problem that cannot be solved by a perceptron is the **XOR problem**. Here, we want the perceptron to learn the XOR boolean function, which is represented by the following truth table:\n",
|
||||
"A classic example of a problem that cannot be solved by a perceptron is the **XOR problem**. In this case, we want the perceptron to learn the XOR boolean function, which is represented by the following truth table:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Let’s give it a try! We will manually input all positive and negative training samples and then use the train function we defined earlier:\n"
|
||||
"Let’s give it a try! We will manually define all positive and negative training samples and then use the train function we defined earlier:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,7 +731,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"As shown in the graph above, the accuracy never exceeds 75% because it is impossible to draw a straight line that correctly classifies all examples.\n",
|
||||
"As shown in the graph above, the accuracy never exceeds 75%, as it is impossible to draw a straight line that correctly classifies all examples.\n",
|
||||
"\n",
|
||||
"The XOR problem is a classic example of the limitations of perceptrons, first highlighted by Marvin Minsky and Seymour Papert in 1969 in their book [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). This observation significantly slowed down research in neural networks for nearly a decade, even though—as we will explore in the next section of our course—multi-layer perceptrons are fully capable of solving such problems.\n",
|
||||
"\n",
|
||||
|
|
@ -613,7 +739,7 @@
|
|||
"\n",
|
||||
"Although perceptrons cannot solve the XOR problem, they can tackle much more complex tasks, such as recognizing handwritten characters.\n",
|
||||
"\n",
|
||||
"A commonly used dataset for learning machine learning techniques is called [MNIST](https://en.wikipedia.org/wiki/MNIST_database). It was developed by the Modified National Institute of Standards and Technology and includes a training set of 60,000 handwritten digits collected from approximately 250 students and employees of the institute. Additionally, there is a test dataset containing 10,000 digits collected from different individuals.\n",
|
||||
"A commonly used dataset for learning machine learning is called [MNIST](https://en.wikipedia.org/wiki/MNIST_database). It was created by the Modified National Institute of Standards and Technology and includes a training set of 60,000 handwritten digits collected from approximately 250 students and employees of the institute. Additionally, there is a test dataset containing 10,000 digits collected from different individuals.\n",
|
||||
"\n",
|
||||
"All digits are represented as grayscale images with dimensions of 28x28 pixels.\n",
|
||||
"\n",
|
||||
|
|
@ -835,7 +961,7 @@
|
|||
"\n",
|
||||
"Please, move the slider to a position near the end of the training and observe the weight matrix displayed on the left. This matrix will help you understand how the perceptron actually functions. You can see high weight values in the center of the field, corresponding to pixels typically present in the digit 1, and low negative values on the sides, where parts of the digit 0 are located. So, if the digit presented to the perceptron is indeed a 1, the middle part will be multiplied by high values, resulting in a positive outcome. Conversely, when the perceptron sees a 0, the corresponding pixels will be multiplied by negative numbers.\n",
|
||||
"\n",
|
||||
"> You might notice that if we present our perceptron with a digit 1 that is slightly shifted horizontally, so its pixels overlap with the vertical parts of a 0, we might get an incorrect result. This happens because the MNIST dataset is designed such that all digits are centered and properly aligned, and the perceptron depends on this to differentiate between digits.\n",
|
||||
"> You might notice that if we present our perceptron with a digit 1 that is slightly shifted horizontally, so its pixels overlap with the vertical parts of a 0, we could get an incorrect result. This happens because the MNIST dataset is designed such that all digits are centered and properly aligned, and the perceptron relies on this alignment to differentiate between digits.\n",
|
||||
"\n",
|
||||
"Now let's try different digits: \n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"For some reason, 2 and 5 are not as easily distinguishable. Even though we achieve relatively high accuracy (above 85%), it's evident that the perceptron stops learning at a certain point.\n",
|
||||
"\n",
|
||||
"To understand why this happens, we can use [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). PCA is a machine learning technique designed to reduce the dimensionality of the input dataset in a way that maximizes the separability between classes.\n",
|
||||
"To understand why this happens, we can use [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). This is a machine learning technique designed to reduce the dimensionality of the input dataset in a way that maximizes the separability between classes.\n",
|
||||
"\n",
|
||||
"In our case, an input image consists of 784 pixels (input features), and we aim to use PCA to reduce the number of parameters to just 2, allowing us to plot them on a graph. These two parameters will be linear combinations of the original features, and this process can be thought of as \"rotating\" our original 784-dimensional space and observing its projection onto a 2D space, until we achieve the best view for separating the classes.\n"
|
||||
"In our case, an input image consists of 784 pixels (input features), and we aim to use PCA to reduce the number of parameters to just 2, allowing us to plot them on a graph. These two parameters would be linear combinations of the original features, and this process can be thought of as \"rotating\" our original 784-dimensional space and observing its projection onto a 2D space, until we achieve the best view for separating the classes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,14 +1153,14 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"As you can see, 0 and 1 can be clearly separated by a straight line. This shows that in the original 784-dimensional space, the points corresponding to these digits are also linearly separable. However, in the case of 2 and 5, it is not possible to find a suitable projection that separates the digits clearly, leading to some cases of incorrect classification.\n",
|
||||
"As you can see, 0 and 1 can be clearly separated by a straight line. This shows that in the original 784-dimensional space, the points corresponding to these digits are also linearly separable. However, in the case of 2 and 5, it is not possible to find a good projection that separates the digits clearly, leading to some cases of incorrect classification.\n",
|
||||
"\n",
|
||||
"> Later in this course, we will learn how to create non-linear classifiers using Neural Networks and address the issue of digits not being properly aligned. Very soon, we will achieve over 99% accuracy in MNIST digit classification while categorizing them into 10 different classes.\n",
|
||||
"> Later in this course, we will learn how to create non-linear classifiers using Neural Networks and how to address the issue of digits not being properly aligned. Very soon, we will achieve over 99% accuracy in MNIST digit classification while categorizing them into 10 different classes.\n",
|
||||
"\n",
|
||||
"## Takeaway\n",
|
||||
"\n",
|
||||
" * We have learned about the simplest neural network architecture—the one-layer perceptron.\n",
|
||||
" * We implemented the perceptron \"manually,\" using a simple training procedure based on gradient descent.\n",
|
||||
" * We have learned about the simplest neural network architecture - the one-layer perceptron.\n",
|
||||
" * We have implemented the perceptron \"manually,\" using a simple training procedure based on gradient descent.\n",
|
||||
" * Despite its simplicity, the one-layer perceptron can solve relatively complex problems like handwritten digit recognition.\n",
|
||||
" * The one-layer perceptron is a linear classifier, offering the same classification capabilities as logistic regression.\n",
|
||||
" * In the feature space, the perceptron can separate two classes of input data using a hyperplane.\n"
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:05:15+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:50:32+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "en"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
"source": [
|
||||
"## Perceptrón\n",
|
||||
"\n",
|
||||
"> Este cuaderno forma parte del [Currículo de IA para Principiantes](http://github.com/microsoft/ai-for-beginners). Visita el repositorio para obtener el conjunto completo de materiales de aprendizaje.\n",
|
||||
"> Este cuaderno forma parte del [Currículo de IA para Principiantes](http://github.com/microsoft/ai-for-beginners). Visita el repositorio para acceder al conjunto completo de materiales de aprendizaje.\n",
|
||||
"\n",
|
||||
"Como hemos discutido, el perceptrón te permite resolver problemas de **clasificación binaria**, es decir, clasificar ejemplos de entrada en dos clases: podemos llamarlas **positiva** y **negativa**.\n",
|
||||
"Como hemos comentado, el perceptrón te permite resolver problemas de **clasificación binaria**, es decir, clasificar ejemplos de entrada en dos clases: podemos llamarlas **positiva** y **negativa**.\n",
|
||||
"\n",
|
||||
"Primero, importemos algunas bibliotecas necesarias.\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Nota sobre la tasa de aprendizaje**: El parámetro `learning_rate` (por defecto `0.01`) controla cuánto ajustamos los pesos durante cada paso de entrenamiento. Esto implementa la fórmula de actualización del descenso de gradiente:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Una tasa de aprendizaje más grande (por ejemplo, `1.0`) hace que el perceptrón aprenda más rápido, pero puede exceder la solución óptima.\n",
|
||||
"- Una tasa de aprendizaje más pequeña (por ejemplo, `0.001`) aprende más lentamente, pero puede converger con mayor precisión.\n",
|
||||
"- Puedes experimentar llamando: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Como puedes ver, la precisión inicial es alrededor del 50%, pero rápidamente aumenta a valores más altos cercanos al 90%.\n",
|
||||
"\n",
|
||||
"Vamos a visualizar cómo se separan las clases. Nuestra función de clasificación se ve como $\\mathbf{w}^Tx$, y es mayor que 0 para una clase, y menor que 0 para otra. Por lo tanto, la línea de separación de clases está definida por $\\mathbf{w}^Tx = 0$. Dado que solo tenemos dos dimensiones $x_0$ y $x_1$, la ecuación de la línea sería $w_0x_0+w_1x_1+w_2 = 0$ (recuerda que hemos definido explícitamente una dimensión extra $x_2=1$). Vamos a graficar esta línea:\n"
|
||||
"Visualicemos cómo se separan las clases. Nuestra función de clasificación tiene la forma $\\mathbf{w}^Tx$, y es mayor que 0 para una clase, y menor que 0 para la otra. Por lo tanto, la línea de separación de clases está definida por $\\mathbf{w}^Tx = 0$. Dado que solo tenemos dos dimensiones $x_0$ y $x_1$, la ecuación de la línea sería $w_0x_0+w_1x_1+w_2 = 0$ (recuerda que hemos definido explícitamente una dimensión extra $x_2=1$). Vamos a graficar esta línea:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimentando con tasas de aprendizaje\n",
|
||||
"\n",
|
||||
"Ahora vamos a explorar cómo diferentes tasas de aprendizaje afectan el proceso de entrenamiento. La tasa de aprendizaje controla el tamaño del paso en el descenso por gradiente, un hiperparámetro crucial que influye tanto en la velocidad de convergencia como en la estabilidad.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Experimento Interactivo de Tasa de Aprendizaje\n",
|
||||
"\n",
|
||||
"Utiliza el control deslizante a continuación para experimentar de manera interactiva con diferentes tasas de aprendizaje y observa cómo afectan la frontera de decisión:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Evaluar en el conjunto de datos de prueba\n",
|
||||
"\n",
|
||||
"Al principio, apartamos algunos datos para el conjunto de datos de prueba. Veamos qué tan preciso es nuestro clasificador en este conjunto de datos de prueba. Para hacer esto, también ampliamos el conjunto de datos de prueba con una dimensión adicional, lo multiplicamos por la matriz de pesos y nos aseguramos de que el valor obtenido tenga el mismo signo que la etiqueta (+1 o -1). Luego sumamos todos los valores booleanos y dividimos por la longitud de la muestra de prueba para obtener la precisión:\n"
|
||||
"Al principio, apartamos algunos datos para el conjunto de prueba. Veamos qué tan preciso es nuestro clasificador en este conjunto de prueba. Para hacerlo, también ampliamos el conjunto de prueba con una dimensión adicional, lo multiplicamos por la matriz de pesos y verificamos que el valor obtenido tenga el mismo signo que la etiqueta (+1 o -1). Luego sumamos todos los valores booleanos y dividimos por la longitud de la muestra de prueba para obtener la precisión:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Observando el proceso de entrenamiento\n",
|
||||
"\n",
|
||||
"Hemos visto anteriormente cómo la precisión disminuye durante el entrenamiento. Sería interesante observar cómo se comporta la línea de separación durante el entrenamiento. El código a continuación visualizará todo en un solo gráfico, y deberías poder mover el deslizador para \"viajar en el tiempo\" a través del proceso de entrenamiento.\n"
|
||||
"Hemos visto antes cómo la precisión disminuye durante el entrenamiento. Sería interesante observar cómo se comporta la línea de separación durante el entrenamiento. El siguiente código visualizará todo en un solo gráfico, y deberías poder mover el deslizador para \"viajar en el tiempo\" a través del proceso de entrenamiento.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -613,7 +739,7 @@
|
|||
"\n",
|
||||
"Aunque el perceptrón no puede resolver el problema XOR, sí puede resolver problemas mucho más complejos, como el reconocimiento de caracteres escritos a mano.\n",
|
||||
"\n",
|
||||
"Un conjunto de datos que se utiliza frecuentemente para aprender sobre aprendizaje automático se llama [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Fue creado por el Instituto Nacional de Estándares y Tecnología Modificado, y contiene un conjunto de entrenamiento de 60,000 dígitos escritos a mano, recopilados de aproximadamente 250 estudiantes y empleados del instituto. También hay un conjunto de prueba de 10,000 dígitos, recopilados de diferentes individuos.\n",
|
||||
"Un conjunto de datos que se utiliza frecuentemente para aprender sobre aprendizaje automático se llama [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Fue creado por el Instituto Nacional de Estándares y Tecnología Modificado, y contiene un conjunto de entrenamiento de 60,000 dígitos escritos a mano, recopilados de alrededor de 250 estudiantes y empleados del instituto. También hay un conjunto de prueba de 10,000 dígitos, recopilados de diferentes individuos.\n",
|
||||
"\n",
|
||||
"Todos los dígitos están representados por imágenes en escala de grises de tamaño 28x28 píxeles.\n",
|
||||
"\n",
|
||||
|
|
@ -831,9 +957,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Por favor, observa cómo la precisión sube casi al 100% muy rápidamente.\n",
|
||||
"Ten en cuenta cómo la precisión sube casi al 100% muy rápidamente.\n",
|
||||
"\n",
|
||||
"Por favor, mueve el deslizador hacia una posición cerca del final del entrenamiento y observa la matriz de pesos representada a la izquierda. Esta matriz te permitirá entender cómo funciona realmente el perceptrón. Puedes ver los valores altos de los pesos en el centro del campo, que corresponden a los píxeles que suelen estar presentes en el dígito 1, y valores negativos bajos en los lados, donde se encuentran partes del dígito 0. Entonces, si el dígito presentado al perceptrón es de hecho un 1, la parte central será multiplicada por valores altos, produciendo un resultado positivo. Por el contrario, cuando el perceptrón observa un 0, los píxeles correspondientes serán multiplicados por números negativos.\n",
|
||||
"Por favor, mueve el deslizador hacia alguna posición cerca del final del entrenamiento y observa la matriz de pesos representada a la izquierda. Esta matriz te permitirá entender cómo funciona realmente el perceptrón. Puedes ver los valores altos de los pesos en el centro del campo, que corresponden a los píxeles que suelen estar presentes en el dígito 1, y valores negativos bajos en los lados, donde se encuentran partes del dígito 0. Entonces, si el dígito presentado al perceptrón es de hecho un 1, la parte central será multiplicada por valores altos, produciendo un resultado positivo. Por el contrario, cuando el perceptrón observa un 0, los píxeles correspondientes serán multiplicados por números negativos.\n",
|
||||
"\n",
|
||||
"> Puedes notar que si le damos a nuestro perceptrón un dígito 1 ligeramente desplazado horizontalmente, de manera que sus píxeles ocupen el lugar donde están las partes verticales del 0, podríamos obtener un resultado incorrecto. Esto se debe a que la naturaleza de nuestro conjunto de datos MNIST es tal que todos los dígitos están centrados y posicionados correctamente, y el perceptrón depende de esto para distinguir entre los dígitos.\n",
|
||||
"\n",
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"Por alguna razón, 2 y 5 no son tan fácilmente separables. Aunque obtenemos una precisión relativamente alta (por encima del 85%), podemos ver claramente cómo el perceptrón deja de aprender en cierto punto.\n",
|
||||
"\n",
|
||||
"Para entender por qué ocurre esto, podemos intentar usar [Análisis de Componentes Principales](https://es.wikipedia.org/wiki/An%C3%A1lisis_de_componentes_principales) (PCA). Es una técnica de aprendizaje automático utilizada para reducir la dimensionalidad del conjunto de datos de entrada, de manera que se obtenga la mejor separabilidad entre las clases.\n",
|
||||
"Para entender por qué ocurre esto, podemos intentar usar [Análisis de Componentes Principales](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Es una técnica de aprendizaje automático utilizada para reducir la dimensionalidad del conjunto de datos de entrada, de manera que se obtenga la mejor separabilidad entre clases.\n",
|
||||
"\n",
|
||||
"En nuestro caso, una imagen de entrada tiene 784 píxeles (características de entrada), y queremos usar PCA para reducir el número de parámetros a solo 2, de modo que podamos representarlos en un gráfico. Esos dos parámetros serían una combinación lineal de las características originales, y podemos ver este procedimiento como una \"rotación\" de nuestro espacio original de 784 dimensiones y observar su proyección en un espacio 2D, hasta obtener la mejor vista que separe las clases.\n"
|
||||
"En nuestro caso, una imagen de entrada tiene 784 píxeles (características de entrada), y queremos usar PCA para reducir el número de parámetros a solo 2, de modo que podamos graficarlos. Esos dos parámetros serían una combinación lineal de las características originales, y podemos ver este procedimiento como una \"rotación\" de nuestro espacio original de 784 dimensiones y observar su proyección en un espacio 2D, hasta obtener la mejor vista que separe las clases.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,7 +1155,7 @@
|
|||
"source": [
|
||||
"Como puedes ver, 0 y 1 pueden separarse claramente mediante una línea recta. Esto indica que en el espacio original de 784 dimensiones, los puntos correspondientes a los dígitos también son linealmente separables. En el caso de 2 y 5, no podemos encontrar una buena proyección que separe los dígitos claramente, y por lo tanto, hay algunos casos de clasificación incorrecta.\n",
|
||||
"\n",
|
||||
"> Más adelante en este curso aprenderemos cómo crear clasificadores no lineales utilizando Redes Neuronales, y cómo abordar el problema de los dígitos que no están correctamente alineados. Muy pronto alcanzaremos una precisión superior al 99% en la clasificación de dígitos MNIST, clasificándolos en 10 clases diferentes.\n",
|
||||
"> Más adelante en este curso aprenderemos cómo crear clasificadores no lineales utilizando Redes Neuronales, y cómo abordar el problema de los dígitos que no están correctamente alineados. Muy pronto alcanzaremos más del 99% de precisión en la clasificación de dígitos MNIST, clasificándolos en 10 clases diferentes.\n",
|
||||
"\n",
|
||||
"## Conclusiones\n",
|
||||
"\n",
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:07:03+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:52:27+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "es"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"\n",
|
||||
"همانطور که بحث کردیم، پرسپترون به شما امکان میدهد **مسئله طبقهبندی دودویی** را حل کنید، یعنی ورودیها را به دو کلاس تقسیم کنید - که میتوانیم آنها را **مثبت** و **منفی** بنامیم.\n",
|
||||
"\n",
|
||||
"ابتدا بیایید برخی از کتابخانههای مورد نیاز را وارد کنیم.\n"
|
||||
"ابتدا، بیایید برخی از کتابخانههای مورد نیاز را وارد کنیم.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -47,9 +47,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## مسئله ساده\n",
|
||||
"## مسئله نمونه\n",
|
||||
"\n",
|
||||
"برای شروع، بیایید با یک مسئله ساده آغاز کنیم که در آن دو ویژگی ورودی داریم. به عنوان مثال، در پزشکی ممکن است بخواهیم تومورها را بر اساس اندازه و سن آنها به خوشخیم و بدخیم دستهبندی کنیم.\n",
|
||||
"برای شروع، بیایید با یک مسئله نمونه آغاز کنیم، جایی که دو ویژگی ورودی داریم. به عنوان مثال، در پزشکی ممکن است بخواهیم تومورها را بر اساس اندازه و سن آنها به خوشخیم و بدخیم دستهبندی کنیم.\n",
|
||||
"\n",
|
||||
"ما یک مجموعه داده طبقهبندی تصادفی با استفاده از تابع `make_classification` از کتابخانه SciKit Learn ایجاد خواهیم کرد:\n"
|
||||
]
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"بیایید مجموعه داده را نیز ترسیم کنیم:\n"
|
||||
"بیایید مجموعه داده را نیز رسم کنیم:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## پرسپترون\n",
|
||||
"\n",
|
||||
"از آنجا که پرسپترون یک دستهبند دودویی است، برای هر بردار ورودی $x$، خروجی پرسپترون ما بسته به کلاس، یا +1 یا -1 خواهد بود. خروجی با استفاده از فرمول زیر محاسبه میشود:\n",
|
||||
"از آنجا که پرسپترون یک دستهبند دودویی است، برای هر بردار ورودی $x$ خروجی پرسپترون ما بسته به کلاس، یا +1 یا -1 خواهد بود. خروجی با استفاده از فرمول زیر محاسبه میشود:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -210,7 +210,7 @@
|
|||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ برای نمونههای آموزشی منفی و مثبت، به ترتیب\n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ برای نمونههای آموزشی منفی و مثبت به ترتیب\n",
|
||||
" * $\\mathcal{M}$ - مجموعهای از مثالهای اشتباه طبقهبندیشده\n",
|
||||
" \n",
|
||||
"ما از فرآیند **نزول گرادیان** استفاده خواهیم کرد. با شروع از وزنهای اولیه تصادفی $\\mathbf{w}^{(0)}$، وزنها را در هر مرحله از آموزش با استفاده از گرادیان $E$ تنظیم خواهیم کرد:\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**توضیح درباره نرخ یادگیری**: پارامتر `learning_rate` (بهطور پیشفرض `0.01`) تعیین میکند که در هر مرحله آموزش، چقدر وزنها را تنظیم کنیم. این پارامتر فرمول بهروزرسانی گرادیان نزولی را پیادهسازی میکند:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- نرخ یادگیری بزرگتر (مثلاً `1.0`) باعث میشود پرسپترون سریعتر یاد بگیرد اما ممکن است از راهحل بهینه عبور کند\n",
|
||||
"- نرخ یادگیری کوچکتر (مثلاً `0.001`) یادگیری را کندتر میکند اما ممکن است با دقت بیشتری همگرا شود\n",
|
||||
"- میتوانید با فراخوانی این دستور آزمایش کنید: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"همانطور که مشاهده میکنید، دقت اولیه حدود ۵۰٪ است، اما بهسرعت به مقادیر بالاتر نزدیک به ۹۰٪ افزایش مییابد.\n",
|
||||
"همانطور که مشاهده میکنید، دقت اولیه حدود ۵۰٪ است، اما به سرعت به مقادیر بالاتری نزدیک به ۹۰٪ افزایش مییابد.\n",
|
||||
"\n",
|
||||
"بیایید ببینیم چگونه کلاسها از یکدیگر جدا میشوند. تابع طبقهبندی ما به شکل $\\mathbf{w}^Tx$ است و برای یک کلاس بزرگتر از ۰ و برای کلاس دیگر کمتر از ۰ است. بنابراین، خط جداسازی کلاسها با $\\mathbf{w}^Tx = 0$ تعریف میشود. از آنجا که فقط دو بعد $x_0$ و $x_1$ داریم، معادله خط به صورت $w_0x_0+w_1x_1+w_2 = 0$ خواهد بود (به یاد داشته باشید که ما بهطور صریح یک بعد اضافی $x_2=1$ تعریف کردهایم). بیایید این خط را رسم کنیم:\n"
|
||||
"بیایید ببینیم چگونه کلاسها از یکدیگر جدا میشوند. تابع طبقهبندی ما به صورت $\\mathbf{w}^Tx$ است و برای یک کلاس بزرگتر از ۰ و برای کلاس دیگر کمتر از ۰ است. بنابراین، خط جداسازی کلاسها با $\\mathbf{w}^Tx = 0$ تعریف میشود. از آنجا که فقط دو بعد $x_0$ و $x_1$ داریم، معادله خط به صورت $w_0x_0+w_1x_1+w_2 = 0$ خواهد بود (به یاد داشته باشید که ما به طور صریح یک بعد اضافی $x_2=1$ تعریف کردهایم). بیایید این خط را رسم کنیم:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## آزمایش با نرخهای یادگیری\n",
|
||||
"\n",
|
||||
"حالا بیایید بررسی کنیم که چگونه نرخهای یادگیری مختلف بر فرآیند آموزش تأثیر میگذارند. نرخ یادگیری اندازه گام در نزول گرادیان را کنترل میکند - یک ابرپارامتر حیاتی که بر سرعت همگرایی و پایداری تأثیر میگذارد.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### آزمایش تعاملی نرخ یادگیری\n",
|
||||
"\n",
|
||||
"از نوار لغزنده زیر استفاده کنید تا به صورت تعاملی نرخهای یادگیری مختلف را آزمایش کنید و ببینید چگونه بر مرز تصمیمگیری تأثیر میگذارند:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## ارزیابی بر روی مجموعه داده آزمایشی\n",
|
||||
"\n",
|
||||
"در ابتدا، مقداری داده را برای مجموعه داده آزمایشی کنار گذاشتهایم. بیایید ببینیم که طبقهبند ما چقدر دقیق بر روی این مجموعه داده آزمایشی عمل میکند. برای انجام این کار، مجموعه داده آزمایشی را با یک بعد اضافی گسترش میدهیم، آن را در ماتریس وزنها ضرب میکنیم، و مطمئن میشویم که مقدار بهدستآمده همان علامت برچسب (+1 یا -1) را دارد. سپس تمام مقادیر بولی را با هم جمع میکنیم و بر طول نمونه آزمایشی تقسیم میکنیم تا دقت را به دست آوریم:\n"
|
||||
"در ابتدا، مقداری داده را برای مجموعه داده آزمایشی کنار گذاشتهایم. بیایید ببینیم که طبقهبند ما چقدر دقیق بر روی این مجموعه داده آزمایشی عمل میکند. برای انجام این کار، مجموعه داده آزمایشی را با یک بعد اضافی گسترش میدهیم، آن را در ماتریس وزنها ضرب میکنیم و مطمئن میشویم که مقدار بهدستآمده همان علامت برچسب (+1 یا -1) را دارد. سپس تمام مقادیر بولی را با هم جمع کرده و بر طول نمونه آزمایشی تقسیم میکنیم تا دقت را به دست آوریم:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -538,7 +664,7 @@
|
|||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"بیایید این کار را امتحان کنیم! ما بهصورت دستی تمام نمونههای مثبت و منفی آموزشی را وارد میکنیم و سپس تابع train که در بالا تعریف شده است را فراخوانی میکنیم:\n"
|
||||
"بیایید این کار را امتحان کنیم! ما بهصورت دستی تمام نمونههای آموزشی مثبت و منفی را وارد میکنیم و سپس تابع آموزش خود را که در بالا تعریف شده است، فراخوانی میکنیم:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"همانطور که از نمودار بالا مشاهده میکنید، دقت هرگز از ۷۵٪ فراتر نمیرود، زیرا امکان کشیدن یک خط مستقیم به گونهای که تمام نمونههای ممکن را به درستی پوشش دهد وجود ندارد.\n",
|
||||
"همانطور که از نمودار بالا مشاهده میکنید، دقت هرگز از ۷۵٪ فراتر نمیرود، زیرا امکان کشیدن یک خط مستقیم به گونهای که تمام مثالهای ممکن را درست کند وجود ندارد.\n",
|
||||
"\n",
|
||||
"مسئله XOR یک مثال کلاسیک از محدودیتهای پرسپترون است و در سال ۱۹۶۹ توسط ماروین مینسکی و سیمور پاپرت در کتابشان [Pereceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) مطرح شد. این مشاهده باعث شد که تحقیقات در زمینه شبکههای عصبی تقریباً به مدت ۱۰ سال محدود شود، حتی با وجود اینکه - و این را در بخش بعدی دوره خود خواهیم دید - پرسپترونهای چندلایه کاملاً قادر به حل چنین مسائلی هستند.\n",
|
||||
"مسئله XOR یک مثال کلاسیک از محدودیتهای پرسپترون است و در سال ۱۹۶۹ توسط ماروین مینسکی و سیمور پاپرت در کتابشان [Pereceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) مطرح شد. این مشاهده باعث شد که تحقیقات در زمینه شبکههای عصبی تقریباً به مدت ۱۰ سال محدود شود، هرچند - و این را در بخش بعدی دوره خود خواهیم دید - پرسپترونهای چندلایه کاملاً قادر به حل چنین مشکلاتی هستند.\n",
|
||||
"\n",
|
||||
"## مثال پیچیده - MNIST\n",
|
||||
"\n",
|
||||
"با اینکه پرسپترون نمیتواند مسئله XOR را حل کند، اما میتواند مسائل بسیار پیچیدهتری مانند تشخیص دستنوشتهها را حل کند.\n",
|
||||
"با اینکه پرسپترون نمیتواند مسئله XOR را حل کند، اما میتواند بسیاری از مسائل پیچیدهتر، مانند تشخیص دستنویس کاراکترها را حل کند.\n",
|
||||
"\n",
|
||||
"یک مجموعه داده که اغلب برای یادگیری ماشین استفاده میشود، [MNIST](https://en.wikipedia.org/wiki/MNIST_database) نام دارد. این مجموعه داده توسط مؤسسه ملی استانداردهای اصلاحشده ایجاد شده و شامل یک مجموعه آموزشی از ۶۰,۰۰۰ رقم دستنویس است که از حدود ۲۵۰ دانشجو و کارمند مؤسسه جمعآوری شده است. همچنین یک مجموعه داده آزمایشی شامل ۱۰,۰۰۰ رقم وجود دارد که از افراد مختلف جمعآوری شده است.\n",
|
||||
"یک مجموعه داده که اغلب هنگام یادگیری ماشین استفاده میشود، [MNIST](https://en.wikipedia.org/wiki/MNIST_database) نام دارد. این مجموعه داده توسط مؤسسه ملی استانداردهای اصلاحشده ایجاد شده و شامل یک مجموعه آموزشی از ۶۰,۰۰۰ رقم دستنویس است که از حدود ۲۵۰ دانشجو و کارمندان مؤسسه جمعآوری شده است. همچنین یک مجموعه داده آزمایشی شامل ۱۰,۰۰۰ رقم وجود دارد که از افراد مختلف جمعآوری شده است.\n",
|
||||
"\n",
|
||||
"تمام ارقام به صورت تصاویر خاکستری با اندازه ۲۸x۲۸ پیکسل نمایش داده شدهاند.\n",
|
||||
"\n",
|
||||
"> مجموعه داده MNIST به عنوان یک رقابت آموزشی در [Kaggle](https://www.kaggle.com/c/digit-recognizer) موجود است، سایتی که میزبان مسابقات و رقابتهای یادگیری ماشین است. پس از یادگیری نحوه طبقهبندی ارقام MNIST، میتوانید راهحل خود را در Kaggle ارسال کنید تا ببینید چگونه در میان سایر شرکتکنندگان رتبهبندی میشود.\n",
|
||||
"> مجموعه داده MNIST به عنوان یک رقابت آموزشی در [Kaggle](https://www.kaggle.com/c/digit-recognizer) در دسترس است، سایتی که میزبان مسابقات و رقابتهای یادگیری ماشین است. پس از اینکه یاد گرفتید چگونه ارقام MNIST را طبقهبندی کنید، میتوانید راهحل خود را به Kaggle ارسال کنید تا ببینید چگونه در میان سایر شرکتکنندگان رتبهبندی میشود.\n",
|
||||
"\n",
|
||||
"ما با بارگذاری مجموعه داده MNIST شروع میکنیم:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"از آنجا که پرسپترون یک دستهبند دودویی است، مسئله خود را به شناسایی تنها دو رقم محدود خواهیم کرد. تابع زیر آرایههای نمونههای مثبت و منفی را با دو رقم دادهشده پر میکند (و همچنین نمونههایی از آن ارقام را برای وضوح نمایش میدهد).\n"
|
||||
"چون پرسپترون یک طبقهبند دودویی است، ما مسئله خود را به شناسایی فقط دو رقم محدود خواهیم کرد. تابع زیر آرایههای نمونه مثبت و منفی را با دو رقم دادهشده پر میکند (و همچنین نمونههایی از آن ارقام را برای وضوح نشان خواهد داد).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,7 +959,7 @@
|
|||
"source": [
|
||||
"لطفاً توجه کنید که دقت خیلی سریع به تقریباً ۱۰۰٪ میرسد.\n",
|
||||
"\n",
|
||||
"لطفاً لغزنده را به موقعیتی نزدیک به انتهای آموزش حرکت دهید و ماتریس وزن نمایش داده شده در سمت چپ را مشاهده کنید. این ماتریس به شما کمک میکند تا بفهمید پرسپترون چگونه کار میکند. میتوانید مقادیر وزن بالا را در وسط میدان ببینید که مربوط به پیکسلهایی است که معمولاً برای رقم ۱ وجود دارند، و مقادیر منفی پایین در کنارهها، جایی که بخشهایی از رقم ۰ قرار دارند. بنابراین، اگر رقمی که به پرسپترون ارائه میشود واقعاً ۱ باشد، بخش میانی آن با مقادیر بالا ضرب میشود و نتیجه مثبت تولید میکند. برعکس، وقتی پرسپترون رقم ۰ را مشاهده میکند، پیکسلهای مربوطه با اعداد منفی ضرب میشوند.\n",
|
||||
"لطفاً اسلایدر را به موقعیتی نزدیک به انتهای آموزش حرکت دهید و ماتریس وزن نمایش داده شده در سمت چپ را مشاهده کنید. این ماتریس به شما کمک میکند تا بفهمید پرسپترون چگونه کار میکند. میتوانید مقادیر وزن بالا را در وسط میدان مشاهده کنید که مربوط به پیکسلهایی است که معمولاً برای رقم ۱ وجود دارند، و مقادیر منفی پایین در کنارهها، جایی که بخشهایی از رقم ۰ قرار دارند. بنابراین، اگر رقمی که به پرسپترون ارائه میشود واقعاً ۱ باشد، بخش میانی آن با مقادیر بالا ضرب میشود و نتیجه مثبت تولید میکند. برعکس، وقتی پرسپترون رقم ۰ را مشاهده میکند، پیکسلهای مربوطه با اعداد منفی ضرب میشوند.\n",
|
||||
"\n",
|
||||
"> ممکن است متوجه شوید که اگر به پرسپترون یک رقم ۱ بدهیم که کمی به صورت افقی جابهجا شده باشد، به طوری که پیکسلهای آن در جایی قرار گیرند که بخشهای عمودی رقم ۰ هستند، ممکن است نتیجه اشتباه دریافت کنیم. از آنجا که ماهیت مجموعه داده MNIST ما به گونهای است که همه ارقام به درستی مرکز و موقعیتیابی شدهاند، پرسپترون برای تمایز بین ارقام به این ویژگی تکیه میکند.\n",
|
||||
"\n",
|
||||
|
|
@ -917,7 +1043,7 @@
|
|||
"\n",
|
||||
"برای درک دلیل این اتفاق، میتوانیم از [تحلیل مؤلفه اصلی](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) استفاده کنیم. این یک تکنیک یادگیری ماشین است که برای کاهش ابعاد مجموعه دادههای ورودی به کار میرود، به گونهای که بهترین تفکیکپذیری بین کلاسها حاصل شود.\n",
|
||||
"\n",
|
||||
"در مورد ما، یک تصویر ورودی دارای ۷۸۴ پیکسل (ویژگیهای ورودی) است و میخواهیم از PCA استفاده کنیم تا تعداد پارامترها را فقط به ۲ کاهش دهیم، به طوری که بتوانیم آنها را روی نمودار رسم کنیم. این دو پارامتر ترکیبی خطی از ویژگیهای اصلی خواهند بود و میتوان این فرآیند را به عنوان \"چرخاندن\" فضای اصلی ۷۸۴ بعدی و مشاهده تصویر آن در فضای دو بعدی در نظر گرفت، تا زمانی که بهترین نمایی که کلاسها را جدا میکند به دست آید.\n"
|
||||
"در مورد ما، یک تصویر ورودی دارای ۷۸۴ پیکسل (ویژگیهای ورودی) است و میخواهیم از PCA استفاده کنیم تا تعداد پارامترها را فقط به ۲ کاهش دهیم، به طوری که بتوانیم آنها را روی نمودار رسم کنیم. این دو پارامتر ترکیبی خطی از ویژگیهای اصلی خواهند بود و میتوان این فرآیند را به عنوان \"چرخاندن\" فضای ۷۸۴ بعدی اصلی و مشاهده تصویر آن در فضای دو بعدی در نظر گرفت، تا زمانی که بهترین نمایی که کلاسها را جدا میکند به دست آید.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"همانطور که مشاهده میکنید، 0 و 1 بهوضوح میتوانند با یک خط مستقیم از هم جدا شوند. این نشان میدهد که در فضای اصلی 784 بعدی، نقاط مربوط به ارقام نیز بهصورت خطی قابل تفکیک هستند. اما در مورد 2 و 5، نمیتوانیم یک تصویر مناسب پیدا کنیم که ارقام را بهطور واضح جدا کند، و به همین دلیل مواردی از طبقهبندی اشتباه وجود دارد.\n",
|
||||
"همانطور که مشاهده میکنید، 0 و 1 به وضوح با یک خط مستقیم قابل جدا شدن هستند. این نشان میدهد که در فضای اصلی 784 بعدی، نقاط مربوط به ارقام نیز به صورت خطی قابل جدا شدن هستند. اما در مورد ارقام 2 و 5، نمیتوانیم یک تصویر مناسب پیدا کنیم که ارقام را به وضوح جدا کند و به همین دلیل مواردی از طبقهبندی اشتباه وجود دارد.\n",
|
||||
"\n",
|
||||
"> در ادامه این دوره، یاد خواهیم گرفت که چگونه با استفاده از شبکههای عصبی، طبقهبندهای غیرخطی ایجاد کنیم و چگونه با مشکل عدم تطابق صحیح ارقام مقابله کنیم. بهزودی به دقت بالای 99% در طبقهبندی ارقام MNIST خواهیم رسید، در حالی که آنها را به 10 کلاس مختلف تقسیم میکنیم.\n",
|
||||
"> در ادامه این دوره یاد خواهیم گرفت که چگونه با استفاده از شبکههای عصبی، طبقهبندهای غیرخطی ایجاد کنیم و چگونه با مشکل عدم تطابق صحیح ارقام مقابله کنیم. به زودی به دقت بالای 99% در طبقهبندی ارقام MNIST خواهیم رسید، در حالی که آنها را به 10 کلاس مختلف دستهبندی میکنیم.\n",
|
||||
"\n",
|
||||
"## نکات کلیدی\n",
|
||||
"\n",
|
||||
" * ما درباره سادهترین معماری شبکه عصبی - پرسپترون تکلایه - یاد گرفتیم.\n",
|
||||
" * پرسپترون را \"بهصورت دستی\" پیادهسازی کردیم، با استفاده از روش آموزشی ساده مبتنی بر گرادیان نزولی.\n",
|
||||
" * با وجود سادگی، پرسپترون تکلایه میتواند مسائل نسبتاً پیچیدهای مانند تشخیص ارقام دستنویس را حل کند.\n",
|
||||
" * پرسپترون را \"به صورت دستی\" پیادهسازی کردیم، با استفاده از روش آموزشی ساده مبتنی بر گرادیان نزولی.\n",
|
||||
" * با وجود سادگی، پرسپترون تکلایه میتواند مشکلات نسبتاً پیچیدهای مانند شناسایی ارقام دستنویس را حل کند.\n",
|
||||
" * پرسپترون تکلایه یک طبقهبند خطی است و بنابراین قدرت طبقهبندی مشابهی با رگرسیون لجستیک ارائه میدهد.\n",
|
||||
" * در فضای نمونه، پرسپترون میتواند دو کلاس داده ورودی را با استفاده از ابرصفحه جدا کند.\n"
|
||||
" * در فضای نمونه، پرسپترون میتواند دو کلاس داده ورودی را با استفاده از یک ابرصفحه جدا کند.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## اعتبارها\n",
|
||||
"\n",
|
||||
"این دفترچه بخشی از [برنامه آموزشی هوش مصنوعی برای مبتدیان](http://github.com/microsoft/ai-for-beginners) است و توسط [دمیتری سوشنیکوف](http://soshnikov.com) تهیه شده است. این دفترچه از کارگاه شبکههای عصبی در Microsoft Research Cambridge الهام گرفته شده است. بخشی از کدها و مواد تصویری از ارائههای [کاتیا هافمن](https://www.microsoft.com/en-us/research/people/kahofman/)، [متیو جانسون](https://www.microsoft.com/en-us/research/people/matjoh/) و [ریوتو تومیوکا](https://www.microsoft.com/en-us/research/people/ryoto/) گرفته شدهاند و همچنین از مخزن [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) استفاده شده است.\n"
|
||||
"این دفترچه بخشی از [برنامه درسی هوش مصنوعی برای مبتدیان](http://github.com/microsoft/ai-for-beginners) است و توسط [دمیتری سوشنیکوف](http://soshnikov.com) تهیه شده است. این دفترچه از کارگاه شبکههای عصبی در Microsoft Research Cambridge الهام گرفته شده است. بخشی از کدها و مواد تصویری از ارائههای [کاتیا هافمن](https://www.microsoft.com/en-us/research/people/kahofman/)، [متیو جانسون](https://www.microsoft.com/en-us/research/people/matjoh/) و [ریوتو تومیئوکا](https://www.microsoft.com/en-us/research/people/ryoto/) گرفته شدهاند و همچنین از مخزن [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) استفاده شده است.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**سلب مسئولیت**: \nاین سند با استفاده از سرویس ترجمه هوش مصنوعی [Co-op Translator](https://github.com/Azure/co-op-translator) ترجمه شده است. در حالی که ما تلاش میکنیم دقت را حفظ کنیم، لطفاً توجه داشته باشید که ترجمههای خودکار ممکن است شامل خطاها یا نادرستیها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، توصیه میشود از ترجمه حرفهای انسانی استفاده کنید. ما مسئولیتی در قبال سوء تفاهمها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.\n"
|
||||
"\n---\n\n**سلب مسئولیت**: \nاین سند با استفاده از سرویس ترجمه هوش مصنوعی [Co-op Translator](https://github.com/Azure/co-op-translator) ترجمه شده است. در حالی که ما تلاش میکنیم ترجمهها دقیق باشند، لطفاً توجه داشته باشید که ترجمههای خودکار ممکن است شامل خطاها یا نادرستیها باشند. سند اصلی به زبان اصلی آن باید به عنوان منبع معتبر در نظر گرفته شود. برای اطلاعات حساس، توصیه میشود از ترجمه انسانی حرفهای استفاده کنید. ما هیچ مسئولیتی در قبال سوء تفاهمها یا تفسیرهای نادرست ناشی از استفاده از این ترجمه نداریم.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:10:56+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:56:37+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "fa"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"\n",
|
||||
"Kuten olemme keskustelleet, perceptron mahdollistaa **binääriluokitteluongelman** ratkaisemisen, eli syöte-esimerkkien luokittelun kahteen luokkaan - voimme kutsua niitä **positiiviseksi** ja **negatiiviseksi**.\n",
|
||||
"\n",
|
||||
"Aloitetaan ensin tarvittavien kirjastojen tuonnilla.\n"
|
||||
"Aloitetaan ensin tuomalla tarvittavat kirjastot.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Kuitenkin yleisessä lineaarisessa mallissa tulisi olla myös bias, eli ihanteellisesti meidän tulisi laskea $y$ muodossa $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Mallin yksinkertaistamiseksi voimme poistaa tämän bias-termin lisäämällä syöteominaisuuksiin yhden ulottuvuuden, joka on aina arvoltaan 1:\n"
|
||||
"Kuitenkin yleisessä lineaarisessa mallissa tulisi olla myös bias, eli ihanteellisesti meidän tulisi laskea $y$ muodossa $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Mallin yksinkertaistamiseksi voimme poistaa tämän bias-termin lisäämällä yhden ulottuvuuden syöteominaisuuksiin, joka on aina arvoltaan 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -210,7 +210,7 @@
|
|||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ negatiivisille ja positiivisille opetusnäytteille, vastaavasti\n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ negatiivisille ja positiivisille harjoitusnäytteille, vastaavasti\n",
|
||||
" * $\\mathcal{M}$ - väärin luokiteltujen esimerkkien joukko\n",
|
||||
" \n",
|
||||
"Käytämme **gradienttimenetelmää**. Aloittaen satunnaisilla alkuarvoilla $\\mathbf{w}^{(0)}$, säädämme painoja jokaisella koulutusaskeleella virheen $E$ gradientin avulla:\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Huomio oppimisnopeudesta**: `learning_rate`-parametri (oletus `0.01`) määrittää, kuinka paljon painoja säädetään jokaisen harjoitusaskeleen aikana. Tämä toteuttaa gradienttilaskeuman päivityskaavan:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Suurempi oppimisnopeus (esim. `1.0`) saa perceptronin oppimaan nopeammin, mutta saattaa ohittaa optimaalisen ratkaisun\n",
|
||||
"- Pienempi oppimisnopeus (esim. `0.001`) oppii hitaammin, mutta voi lähestyä tarkemmin oikeaa ratkaisua\n",
|
||||
"- Voit kokeilla kutsumalla: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Kokeilu oppimisnopeuksilla\n",
|
||||
"\n",
|
||||
"Tutkitaan nyt, miten erilaiset oppimisnopeudet vaikuttavat koulutusprosessiin. Oppimisnopeus säätelee askelkokoa gradienttilaskennassa - tärkeä hyperparametri, joka vaikuttaa sekä lähentymisnopeuteen että vakauteen.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktiivinen oppimisnopeuskokeilu\n",
|
||||
"\n",
|
||||
"Käytä alla olevaa liukusäädintä kokeillaksesi eri oppimisnopeuksia ja nähdäksesi, miten ne vaikuttavat päätösrajaan:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Arvioi testidatalla\n",
|
||||
"\n",
|
||||
"Alussa olemme erottaneet osan datasta testidataksi. Katsotaan, kuinka tarkka luokittimemme on tällä testidatalla. Tätä varten laajennamme testidatan yhdellä lisäulottuvuudella, kerromme sen painomatriisilla ja varmistamme, että saatu arvo on samanmerkkinen kuin tunniste (+1 tai -1). Tämän jälkeen laskemme yhteen kaikki totuusarvot ja jaamme testinäytteen pituudella saadaksemme tarkkuuden:\n"
|
||||
"Alussa olemme erottaneet osan datasta testidataksi. Katsotaan, kuinka tarkka luokittimemme on tällä testidatalla. Tätä varten laajennamme testidatan ylimääräisellä ulottuvuudella, kerromme sen painomatriisilla ja varmistamme, että saatu arvo on samanmerkkinen kuin tunniste (+1 tai -1). Tämän jälkeen laskemme yhteen kaikki totuusarvot ja jaamme testinäytteen pituudella saadaksemme tarkkuuden:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -420,9 +546,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Havainnoimassa koulutusprosessia\n",
|
||||
"## Tarkkaile koulutusprosessia\n",
|
||||
"\n",
|
||||
"Olemme aiemmin nähneet, kuinka tarkkuus heikkenee koulutuksen aikana. Olisi mielenkiintoista nähdä, miten erotusviiva käyttäytyy koulutuksen aikana. Alla oleva koodi visualisoi kaiken yhdellä graafilla, ja sinun pitäisi pystyä siirtämään liukusäädintä \"aikamatkustaaksesi\" koulutusprosessin läpi.\n"
|
||||
"Olemme aiemmin nähneet, kuinka tarkkuus heikkenee koulutuksen aikana. Olisi mielenkiintoista nähdä, miten erotusviiva käyttäytyy koulutuksen aikana. Alla oleva koodi visualisoi kaiken yhteen graafiin, ja sinun pitäisi pystyä siirtämään liukusäädintä \"aikamatkailun\" avulla koulutusprosessin läpi.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,9 +655,9 @@
|
|||
"source": [
|
||||
"## Perceptronin rajoitukset\n",
|
||||
"\n",
|
||||
"Kuten yllä on nähty, perceptron on **lineaarinen luokittelija**. Se pystyy erottamaan kaksi luokkaa hyvin, jos ne ovat **lineaarisesti erotettavissa**, eli ne voidaan erottaa suoralla viivalla. Muussa tapauksessa perceptronin koulutusprosessi ei saavuta konvergenssia.\n",
|
||||
"Kuten yllä on nähty, perceptron on **lineaarinen luokittelija**. Se pystyy erottamaan kaksi luokkaa hyvin, jos ne ovat **lineaarisesti erotettavissa**, eli ne voidaan erottaa suoralla viivalla. Muussa tapauksessa perceptronin koulutusprosessi ei tule konvergoitumaan.\n",
|
||||
"\n",
|
||||
"Selkein esimerkki ongelmasta, jota perceptron ei pysty ratkaisemaan, on niin sanottu **XOR-ongelma**. Haluamme, että perceptron oppii XOR-loogisen funktion, jolla on seuraava totuustaulukko:\n",
|
||||
"Yksi ilmeisimmistä esimerkeistä ongelmasta, jota perceptron ei voi ratkaista, on niin sanottu **XOR-ongelma**. Haluamme, että perceptron oppii XOR-loogisen funktion, jolla on seuraava totuustaulukko:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -607,19 +733,19 @@
|
|||
"source": [
|
||||
"Kuten yllä olevasta kaaviosta näkyy, tarkkuus ei koskaan ylitä 75 %, koska on mahdotonta piirtää suoraa viivaa siten, että kaikki esimerkit saadaan oikein.\n",
|
||||
"\n",
|
||||
"XOR-ongelma on klassinen esimerkki perceptronin rajoituksista, ja Marvin Minsky ja Seymour Papert toivat sen esille vuonna 1969 kirjassaan [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Tämä havainto rajoitti neuroverkkojen tutkimusta lähes 10 vuoden ajan, vaikka - kuten näemme kurssimme seuraavassa osiossa - monikerroksiset perceptronit pystyvät täysin ratkaisemaan tällaisia ongelmia.\n",
|
||||
"XOR-ongelma on klassinen esimerkki perceptronin rajoituksista, ja Marvin Minsky ja Seymour Papert toivat sen esille vuonna 1969 kirjassaan [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Tämä havainto rajoitti neuroverkkojen tutkimusta lähes 10 vuoden ajan, vaikka - kuten näemme kurssimme seuraavassa osiossa - monikerroksiset perceptronit pystyvät ratkaisemaan tällaisia ongelmia.\n",
|
||||
"\n",
|
||||
"## Monimutkainen esimerkki - MNIST\n",
|
||||
"\n",
|
||||
"Vaikka perceptron ei pysty ratkaisemaan XOR-ongelmaa, se voi ratkaista monia muita monimutkaisempia ongelmia, kuten käsinkirjoitettujen merkkien tunnistamisen.\n",
|
||||
"Vaikka perceptron ei pysty ratkaisemaan XOR-ongelmaa, se voi ratkaista monia monimutkaisempia ongelmia, kuten käsinkirjoitettujen merkkien tunnistamisen.\n",
|
||||
"\n",
|
||||
"Koneoppimisen hallitsemisessa usein käytetty tietojoukko on nimeltään [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Sen on luonut Modified National Institute of Standards and Technology, ja se sisältää 60000 käsinkirjoitetun numeron harjoitusaineiston, joka on kerätty noin 250 opiskelijalta ja instituutin työntekijältä. Lisäksi on olemassa testiaineisto, joka sisältää 10000 numeroa, kerätty eri henkilöiltä.\n",
|
||||
"Yksi koneoppimisen hallinnassa usein käytetty datasetti on nimeltään [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Sen on luonut Modified National Institute of Standards and Technology, ja se sisältää 60000 käsinkirjoitettua numeroa harjoitusjoukossa, jotka on kerätty noin 250 opiskelijalta ja instituutin työntekijältä. Lisäksi on olemassa testidatasetti, joka sisältää 10000 numeroa, kerätty eri henkilöiltä.\n",
|
||||
"\n",
|
||||
"Kaikki numerot on esitetty harmaasävykuvina, joiden koko on 28x28 pikseliä.\n",
|
||||
"\n",
|
||||
"> MNIST-tietojoukko on saatavilla harjoituskilpailuna [Kaggle](https://www.kaggle.com/c/digit-recognizer)-sivustolla, joka järjestää koneoppimiskilpailuja ja -haasteita. Kun opit luokittelemaan MNIST-numeroita, voit lähettää ratkaisusi Kaggleen nähdäksesi, miten se arvioidaan muiden osallistujien joukossa.\n",
|
||||
"> MNIST-datasetti on saatavilla harjoituskilpailuna [Kaggle](https://www.kaggle.com/c/digit-recognizer)-sivustolla, joka järjestää koneoppimiskilpailuja ja -haasteita. Kun opit luokittelemaan MNIST-numeroita, voit lähettää ratkaisusi Kaggleen nähdäksesi, miten se arvioidaan muiden osallistujien joukossa.\n",
|
||||
"\n",
|
||||
"Aloitamme lataamalla MNIST-tietojoukon:\n"
|
||||
"Aloitamme lataamalla MNIST-datasetin:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Koska perceptroni on binääriluokitin, rajoitamme ongelmamme vain kahden numeron tunnistamiseen. Alla oleva funktio täyttää positiiviset ja negatiiviset näytearvot kahdella annetulla numerolla (ja näyttää myös näytteet näistä numeroista selkeyden vuoksi).\n"
|
||||
"Koska perceptroni on binääriluokitin, rajoitamme ongelmamme tunnistamaan vain kaksi numeroa. Alla oleva funktio täyttää positiiviset ja negatiiviset näytearvot kahdella annetulla numerolla (ja näyttää myös näytteet näistä numeroista selkeyden vuoksi).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"Huomaa, kuinka tarkkuus nousee lähes 100 %:iin erittäin nopeasti.\n",
|
||||
"\n",
|
||||
"Siirrä liukusäädintä kohti harjoittelun loppua ja tarkastele vasemmalla näkyvää painomatriisia. Tämä matriisi auttaa sinua ymmärtämään, miten perceptroni toimii. Voit nähdä korkeat painoarvot kentän keskellä, jotka vastaavat pikseleitä, jotka ovat tyypillisesti läsnä numerolle 1, ja matalat negatiiviset arvot reunoilla, joissa numeron 0 osat sijaitsevat. Jos perceptronille esitetty numero on todellisuudessa 1, sen keskiosa kerrotaan korkeilla arvoilla, mikä tuottaa positiivisen tuloksen. Toisaalta, kun perceptroni havaitsee numeron 0, vastaavat pikselit kerrotaan negatiivisilla arvoilla.\n",
|
||||
"Siirrä liukusäädintä kohti harjoittelun loppua ja tarkastele vasemmalla näkyvää painomatriisia. Tämä matriisi auttaa sinua ymmärtämään, miten perceptroni toimii. Voit nähdä korkeat painoarvot kentän keskellä, jotka vastaavat pikseleitä, jotka ovat tyypillisesti läsnä numerolle 1, ja matalat negatiiviset arvot reunoilla, joissa numeron 0 osat sijaitsevat. Jos perceptronille esitetty numero on todellisuudessa 1, sen keskiosa kerrotaan korkeilla arvoilla, mikä tuottaa positiivisen tuloksen. Toisaalta, kun perceptroni havaitsee numeron 0, vastaavat pikselit kerrotaan negatiivisilla luvuilla.\n",
|
||||
"\n",
|
||||
"> Saatat huomata, että jos annamme perceptronille numeron 1, joka on hieman siirtynyt vaakasuunnassa niin, että sen pikselit osuvat kohtaan, jossa numeron 0 pystysuorat osat ovat, voimme saada virheellisen tuloksen. MNIST-datasarjamme luonne on sellainen, että kaikki numerot ovat keskitettyjä ja sijoitettu oikein, ja perceptroni perustuu tähän erottaakseen numerot toisistaan.\n",
|
||||
"> Saatat huomata, että jos annamme perceptronille numeron 1, joka on hieman siirtynyt vaakasuunnassa niin, että sen pikselit ovat kohdassa, jossa numeron 0 pystysuorat osat sijaitsevat, voimme saada virheellisen tuloksen. MNIST-datasarjan luonne on sellainen, että kaikki numerot ovat keskitettyjä ja sijoitettu oikein, ja perceptroni perustuu tähän erottaakseen numerot toisistaan.\n",
|
||||
"\n",
|
||||
"Kokeillaan nyt eri numeroita:\n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"Jostain syystä numerot 2 ja 5 eivät ole yhtä helposti erotettavissa. Vaikka saavutamme suhteellisen korkean tarkkuuden (yli 85 %), voimme selvästi nähdä, kuinka perceptron lakkaa oppimasta jossain vaiheessa.\n",
|
||||
"\n",
|
||||
"Ymmärtääksemme, miksi näin tapahtuu, voimme kokeilla käyttää [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Se on koneoppimistekniikka, jota käytetään syötedatan ulottuvuuden pienentämiseen siten, että luokkien välinen erotettavuus saadaan mahdollisimman hyväksi.\n",
|
||||
"Ymmärtääksemme, miksi näin tapahtuu, voimme kokeilla käyttää [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) -menetelmää. Se on koneoppimistekniikka, jota käytetään syötedatan ulottuvuuden pienentämiseen siten, että luokkien välinen erotettavuus saadaan mahdollisimman hyväksi.\n",
|
||||
"\n",
|
||||
"Meidän tapauksessamme syötekuvassa on 784 pikseliä (syöteominaisuuksia), ja haluamme käyttää PCA:ta vähentääksemme parametrien määrän kahteen, jotta voimme piirtää ne graafiin. Nämä kaksi parametria olisivat alkuperäisten ominaisuuksien lineaarinen yhdistelmä, ja voimme nähdä tämän prosessin ikään kuin \"kiertäisimme\" alkuperäistä 784-ulotteista avaruuttamme ja tarkkailisimme sen projektioita 2D-avaruuteen, kunnes saamme parhaan näkymän, joka erottaa luokat.\n"
|
||||
"Meidän tapauksessamme syötekuvassa on 784 pikseliä (syöteominaisuuksia), ja haluamme käyttää PCA:ta vähentääksemme parametrien määrän kahteen, jotta voimme piirtää ne graafiin. Nämä kaksi parametria olisivat alkuperäisten ominaisuuksien lineaarinen yhdistelmä, ja voimme nähdä tämän prosessin ikään kuin \"kiertäisimme\" alkuperäistä 784-ulotteista avaruutta ja tarkastelisimme sen projektioita 2D-avaruuteen, kunnes saamme parhaan näkymän, joka erottaa luokat.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1033,9 +1159,9 @@
|
|||
"\n",
|
||||
"## Yhteenveto\n",
|
||||
"\n",
|
||||
" * Olemme oppineet yksinkertaisimman neuroverkon arkkitehtuurin - yhden kerroksen perceptronin.\n",
|
||||
" * Olemme oppineet yksinkertaisimmasta neuroverkon arkkitehtuurista - yhden kerroksen perceptronista.\n",
|
||||
" * Olemme toteuttaneet perceptronin \"käsin\" käyttäen yksinkertaista koulutusmenetelmää, joka perustuu gradienttilaskentaan.\n",
|
||||
" * Yksinkertaisuudestaan huolimatta yhden kerroksen perceptron voi ratkaista melko monimutkaisia käsinkirjoitettujen numeroiden tunnistusongelmia.\n",
|
||||
" * Yksinkertaisuudestaan huolimatta yhden kerroksen perceptron pystyy ratkaisemaan melko monimutkaisia käsinkirjoitettujen numeroiden tunnistusongelmia.\n",
|
||||
" * Yhden kerroksen perceptron on lineaarinen luokittelija, ja siksi se tarjoaa saman luokittelutehon kuin logistinen regressio.\n",
|
||||
" * Näyteavaruudessa perceptron voi erottaa kaksi syöteaineiston luokkaa hyperpinnan avulla.\n"
|
||||
]
|
||||
|
|
@ -1046,7 +1172,7 @@
|
|||
"source": [
|
||||
"## Tekijätiedot\n",
|
||||
"\n",
|
||||
"Tämä muistikirja on osa [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) -ohjelmaa, ja sen on laatinut [Dmitry Soshnikov](http://soshnikov.com). Se on saanut inspiraationsa Microsoft Research Cambridgen Neural Network Workshopista. Osa koodista ja havainnollistavista materiaaleista on peräisin [Katja Hoffmannin](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnsonin](https://www.microsoft.com/en-us/research/people/matjoh/) ja [Ryoto Tomiokan](https://www.microsoft.com/en-us/research/people/ryoto/) esityksistä sekä [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) -arkistosta.\n"
|
||||
"Tämä muistikirja on osa [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) -ohjelmaa, ja sen on laatinut [Dmitry Soshnikov](http://soshnikov.com). Se on saanut inspiraationsa Neural Network Workshop -työpajasta Microsoft Research Cambridgessa. Osa koodista ja havainnollistavista materiaaleista on peräisin [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) ja [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) esityksistä sekä [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) -arkistosta.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:33:39+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:21:26+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "fi"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Problème Simplifié\n",
|
||||
"## Problème simplifié\n",
|
||||
"\n",
|
||||
"Pour commencer, abordons un problème simplifié, où nous avons deux caractéristiques d'entrée. Par exemple, en médecine, nous pourrions vouloir classer les tumeurs en bénignes et malignes, en fonction de leur taille et de leur âge.\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Cependant, un modèle linéaire générique devrait également inclure un biais, c'est-à-dire qu'idéalement, nous devrions calculer $y$ comme $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Pour simplifier notre modèle, nous pouvons éliminer ce terme de biais en ajoutant une dimension supplémentaire à nos caractéristiques d'entrée, qui sera toujours égale à 1 :\n"
|
||||
"Cependant, un modèle linéaire générique devrait également inclure un biais, c'est-à-dire qu'idéalement, nous devrions calculer $y$ comme $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Pour simplifier notre modèle, nous pouvons éliminer ce terme de biais en ajoutant une dimension supplémentaire à nos caractéristiques d'entrée, qui vaut toujours 1 :\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ pour les exemples d'entraînement négatifs et positifs, respectivement\n",
|
||||
" * $\\mathcal{M}$ - un ensemble d'exemples mal classés\n",
|
||||
" \n",
|
||||
"Nous utiliserons le processus de **descente de gradient**. En commençant par des poids initiaux aléatoires $\\mathbf{w}^{(0)}$, nous ajusterons les poids à chaque étape de l'entraînement en utilisant le gradient de $E$ :\n",
|
||||
"Nous utiliserons le processus de **descente de gradient**. En partant de poids initiaux aléatoires $\\mathbf{w}^{(0)}$, nous ajusterons les poids à chaque étape de l'entraînement en utilisant le gradient de $E$ :\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Remarque sur le taux d'apprentissage** : Le paramètre `learning_rate` (par défaut `0.01`) détermine à quel point nous ajustons les poids à chaque étape d'entraînement. Cela met en œuvre la formule de mise à jour par descente de gradient :\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Un taux d'apprentissage plus élevé (par exemple, `1.0`) permet au perceptron d'apprendre plus rapidement, mais peut dépasser la solution optimale\n",
|
||||
"- Un taux d'apprentissage plus faible (par exemple, `0.001`) apprend plus lentement, mais peut converger de manière plus précise\n",
|
||||
"- Vous pouvez expérimenter en appelant : `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Expérimentation avec les taux d'apprentissage\n",
|
||||
"\n",
|
||||
"Explorons maintenant comment différents taux d'apprentissage influencent le processus d'entraînement. Le taux d'apprentissage détermine la taille des pas dans la descente de gradient - un hyperparamètre essentiel qui impacte à la fois la vitesse de convergence et la stabilité.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Expérience interactive sur le taux d'apprentissage\n",
|
||||
"\n",
|
||||
"Utilisez le curseur ci-dessous pour expérimenter de manière interactive avec différents taux d'apprentissage et observer leur impact sur la frontière de décision :\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Évaluer sur le jeu de données de test\n",
|
||||
"\n",
|
||||
"Au départ, nous avons mis de côté certaines données pour constituer le jeu de données de test. Voyons à quel point notre classificateur est précis sur ce jeu de données. Pour ce faire, nous étendons également le jeu de données de test avec une dimension supplémentaire, nous le multiplions par la matrice des poids, et nous vérifions que la valeur obtenue a le même signe que l'étiquette (+1 ou -1). Ensuite, nous additionnons toutes les valeurs booléennes et divisons par la taille de l'échantillon de test pour obtenir la précision :\n"
|
||||
"Au départ, nous avons mis de côté certaines données pour constituer le jeu de données de test. Voyons à quel point notre classificateur est précis sur ce jeu de données. Pour ce faire, nous étendons également le jeu de données de test avec une dimension supplémentaire, nous le multiplions par la matrice des poids, et nous vérifions que la valeur obtenue a le même signe que l'étiquette (+1 ou -1). Ensuite, nous additionnons toutes les valeurs booléennes et les divisons par la taille de l'échantillon de test pour obtenir la précision :\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,7 +655,7 @@
|
|||
"source": [
|
||||
"## Limitations du Perceptron\n",
|
||||
"\n",
|
||||
"Comme vous l'avez vu ci-dessus, le perceptron est un **classificateur linéaire**. Il peut bien distinguer entre deux classes si elles sont **linéairement séparables**, c'est-à-dire si elles peuvent être séparées par une ligne droite. Sinon, le processus d'entraînement du perceptron ne convergera pas.\n",
|
||||
"Comme vous l'avez vu ci-dessus, le perceptron est un **classificateur linéaire**. Il peut bien distinguer entre deux classes si elles sont **linéairement séparables**, c'est-à-dire qu'elles peuvent être séparées par une ligne droite. Sinon, le processus d'entraînement du perceptron ne convergera pas.\n",
|
||||
"\n",
|
||||
"Un exemple évident d'un problème qui ne peut pas être résolu par un perceptron est le problème dit du **XOR**. Nous voulons que notre perceptron apprenne la fonction booléenne XOR, qui a la table de vérité suivante :\n",
|
||||
"\n",
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Comme vous pouvez le voir sur le graphique ci-dessus, la précision ne dépasse jamais 75 %, car il est impossible de tracer une ligne droite de manière à classer correctement tous les exemples possibles.\n",
|
||||
"Comme vous pouvez le voir sur le graphique ci-dessus, la précision ne dépasse jamais 75 %, car il est impossible de tracer une ligne droite de manière à obtenir tous les exemples corrects.\n",
|
||||
"\n",
|
||||
"Le problème XOR est un exemple classique des limitations du perceptron, et il a été souligné par Marvin Minsky et Seymour Papert en 1969 dans leur livre [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Cette observation a freiné la recherche dans le domaine des réseaux neuronaux pendant près de 10 ans, même si - et nous le verrons dans la prochaine section de notre cours - les perceptrons multicouches sont parfaitement capables de résoudre de tels problèmes.\n",
|
||||
"Le problème XOR est un exemple classique des limitations du perceptron, et il a été souligné par Marvin Minsky et Seymour Papert en 1969 dans leur livre [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Cette observation a freiné les recherches dans le domaine des réseaux neuronaux pendant près de 10 ans, même si - et nous le verrons dans la prochaine section de notre cours - les perceptrons multicouches sont parfaitement capables de résoudre de tels problèmes.\n",
|
||||
"\n",
|
||||
"## Exemple complexe - MNIST\n",
|
||||
"\n",
|
||||
"Bien que le perceptron ne puisse pas résoudre le problème XOR, il peut résoudre des problèmes bien plus complexes, comme la reconnaissance de caractères manuscrits.\n",
|
||||
"\n",
|
||||
"Un jeu de données souvent utilisé pour maîtriser l'apprentissage automatique s'appelle [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Il a été créé par le National Institute of Standards and Technology modifié et contient un ensemble d'entraînement de 60 000 chiffres manuscrits, collectés auprès d'environ 250 étudiants et employés de l'institut. Il existe également un ensemble de test de 10 000 chiffres, collectés auprès d'individus différents.\n",
|
||||
"Un jeu de données souvent utilisé pour maîtriser l'apprentissage automatique s'appelle [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Il a été créé par le National Institute of Standards and Technology modifié et contient un ensemble d'entraînement de 60 000 chiffres manuscrits, collectés auprès d'environ 250 étudiants et employés de l'institut. Il existe également un ensemble de test de 10 000 chiffres, collectés auprès de différentes personnes.\n",
|
||||
"\n",
|
||||
"Tous les chiffres sont représentés par des images en niveaux de gris de taille 28x28 pixels.\n",
|
||||
"\n",
|
||||
"> Le jeu de données MNIST est disponible en tant que compétition d'entraînement sur [Kaggle](https://www.kaggle.com/c/digit-recognizer), un site qui héberge des compétitions et des concours d'apprentissage automatique. Une fois que vous aurez appris à classer les chiffres MNIST, vous pourrez soumettre votre solution sur Kaggle pour voir comment elle est évaluée parmi les autres participants.\n",
|
||||
"> Le jeu de données MNIST est disponible sous forme de compétition d'entraînement sur [Kaggle](https://www.kaggle.com/c/digit-recognizer), un site qui héberge des compétitions et des concours d'apprentissage automatique. Une fois que vous aurez appris à classifier les chiffres MNIST, vous pourrez soumettre votre solution sur Kaggle pour voir comment elle est évaluée parmi les autres participants.\n",
|
||||
"\n",
|
||||
"Nous commençons par charger le jeu de données MNIST :\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Parce que le perceptron est un classificateur binaire, nous limiterons notre problème à la reconnaissance de seulement deux chiffres. La fonction ci-dessous remplira les tableaux d'échantillons positifs et négatifs avec deux chiffres donnés (et affichera également des échantillons de ces chiffres pour plus de clarté).\n"
|
||||
"Parce que le perceptron est un classificateur binaire, nous limiterons notre problème à la reconnaissance de seulement deux chiffres. La fonction ci-dessous remplira les tableaux d'échantillons positifs et négatifs avec deux chiffres donnés (et montrera également des échantillons de ces chiffres pour plus de clarté).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"Veuillez noter que la précision atteint presque 100 % très rapidement.\n",
|
||||
"\n",
|
||||
"Veuillez déplacer le curseur vers une position vers la fin de l'entraînement et observer la matrice de poids affichée à gauche. Cette matrice vous permettra de comprendre comment fonctionne réellement le perceptron. Vous pouvez voir les valeurs de poids élevées au centre du champ, qui correspondent aux pixels généralement présents pour le chiffre 1, et les faibles valeurs négatives sur les côtés, où se trouvent les parties du chiffre 0. Ainsi, si le chiffre présenté au perceptron est effectivement un 1, la partie centrale sera multipliée par des valeurs élevées, produisant un résultat positif. En revanche, lorsque le perceptron observe un 0, les pixels correspondants seront multipliés par des nombres négatifs.\n",
|
||||
"Veuillez déplacer le curseur vers une position proche de la fin de l'entraînement et observer la matrice de poids affichée à gauche. Cette matrice vous permettra de comprendre comment fonctionne réellement le perceptron. Vous pouvez voir les valeurs de poids élevées au centre du champ, qui correspondent aux pixels généralement présents pour le chiffre 1, et les faibles valeurs négatives sur les côtés, où se trouvent les parties du chiffre 0. Ainsi, si le chiffre présenté au perceptron est effectivement un 1, la partie centrale sera multipliée par des valeurs élevées, produisant un résultat positif. En revanche, lorsque le perceptron observe un 0, les pixels correspondants seront multipliés par des nombres négatifs.\n",
|
||||
"\n",
|
||||
"> Vous pouvez remarquer que si nous donnons à notre perceptron un chiffre 1 légèrement décalé horizontalement, de sorte que ses pixels occupent l'endroit où se trouvent les parties verticales du chiffre 0, nous pourrions obtenir un résultat incorrect. Cela est dû au fait que la nature de notre dataset MNIST est telle que tous les chiffres sont centrés et positionnés correctement, et le perceptron s'appuie sur cela pour distinguer les chiffres.\n",
|
||||
"> Vous pouvez remarquer que si nous donnons à notre perceptron un chiffre 1 légèrement décalé horizontalement, de sorte que ses pixels occupent l'endroit où se trouvent les parties verticales du chiffre 0, nous pourrions obtenir un résultat incorrect. Cela s'explique par la nature de notre dataset MNIST, où tous les chiffres sont centrés et correctement positionnés, et le perceptron s'appuie sur cette caractéristique pour distinguer les chiffres.\n",
|
||||
"\n",
|
||||
"Essayons maintenant différents chiffres :\n"
|
||||
]
|
||||
|
|
@ -917,7 +1043,7 @@
|
|||
"\n",
|
||||
"Pour comprendre pourquoi cela se produit, nous pouvons essayer d'utiliser [l'Analyse en Composantes Principales](https://fr.wikipedia.org/wiki/Analyse_en_composantes_principales) (ACP). C'est une technique d'apprentissage automatique utilisée pour réduire la dimensionnalité du jeu de données d'entrée, de manière à obtenir la meilleure séparabilité entre les classes.\n",
|
||||
"\n",
|
||||
"Dans notre cas, une image d'entrée comporte 784 pixels (caractéristiques d'entrée), et nous voulons utiliser l'ACP pour réduire le nombre de paramètres à seulement 2, afin de pouvoir les représenter sur un graphique. Ces deux paramètres seraient une combinaison linéaire des caractéristiques originales, et nous pouvons considérer cette procédure comme une \"rotation\" de notre espace original à 784 dimensions pour observer sa projection dans un espace 2D, jusqu'à obtenir la meilleure vue qui sépare les classes.\n"
|
||||
"Dans notre cas, une image d'entrée comporte 784 pixels (caractéristiques d'entrée), et nous voulons utiliser l'ACP pour réduire le nombre de paramètres à seulement 2, afin de pouvoir les représenter sur un graphique. Ces deux paramètres seraient une combinaison linéaire des caractéristiques originales, et nous pouvons considérer cette procédure comme une \"rotation\" de notre espace original à 784 dimensions et l'observation de sa projection dans un espace 2D, jusqu'à obtenir la meilleure vue qui sépare les classes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,7 +1155,7 @@
|
|||
"source": [
|
||||
"Comme vous pouvez le voir, 0 et 1 peuvent être clairement séparés par une ligne droite. Cela indique que dans l'espace original à 784 dimensions, les points correspondant aux chiffres sont également linéairement séparables. Dans le cas de 2 et 5, nous ne pouvons pas trouver une bonne projection qui sépare clairement les chiffres, ce qui entraîne certains cas de mauvaise classification.\n",
|
||||
"\n",
|
||||
"> Plus tard dans ce cours, nous apprendrons à créer des classificateurs non linéaires en utilisant les réseaux neuronaux, et à résoudre le problème des chiffres qui ne sont pas correctement alignés. Très bientôt, nous atteindrons une précision supérieure à 99 % dans la classification des chiffres MNIST, tout en les classant en 10 catégories différentes.\n",
|
||||
"> Plus tard dans ce cours, nous apprendrons à créer des classificateurs non linéaires en utilisant les réseaux neuronaux, et à résoudre le problème des chiffres qui ne sont pas correctement alignés. Très bientôt, nous atteindrons une précision supérieure à 99 % dans la classification des chiffres MNIST, tout en les classant en 10 classes différentes.\n",
|
||||
"\n",
|
||||
"## Points clés\n",
|
||||
"\n",
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:06:10+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:51:31+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "fr"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
"source": [
|
||||
"## פרספטון\n",
|
||||
"\n",
|
||||
"> מחברת זו היא חלק מ-[AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). בקרו במאגר לקבלת סט מלא של חומרי לימוד.\n",
|
||||
"> מחברת זו היא חלק מ-[AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). בקרו במאגר למערך הלמידה המלא.\n",
|
||||
"\n",
|
||||
"כפי שדיברנו, פרספטון מאפשר לפתור **בעיית סיווג בינארי**, כלומר לסווג דוגמאות קלט לשתי קטגוריות - נוכל לקרוא להן **חיובי** ו**שלילי**.\n",
|
||||
"כפי שדיברנו, פרספטון מאפשר לפתור **בעיית סיווג בינארי**, כלומר לסווג דוגמאות קלט לשתי קטגוריות - נוכל לקרוא להן **חיובי** ו-**שלילי**.\n",
|
||||
"\n",
|
||||
"ראשית, בואו נייבא כמה ספריות נדרשות.\n"
|
||||
]
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## בעיית צעצוע\n",
|
||||
"\n",
|
||||
"נתחיל עם בעיית צעצוע, שבה יש לנו שני מאפייני קלט. לדוגמה, ברפואה ייתכן שנרצה לסווג גידולים לשפירים וממאירים, בהתאם לגודלם וגילם.\n",
|
||||
"נתחיל עם בעיית צעצוע, שבה יש לנו שני מאפייני קלט. לדוגמה, ברפואה נרצה לסווג גידולים לשפירים וממאירים, בהתאם לגודלם וגילם.\n",
|
||||
"\n",
|
||||
"ניצור מערך נתונים אקראי לסיווג באמצעות הפונקציה `make_classification` מספריית SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -154,11 +154,11 @@
|
|||
"source": [
|
||||
"## פרספטרון\n",
|
||||
"\n",
|
||||
"מכיוון שפרספטרון הוא מסווג בינארי, עבור כל וקטור קלט $x$ הפלט של הפרספטרון שלנו יהיה או +1 או -1, בהתאם למחלקה. הפלט יחושב באמצעות הנוסחה\n",
|
||||
"מכיוון שפרספטרון הוא מסווג בינארי, עבור כל וקטור קלט $x$ הפלט של הפרספטרון שלנו יהיה או +1 או -1, בהתאם למחלקה. הפלט יחושב באמצעות הנוסחה:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"כאשר $\\mathbf{w}$ הוא וקטור משקל, $f$ היא פונקציית הפעלה מדרגה:\n",
|
||||
"כאשר $\\mathbf{w}$ הוא וקטור משקל, ו-$f$ היא פונקציית הפעלה מדרגה:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"עם זאת, מודל לינארי כללי צריך גם לכלול הטיה, כלומר באופן אידיאלי עלינו לחשב $y$ כ-$y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. כדי לפשט את המודל שלנו, ניתן להיפטר ממונח ההטיה הזה על ידי הוספת ממד נוסף לתכונות הקלט שלנו, שתמיד שווה ל-1:\n"
|
||||
"עם זאת, מודל לינארי כללי צריך לכלול גם הטיה (bias), כלומר באופן אידיאלי היינו צריכים לחשב $y$ כ-$y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. כדי לפשט את המודל שלנו, ניתן להיפטר ממונח הטיה זה על ידי הוספת ממד נוסף לתכונות הקלט שלנו, שתמיד שווה ל-1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**הערה על קצב הלמידה**: הפרמטר `learning_rate` (ברירת מחדל `0.01`) שולט בכמה אנו מתאימים את המשקלים בכל שלב אימון. זה מיישם את נוסחת העדכון של ירידת המדרון:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- קצב למידה גבוה יותר (לדוגמה, `1.0`) גורם לפרספטור ללמוד מהר יותר אך עשוי להחמיץ את הפתרון האופטימלי\n",
|
||||
"- קצב למידה נמוך יותר (לדוגמה, `0.001`) לומד לאט יותר אך עשוי להתכנס בצורה מדויקת יותר\n",
|
||||
"- ניתן להתנסות על ידי קריאה לפונקציה: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"כפי שניתן לראות, הדיוק ההתחלתי הוא סביב 50%, אך הוא עולה במהירות לערכים גבוהים קרובים ל-90%.\n",
|
||||
"כפי שאתם יכולים לראות, הדיוק ההתחלתי הוא סביב 50%, אך הוא עולה במהירות לערכים גבוהים קרובים ל-90%.\n",
|
||||
"\n",
|
||||
"בואו נמחיש כיצד הקטגוריות מופרדות. פונקציית הסיווג שלנו נראית כמו $\\mathbf{w}^Tx$, והיא גדולה מ-0 עבור קטגוריה אחת, ונמוכה מ-0 עבור קטגוריה אחרת. לכן, קו ההפרדה בין הקטגוריות מוגדר על ידי $\\mathbf{w}^Tx = 0$. מכיוון שיש לנו רק שני ממדים $x_0$ ו-$x_1$, המשוואה עבור הקו תהיה $w_0x_0+w_1x_1+w_2 = 0$ (זכרו שהגדרנו במפורש ממד נוסף $x_2=1$). בואו נשרטט את הקו הזה:\n"
|
||||
"בואו נמחיש כיצד הקטגוריות מופרדות. פונקציית הסיווג שלנו נראית כמו $\\mathbf{w}^Tx$, והיא גדולה מ-0 עבור קטגוריה אחת, ונמוכה מ-0 עבור קטגוריה אחרת. לכן, קו ההפרדה בין הקטגוריות מוגדר על ידי $\\mathbf{w}^Tx = 0$. מכיוון שיש לנו רק שני ממדים $x_0$ ו-$x_1$, המשוואה של הקו תהיה $w_0x_0+w_1x_1+w_2 = 0$ (זכרו שהגדרנו במפורש ממד נוסף $x_2=1$). בואו נשרטט את הקו הזה:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ניסוי עם קצבי למידה\n",
|
||||
"\n",
|
||||
"עכשיו בואו נחקור כיצד קצבי למידה שונים משפיעים על תהליך האימון. קצב הלמידה שולט בגודל הצעד בירידת המדרון - פרמטר חשוב שמשפיע הן על מהירות ההתכנסות והן על היציבות.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### ניסוי אינטראקטיבי של קצב למידה\n",
|
||||
"\n",
|
||||
"השתמשו במחוון למטה כדי להתנסות באופן אינטראקטיבי בקצבי למידה שונים ולראות כיצד הם משפיעים על גבול ההחלטה:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## הערכה על קבוצת הבדיקה\n",
|
||||
"\n",
|
||||
"בהתחלה, שמרנו חלק מהנתונים לקבוצת הבדיקה. בואו נראה עד כמה המסווג שלנו מדויק על קבוצת הבדיקה הזו. כדי לעשות זאת, אנחנו גם מרחיבים את קבוצת הבדיקה עם ממד נוסף, מכפילים במטריצת המשקלים, ומוודאים שהערך שהתקבל הוא באותו סימן כמו התווית (+1 או -1). לאחר מכן, אנחנו מחברים את כל הערכים הבוליאניים ומחלקים באורך הדגימה של הבדיקה, כדי לקבל את רמת הדיוק:\n"
|
||||
"בהתחלה, שמרנו חלק מהנתונים עבור קבוצת הבדיקה. בואו נראה עד כמה המסווג שלנו מדויק על קבוצת הבדיקה הזו. כדי לעשות זאת, אנו גם מרחיבים את קבוצת הבדיקה עם ממד נוסף, מכפילים במטריצת המשקלים, ומוודאים שהערך שהתקבל הוא באותו סימן כמו התווית (+1 או -1). לאחר מכן אנו מחברים את כל הערכים הבוליאניים ומחלקים באורך הדגימה של קבוצת הבדיקה, כדי לקבל את רמת הדיוק:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -605,21 +731,21 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"כפי שניתן לראות מהגרף למעלה, הדיוק לעולם אינו עולה מעל 75%, מכיוון שבלתי אפשרי לצייר קו ישר כך שיכסה את כל הדוגמאות בצורה נכונה.\n",
|
||||
"כפי שניתן לראות מהגרף למעלה, הדיוק לעולם אינו עולה מעל 75%, מכיוון שבלתי אפשרי לצייר קו ישר בצורה כזו שתתאים לכל הדוגמאות האפשריות.\n",
|
||||
"\n",
|
||||
"בעיית XOR היא דוגמה קלאסית למגבלות של פרספטון, והיא הוצגה על ידי מרווין מינסקי וסיימור פפרט בשנת 1969 בספרם [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). תצפית זו הגבילה את המחקר בתחום הרשתות העצביות במשך כמעט 10 שנים, למרות - וכפי שנראה בחלק הבא של הקורס שלנו - פרספטונים רב-שכבתיים מסוגלים לפתור בעיות כאלה בצורה מושלמת.\n",
|
||||
"בעיית XOR היא דוגמה קלאסית למגבלות של פרספטרון, והיא הוצגה על ידי מרווין מינסקי וסיימור פפרט בשנת 1969 בספרם [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). תצפית זו הגבילה את המחקר בתחום הרשתות העצביות במשך כמעט 10 שנים, למרות - וכפי שנראה בחלק הבא של הקורס שלנו - שפרספטרונים רב-שכבתיים מסוגלים לפתור בעיות כאלה בצורה מושלמת.\n",
|
||||
"\n",
|
||||
"## דוגמה מורכבת - MNIST\n",
|
||||
"\n",
|
||||
"למרות שפרספטון אינו יכול לפתור את בעיית XOR, הוא יכול לפתור בעיות מורכבות יותר, כמו זיהוי תווים בכתב יד.\n",
|
||||
"למרות שפרספטרון אינו יכול לפתור את בעיית XOR, הוא יכול לפתור בעיות מורכבות יותר, כמו זיהוי תווים בכתב יד.\n",
|
||||
"\n",
|
||||
"מערך נתונים שנעשה בו שימוש תדיר בלימוד למידת מכונה נקרא [MNIST](https://en.wikipedia.org/wiki/MNIST_database). הוא נוצר על ידי המכון הלאומי לתקנים וטכנולוגיה (Modified National Institute of Standards and Technology), ומכיל מערך אימון של 60,000 ספרות בכתב יד, שנאספו מכ-250 סטודנטים ועובדים של המכון. בנוסף, ישנו מערך בדיקה של 10,000 ספרות, שנאספו מאנשים שונים.\n",
|
||||
"מאגר נתונים שנעשה בו שימוש לעיתים קרובות בלימוד למידת מכונה נקרא [MNIST](https://en.wikipedia.org/wiki/MNIST_database). הוא נוצר על ידי המכון הלאומי לתקנים וטכנולוגיה (Modified National Institute of Standards and Technology), ומכיל סט אימון של 60,000 ספרות בכתב יד, שנאספו מכ-250 תלמידים ועובדים של המכון. בנוסף, ישנו גם סט בדיקה של 10,000 ספרות, שנאספו מאנשים שונים.\n",
|
||||
"\n",
|
||||
"כל הספרות מיוצגות על ידי תמונות בגווני אפור בגודל 28x28 פיקסלים.\n",
|
||||
"\n",
|
||||
"> מערך הנתונים MNIST זמין כתחרות אימון באתר [Kaggle](https://www.kaggle.com/c/digit-recognizer), אתר שמארח תחרויות ואתגרים בתחום למידת מכונה. לאחר שתלמדו כיצד לסווג את הספרות של MNIST, תוכלו להגיש את הפתרון שלכם ל-Kaggle ולראות כיצד הוא מדורג ביחס למשתתפים אחרים.\n",
|
||||
"> מאגר הנתונים MNIST זמין כתחרות אימון באתר [Kaggle](https://www.kaggle.com/c/digit-recognizer), אתר שמארח תחרויות ואתגרים בתחום למידת מכונה. לאחר שתלמדו כיצד לסווג את ספרות MNIST, תוכלו להגיש את הפתרון שלכם ל-Kaggle ולראות כיצד הוא מדורג בין המשתתפים האחרים.\n",
|
||||
"\n",
|
||||
"נתחיל בטעינת מערך הנתונים MNIST:\n"
|
||||
"נתחיל בטעינת מאגר הנתונים MNIST:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,7 +959,7 @@
|
|||
"source": [
|
||||
"שימו לב כיצד הדיוק עולה כמעט ל-100% במהירות רבה.\n",
|
||||
"\n",
|
||||
"אנא הזיזו את המחוון למיקום כלשהו לקראת סוף האימון, והתבוננו במטריצת המשקל המוצגת בצד שמאל. מטריצה זו תאפשר לכם להבין כיצד הפרספטרון עובד בפועל. תוכלו לראות ערכי משקל גבוהים במרכז השדה, אשר מתאימים לפיקסלים שמופיעים בדרך כלל עבור הספרה 1, וערכים שליליים נמוכים בצדדים, שם נמצאים חלקים של הספרה 0. כך שאם הספרה שמוצגת לפרספטרון היא אכן 1, החלק המרכזי שלה יוכפל בערכים גבוהים, מה שייצור תוצאה חיובית. לעומת זאת, כאשר הפרספטרון מזהה את הספרה 0, הפיקסלים המתאימים יוכפלו במספרים שליליים.\n",
|
||||
"אנא, הזיזו את המחוון למיקום כלשהו לקראת סוף האימון, והתבוננו במטריצת המשקל המוצגת בצד שמאל. מטריצה זו תאפשר לכם להבין כיצד הפרספטרון עובד בפועל. תוכלו לראות ערכי משקל גבוהים במרכז השדה, אשר מתאימים לפיקסלים שבדרך כלל מופיעים עבור הספרה 1, וערכים שליליים נמוכים בצדדים, שם נמצאים חלקים של הספרה 0. כך שאם הספרה המוצגת לפרספטרון היא למעשה 1, החלק המרכזי שלה יוכפל בערכים גבוהים, מה שייצור תוצאה חיובית. לעומת זאת, כאשר הפרספטרון מזהה את הספרה 0, הפיקסלים המתאימים יוכפלו במספרים שליליים.\n",
|
||||
"\n",
|
||||
"> ייתכן שתשימו לב שאם ניתן לפרספטרון ספרה 1 שמעט הוזזה אופקית, כך שהפיקסלים שלה תופסים את המקום שבו נמצאים החלקים האנכיים של הספרה 0, אנו עשויים לקבל תוצאה שגויה. מכיוון שטבעו של מאגר הנתונים MNIST הוא כזה שכל הספרות ממורכזות וממוקמות כראוי, והפרספטרון מסתמך על כך כדי להבחין בין הספרות.\n",
|
||||
"\n",
|
||||
|
|
@ -913,9 +1039,9 @@
|
|||
"source": [
|
||||
"## דיון\n",
|
||||
"\n",
|
||||
"מסיבה כלשהי, 2 ו-5 אינם ניתנים להפרדה בקלות. למרות שאנו מקבלים דיוק יחסית גבוה (מעל 85%), ניתן לראות בבירור כיצד ה-perceptron מפסיק ללמוד בשלב מסוים.\n",
|
||||
"מסיבה כלשהי, 2 ו-5 אינם ניתנים להפרדה בקלות. למרות שאנו מקבלים דיוק יחסית גבוה (מעל 85%), ניתן לראות בבירור כיצד הפרספטרון מפסיק ללמוד בשלב מסוים.\n",
|
||||
"\n",
|
||||
"כדי להבין מדוע זה קורה, נוכל לנסות להשתמש ב-[ניתוח רכיבים עיקריים](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). זו טכניקת למידת מכונה שמטרתה להקטין את הממדיות של מערך הנתונים הקלטי, באופן שמאפשר להשיג את ההפרדה הטובה ביותר בין הקטגוריות.\n",
|
||||
"כדי להבין מדוע זה קורה, נוכל לנסות להשתמש ב-[ניתוח רכיבים עיקריים](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). זו טכניקה בלמידת מכונה המשמשת להורדת הממדיות של מערך הנתונים הקלטי, באופן שמאפשר להשיג את ההפרדה הטובה ביותר בין הקטגוריות.\n",
|
||||
"\n",
|
||||
"במקרה שלנו, תמונת קלט מכילה 784 פיקסלים (תכונות קלט), ואנו רוצים להשתמש ב-PCA כדי לצמצם את מספר הפרמטרים לשניים בלבד, כך שנוכל לשרטט אותם על גרף. שני הפרמטרים הללו יהיו שילוב ליניארי של התכונות המקוריות, ואפשר לראות את התהליך הזה כ\"סיבוב\" של המרחב המקורי בעל 784 הממדים והתבוננות בהקרנה שלו למרחב דו-ממדי, עד שנקבל את התצוגה הטובה ביותר שמפרידה בין הקטגוריות.\n"
|
||||
]
|
||||
|
|
@ -1027,7 +1153,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"כפי שניתן לראות, ניתן להפריד בבירור בין 0 ל-1 באמצעות קו ישר. הדבר מצביע על כך שבמרחב המקורי בעל 784 הממדים, הנקודות המתאימות לספרות ניתנות גם להפרדה ליניארית. במקרה של 2 ו-5, לא ניתן למצוא הקרנה טובה שתפריד את הספרות בבירור, ולכן ישנם מקרים של סיווג שגוי.\n",
|
||||
"כפי שניתן לראות, ניתן להפריד בבירור בין 0 ל-1 באמצעות קו ישר. הדבר מצביע על כך שבמרחב המקורי בעל 784 הממדים, הנקודות המתאימות לספרות ניתנות להפרדה ליניארית. במקרה של 2 ו-5, לא ניתן למצוא את ההקרנה המתאימה שתפריד בבירור בין הספרות, ולכן ישנם מקרים של סיווג שגוי.\n",
|
||||
"\n",
|
||||
"> בהמשך הקורס נלמד כיצד ליצור מסווגים לא ליניאריים באמצעות רשתות נוירונים, וכיצד להתמודד עם בעיית ספרות שאינן מיושרות כראוי. בקרוב מאוד נגיע לדיוק של מעל 99% בסיווג ספרות MNIST, תוך סיווגן ל-10 קטגוריות שונות.\n",
|
||||
"\n",
|
||||
|
|
@ -1035,9 +1161,9 @@
|
|||
"\n",
|
||||
" * למדנו על הארכיטקטורה הפשוטה ביותר של רשת נוירונים - פרספטון בעל שכבה אחת.\n",
|
||||
" * יישמנו את הפרספטון \"בידיים\", באמצעות הליך אימון פשוט המבוסס על ירידת גרדיאנט.\n",
|
||||
" * למרות הפשטות, פרספטון בעל שכבה אחת יכול לפתור בעיות מורכבות יחסית של זיהוי ספרות בכתב יד.\n",
|
||||
" * למרות הפשטות, פרספטון בעל שכבה אחת יכול לפתור בעיות מורכבות יחסית של זיהוי ספרות כתובות ביד.\n",
|
||||
" * פרספטון בעל שכבה אחת הוא מסווג ליניארי, ולכן הוא מספק את אותה יכולת סיווג כמו רגרסיה לוגיסטית.\n",
|
||||
" * במרחב הדגימה, פרספטון יכול להפריד בין שתי קטגוריות של נתוני קלט באמצעות היפר-מישור.\n"
|
||||
" * במרחב הדוגמאות, פרספטון יכול להפריד בין שתי קטגוריות של נתוני קלט באמצעות היפר-מישור.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## קרדיטים\n",
|
||||
"\n",
|
||||
"מחברת זו היא חלק מ-[AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), והוכנה על ידי [דמיטרי סושניקוב](http://soshnikov.com). היא נוצרה בהשראת סדנת רשתות עצביות במרכז המחקר של מיקרוסופט בקיימברידג'. חלק מהקוד והחומרים האילוסטרטיביים נלקחו מתוך מצגות של [קטיה הופמן](https://www.microsoft.com/en-us/research/people/kahofman/), [מת'יו ג'ונסון](https://www.microsoft.com/en-us/research/people/matjoh/) ו-[ריוטו טומיוקה](https://www.microsoft.com/en-us/research/people/ryoto/), וכן ממאגר [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"מחברת זו היא חלק מ-[AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), והוכנה על ידי [דמיטרי סושניקוב](http://soshnikov.com). היא נוצרה בהשראת סדנת רשתות עצביות במרכז המחקר של מיקרוסופט בקיימברידג'. חלק מהקוד והחומרים האילוסטרטיביים נלקחו מתוך מצגות של [קטיה הופמן](https://www.microsoft.com/en-us/research/people/kahofman/), [מת'יו ג'ונסון](https://www.microsoft.com/en-us/research/people/matjoh/) ו-[ריוטו טומיוקה](https://www.microsoft.com/en-us/research/people/ryoto/), וכן מתוך מאגר [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**כתב ויתור**: \nמסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית [Co-op Translator](https://github.com/Azure/co-op-translator). למרות שאנו שואפים לדיוק, יש להיות מודעים לכך שתרגומים אוטומטיים עשויים להכיל שגיאות או אי-דיוקים. המסמך המקורי בשפתו המקורית צריך להיחשב כמקור הסמכותי. למידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי בני אדם. איננו אחראים לאי-הבנות או לפרשנויות שגויות הנובעות משימוש בתרגום זה.\n"
|
||||
"\n---\n\n**כתב ויתור**: \nמסמך זה תורגם באמצעות שירות תרגום AI [Co-op Translator](https://github.com/Azure/co-op-translator). למרות שאנו שואפים לדיוק, יש להיות מודעים לכך שתרגומים אוטומטיים עשויים להכיל שגיאות או אי דיוקים. המסמך המקורי בשפתו המקורית צריך להיחשב כמקור סמכותי. עבור מידע קריטי, מומלץ להשתמש בתרגום מקצועי אנושי. איננו אחראים לאי הבנות או לפרשנויות שגויות הנובעות משימוש בתרגום זה.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:35:39+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:23:24+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "he"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,11 +47,11 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## टॉय प्रॉब्लम\n",
|
||||
"## खिलौना समस्या\n",
|
||||
"\n",
|
||||
"शुरुआत करने के लिए, चलिए एक टॉय प्रॉब्लम से शुरू करते हैं, जहां हमारे पास दो इनपुट फीचर्स हैं। उदाहरण के लिए, चिकित्सा में हम ट्यूमर को उसके आकार और उम्र के आधार पर सौम्य और घातक में वर्गीकृत करना चाह सकते हैं।\n",
|
||||
"शुरुआत करने के लिए, चलिए एक खिलौना समस्या से शुरू करते हैं, जहां हमारे पास दो इनपुट विशेषताएँ हैं। उदाहरण के लिए, चिकित्सा में हम ट्यूमर को उसके आकार और उम्र के आधार पर सौम्य और घातक में वर्गीकृत करना चाह सकते हैं।\n",
|
||||
"\n",
|
||||
"हम SciKit Learn लाइब्रेरी के `make_classification` फंक्शन का उपयोग करके एक रैंडम क्लासिफिकेशन डेटासेट बनाएंगे:\n"
|
||||
"हम SciKit Learn लाइब्रेरी के `make_classification` फ़ंक्शन का उपयोग करके एक रैंडम वर्गीकरण डेटासेट बनाएंगे:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,11 +154,11 @@
|
|||
"source": [
|
||||
"## परसेप्ट्रॉन\n",
|
||||
"\n",
|
||||
"चूंकि परसेप्ट्रॉन एक द्विआधारी वर्गीकरणकर्ता है, प्रत्येक इनपुट वेक्टर $x$ के लिए हमारे परसेप्ट्रॉन का आउटपुट या तो +1 होगा या -1, यह वर्ग पर निर्भर करता है। आउटपुट निम्नलिखित सूत्र का उपयोग करके गणना किया जाएगा:\n",
|
||||
"चूंकि परसेप्ट्रॉन एक बाइनरी वर्गीकरणकर्ता है, प्रत्येक इनपुट वेक्टर $x$ के लिए हमारे परसेप्ट्रॉन का आउटपुट या तो +1 होगा या -1, यह वर्ग पर निर्भर करता है। आउटपुट निम्नलिखित सूत्र का उपयोग करके गणना किया जाएगा:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"जहां $\\mathbf{w}$ एक वेट वेक्टर है, और $f$ एक स्टेप एक्टिवेशन फ़ंक्शन है:\n",
|
||||
"जहां $\\mathbf{w}$ एक वेट वेक्टर है, $f$ एक स्टेप एक्टिवेशन फ़ंक्शन है:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"हालांकि, एक सामान्य रैखिक मॉडल में बायस भी होना चाहिए, यानी आदर्श रूप से हमें $y$ को $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ के रूप में गणना करनी चाहिए। हमारे मॉडल को सरल बनाने के लिए, हम इस बायस टर्म को हटा सकते हैं और अपनी इनपुट विशेषताओं में एक और आयाम जोड़ सकते हैं, जो हमेशा 1 के बराबर होता है:\n"
|
||||
"हालांकि, एक सामान्य रैखिक मॉडल में एक बायस भी होना चाहिए, यानी आदर्श रूप से हमें $y$ को $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ के रूप में गणना करनी चाहिए। हमारे मॉडल को सरल बनाने के लिए, हम अपने इनपुट फीचर्स में एक और आयाम जोड़कर इस बायस टर्म को हटा सकते हैं, जो हमेशा 1 के बराबर होता है:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -204,7 +204,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## प्रशिक्षण एल्गोरिथ्म\n",
|
||||
"## प्रशिक्षण एल्गोरिदम\n",
|
||||
"\n",
|
||||
"परसेप्ट्रॉन को प्रशिक्षित करने के लिए, हमें ऐसे वज़न $\\mathbf{w}$ खोजने होंगे जो त्रुटि को न्यूनतम करें। त्रुटि को **परसेप्ट्रॉन मानदंड** का उपयोग करके परिभाषित किया गया है:\n",
|
||||
"\n",
|
||||
|
|
@ -219,7 +219,7 @@
|
|||
"\n",
|
||||
"जहां $\\eta$ एक **लर्निंग रेट** है, और $\\tau\\in\\mathbb{N}$ - पुनरावृत्ति की संख्या।\n",
|
||||
"\n",
|
||||
"आइए इस एल्गोरिथ्म को Python में परिभाषित करें:\n"
|
||||
"आइए इस एल्गोरिदम को Python में परिभाषित करें:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**लर्निंग रेट पर नोट**: `learning_rate` पैरामीटर (डिफ़ॉल्ट `0.01`) यह नियंत्रित करता है कि प्रत्येक प्रशिक्षण चरण के दौरान वज़न को कितना समायोजित किया जाए। यह ग्रेडिएंट डिसेंट अपडेट फॉर्मूला को लागू करता है:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- बड़ा लर्निंग रेट (जैसे, `1.0`) परसेप्ट्रॉन को तेज़ी से सीखने में मदद करता है लेकिन यह आदर्श समाधान को पार कर सकता है\n",
|
||||
"- छोटा लर्निंग रेट (जैसे, `0.001`) धीरे-धीरे सीखता है लेकिन अधिक सटीकता से अभिसरण कर सकता है\n",
|
||||
"- आप इसे आज़माने के लिए कॉल कर सकते हैं: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"जैसा कि आप देख सकते हैं, प्रारंभिक सटीकता लगभग 50% है, लेकिन यह जल्दी ही बढ़कर लगभग 90% के करीब हो जाती है।\n",
|
||||
"जैसा कि आप देख सकते हैं, प्रारंभिक सटीकता लगभग 50% है, लेकिन यह जल्दी ही बढ़कर 90% के करीब उच्च मानों तक पहुंच जाती है।\n",
|
||||
"\n",
|
||||
"आइए देखें कि वर्गों को कैसे अलग किया गया है। हमारा वर्गीकरण फ़ंक्शन $\\mathbf{w}^Tx$ जैसा दिखता है, और यह एक वर्ग के लिए 0 से अधिक है, जबकि दूसरे वर्ग के लिए 0 से कम है। इसलिए, वर्ग अलगाव रेखा $\\mathbf{w}^Tx = 0$ द्वारा परिभाषित होती है। चूंकि हमारे पास केवल दो आयाम $x_0$ और $x_1$ हैं, रेखा के लिए समीकरण $w_0x_0+w_1x_1+w_2 = 0$ होगा (याद रखें कि हमने स्पष्ट रूप से एक अतिरिक्त आयाम $x_2=1$ परिभाषित किया है)। आइए इस रेखा को प्लॉट करें:\n"
|
||||
"आइए देखें कि वर्ग कैसे अलग होते हैं। हमारा वर्गीकरण फ़ंक्शन $\\mathbf{w}^Tx$ जैसा दिखता है, और यह एक वर्ग के लिए 0 से अधिक होता है, और दूसरे के लिए 0 से कम। इस प्रकार, वर्ग अलगाव रेखा $\\mathbf{w}^Tx = 0$ द्वारा परिभाषित होती है। चूंकि हमारे पास केवल दो आयाम $x_0$ और $x_1$ हैं, रेखा का समीकरण $w_0x_0+w_1x_1+w_2 = 0$ होगा (याद रखें कि हमने स्पष्ट रूप से एक अतिरिक्त आयाम $x_2=1$ परिभाषित किया है)। आइए इस रेखा को प्लॉट करें:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## सीखने की दरों के साथ प्रयोग करना\n",
|
||||
"\n",
|
||||
"अब आइए देखें कि विभिन्न सीखने की दरें प्रशिक्षण प्रक्रिया को कैसे प्रभावित करती हैं। सीखने की दर ग्रेडिएंट डिसेंट में कदम के आकार को नियंत्रित करती है - एक महत्वपूर्ण हाइपरपैरामीटर जो अभिसरण गति और स्थिरता दोनों को प्रभावित करता है।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### इंटरएक्टिव लर्निंग रेट प्रयोग\n",
|
||||
"\n",
|
||||
"नीचे दिए गए स्लाइडर का उपयोग करके विभिन्न लर्निंग रेट के साथ इंटरएक्टिव रूप से प्रयोग करें और देखें कि वे निर्णय सीमा को कैसे प्रभावित करते हैं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## परीक्षण डेटा सेट पर मूल्यांकन करें\n",
|
||||
"\n",
|
||||
"शुरुआत में, हमने कुछ डेटा को परीक्षण डेटा सेट के लिए अलग रखा था। आइए देखें कि हमारा वर्गीकरणकर्ता इस परीक्षण डेटा सेट पर कितना सटीक है। ऐसा करने के लिए, हम परीक्षण डेटा सेट में एक अतिरिक्त आयाम जोड़ते हैं, वज़न मैट्रिक्स से गुणा करते हैं, और सुनिश्चित करते हैं कि प्राप्त मान लेबल (+1 या -1) के समान चिह्न का हो। इसके बाद, हम सभी बूलियन मानों को जोड़ते हैं और परीक्षण नमूने की लंबाई से विभाजित करते हैं, ताकि सटीकता प्राप्त की जा सके:\n"
|
||||
"शुरुआत में, हमने कुछ डेटा को परीक्षण डेटा सेट के लिए अलग रखा था। आइए देखें कि हमारा वर्गीकरणकर्ता इस परीक्षण डेटा सेट पर कितना सटीक है। ऐसा करने के लिए, हम परीक्षण डेटा सेट को एक अतिरिक्त आयाम के साथ विस्तारित करते हैं, वज़न मैट्रिक्स से गुणा करते हैं, और सुनिश्चित करते हैं कि प्राप्त मान लेबल (+1 या -1) के समान चिह्न का हो। इसके बाद, हम सभी बूलियन मानों को जोड़ते हैं और परीक्षण नमूने की लंबाई से विभाजित करते हैं, ताकि सटीकता प्राप्त की जा सके:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## प्रशिक्षण प्रक्रिया का अवलोकन\n",
|
||||
"\n",
|
||||
"हमने पहले देखा है कि प्रशिक्षण के दौरान सटीकता कैसे घटती है। यह देखना अच्छा होगा कि प्रशिक्षण के दौरान विभाजन रेखा कैसे व्यवहार करती है। नीचे दिया गया कोड सब कुछ एक ग्राफ पर प्रदर्शित करेगा, और आपको स्लाइडर को स्थानांतरित करके प्रशिक्षण प्रक्रिया के माध्यम से \"समय यात्रा\" करने में सक्षम होना चाहिए।\n"
|
||||
"हमने पहले देखा है कि प्रशिक्षण के दौरान सटीकता कैसे घटती है। यह देखना अच्छा होगा कि प्रशिक्षण के दौरान विभाजन रेखा कैसे व्यवहार करती है। नीचे दिया गया कोड सब कुछ एक ग्राफ पर प्रदर्शित करेगा, और आपको स्लाइडर को स्थानांतरित करके प्रशिक्षण प्रक्रिया में \"समय यात्रा\" करने में सक्षम होना चाहिए।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -531,14 +657,14 @@
|
|||
"\n",
|
||||
"जैसा कि आपने ऊपर देखा, परसेप्ट्रॉन एक **रेखीय वर्गीकरणकर्ता** है। यह दो वर्गों के बीच अच्छी तरह से अंतर कर सकता है यदि वे **रेखीय रूप से पृथक** हों, यानी उन्हें एक सीधी रेखा द्वारा अलग किया जा सके। अन्यथा, परसेप्ट्रॉन प्रशिक्षण प्रक्रिया अभिसरण नहीं करेगी।\n",
|
||||
"\n",
|
||||
"एक सबसे स्पष्ट उदाहरण, जिसे परसेप्ट्रॉन हल नहीं कर सकता, वह है **XOR समस्या**। हम चाहते हैं कि हमारा परसेप्ट्रॉन XOR बूलियन फ़ंक्शन सीखे, जिसका निम्नलिखित सत्य सारणी है:\n",
|
||||
"एक सबसे स्पष्ट उदाहरण जो परसेप्ट्रॉन द्वारा हल नहीं किया जा सकता है, वह है **XOR समस्या**। हम चाहते हैं कि हमारा परसेप्ट्रॉन XOR बूलियन फ़ंक्शन सीखे, जिसका निम्नलिखित सत्य सारणी है:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"आइए इसे आजमाते हैं! हम सभी सकारात्मक और नकारात्मक प्रशिक्षण नमूनों को मैन्युअल रूप से भरेंगे, और फिर ऊपर परिभाषित हमारी ट्रेन फ़ंक्शन को कॉल करेंगे:\n"
|
||||
"आइए इसे आजमाते हैं! हम सभी सकारात्मक और नकारात्मक प्रशिक्षण नमूनों को मैन्युअल रूप से भरेंगे, और फिर ऊपर परिभाषित हमारे train फ़ंक्शन को कॉल करेंगे:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -607,13 +733,13 @@
|
|||
"source": [
|
||||
"जैसा कि आप ऊपर दिए गए ग्राफ से देख सकते हैं, सटीकता कभी 75% से ऊपर नहीं जाती, क्योंकि सभी संभावित उदाहरणों को सही तरीके से प्राप्त करने के लिए एक सीधी रेखा खींचना असंभव है।\n",
|
||||
"\n",
|
||||
"XOR समस्या परसेप्ट्रॉन की सीमाओं का एक क्लासिकल उदाहरण है, और इसे 1969 में मार्विन मिंस्की और सीमोर पैपर्ट ने अपनी पुस्तक [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) में बताया था। इस अवलोकन ने लगभग 10 वर्षों तक न्यूरल नेटवर्क के क्षेत्र में शोध को सीमित कर दिया, हालांकि - और हम इसे अपने पाठ्यक्रम के अगले भाग में देखेंगे - मल्टी-लेयर्ड परसेप्ट्रॉन ऐसी समस्याओं को हल करने में पूरी तरह सक्षम हैं।\n",
|
||||
"XOR समस्या परसेप्ट्रॉन की सीमाओं का एक क्लासिकल उदाहरण है, और इसे 1969 में मार्विन मिंस्की और सीमोर पेपर्ट ने अपनी किताब [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) में बताया था। इस अवलोकन ने लगभग 10 वर्षों तक न्यूरल नेटवर्क के क्षेत्र में शोध को सीमित कर दिया, हालांकि - और हम इसे अपने कोर्स के अगले भाग में देखेंगे - मल्टी-लेयर्ड परसेप्ट्रॉन ऐसी समस्याओं को हल करने में पूरी तरह सक्षम हैं।\n",
|
||||
"\n",
|
||||
"## जटिल उदाहरण - MNIST\n",
|
||||
"\n",
|
||||
"हालांकि परसेप्ट्रॉन XOR समस्या को हल नहीं कर सकता, यह कई अधिक जटिल समस्याओं को हल कर सकता है, जैसे हस्तलिखित अक्षरों की पहचान।\n",
|
||||
"हालांकि परसेप्ट्रॉन XOR समस्या को हल नहीं कर सकता, यह कई और जटिल समस्याओं को हल कर सकता है, जैसे हस्तलिखित अक्षरों की पहचान।\n",
|
||||
"\n",
|
||||
"मशीन लर्निंग में महारत हासिल करने के दौरान अक्सर उपयोग किया जाने वाला एक डेटासेट [MNIST](https://en.wikipedia.org/wiki/MNIST_database) कहलाता है। इसे Modified National Institute of Standards and Technology द्वारा बनाया गया है, और इसमें 60000 हस्तलिखित अंकों का एक प्रशिक्षण सेट शामिल है, जो लगभग 250 छात्रों और संस्थान के कर्मचारियों से एकत्र किया गया है। इसके अलावा, इसमें 10000 अंकों का एक परीक्षण डेटासेट भी है, जो विभिन्न व्यक्तियों से एकत्र किया गया है।\n",
|
||||
"मशीन लर्निंग में महारत हासिल करने के दौरान अक्सर उपयोग किया जाने वाला एक डेटासेट [MNIST](https://en.wikipedia.org/wiki/MNIST_database) कहलाता है। इसे Modified National Institute of Standards and Technology द्वारा बनाया गया है और इसमें 60000 हस्तलिखित अंकों का प्रशिक्षण सेट है, जो लगभग 250 छात्रों और संस्थान के कर्मचारियों से एकत्रित किया गया है। इसके अलावा, इसमें 10000 अंकों का परीक्षण डेटासेट भी है, जो अलग-अलग व्यक्तियों से एकत्रित किया गया है।\n",
|
||||
"\n",
|
||||
"सभी अंक 28x28 पिक्सल के ग्रेस्केल इमेज के रूप में प्रस्तुत किए गए हैं।\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"क्योंकि परसेप्ट्रॉन एक द्विआधारी वर्गीकरणकर्ता है, हम अपनी समस्या को केवल दो अंकों को पहचानने तक सीमित करेंगे। नीचे दिया गया फ़ंक्शन दो दिए गए अंकों के साथ सकारात्मक और नकारात्मक नमूना सरणियों को भर देगा (और स्पष्टता के लिए उन अंकों के नमूने भी दिखाएगा)।\n"
|
||||
"क्योंकि परसेप्ट्रॉन एक द्विआधारी वर्गीकरणकर्ता है, हम अपनी समस्या को केवल दो अंकों को पहचानने तक सीमित करेंगे। नीचे दिया गया फ़ंक्शन दो दिए गए अंकों के साथ सकारात्मक और नकारात्मक नमूना ऐरे को भर देगा (और स्पष्टता के लिए उन अंकों के नमूने भी दिखाएगा)।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"कृपया ध्यान दें कि सटीकता बहुत तेजी से लगभग 100% तक पहुँच जाती है।\n",
|
||||
"\n",
|
||||
"कृपया, प्रशिक्षण के अंत की ओर स्लाइडर को किसी स्थिति पर ले जाएँ और बाईं ओर प्लॉट किए गए वज़न मैट्रिक्स को देखें। यह मैट्रिक्स आपको समझने में मदद करेगा कि परसेप्ट्रॉन वास्तव में कैसे काम करता है। आप देख सकते हैं कि क्षेत्र के मध्य में वज़न मान अधिक हैं, जो उन पिक्सल्स से मेल खाते हैं जो आमतौर पर अंक 1 के लिए मौजूद होते हैं, और किनारों पर नकारात्मक मान कम हैं, जहाँ अंक 0 के हिस्से होते हैं। तो, यदि परसेप्ट्रॉन को प्रस्तुत किया गया अंक वास्तव में 1 है, तो इसका मध्य भाग उच्च मानों से गुणा किया जाएगा, जिससे सकारात्मक परिणाम उत्पन्न होगा। इसके विपरीत, जब परसेप्ट्रॉन 0 को देखता है, तो संबंधित पिक्सल्स नकारात्मक संख्याओं से गुणा किए जाएँगे।\n",
|
||||
"कृपया, प्रशिक्षण के अंत की ओर स्लाइडर को किसी स्थिति पर ले जाएँ और बाईं ओर प्लॉट किए गए वज़न मैट्रिक्स को देखें। यह मैट्रिक्स आपको समझने में मदद करेगा कि परसेप्ट्रॉन वास्तव में कैसे काम करता है। आप देख सकते हैं कि क्षेत्र के बीच में उच्च वज़न मान हैं, जो उन पिक्सल्स से मेल खाते हैं जो आमतौर पर अंक 1 के लिए मौजूद होते हैं, और किनारों पर निम्न नकारात्मक मान हैं, जहाँ अंक 0 के हिस्से होते हैं। तो, यदि परसेप्ट्रॉन को प्रस्तुत किया गया अंक वास्तव में 1 है, तो इसका मध्य भाग उच्च मानों से गुणा किया जाएगा, जिससे सकारात्मक परिणाम उत्पन्न होगा। इसके विपरीत, जब परसेप्ट्रॉन 0 देखता है, तो संबंधित पिक्सल्स नकारात्मक संख्याओं से गुणा किए जाएँगे।\n",
|
||||
"\n",
|
||||
"> आप देख सकते हैं कि यदि हम अपने परसेप्ट्रॉन को अंक 1 थोड़ा क्षैतिज रूप से स्थानांतरित करके देते हैं, ताकि इसके पिक्सल्स उस स्थान पर आ जाएँ जहाँ 0 के ऊर्ध्वाधर भाग होते हैं, तो हमें गलत परिणाम मिल सकता है। चूँकि हमारे MNIST डेटासेट की प्रकृति ऐसी है कि सभी अंक केंद्रित और सही तरीके से स्थित होते हैं, और परसेप्ट्रॉन इसी पर निर्भर करता है ताकि अंकों के बीच अंतर कर सके।\n",
|
||||
"> आप देख सकते हैं कि यदि हम अपने परसेप्ट्रॉन को अंक 1 देते हैं जो क्षैतिज रूप से थोड़ा खिसका हुआ है, ताकि इसके पिक्सल्स उस स्थान पर आ जाएँ जहाँ 0 के ऊर्ध्वाधर हिस्से होते हैं, तो हमें गलत परिणाम मिल सकता है। चूँकि हमारे MNIST डेटासेट की प्रकृति ऐसी है कि सभी अंक केंद्रित और सही तरीके से स्थित होते हैं, और परसेप्ट्रॉन इसी पर निर्भर करता है कि वह अंकों के बीच अंतर कर सके।\n",
|
||||
"\n",
|
||||
"अब चलिए अलग-अलग अंकों को आज़माते हैं:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## चर्चा\n",
|
||||
"\n",
|
||||
"किसी कारणवश, 2 और 5 को आसानी से अलग करना मुश्किल होता है। भले ही हमें अपेक्षाकृत उच्च सटीकता (85% से अधिक) प्राप्त होती है, हम स्पष्ट रूप से देख सकते हैं कि कैसे परसेप्ट्रॉन एक बिंदु पर सीखना बंद कर देता है।\n",
|
||||
"किसी कारणवश, 2 और 5 को आसानी से अलग करना मुश्किल हो रहा है। भले ही हमें अपेक्षाकृत उच्च सटीकता (85% से अधिक) मिल रही है, हम स्पष्ट रूप से देख सकते हैं कि किसी बिंदु पर perceptron सीखना बंद कर देता है।\n",
|
||||
"\n",
|
||||
"यह समझने के लिए कि ऐसा क्यों होता है, हम [प्रिंसिपल कंपोनेंट एनालिसिस](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) का उपयोग कर सकते हैं। यह एक मशीन लर्निंग तकनीक है जिसका उपयोग इनपुट डेटा सेट की आयाम संख्या को कम करने के लिए किया जाता है, ताकि वर्गों के बीच सर्वोत्तम विभाजन प्राप्त किया जा सके।\n",
|
||||
"यह समझने के लिए कि ऐसा क्यों हो रहा है, हम [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) का उपयोग कर सकते हैं। यह एक मशीन लर्निंग तकनीक है जिसका उपयोग इनपुट डेटा सेट की आयाम संख्या को कम करने के लिए किया जाता है, ताकि वर्गों के बीच सर्वोत्तम अलगाव प्राप्त किया जा सके।\n",
|
||||
"\n",
|
||||
"हमारे मामले में, एक इनपुट इमेज में 784 पिक्सल (इनपुट फीचर्स) होते हैं, और हम PCA का उपयोग करके पैरामीटर की संख्या को केवल 2 तक कम करना चाहते हैं, ताकि हम उन्हें ग्राफ पर प्लॉट कर सकें। ये दो पैरामीटर मूल फीचर्स का एक रैखिक संयोजन होंगे, और हम इस प्रक्रिया को इस प्रकार देख सकते हैं कि हमारे मूल 784-आयामी स्थान को \"घुमाकर\" उसकी प्रोजेक्शन को 2D-स्थान में देखा जाए, जब तक कि हमें वर्गों को अलग करने के लिए सबसे अच्छा दृश्य न मिल जाए।\n"
|
||||
"हमारे मामले में, एक इनपुट इमेज में 784 पिक्सल (इनपुट फीचर्स) होते हैं, और हम PCA का उपयोग करके पैरामीटर की संख्या को केवल 2 तक कम करना चाहते हैं, ताकि हम उन्हें ग्राफ पर प्लॉट कर सकें। ये दो पैरामीटर मूल फीचर्स का एक रैखिक संयोजन होंगे, और हम इस प्रक्रिया को इस तरह देख सकते हैं जैसे कि हम अपने मूल 784-आयामी स्थान को \"घुमा\" रहे हैं और इसे 2D-स्थान पर प्रोजेक्ट कर रहे हैं, जब तक कि हमें वर्गों को अलग करने के लिए सबसे अच्छा दृश्य न मिल जाए।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,15 +1155,15 @@
|
|||
"source": [
|
||||
"जैसा कि आप देख सकते हैं, 0 और 1 को एक सीधी रेखा द्वारा स्पष्ट रूप से अलग किया जा सकता है। यह दर्शाता है कि मूल 784-डायमेंशनल स्पेस में अंकों से संबंधित बिंदु भी रेखीय रूप से अलग किए जा सकते हैं। लेकिन 2 और 5 के मामले में, हम ऐसा अच्छा प्रोजेक्शन नहीं ढूंढ सकते जो अंकों को स्पष्ट रूप से अलग कर सके, और इसलिए कुछ गलत वर्गीकरण के मामले सामने आते हैं।\n",
|
||||
"\n",
|
||||
"> इस कोर्स में आगे हम सीखेंगे कि नॉन-लिनियर क्लासिफायर कैसे बनाएं, जैसे कि Neural Networks का उपयोग करके, और उन समस्याओं से कैसे निपटें जहां अंक सही तरीके से संरेखित नहीं होते। बहुत जल्द हम MNIST अंकों की पहचान में 99% से अधिक सटीकता प्राप्त करेंगे, जबकि उन्हें 10 अलग-अलग वर्गों में वर्गीकृत करेंगे।\n",
|
||||
"> इस कोर्स में आगे हम सीखेंगे कि कैसे नॉन-लिनियर क्लासिफायर बनाएं, जैसे कि Neural Networks का उपयोग करके, और उन समस्याओं से निपटें जहां अंक सही तरीके से संरेखित नहीं होते। बहुत जल्द हम MNIST अंकों की पहचान में 99% से अधिक सटीकता प्राप्त करेंगे, जबकि उन्हें 10 अलग-अलग वर्गों में वर्गीकृत करेंगे।\n",
|
||||
"\n",
|
||||
"## मुख्य बातें\n",
|
||||
"\n",
|
||||
" * हमने सबसे सरल Neural Network आर्किटेक्चर - एक-लेयर परसेप्ट्रॉन के बारे में सीखा।\n",
|
||||
" * हमने परसेप्ट्रॉन को \"हाथ से\" लागू किया, जिसमें ग्रेडिएंट डीसेंट पर आधारित एक सरल प्रशिक्षण प्रक्रिया का उपयोग किया गया।\n",
|
||||
" * हमने सबसे सरल न्यूरल नेटवर्क आर्किटेक्चर - एक-लेयर परसेप्ट्रॉन के बारे में सीखा।\n",
|
||||
" * हमने परसेप्ट्रॉन को \"हाथ से\" लागू किया, जिसमें ग्रेडिएंट डीसेंट पर आधारित एक सरल प्रशिक्षण प्रक्रिया का उपयोग किया।\n",
|
||||
" * सरलता के बावजूद, एक-लेयर परसेप्ट्रॉन हस्तलिखित अंकों की पहचान जैसी जटिल समस्याओं को हल कर सकता है।\n",
|
||||
" * एक-लेयर परसेप्ट्रॉन एक रेखीय क्लासिफायर है, और इसलिए यह लॉजिस्टिक रिग्रेशन के समान वर्गीकरण क्षमता प्रदान करता है।\n",
|
||||
" * सैंपल स्पेस में, परसेप्ट्रॉन हाइपरप्लेन का उपयोग करके इनपुट डेटा के दो वर्गों को अलग कर सकता है।\n"
|
||||
" * सैंपल स्पेस में, परसेप्ट्रॉन इनपुट डेटा के दो वर्गों को हाइपरप्लेन का उपयोग करके अलग कर सकता है।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## क्रेडिट्स\n",
|
||||
"\n",
|
||||
"यह नोटबुक [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) का हिस्सा है और इसे [Dmitry Soshnikov](http://soshnikov.com) द्वारा तैयार किया गया है। यह Microsoft Research Cambridge में आयोजित Neural Network Workshop से प्रेरित है। कुछ कोड और चित्रात्मक सामग्री [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) और [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) की प्रस्तुतियों से ली गई हैं, और [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) रिपॉजिटरी से भी।\n"
|
||||
"यह नोटबुक [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) का हिस्सा है और इसे [Dmitry Soshnikov](http://soshnikov.com) द्वारा तैयार किया गया है। यह Microsoft Research Cambridge में आयोजित Neural Network Workshop से प्रेरित है। कुछ कोड और चित्रात्मक सामग्री [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) और [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) की प्रस्तुतियों से ली गई है, और [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) रिपॉजिटरी से भी।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**अस्वीकरण**: \nयह दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) का उपयोग करके अनुवादित किया गया है। जबकि हम सटीकता सुनिश्चित करने का प्रयास करते हैं, कृपया ध्यान दें कि स्वचालित अनुवाद में त्रुटियां या अशुद्धियां हो सकती हैं। मूल भाषा में उपलब्ध मूल दस्तावेज़ को आधिकारिक स्रोत माना जाना चाहिए। महत्वपूर्ण जानकारी के लिए, पेशेवर मानव अनुवाद की सिफारिश की जाती है। इस अनुवाद के उपयोग से उत्पन्न किसी भी गलतफहमी या गलत व्याख्या के लिए हम उत्तरदायी नहीं हैं।\n"
|
||||
"\n---\n\n**अस्वीकरण**: \nयह दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) का उपयोग करके अनुवादित किया गया है। जबकि हम सटीकता सुनिश्चित करने का प्रयास करते हैं, कृपया ध्यान दें कि स्वचालित अनुवाद में त्रुटियां या अशुद्धियां हो सकती हैं। मूल भाषा में उपलब्ध मूल दस्तावेज़ को प्रामाणिक स्रोत माना जाना चाहिए। महत्वपूर्ण जानकारी के लिए, पेशेवर मानव अनुवाद की सिफारिश की जाती है। इस अनुवाद के उपयोग से उत्पन्न किसी भी गलतफहमी या गलत व्याख्या के लिए हम उत्तरदायी नहीं हैं।\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:18:42+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:05:04+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "hi"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"source": [
|
||||
"## 感知器\n",
|
||||
"\n",
|
||||
"> 此筆記本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分。請訪問該存儲庫以獲取完整的學習材料。\n",
|
||||
"> 此筆記本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分。請訪問該倉庫以獲取完整的學習材料。\n",
|
||||
"\n",
|
||||
"如我們所討論的,感知器可以用來解決**二元分類問題**,即將輸入範例分類為兩個類別——我們可以稱它們為**正類**和**負類**。\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"然而,一般的線性模型應該也包含一個偏置項,即理想情況下我們應該計算 $y$ 為 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$。為了簡化模型,我們可以通過在輸入特徵中添加一個始終等於 1 的維度來消除這個偏置項:\n"
|
||||
"然而,一般的線性模型應該也包含一個偏置項,也就是說,理論上我們應該計算 $y$ 為 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$。為了簡化模型,我們可以通過在輸入特徵中添加一個始終等於 1 的維度來去除這個偏置項:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -206,18 +206,18 @@
|
|||
"source": [
|
||||
"## 訓練算法\n",
|
||||
"\n",
|
||||
"為了訓練感知器,我們需要找出權重 $\\mathbf{w}$,以最小化錯誤。錯誤是通過 **感知器準則** 定義的:\n",
|
||||
"為了訓練感知器,我們需要找到能最小化誤差的權重 $\\mathbf{w}$。誤差是使用 **感知器準則** 定義的:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ 分別代表負樣本和正樣本的標籤\n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ 分別代表負樣本和正樣本\n",
|
||||
" * $\\mathcal{M}$ - 錯誤分類的樣本集合\n",
|
||||
" \n",
|
||||
"我們將使用 **梯度下降** 的方法。從某些初始隨機權重 $\\mathbf{w}^{(0)}$ 開始,我們會在每次訓練步驟中根據 $E$ 的梯度來調整權重:\n",
|
||||
"我們將使用 **梯度下降** 的方法。從某些初始隨機權重 $\\mathbf{w}^{(0)}$ 開始,我們將在訓練的每一步通過誤差 $E$ 的梯度來調整權重:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"其中 $\\eta$ 是 **學習率**,而 $\\tau\\in\\mathbb{N}$ 則是迭代次數。\n",
|
||||
"其中 $\\eta$ 是 **學習率**,$\\tau\\in\\mathbb{N}$ - 迭代次數。\n",
|
||||
"\n",
|
||||
"以下是用 Python 定義此算法:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**學習率的注意事項**: `learning_rate` 參數(預設值為 `0.01`)控制每次訓練步驟中調整權重的幅度。這實現了梯度下降更新公式:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- 較大的學習率(例如 `1.0`)會使感知器學習速度更快,但可能會超出最佳解\n",
|
||||
"- 較小的學習率(例如 `0.001`)學習速度較慢,但可能更精確地收斂\n",
|
||||
"- 你可以通過以下方式進行嘗試:`train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"如你所見,初始準確率約為 50%,但很快就提升至接近 90% 的高值。\n",
|
||||
"\n",
|
||||
"現在讓我們來看看類別是如何分隔的。我們的分類函數形式為 $\\mathbf{w}^Tx$,對於其中一個類別,其值大於 0;而對於另一個類別,其值則小於 0。因此,類別分隔線由 $\\mathbf{w}^Tx = 0$ 定義。由於我們只有兩個維度 $x_0$ 和 $x_1$,該線的方程式為 $w_0x_0+w_1x_1+w_2 = 0$(記得我們已明確定義了一個額外的維度 $x_2=1$)。現在讓我們繪製這條線:\n"
|
||||
"現在讓我們來視覺化類別的分隔情況。我們的分類函數形式為 $\\mathbf{w}^Tx$,對於其中一個類別,其值大於 0,而對於另一個類別,其值則小於 0。因此,類別分隔線由 $\\mathbf{w}^Tx = 0$ 定義。由於我們只有兩個維度 $x_0$ 和 $x_1$,該線的方程式為 $w_0x_0+w_1x_1+w_2 = 0$(請記住,我們已明確定義了一個額外的維度 $x_2=1$)。現在讓我們繪製這條線:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 探索學習率\n",
|
||||
"\n",
|
||||
"現在讓我們來研究不同的學習率如何影響訓練過程。學習率控制梯度下降中的步伐大小——這是一個重要的超參數,影響收斂速度和穩定性。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 互動式學習率實驗\n",
|
||||
"\n",
|
||||
"使用下面的滑桿,互動式地嘗試不同的學習率,並觀察它們如何影響決策邊界:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## 在測試數據集上進行評估\n",
|
||||
"\n",
|
||||
"一開始,我們已經將部分數據分配到測試數據集中。現在來看看我們的分類器在這個測試數據集上的準確度如何。為了做到這一點,我們需要將測試數據集擴展一個額外的維度,乘上權重矩陣,並確保得到的值與標籤的符號一致(+1 或 -1)。接著,我們將所有布爾值相加,並除以測試樣本的長度,從而得到準確度:\n"
|
||||
"一開始,我們已經將部分數據分配到測試數據集。現在來看看我們的分類器在這個測試數據集上的準確度如何。為了做到這一點,我們需要將測試數據集擴展一個額外的維度,乘上權重矩陣,並確保得到的值與標籤的符號一致(+1 或 -1)。接著,我們將所有布林值相加,並除以測試樣本的長度,從而得到準確度:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## 觀察訓練過程\n",
|
||||
"\n",
|
||||
"我們之前已經看到,準確率在訓練過程中會下降。能夠觀察分隔線在訓練過程中的變化會很有趣。以下的程式碼將把所有內容可視化在一個圖表上,您可以通過移動滑塊來「時光旅行」查看訓練過程中的變化。\n"
|
||||
"我們之前已經看到,準確率在訓練過程中會下降。能夠觀察分隔線在訓練過程中的變化會很有趣。以下的程式碼將把所有內容可視化在一個圖表上,並且你可以移動滑桿來「時光穿梭」查看訓練過程中的不同階段。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -531,7 +657,7 @@
|
|||
"\n",
|
||||
"如上所述,感知器是一種**線性分類器**。如果兩個類別是**線性可分**的,也就是可以用一條直線分開,那麼感知器可以很好地區分它們。否則,感知器的訓練過程將無法收斂。\n",
|
||||
"\n",
|
||||
"一個最明顯的例子是感知器無法解決的問題,即所謂的**XOR問題**。我們希望感知器能學習 XOR 布爾函數,其真值表如下:\n",
|
||||
"一個最明顯的例子是感知器無法解決的問題,即所謂的**XOR問題**。我們希望感知器能學習XOR布爾函數,其真值表如下:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -605,15 +731,15 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"正如上方圖表所示,準確率從未超過 75%,因為不可能畫出一條直線來正確分類所有可能的例子。\n",
|
||||
"如上圖所示,準確率從未超過 75%,因為不可能畫出一條直線來正確分類所有可能的例子。\n",
|
||||
"\n",
|
||||
"XOR 問題是感知器局限性的經典例子,這一點在 1969 年由 Marvin Minsky 和 Seymour Papert 在他們的書籍 [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) 中指出。這一觀察限制了神經網絡領域的研究近 10 年,儘管——我們會在課程的下一部分看到——多層感知器完全能夠解決這類問題。\n",
|
||||
"\n",
|
||||
"## 複雜例子 - MNIST\n",
|
||||
"\n",
|
||||
"雖然感知器無法解決 XOR 問題,但它可以解決許多更複雜的問題,例如手寫字符識別。\n",
|
||||
"儘管感知器無法解決 XOR 問題,但它可以解決許多更複雜的問題,例如手寫字符識別。\n",
|
||||
"\n",
|
||||
"在學習機器學習時,經常使用的一個數據集叫做 [MNIST](https://en.wikipedia.org/wiki/MNIST_database)。該數據集由美國國家標準技術研究所(Modified National Institute of Standards and Technology)創建,包含 60000 個手寫數字的訓練集,這些數字來自研究所約 250 名學生和員工。此外,還有一個包含 10000 個數字的測試數據集,這些數字來自不同的個體。\n",
|
||||
"在學習機器學習時經常使用的一個數據集叫做 [MNIST](https://en.wikipedia.org/wiki/MNIST_database)。它由美國國家標準與技術研究院(Modified National Institute of Standards and Technology)創建,包含一個由 60000 個手寫數字組成的訓練集,這些數字來自該研究院約 250 名學生和員工。此外,還有一個由 10000 個數字組成的測試數據集,這些數字來自不同的個體。\n",
|
||||
"\n",
|
||||
"所有數字都以 28x28 像素的灰度圖像表示。\n",
|
||||
"\n",
|
||||
|
|
@ -831,11 +957,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"請注意,準確度會非常快速地提升至接近100%。\n",
|
||||
"請注意,準確度會非常快速地接近100%。\n",
|
||||
"\n",
|
||||
"請將滑桿移動到訓練過程接近尾聲的位置,並觀察左側繪製的權重矩陣。這個矩陣能幫助你理解感知器的實際運作方式。你可以看到矩陣中間的高權重值,這些值對應於通常出現在數字1中的像素,而矩陣兩側則有低的負值,這些位置通常是數字0的一部分。因此,如果呈現給感知器的數字確實是1,中間部分的像素會被高權重值相乘,產生正的結果。相反地,當感知器觀察到數字0時,對應的像素會被負數相乘。\n",
|
||||
"請將滑桿移動到訓練過程接近尾聲的位置,並觀察左側繪製的權重矩陣。這個矩陣可以幫助你理解感知器的實際運作方式。你可以看到矩陣中間的高權重值,這些值對應於通常出現在數字1中的像素,而矩陣兩側則有低的負值,這些位置通常是數字0的一部分。因此,如果呈現給感知器的數字確實是1,中間部分的像素會被高權重值相乘,產生正的結果。相反地,當感知器觀察到數字0時,對應的像素會被負數相乘。\n",
|
||||
"\n",
|
||||
"> 你可能會注意到,如果我們給感知器一個稍微水平偏移的數字1,使其像素佔據了數字0的垂直部分位置,我們可能會得到錯誤的結果。由於MNIST數據集的特性是所有數字都居中且定位正確,感知器依賴這一特性來區分不同的數字。\n",
|
||||
"> 你可能會注意到,如果我們給感知器一個稍微水平移動的數字1,使其像素佔據了數字0的垂直部分位置,我們可能會得到錯誤的結果。由於MNIST數據集的特性是所有數字都居中且位置正確,感知器依賴這一特性來區分不同的數字。\n",
|
||||
"\n",
|
||||
"現在讓我們嘗試不同的數字:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## 討論\n",
|
||||
"\n",
|
||||
"不知何故,2 和 5 並不容易分開。即使我們的準確率相對較高(超過 85%),我們仍然可以明顯看到感知器在某個時刻停止學習。\n",
|
||||
"不知何故,數字 2 和 5 並不容易分開。即使我們的準確率相對較高(超過 85%),我們仍然可以明顯看到感知器在某個時刻停止學習。\n",
|
||||
"\n",
|
||||
"為了理解為什麼會發生這種情況,我們可以嘗試使用 [主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)。這是一種機器學習技術,用於降低輸入數據集的維度,以便獲得最佳的類別可分性。\n",
|
||||
"為了理解為什麼會發生這種情況,我們可以嘗試使用[主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)。這是一種機器學習技術,用於降低輸入數據集的維度,以便獲得最佳的類別可分性。\n",
|
||||
"\n",
|
||||
"在我們的例子中,輸入圖像有 784 個像素(輸入特徵),我們希望使用 PCA 將參數數量減少到僅僅 2 個,這樣我們就可以在圖表上繪製它們。這兩個參數將是原始特徵的線性組合,我們可以將這個過程視為“旋轉”我們原本的 784 維空間,並觀察其投影到 2D 空間,直到我們獲得最佳視角來分離類別。\n"
|
||||
"在我們的例子中,輸入圖像有 784 個像素(輸入特徵),我們希望使用 PCA 將參數數量減少到僅僅 2 個,這樣我們就可以在圖表上繪製它們。這兩個參數將是原始特徵的線性組合,我們可以將這個過程視為“旋轉”我們原本的 784 維空間,並觀察其在 2D 空間中的投影,直到我們獲得最佳視角來分離類別。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,9 +1153,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"正如你所見,0 和 1 可以用一條直線清楚地分隔開來。這表明在原始的 784 維空間中,與數字對應的點也是線性可分的。而在 2 和 5 的情況下,我們無法找到能清楚分隔這些數字的良好投影,因此會出現一些錯誤分類的情況。\n",
|
||||
"如你所見,0 和 1 可以用一條直線清楚地分隔開來。這表明在原始的784維空間中,與數字對應的點也是線性可分的。而在2和5的情況下,我們無法找到能清楚分隔這些數字的良好投影,因此會出現一些錯誤分類的情況。\n",
|
||||
"\n",
|
||||
"> 在這門課程的後續部分,我們將學習如何使用神經網絡創建非線性分類器,以及如何處理數字未正確對齊的問題。很快,我們將在 MNIST 數字分類中達到超過 99% 的準確率,同時將數字分類為 10 個不同的類別。\n",
|
||||
"> 在這門課程的後續部分,我們將學習如何使用神經網絡創建非線性分類器,以及如何處理數字未正確對齊的問題。不久之後,我們將在MNIST數字分類中達到超過99%的準確率,同時將數字分類為10個不同的類別。\n",
|
||||
"\n",
|
||||
"## 重點\n",
|
||||
"\n",
|
||||
|
|
@ -1037,7 +1163,7 @@
|
|||
" * 我們通過手動實現了感知器,使用基於梯度下降的簡單訓練過程。\n",
|
||||
" * 儘管簡單,單層感知器可以解決相當複雜的手寫數字識別問題。\n",
|
||||
" * 單層感知器是一個線性分類器,因此它提供了與邏輯回歸相同的分類能力。\n",
|
||||
" * 在樣本空間中,感知器可以使用超平面分隔兩類輸入數據。\n"
|
||||
" * 在樣本空間中,感知器可以使用超平面分隔輸入數據的兩個類別。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## 致謝\n",
|
||||
"\n",
|
||||
"此筆記本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分,由 [Dmitry Soshnikov](http://soshnikov.com) 編寫。靈感來自於微軟劍橋研究院的神經網絡工作坊。一些代碼和示例材料取自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示,以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 資源庫。\n"
|
||||
"此筆記本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分,由 [Dmitry Soshnikov](http://soshnikov.com) 編寫。靈感來自於微軟劍橋研究院的神經網絡工作坊。一些代碼和示例材料取自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示文稿,以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 資源庫。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**免責聲明**: \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋概不負責。\n"
|
||||
"\n---\n\n**免責聲明**: \n本文件已使用人工智能翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋概不負責。\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:14:40+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:00:46+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "hk"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"\n",
|
||||
"> Ova bilježnica dio je [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Posjetite repozitorij za kompletan set materijala za učenje.\n",
|
||||
"\n",
|
||||
"Kao što smo već raspravljali, perceptron vam omogućuje rješavanje problema **binarne klasifikacije**, tj. klasifikaciju ulaznih primjera u dvije klase - možemo ih nazvati **pozitivne** i **negativne**.\n",
|
||||
"Kao što smo već raspravili, perceptron vam omogućuje rješavanje problema **binarne klasifikacije**, tj. klasifikaciju ulaznih primjera u dvije klase - možemo ih nazvati **pozitivne** i **negativne**.\n",
|
||||
"\n",
|
||||
"Prvo, importirajmo neke potrebne biblioteke.\n"
|
||||
]
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Problem s igračkom\n",
|
||||
"\n",
|
||||
"Za početak, krenimo s problemom s igračkom, gdje imamo dva ulazna obilježja. Na primjer, u medicini možda želimo klasificirati tumore kao benigne ili maligne, ovisno o njihovoj veličini i starosti.\n",
|
||||
"Za početak, krenimo s problemom s igračkom, gdje imamo dvije ulazne značajke. Na primjer, u medicini možda želimo klasificirati tumore kao benigne ili maligne, ovisno o njihovoj veličini i starosti.\n",
|
||||
"\n",
|
||||
"Generirat ćemo nasumični skup podataka za klasifikaciju koristeći funkciju `make_classification` iz biblioteke SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -210,14 +210,14 @@
|
|||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ za negativne i pozitivne uzorke za treniranje, respektivno\n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ za negativne i pozitivne primjere u skupu za treniranje\n",
|
||||
" * $\\mathcal{M}$ - skup pogrešno klasificiranih primjera\n",
|
||||
" \n",
|
||||
"Koristit ćemo proces **gradijentnog spuštanja**. Počevši s nekim početnim slučajnim težinama $\\mathbf{w}^{(0)}$, prilagođavat ćemo težine na svakom koraku treniranja koristeći gradijent $E$:\n",
|
||||
"Koristit ćemo proces **gradijentnog spuštanja**. Počevši s početnim slučajnim težinama $\\mathbf{w}^{(0)}$, prilagođavat ćemo težine u svakom koraku treniranja koristeći gradijent $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"gdje je $\\eta$ **stopa učenja**, a $\\tau\\in\\mathbb{N}$ - broj iteracije.\n",
|
||||
"gdje je $\\eta$ **stopa učenja**, a $\\tau\\in\\mathbb{N}$ - broj iteracija.\n",
|
||||
"\n",
|
||||
"Definirajmo ovaj algoritam u Pythonu:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Napomena o brzini učenja**: Parametar `learning_rate` (zadano `0.01`) kontrolira koliko prilagođavamo težine tijekom svakog koraka treniranja. Ovo implementira formulu za ažuriranje gradijentnog spuštanja:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Veća brzina učenja (npr. `1.0`) omogućuje perceptronu da brže uči, ali može promašiti optimalno rješenje\n",
|
||||
"- Manja brzina učenja (npr. `0.001`) uči sporije, ali može preciznije konvergirati\n",
|
||||
"- Možete eksperimentirati pozivom: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Kao što možete vidjeti, početna točnost je oko 50%, ali brzo raste do viših vrijednosti blizu 90%.\n",
|
||||
"\n",
|
||||
"Vizualizirajmo kako su klase razdvojene. Naša funkcija klasifikacije izgleda kao $\\mathbf{w}^Tx$, i veća je od 0 za jednu klasu, a manja od 0 za drugu. Dakle, linija razdvajanja klasa definirana je s $\\mathbf{w}^Tx = 0$. Budući da imamo samo dvije dimenzije $x_0$ i $x_1$, jednadžba za liniju bila bi $w_0x_0+w_1x_1+w_2 = 0$ (sjetite se da smo eksplicitno definirali dodatnu dimenziju $x_2=1$). Nacrtajmo ovu liniju:\n"
|
||||
"Vizualizirajmo kako su klase razdvojene. Naša funkcija klasifikacije izgleda kao $\\mathbf{w}^Tx$, i veća je od 0 za jednu klasu, a manja od 0 za drugu. Dakle, linija razdvajanja klasa definirana je s $\\mathbf{w}^Tx = 0$. Budući da imamo samo dvije dimenzije $x_0$ i $x_1$, jednadžba za liniju bila bi $w_0x_0+w_1x_1+w_2 = 0$ (sjetite se da smo eksplicitno definirali dodatnu dimenziju $x_2=1$). Idemo nacrtati ovu liniju:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Eksperimentiranje s brzinama učenja\n",
|
||||
"\n",
|
||||
"Sada ćemo istražiti kako različite brzine učenja utječu na proces treniranja. Brzina učenja kontrolira veličinu koraka u gradijentnom spuštanju - ključni hiperparametar koji utječe na brzinu konvergencije i stabilnost.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktivni eksperiment s brzinom učenja\n",
|
||||
"\n",
|
||||
"Koristite klizač ispod kako biste interaktivno isprobali različite brzine učenja i vidjeli kako one utječu na granicu odlučivanja:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Procjena na testnom skupu podataka\n",
|
||||
"\n",
|
||||
"Na početku smo izdvojili dio podataka za testni skup podataka. Pogledajmo koliko je naš klasifikator točan na ovom testnom skupu podataka. Da bismo to učinili, proširujemo testni skup podataka s dodatnom dimenzijom, množimo ga s matricom težina i provjeravamo je li dobivena vrijednost istog predznaka kao i oznaka (+1 ili -1). Zatim zbrajamo sve logičke vrijednosti i dijelimo s duljinom testnog uzorka kako bismo dobili točnost:\n"
|
||||
"Na početku smo izdvojili dio podataka za testni skup. Pogledajmo koliko je naš klasifikator točan na ovom testnom skupu podataka. Da bismo to učinili, proširujemo testni skup podataka dodatnom dimenzijom, množimo ga s matricom težina i provjeravamo je li dobivena vrijednost istog predznaka kao i oznaka (+1 ili -1). Zatim zbrajamo sve logičke vrijednosti i dijelimo ih s duljinom testnog uzorka kako bismo dobili točnost:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,7 +655,7 @@
|
|||
"source": [
|
||||
"## Ograničenja perceptrona\n",
|
||||
"\n",
|
||||
"Kao što ste vidjeli gore, perceptron je **linearni klasifikator**. Može dobro razlikovati dvije klase ako su **linearno odvojive**, tj. mogu se razdvojiti ravnom linijom. U suprotnom, proces treniranja perceptrona neće konvergirati.\n",
|
||||
"Kao što ste vidjeli gore, perceptron je **linearni klasifikator**. Može dobro razlikovati dvije klase ako su **linearno odvojive**, tj. ako ih je moguće razdvojiti ravnom linijom. U suprotnom, proces treniranja perceptrona neće konvergirati.\n",
|
||||
"\n",
|
||||
"Najočitiji primjer problema koji perceptron ne može riješiti je takozvani **XOR problem**. Želimo da naš perceptron nauči XOR booleovu funkciju, koja ima sljedeću tablicu istinitosti:\n",
|
||||
"\n",
|
||||
|
|
@ -538,7 +664,7 @@
|
|||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Pokušajmo to učiniti! Ručno ćemo popuniti sve pozitivne i negativne uzorke za treniranje, a zatim pozvati našu funkciju treniranja definiranu gore:\n"
|
||||
"Pokušajmo to napraviti! Ručno ćemo popuniti sve pozitivne i negativne uzorke za treniranje, a zatim pozvati našu funkciju za treniranje definiranu gore:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,15 +731,15 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Kao što možete vidjeti iz gornjeg grafikona, točnost nikada ne prelazi 75%, jer je nemoguće povući ravnu liniju na način da se svi primjeri točno klasificiraju.\n",
|
||||
"Kao što možete vidjeti iz gornjeg grafikona, točnost nikada ne prelazi 75%, jer je nemoguće povući ravnu liniju na način da se svi primjeri ispravno klasificiraju.\n",
|
||||
"\n",
|
||||
"Problem XOR klasičan je primjer ograničenja perceptrona, a na njega su ukazali Marvin Minsky i Seymour Papert 1969. godine u svojoj knjizi [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Ovo opažanje ograničilo je istraživanja u području neuronskih mreža gotovo 10 godina, iako - kao što ćemo vidjeti u sljedećem dijelu našeg tečaja - višeslojni perceptroni mogu savršeno riješiti takve probleme.\n",
|
||||
"Problem XOR klasičan je primjer ograničenja perceptrona, a na njega su ukazali Marvin Minsky i Seymour Papert 1969. godine u svojoj knjizi [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Ovo zapažanje ograničilo je istraživanja u području neuronskih mreža gotovo 10 godina, iako - kao što ćemo vidjeti u sljedećem dijelu našeg tečaja - višeslojni perceptroni savršeno mogu riješiti takve probleme.\n",
|
||||
"\n",
|
||||
"## Složeniji primjer - MNIST\n",
|
||||
"\n",
|
||||
"Iako perceptron ne može riješiti problem XOR, može riješiti mnoge složenije probleme, poput prepoznavanja rukom pisanih znakova.\n",
|
||||
"\n",
|
||||
"Skup podataka koji se često koristi za usvajanje znanja o strojnome učenju zove se [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Kreirao ga je Modificirani Nacionalni Institut za Standarde i Tehnologiju, a sadrži skup za treniranje od 60.000 rukom pisanih znamenki prikupljenih od oko 250 studenata i zaposlenika instituta. Također postoji testni skup podataka od 10.000 znamenki prikupljenih od različitih pojedinaca.\n",
|
||||
"Skup podataka koji se često koristi za usvajanje znanja o strojnome učenju zove se [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Stvorio ga je Modificirani Nacionalni Institut za Standarde i Tehnologiju, a sadrži skup za treniranje od 60.000 rukom pisanih znamenki, prikupljenih od oko 250 studenata i zaposlenika instituta. Također postoji testni skup podataka od 10.000 znamenki, prikupljenih od različitih pojedinaca.\n",
|
||||
"\n",
|
||||
"Sve znamenke predstavljene su sivim slikama veličine 28x28 piksela.\n",
|
||||
"\n",
|
||||
|
|
@ -833,7 +959,7 @@
|
|||
"source": [
|
||||
"Imajte na umu kako točnost vrlo brzo raste gotovo do 100%.\n",
|
||||
"\n",
|
||||
"Molimo, pomaknite klizač na neku poziciju prema kraju treninga i promatrajte matricu težina prikazanu s lijeve strane. Ova matrica omogućit će vam da razumijete kako perceptron zapravo funkcionira. Možete vidjeti visoke vrijednosti težina u sredini polja, koje odgovaraju pikselima koji su obično prisutni za znamenku 1, i niske negativne vrijednosti sa strane, gdje se nalaze dijelovi znamenke 0. Dakle, ako je znamenka prikazana perceptronu zapravo 1, njezin srednji dio bit će pomnožen visokim vrijednostima, što će proizvesti pozitivan rezultat. Suprotno tome, kada perceptron promatra znamenku 0, odgovarajući pikseli bit će pomnoženi negativnim brojevima.\n",
|
||||
"Molimo, pomaknite klizač na neku poziciju prema kraju treninga i promatrajte matricu težina prikazanu s lijeve strane. Ova matrica omogućit će vam da razumijete kako perceptron zapravo funkcionira. Možete vidjeti visoke vrijednosti težina u sredini polja, koje odgovaraju pikselima koji su obično prisutni za znamenku 1, i niske negativne vrijednosti sa strane, gdje se nalaze dijelovi znamenke 0. Dakle, ako je znamenka prikazana perceptronu zapravo 1, njezin srednji dio bit će pomnožen visokim vrijednostima, što će rezultirati pozitivnim ishodom. Suprotno tome, kada perceptron promatra znamenku 0, odgovarajući pikseli bit će pomnoženi negativnim brojevima.\n",
|
||||
"\n",
|
||||
"> Možete primijetiti da ako našem perceptronu damo znamenku 1 koja je malo pomaknuta horizontalno, tako da njezini pikseli zauzimaju mjesto gdje se nalaze vertikalni dijelovi znamenke 0, možemo dobiti netočan rezultat. Budući da je priroda našeg MNIST skupa podataka takva da su sve znamenke centrirane i pravilno pozicionirane, perceptron se oslanja na to kako bi razlikovao znamenke.\n",
|
||||
"\n",
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Rasprava\n",
|
||||
"\n",
|
||||
"Iz nekog razloga, brojevi 2 i 5 nisu tako lako odvojivi. Iako postižemo relativno visoku točnost (iznad 85%), jasno možemo vidjeti kako perceptron u nekom trenutku prestaje učiti.\n",
|
||||
"Iz nekog razloga, brojevi 2 i 5 nisu tako lako odvojivi. Iako postižemo relativno visoku točnost (iznad 85%), jasno možemo vidjeti kako perceptron prestaje učiti u određenom trenutku.\n",
|
||||
"\n",
|
||||
"Kako bismo razumjeli zašto se to događa, možemo pokušati koristiti [Analizu glavnih komponenti](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). To je tehnika strojnog učenja koja se koristi za smanjenje dimenzionalnosti ulaznog skupa podataka, na način da se postigne najbolja odvojivost između klasa.\n",
|
||||
"\n",
|
||||
"U našem slučaju, ulazna slika ima 784 piksela (ulazne značajke), a mi želimo koristiti PCA kako bismo smanjili broj parametara na samo 2, tako da ih možemo prikazati na grafu. Ta dva parametra bila bi linearna kombinacija originalnih značajki, a ovaj postupak možemo promatrati kao \"rotaciju\" našeg originalnog 784-dimenzionalnog prostora i promatranje njegove projekcije u 2D-prostor, sve dok ne dobijemo najbolji prikaz koji razdvaja klase.\n"
|
||||
"U našem slučaju, ulazna slika ima 784 piksela (ulazne značajke), a mi želimo koristiti PCA kako bismo smanjili broj parametara na samo 2, kako bismo ih mogli prikazati na grafu. Ta dva parametra bila bi linearna kombinacija originalnih značajki, a ovaj postupak možemo promatrati kao \"rotaciju\" našeg originalnog 784-dimenzionalnog prostora i promatranje njegove projekcije u 2D-prostor, sve dok ne dobijemo najbolji prikaz koji razdvaja klase.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,11 +1153,11 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Kao što možete vidjeti, 0 i 1 mogu se jasno odvojiti ravnom linijom. To pokazuje da su u izvornom 784-dimenzionalnom prostoru točke koje odgovaraju znamenkama također linearno odvojive. U slučaju 2 i 5, ne možemo pronaći dobru projekciju koja će jasno odvojiti znamenke, pa stoga postoje slučajevi pogrešne klasifikacije.\n",
|
||||
"Kao što možete vidjeti, 0 i 1 mogu se jasno odvojiti ravnom linijom. To pokazuje da su u izvornom 784-dimenzionalnom prostoru točke koje odgovaraju znamenkama također linearno odvojive. U slučaju 2 i 5, ne možemo pronaći dobru projekciju koja će jasno odvojiti znamenke, zbog čega dolazi do nekih slučajeva pogrešne klasifikacije.\n",
|
||||
"\n",
|
||||
"> Kasnije u ovom tečaju naučit ćemo kako stvoriti nelinearne klasifikatore koristeći neuronske mreže i kako se nositi s problemom znamenki koje nisu pravilno poravnate. Vrlo brzo ćemo postići točnost iznad 99% u klasifikaciji znamenki MNIST, dok ih klasificiramo u 10 različitih klasa.\n",
|
||||
"> Kasnije u ovom tečaju naučit ćemo kako stvoriti nelinearne klasifikatore koristeći neuronske mreže i kako se nositi s problemom znamenki koje nisu pravilno poravnane. Vrlo brzo ćemo postići točnost iznad 99% u klasifikaciji znamenki MNIST, dok ih klasificiramo u 10 različitih klasa.\n",
|
||||
"\n",
|
||||
"## Zaključci\n",
|
||||
"## Zaključak\n",
|
||||
"\n",
|
||||
" * Naučili smo o najjednostavnijoj arhitekturi neuronske mreže - perceptronu s jednim slojem.\n",
|
||||
" * Implementirali smo perceptron \"ručno\", koristeći jednostavnu proceduru treniranja temeljenu na gradijentnom spuštanju.\n",
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Zasluge\n",
|
||||
"\n",
|
||||
"Ova bilježnica dio je [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), a pripremio ju je [Dmitry Soshnikov](http://soshnikov.com). Inspirirana je radionicom o neuronskim mrežama u Microsoft Research Cambridge. Dio koda i ilustrativnih materijala preuzet je iz prezentacija [Katje Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthewa Johnsona](https://www.microsoft.com/en-us/research/people/matjoh/) i [Ryota Tomioke](https://www.microsoft.com/en-us/research/people/ryoto/), kao i iz repozitorija [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Ova bilježnica dio je [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), a pripremio ju je [Dmitry Soshnikov](http://soshnikov.com). Inspirirana je radionicom o neuronskim mrežama u Microsoft Research Cambridge. Dio koda i ilustrativnih materijala preuzet je iz prezentacija [Katje Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthewa Johnsona](https://www.microsoft.com/en-us/research/people/matjoh/) i [Ryota Tomioke](https://www.microsoft.com/en-us/research/people/ryoto/), te iz repozitorija [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Izjava o odricanju odgovornosti**: \nOvaj dokument je preveden pomoću AI usluge za prevođenje [Co-op Translator](https://github.com/Azure/co-op-translator). Iako nastojimo osigurati točnost, imajte na umu da automatski prijevodi mogu sadržavati pogreške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati autoritativnim izvorom. Za ključne informacije preporučuje se profesionalni prijevod od strane ljudskog prevoditelja. Ne preuzimamo odgovornost za nesporazume ili pogrešna tumačenja koja mogu proizaći iz korištenja ovog prijevoda.\n"
|
||||
"\n---\n\n**Izjava o odricanju odgovornosti**: \nOvaj dokument je preveden pomoću AI usluge za prevođenje [Co-op Translator](https://github.com/Azure/co-op-translator). Iako nastojimo osigurati točnost, imajte na umu da automatski prijevodi mogu sadržavati pogreške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati autoritativnim izvorom. Za ključne informacije preporučuje se profesionalni prijevod od strane čovjeka. Ne preuzimamo odgovornost za nesporazume ili pogrešna tumačenja koja mogu proizaći iz korištenja ovog prijevoda.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:47:44+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:36:04+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "hr"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"> Ez a jegyzetfüzet a [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) része. Látogass el a repozitóriumba a teljes tananyagért.\n",
|
||||
"> Ez a jegyzet a [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) része. Látogass el a repozitóriumba a teljes tananyagért.\n",
|
||||
"\n",
|
||||
"Ahogy már megbeszéltük, a perceptron lehetővé teszi, hogy megoldjuk a **bináris osztályozási problémát**, azaz az input példákat két osztályba soroljuk - nevezzük őket **pozitív** és **negatív** osztálynak.\n",
|
||||
"\n",
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Játékfeladat\n",
|
||||
"\n",
|
||||
"Kezdjük egy játékfeladattal, ahol két bemeneti jellemzőnk van. Például az orvostudományban előfordulhat, hogy daganatokat szeretnénk osztályozni jóindulatú és rosszindulatú kategóriákba, méretük és koruk alapján.\n",
|
||||
"Kezdjük egy egyszerű játékfeladattal, ahol két bemeneti jellemzőnk van. Például az orvostudományban osztályozhatjuk a daganatokat jóindulatú és rosszindulatú kategóriákba, méretük és koruk alapján.\n",
|
||||
"\n",
|
||||
"Egy véletlenszerű osztályozási adatállományt fogunk létrehozni a SciKit Learn könyvtár `make_classification` függvényével:\n"
|
||||
]
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Rajzoljuk fel az adathalmazt is:\n"
|
||||
"Rajzoljuk fel az adatokat is:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Egy általános lineáris modellnek azonban elfogultságot (bias) is tartalmaznia kellene, azaz ideális esetben $y$-t így kellene számítanunk: $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Modellünk egyszerűsítése érdekében megszabadulhatunk ettől az elfogultsági tagtól, ha hozzáadunk egy további dimenziót a bemeneti jellemzőinkhez, amely mindig 1 értékű:\n"
|
||||
"Egy általános lineáris modellnek azonban elfogultságot (bias) is tartalmaznia kellene, azaz ideális esetben $y$-t így kellene számítanunk: $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. A modell egyszerűsítése érdekében megszabadulhatunk az elfogultság (bias) tagtól, ha hozzáadunk egy további dimenziót a bemeneti jellemzőkhöz, amely mindig 1 értékű:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -204,16 +204,16 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Tanítási algoritmus\n",
|
||||
"## Tanulási algoritmus\n",
|
||||
"\n",
|
||||
"Ahhoz, hogy a perceptront betanítsuk, meg kell találnunk azokat a súlyokat ($\\mathbf{w}$), amelyek minimalizálják a hibát. A hiba a **perceptron kritérium** alapján van meghatározva:\n",
|
||||
"Ahhoz, hogy betanítsuk a perceptront, meg kell találnunk azokat a súlyokat ($\\mathbf{w}$), amelyek minimalizálják a hibát. A hiba a **perceptron kritérium** alapján van meghatározva:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ negatív és pozitív tanító minták esetén\n",
|
||||
" * $\\mathcal{M}$ - a rosszul osztályozott példák halmaza\n",
|
||||
" \n",
|
||||
"A **gradiens csökkentés** módszerét fogjuk használni. Kiindulva egy kezdeti véletlenszerű súlyból ($\\mathbf{w}^{(0)}$), minden tanítási lépésnél módosítjuk a súlyokat az $E$ gradiensének segítségével:\n",
|
||||
"A **gradiens csökkenés** módszerét fogjuk használni. Kezdve néhány kezdeti véletlenszerű súllyal ($\\mathbf{w}^{(0)}$), minden lépésben módosítjuk a súlyokat a $E$ gradiensének segítségével:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -272,7 +272,20 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Most már futtassuk az adatainkon a tanítást:\n"
|
||||
"**Megjegyzés a tanulási rátáról**: A `learning_rate` paraméter (alapértelmezett érték: `0.01`) határozza meg, hogy mennyit módosítunk a súlyokon minden egyes tanítási lépés során. Ez a gradiensdescent frissítési formulát valósítja meg:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Nagyobb tanulási ráta (pl. `1.0`) gyorsabb tanulást eredményezhet, de túllőhet az optimális megoldáson\n",
|
||||
"- Kisebb tanulási ráta (pl. `0.001`) lassabban tanul, de pontosabban konvergálhat\n",
|
||||
"- Kísérletezhetsz vele, ha meghívod: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Most kezdjük el az adataink betanítását:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Amint látható, a kezdeti pontosság körülbelül 50%, de gyorsan növekszik, és eléri a 90%-hoz közeli értékeket.\n",
|
||||
"\n",
|
||||
"Vizualizáljuk, hogyan különülnek el az osztályok. A klasszifikációs függvényünk így néz ki: $\\mathbf{w}^Tx$, és az egyik osztály esetében nagyobb, mint 0, míg a másik osztály esetében kisebb, mint 0. Ezért az osztályokat elválasztó vonalat a $\\mathbf{w}^Tx = 0$ határozza meg. Mivel csak két dimenziónk van, $x_0$ és $x_1$, a vonal egyenlete a következő lesz: $w_0x_0+w_1x_1+w_2 = 0$ (ne feledjük, hogy kifejezetten definiáltunk egy extra dimenziót, $x_2=1$). Ábrázoljuk ezt a vonalat:\n"
|
||||
"Vizualizáljuk, hogyan különülnek el az osztályok. A klasszifikációs függvényünk így néz ki: $\\mathbf{w}^Tx$, és az egyik osztály esetében nagyobb, mint 0, míg a másik osztály esetében kisebb, mint 0. Ezért az osztályokat elválasztó vonalat a $\\mathbf{w}^Tx = 0$ határozza meg. Mivel csak két dimenziónk van, $x_0$ és $x_1$, a vonal egyenlete így nézne ki: $w_0x_0+w_1x_1+w_2 = 0$ (ne feledjük, hogy kifejezetten definiáltunk egy extra dimenziót, $x_2=1$). Ábrázoljuk ezt a vonalat:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Kísérletezés a tanulási rátákkal\n",
|
||||
"\n",
|
||||
"Most nézzük meg, hogyan befolyásolják a különböző tanulási ráták a tanulási folyamatot. A tanulási ráta szabályozza a lépésnagyságot a gradiens csökkentés során – egy kulcsfontosságú hiperparaméter, amely hatással van a konvergencia sebességére és stabilitására.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktív tanulási ráta kísérlet\n",
|
||||
"\n",
|
||||
"Használja az alábbi csúszkát, hogy interaktívan kísérletezzen különböző tanulási rátákkal, és nézze meg, hogyan befolyásolják a döntési határt:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -420,9 +546,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## A tanulási folyamat megfigyelése\n",
|
||||
"## A képzési folyamat megfigyelése\n",
|
||||
"\n",
|
||||
"Korábban láttuk, hogyan csökken a pontosság a tanulás során. Érdekes lenne megfigyelni, hogyan változik az elválasztó vonal a tanulás alatt. Az alábbi kód mindent egy grafikonon fog megjeleníteni, és a csúszka segítségével \"időutazást\" tehetsz a tanulási folyamatban.\n"
|
||||
"Korábban láttuk, hogyan csökken a pontosság a képzés során. Érdekes lenne látni, hogyan változik az elválasztó vonal a képzés alatt. Az alábbi kód mindent egy grafikonon fog megjeleníteni, és a csúszka segítségével \"időutazást\" tehetsz a képzési folyamatban.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -531,7 +657,7 @@
|
|||
"\n",
|
||||
"Ahogy fentebb láthattad, a perceptron egy **lineáris osztályozó**. Két osztályt jól meg tud különböztetni, ha azok **lineárisan szeparálhatók**, azaz egy egyenes vonallal elválaszthatók. Ellenkező esetben a perceptron tanulási folyamata nem fog konvergálni.\n",
|
||||
"\n",
|
||||
"A legnyilvánvalóbb példa egy olyan problémára, amelyet a perceptron nem tud megoldani, az úgynevezett **XOR probléma**. Azt szeretnénk, hogy a perceptron megtanulja az XOR logikai függvényt, amelynek az alábbi igazságtáblája van:\n",
|
||||
"A perceptron által nem megoldható probléma legnyilvánvalóbb példája az úgynevezett **XOR probléma**. Azt szeretnénk, hogy a perceptron megtanulja az XOR logikai függvényt, amelynek az alábbi igazságtáblája van:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -607,15 +733,15 @@
|
|||
"source": [
|
||||
"Amint a fenti grafikonon látható, a pontosság soha nem haladja meg a 75%-ot, mivel lehetetlen olyan egyenes vonalat húzni, amely minden lehetséges példát helyesen osztályozna.\n",
|
||||
"\n",
|
||||
"Az XOR probléma a perceptron korlátainak klasszikus példája, amelyet Marvin Minsky és Seymour Papert 1969-ben mutatott be [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) című könyvükben. Ez a megfigyelés közel 10 évre korlátozta a neurális hálózatok kutatását, annak ellenére, hogy - ahogy a kurzus következő részében látni fogjuk - a többrétegű perceptronok tökéletesen képesek ilyen problémák megoldására.\n",
|
||||
"Az XOR probléma a perceptron korlátainak klasszikus példája, amelyet Marvin Minsky és Seymour Papert 1969-ben mutatott be [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) című könyvükben. Ez a megfigyelés közel 10 évre korlátozta a neurális hálózatok kutatását, annak ellenére, hogy - ahogy a kurzusunk következő részében látni fogjuk - a többrétegű perceptronok tökéletesen képesek ilyen problémák megoldására.\n",
|
||||
"\n",
|
||||
"## Összetett példa - MNIST\n",
|
||||
"\n",
|
||||
"Bár a perceptron nem tudja megoldani az XOR problémát, számos összetettebb problémát képes megoldani, például a kézzel írt karakterek felismerését.\n",
|
||||
"Bár a perceptron nem képes megoldani az XOR problémát, számos összetettebb problémát meg tud oldani, például a kézzel írt karakterek felismerését.\n",
|
||||
"\n",
|
||||
"Egy gyakran használt adatbázis a gépi tanulás elsajátításakor az [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Ezt a Modified National Institute of Standards and Technology hozta létre, és 60000 kézzel írt számjegyet tartalmazó tanulóhalmazt foglal magában, amelyet körülbelül 250 diák és az intézet alkalmazottai gyűjtöttek össze. Emellett van egy tesztadatbázis is, amely 10000 számjegyet tartalmaz, különböző személyektől gyűjtve.\n",
|
||||
"Egy gyakran használt adatbázis a gépi tanulás elsajátításakor az [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Ezt a Módosított Nemzeti Szabványügyi és Technológiai Intézet hozta létre, és 60000 kézzel írt számjegyet tartalmazó tanulóhalmazt foglal magában, amelyet körülbelül 250 diák és az intézet alkalmazottai gyűjtöttek össze. Emellett van egy 10000 számjegyet tartalmazó tesztadatbázis, amelyet különböző személyektől gyűjtöttek.\n",
|
||||
"\n",
|
||||
"Minden számjegy 28x28 pixeles szürkeárnyalatos képként van ábrázolva.\n",
|
||||
"Minden számjegy szürkeárnyalatos képként van ábrázolva, 28x28 pixeles méretben.\n",
|
||||
"\n",
|
||||
"> Az MNIST adatbázis elérhető egy tanulási versenyként a [Kaggle](https://www.kaggle.com/c/digit-recognizer) oldalon, amely gépi tanulási versenyeket és pályázatokat szervez. Miután megtanulod, hogyan kell osztályozni az MNIST számjegyeket, benyújthatod a megoldásodat a Kaggle-re, hogy lásd, hogyan értékelik más résztvevők között.\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Mivel a perceptron egy bináris osztályozó, a problémánkat két számjegy felismerésére korlátozzuk. Az alábbi függvény pozitív és negatív mintatömböket tölt fel két megadott számjeggyel (és a tisztánlátás érdekében meg is jeleníti ezek mintáit).\n"
|
||||
"Mivel a perceptron egy bináris osztályozó, korlátozni fogjuk a problémát csak két számjegy felismerésére. Az alábbi függvény pozitív és negatív mintatömböket tölt fel két megadott számjeggyel (és a tisztánlátás érdekében megmutatja ezeknek a számjegyeknek a mintáit is).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -835,7 +961,7 @@
|
|||
"\n",
|
||||
"Kérjük, mozgassa a csúszkát a tanulási folyamat vége felé, és figyelje meg a bal oldalon ábrázolt súlymátrixot. Ez a mátrix segít megérteni, hogyan működik valójában a perceptron. Láthatja a magas súlyértékeket a mező közepén, amelyek azokhoz a pixelekhez tartoznak, amelyek általában jelen vannak az 1-es számjegynél, és alacsony negatív értékeket az oldalakon, ahol a 0-s számjegy részei találhatók. Tehát, ha a perceptronnak bemutatott számjegy valóban 1, annak középső része magas értékekkel lesz megszorozva, pozitív eredményt produkálva. Ezzel szemben, amikor a perceptron 0-t figyel meg, a megfelelő pixelek negatív számokkal lesznek megszorozva.\n",
|
||||
"\n",
|
||||
"> Észreveheti, hogy ha a perceptronnak egy kissé vízszintesen eltolódott 1-es számjegyet adunk, amelynek pixelei olyan helyet foglalnak el, ahol a 0 függőleges részei vannak, hibás eredményt kaphatunk. Mivel az MNIST adatbázisunk természete olyan, hogy minden számjegy középre van igazítva és megfelelően van pozicionálva, a perceptron erre támaszkodik a számjegyek megkülönböztetéséhez.\n",
|
||||
"> Észreveheti, hogy ha a perceptronnak egy kissé vízszintesen eltolódott 1-es számjegyet adunk, úgy, hogy annak pixelei olyan helyet foglalnak el, ahol a 0 függőleges részei vannak, hibás eredményt kaphatunk. Mivel az MNIST adatbázis természete olyan, hogy minden számjegy középre van igazítva és megfelelően van pozicionálva, a perceptron erre támaszkodik a számjegyek megkülönböztetéséhez.\n",
|
||||
"\n",
|
||||
"Most próbáljunk ki különböző számjegyeket:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Megbeszélés\n",
|
||||
"\n",
|
||||
"Valamilyen oknál fogva a 2-es és az 5-ös számjegyek nem különíthetők el olyan könnyen. Bár viszonylag magas pontosságot érünk el (85% felett), egyértelműen látható, hogy a perceptron egy ponton megáll a tanulásban.\n",
|
||||
"Valamilyen oknál fogva a 2-es és az 5-ös szám nem választható el olyan könnyen egymástól. Bár viszonylag magas pontosságot érünk el (85% felett), egyértelműen látható, hogy a perceptron egy ponton megáll a tanulásban.\n",
|
||||
"\n",
|
||||
"Hogy megértsük, miért történik ez, megpróbálhatjuk alkalmazni a [Főkomponens-analízist](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Ez egy gépi tanulási technika, amelyet az input adathalmaz dimenziójának csökkentésére használnak, oly módon, hogy a legjobb osztályelválasztást érjük el.\n",
|
||||
"Hogy megértsük, miért történik ez, megpróbálhatjuk alkalmazni a [Főkomponens-elemzést](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Ez egy gépi tanulási technika, amelyet az input adathalmaz dimenzióinak csökkentésére használnak, úgy, hogy a lehető legjobb osztályok közötti elkülöníthetőséget érjük el.\n",
|
||||
"\n",
|
||||
"Esetünkben egy bemeneti kép 784 pixelt (bemeneti jellemzőt) tartalmaz, és a PCA segítségével szeretnénk ezt a paraméterszámot 2-re csökkenteni, hogy ábrázolhassuk őket egy grafikonon. Ez a két paraméter az eredeti jellemzők lineáris kombinációja lenne, és ezt az eljárást úgy tekinthetjük, mint az eredeti 784-dimenziós tér \"elforgatását\", majd annak vetületét a 2D-térre, amíg meg nem kapjuk a legjobb nézetet, amely elválasztja az osztályokat.\n"
|
||||
"Esetünkben egy bemeneti kép 784 pixelt (bemeneti jellemzőt) tartalmaz, és a PCA segítségével szeretnénk a paraméterek számát 2-re csökkenteni, hogy grafikonon ábrázolhassuk őket. Ez a két paraméter az eredeti jellemzők lineáris kombinációja lenne, és ezt az eljárást úgy tekinthetjük, mint az eredeti 784-dimenziós tér \"elforgatását\", majd annak vetületét a 2D-térre, amíg meg nem kapjuk a legjobb nézetet, amely elválasztja az osztályokat.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,13 +1153,13 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Amint látható, a 0 és az 1 egyértelműen elválasztható egy egyenes vonallal. Ez azt jelzi, hogy az eredeti 784-dimenziós térben a számjegyekhez tartozó pontok is lineárisan elválaszthatók. A 2 és az 5 esetében viszont nem található olyan jó vetítés, amely egyértelműen elválasztaná a számjegyeket, így előfordulhatnak hibás osztályozási esetek.\n",
|
||||
"Amint látható, a 0 és az 1 egyértelműen elválasztható egy egyenes vonallal. Ez azt jelzi, hogy az eredeti 784-dimenziós térben a számjegyekhez tartozó pontok is lineárisan elválaszthatók. A 2 és az 5 esetében azonban nem található olyan jó vetítés, amely egyértelműen elválasztaná a számjegyeket, ezért előfordulhatnak hibás osztályozási esetek.\n",
|
||||
"\n",
|
||||
"> A kurzus későbbi részében megtanuljuk, hogyan hozzunk létre nem-lineáris osztályozókat neurális hálózatok segítségével, és hogyan kezeljük azt a problémát, amikor a számjegyek nincsenek megfelelően elrendezve. Nagyon hamar elérjük a 99%-os pontosságot az MNIST számjegyosztályozásban, miközben 10 különböző osztályba soroljuk őket.\n",
|
||||
"\n",
|
||||
"## Összegzés\n",
|
||||
"\n",
|
||||
" * Megismerkedtünk a legegyszerűbb neurális hálózat architektúrával – az egyrétegű perceptronnal.\n",
|
||||
" * Megtanultuk a legegyszerűbb neurális hálózat architektúrát - az egyrétegű perceptront.\n",
|
||||
" * Kézzel implementáltuk a perceptront, egy egyszerű, gradiens alapú tanítási eljárást használva.\n",
|
||||
" * Az egyszerűsége ellenére az egyrétegű perceptron képes meglehetősen összetett problémák megoldására, például kézzel írt számjegyek felismerésére.\n",
|
||||
" * Az egyrétegű perceptron egy lineáris osztályozó, így ugyanazt az osztályozási teljesítményt nyújtja, mint a logisztikus regresszió.\n",
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Köszönetnyilvánítás\n",
|
||||
"\n",
|
||||
"Ez a jegyzetfüzet az [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) része, és [Dmitry Soshnikov](http://soshnikov.com) készítette. Az anyag a Microsoft Research Cambridge Neural Network Workshop-jából merít ihletet. Néhány kód és szemléltető anyag [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) és [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) prezentációiból származik, valamint a [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) repozitóriumból.\n"
|
||||
"Ez a jegyzetfüzet az [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) része, és [Dmitry Soshnikov](http://soshnikov.com) készítette. Az anyag a Microsoft Research Cambridge által szervezett Neural Network Workshop ihletésére készült. Néhány kód és szemléltető anyag [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) és [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) prezentációiból származik, valamint a [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) repozitóriumból.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Felelősség kizárása**: \nEz a dokumentum az [Co-op Translator](https://github.com/Azure/co-op-translator) AI fordítási szolgáltatás segítségével lett lefordítva. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Fontos információk esetén javasolt professzionális emberi fordítást igénybe venni. Nem vállalunk felelősséget semmilyen félreértésért vagy téves értelmezésért, amely a fordítás használatából eredhet.\n"
|
||||
"\n---\n\n**Felelősség kizárása**: \nEz a dokumentum az [Co-op Translator](https://github.com/Azure/co-op-translator) AI fordítási szolgáltatás segítségével lett lefordítva. Bár törekszünk a pontosságra, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az eredeti nyelvén tekintendő hiteles forrásnak. Kritikus információk esetén javasolt professzionális emberi fordítást igénybe venni. Nem vállalunk felelősséget semmilyen félreértésért vagy téves értelmezésért, amely a fordítás használatából eredhet.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:41:40+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:29:31+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "hu"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"> Notebook ini adalah bagian dari [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Kunjungi repositori untuk mendapatkan materi pembelajaran lengkap.\n",
|
||||
"> Notebook ini adalah bagian dari [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Kunjungi repositori untuk set lengkap materi pembelajaran.\n",
|
||||
"\n",
|
||||
"Seperti yang telah kita bahas, perceptron memungkinkan Anda untuk menyelesaikan **masalah klasifikasi biner**, yaitu mengklasifikasikan contoh input ke dalam dua kelas - kita bisa menyebutnya **positif** dan **negatif**.\n",
|
||||
"\n",
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Masalah Sederhana\n",
|
||||
"\n",
|
||||
"Sebagai permulaan, mari kita mulai dengan masalah sederhana, di mana kita memiliki dua fitur input. Sebagai contoh, dalam bidang medis kita mungkin ingin mengklasifikasikan tumor menjadi jinak dan ganas, tergantung pada ukurannya dan usianya.\n",
|
||||
"Sebagai permulaan, mari kita mulai dengan masalah sederhana, di mana kita memiliki dua fitur input. Sebagai contoh, dalam dunia medis kita mungkin ingin mengklasifikasikan tumor menjadi jinak dan ganas, tergantung pada ukuran dan usianya.\n",
|
||||
"\n",
|
||||
"Kita akan membuat dataset klasifikasi acak menggunakan fungsi `make_classification` dari pustaka SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Catatan tentang Learning Rate**: Parameter `learning_rate` (default `0.01`) mengontrol seberapa besar kita menyesuaikan bobot selama setiap langkah pelatihan. Ini menerapkan rumus pembaruan gradient descent:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Learning rate yang lebih besar (misalnya, `1.0`) membuat perceptron belajar lebih cepat tetapi mungkin melewati solusi optimal\n",
|
||||
"- Learning rate yang lebih kecil (misalnya, `0.001`) belajar lebih lambat tetapi mungkin lebih tepat dalam mencapai konvergensi\n",
|
||||
"- Anda dapat bereksperimen dengan memanggil: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Seperti yang dapat Anda lihat, akurasi awal sekitar 50%, tetapi dengan cepat meningkat ke nilai yang lebih tinggi mendekati 90%.\n",
|
||||
"\n",
|
||||
"Mari kita visualisasikan bagaimana kelas-kelas dipisahkan. Fungsi klasifikasi kita berbentuk $\\mathbf{w}^Tx$, dan nilainya lebih besar dari 0 untuk satu kelas, serta di bawah 0 untuk kelas lainnya. Dengan demikian, garis pemisah kelas didefinisikan oleh $\\mathbf{w}^Tx = 0$. Karena kita hanya memiliki dua dimensi $x_0$ dan $x_1$, persamaan untuk garis tersebut adalah $w_0x_0+w_1x_1+w_2 = 0$ (ingat bahwa kita telah secara eksplisit mendefinisikan dimensi tambahan $x_2=1$). Mari kita plot garis ini:\n"
|
||||
"Mari kita visualisasikan bagaimana kelas-kelas dipisahkan. Fungsi klasifikasi kita terlihat seperti $\\mathbf{w}^Tx$, dan nilainya lebih besar dari 0 untuk satu kelas, serta di bawah 0 untuk kelas lainnya. Oleh karena itu, garis pemisah kelas didefinisikan oleh $\\mathbf{w}^Tx = 0$. Karena kita hanya memiliki dua dimensi $x_0$ dan $x_1$, persamaan untuk garis tersebut adalah $w_0x_0+w_1x_1+w_2 = 0$ (ingat bahwa kita telah secara eksplisit mendefinisikan dimensi tambahan $x_2=1$). Mari kita plot garis ini:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Bereksperimen dengan Tingkat Pembelajaran\n",
|
||||
"\n",
|
||||
"Sekarang mari kita eksplorasi bagaimana tingkat pembelajaran yang berbeda memengaruhi proses pelatihan. Tingkat pembelajaran mengontrol ukuran langkah dalam penurunan gradien - sebuah hiperparameter penting yang memengaruhi kecepatan konvergensi dan stabilitas.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Eksperimen Interaktif Tingkat Pembelajaran\n",
|
||||
"\n",
|
||||
"Gunakan slider di bawah ini untuk bereksperimen secara interaktif dengan berbagai tingkat pembelajaran dan lihat bagaimana mereka memengaruhi batas keputusan:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Evaluasi pada Dataset Uji\n",
|
||||
"\n",
|
||||
"Di awal, kita telah memisahkan beberapa data ke dalam dataset uji. Mari kita lihat seberapa akurat classifier kita pada dataset uji ini. Untuk melakukan ini, kita juga memperluas dataset uji dengan satu dimensi tambahan, mengalikan dengan matriks bobot, dan memastikan bahwa nilai yang diperoleh memiliki tanda yang sama dengan label (+1 atau -1). Kemudian, kita menjumlahkan semua nilai boolean dan membaginya dengan panjang sampel uji untuk mendapatkan akurasi:\n"
|
||||
"Di awal, kita telah memisahkan sebagian data untuk dataset uji. Mari kita lihat seberapa akurat classifier kita pada dataset uji ini. Untuk melakukan ini, kita juga memperluas dataset uji dengan dimensi tambahan, mengalikan dengan matriks bobot, dan memastikan bahwa nilai yang diperoleh memiliki tanda yang sama dengan label (+1 atau -1). Kemudian, kita menjumlahkan semua nilai boolean dan membaginya dengan panjang sampel uji untuk mendapatkan akurasi:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Mengamati proses pelatihan\n",
|
||||
"\n",
|
||||
"Kita telah melihat sebelumnya bagaimana akurasi menurun selama pelatihan. Akan menarik untuk melihat bagaimana garis pemisah berubah selama pelatihan. Kode di bawah ini akan memvisualisasikan semuanya dalam satu grafik, dan Anda seharusnya dapat menggerakkan slider untuk \"berjalan mundur waktu\" melalui proses pelatihan.\n"
|
||||
"Kita telah melihat sebelumnya bagaimana akurasi menurun selama pelatihan. Akan menarik untuk melihat bagaimana garis pemisah berubah selama pelatihan. Kode di bawah ini akan memvisualisasikan semuanya dalam satu grafik, dan Anda seharusnya dapat menggeser slider untuk \"berjalan melalui waktu\" selama proses pelatihan.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,7 +655,7 @@
|
|||
"source": [
|
||||
"## Keterbatasan Perceptron\n",
|
||||
"\n",
|
||||
"Seperti yang telah Anda lihat di atas, perceptron adalah **klasifikator linear**. Perceptron dapat membedakan antara dua kelas dengan baik jika mereka **dapat dipisahkan secara linear**, yaitu dapat dipisahkan oleh garis lurus. Jika tidak, proses pelatihan perceptron tidak akan mencapai konvergensi.\n",
|
||||
"Seperti yang telah Anda lihat di atas, perceptron adalah **klasifikator linear**. Perceptron dapat membedakan antara dua kelas dengan baik jika mereka **dapat dipisahkan secara linear**, yaitu dapat dipisahkan oleh garis lurus. Jika tidak, proses pelatihan perceptron tidak akan konvergen.\n",
|
||||
"\n",
|
||||
"Contoh paling jelas dari masalah yang tidak dapat diselesaikan oleh perceptron adalah masalah yang disebut **XOR problem**. Kita ingin perceptron kita mempelajari fungsi boolean XOR, yang memiliki tabel kebenaran berikut:\n",
|
||||
"\n",
|
||||
|
|
@ -607,13 +733,13 @@
|
|||
"source": [
|
||||
"Seperti yang dapat Anda lihat dari grafik di atas, akurasi tidak pernah melebihi 75%, karena tidak mungkin menggambar garis lurus sedemikian rupa sehingga semua contoh dapat diprediksi dengan benar.\n",
|
||||
"\n",
|
||||
"Masalah XOR adalah contoh klasik dari keterbatasan perceptron, dan hal ini telah disoroti oleh Marvin Minsky dan Seymour Papert pada tahun 1969 dalam buku mereka [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Pengamatan ini membatasi penelitian di bidang jaringan saraf selama hampir 10 tahun, meskipun - seperti yang akan kita lihat di bagian berikutnya dari kursus ini - perceptron berlapis-lapis mampu menyelesaikan masalah semacam itu dengan baik.\n",
|
||||
"Masalah XOR adalah contoh klasik dari keterbatasan perceptron, dan hal ini telah disoroti oleh Marvin Minsky dan Seymour Papert pada tahun 1969 dalam buku mereka [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Pengamatan ini membatasi penelitian di bidang jaringan saraf selama hampir 10 tahun, meskipun - seperti yang akan kita lihat di bagian berikutnya dari kursus ini - perceptron berlapis-lapis sebenarnya mampu menyelesaikan masalah semacam itu.\n",
|
||||
"\n",
|
||||
"## Contoh Kompleks - MNIST\n",
|
||||
"\n",
|
||||
"Meskipun perceptron tidak dapat menyelesaikan masalah XOR, ia dapat menyelesaikan banyak masalah yang lebih kompleks, seperti pengenalan karakter tulisan tangan.\n",
|
||||
"\n",
|
||||
"Dataset yang sering digunakan saat mempelajari pembelajaran mesin disebut [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Dataset ini dibuat oleh Modified National Institute of Standards and Technology, dan berisi set pelatihan sebanyak 60.000 digit tulisan tangan, yang dikumpulkan dari sekitar 250 siswa dan karyawan institut tersebut. Selain itu, terdapat juga dataset pengujian sebanyak 10.000 digit, yang dikumpulkan dari individu yang berbeda.\n",
|
||||
"Dataset yang sering digunakan saat mempelajari pembelajaran mesin disebut [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Dataset ini dibuat oleh Modified National Institute of Standards and Technology, dan berisi set pelatihan yang terdiri dari 60.000 digit tulisan tangan, yang dikumpulkan dari sekitar 250 siswa dan karyawan institut tersebut. Selain itu, terdapat juga dataset pengujian yang terdiri dari 10.000 digit, yang dikumpulkan dari individu yang berbeda.\n",
|
||||
"\n",
|
||||
"Semua digit direpresentasikan dalam bentuk gambar grayscale berukuran 28x28 piksel.\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Karena perceptron adalah pengklasifikasi biner, kita akan membatasi masalah kita untuk mengenali hanya dua digit. Fungsi di bawah ini akan mengisi array sampel positif dan negatif dengan dua digit yang diberikan (dan juga akan menampilkan sampel dari digit tersebut untuk kejelasan).\n"
|
||||
"Karena perceptron adalah pengklasifikasi biner, kita akan membatasi masalah kita untuk mengenali hanya dua digit. Fungsi di bawah ini akan mengisi array sampel positif dan negatif dengan dua digit yang diberikan (dan juga akan menunjukkan sampel dari digit tersebut untuk kejelasan).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -735,7 +861,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Kita akan mulai dengan mencoba mengklasifikasikan antara 0 dan 1:\n"
|
||||
"Kami akan mulai dengan mencoba mengklasifikasikan antara 0 dan 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,11 +959,11 @@
|
|||
"source": [
|
||||
"Perhatikan bagaimana akurasi meningkat hingga hampir 100% dengan sangat cepat.\n",
|
||||
"\n",
|
||||
"Silakan geser slider ke posisi mendekati akhir pelatihan, dan amati matriks bobot yang dipetakan di sebelah kiri. Matriks ini akan membantu Anda memahami cara kerja perceptron. Anda dapat melihat nilai bobot tinggi di tengah bidang, yang sesuai dengan piksel yang biasanya ada pada digit 1, dan nilai negatif rendah di sisi-sisi, di mana bagian dari digit 0 berada. Jadi, jika digit yang diberikan kepada perceptron adalah 1, bagian tengahnya akan dikalikan dengan nilai tinggi, menghasilkan hasil positif. Sebaliknya, ketika perceptron mengamati digit 0, piksel yang sesuai akan dikalikan dengan angka negatif.\n",
|
||||
"Silakan geser slider ke posisi mendekati akhir pelatihan, dan amati matriks bobot yang ditampilkan di sebelah kiri. Matriks ini akan membantu Anda memahami cara kerja perceptron. Anda dapat melihat nilai bobot tinggi di bagian tengah bidang, yang sesuai dengan piksel yang biasanya ada pada angka 1, dan nilai negatif rendah di sisi-sisinya, di mana bagian dari angka 0 berada. Jadi, jika angka yang diberikan kepada perceptron adalah angka 1, bagian tengahnya akan dikalikan dengan nilai tinggi, menghasilkan hasil positif. Sebaliknya, ketika perceptron mengamati angka 0, piksel yang sesuai akan dikalikan dengan angka negatif.\n",
|
||||
"\n",
|
||||
"> Anda mungkin memperhatikan bahwa jika kita memberikan digit 1 kepada perceptron yang sedikit bergeser secara horizontal, sehingga pikselnya menempati tempat di mana terdapat bagian vertikal dari digit 0, kita mungkin mendapatkan hasil yang salah. Karena sifat dataset MNIST kita adalah semua digit terpusat dan diposisikan dengan benar, dan perceptron mengandalkan hal ini untuk membedakan antara digit.\n",
|
||||
"> Anda mungkin memperhatikan bahwa jika kita memberikan angka 1 kepada perceptron yang sedikit bergeser secara horizontal, sehingga pikselnya berada di tempat di mana terdapat bagian vertikal dari angka 0, kita mungkin mendapatkan hasil yang salah. Karena sifat dataset MNIST kita adalah semua angka dipusatkan dan diposisikan dengan benar, dan perceptron mengandalkan hal ini untuk membedakan antara angka-angka.\n",
|
||||
"\n",
|
||||
"Sekarang mari kita coba digit yang berbeda:\n"
|
||||
"Sekarang mari kita coba angka yang berbeda:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -913,9 +1039,9 @@
|
|||
"source": [
|
||||
"## Diskusi\n",
|
||||
"\n",
|
||||
"Entah mengapa, angka 2 dan 5 tidak mudah dipisahkan. Meskipun kita mendapatkan akurasi yang cukup tinggi (di atas 85%), kita dapat melihat dengan jelas bagaimana perceptron berhenti belajar pada titik tertentu.\n",
|
||||
"Entah mengapa, angka 2 dan 5 tidak mudah dipisahkan. Meskipun kita mendapatkan akurasi yang cukup tinggi (di atas 85%), kita dapat dengan jelas melihat bagaimana perceptron berhenti belajar pada titik tertentu.\n",
|
||||
"\n",
|
||||
"Untuk memahami mengapa hal ini terjadi, kita dapat mencoba menggunakan [Analisis Komponen Utama](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Ini adalah teknik pembelajaran mesin yang digunakan untuk mengurangi dimensi dataset input, dengan cara sedemikian rupa sehingga mendapatkan pemisahan terbaik antara kelas-kelas.\n",
|
||||
"Untuk memahami mengapa hal ini terjadi, kita dapat mencoba menggunakan [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Ini adalah teknik pembelajaran mesin yang digunakan untuk mengurangi dimensi dataset input, dengan cara sedemikian rupa sehingga mendapatkan pemisahan terbaik antara kelas-kelas.\n",
|
||||
"\n",
|
||||
"Dalam kasus kita, sebuah gambar input memiliki 784 piksel (fitur input), dan kita ingin menggunakan PCA untuk mengurangi jumlah parameter menjadi hanya 2, sehingga kita dapat memplotnya pada grafik. Kedua parameter tersebut akan menjadi kombinasi linear dari fitur asli, dan kita dapat melihat prosedur ini sebagai \"memutar\" ruang 784 dimensi asli kita dan mengamati proyeksinya ke ruang 2D, hingga kita mendapatkan pandangan terbaik yang memisahkan kelas-kelas.\n"
|
||||
]
|
||||
|
|
@ -1027,15 +1153,15 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Seperti yang dapat Anda lihat, angka 0 dan 1 dapat dengan jelas dipisahkan oleh garis lurus. Hal ini menunjukkan bahwa dalam ruang 784 dimensi asli, titik-titik yang mewakili angka juga dapat dipisahkan secara linear. Namun, dalam kasus angka 2 dan 5, kita tidak dapat menemukan proyeksi yang baik untuk memisahkan angka-angka tersebut dengan jelas, sehingga ada beberapa kasus klasifikasi yang salah.\n",
|
||||
"Seperti yang dapat Anda lihat, angka 0 dan 1 dapat dipisahkan dengan jelas menggunakan garis lurus. Hal ini menunjukkan bahwa dalam ruang 784 dimensi asli, titik-titik yang mewakili digit juga dapat dipisahkan secara linear. Namun, dalam kasus angka 2 dan 5, kita tidak dapat menemukan proyeksi yang baik untuk memisahkan digit dengan jelas, sehingga ada beberapa kasus klasifikasi yang salah.\n",
|
||||
"\n",
|
||||
"> Nanti dalam kursus ini kita akan belajar cara membuat pengklasifikasi non-linear menggunakan Neural Networks, dan bagaimana menangani masalah angka yang tidak sejajar dengan baik. Dalam waktu dekat, kita akan mencapai akurasi di atas 99% dalam klasifikasi angka MNIST, sambil mengklasifikasikan mereka ke dalam 10 kelas yang berbeda.\n",
|
||||
"> Nanti dalam kursus ini kita akan belajar cara membuat pengklasifikasi non-linear menggunakan Neural Networks, dan bagaimana menangani masalah digit yang tidak sejajar dengan baik. Dalam waktu dekat, kita akan mencapai akurasi di atas 99% dalam klasifikasi digit MNIST, sambil mengklasifikasikan mereka ke dalam 10 kelas yang berbeda.\n",
|
||||
"\n",
|
||||
"## Kesimpulan\n",
|
||||
"\n",
|
||||
" * Kita telah mempelajari arsitektur jaringan saraf yang paling sederhana - perceptron satu lapis.\n",
|
||||
" * Kita telah mempelajari arsitektur jaringan neural yang paling sederhana - perceptron satu lapis.\n",
|
||||
" * Kita telah mengimplementasikan perceptron \"secara manual\", menggunakan prosedur pelatihan sederhana berbasis gradient descent.\n",
|
||||
" * Meskipun sederhana, perceptron satu lapis dapat menyelesaikan masalah yang cukup kompleks dalam pengenalan angka tulisan tangan.\n",
|
||||
" * Meskipun sederhana, perceptron satu lapis dapat menyelesaikan masalah yang cukup kompleks dalam pengenalan digit tulisan tangan.\n",
|
||||
" * Perceptron satu lapis adalah pengklasifikasi linear, sehingga memberikan kekuatan klasifikasi yang sama seperti regresi logistik.\n",
|
||||
" * Dalam ruang sampel, perceptron dapat memisahkan dua kelas data input menggunakan hyperplane.\n"
|
||||
]
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Penafian**: \nDokumen ini telah diterjemahkan menggunakan layanan terjemahan AI [Co-op Translator](https://github.com/Azure/co-op-translator). Meskipun kami berupaya untuk memberikan hasil yang akurat, harap diperhatikan bahwa terjemahan otomatis mungkin mengandung kesalahan atau ketidakakuratan. Dokumen asli dalam bahasa aslinya harus dianggap sebagai sumber yang berwenang. Untuk informasi yang bersifat kritis, disarankan menggunakan jasa terjemahan manusia profesional. Kami tidak bertanggung jawab atas kesalahpahaman atau interpretasi yang keliru yang timbul dari penggunaan terjemahan ini.\n"
|
||||
"\n---\n\n**Penafian**: \nDokumen ini telah diterjemahkan menggunakan layanan penerjemahan AI [Co-op Translator](https://github.com/Azure/co-op-translator). Meskipun kami berusaha untuk memberikan hasil yang akurat, harap diperhatikan bahwa terjemahan otomatis mungkin mengandung kesalahan atau ketidakakuratan. Dokumen asli dalam bahasa aslinya harus dianggap sebagai sumber yang otoritatif. Untuk informasi yang bersifat kritis, disarankan menggunakan jasa penerjemahan manusia profesional. Kami tidak bertanggung jawab atas kesalahpahaman atau penafsiran yang keliru yang timbul dari penggunaan terjemahan ini.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:37:40+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:25:20+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "id"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@
|
|||
"source": [
|
||||
"## Algoritmo di Addestramento\n",
|
||||
"\n",
|
||||
"Per addestrare il percettrone, dobbiamo determinare i pesi $\\mathbf{w}$ che minimizzano l'errore. L'errore è definito utilizzando il **criterio del percettrone**:\n",
|
||||
"Per addestrare il percettrone, dobbiamo determinare i pesi $\\mathbf{w}$ che minimizzeranno l'errore. L'errore è definito utilizzando il **criterio del percettrone**:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
|
|
@ -217,7 +217,7 @@
|
|||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"dove $\\eta$ è un **tasso di apprendimento**, e $\\tau\\in\\mathbb{N}$ - numero di iterazione.\n",
|
||||
"dove $\\eta$ è il **tasso di apprendimento**, e $\\tau\\in\\mathbb{N}$ - numero di iterazione.\n",
|
||||
"\n",
|
||||
"Definiamo questo algoritmo in Python:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Nota sul tasso di apprendimento**: Il parametro `learning_rate` (valore predefinito `0.01`) controlla quanto modifichiamo i pesi durante ogni passo di addestramento. Questo implementa la formula di aggiornamento del gradiente discendente:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Un tasso di apprendimento più alto (ad esempio, `1.0`) fa sì che il percettrone apprenda più velocemente, ma potrebbe superare la soluzione ottimale\n",
|
||||
"- Un tasso di apprendimento più basso (ad esempio, `0.001`) apprende più lentamente, ma potrebbe convergere in modo più preciso\n",
|
||||
"- Puoi sperimentare chiamando: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Come puoi vedere, l'accuratezza iniziale è intorno al 50%, ma aumenta rapidamente fino a valori più alti vicini al 90%.\n",
|
||||
"\n",
|
||||
"Visualizziamo come le classi sono separate. La nostra funzione di classificazione ha la forma $\\mathbf{w}^Tx$, ed è maggiore di 0 per una classe, mentre è inferiore a 0 per l'altra. Pertanto, la linea di separazione delle classi è definita da $\\mathbf{w}^Tx = 0$. Poiché abbiamo solo due dimensioni $x_0$ e $x_1$, l'equazione della linea sarebbe $w_0x_0+w_1x_1+w_2 = 0$ (ricorda che abbiamo esplicitamente definito una dimensione extra $x_2=1$). Tracciamo questa linea:\n"
|
||||
"Visualizziamo come le classi sono separate. La nostra funzione di classificazione ha la forma $\\mathbf{w}^Tx$, ed è maggiore di 0 per una classe, e minore di 0 per l'altra. Pertanto, la linea di separazione delle classi è definita da $\\mathbf{w}^Tx = 0$. Poiché abbiamo solo due dimensioni $x_0$ e $x_1$, l'equazione della linea sarà $w_0x_0+w_1x_1+w_2 = 0$ (ricorda che abbiamo esplicitamente definito una dimensione extra $x_2=1$). Tracciamo questa linea:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Sperimentare con i tassi di apprendimento\n",
|
||||
"\n",
|
||||
"Ora esploriamo come diversi tassi di apprendimento influenzano il processo di allenamento. Il tasso di apprendimento controlla la dimensione del passo nella discesa del gradiente - un iperparametro cruciale che influisce sia sulla velocità di convergenza che sulla stabilità.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Esperimento Interattivo sul Tasso di Apprendimento\n",
|
||||
"\n",
|
||||
"Usa il cursore qui sotto per sperimentare interattivamente con diversi tassi di apprendimento e osserva come influenzano il confine decisionale:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Valutazione sul dataset di test\n",
|
||||
"\n",
|
||||
"All'inizio, abbiamo messo da parte alcuni dati per il dataset di test. Vediamo quanto è accurato il nostro classificatore su questo dataset di test. Per fare ciò, espandiamo il dataset di test con una dimensione extra, lo moltiplichiamo per la matrice dei pesi e ci assicuriamo che il valore ottenuto abbia lo stesso segno dell'etichetta (+1 o -1). Sommiamo quindi tutti i valori booleani e dividiamo per la lunghezza del campione di test, per ottenere l'accuratezza:\n"
|
||||
"All'inizio, abbiamo messo da parte alcuni dati per il dataset di test. Vediamo quanto è accurato il nostro classificatore su questo dataset di test. Per farlo, espandiamo il dataset di test con una dimensione extra, lo moltiplichiamo per la matrice dei pesi e ci assicuriamo che il valore ottenuto abbia lo stesso segno dell'etichetta (+1 o -1). Sommiamo quindi tutti i valori booleani e dividiamo per la lunghezza del campione di test, per ottenere l'accuratezza:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -607,7 +733,7 @@
|
|||
"source": [
|
||||
"Come puoi vedere dal grafico sopra, l'accuratezza non supera mai il 75%, perché è impossibile tracciare una linea retta in modo da classificare correttamente tutti gli esempi possibili.\n",
|
||||
"\n",
|
||||
"Il problema XOR è un esempio classico delle limitazioni del perceptron, ed è stato evidenziato da Marvin Minsky e Seymour Papert nel 1969 nel loro libro [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Questa osservazione ha limitato la ricerca nell'ambito delle reti neurali per quasi 10 anni, anche se - e lo vedremo nella prossima sezione del nostro corso - i perceptron multi-strato sono perfettamente in grado di risolvere problemi di questo tipo.\n",
|
||||
"Il problema XOR è un esempio classico delle limitazioni del perceptron, ed è stato evidenziato da Marvin Minsky e Seymour Papert nel 1969 nel loro libro [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Questa osservazione ha limitato la ricerca nell'ambito delle reti neurali per quasi 10 anni, anche se - e lo vedremo nella prossima sezione del nostro corso - i perceptron multistrato sono perfettamente in grado di risolvere problemi di questo tipo.\n",
|
||||
"\n",
|
||||
"## Esempio Complesso - MNIST\n",
|
||||
"\n",
|
||||
|
|
@ -831,11 +957,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Si noti come l'accuratezza aumenti quasi al 100% molto rapidamente.\n",
|
||||
"Si noti come l'accuratezza aumenta quasi al 100% molto rapidamente.\n",
|
||||
"\n",
|
||||
"Per favore, sposta il cursore verso una posizione verso la fine dell'addestramento e osserva la matrice dei pesi tracciata a sinistra. Questa matrice ti permetterà di capire come funziona effettivamente il perceptron. Puoi vedere i valori di peso elevati al centro del campo, che corrispondono ai pixel tipicamente presenti per la cifra 1, e valori negativi bassi ai lati, dove si trovano le parti della cifra 0. Quindi, se la cifra presentata al perceptron è effettivamente 1, la parte centrale verrà moltiplicata per valori elevati, producendo un risultato positivo. Al contrario, quando il perceptron osserva la cifra 0, i pixel corrispondenti verranno moltiplicati per numeri negativi.\n",
|
||||
"Per favore, sposta il cursore verso una posizione alla fine dell'addestramento e osserva la matrice dei pesi tracciata a sinistra. Questa matrice ti permetterà di capire come funziona effettivamente il perceptron. Puoi vedere i valori di peso elevati al centro del campo, che corrispondono ai pixel tipicamente presenti per la cifra 1, e valori negativi bassi ai lati, dove si trovano le parti della cifra 0. Quindi, se la cifra presentata al perceptron è effettivamente 1, la parte centrale verrà moltiplicata per valori elevati, producendo un risultato positivo. Al contrario, quando il perceptron osserva la cifra 0, i pixel corrispondenti verranno moltiplicati per numeri negativi.\n",
|
||||
"\n",
|
||||
"> Potresti notare che se diamo al nostro perceptron una cifra 1 leggermente spostata orizzontalmente, in modo che i suoi pixel occupino il posto dove ci sono le parti verticali della cifra 0, potremmo ottenere un risultato errato. Poiché la natura del nostro dataset MNIST è tale che tutte le cifre sono centrate e posizionate correttamente, il perceptron si basa su questo per distinguere tra le cifre.\n",
|
||||
"> Potresti notare che se diamo al nostro perceptron una cifra 1 leggermente spostata orizzontalmente, in modo che i suoi pixel occupino la posizione dove ci sono le parti verticali della cifra 0, potremmo ottenere un risultato errato. Poiché la natura del nostro dataset MNIST è tale che tutte le cifre sono centrate e posizionate correttamente, il perceptron si basa su questo per distinguere tra le cifre.\n",
|
||||
"\n",
|
||||
"Ora proviamo con cifre diverse:\n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"Per qualche motivo, 2 e 5 non sono così facilmente separabili. Anche se otteniamo un'accuratezza relativamente alta (superiore all'85%), possiamo chiaramente vedere come il perceptron smetta di apprendere a un certo punto.\n",
|
||||
"\n",
|
||||
"Per capire perché accade, possiamo provare a utilizzare [l'Analisi delle Componenti Principali](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Si tratta di una tecnica di machine learning utilizzata per ridurre la dimensionalità del dataset di input, in modo da ottenere la migliore separabilità tra le classi.\n",
|
||||
"Per capire perché ciò accade, possiamo provare a utilizzare [l'Analisi delle Componenti Principali](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Si tratta di una tecnica di machine learning utilizzata per ridurre la dimensionalità del dataset di input, in modo da ottenere la migliore separabilità tra le classi.\n",
|
||||
"\n",
|
||||
"Nel nostro caso, un'immagine di input ha 784 pixel (caratteristiche di input), e vogliamo utilizzare la PCA per ridurre il numero di parametri a soli 2, così da poterli rappresentare su un grafico. Questi due parametri sarebbero una combinazione lineare delle caratteristiche originali, e possiamo considerare questa procedura come una \"rotazione\" del nostro spazio originale a 784 dimensioni, osservandone la proiezione nello spazio 2D, fino a ottenere la vista migliore che separa le classi.\n"
|
||||
"Nel nostro caso, un'immagine di input ha 784 pixel (caratteristiche di input), e vogliamo utilizzare la PCA per ridurre il numero di parametri a soli 2, così da poterli rappresentare su un grafico. Questi due parametri sarebbero una combinazione lineare delle caratteristiche originali, e possiamo considerare questa procedura come una \"rotazione\" del nostro spazio originale a 784 dimensioni, osservandone la proiezione nello spazio bidimensionale, fino a ottenere la vista migliore che separa le classi.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,14 +1155,14 @@
|
|||
"source": [
|
||||
"Come puoi vedere, 0 e 1 possono essere chiaramente separati da una linea retta. Questo indica che nello spazio originale a 784 dimensioni i punti corrispondenti alle cifre sono anche linearmente separabili. Nel caso di 2 e 5, non possiamo trovare una buona proiezione che separi chiaramente le cifre, e quindi ci sono alcuni casi di classificazione errata.\n",
|
||||
"\n",
|
||||
"> Più avanti in questo corso impareremo come creare classificatori non lineari utilizzando le Reti Neurali e come affrontare il problema delle cifre non correttamente allineate. Molto presto raggiungeremo un'accuratezza superiore al 99% nella classificazione delle cifre MNIST, classificandole in 10 classi diverse.\n",
|
||||
"> Più avanti in questo corso impareremo come creare classificatori non lineari utilizzando le Reti Neurali e come affrontare il problema delle cifre non correttamente allineate. Molto presto raggiungeremo un'accuratezza superiore al 99% nella classificazione delle cifre MNIST, classificandole in 10 diverse categorie.\n",
|
||||
"\n",
|
||||
"## Conclusioni\n",
|
||||
"\n",
|
||||
" * Abbiamo imparato l'architettura più semplice di rete neurale: il percettrone a uno strato.\n",
|
||||
" * Abbiamo implementato il percettrone \"a mano\", utilizzando una procedura di addestramento semplice basata sulla discesa del gradiente.\n",
|
||||
" * Nonostante la semplicità, il percettrone a uno strato può risolvere problemi piuttosto complessi di riconoscimento di cifre scritte a mano.\n",
|
||||
" * Il percettrone a uno strato è un classificatore lineare e, quindi, offre la stessa capacità di classificazione della regressione logistica.\n",
|
||||
" * Abbiamo imparato la più semplice architettura di rete neurale: il percettrone a un livello.\n",
|
||||
" * Abbiamo implementato il percettrone \"a mano\", utilizzando una semplice procedura di addestramento basata sulla discesa del gradiente.\n",
|
||||
" * Nonostante la semplicità, il percettrone a un livello può risolvere problemi piuttosto complessi di riconoscimento delle cifre scritte a mano.\n",
|
||||
" * Il percettrone a un livello è un classificatore lineare e, di conseguenza, offre la stessa capacità di classificazione della regressione logistica.\n",
|
||||
" * Nel campione di spazio, il percettrone può separare due classi di dati di input utilizzando un iperpiano.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Disclaimer**: \nQuesto documento è stato tradotto utilizzando il servizio di traduzione automatica [Co-op Translator](https://github.com/Azure/co-op-translator). Pur cercando di garantire la massima accuratezza, si prega di notare che le traduzioni automatiche possono contenere errori o imprecisioni. Il documento originale nella sua lingua nativa dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale effettuata da un traduttore umano. Non siamo responsabili per eventuali incomprensioni o interpretazioni errate derivanti dall'uso di questa traduzione.\n"
|
||||
"\n---\n\n**Clausola di esclusione della responsabilità**: \nQuesto documento è stato tradotto utilizzando il servizio di traduzione automatica [Co-op Translator](https://github.com/Azure/co-op-translator). Sebbene ci impegniamo per garantire l'accuratezza, si prega di notare che le traduzioni automatiche possono contenere errori o imprecisioni. Il documento originale nella sua lingua nativa dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale effettuata da un traduttore umano. Non siamo responsabili per eventuali incomprensioni o interpretazioni errate derivanti dall'uso di questa traduzione.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:25:43+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:12:52+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "it"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## おもちゃの問題\n",
|
||||
"\n",
|
||||
"まずはおもちゃの問題から始めましょう。ここでは、2つの入力特徴量を扱います。例えば、医学の分野では、腫瘍をそのサイズと年齢に基づいて良性か悪性かを分類したい場合があります。\n",
|
||||
"まずは、おもちゃの問題から始めましょう。ここでは、2つの入力特徴量を持つ例を考えます。例えば、医学では腫瘍をその大きさや年齢に基づいて良性か悪性かを分類したい場合があります。\n",
|
||||
"\n",
|
||||
"SciKit Learnライブラリの`make_classification`関数を使ってランダムな分類データセットを生成します:\n"
|
||||
]
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"データセットもプロットしましょう。\n"
|
||||
"データセットもプロットしましょう:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"ただし、一般的な線形モデルにはバイアスも含まれるべきです。つまり、理想的には $y$ を $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ として計算する必要があります。モデルを簡略化するために、入力特徴に常に1の値を持つ次元を追加することで、このバイアス項を取り除くことができます。\n"
|
||||
"ただし、一般的な線形モデルにはバイアスも含まれるべきです。つまり、理想的には $y$ を $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ として計算するべきです。モデルを簡略化するために、入力特徴に常に1である次元を1つ追加することで、このバイアス項を取り除くことができます。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -217,7 +217,7 @@
|
|||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"ここで、$\\eta$ は**学習率**、$\\tau\\in\\mathbb{N}$ はイテレーションの回数です。\n",
|
||||
"ここで、$\\eta$ は**学習率**であり、$\\tau\\in\\mathbb{N}$ はイテレーションの回数です。\n",
|
||||
"\n",
|
||||
"このアルゴリズムをPythonで定義してみましょう:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**学習率についての注意**: `learning_rate` パラメータ(デフォルトは `0.01`)は、各トレーニングステップで重みをどれだけ調整するかを制御します。これは、以下の勾配降下更新式を実装しています:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- 学習率が大きい場合(例: `1.0`)、パーセプトロンはより速く学習しますが、最適解を行き過ぎる可能性があります\n",
|
||||
"- 学習率が小さい場合(例: `0.001`)、学習速度は遅くなりますが、より正確に収束する可能性があります\n",
|
||||
"- 以下のように呼び出して試すことができます: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"ご覧の通り、初期の精度は約50%ですが、すぐに90%近くの高い値に向上します。\n",
|
||||
"\n",
|
||||
"クラスがどのように分離されているかを視覚化してみましょう。私たちの分類関数は $\\mathbf{w}^Tx$ の形をしており、あるクラスでは0より大きく、別のクラスでは0未満になります。したがって、クラス分離線は $\\mathbf{w}^Tx = 0$ によって定義されます。次に、次元が2つしかない場合($x_0$ と $x_1$)、この線の方程式は $w_0x_0+w_1x_1+w_2 = 0$ となります(追加の次元 $x_2=1$ を明示的に定義したことを思い出してください)。この線をプロットしてみましょう。\n"
|
||||
"クラスがどのように分離されているかを視覚化してみましょう。分類関数は $\\mathbf{w}^Tx$ の形をしており、あるクラスでは0より大きく、別のクラスでは0未満になります。したがって、クラス分離線は $\\mathbf{w}^Tx = 0$ によって定義されます。次に、次元が2つだけ ($x_0$ と $x_1$) ある場合、線の方程式は $w_0x_0+w_1x_1+w_2 = 0$ となります(追加の次元 $x_2=1$ を明示的に定義したことを思い出してください)。この線をプロットしてみましょう:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 学習率の実験\n",
|
||||
"\n",
|
||||
"次に、異なる学習率がトレーニングプロセスにどのように影響するかを調べてみましょう。学習率は勾配降下法におけるステップサイズを制御するもので、収束速度や安定性に影響を与える重要なハイパーパラメータです。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 学習率のインタラクティブ実験\n",
|
||||
"\n",
|
||||
"以下のスライダーを使用して、さまざまな学習率をインタラクティブに試し、それが決定境界にどのように影響するかを確認してください:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,9 +655,9 @@
|
|||
"source": [
|
||||
"## パーセプトロンの限界\n",
|
||||
"\n",
|
||||
"上記で見たように、パーセプトロンは**線形分類器**です。クラスが**線形分離可能**、つまり直線で分けられる場合には、2つのクラスをうまく区別できます。しかし、そうでない場合、パーセプトロンの学習プロセスは収束しません。\n",
|
||||
"上記で見たように、パーセプトロンは**線形分類器**です。クラス間が**線形分離可能**、つまり直線で分けられる場合には、2つのクラスをうまく区別できます。しかし、そうでない場合、パーセプトロンの学習プロセスは収束しません。\n",
|
||||
"\n",
|
||||
"パーセプトロンで解けない問題の最も明白な例は、いわゆる**XOR問題**です。ここでは、パーセプトロンにXOR論理関数を学習させたいと考えています。この関数の真理値表は以下の通りです:\n",
|
||||
"パーセプトロンでは解決できない問題の最も明白な例が、いわゆる**XOR問題**です。ここでは、パーセプトロンにXOR論理関数を学習させたいと考えています。この関数の真理値表は以下の通りです:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"グラフからわかるように、精度は75%を超えることはありません。これは、すべての例を正しく分類するような直線を引くことが不可能だからです。\n",
|
||||
"グラフから分かるように、精度は75%を超えることはありません。これは、すべての例を正しく分類するような直線を引くことが不可能だからです。\n",
|
||||
"\n",
|
||||
"XOR問題は、パーセプトロンの限界を示す古典的な例であり、1969年にマービン・ミンスキーとセイモア・パパートが著書『[Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book))』で指摘しました。この観察により、ニューラルネットワークの研究は約10年間停滞しました。しかし、次のセクションで学ぶように、多層パーセプトロンはこのような問題を完全に解決することができます。\n",
|
||||
"\n",
|
||||
"## 複雑な例 - MNIST\n",
|
||||
"\n",
|
||||
"パーセプトロンはXOR問題を解決できないものの、手書き文字認識のようなより複雑な問題を解決することができます。\n",
|
||||
"パーセプトロンはXOR問題を解くことはできませんが、手書き文字認識のような、より複雑な問題を解くことは可能です。\n",
|
||||
"\n",
|
||||
"機械学習を習得する際によく使用されるデータセットに、[MNIST](https://en.wikipedia.org/wiki/MNIST_database)があります。このデータセットは、改良された米国標準技術研究所(Modified National Institute of Standards and Technology)によって作成され、60000個の手書き数字のトレーニングセットが含まれています。これらの数字は、研究所の約250人の学生や職員から収集されました。また、異なる個人から収集された10000個の数字のテストデータセットも含まれています。\n",
|
||||
"\n",
|
||||
"すべての数字は、28x28ピクセルのグレースケール画像で表されています。\n",
|
||||
"\n",
|
||||
"> MNISTデータセットは、機械学習コンペティションを開催するサイト[Kaggle](https://www.kaggle.com/c/digit-recognizer)でトレーニングコンペティションとして利用可能です。MNIST数字の分類方法を学んだら、Kaggleにソリューションを提出して、他の参加者と比較して評価を確認することができます。\n",
|
||||
"> MNISTデータセットは、機械学習の競技会を開催するサイト[Kaggle](https://www.kaggle.com/c/digit-recognizer)でトレーニングコンペティションとして利用可能です。MNISTの数字を分類する方法を学んだら、Kaggleにソリューションを提出して、他の参加者と比較して評価を確認することができます。\n",
|
||||
"\n",
|
||||
"まず、MNISTデータセットを読み込みます:\n"
|
||||
]
|
||||
|
|
@ -833,11 +959,11 @@
|
|||
"source": [
|
||||
"精度が非常に速くほぼ100%に達することに注目してください。\n",
|
||||
"\n",
|
||||
"トレーニングの終盤にスライダーを移動し、左側にプロットされた重み行列を観察してください。この行列を見ることで、パーセプトロンが実際にどのように動作するかを理解することができます。フィールドの中央部分には、通常数字の「1」に対応するピクセルがあり、高い重み値が見られます。一方、両端には「0」の数字の部分に対応する低い負の値があります。そのため、パーセプトロンに提示された数字が実際に「1」である場合、中央部分が高い値で乗算され、正の結果が得られます。逆に、パーセプトロンが「0」を観察すると、対応するピクセルが負の数で乗算されます。\n",
|
||||
"トレーニングの終盤にスライダーを移動し、左側にプロットされた重み行列を観察してください。この行列を見れば、パーセプトロンがどのように動作するかを理解する手助けになります。フィールドの中央部分には、通常数字の「1」に対応するピクセルがあり、高い重み値が見られます。一方、数字の「0」の部分に対応する側面には低い負の値が見られます。そのため、パーセプトロンに提示された数字が実際に「1」であれば、中央部分が高い値で乗算され、正の結果が得られます。逆に、パーセプトロンが「0」を観察すると、対応するピクセルが負の数で乗算されます。\n",
|
||||
"\n",
|
||||
"> 数字「1」を横方向に少しずらして与えると、そのピクセルが「0」の垂直部分に対応する位置を占める場合、誤った結果が得られる可能性があることに気付くかもしれません。MNISTデータセットの性質上、すべての数字は中央に配置され、適切に位置付けられており、パーセプトロンはこれに依存して数字を区別しています。\n",
|
||||
"> 数字の「1」を横方向に少しずらして与えると、そのピクセルが「0」の垂直部分に対応する位置を占める場合、誤った結果が得られる可能性があることに気付くかもしれません。MNISTデータセットの性質上、すべての数字は中央に配置され、適切に位置付けられており、パーセプトロンはこれに依存して数字を区別しています。\n",
|
||||
"\n",
|
||||
"では、別の数字を試してみましょう:\n"
|
||||
"では、異なる数字を試してみましょう:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -913,7 +1039,7 @@
|
|||
"source": [
|
||||
"## 議論\n",
|
||||
"\n",
|
||||
"なぜか、2と5は簡単に分離できないことがあります。正確性が比較的高い(85%以上)にもかかわらず、パーセプトロンがある時点で学習を停止してしまう様子が明らかです。\n",
|
||||
"なぜか、2と5は簡単に分離できないことがあります。精度が比較的高い(85%以上)にもかかわらず、パーセプトロンがある時点で学習を停止してしまう様子が明らかに見て取れます。\n",
|
||||
"\n",
|
||||
"これがなぜ起こるのかを理解するために、[主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) を試してみることができます。PCAは、入力データセットの次元を削減し、クラス間の分離性を最大化する機械学習技術です。\n",
|
||||
"\n",
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"ご覧の通り、0と1は直線で明確に分離することができます。これは、元の784次元空間でも数字に対応する点が線形分離可能であることを示しています。一方、2と5の場合、数字を明確に分離する良い投影を見つけることができず、誤分類が発生するケースがあります。\n",
|
||||
"ご覧の通り、0と1は直線で明確に分離することができます。これは、元の784次元空間でも数字に対応する点が線形分離可能であることを示しています。一方で、2と5の場合は、数字を明確に分離する良い投影を見つけることができず、誤分類が発生するケースがあります。\n",
|
||||
"\n",
|
||||
"> このコースの後半では、ニューラルネットワークを使用して非線形分類器を作成する方法や、数字が適切に整列していない問題への対処方法を学びます。すぐにMNISTの数字分類で99%以上の精度を達成し、10種類のクラスに分類できるようになります。\n",
|
||||
"> このコースの後半では、ニューラルネットワークを使用して非線形分類器を作成する方法や、数字が適切に整列していない問題への対処方法を学びます。近いうちに、MNISTの数字分類で10種類のクラスに分類しながら99%以上の精度を達成することができます。\n",
|
||||
"\n",
|
||||
"## まとめ\n",
|
||||
"\n",
|
||||
" * 最も基本的なニューラルネットワークのアーキテクチャである1層パーセプトロンについて学びました。\n",
|
||||
" * 勾配降下法に基づくシンプルなトレーニング手順を使用して、パーセプトロンを「手作業」で実装しました。\n",
|
||||
" * シンプルでありながら、1層パーセプトロンは手書き数字認識という比較的複雑な問題を解決できます。\n",
|
||||
" * シンプルでありながら、1層パーセプトロンは手書き数字認識という比較的複雑な問題を解決することができます。\n",
|
||||
" * 1層パーセプトロンは線形分類器であり、ロジスティック回帰と同じ分類能力を提供します。\n",
|
||||
" * サンプル空間では、パーセプトロンは入力データの2つのクラスを超平面を使って分離することができます。\n"
|
||||
" * サンプル空間では、パーセプトロンは入力データの2つのクラスをハイパープレーンで分離することができます。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## クレジット\n",
|
||||
"\n",
|
||||
"このノートブックは [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) の一部であり、[Dmitry Soshnikov](http://soshnikov.com) によって作成されました。Microsoft Research Cambridgeで開催されたニューラルネットワークワークショップに触発されています。一部のコードや説明資料は、[Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/)、[Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) のプレゼンテーションから、また [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) リポジトリから引用されています。\n"
|
||||
"このノートブックは [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) の一部であり、[Dmitry Soshnikov](http://soshnikov.com) によって作成されました。Microsoft Research Cambridge におけるニューラルネットワークワークショップに触発されています。一部のコードや説明資料は、[Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) および [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) のプレゼンテーションから、また [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) リポジトリから引用されています。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**免責事項**: \nこの文書は、AI翻訳サービス [Co-op Translator](https://github.com/Azure/co-op-translator) を使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があることをご承知ください。元の言語で記載された文書が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤解釈について、当方は責任を負いません。\n"
|
||||
"\n---\n\n**免責事項**: \nこの文書は、AI翻訳サービス[Co-op Translator](https://github.com/Azure/co-op-translator)を使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があることをご承知ください。元の言語で記載された文書が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤解釈について、当方は責任を負いません。\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:16:40+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:02:55+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "ja"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@
|
|||
"\n",
|
||||
"> 이 노트북은 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners)의 일부입니다. 전체 학습 자료는 해당 저장소를 방문하세요.\n",
|
||||
"\n",
|
||||
"앞서 논의했듯이, 퍼셉트론은 **이진 분류 문제**를 해결할 수 있게 해줍니다. 즉, 입력 예제를 두 개의 클래스, **긍정**과 **부정**으로 분류할 수 있습니다.\n",
|
||||
"앞서 논의했듯이, 퍼셉트론은 **이진 분류 문제**를 해결할 수 있도록 해줍니다. 즉, 입력 예제를 두 개의 클래스, **긍정**과 **부정**으로 분류할 수 있습니다.\n",
|
||||
"\n",
|
||||
"먼저 필요한 라이브러리를 몇 가지 가져오겠습니다.\n"
|
||||
"먼저, 필요한 라이브러리를 몇 가지 가져오겠습니다.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## 퍼셉트론\n",
|
||||
"\n",
|
||||
"퍼셉트론은 이진 분류기이므로, 각 입력 벡터 $x$에 대해 퍼셉트론의 출력은 클래스에 따라 +1 또는 -1이 됩니다. 출력은 다음 공식을 사용하여 계산됩니다:\n",
|
||||
"퍼셉트론은 이진 분류기이므로, 각 입력 벡터 $x$에 대해 퍼셉트론의 출력은 클래스에 따라 +1 또는 -1이 됩니다. 출력은 다음 공식으로 계산됩니다:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"하지만 일반적인 선형 모델은 바이어스도 포함해야 하므로, 이상적으로는 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$로 $y$를 계산해야 합니다. 모델을 간소화하기 위해, 항상 1로 설정된 추가 차원을 입력 특징에 추가하여 이 바이어스 항을 제거할 수 있습니다:\n"
|
||||
"하지만 일반적인 선형 모델은 바이어스도 포함해야 하므로, 이상적으로는 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$로 $y$를 계산해야 합니다. 모델을 간소화하기 위해, 항상 1로 설정된 추가 차원을 입력 특징에 추가함으로써 이 바이어스 항을 제거할 수 있습니다:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**학습률에 대한 참고사항**: `learning_rate` 매개변수(기본값 `0.01`)는 각 학습 단계에서 가중치를 얼마나 조정할지를 결정합니다. 이는 다음과 같은 경사 하강 업데이트 공식을 구현합니다:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- 학습률이 크면(예: `1.0`) 퍼셉트론이 더 빠르게 학습하지만 최적의 해를 지나칠 수 있습니다.\n",
|
||||
"- 학습률이 작으면(예: `0.001`) 학습 속도가 느려지지만 더 정확하게 수렴할 수 있습니다.\n",
|
||||
"- 다음을 호출하여 실험해볼 수 있습니다: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"보시다시피 초기 정확도는 약 50% 정도이지만, 빠르게 증가하여 90%에 가까운 높은 값에 도달합니다.\n",
|
||||
"\n",
|
||||
"이제 클래스가 어떻게 분리되는지 시각화해 보겠습니다. 우리의 분류 함수는 $\\mathbf{w}^Tx$ 형태이며, 한 클래스에서는 0보다 크고, 다른 클래스에서는 0보다 작습니다. 따라서 클래스 분리선은 $\\mathbf{w}^Tx = 0$으로 정의됩니다. 우리가 두 개의 차원 $x_0$과 $x_1$만 가지고 있으므로, 선의 방정식은 $w_0x_0+w_1x_1+w_2 = 0$이 됩니다 (추가 차원 $x_2=1$을 명시적으로 정의한 것을 기억하세요). 이제 이 선을 그려보겠습니다:\n"
|
||||
"이제 클래스가 어떻게 분리되는지 시각화해 보겠습니다. 우리의 분류 함수는 $\\mathbf{w}^Tx$ 형태이며, 한 클래스에서는 0보다 크고 다른 클래스에서는 0보다 작습니다. 따라서 클래스 분리 선은 $\\mathbf{w}^Tx = 0$으로 정의됩니다. 우리가 가진 차원이 $x_0$와 $x_1$ 두 개뿐이므로, 선의 방정식은 $w_0x_0+w_1x_1+w_2 = 0$이 됩니다 (추가 차원 $x_2=1$을 명시적으로 정의한 것을 기억하세요). 이제 이 선을 그려보겠습니다:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 학습률 실험하기\n",
|
||||
"\n",
|
||||
"이제 다양한 학습률이 훈련 과정에 어떤 영향을 미치는지 살펴보겠습니다. 학습률은 경사 하강법에서 단계 크기를 조절하는 중요한 하이퍼파라미터로, 수렴 속도와 안정성에 모두 영향을 미칩니다.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 학습률 실험 인터랙티브\n",
|
||||
"\n",
|
||||
"아래 슬라이더를 사용하여 다양한 학습률을 실험적으로 조정하고, 학습률이 결정 경계에 어떤 영향을 미치는지 확인하세요:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## 테스트 데이터셋 평가\n",
|
||||
"\n",
|
||||
"처음에 일부 데이터를 테스트 데이터셋으로 분리해 두었습니다. 이제 이 테스트 데이터셋에서 우리의 분류기가 얼마나 정확한지 확인해 봅시다. 이를 위해 테스트 데이터셋에 추가 차원을 확장하고, 가중치 행렬을 곱한 뒤, 얻어진 값이 레이블(+1 또는 -1)과 동일한 부호인지 확인합니다. 그런 다음 모든 불리언 값을 합산하고 테스트 샘플의 길이로 나누어 정확도를 계산합니다:\n"
|
||||
"처음에 일부 데이터를 테스트 데이터셋으로 분리해 두었습니다. 이제 이 테스트 데이터셋에서 우리의 분류기가 얼마나 정확한지 확인해 보겠습니다. 이를 위해 테스트 데이터셋에 추가 차원을 확장하고, 가중치 행렬을 곱한 뒤, 얻어진 값이 레이블(+1 또는 -1)과 동일한 부호인지 확인합니다. 그런 다음 모든 불리언 값을 합산하고 테스트 샘플의 길이로 나누어 정확도를 계산합니다:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## 훈련 과정 관찰하기\n",
|
||||
"\n",
|
||||
"이전에 훈련 중 정확도가 감소하는 것을 본 적이 있습니다. 훈련 중 분리선이 어떻게 변화하는지 보는 것도 흥미로울 것입니다. 아래 코드는 모든 것을 하나의 그래프에 시각화하며, 슬라이더를 움직여 훈련 과정을 \"시간 여행\"하듯 관찰할 수 있습니다.\n"
|
||||
"이전에 훈련 중 정확도가 감소하는 것을 본 적이 있습니다. 훈련 중 분리선이 어떻게 변화하는지 보는 것도 흥미로울 것입니다. 아래 코드는 모든 것을 하나의 그래프에 시각화하며, 슬라이더를 움직여 훈련 과정을 \"시간 여행\"하듯이 살펴볼 수 있습니다.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,9 +655,9 @@
|
|||
"source": [
|
||||
"## 퍼셉트론의 한계\n",
|
||||
"\n",
|
||||
"위에서 본 것처럼 퍼셉트론은 **선형 분류기**입니다. 두 클래스가 **선형적으로 분리 가능**할 경우, 즉 직선으로 구분할 수 있는 경우에는 잘 구분할 수 있습니다. 하지만 그렇지 않은 경우에는 퍼셉트론의 학습 과정이 수렴하지 않습니다.\n",
|
||||
"위에서 본 것처럼 퍼셉트론은 **선형 분류기**입니다. 두 클래스가 **선형적으로 분리 가능**할 경우, 즉 직선으로 분리할 수 있는 경우에는 잘 구분할 수 있습니다. 그렇지 않으면 퍼셉트론 학습 과정이 수렴하지 않습니다.\n",
|
||||
"\n",
|
||||
"퍼셉트론으로 해결할 수 없는 문제의 가장 명확한 예는 **XOR 문제**입니다. 우리는 퍼셉트론이 다음과 같은 진리표를 가진 XOR 부울 함수를 학습하도록 하고 싶습니다:\n",
|
||||
"퍼셉트론으로 해결할 수 없는 문제의 가장 명확한 예는 소위 **XOR 문제**입니다. 우리는 퍼셉트론이 다음과 같은 진리표를 가진 XOR 부울 함수를 학습하기를 원합니다:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"위의 그래프에서 볼 수 있듯이, 정확도는 절대 75%를 넘지 않습니다. 이는 모든 예제를 올바르게 분류할 수 있도록 직선을 그리는 것이 불가능하기 때문입니다.\n",
|
||||
"위의 그래프에서 볼 수 있듯이, 정확도가 75%를 넘지 않습니다. 이는 모든 가능한 예제를 올바르게 분류할 수 있도록 직선을 그리는 것이 불가능하기 때문입니다.\n",
|
||||
"\n",
|
||||
"XOR 문제는 퍼셉트론의 한계를 보여주는 고전적인 예로, 1969년 Marvin Minsky와 Seymour Papert가 그들의 책 [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book))에서 지적한 바 있습니다. 이 관찰은 신경망 연구를 거의 10년 동안 제한했지만, - 이는 우리 강의의 다음 섹션에서 보게 될 것입니다 - 다층 퍼셉트론은 이러한 문제를 완벽히 해결할 수 있습니다.\n",
|
||||
"XOR 문제는 퍼셉트론의 한계를 보여주는 고전적인 사례로, 1969년 Marvin Minsky와 Seymour Papert가 그들의 책 [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book))에서 지적한 바 있습니다. 이 관찰은 신경망 분야의 연구를 거의 10년 동안 제한했지만, - 그리고 우리는 이 강좌의 다음 섹션에서 이를 확인할 것입니다 - 다층 퍼셉트론은 이러한 문제를 완벽히 해결할 수 있습니다.\n",
|
||||
"\n",
|
||||
"## 복잡한 예제 - MNIST\n",
|
||||
"\n",
|
||||
"퍼셉트론이 XOR 문제를 해결할 수는 없지만, 손글씨 문자 인식과 같은 훨씬 더 복잡한 문제를 해결할 수 있습니다.\n",
|
||||
"퍼셉트론이 XOR 문제를 해결할 수 없더라도, 손글씨 문자 인식과 같은 훨씬 더 복잡한 문제를 해결할 수 있습니다.\n",
|
||||
"\n",
|
||||
"머신 러닝을 익힐 때 자주 사용되는 데이터셋은 [MNIST](https://en.wikipedia.org/wiki/MNIST_database)라고 불립니다. 이 데이터셋은 수정된 미국 표준 기술 연구소(Modified National Institute of Standards and Technology)에 의해 만들어졌으며, 약 250명의 학생과 연구소 직원들로부터 수집된 60000개의 손글씨 숫자로 구성된 학습 세트를 포함하고 있습니다. 또한, 다른 개인들로부터 수집된 10000개의 숫자로 구성된 테스트 데이터셋도 있습니다.\n",
|
||||
"머신러닝을 익힐 때 자주 사용되는 데이터셋은 [MNIST](https://en.wikipedia.org/wiki/MNIST_database)라고 불립니다. 이 데이터셋은 수정된 미국 표준 기술 연구소(Modified National Institute of Standards and Technology)에 의해 만들어졌으며, 약 250명의 학생과 연구소 직원으로부터 수집된 60000개의 손글씨 숫자로 구성된 학습 세트를 포함하고 있습니다. 또한, 다른 개인들로부터 수집된 10000개의 숫자로 구성된 테스트 데이터셋도 있습니다.\n",
|
||||
"\n",
|
||||
"모든 숫자는 28x28 픽셀 크기의 그레이스케일 이미지로 표현됩니다.\n",
|
||||
"\n",
|
||||
"> MNIST 데이터셋은 머신 러닝 대회와 콘테스트를 주최하는 사이트인 [Kaggle](https://www.kaggle.com/c/digit-recognizer)에서 학습 대회로 제공됩니다. MNIST 숫자를 분류하는 방법을 배우고 나면, Kaggle에 솔루션을 제출하여 다른 참가자들 사이에서 어떻게 평가되는지 확인할 수 있습니다.\n",
|
||||
"> MNIST 데이터셋은 머신러닝 대회와 콘테스트를 주최하는 사이트인 [Kaggle](https://www.kaggle.com/c/digit-recognizer)에서 학습용 대회로 제공됩니다. MNIST 숫자를 분류하는 방법을 배우고 나면, Kaggle에 솔루션을 제출하여 다른 참가자들 사이에서 자신의 평가를 확인할 수 있습니다.\n",
|
||||
"\n",
|
||||
"우리는 MNIST 데이터셋을 로드하는 것으로 시작합니다:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"퍼셉트론은 이진 분류기이기 때문에, 우리는 문제를 두 개의 숫자만 인식하도록 제한할 것입니다. 아래 함수는 주어진 두 숫자로 긍정 및 부정 샘플 배열을 채우고 (명확성을 위해 해당 숫자의 샘플도 표시할 것입니다).\n"
|
||||
"퍼셉트론은 이진 분류기이기 때문에, 우리는 문제를 두 개의 숫자만 인식하도록 제한할 것입니다. 아래 함수는 주어진 두 숫자로 양성 및 음성 샘플 배열을 채우고 (명확성을 위해 해당 숫자 샘플도 표시할 것입니다).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -735,7 +861,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"우리는 0과 1을 구분하는 것부터 시작할 것입니다:\n"
|
||||
"우리는 0과 1을 구분하려고 시도하는 것으로 시작할 것입니다:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"정확도가 매우 빠르게 거의 100%에 도달하는 것을 주목하세요.\n",
|
||||
"\n",
|
||||
"슬라이더를 훈련 후반부로 이동시키고 왼쪽에 표시된 가중치 행렬을 관찰해 보세요. 이 행렬은 퍼셉트론이 실제로 어떻게 작동하는지 이해하는 데 도움을 줄 것입니다. 필드 중앙에 높은 가중치 값이 있는 것을 볼 수 있는데, 이는 일반적으로 숫자 1에 해당하는 픽셀을 나타냅니다. 반면, 양쪽 끝에는 숫자 0의 일부에 해당하는 낮은 음수 값이 있습니다. 따라서 퍼셉트론에 제시된 숫자가 실제로 1이라면, 중앙 부분이 높은 값으로 곱해져 긍정적인 결과를 생성합니다. 반대로 퍼셉트론이 숫자 0을 관찰할 때는 해당 픽셀이 음수로 곱해집니다.\n",
|
||||
"슬라이더를 훈련 후반부로 이동시키고, 왼쪽에 표시된 가중치 행렬을 관찰해 보세요. 이 행렬은 퍼셉트론이 실제로 어떻게 작동하는지 이해하는 데 도움을 줄 것입니다. 필드 중앙에 높은 가중치 값이 있는 것을 볼 수 있는데, 이는 일반적으로 숫자 1에 해당하는 픽셀에 해당하며, 0 숫자의 일부가 있는 양쪽에는 낮은 음수 값이 있습니다. 따라서 퍼셉트론에 제시된 숫자가 실제로 1이라면, 중앙 부분이 높은 값으로 곱해져 긍정적인 결과를 생성합니다. 반대로 퍼셉트론이 0을 관찰할 때는 해당 픽셀이 음수로 곱해집니다.\n",
|
||||
"\n",
|
||||
"> 숫자 1을 약간 수평으로 이동시켜 픽셀이 숫자 0의 수직 부분에 해당하는 위치를 차지하도록 하면, 잘못된 결과를 받을 수 있다는 점을 알 수 있습니다. MNIST 데이터셋의 특성상 모든 숫자가 중앙에 위치하고 올바르게 정렬되어 있으며, 퍼셉트론은 이를 기반으로 숫자를 구분합니다.\n",
|
||||
"> 숫자 1이 약간 수평으로 이동되어 픽셀이 0의 수직 부분이 있는 위치를 차지하게 되면, 잘못된 결과를 받을 수 있다는 점을 주목할 수 있습니다. MNIST 데이터셋의 특성상 모든 숫자가 중앙에 위치하고 올바르게 정렬되어 있으며, 퍼셉트론은 이를 기반으로 숫자를 구분합니다.\n",
|
||||
"\n",
|
||||
"이제 다른 숫자를 시도해 봅시다:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## 논의\n",
|
||||
"\n",
|
||||
"어떤 이유에서인지, 2와 5는 쉽게 분리되지 않습니다. 비록 비교적 높은 정확도(85% 이상)를 얻었지만, 퍼셉트론이 어느 시점에서 학습을 멈추는 것을 분명히 볼 수 있습니다.\n",
|
||||
"어떤 이유에서인지, 2와 5는 쉽게 분리되지 않습니다. 정확도가 비교적 높게 나와도 (85% 이상), 퍼셉트론이 어느 시점에서 학습을 멈추는 것을 분명히 확인할 수 있습니다.\n",
|
||||
"\n",
|
||||
"이 현상을 이해하기 위해 [주성분 분석](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)을 사용해 볼 수 있습니다. PCA는 입력 데이터셋의 차원을 줄여 클래스 간의 최적의 분리 가능성을 얻는 데 사용되는 머신 러닝 기법입니다.\n",
|
||||
"이 현상을 이해하기 위해 [주성분 분석](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)을 사용해 볼 수 있습니다. PCA는 입력 데이터셋의 차원을 줄여 클래스 간의 최적의 분리 가능성을 얻도록 하는 머신 러닝 기법입니다.\n",
|
||||
"\n",
|
||||
"우리의 경우, 입력 이미지는 784개의 픽셀(입력 특징)을 가지고 있으며, PCA를 사용하여 매개변수 수를 2개로 줄이고 이를 그래프에 표시하려고 합니다. 이 두 매개변수는 원래 특징들의 선형 결합이 될 것이며, 이 과정을 원래의 784차원 공간을 \"회전\"시키고 이를 2차원 공간에 투영하여 클래스 간의 최적의 분리를 제공하는 뷰를 얻는 것으로 볼 수 있습니다.\n"
|
||||
"우리의 경우, 입력 이미지는 784개의 픽셀(입력 특징)을 가지고 있으며, PCA를 사용하여 매개변수 수를 2개로 줄이고 이를 그래프에 표시하려고 합니다. 이 두 매개변수는 원래 특징들의 선형 결합이 될 것이며, 이 과정을 원래의 784차원 공간을 \"회전\"시키고 이를 2차원 공간에 투영하여 클래스 간의 분리가 가장 잘 이루어지는 뷰를 얻는 것으로 볼 수 있습니다.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"0과 1은 직선으로 명확히 구분될 수 있다는 것을 알 수 있습니다. 이는 원래의 784차원 공간에서도 숫자에 해당하는 점들이 선형적으로 분리 가능하다는 것을 나타냅니다. 하지만 2와 5의 경우, 숫자를 명확히 구분할 수 있는 적절한 투영을 찾을 수 없으며, 따라서 잘못된 분류 사례가 발생할 수 있습니다.\n",
|
||||
"0과 1은 직선으로 명확히 구분될 수 있다는 것을 알 수 있습니다. 이는 원래의 784차원 공간에서도 숫자에 해당하는 점들이 선형적으로 구분 가능하다는 것을 나타냅니다. 하지만 2와 5의 경우, 숫자를 명확히 구분할 수 있는 좋은 투영을 찾을 수 없으며, 이로 인해 잘못된 분류 사례가 발생할 수 있습니다.\n",
|
||||
"\n",
|
||||
"> 이 과정에서 우리는 신경망을 사용하여 비선형 분류기를 만드는 방법과 숫자가 제대로 정렬되지 않는 문제를 해결하는 방법을 배우게 될 것입니다. 곧 MNIST 숫자 분류에서 99% 이상의 정확도를 달성하며, 숫자를 10개의 다른 클래스에 분류할 수 있게 될 것입니다.\n",
|
||||
"> 이 과정의 후반부에서는 신경망을 사용하여 비선형 분류기를 만드는 방법과 숫자가 제대로 정렬되지 않는 문제를 해결하는 방법을 배우게 될 것입니다. 곧 MNIST 숫자 분류에서 99% 이상의 정확도를 달성하며, 숫자를 10개의 다른 클래스에 분류할 수 있게 될 것입니다.\n",
|
||||
"\n",
|
||||
"## 주요 내용\n",
|
||||
"\n",
|
||||
" * 가장 간단한 신경망 구조인 단일 계층 퍼셉트론에 대해 배웠습니다.\n",
|
||||
" * 간단한 경사 하강법 기반의 학습 절차를 사용하여 퍼셉트론을 \"직접 구현\"했습니다.\n",
|
||||
" * 단순함에도 불구하고, 단일 계층 퍼셉트론은 손글씨 숫자 인식이라는 비교적 복잡한 문제를 해결할 수 있습니다.\n",
|
||||
" * 단순함에도 불구하고, 단일 계층 퍼셉트론은 손글씨 숫자 인식과 같은 복잡한 문제를 해결할 수 있습니다.\n",
|
||||
" * 단일 계층 퍼셉트론은 선형 분류기이며, 따라서 로지스틱 회귀와 동일한 분류 능력을 제공합니다.\n",
|
||||
" * 샘플 공간에서 퍼셉트론은 초평면을 사용하여 입력 데이터의 두 클래스를 분리할 수 있습니다.\n"
|
||||
" * 샘플 공간에서 퍼셉트론은 초평면을 사용하여 입력 데이터의 두 클래스를 구분할 수 있습니다.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**면책 조항**: \n이 문서는 AI 번역 서비스 [Co-op Translator](https://github.com/Azure/co-op-translator)를 사용하여 번역되었습니다. 정확성을 위해 최선을 다하고 있으나, 자동 번역에는 오류나 부정확성이 포함될 수 있습니다. 원본 문서의 원어 버전을 권위 있는 자료로 간주해야 합니다. 중요한 정보에 대해서는 전문적인 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.\n"
|
||||
"\n---\n\n**면책 조항**: \n이 문서는 AI 번역 서비스 [Co-op Translator](https://github.com/Azure/co-op-translator)를 사용하여 번역되었습니다. 정확성을 위해 노력하고 있지만, 자동 번역에는 오류나 부정확성이 포함될 수 있습니다. 원본 문서의 모국어 버전이 권위 있는 자료로 간주되어야 합니다. 중요한 정보의 경우, 전문적인 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:17:39+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:03:57+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "ko"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Žaislinė problema\n",
|
||||
"## Žaislinė užduotis\n",
|
||||
"\n",
|
||||
"Pradėkime nuo žaislinės problemos, kurioje turime du įvesties požymius. Pavyzdžiui, medicinoje galime norėti klasifikuoti auglius į gerybinius ir piktybinius, priklausomai nuo jų dydžio ir amžiaus.\n",
|
||||
"Pradėkime nuo žaislinės užduoties, kurioje turime du įvesties požymius. Pavyzdžiui, medicinoje galime norėti klasifikuoti auglius į gerybinius ir piktybinius, priklausomai nuo jų dydžio ir amžiaus.\n",
|
||||
"\n",
|
||||
"Sukursime atsitiktinį klasifikacijos duomenų rinkinį naudodami `make_classification` funkciją iš SciKit Learn bibliotekos:\n"
|
||||
]
|
||||
|
|
@ -158,7 +158,7 @@
|
|||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"kur $\\mathbf{w}$ yra svorių vektorius, o $f$ yra žingsninė aktyvavimo funkcija:\n",
|
||||
"kur $\\mathbf{w}$ yra svorių vektorius, o $f$ yra laiptinė aktyvavimo funkcija:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Tačiau bendras linijinis modelis taip pat turėtų turėti poslinkį (bias), t. y. idealiu atveju $y$ turėtume skaičiuoti kaip $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Norėdami supaprastinti mūsų modelį, galime atsikratyti šio poslinkio termino, pridėdami dar vieną dimensiją prie mūsų įvesties požymių, kuri visada lygi 1:\n"
|
||||
"Tačiau bendras linijinis modelis taip pat turėtų turėti poslinkį (bias), t. y. idealiu atveju $y$ turėtume skaičiuoti kaip $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Norėdami supaprastinti mūsų modelį, galime atsisakyti šio poslinkio termino, pridėdami dar vieną dimensiją prie mūsų įvesties požymių, kuri visada lygi 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Pastaba apie mokymosi tempą**: Parametras `learning_rate` (numatytasis `0.01`) reguliuoja, kiek koreguojame svorius kiekvieno mokymo žingsnio metu. Tai įgyvendina gradientinio nusileidimo atnaujinimo formulę:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Didesnis mokymosi tempas (pvz., `1.0`) leidžia perceptronui mokytis greičiau, tačiau gali praleisti optimalią sprendimo vietą\n",
|
||||
"- Mažesnis mokymosi tempas (pvz., `0.001`) mokosi lėčiau, bet gali tiksliau susikoncentruoti ties sprendimu\n",
|
||||
"- Galite eksperimentuoti, iškviesdami: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,7 +324,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Kaip matote, pradinė tikslumo vertė yra apie 50%, tačiau ji greitai padidėja iki aukštesnių, beveik 90%, reikšmių.\n",
|
||||
"Kaip matote, pradinė tikslumo vertė yra apie 50%, tačiau ji greitai kyla iki aukštesnių, beveik 90%, reikšmių.\n",
|
||||
"\n",
|
||||
"Pažvelkime, kaip klasės yra atskirtos. Mūsų klasifikavimo funkcija atrodo kaip $\\mathbf{w}^Tx$, ir ji yra didesnė nei 0 vienai klasei, o mažesnė nei 0 kitai. Taigi, klasių atskyrimo linija apibrėžiama kaip $\\mathbf{w}^Tx = 0$. Kadangi turime tik du matmenis $x_0$ ir $x_1$, linijos lygtis būtų $w_0x_0+w_1x_1+w_2 = 0$ (prisiminkite, kad aiškiai apibrėžėme papildomą matmenį $x_2=1$). Nubraižykime šią liniją:\n"
|
||||
]
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Eksperimentavimas su mokymosi tempais\n",
|
||||
"\n",
|
||||
"Dabar panagrinėkime, kaip skirtingi mokymosi tempai veikia mokymo procesą. Mokymosi tempas reguliuoja žingsnio dydį gradientinio nusileidimo metu – tai svarbus hiperparametras, kuris daro įtaką tiek konvergencijos greičiui, tiek stabilumui.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktyvus mokymosi tempo eksperimentas\n",
|
||||
"\n",
|
||||
"Naudokite žemiau esantį slankiklį, kad interaktyviai eksperimentuotumėte su skirtingais mokymosi tempais ir pamatytumėte, kaip jie veikia sprendimo ribą:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Įvertinimas testavimo duomenų rinkinyje\n",
|
||||
"\n",
|
||||
"Pradžioje mes atskyrėme dalį duomenų testavimo duomenų rinkiniui. Pažiūrėkime, koks tikslus mūsų klasifikatorius yra šiame testavimo duomenų rinkinyje. Norėdami tai padaryti, mes taip pat praplečiame testavimo duomenų rinkinį papildoma dimensija, padauginame iš svorių matricos ir įsitikiname, kad gauta reikšmė turi tą patį ženklą kaip ir etiketė (+1 arba -1). Tada sudedame visas logines reikšmes ir padalijame iš testavimo pavyzdžių ilgio, kad gautume tikslumą:\n"
|
||||
"Pradžioje mes atskyrėme dalį duomenų testavimo duomenų rinkiniui. Pažiūrėkime, kaip tiksliai mūsų klasifikatorius veikia su šiuo testavimo duomenų rinkiniu. Norėdami tai padaryti, mes taip pat praplečiame testavimo duomenų rinkinį papildoma dimensija, padauginame iš svorių matricos ir įsitikiname, kad gauta vertė turi tą patį ženklą kaip ir etiketė (+1 arba -1). Tada sudedame visas logines reikšmes ir padaliname iš testavimo pavyzdžių ilgio, kad gautume tikslumą:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Stebėjimas mokymo proceso metu\n",
|
||||
"\n",
|
||||
"Anksčiau matėme, kaip tikslumas mažėja mokymo metu. Būtų įdomu pamatyti, kaip keičiasi atskyrimo linija mokymo proceso metu. Žemiau pateiktas kodas vizualizuos viską viename grafike, ir jūs galėsite perkelti slankiklį, kad „keliautumėte laiku“ per mokymo procesą.\n"
|
||||
"Anksčiau matėme, kaip tikslumas mažėja mokymo metu. Būtų įdomu pamatyti, kaip mokymo metu keičiasi atskyrimo linija. Žemiau pateiktas kodas vizualizuos viską viename grafike, ir jūs galėsite perkelti slankiklį, kad „keliautumėte laiku“ per mokymo procesą.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -605,15 +731,15 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Kaip matote iš aukščiau pateikto grafiko, tikslumas niekada neviršija 75%, nes neįmanoma nubrėžti tiesios linijos taip, kad būtų teisingai apdoroti visi galimi pavyzdžiai.\n",
|
||||
"Kaip matote iš aukščiau pateikto grafiko, tikslumas niekada neviršija 75%, nes neįmanoma nubrėžti tiesės taip, kad būtų teisingai klasifikuoti visi galimi pavyzdžiai.\n",
|
||||
"\n",
|
||||
"XOR problema yra klasikinis perceptrono apribojimų pavyzdys, kurį 1969 metais savo knygoje [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) paminėjo Marvin Minsky ir Seymour Papert. Šis pastebėjimas beveik 10 metų apribojo tyrimus neuroninių tinklų srityje, nors - kaip pamatysime kitame mūsų kurso skyriuje - daugiapakopiai perceptronai puikiai sugeba spręsti tokias problemas.\n",
|
||||
"XOR problema yra klasikinis perceptrono apribojimų pavyzdys, ir ją 1969 m. savo knygoje [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) paminėjo Marvin Minsky ir Seymour Papert. Ši pastaba beveik 10 metų apribojo tyrimus neuroninių tinklų srityje, nors - kaip pamatysime kitame mūsų kurso skyriuje - daugiapakopiai perceptronai puikiai sugeba spręsti tokias problemas.\n",
|
||||
"\n",
|
||||
"## Sudėtingas pavyzdys - MNIST\n",
|
||||
"\n",
|
||||
"Nors perceptronas negali išspręsti XOR problemos, jis gali išspręsti daug sudėtingesnių problemų, tokių kaip ranka rašytų simbolių atpažinimas.\n",
|
||||
"\n",
|
||||
"Duomenų rinkinys, kuris dažnai naudojamas mokantis mašininio mokymosi, vadinamas [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Jį sukūrė Modifikuotas Nacionalinis Standartų ir Technologijų Institutas, ir jis apima 60000 ranka rašytų skaitmenų mokymo rinkinį, surinktą iš maždaug 250 instituto studentų ir darbuotojų. Taip pat yra testavimo duomenų rinkinys, kuriame yra 10000 skaitmenų, surinktų iš skirtingų asmenų.\n",
|
||||
"Duomenų rinkinys, kuris dažnai naudojamas mokantis mašininio mokymosi, vadinamas [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Jį sukūrė Modifikuotas Nacionalinis Standartų ir Technologijų Institutas, ir jis apima mokymo rinkinį, sudarytą iš 60000 ranka rašytų skaitmenų, surinktų iš maždaug 250 instituto studentų ir darbuotojų. Taip pat yra testavimo duomenų rinkinys, sudarytas iš 10000 skaitmenų, surinktų iš skirtingų asmenų.\n",
|
||||
"\n",
|
||||
"Visi skaitmenys pateikiami kaip pilkų atspalvių vaizdai, kurių dydis yra 28x28 pikseliai.\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Kadangi perceptronas yra dvejetainis klasifikatorius, mes apribosime savo problemą tik dviejų skaitmenų atpažinimu. Žemiau pateikta funkcija užpildys teigiamų ir neigiamų pavyzdžių masyvus dviem nurodytais skaitmenimis (ir taip pat parodys tų skaitmenų pavyzdžius aiškumui).\n"
|
||||
"Kadangi perceptronas yra dvejetainis klasifikatorius, mes apribosime savo problemą tik dviejų skaitmenų atpažinimu. Žemiau pateikta funkcija užpildys teigiamų ir neigiamų pavyzdžių masyvus su dviem nurodytais skaitmenimis (ir taip pat parodys tų skaitmenų pavyzdžius aiškumui).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,11 +959,11 @@
|
|||
"source": [
|
||||
"Atkreipkite dėmesį, kaip tikslumas labai greitai pasiekia beveik 100%.\n",
|
||||
"\n",
|
||||
"Prašome perkelti slankiklį į poziciją, esančią arčiau mokymo pabaigos, ir stebėti svorio matricą, pateiktą kairėje. Ši matrica padės jums suprasti, kaip veikia perceptronas. Galite matyti aukštas svorio reikšmes lauko viduryje, kurios atitinka pikselius, paprastai esančius skaitmenyje 1, ir žemas neigiamas reikšmes šonuose, kur yra skaitmens 0 dalys. Taigi, jei perceptronui pateiktas skaitmuo iš tiesų yra 1, jo vidurinė dalis bus padauginta iš aukštų reikšmių, gaunant teigiamą rezultatą. Priešingai, kai perceptronas stebi 0, atitinkami pikseliai bus padauginti iš neigiamų skaičių.\n",
|
||||
"Prašome perkelti slankiklį į poziciją, esančią arčiau mokymo pabaigos, ir stebėti svorio matricą, pavaizduotą kairėje. Ši matrica padės jums suprasti, kaip veikia perceptronas. Galite matyti aukštas svorio reikšmes lauko viduryje, kurios atitinka pikselius, paprastai esančius skaitmenyje 1, ir žemas neigiamas reikšmes šonuose, kur yra skaitmens 0 dalys. Taigi, jei perceptronui pateikiamas skaitmuo 1, jo vidurinė dalis bus padauginta iš aukštų reikšmių, gaunant teigiamą rezultatą. Priešingai, kai perceptronas stebi skaitmenį 0, atitinkami pikseliai bus padauginti iš neigiamų skaičių.\n",
|
||||
"\n",
|
||||
"> Galite pastebėti, kad jei perceptronui pateikiame šiek tiek horizontaliai paslinktą skaitmenį 1, kurio pikseliai užima vietą, kur yra vertikalios skaitmens 0 dalys, galime gauti neteisingą rezultatą. Kadangi mūsų MNIST duomenų rinkinio pobūdis yra toks, kad visi skaitmenys yra centruoti ir tinkamai išdėstyti, perceptronas remiasi tuo, kad galėtų atskirti skaitmenis.\n",
|
||||
"\n",
|
||||
"Dabar išbandykime skirtingus skaitmenis:\n"
|
||||
"Dabar pabandykime skirtingus skaitmenis:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Diskusija\n",
|
||||
"\n",
|
||||
"Dėl tam tikrų priežasčių skaičiai 2 ir 5 nėra taip lengvai atskiriami. Nors pasiekiame gana aukštą tikslumą (virš 85%), aiškiai matome, kaip perceptronas tam tikru momentu nustoja mokytis.\n",
|
||||
"Dėl tam tikrų priežasčių skaičiai 2 ir 5 nėra lengvai atskiriami. Nors pasiekiame gana aukštą tikslumą (virš 85%), aiškiai matome, kaip perceptronas tam tikru momentu nustoja mokytis.\n",
|
||||
"\n",
|
||||
"Norėdami suprasti, kodėl taip nutinka, galime pasitelkti [Pagrindinių komponentų analizę](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Tai mašininio mokymosi technika, naudojama sumažinti įvesties duomenų dimensiją taip, kad būtų pasiekta geriausia klasių atskirtis.\n",
|
||||
"Norėdami suprasti, kodėl taip nutinka, galime pasitelkti [Pagrindinių komponentų analizę](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Tai mašininio mokymosi metodas, naudojamas sumažinti įvesties duomenų dimensionalumą taip, kad būtų pasiekta geriausia klasių atskirtis.\n",
|
||||
"\n",
|
||||
"Mūsų atveju įvesties vaizdas turi 784 pikselius (įvesties požymius), o mes norime naudoti PCA, kad sumažintume parametrų skaičių iki 2, jog galėtume juos pavaizduoti grafike. Tie du parametrai būtų linijinė originalių požymių kombinacija, ir šį procesą galime įsivaizduoti kaip mūsų pradinės 784 dimensijų erdvės „sukimą“ ir jos projekcijos stebėjimą 2D erdvėje, kol gausime geriausią vaizdą, kuris atskiria klases.\n"
|
||||
"Mūsų atveju įvesties vaizdas turi 784 pikselius (įvesties požymius), o PCA norime sumažinti parametrų skaičių iki 2, kad galėtume juos pavaizduoti grafike. Tie du parametrai būtų originalių požymių linijinė kombinacija, ir šį procesą galime įsivaizduoti kaip mūsų pradinės 784 dimensijų erdvės „sukimą“ ir jos projekcijos stebėjimą 2D erdvėje, kol gausime geriausią vaizdą, kuris atskiria klases.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Kaip matote, 0 ir 1 galima aiškiai atskirti tiesia linija. Tai rodo, kad pradiniame 784 matmenų erdvėje taškai, atitinkantys skaitmenis, taip pat yra linijiškai atskiriami. Kalbant apie 2 ir 5, negalime rasti tinkamos projekcijos, kuri aiškiai atskirtų skaitmenis, todėl kai kuriais atvejais įvyksta neteisinga klasifikacija.\n",
|
||||
"Kaip matote, 0 ir 1 galima aiškiai atskirti tiesia linija. Tai rodo, kad pradiniame 784 matmenų erdvėje taškai, atitinkantys skaitmenis, taip pat yra linijiškai atskiriami. Kalbant apie 2 ir 5, mes negalime rasti tinkamos projekcijos, kuri aiškiai atskirtų skaitmenis, todėl kai kuriais atvejais įvyksta neteisinga klasifikacija.\n",
|
||||
"\n",
|
||||
"> Vėliau šiame kurse išmoksime kurti nelinijinius klasifikatorius naudojant neuroninius tinklus ir spręsti problemą, kai skaitmenys nėra tinkamai išdėstyti. Labai greitai pasieksime daugiau nei 99% tikslumą MNIST skaitmenų klasifikacijoje, klasifikuodami juos į 10 skirtingų klasių.\n",
|
||||
"> Vėliau šiame kurse išmoksime kurti nelinijinius klasifikatorius, naudodami neuroninius tinklus, ir spręsti problemą, kai skaitmenys nėra tinkamai išdėstyti. Labai greitai pasieksime daugiau nei 99% tikslumą MNIST skaitmenų klasifikacijoje, klasifikuodami juos į 10 skirtingų klasių.\n",
|
||||
"\n",
|
||||
"## Svarbiausi dalykai\n",
|
||||
"## Pagrindinės mintys\n",
|
||||
"\n",
|
||||
" * Išmokome apie paprasčiausią neuroninio tinklo architektūrą – vieno sluoksnio perceptroną.\n",
|
||||
" * Įgyvendinome perceptroną „rankiniu būdu“, naudodami paprastą mokymo procedūrą, pagrįstą gradientiniu nusileidimu.\n",
|
||||
" * Nepaisant paprastumo, vieno sluoksnio perceptronas gali spręsti gana sudėtingas ranka rašytų skaitmenų atpažinimo problemas.\n",
|
||||
" * Vieno sluoksnio perceptronas yra linijinis klasifikatorius, todėl jis turi tokią pačią klasifikavimo galią kaip ir logistinė regresija.\n",
|
||||
" * Duomenų erdvėje perceptronas gali atskirti dvi įvesties duomenų klases naudodamas hiperplokštumą.\n"
|
||||
" * Mėginių erdvėje perceptronas gali atskirti dvi įvesties duomenų klases, naudodamas hiperplokštumą.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Atsakomybės apribojimas**: \nŠis dokumentas buvo išverstas naudojant dirbtinio intelekto vertimo paslaugą [Co-op Translator](https://github.com/Azure/co-op-translator). Nors siekiame tikslumo, atkreipkite dėmesį, kad automatiniai vertimai gali turėti klaidų ar netikslumų. Originalus dokumentas jo gimtąja kalba turėtų būti laikomas autoritetingu šaltiniu. Dėl svarbios informacijos rekomenduojama profesionali žmogaus vertimo paslauga. Mes neprisiimame atsakomybės už nesusipratimus ar klaidingus aiškinimus, kylančius dėl šio vertimo naudojimo.\n"
|
||||
"\n---\n\n**Atsakomybės atsisakymas**: \nŠis dokumentas buvo išverstas naudojant AI vertimo paslaugą [Co-op Translator](https://github.com/Azure/co-op-translator). Nors siekiame tikslumo, prašome atkreipti dėmesį, kad automatiniai vertimai gali turėti klaidų ar netikslumų. Originalus dokumentas jo gimtąja kalba turėtų būti laikomas autoritetingu šaltiniu. Dėl svarbios informacijos rekomenduojama profesionali žmogaus vertimo paslauga. Mes neprisiimame atsakomybės už nesusipratimus ar neteisingus interpretavimus, atsiradusius naudojant šį vertimą.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:52:05+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:40:41+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "lt"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## 玩具問題\n",
|
||||
"\n",
|
||||
"首先,我們從一個玩具問題開始,這個問題有兩個輸入特徵。例如,在醫學中,我們可能希望根據腫瘤的大小和年齡將其分類為良性或惡性。\n",
|
||||
"首先,讓我們從一個玩具問題開始,這裡我們有兩個輸入特徵。例如,在醫學中,我們可能希望根據腫瘤的大小和年齡將其分類為良性或惡性。\n",
|
||||
"\n",
|
||||
"我們將使用 SciKit Learn 庫中的 `make_classification` 函數生成一個隨機分類數據集:\n"
|
||||
]
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"然而,一般的線性模型通常還需要一個偏置項,也就是說,理想情況下我們應該計算 $y$ 為 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$。為了簡化模型,我們可以通過在輸入特徵中添加一個始終等於 1 的維度來消除這個偏置項:\n"
|
||||
"然而,一般的線性模型通常還需要一個偏置項,也就是理想情況下我們應該計算 $y$ 為 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$。為了簡化模型,我們可以通過在輸入特徵中添加一個始終等於 1 的維度來去除這個偏置項:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -206,20 +206,20 @@
|
|||
"source": [
|
||||
"## 訓練算法\n",
|
||||
"\n",
|
||||
"為了訓練感知器,我們需要找到權重 $\\mathbf{w}$,以最小化錯誤。錯誤是使用**感知器準則**定義的:\n",
|
||||
"為了訓練感知器,我們需要找出能夠最小化誤差的權重 $\\mathbf{w}$。誤差是使用**感知器準則**定義的:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ 分別代表負樣本和正樣本\n",
|
||||
" * $\\mathcal{M}$ - 錯誤分類的樣本集合\n",
|
||||
" \n",
|
||||
"我們將使用**梯度下降**的過程。從一些初始隨機權重 $\\mathbf{w}^{(0)}$ 開始,我們將在訓練的每一步根據 $E$ 的梯度調整權重:\n",
|
||||
"我們將使用**梯度下降法**的過程。從一些初始隨機權重 $\\mathbf{w}^{(0)}$ 開始,我們將在訓練的每一步根據 $E$ 的梯度調整權重:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"其中 $\\eta$ 是**學習率**,$\\tau\\in\\mathbb{N}$ - 迭代次數。\n",
|
||||
"\n",
|
||||
"以下是用 Python 定義此算法:\n"
|
||||
"讓我們用 Python 定義這個算法:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**關於學習率的說明**: `learning_rate` 參數(預設值為 `0.01`)控制每次訓練步驟中調整權重的幅度。這是根據梯度下降更新公式實現的:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- 較大的學習率(例如 `1.0`)會使感知器學習速度加快,但可能會超過最佳解\n",
|
||||
"- 較小的學習率(例如 `0.001`)學習速度較慢,但可能更精確地收斂\n",
|
||||
"- 您可以透過以下方式進行嘗試:`train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"如你所見,初始準確率約為 50%,但很快就提升到接近 90% 的較高值。\n",
|
||||
"\n",
|
||||
"讓我們來視覺化類別的分隔情況。我們的分類函數形式為 $\\mathbf{w}^Tx$,對於其中一個類別,其值大於 0;而對於另一個類別,其值則小於 0。因此,類別分隔線由 $\\mathbf{w}^Tx = 0$ 定義。由於我們只有兩個維度 $x_0$ 和 $x_1$,該線的方程式為 $w_0x_0+w_1x_1+w_2 = 0$(記住,我們已明確定義了一個額外的維度 $x_2=1$)。現在讓我們繪製這條線:\n"
|
||||
"讓我們來視覺化類別的分隔情況。我們的分類函數形式為 $\\mathbf{w}^Tx$,對於某一類別,其值大於 0;而對於另一類別,其值則小於 0。因此,類別分隔線由 $\\mathbf{w}^Tx = 0$ 定義。由於我們只有兩個維度 $x_0$ 和 $x_1$,該直線的方程式為 $w_0x_0+w_1x_1+w_2 = 0$(記得我們已明確定義了一個額外的維度 $x_2=1$)。現在讓我們繪製這條直線:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 探索學習率\n",
|
||||
"\n",
|
||||
"現在讓我們來探討不同的學習率如何影響訓練過程。學習率控制梯度下降中的步伐大小——這是一個重要的超參數,會影響收斂速度和穩定性。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 互動式學習率實驗\n",
|
||||
"\n",
|
||||
"使用下面的滑桿,互動式地嘗試不同的學習率,並觀察它們如何影響決策邊界:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## 在測試數據集上進行評估\n",
|
||||
"\n",
|
||||
"一開始,我們已經將部分數據分離出來作為測試數據集。現在來看看我們的分類器在這個測試數據集上的準確度如何。為了做到這一點,我們需要將測試數據集擴展一個額外的維度,與權重矩陣相乘,並確保得到的值與標籤的符號一致(+1 或 -1)。接著,我們將所有布林值相加,並除以測試樣本的長度,從而得到準確度:\n"
|
||||
"一開始,我們已經將部分數據分離出來作為測試數據集。現在來看看我們的分類器在這個測試數據集上的準確度如何。為了做到這一點,我們需要將測試數據集擴展一個額外的維度,與權重矩陣相乘,並確保得到的值與標籤的符號一致(+1 或 -1)。接著,我們將所有布林值相加,並除以測試樣本的長度,來計算準確度:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## 觀察訓練過程\n",
|
||||
"\n",
|
||||
"我們之前已經看到,準確率在訓練過程中會下降。能夠觀察分隔線在訓練過程中的變化會很有趣。以下的程式碼將把所有內容可視化在一個圖表上,您可以移動滑桿來「時光旅行」查看訓練過程中的變化。\n"
|
||||
"我們之前已經看到在訓練過程中準確率如何下降。能夠看到分隔線在訓練過程中的變化會很有趣。以下的程式碼將把所有內容可視化在一個圖表上,您可以移動滑桿來「時光旅行」觀察訓練過程。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -531,14 +657,14 @@
|
|||
"\n",
|
||||
"如上所述,感知器是一種**線性分類器**。如果兩個類別是**線性可分**的,也就是可以用一條直線分開,那麼感知器可以很好地區分它們。否則,感知器的訓練過程將無法收斂。\n",
|
||||
"\n",
|
||||
"一個最明顯的例子是感知器無法解決的問題,即所謂的**XOR問題**。我們希望感知器能學習XOR布林函數,其真值表如下:\n",
|
||||
"一個最明顯的例子是感知器無法解決的問題,即所謂的**XOR問題**。我們希望感知器能學習 XOR 布林函數,其真值表如下:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"讓我們試試看!我們將手動填入所有正樣本和負樣本,然後調用我們上面定義的訓練函數:\n"
|
||||
"讓我們試試看!我們將手動填入所有正樣本和負樣本,然後調用我們之前定義的訓練函數:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -607,13 +733,13 @@
|
|||
"source": [
|
||||
"如上圖所示,準確率從未超過 75%,因為不可能畫出一條直線來正確分類所有可能的例子。\n",
|
||||
"\n",
|
||||
"XOR 問題是感知器局限性的經典例子,這一點在 1969 年由 Marvin Minsky 和 Seymour Papert 在他們的書籍 [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) 中指出。這一觀察限制了神經網絡領域的研究近十年,儘管——我們會在課程的下一部分看到——多層感知器完全能夠解決這類問題。\n",
|
||||
"XOR 問題是感知器局限性的經典例子,這一點在 1969 年由 Marvin Minsky 和 Seymour Papert 在他們的書籍 [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) 中指出。這一觀察限制了神經網絡領域的研究近 10 年,儘管——我們會在課程的下一部分看到——多層感知器完全能夠解決這類問題。\n",
|
||||
"\n",
|
||||
"## 複雜範例 - MNIST\n",
|
||||
"\n",
|
||||
"儘管感知器無法解決 XOR 問題,但它可以解決許多更複雜的問題,例如手寫字符識別。\n",
|
||||
"雖然感知器無法解決 XOR 問題,但它可以解決許多更複雜的問題,例如手寫字符識別。\n",
|
||||
"\n",
|
||||
"在學習機器學習時,經常使用的一個數據集叫做 [MNIST](https://en.wikipedia.org/wiki/MNIST_database)。它由美國國家標準與技術研究院(Modified National Institute of Standards and Technology)創建,包含一個由 60000 個手寫數字組成的訓練集,這些數字來自該研究院約 250 名學生和員工。此外,還有一個由 10000 個手寫數字組成的測試數據集,這些數字來自不同的個體。\n",
|
||||
"在學習機器學習時,經常使用的一個數據集叫做 [MNIST](https://en.wikipedia.org/wiki/MNIST_database)。它由美國國家標準技術研究所(Modified National Institute of Standards and Technology)創建,包含 60000 個手寫數字的訓練集,這些數字來自研究所約 250 名學生和員工。此外,還有一個包含 10000 個數字的測試數據集,這些數字來自不同的個體。\n",
|
||||
"\n",
|
||||
"所有數字都以 28x28 像素的灰度圖像表示。\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"因為感知器是一個二元分類器,我們將把問題限制為僅識別兩個數字。以下函數將用兩個給定的數字填充正樣本和負樣本數組(並且還會顯示這些數字的樣本以便清楚了解)。\n"
|
||||
"因為感知器是一個二元分類器,我們將把問題限制在只識別兩個數字。以下的函數將用兩個給定的數字填充正樣本和負樣本陣列(並且也會顯示這些數字的樣本以便於理解)。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"請注意,準確率會非常快速地接近幾乎 100%。\n",
|
||||
"\n",
|
||||
"請將滑塊移動到訓練過程接近尾聲的位置,並觀察左側繪製的權重矩陣。這個矩陣可以幫助你理解感知器的實際工作原理。你可以看到矩陣中間的高權重值,這些值對應於通常出現在數字 1 中的像素,而矩陣兩側則是低的負值,這些位置通常是數字 0 的部分。因此,如果呈現給感知器的數字確實是 1,中間部分的像素會與高權重值相乘,產生正的結果。相反地,當感知器觀察到數字 0 時,對應的像素會與負數相乘。\n",
|
||||
"請將滑塊移動到訓練過程接近尾聲的位置,並觀察左側繪製的權重矩陣。這個矩陣可以幫助你理解感知器的實際運作方式。你可以看到矩陣中間的高權重值,這些值對應於通常出現在數字 1 中的像素,而矩陣兩側則是低的負值,這些位置通常是數字 0 的部分。因此,如果呈現給感知器的數字確實是 1,中間部分的像素會被高權重值相乘,產生正的結果。相反地,當感知器觀察到數字 0時,對應的像素會被負數相乘。\n",
|
||||
"\n",
|
||||
"> 你可能會注意到,如果我們給感知器一個數字 1,並且它稍微水平移動,使得它的像素佔據了數字 0 垂直部分的位置,我們可能會得到錯誤的結果。由於 MNIST 數據集的特性是所有數字都居中且位置正確,而感知器依賴這一點來區分數字。\n",
|
||||
"> 你可能會注意到,如果我們給感知器一個數字 1,並且它稍微水平移動,使其像素佔據了數字 0 垂直部分的位置,我們可能會得到錯誤的結果。由於 MNIST 數據集的特性是所有數字都居中且位置正確,感知器依賴這一點來區分數字。\n",
|
||||
"\n",
|
||||
"現在讓我們嘗試不同的數字:\n"
|
||||
]
|
||||
|
|
@ -917,7 +1043,7 @@
|
|||
"\n",
|
||||
"為了理解為什麼會發生這種情況,我們可以嘗試使用 [主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)。這是一種機器學習技術,用於降低輸入數據集的維度,以便獲得最佳的類別可分性。\n",
|
||||
"\n",
|
||||
"在我們的例子中,輸入圖像有 784 個像素(輸入特徵),我們希望使用 PCA 將參數數量減少到僅僅 2 個,這樣我們就可以在圖表上繪製它們。這兩個參數將是原始特徵的線性組合,我們可以將這個過程視為「旋轉」我們原本的 784 維空間,並觀察其在 2D 空間中的投影,直到我們獲得最佳視角來分離類別。\n"
|
||||
"在我們的例子中,輸入圖像有 784 個像素(輸入特徵),我們希望使用 PCA 將參數數量減少到僅僅 2 個,這樣我們就可以在圖表上繪製它們。這兩個參數將是原始特徵的線性組合,我們可以將這個過程視為“旋轉”我們原本的 784 維空間,並觀察其在 2D 空間中的投影,直到我們獲得最佳視角來分離類別。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1034,9 +1160,9 @@
|
|||
"## 重點\n",
|
||||
"\n",
|
||||
" * 我們學習了最簡單的神經網絡架構——單層感知器。\n",
|
||||
" * 我們通過手動實現了感知器,使用基於梯度下降的簡單訓練過程。\n",
|
||||
" * 我們使用基於梯度下降的簡單訓練過程,手動實現了感知器。\n",
|
||||
" * 儘管簡單,單層感知器可以解決相當複雜的手寫數字識別問題。\n",
|
||||
" * 單層感知器是一個線性分類器,因此它提供了與邏輯回歸相同的分類能力。\n",
|
||||
" * 單層感知器是一種線性分類器,因此它提供了與邏輯回歸相同的分類能力。\n",
|
||||
" * 在樣本空間中,感知器可以使用超平面分隔輸入數據的兩個類別。\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## 致謝\n",
|
||||
"\n",
|
||||
"此筆記本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分,由 [Dmitry Soshnikov](http://soshnikov.com) 編寫。靈感來自於微軟劍橋研究院的神經網絡工作坊。一些代碼和示例材料取自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示,以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 資源庫。\n"
|
||||
"此筆記本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分,由 [Dmitry Soshnikov](http://soshnikov.com) 編寫。靈感來自於微軟劍橋研究院的神經網絡工作坊。一些程式碼和示例材料取自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示,以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 資源庫。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**免責聲明**: \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。\n"
|
||||
"\n---\n\n**免責聲明**: \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:13:42+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:59:45+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "mo"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"\n",
|
||||
"> हे नोटबुक [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) चा एक भाग आहे. संपूर्ण शिक्षण सामग्रीसाठी रेपॉझिटरीला भेट द्या.\n",
|
||||
"\n",
|
||||
"जसे आपण चर्चा केली आहे, परसेप्ट्रॉन तुम्हाला **द्विआधारी वर्गीकरण समस्या** सोडवण्यास अनुमती देते, म्हणजेच इनपुट उदाहरणांना दोन वर्गांमध्ये वर्गीकृत करणे - आपण त्यांना **सकारात्मक** आणि **नकारात्मक** म्हणू शकतो.\n",
|
||||
"जसे आपण चर्चा केली आहे, परसेप्ट्रॉन तुम्हाला **द्वि-श्रेणी वर्गीकरण समस्या** सोडवण्यास अनुमती देते, म्हणजेच इनपुट उदाहरणांना दोन वर्गांमध्ये वर्गीकृत करणे - आपण त्यांना **सकारात्मक** आणि **नकारात्मक** म्हणू शकतो.\n",
|
||||
"\n",
|
||||
"सर्वप्रथम, काही आवश्यक लायब्ररी आयात करूया.\n"
|
||||
]
|
||||
|
|
@ -47,9 +47,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## खेळणी समस्या\n",
|
||||
"## खेळण्याचा प्रश्न\n",
|
||||
"\n",
|
||||
"सुरुवातीला, आपण एक खेळणी समस्या घेऊ, जिथे आपल्याकडे दोन इनपुट वैशिष्ट्ये आहेत. उदाहरणार्थ, वैद्यकीय क्षेत्रात, आपण ट्यूमरचा आकार आणि वय यावर आधारित त्यांना सौम्य आणि घातक वर्गांमध्ये वर्गीकृत करू इच्छितो.\n",
|
||||
"सुरुवातीला, आपण एक साधा प्रश्न घेऊ, जिथे आपल्याकडे दोन इनपुट वैशिष्ट्ये आहेत. उदाहरणार्थ, औषधांमध्ये, आपण ट्यूमरचा आकार आणि वय यावर आधारित त्यांना सौम्य आणि घातक वर्गांमध्ये वर्गीकृत करू इच्छितो.\n",
|
||||
"\n",
|
||||
"आपण SciKit Learn लायब्ररीमधील `make_classification` फंक्शन वापरून एक रँडम वर्गीकरण डेटासेट तयार करू:\n"
|
||||
]
|
||||
|
|
@ -154,11 +154,11 @@
|
|||
"source": [
|
||||
"## परसेप्ट्रॉन\n",
|
||||
"\n",
|
||||
"परसेप्ट्रॉन हा एक बायनरी वर्गीकरण करणारा मॉडेल आहे, त्यामुळे प्रत्येक इनपुट वेक्टर $x$ साठी परसेप्ट्रॉनचा आउटपुट +1 किंवा -1 असेल, वर्गावर अवलंबून. आउटपुट खालील सूत्राद्वारे गणना केला जाईल:\n",
|
||||
"परसेप्ट्रॉन हा एक बायनरी वर्गीकरण करणारा मॉडेल असल्यामुळे, प्रत्येक इनपुट व्हेक्टर $x$ साठी परसेप्ट्रॉनचा आउटपुट +1 किंवा -1 असेल, वर्गावर अवलंबून. आउटपुट खालील सूत्राने गणना केली जाईल:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"जिथे $\\mathbf{w}$ हा वजनाचा वेक्टर आहे, $f$ ही एक स्टेप अॅक्टिवेशन फंक्शन आहे:\n",
|
||||
"जिथे $\\mathbf{w}$ हा वजन व्हेक्टर आहे, आणि $f$ हा स्टेप अॅक्टिवेशन फंक्शन आहे:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"तथापि, एक सामान्य रेषीय मॉडेलमध्ये बायस देखील असावा, म्हणजेच आदर्शतः $y$ ची गणना $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ अशी केली पाहिजे. आपले मॉडेल सोपे करण्यासाठी, आपण इनपुट फीचर्समध्ये एक अतिरिक्त डायमेन्शन जोडून हा बायस टर्म काढून टाकू शकतो, ज्याची किंमत नेहमी 1 असते:\n"
|
||||
"तथापि, एक सामान्य रेषीय मॉडेलमध्ये बायस असावा, म्हणजेच आदर्शतः $y$ ची गणना $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ अशी केली पाहिजे. आपला मॉडेल सोपा करण्यासाठी, आपण इनपुट फीचर्समध्ये एक अतिरिक्त डायमेन्शन जोडू शकतो, ज्याची किंमत नेहमी 1 असते, ज्यामुळे बायस टर्म काढून टाकता येईल:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -206,18 +206,18 @@
|
|||
"source": [
|
||||
"## प्रशिक्षण अल्गोरिदम\n",
|
||||
"\n",
|
||||
"पर्सेप्ट्रॉन प्रशिक्षणासाठी, आपल्याला अशा वजनांचा ($\\mathbf{w}$) शोध घ्यायचा आहे जो त्रुटी कमी करेल. त्रुटी **पर्सेप्ट्रॉन निकष** वापरून परिभाषित केली जाते:\n",
|
||||
"पर्सेप्ट्रॉन प्रशिक्षणासाठी, आपल्याला अशा वजनांचा ($\\mathbf{w}$) शोध घ्यायचा आहे जे त्रुटी कमी करतील. त्रुटी **पर्सेप्ट्रॉन निकष** वापरून परिभाषित केली जाते:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ नकारात्मक आणि सकारात्मक प्रशिक्षण नमुन्यांसाठी अनुक्रमे\n",
|
||||
" * $\\mathcal{M}$ - चुकीच्या वर्गीकृत उदाहरणांचा संच\n",
|
||||
" \n",
|
||||
"आपण **ग्रेडियंट डिसेंट** प्रक्रिया वापरणार आहोत. काही प्रारंभिक यादृच्छिक वजन $\\mathbf{w}^{(0)}$ पासून सुरुवात करून, प्रशिक्षणाच्या प्रत्येक टप्प्यावर $E$ च्या ग्रेडियंटचा वापर करून वजन समायोजित करू:\n",
|
||||
"आपण **ग्रेडियंट डिसेंट** प्रक्रिया वापरणार आहोत. काही प्रारंभिक यादृच्छिक वजनांसह ($\\mathbf{w}^{(0)}$) सुरुवात करून, प्रशिक्षणाच्या प्रत्येक टप्प्यावर $E$ च्या ग्रेडियंटचा वापर करून वजन समायोजित करू:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"जिथे $\\eta$ हा **शिकण्याचा दर** आहे, आणि $\\tau\\in\\mathbb{N}$ - पुनरावृत्तीची संख्या.\n",
|
||||
"इथे $\\eta$ म्हणजे **लर्निंग रेट**, आणि $\\tau\\in\\mathbb{N}$ - पुनरावृत्तीची संख्या.\n",
|
||||
"\n",
|
||||
"चला हा अल्गोरिदम Python मध्ये परिभाषित करू:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -272,7 +272,20 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"आता आपण आपल्या डेटासेटवर प्रशिक्षण चालवूया:\n"
|
||||
"**लर्निंग रेटबद्दल टीप**: `learning_rate` पॅरामीटर (डिफॉल्ट `0.01`) प्रत्येक प्रशिक्षण चरणात वजन किती प्रमाणात बदलायचे हे नियंत्रित करते. हे ग्रेडियंट डिसेंट अपडेट सूत्र लागू करते:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- मोठा लर्निंग रेट (उदा., `1.0`) परसेप्ट्रॉनला जलद शिकवतो पण कधीकधी आदर्श समाधानापर्यंत पोहोचण्याऐवजी जास्त पुढे जाऊ शकतो\n",
|
||||
"- लहान लर्निंग रेट (उदा., `0.001`) हळूहळू शिकतो पण अधिक अचूकतेने एकत्रित होऊ शकतो\n",
|
||||
"- तुम्ही खालीलप्रमाणे प्रयोग करू शकता: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"आता आपल्या डेटासेटवर प्रशिक्षण चालवूया:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -311,7 +324,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"जसे तुम्ही पाहू शकता, सुरुवातीची अचूकता सुमारे 50% आहे, परंतु ती लवकरच वाढून जवळपास 90% च्या उच्च मूल्यांपर्यंत पोहोचते.\n",
|
||||
"जसे तुम्ही पाहू शकता, सुरुवातीची अचूकता सुमारे 50% आहे, परंतु ती लवकरच वाढून 90% च्या जवळ पोहोचते.\n",
|
||||
"\n",
|
||||
"आता वर्ग कसे विभाजित केले जातात ते पाहूया. आमचे वर्गीकरण कार्य $\\mathbf{w}^Tx$ सारखे दिसते, आणि ते एका वर्गासाठी 0 पेक्षा जास्त आहे, तर दुसऱ्या वर्गासाठी 0 पेक्षा कमी आहे. त्यामुळे, वर्ग विभाजन रेषा $\\mathbf{w}^Tx = 0$ ने परिभाषित केली जाते. कारण आपल्याकडे फक्त दोन परिमाणे $x_0$ आणि $x_1$ आहेत, रेषेसाठी समीकरण $w_0x_0+w_1x_1+w_2 = 0$ असेल (लक्षात ठेवा की आपण स्पष्टपणे एक अतिरिक्त परिमाण $x_2=1$ परिभाषित केले आहे). चला ही रेषा प्लॉट करूया:\n"
|
||||
]
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## शिकण्याच्या दरांसह प्रयोग करणे\n",
|
||||
"\n",
|
||||
"आता वेगवेगळ्या शिकण्याच्या दरांचा प्रशिक्षण प्रक्रियेवर कसा परिणाम होतो ते शोधूया. शिकण्याचा दर ग्रेडियंट डिसेंटमधील पायरीचा आकार नियंत्रित करतो - एक महत्त्वाचा हायपरपॅरामीटर जो एकत्रीकरणाचा वेग आणि स्थिरता यावर परिणाम करतो.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### इंटरएक्टिव लर्निंग रेट प्रयोग\n",
|
||||
"\n",
|
||||
"खालील स्लायडर वापरून विविध लर्निंग रेटसह प्रयोग करा आणि ते निर्णय सीमा कशी प्रभावित करतात ते पाहा:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -527,18 +653,18 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## परसेप्ट्रॉनची मर्यादा\n",
|
||||
"## परसेप्ट्रॉनच्या मर्यादा\n",
|
||||
"\n",
|
||||
"जसे तुम्ही वर पाहिले, परसेप्ट्रॉन हा **रेखीय वर्गीकरणकर्ता** आहे. जर दोन वर्ग **रेखीय विभाजनीय** असतील, म्हणजे सरळ रेषेने विभाजित करता येत असतील, तर तो त्यांच्यातील फरक चांगल्या प्रकारे ओळखू शकतो. अन्यथा, परसेप्ट्रॉन प्रशिक्षण प्रक्रिया यशस्वी होणार नाही.\n",
|
||||
"जसे तुम्ही वर पाहिले, परसेप्ट्रॉन हा एक **रेखीय वर्गीकरण करणारा** आहे. जर दोन वर्ग **रेखीय विभाज्य** असतील, म्हणजेच सरळ रेषेने विभाजित करता येतील, तर तो त्यांना चांगल्या प्रकारे वेगळे करू शकतो. अन्यथा, परसेप्ट्रॉनचे प्रशिक्षण प्रक्रिया एकत्र येणार नाही.\n",
|
||||
"\n",
|
||||
"परसेप्ट्रॉनद्वारे सोडवता न येणाऱ्या समस्येचे सर्वात स्पष्ट उदाहरण म्हणजे **XOR समस्या**. आपल्याला परसेप्ट्रॉनला XOR बूलियन फंक्शन शिकवायचे आहे, ज्याचे खालील सत्य सारणी आहे:\n",
|
||||
"परसेप्ट्रॉनद्वारे सोडवता न येणाऱ्या समस्येचे सर्वात स्पष्ट उदाहरण म्हणजे तथाकथित **XOR समस्या**. आपल्याला परसेप्ट्रॉनने XOR बूलियन फंक्शन शिकावे असे वाटते, ज्याचे खालील सत्य सारणी आहे:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"चला, हे करून पाहूया! आपण सर्व सकारात्मक आणि नकारात्मक प्रशिक्षण नमुने मॅन्युअली भरू आणि नंतर वर परिभाषित केलेल्या train फंक्शनला कॉल करू:\n"
|
||||
"चला, हे करून पाहूया! आपण सर्व सकारात्मक आणि नकारात्मक प्रशिक्षण नमुने हाताने भरू आणि नंतर वरीलप्रमाणे परिभाषित केलेल्या आपल्या train फंक्शनला कॉल करू:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"जसे तुम्ही वरच्या ग्राफमधून पाहू शकता, अचूकता कधीच 75% पेक्षा जास्त होत नाही, कारण सर्व उदाहरणे योग्यरीत्या मिळवण्यासाठी सरळ रेषा काढणे अशक्य आहे.\n",
|
||||
"जसे तुम्ही वरच्या ग्राफमधून पाहू शकता, अचूकता कधीच 75% पेक्षा जास्त जात नाही, कारण सर्व उदाहरणे योग्यरीत्या मिळवण्यासाठी सरळ रेषा काढणे अशक्य आहे.\n",
|
||||
"\n",
|
||||
"XOR समस्या ही परसेप्ट्रॉनच्या मर्यादांचे एक पारंपरिक उदाहरण आहे, आणि 1969 मध्ये मार्विन मिंस्की आणि सीमोर पॅपर्ट यांनी त्यांच्या [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) या पुस्तकात याचा उल्लेख केला होता. या निरीक्षणामुळे जवळजवळ 10 वर्षे न्यूरल नेटवर्क्सच्या क्षेत्रातील संशोधन मर्यादित झाले, जरी - आणि आपण आपल्या अभ्यासक्रमाच्या पुढील विभागात हे पाहू - मल्टी-लेयर्ड परसेप्ट्रॉन अशा समस्यांचे निराकरण करण्यास पूर्णपणे सक्षम आहेत.\n",
|
||||
"XOR समस्या ही परसेप्ट्रॉनच्या मर्यादांचे एक क्लासिकल उदाहरण आहे, आणि 1969 मध्ये मार्विन मिन्स्की आणि सीमोर पॅपर्ट यांनी त्यांच्या [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) या पुस्तकात याचा उल्लेख केला होता. या निरीक्षणामुळे जवळजवळ 10 वर्षे न्यूरल नेटवर्क्सच्या संशोधनावर मर्यादा आल्या, जरी - आणि आपण हे आपल्या अभ्यासक्रमाच्या पुढील विभागात पाहू - मल्टी-लेयर्ड परसेप्ट्रॉन अशा समस्यांचे निराकरण करण्यास पूर्णपणे सक्षम आहेत.\n",
|
||||
"\n",
|
||||
"## जटिल उदाहरण - MNIST\n",
|
||||
"\n",
|
||||
"जरी परसेप्ट्रॉन XOR समस्या सोडवू शकत नाही, तरी ते हस्तलिखित अक्षर ओळखण्यासारख्या अनेक अधिक जटिल समस्या सोडवू शकते.\n",
|
||||
"\n",
|
||||
"मशीन लर्निंग शिकताना वापरला जाणारा एक डेटासेट [MNIST](https://en.wikipedia.org/wiki/MNIST_database) म्हणून ओळखला जातो. हे मॉडिफाइड नॅशनल इन्स्टिट्यूट ऑफ स्टँडर्ड्स अँड टेक्नॉलॉजीने तयार केले आहे आणि त्यात 60000 हस्तलिखित अंकांचा प्रशिक्षण संच आहे, जो सुमारे 250 विद्यार्थी आणि संस्थेच्या कर्मचाऱ्यांकडून गोळा केला आहे. याशिवाय, 10000 अंकांचा एक चाचणी डेटासेट आहे, जो वेगवेगळ्या व्यक्तींमधून गोळा केला आहे.\n",
|
||||
"मशीन लर्निंग शिकताना वापरला जाणारा एक डेटासेट [MNIST](https://en.wikipedia.org/wiki/MNIST_database) म्हणून ओळखला जातो. हे मॉडिफाइड नॅशनल इन्स्टिट्यूट ऑफ स्टँडर्ड्स अँड टेक्नॉलॉजीने तयार केले आहे आणि यात 60000 हस्तलिखित अंकांचा प्रशिक्षण संच आहे, जो सुमारे 250 विद्यार्थी आणि संस्थेच्या कर्मचाऱ्यांकडून गोळा केला आहे. याशिवाय, 10000 अंकांचा एक चाचणी डेटासेट आहे, जो वेगवेगळ्या व्यक्तींमधून गोळा केला आहे.\n",
|
||||
"\n",
|
||||
"सर्व अंक 28x28 पिक्सेल आकाराच्या ग्रेस्केल प्रतिमांद्वारे दर्शवले जातात.\n",
|
||||
"\n",
|
||||
"> MNIST डेटासेट [Kaggle](https://www.kaggle.com/c/digit-recognizer) वर प्रशिक्षण स्पर्धा म्हणून उपलब्ध आहे, जे मशीन लर्निंग स्पर्धा आणि स्पर्धा आयोजित करणारे एक साइट आहे. एकदा तुम्ही MNIST अंक वर्गीकृत कसे करायचे ते शिकल्यावर, तुम्ही तुमचे समाधान Kaggle वर सबमिट करू शकता आणि इतर सहभागींच्या तुलनेत ते कसे रेट केले जाते ते पाहू शकता.\n",
|
||||
"> MNIST डेटासेट [Kaggle](https://www.kaggle.com/c/digit-recognizer) वर प्रशिक्षण स्पर्धा म्हणून उपलब्ध आहे, जे मशीन लर्निंग स्पर्धा आणि स्पर्धा आयोजित करणारे एक साइट आहे. एकदा तुम्ही MNIST अंक वर्गीकृत कसे करायचे ते शिकलात, तुम्ही तुमचे समाधान Kaggle वर सबमिट करू शकता आणि इतर सहभागींच्या तुलनेत ते कसे रेट केले जाते ते पाहू शकता.\n",
|
||||
"\n",
|
||||
"आम्ही MNIST डेटासेट लोड करून सुरुवात करतो:\n"
|
||||
]
|
||||
|
|
@ -644,7 +770,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"आता डेटासेट प्लॉट करूया:\n"
|
||||
"आता आपण डेटासेट प्लॉट करूया:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"कृपया लक्षात घ्या की अचूकता खूप वेगाने जवळजवळ 100% पर्यंत पोहोचते.\n",
|
||||
"\n",
|
||||
"कृपया, प्रशिक्षणाच्या शेवटाकडे स्लायडर हलवा आणि डाव्या बाजूला प्लॉट केलेले वजन मॅट्रिक्स पाहा. हे मॅट्रिक्स तुम्हाला समजून घेण्यास मदत करेल की परसेप्ट्रॉन प्रत्यक्षात कसे कार्य करते. तुम्ही क्षेत्राच्या मध्यभागी उच्च वजन मूल्ये पाहू शकता, जी सहसा अंक 1 साठी असलेल्या पिक्सल्सशी संबंधित असतात, आणि बाजूला कमी नकारात्मक मूल्ये, जिथे अंक 0 च्या भाग असतात. त्यामुळे, जर परसेप्ट्रॉनला सादर केलेला अंक प्रत्यक्षात 1 असेल, तर त्याचा मध्यभाग उच्च मूल्यांनी गुणाकार केला जाईल, ज्यामुळे सकारात्मक परिणाम मिळेल. उलट, जेव्हा परसेप्ट्रॉन 0 पाहतो, तेव्हा संबंधित पिक्सल्स नकारात्मक संख्यांनी गुणाकार केले जातात.\n",
|
||||
"कृपया, प्रशिक्षणाच्या शेवटाकडे स्लायडर हलवा आणि डाव्या बाजूला प्लॉट केलेले वजन मॅट्रिक्स पाहा. हे मॅट्रिक्स तुम्हाला समजून घेण्यास मदत करेल की परसेप्ट्रॉन प्रत्यक्षात कसे कार्य करते. तुम्ही क्षेत्राच्या मध्यभागी उच्च वजन मूल्ये पाहू शकता, जी सहसा अंक 1 साठी असलेल्या पिक्सल्सशी संबंधित असतात, आणि बाजूला कमी नकारात्मक मूल्ये असतात, जिथे अंक 0 च्या भाग असतात. त्यामुळे, जर परसेप्ट्रॉनला सादर केलेला अंक प्रत्यक्षात 1 असेल, तर त्याचा मध्यभाग उच्च मूल्यांनी गुणाकार केला जाईल, ज्यामुळे सकारात्मक परिणाम मिळेल. उलट, जेव्हा परसेप्ट्रॉन 0 पाहतो, तेव्हा संबंधित पिक्सल्स नकारात्मक संख्यांनी गुणाकार केले जातात.\n",
|
||||
"\n",
|
||||
"> तुम्ही हे लक्षात घेऊ शकता की जर आपण आपल्या परसेप्ट्रॉनला अंक 1 थोडासा आडवा हलवून दिला, ज्यामुळे त्याचे पिक्सल्स अशा ठिकाणी येतात जिथे 0 चे उभे भाग असतात, तर आपल्याला चुकीचा परिणाम मिळू शकतो. कारण आमच्या MNIST डेटासेटची प्रकृती अशी आहे की सर्व अंक केंद्रित आणि योग्य प्रकारे स्थित आहेत, आणि परसेप्ट्रॉन यावर अवलंबून असतो अंक ओळखण्यासाठी.\n",
|
||||
"> तुम्ही हे लक्षात घेऊ शकता की जर आपण आपल्या परसेप्ट्रॉनला अंक 1 थोडासा आडवा हलवून दिला, ज्यामुळे त्याचे पिक्सल्स अशा ठिकाणी जातील जिथे 0 चे उभे भाग असतात, तर आपल्याला चुकीचा परिणाम मिळू शकतो. कारण आमच्या MNIST डेटासेटची प्रकृती अशी आहे की सर्व अंक केंद्रित आणि योग्यरित्या स्थित आहेत, आणि परसेप्ट्रॉन यावर अवलंबून असतो अंक ओळखण्यासाठी.\n",
|
||||
"\n",
|
||||
"आता वेगवेगळे अंक वापरून पाहूया:\n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"काही कारणांमुळे, 2 आणि 5 सहजपणे वेगळे करता येत नाहीत. जरी आपल्याला तुलनेने उच्च अचूकता (85% पेक्षा जास्त) मिळत असली तरी, आपण स्पष्टपणे पाहू शकतो की काही वेळानंतर perceptron शिकणे थांबवते.\n",
|
||||
"\n",
|
||||
"हे का घडते हे समजून घेण्यासाठी, आपण [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) वापरण्याचा प्रयत्न करू शकतो. ही एक मशीन लर्निंग तंत्र आहे जी इनपुट डेटासेटची परिमाण कमी करण्यासाठी वापरली जाते, ज्यामुळे वर्गांमधील सर्वोत्तम वेगळेपणा मिळतो.\n",
|
||||
"हे का घडते हे समजून घेण्यासाठी, आपण [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) वापरण्याचा प्रयत्न करू शकतो. ही मशीन लर्निंग तंत्र आहे जी इनपुट डेटासेटची परिमाण कमी करण्यासाठी वापरली जाते, ज्यामुळे वर्गांमधील सर्वोत्तम वेगळेपणा मिळतो.\n",
|
||||
"\n",
|
||||
"आपल्या प्रकरणात, इनपुट प्रतिमेमध्ये 784 पिक्सेल (इनपुट वैशिष्ट्ये) आहेत, आणि आम्हाला PCA वापरून पॅरामीटर्सची संख्या फक्त 2 पर्यंत कमी करायची आहे, जेणेकरून आम्ही त्यांना ग्राफवर प्लॉट करू शकू. हे दोन पॅरामीटर्स मूळ वैशिष्ट्यांचे रेखीय संयोजन असतील, आणि आपण या प्रक्रियेला आपल्या मूळ 784-आयामी जागेचे \"फिरवणे\" आणि त्याचे प्रोजेक्शन 2D-स्पेसमध्ये निरीक्षण करणे असे पाहू शकतो, जोपर्यंत वर्ग वेगळे करण्यासाठी सर्वोत्तम दृश्य मिळत नाही.\n"
|
||||
"आपल्या प्रकरणात, इनपुट प्रतिमेमध्ये 784 पिक्सल्स (इनपुट वैशिष्ट्ये) असतात, आणि आम्हाला PCA वापरून पॅरामीटर्सची संख्या फक्त 2 पर्यंत कमी करायची आहे, जेणेकरून आम्ही त्यांना ग्राफवर प्लॉट करू शकू. हे दोन पॅरामीटर्स मूळ वैशिष्ट्यांचे रेखीय संयोजन असतील, आणि आपण या प्रक्रियेला आपल्या मूळ 784-परिमाणीय जागेचे \"फिरवणे\" म्हणून पाहू शकतो आणि त्याचे प्रक्षेपण 2D-स्थलावर निरीक्षण करू शकतो, जोपर्यंत वर्ग वेगळे करण्यासाठी सर्वोत्तम दृश्य मिळत नाही.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,16 +1153,16 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"जसे तुम्ही पाहू शकता, 0 आणि 1 यांना सरळ रेषेने स्पष्टपणे वेगळे करता येते. याचा अर्थ असा की मूळ 784-डायमेन्शनल स्पेसमध्ये अंकांशी संबंधित बिंदू देखील रेषात्मकपणे वेगळे करता येतात. 2 आणि 5 च्या बाबतीत, अंकांना स्पष्टपणे वेगळे करणारे चांगले प्रोजेक्शन शोधणे शक्य नाही, आणि त्यामुळे चुकीच्या वर्गीकरणाच्या काही प्रकरणे दिसून येतात.\n",
|
||||
"जसे तुम्ही पाहू शकता, 0 आणि 1 यांना सरळ रेषेने स्पष्टपणे वेगळे करता येते. याचा अर्थ असा की मूळ 784-डायमेन्शनल स्पेसमध्ये अंकांशी संबंधित बिंदू देखील रेषात्मकपणे वेगळे करता येतात. 2 आणि 5 च्या बाबतीत, अंकांना स्पष्टपणे वेगळे करणारी चांगली प्रोजेक्शन शोधता येत नाही, त्यामुळे चुकीच्या वर्गीकरणाच्या काही घटना घडतात.\n",
|
||||
"\n",
|
||||
"> या कोर्समध्ये पुढे आपण Neural Networks वापरून नॉन-लिनियर क्लासिफायर्स कसे तयार करायचे ते शिकणार आहोत, आणि अंक योग्य प्रकारे न जुळण्याच्या समस्येवर कसे मात करायचे तेही शिकणार आहोत. लवकरच आपण MNIST अंक वर्गीकरणामध्ये 99% पेक्षा जास्त अचूकता गाठू, जिथे आपण त्यांना 10 वेगवेगळ्या वर्गांमध्ये वर्गीकृत करू.\n",
|
||||
"> या कोर्समध्ये पुढे आपण Neural Networks वापरून नॉन-लिनियर वर्गीकरण कसे तयार करायचे ते शिकू, तसेच अंक योग्य प्रकारे न जुळण्याच्या समस्येवर कसे मात करायचे तेही शिकू. लवकरच आपण MNIST अंक वर्गीकरणामध्ये 99% पेक्षा जास्त अचूकता मिळवू, जिथे अंक 10 वेगवेगळ्या वर्गांमध्ये वर्गीकृत केले जातील.\n",
|
||||
"\n",
|
||||
"## मुख्य मुद्दे\n",
|
||||
"\n",
|
||||
" * आपण सर्वात सोप्या Neural Network आर्किटेक्चरबद्दल शिकले - एक-लेयर परसेप्ट्रॉन.\n",
|
||||
" * आपण परसेप्ट्रॉन \"हाताने\" अंमलात आणला, ज्यामध्ये gradient descent आधारित सोपी प्रशिक्षण प्रक्रिया वापरली.\n",
|
||||
" * साधेपण असूनही, एक-लेयर परसेप्ट्रॉन हस्तलिखित अंक ओळखण्याचे तुलनेने जटिल समस्या सोडवू शकतो.\n",
|
||||
" * एक-लेयर परसेप्ट्रॉन हा एक रेषात्मक वर्गीकरण करणारा आहे, आणि त्यामुळे तो logistic regression इतकीच वर्गीकरण क्षमता प्रदान करतो.\n",
|
||||
" * आपण सर्वात सोपी Neural Network आर्किटेक्चर - एक-लेयर परसेप्ट्रॉन बद्दल शिकले.\n",
|
||||
" * आपण परसेप्ट्रॉन \"हाताने\" अंमलात आणले, ज्यामध्ये gradient descent आधारित सोपी प्रशिक्षण प्रक्रिया वापरली.\n",
|
||||
" * साधेपणा असूनही, एक-लेयर परसेप्ट्रॉन हस्तलिखित अंक ओळखण्याचे तुलनेने जटिल समस्या सोडवू शकतो.\n",
|
||||
" * एक-लेयर परसेप्ट्रॉन हा एक रेषात्मक वर्गीकरणकर्ता आहे, त्यामुळे तो logistic regression इतकीच वर्गीकरण क्षमता प्रदान करतो.\n",
|
||||
" * सॅम्पल स्पेसमध्ये, परसेप्ट्रॉन हायपरप्लेन वापरून इनपुट डेटाच्या दोन वर्गांना वेगळे करू शकतो.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1046,7 +1172,7 @@
|
|||
"source": [
|
||||
"## श्रेय\n",
|
||||
"\n",
|
||||
"हे नोटबुक [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) चा एक भाग आहे आणि [Dmitry Soshnikov](http://soshnikov.com) यांनी तयार केले आहे. हे Microsoft Research Cambridge मधील Neural Network Workshop द्वारे प्रेरित आहे. काही कोड आणि चित्रात्मक सामग्री [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) आणि [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) यांच्या सादरीकरणांमधून घेतली आहे, तसेच [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) रेपॉझिटरीमधून घेतली आहे.\n"
|
||||
"हे नोटबुक [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) चा एक भाग आहे आणि [Dmitry Soshnikov](http://soshnikov.com) यांनी तयार केले आहे. हे Microsoft Research Cambridge मधील Neural Network Workshop वर आधारित आहे. काही कोड आणि चित्रात्मक सामग्री [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) आणि [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) यांच्या सादरीकरणांमधून घेतली आहे, तसेच [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) रेपॉझिटरीमधून घेतली आहे.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:20:43+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:07:24+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "mr"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Masalah Mainan\n",
|
||||
"\n",
|
||||
"Untuk permulaan, mari kita mulakan dengan masalah mainan, di mana kita mempunyai dua ciri input. Sebagai contoh, dalam bidang perubatan, kita mungkin ingin mengklasifikasikan tumor kepada jinak dan malignan, bergantung kepada saiz dan usianya.\n",
|
||||
"Sebagai permulaan, mari kita mulakan dengan masalah mainan, di mana kita mempunyai dua ciri input. Sebagai contoh, dalam bidang perubatan, kita mungkin ingin mengklasifikasikan tumor kepada jinak dan malignan, bergantung kepada saiz dan usianya.\n",
|
||||
"\n",
|
||||
"Kita akan menghasilkan dataset klasifikasi rawak menggunakan fungsi `make_classification` daripada perpustakaan SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"Oleh kerana perceptron adalah pengklasifikasi binari, untuk setiap vektor input $x$, output perceptron kita akan sama ada +1 atau -1, bergantung pada kelasnya. Output akan dikira menggunakan formula\n",
|
||||
"Oleh kerana perceptron adalah pengklasifikasi binari, untuk setiap vektor input $x$, output perceptron kita akan sama ada +1 atau -1, bergantung kepada kelasnya. Output akan dikira menggunakan formula\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Namun, model linear generik juga sepatutnya mempunyai bias, iaitu secara ideal kita perlu mengira $y$ sebagai $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Untuk mempermudahkan model kita, kita boleh menghapuskan terma bias ini dengan menambah satu dimensi lagi pada ciri input kita, yang sentiasa sama dengan 1:\n"
|
||||
"Namun, model linear generik juga sepatutnya mempunyai bias, iaitu secara ideal kita sepatutnya mengira $y$ sebagai $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Untuk mempermudahkan model kita, kita boleh menghapuskan terma bias ini dengan menambah satu dimensi lagi kepada ciri input kita, yang sentiasa bernilai 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ untuk sampel latihan negatif dan positif, masing-masing\n",
|
||||
" * $\\mathcal{M}$ - satu set contoh yang diklasifikasikan dengan salah\n",
|
||||
" \n",
|
||||
"Kita akan menggunakan proses **penurunan kecerunan**. Bermula dengan berat rawak awal $\\mathbf{w}^{(0)}$, kita akan melaraskan berat pada setiap langkah latihan menggunakan kecerunan $E$:\n",
|
||||
"Kita akan menggunakan proses **penurunan kecerunan**. Bermula dengan berat rawak awal $\\mathbf{w}^{(0)}$, kita akan menyesuaikan berat pada setiap langkah latihan menggunakan kecerunan $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -272,7 +272,20 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Sekarang mari jalankan latihan pada set data kita:\n"
|
||||
"**Nota Mengenai Kadar Pembelajaran**: Parameter `learning_rate` (lalai `0.01`) mengawal sejauh mana kita menyesuaikan berat semasa setiap langkah latihan. Ini melaksanakan formula kemas kini penurunan kecerunan:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Kadar pembelajaran yang lebih besar (contohnya, `1.0`) membuat perceptron belajar dengan lebih cepat tetapi mungkin melampaui penyelesaian optimum\n",
|
||||
"- Kadar pembelajaran yang lebih kecil (contohnya, `0.001`) belajar dengan lebih perlahan tetapi mungkin menumpu dengan lebih tepat\n",
|
||||
"- Anda boleh mencuba dengan memanggil: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Sekarang mari kita jalankan latihan pada set data kita:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Seperti yang anda lihat, ketepatan awal adalah sekitar 50%, tetapi ia cepat meningkat ke nilai yang lebih tinggi hampir 90%.\n",
|
||||
"\n",
|
||||
"Mari kita visualkan bagaimana kelas-kelas dipisahkan. Fungsi klasifikasi kita kelihatan seperti $\\mathbf{w}^Tx$, dan ia lebih besar daripada 0 untuk satu kelas, dan kurang daripada 0 untuk kelas yang lain. Oleh itu, garis pemisahan kelas ditakrifkan oleh $\\mathbf{w}^Tx = 0$. Oleh kerana kita hanya mempunyai dua dimensi $x_0$ dan $x_1$, persamaan untuk garis tersebut adalah $w_0x_0+w_1x_1+w_2 = 0$ (ingat bahawa kita telah secara eksplisit mentakrifkan satu dimensi tambahan $x_2=1$). Mari kita plot garis ini:\n"
|
||||
"Mari kita visualkan bagaimana kelas-kelas dipisahkan. Fungsi klasifikasi kita kelihatan seperti $\\mathbf{w}^Tx$, dan ia lebih besar daripada 0 untuk satu kelas, dan kurang daripada 0 untuk kelas yang lain. Oleh itu, garis pemisahan kelas ditakrifkan oleh $\\mathbf{w}^Tx = 0$. Memandangkan kita hanya mempunyai dua dimensi $x_0$ dan $x_1$, persamaan untuk garis tersebut adalah $w_0x_0+w_1x_1+w_2 = 0$ (ingat bahawa kita telah secara eksplisit mentakrifkan satu dimensi tambahan $x_2=1$). Mari kita plot garis ini:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Mencuba Kadar Pembelajaran\n",
|
||||
"\n",
|
||||
"Sekarang mari kita terokai bagaimana kadar pembelajaran yang berbeza mempengaruhi proses latihan. Kadar pembelajaran mengawal saiz langkah dalam penurunan kecerunan - satu hiperparameter penting yang mempengaruhi kelajuan dan kestabilan penumpuan.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Eksperimen Kadar Pembelajaran Interaktif\n",
|
||||
"\n",
|
||||
"Gunakan peluncur di bawah untuk bereksperimen secara interaktif dengan kadar pembelajaran yang berbeza dan lihat bagaimana ia mempengaruhi sempadan keputusan:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Menilai pada Dataset Ujian\n",
|
||||
"\n",
|
||||
"Pada permulaan, kami telah memisahkan sebahagian data untuk dataset ujian. Mari kita lihat sejauh mana ketepatan pengklasifikasi kita pada dataset ujian ini. Untuk melakukan ini, kita juga mengembangkan dataset ujian dengan satu dimensi tambahan, mendarabkan dengan matriks berat, dan memastikan nilai yang diperoleh mempunyai tanda yang sama seperti label (+1 atau -1). Kemudian, kita jumlahkan semua nilai boolean dan bahagikan dengan panjang sampel ujian untuk mendapatkan ketepatan:\n"
|
||||
"Pada permulaan, kami telah memisahkan sebahagian data untuk dataset ujian. Mari kita lihat sejauh mana ketepatan pengklasifikasi kita pada dataset ujian ini. Untuk melakukan ini, kita juga mengembangkan dataset ujian dengan dimensi tambahan, menggandakan dengan matriks berat, dan memastikan bahawa nilai yang diperoleh mempunyai tanda yang sama seperti label (+1 atau -1). Kemudian, kita jumlahkan semua nilai boolean dan bahagikan dengan panjang sampel ujian untuk mendapatkan ketepatan:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Memerhati proses latihan\n",
|
||||
"\n",
|
||||
"Kita telah melihat sebelum ini bagaimana ketepatan menurun semasa latihan. Akan menarik untuk melihat bagaimana garis pemisahan berubah semasa latihan. Kod di bawah akan memvisualisasikan segalanya dalam satu graf, dan anda sepatutnya boleh menggerakkan slider untuk \"mengembara masa\" melalui proses latihan.\n"
|
||||
"Kita telah melihat sebelum ini bagaimana ketepatan menurun semasa latihan. Ia akan menarik untuk melihat bagaimana garis pemisahan berubah semasa latihan. Kod di bawah akan memvisualisasikan segalanya dalam satu graf, dan anda sepatutnya boleh menggerakkan slider untuk \"mengembara masa\" melalui proses latihan.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,7 +655,7 @@
|
|||
"source": [
|
||||
"## Keterbatasan Perceptron\n",
|
||||
"\n",
|
||||
"Seperti yang anda lihat di atas, perceptron adalah **pengklasifikasi linear**. Ia dapat membezakan antara dua kelas dengan baik jika mereka **boleh dipisahkan secara linear**, iaitu boleh dipisahkan oleh garis lurus. Jika tidak, proses latihan perceptron tidak akan mencapai kesimpulan.\n",
|
||||
"Seperti yang anda lihat di atas, perceptron adalah **pengelas linear**. Ia dapat membezakan antara dua kelas dengan baik jika mereka **boleh dipisahkan secara linear**, iaitu boleh dipisahkan oleh garis lurus. Jika tidak, proses latihan perceptron tidak akan mencapai penyelesaian.\n",
|
||||
"\n",
|
||||
"Contoh yang paling jelas bagi masalah yang tidak dapat diselesaikan oleh perceptron ialah masalah yang dikenali sebagai **masalah XOR**. Kita mahu perceptron kita mempelajari fungsi boolean XOR, yang mempunyai jadual kebenaran berikut:\n",
|
||||
"\n",
|
||||
|
|
@ -611,9 +737,9 @@
|
|||
"\n",
|
||||
"## Contoh Kompleks - MNIST\n",
|
||||
"\n",
|
||||
"Walaupun perceptron tidak dapat menyelesaikan masalah XOR, ia dapat menyelesaikan banyak masalah yang lebih kompleks, seperti pengenalan watak tulisan tangan.\n",
|
||||
"Walaupun perceptron tidak dapat menyelesaikan masalah XOR, ia boleh menyelesaikan banyak masalah yang lebih kompleks, seperti pengenalan watak tulisan tangan.\n",
|
||||
"\n",
|
||||
"Dataset yang sering digunakan ketika mempelajari pembelajaran mesin dipanggil [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Ia telah dicipta oleh Modified National Institute of Standards and Technology, dan mengandungi set latihan sebanyak 60000 digit tulisan tangan, yang dikumpulkan daripada sekitar 250 pelajar dan pekerja institut tersebut. Terdapat juga dataset ujian sebanyak 10000 digit, yang dikumpulkan daripada individu yang berbeza.\n",
|
||||
"Dataset yang sering digunakan ketika mempelajari pembelajaran mesin dipanggil [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Ia telah dicipta oleh Modified National Institute of Standards and Technology, dan mengandungi set latihan sebanyak 60000 digit tulisan tangan, yang dikumpulkan daripada sekitar 250 pelajar dan kakitangan institut tersebut. Terdapat juga dataset ujian sebanyak 10000 digit, yang dikumpulkan daripada individu yang berbeza.\n",
|
||||
"\n",
|
||||
"Semua digit diwakili oleh imej skala kelabu bersaiz 28x28 piksel.\n",
|
||||
"\n",
|
||||
|
|
@ -644,7 +770,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Mari kita plotkan dataset:\n"
|
||||
"Mari kita plot dataset:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Oleh kerana perceptron adalah pengklasifikasi binari, kita akan mengehadkan masalah kita kepada pengenalan hanya dua digit. Fungsi di bawah akan mengisi array sampel positif dan negatif dengan dua digit yang diberikan (dan juga akan menunjukkan sampel digit tersebut untuk kejelasan).\n"
|
||||
"Kerana perceptron adalah pengklasifikasi binari, kita akan mengehadkan masalah kita kepada mengenal pasti hanya dua digit. Fungsi di bawah akan mengisi array sampel positif dan negatif dengan dua digit yang diberikan (dan juga akan menunjukkan sampel digit tersebut untuk kejelasan).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -835,7 +961,7 @@
|
|||
"\n",
|
||||
"Sila gerakkan slider ke kedudukan yang lebih ke hujung latihan, dan perhatikan matriks berat yang diplotkan di sebelah kiri. Matriks ini akan membantu anda memahami bagaimana perceptron sebenarnya berfungsi. Anda boleh melihat nilai berat yang tinggi di tengah medan, yang sepadan dengan piksel yang biasanya hadir untuk digit 1, dan nilai negatif rendah di sisi, di mana bahagian digit 0 berada. Jadi, jika digit yang diberikan kepada perceptron sebenarnya adalah 1, bahagian tengahnya akan didarabkan dengan nilai tinggi, menghasilkan keputusan positif. Sebaliknya, apabila perceptron memerhatikan digit 0, piksel yang sepadan akan didarabkan dengan nombor negatif.\n",
|
||||
"\n",
|
||||
"> Anda mungkin perasan bahawa jika kita memberikan perceptron digit 1 yang sedikit beralih secara mendatar, sehingga pikselnya berada di tempat di mana terdapat bahagian menegak digit 0, kita mungkin mendapat keputusan yang salah. Oleh kerana sifat dataset MNIST kita adalah sedemikian rupa sehingga semua digit berpusat dan diposisikan dengan betul, perceptron bergantung pada ini untuk membezakan antara digit.\n",
|
||||
"> Anda mungkin perasan bahawa jika kita memberikan perceptron digit 1 yang sedikit beralih secara mendatar, sehingga pikselnya menduduki tempat di mana terdapat bahagian menegak digit 0, kita mungkin mendapat keputusan yang salah. Oleh kerana sifat dataset MNIST kita adalah sedemikian rupa sehingga semua digit berpusat dan diposisikan dengan betul, perceptron bergantung pada ini untuk membezakan antara digit.\n",
|
||||
"\n",
|
||||
"Sekarang mari kita cuba digit yang berbeza:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Perbincangan\n",
|
||||
"\n",
|
||||
"Atas sebab tertentu, 2 dan 5 tidak mudah dipisahkan. Walaupun kita mendapat ketepatan yang agak tinggi (melebihi 85%), kita dapat melihat dengan jelas bagaimana perceptron berhenti belajar pada satu ketika.\n",
|
||||
"Atas sebab tertentu, 2 dan 5 tidak mudah dipisahkan. Walaupun kita mendapat ketepatan yang agak tinggi (melebihi 85%), kita dapat melihat dengan jelas bagaimana perceptron berhenti belajar pada satu titik.\n",
|
||||
"\n",
|
||||
"Untuk memahami mengapa ini berlaku, kita boleh cuba menggunakan [Analisis Komponen Utama](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Ia adalah teknik pembelajaran mesin yang digunakan untuk mengurangkan dimensi dataset input, dengan cara mendapatkan pemisahan terbaik antara kelas.\n",
|
||||
"\n",
|
||||
"Dalam kes kita, imej input mempunyai 784 piksel (ciri input), dan kita ingin menggunakan PCA untuk mengurangkan bilangan parameter kepada hanya 2, supaya kita boleh memplotnya pada graf. Dua parameter tersebut akan menjadi gabungan linear ciri asal, dan kita boleh melihat prosedur ini sebagai \"memutar\" ruang 784-dimensi asal kita dan memerhatikan proyeksinya ke ruang 2D kita, sehingga kita mendapat pandangan terbaik yang memisahkan kelas.\n"
|
||||
"Dalam kes kita, imej input mempunyai 784 piksel (ciri input), dan kita ingin menggunakan PCA untuk mengurangkan bilangan parameter kepada hanya 2, supaya kita boleh memplotnya pada graf. Dua parameter tersebut akan menjadi gabungan linear ciri asal, dan kita boleh melihat prosedur ini sebagai \"memutar\" ruang 784-dimensi asal kita dan memerhatikan proyeksinya ke ruang 2D, sehingga kita mendapat pandangan terbaik yang memisahkan kelas.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,13 +1155,13 @@
|
|||
"source": [
|
||||
"Seperti yang anda lihat, 0 dan 1 dapat dipisahkan dengan jelas menggunakan garis lurus. Ini menunjukkan bahawa dalam ruang asal berdimensi 784, titik-titik yang mewakili digit juga boleh dipisahkan secara linear. Dalam kes 2 dan 5, kita tidak dapat mencari unjuran yang baik untuk memisahkan digit dengan jelas, dan oleh itu terdapat beberapa kes klasifikasi yang salah.\n",
|
||||
"\n",
|
||||
"> Kemudian dalam kursus ini, kita akan belajar bagaimana mencipta pengklasifikasi tidak linear menggunakan Rangkaian Neural, dan bagaimana menangani masalah digit yang tidak sejajar dengan betul. Tidak lama lagi kita akan mencapai ketepatan lebih daripada 99% dalam klasifikasi digit MNIST, sambil mengklasifikasikan mereka ke dalam 10 kelas yang berbeza.\n",
|
||||
"> Kemudian dalam kursus ini kita akan belajar cara mencipta pengklasifikasi tidak linear menggunakan Rangkaian Neural, dan bagaimana menangani masalah digit yang tidak sejajar dengan betul. Tidak lama lagi kita akan mencapai ketepatan melebihi 99% dalam klasifikasi digit MNIST, sambil mengklasifikasikan mereka ke dalam 10 kelas yang berbeza.\n",
|
||||
"\n",
|
||||
"## Kesimpulan\n",
|
||||
"\n",
|
||||
" * Kita telah mempelajari tentang seni bina rangkaian neural yang paling mudah - perceptron satu lapisan.\n",
|
||||
" * Kita telah belajar tentang seni bina rangkaian neural yang paling mudah - perceptron satu lapisan.\n",
|
||||
" * Kita telah melaksanakan perceptron \"secara manual\", menggunakan prosedur latihan mudah berdasarkan penurunan kecerunan.\n",
|
||||
" * Walaupun mudah, perceptron satu lapisan dapat menyelesaikan masalah yang agak kompleks dalam pengenalan tulisan tangan.\n",
|
||||
" * Walaupun ringkas, perceptron satu lapisan dapat menyelesaikan masalah yang agak kompleks dalam pengenalan digit tulisan tangan.\n",
|
||||
" * Perceptron satu lapisan adalah pengklasifikasi linear, dan oleh itu ia memberikan kuasa klasifikasi yang sama seperti regresi logistik.\n",
|
||||
" * Dalam ruang sampel, perceptron dapat memisahkan dua kelas data input menggunakan hiperplan.\n"
|
||||
]
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:38:32+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:26:20+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "ms"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"> ဒီ notebook ဟာ [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) ရဲ့ အစိတ်အပိုင်းတစ်ခုဖြစ်ပါတယ်။ လေ့လာရန်အတွက် အပြည့်အစုံသော အကြောင်းအရာများကို repository မှာ သွားရောက်ကြည့်ရှုနိုင်ပါတယ်။\n",
|
||||
"> ဒီ notebook ဟာ [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) ရဲ့ အစိတ်အပိုင်းတစ်ခုဖြစ်ပါတယ်။ လေ့လာရေးအထောက်အကူပစ္စည်းများအပြည့်အစုံကို repository မှာ သွားရောက်ကြည့်ရှုနိုင်ပါတယ်။\n",
|
||||
"\n",
|
||||
"ကျွန်တော်တို့ ဆွေးနွေးခဲ့သလိုပဲ၊ perceptron က **binary classification problem** ကို ဖြေရှင်းနိုင်စေပါတယ်။ ဒါဟာ input ตัวอย่างတွေကို အမျိုးအစားနှစ်မျိုး - **positive** နဲ့ **negative** အဖြစ် ခွဲခြားနိုင်စေပါတယ်။\n",
|
||||
"ကျွန်တော်တို့ ဆွေးနွေးခဲ့သလိုပဲ၊ perceptron က **binary classification problem** ကို ဖြေရှင်းနိုင်စေပါတယ်။ ဒါဟာ input ตัวอย่างတွေကို အမျိုးအစားနှစ်မျိုး - **positive** နဲ့ **negative** အဖြစ် ခွဲခြားနိုင်စေတဲ့ အရာပါ။\n",
|
||||
"\n",
|
||||
"ပထမဆုံး၊ လိုအပ်တဲ့ library တွေကို import လုပ်ကြရအောင်။\n"
|
||||
]
|
||||
|
|
@ -49,9 +49,9 @@
|
|||
"source": [
|
||||
"## အရုပ်ပြဿနာ\n",
|
||||
"\n",
|
||||
"စတင်ရန်အတွက် အရုပ်ပြဿနာတစ်ခုဖြင့် စတင်ပါမည်။ ဤနေရာတွင် input feature နှစ်ခုရှိပါသည်။ ဥပမာအားဖြင့် ဆေးဘက်ဆိုင်ရာတွင် ကျောက်ကပ်များကို ၎င်း၏အရွယ်အစားနှင့် အသက်ပေါ်မူတည်၍ ကောင်းမွန်သော (benign) နှင့် မကောင်းသော (malignant) ဟု ခွဲခြားလိုပါသည်။\n",
|
||||
"စတင်ရန်အတွက် အရုပ်ပြဿနာတစ်ခုဖြင့် စတင်ပါမည်။ ဤနေရာတွင် input feature နှစ်ခုရှိပါသည်။ ဥပမာအားဖြင့် ဆေးဘက်ဆိုင်ရာတွင် ကျောက်ကပ်များကို အဆိပ်မရှိသော (benign) နှင့် အဆိပ်ရှိသော (malignant) ဟု အရွယ်အစားနှင့် အသက်ပေါ်မူတည်၍ ခွဲခြားလိုပါသည်။\n",
|
||||
"\n",
|
||||
"SciKit Learn library မှ `make_classification` function ကို အသုံးပြု၍ အမှတ်အသားခွဲခြားမှု dataset ကို အလွတ်တန်းဖန်တီးပါမည်။\n"
|
||||
"SciKit Learn library မှ `make_classification` function ကို အသုံးပြု၍ အမှတ်အသားခွဲခြားမှု dataset ကို အလွတ်တင်ဆက်မည်:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,11 +154,11 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"Perceptron သည် binary classifier ဖြစ်သောကြောင့် input vector $x$ တစ်ခုစီအတွက် perceptron ၏ output သည် class အပေါ်မူတည်၍ +1 သို့မဟုတ် -1 ဖြစ်ပါမည်။ Output ကို အောက်ပါနည်းဖြင့်တွက်ချက်ပါမည်-\n",
|
||||
"Perceptron သည် binary classifier ဖြစ်သောကြောင့် input vector $x$ တစ်ခုစီအတွက် perceptron ၏ output သည် class အပေါ်မူတည်၍ +1 သို့မဟုတ် -1 ဖြစ်မည်။ Output ကို အောက်ပါနည်းဖြင့်တွက်ချက်မည်။\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"ဤနေရာတွင် $\\mathbf{w}$ သည် weight vector ဖြစ်ပြီး၊ $f$ သည် step activation function ဖြစ်ပါသည်။\n",
|
||||
"ဤနေရာတွင် $\\mathbf{w}$ သည် weight vector ဖြစ်ပြီး၊ $f$ သည် step activation function ဖြစ်သည်။\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"သို့သော်၊ generic linear model တစ်ခုတွင် bias ပါဝင်သင့်ပြီး၊ အကောင်းဆုံးနည်းလမ်းမှာ $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ အတိုင်း $y$ ကိုတွက်ချက်သင့်ပါသည်။ သို့သော်၊ မODEL ကိုရိုးရှင်းစေရန် bias term ကိုဖယ်ရှားပြီး input features တွင် အမြဲတမ်း 1 ဖြစ်သော dimension တစ်ခုထပ်ထည့်ခြင်းဖြင့် ပြဿနာကို ဖြေရှင်းနိုင်ပါသည်။\n"
|
||||
"သို့သော်၊ generic linear model တစ်ခုတွင် bias ပါဝင်သင့်သည်၊ အတိအကျဆိုပါက $y$ ကို $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ အဖြစ်တွက်ချက်သင့်သည်။ သို့သော်၊ မODEL ကိုရိုးရှင်းစေရန် bias term ကိုဖယ်ရှားပြီး input features တွင် dimension တစ်ခုထပ်ထည့်နိုင်သည်၊ ထို dimension သည် အမြဲတမ်း 1 ဖြစ်သည်။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -206,20 +206,20 @@
|
|||
"source": [
|
||||
"## လေ့ကျင့်မှု အယ်လဂိုရီသမ်\n",
|
||||
"\n",
|
||||
"Perceptron ကို လေ့ကျင့်ရန်အတွက် အမှားကို လျှော့ချနိုင်မည့် အလေးချိန်များ $\\mathbf{w}$ ကို ရှာဖွေဖို့ လိုအပ်ပါတယ်။ အမှားကို **perceptron criteria** ကို အသုံးပြု၍ သတ်မှတ်ထားပါတယ်-\n",
|
||||
"Perceptron ကို လေ့ကျင့်ရန်အတွက် အမှားကို လျှော့ချနိုင်မည့် အလေးချိန်များ $\\mathbf{w}$ ကို ရှာဖွေဖို့ လိုအပ်ပါတယ်။ အမှားကို **perceptron criteria** ကို အသုံးပြု၍ သတ်မှတ်ထားပါတယ်။\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ သည် အနုတ်လက္ခဏာနှင့် အပေါင်းလက္ခဏာ training samples အတွက် ဖြစ်သည်။\n",
|
||||
" * $\\mathcal{M}$ - မှားယွင်းစွာ ခွဲခြားထားသော နမူနာများ၏ အစု\n",
|
||||
" * $\\mathcal{M}$ - မှားယွင်းစွာ ခွဲခြားထားသော နမူနာများ၏ စုပေါင်း\n",
|
||||
"\n",
|
||||
"**gradient descent** လုပ်ငန်းစဉ်ကို အသုံးပြုမည်။ အစပိုင်းတွင် အလေးချိန် $\\mathbf{w}^{(0)}$ ကို အလွတ်တင်ထားပြီး၊ training တစ်ဆင့်ဆင့်တွင် $E$ ၏ gradient ကို အသုံးပြု၍ အလေးချိန်များကို ပြင်ဆင်မည်-\n",
|
||||
"**gradient descent** လုပ်ငန်းစဉ်ကို အသုံးပြုမည်ဖြစ်သည်။ အစပိုင်းတွင် အလေးချိန် $\\mathbf{w}^{(0)}$ ကို အလွတ်တင်ထားပြီး၊ training တစ်ဆင့်ဆင့်တွင် $E$ ၏ gradient ကို အသုံးပြု၍ အလေးချိန်များကို ပြင်ဆင်သွားမည်ဖြစ်သည်။\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"ဒီမှာ $\\eta$ သည် **learning rate** ဖြစ်ပြီး၊ $\\tau\\in\\mathbb{N}$ သည် iteration အရေအတွက် ဖြစ်သည်။\n",
|
||||
"ဤနေရာတွင် $\\eta$ သည် **learning rate** ဖြစ်ပြီး၊ $\\tau\\in\\mathbb{N}$ သည် iteration အရေအတွက် ဖြစ်သည်။\n",
|
||||
"\n",
|
||||
"Python မှာ ဒီအယ်လဂိုရီသမ်ကို သတ်မှတ်ကြရအောင်-\n"
|
||||
"Python မှာ ဒီအယ်လဂိုရီသမ်ကို သတ်မှတ်ကြရအောင်:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**သင်ယူနှုန်းအကြောင်းမှတ်ချက်**: `learning_rate` ပါရာမီတာ (ပုံမှန် `0.01`) သည် သင်ကြားမှုအဆင့်တစ်ခုစီတွင် အလေးချိန်များကို ဘယ်လောက်အထိ ပြင်ဆင်မည်ကို ထိန်းချုပ်ပေးသည်။ ဤသည်သည် gradient descent update formula ကို အကောင်အထည်ဖော်ထားခြင်းဖြစ်သည်။\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- သင်ယူနှုန်းကို ကြီးမားစွာ (ဥပမာ `1.0`) သတ်မှတ်ပါက perceptron သည် အလျင်အမြန် သင်ယူနိုင်သော်လည်း အကောင်းဆုံးဖြေရှင်းချက်ကို ကျော်လွန်နိုင်ပါသည်။\n",
|
||||
"- သင်ယူနှုန်းကို သေးငယ်စွာ (ဥပမာ `0.001`) သတ်မှတ်ပါက perceptron သည် ဖြည်းဖြည်းလေး သင်ယူသော်လည်း ပိုမိုတိကျစွာ ရောက်ရှိနိုင်ပါသည်။\n",
|
||||
"- သင်သည် အောက်ပါအတိုင်း စမ်းသပ်နိုင်ပါသည်: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"စတင်အချိန်တွင် တိကျမှုသည် ၅၀% အနီးအနားရှိသော်လည်း အလျင်အမြန်တိုးတက်လာပြီး ၉၀% အနီးအနားရှိတိကျမှုအဆင့်များကို ရောက်ရှိလာသည်ကို တွေ့နိုင်ပါသည်။\n",
|
||||
"အပေါ်မှာမြင်နိုင်သည့်အတိုင်း၊ အစပိုင်းတိကျမှုသည် ၅၀% အနီးအနားတွင်ရှိပြီး၊ အလျင်အမြန် ၉၀% အနီးအနားရှိအမြင့်တက်တက်တက်လာသည်။\n",
|
||||
"\n",
|
||||
"အတန်းများကို ဘယ်လိုခွဲထားသည်ကို ရှင်းလင်းဖော်ပြကြည့်ရအောင်။ ကျွန်ုပ်တို့၏ အတန်းခွဲခြားမှုအလုပ်ဆောင်မှုသည် $\\mathbf{w}^Tx$ ဖြစ်ပြီး၊ တစ်ဖက်အတန်းအတွက် ၀ ထက်ကြီးကာ၊ အခြားအတန်းအတွက် ၀ ထက်ငယ်သည်။ ထို့ကြောင့် အတန်းခွဲခြားမှုလိုင်းကို $\\mathbf{w}^Tx = 0$ ဖြင့် သတ်မှတ်နိုင်သည်။ $x_0$ နှင့် $x_1$ ဆိုသည့် နှစ်ခုသောအတိုင်းအတာများသာရှိသောကြောင့်၊ လိုင်းအတွက် သင်္ကေတသည် $w_0x_0+w_1x_1+w_2 = 0$ ဖြစ်သည် (ကျွန်ုပ်တို့သည် အပိုအတိုင်းအတာ $x_2=1$ ကို ထည့်သွင်းသတ်မှတ်ထားသည်ကို သတိပြုပါ။) အဆိုပါလိုင်းကို ရှုထောင်ကြည့်ရအောင်:\n"
|
||||
"အတန်းများကို ဘယ်လိုခွဲထားသည်ကို ရှင်းလင်းကြည့်ကြမယ်။ ကျွန်ုပ်တို့ရဲ့ အတန်းခွဲခြားမှုအလုပ်ဆောင်ပုံသည် $\\mathbf{w}^Tx$ ဖြစ်ပြီး၊ တစ်ဖက်အတန်းအတွက် ၀ ထက်ကြီးပြီး၊ တစ်ဖက်အတန်းအတွက် ၀ ထက်ငယ်သည်။ ထို့ကြောင့် အတန်းခွဲခြားမှုလိုင်းကို $\\mathbf{w}^Tx = 0$ ဖြင့် သတ်မှတ်နိုင်သည်။ ကျွန်ုပ်တို့တွင် $x_0$ နှင့် $x_1$ ဆိုသည့် အတိုင်းတာနှစ်ခုသာရှိသောကြောင့်၊ အဆိုပါလိုင်းအတွက် အချိုးအစားသည် $w_0x_0+w_1x_1+w_2 = 0$ ဖြစ်သည် (ကျွန်ုပ်တို့သည် ထပ်တိုးအတိုင်းတာ $x_2=1$ ကို ထင်ရှားစွာ သတ်မှတ်ထားသည်ကို မှတ်မိပါစေ။) အဆိုပါလိုင်းကို ရှုထောင့်ပုံဖော်ကြည့်ရအောင်:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## သင်ယူနှုန်းများနှင့် စမ်းသပ်ခြင်း\n",
|
||||
"\n",
|
||||
"အခုတော့ သင်ယူနှုန်းများက သင်ကြားမှုလုပ်ငန်းစဉ်ကို ဘယ်လိုသက်ရောက်မှုရှိသလဲဆိုတာကို စမ်းသပ်ကြည့်ရအောင်။ သင်ယူနှုန်းက gradient descent မှာ အဆင့်တိုင်းရဲ့ အရွယ်အစားကို ထိန်းချုပ်ပေးတဲ့ အရေးပါတဲ့ hyperparameter ဖြစ်ပြီး၊ အမြန်နှုန်းနဲ့ တည်ငြိမ်မှုကိုလည်း သက်ရောက်စေပါတယ်။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### လေ့လာမှုနှုန်းကို အကျိုးသက်ရောက်မှု စမ်းသပ်ခြင်း\n",
|
||||
"\n",
|
||||
"အောက်ရှိ slider ကို အသုံးပြု၍ လေ့လာမှုနှုန်းများကို အကျိုးသက်ရောက်မှုအမျိုးမျိုးဖြင့် စမ်းသပ်ပြီး ဆုံးဖြတ်မှုနယ်နိမိတ်ကို ဘယ်လိုသက်ရောက်မှုရှိသလဲ ကြည့်ရှုနိုင်ပါသည်။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## စမ်းသပ်မှု ဒေတာစုပေါ်တွင် အကဲဖြတ်ခြင်း\n",
|
||||
"\n",
|
||||
"အစပိုင်းတွင် ကျွန်ုပ်တို့သည် စမ်းသပ်မှု ဒေတာစုအတွက် ဒေတာအချို့ကို ခွဲထားခဲ့ပါသည်။ ကျွန်ုပ်တို့၏ ခွဲခြားသူသည် စမ်းသပ်မှု ဒေတာစုပေါ်တွင် ဘယ်လောက်တိကျမှုရှိသည်ကို ကြည့်ပါစို့။ ဒါကိုလုပ်ရန် ကျွန်ုပ်တို့သည် စမ်းသပ်မှု ဒေတာစုကို အပိုအတိုင်းအတာတစ်ခုဖြင့် တိုးချဲ့ပြီး၊ အလေးချိန် matrix ဖြင့် များပြားစေပြီး၊ ရရှိသောတန်ဖိုးသည် label (+1 သို့မဟုတ် -1) နှင့် အတူတူသော အမှတ်အသားရှိကြောင်း သေချာစေပါသည်။ ထို့နောက် boolean တန်ဖိုးအားလုံးကို ပေါင်းပြီး စမ်းသပ်မှု နမူနာ၏ အရှည်ဖြင့် ခွဲခြားကာ တိကျမှုကို ရရှိစေရန် လုပ်ဆောင်ပါသည်။\n"
|
||||
"အစပိုင်းတွင်၊ စမ်းသပ်မှု ဒေတာစုအတွက် အချို့သော ဒေတာများကို ခွဲထားခဲ့ပါသည်။ အခုတော့ ကျွန်ုပ်တို့၏ ခွဲခြားသူသည် စမ်းသပ်မှု ဒေတာစုပေါ်တွင် ဘယ်လောက်တိကျမှုရှိသည်ကို ကြည့်လိုက်ရအောင်။ ဒါကိုလုပ်ရန်၊ စမ်းသပ်မှု ဒေတာစုကို အပိုအတိုင်းအတာတစ်ခုဖြင့် တိုးချဲ့ပြီး၊ အလေးချိန် matrix ဖြင့် မကြိမ်မကြိမ်မြှောက်ပြီး၊ ရရှိသောတန်ဖိုးသည် label (+1 သို့မဟုတ် -1) နှင့် အတူတူသော အမှတ်အသားရှိကြောင်း သေချာစေပါသည်။ ထို့နောက် boolean တန်ဖိုးများအားလုံးကို ပေါင်းပြီး စမ်းသပ်မှု sample ၏ အရှည်ဖြင့် ခွဲခြားကာ တိကျမှုကို ရယူပါ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## လေ့ကျင့်မှုလုပ်ငန်းစဉ်ကိုကြည့်ရှုခြင်း\n",
|
||||
"\n",
|
||||
"လေ့ကျင့်မှုအတွင်းမှာ အတိအကျမှုက ကျဆင်းသွားပုံကို အရင်က ကြည့်ဖူးခဲ့ပါတယ်။ လေ့ကျင့်မှုအတွင်းမှာ ခွဲခြားရေးလိုင်းက ဘယ်လိုပြောင်းလဲသွားတယ်ဆိုတာကို ကြည့်ရှုနိုင်ရင် ကောင်းမယ်လို့ ထင်ပါတယ်။ အောက်မှာရှိတဲ့ code က အားလုံးကို တစ်ခုတည်းသော graph ပေါ်မှာ ရှင်းလင်းပြသပေးမှာဖြစ်ပြီး slider ကို ရွှေ့ပြီး \"အချိန်ခရီး\" လုပ်ကာ လေ့ကျင့်မှုလုပ်ငန်းစဉ်ကို ကြည့်ရှုနိုင်ပါမယ်။\n"
|
||||
"လေ့ကျင့်မှုအတွင်းမှာ တိကျမှုနည်းလာပုံကို အရင်က ကြည့်ဖူးခဲ့ပါတယ်။ လေ့ကျင့်မှုအတွင်းမှာ ခွဲခြားရေးလိုင်းက ဘယ်လိုပြောင်းလဲသွားတယ်ဆိုတာကို ကြည့်ရတာကောင်းမယ်လို့ ထင်ပါတယ်။ အောက်မှာရှိတဲ့ code က အားလုံးကို တစ်ခုတည်းသော graph ပေါ်မှာ ရှင်းလင်းပြသပေးမှာဖြစ်ပြီး slider ကို ရွှေ့ပြီး \"အချိန်ခရီး\" လုပ်ကာ လေ့ကျင့်မှုလုပ်ငန်းစဉ်ကို ကြည့်နိုင်ပါမယ်။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,16 +655,16 @@
|
|||
"source": [
|
||||
"## Perceptron ၏ အကန့်အသတ်များ\n",
|
||||
"\n",
|
||||
"အထက်တွင် ကြည့်ရှုခဲ့သလို Perceptron သည် **linear classifier** တစ်ခုဖြစ်သည်။ ဒါဟာ **linearly separable** ဖြစ်သောအခါ၊ အတန်းနှစ်ခုကို တိကျစွာ ခွဲခြားနိုင်သည်။ အတန်းများကို တိုင်းရင်းလိုင်းဖြင့် ခွဲခြား၍မရပါက Perceptron ၏ လေ့ကျင့်မှုလုပ်ငန်းစဉ်သည် မအောင်မြင်နိုင်ပါ။\n",
|
||||
"အထက်တွင် ကြည့်ရှုခဲ့သလို၊ perceptron သည် **linear classifier** တစ်ခုဖြစ်သည်။ **linearly separable** ဖြစ်သောအခါ၊ အတန်းနှစ်ခုကို တိုင်းရင်းလိုက်စွာ ခွဲခြားနိုင်သည်။ အတန်းများကို တိုင်းရင်းလိုက်စွာ ခွဲခြား၍ မရပါက၊ perceptron ၏ လေ့ကျင့်မှုလုပ်ငန်းစဉ်သည် မအောင်မြင်နိုင်ပါ။\n",
|
||||
"\n",
|
||||
"Perceptron ဖြင့် ဖြေရှင်း၍မရနိုင်သော ပြဿနာတစ်ခု၏ အထင်ရှားဆုံး ဥပမာမှာ **XOR problem** ဟုခေါ်သော ပြဿနာဖြစ်သည်။ Perceptron သည် XOR boolean function ကို လေ့လာရန်လိုအပ်ပြီး၊ ၎င်းတွင် အောက်ပါ Truth Table ရှိသည်။\n",
|
||||
"perceptron ဖြင့် ဖြေရှင်း၍ မရနိုင်သော ပြဿနာတစ်ခု၏ အထင်ရှားဆုံး ဥပမာမှာ **XOR problem** ဟုခေါ်သော ပြဿနာဖြစ်သည်။ perceptron သည် XOR boolean function ကို လေ့လာရန်လိုအပ်ပြီး၊ ၎င်းတွင် အောက်ပါ truth table ရှိသည်-\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"အဲဒါကို လုပ်ကြည့်ရအောင်! အပေါင်းအပေါင်းနှင့် အနုတ်အနုတ် training samples များကို ကိုယ်တိုင်ဖြည့်ပြီး၊ အထက်တွင် သတ်မှတ်ထားသော train function ကို ခေါ်သုံးကြည့်မည်:\n"
|
||||
"အဲဒါကို လုပ်ကြည့်ရအောင်! အပေါင်းအပိုင်း training samples အားလုံးကို ကိုယ်တိုင်ဖြည့်စွက်ပြီး၊ အထက်တွင် သတ်မှတ်ထားသော train function ကို ခေါ်သုံးကြည့်မည်-\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,21 +731,21 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"အပေါ်ရှိဂရပ်မှကြည့်လိုက်ပါက၊ တိကျမှုသည် ၇၅% အထက်မတက်နိုင်ပါ၊ အကြောင်းမှာ အားလုံးကိုမှန်ကန်စွာဖြေရှင်းနိုင်ရန် တိုက်တန်းလိုင်းတစ်ခုကိုဆွဲရန် မဖြစ်နိုင်သောကြောင့်ဖြစ်ပါသည်။\n",
|
||||
"အပေါ်ရှိဂရပ်မှကြည့်လိုက်ရင်၊ တိကျမှုက ၇၅% ထက်မကျော်နိုင်ပါဘူး၊ အကြောင်းကတော့ တိုင်းတန်းတစ်ခုကို အားလုံးမှန်အောင်ဆွဲဖို့ မဖြစ်နိုင်တဲ့အခြေအနေကြောင့်ပါ။\n",
|
||||
"\n",
|
||||
"XOR ပြဿနာသည် perceptron ၏ အကန့်အသတ်များကို ဖော်ပြသည့် ဂန္ထဝင်ဥပမာတစ်ခုဖြစ်ပြီး၊ ၎င်းကို Marvin Minsky နှင့် Seymour Papert က ၁၉၆၉ ခုနှစ်တွင် ၎င်းတို့၏စာအုပ် [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) တွင် ဖော်ပြခဲ့သည်။ ဤအချက်အလက်သည် နယူးရယ်နက်ဝက်များဆိုင်ရာ သုတေသနကို ၁၀ နှစ်နီးပါးတိုးတက်မှုမရှိစေခဲ့သည်။ သို့သော် - ကျွန်ုပ်တို့၏သင်တန်း၏ နောက်ပိုင်းအပိုင်းတွင် မြင်ရမည်ဖြစ်သည့်အတိုင်း - အလွှာများစွာပါဝင်သော perceptrons များသည် ဤပြဿနာများကို အလွယ်တကူဖြေရှင်းနိုင်သည်။\n",
|
||||
"XOR ပြဿနာက perceptron အကန့်အသတ်များကို ဖော်ပြတဲ့ ဂန္ထဝင်ဥပမာတစ်ခုဖြစ်ပြီး၊ ၁၉၆၉ ခုနှစ်မှာ Marvin Minsky နဲ့ Seymour Papert တို့ရဲ့ [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) စာအုပ်မှာ ဖော်ပြခဲ့ပါတယ်။ ဒီအချက်အလက်က neural networks နယ်ပယ်မှာ သုတေသနလုပ်ငန်းတွေကို ၁၀ နှစ်နီးပါးတိုးတက်မှုမရှိအောင် ကန့်သတ်ခဲ့ပါတယ်။ သို့သော် - ကျွန်တော်တို့သင်ခန်းစာရဲ့ နောက်ပိုင်းအပိုင်းမှာ မြင်ရမှာဖြစ်တဲ့အတိုင်း - အလွှာများပါဝင်တဲ့ perceptrons တွေက ဒီလိုပြဿနာတွေကို ဖြေရှင်းနိုင်စွမ်းရှိပါတယ်။\n",
|
||||
"\n",
|
||||
"## ရှုပ်ထွေးသော ဥပမာ - MNIST\n",
|
||||
"## ရှုပ်ထွေးတဲ့ ဥပမာ - MNIST\n",
|
||||
"\n",
|
||||
"Perceptron သည် XOR ပြဿနာကို မဖြေရှင်းနိုင်သော်လည်း၊ လက်ရေးအက္ခရာများကို မှတ်မိစေခြင်းကဲ့သို့သော ရှုပ်ထွေးသော ပြဿနာများစွာကို ဖြေရှင်းနိုင်သည်။\n",
|
||||
"Perceptron က XOR ပြဿနာကို မဖြေရှင်းနိုင်ပေမယ့်၊ လက်ရေးအက္ခရာများကို မှတ်မိစေတဲ့လိုအပ်ချက်လိုမျိုး ရှုပ်ထွေးတဲ့ပြဿနာများစွာကို ဖြေရှင်းနိုင်ပါတယ်။\n",
|
||||
"\n",
|
||||
"Machine learning ကို ကျွမ်းကျင်ရန် အသုံးပြုသော dataset တစ်ခုမှာ [MNIST](https://en.wikipedia.org/wiki/MNIST_database) ဟုခေါ်သည်။ ၎င်းကို Modified National Institute of Standards and Technology မှ ဖန်တီးခဲ့ပြီး၊ 60000 လက်ရေးဂဏန်းများပါဝင်သော training set တစ်ခုနှင့်၊ အင်စတီကျု၏ ကျောင်းသားများနှင့် ဝန်ထမ်း 250 ခန့်မှ စုဆောင်းထားသည်။ ထို့အပြင်၊ အခြားသူများမှ စုဆောင်းထားသော 10000 ဂဏန်းများပါဝင်သော test dataset တစ်ခုလည်းရှိသည်။\n",
|
||||
"Machine learning ကို ကျွမ်းကျင်ဖို့အတွက် မကြာခဏအသုံးပြုတဲ့ dataset တစ်ခုက [MNIST](https://en.wikipedia.org/wiki/MNIST_database) လို့ခေါ်ပါတယ်။ ဒါကို Modified National Institute of Standards and Technology က ဖန်တီးထားပြီး၊ 60000 လက်ရေးဂဏန်းများပါဝင်တဲ့ training set တစ်ခုကို ထုတ်ဝေထားပါတယ်။ ဒီဂဏန်းတွေကို အင်စတီကျုရဲ့ ကျောင်းသားနဲ့ ဝန်ထမ်း 250 ကျော်က ရယူထားတာဖြစ်ပါတယ်။ ထို့အပြင်၊ အခြားသူများထံမှ ရယူထားတဲ့ 10000 ဂဏန်းများပါဝင်တဲ့ test dataset တစ်ခုလည်းရှိပါတယ်။\n",
|
||||
"\n",
|
||||
"ဂဏန်းအားလုံးကို 28x28 pixels အရွယ်ရှိသော grayscale ပုံများဖြင့် ကိုယ်စားပြုထားသည်။\n",
|
||||
"ဂဏန်းအားလုံးကို 28x28 pixels အရွယ်ရှိတဲ့ grayscale images အနေနဲ့ ဖော်ပြထားပါတယ်။\n",
|
||||
"\n",
|
||||
"> MNIST Dataset ကို [Kaggle](https://www.kaggle.com/c/digit-recognizer) တွင် training ပြိုင်ပွဲအဖြစ်ရရှိနိုင်ပါသည်။ Kaggle သည် machine learning ပြိုင်ပွဲများနှင့် ပြိုင်ဆိုင်မှုများကို ဖွင့်လှစ်ထားသော site တစ်ခုဖြစ်သည်။ MNIST ဂဏန်းများကို အကွာအကွေ ခွဲခြားနိုင်ရန် သင်လေ့လာပြီးပါက၊ သင့်ဖြေရှင်းချက်ကို Kaggle တွင် တင်သွင်းပြီး အခြားပါဝင်သူများနှင့် နှိုင်းယှဉ်၍ အဆင့်သတ်မှတ်မှုကို ကြည့်နိုင်ပါသည်။\n",
|
||||
"> MNIST Dataset ကို [Kaggle](https://www.kaggle.com/c/digit-recognizer) မှာ training competition အနေနဲ့ ရရှိနိုင်ပါတယ်။ Kaggle က machine learning ပြိုင်ပွဲနဲ့ ပြိုင်ဆိုင်မှုတွေကို ဖော်ပြတဲ့ site တစ်ခုဖြစ်ပါတယ်။ MNIST ဂဏန်းတွေကို ဘယ်လိုခွဲခြားရမလဲ သင်လေ့လာပြီးရင်၊ Kaggle မှာ သင့်ရဲ့ဖြေရှင်းချက်ကို တင်သွင်းပြီး အခြားပါဝင်သူတွေအကြား ဘယ်လိုအဆင့်သတ်မှတ်ခံရလဲ ကြည့်နိုင်ပါတယ်။\n",
|
||||
"\n",
|
||||
"ကျွန်ုပ်တို့ MNIST dataset ကို load လုပ်ခြင်းဖြင့် စတင်ပါမည်။\n"
|
||||
"အရင်ဆုံး MNIST dataset ကို load လုပ်ပါမယ်။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -735,7 +861,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"ကျွန်ုပ်တို့ ၀ နှင့် ၁ အကြား ခွဲခြားရန် ကြိုးစားမည်။\n"
|
||||
"ကျွန်ုပ်တို့ 0 နှင့် 1 အကြား ခွဲခြားရန် ကြိုးစားမည်ဖြင့် စတင်ပါမည်။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,11 +959,11 @@
|
|||
"source": [
|
||||
"ကျေးဇူးပြု၍ သတိပြုပါ၊ တိကျမှုသည် အလွန်မြန်စွာ ၁၀၀% အနီးအနားသို့ တက်လာသည်။\n",
|
||||
"\n",
|
||||
"ကျေးဇူးပြု၍ slider ကို သင်ကြားမှု၏ နောက်ဆုံးပိုင်းအနီးတစ်နေရာသို့ ရွှေ့ပြီး ဘယ်ဘက်တွင် ဖော်ပြထားသော weight matrix ကို ကြည့်ရှုပါ။ ဒီ matrix က perceptron အကောင်အထည်ဖော်ပုံကို နားလည်စေမည်ဖြစ်သည်။ သင်သည် field ၏ အလယ်ပိုင်းတွင် အမြင့်ဆုံး weight အတန်တစ်ခုကို မြင်နိုင်ပြီး၊ ၎င်းသည် digit 1 အတွက် မကြာခဏရှိနေသော pixels ကို ကိုယ်စားပြုသည်။ အနည်းဆုံး negative အတန်များကို ဘေးဘက်တွင် မြင်နိုင်ပြီး၊ ၎င်းသည် digit 0 ၏ အပိုင်းများကို ကိုယ်စားပြုသည်။ ထို့ကြောင့်၊ perceptron သို့ တင်ပြထားသော digit သည် အမှန်တကယ် 1 ဖြစ်ပါက၊ ၎င်း၏ အလယ်ပိုင်းသည် အမြင့်တန်ဖိုးများဖြင့် မျိုးစပ်ခံရမည်ဖြစ်ပြီး၊ အပေါင်းအမြင့်ရလဒ်ကို ထုတ်ပေးမည်ဖြစ်သည်။ အပြန်အလှန်၊ perceptron သည် digit 0 ကို ကြည့်ရှုသောအခါ၊ သက်ဆိုင် pixel များသည် negative အရေအတွက်များဖြင့် မျိုးစပ်ခံရမည်ဖြစ်သည်။\n",
|
||||
"ကျေးဇူးပြု၍ slider ကို သင်ကြားမှု၏ နောက်ဆုံးပိုင်းအနီးတစ်ခုခုသို့ ရွှေ့ထားပြီး ဘယ်ဘက်တွင် ဖော်ပြထားသော weight matrix ကို ကြည့်ရှုပါ။ ဒီ matrix က perceptron အလုပ်လုပ်ပုံကို နားလည်စေမည်ဖြစ်သည်။ သင်သည် field ၏ အလယ်ပိုင်းတွင် အမြင့်ဆုံး weight အတန်တစ်ခုကို မြင်နိုင်ပြီး၊ ၎င်းသည် digit 1 အတွက် များသောအားဖြင့်ရှိနေသော pixels ကို ကိုယ်စားပြုသည်။ အနည်းဆုံး negative အတန်တစ်ခုကို ဘေးဘက်တွင် မြင်နိုင်ပြီး၊ ၎င်းသည် digit 0 ၏ အပိုင်းများကို ကိုယ်စားပြုသည်။ ထို့ကြောင့်၊ perceptron သို့ တင်ပြထားသော digit သည် တကယ်ပင် 1 ဖြစ်ပါက၊ ၎င်း၏ အလယ်ပိုင်းသည် အမြင့်တန်ဖိုးများဖြင့် မျှတစွာမြှောက်ပေးပြီး အပေါင်းရလဒ်ကို ထုတ်ပေးမည်ဖြစ်သည်။ အတူတူပင်၊ perceptron သည် digit 0 ကို ကြည့်ရှုသောအခါ၊ သက်ဆိုင် pixel များကို negative အတန်များဖြင့် မျှတစွာမြှောက်ပေးမည်ဖြစ်သည်။\n",
|
||||
"\n",
|
||||
"> သင်သည် perceptron သို့ digit 1 ကို အနည်းငယ် အလျားလိုက်ရွှေ့ထားပြီး၊ ၎င်း၏ pixels များသည် digit 0 ၏ vertical အပိုင်းများရှိနေသောနေရာကို ရောက်ရှိနေပါက၊ မမှန်သောရလဒ်ကို ရရှိနိုင်သည်ကို သတိထားမိနိုင်ပါသည်။ MNIST dataset ၏ သဘာဝသည် digit များအားလုံးကို အလယ်တွင် ဗဟိုထားပြီး၊ သေချာစွာ တည်နေရာချထားသောကြောင့်၊ perceptron သည် ၎င်းကို အားကိုးပြီး digit များကို ခွဲခြားသည်။\n",
|
||||
"> သင်သည် perceptron ကို digit 1 ကို အနည်းငယ် အလျားလိုက်ရွှေ့ထားပြီး၊ ၎င်း၏ pixels များသည် digit 0 ၏ လျှောက်လမ်းလိုက်အပိုင်းများရှိနေသောနေရာကို ရောက်နေပါက၊ မမှန်သောရလဒ်ကို ရရှိနိုင်သည်ကို သတိပြုနိုင်ပါသည်။ ကျွန်ုပ်တို့၏ MNIST dataset ၏ သဘာဝသည် digit များအားလုံးကို အလယ်တွင် ဗဟိုထားပြီး သေချာစွာ တည်နေရာချထားသောကြောင့်၊ perceptron သည် ၎င်းကို အခြေခံ၍ digit များကို ခွဲခြားနိုင်သည်။\n",
|
||||
"\n",
|
||||
"အခုတော့ digit များကို ကွဲပြားစွာ စမ်းကြည့်ရအောင်: \n"
|
||||
"အခုတော့ digit များကို ကွဲပြားစွာ စမ်းကြည့်ရအောင်:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## ဆွေးနွေးချက်\n",
|
||||
"\n",
|
||||
"တစ်ခုခုကြောင့် 2 နဲ့ 5 ကို အလွယ်တကူ ခွဲခြားနိုင်ခြင်း မရှိပါဘူး။ Accuracy အနေနဲ့ 85% အထက်ရရှိနေတဲ့အချိန်မှာတောင် Perceptron က တစ်ချို့အချိန်မှာ သင်ယူမှုရပ်တန့်သွားတာကို ရှင်းရှင်းလင်းလင်း မြင်နိုင်ပါတယ်။\n",
|
||||
"တစ်ခုခုကြောင့် 2 နဲ့ 5 ကို အလွယ်တကူ ခွဲခြားဖို့ မဖြစ်နိုင်ပါဘူး။ Accuracy အနေနဲ့ 85% ကျော်ရရှိနေတဲ့အချိန်မှာတောင် Perceptron က တစ်ချို့အချိန်မှာ သင်ယူတာရပ်သွားတာကို ရှင်းရှင်းလင်းလင်း မြင်နိုင်ပါတယ်။\n",
|
||||
"\n",
|
||||
"ဒီအကြောင်းကို နားလည်ဖို့ [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) ကို အသုံးပြုကြည့်နိုင်ပါတယ်။ PCA က input dataset ရဲ့ dimensionality ကို လျှော့ချပြီး class တွေကို အကောင်းဆုံး ခွဲခြားနိုင်အောင် လုပ်ဆောင်တဲ့ machine learning နည်းလမ်းတစ်ခုဖြစ်ပါတယ်။\n",
|
||||
"ဒါကို နားလည်ဖို့ [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) ကို အသုံးပြုနိုင်ပါတယ်။ PCA က input dataset ရဲ့ dimensionality ကို လျှော့ချပြီး classes တွေကို အကောင်းဆုံး ခွဲခြားနိုင်ဖို့ အထောက်အကူပြုတဲ့ machine learning နည်းလမ်းတစ်ခုဖြစ်ပါတယ်။\n",
|
||||
"\n",
|
||||
"ဒီအခါမှာတော့ input image တစ်ခုမှာ pixel 784 ခု (input features) ရှိပြီး PCA ကို အသုံးပြုပြီး parameter အရေအတွက်ကို 2 ခုအထိ လျှော့ချချင်ပါတယ်။ ဒါကို graph ပေါ်မှာ plot လုပ်နိုင်ဖို့ပါ။ ဒီ parameter 2 ခုဟာ original features တွေကို linear combination အနေနဲ့ ရရှိလာမှာဖြစ်ပြီး ဒီလုပ်ငန်းစဉ်ကို original 784-dimensional space ကို \"လှည့်\"ပြီး 2D-space ပေါ်မှာ projection ကို ကြည့်ရှုတာအဖြစ် သတ်မှတ်နိုင်ပါတယ်။ အကောင်းဆုံး class တွေကို ခွဲခြားနိုင်တဲ့ view ကို ရရှိတဲ့အထိ ဒီလုပ်ငန်းစဉ်ကို ဆက်လုပ်ရမှာဖြစ်ပါတယ်။\n"
|
||||
"ဒီအခါမှာတော့ input image တစ်ခုမှာ pixel 784 ခု (input features) ရှိပြီး၊ parameter အရေအတွက်ကို 2 ခုအထိ လျှော့ချဖို့ PCA ကို အသုံးပြုချင်ပါတယ်။ ဒါကို graph ပေါ်မှာ plot လုပ်နိုင်ဖို့ပါ။ ဒီ parameter 2 ခုဟာ original features တွေကို linear combination လုပ်ထားတာဖြစ်ပြီး၊ ဒီလုပ်ငန်းစဉ်ကို 784-dimensional space ကို \"လှည့်\"ပြီး၊ 2D-space ပေါ်မှာ projection ကို ကြည့်ရှုတာအဖြစ် သတ်မှတ်နိုင်ပါတယ်။ အကောင်းဆုံး class ခွဲခြားမှုရရှိတဲ့ view ကို ရှာဖွေတဲ့အထိ ဒီလုပ်ငန်းစဉ်ကို ဆက်လုပ်ရမှာပါ။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"0 နှင့် 1 ကို တိုင်းရင်းလိုင်းတစ်ခုဖြင့် အလွယ်တကူ ခွဲခြားနိုင်သည်ကို သင်မြင်နိုင်ပါသည်။ ဒါကတော့ မူရင်း 784-အတိုင်းအတာရှိ နေရာတွင် ဂဏန်းများနှင့် ဆက်စပ်နေသော အမှတ်များကိုလည်း တိုင်းရင်းလိုင်းဖြင့် ခွဲခြားနိုင်သည်ကို ဖော်ပြသည်။ 2 နှင့် 5 ရဲ့ အခြေအနေတွင်တော့ ဂဏန်းများကို အလွယ်တကူ ခွဲခြားနိုင်မည့် projection ကို ရှာမတွေ့နိုင်ပါ၊ ထို့ကြောင့် classification မှားယွင်းမှုအချို့ ဖြစ်ပေါ်နိုင်ပါသည်။\n",
|
||||
"0 နှင့် 1 ကို တိုက်ရိုက်လိုင်းတစ်ခုဖြင့် အလွယ်တကူခွဲခြားနိုင်သည်ကို သင်မြင်နိုင်ပါသည်။ ဒါကတော့ မူရင်း 784-အတိုင်းအတာရှိနေရာတွင် ဂဏန်းများနှင့်ဆက်စပ်နေသော အမှတ်များကိုလည်း တိုက်ရိုက်ခွဲခြားနိုင်သည်ကို ဖော်ပြသည်။ 2 နှင့် 5 ရဲ့အခြေအနေတွင်တော့ ဂဏန်းများကို အလွယ်တကူခွဲခြားနိုင်မည့် projection ကို ရှာမတွေ့နိုင်ပါ၊ ထို့ကြောင့် classification မှားယွင်းမှုအချို့ရှိနေပါသည်။\n",
|
||||
"\n",
|
||||
"> ဒီသင်ခန်းစာမှာ နောက်ပိုင်းမှာတော့ Neural Networks ကို အသုံးပြုပြီး non-linear classifiers ဖန်တီးနည်းကို သင်ယူမည်ဖြစ်ပြီး၊ alignment မမှန်သော ဂဏန်းများကို ပြဿနာဖြေရှင်းနည်းကိုလည်း လေ့လာမည်ဖြစ်သည်။ မကြာမီမှာတော့ MNIST digit classification တွင် 99% ကျော်သော တိကျမှုကို ရောက်ရှိမည်ဖြစ်ပြီး၊ ဂဏန်းများကို 10 မျိုးခွဲခြားနိုင်မည်ဖြစ်သည်။\n",
|
||||
"> ဒီသင်ခန်းစာရဲ့ နောက်ပိုင်းမှာတော့ Neural Networks ကို အသုံးပြုပြီး non-linear classifiers ဖန်တီးနည်းကို သင်ယူမည်ဖြစ်ပြီး၊ ဂဏန်းများ alignment မမှန်ကန်မှုကို ဖြေရှင်းနည်းကိုလည်း လေ့လာမည်ဖြစ်သည်။ မကြာမီမှာတော့ MNIST digit classification တွင် 99% ကျော်သော တိကျမှုကို ရောက်ရှိမည်ဖြစ်ပြီး၊ ဂဏန်းများကို 10 မျိုးခွဲခြားနိုင်မည်ဖြစ်သည်။\n",
|
||||
"\n",
|
||||
"## အဓိကအချက်များ\n",
|
||||
"\n",
|
||||
" * အလွယ်ဆုံးသော neural network architecture - one-layer perceptron ကို သင်ယူခဲ့ပါသည်။\n",
|
||||
" * gradient descent ကို အခြေခံပြီး training procedure ရေးသားကာ perceptron ကို \"ကိုယ်တိုင်\" အကောင်အထည်ဖော်ခဲ့ပါသည်။\n",
|
||||
" * ရိုးရှင်းမှုရှိသော်လည်း၊ one-layered perceptron သည် လက်ရေးဂဏန်းများကို အသိအမှတ်ပြုနိုင်သော rather complex problems ကို ဖြေရှင်းနိုင်သည်။\n",
|
||||
" * One-layered perceptron သည် linear classifier ဖြစ်ပြီး၊ logistic regression နှင့် တူညီသော classification စွမ်းရည်ကို ပေးစွမ်းသည်။\n",
|
||||
" * Sample space တွင် perceptron သည် hyperplane ကို အသုံးပြုကာ input data ရဲ့ class နှစ်ခုကို ခွဲခြားနိုင်သည်။\n"
|
||||
" * အလွယ်ဆုံးသော neural network architecture - one-layer perceptron အကြောင်းကို သင်ယူခဲ့ပါသည်။\n",
|
||||
" * gradient descent ကို အခြေခံပြီး training procedure ရေးဆွဲကာ perceptron ကို \"ကိုယ်တိုင်\" အကောင်အထည်ဖော်ခဲ့ပါသည်။\n",
|
||||
" * ရိုးရှင်းမှုရှိသော်လည်း၊ one-layered perceptron သည် လက်ရေးဂဏန်းများကို အသိအမှတ်ပြုနိုင်သော rather complex problems များကို ဖြေရှင်းနိုင်သည်။\n",
|
||||
" * One-layered perceptron သည် linear classifier ဖြစ်ပြီး၊ logistic regression နှင့် တူညီသော classification power ကို ပေးစွမ်းသည်။\n",
|
||||
" * Sample space တွင် perceptron သည် input data ရဲ့ class နှစ်ခုကို hyperplane အသုံးပြု၍ ခွဲခြားနိုင်သည်။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## ခရက်ဒစ်များ\n",
|
||||
"\n",
|
||||
"ဒီနော့ဘွတ်ခ်ကို [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) ရဲ့ အစိတ်အပိုင်းတစ်ခုအနေနဲ့ ပြုလုပ်ထားပြီး [Dmitry Soshnikov](http://soshnikov.com) က ပြင်ဆင်ထားပါတယ်။ Microsoft Research Cambridge မှ Neural Network Workshop မှာ အကြောင်းအရာတွေကို အခြေခံပြီး အားထားပြုလုပ်ထားတာဖြစ်ပါတယ်။ အချို့သော ကုဒ်နဲ့ ရှင်းလင်းရေးပစ္စည်းတွေကို [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) နဲ့ [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) ရဲ့ တင်ဆက်မှုတွေကနေ ယူထားပြီး [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) repository ကနေပါ အချို့ယူထားပါတယ်။\n"
|
||||
"ဒီနိုတ်ဘွတ်ခ်ကို [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) ရဲ့ အစိတ်အပိုင်းတစ်ခုအဖြစ် ဖန်တီးထားပြီး [Dmitry Soshnikov](http://soshnikov.com) က ပြင်ဆင်ထားပါတယ်။ Microsoft Research Cambridge ရဲ့ Neural Network Workshop မှ အကြောင်းအရာများကို အခြေခံထားပြီး ဖန်တီးထားတာဖြစ်ပါတယ်။ အချို့သော ကုဒ်များနှင့် ရှင်းလင်းဖော်ပြချက်များကို [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) နှင့် [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) တို့ရဲ့ ဖော်ပြချက်များမှယူထားပြီး [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) repository မှလည်း အချို့သောအရာများကို အသုံးပြုထားပါတယ်။\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**ဝန်ခံချက်**: \nဤစာရွက်စာတမ်းကို AI ဘာသာပြန်ဝန်ဆောင်မှု [Co-op Translator](https://github.com/Azure/co-op-translator) ကို အသုံးပြု၍ ဘာသာပြန်ထားပါသည်။ ကျွန်ုပ်တို့သည် တိကျမှန်ကန်မှုအတွက် ကြိုးစားနေသော်လည်း၊ အလိုအလျောက်ဘာသာပြန်ခြင်းတွင် အမှားများ သို့မဟုတ် မမှန်ကန်မှုများ ပါဝင်နိုင်သည်ကို သတိပြုပါ။ မူလဘာသာစကားဖြင့် ရေးသားထားသော စာရွက်စာတမ်းကို အာဏာတည်သော ရင်းမြစ်အဖြစ် သတ်မှတ်သင့်ပါသည်။ အရေးကြီးသော အချက်အလက်များအတွက် လူ့ဘာသာပြန်ပညာရှင်များကို အသုံးပြုရန် အကြံပြုပါသည်။ ဤဘာသာပြန်ကို အသုံးပြုခြင်းမှ ဖြစ်ပေါ်လာသော နားလည်မှုမှားများ သို့မဟုတ် အဓိပ္ပါယ်မှားများအတွက် ကျွန်ုပ်တို့သည် တာဝန်မယူပါ။\n"
|
||||
"\n---\n\n**အကြောင်းကြားချက်**: \nဤစာရွက်စာတမ်းကို AI ဘာသာပြန်ဝန်ဆောင်မှု [Co-op Translator](https://github.com/Azure/co-op-translator) ကို အသုံးပြု၍ ဘာသာပြန်ထားပါသည်။ ကျွန်ုပ်တို့သည် တိကျမှုအတွက် ကြိုးစားနေသော်လည်း အလိုအလျောက် ဘာသာပြန်မှုများတွင် အမှားများ သို့မဟုတ် မမှန်ကန်မှုများ ပါဝင်နိုင်သည်ကို သတိပြုပါ။ မူရင်းဘာသာစကားဖြင့် ရေးသားထားသော စာရွက်စာတမ်းကို အာဏာတရားရှိသော အရင်းအမြစ်အဖြစ် သတ်မှတ်သင့်ပါသည်။ အရေးကြီးသော အချက်အလက်များအတွက် လူသားမှ ဘာသာပြန်မှုကို အကြံပြုပါသည်။ ဤဘာသာပြန်မှုကို အသုံးပြုခြင်းမှ ဖြစ်ပေါ်လာသော အလွဲအမှားများ သို့မဟုတ် အနားယူမှုများအတွက် ကျွန်ုပ်တို့သည် တာဝန်မယူပါ။\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:49:56+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:38:26+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "my"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@
|
|||
"\n",
|
||||
"> यो नोटबुक [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) को एक भाग हो। सम्पूर्ण सिकाइ सामग्रीको लागि रिपोजिटरी भ्रमण गर्नुहोस्।\n",
|
||||
"\n",
|
||||
"जसरी हामीले चर्चा गर्यौं, पर्सेप्ट्रोनले तपाईंलाई **द्वैध वर्गीकरण समस्या** समाधान गर्न अनुमति दिन्छ, अर्थात् इनपुट उदाहरणहरूलाई दुई वर्गहरूमा वर्गीकृत गर्न - हामी तिनीहरूलाई **सकारात्मक** र **नकारात्मक** भन्न सक्छौं।\n",
|
||||
"जसरी हामीले चर्चा गर्यौं, पर्सेप्ट्रोनले तपाईंलाई **द्विआधारी वर्गीकरण समस्या** समाधान गर्न अनुमति दिन्छ, अर्थात् इनपुट उदाहरणहरूलाई दुई वर्गहरूमा वर्गीकृत गर्न - हामी तिनीहरूलाई **सकारात्मक** र **नकारात्मक** भन्न सक्छौं।\n",
|
||||
"\n",
|
||||
"पहिले, केही आवश्यक पुस्तकालयहरू आयात गरौं।\n"
|
||||
"पहिले, केही आवश्यक लाइब्रेरीहरू आयात गरौं।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"हामी डेटासेट पनि प्लट गरौं:\n"
|
||||
"आउनुहोस्, डेटासेट पनि प्लट गरौं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"तर, एक सामान्य रेखीय मोडेलमा बायस पनि हुनुपर्छ, अर्थात् आदर्श रूपमा हामी $y$ लाई $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ को रूपमा गणना गर्नुपर्छ। हाम्रो मोडेललाई सरल बनाउन, हामी इनपुट विशेषताहरूमा एउटा थप आयाम थपेर, जुन सधैं 1 बराबर हुन्छ, यो बायस टर्म हटाउन सक्छौं:\n"
|
||||
"तर, एक सामान्य रेखीय मोडेलमा बायस पनि हुनुपर्छ, अर्थात् आदर्श रूपमा हामी $y$ लाई $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ को रूपमा गणना गर्नुपर्छ। हाम्रो मोडेललाई सरल बनाउन, हामी इनपुट विशेषताहरूमा एउटा थप आयाम थपेर, जुन सधैं 1 बराबर हुन्छ, यो बायस पद हटाउन सक्छौं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -206,20 +206,20 @@
|
|||
"source": [
|
||||
"## प्रशिक्षण एल्गोरिदम\n",
|
||||
"\n",
|
||||
"परसेप्ट्रोनलाई प्रशिक्षण दिनको लागि, हामीले तौलहरू $\\mathbf{w}$ पत्ता लगाउनुपर्छ जसले त्रुटि न्यूनतम बनाउँछ। त्रुटि **परसेप्ट्रोन मापदण्ड** प्रयोग गरेर परिभाषित गरिन्छ:\n",
|
||||
"पर्सेप्ट्रोनलाई प्रशिक्षण दिनको लागि, हामी $\\mathbf{w}$ तौलहरू पत्ता लगाउन आवश्यक छ जसले त्रुटि न्यूनतम बनाउँछ। त्रुटि **पर्सेप्ट्रोन मापदण्ड** प्रयोग गरेर परिभाषित गरिएको छ:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ नकारात्मक र सकारात्मक प्रशिक्षण नमूनाहरूको लागि क्रमशः\n",
|
||||
" * $\\mathcal{M}$ - गलत वर्गीकृत उदाहरणहरूको सेट\n",
|
||||
" \n",
|
||||
"हामी **ग्रेडियन्ट डिसेन्ट** प्रक्रिया प्रयोग गर्नेछौं। केही सुरुवाती अनियमित तौलहरू $\\mathbf{w}^{(0)}$ बाट सुरु गर्दै, हामी प्रत्येक प्रशिक्षण चरणमा $E$ को ग्रेडियन्ट प्रयोग गरेर तौलहरू समायोजन गर्नेछौं:\n",
|
||||
"हामी **ग्रेडियन्ट डिसेन्ट** प्रक्रिया प्रयोग गर्नेछौं। केही प्रारम्भिक र्यान्डम तौलहरू $\\mathbf{w}^{(0)}$ बाट सुरु गर्दै, हामी प्रत्येक प्रशिक्षण चरणमा $E$ को ग्रेडियन्ट प्रयोग गरेर तौलहरू समायोजन गर्नेछौं:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"जहाँ $\\eta$ **लर्निङ दर** हो, र $\\tau\\in\\mathbb{N}$ - पुनरावृत्तिको संख्या।\n",
|
||||
"जहाँ $\\eta$ **शिक्षण दर** हो, र $\\tau\\in\\mathbb{N}$ - पुनरावृत्तिको संख्या।\n",
|
||||
"\n",
|
||||
"अब, यस एल्गोरिदमलाई Python मा परिभाषित गरौं:\n"
|
||||
"अब यस एल्गोरिदमलाई Python मा परिभाषित गरौं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -272,7 +272,20 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"अब हाम्रो डाटासेटमा प्रशिक्षण चलाउँ।\n"
|
||||
"**शिक्षण दरको नोट**: `learning_rate` प्यारामिटर (डिफल्ट `0.01`) ले प्रत्येक प्रशिक्षण चरणमा तौलहरू कति समायोजन गर्ने भन्ने कुरा नियन्त्रण गर्छ। यसले ग्रेडियन्ट डिसेन्ट अपडेट सूत्र लागू गर्दछ:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- ठूलो शिक्षण दर (जस्तै, `1.0`) ले पर्सेप्ट्रोनलाई छिटो सिक्न मद्दत गर्छ तर इष्टतम समाधानलाई पार गर्न सक्छ\n",
|
||||
"- सानो शिक्षण दर (जस्तै, `0.001`) बिस्तारै सिक्छ तर अधिक सटीक रूपमा अभिसरण गर्न सक्छ\n",
|
||||
"- तपाईं यसलाई प्रयोग गरेर परीक्षण गर्न सक्नुहुन्छ: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"अब हाम्रो डाटासेटमा प्रशिक्षण चलाउँ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"जस्तो तपाईंले देख्न सक्नुहुन्छ, सुरुवाती शुद्धता लगभग ५०% छ, तर यो छिट्टै बढेर ९०% नजिकका उच्च मानहरूमा पुग्छ।\n",
|
||||
"\n",
|
||||
"अब कक्षाहरू कसरी छुट्याइन्छन् भनेर दृश्यात्मक बनाऔं। हाम्रो वर्गीकरण कार्य $\\mathbf{w}^Tx$ जस्तो देखिन्छ, र यो एक कक्षाको लागि ० भन्दा ठूलो छ, र अर्को कक्षाको लागि ० भन्दा सानो छ। त्यसैले, कक्षा छुट्याउने रेखा $\\mathbf{w}^Tx = 0$ द्वारा परिभाषित हुन्छ। किनकि हामीसँग केवल दुई आयाम $x_0$ र $x_1$ छन्, रेखाको समीकरण $w_0x_0+w_1x_1+w_2 = 0$ हुनेछ (याद गर्नुहोस् कि हामीले स्पष्ट रूपमा एक अतिरिक्त आयाम $x_2=1$ परिभाषित गरेका छौं)। अब यो रेखा प्लट गरौं:\n"
|
||||
"अब कक्षाहरू कसरी छुट्याइन्छन् भनेर हेर्नुहोस्। हाम्रो वर्गीकरण कार्य $\\mathbf{w}^Tx$ जस्तो देखिन्छ, र यो एक कक्षाको लागि ० भन्दा ठूलो हुन्छ, र अर्को कक्षाको लागि ० भन्दा सानो। त्यसैले, कक्षा छुट्याउने रेखा $\\mathbf{w}^Tx = 0$ द्वारा परिभाषित हुन्छ। किनकि हामीसँग केवल दुई आयाम $x_0$ र $x_1$ छन्, रेखाको समीकरण $w_0x_0+w_1x_1+w_2 = 0$ हुनेछ (याद गर्नुहोस् कि हामीले स्पष्ट रूपमा एक अतिरिक्त आयाम $x_2=1$ परिभाषित गरेका छौं)। अब यो रेखा प्लट गरौं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## सिकाइ दरहरूसँग प्रयोग गर्दै\n",
|
||||
"\n",
|
||||
"अब विभिन्न सिकाइ दरहरूले प्रशिक्षण प्रक्रियामा कसरी प्रभाव पार्छन् भनेर अन्वेषण गरौं। सिकाइ दरले ग्रेडियन्ट डिसेन्टमा कदमको आकार नियन्त्रण गर्छ - एक महत्वपूर्ण हाइपरप्यारामिटर जसले अभिसरणको गति र स्थिरतालाई प्रभाव पार्छ।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### अन्तरक्रियात्मक सिकाइ दर प्रयोग\n",
|
||||
"\n",
|
||||
"तलको स्लाइडर प्रयोग गरेर विभिन्न सिकाइ दरहरूसँग अन्तरक्रियात्मक रूपमा प्रयोग गर्नुहोस् र तिनीहरूले निर्णय सीमा कसरी प्रभावित गर्छन् हेर्नुहोस्:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -379,9 +505,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## परीक्षण डेटासेटमा मूल्यांकन गर्नुहोस्\n",
|
||||
"## परीक्षण डाटासेटमा मूल्यांकन गर्नुहोस्\n",
|
||||
"\n",
|
||||
"सुरुमा, हामीले केही डाटा परीक्षण डेटासेटका लागि छुट्याएका थियौं। अब हेरौं कि हाम्रो वर्गीकरणकर्ता यो परीक्षण डेटासेटमा कति सही छ। यसका लागि, हामी परीक्षण डेटासेटलाई एउटा अतिरिक्त आयामसँग विस्तार गर्छौं, तौल म्याट्रिक्ससँग गुणा गर्छौं, र सुनिश्चित गर्छौं कि प्राप्त मान लेबल (+1 वा -1) जस्तै चिन्हको हो। त्यसपछि हामी सबै बूलियन मानहरूलाई जोड्छौं र परीक्षण नमूनाको लम्बाइले भाग लगाउँछौं, सहीताको प्राप्त गर्न:\n"
|
||||
"सुरुमा, हामीले केही डाटा परीक्षण डाटासेटका लागि छुट्याएका थियौं। अब हेरौं कि हाम्रो वर्गीकरणकर्ता यो परीक्षण डाटासेटमा कति सही छ। यो गर्नको लागि, हामी परीक्षण डाटासेटलाई एउटा अतिरिक्त आयामसँग विस्तार गर्छौं, तौल म्याट्रिक्ससँग गुणा गर्छौं, र सुनिश्चित गर्छौं कि प्राप्त मान लेबल (+1 वा -1) को समान चिन्हको हो। त्यसपछि हामी सबै बूलियन मानहरूलाई जोड्छौं र परीक्षण नमूनाको लम्बाइले भाग गर्छौं, सहीताको गणना गर्न:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## प्रशिक्षण प्रक्रिया अवलोकन गर्दै\n",
|
||||
"\n",
|
||||
"हामीले पहिले देखेका थियौं कि प्रशिक्षणको क्रममा शुद्धता घट्छ। प्रशिक्षणको क्रममा छुट्ट्याउने रेखा कसरी व्यवहार गर्छ भन्ने हेर्नु राम्रो हुनेछ। तलको कोडले सबै कुरा एउटै ग्राफमा देखाउनेछ, र तपाईंले स्लाइडर सारेर प्रशिक्षण प्रक्रियामा \"समय यात्रा\" गर्न सक्नुहुनेछ।\n"
|
||||
"हामीले पहिले देखेका थियौं कि प्रशिक्षणको क्रममा शुद्धता घट्छ। प्रशिक्षणको क्रममा छुट्ट्याउने रेखा कसरी व्यवहार गर्छ भन्ने हेर्न राम्रो हुनेछ। तलको कोडले सबै कुरा एउटै ग्राफमा देखाउनेछ, र तपाईंले स्लाइडर सारेर प्रशिक्षण प्रक्रियामा \"समय यात्रा\" गर्न सक्नुहुनेछ।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -527,18 +653,18 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## परसेप्ट्रोनका सीमाहरू\n",
|
||||
"## पर्सेप्ट्रोनको सीमितताहरू\n",
|
||||
"\n",
|
||||
"जसरी तपाईंले माथि देख्नुभयो, परसेप्ट्रोन एक **रेखीय वर्गीकरणकर्ता** हो। यदि दुई वर्गहरू **रेखीय रूपमा छुट्याउन मिल्ने** छन्, अर्थात् सीधा रेखाले छुट्याउन सकिन्छ भने, यसले ती दुई वर्गहरूलाई राम्रोसँग छुट्याउन सक्छ। अन्यथा, परसेप्ट्रोनको प्रशिक्षण प्रक्रिया अभिसरण गर्दैन।\n",
|
||||
"जस्तो तपाईंले माथि देख्नुभयो, पर्सेप्ट्रोन एक **रेखीय वर्गीकरणकर्ता** हो। यदि दुई वर्गहरू **रेखीय रूपमा छुट्याउन सकिने** छन्, अर्थात् सीधा रेखाले छुट्याउन सकिन्छ भने, यसले ती वर्गहरू राम्रोसँग छुट्याउन सक्छ। अन्यथा, पर्सेप्ट्रोनको प्रशिक्षण प्रक्रिया सधैं सफल हुँदैन।\n",
|
||||
"\n",
|
||||
"परसेप्ट्रोनले समाधान गर्न नसक्ने समस्याको सबैभन्दा स्पष्ट उदाहरण भनेको **XOR समस्या** हो। हामी चाहन्छौं कि हाम्रो परसेप्ट्रोनले XOR बूलियन फङ्सन सिकून, जसको सत्यतालिका यस प्रकार छ:\n",
|
||||
"पर्सेप्ट्रोनले समाधान गर्न नसक्ने समस्याको सबैभन्दा स्पष्ट उदाहरण भनेको **XOR समस्या** हो। हामी चाहन्छौं कि हाम्रो पर्सेप्ट्रोनले XOR बूलियन फलन सिकून, जसको सत्य तालिका निम्न प्रकारको छ:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"अब यसलाई प्रयास गरौं! हामी सबै सकारात्मक र नकारात्मक प्रशिक्षण नमूनाहरूलाई म्यानुअली भर्नेछौं, र त्यसपछि माथि परिभाषित गरिएको हाम्रो train फङ्सनलाई कल गर्नेछौं:\n"
|
||||
"अब हामी यसलाई प्रयास गरौं! हामी सबै सकारात्मक र नकारात्मक प्रशिक्षण नमूनाहरू म्यानुअली भर्नेछौं, अनि माथि परिभाषित गरिएको हाम्रो प्रशिक्षण फलनलाई कल गर्नेछौं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -607,19 +733,19 @@
|
|||
"source": [
|
||||
"जस्तो कि माथिको ग्राफबाट देख्न सकिन्छ, शुद्धता कहिल्यै ७५% भन्दा माथि जान सक्दैन, किनभने सबै सम्भावित उदाहरणहरू सही पार्न सीधा रेखा कोर्न असम्भव छ।\n",
|
||||
"\n",
|
||||
"XOR समस्या परसेप्ट्रोनको सीमाको एक क्लासिकल उदाहरण हो, र यो १९६९ मा मार्विन मिन्स्की र सेमोर पेपर्टले आफ्नो पुस्तक [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) मा उल्लेख गरेका थिए। यो अवलोकनले न्यूरल नेटवर्कको क्षेत्रमा लगभग १० वर्षसम्म अनुसन्धानलाई सीमित गर्यो, यद्यपि - र हामी यो हाम्रो पाठको अर्को खण्डमा देख्नेछौं - बहु-स्तरीय परसेप्ट्रोनहरूले यस्ता समस्याहरू समाधान गर्न सक्षम छन्।\n",
|
||||
"XOR समस्या परसेप्ट्रोनको सीमाको एक क्लासिकल उदाहरण हो, र यो १९६९ मा मार्विन मिन्स्की र सेमोर पेपर्टले आफ्नो पुस्तक [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) मा उल्लेख गरेका थिए। यो अवलोकनले न्यूरल नेटवर्कको क्षेत्रमा लगभग १० वर्षसम्म अनुसन्धानलाई सीमित गर्यो, यद्यपि - र हामी यो हाम्रो पाठको अर्को खण्डमा देख्नेछौं - बहु-स्तरीय परसेप्ट्रोनहरूले यस्ता समस्याहरू समाधान गर्न पूर्ण रूपमा सक्षम छन्।\n",
|
||||
"\n",
|
||||
"## जटिल उदाहरण - MNIST\n",
|
||||
"\n",
|
||||
"यद्यपि परसेप्ट्रोनले XOR समस्या समाधान गर्न सक्दैन, यसले हस्तलेखन गरिएको अक्षर पहिचान जस्ता धेरै जटिल समस्याहरू समाधान गर्न सक्छ।\n",
|
||||
"यद्यपि परसेप्ट्रोनले XOR समस्या समाधान गर्न सक्दैन, यसले हस्तलिखित अक्षर पहिचान जस्ता धेरै जटिल समस्याहरू समाधान गर्न सक्छ।\n",
|
||||
"\n",
|
||||
"मेसिन लर्निङ सिक्दा प्राय: प्रयोग गरिने डाटासेटलाई [MNIST](https://en.wikipedia.org/wiki/MNIST_database) भनिन्छ। यो Modified National Institute of Standards and Technology द्वारा सिर्जना गरिएको हो, र यसमा ६०,००० हस्तलेखन गरिएको अंकहरूको प्रशिक्षण सेट समावेश छ, जुन लगभग २५० विद्यार्थी र संस्थाका कर्मचारीहरूबाट संकलन गरिएको हो। त्यस्तै, १०,००० अंकहरूको परीक्षण डाटासेट पनि छ, जुन विभिन्न व्यक्तिहरूबाट संकलन गरिएको छ।\n",
|
||||
"मेसिन लर्निङ सिक्दा प्राय: प्रयोग गरिने डेटासेटलाई [MNIST](https://en.wikipedia.org/wiki/MNIST_database) भनिन्छ। यो Modified National Institute of Standards and Technology द्वारा सिर्जना गरिएको हो, र यसमा ६०,००० हस्तलिखित अंकहरूको प्रशिक्षण सेट समावेश छ, जुन लगभग २५० विद्यार्थी र संस्थाका कर्मचारीहरूबाट संकलन गरिएको हो। त्यस्तै, १०,००० अंकहरूको परीक्षण डेटासेट पनि छ, जुन विभिन्न व्यक्तिहरूबाट संकलन गरिएको छ।\n",
|
||||
"\n",
|
||||
"सबै अंकहरू २८x२८ पिक्सेलको ग्रेस्केल छविहरूद्वारा प्रतिनिधित्व गरिएका छन्।\n",
|
||||
"\n",
|
||||
"> MNIST डाटासेट [Kaggle](https://www.kaggle.com/c/digit-recognizer) मा प्रशिक्षण प्रतियोगिताको रूपमा उपलब्ध छ, जुन मेसिन लर्निङ प्रतियोगिता र प्रतिस्पर्धा आयोजना गर्ने साइट हो। जब तपाईं MNIST अंकहरू वर्गीकृत गर्न सिक्नुहुन्छ, तपाईं आफ्नो समाधान Kaggle मा पेश गर्न सक्नुहुन्छ र अन्य सहभागीहरूसँग तुलना गरेर यसको मूल्याङ्कन हेर्न सक्नुहुन्छ।\n",
|
||||
"> MNIST डेटासेट [Kaggle](https://www.kaggle.com/c/digit-recognizer) मा प्रशिक्षण प्रतियोगिताको रूपमा उपलब्ध छ, जुन मेसिन लर्निङ प्रतियोगिता र प्रतिस्पर्धाहरू आयोजना गर्ने साइट हो। जब तपाईं MNIST अंकहरू वर्गीकृत गर्न सिक्नुहुन्छ, तपाईं आफ्नो समाधान Kaggle मा पेश गर्न सक्नुहुन्छ र अन्य सहभागीहरूसँग तुलना गरेर यसको मूल्याङ्कन हेर्न सक्नुहुन्छ।\n",
|
||||
"\n",
|
||||
"हामी MNIST डाटासेट लोड गरेर सुरु गर्छौं:\n"
|
||||
"हामी MNIST डेटासेट लोड गरेर सुरु गर्छौं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -644,7 +770,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"अब डेटासेट प्लट गरौं:\n"
|
||||
"अब डेटासेटलाई प्लट गरौं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"किनभने पर्सेप्ट्रोन एक द्विआधारी वर्गीकरणकर्ता हो, हामी हाम्रो समस्या दुई अंक मात्र चिन्नेमा सीमित गर्नेछौं। तलको कार्यले दुई दिइएका अंकहरू सहित सकारात्मक र नकारात्मक नमूना एरेहरू भरिनेछ (र स्पष्टताको लागि ती अंकहरूको नमूनाहरू पनि देखाउनेछ)।\n"
|
||||
"किनभने पर्सेप्ट्रोन एक द्विपक्षीय वर्गीकरणकर्ता हो, हामी हाम्रो समस्यालाई केवल दुई अंकहरू पहिचान गर्न सीमित गर्नेछौं। तलको कार्यले दुई दिइएका अंकहरू सहित सकारात्मक र नकारात्मक नमूना एरेहरू भर्नेछ (र स्पष्टताको लागि ती अंकहरूको नमूनाहरू पनि देखाउनेछ)।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -735,7 +861,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"हामी ० र १ बीच वर्गीकरण गर्ने प्रयास गरेर सुरु गर्नेछौं:\n"
|
||||
"हामी 0 र 1 बीच वर्गीकरण गर्ने प्रयास गरेर सुरु गर्नेछौं:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"कृपया ध्यान दिनुहोस् कि सटीकता धेरै छिटो लगभग १००% सम्म पुग्छ।\n",
|
||||
"\n",
|
||||
"कृपया, प्रशिक्षणको अन्त्यतिर स्लाइडरलाई कुनै स्थानमा सार्नुहोस्, र बायाँपट्टि प्लट गरिएको वजन म्याट्रिक्सलाई अवलोकन गर्नुहोस्। यो म्याट्रिक्सले तपाईंलाई बुझ्न मद्दत गर्नेछ कि पर्सेप्ट्रोन वास्तवमा कसरी काम गर्छ। तपाईंले क्षेत्रको बीचमा उच्च वजन मानहरू देख्न सक्नुहुन्छ, जुन सामान्यतया अंक १ को लागि उपस्थित हुने पिक्सेलसँग मेल खान्छ, र छेउमा कम नकारात्मक मानहरू, जहाँ अंक ० को भागहरू हुन्छन्। त्यसैले, यदि पर्सेप्ट्रोनलाई प्रस्तुत गरिएको अंक वास्तवमा १ हो भने, यसको बीच भाग उच्च मानहरूद्वारा गुणा गरिनेछ, जसले सकारात्मक परिणाम उत्पादन गर्नेछ। यसको विपरीत, जब पर्सेप्ट्रोनले ० अवलोकन गर्छ, सम्बन्धित पिक्सेलहरू नकारात्मक संख्याहरूद्वारा गुणा गरिनेछन्।\n",
|
||||
"कृपया, प्रशिक्षणको अन्त्यतिर स्लाइडरलाई कुनै स्थानमा सार्नुहोस्, र बायाँतिर प्लट गरिएको वजन म्याट्रिक्सलाई अवलोकन गर्नुहोस्। यो म्याट्रिक्सले तपाईंलाई बुझ्न मद्दत गर्नेछ कि पर्सेप्ट्रोन वास्तवमा कसरी काम गर्छ। तपाईंले क्षेत्रको बीचमा उच्च वजन मानहरू देख्न सक्नुहुन्छ, जुन सामान्यतया अंक १ को लागि उपस्थित हुने पिक्सेलसँग मेल खान्छ, र छेउमा कम नकारात्मक मानहरू, जहाँ अंक ० को भागहरू हुन्छन्। त्यसैले, यदि पर्सेप्ट्रोनलाई प्रस्तुत गरिएको अंक वास्तवमा १ हो भने, यसको बीच भाग उच्च मानहरूद्वारा गुणा गरिनेछ, जसले सकारात्मक परिणाम उत्पादन गर्नेछ। यसको विपरीत, जब पर्सेप्ट्रोनले ० अवलोकन गर्छ, सम्बन्धित पिक्सेलहरू नकारात्मक संख्याहरूद्वारा गुणा गरिनेछन्।\n",
|
||||
"\n",
|
||||
"> तपाईंले देख्न सक्नुहुन्छ कि यदि हामीले हाम्रो पर्सेप्ट्रोनलाई अंक १ थोरै क्षैतिज रूपमा सरेको अवस्थामा दिन्छौं, जसले गर्दा यसको पिक्सेलहरू त्यहाँ स्थान ओगट्छ जहाँ ० को ठाडो भागहरू छन्, हामीले गलत परिणाम प्राप्त गर्न सक्छौं। किनकि हाम्रो MNIST डेटासेटको प्रकृति यस्तो छ कि सबै अंकहरू केन्द्रित र सही रूपमा स्थित छन्, र पर्सेप्ट्रोनले अंकहरू छुट्याउन यसमा निर्भर गर्दछ।\n",
|
||||
"> तपाईंले यो पनि देख्न सक्नुहुन्छ कि यदि हामीले हाम्रो पर्सेप्ट्रोनलाई अंक १ थोरै क्षैतिज रूपमा सारेर दिन्छौं, जसले गर्दा यसको पिक्सेलहरू त्यहाँको स्थान ओगट्छ जहाँ ० को ठाडो भागहरू छन्, हामीले गलत परिणाम प्राप्त गर्न सक्छौं। किनकि हाम्रो MNIST डेटासेटको प्रकृति यस्तो छ कि सबै अंकहरू केन्द्रित र सही रूपमा स्थित छन्, र पर्सेप्ट्रोनले अंकहरू छुट्याउन यसमा निर्भर गर्दछ।\n",
|
||||
"\n",
|
||||
"अब विभिन्न अंकहरू प्रयास गरौं:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## छलफल\n",
|
||||
"\n",
|
||||
"कुनै कारणले गर्दा, २ र ५ लाई सजिलै छुट्याउन सकिँदैन। यद्यपि हामीले तुलनात्मक रूपमा उच्च शुद्धता (८५% भन्दा माथि) प्राप्त गर्छौं, हामी स्पष्ट रूपमा देख्न सक्छौं कि Perceptron केही बिन्दुमा सिक्न रोक्छ।\n",
|
||||
"केही कारणले गर्दा, २ र ५ यति सजिलै छुट्याउन सकिँदैन। यद्यपि हामीले तुलनात्मक रूपमा उच्च शुद्धता (८५% भन्दा माथि) प्राप्त गर्छौं, हामी स्पष्ट रूपमा देख्न सक्छौं कि कसरी परसेप्ट्रोनले कुनै बिन्दुमा सिक्न रोक्छ।\n",
|
||||
"\n",
|
||||
"यो किन हुन्छ भनेर बुझ्नका लागि, हामी [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) प्रयोग गर्न सक्छौं। यो एक मेसिन लर्निङ प्रविधि हो जसले इनपुट डेटासेटको आयाम घटाउन प्रयोग गरिन्छ, ताकि वर्गहरू बीचको छुट्ट्याउने क्षमता सुधार गर्न सकियोस्।\n",
|
||||
"यो किन हुन्छ भनेर बुझ्नको लागि, हामी [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) प्रयोग गर्न सक्छौं। यो एक मेसिन लर्निङ प्रविधि हो जसले इनपुट डेटासेटको आयाम घटाउन प्रयोग गरिन्छ, ताकि वर्गहरू बीचको उत्तम छुट्टयापन प्राप्त गर्न सकियोस्।\n",
|
||||
"\n",
|
||||
"हाम्रो अवस्थामा, इनपुट इमेजमा ७८४ पिक्सेल (इनपुट विशेषताहरू) छन्, र हामी PCA प्रयोग गरेर प्यारामिटरहरूको संख्या केवल २ मा घटाउन चाहन्छौं, ताकि हामी तिनीहरूलाई ग्राफमा प्लट गर्न सकौं। ती दुई प्यारामिटरहरू मूल विशेषताहरूको रेखीय संयोजन हुनेछन्, र हामी यस प्रक्रियालाई हाम्रो मूल ७८४-आयामीय स्थानलाई \"घुमाउने\" र यसको प्रक्षेपणलाई २D-स्थानमा अवलोकन गर्ने रूपमा हेर्न सक्छौं, जबसम्म वर्गहरू छुट्याउनको लागि उत्तम दृश्य प्राप्त हुँदैन।\n"
|
||||
"हाम्रो अवस्थामा, इनपुट छवि ७८४ पिक्सेल (इनपुट विशेषताहरू) हुन्छ, र हामी PCA प्रयोग गरेर प्यारामिटरहरूको संख्या केवल २ मा घटाउन चाहन्छौं, ताकि हामी तिनीहरूलाई ग्राफमा प्लट गर्न सकौं। ती दुई प्यारामिटरहरू मूल विशेषताहरूको रेखीय संयोजन हुनेछन्, र हामी यस प्रक्रियालाई हाम्रो मूल ७८४-आयामीय स्थानलाई \"घुमाउने\" र यसको प्रक्षेपणलाई हाम्रो २D-स्थानमा अवलोकन गर्ने रूपमा हेर्न सक्छौं, जबसम्म हामी वर्गहरू छुट्याउने उत्तम दृश्य प्राप्त गर्दैनौं।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,16 +1153,16 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"जस्तो कि तपाईंले देख्न सक्नुहुन्छ, 0 र 1 लाई स्पष्ट रूपमा एक सीधा रेखाले छुट्याउन सकिन्छ। यसले संकेत गर्दछ कि मूल 784-आयामीय स्थानमा अंकहरूलाई प्रतिनिधित्व गर्ने बिन्दुहरू पनि रेखीय रूपमा छुट्याउन सकिन्छ। तर 2 र 5 को मामलामा, अंकहरूलाई स्पष्ट रूपमा छुट्याउने राम्रो प्रक्षेपण पाउन सकिँदैन, जसका कारण केही गलत वर्गीकरणका केसहरू देखिन्छन्।\n",
|
||||
"जस्तो कि तपाईं देख्न सक्नुहुन्छ, 0 र 1 लाई स्पष्ट रूपमा सीधा रेखाले छुट्याउन सकिन्छ। यसले संकेत गर्दछ कि मूल 784-आयामीय स्थानमा अंकहरूलाई प्रतिनिधित्व गर्ने बिन्दुहरू पनि रेखीय रूपमा छुट्याउन सकिन्छ। तर 2 र 5 को मामलामा, अंकहरूलाई स्पष्ट रूपमा छुट्याउने राम्रो प्रक्षेपण पाउन सकिँदैन, जसका कारण केही गलत वर्गीकरणका केसहरू देखिन्छन्।\n",
|
||||
"\n",
|
||||
"> यस पाठक्रमको पछि हामी Neural Networks प्रयोग गरेर गैर-रेखीय वर्गीकरणकर्ता कसरी बनाउने भन्ने कुरा सिक्नेछौं, र अंकहरू सही रूपमा नजोडिएको समस्यालाई कसरी समाधान गर्ने भन्ने कुरा पनि बुझ्नेछौं। धेरै चाँडै हामी MNIST अंक वर्गीकरणमा 99% भन्दा माथिको शुद्धता हासिल गर्नेछौं, जहाँ हामी अंकहरूलाई 10 विभिन्न वर्गहरूमा वर्गीकृत गर्नेछौं।\n",
|
||||
"> यस पाठक्रममा पछि हामी Neural Networks प्रयोग गरेर गैर-रेखीय वर्गीकरणकर्ता कसरी बनाउने भन्ने कुरा सिक्नेछौं, र अंकहरू सही रूपमा नजोडिएको समस्यालाई कसरी समाधान गर्ने भन्ने कुरा पनि बुझ्नेछौं। धेरै चाँडै हामी MNIST अंक वर्गीकरणमा 99% भन्दा माथिको शुद्धता हासिल गर्नेछौं, जहाँ हामी अंकहरूलाई 10 विभिन्न वर्गहरूमा वर्गीकृत गर्नेछौं।\n",
|
||||
"\n",
|
||||
"## मुख्य कुरा\n",
|
||||
"\n",
|
||||
" * हामीले सबैभन्दा सरल Neural Network संरचना - एक-स्तरको Perceptron को बारेमा सिक्यौं।\n",
|
||||
" * हामीले सबैभन्दा सरल Neural Network संरचना - एक-स्तरीय Perceptron को बारेमा सिक्यौं।\n",
|
||||
" * हामीले Gradient Descent आधारित सरल प्रशिक्षण प्रक्रिया प्रयोग गरेर Perceptron \"हातले\" कार्यान्वयन गर्यौं।\n",
|
||||
" * सरल भए पनि, एक-स्तरको Perceptron हस्तलेखन गरिएको अंक पहिचानको जटिल समस्याहरू समाधान गर्न सक्षम छ।\n",
|
||||
" * एक-स्तरको Perceptron एक रेखीय वर्गीकरणकर्ता हो, त्यसैले यसले Logistic Regression जत्तिकै वर्गीकरण क्षमता प्रदान गर्दछ।\n",
|
||||
" * सरल भए पनि, एक-स्तरीय Perceptron हस्तलेखन गरिएको अंक पहिचानको जटिल समस्याहरू समाधान गर्न सक्षम छ।\n",
|
||||
" * एक-स्तरीय Perceptron एक रेखीय वर्गीकरणकर्ता हो, र यसले Logistic Regression जत्तिकै वर्गीकरण क्षमता प्रदान गर्दछ।\n",
|
||||
" * नमूना स्थानमा, Perceptron ले Hyperplane प्रयोग गरेर इनपुट डाटाका दुई वर्गहरू छुट्याउन सक्छ।\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## श्रेय\n",
|
||||
"\n",
|
||||
"यो नोटबुक [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) को एक भाग हो, र यसलाई [Dmitry Soshnikov](http://soshnikov.com) द्वारा तयार गरिएको हो। यो Microsoft Research Cambridge मा आयोजित Neural Network Workshop बाट प्रेरित छ। केही कोड र चित्रात्मक सामग्रीहरू [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) र [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) का प्रस्तुतीकरणहरूबाट लिइएको हो, साथै [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) रिपोजिटरीबाट पनि।\n"
|
||||
"यो नोटबुक [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) को एक हिस्सा हो, र यसलाई [Dmitry Soshnikov](http://soshnikov.com) द्वारा तयार गरिएको हो। यो Microsoft Research Cambridge मा आयोजित Neural Network Workshop बाट प्रेरित छ। केही कोड र चित्रात्मक सामग्रीहरू [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) र [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) का प्रस्तुतीकरणहरूबाट लिइएको छ, साथै [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) रिपोजिटरीबाट पनि।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**अस्वीकरण**: \nयो दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) प्रयोग गरेर अनुवाद गरिएको छ। हामी यथार्थताको लागि प्रयास गर्छौं, तर कृपया ध्यान दिनुहोस् कि स्वचालित अनुवादमा त्रुटिहरू वा अशुद्धताहरू हुन सक्छ। यसको मूल भाषा मा रहेको मूल दस्तावेज़लाई आधिकारिक स्रोत मानिनुपर्छ। महत्वपूर्ण जानकारीको लागि, व्यावसायिक मानव अनुवाद सिफारिस गरिन्छ। यस अनुवादको प्रयोगबाट उत्पन्न हुने कुनै पनि गलतफहमी वा गलत व्याख्याको लागि हामी जिम्मेवार हुने छैनौं।\n"
|
||||
"\n---\n\n**अस्वीकरण**: \nयो दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) प्रयोग गरेर अनुवाद गरिएको हो। हामी यथार्थताको लागि प्रयास गर्छौं, तर कृपया ध्यान दिनुहोस् कि स्वचालित अनुवादमा त्रुटिहरू वा अशुद्धताहरू हुन सक्छ। यसको मूल भाषा मा रहेको मूल दस्तावेज़लाई आधिकारिक स्रोत मानिनुपर्छ। महत्वपूर्ण जानकारीको लागि, व्यावसायिक मानव अनुवाद सिफारिस गरिन्छ। यस अनुवादको प्रयोगबाट उत्पन्न हुने कुनै पनि गलतफहमी वा गलत व्याख्याको लागि हामी जिम्मेवार हुने छैनौं।\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:21:42+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:08:30+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "ne"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Speelprobleem\n",
|
||||
"## Speelgoedprobleem\n",
|
||||
"\n",
|
||||
"Laten we beginnen met een eenvoudig probleem, waarbij we twee invoerkenmerken hebben. Bijvoorbeeld, in de geneeskunde willen we mogelijk tumoren classificeren als goedaardig of kwaadaardig, afhankelijk van hun grootte en leeftijd.\n",
|
||||
"\n",
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Laten we de dataset ook plotten:\n"
|
||||
"Laten we ook de dataset plotten:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ voor respectievelijk negatieve en positieve trainingsvoorbeelden\n",
|
||||
" * $\\mathcal{M}$ - een verzameling verkeerd geclassificeerde voorbeelden\n",
|
||||
" \n",
|
||||
"We zullen het proces van **gradient descent** gebruiken. Beginnend met willekeurige initiële gewichten $\\mathbf{w}^{(0)}$, passen we de gewichten aan bij elke stap van de training met behulp van de gradient van $E$:\n",
|
||||
"We zullen het proces van **gradient descent** gebruiken. Beginnend met willekeurige initiële gewichten $\\mathbf{w}^{(0)}$, passen we de gewichten bij elke stap van de training aan met behulp van de gradient van $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Opmerking over Leerpercentage**: De parameter `learning_rate` (standaard `0.01`) bepaalt hoeveel we de gewichten aanpassen tijdens elke trainingsstap. Dit implementeert de updateformule van gradient descent:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Een hoger leerpercentage (bijv. `1.0`) zorgt ervoor dat de perceptron sneller leert, maar kan de optimale oplossing voorbijschieten\n",
|
||||
"- Een lager leerpercentage (bijv. `0.001`) leert langzamer, maar kan nauwkeuriger convergeren\n",
|
||||
"- Je kunt experimenteren door het volgende aan te roepen: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Zoals je kunt zien, is de initiële nauwkeurigheid ongeveer 50%, maar deze neemt snel toe naar hogere waarden dicht bij 90%.\n",
|
||||
"\n",
|
||||
"Laten we visualiseren hoe klassen worden gescheiden. Onze classificatiefunctie ziet eruit als $\\mathbf{w}^Tx$, en deze is groter dan 0 voor de ene klasse, en kleiner dan 0 voor de andere. Dus, de scheidingslijn tussen klassen wordt gedefinieerd door $\\mathbf{w}^Tx = 0$. Aangezien we slechts twee dimensies hebben, $x_0$ en $x_1$, zou de vergelijking voor de lijn zijn $w_0x_0+w_1x_1+w_2 = 0$ (onthoud dat we expliciet een extra dimensie hebben gedefinieerd, $x_2=1$). Laten we deze lijn plotten:\n"
|
||||
"Laten we visualiseren hoe de klassen worden gescheiden. Onze classificatiefunctie ziet eruit als $\\mathbf{w}^Tx$, en deze is groter dan 0 voor de ene klasse, en kleiner dan 0 voor de andere. Dus, de scheidingslijn tussen de klassen wordt gedefinieerd door $\\mathbf{w}^Tx = 0$. Aangezien we slechts twee dimensies hebben, $x_0$ en $x_1$, zou de vergelijking voor de lijn zijn $w_0x_0+w_1x_1+w_2 = 0$ (onthoud dat we expliciet een extra dimensie hebben gedefinieerd, $x_2=1$). Laten we deze lijn plotten:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimenteren met Leerpercentages\n",
|
||||
"\n",
|
||||
"Laten we nu onderzoeken hoe verschillende leerpercentages het trainingsproces beïnvloeden. Het leerpercentage bepaalt de stapgrootte in gradient descent - een cruciale hyperparameter die zowel de snelheid van convergentie als de stabiliteit beïnvloedt.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interactieve Leerproces Experiment\n",
|
||||
"\n",
|
||||
"Gebruik de schuifregelaar hieronder om interactief te experimenteren met verschillende leerprocessen en te zien hoe ze de beslissingsgrens beïnvloeden:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Het trainingsproces observeren\n",
|
||||
"\n",
|
||||
"We hebben eerder gezien hoe de nauwkeurigheid afneemt tijdens het trainen. Het zou interessant zijn om te zien hoe de scheidingslijn zich gedraagt tijdens het trainen. De onderstaande code zal alles visualiseren op één grafiek, en je zou de schuifregelaar moeten kunnen gebruiken om door het trainingsproces te \"reizen\".\n"
|
||||
"We hebben eerder gezien hoe de nauwkeurigheid afneemt tijdens het trainen. Het zou interessant zijn om te zien hoe de scheidingslijn zich gedraagt tijdens het trainen. De onderstaande code zal alles op één grafiek visualiseren, en je zou de schuifregelaar moeten kunnen gebruiken om door het trainingsproces te \"reizen\".\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -607,17 +733,17 @@
|
|||
"source": [
|
||||
"Zoals je kunt zien in de bovenstaande grafiek, gaat de nauwkeurigheid nooit boven de 75%, omdat het onmogelijk is om een rechte lijn te tekenen die alle mogelijke voorbeelden correct classificeert.\n",
|
||||
"\n",
|
||||
"Het XOR-probleem is een klassiek voorbeeld van de beperkingen van perceptrons, en dit werd in 1969 aangekaart door Marvin Minsky en Seymour Papert in hun boek [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Deze observatie remde het onderzoek op het gebied van neurale netwerken bijna 10 jaar, hoewel - en dat zullen we in het volgende deel van onze cursus zien - meerlagige perceptrons dergelijke problemen perfect kunnen oplossen.\n",
|
||||
"Het XOR-probleem is een klassiek voorbeeld van de beperkingen van perceptrons, en dit werd in 1969 aangetoond door Marvin Minsky en Seymour Papert in hun boek [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Deze observatie beperkte het onderzoek op het gebied van neurale netwerken bijna 10 jaar, hoewel - en dat zullen we zien in het volgende deel van onze cursus - meerlagige perceptrons dergelijke problemen perfect kunnen oplossen.\n",
|
||||
"\n",
|
||||
"## Complex voorbeeld - MNIST\n",
|
||||
"\n",
|
||||
"Hoewel een perceptron het XOR-probleem niet kan oplossen, kan het wel veel complexere problemen aanpakken, zoals het herkennen van handgeschreven tekens.\n",
|
||||
"\n",
|
||||
"Een dataset die vaak wordt gebruikt bij het leren van machine learning heet [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Deze dataset is ontwikkeld door het Modified National Institute of Standards and Technology en bevat een trainingsset van 60.000 handgeschreven cijfers, verzameld van ongeveer 250 studenten en medewerkers van het instituut. Daarnaast is er een testdataset van 10.000 cijfers, verzameld van verschillende individuen.\n",
|
||||
"Een dataset die vaak wordt gebruikt bij het leren van machine learning heet [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Deze dataset is gemaakt door het Modified National Institute of Standards and Technology en bevat een trainingsset van 60.000 handgeschreven cijfers, verzameld van ongeveer 250 studenten en medewerkers van het instituut. Daarnaast is er een testdataset van 10.000 cijfers, verzameld van verschillende individuen.\n",
|
||||
"\n",
|
||||
"Alle cijfers worden weergegeven als grijswaardenafbeeldingen van 28x28 pixels.\n",
|
||||
"Alle cijfers worden weergegeven door grijswaardenafbeeldingen van 28x28 pixels.\n",
|
||||
"\n",
|
||||
"> De MNIST-dataset is beschikbaar als een trainingscompetitie op [Kaggle](https://www.kaggle.com/c/digit-recognizer), een website die machine learning-wedstrijden en competities organiseert. Zodra je hebt geleerd hoe je MNIST-cijfers kunt classificeren, kun je je oplossing indienen op Kaggle om te zien hoe deze wordt beoordeeld in vergelijking met andere deelnemers.\n",
|
||||
"> De MNIST-dataset is beschikbaar als een trainingscompetitie op [Kaggle](https://www.kaggle.com/c/digit-recognizer), een site die machine learning-wedstrijden en competities organiseert. Zodra je hebt geleerd hoe je MNIST-cijfers kunt classificeren, kun je je oplossing indienen op Kaggle om te zien hoe deze wordt beoordeeld ten opzichte van andere deelnemers.\n",
|
||||
"\n",
|
||||
"We beginnen met het laden van de MNIST-dataset:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Omdat perceptron een binaire classifier is, zullen we ons probleem beperken tot het herkennen van slechts twee cijfers. De onderstaande functie zal positieve en negatieve voorbeeldarrays vullen met twee gegeven cijfers (en zal ook voorbeelden van die cijfers tonen voor duidelijkheid).\n"
|
||||
"Omdat perceptron een binaire classifier is, zullen we ons probleem beperken tot het herkennen van slechts twee cijfers. De onderstaande functie zal positieve en negatieve monsterarrays vullen met twee gegeven cijfers (en zal ook voorbeelden van die cijfers tonen voor duidelijkheid).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -735,7 +861,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We zullen beginnen met proberen te classificeren tussen 0 en 1:\n"
|
||||
"We beginnen met proberen te classificeren tussen 0 en 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -831,11 +957,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let op hoe de nauwkeurigheid heel snel bijna 100% wordt.\n",
|
||||
"Let op hoe de nauwkeurigheid heel snel bijna 100% bereikt.\n",
|
||||
"\n",
|
||||
"Verplaats de schuifregelaar naar een positie tegen het einde van de training en bekijk de gewichts matrix die links wordt weergegeven. Deze matrix helpt je te begrijpen hoe de perceptron eigenlijk werkt. Je kunt de hoge gewichtswaarden in het midden van het veld zien, die overeenkomen met pixels die typisch aanwezig zijn bij cijfer 1, en lage negatieve waarden aan de zijkanten, waar delen van cijfer 0 zich bevinden. Dus, als het cijfer dat aan de perceptron wordt gepresenteerd daadwerkelijk een 1 is, zal het midden ervan worden vermenigvuldigd met hoge waarden, wat een positief resultaat oplevert. Daarentegen, wanneer de perceptron een 0 observeert, zullen de corresponderende pixels worden vermenigvuldigd met negatieve getallen.\n",
|
||||
"Verplaats de schuifregelaar naar een positie tegen het einde van de training en bekijk de gewichtenmatrix die links wordt weergegeven. Deze matrix helpt je te begrijpen hoe de perceptron daadwerkelijk werkt. Je kunt de hoge gewichtswaarden in het midden van het veld zien, die overeenkomen met pixels die typisch aanwezig zijn bij cijfer 1, en lage negatieve waarden aan de zijkanten, waar delen van cijfer 0 zich bevinden. Dus, als het cijfer dat aan de perceptron wordt gepresenteerd daadwerkelijk een 1 is, zal het midden ervan worden vermenigvuldigd met hoge waarden, wat een positief resultaat oplevert. Daarentegen, wanneer de perceptron een 0 waarneemt, zullen de corresponderende pixels worden vermenigvuldigd met negatieve getallen.\n",
|
||||
"\n",
|
||||
"> Je kunt opmerken dat als we onze perceptron een cijfer 1 geven dat iets horizontaal verschoven is, zodat de pixels zich bevinden op de plek waar verticale delen van een 0 zijn, we mogelijk een incorrect resultaat krijgen. Dit komt omdat de aard van onze MNIST-dataset zodanig is dat alle cijfers gecentreerd en correct gepositioneerd zijn, en de perceptron hierop vertrouwt om onderscheid te maken tussen cijfers.\n",
|
||||
"> Je kunt opmerken dat als we onze perceptron een cijfer 1 geven dat iets horizontaal verschoven is, zodat de pixels zich bevinden op de plek waar verticale delen van een 0 zijn, we mogelijk een incorrect resultaat krijgen. Omdat de aard van onze MNIST-dataset zodanig is dat alle cijfers gecentreerd en correct gepositioneerd zijn, vertrouwt de perceptron hierop om onderscheid te maken tussen de cijfers.\n",
|
||||
"\n",
|
||||
"Laten we nu verschillende cijfers proberen:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Discussie\n",
|
||||
"\n",
|
||||
"Om de een of andere reden zijn 2 en 5 niet zo gemakkelijk te scheiden. Hoewel we een relatief hoge nauwkeurigheid behalen (boven de 85%), kunnen we duidelijk zien hoe de perceptron op een bepaald moment stopt met leren.\n",
|
||||
"Om de een of andere reden zijn 2 en 5 niet zo gemakkelijk te scheiden. Hoewel we een relatief hoge nauwkeurigheid behalen (boven de 85%), kunnen we duidelijk zien dat de perceptron op een bepaald moment stopt met leren.\n",
|
||||
"\n",
|
||||
"Om te begrijpen waarom dit gebeurt, kunnen we proberen [Principale Componenten Analyse](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) te gebruiken. Dit is een machine learning-techniek die wordt gebruikt om de dimensionaliteit van de invoerdataset te verlagen, op een manier die de beste scheiding tussen klassen oplevert.\n",
|
||||
"Om te begrijpen waarom dit gebeurt, kunnen we [Principale Componentenanalyse](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) gebruiken. Dit is een machine learning-techniek die wordt gebruikt om de dimensionaliteit van de invoerdataset te verlagen, zodat de beste scheiding tussen klassen wordt verkregen.\n",
|
||||
"\n",
|
||||
"In ons geval heeft een invoerafbeelding 784 pixels (invoerkenmerken), en we willen PCA gebruiken om het aantal parameters te verminderen tot slechts 2, zodat we ze op een grafiek kunnen plotten. Die twee parameters zouden een lineaire combinatie van de oorspronkelijke kenmerken zijn, en we kunnen deze procedure zien als het \"roteren\" van onze oorspronkelijke 784-dimensionale ruimte en het observeren van de projectie ervan naar onze 2D-ruimte, totdat we het beste zicht krijgen dat de klassen scheidt.\n"
|
||||
"In ons geval heeft een invoerafbeelding 784 pixels (invoerkenmerken), en we willen PCA gebruiken om het aantal parameters te reduceren tot slechts 2, zodat we ze op een grafiek kunnen plotten. Die twee parameters zouden een lineaire combinatie van de oorspronkelijke kenmerken zijn, en we kunnen deze procedure zien als het \"roteren\" van onze oorspronkelijke 784-dimensionale ruimte en het observeren van de projectie ervan naar onze 2D-ruimte, totdat we het beste zicht krijgen dat de klassen scheidt.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,14 +1153,14 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Zoals je kunt zien, kunnen 0 en 1 duidelijk worden gescheiden door een rechte lijn. Dit geeft aan dat in de oorspronkelijke 784-dimensionale ruimte punten die overeenkomen met cijfers ook lineair scheidbaar zijn. In het geval van 2 en 5 kunnen we geen goede projectie vinden die de cijfers duidelijk scheidt, en daarom zijn er enkele gevallen van verkeerde classificatie.\n",
|
||||
"Zoals je kunt zien, kunnen 0 en 1 duidelijk worden gescheiden door een rechte lijn. Dit geeft aan dat in de oorspronkelijke 784-dimensionale ruimte de punten die overeenkomen met cijfers ook lineair scheidbaar zijn. In het geval van 2 en 5 kunnen we geen goede projectie vinden die de cijfers duidelijk scheidt, en daarom zijn er enkele gevallen van verkeerde classificatie.\n",
|
||||
"\n",
|
||||
"> Later in deze cursus zullen we leren hoe we niet-lineaire classifiers kunnen maken met behulp van neurale netwerken, en hoe we het probleem kunnen aanpakken van cijfers die niet goed uitgelijnd zijn. Binnenkort zullen we een nauwkeurigheid van meer dan 99% bereiken in de MNIST-cijferclassificatie, terwijl we ze indelen in 10 verschillende klassen.\n",
|
||||
"> Later in deze cursus zullen we leren hoe we niet-lineaire classifiers kunnen maken met behulp van neurale netwerken, en hoe we het probleem kunnen aanpakken van cijfers die niet goed uitgelijnd zijn. Binnenkort zullen we een nauwkeurigheid van meer dan 99% bereiken in de classificatie van MNIST-cijfers, terwijl we ze indelen in 10 verschillende klassen.\n",
|
||||
"\n",
|
||||
"## Belangrijkste punten\n",
|
||||
"\n",
|
||||
" * We hebben geleerd over de eenvoudigste neurale netwerkarchitectuur - de éénlaagse perceptron.\n",
|
||||
" * We hebben de perceptron \"met de hand\" geïmplementeerd, met behulp van een eenvoudige trainingsprocedure gebaseerd op gradient descent.\n",
|
||||
" * We hebben de perceptron \"met de hand\" geïmplementeerd, met een eenvoudige trainingsprocedure gebaseerd op gradient descent.\n",
|
||||
" * Ondanks de eenvoud kan een éénlaagse perceptron vrij complexe problemen oplossen, zoals het herkennen van handgeschreven cijfers.\n",
|
||||
" * Een éénlaagse perceptron is een lineaire classifier en biedt dus dezelfde classificatiemogelijkheden als logistische regressie.\n",
|
||||
" * In de voorbeeldruimte kan een perceptron twee klassen van invoergegevens scheiden met behulp van een hypervlak.\n"
|
||||
|
|
@ -1046,7 +1172,7 @@
|
|||
"source": [
|
||||
"## Credits\n",
|
||||
"\n",
|
||||
"Dit notebook maakt deel uit van [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) en is opgesteld door [Dmitry Soshnikov](http://soshnikov.com). Het is geïnspireerd door de Neural Network Workshop bij Microsoft Research Cambridge. Sommige code en illustratieve materialen zijn afkomstig uit presentaties van [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) en [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), en uit de [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) repository.\n"
|
||||
"Dit notebook maakt deel uit van [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) en is samengesteld door [Dmitry Soshnikov](http://soshnikov.com). Het is geïnspireerd door de Neural Network Workshop bij Microsoft Research Cambridge. Sommige code en illustratieve materialen zijn afkomstig uit presentaties van [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) en [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), en uit de [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) repository.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:34:36+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:22:24+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "nl"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Leketilfelle\n",
|
||||
"## Leketøysproblem\n",
|
||||
"\n",
|
||||
"La oss starte med et leketilfelle, der vi har to inngangsfunksjoner. For eksempel, innen medisin kan vi ønske å klassifisere svulster som godartede eller ondartede, avhengig av størrelse og alder.\n",
|
||||
"La oss starte med et leketøysproblem, hvor vi har to inngangsvariabler. For eksempel, innen medisin kan vi ønske å klassifisere svulster som godartede eller ondartede, avhengig av størrelse og alder.\n",
|
||||
"\n",
|
||||
"Vi vil generere et tilfeldig klassifiseringsdatasett ved hjelp av `make_classification`-funksjonen fra SciKit Learn-biblioteket:\n"
|
||||
]
|
||||
|
|
@ -154,11 +154,11 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"Siden perceptron er en binær klassifikator, vil utdataene for hver inputvektor $x$ fra vår perceptron være enten +1 eller -1, avhengig av klassen. Utdataene beregnes ved hjelp av formelen\n",
|
||||
"Siden perceptron er en binær klassifiserer, vil utdataene fra vår perceptron for hver inputvektor $x$ være enten +1 eller -1, avhengig av klassen. Utdataene beregnes ved hjelp av formelen\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"hvor $\\mathbf{w}$ er en vektvektor, og $f$ er en stegaktiveringsfunksjon:\n",
|
||||
"hvor $\\mathbf{w}$ er en vektvektor, og $f$ er en trinnaktiveringsfunksjon:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"En generell lineær modell bør imidlertid også ha en bias, altså bør vi ideelt sett beregne $y$ som $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. For å forenkle modellen vår kan vi eliminere denne bias-termen ved å legge til én ekstra dimensjon til våre inputfunksjoner, som alltid er lik 1:\n"
|
||||
"En generell lineær modell bør imidlertid også ha en bias, dvs. ideelt sett bør vi beregne $y$ som $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. For å forenkle modellen vår kan vi fjerne denne bias-termen ved å legge til én ekstra dimensjon til våre inputfunksjoner, som alltid er lik 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ for henholdsvis negative og positive treningsprøver\n",
|
||||
" * $\\mathcal{M}$ - et sett med feilklassifiserte eksempler\n",
|
||||
" \n",
|
||||
"Vi vil bruke prosessen **gradientnedstigning**. Med utgangspunkt i noen tilfeldige startvekter $\\mathbf{w}^{(0)}$, vil vi justere vektene på hvert steg i treningen ved hjelp av gradienten til $E$:\n",
|
||||
"Vi vil bruke prosessen **gradientnedstigning**. Med utgangspunkt i noen tilfeldige startvekter $\\mathbf{w}^{(0)}$, vil vi justere vektene på hvert trinn i treningen ved hjelp av gradienten til $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Merk om læringsrate**: Parameteren `learning_rate` (standardverdi `0.01`) styrer hvor mye vi justerer vektene under hvert treningssteg. Dette implementerer oppdateringsformelen for gradientnedstigning:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- En høyere læringsrate (f.eks. `1.0`) gjør at perceptronen lærer raskere, men kan overskyte den optimale løsningen\n",
|
||||
"- En lavere læringsrate (f.eks. `0.001`) lærer saktere, men kan konvergere mer presist\n",
|
||||
"- Du kan eksperimentere ved å kalle: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Eksperimentere med læringsrater\n",
|
||||
"\n",
|
||||
"La oss nå undersøke hvordan ulike læringsrater påvirker treningsprosessen. Læringsraten styrer steglengden i gradientnedstigning - en viktig hyperparameter som påvirker både konvergenshastighet og stabilitet.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktivt eksperiment med læringsrate\n",
|
||||
"\n",
|
||||
"Bruk glidebryteren nedenfor for å eksperimentere interaktivt med ulike læringsrater og se hvordan de påvirker beslutningsgrensen:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Evaluer på testdatasettet\n",
|
||||
"\n",
|
||||
"I starten satte vi til side noe data til testdatasettet. La oss se hvor nøyaktig klassifiseringen vår er på dette testdatasettet. For å gjøre dette utvider vi også testdatasettet med en ekstra dimensjon, multipliserer med vektsmatrisen, og sørger for at den oppnådde verdien har samme fortegn som etiketten (+1 eller -1). Deretter summerer vi alle boolske verdier og deler på lengden av testprøven for å finne nøyaktigheten:\n"
|
||||
"I starten satte vi til side noen data til testdatasettet. La oss se hvor nøyaktig klassifikatoren vår er på dette testdatasettet. For å gjøre dette utvider vi også testdatasettet med en ekstra dimensjon, multipliserer med vektmatrisen, og sørger for at den oppnådde verdien har samme fortegn som etiketten (+1 eller -1). Deretter summerer vi alle boolske verdier og deler på lengden av testprøven for å få nøyaktigheten:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Observere treningsprosessen\n",
|
||||
"\n",
|
||||
"Vi har tidligere sett hvordan nøyaktigheten reduseres under trening. Det hadde vært interessant å se hvordan separasjonslinjen oppfører seg under trening. Koden nedenfor vil visualisere alt på én graf, og du skal kunne flytte glidebryteren for å \"reise i tid\" gjennom treningsprosessen.\n"
|
||||
"Vi har tidligere sett hvordan nøyaktigheten synker under trening. Det hadde vært interessant å se hvordan separasjonslinjen oppfører seg under trening. Koden nedenfor vil visualisere alt på én graf, og du skal kunne flytte glidebryteren for å \"reise i tid\" gjennom treningsprosessen.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,9 +655,9 @@
|
|||
"source": [
|
||||
"## Begrensninger ved Perceptron\n",
|
||||
"\n",
|
||||
"Som du har sett ovenfor, er perceptron en **lineær klassifikator**. Den kan skille mellom to klasser godt hvis de er **lineært separerbare**, altså kan skilles med en rett linje. Hvis ikke, vil treningsprosessen for perceptron ikke konvergere.\n",
|
||||
"Som du har sett ovenfor, er perceptron en **lineær klassifiserer**. Den kan skille mellom to klasser godt hvis de er **lineært separerbare**, dvs. kan skilles med en rett linje. Ellers vil ikke treningsprosessen for perceptron konvergere.\n",
|
||||
"\n",
|
||||
"Et av de mest åpenbare eksemplene på et problem som ikke kan løses av en perceptron, er det såkalte **XOR-problemet**. Vi ønsker at vår perceptron skal lære den boolske XOR-funksjonen, som har følgende sannhetstabell:\n",
|
||||
"Et åpenbart eksempel på et problem som ikke kan løses av en perceptron, er det såkalte **XOR-problemet**. Vi ønsker at vår perceptron skal lære den boolske XOR-funksjonen, som har følgende sannhetstabell:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -831,11 +957,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Vær oppmerksom på hvordan nøyaktigheten stiger til nesten 100% veldig raskt.\n",
|
||||
"Vær oppmerksom på hvordan nøyaktigheten stiger til nesten 100 % veldig raskt.\n",
|
||||
"\n",
|
||||
"Vennligst flytt glidebryteren til en posisjon mot slutten av treningen, og observer vektmatrisen som er plottet til venstre. Denne matrisen vil hjelpe deg å forstå hvordan perceptronen faktisk fungerer. Du kan se de høye vektverdiene i midten av feltet, som tilsvarer piksler som vanligvis er til stede for sifferet 1, og lave negative verdier på sidene, der deler av sifferet 0 er. Så, hvis sifferet som presenteres for perceptronen faktisk er 1, vil midtdelen av det bli multiplisert med høye verdier, og gi et positivt resultat. Derimot, når perceptronen observerer 0, vil de tilsvarende pikslene bli multiplisert med negative tall.\n",
|
||||
"Vennligst flytt glidebryteren til en posisjon mot slutten av treningen, og observer vektmatrisen som er plottet til venstre. Denne matrisen vil hjelpe deg å forstå hvordan perceptronen faktisk fungerer. Du kan se de høye vektverdiene i midten av feltet, som tilsvarer piksler som vanligvis er til stede for sifferet 1, og lave negative verdier på sidene, der deler av sifferet 0 er. Så, hvis sifferet som presenteres for perceptronen faktisk er 1, vil midtdelen av det bli multiplisert med høye verdier, noe som gir et positivt resultat. Derimot, når perceptronen observerer 0, vil de tilsvarende pikslene bli multiplisert med negative tall.\n",
|
||||
"\n",
|
||||
"> Du kan legge merke til at hvis vi gir vår perceptron et siffer 1 som er litt forskjøvet horisontalt, slik at pikslene opptar plassen der det er vertikale deler av 0, kan vi få et feilaktig resultat. Siden MNIST-datasettet vårt er slik at alle sifre er sentrert og posisjonert riktig, er perceptronen avhengig av dette for å skille mellom sifrene.\n",
|
||||
"> Du kan legge merke til at hvis vi gir vår perceptron et siffer 1 som er litt forskjøvet horisontalt, slik at pikslene opptar plassen der det er vertikale deler av 0, kan vi få et feilaktig resultat. Siden MNIST-datasettet vårt er slik at alle sifrene er sentrert og posisjonert riktig, er perceptronen avhengig av dette for å skille mellom sifrene.\n",
|
||||
"\n",
|
||||
"La oss nå prøve forskjellige sifre:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Diskusjon\n",
|
||||
"\n",
|
||||
"Av en eller annen grunn er 2 og 5 ikke like lett å skille. Selv om vi oppnår relativt høy nøyaktighet (over 85 %), kan vi tydelig se hvordan perceptronen slutter å lære på et tidspunkt.\n",
|
||||
"Av en eller annen grunn er 2 og 5 ikke like lett å skille fra hverandre. Selv om vi oppnår relativt høy nøyaktighet (over 85 %), kan vi tydelig se hvordan perceptronen slutter å lære på et tidspunkt.\n",
|
||||
"\n",
|
||||
"For å forstå hvorfor dette skjer, kan vi prøve å bruke [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Det er en maskinlæringsteknikk som brukes til å redusere dimensjonaliteten til datasettet, på en måte som gir best mulig separasjon mellom klassene.\n",
|
||||
"\n",
|
||||
"I vårt tilfelle har et inputbilde 784 piksler (inputfunksjoner), og vi ønsker å bruke PCA for å redusere antall parametere til bare 2, slik at vi kan plotte dem på en graf. Disse to parameterne vil være en lineær kombinasjon av de opprinnelige funksjonene, og vi kan se på denne prosessen som en \"rotasjon\" av vårt opprinnelige 784-dimensjonale rom og observere projeksjonen til vårt 2D-rom, inntil vi får den beste visningen som skiller klassene.\n"
|
||||
"I vårt tilfelle har et input-bilde 784 piksler (input-funksjoner), og vi ønsker å bruke PCA for å redusere antall parametere til bare 2, slik at vi kan plotte dem på en graf. Disse to parameterne vil være en lineær kombinasjon av de opprinnelige funksjonene, og vi kan se på denne prosedyren som en \"rotasjon\" av vårt opprinnelige 784-dimensjonale rom og observere projeksjonen til vårt 2D-rom, inntil vi får den beste visningen som skiller klassene.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,7 +1155,7 @@
|
|||
"source": [
|
||||
"Som du kan se, kan 0 og 1 tydelig skilles med en rett linje. Dette indikerer at i det opprinnelige 784-dimensjonale rommet er punktene som tilsvarer sifrene også lineært separerbare. Når det gjelder 2 og 5, kan vi ikke finne en god projeksjon som skiller sifrene tydelig, og derfor oppstår det noen tilfeller av feil klassifisering.\n",
|
||||
"\n",
|
||||
"> Senere i dette kurset vil vi lære hvordan vi kan lage ikke-lineære klassifikatorer ved hjelp av nevrale nettverk, og hvordan vi kan håndtere problemet med sifre som ikke er riktig justert. Svært snart vil vi oppnå over 99 % nøyaktighet i MNIST-sifferklassifisering, mens vi klassifiserer dem i 10 forskjellige klasser.\n",
|
||||
"> Senere i dette kurset vil vi lære hvordan vi kan lage ikke-lineære klassifikatorer ved hjelp av nevrale nettverk, og hvordan vi kan håndtere problemet med sifre som ikke er riktig justert. Veldig snart vil vi oppnå over 99 % nøyaktighet i MNIST-sifferklassifisering, mens vi klassifiserer dem i 10 forskjellige klasser.\n",
|
||||
"\n",
|
||||
"## Oppsummering\n",
|
||||
"\n",
|
||||
|
|
@ -1037,7 +1163,7 @@
|
|||
" * Vi har implementert perceptron \"for hånd\", ved å bruke en enkel treningsprosedyre basert på gradientnedstigning.\n",
|
||||
" * Til tross for enkelheten kan én-lags perceptron løse ganske komplekse problemer med håndskrevet siffergjenkjenning.\n",
|
||||
" * Én-lags perceptron er en lineær klassifikator, og gir derfor samme klassifiseringskraft som logistisk regresjon.\n",
|
||||
" * I prøverommet kan perceptron skille to klasser av inputdata ved hjelp av et hyperplan.\n"
|
||||
" * I prøverommet kan perceptron skille to klasser av inndata ved hjelp av et hyperplan.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Kreditering\n",
|
||||
"\n",
|
||||
"Denne notatboken er en del av [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), og er utarbeidet av [Dmitry Soshnikov](http://soshnikov.com). Den er inspirert av Neural Network Workshop ved Microsoft Research Cambridge. Noe kode og illustrerende materiale er hentet fra presentasjoner av [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) og [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), samt fra [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop)-repositoryen.\n"
|
||||
"Denne notatboken er en del av [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), og er utarbeidet av [Dmitry Soshnikov](http://soshnikov.com). Den er inspirert av Neural Network Workshop ved Microsoft Research Cambridge. Noe kode og illustrerende materiale er hentet fra presentasjoner av [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) og [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), samt fra [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop)-repositoryet.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Ansvarsfraskrivelse**: \nDette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selv om vi tilstreber nøyaktighet, vennligst vær oppmerksom på at automatiserte oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør betraktes som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for eventuelle misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.\n"
|
||||
"\n---\n\n**Ansvarsfraskrivelse**: \nDette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selv om vi tilstreber nøyaktighet, vær oppmerksom på at automatiserte oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for eventuelle misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:32:39+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:20:24+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "no"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@
|
|||
"\n",
|
||||
"> ਇਹ ਨੋਟਬੁੱਕ [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) ਦਾ ਹਿੱਸਾ ਹੈ। ਪੂਰੇ ਸਿੱਖਣ ਸਮੱਗਰੀ ਦੇ ਸੈੱਟ ਲਈ ਰਿਪੋਜ਼ਟਰੀ 'ਤੇ ਜਾਓ।\n",
|
||||
"\n",
|
||||
"ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਚਰਚਾ ਕੀਤੀ ਹੈ, ਪਰਸੈਪਟ੍ਰਾਨ ਤੁਹਾਨੂੰ **ਦੁਵਿਅਕ ਵਰਗੀਕਰਨ ਸਮੱਸਿਆ** ਹੱਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਯਾਨੀ ਇਨਪੁਟ ਉਦਾਹਰਣਾਂ ਨੂੰ ਦੋ ਵਰਗਾਂ ਵਿੱਚ ਵਰਗੀਕ੍ਰਿਤ ਕਰਨ ਲਈ - ਅਸੀਂ ਉਨ੍ਹਾਂ ਨੂੰ **ਸਕਾਰਾਤਮਕ** ਅਤੇ **ਨਕਾਰਾਤਮਕ** ਕਹਿ ਸਕਦੇ ਹਾਂ।\n",
|
||||
"ਜਿਵੇਂ ਕਿ ਅਸੀਂ ਚਰਚਾ ਕੀਤੀ ਹੈ, ਪਰਸੈਪਟ੍ਰਾਨ ਤੁਹਾਨੂੰ **ਦੁਵੈਧ ਵਰਗੀਕਰਨ ਸਮੱਸਿਆ** ਹੱਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਅਰਥਾਤ, ਇਨਪੁਟ ਉਦਾਹਰਣਾਂ ਨੂੰ ਦੋ ਵਰਗਾਂ ਵਿੱਚ ਵਰਗੀਕ੍ਰਿਤ ਕਰਨ ਲਈ - ਅਸੀਂ ਉਨ੍ਹਾਂ ਨੂੰ **ਸਕਾਰਾਤਮਕ** ਅਤੇ **ਨਕਾਰਾਤਮਕ** ਕਹਿ ਸਕਦੇ ਹਾਂ।\n",
|
||||
"\n",
|
||||
"ਸਭ ਤੋਂ ਪਹਿਲਾਂ, ਆਓ ਕੁਝ ਲੋੜੀਂਦੇ ਲਾਇਬ੍ਰੇਰੀਆਂ ਨੂੰ ਇਮਪੋਰਟ ਕਰੀਏ।\n"
|
||||
"ਸਭ ਤੋਂ ਪਹਿਲਾਂ, ਆਓ ਕੁਝ ਲੋੜੀਂਦੇ ਲਾਇਬ੍ਰੇਰੀਆਂ ਇਮਪੋਰਟ ਕਰੀਏ।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## ਖਿਲੌਣਾ ਸਮੱਸਿਆ\n",
|
||||
"\n",
|
||||
"ਸਭ ਤੋਂ ਪਹਿਲਾਂ, ਆਓ ਇੱਕ ਖਿਲੌਣਾ ਸਮੱਸਿਆ ਨਾਲ ਸ਼ੁਰੂ ਕਰੀਏ, ਜਿੱਥੇ ਸਾਡੇ ਕੋਲ ਦੋ ਇਨਪੁਟ ਫੀਚਰ ਹਨ। ਉਦਾਹਰਣ ਵਜੋਂ, ਦਵਾਈ ਵਿੱਚ ਅਸੀਂ ਟਿਊਮਰਾਂ ਨੂੰ ਇਸਦੇ ਆਕਾਰ ਅਤੇ ਉਮਰ ਦੇ ਅਧਾਰ 'ਚ ਸਧਾਰਨ ਅਤੇ ਘਾਤਕ ਵਿੱਚ ਵੰਡਣਾ ਚਾਹੁੰਦੇ ਹਾਂ।\n",
|
||||
"ਸਭ ਤੋਂ ਪਹਿਲਾਂ, ਆਓ ਇੱਕ ਖਿਲੌਣਾ ਸਮੱਸਿਆ ਨਾਲ ਸ਼ੁਰੂ ਕਰੀਏ, ਜਿੱਥੇ ਸਾਡੇ ਕੋਲ ਦੋ ਇਨਪੁਟ ਫੀਚਰ ਹਨ। ਉਦਾਹਰਣ ਵਜੋਂ, ਦਵਾਈ ਵਿੱਚ ਅਸੀਂ ਟਿਊਮਰਾਂ ਨੂੰ ਇਸਦੇ ਆਕਾਰ ਅਤੇ ਉਮਰ ਦੇ ਆਧਾਰ 'ਸਧਾਰਨ' ਅਤੇ 'ਖਤਰਨਾਕ' ਵਿੱਚ ਵੰਡਣਾ ਚਾਹੁੰਦੇ ਹਾਂ।\n",
|
||||
"\n",
|
||||
"ਅਸੀਂ SciKit Learn ਲਾਇਬ੍ਰੇਰੀ ਦੀ `make_classification` ਫੰਕਸ਼ਨ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਇੱਕ ਰੈਂਡਮ ਕਲਾਸੀਫਿਕੇਸ਼ਨ ਡੇਟਾਸੈੱਟ ਤਿਆਰ ਕਰਾਂਗੇ:\n"
|
||||
]
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"ਚਲੋ ਡੇਟਾਸੈੱਟ ਨੂੰ ਵੀ ਪਲਾਟ ਕਰੀਏ:\n"
|
||||
"ਚਲੋ ਡੇਟਾਸੈੱਟ ਨੂੰ ਵੀ ਪਲਾਟ ਕਰਦੇ ਹਾਂ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## ਪਰਸੈਪਟ੍ਰਾਨ\n",
|
||||
"\n",
|
||||
"ਕਿਉਂਕਿ ਪਰਸੈਪਟ੍ਰਾਨ ਇੱਕ ਬਾਈਨਰੀ ਕਲਾਸੀਫਾਇਰ ਹੈ, ਹਰ ਇਨਪੁਟ ਵੇਕਟਰ $x$ ਲਈ ਸਾਡੇ ਪਰਸੈਪਟ੍ਰਾਨ ਦਾ ਆਉਟਪੁਟ ਕਲਾਸ ਦੇ ਅਧਾਰ 'ਤੇ +1 ਜਾਂ -1 ਹੋਵੇਗਾ। ਆਉਟਪੁਟ ਹੇਠਾਂ ਦਿੱਤੇ ਫਾਰਮੂਲੇ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਗਣਨਾ ਕੀਤਾ ਜਾਵੇਗਾ:\n",
|
||||
"ਕਿਉਂਕਿ ਪਰਸੈਪਟ੍ਰਾਨ ਇੱਕ ਬਾਈਨਰੀ ਕਲਾਸੀਫਾਇਰ ਹੈ, ਹਰ ਇਨਪੁਟ ਵੇਕਟਰ $x$ ਲਈ ਸਾਡੇ ਪਰਸੈਪਟ੍ਰਾਨ ਦਾ ਆਉਟਪੁਟ +1 ਜਾਂ -1 ਹੋਵੇਗਾ, ਕਲਾਸ ਦੇ ਅਧਾਰ 'ਤੇ। ਆਉਟਪੁਟ ਹੇਠਾਂ ਦਿੱਤੇ ਫਾਰਮੂਲੇ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਗਣਨਾ ਕੀਤੀ ਜਾਵੇਗੀ:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"ਹਾਲਾਂਕਿ, ਇੱਕ ਜਨਰਲ ਲੀਨਿਅਰ ਮਾਡਲ ਵਿੱਚ ਇੱਕ ਬਾਇਸ ਵੀ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਅਰਥਾਤ ਆਦਰਸ਼ ਤੌਰ 'ਤੇ ਸਾਨੂੰ $y$ ਦੀ ਗਣਨਾ ਇਸ ਤਰ੍ਹਾਂ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ: $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$। ਸਾਡੇ ਮਾਡਲ ਨੂੰ ਸਧਾਰਨ ਬਣਾਉਣ ਲਈ, ਅਸੀਂ ਇਸ ਬਾਇਸ ਟਰਮ ਨੂੰ ਹਟਾ ਸਕਦੇ ਹਾਂ ਜੇਕਰ ਅਸੀਂ ਆਪਣੇ ਇਨਪੁਟ ਫੀਚਰਜ਼ ਵਿੱਚ ਇੱਕ ਹੋਰ ਡਾਇਮੈਂਸ਼ਨ ਸ਼ਾਮਲ ਕਰੀਏ, ਜੋ ਹਮੇਸ਼ਾਂ 1 ਦੇ ਬਰਾਬਰ ਹੋਵੇ:\n"
|
||||
"ਹਾਲਾਂਕਿ, ਇੱਕ ਜਨਰਲ ਲੀਨੀਅਰ ਮਾਡਲ ਵਿੱਚ ਬਾਇਅਸ ਵੀ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਅਰਥਾਤ ਆਦਰਸ਼ ਤੌਰ 'ਤੇ ਸਾਨੂੰ $y$ ਦੀ ਗਣਨਾ ਇਸ ਤਰ੍ਹਾਂ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ: $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$। ਸਾਡੇ ਮਾਡਲ ਨੂੰ ਸਧਾਰਨ ਬਣਾਉਣ ਲਈ, ਅਸੀਂ ਇਸ ਬਾਇਅਸ ਟਰਮ ਨੂੰ ਹਟਾ ਸਕਦੇ ਹਾਂ ਜੇਕਰ ਅਸੀਂ ਆਪਣੇ ਇਨਪੁਟ ਫੀਚਰਜ਼ ਵਿੱਚ ਇੱਕ ਹੋਰ ਡਾਇਮੈਂਸ਼ਨ ਸ਼ਾਮਲ ਕਰ ਲਈਏ, ਜੋ ਹਮੇਸ਼ਾ 1 ਦੇ ਬਰਾਬਰ ਹੁੰਦੀ ਹੈ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -211,13 +211,13 @@
|
|||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ ਨਕਾਰਾਤਮਕ ਅਤੇ ਸਕਾਰਾਤਮਕ ਟ੍ਰੇਨਿੰਗ ਨਮੂਨਿਆਂ ਲਈ, ਅਨੁਕ੍ਰਮਵਾਰ\n",
|
||||
" * $\\mathcal{M}$ - ਗਲਤ ਵਰਗਬੱਧ ਕੀਤੇ ਉਦਾਹਰਣਾਂ ਦਾ ਸੈੱਟ\n",
|
||||
" * $\\mathcal{M}$ - ਗਲਤ ਵਰਗੀਕ੍ਰਿਤ ਉਦਾਹਰਣਾਂ ਦਾ ਸੈੱਟ\n",
|
||||
" \n",
|
||||
"ਅਸੀਂ **ਗ੍ਰੇਡੀਅੰਟ ਡਿਸੈਂਟ** ਦੀ ਪ੍ਰਕਿਰਿਆ ਦੀ ਵਰਤੋਂ ਕਰਾਂਗੇ। ਕੁਝ ਸ਼ੁਰੂਆਤੀ ਰੈਂਡਮ ਵਜ਼ਨਾਂ $\\mathbf{w}^{(0)}$ ਨਾਲ ਸ਼ੁਰੂ ਕਰਦੇ ਹੋਏ, ਅਸੀਂ ਟ੍ਰੇਨਿੰਗ ਦੇ ਹਰ ਕਦਮ 'ਤੇ ਗਲਤੀ $E$ ਦੇ ਗ੍ਰੇਡੀਅੰਟ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਵਜ਼ਨਾਂ ਨੂੰ ਢਾਲਾਂਗੇ:\n",
|
||||
"ਅਸੀਂ **ਗ੍ਰੇਡੀਅੰਟ ਡਿਸੈਂਟ** ਦੀ ਪ੍ਰਕਿਰਿਆ ਦੀ ਵਰਤੋਂ ਕਰਾਂਗੇ। ਕੁਝ ਸ਼ੁਰੂਆਤੀ ਰੈਂਡਮ ਵਜ਼ਨਾਂ $\\mathbf{w}^{(0)}$ ਨਾਲ ਸ਼ੁਰੂ ਕਰਦੇ ਹੋਏ, ਅਸੀਂ ਟ੍ਰੇਨਿੰਗ ਦੇ ਹਰ ਕਦਮ 'ਤੇ ਗਲਤੀ $E$ ਦੇ ਗ੍ਰੇਡੀਅੰਟ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਵਜ਼ਨਾਂ ਨੂੰ ਸਮਾਯੋਜਿਤ ਕਰਾਂਗੇ:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"ਜਿੱਥੇ $\\eta$ ਇੱਕ **ਲਰਨਿੰਗ ਰੇਟ** ਹੈ, ਅਤੇ $\\tau\\in\\mathbb{N}$ - ਇਟਰੇਸ਼ਨ ਦੀ ਗਿਣਤੀ।\n",
|
||||
"ਜਿੱਥੇ $\\eta$ ਇੱਕ **ਲਰਨਿੰਗ ਰੇਟ** ਹੈ, ਅਤੇ $\\tau\\in\\mathbb{N}$ - ਇਤਰਾਂ ਦੀ ਗਿਣਤੀ।\n",
|
||||
"\n",
|
||||
"ਆਓ ਇਸ ਐਲਗੋਰਿਥਮ ਨੂੰ Python ਵਿੱਚ ਪਰਿਭਾਸ਼ਿਤ ਕਰੀਏ:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**ਲਰਨਿੰਗ ਰੇਟ ਬਾਰੇ ਨੋਟ**: `learning_rate` ਪੈਰਾਮੀਟਰ (ਡਿਫਾਲਟ `0.01`) ਇਹ ਨਿਰਧਾਰਤ ਕਰਦਾ ਹੈ ਕਿ ਹਰ ਟ੍ਰੇਨਿੰਗ ਕਦਮ ਦੌਰਾਨ ਅਸੀਂ ਵਜ਼ਨਾਂ ਨੂੰ ਕਿੰਨਾ ਸਮਾਝਦਾਰ ਤਰੀਕੇ ਨਾਲ ਢਾਲਦੇ ਹਾਂ। ਇਹ ਗ੍ਰੇਡੀਅੰਟ ਡਿਸੈਂਟ ਅਪਡੇਟ ਫਾਰਮੂਲਾ ਨੂੰ ਲਾਗੂ ਕਰਦਾ ਹੈ:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- ਵੱਡਾ ਲਰਨਿੰਗ ਰੇਟ (ਜਿਵੇਂ `1.0`) ਪਰਸੈਪਟ੍ਰਾਨ ਨੂੰ ਤੇਜ਼ੀ ਨਾਲ ਸਿੱਖਣ ਦਿੰਦਾ ਹੈ ਪਰ ਇਹ ਸੰਭਵ ਹੈ ਕਿ ਇਹ ਵਧੀਆ ਹੱਲ ਨੂੰ ਪਾਰ ਕਰ ਜਾਵੇ\n",
|
||||
"- ਛੋਟਾ ਲਰਨਿੰਗ ਰੇਟ (ਜਿਵੇਂ `0.001`) ਹੌਲੀ ਹੌਲੀ ਸਿੱਖਦਾ ਹੈ ਪਰ ਇਹ ਜ਼ਿਆਦਾ ਸਹੀ ਤਰੀਕੇ ਨਾਲ ਇਕੱਠਾ ਹੋ ਸਕਦਾ ਹੈ\n",
|
||||
"- ਤੁਸੀਂ ਇਸਨੂੰ ਅਜ਼ਮਾਉਣ ਲਈ ਕਾਲ ਕਰ ਸਕਦੇ ਹੋ: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ਲਰਨਿੰਗ ਰੇਟਾਂ ਨਾਲ ਪ੍ਰਯੋਗ ਕਰਨਾ\n",
|
||||
"\n",
|
||||
"ਹੁਣ ਆਓ ਵੇਖੀਏ ਕਿ ਵੱਖ-ਵੱਖ ਲਰਨਿੰਗ ਰੇਟਾਂ ਸਿਖਲਾਈ ਪ੍ਰਕਿਰਿਆ ਨੂੰ ਕਿਵੇਂ ਪ੍ਰਭਾਵਿਤ ਕਰਦੀਆਂ ਹਨ। ਲਰਨਿੰਗ ਰੇਟ ਗ੍ਰੇਡੀਅੰਟ ਡਿਸੈਂਟ ਵਿੱਚ ਕਦਮ ਦੇ ਆਕਾਰ ਨੂੰ ਨਿਯੰਤਰਿਤ ਕਰਦੀ ਹੈ - ਇੱਕ ਮਹੱਤਵਪੂਰਨ ਹਾਈਪਰਪੈਰਾਮੀਟਰ ਜੋ ਸਮਾਪਤੀ ਦੀ ਗਤੀ ਅਤੇ ਸਥਿਰਤਾ ਦੋਵਾਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕਰਦਾ ਹੈ।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### ਇੰਟਰਐਕਟਿਵ ਲਰਨਿੰਗ ਰੇਟ ਪ੍ਰਯੋਗ\n",
|
||||
"\n",
|
||||
"ਹੇਠਾਂ ਦਿੱਤੇ ਸਲਾਈਡਰ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਵੱਖ-ਵੱਖ ਲਰਨਿੰਗ ਰੇਟਾਂ ਨਾਲ ਪ੍ਰਯੋਗ ਕਰੋ ਅਤੇ ਵੇਖੋ ਕਿ ਇਹ ਫੈਸਲਾ ਸੀਮਾ 'ਤੇ ਕਿਵੇਂ ਅਸਰ ਕਰਦੇ ਹਨ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -379,9 +505,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## ਟੈਸਟ ਡਾਟਾਸੈੱਟ 'ਤੇ ਮੁਲਾਂਕਨ ਕਰੋ\n",
|
||||
"## ਟੈਸਟ ਡੇਟਾਸੈੱਟ 'ਤੇ ਮੁਲਾਂਕਨ ਕਰੋ\n",
|
||||
"\n",
|
||||
"ਸ਼ੁਰੂ ਵਿੱਚ, ਅਸੀਂ ਕੁਝ ਡਾਟਾ ਨੂੰ ਟੈਸਟ ਡਾਟਾਸੈੱਟ ਲਈ ਅਲੱਗ ਕੀਤਾ ਸੀ। ਆਓ ਵੇਖੀਏ ਕਿ ਸਾਡਾ ਕਲਾਸੀਫਾਇਰ ਇਸ ਟੈਸਟ ਡਾਟਾਸੈੱਟ 'ਤੇ ਕਿੰਨਾ ਸਹੀ ਹੈ। ਇਹ ਕਰਨ ਲਈ, ਅਸੀਂ ਟੈਸਟ ਡਾਟਾਸੈੱਟ ਨੂੰ ਇੱਕ ਵਾਧੂ ਡਾਇਮੈਂਸ਼ਨ ਨਾਲ ਵਧਾਉਂਦੇ ਹਾਂ, ਵਜ਼ਨ ਮੈਟ੍ਰਿਕਸ ਨਾਲ ਗੁਣਾ ਕਰਦੇ ਹਾਂ, ਅਤੇ ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦੇ ਹਾਂ ਕਿ ਪ੍ਰਾਪਤ ਕੀਤੀ ਗਈ ਮੁੱਲ ਲੇਬਲ (+1 ਜਾਂ -1) ਦੇ ਸਮਾਨ ਚਿੰਨ੍ਹ ਦੀ ਹੈ। ਫਿਰ ਅਸੀਂ ਸਾਰੇ ਬੂਲੀਅਨ ਮੁੱਲਾਂ ਨੂੰ ਜੋੜਦੇ ਹਾਂ ਅਤੇ ਟੈਸਟ ਨਮੂਨੇ ਦੀ ਲੰਬਾਈ ਨਾਲ ਵੰਡਦੇ ਹਾਂ, ਸਹੀਤਾ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ:\n"
|
||||
"ਸ਼ੁਰੂ ਵਿੱਚ, ਅਸੀਂ ਕੁਝ ਡੇਟਾ ਨੂੰ ਟੈਸਟ ਡੇਟਾਸੈੱਟ ਲਈ ਅਲੱਗ ਕੀਤਾ ਸੀ। ਆਓ ਵੇਖੀਏ ਕਿ ਸਾਡਾ ਕਲਾਸੀਫਾਇਰ ਇਸ ਟੈਸਟ ਡੇਟਾਸੈੱਟ 'ਤੇ ਕਿੰਨਾ ਸਹੀ ਹੈ। ਇਹ ਕਰਨ ਲਈ, ਅਸੀਂ ਟੈਸਟ ਡੇਟਾਸੈੱਟ ਨੂੰ ਇੱਕ ਵਾਧੂ ਡਾਇਮੈਂਸ਼ਨ ਨਾਲ ਵਧਾਉਂਦੇ ਹਾਂ, ਵਜ਼ਨ ਮੈਟ੍ਰਿਕਸ ਨਾਲ ਗੁਣਾ ਕਰਦੇ ਹਾਂ, ਅਤੇ ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦੇ ਹਾਂ ਕਿ ਪ੍ਰਾਪਤ ਕੀਤੀ ਗਈ ਮੁੱਲ ਲੇਬਲ (+1 ਜਾਂ -1) ਦੇ ਸਮਾਨ ਚਿੰਨ੍ਹ ਦੀ ਹੈ। ਫਿਰ ਅਸੀਂ ਸਾਰੇ ਬੂਲੀਅਨ ਮੁੱਲਾਂ ਨੂੰ ਜੋੜਦੇ ਹਾਂ ਅਤੇ ਟੈਸਟ ਨਮੂਨੇ ਦੀ ਲੰਬਾਈ ਨਾਲ ਵੰਡਦੇ ਹਾਂ, ਸਹੀਤਾ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -420,9 +546,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## ਟ੍ਰੇਨਿੰਗ ਪ੍ਰਕਿਰਿਆ ਦਾ ਅਧਿਐਨ ਕਰਨਾ\n",
|
||||
"## ਟ੍ਰੇਨਿੰਗ ਪ੍ਰਕਿਰਿਆ ਨੂੰ ਦੇਖਣਾ\n",
|
||||
"\n",
|
||||
"ਅਸੀਂ ਪਹਿਲਾਂ ਵੇਖਿਆ ਹੈ ਕਿ ਟ੍ਰੇਨਿੰਗ ਦੌਰਾਨ ਸਹੀਤਾ ਘਟਦੀ ਹੈ। ਇਹ ਦੇਖਣਾ ਚੰਗਾ ਹੋਵੇਗਾ ਕਿ ਟ੍ਰੇਨਿੰਗ ਦੌਰਾਨ ਵੱਖ-ਵੱਖ ਕਰਨ ਵਾਲੀ ਰੇਖਾ ਕਿਵੇਂ ਬਦਲਦੀ ਹੈ। ਹੇਠਾਂ ਦਿੱਤਾ ਕੋਡ ਸਭ ਕੁਝ ਇੱਕ ਗ੍ਰਾਫ 'ਤੇ ਵਿਜੁਅਲਾਈਜ਼ ਕਰੇਗਾ, ਅਤੇ ਤੁਸੀਂ ਸਲਾਈਡਰ ਨੂੰ ਹਿਲਾ ਕੇ ਟ੍ਰੇਨਿੰਗ ਪ੍ਰਕਿਰਿਆ ਵਿੱਚ \"ਸਮੇਂ ਦੀ ਯਾਤਰਾ\" ਕਰ ਸਕਦੇ ਹੋ।\n"
|
||||
"ਅਸੀਂ ਪਹਿਲਾਂ ਦੇਖਿਆ ਹੈ ਕਿ ਟ੍ਰੇਨਿੰਗ ਦੌਰਾਨ ਸਹੀਤਾ ਘਟਦੀ ਹੈ। ਇਹ ਦੇਖਣਾ ਚੰਗਾ ਹੋਵੇਗਾ ਕਿ ਟ੍ਰੇਨਿੰਗ ਦੌਰਾਨ ਵੱਖਰੇ ਕਰਨ ਵਾਲੀ ਰੇਖਾ ਕਿਵੇਂ ਬਦਲਦੀ ਹੈ। ਹੇਠਾਂ ਦਿੱਤਾ ਕੋਡ ਸਭ ਕੁਝ ਇੱਕ ਗ੍ਰਾਫ 'ਤੇ ਵਿਜੁਅਲਾਈਜ਼ ਕਰੇਗਾ, ਅਤੇ ਤੁਸੀਂ ਸਲਾਈਡਰ ਨੂੰ ਹਿਲਾ ਕੇ ਟ੍ਰੇਨਿੰਗ ਪ੍ਰਕਿਰਿਆ ਵਿੱਚ \"ਸਮੇਂ ਦੀ ਯਾਤਰਾ\" ਕਰ ਸਕਦੇ ਹੋ।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,9 +655,9 @@
|
|||
"source": [
|
||||
"## ਪਰਸੈਪਟ੍ਰਾਨ ਦੀਆਂ ਸੀਮਾਵਾਂ\n",
|
||||
"\n",
|
||||
"ਜਿਵੇਂ ਤੁਸੀਂ ਉੱਪਰ ਦੇਖਿਆ, ਪਰਸੈਪਟ੍ਰਾਨ ਇੱਕ **ਰੇਖੀਕ ਵਰਗੀਕਰਤਾ** ਹੈ। ਇਹ ਦੋ ਵਰਗਾਂ ਵਿੱਚ ਵੱਖ-ਵੱਖ ਕਰ ਸਕਦਾ ਹੈ ਜੇਕਰ ਉਹ **ਰੇਖੀਕ ਤੌਰ 'ਤੇ ਵੱਖ-ਵੱਖ ਕਰਨਯੋਗ** ਹਨ, ਅਰਥਾਤ ਇੱਕ ਸਿੱਧੀ ਰੇਖਾ ਦੁਆਰਾ ਵੱਖ ਕੀਤੇ ਜਾ ਸਕਦੇ ਹਨ। ਨਹੀਂ ਤਾਂ, ਪਰਸੈਪਟ੍ਰਾਨ ਟ੍ਰੇਨਿੰਗ ਪ੍ਰਕਿਰਿਆ ਸੰਮਤ ਨਹੀਂ ਹੋਵੇਗੀ।\n",
|
||||
"ਜਿਵੇਂ ਤੁਸੀਂ ਉੱਪਰ ਵੇਖਿਆ, ਪਰਸੈਪਟ੍ਰਾਨ ਇੱਕ **ਰੇਖੀਕ ਵਰਗੀਕਰਤਾ** ਹੈ। ਇਹ ਦੋ ਵਰਗਾਂ ਵਿੱਚ ਵੱਖ-ਵੱਖ ਕਰ ਸਕਦਾ ਹੈ ਜੇ ਉਹ **ਰੇਖੀਕ ਤੌਰ 'ਤੇ ਵੱਖ-ਵੱਖ ਕਰਨਯੋਗ** ਹਨ, ਅਰਥਾਤ ਇੱਕ ਸਿੱਧੀ ਰੇਖਾ ਦੁਆਰਾ ਵੱਖ ਕੀਤੇ ਜਾ ਸਕਦੇ ਹਨ। ਨਹੀਂ ਤਾਂ, ਪਰਸੈਪਟ੍ਰਾਨ ਟ੍ਰੇਨਿੰਗ ਪ੍ਰਕਿਰਿਆ ਸੰਮਤ ਨਹੀਂ ਹੋਵੇਗੀ।\n",
|
||||
"\n",
|
||||
"ਇੱਕ ਸਭ ਤੋਂ ਸਪਸ਼ਟ ਉਦਾਹਰਨ ਜਿਸ ਨੂੰ ਪਰਸੈਪਟ੍ਰਾਨ ਹੱਲ ਨਹੀਂ ਕਰ ਸਕਦਾ, ਉਹ ਹੈ **XOR ਸਮੱਸਿਆ**। ਅਸੀਂ ਚਾਹੁੰਦੇ ਹਾਂ ਕਿ ਸਾਡਾ ਪਰਸੈਪਟ੍ਰਾਨ XOR ਬੂਲੀਅਨ ਫੰਕਸ਼ਨ ਸਿੱਖੇ, ਜਿਸਦਾ ਸੱਚਾਈ ਟੇਬਲ ਹੇਠਾਂ ਦਿੱਤਾ ਗਿਆ ਹੈ:\n",
|
||||
"ਇੱਕ ਸਭ ਤੋਂ ਸਪਸ਼ਟ ਉਦਾਹਰਨ ਜਿਸਨੂੰ ਪਰਸੈਪਟ੍ਰਾਨ ਹੱਲ ਨਹੀਂ ਕਰ ਸਕਦਾ, ਉਹ ਹੈ **XOR ਸਮੱਸਿਆ**। ਅਸੀਂ ਚਾਹੁੰਦੇ ਹਾਂ ਕਿ ਸਾਡਾ ਪਰਸੈਪਟ੍ਰਾਨ XOR ਬੂਲੀਅਨ ਫੰਕਸ਼ਨ ਸਿੱਖੇ, ਜਿਸਦਾ ਸੱਚਾਈ ਟੇਬਲ ਹੇਠਾਂ ਦਿੱਤਾ ਗਿਆ ਹੈ:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -605,21 +731,21 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"ਜਿਵੇਂ ਕਿ ਤੁਸੀਂ ਉੱਪਰ ਦਿੱਤੇ ਗ੍ਰਾਫ ਤੋਂ ਦੇਖ ਸਕਦੇ ਹੋ, ਸਹੀਤਾ ਕਦੇ ਵੀ 75% ਤੋਂ ਉੱਪਰ ਨਹੀਂ ਜਾਂਦੀ, ਕਿਉਂਕਿ ਸਾਰੇ ਸੰਭਾਵਿਤ ਉਦਾਹਰਣਾਂ ਨੂੰ ਸਹੀ ਕਰਨ ਲਈ ਸਿੱਧੀ ਰੇਖਾ ਖਿੱਚਣਾ ਅਸੰਭਵ ਹੈ।\n",
|
||||
"ਜਿਵੇਂ ਤੁਸੀਂ ਉੱਪਰ ਦਿੱਤੇ ਗ੍ਰਾਫ ਤੋਂ ਦੇਖ ਸਕਦੇ ਹੋ, ਸਹੀਤਾ ਕਦੇ ਵੀ 75% ਤੋਂ ਉੱਪਰ ਨਹੀਂ ਜਾਂਦੀ, ਕਿਉਂਕਿ ਸਾਰੇ ਸੰਭਾਵਿਤ ਉਦਾਹਰਣਾਂ ਨੂੰ ਸਹੀ ਕਰਨ ਲਈ ਸਿੱਧੀ ਰੇਖਾ ਖਿੱਚਣਾ ਅਸੰਭਵ ਹੈ।\n",
|
||||
"\n",
|
||||
"XOR ਸਮੱਸਿਆ ਪਰਸੈਪਟ੍ਰਾਨ ਦੀਆਂ ਸੀਮਾਵਾਂ ਦਾ ਇੱਕ ਕਲਾਸਿਕ ਉਦਾਹਰਣ ਹੈ, ਅਤੇ ਇਸਨੂੰ 1969 ਵਿੱਚ ਮਾਰਵਿਨ ਮਿੰਸਕੀ ਅਤੇ ਸੇਮੂਰ ਪੈਪਰਟ ਨੇ ਆਪਣੀ ਕਿਤਾਬ [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) ਵਿੱਚ ਦਰਸਾਇਆ ਸੀ। ਇਸ ਅਵਲੋਕਨ ਨੇ ਨਿਊਰਲ ਨੈਟਵਰਕ ਦੇ ਖੇਤਰ ਵਿੱਚ ਲਗਭਗ 10 ਸਾਲਾਂ ਤੱਕ ਖੋਜ ਨੂੰ ਸੀਮਿਤ ਕਰ ਦਿੱਤਾ, ਹਾਲਾਂਕਿ - ਅਤੇ ਅਸੀਂ ਇਸ ਨੂੰ ਆਪਣੇ ਕੋਰਸ ਦੇ ਅਗਲੇ ਭਾਗ ਵਿੱਚ ਦੇਖਾਂਗੇ - ਬਹੁ-ਪਤਰੀ ਪਰਸੈਪਟ੍ਰਾਨ ਇਸ ਤਰ੍ਹਾਂ ਦੀਆਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਸਹੀ ਤਰੀਕੇ ਨਾਲ ਹੱਲ ਕਰਨ ਦੇ ਯੋਗ ਹਨ।\n",
|
||||
"XOR ਸਮੱਸਿਆ ਪਰਸੈਪਟ੍ਰਾਨ ਦੀਆਂ ਸੀਮਾਵਾਂ ਦਾ ਇੱਕ ਕਲਾਸਿਕ ਉਦਾਹਰਣ ਹੈ, ਅਤੇ ਇਸਨੂੰ 1969 ਵਿੱਚ ਮਾਰਵਿਨ ਮਿੰਸਕੀ ਅਤੇ ਸੇਮੂਰ ਪੈਪਰਟ ਨੇ ਆਪਣੀ ਕਿਤਾਬ [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) ਵਿੱਚ ਦਰਸਾਇਆ ਸੀ। ਇਸ ਅਵਲੋਕਨ ਨੇ ਨਿਊਰਲ ਨੈਟਵਰਕ ਦੇ ਖੇਤਰ ਵਿੱਚ ਲਗਭਗ 10 ਸਾਲਾਂ ਤੱਕ ਖੋਜ ਨੂੰ ਸੀਮਿਤ ਕਰ ਦਿੱਤਾ, ਹਾਲਾਂਕਿ - ਅਤੇ ਅਸੀਂ ਇਸ ਨੂੰ ਆਪਣੇ ਕੋਰਸ ਦੇ ਅਗਲੇ ਭਾਗ ਵਿੱਚ ਦੇਖਾਂਗੇ - ਬਹੁ-ਪਰਤ ਵਾਲੇ ਪਰਸੈਪਟ੍ਰਾਨ ਇਸ ਤਰ੍ਹਾਂ ਦੀਆਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਸਹੀ ਤਰੀਕੇ ਨਾਲ ਹੱਲ ਕਰਨ ਦੇ ਯੋਗ ਹਨ।\n",
|
||||
"\n",
|
||||
"## ਜਟਿਲ ਉਦਾਹਰਣ - MNIST\n",
|
||||
"\n",
|
||||
"ਹਾਲਾਂਕਿ ਪਰਸੈਪਟ੍ਰਾਨ XOR ਸਮੱਸਿਆ ਨੂੰ ਹੱਲ ਨਹੀਂ ਕਰ ਸਕਦਾ, ਇਹ ਕਈ ਹੋਰ ਜਟਿਲ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਹੱਲ ਕਰ ਸਕਦਾ ਹੈ, ਜਿਵੇਂ ਕਿ ਹੱਥ ਨਾਲ ਲਿਖੇ ਅੱਖਰਾਂ ਦੀ ਪਹਿਚਾਣ।\n",
|
||||
"\n",
|
||||
"ਇੱਕ ਡੇਟਾਸੈਟ ਜੋ ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਵਿੱਚ ਮਾਹਰ ਬਣਨ ਦੌਰਾਨ ਅਕਸਰ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ, ਉਸਨੂੰ [MNIST](https://en.wikipedia.org/wiki/MNIST_database) ਕਿਹਾ ਜਾਂਦਾ ਹੈ। ਇਹ Modified National Institute of Standards and Technology ਦੁਆਰਾ ਬਣਾਇਆ ਗਿਆ ਹੈ, ਅਤੇ ਇਸ ਵਿੱਚ 60000 ਹੱਥ ਨਾਲ ਲਿਖੇ ਅੰਕਾਂ ਦਾ ਟ੍ਰੇਨਿੰਗ ਸੈੱਟ ਸ਼ਾਮਲ ਹੈ, ਜੋ ਲਗਭਗ 250 ਵਿਦਿਆਰਥੀਆਂ ਅਤੇ ਸੰਸਥਾਨ ਦੇ ਕਰਮਚਾਰੀਆਂ ਤੋਂ ਇਕੱਠੇ ਕੀਤੇ ਗਏ ਹਨ। ਇਸ ਵਿੱਚ 10000 ਅੰਕਾਂ ਦਾ ਟੈਸਟ ਡੇਟਾਸੈਟ ਵੀ ਹੈ, ਜੋ ਵੱਖ-ਵੱਖ ਵਿਅਕਤੀਆਂ ਤੋਂ ਇਕੱਠੇ ਕੀਤੇ ਗਏ ਹਨ।\n",
|
||||
"ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਵਿੱਚ ਮਾਹਰ ਬਣਨ ਦੌਰਾਨ ਅਕਸਰ ਵਰਤਿਆ ਜਾਣ ਵਾਲਾ ਡਾਟਾਸੈਟ [MNIST](https://en.wikipedia.org/wiki/MNIST_database) ਕਹਿੰਦਾ ਹੈ। ਇਹ Modified National Institute of Standards and Technology ਦੁਆਰਾ ਬਣਾਇਆ ਗਿਆ ਹੈ, ਅਤੇ ਇਸ ਵਿੱਚ 60000 ਹੱਥ ਨਾਲ ਲਿਖੇ ਅੰਕਾਂ ਦਾ ਟ੍ਰੇਨਿੰਗ ਸੈੱਟ ਹੈ, ਜੋ ਲਗਭਗ 250 ਵਿਦਿਆਰਥੀਆਂ ਅਤੇ ਸੰਸਥਾ ਦੇ ਕਰਮਚਾਰੀਆਂ ਤੋਂ ਇਕੱਠੇ ਕੀਤੇ ਗਏ ਹਨ। ਇਸ ਵਿੱਚ 10000 ਅੰਕਾਂ ਦਾ ਟੈਸਟ ਡਾਟਾਸੈਟ ਵੀ ਹੈ, ਜੋ ਵੱਖ-ਵੱਖ ਵਿਅਕਤੀਆਂ ਤੋਂ ਇਕੱਠੇ ਕੀਤੇ ਗਏ ਹਨ।\n",
|
||||
"\n",
|
||||
"ਸਾਰੇ ਅੰਕ 28x28 ਪਿਕਸਲ ਦੇ ਗ੍ਰੇਸਕੇਲ ਚਿੱਤਰਾਂ ਦੁਆਰਾ ਦਰਸਾਏ ਗਏ ਹਨ।\n",
|
||||
"\n",
|
||||
"> MNIST ਡੇਟਾਸੈਟ [Kaggle](https://www.kaggle.com/c/digit-recognizer) 'ਤੇ ਇੱਕ ਟ੍ਰੇਨਿੰਗ ਮੁਕਾਬਲੇ ਵਜੋਂ ਉਪਲਬਧ ਹੈ, ਜੋ ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਮੁਕਾਬਲਿਆਂ ਅਤੇ ਪ੍ਰਤੀਯੋਗਿਤਾਵਾਂ ਦੀ ਮਿਜ਼ਬਾਨੀ ਕਰਦਾ ਹੈ। ਜਦੋਂ ਤੁਸੀਂ MNIST ਅੰਕਾਂ ਨੂੰ ਵਰਗਬੱਧ ਕਰਨ ਦਾ ਤਰੀਕਾ ਸਿੱਖ ਲੈਂਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਆਪਣਾ ਹੱਲ Kaggle 'ਤੇ ਜਮ੍ਹਾਂ ਕਰ ਸਕਦੇ ਹੋ ਤਾਂ ਜੋ ਇਹ ਦੇਖਿਆ ਜਾ ਸਕੇ ਕਿ ਇਹ ਹੋਰ ਭਾਗੀਦਾਰਾਂ ਵਿੱਚ ਕਿਵੇਂ ਦਰਜ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।\n",
|
||||
"> MNIST ਡਾਟਾਸੈਟ [Kaggle](https://www.kaggle.com/c/digit-recognizer) 'ਤੇ ਇੱਕ ਟ੍ਰੇਨਿੰਗ ਮੁਕਾਬਲੇ ਵਜੋਂ ਉਪਲਬਧ ਹੈ, ਜੋ ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਮੁਕਾਬਲਿਆਂ ਅਤੇ ਪ੍ਰਤੀਯੋਗਿਤਾਵਾਂ ਦੀ ਮਿਜ਼ਬਾਨੀ ਕਰਦਾ ਹੈ। ਜਦੋਂ ਤੁਸੀਂ MNIST ਅੰਕਾਂ ਨੂੰ ਵਰਗਬੱਧ ਕਰਨ ਦਾ ਤਰੀਕਾ ਸਿੱਖ ਲੈਂਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਆਪਣਾ ਹੱਲ Kaggle 'ਤੇ ਜਮ੍ਹਾਂ ਕਰ ਸਕਦੇ ਹੋ ਤਾਂ ਜੋ ਇਹ ਦੇਖਿਆ ਜਾ ਸਕੇ ਕਿ ਇਹ ਹੋਰ ਭਾਗੀਦਾਰਾਂ ਵਿੱਚ ਕਿਵੇਂ ਦਰਜ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।\n",
|
||||
"\n",
|
||||
"ਅਸੀਂ MNIST ਡੇਟਾਸੈਟ ਨੂੰ ਲੋਡ ਕਰਕੇ ਸ਼ੁਰੂ ਕਰਦੇ ਹਾਂ:\n"
|
||||
"ਅਸੀਂ MNIST ਡਾਟਾਸੈਟ ਨੂੰ ਲੋਡ ਕਰਕੇ ਸ਼ੁਰੂ ਕਰਦੇ ਹਾਂ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"ਕਿਉਂਕਿ ਪਰਸੈਪਟ੍ਰਾਨ ਇੱਕ ਦੁਅਲ ਵਰਗੀਕਰਨ ਹੈ, ਅਸੀਂ ਆਪਣੀ ਸਮੱਸਿਆ ਨੂੰ ਸਿਰਫ ਦੋ ਅੰਕਾਂ ਦੀ ਪਹਿਚਾਣ ਤੱਕ ਸੀਮਿਤ ਕਰਾਂਗੇ। ਹੇਠਾਂ ਦਿੱਤਾ ਫੰਕਸ਼ਨ ਦੋ ਦਿੱਤੇ ਅੰਕਾਂ ਨਾਲ ਸਕਾਰਾਤਮਕ ਅਤੇ ਨਕਾਰਾਤਮਕ ਨਮੂਨਾ ਐਰੇ ਭਰੇਗਾ (ਅਤੇ ਸਪਸ਼ਟਤਾ ਲਈ ਉਹਨਾਂ ਅੰਕਾਂ ਦੇ ਨਮੂਨੇ ਵੀ ਦਿਖਾਵੇਗਾ)।\n"
|
||||
"ਕਿਉਂਕਿ ਪਰਸੈਪਟ੍ਰਾਨ ਇੱਕ ਦੁਅਲ ਵਰਗੀਕਰਨ ਹੈ, ਅਸੀਂ ਆਪਣੀ ਸਮੱਸਿਆ ਨੂੰ ਸਿਰਫ਼ ਦੋ ਅੰਕਾਂ ਦੀ ਪਹਿਚਾਣ ਤੱਕ ਸੀਮਿਤ ਕਰਾਂਗੇ। ਹੇਠਾਂ ਦਿੱਤਾ ਫੰਕਸ਼ਨ ਦੋ ਦਿੱਤੇ ਅੰਕਾਂ ਨਾਲ ਸਕਾਰਾਤਮਕ ਅਤੇ ਨਕਾਰਾਤਮਕ ਨਮੂਨਾ ਐਰੇ ਭਰੇਗਾ (ਅਤੇ ਸਪਸ਼ਟਤਾ ਲਈ ਉਹਨਾਂ ਅੰਕਾਂ ਦੇ ਨਮੂਨੇ ਵੀ ਦਿਖਾਵੇਗਾ)।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -735,7 +861,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"ਅਸੀਂ 0 ਅਤੇ 1 ਦੇ ਵਿਚਕਾਰ ਵਰਗੀਕਰਨ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਕੇ ਸ਼ੁਰੂ ਕਰਾਂਗੇ:\n"
|
||||
"ਅਸੀਂ 0 ਅਤੇ 1 ਦੇ ਵਿਚਕਾਰ ਵੱਖ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਕੇ ਸ਼ੁਰੂ ਕਰਾਂਗੇ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"ਕਿਰਪਾ ਕਰਕੇ ਧਿਆਨ ਦਿਓ ਕਿ ਸਹੀਤਾ ਬਹੁਤ ਤੇਜ਼ੀ ਨਾਲ ਲਗਭਗ 100% ਤੱਕ ਪਹੁੰਚ ਜਾਂਦੀ ਹੈ।\n",
|
||||
"\n",
|
||||
"ਕਿਰਪਾ ਕਰਕੇ ਸਲਾਈਡਰ ਨੂੰ ਟ੍ਰੇਨਿੰਗ ਦੇ ਅੰਤ ਵੱਲ ਕਿਸੇ ਸਥਾਨ 'ਤੇ ਖਿਸਕਾਓ ਅਤੇ ਖੱਬੇ ਪਾਸੇ ਦਿਖਾਈ ਗਈ ਵਜ਼ਨ ਮੈਟ੍ਰਿਕਸ ਨੂੰ ਦੇਖੋ। ਇਹ ਮੈਟ੍ਰਿਕਸ ਤੁਹਾਨੂੰ ਸਮਝਣ ਵਿੱਚ ਮਦਦ ਕਰੇਗਾ ਕਿ ਪਰਸੈਪਟ੍ਰਾਨ ਅਸਲ ਵਿੱਚ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ। ਤੁਸੀਂ ਖੇਤਰ ਦੇ ਵਿਚਕਾਰ ਉੱਚ ਵਜ਼ਨ ਮੁੱਲਾਂ ਨੂੰ ਦੇਖ ਸਕਦੇ ਹੋ, ਜੋ ਉਹ ਪਿਕਸਲਾਂ ਨੂੰ ਦਰਸਾਉਂਦੇ ਹਨ ਜੋ ਆਮ ਤੌਰ 'ਤੇ ਅੰਕ 1 ਲਈ ਮੌਜੂਦ ਹੁੰਦੇ ਹਨ, ਅਤੇ ਪਾਸੇ ਘੱਟ ਨਕਾਰਾਤਮਕ ਮੁੱਲਾਂ, ਜਿੱਥੇ ਅੰਕ 0 ਦੇ ਹਿੱਸੇ ਹੁੰਦੇ ਹਨ। ਇਸ ਲਈ, ਜੇ ਪਰਸੈਪਟ੍ਰਾਨ ਨੂੰ ਦਿੱਤਾ ਗਿਆ ਅੰਕ ਅਸਲ ਵਿੱਚ 1 ਹੈ, ਤਾਂ ਇਸਦਾ ਵਿਚਕਾਰਲਾ ਹਿੱਸਾ ਉੱਚ ਮੁੱਲਾਂ ਨਾਲ ਗੁਣਾ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਕਾਰਾਤਮਕ ਨਤੀਜਾ ਨਿਕਲੇਗਾ। ਇਸਦੇ ਉਲਟ, ਜਦੋਂ ਪਰਸੈਪਟ੍ਰਾਨ 0 ਨੂੰ ਦੇਖਦਾ ਹੈ, ਤਾਂ ਸੰਬੰਧਿਤ ਪਿਕਸਲਾਂ ਨੂੰ ਨਕਾਰਾਤਮਕ ਸੰਖਿਆਵਾਂ ਨਾਲ ਗੁਣਾ ਕੀਤਾ ਜਾਵੇਗਾ।\n",
|
||||
"ਕਿਰਪਾ ਕਰਕੇ ਸਲਾਈਡਰ ਨੂੰ ਟ੍ਰੇਨਿੰਗ ਦੇ ਅੰਤ ਵੱਲ ਕਿਸੇ ਸਥਿਤੀ 'ਤੇ ਲਿਜਾਓ ਅਤੇ ਖੱਬੇ ਪਾਸੇ ਦਿਖਾਈ ਗਈ ਵਜ਼ਨ ਮੈਟ੍ਰਿਕਸ ਨੂੰ ਦੇਖੋ। ਇਹ ਮੈਟ੍ਰਿਕਸ ਤੁਹਾਨੂੰ ਸਮਝਣ ਵਿੱਚ ਮਦਦ ਕਰੇਗਾ ਕਿ ਪਰਸੈਪਟ੍ਰਾਨ ਅਸਲ ਵਿੱਚ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ। ਤੁਸੀਂ ਖੇਤਰ ਦੇ ਵਿਚਕਾਰ ਉੱਚ ਵਜ਼ਨ ਮੁੱਲਾਂ ਨੂੰ ਦੇਖ ਸਕਦੇ ਹੋ, ਜੋ ਉਹ ਪਿਕਸਲਾਂ ਨੂੰ ਦਰਸਾਉਂਦੇ ਹਨ ਜੋ ਆਮ ਤੌਰ 'ਤੇ ਅੰਕ 1 ਲਈ ਮੌਜੂਦ ਹੁੰਦੇ ਹਨ, ਅਤੇ ਪਾਸੇ ਨੀਵਾਂ ਨਕਾਰਾਤਮਕ ਮੁੱਲ, ਜਿੱਥੇ ਅੰਕ 0 ਦੇ ਹਿੱਸੇ ਹੁੰਦੇ ਹਨ। ਇਸ ਲਈ, ਜੇ ਪਰਸੈਪਟ੍ਰਾਨ ਨੂੰ ਦਿੱਤਾ ਗਿਆ ਅੰਕ ਅਸਲ ਵਿੱਚ 1 ਹੈ, ਤਾਂ ਇਸਦਾ ਵਿਚਲਾ ਹਿੱਸਾ ਉੱਚ ਮੁੱਲਾਂ ਨਾਲ ਗੁਣਾ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਕਾਰਾਤਮਕ ਨਤੀਜਾ ਨਿਕਲਦਾ ਹੈ। ਇਸਦੇ ਉਲਟ, ਜਦੋਂ ਪਰਸੈਪਟ੍ਰਾਨ 0 ਨੂੰ ਦੇਖਦਾ ਹੈ, ਤਾਂ ਸੰਬੰਧਿਤ ਪਿਕਸਲ ਨਕਾਰਾਤਮਕ ਗਿਣਤੀਆਂ ਨਾਲ ਗੁਣਾ ਕੀਤੇ ਜਾਂਦੇ ਹਨ।\n",
|
||||
"\n",
|
||||
"> ਤੁਸੀਂ ਧਿਆਨ ਦੇ ਸਕਦੇ ਹੋ ਕਿ ਜੇ ਅਸੀਂ ਆਪਣੇ ਪਰਸੈਪਟ੍ਰਾਨ ਨੂੰ ਅੰਕ 1 ਦੇਵਾਂ ਜੋ ਹੌਲੀ-ਹੌਲੀ ਖਿਤਿਜੀ ਰੂਪ ਵਿੱਚ ਖਿਸਕਿਆ ਹੋਇਆ ਹੈ, ਤਾਂ ਇਸਦੇ ਪਿਕਸਲ ਉਹ ਜਗ੍ਹਾ ਘੇਰ ਲੈਂਦੇ ਹਨ ਜਿੱਥੇ 0 ਦੇ ਲੰਬੇ ਹਿੱਸੇ ਹੁੰਦੇ ਹਨ, ਤਾਂ ਸਾਨੂੰ ਗਲਤ ਨਤੀਜਾ ਮਿਲ ਸਕਦਾ ਹੈ। ਕਿਉਂਕਿ ਸਾਡੇ MNIST ਡੇਟਾਸੈਟ ਦੀ ਪ੍ਰਕਿਰਤੀ ਇਹ ਹੈ ਕਿ ਸਾਰੇ ਅੰਕ ਕੇਂਦਰਿਤ ਅਤੇ ਠੀਕ ਤਰੀਕੇ ਨਾਲ ਸਥਿਤ ਹਨ, ਅਤੇ ਪਰਸੈਪਟ੍ਰਾਨ ਇਸ 'ਤੇ ਨਿਰਭਰ ਕਰਦਾ ਹੈ ਅੰਕਾਂ ਵਿੱਚ ਫਰਕ ਕਰਨ ਲਈ।\n",
|
||||
"> ਤੁਸੀਂ ਧਿਆਨ ਦੇ ਸਕਦੇ ਹੋ ਕਿ ਜੇ ਅਸੀਂ ਆਪਣੇ ਪਰਸੈਪਟ੍ਰਾਨ ਨੂੰ ਅੰਕ 1 ਦੇਵਾਂ ਜੋ ਥੋੜ੍ਹਾ ਜਿਹਾ ਖਿੱਤ ਵਿੱਚ ਖੱਬੇ ਜਾਂ ਸੱਜੇ ਵੱਲ ਖਿਸਕਿਆ ਹੋਇਆ ਹੈ, ਤਾਂ ਇਸਦੇ ਪਿਕਸਲ ਉਸ ਜਗ੍ਹਾ ਨੂੰ ਘੇਰ ਲੈਂਦੇ ਹਨ ਜਿੱਥੇ 0 ਦੇ ਖੜ੍ਹੇ ਹਿੱਸੇ ਹੁੰਦੇ ਹਨ, ਤਾਂ ਸਾਨੂੰ ਗਲਤ ਨਤੀਜਾ ਮਿਲ ਸਕਦਾ ਹੈ। ਕਿਉਂਕਿ ਸਾਡੇ MNIST ਡੇਟਾਸੈਟ ਦੀ ਪ੍ਰਕਿਰਤੀ ਇਹ ਹੈ ਕਿ ਸਾਰੇ ਅੰਕ ਕੇਂਦਰਿਤ ਅਤੇ ਠੀਕ ਤਰੀਕੇ ਨਾਲ ਸਥਿਤ ਹਨ, ਅਤੇ ਪਰਸੈਪਟ੍ਰਾਨ ਇਸ 'ਤੇ ਨਿਰਭਰ ਕਰਦਾ ਹੈ ਅੰਕਾਂ ਵਿੱਚ ਫਰਕ ਕਰਨ ਲਈ।\n",
|
||||
"\n",
|
||||
"ਹੁਣ ਚਲੋ ਵੱਖ-ਵੱਖ ਅੰਕਾਂ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਹਾਂ:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## ਚਰਚਾ\n",
|
||||
"\n",
|
||||
"ਕਿਸੇ ਕਾਰਨ ਕਰਕੇ, 2 ਅਤੇ 5 ਨੂੰ ਆਸਾਨੀ ਨਾਲ ਵੱਖ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਹਾਲਾਂਕਿ ਸਾਨੂੰ ਕਾਫ਼ੀ ਉੱਚੀ ਸਹੀਤਾ (85% ਤੋਂ ਉੱਪਰ) ਮਿਲਦੀ ਹੈ, ਅਸੀਂ ਸਪਸ਼ਟ ਤੌਰ 'ਤੇ ਦੇਖ ਸਕਦੇ ਹਾਂ ਕਿ perceptron ਕਿਸੇ ਸਮੇਂ ਸਿੱਖਣਾ ਬੰਦ ਕਰ ਦਿੰਦਾ ਹੈ।\n",
|
||||
"ਕਿਸੇ ਕਾਰਨ ਕਰਕੇ, 2 ਅਤੇ 5 ਨੂੰ ਆਸਾਨੀ ਨਾਲ ਵੱਖ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਹਾਲਾਂਕਿ ਸਾਨੂੰ ਕਾਫ਼ੀ ਉੱਚ ਸਹੀਤਾ (85% ਤੋਂ ਉੱਪਰ) ਮਿਲਦੀ ਹੈ, ਅਸੀਂ ਸਪਸ਼ਟ ਤੌਰ 'ਤੇ ਦੇਖ ਸਕਦੇ ਹਾਂ ਕਿ perceptron ਕਿਸੇ ਸਮੇਂ ਸਿੱਖਣਾ ਬੰਦ ਕਰ ਦਿੰਦਾ ਹੈ।\n",
|
||||
"\n",
|
||||
"ਇਸ ਨੂੰ ਸਮਝਣ ਲਈ, ਅਸੀਂ [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਸਕਦੇ ਹਾਂ। ਇਹ ਇੱਕ ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਤਕਨੀਕ ਹੈ ਜੋ ਇਨਪੁਟ ਡੇਟਾਸੈਟ ਦੀ ਡਾਇਮੈਂਸ਼ਨਲਿਟੀ ਨੂੰ ਘਟਾਉਣ ਲਈ ਵਰਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਜੋ ਕਲਾਸਾਂ ਦੇ ਵਿਚਕਾਰ ਵਧੀਆ ਵੱਖ-ਵੱਖਤਾ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਸਕੇ।\n",
|
||||
"ਇਸ ਗੱਲ ਨੂੰ ਸਮਝਣ ਲਈ, ਅਸੀਂ [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹਾਂ। ਇਹ ਇੱਕ ਮਸ਼ੀਨ ਲਰਨਿੰਗ ਤਕਨੀਕ ਹੈ ਜੋ ਇਨਪੁਟ ਡਾਟਾਸੈਟ ਦੀ ਮਾਪ ਨੂੰ ਘਟਾਉਣ ਲਈ ਵਰਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਜੋ ਕਲਾਸਾਂ ਦੇ ਵਿਚਕਾਰ ਵਧੀਆ ਵੱਖ-ਵੱਖਤਾ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਸਕੇ।\n",
|
||||
"\n",
|
||||
"ਸਾਡੇ ਕੇਸ ਵਿੱਚ, ਇੱਕ ਇਨਪੁਟ ਚਿੱਤਰ ਵਿੱਚ 784 ਪਿਕਸਲ (ਇਨਪੁਟ ਫੀਚਰ) ਹੁੰਦੇ ਹਨ, ਅਤੇ ਅਸੀਂ PCA ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਪੈਰਾਮੀਟਰਾਂ ਦੀ ਗਿਣਤੀ ਸਿਰਫ 2 ਤੱਕ ਘਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹਾਂ, ਤਾਂ ਜੋ ਅਸੀਂ ਉਨ੍ਹਾਂ ਨੂੰ ਗ੍ਰਾਫ 'ਤੇ ਪਲਾਟ ਕਰ ਸਕੀਏ। ਇਹ ਦੋ ਪੈਰਾਮੀਟਰ ਮੂਲ ਫੀਚਰਾਂ ਦੇ ਲੀਨੀਅਰ ਕੌਂਬੀਨੇਸ਼ਨ ਹੋਣਗੇ, ਅਤੇ ਅਸੀਂ ਇਸ ਪ੍ਰਕਿਰਿਆ ਨੂੰ \"ਸਾਡੇ ਮੂਲ 784-ਡਾਇਮੈਂਸ਼ਨਲ ਸਪੇਸ ਨੂੰ ਘੁਮਾਉਣ\" ਵਜੋਂ ਦੇਖ ਸਕਦੇ ਹਾਂ ਅਤੇ ਇਸਦੀ ਪ੍ਰੋਜੈਕਸ਼ਨ ਨੂੰ 2D-ਸਪੇਸ ਵਿੱਚ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਜਦੋਂ ਤੱਕ ਸਾਨੂੰ ਕਲਾਸਾਂ ਨੂੰ ਵੱਖ ਕਰਨ ਲਈ ਵਧੀਆ ਦ੍ਰਿਸ਼ਟੀਕੋਣ ਨਹੀਂ ਮਿਲਦਾ।\n"
|
||||
"ਸਾਡੇ ਕੇਸ ਵਿੱਚ, ਇੱਕ ਇਨਪੁਟ ਚਿੱਤਰ ਵਿੱਚ 784 ਪਿਕਸਲ (ਇਨਪੁਟ ਫੀਚਰ) ਹੁੰਦੇ ਹਨ, ਅਤੇ ਅਸੀਂ PCA ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਪੈਰਾਮੀਟਰਾਂ ਦੀ ਗਿਣਤੀ ਸਿਰਫ 2 ਤੱਕ ਘਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹਾਂ, ਤਾਂ ਜੋ ਅਸੀਂ ਉਨ੍ਹਾਂ ਨੂੰ ਗ੍ਰਾਫ 'ਤੇ ਪਲਾਟ ਕਰ ਸਕੀਏ। ਇਹ ਦੋ ਪੈਰਾਮੀਟਰ ਮੂਲ ਫੀਚਰਾਂ ਦੇ ਰੇਖੀ ਸੰਯੋਜਨ ਹੋਣਗੇ, ਅਤੇ ਅਸੀਂ ਇਸ ਪ੍ਰਕਿਰਿਆ ਨੂੰ \"ਸਾਡੇ ਮੂਲ 784-ਮਾਪ ਵਾਲੇ ਸਪੇਸ ਨੂੰ ਘੁਮਾਉਣ\" ਵਜੋਂ ਦੇਖ ਸਕਦੇ ਹਾਂ ਅਤੇ ਇਸਦੀ ਪ੍ਰੋਜੈਕਸ਼ਨ ਨੂੰ 2D-ਸਪੇਸ ਵਿੱਚ ਦੇਖ ਸਕਦੇ ਹਾਂ, ਜਦ ਤੱਕ ਸਾਨੂੰ ਕਲਾਸਾਂ ਨੂੰ ਵੱਖ ਕਰਨ ਲਈ ਸਭ ਤੋਂ ਵਧੀਆ ਦ੍ਰਿਸ਼ਟੀਕੋਣ ਨਹੀਂ ਮਿਲਦਾ।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"ਜਿਵੇਂ ਤੁਸੀਂ ਦੇਖ ਸਕਦੇ ਹੋ, 0 ਅਤੇ 1 ਨੂੰ ਸਿੱਧੀ ਰੇਖਾ ਦੁਆਰਾ ਸਪਸ਼ਟ ਤੌਰ 'ਤੇ ਵੱਖ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ। ਇਹ ਦਰਸਾਉਂਦਾ ਹੈ ਕਿ ਮੂਲ 784-ਡਾਈਮੇਨਸ਼ਨਲ ਸਪੇਸ ਵਿੱਚ ਅੰਕਾਂ ਦੇ ਅਨੁਕੂਲ ਬਿੰਦੂ ਵੀ ਲੀਨੀਅਰ ਤਰੀਕੇ ਨਾਲ ਵੱਖ ਕੀਤੇ ਜਾ ਸਕਦੇ ਹਨ। 2 ਅਤੇ 5 ਦੇ ਮਾਮਲੇ ਵਿੱਚ, ਅਸੀਂ ਅੰਕਾਂ ਨੂੰ ਸਪਸ਼ਟ ਤੌਰ 'ਤੇ ਵੱਖ ਕਰਨ ਲਈ ਚੰਗੀ ਪ੍ਰੋਜੈਕਸ਼ਨ ਨਹੀਂ ਲੱਭ ਸਕਦੇ, ਅਤੇ ਇਸ ਲਈ ਕੁਝ ਗਲਤ ਵਰਗੀਕਰਨ ਦੇ ਮਾਮਲੇ ਹੁੰਦੇ ਹਨ।\n",
|
||||
"ਜਿਵੇਂ ਤੁਸੀਂ ਦੇਖ ਸਕਦੇ ਹੋ, 0 ਅਤੇ 1 ਨੂੰ ਸਿੱਧੀ ਰੇਖਾ ਦੁਆਰਾ ਸਪਸ਼ਟ ਤੌਰ 'ਤੇ ਵੱਖ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ। ਇਹ ਦਰਸਾਉਂਦਾ ਹੈ ਕਿ ਮੂਲ 784-ਡਾਈਮੇਨਸ਼ਨਲ ਸਪੇਸ ਵਿੱਚ ਅੰਕਾਂ ਨਾਲ ਸੰਬੰਧਿਤ ਡਾਟਸ ਵੀ ਲੀਨੀਅਰ ਤਰੀਕੇ ਨਾਲ ਵੱਖ ਕੀਤੇ ਜਾ ਸਕਦੇ ਹਨ। 2 ਅਤੇ 5 ਦੇ ਮਾਮਲੇ ਵਿੱਚ, ਅਸੀਂ ਅਜਿਹੀ ਚੰਗੀ ਪ੍ਰੋਜੈਕਸ਼ਨ ਨਹੀਂ ਲੱਭ ਸਕਦੇ ਜੋ ਅੰਕਾਂ ਨੂੰ ਸਪਸ਼ਟ ਤੌਰ 'ਤੇ ਵੱਖ ਕਰ ਸਕੇ, ਅਤੇ ਇਸ ਲਈ ਕੁਝ ਗਲਤ ਕਲਾਸੀਫਿਕੇਸ਼ਨ ਦੇ ਮਾਮਲੇ ਹੁੰਦੇ ਹਨ।\n",
|
||||
"\n",
|
||||
"> ਇਸ ਕੋਰਸ ਵਿੱਚ ਅੱਗੇ ਜਾ ਕੇ ਅਸੀਂ ਸਿੱਖਾਂਗੇ ਕਿ ਨਿਊਰਲ ਨੈਟਵਰਕ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਗੈਰ-ਲੀਨੀਅਰ ਵਰਗੀਕਰਨ ਕਿਵੇਂ ਬਣਾਈ ਜਾ ਸਕਦੀ ਹੈ, ਅਤੇ ਅੰਕਾਂ ਦੇ ਸਹੀ ਤਰੀਕੇ ਨਾਲ ਸੰਰੂਪਿਤ ਨਾ ਹੋਣ ਦੀ ਸਮੱਸਿਆ ਨਾਲ ਕਿਵੇਂ ਨਜਿੱਠਿਆ ਜਾ ਸਕਦਾ ਹੈ। ਬਹੁਤ ਜਲਦੀ ਅਸੀਂ MNIST ਅੰਕ ਵਰਗੀਕਰਨ ਵਿੱਚ 99% ਤੋਂ ਵੱਧ ਸ਼ੁੱਧਤਾ ਹਾਸਲ ਕਰਾਂਗੇ, ਜਦੋਂ ਅਸੀਂ ਉਨ੍ਹਾਂ ਨੂੰ 10 ਵੱਖ-ਵੱਖ ਵਰਗਾਂ ਵਿੱਚ ਵਰਗੀਕਰ ਰਹੇ ਹੋਵਾਂਗੇ।\n",
|
||||
"> ਇਸ ਕੋਰਸ ਵਿੱਚ ਅੱਗੇ ਜਾ ਕੇ ਅਸੀਂ ਸਿੱਖਾਂਗੇ ਕਿ ਨਾਨ-ਲੀਨੀਅਰ ਕਲਾਸੀਫਾਇਰਜ਼ ਨੂੰ ਨਿਊਰਲ ਨੈਟਵਰਕ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਕਿਵੇਂ ਬਣਾਇਆ ਜਾ ਸਕਦਾ ਹੈ, ਅਤੇ ਅੰਕਾਂ ਦੇ ਸਹੀ ਤਰੀਕੇ ਨਾਲ ਅਲਾਈਨ ਨਾ ਹੋਣ ਦੀ ਸਮੱਸਿਆ ਨਾਲ ਕਿਵੇਂ ਨਜਿੱਠਿਆ ਜਾ ਸਕਦਾ ਹੈ। ਬਹੁਤ ਜਲਦੀ ਅਸੀਂ MNIST ਅੰਕ ਕਲਾਸੀਫਿਕੇਸ਼ਨ ਵਿੱਚ 99% ਤੋਂ ਵੱਧ ਸ਼ੁੱਧਤਾ ਹਾਸਲ ਕਰਾਂਗੇ, ਜਦੋਂ ਅਸੀਂ ਉਨ੍ਹਾਂ ਨੂੰ 10 ਵੱਖ-ਵੱਖ ਕਲਾਸਾਂ ਵਿੱਚ ਵੰਡਾਂਗੇ।\n",
|
||||
"\n",
|
||||
"## ਸਿੱਖਣ ਵਾਲੀਆਂ ਗੱਲਾਂ\n",
|
||||
"## ਸਿੱਟਾ\n",
|
||||
"\n",
|
||||
" * ਅਸੀਂ ਸਭ ਤੋਂ ਸਧਾਰਨ ਨਿਊਰਲ ਨੈਟਵਰਕ ਆਰਕੀਟੈਕਚਰ - ਇੱਕ-ਪਰਤ ਪਰਸੈਪਟ੍ਰਾਨ ਬਾਰੇ ਸਿੱਖਿਆ।\n",
|
||||
" * ਅਸੀਂ ਪਰਸੈਪਟ੍ਰਾਨ ਨੂੰ \"ਹੱਥੋਂ\" ਲਾਗੂ ਕੀਤਾ, ਸਧਾਰਨ ਟ੍ਰੇਨਿੰਗ ਪ੍ਰਕਿਰਿਆ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਹੋਏ ਜੋ ਗ੍ਰੇਡੀਅੰਟ ਡਿਸੈਂਟ 'ਤੇ ਆਧਾਰਿਤ ਹੈ।\n",
|
||||
" * ਸਧਾਰਨਤਾ ਦੇ ਬਾਵਜੂਦ, ਇੱਕ-ਪਰਤ ਵਾਲਾ ਪਰਸੈਪਟ੍ਰਾਨ ਹੱਥੋਂ ਲਿਖੇ ਅੰਕਾਂ ਦੀ ਪਹਿਚਾਣ ਦੇ ਕਾਫੀ ਜਟਿਲ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਹੱਲ ਕਰ ਸਕਦਾ ਹੈ।\n",
|
||||
" * ਇੱਕ-ਪਰਤ ਵਾਲਾ ਪਰਸੈਪਟ੍ਰਾਨ ਇੱਕ ਲੀਨੀਅਰ ਵਰਗੀਕਰ ਹੈ, ਅਤੇ ਇਸ ਲਈ ਇਹ ਲੌਜਿਸਟਿਕ ਰਿਗਰੈਸ਼ਨ ਦੇ ਸਮਾਨ ਵਰਗੀਕਰਨ ਦੀ ਸਮਰੱਥਾ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ।\n",
|
||||
" * ਸੈਂਪਲ ਸਪੇਸ ਵਿੱਚ, ਪਰਸੈਪਟ੍ਰਾਨ ਹਾਈਪਰਪਲੇਨ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਇਨਪੁਟ ਡਾਟਾ ਦੇ ਦੋ ਵਰਗਾਂ ਨੂੰ ਵੱਖ ਕਰ ਸਕਦਾ ਹੈ।\n"
|
||||
" * ਅਸੀਂ ਸਭ ਤੋਂ ਸਧਾਰਨ ਨਿਊਰਲ ਨੈਟਵਰਕ ਆਰਕੀਟੈਕਚਰ - ਇੱਕ-ਲੇਅਰ ਪਰਸੈਪਟ੍ਰਾਨ ਬਾਰੇ ਸਿੱਖਿਆ।\n",
|
||||
" * ਅਸੀਂ ਪਰਸੈਪਟ੍ਰਾਨ ਨੂੰ \"ਹੱਥੋਂ\" ਲਾਗੂ ਕੀਤਾ, ਸਧਾਰਨ ਟ੍ਰੇਨਿੰਗ ਪ੍ਰਕਿਰਿਆ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਜੋ ਗ੍ਰੇਡੀਅੰਟ ਡਿਸੈਂਟ 'ਤੇ ਆਧਾਰਿਤ ਹੈ।\n",
|
||||
" * ਸਧਾਰਨਤਾ ਦੇ ਬਾਵਜੂਦ, ਇੱਕ-ਲੇਅਰ ਪਰਸੈਪਟ੍ਰਾਨ ਹੱਥ ਨਾਲ ਲਿਖੇ ਅੰਕਾਂ ਦੀ ਪਹਿਚਾਣ ਦੇ ਕਾਫ਼ੀ ਜਟਿਲ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਹੱਲ ਕਰ ਸਕਦਾ ਹੈ।\n",
|
||||
" * ਇੱਕ-ਲੇਅਰ ਪਰਸੈਪਟ੍ਰਾਨ ਇੱਕ ਲੀਨੀਅਰ ਕਲਾਸੀਫਾਇਰ ਹੈ, ਅਤੇ ਇਸ ਲਈ ਇਹ ਲੌਜਿਸਟਿਕ ਰਿਗਰੈਸ਼ਨ ਦੇ ਸਮਾਨ ਕਲਾਸੀਫਿਕੇਸ਼ਨ ਸ਼ਕਤੀ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ।\n",
|
||||
" * ਸੈਂਪਲ ਸਪੇਸ ਵਿੱਚ, ਪਰਸੈਪਟ੍ਰਾਨ ਹਾਈਪਰਪਲੇਨ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਇਨਪੁਟ ਡਾਟਾ ਦੀਆਂ ਦੋ ਕਲਾਸਾਂ ਨੂੰ ਵੱਖ ਕਰ ਸਕਦਾ ਹੈ।\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**ਅਸਵੀਕਰਤਾ**: \nਇਹ ਦਸਤਾਵੇਜ਼ AI ਅਨੁਵਾਦ ਸੇਵਾ [Co-op Translator](https://github.com/Azure/co-op-translator) ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਅਨੁਵਾਦ ਕੀਤਾ ਗਿਆ ਹੈ। ਜਦੋਂ ਕਿ ਅਸੀਂ ਸਹੀ ਹੋਣ ਦਾ ਯਤਨ ਕਰਦੇ ਹਾਂ, ਕਿਰਪਾ ਕਰਕੇ ਧਿਆਨ ਦਿਓ ਕਿ ਸਵੈਚਾਲਿਤ ਅਨੁਵਾਦਾਂ ਵਿੱਚ ਗਲਤੀਆਂ ਜਾਂ ਅਸੁਚਤਤਾਵਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਇਸ ਦੀ ਮੂਲ ਭਾਸ਼ਾ ਵਿੱਚ ਮੌਜੂਦ ਦਸਤਾਵੇਜ਼ ਨੂੰ ਅਧਿਕਾਰਤ ਸਰੋਤ ਮੰਨਿਆ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ। ਮਹੱਤਵਪੂਰਨ ਜਾਣਕਾਰੀ ਲਈ, ਪੇਸ਼ੇਵਰ ਮਨੁੱਖੀ ਅਨੁਵਾਦ ਦੀ ਸਿਫਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਸ ਅਨੁਵਾਦ ਦੀ ਵਰਤੋਂ ਤੋਂ ਪੈਦਾ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਗਲਤ ਫਹਿਮੀ ਜਾਂ ਗਲਤ ਵਿਆਖਿਆ ਲਈ ਅਸੀਂ ਜ਼ਿੰਮੇਵਾਰ ਨਹੀਂ ਹਾਂ।\n"
|
||||
"\n---\n\n**ਅਸਵੀਕਰਤਾ**: \nਇਹ ਦਸਤਾਵੇਜ਼ AI ਅਨੁਵਾਦ ਸੇਵਾ [Co-op Translator](https://github.com/Azure/co-op-translator) ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਅਨੁਵਾਦ ਕੀਤਾ ਗਿਆ ਹੈ। ਹਾਲਾਂਕਿ ਅਸੀਂ ਸਹੀ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਹਾਂ, ਕਿਰਪਾ ਕਰਕੇ ਧਿਆਨ ਦਿਓ ਕਿ ਸਵੈਚਾਲਿਤ ਅਨੁਵਾਦਾਂ ਵਿੱਚ ਗਲਤੀਆਂ ਜਾਂ ਅਸੁਚਾਰੂਤਾਵਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਇਸ ਦਸਤਾਵੇਜ਼ ਦਾ ਮੂਲ ਰੂਪ ਇਸਦੀ ਮੂਲ ਭਾਸ਼ਾ ਵਿੱਚ ਅਧਿਕਾਰਤ ਸਰੋਤ ਮੰਨਿਆ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ। ਮਹੱਤਵਪੂਰਨ ਜਾਣਕਾਰੀ ਲਈ, ਪੇਸ਼ੇਵਰ ਮਨੁੱਖੀ ਅਨੁਵਾਦ ਦੀ ਸਿਫਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਅਸੀਂ ਇਸ ਅਨੁਵਾਦ ਦੀ ਵਰਤੋਂ ਤੋਂ ਪੈਦਾ ਹੋਣ ਵਾਲੇ ਕਿਸੇ ਵੀ ਗਲਤ ਫਹਿਮੀ ਜਾਂ ਗਲਤ ਵਿਆਖਿਆ ਲਈ ਜ਼ਿੰਮੇਵਾਰ ਨਹੀਂ ਹਾਂ।\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:23:01+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:09:57+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "pa"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"\n",
|
||||
"Jak już omówiliśmy, perceptron pozwala rozwiązać **problem klasyfikacji binarnej**, czyli klasyfikować przykłady wejściowe do dwóch klas - możemy je nazwać **pozytywną** i **negatywną**.\n",
|
||||
"\n",
|
||||
"Najpierw zaimportujmy kilka potrzebnych bibliotek.\n"
|
||||
"Najpierw zaimportujmy kilka wymaganych bibliotek.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Jednakże ogólny model liniowy powinien również uwzględniać bias, czyli idealnie powinniśmy obliczać $y$ jako $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Aby uprościć nasz model, możemy pozbyć się tego biasu, dodając jeden dodatkowy wymiar do naszych cech wejściowych, który zawsze będzie równy 1:\n"
|
||||
"Jednakże ogólny model liniowy powinien również uwzględniać bias, czyli idealnie powinniśmy obliczać $y$ jako $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Aby uprościć nasz model, możemy pozbyć się tego terminu bias, dodając jeden dodatkowy wymiar do naszych cech wejściowych, który zawsze będzie równy 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -210,10 +210,10 @@
|
|||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ dla odpowiednio negatywnych i pozytywnych próbek treningowych\n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ dla negatywnych i pozytywnych próbek treningowych, odpowiednio\n",
|
||||
" * $\\mathcal{M}$ - zbiór błędnie sklasyfikowanych przykładów\n",
|
||||
" \n",
|
||||
"Wykorzystamy proces **spadku gradientu**. Zaczynając od początkowych losowych wag $\\mathbf{w}^{(0)}$, będziemy dostosowywać wagi na każdym kroku treningu, używając gradientu $E$:\n",
|
||||
"Wykorzystamy proces **gradientowego spadku**. Zaczynając od początkowych losowych wag $\\mathbf{w}^{(0)}$, będziemy dostosowywać wagi na każdym kroku treningu, używając gradientu $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Uwaga dotycząca współczynnika uczenia**: Parametr `learning_rate` (domyślnie `0.01`) kontroluje, jak bardzo dostosowujemy wagi podczas każdego kroku treningowego. Implementuje on formułę aktualizacji gradientu:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Większy współczynnik uczenia (np. `1.0`) sprawia, że perceptron uczy się szybciej, ale może przeskoczyć optymalne rozwiązanie\n",
|
||||
"- Mniejszy współczynnik uczenia (np. `0.001`) uczy się wolniej, ale może precyzyjniej się zbiegać\n",
|
||||
"- Możesz eksperymentować, wywołując: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Eksperymentowanie z szybkością uczenia\n",
|
||||
"\n",
|
||||
"Teraz przyjrzyjmy się, jak różne szybkości uczenia wpływają na proces treningu. Szybkość uczenia kontroluje wielkość kroku w algorytmie gradientowego spadku - kluczowy hiperparametr, który wpływa zarówno na szybkość zbieżności, jak i stabilność.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktywny Eksperyment z Współczynnikiem Uczenia\n",
|
||||
"\n",
|
||||
"Użyj suwaka poniżej, aby interaktywnie eksperymentować z różnymi współczynnikami uczenia i zobaczyć, jak wpływają one na granicę decyzyjną:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Ocena na zbiorze testowym\n",
|
||||
"\n",
|
||||
"Na początku odłożyliśmy część danych do zbioru testowego. Sprawdźmy, jak dokładny jest nasz klasyfikator na tym zbiorze testowym. Aby to zrobić, rozszerzamy również zbiór testowy o dodatkowy wymiar, mnożymy przez macierz wag i upewniamy się, że uzyskana wartość ma ten sam znak co etykieta (+1 lub -1). Następnie sumujemy wszystkie wartości logiczne i dzielimy przez długość próbki testowej, aby uzyskać dokładność:\n"
|
||||
"Na początku odłożyliśmy część danych do zbioru testowego. Sprawdźmy, jak dokładny jest nasz klasyfikator na tym zbiorze testowym. Aby to zrobić, rozszerzamy zbiór testowy o dodatkowy wymiar, mnożymy przez macierz wag i upewniamy się, że uzyskana wartość ma ten sam znak co etykieta (+1 lub -1). Następnie sumujemy wszystkie wartości logiczne i dzielimy przez długość próbki testowej, aby uzyskać dokładność:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Obserwowanie procesu treningowego\n",
|
||||
"\n",
|
||||
"Wcześniej zauważyliśmy, jak dokładność zmniejsza się podczas treningu. Byłoby interesujące zobaczyć, jak linia separacji zmienia się w trakcie treningu. Poniższy kod zwizualizuje wszystko na jednym wykresie, a Ty będziesz mógł przesuwać suwak, aby \"podróżować w czasie\" przez proces treningowy.\n"
|
||||
"Wcześniej zauważyliśmy, jak dokładność spada podczas treningu. Byłoby interesujące zobaczyć, jak linia separacji zmienia się w trakcie treningu. Poniższy kod zwizualizuje wszystko na jednym wykresie, a Ty będziesz mógł przesuwać suwak, aby \"podróżować w czasie\" przez proces treningowy.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -607,17 +733,17 @@
|
|||
"source": [
|
||||
"Jak widać na powyższym wykresie, dokładność nigdy nie przekracza 75%, ponieważ nie da się narysować prostej linii w taki sposób, aby poprawnie sklasyfikować wszystkie możliwe przykłady.\n",
|
||||
"\n",
|
||||
"Problem XOR jest klasycznym przykładem ograniczeń perceptronu, a został on wskazany przez Marvina Minsky'ego i Seymoura Paperta w 1969 roku w ich książce [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). To spostrzeżenie zahamowało badania w dziedzinie sieci neuronowych na prawie 10 lat, mimo że - jak zobaczymy w następnej części naszego kursu - perceptrony wielowarstwowe są w pełni zdolne do rozwiązywania takich problemów.\n",
|
||||
"Problem XOR jest klasycznym przykładem ograniczeń perceptronu, a został wskazany przez Marvina Minsky'ego i Seymoura Paperta w 1969 roku w ich książce [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). To spostrzeżenie ograniczyło badania w dziedzinie sieci neuronowych na prawie 10 lat, mimo że - jak zobaczymy w następnej części naszego kursu - perceptrony wielowarstwowe są w pełni zdolne do rozwiązywania takich problemów.\n",
|
||||
"\n",
|
||||
"## Złożony przykład - MNIST\n",
|
||||
"\n",
|
||||
"Mimo że perceptron nie potrafi rozwiązać problemu XOR, może rozwiązywać wiele bardziej złożonych problemów, takich jak rozpoznawanie odręcznie pisanych znaków.\n",
|
||||
"\n",
|
||||
"Zbiorem danych, który często jest używany podczas nauki maszynowej, jest [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Został on stworzony przez zmodyfikowany Narodowy Instytut Standaryzacji i Technologii (Modified National Institute of Standards and Technology) i zawiera zestaw treningowy składający się z 60 000 odręcznie napisanych cyfr, zebranych od około 250 studentów i pracowników instytutu. Istnieje również zestaw testowy zawierający 10 000 cyfr, zebranych od innych osób.\n",
|
||||
"Zbiorem danych, który często jest używany podczas nauki maszynowej, jest [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Został on stworzony przez Zmodyfikowany Narodowy Instytut Standardów i Technologii i zawiera zestaw treningowy składający się z 60 000 odręcznie napisanych cyfr, zebranych od około 250 studentów i pracowników instytutu. Istnieje również zestaw testowy zawierający 10 000 cyfr, zebranych od innych osób.\n",
|
||||
"\n",
|
||||
"Wszystkie cyfry są przedstawione w postaci obrazów w skali szarości o rozmiarze 28x28 pikseli.\n",
|
||||
"Wszystkie cyfry są reprezentowane przez obrazy w skali szarości o rozmiarze 28x28 pikseli.\n",
|
||||
"\n",
|
||||
"> Zbiór danych MNIST jest dostępny jako konkurs treningowy na [Kaggle](https://www.kaggle.com/c/digit-recognizer), stronie, która organizuje konkursy i zawody związane z uczeniem maszynowym. Gdy nauczysz się klasyfikować cyfry z MNIST, możesz przesłać swoje rozwiązanie na Kaggle, aby zobaczyć, jak jest oceniane w porównaniu z innymi uczestnikami.\n",
|
||||
"> Zbiór danych MNIST jest dostępny jako konkurs treningowy na [Kaggle](https://www.kaggle.com/c/digit-recognizer), stronie, która organizuje konkursy i zawody związane z uczeniem maszynowym. Gdy nauczysz się klasyfikować cyfry MNIST, możesz przesłać swoje rozwiązanie na Kaggle, aby zobaczyć, jak jest oceniane w porównaniu z innymi uczestnikami.\n",
|
||||
"\n",
|
||||
"Zaczynamy od załadowania zbioru danych MNIST:\n"
|
||||
]
|
||||
|
|
@ -644,7 +770,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Teraz narysujmy wykres zestawu danych:\n"
|
||||
"Teraz narysujmy wykres dla zestawu danych:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"Zauważ, jak dokładność bardzo szybko wzrasta prawie do 100%.\n",
|
||||
"\n",
|
||||
"Proszę, przesuń suwak na pozycję pod koniec treningu i obserwuj macierz wagową wyświetlaną po lewej stronie. Ta macierz pozwoli Ci zrozumieć, jak perceptron faktycznie działa. Możesz zauważyć wysokie wartości wagowe w środku pola, które odpowiadają pikselom typowo obecnym dla cyfry 1, oraz niskie wartości ujemne po bokach, gdzie znajdują się części cyfry 0. Tak więc, jeśli cyfra przedstawiona perceptronowi to faktycznie 1, jej środkowa część zostanie pomnożona przez wysokie wartości, co da wynik dodatni. Natomiast, gdy perceptron obserwuje cyfrę 0, odpowiadające jej piksele zostaną pomnożone przez liczby ujemne.\n",
|
||||
"Proszę, przesuń suwak na pozycję pod koniec treningu i obserwuj macierz wagową wyświetlaną po lewej stronie. Ta macierz pozwoli Ci zrozumieć, jak perceptron faktycznie działa. Możesz zobaczyć wysokie wartości wagowe w środku pola, które odpowiadają pikselom typowo obecnym dla cyfry 1, oraz niskie wartości ujemne po bokach, gdzie znajdują się części cyfry 0. Tak więc, jeśli cyfra przedstawiona perceptronowi to faktycznie 1, jej środkowa część zostanie pomnożona przez wysokie wartości, co da wynik dodatni. Natomiast, gdy perceptron widzi cyfrę 0, odpowiadające jej piksele zostaną pomnożone przez liczby ujemne.\n",
|
||||
"\n",
|
||||
"> Możesz zauważyć, że jeśli podamy perceptronowi cyfrę 1 nieco przesuniętą poziomo, tak że jej piksele zajmują miejsce, gdzie znajdują się pionowe części cyfry 0, możemy otrzymać nieprawidłowy wynik. Wynika to z natury naszego zbioru danych MNIST, w którym wszystkie cyfry są wyśrodkowane i odpowiednio ustawione, a perceptron opiera się na tym, aby rozróżniać cyfry.\n",
|
||||
"> Możesz zauważyć, że jeśli podamy naszemu perceptronowi cyfrę 1 nieco przesuniętą poziomo, tak że jej piksele zajmują miejsce, gdzie znajdują się pionowe części cyfry 0, możemy otrzymać nieprawidłowy wynik. Wynika to z natury naszego zbioru danych MNIST, w którym wszystkie cyfry są wyśrodkowane i odpowiednio ustawione, a perceptron opiera się na tym, aby rozróżniać cyfry.\n",
|
||||
"\n",
|
||||
"Teraz spróbujmy z różnymi cyframi:\n"
|
||||
]
|
||||
|
|
@ -915,7 +1041,7 @@
|
|||
"\n",
|
||||
"Z jakiegoś powodu cyfry 2 i 5 nie są łatwo rozróżnialne. Mimo że uzyskujemy stosunkowo wysoką dokładność (powyżej 85%), wyraźnie widać, że perceptron przestaje się uczyć w pewnym momencie.\n",
|
||||
"\n",
|
||||
"Aby zrozumieć, dlaczego tak się dzieje, możemy spróbować użyć [Analizy Głównych Składników](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Jest to technika uczenia maszynowego, która pozwala na zmniejszenie wymiarowości zestawu danych wejściowych w taki sposób, aby uzyskać najlepszą separowalność między klasami.\n",
|
||||
"Aby zrozumieć, dlaczego tak się dzieje, możemy spróbować użyć [Analizy Głównych Składników](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Jest to technika uczenia maszynowego stosowana do zmniejszenia wymiarowości zbioru danych wejściowych w taki sposób, aby uzyskać jak najlepsze rozdzielenie między klasami.\n",
|
||||
"\n",
|
||||
"W naszym przypadku obraz wejściowy ma 784 piksele (cechy wejściowe), a my chcemy użyć PCA, aby zredukować liczbę parametrów do zaledwie 2, tak aby można je było przedstawić na wykresie. Te dwa parametry będą liniową kombinacją oryginalnych cech, a cały proces można postrzegać jako \"obracanie\" naszej pierwotnej przestrzeni 784-wymiarowej i obserwowanie jej projekcji na przestrzeń 2D, aż uzyskamy najlepszy widok, który rozdziela klasy.\n"
|
||||
]
|
||||
|
|
@ -1027,16 +1153,16 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Jak widać, cyfry 0 i 1 można wyraźnie oddzielić za pomocą prostej linii. Wskazuje to, że w pierwotnej przestrzeni o 784 wymiarach punkty odpowiadające cyfrom są również liniowo separowalne. W przypadku cyfr 2 i 5 nie możemy znaleźć odpowiedniej projekcji, która wyraźnie oddzieli cyfry, co prowadzi do pewnych przypadków błędnej klasyfikacji.\n",
|
||||
"Jak widać, cyfry 0 i 1 można wyraźnie oddzielić za pomocą prostej linii. Oznacza to, że w pierwotnej przestrzeni o wymiarze 784 punkty odpowiadające cyfrom są również liniowo separowalne. W przypadku cyfr 2 i 5 nie możemy znaleźć odpowiedniej projekcji, która wyraźnie oddzieli cyfry, co prowadzi do pewnych przypadków błędnej klasyfikacji.\n",
|
||||
"\n",
|
||||
"> W dalszej części tego kursu nauczymy się tworzyć nieliniowe klasyfikatory za pomocą sieci neuronowych oraz radzić sobie z problemem niewłaściwego wyrównania cyfr. Już wkrótce osiągniemy ponad 99% dokładności w klasyfikacji cyfr MNIST, dzieląc je na 10 różnych klas.\n",
|
||||
"> W dalszej części tego kursu nauczymy się tworzyć nieliniowe klasyfikatory za pomocą sieci neuronowych oraz radzić sobie z problemem nieprawidłowego wyrównania cyfr. Już wkrótce osiągniemy ponad 99% dokładności w klasyfikacji cyfr MNIST, klasyfikując je do 10 różnych klas.\n",
|
||||
"\n",
|
||||
"## Wnioski\n",
|
||||
"\n",
|
||||
" * Poznaliśmy najprostszą architekturę sieci neuronowej - perceptron jednowarstwowy.\n",
|
||||
" * Zaimplementowaliśmy perceptron \"ręcznie\", korzystając z prostego procesu uczenia opartego na metodzie gradientu.\n",
|
||||
" * Pomimo swojej prostoty, perceptron jednowarstwowy potrafi rozwiązywać dość złożone problemy rozpoznawania odręcznie pisanych cyfr.\n",
|
||||
" * Perceptron jednowarstwowy jest klasyfikatorem liniowym, co oznacza, że oferuje taką samą moc klasyfikacyjną jak regresja logistyczna.\n",
|
||||
" * Perceptron jednowarstwowy jest klasyfikatorem liniowym, co oznacza, że ma taką samą moc klasyfikacyjną jak regresja logistyczna.\n",
|
||||
" * W przestrzeni próbek perceptron może oddzielić dwie klasy danych wejściowych za pomocą hiperpłaszczyzny.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Podziękowania\n",
|
||||
"\n",
|
||||
"Ten notebook jest częścią [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) i został przygotowany przez [Dmitry Soshnikov](http://soshnikov.com). Inspiracją dla niego były warsztaty dotyczące sieci neuronowych w Microsoft Research Cambridge. Niektóre fragmenty kodu oraz materiały ilustracyjne pochodzą z prezentacji przygotowanych przez [Katję Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnsona](https://www.microsoft.com/en-us/research/people/matjoh/) oraz [Ryoto Tomiokę](https://www.microsoft.com/en-us/research/people/ryoto/), a także z repozytorium [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Ten notatnik jest częścią [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) i został przygotowany przez [Dmitry Soshnikov](http://soshnikov.com). Inspiracją dla niego były warsztaty dotyczące sieci neuronowych w Microsoft Research Cambridge. Niektóre fragmenty kodu oraz materiały ilustracyjne pochodzą z prezentacji [Katji Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnsona](https://www.microsoft.com/en-us/research/people/matjoh/) i [Ryoto Tomioki](https://www.microsoft.com/en-us/research/people/ryoto/), a także z repozytorium [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Zastrzeżenie**: \nTen dokument został przetłumaczony za pomocą usługi tłumaczenia AI [Co-op Translator](https://github.com/Azure/co-op-translator). Chociaż staramy się zapewnić dokładność, prosimy pamiętać, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego rodzimym języku powinien być uznawany za autorytatywne źródło. W przypadku informacji krytycznych zaleca się skorzystanie z profesjonalnego tłumaczenia przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z użycia tego tłumaczenia.\n"
|
||||
"\n---\n\n**Zastrzeżenie**: \nTen dokument został przetłumaczony za pomocą usługi tłumaczenia AI [Co-op Translator](https://github.com/Azure/co-op-translator). Chociaż dokładamy wszelkich starań, aby tłumaczenie było precyzyjne, prosimy pamiętać, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego języku źródłowym powinien być uznawany za autorytatywne źródło. W przypadku informacji krytycznych zaleca się skorzystanie z profesjonalnego tłumaczenia przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z użycia tego tłumaczenia.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:26:43+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:13:56+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "pl"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"\n",
|
||||
"> Este notebook faz parte do [Currículo de IA para Iniciantes](http://github.com/microsoft/ai-for-beginners). Visite o repositório para o conjunto completo de materiais de aprendizagem.\n",
|
||||
"\n",
|
||||
"Como discutimos, o perceptron permite resolver o **problema de classificação binária**, ou seja, classificar exemplos de entrada em duas classes - podemos chamá-las de **positiva** e **negativa**.\n",
|
||||
"Como discutimos, o perceptrão permite resolver o **problema de classificação binária**, ou seja, classificar exemplos de entrada em duas classes - podemos chamá-las de **positiva** e **negativa**.\n",
|
||||
"\n",
|
||||
"Primeiro, vamos importar algumas bibliotecas necessárias.\n"
|
||||
]
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ para amostras de treino negativas e positivas, respetivamente\n",
|
||||
" * $\\mathcal{M}$ - um conjunto de exemplos classificados incorretamente\n",
|
||||
" \n",
|
||||
"Utilizaremos o processo de **descida do gradiente**. Começando com alguns pesos iniciais aleatórios $\\mathbf{w}^{(0)}$, ajustaremos os pesos em cada etapa do treino utilizando o gradiente de $E$:\n",
|
||||
"Iremos utilizar o processo de **descida do gradiente**. Começando com alguns pesos iniciais aleatórios $\\mathbf{w}^{(0)}$, ajustaremos os pesos em cada passo do treino utilizando o gradiente de $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Nota sobre a Taxa de Aprendizagem**: O parâmetro `learning_rate` (por defeito `0.01`) controla o quanto ajustamos os pesos durante cada passo de treino. Isto implementa a fórmula de atualização do gradiente descendente:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Uma taxa de aprendizagem maior (por exemplo, `1.0`) faz com que o perceptrão aprenda mais rapidamente, mas pode ultrapassar a solução ótima\n",
|
||||
"- Uma taxa de aprendizagem menor (por exemplo, `0.001`) aprende mais lentamente, mas pode convergir de forma mais precisa\n",
|
||||
"- Pode experimentar chamando: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimentar com Taxas de Aprendizagem\n",
|
||||
"\n",
|
||||
"Agora vamos explorar como diferentes taxas de aprendizagem afetam o processo de treino. A taxa de aprendizagem controla o tamanho do passo no gradiente descendente - um hiperparâmetro crucial que afeta tanto a velocidade de convergência como a estabilidade.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Experiência Interativa com Taxa de Aprendizagem\n",
|
||||
"\n",
|
||||
"Utilize o controlo deslizante abaixo para experimentar interativamente diferentes taxas de aprendizagem e observar como elas influenciam a fronteira de decisão:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -420,7 +546,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Observar o processo de treino\n",
|
||||
"## Observando o processo de treino\n",
|
||||
"\n",
|
||||
"Já vimos anteriormente como a precisão diminui durante o treino. Seria interessante observar como a linha de separação se comporta durante o treino. O código abaixo irá visualizar tudo num único gráfico, e deverá ser possível mover o cursor para \"viajar no tempo\" através do processo de treino.\n"
|
||||
]
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -531,7 +657,7 @@
|
|||
"\n",
|
||||
"Como visto acima, o perceptron é um **classificador linear**. Ele consegue distinguir bem entre duas classes se forem **linearmente separáveis**, ou seja, se puderem ser separadas por uma linha reta. Caso contrário, o processo de treino do perceptron não irá convergir.\n",
|
||||
"\n",
|
||||
"Um exemplo mais evidente de um problema que não pode ser resolvido por um perceptron é o chamado **problema XOR**. Queremos que o nosso perceptron aprenda a função booleana XOR, que possui a seguinte tabela de verdade:\n",
|
||||
"Um exemplo claro de um problema que não pode ser resolvido por um perceptron é o chamado **problema XOR**. Queremos que o perceptron aprenda a função booleana XOR, que possui a seguinte tabela de verdade:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Como pode ver no gráfico acima, a precisão nunca ultrapassa os 75%, porque é impossível traçar uma linha reta de forma a acertar em todos os exemplos possíveis.\n",
|
||||
"Como pode ver no gráfico acima, a precisão nunca ultrapassa os 75%, porque é impossível traçar uma linha reta de forma a acertar todos os exemplos possíveis.\n",
|
||||
"\n",
|
||||
"O problema XOR é um exemplo clássico das limitações do perceptrão, e foi destacado por Marvin Minsky e Seymour Papert em 1969 no seu livro [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Esta observação limitou a investigação na área das redes neuronais durante quase 10 anos, apesar de - como veremos na próxima secção do nosso curso - perceptrões com múltiplas camadas serem perfeitamente capazes de resolver tais problemas.\n",
|
||||
"O problema XOR é um exemplo clássico das limitações do perceptron, e foi destacado por Marvin Minsky e Seymour Papert em 1969 no seu livro [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Esta observação limitou a investigação na área das redes neuronais durante quase 10 anos, embora - e veremos isto na próxima secção do nosso curso - perceptrons com múltiplas camadas sejam perfeitamente capazes de resolver tais problemas.\n",
|
||||
"\n",
|
||||
"## Exemplo Complexo - MNIST\n",
|
||||
"\n",
|
||||
"Embora o perceptrão não consiga resolver o problema XOR, ele consegue resolver problemas muito mais complexos, como o reconhecimento de caracteres manuscritos.\n",
|
||||
"Embora o perceptron não consiga resolver o problema XOR, consegue resolver problemas muito mais complexos, como o reconhecimento de caracteres manuscritos.\n",
|
||||
"\n",
|
||||
"Um conjunto de dados frequentemente utilizado para aprender machine learning chama-se [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Foi criado pelo Instituto Nacional de Padrões e Tecnologia Modificado (Modified National Institute of Standards and Technology) e contém um conjunto de treino com 60.000 dígitos manuscritos, recolhidos de cerca de 250 estudantes e funcionários do instituto. Existe também um conjunto de teste com 10.000 dígitos, recolhidos de diferentes indivíduos.\n",
|
||||
"Um conjunto de dados frequentemente utilizado para aprender machine learning chama-se [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Foi criado pelo Instituto Nacional de Padrões e Tecnologia Modificado e contém um conjunto de treino com 60.000 dígitos manuscritos, recolhidos de cerca de 250 estudantes e funcionários do instituto. Existe também um conjunto de teste com 10.000 dígitos, recolhidos de diferentes indivíduos.\n",
|
||||
"\n",
|
||||
"Todos os dígitos são representados por imagens em tons de cinzento com tamanho de 28x28 píxeis.\n",
|
||||
"Todos os dígitos são representados por imagens em escala de cinza com tamanho de 28x28 pixels.\n",
|
||||
"\n",
|
||||
"> O Conjunto de Dados MNIST está disponível como uma competição de treino no [Kaggle](https://www.kaggle.com/c/digit-recognizer), um site que organiza competições e desafios de machine learning. Assim que aprender a classificar os dígitos do MNIST, pode submeter a sua solução no Kaggle para ver como é classificada entre outros participantes.\n",
|
||||
"> O conjunto de dados MNIST está disponível como uma competição de treino no [Kaggle](https://www.kaggle.com/c/digit-recognizer), um site que organiza competições e desafios de machine learning. Assim que aprender a classificar os dígitos do MNIST, pode submeter a sua solução no Kaggle para ver como é classificada entre outros participantes.\n",
|
||||
"\n",
|
||||
"Começamos por carregar o conjunto de dados MNIST:\n"
|
||||
]
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"Por favor, note como a precisão aumenta para quase 100% muito rapidamente.\n",
|
||||
"\n",
|
||||
"Por favor, mova o cursor para uma posição próxima ao final do treino e observe a matriz de pesos representada à esquerda. Esta matriz permitirá que compreenda como o perceptrão realmente funciona. Pode ver os valores altos de peso no meio do campo, que correspondem a píxeis que normalmente estão presentes no dígito 1, e valores negativos baixos nas extremidades, onde estão partes do dígito 0. Assim, se o dígito apresentado ao perceptrão for de facto 1, a parte central será multiplicada por valores altos, produzindo um resultado positivo. Por outro lado, quando o perceptrão observa o dígito 0, os píxeis correspondentes serão multiplicados por números negativos.\n",
|
||||
"Por favor, mova o cursor para uma posição mais próxima do final do treino e observe a matriz de pesos representada à esquerda. Esta matriz permitirá que compreenda como o perceptrão realmente funciona. Pode ver os valores altos de peso no meio do campo, que correspondem a píxeis que estão tipicamente presentes no dígito 1, e valores negativos baixos nos lados, onde estão partes do dígito 0. Assim, se o dígito apresentado ao perceptrão for de facto 1, a parte central será multiplicada por valores altos, produzindo um resultado positivo. Por outro lado, quando o perceptrão observa o dígito 0, os píxeis correspondentes serão multiplicados por números negativos.\n",
|
||||
"\n",
|
||||
"> Pode reparar que, se dermos ao perceptrão um dígito 1 ligeiramente deslocado horizontalmente, de forma que os seus píxeis ocupem o lugar onde há partes verticais do dígito 0, podemos obter um resultado incorreto. Isto acontece porque a natureza do nosso conjunto de dados MNIST é tal que todos os dígitos estão centrados e posicionados corretamente, e o perceptrão depende disso para distinguir entre os dígitos.\n",
|
||||
"> Pode reparar que, se dermos ao nosso perceptrão um dígito 1 ligeiramente deslocado horizontalmente, de forma que os seus píxeis ocupem o lugar onde há partes verticais do dígito 0, podemos obter um resultado incorreto. Isto acontece porque a natureza do nosso conjunto de dados MNIST é tal que todos os dígitos estão centrados e posicionados corretamente, e o perceptrão depende disso para distinguir entre os dígitos.\n",
|
||||
"\n",
|
||||
"Agora vamos experimentar com dígitos diferentes:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Discussão\n",
|
||||
"\n",
|
||||
"Por alguma razão, 2 e 5 não são tão facilmente separáveis. Apesar de obtermos uma precisão relativamente alta (acima de 85%), é evidente que o perceptron deixa de aprender a partir de certo ponto.\n",
|
||||
"Por alguma razão, 2 e 5 não são tão facilmente separáveis. Apesar de obtermos uma precisão relativamente alta (acima de 85%), podemos claramente perceber que o perceptron para de aprender em determinado momento.\n",
|
||||
"\n",
|
||||
"Para entender por que isso acontece, podemos tentar usar [Análise de Componentes Principais](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Trata-se de uma técnica de aprendizagem automática utilizada para reduzir a dimensionalidade do conjunto de dados de entrada, de forma a obter a melhor separabilidade entre classes.\n",
|
||||
"Para entender por que isso acontece, podemos tentar usar [Análise de Componentes Principais](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). É uma técnica de aprendizagem automática usada para reduzir a dimensionalidade do conjunto de dados de entrada, de forma a obter a melhor separação entre as classes.\n",
|
||||
"\n",
|
||||
"No nosso caso, uma imagem de entrada tem 784 pixels (características de entrada), e queremos usar o PCA para reduzir o número de parâmetros para apenas 2, de modo a podermos representá-los num gráfico. Esses dois parâmetros seriam uma combinação linear das características originais, e podemos encarar este procedimento como uma \"rotação\" do nosso espaço original de 784 dimensões, observando a sua projeção no espaço 2D, até obtermos a melhor visualização que separa as classes.\n"
|
||||
"No nosso caso, uma imagem de entrada tem 784 pixels (características de entrada), e queremos usar o PCA para reduzir o número de parâmetros para apenas 2, para que possamos representá-los num gráfico. Esses dois parâmetros seriam uma combinação linear das características originais, e podemos ver este procedimento como uma \"rotação\" do nosso espaço original de 784 dimensões e observar a sua projeção no espaço 2D, até obtermos a melhor visualização que separa as classes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Como pode ver, 0 e 1 podem ser claramente separados por uma linha reta. Isto indica que, no espaço original de 784 dimensões, os pontos correspondentes aos dígitos também são linearmente separáveis. No caso de 2 e 5, não conseguimos encontrar uma boa projeção que separe os dígitos claramente, e, por isso, há alguns casos de classificação incorreta.\n",
|
||||
"Como pode ver, 0 e 1 podem ser claramente separados por uma linha reta. Isto indica que, no espaço original de 784 dimensões, os pontos correspondentes aos dígitos também são linearmente separáveis. No caso de 2 e 5, não conseguimos encontrar uma boa projeção que separe os dígitos claramente, e, por isso, há alguns casos de classificação errada.\n",
|
||||
"\n",
|
||||
"> Mais adiante neste curso, aprenderemos como criar classificadores não lineares usando Redes Neurais e como lidar com o problema de dígitos que não estão devidamente alinhados. Muito em breve, alcançaremos uma precisão acima de 99% na classificação de dígitos MNIST, classificando-os em 10 classes diferentes.\n",
|
||||
"> Mais tarde neste curso, iremos aprender como criar classificadores não lineares utilizando Redes Neuronais e como lidar com o problema de dígitos que não estão devidamente alinhados. Muito em breve, alcançaremos uma precisão acima de 99% na classificação de dígitos MNIST, classificando-os em 10 diferentes classes.\n",
|
||||
"\n",
|
||||
"## Conclusão\n",
|
||||
"## Conclusões\n",
|
||||
"\n",
|
||||
" * Aprendemos sobre a arquitetura mais simples de rede neural - o perceptron de uma camada.\n",
|
||||
" * Implementámos o perceptron \"manualmente\", utilizando um procedimento de treino simples baseado no gradiente descendente.\n",
|
||||
" * Apesar da simplicidade, o perceptron de uma camada consegue resolver problemas relativamente complexos de reconhecimento de dígitos manuscritos.\n",
|
||||
" * O perceptron de uma camada é um classificador linear e, por isso, oferece o mesmo poder de classificação que a regressão logística.\n",
|
||||
" * No espaço de amostra, o perceptron pode separar duas classes de dados de entrada utilizando um hiperplano.\n"
|
||||
" * Aprendemos sobre a arquitetura mais simples de rede neuronal - o perceptrão de uma camada.\n",
|
||||
" * Implementámos o perceptrão \"manualmente\", utilizando um procedimento de treino simples baseado no gradiente descendente.\n",
|
||||
" * Apesar da simplicidade, o perceptrão de uma camada consegue resolver problemas relativamente complexos de reconhecimento de dígitos manuscritos.\n",
|
||||
" * O perceptrão de uma camada é um classificador linear e, por isso, oferece o mesmo poder de classificação que a regressão logística.\n",
|
||||
" * No espaço de amostras, o perceptrão pode separar duas classes de dados de entrada utilizando um hiperplano.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Créditos\n",
|
||||
"\n",
|
||||
"Este notebook faz parte do [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) e foi preparado por [Dmitry Soshnikov](http://soshnikov.com). É inspirado no Workshop de Redes Neuronais da Microsoft Research Cambridge. Parte do código e dos materiais ilustrativos foram retirados de apresentações de [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) e [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), bem como do repositório [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Este notebook faz parte do [Currículo de IA para Iniciantes](http://github.com/microsoft/ai-for-beginners) e foi preparado por [Dmitry Soshnikov](http://soshnikov.com). É inspirado no Workshop de Redes Neuronais da Microsoft Research Cambridge. Parte do código e dos materiais ilustrativos foram retirados de apresentações de [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) e [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), bem como do repositório [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
"\n---\n\n**Aviso**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:23:53+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:10:54+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Problemă simplă\n",
|
||||
"\n",
|
||||
"Pentru început, să luăm o problemă simplă, unde avem două caracteristici de intrare. De exemplu, în medicină, am putea dori să clasificăm tumorile în benigne și maligne, în funcție de mărimea și vârsta lor.\n",
|
||||
"Pentru început, să începem cu o problemă simplă, unde avem două caracteristici de intrare. De exemplu, în medicină, s-ar putea să dorim să clasificăm tumorile în benigne și maligne, în funcție de mărimea și vârsta lor.\n",
|
||||
"\n",
|
||||
"Vom genera un set de date de clasificare aleatoriu folosind funcția `make_classification` din biblioteca SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Să reprezentăm grafic și setul de date:\n"
|
||||
"Să plotăm și setul de date:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -217,7 +217,7 @@
|
|||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"unde $\\eta$ este **rata de învățare**, iar $\\tau\\in\\mathbb{N}$ - numărul de iterații.\n",
|
||||
"unde $\\eta$ este o **rată de învățare**, iar $\\tau\\in\\mathbb{N}$ - numărul de iterații.\n",
|
||||
"\n",
|
||||
"Să definim acest algoritm în Python:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Notă despre rata de învățare**: Parametrul `learning_rate` (implicit `0.01`) controlează cât de mult ajustăm greutățile în timpul fiecărui pas de antrenament. Acesta implementează formula de actualizare prin gradient descendent:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- O rată de învățare mai mare (de exemplu, `1.0`) face ca perceptronul să învețe mai rapid, dar poate depăși soluția optimă\n",
|
||||
"- O rată de învățare mai mică (de exemplu, `0.001`) învață mai lent, dar poate converge mai precis\n",
|
||||
"- Puteți experimenta apelând: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimentarea cu ratele de învățare\n",
|
||||
"\n",
|
||||
"Acum să explorăm cum diferite rate de învățare influențează procesul de antrenare. Rata de învățare controlează dimensiunea pasului în metoda gradientului descendent - un hiperparametru esențial care afectează atât viteza de convergență, cât și stabilitatea.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Experiment Interactiv cu Rata de Învățare\n",
|
||||
"\n",
|
||||
"Folosește cursorul de mai jos pentru a experimenta interactiv cu diferite rate de învățare și vezi cum influențează linia de decizie:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Observarea procesului de antrenament\n",
|
||||
"\n",
|
||||
"Am văzut anterior cum scade acuratețea în timpul antrenamentului. Ar fi interesant să vedem cum se comportă linia de separare pe parcursul antrenamentului. Codul de mai jos va vizualiza totul pe un singur grafic, iar tu ar trebui să poți muta cursorul pentru a \"călători în timp\" prin procesul de antrenament.\n"
|
||||
"Am văzut anterior cum acuratețea scade în timpul antrenamentului. Ar fi interesant să vedem cum se comportă linia de separare pe parcursul antrenamentului. Codul de mai jos va vizualiza totul pe un singur grafic, iar tu ar trebui să poți muta cursorul pentru a \"călători în timp\" prin procesul de antrenament.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -605,7 +731,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"După cum se poate observa din graficul de mai sus, acuratețea nu depășește niciodată 75%, deoarece este imposibil să tragi o linie dreaptă astfel încât să obții toate exemplele corecte.\n",
|
||||
"După cum se poate observa din graficul de mai sus, acuratețea nu depășește niciodată 75%, deoarece este imposibil să se traseze o linie dreaptă astfel încât să se obțină toate exemplele corecte.\n",
|
||||
"\n",
|
||||
"Problema XOR este un exemplu clasic al limitărilor perceptronului, iar aceasta a fost subliniată de Marvin Minsky și Seymour Papert în 1969, în cartea lor [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Această observație a limitat cercetările în domeniul rețelelor neuronale timp de aproape 10 ani, deși - și vom vedea acest lucru în secțiunea următoare a cursului nostru - perceptronii cu mai multe straturi sunt perfect capabili să rezolve astfel de probleme.\n",
|
||||
"\n",
|
||||
|
|
@ -613,7 +739,7 @@
|
|||
"\n",
|
||||
"Deși perceptronul nu poate rezolva problema XOR, acesta poate rezolva multe probleme mult mai complexe, cum ar fi recunoașterea caracterelor scrise de mână.\n",
|
||||
"\n",
|
||||
"Un set de date utilizat frecvent pentru a învăța machine learning se numește [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Acesta a fost creat de Institutul Național de Standarde și Tehnologie Modificat și conține un set de antrenament cu 60.000 de cifre scrise de mână, colectate de la aproximativ 250 de studenți și angajați ai institutului. Există, de asemenea, un set de testare cu 10.000 de cifre, colectate de la persoane diferite.\n",
|
||||
"Un set de date utilizat frecvent pentru a învăța machine learning se numește [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Acesta a fost creat de Institutul Național de Standarde și Tehnologie Modificat și conține un set de antrenament de 60.000 de cifre scrise de mână, colectate de la aproximativ 250 de studenți și angajați ai institutului. Există, de asemenea, un set de testare de 10.000 de cifre, colectate de la persoane diferite.\n",
|
||||
"\n",
|
||||
"Toate cifrele sunt reprezentate prin imagini în tonuri de gri, de dimensiunea 28x28 pixeli.\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Deoarece perceptronul este un clasificator binar, vom limita problema noastră la recunoașterea a doar două cifre. Funcția de mai jos va popula tablourile de mostre pozitive și negative cu două cifre date (și va afișa, de asemenea, mostre ale acelor cifre pentru claritate).\n"
|
||||
"Deoarece perceptronul este un clasificator binar, vom limita problema noastră la recunoașterea a doar două cifre. Funcția de mai jos va popula tablourile de exemple pozitive și negative cu două cifre date (și va afișa, de asemenea, exemple ale acelor cifre pentru claritate).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"Vă rugăm să observați cum acuratețea crește aproape de 100% foarte rapid.\n",
|
||||
"\n",
|
||||
"Vă rugăm să mutați cursorul spre o poziție din apropierea sfârșitului antrenamentului și să observați matricea de greutăți afișată în stânga. Această matrice vă va ajuta să înțelegeți cum funcționează perceptronul. Puteți vedea valorile mari ale greutăților în mijlocul câmpului, care corespund pixelilor ce sunt de obicei prezenți pentru cifra 1, și valorile negative mici pe margini, unde se află părți ale cifrei 0. Astfel, dacă cifra prezentată perceptronului este de fapt 1, partea din mijloc va fi înmulțită cu valori mari, producând un rezultat pozitiv. În schimb, când perceptronul observă cifra 0, pixelii corespunzători vor fi înmulțiți cu numere negative.\n",
|
||||
"Vă rugăm să mutați cursorul spre o poziție de la sfârșitul antrenamentului și să observați matricea de greutăți afișată în stânga. Această matrice vă va ajuta să înțelegeți cum funcționează perceptronul. Puteți vedea valorile mari ale greutăților în mijlocul câmpului, care corespund pixelilor ce sunt de obicei prezenți pentru cifra 1, și valorile negative mici pe margini, unde se află părți ale cifrei 0. Astfel, dacă cifra prezentată perceptronului este de fapt 1, partea din mijloc a acesteia va fi înmulțită cu valori mari, producând un rezultat pozitiv. În schimb, când perceptronul observă cifra 0, pixelii corespunzători vor fi înmulțiți cu numere negative.\n",
|
||||
"\n",
|
||||
"> Puteți observa că, dacă oferim perceptronului o cifră 1 ușor deplasată orizontal, astfel încât pixelii să ocupe locul unde se află părțile verticale ale cifrei 0, putem obține un rezultat incorect. Deoarece natura setului nostru de date MNIST este astfel încât toate cifrele sunt centrate și poziționate corect, perceptronul se bazează pe acest aspect pentru a distinge între cifre.\n",
|
||||
"> Puteți observa că, dacă oferim perceptronului o cifră 1 ușor deplasată pe orizontală, astfel încât pixelii să ocupe locul unde se află părțile verticale ale cifrei 0, putem obține un rezultat incorect. Deoarece natura setului nostru de date MNIST este astfel încât toate cifrele sunt centrate și poziționate corect, perceptronul se bazează pe acest aspect pentru a distinge între cifre.\n",
|
||||
"\n",
|
||||
"Acum să încercăm cifre diferite:\n"
|
||||
]
|
||||
|
|
@ -913,7 +1039,7 @@
|
|||
"source": [
|
||||
"## Discuție\n",
|
||||
"\n",
|
||||
"Dintr-un motiv oarecare, 2 și 5 nu sunt atât de ușor de separabile. Deși obținem o acuratețe relativ ridicată (peste 85%), putem observa clar cum perceptronul încetează să mai învețe la un moment dat.\n",
|
||||
"Dintr-un motiv oarecare, 2 și 5 nu sunt la fel de ușor de separat. Deși obținem o acuratețe relativ ridicată (peste 85%), putem observa clar cum perceptronul încetează să mai învețe la un moment dat.\n",
|
||||
"\n",
|
||||
"Pentru a înțelege de ce se întâmplă acest lucru, putem încerca să folosim [Analiza Componentelor Principale](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Este o tehnică de învățare automată utilizată pentru a reduce dimensionalitatea setului de date de intrare, astfel încât să obținem cea mai bună separabilitate între clase.\n",
|
||||
"\n",
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Credite\n",
|
||||
"\n",
|
||||
"Acest notebook face parte din [Curricula AI pentru Începători](http://github.com/microsoft/ai-for-beginners) și a fost pregătit de [Dmitry Soshnikov](http://soshnikov.com). Este inspirat de Atelierul de Rețele Neurale de la Microsoft Research Cambridge. O parte din cod și materialele ilustrative sunt preluate din prezentările realizate de [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) și [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), precum și din depozitul [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Acest notebook face parte din [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) și a fost pregătit de [Dmitry Soshnikov](http://soshnikov.com). Este inspirat de Workshop-ul despre Rețele Neurale de la Microsoft Research Cambridge. O parte din cod și materialele ilustrative sunt preluate din prezentările realizate de [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) și [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), precum și din repository-ul [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Declinare de responsabilitate**: \nAcest document a fost tradus folosind serviciul de traducere AI [Co-op Translator](https://github.com/Azure/co-op-translator). Deși ne străduim să asigurăm acuratețea, vă rugăm să fiți conștienți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa natală ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist uman. Nu ne asumăm responsabilitatea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.\n"
|
||||
"\n---\n\n**Declinare de responsabilitate**: \nAcest document a fost tradus folosind serviciul de traducere AI [Co-op Translator](https://github.com/Azure/co-op-translator). Deși ne străduim să asigurăm acuratețea, vă rugăm să fiți conștienți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa maternă ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist uman. Nu ne asumăm responsabilitatea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:44:37+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:32:49+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "ro"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"source": [
|
||||
"## Перцептрон\n",
|
||||
"\n",
|
||||
"> Этот ноутбук является частью [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Посетите репозиторий для полного набора учебных материалов.\n",
|
||||
"> Этот ноутбук является частью [Учебной программы \"Искусственный интеллект для начинающих\"](http://github.com/microsoft/ai-for-beginners). Посетите репозиторий, чтобы получить полный набор учебных материалов.\n",
|
||||
"\n",
|
||||
"Как мы уже обсуждали, перцептрон позволяет решать задачу **бинарной классификации**, то есть классифицировать входные примеры на два класса - мы можем назвать их **положительный** и **отрицательный**.\n",
|
||||
"\n",
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Упрощённая задача\n",
|
||||
"\n",
|
||||
"Для начала давайте рассмотрим упрощённую задачу, где у нас есть два входных признака. Например, в медицине мы можем захотеть классифицировать опухоли как доброкачественные или злокачественные, в зависимости от их размера и возраста.\n",
|
||||
"Для начала рассмотрим упрощённую задачу, где у нас есть два входных признака. Например, в медицине мы можем захотеть классифицировать опухоли как доброкачественные или злокачественные, в зависимости от их размера и возраста.\n",
|
||||
"\n",
|
||||
"Мы создадим случайный набор данных для классификации, используя функцию `make_classification` из библиотеки SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Примечание о скорости обучения**: Параметр `learning_rate` (по умолчанию `0.01`) определяет, насколько сильно мы корректируем веса на каждом шаге обучения. Это реализует формулу обновления градиентного спуска:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Большая скорость обучения (например, `1.0`) позволяет перцептрону обучаться быстрее, но может привести к пропуску оптимального решения\n",
|
||||
"- Малая скорость обучения (например, `0.001`) обучается медленнее, но может более точно сходиться к оптимальному решению\n",
|
||||
"- Вы можете экспериментировать, вызвав: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Как видно, начальная точность составляет около 50%, но она быстро увеличивается до более высоких значений, близких к 90%.\n",
|
||||
"\n",
|
||||
"Давайте визуализируем, как разделяются классы. Наша функция классификации выглядит как $\\mathbf{w}^Tx$, и она больше 0 для одного класса, а меньше 0 для другого. Таким образом, линия разделения классов определяется уравнением $\\mathbf{w}^Tx = 0$. Поскольку у нас есть только две размерности $x_0$ и $x_1$, уравнение для линии будет $w_0x_0+w_1x_1+w_2 = 0$ (помните, что мы явно определили дополнительную размерность $x_2=1$). Давайте построим эту линию:\n"
|
||||
"Давайте визуализируем, как классы разделяются. Наша функция классификации выглядит как $\\mathbf{w}^Tx$, и она больше 0 для одного класса, и меньше 0 для другого. Таким образом, линия разделения классов определяется уравнением $\\mathbf{w}^Tx = 0$. Поскольку у нас есть только две размерности $x_0$ и $x_1$, уравнение для линии будет $w_0x_0+w_1x_1+w_2 = 0$ (помните, что мы явно определили дополнительную размерность $x_2=1$). Давайте построим эту линию:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Эксперименты с темпами обучения\n",
|
||||
"\n",
|
||||
"Теперь давайте изучим, как различные темпы обучения влияют на процесс тренировки. Темп обучения определяет размер шага в градиентном спуске - это важный гиперпараметр, который влияет как на скорость сходимости, так и на стабильность.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Интерактивный эксперимент с коэффициентом обучения\n",
|
||||
"\n",
|
||||
"Используйте ползунок ниже, чтобы интерактивно экспериментировать с различными коэффициентами обучения и увидеть, как они влияют на границу принятия решений:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Оценка на тестовом наборе данных\n",
|
||||
"\n",
|
||||
"В начале мы выделили часть данных для тестового набора. Давайте проверим, насколько точен наш классификатор на этом тестовом наборе данных. Для этого мы также расширяем тестовый набор данных, добавляя дополнительное измерение, умножаем на матрицу весов и проверяем, чтобы полученное значение имело тот же знак, что и метка (+1 или -1). Затем мы суммируем все булевы значения и делим на длину тестовой выборки, чтобы получить точность:\n"
|
||||
"С самого начала мы выделили часть данных для тестового набора. Давайте проверим, насколько точен наш классификатор на этом тестовом наборе данных. Для этого мы также расширяем тестовый набор данных, добавляя дополнительное измерение, умножаем на матрицу весов и убеждаемся, что полученное значение имеет тот же знак, что и метка (+1 или -1). Затем мы суммируем все булевы значения и делим на длину тестовой выборки, чтобы получить точность:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Наблюдение за процессом обучения\n",
|
||||
"\n",
|
||||
"Мы уже видели, как точность уменьшается в процессе обучения. Было бы интересно посмотреть, как ведет себя линия разделения во время обучения. Код ниже визуализирует все на одном графике, и вы сможете перемещать ползунок, чтобы \"путешествовать во времени\" через процесс обучения.\n"
|
||||
"Мы уже видели, как точность уменьшается во время обучения. Было бы интересно посмотреть, как ведет себя линия разделения в процессе обучения. Код ниже визуализирует всё на одном графике, и вы сможете перемещать ползунок, чтобы \"путешествовать во времени\" через процесс обучения.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -538,7 +664,7 @@
|
|||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Давайте попробуем это сделать! Мы вручную заполним все положительные и отрицательные обучающие примеры, а затем вызовем нашу функцию train, определенную выше:\n"
|
||||
"Давайте попробуем это сделать! Мы вручную заполним все положительные и отрицательные обучающие примеры, а затем вызовем нашу функцию train, определённую выше:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -617,7 +743,7 @@
|
|||
"\n",
|
||||
"Все цифры представлены в виде изображений в градациях серого размером 28x28 пикселей.\n",
|
||||
"\n",
|
||||
"> Набор данных MNIST доступен в виде тренировочного соревнования на [Kaggle](https://www.kaggle.com/c/digit-recognizer), сайте, который проводит конкурсы и соревнования по машинному обучению. Как только вы научитесь классифицировать цифры MNIST, вы можете отправить свое решение на Kaggle, чтобы узнать, как оно оценивается среди других участников.\n",
|
||||
"> Набор данных MNIST доступен в качестве тренировочного соревнования на платформе [Kaggle](https://www.kaggle.com/c/digit-recognizer), сайте, который проводит конкурсы и соревнования по машинному обучению. Как только вы научитесь классифицировать цифры из MNIST, вы можете отправить свое решение на Kaggle, чтобы узнать, как оно оценивается среди других участников.\n",
|
||||
"\n",
|
||||
"Начнем с загрузки набора данных MNIST:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Поскольку перцептрон является бинарным классификатором, мы ограничим нашу задачу распознаванием только двух цифр. Функция ниже заполнит массивы положительных и отрицательных образцов двумя заданными цифрами (а также покажет примеры этих цифр для наглядности).\n"
|
||||
"Поскольку перцептрон является бинарным классификатором, мы ограничим нашу задачу распознаванием только двух цифр. Функция ниже заполнит массивы положительных и отрицательных образцов двумя заданными цифрами (а также покажет образцы этих цифр для наглядности).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -835,7 +961,7 @@
|
|||
"\n",
|
||||
"Пожалуйста, переместите ползунок ближе к концу обучения и посмотрите на матрицу весов, отображаемую слева. Эта матрица поможет вам понять, как работает перцептрон. Вы можете увидеть высокие значения весов в центре поля, которые соответствуют пикселям, обычно присутствующим для цифры 1, и низкие отрицательные значения по краям, где находятся части цифры 0. Таким образом, если цифра, представленная перцептрону, действительно является 1, центральная часть будет умножена на высокие значения, что даст положительный результат. Напротив, когда перцептрон видит цифру 0, соответствующие пиксели умножаются на отрицательные числа.\n",
|
||||
"\n",
|
||||
"> Вы можете заметить, что если мы дадим нашему перцептрону цифру 1, слегка смещённую по горизонтали, так что её пиксели займут место, где находятся вертикальные части цифры 0, мы можем получить некорректный результат. Поскольку природа нашего набора данных MNIST такова, что все цифры центрированы и правильно расположены, перцептрон полагается на это, чтобы различать цифры.\n",
|
||||
"> Вы можете заметить, что если мы дадим нашему перцептрону цифру 1, слегка смещённую по горизонтали, так что её пиксели займут место, где находятся вертикальные части цифры 0, мы можем получить некорректный результат. Поскольку природа нашего набора данных MNIST такова, что все цифры центрированы и правильно расположены, перцептрон полагается на это для различения цифр.\n",
|
||||
"\n",
|
||||
"Теперь давайте попробуем разные цифры:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Обсуждение\n",
|
||||
"\n",
|
||||
"По какой-то причине цифры 2 и 5 не так легко разделить. Несмотря на то, что мы достигаем довольно высокой точности (выше 85%), можно заметить, что в какой-то момент персептрон перестает обучаться.\n",
|
||||
"По какой-то причине цифры 2 и 5 не так легко разделить. Несмотря на то, что мы достигаем довольно высокой точности (выше 85%), можно заметить, что в какой-то момент перцептрон перестает обучаться.\n",
|
||||
"\n",
|
||||
"Чтобы понять, почему это происходит, мы можем попробовать использовать [Анализ главных компонент](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Это метод машинного обучения, который используется для снижения размерности входного набора данных таким образом, чтобы обеспечить наилучшее разделение между классами.\n",
|
||||
"\n",
|
||||
"В нашем случае входное изображение содержит 784 пикселя (входных признака), и мы хотим использовать PCA, чтобы уменьшить количество параметров до всего лишь 2, чтобы можно было их отобразить на графике. Эти два параметра будут линейной комбинацией исходных признаков, и этот процесс можно представить как \"поворот\" нашего исходного 784-мерного пространства и наблюдение его проекции на 2D-пространство, пока мы не получим наилучший вид, который разделяет классы.\n"
|
||||
"В нашем случае входное изображение имеет 784 пикселя (входных признака), и мы хотим использовать PCA, чтобы сократить количество параметров до всего лишь 2, чтобы можно было их отобразить на графике. Эти два параметра будут линейной комбинацией исходных признаков, и этот процесс можно представить как \"поворот\" нашего исходного 784-мерного пространства и наблюдение его проекции на 2D-пространство, пока мы не получим наилучший вид, который разделяет классы.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,15 +1153,15 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Как видно, 0 и 1 можно четко разделить прямой линией. Это указывает на то, что в исходном 784-мерном пространстве точки, соответствующие цифрам, также линейно разделимы. В случае с 2 и 5 мы не можем найти подходящую проекцию, которая бы четко разделила цифры, и поэтому возникают случаи неправильной классификации.\n",
|
||||
"Как видно, 0 и 1 можно четко разделить прямой линией. Это указывает на то, что в исходном 784-мерном пространстве точки, соответствующие цифрам, также линейно разделимы. В случае с 2 и 5 мы не можем найти подходящую проекцию, которая четко разделит цифры, и поэтому возникают случаи неправильной классификации.\n",
|
||||
"\n",
|
||||
"> Позже в этом курсе мы научимся создавать нелинейные классификаторы с использованием нейронных сетей и решать проблему неправильного выравнивания цифр. Очень скоро мы достигнем точности выше 99% в классификации цифр MNIST, разделяя их на 10 различных классов.\n",
|
||||
"> Позже в этом курсе мы узнаем, как создавать нелинейные классификаторы с использованием нейронных сетей, а также как решать проблему неправильного выравнивания цифр. Очень скоро мы достигнем точности выше 99% в классификации цифр MNIST, разделяя их на 10 различных классов.\n",
|
||||
"\n",
|
||||
"## Основные выводы\n",
|
||||
"\n",
|
||||
" * Мы изучили самую простую архитектуру нейронной сети — однослойный перцептрон.\n",
|
||||
" * Мы реализовали перцептрон \"вручную\", используя простую процедуру обучения на основе градиентного спуска.\n",
|
||||
" * Несмотря на простоту, однослойный перцептрон способен решать довольно сложные задачи распознавания рукописных цифр.\n",
|
||||
" * Несмотря на простоту, однослойный перцептрон способен решать достаточно сложные задачи распознавания рукописных цифр.\n",
|
||||
" * Однослойный перцептрон является линейным классификатором, и, таким образом, обладает той же классификационной мощностью, что и логистическая регрессия.\n",
|
||||
" * В пространстве выборки перцептрон может разделять два класса входных данных с помощью гиперплоскости.\n"
|
||||
]
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Благодарности\n",
|
||||
"\n",
|
||||
"Этот ноутбук является частью [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) и был подготовлен [Дмитрием Сошниковым](http://soshnikov.com). Он вдохновлен семинаром по нейронным сетям в Microsoft Research Cambridge. Некоторый код и иллюстративные материалы взяты из презентаций [Катьи Хоффман](https://www.microsoft.com/en-us/research/people/kahofman/), [Мэттью Джонсона](https://www.microsoft.com/en-us/research/people/matjoh/) и [Рёто Томиоки](https://www.microsoft.com/en-us/research/people/ryoto/), а также из репозитория [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Этот ноутбук является частью [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) и был подготовлен [Дмитрием Сошниковым](http://soshnikov.com). Он вдохновлен семинаром по нейронным сетям в Microsoft Research Cambridge. Некоторый код и иллюстративные материалы взяты из презентаций [Катьи Хоффман](https://www.microsoft.com/en-us/research/people/kahofman/), [Мэтью Джонсона](https://www.microsoft.com/en-us/research/people/matjoh/) и [Рёто Томиоки](https://www.microsoft.com/en-us/research/people/ryoto/), а также из репозитория [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Отказ от ответственности**: \nЭтот документ был переведен с использованием сервиса автоматического перевода [Co-op Translator](https://github.com/Azure/co-op-translator). Хотя мы стремимся к точности, пожалуйста, учитывайте, что автоматические переводы могут содержать ошибки или неточности. Оригинальный документ на его родном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные интерпретации, возникшие в результате использования данного перевода.\n"
|
||||
"\n---\n\n**Отказ от ответственности**: \nЭтот документ был переведен с помощью сервиса автоматического перевода [Co-op Translator](https://github.com/Azure/co-op-translator). Несмотря на наши усилия обеспечить точность перевода, автоматические переводы могут содержать ошибки или неточности. Оригинальный документ на его родном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные интерпретации, возникшие в результате использования данного перевода.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:08:58+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:54:31+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "ru"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Hračkový problém\n",
|
||||
"\n",
|
||||
"Začnime hračkovým problémom, kde máme dve vstupné vlastnosti. Napríklad v medicíne môžeme chcieť klasifikovať nádory na benígne a malígne, v závislosti od ich veľkosti a veku.\n",
|
||||
"Začnime jednoduchým problémom, kde máme dve vstupné vlastnosti. Napríklad v medicíne môžeme chcieť klasifikovať nádory na benígne a malígne, v závislosti od ich veľkosti a veku.\n",
|
||||
"\n",
|
||||
"Vygenerujeme náhodný klasifikačný dataset pomocou funkcie `make_classification` z knižnice SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -158,7 +158,7 @@
|
|||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"kde $\\mathbf{w}$ je vektor váh, $f$ je aktivačná funkcia typu krok:\n",
|
||||
"kde $\\mathbf{w}$ je vektor váh, $f$ je aktivačná funkcia typu prahová hodnota:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Avšak všeobecný lineárny model by mal mať aj bias, t.j. ideálne by sme mali počítať $y$ ako $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Na zjednodušenie nášho modelu sa môžeme zbaviť tohto biasu pridaním jednej ďalšej dimenzie k našim vstupným prvkom, ktorá bude vždy rovná 1:\n"
|
||||
"Avšak všeobecný lineárny model by mal mať aj bias, t.j. ideálne by sme mali počítať $y$ ako $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Na zjednodušenie nášho modelu sa môžeme zbaviť tohto biasu pridaním jednej ďalšej dimenzie k našim vstupným vlastnostiam, ktorá bude vždy rovná 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -206,14 +206,14 @@
|
|||
"source": [
|
||||
"## Tréningový algoritmus\n",
|
||||
"\n",
|
||||
"Aby sme mohli trénovať perceptron, musíme nájsť váhy $\\mathbf{w}$, ktoré minimalizujú chybu. Chyba je definovaná pomocou **kritéria perceptronu**:\n",
|
||||
"Na to, aby sme mohli trénovať perceptron, musíme nájsť váhy $\\mathbf{w}$, ktoré minimalizujú chybu. Chyba je definovaná pomocou **kritéria perceptronu**:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ pre negatívne a pozitívne trénovacie vzorky\n",
|
||||
" * $\\mathcal{M}$ - množina nesprávne klasifikovaných príkladov\n",
|
||||
" \n",
|
||||
"Použijeme proces **gradientného zostupu**. Začneme s nejakými náhodnými počiatočnými váhami $\\mathbf{w}^{(0)}$ a na každom kroku tréningu upravíme váhy pomocou gradientu $E$:\n",
|
||||
"Použijeme proces **gradientného zostupu**. Začneme s nejakými počiatočnými náhodnými váhami $\\mathbf{w}^{(0)}$ a na každom kroku tréningu upravíme váhy pomocou gradientu $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Poznámka k učebnej rýchlosti**: Parameter `learning_rate` (predvolená hodnota `0.01`) určuje, ako veľmi upravujeme váhy počas každého kroku tréningu. Tento parameter implementuje vzorec aktualizácie gradientného zostupu:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Väčšia učebná rýchlosť (napr. `1.0`) spôsobí, že perceptron sa učí rýchlejšie, ale môže preskočiť optimálne riešenie\n",
|
||||
"- Menšia učebná rýchlosť (napr. `0.001`) sa učí pomalšie, ale môže presnejšie konvergovať\n",
|
||||
"- Môžete experimentovať zavolaním: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Ako vidíte, počiatočná presnosť je okolo 50 %, ale rýchlo sa zvyšuje na vyššie hodnoty blízke 90 %.\n",
|
||||
"\n",
|
||||
"Vizualizujme, ako sú triedy oddelené. Naša klasifikačná funkcia vyzerá ako $\\mathbf{w}^Tx$, a je väčšia ako 0 pre jednu triedu, a menšia ako 0 pre druhú. Teda, deliaca čiara medzi triedami je definovaná ako $\\mathbf{w}^Tx = 0$. Keďže máme iba dve rozmery $x_0$ a $x_1$, rovnica pre čiaru by bola $w_0x_0+w_1x_1+w_2 = 0$ (pamätajte, že sme explicitne definovali extra rozmer $x_2=1$). Poďme túto čiaru vykresliť:\n"
|
||||
"Vizualizujme, ako sú triedy oddelené. Naša klasifikačná funkcia vyzerá ako $\\mathbf{w}^Tx$, a je väčšia ako 0 pre jednu triedu a menšia ako 0 pre druhú. Teda, deliaca čiara medzi triedami je definovaná ako $\\mathbf{w}^Tx = 0$. Keďže máme iba dve rozmery $x_0$ a $x_1$, rovnica pre čiaru by bola $w_0x_0+w_1x_1+w_2 = 0$ (pamätajte, že sme explicitne definovali extra rozmer $x_2=1$). Poďme túto čiaru vykresliť:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimentovanie s učebnými rýchlosťami\n",
|
||||
"\n",
|
||||
"Teraz sa pozrime, ako rôzne učebné rýchlosti ovplyvňujú proces trénovania. Učebná rýchlosť riadi veľkosť kroku pri gradientnom zostupe - kľúčový hyperparameter, ktorý ovplyvňuje rýchlosť konvergencie aj stabilitu.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktívny experiment s učebnou rýchlosťou\n",
|
||||
"\n",
|
||||
"Použite posuvník nižšie na interaktívne experimentovanie s rôznymi učebnými rýchlosťami a zistite, ako ovplyvňujú rozhodovaciu hranicu:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Vyhodnotenie na testovacej množine\n",
|
||||
"\n",
|
||||
"Na začiatku sme odložili časť údajov do testovacej množiny. Pozrime sa, aká presná je naša klasifikácia na tejto testovacej množine. Aby sme to dosiahli, rozšírime testovaciu množinu o ďalší rozmer, vynásobíme maticou váh a uistíme sa, že získaná hodnota má rovnaké znamienko ako štítok (+1 alebo -1). Následne spočítame všetky logické hodnoty a vydelíme ich dĺžkou testovacej vzorky, aby sme získali presnosť:\n"
|
||||
"Na začiatku sme odložili časť údajov do testovacej množiny. Pozrime sa, aká presná je naša klasifikácia na tejto testovacej množine. Aby sme to dosiahli, rozšírime testovaciu množinu o ďalší rozmer, vynásobíme maticou váh a uistíme sa, že získaná hodnota má rovnaké znamienko ako štítok (+1 alebo -1). Následne spočítame všetky hodnoty typu boolean a vydelíme ich dĺžkou testovacej vzorky, aby sme získali presnosť:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Pozorovanie procesu trénovania\n",
|
||||
"\n",
|
||||
"Už sme videli, ako sa presnosť znižuje počas trénovania. Bolo by zaujímavé vidieť, ako sa správa deliaca čiara počas trénovania. Kód nižšie zobrazí všetko na jednom grafe, a budete môcť posúvať posuvník, aby ste \"cestovali v čase\" cez proces trénovania.\n"
|
||||
"Už sme videli, ako sa presnosť znižuje počas trénovania. Bolo by zaujímavé vidieť, ako sa správa deliaca čiara počas trénovania. Kód nižšie zobrazí všetko na jednom grafe, pričom budete môcť posúvať posuvník a \"cestovať v čase\" cez proces trénovania.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -527,18 +653,18 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Obmedzenia perceptronu\n",
|
||||
"## Obmedzenia perceptrónu\n",
|
||||
"\n",
|
||||
"Ako ste videli vyššie, perceptron je **lineárny klasifikátor**. Dokáže dobre rozlíšiť medzi dvoma triedami, ak sú **lineárne oddeliteľné**, t. j. ak ich možno oddeliť priamkou. V opačnom prípade proces učenia perceptronu nebude konvergovať.\n",
|
||||
"Ako ste videli vyššie, perceptrón je **lineárny klasifikátor**. Dokáže dobre rozlišovať medzi dvoma triedami, ak sú **lineárne separovateľné**, t. j. ak ich možno oddeliť priamkou. V opačnom prípade proces trénovania perceptrónu nebude konvergovať.\n",
|
||||
"\n",
|
||||
"Najzjavnejším príkladom problému, ktorý perceptron nedokáže vyriešiť, je tzv. **XOR problém**. Chceme, aby sa perceptron naučil logickú funkciu XOR, ktorá má nasledujúcu pravdivostnú tabuľku:\n",
|
||||
"Najzrejmejším príkladom problému, ktorý perceptrón nedokáže vyriešiť, je takzvaný **XOR problém**. Chceme, aby sa náš perceptrón naučil booleovskú funkciu XOR, ktorá má nasledujúcu pravdivostnú tabuľku:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Skúsme to! Ručne naplníme všetky pozitívne a negatívne vzorky na trénovanie a potom zavoláme našu funkciu train, ktorú sme definovali vyššie:\n"
|
||||
"Poďme to skúsiť! Ručne naplníme všetky pozitívne a negatívne trénovacie vzorky a potom zavoláme našu trénovaciu funkciu definovanú vyššie:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,7 +731,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Ako môžete vidieť na grafe vyššie, presnosť nikdy nepresiahne 75 %, pretože nie je možné nakresliť priamku tak, aby správne klasifikovala všetky možné príklady.\n",
|
||||
"Ako môžete vidieť z grafu vyššie, presnosť nikdy nepresiahne 75 %, pretože nie je možné nakresliť priamku tak, aby správne klasifikovala všetky možné príklady.\n",
|
||||
"\n",
|
||||
"Problém XOR je klasickým príkladom obmedzení perceptronu, na ktorý upozornili Marvin Minsky a Seymour Papert v roku 1969 vo svojej knihe [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Toto zistenie obmedzilo výskum v oblasti neurónových sietí takmer na 10 rokov, aj keď - ako uvidíme v ďalšej časti nášho kurzu - viacvrstvové perceptrony dokážu takéto problémy bez problémov vyriešiť.\n",
|
||||
"\n",
|
||||
|
|
@ -613,7 +739,7 @@
|
|||
"\n",
|
||||
"Aj keď perceptron nedokáže vyriešiť problém XOR, dokáže riešiť oveľa zložitejšie problémy, ako je rozpoznávanie ručne písaných znakov.\n",
|
||||
"\n",
|
||||
"Dataset, ktorý sa často používa pri osvojovaní strojového učenia, sa nazýva [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Bol vytvorený Modifikovaným národným inštitútom pre normy a technológie a obsahuje tréningovú množinu 60 000 ručne písaných číslic, zozbieraných od približne 250 študentov a zamestnancov inštitútu. Existuje aj testovacia množina 10 000 číslic, zozbieraných od rôznych jednotlivcov.\n",
|
||||
"Dataset, ktorý sa často používa pri osvojovaní strojového učenia, sa nazýva [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Bol vytvorený Modifikovaným národným inštitútom pre normy a technológie a obsahuje tréningovú množinu 60 000 ručne písaných číslic, zozbieraných od približne 250 študentov a zamestnancov inštitútu. Existuje tiež testovacia množina 10 000 číslic, zozbieraných od rôznych jednotlivcov.\n",
|
||||
"\n",
|
||||
"Všetky číslice sú reprezentované obrázkami v odtieňoch sivej s rozmermi 28x28 pixelov.\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Pretože perceptron je binárny klasifikátor, obmedzíme náš problém na rozpoznávanie iba dvoch číslic. Funkcia nižšie naplní pole pozitívnych a negatívnych vzoriek dvoma zadanými číslicami (a tiež zobrazí vzorky týchto číslic pre prehľadnosť).\n"
|
||||
"Pretože perceptron je binárny klasifikátor, obmedzíme náš problém na rozpoznávanie iba dvoch číslic. Funkcia nižšie naplní pole pozitívnych a negatívnych vzoriek dvoma danými číslicami (a tiež zobrazí vzorky týchto číslic pre prehľadnosť).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,11 +959,11 @@
|
|||
"source": [
|
||||
"Všimnite si, ako presnosť veľmi rýchlo stúpa takmer na 100 %.\n",
|
||||
"\n",
|
||||
"Prosím, posuňte posuvník na nejakú pozíciu ku koncu tréningu a pozorujte maticu váh zobrazenú naľavo. Táto matica vám umožní pochopiť, ako perceptron vlastne funguje. Môžete vidieť vysoké hodnoty váh v strede poľa, ktoré zodpovedajú pixelom, ktoré sú typicky prítomné pri čísle 1, a nízke negatívne hodnoty po stranách, kde sa nachádzajú časti čísla 0. Takže, ak je číslo prezentované perceptronu skutočne 1, jeho stredná časť bude násobená vysokými hodnotami, čo vyprodukuje pozitívny výsledok. Naopak, keď perceptron pozoruje číslo 0, zodpovedajúce pixely budú násobené negatívnymi číslami.\n",
|
||||
"Prosím, posuňte posuvník na nejakú pozíciu ku koncu tréningu a pozorujte maticu váh zobrazenú naľavo. Táto matica vám umožní pochopiť, ako perceptron skutočne funguje. Môžete vidieť vysoké hodnoty váh v strede poľa, ktoré zodpovedajú pixelom, ktoré sú typicky prítomné pre číslicu 1, a nízke negatívne hodnoty po stranách, kde sa nachádzajú časti číslice 0. Takže, ak je číslica prezentovaná perceptronu skutočne 1, jej stredná časť bude násobená vysokými hodnotami, čo vyprodukuje pozitívny výsledok. Naopak, keď perceptron pozoruje číslicu 0, zodpovedajúce pixely budú násobené negatívnymi číslami.\n",
|
||||
"\n",
|
||||
"> Môžete si všimnúť, že ak dáme nášmu perceptronu číslo 1 mierne posunuté horizontálne, takže jeho pixely zaberajú miesto, kde sú vertikálne časti čísla 0, môžeme dostať nesprávny výsledok. Keďže povaha nášho MNIST datasetu je taká, že všetky čísla sú centrované a správne umiestnené, perceptron sa na to spolieha pri rozlišovaní medzi číslami.\n",
|
||||
"> Môžete si všimnúť, že ak dáme nášmu perceptronu číslicu 1 mierne posunutú horizontálne, takže jej pixely zaberajú miesto, kde sú vertikálne časti číslice 0, môžeme dostať nesprávny výsledok. Keďže povaha nášho MNIST datasetu je taká, že všetky číslice sú centrované a správne umiestnené, perceptron sa na to spolieha pri rozlišovaní medzi číslicami.\n",
|
||||
"\n",
|
||||
"Teraz vyskúšajme rôzne čísla:\n"
|
||||
"Teraz vyskúšajme rôzne číslice:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Diskusia\n",
|
||||
"\n",
|
||||
"Z nejakého dôvodu nie sú čísla 2 a 5 tak ľahko oddeliteľné. Aj keď dosahujeme pomerne vysokú presnosť (nad 85 %), je zrejmé, že perceptron prestáva v určitom bode učiť.\n",
|
||||
"Z nejakého dôvodu nie sú čísla 2 a 5 tak ľahko oddeliteľné. Aj keď dosahujeme pomerne vysokú presnosť (nad 85 %), je zrejmé, že perceptron prestáva učiť v určitom bode.\n",
|
||||
"\n",
|
||||
"Aby sme pochopili, prečo sa to deje, môžeme použiť [Analýzu hlavných komponentov](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Ide o techniku strojového učenia, ktorá sa používa na zníženie dimenzionality vstupného datasetu tak, aby sa dosiahla čo najlepšia oddeliteľnosť medzi triedami.\n",
|
||||
"\n",
|
||||
"V našom prípade má vstupný obrázok 784 pixelov (vstupných vlastností) a chceme použiť PCA na zníženie počtu parametrov na iba 2, aby sme ich mohli zobraziť na grafe. Tieto dva parametre by boli lineárnou kombináciou pôvodných vlastností a tento postup si môžeme predstaviť ako „otáčanie“ nášho pôvodného 784-dimenzionálneho priestoru a pozorovanie jeho projekcie do 2D priestoru, až kým nezískame najlepší pohľad, ktorý triedy oddeľuje.\n"
|
||||
"V našom prípade má vstupný obrázok 784 pixelov (vstupných vlastností) a chceme použiť PCA na zníženie počtu parametrov na iba 2, aby sme ich mohli vykresliť na grafe. Tieto dva parametre by boli lineárnou kombináciou pôvodných vlastností a tento postup si môžeme predstaviť ako „otáčanie“ nášho pôvodného 784-dimenzionálneho priestoru a pozorovanie jeho projekcie do 2D-priestoru, až kým nezískame najlepší pohľad, ktorý oddeľuje triedy.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,16 +1153,16 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Ako vidíte, čísla 0 a 1 je možné jasne oddeliť priamkou. To naznačuje, že v pôvodnom 784-rozmernom priestore sú body zodpovedajúce čísliciam tiež lineárne oddeliteľné. V prípade číslic 2 a 5 však nemôžeme nájsť vhodnú projekciu, ktorá by číslice jasne oddelila, a preto dochádza k niektorým nesprávnym klasifikáciám.\n",
|
||||
"Ako vidíte, čísla 0 a 1 môžu byť jasne oddelené priamkou. To naznačuje, že v pôvodnom 784-rozmernom priestore sú body zodpovedajúce čísliciam tiež lineárne oddeliteľné. V prípade číslic 2 a 5 však nemôžeme nájsť vhodnú projekciu, ktorá by číslice jasne oddelila, a preto dochádza k niektorým nesprávnym klasifikáciám.\n",
|
||||
"\n",
|
||||
"> Neskôr v tomto kurze sa naučíme, ako vytvárať nelineárne klasifikátory pomocou neurónových sietí a ako riešiť problém nesprávne zarovnaných číslic. Veľmi skoro dosiahneme presnosť nad 99 % pri klasifikácii číslic MNIST, pričom ich budeme klasifikovať do 10 rôznych tried.\n",
|
||||
"> Neskôr v tomto kurze sa naučíme, ako vytvárať nelineárne klasifikátory pomocou neurónových sietí a ako riešiť problém nesprávne zarovnaných číslic. Veľmi skoro dosiahneme presnosť nad 99 % pri klasifikácii číslic MNIST, pričom ich budeme rozdeľovať do 10 rôznych tried.\n",
|
||||
"\n",
|
||||
"## Zhrnutie\n",
|
||||
"\n",
|
||||
" * Naučili sme sa o najjednoduchšej architektúre neurónovej siete – jednovrstvovom perceptrone.\n",
|
||||
" * Implementovali sme perceptron „ručne“ pomocou jednoduchého tréningového postupu založeného na gradientnom zostupe.\n",
|
||||
" * Napriek svojej jednoduchosti dokáže jednovrstvový perceptron riešiť pomerne zložité problémy rozpoznávania ručne písaných číslic.\n",
|
||||
" * Jednovrstvový perceptron je lineárny klasifikátor, a preto poskytuje rovnakú klasifikačnú silu ako logistická regresia.\n",
|
||||
" * Napriek jednoduchosti dokáže jednovrstvový perceptron riešiť pomerne zložité problémy rozpoznávania ručne písaných číslic.\n",
|
||||
" * Jednovrstvový perceptron je lineárny klasifikátor, a preto poskytuje rovnakú klasifikačnú schopnosť ako logistická regresia.\n",
|
||||
" * V priestore vzoriek dokáže perceptron oddeliť dve triedy vstupných dát pomocou hyperroviny.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Upozornenie**: \nTento dokument bol preložený pomocou služby AI prekladu [Co-op Translator](https://github.com/Azure/co-op-translator). Hoci sa snažíme o presnosť, prosím, berte na vedomie, že automatizované preklady môžu obsahovať chyby alebo nepresnosti. Pôvodný dokument v jeho pôvodnom jazyku by mal byť považovaný za autoritatívny zdroj. Pre kritické informácie sa odporúča profesionálny ľudský preklad. Nenesieme zodpovednosť za akékoľvek nedorozumenia alebo nesprávne interpretácie vyplývajúce z použitia tohto prekladu.\n"
|
||||
"\n---\n\n**Zrieknutie sa zodpovednosti**: \nTento dokument bol preložený pomocou služby AI prekladu [Co-op Translator](https://github.com/Azure/co-op-translator). Hoci sa snažíme o presnosť, prosím, berte na vedomie, že automatizované preklady môžu obsahovať chyby alebo nepresnosti. Pôvodný dokument v jeho rodnom jazyku by mal byť považovaný za autoritatívny zdroj. Pre kritické informácie sa odporúča profesionálny ľudský preklad. Nenesieme zodpovednosť za akékoľvek nedorozumenia alebo nesprávne interpretácie vyplývajúce z použitia tohto prekladu.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:43:37+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:31:44+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "sk"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"\n",
|
||||
"> Ta zvezek je del [Učnega načrta za začetnike v AI](http://github.com/microsoft/ai-for-beginners). Obiščite repozitorij za celoten nabor učnih gradiv.\n",
|
||||
"\n",
|
||||
"Kot smo že omenili, perceptron omogoča reševanje **problema binarne klasifikacije**, torej razvrščanje vhodnih primerov v dva razreda - lahko jih imenujemo **pozitivni** in **negativni**.\n",
|
||||
"Kot smo že razpravljali, perceptron omogoča reševanje **problema binarne klasifikacije**, tj. razvrščanje vhodnih primerov v dva razreda - lahko jih imenujemo **pozitivni** in **negativni**.\n",
|
||||
"\n",
|
||||
"Najprej uvozimo nekaj potrebnih knjižnic.\n"
|
||||
]
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Igrača problem\n",
|
||||
"\n",
|
||||
"Za začetek se lotimo igrača problema, kjer imamo dve vhodni značilnosti. Na primer, v medicini želimo razvrstiti tumorje v benigne in maligne, glede na njihovo velikost in starost.\n",
|
||||
"Za začetek se lotimo igrača problema, kjer imamo dve vhodni značilnosti. Na primer, v medicini želimo razvrstiti tumorje v benigne in maligne, odvisno od njihove velikosti in starosti.\n",
|
||||
"\n",
|
||||
"Naključno klasifikacijsko podatkovno zbirko bomo ustvarili z uporabo funkcije `make_classification` iz knjižnice SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Vendar pa bi splošni linearni model moral imeti tudi pristranskost (bias), tj. idealno bi morali $y$ izračunati kot $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Da poenostavimo naš model, se lahko znebimo tega pristranskostnega člena tako, da dodamo še eno dimenzijo našim vhodnim značilnostim, ki je vedno enaka 1:\n"
|
||||
"Vendar pa bi splošni linearni model moral imeti tudi pristranskost (bias), torej bi idealno morali izračunati $y$ kot $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Da poenostavimo naš model, se lahko znebimo tega pristranskostnega člena tako, da dodamo še eno dimenzijo našim vhodnim značilnostim, ki vedno znaša 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -204,7 +204,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Algoritem za učenje\n",
|
||||
"## Algoritem učenja\n",
|
||||
"\n",
|
||||
"Da bi trenirali perceptron, moramo določiti uteži $\\mathbf{w}$, ki bodo minimizirale napako. Napaka je definirana z uporabo **kriterija perceptrona**:\n",
|
||||
"\n",
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ za negativne in pozitivne učne vzorce\n",
|
||||
" * $\\mathcal{M}$ - množica napačno klasificiranih primerov\n",
|
||||
" \n",
|
||||
"Uporabili bomo proces **gradientnega spusta**. Začnemo z začetnimi naključnimi utežmi $\\mathbf{w}^{(0)}$, nato pa na vsakem koraku učenja prilagodimo uteži z uporabo gradienta $E$:\n",
|
||||
"Uporabili bomo proces **gradientnega spusta**. Začnemo z začetnimi naključnimi utežmi $\\mathbf{w}^{(0)}$ in na vsakem koraku učenja prilagodimo uteži z uporabo gradienta $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Opomba o učni stopnji**: Parameter `learning_rate` (privzeto `0.01`) določa, koliko prilagodimo uteži med vsakim korakom učenja. To izvaja formulo za posodobitev gradientnega spusta:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Večja učna stopnja (npr. `1.0`) omogoča hitrejše učenje perceptrona, vendar lahko preseže optimalno rešitev\n",
|
||||
"- Manjša učna stopnja (npr. `0.001`) omogoča počasnejše učenje, vendar lahko natančneje konvergira\n",
|
||||
"- Eksperimentirate lahko z uporabo: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Eksperimentiranje z učnimi hitrostmi\n",
|
||||
"\n",
|
||||
"Zdaj si poglejmo, kako različne učne hitrosti vplivajo na proces učenja. Učna hitrost določa velikost koraka pri gradientnem spustu - ključni hiperparameter, ki vpliva na hitrost konvergence in stabilnost.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktivni eksperiment z učnim korakom\n",
|
||||
"\n",
|
||||
"Uporabite drsnik spodaj za interaktivno preizkušanje različnih učnih korakov in opazujte, kako vplivajo na mejo odločanja:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Ocena na testnem naboru podatkov\n",
|
||||
"\n",
|
||||
"Na začetku smo nekaj podatkov ločili za testni nabor. Poglejmo, kako natančen je naš klasifikator na tem testnem naboru. Da to dosežemo, testni nabor razširimo z dodatno dimenzijo, pomnožimo z matriko uteži in preverimo, ali je pridobljena vrednost istega predznaka kot oznaka (+1 ali -1). Nato seštejemo vse logične vrednosti in jih delimo z dolžino testnega vzorca, da dobimo natančnost:\n"
|
||||
"Na začetku smo nekaj podatkov ločili za testni nabor. Poglejmo, kako natančen je naš klasifikator na tem testnem naboru. Da to preverimo, razširimo testni nabor podatkov z dodatno dimenzijo, pomnožimo z matriko uteži in se prepričamo, da ima pridobljena vrednost enak predznak kot oznaka (+1 ali -1). Nato seštejemo vse logične vrednosti in jih delimo z dolžino testnega vzorca, da dobimo natančnost:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Opazovanje procesa učenja\n",
|
||||
"\n",
|
||||
"Prej smo videli, kako se natančnost zmanjšuje med procesom učenja. Zanimivo bi bilo opazovati, kako se ločilna črta spreminja med učenjem. Spodnja koda bo vse prikazala na enem grafu, kjer boste lahko premikali drsnik in \"potovali skozi čas\" med procesom učenja.\n"
|
||||
"Prej smo videli, kako se natančnost zmanjšuje med procesom učenja. Lepo bi bilo videti, kako se ločilna črta spreminja med učenjem. Spodnja koda bo vse prikazala na enem grafu, vi pa boste lahko premikali drsnik, da \"potujete skozi čas\" med procesom učenja.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -607,13 +733,13 @@
|
|||
"source": [
|
||||
"Kot lahko vidite iz zgornjega grafa, natančnost nikoli ne preseže 75 %, saj je nemogoče narisati ravno črto tako, da bi pravilno zajeli vse primere.\n",
|
||||
"\n",
|
||||
"Problem XOR je klasičen primer omejitev perceptrona, na kar sta leta 1969 opozorila Marvin Minsky in Seymour Papert v svoji knjigi [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). To opažanje je skoraj 10 let omejevalo raziskave na področju nevronskih mrež, čeprav - kot bomo videli v naslednjem delu našega tečaja - večplastni perceptroni zlahka rešujejo takšne probleme.\n",
|
||||
"Problem XOR je klasičen primer omejitev perceptrona, na kar sta leta 1969 opozorila Marvin Minsky in Seymour Papert v svoji knjigi [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). To opažanje je za skoraj 10 let omejilo raziskave na področju nevronskih mrež, čeprav - kot bomo videli v naslednjem delu našega tečaja - večplastni perceptroni zlahka rešujejo takšne probleme.\n",
|
||||
"\n",
|
||||
"## Kompleksen primer - MNIST\n",
|
||||
"\n",
|
||||
"Čeprav perceptron ne more rešiti problema XOR, lahko rešuje veliko bolj kompleksne probleme, kot je prepoznavanje ročno napisanih znakov.\n",
|
||||
"Čeprav perceptron ne more rešiti problema XOR, lahko reši veliko bolj kompleksne probleme, kot je prepoznavanje ročno napisanih znakov.\n",
|
||||
"\n",
|
||||
"Podatkovni niz, ki se pogosto uporablja pri učenju strojnega učenja, se imenuje [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Ustvaril ga je Modified National Institute of Standards and Technology in vsebuje učni niz 60.000 ročno napisanih številk, zbranih od približno 250 študentov in zaposlenih na inštitutu. Obstaja tudi testni podatkovni niz s 10.000 številkami, zbranimi od različnih posameznikov.\n",
|
||||
"Podatkovni niz, ki se pogosto uporablja pri učenju strojnega učenja, se imenuje [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Ustvaril ga je spremenjeni Nacionalni inštitut za standarde in tehnologijo (Modified National Institute of Standards and Technology) ter vsebuje učni niz 60.000 ročno napisanih številk, zbranih od približno 250 študentov in zaposlenih na inštitutu. Obstaja tudi testni podatkovni niz s 10.000 številkami, zbranimi od različnih posameznikov.\n",
|
||||
"\n",
|
||||
"Vse številke so predstavljene kot sivinske slike velikosti 28x28 pik.\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Ker je perceptron binarni klasifikator, bomo našo težavo omejili na prepoznavanje samo dveh številk. Spodnja funkcija bo napolnila pozitivne in negativne vzorčne tabele z dvema danima številkama (in bo za jasnost prikazala tudi vzorce teh številk).\n"
|
||||
"Ker je perceptron binarni klasifikator, bomo našo težavo omejili na prepoznavanje samo dveh številk. Spodnja funkcija bo napolnila pozitivne in negativne vzorčne matrike z dvema danima številkama (in bo za jasnost prikazala tudi vzorce teh številk).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,11 +959,11 @@
|
|||
"source": [
|
||||
"Upoštevajte, kako natančnost zelo hitro naraste skoraj do 100 %.\n",
|
||||
"\n",
|
||||
"Prosimo, premaknite drsnik na položaj proti koncu učenja in opazujte matriko uteži, prikazano na levi. Ta matrika vam bo omogočila razumeti, kako perceptron dejansko deluje. Vidite lahko visoke vrednosti uteži na sredini polja, ki ustrezajo pikslom, ki so običajno prisotni pri številki 1, ter nizke negativne vrednosti ob straneh, kjer so deli številke 0. Torej, če je številka, predstavljena perceptronu, dejansko 1, bo njen srednji del pomnožen z visokimi vrednostmi, kar bo dalo pozitiven rezultat. Nasprotno pa, ko perceptron opazuje številko 0, bodo ustrezni piksli pomnoženi z negativnimi številkami.\n",
|
||||
"Prosimo, premaknite drsnik proti koncu usposabljanja in opazujte matriko uteži, prikazano na levi. Ta matrika vam bo omogočila, da razumete, kako perceptron dejansko deluje. Vidite lahko visoke vrednosti uteži na sredini polja, ki ustrezajo pikslom, ki so običajno prisotni pri številki 1, ter nizke negativne vrednosti ob straneh, kjer so deli številke 0. Torej, če je številka, predstavljena perceptronu, dejansko 1, bo njen srednji del pomnožen z visokimi vrednostmi, kar bo dalo pozitiven rezultat. Nasprotno pa, ko perceptron opazuje številko 0, bodo ustrezni piksli pomnoženi z negativnimi številkami.\n",
|
||||
"\n",
|
||||
"> Opazite lahko, da če perceptronu podamo številko 1, ki je rahlo premaknjena horizontalno, tako da njeni piksli zasedajo mesto, kjer so vertikalni deli številke 0, lahko dobimo napačen rezultat. Narava našega MNIST nabora podatkov je namreč takšna, da so vse številke centrirane in pravilno pozicionirane, perceptron pa se zanaša na to, da razlikuje med številkami.\n",
|
||||
"\n",
|
||||
"Zdaj poskusimo različne številke:\n"
|
||||
"Zdaj poskusimo z različnimi številkami:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -915,7 +1041,7 @@
|
|||
"\n",
|
||||
"Iz nekega razloga 2 in 5 nista tako enostavno ločljivi. Čeprav dosežemo razmeroma visoko natančnost (nad 85 %), lahko jasno opazimo, kako perceptron na neki točki preneha učiti.\n",
|
||||
"\n",
|
||||
"Da bi razumeli, zakaj se to zgodi, lahko poskusimo uporabiti [analizo glavnih komponent](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). To je tehnika strojnega učenja, ki se uporablja za zmanjšanje dimenzionalnosti vhodnega nabora podatkov na način, da dosežemo najboljšo ločljivost med razredi.\n",
|
||||
"Da bi razumeli, zakaj se to zgodi, lahko poskusimo uporabiti [Glavno komponentno analizo](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). To je tehnika strojnega učenja, ki se uporablja za zmanjšanje dimenzionalnosti vhodnega nabora podatkov, tako da dosežemo najboljšo ločljivost med razredi.\n",
|
||||
"\n",
|
||||
"V našem primeru ima vhodna slika 784 pikslov (vhodnih značilnosti), mi pa želimo uporabiti PCA, da zmanjšamo število parametrov na samo 2, da jih lahko prikažemo na grafu. Ti dva parametra bi bila linearna kombinacija izvirnih značilnosti, ta postopek pa si lahko predstavljamo kot \"vrtenje\" našega izvirnega 784-dimenzionalnega prostora in opazovanje njegove projekcije v 2D-prostor, dokler ne dobimo najboljše perspektive, ki ločuje razrede.\n"
|
||||
]
|
||||
|
|
@ -1027,13 +1153,13 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Kot lahko vidite, je mogoče 0 in 1 jasno ločiti z ravno črto. To kaže, da so v prvotnem 784-dimenzionalnem prostoru točke, ki ustrezajo številkam, tudi linearno ločljive. V primeru 2 in 5 pa ne moremo najti dobre projekcije, ki bi jasno ločila številke, zato pride do nekaterih primerov napačne klasifikacije.\n",
|
||||
"Kot lahko vidite, 0 in 1 je mogoče jasno ločiti z ravno črto. To kaže, da so v prvotnem 784-dimenzionalnem prostoru točke, ki ustrezajo številkam, tudi linearno ločljive. V primeru 2 in 5 pa ne moremo najti dobre projekcije, ki bi številke jasno ločila, zato pride do nekaterih primerov napačne klasifikacije.\n",
|
||||
"\n",
|
||||
"> Kasneje v tem tečaju se bomo naučili, kako ustvariti nelinearne klasifikatorje z uporabo nevronskih mrež in kako se spopasti s težavo, ko številke niso pravilno poravnane. Zelo kmalu bomo dosegli več kot 99 % natančnost pri klasifikaciji številk MNIST, medtem ko jih bomo razvrščali v 10 različnih razredov.\n",
|
||||
"\n",
|
||||
"## Ključne točke\n",
|
||||
"\n",
|
||||
" * Naučili smo se o najpreprostejši arhitekturi nevronske mreže - enoslojnem perceptronu.\n",
|
||||
" * Spoznali smo najpreprostejšo arhitekturo nevronske mreže - enoslojni perceptron.\n",
|
||||
" * Perceptron smo implementirali \"ročno\" z uporabo preprostega postopka učenja, ki temelji na gradientnem spustu.\n",
|
||||
" * Kljub preprostosti lahko enoslojni perceptron reši precej zapletene probleme prepoznavanja ročno napisanih številk.\n",
|
||||
" * Enoslojni perceptron je linearni klasifikator, zato ponuja enako klasifikacijsko moč kot logistična regresija.\n",
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Zasluge\n",
|
||||
"\n",
|
||||
"Ta zvezek je del [Učnega načrta za začetnike v AI](http://github.com/microsoft/ai-for-beginners) in ga je pripravil [Dmitry Soshnikov](http://soshnikov.com). Navdih je črpal iz delavnice o nevronskih mrežah v Microsoft Research Cambridge. Nekatera koda in ilustrativni materiali so vzeti iz predstavitev [Katje Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthewa Johnsona](https://www.microsoft.com/en-us/research/people/matjoh/) in [Ryota Tomioke](https://www.microsoft.com/en-us/research/people/ryoto/), ter iz repozitorija [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Ta zvezek je del [Učnega načrta AI za začetnike](http://github.com/microsoft/ai-for-beginners) in ga je pripravil [Dmitry Soshnikov](http://soshnikov.com). Navdih je črpal iz delavnice o nevronskih mrežah v Microsoft Research Cambridge. Nekatera koda in ilustrativni materiali so vzeti iz predstavitev [Katje Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthewa Johnsona](https://www.microsoft.com/en-us/research/people/matjoh/) in [Ryota Tomioke](https://www.microsoft.com/en-us/research/people/ryoto/), ter iz repozitorija [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Omejitev odgovornosti**: \nTa dokument je bil preveden z uporabo storitve AI za prevajanje [Co-op Translator](https://github.com/Azure/co-op-translator). Čeprav si prizadevamo za natančnost, vas prosimo, da upoštevate, da lahko avtomatizirani prevodi vsebujejo napake ali netočnosti. Izvirni dokument v njegovem maternem jeziku je treba obravnavati kot avtoritativni vir. Za ključne informacije priporočamo profesionalni človeški prevod. Ne prevzemamo odgovornosti za morebitna nesporazumevanja ali napačne razlage, ki izhajajo iz uporabe tega prevoda.\n"
|
||||
"\n---\n\n**Omejitev odgovornosti**: \nTa dokument je bil preveden z uporabo storitve AI za prevajanje [Co-op Translator](https://github.com/Azure/co-op-translator). Čeprav si prizadevamo za natančnost, vas prosimo, da upoštevate, da lahko avtomatizirani prevodi vsebujejo napake ali netočnosti. Izvirni dokument v njegovem maternem jeziku naj se šteje za avtoritativni vir. Za ključne informacije priporočamo profesionalni človeški prevod. Ne odgovarjamo za morebitne nesporazume ali napačne razlage, ki izhajajo iz uporabe tega prevoda.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:48:41+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:37:06+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "sl"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Проблем играчке\n",
|
||||
"\n",
|
||||
"За почетак, хајде да кренемо са проблемом играчке, где имамо две улазне карактеристике. На пример, у медицини можемо желети да класификујемо туморе као бенигне и малигне, у зависности од њихове величине и старости.\n",
|
||||
"За почетак, хајде да кренемо са једноставним проблемом, где имамо две улазне карактеристике. На пример, у медицини можемо желети да класификујемо туморе као бенигне и малигне, у зависности од њихове величине и старости.\n",
|
||||
"\n",
|
||||
"Генерисаћемо насумични класификациони скуп података користећи функцију `make_classification` из библиотеке SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -158,7 +158,7 @@
|
|||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"где је $\\mathbf{w}$ вектор тежина, а $f$ је функција активације типа корак:\n",
|
||||
"где је $\\mathbf{w}$ вектор тежина, а $f$ је функција активације типа степен:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Међутим, општи линеарни модел би требало да има и пристрасност (bias), тј. идеално би требало да рачунамо $y$ као $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Да бисмо поједноставили наш модел, можемо уклонити овај термин пристрасности додавањем још једне димензије нашим улазним карактеристикама, која увек има вредност 1:\n"
|
||||
"Међутим, општи линеарни модел би требало да има и пристрасност (bias), тј. идеално би требало да рачунамо $y$ као $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Да бисмо поједноставили наш модел, можемо елиминисати овај термин пристрасности додавањем још једне димензије нашим улазним карактеристикама, која увек има вредност 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ за негативне и позитивне узорке за тренирање, респективно\n",
|
||||
" * $\\mathcal{M}$ - скуп погрешно класификованих примера\n",
|
||||
" \n",
|
||||
"Користићемо процес **градијентског спуштања**. Почевши од неких почетних насумичних тежина $\\mathbf{w}^{(0)}$, прилагођаваћемо тежине на сваком кораку тренинга користећи градијент $E$:\n",
|
||||
"Користићемо процес **градијентског спуштања**. Почевши од неких почетних случајних тежина $\\mathbf{w}^{(0)}$, прилагођаваћемо тежине на сваком кораку тренинга користећи градијент $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Напомена о стопи учења**: Параметар `learning_rate` (подразумевано `0.01`) контролише колико прилагођавамо тежине током сваког корака тренинга. Ово примењује формулу ажурирања градијентног спуштања:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Већа стопа учења (нпр. `1.0`) омогућава перцептрону да брже учи, али може прелазити оптимално решење\n",
|
||||
"- Мања стопа учења (нпр. `0.001`) учи спорије, али може прецизније конвергирати\n",
|
||||
"- Можете експериментисати позивањем: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Експериментисање са брзинама учења\n",
|
||||
"\n",
|
||||
"Сада ћемо истражити како различите брзине учења утичу на процес тренирања. Брзина учења контролише величину корака у градијентском спуштању - кључни хиперпараметар који утиче на брзину конвергенције и стабилност.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Интерактивни експеримент са стопом учења\n",
|
||||
"\n",
|
||||
"Користите клизач испод да интерактивно експериментишете са различитим стопама учења и видите како оне утичу на границу одлуке:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Тестирање на тест датасету\n",
|
||||
"\n",
|
||||
"На почетку смо издвојили део података за тест датасет. Хајде да видимо колико је наш класификатор тачан на овом тест датасету. Да бисмо то урадили, проширујемо тест датасет са додатном димензијом, множимо га са матрицом тежина и проверавамо да ли добијена вредност има исти знак као и ознака (+1 или -1). Затим сабирамо све булове вредности и делимо их са дужином тест узорка како бисмо добили тачност:\n"
|
||||
"На почетку смо издвојили део података за тест датасет. Хајде да видимо колико је наш класификатор тачан на овом тест датасету. Да бисмо то урадили, проширујемо тест датасет са додатном димензијом, множимо са матрицом тежина и проверавамо да ли добијена вредност има исти знак као и ознака (+1 или -1). Затим сабирамо све булове вредности и делимо са дужином тест узорка како бисмо добили тачност:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -420,9 +546,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Посматрање процеса тренинга\n",
|
||||
"## Посматрање процеса обуке\n",
|
||||
"\n",
|
||||
"Видели смо раније како се тачност смањује током тренинга. Било би занимљиво видети како се линија раздвајања понаша током тренинга. Код испод ће визуализовати све на једном графику, и требало би да можете да померате клизач како бисте \"путовали кроз време\" током процеса тренинга.\n"
|
||||
"Видели смо раније како се тачност смањује током обуке. Било би занимљиво видети како се линија раздвајања понаша током обуке. Код испод ће све визуализовати на једном графику, а требало би да можете да померате клизач како бисте \"путовали кроз време\" током процеса обуке.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -605,21 +731,21 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Као што можете видети из графика изнад, тачност никада не прелази 75%, јер је немогуће нацртати праву линију тако да се сви могући примери реше исправно.\n",
|
||||
"Као што можете видети из графика изнад, тачност никада не прелази 75%, јер је немогуће повући праву линију тако да се сви могући примери реше исправно.\n",
|
||||
"\n",
|
||||
"Проблем XOR је класичан пример ограничења перцептрона, а на њега су указали Марвин Мински и Симор Паперт 1969. године у својој књизи [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Ово запажање је ограничило истраживања у области неуронских мрежа скоро 10 година, иако - као што ћемо видети у следећем делу нашег курса - перцептрони са више слојева могу савршено решити овакве проблеме.\n",
|
||||
"\n",
|
||||
"## Комплексни пример - MNIST\n",
|
||||
"\n",
|
||||
"Иако перцептрон не може решити проблем XOR, он може решити много сложеније проблеме, као што је препознавање руком писаних карактера.\n",
|
||||
"Иако перцептрон не може решити XOR проблем, он може решити много сложеније проблеме, као што је препознавање руком писаних карактера.\n",
|
||||
"\n",
|
||||
"Скуп података који се често користи приликом савладавања машинског учења назива се [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Направљен је од стране Модификованог Националног института за стандарде и технологију и садржи скуп за обуку од 60.000 руком писаних цифара, прикупљених од око 250 студената и запослених у институту. Постоји и тестни скуп података од 10.000 цифара, прикупљених од различитих особа.\n",
|
||||
"Скуп података који се често користи приликом савладавања машинског учења назива се [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Овај скуп је креиран од стране Модификованог Националног института за стандарде и технологију и садржи скуп за обуку од 60.000 руком писаних цифара, прикупљених од око 250 студената и запослених у институту. Постоји и тестни скуп података од 10.000 цифара, прикупљених од различитих особа.\n",
|
||||
"\n",
|
||||
"Све цифре су представљене сликама у нијансама сиве величине 28x28 пиксела.\n",
|
||||
"\n",
|
||||
"> Скуп података MNIST је доступан као такмичење за обуку на [Kaggle](https://www.kaggle.com/c/digit-recognizer), сајту који организује такмичења и конкурсе у машинском учењу. Када научите како да класификујете MNIST цифре, можете послати своје решење на Kaggle да видите како је оцењено међу осталим учесницима.\n",
|
||||
"> MNIST скуп података је доступан као такмичење за обуку на [Kaggle](https://www.kaggle.com/c/digit-recognizer), сајту који организује такмичења и конкурсе у машинском учењу. Када научите како да класификујете MNIST цифре, можете послати своје решење на Kaggle да видите како је оцењено међу осталим учесницима.\n",
|
||||
"\n",
|
||||
"Почињемо учитавањем скупа података MNIST:\n"
|
||||
"Почињемо учитавањем MNIST скупа података:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,7 +959,7 @@
|
|||
"source": [
|
||||
"Молимо вас да обратите пажњу како тачност веома брзо достиже скоро 100%.\n",
|
||||
"\n",
|
||||
"Молимо вас, померите клизач на неку позицију према крају тренинга и посматрајте матрицу тежина приказану са леве стране. Ова матрица ће вам омогућити да разумете како перцептрон заправо функционише. Можете видети високе вредности тежина у средини поља, које одговарају пикселима који су типично присутни за цифру 1, и ниске негативне вредности са стране, где се налазе делови цифре 0. Дакле, ако је цифра представљена перцептрону заиста 1, њен средишњи део ће бити помножен високим вредностима, што ће произвести позитиван резултат. Насупрот томе, када перцептрон посматра цифру 0, одговарајући пиксели ће бити помножени негативним бројевима.\n",
|
||||
"Молимо вас, померите клизач на неку позицију према крају тренинга и посматрајте матрицу тежина приказану са леве стране. Ова матрица ће вам омогућити да разумете како перцептрон заправо функционише. Можете видети високе вредности тежина у средини поља, које одговарају пикселима који су обично присутни за цифру 1, и ниске негативне вредности са стране, где се налазе делови цифре 0. Дакле, ако је цифра представљена перцептрону заиста 1, њен средишњи део ће бити помножен високим вредностима, што ће произвести позитиван резултат. Насупрот томе, када перцептрон посматра цифру 0, одговарајући пиксели ће бити помножени негативним бројевима.\n",
|
||||
"\n",
|
||||
"> Можете приметити да ако нашем перцептрону дамо цифру 1 која је благо померена хоризонтално, тако да њени пиксели заузимају место где се налазе вертикални делови цифре 0, можемо добити нетачан резултат. Пошто је природа нашег MNIST скупа података таква да су све цифре центриране и правилно позициониране, перцептрон се ослања на то како би разликовао цифре.\n",
|
||||
"\n",
|
||||
|
|
@ -917,7 +1043,7 @@
|
|||
"\n",
|
||||
"Да бисмо разумели зашто се то дешава, можемо покушати да користимо [Анализу главних компоненти](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). То је техника машинског учења која се користи за смањење димензионалности улазног скупа података, на начин који омогућава најбољу раздвојивост између класа.\n",
|
||||
"\n",
|
||||
"У нашем случају, улазна слика има 784 пиксела (улазне карактеристике), а ми желимо да користимо PCA како бисмо смањили број параметара на само 2, тако да их можемо приказати на графику. Та два параметра би била линеарна комбинација оригиналних карактеристика, а овај процес можемо посматрати као \"ротацију\" нашег оригиналног 784-димензионалног простора и посматрање његове пројекције на наш 2Д-простор, све док не добијемо најбољи приказ који раздваја класе.\n"
|
||||
"У нашем случају, улазна слика има 784 пиксела (улазне карактеристике), а ми желимо да користимо PCA како бисмо смањили број параметара на само 2, тако да их можемо приказати на графику. Та два параметра би била линеарна комбинација оригиналних карактеристика, а овај поступак можемо посматрати као \"ротацију\" нашег оригиналног 784-димензионалног простора и посматрање његове пројекције на наш 2D-простор, све док не добијемо најбољи приказ који раздваја класе.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1029,12 +1155,12 @@
|
|||
"source": [
|
||||
"Као што можете видети, 0 и 1 могу бити јасно раздвојени правом линијом. Ово указује да су у оригиналном 784-димензионалном простору тачке које одговарају цифрама такође линеарно раздвојиве. У случају цифара 2 и 5, не можемо пронаћи добру пројекцију која ће јасно раздвојити цифре, и због тога постоје случајеви погрешне класификације.\n",
|
||||
"\n",
|
||||
"> Касније у овом курсу ћемо научити како да креирамо нелинеарне класификаторе користећи неуронске мреже, и како да решимо проблем цифара које нису правилно поравнате. Ускоро ћемо достићи тачност изнад 99% у класификацији цифара из MNIST скупа, класификујући их у 10 различитих класа.\n",
|
||||
"> Касније на овом курсу ћемо научити како да креирамо нелинеарне класификаторе користећи неуронске мреже, и како да решимо проблем цифара које нису правилно поравнате. Врло брзо ћемо достићи тачност изнад 99% у класификацији цифара из MNIST скупа, док их класификујемо у 10 различитих класа.\n",
|
||||
"\n",
|
||||
"## Закључак\n",
|
||||
"\n",
|
||||
" * Научили смо о најједноставнијој архитектури неуронске мреже - једнослојном перцептрону.\n",
|
||||
" * Имплементирали смо перцептрон \"ручно\", користећи једноставну процедуру тренирања засновану на градијентском спуштању.\n",
|
||||
" * Имплементирали смо перцептрон \"ручно\", користећи једноставну процедуру тренирања засновану на градијентном спуштању.\n",
|
||||
" * Упркос једноставности, једнослојни перцептрон може решити прилично сложене проблеме препознавања руком писаних цифара.\n",
|
||||
" * Једнослојни перцептрон је линеарни класификатор, и стога пружа исту моћ класификације као логистичка регресија.\n",
|
||||
" * У простору узорака, перцептрон може раздвојити две класе улазних података користећи хиперплан.\n"
|
||||
|
|
@ -1044,16 +1170,16 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Захвалнице\n",
|
||||
"## Кредити\n",
|
||||
"\n",
|
||||
"Овај нотебук је део [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), и припремио га је [Дмитриј Сошњиков](http://soshnikov.com). Инспирисан је радионицом о неуронским мрежама у Microsoft Research Cambridge. Део кода и илустративних материјала преузет је из презентација [Катје Хофман](https://www.microsoft.com/en-us/research/people/kahofman/), [Метјуа Џонсона](https://www.microsoft.com/en-us/research/people/matjoh/) и [Рјота Томиоке](https://www.microsoft.com/en-us/research/people/ryoto/), као и из репозиторијума [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Овај нотебук је део [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), и припремио га је [Дмитриј Сошњиков](http://soshnikov.com). Инспирисан је радионицом о неуронским мрежама у Microsoft Research Cambridge. Неки код и илустративни материјали преузети су из презентација [Катје Хофман](https://www.microsoft.com/en-us/research/people/kahofman/), [Метјуа Џонсона](https://www.microsoft.com/en-us/research/people/matjoh/) и [Рјота Томиоке](https://www.microsoft.com/en-us/research/people/ryoto/), као и из репозиторијума [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Одрицање од одговорности**: \nОвај документ је преведен помоћу услуге за превођење уз помоћ вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако се трудимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу произаћи из коришћења овог превода.\n"
|
||||
"\n---\n\n**Одрицање од одговорности**: \nОвај документ је преведен помоћу услуге за превођење вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако се трудимо да обезбедимо тачност, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу произаћи из коришћења овог превода.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:46:46+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:35:01+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "sr"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"> Den här anteckningsboken är en del av [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Besök repot för att få tillgång till hela uppsättningen av läromaterial.\n",
|
||||
"> Den här anteckningsboken är en del av [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Besök arkivet för en komplett uppsättning läromaterial.\n",
|
||||
"\n",
|
||||
"Som vi har diskuterat, gör perceptron det möjligt att lösa **binära klassificeringsproblem**, det vill säga att klassificera indataexempel i två klasser - vi kan kalla dem **positiva** och **negativa**.\n",
|
||||
"\n",
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## Leksaksproblem\n",
|
||||
"\n",
|
||||
"Låt oss börja med ett leksaksproblem där vi har två indatafunktioner. Till exempel, inom medicin kanske vi vill klassificera tumörer som godartade eller elakartade, beroende på deras storlek och ålder.\n",
|
||||
"Till att börja med, låt oss börja med ett leksaksproblem där vi har två indatafunktioner. Till exempel, inom medicin kanske vi vill klassificera tumörer som godartade eller elakartade, beroende på deras storlek och ålder.\n",
|
||||
"\n",
|
||||
"Vi kommer att generera en slumpmässig klassificeringsdataset med hjälp av funktionen `make_classification` från SciKit Learn-biblioteket:\n"
|
||||
]
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"Eftersom perceptron är en binär klassificerare, kommer utdata för varje inmatningsvektor $x$ från vår perceptron att vara antingen +1 eller -1, beroende på klass. Utdata beräknas med formeln\n",
|
||||
"Eftersom perceptron är en binär klassificerare, kommer utdata för varje ingångsvektor $x$ från vår perceptron att vara antingen +1 eller -1, beroende på klass. Utdata beräknas med formeln\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"En generell linjär modell bör dock också ha en bias, dvs. idealt bör vi beräkna $y$ som $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. För att förenkla vår modell kan vi eliminera denna bias-term genom att lägga till en extra dimension till våra inmatningsfunktioner, som alltid är lika med 1:\n"
|
||||
"En generell linjär modell bör dock också ha en bias, det vill säga att vi idealt sett borde beräkna $y$ som $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. För att förenkla vår modell kan vi eliminera denna bias-term genom att lägga till en extra dimension till våra ingångsfunktioner, som alltid är lika med 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -272,7 +272,20 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Nu kör vi träningen på vår dataset:\n"
|
||||
"**Notering om inlärningshastighet**: Parametern `learning_rate` (standardvärde `0.01`) styr hur mycket vi justerar vikterna under varje träningssteg. Detta implementerar uppdateringsformeln för gradientnedstigning:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- En högre inlärningshastighet (t.ex. `1.0`) gör att perceptronen lär sig snabbare men kan överskrida den optimala lösningen\n",
|
||||
"- En lägre inlärningshastighet (t.ex. `0.001`) lär sig långsammare men kan konvergera mer exakt\n",
|
||||
"- Du kan experimentera genom att kalla: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Nu låt oss köra träningen på vår dataset:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Som du kan se är den initiala noggrannheten runt 50 %, men den ökar snabbt till högre värden nära 90 %.\n",
|
||||
"\n",
|
||||
"Låt oss visualisera hur klasserna separeras. Vår klassificeringsfunktion ser ut som $\\mathbf{w}^Tx$, och den är större än 0 för en klass och mindre än 0 för en annan. Därför definieras klassens separationslinje av $\\mathbf{w}^Tx = 0$. Eftersom vi bara har två dimensioner $x_0$ och $x_1$, skulle ekvationen för linjen vara $w_0x_0+w_1x_1+w_2 = 0$ (kom ihåg att vi uttryckligen har definierat en extra dimension $x_2=1$). Låt oss plotta denna linje:\n"
|
||||
"Låt oss visualisera hur klasserna separeras. Vår klassificeringsfunktion ser ut som $\\mathbf{w}^Tx$, och den är större än 0 för en klass och mindre än 0 för en annan. Därför definieras klassens separationslinje av $\\mathbf{w}^Tx = 0$. Eftersom vi bara har två dimensioner $x_0$ och $x_1$, skulle ekvationen för linjen vara $w_0x_0+w_1x_1+w_2 = 0$ (kom ihåg att vi uttryckligen har definierat en extra dimension $x_2=1$). Låt oss rita upp denna linje:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Experimentera med inlärningshastigheter\n",
|
||||
"\n",
|
||||
"Nu ska vi undersöka hur olika inlärningshastigheter påverkar träningsprocessen. Inlärningshastigheten styr steglängden i gradientnedstigningen - en viktig hyperparameter som påverkar både konvergenshastighet och stabilitet.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Interaktivt experiment med inlärningshastighet\n",
|
||||
"\n",
|
||||
"Använd reglaget nedan för att interaktivt experimentera med olika inlärningshastigheter och se hur de påverkar beslutsgränsen:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Observera träningsprocessen\n",
|
||||
"\n",
|
||||
"Vi har tidigare sett hur noggrannheten minskar under träningen. Det skulle vara intressant att se hur separationslinjen beter sig under träningen. Koden nedan kommer att visualisera allt på en graf, och du ska kunna flytta reglaget för att \"resa i tiden\" genom träningsprocessen.\n"
|
||||
"Vi har tidigare sett hur noggrannheten minskar under träningen. Det skulle vara intressant att se hur separationslinjen beter sig under träningen. Koden nedan kommer att visualisera allt på en enda graf, och du ska kunna flytta reglaget för att \"resa i tiden\" genom träningsprocessen.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -538,7 +664,7 @@
|
|||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Låt oss försöka göra det! Vi kommer manuellt att fylla i alla positiva och negativa träningsprover och sedan kalla på vår träningsfunktion som definierades ovan:\n"
|
||||
"Låt oss försöka göra det! Vi kommer manuellt att fylla i alla positiva och negativa träningsprover och sedan kalla på vår träningsfunktion som definierats ovan:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,7 +959,7 @@
|
|||
"source": [
|
||||
"Observera hur noggrannheten snabbt når nästan 100%.\n",
|
||||
"\n",
|
||||
"Flytta reglaget till en position mot slutet av träningen och titta på viktmatrisen som visas till vänster. Denna matris hjälper dig att förstå hur perceptronen faktiskt fungerar. Du kan se höga viktvärden i mitten av fältet, vilket motsvarar pixlar som vanligtvis finns för siffran 1, och låga negativa värden vid kanterna, där delar av siffran 0 finns. Så om siffran som presenteras för perceptronen faktiskt är 1, kommer mitten av den att multipliceras med höga värden, vilket ger ett positivt resultat. Däremot, när perceptronen observerar siffran 0, kommer motsvarande pixlar att multipliceras med negativa tal.\n",
|
||||
"Flytta reglaget till en position mot slutet av träningen och titta på viktmatrisen som visas till vänster. Denna matris hjälper dig att förstå hur perceptronen faktiskt fungerar. Du kan se höga viktvärden i mitten av fältet, vilket motsvarar pixlar som vanligtvis finns för siffran 1, och låga negativa värden vid sidorna, där delar av siffran 0 finns. Så om siffran som presenteras för perceptronen faktiskt är 1, kommer dess mittdel att multipliceras med höga värden, vilket ger ett positivt resultat. Däremot, när perceptronen observerar siffran 0, kommer motsvarande pixlar att multipliceras med negativa tal.\n",
|
||||
"\n",
|
||||
"> Du kanske märker att om vi ger vår perceptron en siffra 1 som är något förskjuten horisontellt, så att dess pixlar hamnar där de vertikala delarna av siffran 0 finns, kan vi få ett felaktigt resultat. Eftersom MNIST-datasetet är utformat så att alla siffror är centrerade och korrekt positionerade, förlitar sig perceptronen på detta för att skilja mellan siffrorna.\n",
|
||||
"\n",
|
||||
|
|
@ -915,7 +1041,7 @@
|
|||
"\n",
|
||||
"Av någon anledning är 2 och 5 inte lika lätt att separera. Även om vi får relativt hög noggrannhet (över 85%) kan vi tydligt se hur perceptronen slutar lära sig vid en viss punkt.\n",
|
||||
"\n",
|
||||
"För att förstå varför detta händer kan vi försöka använda [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Det är en maskininlärningsteknik som används för att minska dimensionerna i inmatningsdatamängden, på ett sätt som ger bästa möjliga separabilitet mellan klasser.\n",
|
||||
"För att förstå varför detta händer kan vi försöka använda [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Det är en maskininlärningsteknik som används för att minska dimensionerna i inmatningsdatasetet, på ett sätt som ger bästa möjliga separabilitet mellan klasser.\n",
|
||||
"\n",
|
||||
"I vårt fall har en inmatningsbild 784 pixlar (inmatningsfunktioner), och vi vill använda PCA för att minska antalet parametrar till bara 2, så att vi kan plotta dem på en graf. Dessa två parametrar skulle vara en linjär kombination av de ursprungliga funktionerna, och vi kan se denna procedur som att \"rotera\" vårt ursprungliga 784-dimensionella utrymme och observera dess projektion till vårt 2D-utrymme, tills vi får den bästa vyn som separerar klasserna.\n"
|
||||
]
|
||||
|
|
@ -1029,14 +1155,14 @@
|
|||
"source": [
|
||||
"Som du kan se kan 0 och 1 tydligt separeras med en rak linje. Detta indikerar att punkterna som motsvarar siffror i det ursprungliga 784-dimensionella rummet också är linjärt separerbara. När det gäller 2 och 5 kan vi inte hitta en bra projektion som separerar siffrorna tydligt, och därför finns det vissa fall av felaktig klassificering.\n",
|
||||
"\n",
|
||||
"> Senare i den här kursen kommer vi att lära oss hur man skapar icke-linjära klassificerare med hjälp av neurala nätverk, och hur man hanterar problemet med siffror som inte är korrekt justerade. Mycket snart kommer vi att nå över 99 % noggrannhet i klassificeringen av MNIST-siffror, samtidigt som vi klassificerar dem i 10 olika klasser.\n",
|
||||
"> Senare i den här kursen kommer vi att lära oss hur man skapar icke-linjära klassificerare med hjälp av neurala nätverk, och hur man hanterar problemet med siffror som inte är korrekt justerade. Mycket snart kommer vi att nå över 99 % noggrannhet i MNIST-sifferklassificering, samtidigt som vi klassificerar dem i 10 olika klasser.\n",
|
||||
"\n",
|
||||
"## Slutsatser\n",
|
||||
"\n",
|
||||
" * Vi har lärt oss om den enklaste neurala nätverksarkitekturen - enlagers perceptron.\n",
|
||||
" * Vi har implementerat perceptronen \"för hand\", med hjälp av en enkel träningsprocedur baserad på gradientnedstigning.\n",
|
||||
" * Trots sin enkelhet kan enlagers perceptron lösa ganska komplexa problem med igenkänning av handskrivna siffror.\n",
|
||||
" * Enlagers perceptron är en linjär klassificerare och har därför samma klassificeringsförmåga som logistisk regression.\n",
|
||||
" * Vi har implementerat perceptronen \"för hand\", med en enkel träningsprocedur baserad på gradientnedstigning.\n",
|
||||
" * Trots sin enkelhet kan enlagers perceptron lösa ganska komplexa problem med handskriven sifferigenkänning.\n",
|
||||
" * Enlagers perceptron är en linjär klassificerare och erbjuder därmed samma klassificeringsförmåga som logistisk regression.\n",
|
||||
" * I det ursprungliga rummet kan perceptronen separera två klasser av indata med hjälp av ett hyperplan.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:30:44+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:18:27+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "sv"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
"\n",
|
||||
"Kuanza, hebu tuanze na tatizo la msingi, ambapo tuna vipengele viwili vya ingizo. Kwa mfano, katika tiba tunaweza kutaka kuainisha uvimbe kuwa wa kawaida au hatari, kulingana na ukubwa wake na umri.\n",
|
||||
"\n",
|
||||
"Tutazalisha seti ya data ya uainishaji kwa kutumia kazi ya `make_classification` kutoka maktaba ya SciKit Learn:\n"
|
||||
"Tutazalisha seti ya data ya uainishaji wa nasibu kwa kutumia kazi ya `make_classification` kutoka maktaba ya SciKit Learn:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Hebu pia tuweke dataset:\n"
|
||||
"Hebu pia tuweke grafu ya seti ya data:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"Kwa kuwa perceptron ni classifier ya binary, kwa kila vector ya ingizo $x$, matokeo ya perceptron yetu yatakuwa aidha +1 au -1, kulingana na darasa. Matokeo yatakokotolewa kwa kutumia fomula\n",
|
||||
"Kwa kuwa perceptron ni classifier ya binary, kwa kila vector ya pembejeo $x$, matokeo ya perceptron yetu yatakuwa aidha +1 au -1, kulingana na darasa. Matokeo yatakokotolewa kwa kutumia fomula\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Hata hivyo, modeli ya mstari ya kawaida inapaswa pia kuwa na upendeleo, yaani, kwa hali bora tunapaswa kukokotoa $y$ kama $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Ili kurahisisha modeli yetu, tunaweza kuondoa kipengele cha upendeleo kwa kuongeza kipimo kingine kwenye sifa zetu za ingizo, ambacho daima ni sawa na 1:\n"
|
||||
"Hata hivyo, mfano wa mstari wa kawaida unapaswa pia kuwa na upendeleo, yaani, kwa hali bora tunapaswa kukokotoa $y$ kama $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Ili kurahisisha mfano wetu, tunaweza kuondoa kipengele cha upendeleo kwa kuongeza kipimo kingine kwenye sifa zetu za pembejeo, ambacho daima ni sawa na 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -217,7 +217,7 @@
|
|||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"ambapo $\\eta$ ni **kiwango cha kujifunza**, na $\\tau\\in\\mathbb{N}$ - idadi ya mizunguko.\n",
|
||||
"ambapo $\\eta$ ni **kiwango cha kujifunza**, na $\\tau\\in\\mathbb{N}$ - idadi ya marudio.\n",
|
||||
"\n",
|
||||
"Hebu tueleze algorithimu hii kwa Python:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Kumbuka Kuhusu Kiwango cha Kujifunza**: Kigezo cha `learning_rate` (chaguo-msingi `0.01`) kinadhibiti jinsi tunavyorekebisha uzito wakati wa kila hatua ya mafunzo. Hii inatekeleza fomula ya kusasisha gradient descent:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Kiwango cha kujifunza kikubwa (mfano, `1.0`) hufanya perceptron kujifunza haraka lakini kinaweza kupitiliza suluhisho bora\n",
|
||||
"- Kiwango cha kujifunza kidogo (mfano, `0.001`) hujifunza polepole zaidi lakini kinaweza kufikia kwa usahihi zaidi\n",
|
||||
"- Unaweza kujaribu kwa kuita: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Kama unavyoona, usahihi wa awali ni karibu 50%, lakini unakua haraka hadi thamani za juu karibu na 90%.\n",
|
||||
"Kama unavyoona, usahihi wa awali ni karibu 50%, lakini unakua haraka hadi kufikia thamani za juu karibu na 90%.\n",
|
||||
"\n",
|
||||
"Hebu tuone jinsi madarasa yanavyotenganishwa. Kazi yetu ya uainishaji inaonekana kama $\\mathbf{w}^Tx$, na ni kubwa kuliko 0 kwa darasa moja, na iko chini ya 0 kwa lingine. Kwa hivyo, mstari wa kutenganisha madarasa unafafanuliwa na $\\mathbf{w}^Tx = 0$. Kwa kuwa tuna vipimo viwili tu $x_0$ na $x_1$, mlinganyo wa mstari ungekuwa $w_0x_0+w_1x_1+w_2 = 0$ (kumbuka kwamba tumeweka wazi kipimo cha ziada $x_2=1$). Hebu tupake mstari huu:\n"
|
||||
"Hebu tuone jinsi madarasa yanavyotenganishwa. Kazi yetu ya uainishaji inaonekana kama $\\mathbf{w}^Tx$, na inakuwa kubwa kuliko 0 kwa darasa moja, na chini ya 0 kwa lingine. Kwa hivyo, mstari wa kutenganisha madarasa unafafanuliwa na $\\mathbf{w}^Tx = 0$. Kwa kuwa tuna vipimo viwili tu $x_0$ na $x_1$, mlinganyo wa mstari ungekuwa $w_0x_0+w_1x_1+w_2 = 0$ (kumbuka kwamba tumeweka wazi kipimo cha ziada $x_2=1$). Hebu tupake mstari huu:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Kujaribu Viwango vya Kujifunza\n",
|
||||
"\n",
|
||||
"Sasa hebu tuchunguze jinsi viwango tofauti vya kujifunza vinavyoathiri mchakato wa mafunzo. Kiwango cha kujifunza kinadhibiti ukubwa wa hatua katika gradient descent - hyperparameter muhimu inayochangia kasi ya muunganisho na uthabiti.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Jaribio la Kiwango cha Kujifunza cha Kuingiliana\n",
|
||||
"\n",
|
||||
"Tumia kitelezi hapa chini kujaribu viwango tofauti vya kujifunza na kuona jinsi vinavyoathiri mpaka wa maamuzi:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -379,9 +505,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Tathmini kwenye Seti ya Data ya Mtihani\n",
|
||||
"## Tathmini kwenye Seti ya Data ya Majaribio\n",
|
||||
"\n",
|
||||
"Mwanzoni, tulitenga baadhi ya data kwa ajili ya seti ya data ya mtihani. Hebu tuone jinsi classifier yetu ilivyo sahihi kwenye seti hii ya mtihani. Ili kufanya hivyo, tunapanua seti ya data ya mtihani kwa kuongeza kipimo cha ziada, tunazidisha na matrix ya uzito, na kuhakikisha kwamba thamani inayopatikana ina alama sawa na lebo (+1 au -1). Kisha tunajumlisha thamani zote za boolean na kugawanya kwa urefu wa sampuli ya mtihani, ili kupata usahihi:\n"
|
||||
"Mwanzoni, tulitenga baadhi ya data kwa ajili ya seti ya data ya majaribio. Hebu tuone jinsi classifier yetu ilivyo sahihi kwenye seti hii ya majaribio. Ili kufanya hivyo, tunapanua seti ya data ya majaribio kwa kuongeza kipimo cha ziada, tunazidisha na matrix ya uzito, na kuhakikisha kwamba thamani iliyopatikana ina alama sawa na lebo (+1 au -1). Kisha tunajumlisha thamani zote za boolean na kugawanya kwa urefu wa sampuli ya majaribio, ili kupata usahihi:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,7 +655,7 @@
|
|||
"source": [
|
||||
"## Mapungufu ya Perceptron\n",
|
||||
"\n",
|
||||
"Kama ulivyoona hapo juu, perceptron ni **kainishi cha mstari**. Inaweza kutofautisha kati ya madarasa mawili vizuri ikiwa madarasa hayo ni **yanayoweza kutenganishwa kwa mstari**, yaani yanaweza kutenganishwa kwa mstari wa moja kwa moja. Vinginevyo, mchakato wa mafunzo ya perceptron hautafikia hitimisho.\n",
|
||||
"Kama ulivyoona hapo juu, perceptron ni **kainishaji wa mstari**. Inaweza kutofautisha kati ya madarasa mawili vizuri ikiwa madarasa hayo ni **yanayoweza kutenganishwa kwa mstari**, yaani yanaweza kutenganishwa kwa mstari wa moja kwa moja. Vinginevyo, mchakato wa mafunzo ya perceptron hautafikia hitimisho.\n",
|
||||
"\n",
|
||||
"Mfano wa wazi kabisa wa tatizo ambalo haliwezi kutatuliwa na perceptron ni tatizo linalojulikana kama **tatizo la XOR**. Tunataka perceptron yetu ijifunze kazi ya mantiki ya XOR, ambayo ina jedwali la ukweli lifuatalo:\n",
|
||||
"\n",
|
||||
|
|
@ -605,7 +731,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Kama unavyoona kutoka kwenye grafu hapo juu, usahihi hauzidi 75%, kwa sababu haiwezekani kuchora mstari wa moja kwa moja kwa namna ya kupata mifano yote sahihi.\n",
|
||||
"Kama unavyoona kutoka kwenye grafu hapo juu, usahihi hauzidi asilimia 75%, kwa sababu haiwezekani kuchora mstari wa moja kwa moja kwa namna ya kupata mifano yote kwa usahihi.\n",
|
||||
"\n",
|
||||
"Tatizo la XOR ni mfano wa kawaida wa mipaka ya perceptron, na lilionyeshwa na Marvin Minsky na Seymour Papert mwaka 1969 katika kitabu chao [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Uangalizi huu ulizuia utafiti katika eneo la mitandao ya neva kwa karibu miaka 10, ingawa - na tutaona hili katika sehemu inayofuata ya kozi yetu - perceptrons zenye tabaka nyingi zina uwezo wa kutatua matatizo kama haya.\n",
|
||||
"\n",
|
||||
|
|
@ -613,11 +739,11 @@
|
|||
"\n",
|
||||
"Ingawa perceptron haiwezi kutatua tatizo la XOR, inaweza kutatua matatizo mengine magumu zaidi, kama vile utambuzi wa herufi zilizoandikwa kwa mkono.\n",
|
||||
"\n",
|
||||
"Seti ya data ambayo mara nyingi hutumika wakati wa kujifunza mashine inaitwa [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Imetengenezwa na Taasisi ya Kitaifa ya Viwango na Teknolojia iliyorekebishwa, na ina seti ya mafunzo ya tarakimu 60000 zilizoandikwa kwa mkono, zilizokusanywa kutoka kwa takriban wanafunzi 250 na wafanyakazi wa taasisi hiyo. Pia kuna seti ya majaribio ya tarakimu 10000, zilizokusanywa kutoka kwa watu tofauti.\n",
|
||||
"Seti ya data ambayo mara nyingi hutumiwa wakati wa kujifunza mashine inaitwa [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Imeundwa na Taasisi ya Kitaifa ya Viwango na Teknolojia iliyorekebishwa, na ina seti ya mafunzo ya tarakimu 60000 zilizoandikwa kwa mkono, zilizokusanywa kutoka kwa takriban wanafunzi 250 na wafanyakazi wa taasisi hiyo. Pia kuna seti ya majaribio ya tarakimu 10000, zilizokusanywa kutoka kwa watu tofauti.\n",
|
||||
"\n",
|
||||
"Tarakimu zote zinawakilishwa na picha za rangi ya kijivu zenye ukubwa wa pikseli 28x28.\n",
|
||||
"\n",
|
||||
"> Seti ya data ya MNIST inapatikana kama shindano la mafunzo kwenye [Kaggle](https://www.kaggle.com/c/digit-recognizer), tovuti inayoshirikisha mashindano na mashindano ya kujifunza mashine. Mara tu unapojifunza jinsi ya kuainisha tarakimu za MNIST, unaweza kuwasilisha suluhisho lako kwa Kaggle ili kuona jinsi linavyokadiriwa miongoni mwa washiriki wengine.\n",
|
||||
"> Seti ya data ya MNIST inapatikana kama shindano la mafunzo kwenye [Kaggle](https://www.kaggle.com/c/digit-recognizer), tovuti inayoshirikisha mashindano na michuano ya kujifunza mashine. Mara tu unapojifunza jinsi ya kuainisha tarakimu za MNIST, unaweza kuwasilisha suluhisho lako kwa Kaggle ili kuona jinsi linavyokadiriwa miongoni mwa washiriki wengine.\n",
|
||||
"\n",
|
||||
"Tunaanza kwa kupakia seti ya data ya MNIST:\n"
|
||||
]
|
||||
|
|
@ -831,11 +957,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Tafadhali kumbuka jinsi usahihi unavyopanda haraka hadi karibu 100%.\n",
|
||||
"Tafadhali kumbuka jinsi usahihi unavyopanda hadi karibu 100% kwa haraka sana.\n",
|
||||
"\n",
|
||||
"Tafadhali, songesha kitelezi hadi sehemu fulani mwishoni mwa mafunzo, na angalia matriki ya uzito iliyochorwa upande wa kushoto. Matriki hii itakusaidia kuelewa jinsi perceptron inavyofanya kazi. Unaweza kuona thamani za juu za uzito katikati ya uwanja, ambazo zinahusiana na pikseli ambazo mara nyingi zinapatikana kwa tarakimu 1, na thamani za chini hasi kando, ambapo sehemu za tarakimu 0 zipo. Kwa hivyo, ikiwa tarakimu iliyowasilishwa kwa perceptron ni kweli 1, sehemu ya katikati yake itazidishwa na thamani za juu, ikizalisha matokeo chanya. Kinyume chake, wakati perceptron inapoona 0, pikseli zinazohusiana zitazidishwa na namba hasi.\n",
|
||||
"Tafadhali, songesha kitelezi hadi sehemu fulani mwishoni mwa mafunzo, na angalia matriki ya uzito iliyochorwa upande wa kushoto. Matriki hii itakusaidia kuelewa jinsi perceptron inavyofanya kazi. Unaweza kuona thamani za juu za uzito katikati ya uwanja, ambazo zinahusiana na pikseli ambazo mara nyingi zinapatikana kwa tarakimu 1, na thamani za chini hasi pembeni, ambapo sehemu za tarakimu 0 zipo. Kwa hivyo, ikiwa tarakimu iliyowasilishwa kwa perceptron ni kweli 1, sehemu ya katikati yake itazidishwa na thamani za juu, ikizalisha matokeo chanya. Kinyume chake, wakati perceptron inapoona 0, pikseli zinazohusiana zitazidishwa na namba hasi.\n",
|
||||
"\n",
|
||||
"> Unaweza kugundua kwamba tukimpa perceptron yetu tarakimu 1 iliyosogezwa kidogo kwa usawa, ili pikseli zake zichukue nafasi ambapo kuna sehemu za wima za 0, tunaweza kupata matokeo yasiyo sahihi. Kwa kuwa asili ya seti yetu ya data ya MNIST ni kwamba tarakimu zote ziko katikati na zimewekwa vizuri, na perceptron inategemea hili kutofautisha kati ya tarakimu.\n",
|
||||
"> Unaweza kugundua kwamba tukimpa perceptron yetu tarakimu 1 iliyosogezwa kidogo kwa usawa, ili pikseli zake zichukue nafasi ambapo kuna sehemu za wima za 0, tunaweza kupata matokeo yasiyo sahihi. Kwa kuwa asili ya seti yetu ya data ya MNIST ni kwamba tarakimu zote ziko katikati na zimewekwa vizuri, perceptron inategemea hili kutofautisha kati ya tarakimu.\n",
|
||||
"\n",
|
||||
"Sasa hebu tujaribu tarakimu tofauti:\n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"Kwa sababu fulani, 2 na 5 hazitenganishwi kwa urahisi. Ingawa tunapata usahihi wa juu (zaidi ya 85%), tunaweza kuona wazi jinsi perceptron inavyokoma kujifunza katika hatua fulani.\n",
|
||||
"\n",
|
||||
"Ili kuelewa kwa nini hili linatokea, tunaweza kujaribu kutumia [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Hii ni mbinu ya kujifunza kwa mashine inayotumika kupunguza ukubwa wa dataset ya pembejeo, kwa namna ambayo inapatikana utenganisho bora kati ya madarasa.\n",
|
||||
"Ili kuelewa kwa nini hili linatokea, tunaweza kujaribu kutumia [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Hii ni mbinu ya kujifunza kwa mashine inayotumika kupunguza vipimo vya seti ya data ya ingizo, kwa namna ambayo inapatikana utenganisho bora kati ya madarasa.\n",
|
||||
"\n",
|
||||
"Katika hali yetu, picha ya pembejeo ina pikseli 784 (vipengele vya pembejeo), na tunataka kutumia PCA kupunguza idadi ya vigezo hadi 2 tu, ili tuweze kuviweka kwenye grafu. Vigezo hivyo viwili vitakuwa mchanganyiko wa mstari wa vipengele vya awali, na tunaweza kuona mchakato huu kama \"kuzungusha\" nafasi yetu ya awali ya vipimo 784 na kuangalia makadirio yake kwenye nafasi ya vipimo 2, hadi tupate mtazamo bora unaotenganisha madarasa.\n"
|
||||
"Katika hali yetu, picha ya ingizo ina pikseli 784 (vipengele vya ingizo), na tunataka kutumia PCA kupunguza idadi ya vigezo hadi 2 tu, ili tuweze kuviweka kwenye grafu. Vigezo hivyo viwili vitakuwa mchanganyiko wa mstari wa vipengele asilia, na tunaweza kuona mchakato huu kama \"kuzungusha\" nafasi yetu ya vipimo 784 na kuangalia makadirio yake kwenye nafasi ya 2D, hadi tupate mtazamo bora unaotenganisha madarasa.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,16 +1153,16 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Kama unavyoona, 0 na 1 zinaweza kutenganishwa wazi na mstari wa moja kwa moja. Hii inaonyesha kwamba katika nafasi ya asili yenye vipimo 784, nukta zinazowakilisha tarakimu pia zinaweza kutenganishwa kwa mstari. Kwa upande wa 2 na 5, hatuwezi kupata makadirio mazuri yatakayozitenganisha tarakimu kwa uwazi, na hivyo kuna baadhi ya matukio ya uainishaji usio sahihi.\n",
|
||||
"Kama unavyoona, 0 na 1 zinaweza kutenganishwa wazi na mstari wa moja kwa moja. Hii inaonyesha kwamba katika nafasi ya asili ya vipimo 784, nukta zinazowakilisha tarakimu pia zinaweza kutenganishwa kwa mstari. Katika hali ya 2 na 5, hatuwezi kupata makadirio mazuri yatakayozitenganisha tarakimu kwa uwazi, na hivyo kuna baadhi ya kesi za uainishaji usio sahihi.\n",
|
||||
"\n",
|
||||
"> Baadaye katika kozi hii tutajifunza jinsi ya kuunda uainishaji usio wa mstari kwa kutumia Mitandao ya Neva, na jinsi ya kushughulikia tatizo la tarakimu kutokuwa zimepangwa vizuri. Hivi karibuni tutafikia usahihi wa zaidi ya 99% katika uainishaji wa tarakimu za MNIST, huku tukizigawa katika madarasa 10 tofauti.\n",
|
||||
"\n",
|
||||
"## Mambo ya Kujifunza\n",
|
||||
"## Muhimu\n",
|
||||
"\n",
|
||||
" * Tumeelewa kuhusu usanifu rahisi zaidi wa mtandao wa neva - perceptron ya tabaka moja.\n",
|
||||
" * Tumetekeleza perceptron \"kwa mkono\", kwa kutumia utaratibu rahisi wa mafunzo unaotegemea gradient descent.\n",
|
||||
" * Licha ya urahisi wake, perceptron ya tabaka moja inaweza kutatua matatizo changamani ya utambuzi wa tarakimu zilizoandikwa kwa mkono.\n",
|
||||
" * Perceptron ya tabaka moja ni uainishaji wa mstari, na hivyo inatoa uwezo sawa wa uainishaji kama logistic regression.\n",
|
||||
" * Licha ya urahisi, perceptron ya tabaka moja inaweza kutatua matatizo magumu ya utambuzi wa tarakimu zilizoandikwa kwa mkono.\n",
|
||||
" * Perceptron ya tabaka moja ni uainishaji wa mstari, na hivyo inatoa nguvu sawa ya uainishaji kama logistic regression.\n",
|
||||
" * Katika nafasi ya sampuli, perceptron inaweza kutenganisha madarasa mawili ya data ya ingizo kwa kutumia hyperplane.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Shukrani\n",
|
||||
"\n",
|
||||
"Notebook hii ni sehemu ya [Mtaala wa AI kwa Kompyuta](http://github.com/microsoft/ai-for-beginners), na imeandaliwa na [Dmitry Soshnikov](http://soshnikov.com). Imechochewa na Warsha ya Mtandao wa Neva katika Microsoft Research Cambridge. Baadhi ya msimbo na vifaa vya maonyesho vimechukuliwa kutoka kwa mawasilisho ya [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) na [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), na kutoka kwa hifadhi ya [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Notebook hii ni sehemu ya [Mtaala wa AI kwa Kompyuta](http://github.com/microsoft/ai-for-beginners), na imeandaliwa na [Dmitry Soshnikov](http://soshnikov.com). Imechochewa na Warsha ya Mtandao wa Neva katika Microsoft Research Cambridge. Baadhi ya msimbo na vifaa vya maonyesho vimechukuliwa kutoka kwa mawasilisho ya [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) na [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), pamoja na hifadhi ya [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Kanusho**: \nHati hii imetafsiriwa kwa kutumia huduma ya tafsiri ya AI [Co-op Translator](https://github.com/Azure/co-op-translator). Ingawa tunajitahidi kuhakikisha usahihi, tafadhali fahamu kuwa tafsiri za kiotomatiki zinaweza kuwa na makosa au kutokuwa sahihi. Hati ya asili katika lugha yake ya awali inapaswa kuzingatiwa kama chanzo cha mamlaka. Kwa taarifa muhimu, tafsiri ya kitaalamu ya binadamu inapendekezwa. Hatutawajibika kwa kutoelewana au tafsiri zisizo sahihi zinazotokana na matumizi ya tafsiri hii.\n"
|
||||
"\n---\n\n**Kanusho**: \nHati hii imetafsiriwa kwa kutumia huduma ya kutafsiri ya AI [Co-op Translator](https://github.com/Azure/co-op-translator). Ingawa tunajitahidi kuhakikisha usahihi, tafadhali fahamu kuwa tafsiri za kiotomatiki zinaweza kuwa na makosa au kutokuwa sahihi. Hati ya asili katika lugha yake ya awali inapaswa kuzingatiwa kama chanzo cha mamlaka. Kwa taarifa muhimu, tafsiri ya kitaalamu ya binadamu inapendekezwa. Hatutawajibika kwa kutoelewana au tafsiri zisizo sahihi zinazotokana na matumizi ya tafsiri hii.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:40:32+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:28:24+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "sw"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@
|
|||
"\n",
|
||||
"> โน้ตบุ๊กนี้เป็นส่วนหนึ่งของ [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) เยี่ยมชมที่เก็บข้อมูลเพื่อดูชุดเอกสารการเรียนรู้ทั้งหมด\n",
|
||||
"\n",
|
||||
"ตามที่เราได้พูดถึง เพอร์เซปตรอนช่วยให้คุณแก้ปัญหา **การจำแนกประเภทแบบทวิภาค** หรือการจัดประเภทตัวอย่างข้อมูลเข้าไปในสองกลุ่ม - เราสามารถเรียกพวกมันว่า **กลุ่มบวก** และ **กลุ่มลบ**\n",
|
||||
"ตามที่เราได้พูดถึง เพอร์เซปตรอนช่วยให้คุณแก้ปัญหา **การจำแนกประเภทแบบไบนารี** ได้ นั่นคือการจัดประเภทตัวอย่างข้อมูลเข้าไปในสองกลุ่ม - เราสามารถเรียกพวกมันว่า **กลุ่มบวก** และ **กลุ่มลบ**\n",
|
||||
"\n",
|
||||
"ก่อนอื่น มาเริ่มต้นด้วยการนำเข้าไลบรารีที่จำเป็นกันก่อน\n"
|
||||
"ก่อนอื่น มาเริ่มต้นด้วยการนำเข้าไลบรารีที่จำเป็นบางตัว\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## ปัญหาตัวอย่าง\n",
|
||||
"\n",
|
||||
"เริ่มต้นกันด้วยปัญหาตัวอย่างง่าย ๆ โดยเรามีคุณลักษณะข้อมูลสองตัวอย่าง เช่น ในทางการแพทย์ เราอาจต้องการจัดประเภทเนื้องอกว่าเป็นชนิดไม่ร้ายแรงหรือชนิดร้ายแรง โดยพิจารณาจากขนาดและอายุของมัน\n",
|
||||
"เริ่มต้นกันด้วยปัญหาตัวอย่างที่มีคุณลักษณะนำเข้า 2 ตัว เช่น ในทางการแพทย์ เราอาจต้องการจัดประเภทเนื้องอกว่าเป็นชนิดไม่ร้ายแรงหรือชนิดร้ายแรง โดยพิจารณาจากขนาดและอายุของมัน\n",
|
||||
"\n",
|
||||
"เราจะสร้างชุดข้อมูลการจำแนกแบบสุ่มโดยใช้ฟังก์ชัน `make_classification` จากไลบรารี SciKit Learn:\n"
|
||||
]
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"มาพล็อตชุดข้อมูลกันเถอะ:\n"
|
||||
"มาลองสร้างกราฟของชุดข้อมูลกัน:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## เพอร์เซปตรอน\n",
|
||||
"\n",
|
||||
"เนื่องจากเพอร์เซปตรอนเป็นตัวจำแนกประเภทแบบสองค่า สำหรับแต่ละเวกเตอร์อินพุต $x$ ผลลัพธ์ของเพอร์เซปตรอนจะเป็น +1 หรือ -1 ขึ้นอยู่กับคลาส ผลลัพธ์จะถูกคำนวณโดยใช้สูตร\n",
|
||||
"เนื่องจากเพอร์เซปตรอนเป็นตัวจำแนกประเภทแบบไบนารี สำหรับแต่ละเวกเตอร์อินพุต $x$ ผลลัพธ์ของเพอร์เซปตรอนของเราจะเป็น +1 หรือ -1 ขึ้นอยู่กับคลาส ผลลัพธ์จะถูกคำนวณโดยใช้สูตร\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"อย่างไรก็ตาม โมเดลเชิงเส้นทั่วไปควรมีไบแอสด้วย กล่าวคือ โดยอุดมคติแล้วเราควรคำนวณ $y$ เป็น $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ เพื่อทำให้โมเดลของเราง่ายขึ้น เราสามารถกำจัดเทอมไบแอสนี้ได้โดยการเพิ่มมิติหนึ่งให้กับคุณลักษณะอินพุตของเรา ซึ่งจะมีค่าเท่ากับ 1 เสมอ:\n"
|
||||
"อย่างไรก็ตาม โมเดลเชิงเส้นทั่วไปควรมีไบแอสด้วย กล่าวคือ ในอุดมคติเราควรคำนวณ $y$ เป็น $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ เพื่อทำให้โมเดลของเราง่ายขึ้น เราสามารถกำจัดเทอมไบแอสนี้ได้โดยการเพิ่มมิติหนึ่งเข้าไปในคุณลักษณะอินพุตของเรา ซึ่งจะมีค่าเท่ากับ 1 เสมอ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -206,18 +206,18 @@
|
|||
"source": [
|
||||
"## อัลกอริทึมการฝึก\n",
|
||||
"\n",
|
||||
"เพื่อฝึก Perceptron เราจำเป็นต้องหาค่าน้ำหนัก $\\mathbf{w}$ ที่จะช่วยลดข้อผิดพลาดให้น้อยที่สุด โดยข้อผิดพลาดถูกกำหนดด้วย **เกณฑ์ของ Perceptron**:\n",
|
||||
"เพื่อฝึก perceptron เราจำเป็นต้องหาค่าน้ำหนัก $\\mathbf{w}$ ที่จะลดข้อผิดพลาดให้น้อยที่สุด ข้อผิดพลาดถูกกำหนดโดยใช้ **perceptron criteria**:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ สำหรับตัวอย่างการฝึกที่เป็นลบและบวกตามลำดับ\n",
|
||||
" * $\\mathcal{M}$ - ชุดของตัวอย่างที่ถูกจัดประเภทผิด\n",
|
||||
" * $\\mathcal{M}$ - เซตของตัวอย่างที่ถูกจัดประเภทผิด\n",
|
||||
" \n",
|
||||
"เราจะใช้กระบวนการ **Gradient Descent** โดยเริ่มต้นด้วยค่าน้ำหนักเริ่มต้นแบบสุ่ม $\\mathbf{w}^{(0)}$ และปรับค่าน้ำหนักในแต่ละขั้นตอนของการฝึกโดยใช้ Gradient ของ $E$:\n",
|
||||
"เราจะใช้กระบวนการ **gradient descent** โดยเริ่มต้นด้วยค่าน้ำหนักสุ่มเริ่มต้น $\\mathbf{w}^{(0)}$ เราจะปรับค่าน้ำหนักในแต่ละขั้นตอนของการฝึกโดยใช้ gradient ของ $E$:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"โดยที่ $\\eta$ คือ **อัตราการเรียนรู้** และ $\\tau\\in\\mathbb{N}$ คือจำนวนรอบของการทำซ้ำ\n",
|
||||
"โดยที่ $\\eta$ คือ **learning rate** และ $\\tau\\in\\mathbb{N}$ - จำนวนรอบการทำงาน\n",
|
||||
"\n",
|
||||
"มานิยามอัลกอริทึมนี้ใน Python กัน:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -272,7 +272,20 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"ตอนนี้มาเริ่มการฝึกอบรมบนชุดข้อมูลของเรา:\n"
|
||||
"**หมายเหตุเกี่ยวกับ Learning Rate**: พารามิเตอร์ `learning_rate` (ค่าเริ่มต้น `0.01`) ใช้ควบคุมว่าปรับน้ำหนักมากน้อยแค่ไหนในแต่ละขั้นตอนการฝึกสอน โดยใช้สูตรอัปเดตของ gradient descent:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- ค่า learning rate ที่มากขึ้น (เช่น `1.0`) ทำให้ perceptron เรียนรู้เร็วขึ้น แต่มีโอกาสที่จะเลยจุดคำตอบที่เหมาะสม\n",
|
||||
"- ค่า learning rate ที่น้อยลง (เช่น `0.001`) จะเรียนรู้ช้าลง แต่มีโอกาสที่จะคอนเวิร์จได้แม่นยำมากขึ้น\n",
|
||||
"- คุณสามารถทดลองได้โดยเรียก: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"ตอนนี้เรามาเริ่มการฝึกอบรมบนชุดข้อมูลของเรา:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"ดังที่คุณเห็น ความแม่นยำเริ่มต้นอยู่ที่ประมาณ 50% แต่เพิ่มขึ้นอย่างรวดเร็วไปสู่ค่าที่สูงขึ้นใกล้เคียง 90%\n",
|
||||
"ดังที่คุณเห็น ความแม่นยำเริ่มต้นอยู่ที่ประมาณ 50% แต่เพิ่มขึ้นอย่างรวดเร็วไปถึงค่าที่สูงขึ้นใกล้เคียง 90%\n",
|
||||
"\n",
|
||||
"มาลองดูว่าคลาสถูกแยกออกจากกันอย่างไร ฟังก์ชันการจำแนกของเรามีลักษณะเป็น $\\mathbf{w}^Tx$ และจะมีค่ามากกว่า 0 สำหรับคลาสหนึ่ง และมีค่าต่ำกว่า 0 สำหรับอีกคลาสหนึ่ง ดังนั้น เส้นแบ่งคลาสจะถูกกำหนดโดย $\\mathbf{w}^Tx = 0$ เนื่องจากเรามีเพียงสองมิติ $x_0$ และ $x_1$ สมการของเส้นจะเป็น $w_0x_0+w_1x_1+w_2 = 0$ (อย่าลืมว่าเราได้กำหนดมิติพิเศษ $x_2=1$ ไว้อย่างชัดเจน) มาลองวาดเส้นนี้กัน:\n"
|
||||
"มาลองดูว่าคลาสต่าง ๆ ถูกแยกออกจากกันอย่างไร ฟังก์ชันการจำแนกของเรามีลักษณะเป็น $\\mathbf{w}^Tx$ และจะมีค่ามากกว่า 0 สำหรับคลาสหนึ่ง และมีค่าต่ำกว่า 0 สำหรับอีกคลาสหนึ่ง ดังนั้น เส้นแบ่งคลาสจึงถูกกำหนดโดย $\\mathbf{w}^Tx = 0$ เนื่องจากเรามีเพียงสองมิติ $x_0$ และ $x_1$ สมการของเส้นจะเป็น $w_0x_0+w_1x_1+w_2 = 0$ (อย่าลืมว่าเราได้กำหนดมิติพิเศษ $x_2=1$ ไว้อย่างชัดเจน) มาลองวาดเส้นนี้กัน:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ทดลองปรับอัตราการเรียนรู้\n",
|
||||
"\n",
|
||||
"ตอนนี้เรามาลองสำรวจว่าอัตราการเรียนรู้ที่แตกต่างกันส่งผลต่อกระบวนการฝึกโมเดลอย่างไร อัตราการเรียนรู้จะควบคุมขนาดของขั้นตอนในกระบวนการ Gradient Descent ซึ่งเป็นไฮเปอร์พารามิเตอร์สำคัญที่มีผลต่อทั้งความเร็วในการลู่เข้าและความเสถียรของการฝึกโมเดล\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### การทดลองอัตราการเรียนรู้แบบโต้ตอบ\n",
|
||||
"\n",
|
||||
"ใช้ตัวเลื่อนด้านล่างเพื่อทดลองปรับอัตราการเรียนรู้แบบโต้ตอบ และดูว่ามันส่งผลต่อเส้นแบ่งการตัดสินใจอย่างไร:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## ประเมินผลบนชุดข้อมูลทดสอบ\n",
|
||||
"\n",
|
||||
"ในตอนแรก เราได้แยกข้อมูลบางส่วนออกมาเป็นชุดข้อมูลทดสอบ ลองมาดูกันว่า classifier ของเรามีความแม่นยำแค่ไหนบนชุดข้อมูลทดสอบนี้ เพื่อทำสิ่งนี้ เราจะขยายชุดข้อมูลทดสอบด้วยมิติพิเศษ คูณด้วยเมทริกซ์น้ำหนัก และตรวจสอบให้แน่ใจว่าค่าที่ได้มีเครื่องหมายเดียวกันกับ label (+1 หรือ -1) จากนั้นเรารวมค่าบูลีนทั้งหมดเข้าด้วยกันและหารด้วยความยาวของตัวอย่างทดสอบ เพื่อคำนวณความแม่นยำ:\n"
|
||||
"ในตอนแรก เราได้แยกข้อมูลบางส่วนออกมาเป็นชุดข้อมูลทดสอบ ลองมาดูกันว่าตัวจำแนกของเรามีความแม่นยำแค่ไหนบนชุดข้อมูลทดสอบนี้ เพื่อทำสิ่งนี้ เราจะขยายชุดข้อมูลทดสอบด้วยมิติพิเศษ คูณด้วยเมทริกซ์น้ำหนัก และตรวจสอบให้แน่ใจว่าค่าที่ได้มีเครื่องหมายเดียวกันกับป้ายกำกับ (+1 หรือ -1) จากนั้นเราจะรวมค่าบูลีนทั้งหมดเข้าด้วยกันและหารด้วยความยาวของตัวอย่างทดสอบเพื่อหาค่าความแม่นยำ:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -420,9 +546,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## การสังเกตกระบวนการฝึกอบรม\n",
|
||||
"## การสังเกตกระบวนการฝึก\n",
|
||||
"\n",
|
||||
"เราเคยเห็นมาก่อนแล้วว่า ความแม่นยำลดลงระหว่างการฝึกอบรม จะดีมากถ้าเราสามารถดูว่าการเปลี่ยนแปลงของเส้นแบ่งเกิดขึ้นอย่างไรในระหว่างการฝึกอบรม โค้ดด้านล่างนี้จะช่วยให้คุณสามารถมองเห็นทุกอย่างในกราฟเดียว และคุณจะสามารถเลื่อนตัวเลื่อนเพื่อ \"เดินทางข้ามเวลา\" ผ่านกระบวนการฝึกอบรมได้\n"
|
||||
"เราเคยเห็นมาก่อนแล้วว่า ความแม่นยำลดลงระหว่างการฝึก จะดีมากถ้าเราได้เห็นว่าการแบ่งเส้นแยกเปลี่ยนแปลงอย่างไรระหว่างการฝึก โค้ดด้านล่างนี้จะช่วยให้คุณเห็นทุกอย่างในกราฟเดียว และคุณสามารถเลื่อนตัวเลื่อนเพื่อ \"เดินทางข้ามเวลา\" ผ่านกระบวนการฝึกได้\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,9 +655,9 @@
|
|||
"source": [
|
||||
"## ข้อจำกัดของ Perceptron\n",
|
||||
"\n",
|
||||
"ดังที่คุณได้เห็นข้างต้น Perceptron เป็น **ตัวจำแนกเชิงเส้น** ซึ่งสามารถแยกแยะระหว่างสองคลาสได้ดีหากคลาสเหล่านั้น **แยกกันได้เชิงเส้น** หรือสามารถแยกด้วยเส้นตรงได้ อย่างไรก็ตาม หากไม่เป็นเช่นนั้น กระบวนการฝึก Perceptron จะไม่สามารถหาคำตอบที่เหมาะสมได้\n",
|
||||
"ดังที่คุณได้เห็นข้างต้น Perceptron เป็น **ตัวจำแนกเชิงเส้น** ซึ่งสามารถแยกแยะระหว่างสองคลาสได้ดีหากคลาสเหล่านั้น **แยกกันได้เชิงเส้น** หรือสามารถแยกด้วยเส้นตรงได้ แต่หากไม่เป็นเช่นนั้น กระบวนการฝึก Perceptron จะไม่สามารถหาคำตอบที่เหมาะสมได้\n",
|
||||
"\n",
|
||||
"ตัวอย่างที่ชัดเจนที่สุดของปัญหาที่ไม่สามารถแก้ไขได้ด้วย Perceptron คือปัญหาที่เรียกว่า **XOR problem** เราต้องการให้ Perceptron ของเราเรียนรู้ฟังก์ชันบูลีน XOR ซึ่งมีตารางความจริงดังนี้:\n",
|
||||
"ตัวอย่างที่ชัดเจนที่สุดของปัญหาที่ Perceptron ไม่สามารถแก้ไขได้คือปัญหาที่เรียกว่า **XOR problem** เราต้องการให้ Perceptron ของเราเรียนรู้ฟังก์ชันบูลีน XOR ซึ่งมีตารางความจริงดังนี้:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -605,19 +731,19 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"จากกราฟด้านบน คุณจะเห็นว่า ความแม่นยำไม่เคยเกิน 75% เนื่องจากไม่สามารถวาดเส้นตรงในลักษณะที่จะทำให้ตัวอย่างทั้งหมดถูกต้องได้\n",
|
||||
"จากกราฟด้านบน คุณจะเห็นว่า ความแม่นยำไม่เคยเกิน 75% เพราะไม่สามารถวาดเส้นตรงในลักษณะที่จะทำให้ตัวอย่างทั้งหมดถูกต้องได้\n",
|
||||
"\n",
|
||||
"ปัญหา XOR เป็นตัวอย่างคลาสสิกของข้อจำกัดของ perceptron ซึ่งถูกชี้ให้เห็นโดย Marvin Minsky และ Seymour Papert ในปี 1969 ในหนังสือของพวกเขา [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) การสังเกตนี้ทำให้การวิจัยในด้านเครือข่ายประสาทเทียมถูกจำกัดไปเกือบ 10 ปี แม้ว่า - และเราจะเห็นในส่วนถัดไปของหลักสูตร - perceptron แบบหลายชั้นสามารถแก้ปัญหาเหล่านี้ได้อย่างสมบูรณ์แบบ\n",
|
||||
"ปัญหา XOR เป็นตัวอย่างคลาสสิกของข้อจำกัดของ perceptron และถูกชี้ให้เห็นโดย Marvin Minsky และ Seymour Papert ในปี 1969 ในหนังสือของพวกเขา [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) การสังเกตนี้ทำให้การวิจัยในด้านเครือข่ายประสาทเทียมถูกจำกัดไปเกือบ 10 ปี แม้ว่า - และเราจะเห็นในส่วนถัดไปของคอร์สนี้ - perceptron แบบหลายชั้นสามารถแก้ปัญหาเหล่านี้ได้อย่างสมบูรณ์แบบ\n",
|
||||
"\n",
|
||||
"## ตัวอย่างที่ซับซ้อน - MNIST\n",
|
||||
"\n",
|
||||
"แม้ว่า perceptron จะไม่สามารถแก้ปัญหา XOR ได้ แต่ก็สามารถแก้ปัญหาที่ซับซ้อนกว่านั้นได้ เช่น การจดจำตัวอักษรที่เขียนด้วยมือ\n",
|
||||
"\n",
|
||||
"ชุดข้อมูลที่มักถูกใช้เมื่อเรียนรู้การเรียนรู้ของเครื่องเรียกว่า [MNIST](https://en.wikipedia.org/wiki/MNIST_database) ซึ่งถูกสร้างขึ้นโดย Modified National Institute of Standards and Technology และประกอบด้วยชุดข้อมูลการฝึก 60,000 ตัวเลขที่เขียนด้วยมือ ซึ่งรวบรวมจากนักเรียนและพนักงานประมาณ 250 คนของสถาบัน นอกจากนี้ยังมีชุดข้อมูลทดสอบ 10,000 ตัวเลขที่รวบรวมจากบุคคลอื่น ๆ\n",
|
||||
"ชุดข้อมูลที่มักถูกใช้เมื่อเรียนรู้การเรียนรู้ของเครื่องเรียกว่า [MNIST](https://en.wikipedia.org/wiki/MNIST_database) ชุดข้อมูลนี้ถูกสร้างขึ้นโดย Modified National Institute of Standards and Technology และประกอบด้วยชุดข้อมูลการฝึก 60,000 ตัวเลขที่เขียนด้วยมือ ซึ่งรวบรวมจากนักเรียนและพนักงานประมาณ 250 คนของสถาบัน นอกจากนี้ยังมีชุดข้อมูลทดสอบ 10,000 ตัวเลขที่รวบรวมจากบุคคลอื่นๆ\n",
|
||||
"\n",
|
||||
"ตัวเลขทั้งหมดแสดงในรูปภาพระดับสีเทาขนาด 28x28 พิกเซล\n",
|
||||
"ตัวเลขทั้งหมดถูกแสดงในรูปภาพระดับสีเทาที่มีขนาด 28x28 พิกเซล\n",
|
||||
"\n",
|
||||
"> ชุดข้อมูล MNIST มีให้เป็นการแข่งขันการฝึกอบรมบน [Kaggle](https://www.kaggle.com/c/digit-recognizer) ซึ่งเป็นเว็บไซต์ที่จัดการแข่งขันและการประกวดการเรียนรู้ของเครื่อง เมื่อคุณเรียนรู้วิธีการจำแนกตัวเลข MNIST แล้ว คุณสามารถส่งคำตอบของคุณไปยัง Kaggle เพื่อดูว่าคำตอบของคุณได้รับการจัดอันดับอย่างไรเมื่อเทียบกับผู้เข้าร่วมคนอื่น ๆ\n",
|
||||
"> ชุดข้อมูล MNIST มีให้ใช้งานเป็นการแข่งขันการฝึกอบรมบน [Kaggle](https://www.kaggle.com/c/digit-recognizer) ซึ่งเป็นเว็บไซต์ที่จัดการแข่งขันและการประกวดเกี่ยวกับการเรียนรู้ของเครื่อง เมื่อคุณเรียนรู้วิธีการจำแนกตัวเลข MNIST แล้ว คุณสามารถส่งคำตอบของคุณไปยัง Kaggle เพื่อดูว่าคำตอบของคุณได้รับการจัดอันดับอย่างไรเมื่อเทียบกับผู้เข้าร่วมคนอื่นๆ\n",
|
||||
"\n",
|
||||
"เราจะเริ่มต้นด้วยการโหลดชุดข้อมูล MNIST:\n"
|
||||
]
|
||||
|
|
@ -831,11 +957,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"โปรดสังเกตว่า ความแม่นยำเพิ่มขึ้นจนเกือบถึง 100% อย่างรวดเร็ว\n",
|
||||
"โปรดสังเกตว่าความแม่นยำเพิ่มขึ้นเกือบถึง 100% อย่างรวดเร็ว\n",
|
||||
"\n",
|
||||
"กรุณาเลื่อนแถบสไลด์ไปยังตำแหน่งใกล้จุดสิ้นสุดของการฝึก และสังเกตเมทริกซ์น้ำหนักที่แสดงทางด้านซ้าย เมทริกซ์นี้จะช่วยให้คุณเข้าใจว่าการทำงานของ perceptron เป็นอย่างไร คุณจะเห็นค่าน้ำหนักสูงในส่วนกลางของพื้นที่ ซึ่งสอดคล้องกับพิกเซลที่มักปรากฏในตัวเลข 1 และค่าติดลบต่ำบริเวณด้านข้าง ซึ่งเป็นส่วนของตัวเลข 0 ดังนั้น หากตัวเลขที่นำเสนอให้ perceptron คือ 1 ส่วนกลางของตัวเลขจะถูกคูณด้วยค่าสูง ส่งผลให้ได้ผลลัพธ์เป็นบวก ในทางกลับกัน เมื่อ perceptron เห็นตัวเลข 0 พิกเซลที่เกี่ยวข้องจะถูกคูณด้วยตัวเลขติดลบ\n",
|
||||
"กรุณาเลื่อนแถบสไลด์ไปยังตำแหน่งใดตำแหน่งหนึ่งในช่วงท้ายของการฝึก และสังเกตเมทริกซ์น้ำหนักที่แสดงทางด้านซ้าย เมทริกซ์นี้จะช่วยให้คุณเข้าใจว่าการทำงานของ perceptron เป็นอย่างไร คุณจะเห็นค่าน้ำหนักสูงในส่วนกลางของพื้นที่ ซึ่งสอดคล้องกับพิกเซลที่มักปรากฏในตัวเลข 1 และค่าติดลบต่ำบริเวณด้านข้าง ซึ่งเป็นส่วนของตัวเลข 0 ดังนั้น หากตัวเลขที่นำเสนอให้ perceptron คือ 1 ส่วนกลางของมันจะถูกคูณด้วยค่าสูง ทำให้ได้ผลลัพธ์เป็นบวก ในทางกลับกัน เมื่อ perceptron เห็นตัวเลข 0 พิกเซลที่เกี่ยวข้องจะถูกคูณด้วยตัวเลขติดลบ\n",
|
||||
"\n",
|
||||
"> คุณอาจสังเกตได้ว่า หากเราให้ perceptron ตัวเลข 1 ที่เลื่อนออกไปทางแนวนอนเล็กน้อย ทำให้พิกเซลของมันไปอยู่ในตำแหน่งที่มีส่วนแนวตั้งของตัวเลข 0 เราอาจได้รับผลลัพธ์ที่ไม่ถูกต้อง เนื่องจากลักษณะของชุดข้อมูล MNIST ของเราคือ ตัวเลขทั้งหมดจะถูกจัดให้อยู่ตรงกลางและวางตำแหน่งอย่างเหมาะสม และ perceptron อาศัยสิ่งนี้ในการแยกแยะตัวเลข\n",
|
||||
"> คุณอาจสังเกตได้ว่าหากเราให้ perceptron ตัวเลข 1 ที่ถูกเลื่อนในแนวนอนเล็กน้อยจนพิกเซลของมันไปอยู่ในตำแหน่งที่มีส่วนแนวตั้งของตัวเลข 0 เราอาจได้รับผลลัพธ์ที่ไม่ถูกต้อง เนื่องจากลักษณะของชุดข้อมูล MNIST ของเราคือตัวเลขทั้งหมดจะถูกจัดให้อยู่ตรงกลางและวางตำแหน่งอย่างเหมาะสม และ perceptron อาศัยสิ่งนี้ในการแยกแยะตัวเลข\n",
|
||||
"\n",
|
||||
"ตอนนี้ลองใช้ตัวเลขอื่นดู:\n"
|
||||
]
|
||||
|
|
@ -1027,16 +1153,16 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"ดังที่คุณเห็น ตัวเลข 0 และ 1 สามารถแยกออกจากกันได้อย่างชัดเจนด้วยเส้นตรง ซึ่งบ่งชี้ว่าในพื้นที่ 784 มิติเดิม จุดที่สอดคล้องกับตัวเลขก็สามารถแยกออกจากกันได้เชิงเส้นเช่นกัน ในกรณีของตัวเลข 2 และ 5 เราไม่สามารถหาการฉายภาพที่ดีเพื่อแยกตัวเลขออกจากกันได้อย่างชัดเจน และดังนั้นจึงมีบางกรณีที่เกิดการจัดประเภทผิดพลาด\n",
|
||||
"ดังที่คุณเห็น ตัวเลข 0 และ 1 สามารถแยกออกจากกันได้อย่างชัดเจนด้วยเส้นตรง ซึ่งแสดงให้เห็นว่าในพื้นที่ 784 มิติเดิม จุดที่สอดคล้องกับตัวเลขก็สามารถแยกออกจากกันได้เชิงเส้นเช่นกัน ในกรณีของตัวเลข 2 และ 5 เราไม่สามารถหาการฉายภาพที่ดีเพื่อแยกตัวเลขออกจากกันได้อย่างชัดเจน และดังนั้นจึงมีบางกรณีที่เกิดการจัดประเภทผิดพลาด\n",
|
||||
"\n",
|
||||
"> ในภายหลังในคอร์สนี้ เราจะเรียนรู้วิธีสร้างตัวจำแนกที่ไม่เป็นเชิงเส้นโดยใช้ Neural Networks และวิธีจัดการกับปัญหาที่ตัวเลขไม่ได้ถูกจัดเรียงอย่างเหมาะสม ในไม่ช้าเราจะสามารถบรรลุความแม่นยำเกิน 99% ในการจำแนกตัวเลข MNIST โดยการจัดประเภทพวกมันเป็น 10 คลาสที่แตกต่างกัน\n",
|
||||
"> ในบทเรียนนี้ เราจะเรียนรู้วิธีสร้างตัวจำแนกที่ไม่เป็นเชิงเส้นโดยใช้ Neural Networks และวิธีจัดการกับปัญหาที่ตัวเลขไม่ได้เรียงตัวอย่างเหมาะสม ในไม่ช้าเราจะสามารถบรรลุความแม่นยำเกิน 99% ในการจำแนกตัวเลข MNIST โดยแบ่งออกเป็น 10 คลาสที่แตกต่างกัน\n",
|
||||
"\n",
|
||||
"## สิ่งที่ได้เรียนรู้\n",
|
||||
"\n",
|
||||
" * เราได้เรียนรู้เกี่ยวกับสถาปัตยกรรมของ Neural Network ที่ง่ายที่สุด - one-layer perceptron\n",
|
||||
" * เราได้ทำการสร้าง perceptron \"ด้วยมือ\" โดยใช้กระบวนการฝึกอบรมง่าย ๆ ที่อิงกับ gradient descent\n",
|
||||
" * แม้จะมีความเรียบง่าย แต่ one-layered perceptron สามารถแก้ปัญหาที่ซับซ้อนเกี่ยวกับการจดจำตัวเลขที่เขียนด้วยมือได้\n",
|
||||
" * one-layered perceptron เป็นตัวจำแนกเชิงเส้น และดังนั้นจึงมีพลังการจัดประเภทเหมือนกับ logistic regression\n",
|
||||
" * เราได้ทดลองสร้าง perceptron \"ด้วยมือ\" โดยใช้กระบวนการฝึกอบรมง่าย ๆ ที่อิงกับ gradient descent\n",
|
||||
" * แม้จะมีความเรียบง่าย แต่ one-layered perceptron ก็สามารถแก้ปัญหาที่ซับซ้อนเกี่ยวกับการจดจำตัวเลขที่เขียนด้วยมือได้\n",
|
||||
" * one-layered perceptron เป็นตัวจำแนกเชิงเส้น และดังนั้นจึงมีพลังในการจัดประเภทเหมือนกับ logistic regression\n",
|
||||
" * ในพื้นที่ตัวอย่าง perceptron สามารถแยกสองคลาสของข้อมูลอินพุตโดยใช้ hyperplane\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -1053,7 +1179,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**ข้อจำกัดความรับผิดชอบ**: \nเอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้การแปลมีความถูกต้อง แต่โปรดทราบว่าการแปลอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่ถูกต้อง เอกสารต้นฉบับในภาษาดั้งเดิมควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลสำคัญ แนะนำให้ใช้บริการแปลภาษามืออาชีพ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความผิดที่เกิดจากการใช้การแปลนี้\n"
|
||||
"\n---\n\n**ข้อจำกัดความรับผิดชอบ**: \nเอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้การแปลมีความถูกต้อง แต่โปรดทราบว่าการแปลโดยอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่ถูกต้อง เอกสารต้นฉบับในภาษาดั้งเดิมควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลภาษามนุษย์ที่มีความเชี่ยวชาญ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความผิดที่เกิดจากการใช้การแปลนี้\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:29:47+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:17:25+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "th"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## Simpleng Problema\n",
|
||||
"## Toy Problem\n",
|
||||
"\n",
|
||||
"Para magsimula, simulan natin sa isang simpleng problema kung saan mayroon tayong dalawang input na katangian. Halimbawa, sa medisina, maaaring gusto nating uriin ang mga tumor bilang benign o malignant, depende sa laki at edad nito.\n",
|
||||
"Para magsimula, simulan natin sa isang simpleng problema, kung saan mayroon tayong dalawang input na katangian. Halimbawa, sa medisina, maaaring gusto nating uriin ang mga tumor bilang benign o malignant, depende sa laki at edad nito.\n",
|
||||
"\n",
|
||||
"Gagawa tayo ng random na dataset para sa klasipikasyon gamit ang `make_classification` na function mula sa SciKit Learn library:\n"
|
||||
]
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Iplot din natin ang dataset:\n"
|
||||
"I-plot din natin ang dataset:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Gayunpaman, ang isang pangkalahatang linear na modelo ay dapat ding may bias, ibig sabihin, ideal na kakalkulahin natin ang $y$ bilang $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Upang gawing mas simple ang ating modelo, maaari nating alisin ang bias term na ito sa pamamagitan ng pagdaragdag ng isa pang dimensyon sa ating input features, na laging katumbas ng 1:\n"
|
||||
"Gayunpaman, ang isang pangkalahatang linear na modelo ay dapat ding may bias, ibig sabihin, ideal na dapat nating kalkulahin ang $y$ bilang $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$. Upang gawing mas simple ang ating modelo, maaari nating alisin ang bias term na ito sa pamamagitan ng pagdaragdag ng isa pang dimensyon sa ating input features, na laging katumbas ng 1:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -217,7 +217,7 @@
|
|||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"kung saan ang $\\eta$ ay ang **learning rate**, at $\\tau\\in\\mathbb{N}$ - bilang ng iteration.\n",
|
||||
"kung saan ang $\\eta$ ay ang **learning rate**, at $\\tau\\in\\mathbb{N}$ - bilang ng iterasyon.\n",
|
||||
"\n",
|
||||
"I-define natin ang algorithm na ito sa Python:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Tandaan Tungkol sa Learning Rate**: Ang parameter na `learning_rate` (default `0.01`) ang nagkokontrol kung gaano kalaki ang ina-adjust natin sa mga weights sa bawat hakbang ng training. Ito ay sumusunod sa formula ng gradient descent update:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Ang mas mataas na learning rate (hal., `1.0`) ay nagpapabilis sa pagkatuto ng perceptron ngunit maaaring lumampas sa optimal na solusyon\n",
|
||||
"- Ang mas mababang learning rate (hal., `0.001`) ay mas mabagal matuto ngunit maaaring mas tumpak ang convergence\n",
|
||||
"- Maaari kang mag-eksperimento sa pamamagitan ng pagtawag: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Tulad ng nakikita mo, ang paunang katumpakan ay nasa paligid ng 50%, ngunit mabilis itong tumataas sa mas mataas na halaga malapit sa 90%.\n",
|
||||
"\n",
|
||||
"I-visualize natin kung paano nahahati ang mga klase. Ang ating classification function ay mukhang $\\mathbf{w}^Tx$, at ito ay mas mataas sa 0 para sa isang klase, at mas mababa sa 0 para sa isa pa. Kaya, ang linya ng paghihiwalay ng klase ay tinutukoy ng $\\mathbf{w}^Tx = 0$. Dahil mayroon lamang tayong dalawang dimensyon $x_0$ at $x_1$, ang equation para sa linya ay magiging $w_0x_0+w_1x_1+w_2 = 0$ (tandaan na malinaw nating tinukoy ang isang karagdagang dimensyon $x_2=1$). I-plot natin ang linyang ito:\n"
|
||||
"I-visualize natin kung paano nahihiwalay ang mga klase. Ang ating classification function ay mukhang $\\mathbf{w}^Tx$, at ito ay mas mataas sa 0 para sa isang klase, at mas mababa sa 0 para sa isa pa. Kaya, ang linya ng paghihiwalay ng klase ay tinutukoy ng $\\mathbf{w}^Tx = 0$. Dahil mayroon lamang tayong dalawang dimensyon $x_0$ at $x_1$, ang equation para sa linya ay magiging $w_0x_0+w_1x_1+w_2 = 0$ (tandaan na malinaw nating tinukoy ang isang karagdagang dimensyon $x_2=1$). I-plot natin ang linyang ito:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Pagsubok sa Iba't Ibang Learning Rates\n",
|
||||
"\n",
|
||||
"Ngayon, tuklasin natin kung paano naaapektuhan ng iba't ibang learning rates ang proseso ng training. Ang learning rate ang nagkokontrol sa laki ng hakbang sa gradient descent - isang mahalagang hyperparameter na nakakaapekto sa bilis ng convergence at katatagan.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Eksperimento sa Interactive na Learning Rate\n",
|
||||
"\n",
|
||||
"Gamitin ang slider sa ibaba upang subukan nang interaktibo ang iba't ibang learning rate at makita kung paano nito naaapektuhan ang decision boundary:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Suriin sa Test Dataset\n",
|
||||
"\n",
|
||||
"Sa simula, itinabi natin ang ilang data para sa test dataset. Tingnan natin kung gaano katumpak ang ating classifier sa test dataset na ito. Para magawa ito, palalawakin din natin ang test dataset gamit ang isang karagdagang dimensyon, imumultiply sa weights matrix, at titiyakin na ang nakuha na halaga ay may parehong tanda tulad ng label (+1 o -1). Pagkatapos, pagsasamahin natin ang lahat ng boolean values at hahatiin sa haba ng test sample upang makuha ang accuracy:\n"
|
||||
"Sa simula, itinabi natin ang ilang data para sa test dataset. Tingnan natin kung gaano katumpak ang ating classifier sa test dataset na ito. Upang magawa ito, palalawakin din natin ang test dataset gamit ang karagdagang dimensyon, imumultiply sa weights matrix, at titiyakin na ang nakuha na halaga ay may parehong tanda tulad ng label (+1 o -1). Pagkatapos, pagsasamahin natin ang lahat ng boolean values at hahatiin sa haba ng test sample upang makuha ang accuracy:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Pagmamasid sa proseso ng pagsasanay\n",
|
||||
"\n",
|
||||
"Nakita na natin dati kung paano bumababa ang accuracy habang nagsasanay. Maganda sanang makita kung paano gumagalaw ang linya ng paghihiwalay habang nagsasanay. Ang code sa ibaba ay magpapakita ng lahat sa isang graph, at magagawa mong ilipat ang slider upang \"maglakbay sa oras\" sa proseso ng pagsasanay.\n"
|
||||
"Nakita na natin dati kung paano bumababa ang accuracy habang nagsasanay. Maganda sana kung makikita natin kung paano gumagalaw ang linya ng paghihiwalay habang nagsasanay. Ang code sa ibaba ay magpapakita ng lahat sa isang graph, at magagawa mong ilipat ang slider upang \"maglakbay sa oras\" sa proseso ng pagsasanay.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -538,7 +664,7 @@
|
|||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"Subukan natin ito! Manu-mano nating pupunuin ang lahat ng positibo at negatibong training samples, at pagkatapos ay tatawagin ang ating train function na naidefine sa itaas:\n"
|
||||
"Subukan natin ito! Manu-mano nating pupunuin ang lahat ng positibo at negatibong training samples, at pagkatapos ay tatawagin ang ating train function na na-define sa itaas:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -605,13 +731,13 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Tulad ng makikita mo sa graph sa itaas, ang accuracy ay hindi kailanman lumampas sa 75%, dahil imposible ang mag-drawing ng tuwid na linya na makakakuha ng tamang sagot para sa lahat ng posibleng halimbawa.\n",
|
||||
"Tulad ng makikita mo sa graph sa itaas, ang accuracy ay hindi kailanman lumampas sa 75%, dahil imposible ang mag-drawing ng tuwid na linya na makakakuha ng lahat ng tamang halimbawa.\n",
|
||||
"\n",
|
||||
"Ang XOR problem ay isang klasikong halimbawa ng mga limitasyon ng perceptron, at ito ay itinuro nina Marvin Minsky at Seymour Papert noong 1969 sa kanilang aklat na [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Ang obserbasyong ito ay naglimita sa pananaliksik sa larangan ng neural networks sa halos 10 taon, kahit na - at makikita natin ito sa susunod na bahagi ng ating kurso - ang multi-layered perceptrons ay lubos na kayang lutasin ang ganitong mga problema.\n",
|
||||
"\n",
|
||||
"## Mas Komplikadong Halimbawa - MNIST\n",
|
||||
"\n",
|
||||
"Bagamat hindi kayang lutasin ng perceptron ang XOR problem, kaya nitong lutasin ang mas maraming mas komplikadong problema, tulad ng pagkilala sa mga sulat-kamay na karakter.\n",
|
||||
"Kahit na hindi kayang lutasin ng perceptron ang XOR problem, kaya nitong lutasin ang mas maraming mas komplikadong problema, tulad ng pagkilala sa mga sulat-kamay na karakter.\n",
|
||||
"\n",
|
||||
"Ang isang dataset na madalas gamitin sa pag-aaral ng machine learning ay tinatawag na [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Ito ay nilikha ng Modified National Institute of Standards and Technology, at naglalaman ng training set na may 60,000 sulat-kamay na mga numero, na nakolekta mula sa humigit-kumulang 250 estudyante at empleyado ng institusyon. Mayroon ding test dataset na may 10,000 numero, na nakolekta mula sa iba't ibang indibidwal.\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Dahil ang perceptron ay isang binary classifier, lilimitahan natin ang ating problema sa pagkilala lamang ng dalawang numero. Ang function sa ibaba ay magpupuno ng positibo at negatibong sample arrays gamit ang dalawang ibinigay na numero (at ipapakita rin ang mga sample ng mga numerong iyon para sa kalinawan).\n"
|
||||
"Dahil ang perceptron ay isang binary classifier, lilimitahan natin ang ating problema sa pagkilala ng dalawang numero lamang. Ang function sa ibaba ay magpupuno ng positibo at negatibong sample arrays gamit ang dalawang ibinigay na numero (at ipapakita rin ang mga sample ng mga numerong iyon para sa kalinawan).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -835,7 +961,7 @@
|
|||
"\n",
|
||||
"Pakiusog ang slider sa isang posisyon malapit sa dulo ng pagsasanay, at obserbahan ang weight matrix na ipinapakita sa kaliwa. Ang matrix na ito ay magpapaliwanag kung paano talaga gumagana ang perceptron. Makikita mo ang mataas na halaga ng timbang sa gitna ng field, na tumutugma sa mga pixel na karaniwang naroroon para sa digit na 1, at mababang negatibong halaga sa mga gilid, kung saan naroroon ang mga bahagi ng digit na 0. Kaya, kung ang digit na ipinakita sa perceptron ay talagang 1, ang gitnang bahagi nito ay mamumultiply sa mataas na halaga, na magreresulta sa positibong output. Sa kabaligtaran, kapag ang perceptron ay nakakita ng 0, ang mga kaukulang pixel ay mamumultiply sa mga negatibong numero.\n",
|
||||
"\n",
|
||||
"> Mapapansin mo na kung bibigyan natin ang ating perceptron ng digit na 1 na bahagyang nausog nang pahalang, kaya ang mga pixel nito ay sumasakop sa lugar kung saan naroroon ang mga patayong bahagi ng 0, maaaring makuha natin ang maling resulta. Dahil ang likas na katangian ng ating MNIST dataset ay ang lahat ng mga digit ay nakasentro at maayos ang posisyon, at ang perceptron ay umaasa dito upang makilala ang mga digit.\n",
|
||||
"> Mapapansin mo na kung bibigyan natin ang ating perceptron ng digit na 1 na bahagyang nausog nang pahalang, kaya ang mga pixel nito ay sumasakop sa lugar kung saan naroroon ang mga patayong bahagi ng 0, maaari tayong makakuha ng maling resulta. Dahil ang likas na katangian ng ating MNIST dataset ay ang lahat ng mga digit ay nakasentro at maayos ang posisyon, at ang perceptron ay umaasa dito upang makilala ang mga digit.\n",
|
||||
"\n",
|
||||
"Ngayon, subukan natin ang iba't ibang mga digit:\n"
|
||||
]
|
||||
|
|
@ -1027,9 +1153,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Tulad ng nakikita mo, ang 0 at 1 ay maaaring malinaw na paghiwalayin gamit ang isang tuwid na linya. Ipinapakita nito na sa orihinal na 784-dimensional na espasyo, ang mga tuldok na tumutugma sa mga digit ay linearly separable din. Sa kaso ng 2 at 5, hindi natin mahanap ang tamang projection na maghihiwalay nang malinaw sa mga digit, kaya't may ilang mga kaso ng maling klasipikasyon.\n",
|
||||
"Tulad ng nakikita mo, ang 0 at 1 ay maaaring malinaw na paghiwalayin gamit ang isang tuwid na linya. Ipinapakita nito na sa orihinal na 784-dimensional na espasyo, ang mga tuldok na tumutukoy sa mga digit ay linearly separable din. Sa kaso ng 2 at 5, hindi natin mahanap ang tamang projection na maghihiwalay nang malinaw sa mga digit, kaya't may ilang pagkakataon ng maling klasipikasyon.\n",
|
||||
"\n",
|
||||
"> Sa susunod na bahagi ng kursong ito, matutunan natin kung paano gumawa ng mga non-linear na classifier gamit ang Neural Networks, at kung paano harapin ang problema ng mga digit na hindi maayos na naka-align. Hindi magtatagal, maaabot natin ang higit sa 99% na accuracy sa MNIST digit classification, habang ikinuklasipika ang mga ito sa 10 iba't ibang klase.\n",
|
||||
"> Sa susunod na bahagi ng kursong ito, matutunan natin kung paano gumawa ng mga non-linear classifiers gamit ang Neural Networks, at kung paano harapin ang problema ng mga digit na hindi maayos na naka-align. Hindi magtatagal, maaabot natin ang higit sa 99% na accuracy sa MNIST digit classification, habang ikinuklasipika ang mga ito sa 10 iba't ibang klase.\n",
|
||||
"\n",
|
||||
"## Mga Mahalagang Punto\n",
|
||||
"\n",
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Mga Kredito\n",
|
||||
"\n",
|
||||
"Ang notebook na ito ay bahagi ng [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), at inihanda ni [Dmitry Soshnikov](http://soshnikov.com). Ito ay inspirasyon mula sa Neural Network Workshop sa Microsoft Research Cambridge. Ang ilang code at mga materyal na pang-illustrasyon ay kinuha mula sa mga presentasyon nina [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) at [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), at mula sa repositoryong [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Ang notebook na ito ay bahagi ng [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), at inihanda ni [Dmitry Soshnikov](http://soshnikov.com). Ito ay inspirasyon mula sa Neural Network Workshop sa Microsoft Research Cambridge. Ang ilang code at mga materyal na pang-illustrasyon ay kinuha mula sa mga presentasyon nina [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) at [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), at mula sa repository ng [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Paunawa**: \nAng dokumentong ito ay isinalin gamit ang AI translation service na [Co-op Translator](https://github.com/Azure/co-op-translator). Bagama't sinisikap naming maging tumpak, pakitandaan na ang mga awtomatikong pagsasalin ay maaaring maglaman ng mga pagkakamali o hindi pagkakatugma. Ang orihinal na dokumento sa kanyang katutubong wika ang dapat ituring na opisyal na sanggunian. Para sa mahalagang impormasyon, inirerekomenda ang propesyonal na pagsasalin ng tao. Hindi kami mananagot sa anumang hindi pagkakaunawaan o maling interpretasyon na dulot ng paggamit ng pagsasaling ito.\n"
|
||||
"\n---\n\n**Paunawa**: \nAng dokumentong ito ay isinalin gamit ang AI translation service na [Co-op Translator](https://github.com/Azure/co-op-translator). Bagama't sinisikap naming maging tumpak, mangyaring tandaan na ang mga awtomatikong pagsasalin ay maaaring maglaman ng mga pagkakamali o hindi pagkakatugma. Ang orihinal na dokumento sa kanyang katutubong wika ang dapat ituring na opisyal na sanggunian. Para sa mahalagang impormasyon, inirerekomenda ang propesyonal na pagsasalin ng tao. Hindi kami mananagot sa anumang hindi pagkakaunawaan o maling interpretasyon na dulot ng paggamit ng pagsasaling ito.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:39:31+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:27:21+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "tl"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"> Bu not defteri, [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) kapsamında yer almaktadır. Tam öğrenim materyalleri seti için depoyu ziyaret edin.\n",
|
||||
"> Bu not defteri, [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) programının bir parçasıdır. Tam öğrenim materyalleri seti için depoyu ziyaret edin.\n",
|
||||
"\n",
|
||||
"Daha önce tartıştığımız gibi, perceptron **ikili sınıflandırma problemini** çözmenize olanak tanır, yani giriş örneklerini iki sınıfa ayırabilirsiniz - bunlara **pozitif** ve **negatif** diyebiliriz.\n",
|
||||
"\n",
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
"\n",
|
||||
"Başlangıç olarak, iki giriş özelliğine sahip bir oyuncak problemle başlayalım. Örneğin, tıpta tümörleri boyutuna ve yaşına bağlı olarak iyi huylu ve kötü huylu olarak sınıflandırmak isteyebiliriz.\n",
|
||||
"\n",
|
||||
"SciKit Learn kütüphanesinden `make_classification` fonksiyonunu kullanarak rastgele bir sınıflandırma veri seti oluşturacağız:\n"
|
||||
"SciKit Learn kütüphanesindeki `make_classification` fonksiyonunu kullanarak rastgele bir sınıflandırma veri seti oluşturacağız:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Ancak, genel bir doğrusal modelin aynı zamanda bir bias terimi de olmalıdır, yani ideal olarak $y$'yi $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ olarak hesaplamalıyız. Modelimizi basitleştirmek için, giriş özelliklerimize her zaman 1'e eşit olan bir boyut daha ekleyerek bu bias teriminden kurtulabiliriz:\n"
|
||||
"Ancak, genel bir doğrusal modelin bir de bias terimi olmalıdır, yani ideal olarak $y$'yi $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ olarak hesaplamalıyız. Modelimizi basitleştirmek için, giriş özelliklerimize her zaman 1'e eşit olan bir boyut daha ekleyerek bu bias teriminden kurtulabiliriz:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ negatif ve pozitif eğitim örnekleri için sırasıyla\n",
|
||||
" * $\\mathcal{M}$ - yanlış sınıflandırılmış örneklerin kümesi\n",
|
||||
" \n",
|
||||
"**Gradient descent** (gradyan inişi) yöntemini kullanacağız. Başlangıçta rastgele bir ağırlık $\\mathbf{w}^{(0)}$ ile başlayarak, her eğitim adımında $E$'nin gradyanını kullanarak ağırlıkları ayarlayacağız:\n",
|
||||
"**Gradient descent** (gradyan inişi) yöntemini kullanacağız. Başlangıçta rastgele bir $\\mathbf{w}^{(0)}$ ağırlık setiyle başlayarak, her eğitim adımında $E$'nin gradyanını kullanarak ağırlıkları ayarlayacağız:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Öğrenme Oranı Hakkında Not**: `learning_rate` parametresi (varsayılan `0.01`), her eğitim adımında ağırlıkları ne kadar ayarlayacağımızı kontrol eder. Bu, gradyan inişi güncelleme formülünü uygular:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Daha büyük bir öğrenme oranı (örneğin, `1.0`), perceptronun daha hızlı öğrenmesini sağlar ancak optimal çözümü aşabilir\n",
|
||||
"- Daha küçük bir öğrenme oranı (örneğin, `0.001`), daha yavaş öğrenir ancak daha hassas bir şekilde yakınsama sağlayabilir\n",
|
||||
"- Şu şekilde deney yapabilirsiniz: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Gördüğünüz gibi, başlangıç doğruluğu yaklaşık %50 civarında, ancak hızla %90'a yakın daha yüksek değerlere ulaşıyor.\n",
|
||||
"Gördüğünüz gibi, başlangıç doğruluğu yaklaşık %50 civarında, ancak hızla %90'a yakın daha yüksek değerlere çıkıyor.\n",
|
||||
"\n",
|
||||
"Şimdi sınıfların nasıl ayrıldığını görselleştirelim. Sınıflandırma fonksiyonumuz $\\mathbf{w}^Tx$ şeklindedir ve bir sınıf için 0'dan büyük, diğer sınıf için ise 0'dan küçüktür. Dolayısıyla, sınıf ayırma çizgisi $\\mathbf{w}^Tx = 0$ ile tanımlanır. Sadece iki boyutumuz $x_0$ ve $x_1$ olduğu için, çizgi denklemi $w_0x_0+w_1x_1+w_2 = 0$ olacaktır (ekstra bir boyut $x_2=1$ tanımladığımızı unutmayın). Şimdi bu çizgiyi çizelim:\n"
|
||||
"Şimdi sınıfların nasıl ayrıldığını görselleştirelim. Sınıflandırma fonksiyonumuz $\\mathbf{w}^Tx$ şeklindedir ve bir sınıf için 0'dan büyük, diğer sınıf için 0'dan küçüktür. Bu nedenle, sınıf ayırma çizgisi $\\mathbf{w}^Tx = 0$ ile tanımlanır. Sadece iki boyutumuz $x_0$ ve $x_1$ olduğu için, çizgi için denklem $w_0x_0+w_1x_1+w_2 = 0$ olacaktır (unutmayın, açıkça bir ekstra boyut $x_2=1$ tanımlamıştık). Şimdi bu çizgiyi çizelim:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Öğrenme Hızlarıyla Deney Yapma\n",
|
||||
"\n",
|
||||
"Şimdi farklı öğrenme hızlarının eğitim sürecini nasıl etkilediğini inceleyelim. Öğrenme hızı, gradyan inişindeki adım boyutunu kontrol eder - hem yakınsama hızı hem de kararlılığı etkileyen önemli bir hiperparametredir.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Etkileşimli Öğrenme Hızı Deneyi\n",
|
||||
"\n",
|
||||
"Aşağıdaki kaydırıcıyı kullanarak farklı öğrenme hızlarını deneyebilir ve bunların karar sınırını nasıl etkilediğini görebilirsiniz:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## Test Veri Setinde Değerlendirme\n",
|
||||
"\n",
|
||||
"Başlangıçta, test veri seti için bir miktar veri ayırmıştık. Şimdi sınıflandırıcımızın bu test veri setindeki doğruluğunu görelim. Bunu yapmak için, test veri setini ekstra bir boyutla genişletiyoruz, ağırlıklar matrisiyle çarpıyoruz ve elde edilen değerin etiketle (+1 veya -1) aynı işarete sahip olduğundan emin oluyoruz. Daha sonra tüm boolean değerlerini topluyor ve test örneğinin uzunluğuna bölerek doğruluğu elde ediyoruz:\n"
|
||||
"Başlangıçta, test veri seti için bir miktar veri ayırmıştık. Şimdi sınıflandırıcımızın bu test veri setindeki doğruluğunu görelim. Bunu yapmak için, test veri setini ekstra bir boyutla genişletiyoruz, ağırlık matrisini çarpıyoruz ve elde edilen değerin etiketle (+1 veya -1) aynı işarete sahip olduğundan emin oluyoruz. Daha sonra tüm boolean değerlerini topluyor ve test örneğinin uzunluğuna bölerek doğruluğu elde ediyoruz:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -607,17 +733,17 @@
|
|||
"source": [
|
||||
"Yukarıdaki grafikten de görebileceğiniz gibi, doğruluk oranı hiçbir zaman %75'in üzerine çıkmaz, çünkü tüm örnekleri doğru şekilde sınıflandıracak bir doğru çizmek imkansızdır.\n",
|
||||
"\n",
|
||||
"XOR problemi, algılayıcıların sınırlamalarına klasik bir örnektir ve 1969 yılında Marvin Minsky ve Seymour Papert tarafından [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) adlı kitaplarında dile getirilmiştir. Bu gözlem, sinir ağları alanındaki araştırmaları neredeyse 10 yıl boyunca sınırlamıştır. Ancak - bunu kursumuzun bir sonraki bölümünde göreceğiz - çok katmanlı algılayıcılar bu tür problemleri çözme kapasitesine sahiptir.\n",
|
||||
"XOR problemi, algılayıcıların sınırlamalarına klasik bir örnektir ve 1969 yılında Marvin Minsky ve Seymour Papert tarafından [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) adlı kitaplarında dile getirilmiştir. Bu gözlem, nöral ağlar alanındaki araştırmaları neredeyse 10 yıl boyunca sınırlamıştır. Ancak - ve bunu kursumuzun bir sonraki bölümünde göreceğiz - çok katmanlı algılayıcılar bu tür problemleri çözme kapasitesine sahiptir.\n",
|
||||
"\n",
|
||||
"## Karmaşık Örnek - MNIST\n",
|
||||
"\n",
|
||||
"Algılayıcı XOR problemini çözemese de, el yazısı karakter tanıma gibi çok daha karmaşık problemleri çözebilir.\n",
|
||||
"\n",
|
||||
"Makine öğrenimini öğrenirken sıkça kullanılan bir veri seti [MNIST](https://en.wikipedia.org/wiki/MNIST_database) olarak adlandırılır. Bu veri seti, Ulusal Standartlar ve Teknoloji Enstitüsü tarafından oluşturulmuş ve 60000 el yazısı rakamdan oluşan bir eğitim seti içerir. Bu rakamlar, enstitüdeki yaklaşık 250 öğrenci ve çalışan tarafından toplanmıştır. Ayrıca, farklı bireylerden toplanmış 10000 rakamdan oluşan bir test veri seti de bulunmaktadır.\n",
|
||||
"Makine öğrenimini öğrenirken sıkça kullanılan bir veri seti [MNIST](https://en.wikipedia.org/wiki/MNIST_database) olarak adlandırılır. Bu veri seti, Ulusal Standartlar ve Teknoloji Enstitüsü tarafından oluşturulmuş ve yaklaşık 250 öğrenci ve enstitü çalışanından toplanmış 60000 el yazısı rakam içeren bir eğitim seti içerir. Ayrıca, farklı bireylerden toplanmış 10000 rakam içeren bir test veri seti de bulunmaktadır.\n",
|
||||
"\n",
|
||||
"Tüm rakamlar, 28x28 piksel boyutunda gri tonlamalı görüntülerle temsil edilmektedir.\n",
|
||||
"Tüm rakamlar, 28x28 piksel boyutunda gri tonlamalı görüntülerle temsil edilir.\n",
|
||||
"\n",
|
||||
"> MNIST Veri Seti, makine öğrenimi yarışmalarına ve yarışmalarına ev sahipliği yapan bir site olan [Kaggle](https://www.kaggle.com/c/digit-recognizer) üzerinde bir eğitim yarışması olarak mevcuttur. MNIST rakamlarını nasıl sınıflandıracağınızı öğrendikten sonra, çözümünüzü Kaggle'a göndererek diğer katılımcılar arasında nasıl değerlendirildiğini görebilirsiniz.\n",
|
||||
"> MNIST Veri Seti, makine öğrenimi yarışmaları ve yarışmalarına ev sahipliği yapan bir site olan [Kaggle](https://www.kaggle.com/c/digit-recognizer) üzerinde bir eğitim yarışması olarak mevcuttur. MNIST rakamlarını nasıl sınıflandıracağınızı öğrendikten sonra, çözümünüzü Kaggle'a göndererek diğer katılımcılar arasında nasıl değerlendirildiğini görebilirsiniz.\n",
|
||||
"\n",
|
||||
"MNIST veri setini yükleyerek başlıyoruz:\n"
|
||||
]
|
||||
|
|
@ -644,7 +770,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Şimdi veri setini çizdirelim:\n"
|
||||
"Haydi şimdi veri setini çizelim:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Perceptron bir ikili sınıflandırıcı olduğu için, problemimizi yalnızca iki rakamı tanımakla sınırlayacağız. Aşağıdaki fonksiyon, verilen iki rakamla pozitif ve negatif örnek dizilerini dolduracak (ve ayrıca açıklık için bu rakamların örneklerini gösterecektir).\n"
|
||||
"Perceptron bir ikili sınıflandırıcı olduğu için, problemimizi yalnızca iki rakamı tanımayla sınırlandıracağız. Aşağıdaki fonksiyon, verilen iki rakamla pozitif ve negatif örnek dizilerini dolduracak (ve ayrıca açıklık sağlamak için bu rakamların örneklerini gösterecektir).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"Lütfen, doğruluğun çok hızlı bir şekilde neredeyse %100'e çıktığını fark edin.\n",
|
||||
"\n",
|
||||
"Eğitimin sonlarına doğru kaydırıcıyı bir konuma getirin ve sol tarafta çizilen ağırlık matrisini gözlemleyin. Bu matris, algılayıcının (perceptron) nasıl çalıştığını anlamanızı sağlayacaktır. Alanın ortasında genellikle 1 rakamı için mevcut olan piksellere karşılık gelen yüksek ağırlık değerlerini ve 0 rakamının parçalarının bulunduğu kenarlarda düşük negatif değerleri görebilirsiniz. Dolayısıyla, algılayıcıya sunulan rakam gerçekten 1 ise, orta kısmı yüksek değerlerle çarpılacak ve pozitif bir sonuç üretecektir. Buna karşılık, algılayıcı 0'ı gözlemlediğinde, ilgili pikseller negatif sayılarla çarpılacaktır.\n",
|
||||
"Eğitimin sonuna doğru bir noktaya kaydırıcıyı hareket ettirin ve sol tarafta çizilen ağırlık matrisini gözlemleyin. Bu matris, perceptron'un nasıl çalıştığını anlamanızı sağlayacaktır. Alanın ortasında genellikle 1 rakamı için mevcut olan piksellere karşılık gelen yüksek ağırlık değerlerini ve kenarlarda, 0 rakamının parçalarının bulunduğu yerlerde düşük negatif değerleri görebilirsiniz. Dolayısıyla, perceptron'a sunulan rakam gerçekten 1 ise, orta kısmı yüksek değerlerle çarpılacak ve pozitif bir sonuç üretecektir. Buna karşılık, perceptron 0 rakamını gözlemlediğinde, ilgili pikseller negatif sayılarla çarpılacaktır.\n",
|
||||
"\n",
|
||||
"> Algılayıcımıza yatay olarak hafifçe kaydırılmış bir 1 rakamı verirsek, pikselleri 0'ın dikey parçalarının bulunduğu yere denk gelirse, yanlış bir sonuç alabileceğimizi fark edebilirsiniz. MNIST veri setimizin doğası gereği, tüm rakamlar merkezlenmiş ve düzgün bir şekilde konumlandırılmıştır ve algılayıcı, rakamları ayırt etmek için buna güvenir.\n",
|
||||
"> Şunu fark edebilirsiniz: Eğer perceptron'a yatay olarak hafifçe kaydırılmış bir 1 rakamı verirsek, yani pikselleri 0'ın dikey parçalarının bulunduğu yere denk gelirse, yanlış bir sonuç alabiliriz. MNIST veri setimizin doğası gereği tüm rakamlar merkezlenmiş ve düzgün bir şekilde konumlandırılmıştır, ve perceptron rakamları ayırt etmek için buna güvenir.\n",
|
||||
"\n",
|
||||
"Şimdi farklı rakamları deneyelim:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Tartışma\n",
|
||||
"\n",
|
||||
"Bazı nedenlerden dolayı, 2 ve 5 rakamları birbirinden kolayca ayrılabilir değil. Yüksek doğruluk oranı (yüzde 85'in üzerinde) elde etmemize rağmen, perceptronun bir noktada öğrenmeyi durdurduğunu açıkça görebiliyoruz.\n",
|
||||
"Bazı nedenlerden dolayı, 2 ve 5 rakamları kolayca ayrılabilir değil. Yüksek doğruluk oranı (yüzde 85'in üzerinde) elde etsek bile, perceptron'un bir noktada öğrenmeyi durdurduğunu açıkça görebiliyoruz.\n",
|
||||
"\n",
|
||||
"Bu durumun nedenini anlamak için [Temel Bileşen Analizi](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) kullanmayı deneyebiliriz. PCA, sınıflar arasında en iyi ayrımı elde etmek amacıyla giriş veri setinin boyutunu azaltmak için kullanılan bir makine öğrenimi tekniğidir.\n",
|
||||
"\n",
|
||||
"Bizim durumumuzda, bir giriş görüntüsü 784 piksel (giriş özellikleri) içeriyor ve PCA'yı kullanarak parametre sayısını sadece 2'ye düşürmek istiyoruz, böylece bunları grafikte gösterebiliriz. Bu iki parametre, orijinal özelliklerin lineer bir kombinasyonu olacaktır ve bu işlemi, orijinal 784 boyutlu uzayımızı \"döndürmek\" ve sınıfları en iyi şekilde ayıran görünümü elde edene kadar 2 boyutlu uzayımıza projeksiyonunu gözlemlemek olarak düşünebiliriz.\n"
|
||||
"Bizim durumumuzda, bir giriş görüntüsü 784 pikselden (giriş özellikleri) oluşuyor ve PCA'yı kullanarak parametre sayısını sadece 2'ye düşürmek istiyoruz, böylece bunları bir grafikte çizebiliriz. Bu iki parametre, orijinal özelliklerin lineer bir kombinasyonu olacak ve bu işlemi, orijinal 784 boyutlu uzayımızı \"döndürmek\" ve sınıfları en iyi şekilde ayıran görünümü elde edene kadar 2 boyutlu uzaya projeksiyonunu gözlemlemek olarak düşünebiliriz.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1033,8 +1159,8 @@
|
|||
"\n",
|
||||
"## Özet\n",
|
||||
"\n",
|
||||
" * En basit sinir ağı mimarisini - tek katmanlı perceptron - öğrendik.\n",
|
||||
" * Perceptron'u \"elle\" basit bir eğitim prosedürü kullanarak, gradient descent temelli olarak uyguladık.\n",
|
||||
" * En basit sinir ağı mimarisi olan tek katmanlı perceptron hakkında bilgi edindik.\n",
|
||||
" * Perceptron'u \"elle\" uyguladık ve basit bir eğitim prosedürü olan gradient descent kullandık.\n",
|
||||
" * Basitliğine rağmen, tek katmanlı perceptron el yazısı rakam tanıma gibi oldukça karmaşık problemleri çözebilir.\n",
|
||||
" * Tek katmanlı perceptron doğrusal bir sınıflandırıcıdır ve bu nedenle lojistik regresyon ile aynı sınıflandırma gücünü sağlar.\n",
|
||||
" * Örnek uzayında, perceptron giriş verisinin iki sınıfını bir hiper düzlem kullanarak ayırabilir.\n"
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Katkılar\n",
|
||||
"\n",
|
||||
"Bu not defteri, [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) programının bir parçasıdır ve [Dmitry Soshnikov](http://soshnikov.com) tarafından hazırlanmıştır. Microsoft Research Cambridge'deki Neural Network Workshop'tan ilham alınmıştır. Bazı kodlar ve görsel materyaller [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) ve [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) tarafından yapılan sunumlardan ve [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) deposundan alınmıştır.\n"
|
||||
"Bu not defteri, [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) programının bir parçasıdır ve [Dmitry Soshnikov](http://soshnikov.com) tarafından hazırlanmıştır. Microsoft Research Cambridge'deki Sinir Ağı Atölyesi'nden ilham alınmıştır. Bazı kodlar ve görsel materyaller, [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) ve [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) tarafından yapılan sunumlardan ve [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) deposundan alınmıştır.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Feragatname**: \nBu belge, AI çeviri hizmeti [Co-op Translator](https://github.com/Azure/co-op-translator) kullanılarak çevrilmiştir. Doğruluk için çaba göstersek de, otomatik çevirilerin hata veya yanlışlıklar içerebileceğini lütfen unutmayın. Belgenin orijinal dili, yetkili kaynak olarak kabul edilmelidir. Kritik bilgiler için profesyonel insan çevirisi önerilir. Bu çevirinin kullanımından kaynaklanan yanlış anlamalar veya yanlış yorumlamalar için sorumluluk kabul etmiyoruz.\n"
|
||||
"\n---\n\n**Feragatname**: \nBu belge, AI çeviri hizmeti [Co-op Translator](https://github.com/Azure/co-op-translator) kullanılarak çevrilmiştir. Doğruluk için çaba göstersek de, otomatik çevirilerin hata veya yanlışlık içerebileceğini lütfen unutmayın. Belgenin orijinal dili, yetkili kaynak olarak kabul edilmelidir. Kritik bilgiler için profesyonel insan çevirisi önerilir. Bu çevirinin kullanımından kaynaklanan yanlış anlamalar veya yanlış yorumlamalar için sorumluluk kabul etmiyoruz.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:27:41+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:15:01+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "tr"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"\n",
|
||||
"如我們所討論的,感知器可以幫助解決**二元分類問題**,也就是將輸入範例分類為兩個類別——我們可以稱它們為**正類**和**負類**。\n",
|
||||
"\n",
|
||||
"首先,讓我們導入一些所需的庫。\n"
|
||||
"首先,讓我們導入一些必要的庫。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
"source": [
|
||||
"## 感知器\n",
|
||||
"\n",
|
||||
"由於感知器是一種二元分類器,對於每個輸入向量 $x$,感知器的輸出將根據所屬的類別為 +1 或 -1。輸出將根據以下公式計算:\n",
|
||||
"由於感知器是一種二元分類器,對於每個輸入向量 $x$,感知器的輸出將根據所屬的類別為 +1 或 -1。輸出將通過以下公式計算:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"然而,一般的線性模型通常還需要一個偏置項,也就是說,理想情況下我們應該計算 $y$ 為 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$。為了簡化模型,我們可以通過在輸入特徵中添加一個始終等於 1 的維度來消除這個偏置項:\n"
|
||||
"然而,一般的線性模型通常還需要一個偏差項,也就是說,理想情況下我們應該計算 $y$ 為 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$。為了簡化模型,我們可以通過在輸入特徵中添加一個始終等於 1 的維度來消除這個偏差項:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -210,14 +210,14 @@
|
|||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ 分別表示負樣本和正樣本的標籤\n",
|
||||
" * $t_{n} \\in \\{-1, +1\\}$ 分別代表負樣本和正樣本的標籤\n",
|
||||
" * $\\mathcal{M}$ - 錯誤分類的樣本集合\n",
|
||||
" \n",
|
||||
"我們將使用**梯度下降**的過程。從一些初始隨機權重 $\\mathbf{w}^{(0)}$ 開始,我們會在訓練的每一步根據 $E$ 的梯度來調整權重:\n",
|
||||
"我們將使用**梯度下降**的過程。從某些初始隨機權重 $\\mathbf{w}^{(0)}$ 開始,我們將在訓練的每一步根據 $E$ 的梯度調整權重:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"其中 $\\eta$ 是**學習率**,$\\tau\\in\\mathbb{N}$ 表示迭代次數。\n",
|
||||
"其中 $\\eta$ 是**學習率**,$\\tau\\in\\mathbb{N}$ 是迭代次數。\n",
|
||||
"\n",
|
||||
"以下是用 Python 定義此算法:\n"
|
||||
]
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -272,7 +272,20 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"現在讓我們在我們的數據集上運行訓練:\n"
|
||||
"**學習率的注意事項**:`learning_rate` 參數(預設值為 `0.01`)控制每次訓練步驟中調整權重的幅度。這是根據梯度下降更新公式實現的:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- 較大的學習率(例如 `1.0`)會使感知器學習速度加快,但可能會超出最佳解\n",
|
||||
"- 較小的學習率(例如 `0.001`)學習速度較慢,但可能更精確地收斂\n",
|
||||
"- 您可以透過以下方式進行嘗試:`train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"現在讓我們在我們的數據集上進行訓練:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"如您所見,初始準確率約為 50%,但很快就提升到接近 90% 的較高值。\n",
|
||||
"\n",
|
||||
"接下來,我們來視覺化類別的分隔情況。我們的分類函數形式為 $\\mathbf{w}^Tx$,對於某一類別,其值大於 0;而對於另一類別,其值則小於 0。因此,類別分隔線由 $\\mathbf{w}^Tx = 0$ 定義。由於我們只有兩個維度 $x_0$ 和 $x_1$,該直線的方程式為 $w_0x_0+w_1x_1+w_2 = 0$(請記住,我們已明確定義了一個額外的維度 $x_2=1$)。現在讓我們繪製這條直線:\n"
|
||||
"接下來,我們來視覺化類別的分隔情況。我們的分類函數形式為 $\\mathbf{w}^Tx$,對於一個類別,其值大於 0;對於另一個類別,其值小於 0。因此,類別分隔線由 $\\mathbf{w}^Tx = 0$ 定義。由於我們只有兩個維度 $x_0$ 和 $x_1$,該直線的方程式為 $w_0x_0+w_1x_1+w_2 = 0$(請記住,我們已明確定義了一個額外的維度 $x_2=1$)。現在讓我們繪製這條直線:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 探索學習率\n",
|
||||
"\n",
|
||||
"現在讓我們來探討不同的學習率如何影響訓練過程。學習率控制梯度下降中的步伐大小——這是一個重要的超參數,影響收斂速度和穩定性。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 互動式學習率實驗\n",
|
||||
"\n",
|
||||
"使用下面的滑桿,互動式地嘗試不同的學習率,並觀察它們如何影響決策邊界:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## 觀察訓練過程\n",
|
||||
"\n",
|
||||
"我們之前已經看到,準確率在訓練過程中會下降。能夠觀察分隔線在訓練過程中的變化會很有趣。以下的程式碼將把所有內容可視化在一個圖表上,您可以移動滑桿來「時光旅行」查看訓練過程中的變化。\n"
|
||||
"我們之前已經看到在訓練過程中準確率如何下降。能夠看到分隔線在訓練過程中的變化會很有趣。以下的程式碼將把所有內容可視化在一個圖表上,您可以移動滑桿來「時光旅行」觀察訓練過程。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -607,7 +733,7 @@
|
|||
"source": [
|
||||
"如上圖所示,準確率從未超過 75%,因為不可能畫出一條直線來正確分類所有可能的例子。\n",
|
||||
"\n",
|
||||
"XOR 問題是感知器局限性的經典例子,這一點在 1969 年由 Marvin Minsky 和 Seymour Papert 在他們的書籍 [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) 中指出。這一觀察限制了神經網絡領域的研究近 10 年,儘管——我們會在課程的下一部分看到——多層感知器完全能夠解決這類問題。\n",
|
||||
"XOR 問題是感知器局限性的經典例子,這一點在 1969 年由 Marvin Minsky 和 Seymour Papert 在他們的書籍 [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)) 中指出。這一觀察限制了神經網絡領域的研究近十年,儘管——我們會在課程的下一部分看到——多層感知器完全有能力解決這類問題。\n",
|
||||
"\n",
|
||||
"## 複雜範例 - MNIST\n",
|
||||
"\n",
|
||||
|
|
@ -617,7 +743,7 @@
|
|||
"\n",
|
||||
"所有數字都以 28x28 像素的灰度圖像表示。\n",
|
||||
"\n",
|
||||
"> MNIST 數據集作為一個訓練競賽可在 [Kaggle](https://www.kaggle.com/c/digit-recognizer) 上找到,Kaggle 是一個舉辦機器學習競賽和比賽的網站。一旦你學會如何分類 MNIST 數字,你可以將你的解決方案提交到 Kaggle,看看它在其他參賽者中的排名。\n",
|
||||
"> MNIST 數據集作為一個訓練競賽可在 [Kaggle](https://www.kaggle.com/c/digit-recognizer) 上找到,這是一個舉辦機器學習競賽和比賽的網站。一旦你學會如何分類 MNIST 數字,你可以將你的解決方案提交到 Kaggle,看看它在其他參賽者中的排名。\n",
|
||||
"\n",
|
||||
"我們首先載入 MNIST 數據集:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"因為感知器是一個二元分類器,我們將把問題限制在僅識別兩個數字。以下函數將使用兩個給定的數字填充正樣本和負樣本數組(並且還會顯示這些數字的樣本以便清晰)。\n"
|
||||
"因為感知器是一個二元分類器,我們將把問題限制在僅識別兩個數字。以下函數將使用兩個給定的數字填充正樣本和負樣本陣列(並且也會顯示這些數字的樣本以便清晰)。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"請注意,準確率會非常快速地接近幾乎 100%。\n",
|
||||
"\n",
|
||||
"請將滑桿移動到訓練過程接近尾聲的位置,並觀察左側繪製的權重矩陣。這個矩陣可以幫助您理解感知器的實際運作方式。您可以看到矩陣中間的高權重值,這些值對應於通常出現在數字 1 中的像素;而矩陣兩側則是低的負值,這些位置通常是數字 0 的部分。因此,如果呈現給感知器的數字確實是 1,中間部分的像素會與高權重值相乘,產生正的結果。相反地,當感知器觀察到數字 0 時,對應的像素會與負數相乘。\n",
|
||||
"請將滑桿移動到訓練過程接近尾聲的位置,並觀察左側繪製的權重矩陣。這個矩陣可以幫助你理解感知器的實際運作方式。你可以看到矩陣中間的高權重值,這些值對應於通常出現在數字 1 中的像素;而矩陣兩側則是低的負值,這些位置通常是數字 0 的部分。因此,如果呈現給感知器的數字確實是 1,中間部分的像素會被高權重值相乘,產生正的結果。相反地,當感知器觀察到數字 0 時,對應的像素會被負數相乘。\n",
|
||||
"\n",
|
||||
"> 您可能會注意到,如果我們給感知器一個數字 1,並且稍微水平移動,使其像素佔據了數字 0 垂直部分的位置,我們可能會得到錯誤的結果。由於 MNIST 數據集的特性是所有數字都居中且定位正確,感知器依賴這一特性來區分數字。\n",
|
||||
"> 你可能會注意到,如果我們給感知器一個數字 1,並且稍微水平移動,使其像素佔據數字 0 垂直部分的位置,我們可能會得到錯誤的結果。由於 MNIST 數據集的特性是所有數字都居中且定位正確,感知器依賴這一特性來區分數字。\n",
|
||||
"\n",
|
||||
"現在讓我們嘗試不同的數字:\n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"出於某些原因,數字 2 和 5 並不容易分開。即使我們的準確率相對較高(超過 85%),我們仍然可以明顯看到感知器在某個時刻停止學習。\n",
|
||||
"\n",
|
||||
"為了理解為什麼會發生這種情況,我們可以嘗試使用[主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)。這是一種機器學習技術,用於降低輸入數據集的維度,以便獲得最佳的類別可分性。\n",
|
||||
"為了理解為什麼會發生這種情況,我們可以嘗試使用 [主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)。這是一種機器學習技術,用於降低輸入數據集的維度,以便獲得最佳的類別可分性。\n",
|
||||
"\n",
|
||||
"在我們的例子中,輸入圖像有 784 個像素(輸入特徵),我們希望使用 PCA 將參數數量減少到僅僅 2 個,這樣我們就可以在圖表上繪製它們。這兩個參數將是原始特徵的線性組合,我們可以將這個過程視為“旋轉”我們原本的 784 維空間,並觀察其在 2D 空間中的投影,直到我們獲得最佳視角來分離這些類別。\n"
|
||||
"在我們的例子中,輸入圖像有 784 個像素(輸入特徵),我們希望使用 PCA 將參數數量減少到僅僅 2 個,這樣我們就可以在圖表上繪製它們。這兩個參數將是原始特徵的線性組合,我們可以將這個過程視為“旋轉”我們原本的 784 維空間,並觀察其在 2D 空間中的投影,直到我們獲得最佳視角來分離類別。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,14 +1153,14 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"如您所見,0 和 1 可以用一條直線清楚地分隔開來。這表明在原始的 784 維空間中,與數字對應的點也是線性可分的。而在 2 和 5 的情況下,我們無法找到能清楚分隔這些數字的良好投影,因此會出現一些錯誤分類的情況。\n",
|
||||
"如您所見,0 和 1 可以用一條直線清楚地分隔開來。這表明在原始的784維空間中,與數字對應的點也是線性可分的。而在2和5的情況下,我們無法找到能清楚分隔這些數字的良好投影,因此會出現一些錯誤分類的情況。\n",
|
||||
"\n",
|
||||
"> 在這門課程的後續部分,我們將學習如何使用神經網絡創建非線性分類器,以及如何處理數字未正確對齊的問題。很快,我們將在 MNIST 數字分類中達到超過 99% 的準確率,同時將數字分類為 10 個不同的類別。\n",
|
||||
"> 在這門課程的後續部分,我們將學習如何使用神經網絡創建非線性分類器,以及如何處理數字未正確對齊的問題。不久之後,我們將在MNIST數字分類中達到超過99%的準確率,同時將數字分類為10個不同的類別。\n",
|
||||
"\n",
|
||||
"## 重點\n",
|
||||
"\n",
|
||||
" * 我們學習了最簡單的神經網絡架構——單層感知器。\n",
|
||||
" * 我們使用基於梯度下降的簡單訓練過程,\"手動\"實現了感知器。\n",
|
||||
" * 我們通過手動實現了感知器,使用基於梯度下降的簡單訓練過程。\n",
|
||||
" * 儘管簡單,單層感知器可以解決相當複雜的手寫數字識別問題。\n",
|
||||
" * 單層感知器是一個線性分類器,因此它提供的分類能力與邏輯回歸相同。\n",
|
||||
" * 在樣本空間中,感知器可以使用超平面分隔輸入數據的兩個類別。\n"
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## 致謝\n",
|
||||
"\n",
|
||||
"此筆記本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分,由 [Dmitry Soshnikov](http://soshnikov.com) 編寫。靈感來自於微軟劍橋研究院的神經網絡工作坊。一些代碼和示例材料取自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示文稿,以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 資源庫。\n"
|
||||
"此筆記本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分,由 [Dmitry Soshnikov](http://soshnikov.com) 編寫。靈感來自於微軟劍橋研究院的神經網絡工作坊。一些程式碼和示例材料取自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示,以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 資料庫。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**免責聲明**: \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。\n"
|
||||
"\n---\n\n**免責聲明**: \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:15:40+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:01:48+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "tw"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"source": [
|
||||
"## Перцептрон\n",
|
||||
"\n",
|
||||
"> Цей ноутбук є частиною [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Відвідайте репозиторій для повного набору навчальних матеріалів.\n",
|
||||
"> Цей блокнот є частиною [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Відвідайте репозиторій для повного набору навчальних матеріалів.\n",
|
||||
"\n",
|
||||
"Як ми вже обговорювали, перцептрон дозволяє вирішувати **задачу бінарної класифікації**, тобто класифікувати вхідні приклади на два класи - ми можемо назвати їх **позитивний** і **негативний**.\n",
|
||||
"\n",
|
||||
|
|
@ -206,7 +206,7 @@
|
|||
"source": [
|
||||
"## Алгоритм навчання\n",
|
||||
"\n",
|
||||
"Для навчання перцептрона нам потрібно знайти ваги $\\mathbf{w}$, які мінімізують помилку. Помилка визначається за допомогою **критерію перцептрона**:\n",
|
||||
"Для навчання перцептрона необхідно знайти ваги $\\mathbf{w}$, які мінімізують помилку. Помилка визначається за допомогою **критерію перцептрона**:\n",
|
||||
"\n",
|
||||
"$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n",
|
||||
" \n",
|
||||
|
|
@ -219,7 +219,7 @@
|
|||
"\n",
|
||||
"де $\\eta$ - **швидкість навчання**, а $\\tau\\in\\mathbb{N}$ - номер ітерації.\n",
|
||||
"\n",
|
||||
"Давайте визначимо цей алгоритм на Python:\n"
|
||||
"Визначимо цей алгоритм на Python:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Примітка щодо швидкості навчання**: Параметр `learning_rate` (за замовчуванням `0.01`) визначає, наскільки ми коригуємо ваги під час кожного кроку навчання. Це реалізує формулу оновлення градієнтного спуску:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Більша швидкість навчання (наприклад, `1.0`) дозволяє перцептрону навчатися швидше, але може призвести до пропуску оптимального рішення\n",
|
||||
"- Менша швидкість навчання (наприклад, `0.001`) забезпечує повільніше навчання, але може точніше збігатися з оптимальним рішенням\n",
|
||||
"- Ви можете експериментувати, викликаючи: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -313,7 +326,7 @@
|
|||
"source": [
|
||||
"Як ви можете бачити, початкова точність становить близько 50%, але вона швидко зростає до вищих значень, близьких до 90%.\n",
|
||||
"\n",
|
||||
"Давайте візуалізуємо, як класи розділяються. Наша функція класифікації виглядає як $\\mathbf{w}^Tx$, і вона більша за 0 для одного класу, а менша за 0 для іншого. Таким чином, лінія розділення класів визначається рівнянням $\\mathbf{w}^Tx = 0$. Оскільки у нас є лише дві виміри $x_0$ та $x_1$, рівняння для лінії буде $w_0x_0+w_1x_1+w_2 = 0$ (пам'ятайте, що ми явно визначили додаткову вимірність $x_2=1$). Давайте побудуємо цю лінію:\n"
|
||||
"Давайте візуалізуємо, як класи розділяються. Наша функція класифікації виглядає як $\\mathbf{w}^Tx$, і вона більша за 0 для одного класу, а менша за 0 для іншого. Таким чином, лінія розділення класів визначається рівнянням $\\mathbf{w}^Tx = 0$. Оскільки у нас є лише два виміри $x_0$ та $x_1$, рівняння для лінії буде $w_0x_0+w_1x_1+w_2 = 0$ (пам'ятайте, що ми явно визначили додатковий вимір $x_2=1$). Давайте побудуємо цю лінію:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Експериментування з темпами навчання\n",
|
||||
"\n",
|
||||
"Тепер давайте дослідимо, як різні темпи навчання впливають на процес тренування. Темп навчання визначає розмір кроку в градієнтному спуску — це важливий гіперпараметр, який впливає як на швидкість збіжності, так і на стабільність.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Інтерактивний експеримент з навчальною швидкістю\n",
|
||||
"\n",
|
||||
"Використовуйте повзунок нижче, щоб інтерактивно експериментувати з різними навчальними швидкостями та побачити, як вони впливають на межу прийняття рішень:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## Спостереження за процесом навчання\n",
|
||||
"\n",
|
||||
"Ми вже бачили, як точність зменшується під час навчання. Було б цікаво побачити, як змінюється лінія розділення під час навчання. Наведений нижче код дозволить візуалізувати все на одному графіку, і ви зможете переміщати повзунок, щоб \"подорожувати в часі\" через процес навчання.\n"
|
||||
"Ми вже бачили, як точність зменшується під час навчання. Було б цікаво побачити, як змінюється лінія розділення під час навчання. Наведений нижче код дозволить візуалізувати все на одному графіку, і ви зможете переміщати повзунок, щоб \"подорожувати у часі\" через процес навчання.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -529,9 +655,9 @@
|
|||
"source": [
|
||||
"## Обмеження перцептрона\n",
|
||||
"\n",
|
||||
"Як ви вже бачили, перцептрон є **лінійним класифікатором**. Він добре розрізняє два класи, якщо вони **лінійно роздільні**, тобто можуть бути розділені прямою лінією. В іншому випадку процес навчання перцептрона не буде сходитися.\n",
|
||||
"Як ви бачили вище, перцептрон є **лінійним класифікатором**. Він добре розрізняє два класи, якщо вони **лінійно роздільні**, тобто можуть бути розділені прямою лінією. В іншому випадку процес навчання перцептрона не буде сходитися.\n",
|
||||
"\n",
|
||||
"Найочевиднішим прикладом задачі, яку неможливо вирішити за допомогою перцептрона, є так звана **XOR задача**. Ми хочемо, щоб наш перцептрон навчився булевій функції XOR, яка має наступну таблицю істинності:\n",
|
||||
"Найочевиднішим прикладом задачі, яку не можна вирішити за допомогою перцептрона, є так звана **XOR задача**. Ми хочемо, щоб наш перцептрон навчився булевій функції XOR, яка має наступну таблицю істинності:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -605,7 +731,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Як видно з графіка вище, точність ніколи не перевищує 75%, оскільки неможливо провести пряму лінію таким чином, щоб правильно класифікувати всі можливі приклади.\n",
|
||||
"Як видно з графіка вище, точність ніколи не перевищує 75%, оскільки неможливо провести пряму лінію так, щоб правильно класифікувати всі можливі приклади.\n",
|
||||
"\n",
|
||||
"Проблема XOR є класичним прикладом обмежень перцептрона, і на неї звернули увагу Марвін Мінскі та Сеймур Паперт у 1969 році у своїй книзі [Perceptrons](https://en.wikipedia.org/wiki/Perceptrons_(book)). Це спостереження обмежило дослідження в області нейронних мереж майже на 10 років, хоча - і ми побачимо це в наступному розділі нашого курсу - багатошарові перцептрони цілком здатні вирішувати такі задачі.\n",
|
||||
"\n",
|
||||
|
|
@ -835,7 +961,7 @@
|
|||
"\n",
|
||||
"Будь ласка, перемістіть повзунок до якоїсь позиції ближче до кінця навчання і спостерігайте за матрицею ваг, яка відображається зліва. Ця матриця допоможе вам зрозуміти, як працює перцептрон. Ви можете побачити високі значення ваг у центрі поля, які відповідають пікселям, що зазвичай присутні для цифри 1, і низькі негативні значення по краях, де знаходяться частини цифри 0. Отже, якщо цифра, представлена перцептрону, дійсно є 1, її центральна частина буде множитися на високі значення, що дасть позитивний результат. Навпаки, коли перцептрон бачить цифру 0, відповідні пікселі будуть множитися на негативні числа.\n",
|
||||
"\n",
|
||||
"> Ви можете помітити, що якщо ми подамо нашому перцептрону цифру 1, трохи зміщену горизонтально, так що її пікселі займають місце, де знаходяться вертикальні частини цифри 0, ми можемо отримати некоректний результат. Оскільки природа нашого набору даних MNIST така, що всі цифри центровані та правильно позиціоновані, перцептрон покладається на це для розрізнення цифр.\n",
|
||||
"> Ви можете помітити, що якщо ми дамо нашому перцептрону цифру 1, трохи зміщену горизонтально, так що її пікселі займають місце, де знаходяться вертикальні частини цифри 0, ми можемо отримати некоректний результат. Оскільки природа нашого набору даних MNIST така, що всі цифри центровані та правильно позиціоновані, перцептрон покладається на це для розрізнення цифр.\n",
|
||||
"\n",
|
||||
"Тепер спробуймо різні цифри:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## Обговорення\n",
|
||||
"\n",
|
||||
"З якоїсь причини цифри 2 і 5 не так легко розділити. Хоча ми отримуємо відносно високу точність (понад 85%), ми чітко бачимо, як перцептрон перестає навчатися на певному етапі.\n",
|
||||
"З якоїсь причини цифри 2 і 5 не так легко розділити. Хоча ми отримуємо досить високу точність (понад 85%), можна чітко побачити, як перцептрон перестає навчатися на певному етапі.\n",
|
||||
"\n",
|
||||
"Щоб зрозуміти, чому це відбувається, ми можемо спробувати використати [Аналіз головних компонент](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Це техніка машинного навчання, яка використовується для зменшення розмірності вхідного набору даних таким чином, щоб досягти найкращого розділення між класами.\n",
|
||||
"\n",
|
||||
"У нашому випадку вхідне зображення має 784 пікселі (вхідні ознаки), і ми хочемо використати PCA, щоб зменшити кількість параметрів до лише 2, щоб ми могли побудувати їх на графіку. Ці два параметри будуть лінійною комбінацією оригінальних ознак, і ми можемо розглядати цю процедуру як \"обертання\" нашого початкового 784-вимірного простору та спостереження його проекції на наш 2D-простір, поки ми не отримаємо найкращий вигляд, який розділяє класи.\n"
|
||||
"У нашому випадку вхідне зображення має 784 пікселі (вхідні ознаки), і ми хочемо використати PCA, щоб зменшити кількість параметрів до лише 2, щоб можна було побудувати їх графік. Ці два параметри будуть лінійною комбінацією оригінальних ознак, і цей процес можна уявити як \"обертання\" нашого початкового 784-вимірного простору та спостереження його проекції на 2D-простір, поки ми не отримаємо найкращий вигляд, який розділяє класи.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1031,9 +1157,9 @@
|
|||
"\n",
|
||||
"> Пізніше в цьому курсі ми навчимося створювати нелінійні класифікатори за допомогою нейронних мереж і вирішувати проблему неправильного вирівнювання цифр. Дуже скоро ми досягнемо точності понад 99% у класифікації цифр MNIST, класифікуючи їх у 10 різних класів.\n",
|
||||
"\n",
|
||||
"## Основні висновки\n",
|
||||
"## Висновки\n",
|
||||
"\n",
|
||||
" * Ми ознайомилися з найпростішою архітектурою нейронної мережі — одношаровим перцептроном.\n",
|
||||
" * Ми дізналися про найпростішу архітектуру нейронної мережі — одношаровий перцептрон.\n",
|
||||
" * Ми реалізували перцептрон \"вручну\", використовуючи просту процедуру навчання на основі градієнтного спуску.\n",
|
||||
" * Незважаючи на простоту, одношаровий перцептрон може вирішувати досить складні задачі розпізнавання рукописних цифр.\n",
|
||||
" * Одношаровий перцептрон є лінійним класифікатором, і тому він забезпечує таку ж класифікаційну потужність, як і логістична регресія.\n",
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## Подяки\n",
|
||||
"\n",
|
||||
"Цей ноутбук є частиною [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) і був підготовлений [Дмитром Сошниковим](http://soshnikov.com). Він натхненний семінаром з нейронних мереж у Microsoft Research Cambridge. Деякий код і ілюстративні матеріали взяті з презентацій [Каті Хоффман](https://www.microsoft.com/en-us/research/people/kahofman/), [Метью Джонсона](https://www.microsoft.com/en-us/research/people/matjoh/) і [Рьото Томіоки](https://www.microsoft.com/en-us/research/people/ryoto/), а також із репозиторію [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Цей ноутбук є частиною [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) і був підготовлений [Дмитром Сошниковим](http://soshnikov.com). Він натхненний майстернею з нейронних мереж у Microsoft Research Cambridge. Деякий код і ілюстративні матеріали взяті з презентацій [Каті Гоффманн](https://www.microsoft.com/en-us/research/people/kahofman/), [Меттью Джонсона](https://www.microsoft.com/en-us/research/people/matjoh/) і [Рьото Томіоки](https://www.microsoft.com/en-us/research/people/ryoto/), а також із репозиторію [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Відмова від відповідальності**: \nЦей документ був перекладений за допомогою сервісу автоматичного перекладу [Co-op Translator](https://github.com/Azure/co-op-translator). Хоча ми прагнемо до точності, звертаємо вашу увагу, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критично важливої інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.\n"
|
||||
"\n---\n\n**Відмова від відповідальності**: \nЦей документ був перекладений за допомогою сервісу автоматичного перекладу [Co-op Translator](https://github.com/Azure/co-op-translator). Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критичної інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникають внаслідок використання цього перекладу.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:51:00+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:39:33+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "uk"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"\n",
|
||||
"> یہ نوٹ بک [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) کا حصہ ہے۔ مکمل تعلیمی مواد کے لیے ریپوزیٹری کا دورہ کریں۔\n",
|
||||
"\n",
|
||||
"جیسا کہ ہم نے بات کی ہے، پرسیپٹرون آپ کو **بائنری کلاسیفکیشن مسئلہ** حل کرنے کی اجازت دیتا ہے، یعنی ان پٹ مثالوں کو دو کلاسز میں تقسیم کرنا - جنہیں ہم **مثبت** اور **منفی** کہہ سکتے ہیں۔\n",
|
||||
"جیسا کہ ہم نے بات کی ہے، پرسیپٹرون آپ کو **بائنری کلاسیفیکیشن مسئلہ** حل کرنے کی اجازت دیتا ہے، یعنی ان پٹ مثالوں کو دو کلاسز میں تقسیم کرنا - ہم انہیں **مثبت** اور **منفی** کہہ سکتے ہیں۔\n",
|
||||
"\n",
|
||||
"سب سے پہلے، کچھ ضروری لائبریریاں درآمد کرتے ہیں۔\n"
|
||||
]
|
||||
|
|
@ -49,9 +49,9 @@
|
|||
"source": [
|
||||
"## کھلونا مسئلہ\n",
|
||||
"\n",
|
||||
"شروع کرتے ہیں ایک آسان مسئلے سے، جہاں ہمارے پاس دو ان پٹ خصوصیات ہیں۔ مثال کے طور پر، طب میں ہم ٹیومرز کو خوش خیم اور مہلک میں تقسیم کرنا چاہتے ہیں، ان کے سائز اور عمر کی بنیاد پر۔\n",
|
||||
"شروع کرنے کے لیے، آئیے ایک کھلونا مسئلہ سے آغاز کرتے ہیں، جہاں ہمارے پاس دو ان پٹ خصوصیات ہیں۔ مثال کے طور پر، طب میں ہم ٹیومرز کو ان کے سائز اور عمر کی بنیاد پر خوش خیم اور بدخیم میں تقسیم کرنا چاہتے ہیں۔\n",
|
||||
"\n",
|
||||
"ہم SciKit Learn لائبریری کے `make_classification` فنکشن کا استعمال کرتے ہوئے ایک تصادفی درجہ بندی ڈیٹا سیٹ بنائیں گے:\n"
|
||||
"ہم SciKit Learn لائبریری کے `make_classification` فنکشن کا استعمال کرتے ہوئے ایک تصادفی درجہ بندی ڈیٹا سیٹ تیار کریں گے:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"تاہم، ایک عمومی لکیری ماڈل میں بایاس بھی شامل ہونا چاہیے، یعنی مثالی طور پر ہمیں $y$ کو $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ کے طور پر حساب کرنا چاہیے۔ اپنے ماڈل کو آسان بنانے کے لیے، ہم اس بایاس ٹرم کو ختم کر سکتے ہیں، اور اپنی ان پٹ فیچرز میں ایک اضافی ڈائمینشن شامل کر سکتے ہیں، جو ہمیشہ 1 کے برابر ہوتی ہے:\n"
|
||||
"تاہم، ایک عمومی لکیری ماڈل میں بایاس بھی ہونا چاہیے، یعنی مثالی طور پر ہمیں $y$ کو $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ کے طور پر حساب کرنا چاہیے۔ اپنے ماڈل کو آسان بنانے کے لیے، ہم اس بایاس ٹرم کو ختم کر سکتے ہیں، اور اپنی ان پٹ فیچرز میں ایک اضافی ڈائمینشن شامل کر سکتے ہیں، جو ہمیشہ 1 کے برابر ہوتی ہے:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
" * $t_{n} \\in \\{-1, +1\\}$ منفی اور مثبت تربیتی نمونوں کے لیے، بالترتیب\n",
|
||||
" * $\\mathcal{M}$ - غلط طور پر درجہ بند مثالوں کا مجموعہ\n",
|
||||
" \n",
|
||||
"ہم **گریڈینٹ ڈیسنٹ** کے عمل کا استعمال کریں گے۔ کچھ ابتدائی بے ترتیب وزن $\\mathbf{w}^{(0)}$ سے شروع کرتے ہوئے، ہم تربیت کے ہر مرحلے پر وزن کو $E$ کے گریڈینٹ کا استعمال کرتے ہوئے ایڈجسٹ کریں گے:\n",
|
||||
"ہم **گریڈینٹ ڈیسنٹ** کے عمل کا استعمال کریں گے۔ ابتدائی طور پر کچھ بے ترتیب وزن $\\mathbf{w}^{(0)}$ سے شروع کرتے ہوئے، ہم تربیت کے ہر مرحلے پر وزن کو $E$ کے گریڈینٹ کا استعمال کرتے ہوئے ایڈجسٹ کریں گے:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta\\sum_{n \\in \\mathcal{M}}\\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**نوٹ برائے لرننگ ریٹ**: `learning_rate` پیرامیٹر (ڈیفالٹ `0.01`) یہ کنٹرول کرتا ہے کہ ہم ہر تربیتی مرحلے میں وزن کو کتنا ایڈجسٹ کرتے ہیں۔ یہ گریڈینٹ ڈیسنٹ اپڈیٹ فارمولے کو نافذ کرتا ہے:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- بڑا لرننگ ریٹ (مثلاً، `1.0`) پرسیپٹرون کو تیزی سے سیکھنے دیتا ہے لیکن ممکن ہے کہ بہترین حل کو اوور شوٹ کر دے\n",
|
||||
"- چھوٹا لرننگ ریٹ (مثلاً، `0.001`) آہستہ سیکھتا ہے لیکن زیادہ درستگی کے ساتھ کنورج کر سکتا ہے\n",
|
||||
"- آپ تجربہ کر سکتے ہیں اس کو کال کر کے: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"جیسا کہ آپ دیکھ سکتے ہیں، ابتدائی درستگی تقریباً 50% کے قریب ہے، لیکن یہ جلد ہی بڑھ کر 90% کے قریب اعلیٰ اقدار تک پہنچ جاتی ہے۔\n",
|
||||
"جیسا کہ آپ دیکھ سکتے ہیں، ابتدائی درستگی تقریباً 50% ہے، لیکن یہ جلد ہی بڑھ کر 90% کے قریب اعلیٰ اقدار تک پہنچ جاتی ہے۔\n",
|
||||
"\n",
|
||||
"آئیے دیکھتے ہیں کہ کلاسز کس طرح الگ ہوتی ہیں۔ ہماری درجہ بندی کی فنکشن $\\mathbf{w}^Tx$ کی طرح دکھائی دیتی ہے، اور یہ ایک کلاس کے لیے 0 سے زیادہ ہے، اور دوسری کے لیے 0 سے کم۔ اس طرح، کلاسز کو الگ کرنے والی لائن $\\mathbf{w}^Tx = 0$ سے متعین ہوتی ہے۔ چونکہ ہمارے پاس صرف دو ابعاد $x_0$ اور $x_1$ ہیں، لائن کے لیے مساوات $w_0x_0+w_1x_1+w_2 = 0$ ہوگی (یاد رکھیں کہ ہم نے واضح طور پر ایک اضافی بُعد $x_2=1$ کو متعین کیا ہے)۔ آئیے اس لائن کو گراف پر دکھاتے ہیں:\n"
|
||||
"آئیے دیکھتے ہیں کہ کلاسز کیسے الگ ہوتی ہیں۔ ہماری درجہ بندی کی فنکشن $\\mathbf{w}^Tx$ کی طرح ہے، اور یہ ایک کلاس کے لیے 0 سے زیادہ ہے، اور دوسری کے لیے 0 سے کم۔ اس طرح، کلاس کو الگ کرنے والی لائن $\\mathbf{w}^Tx = 0$ سے متعین ہوتی ہے۔ چونکہ ہمارے پاس صرف دو جہتیں $x_0$ اور $x_1$ ہیں، لائن کے لیے مساوات $w_0x_0+w_1x_1+w_2 = 0$ ہوگی (یاد رکھیں کہ ہم نے واضح طور پر ایک اضافی جہت $x_2=1$ کو متعین کیا ہے)۔ آئیے اس لائن کو گراف میں دکھاتے ہیں:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## مختلف لرننگ ریٹس کے ساتھ تجربہ کرنا\n",
|
||||
"\n",
|
||||
"اب آئیے دیکھتے ہیں کہ مختلف لرننگ ریٹس تربیتی عمل پر کیسے اثر ڈالتے ہیں۔ لرننگ ریٹ گریڈینٹ ڈیسنٹ میں قدم کے سائز کو کنٹرول کرتا ہے - ایک اہم ہائپر پیرامیٹر جو کنورجنس کی رفتار اور استحکام دونوں پر اثر انداز ہوتا ہے۔\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### انٹرایکٹو لرننگ ریٹ تجربہ\n",
|
||||
"\n",
|
||||
"نیچے دیے گئے سلائیڈر کا استعمال کریں تاکہ مختلف لرننگ ریٹس کے ساتھ تجربہ کریں اور دیکھیں کہ یہ فیصلہ کن حد کو کیسے متاثر کرتے ہیں:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## ٹیسٹ ڈیٹاسیٹ پر جانچ کریں\n",
|
||||
"\n",
|
||||
"شروع میں، ہم نے کچھ ڈیٹا کو ٹیسٹ ڈیٹاسیٹ کے لیے الگ رکھا تھا۔ آئیے دیکھتے ہیں کہ ہمارا کلاسفائر اس ٹیسٹ ڈیٹاسیٹ پر کتنا درست ہے۔ ایسا کرنے کے لیے، ہم ٹیسٹ ڈیٹاسیٹ کو ایک اضافی ڈائمینشن کے ساتھ بڑھاتے ہیں، ویٹس میٹرکس سے ضرب دیتے ہیں، اور یہ یقینی بناتے ہیں کہ حاصل شدہ قدر لیبل (+1 یا -1) کے جیسی علامت رکھتی ہو۔ پھر ہم تمام بولین ویلیوز کو جمع کرتے ہیں اور ٹیسٹ سیمپل کی لمبائی سے تقسیم کرتے ہیں تاکہ درستگی حاصل کی جا سکے:\n"
|
||||
"شروع میں، ہم نے کچھ ڈیٹا کو ٹیسٹ ڈیٹاسیٹ کے لیے الگ کیا تھا۔ آئیے دیکھتے ہیں کہ ہمارا کلاسفائر اس ٹیسٹ ڈیٹاسیٹ پر کتنا درست ہے۔ ایسا کرنے کے لیے، ہم ٹیسٹ ڈیٹاسیٹ کو ایک اضافی ڈائمینشن کے ساتھ بڑھاتے ہیں، ویٹس میٹرکس سے ضرب دیتے ہیں، اور یہ یقینی بناتے ہیں کہ حاصل شدہ قدر لیبل (+1 یا -1) کے جیسی علامت رکھتی ہو۔ پھر ہم تمام بولین ویلیوز کو جمع کرتے ہیں اور ٹیسٹ سیمپل کی لمبائی سے تقسیم کرتے ہیں تاکہ درستگی حاصل کی جا سکے:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -420,9 +546,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## تربیتی عمل کا مشاہدہ\n",
|
||||
"## تربیتی عمل کا مشاہدہ کرنا\n",
|
||||
"\n",
|
||||
"ہم نے پہلے دیکھا ہے کہ تربیت کے دوران درستگی کم ہوتی ہے۔ یہ دلچسپ ہوگا کہ تربیت کے دوران علیحدگی کی لائن کیسے تبدیل ہوتی ہے۔ نیچے دیا گیا کوڈ سب کچھ ایک گراف پر دکھائے گا، اور آپ سلائیڈر کو حرکت دے کر تربیتی عمل کے دوران \"وقت کا سفر\" کر سکیں گے۔\n"
|
||||
"ہم نے پہلے دیکھا ہے کہ تربیت کے دوران درستگی کیسے کم ہوتی ہے۔ یہ دیکھنا دلچسپ ہوگا کہ تربیت کے دوران علیحدگی کی لائن کیسے تبدیل ہوتی ہے۔ نیچے دیا گیا کوڈ سب کچھ ایک گراف پر دکھائے گا، اور آپ سلائیڈر کو حرکت دے کر تربیتی عمل کے دوران \"وقت کا سفر\" کر سکیں گے۔\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -613,9 +739,9 @@
|
|||
"\n",
|
||||
"اگرچہ پرسیپٹرون XOR مسئلہ کو حل نہیں کر سکتا، یہ بہت زیادہ پیچیدہ مسائل کو حل کر سکتا ہے، جیسے ہاتھ سے لکھے ہوئے کرداروں کی شناخت۔\n",
|
||||
"\n",
|
||||
"مشین لرننگ میں مہارت حاصل کرنے کے دوران اکثر استعمال ہونے والا ڈیٹا سیٹ [MNIST](https://en.wikipedia.org/wiki/MNIST_database) کہلاتا ہے۔ یہ Modified National Institute of Standards and Technology کے ذریعے بنایا گیا ہے، اور اس میں 60000 ہاتھ سے لکھے گئے ہندسوں کا تربیتی سیٹ شامل ہے، جو تقریباً 250 طلباء اور انسٹیٹیوٹ کے ملازمین سے جمع کیے گئے ہیں۔ اس کے علاوہ 10000 ہندسوں کا ایک ٹیسٹ ڈیٹا سیٹ بھی موجود ہے، جو مختلف افراد سے جمع کیا گیا ہے۔\n",
|
||||
"مشین لرننگ سیکھنے کے دوران اکثر استعمال ہونے والا ڈیٹا سیٹ [MNIST](https://en.wikipedia.org/wiki/MNIST_database) کہلاتا ہے۔ یہ Modified National Institute of Standards and Technology کے ذریعے بنایا گیا ہے، اور اس میں 60000 ہاتھ سے لکھے گئے ہندسوں کا تربیتی سیٹ شامل ہے، جو تقریباً 250 طلباء اور انسٹیٹیوٹ کے ملازمین سے جمع کیے گئے ہیں۔ اس کے علاوہ 10000 ہندسوں کا ایک ٹیسٹ ڈیٹا سیٹ بھی موجود ہے، جو مختلف افراد سے جمع کیا گیا ہے۔\n",
|
||||
"\n",
|
||||
"تمام ہندسے 28x28 پکسلز کے سائز کی گرے اسکیل تصاویر میں پیش کیے گئے ہیں۔\n",
|
||||
"تمام ہندسے 28x28 پکسلز کے گرے اسکیل تصاویر کی صورت میں پیش کیے گئے ہیں۔\n",
|
||||
"\n",
|
||||
"> MNIST ڈیٹا سیٹ [Kaggle](https://www.kaggle.com/c/digit-recognizer) پر ایک تربیتی مقابلے کے طور پر دستیاب ہے، جو مشین لرننگ کے مقابلے اور مقابلہ جات کی میزبانی کرتا ہے۔ جب آپ MNIST ہندسوں کو درجہ بندی کرنا سیکھ لیں، تو آپ اپنا حل Kaggle پر جمع کروا سکتے ہیں تاکہ دیکھ سکیں کہ یہ دیگر شرکاء کے درمیان کیسے درجہ بندی کرتا ہے۔\n",
|
||||
"\n",
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"چونکہ پرسیپٹرون ایک بائنری کلاسیفائر ہے، ہم اپنی مسئلے کو صرف دو ہندسوں کو پہچاننے تک محدود رکھیں گے۔ نیچے دی گئی فنکشن دو دیے گئے ہندسوں کے ساتھ مثبت اور منفی نمونوں کے ارے کو بھرے گی (اور وضاحت کے لیے ان ہندسوں کے نمونے بھی دکھائے گی)۔\n"
|
||||
"چونکہ پرسیپٹرون ایک بائنری کلاسیفائر ہے، ہم اپنی مسئلے کو صرف دو ہندسوں کی شناخت تک محدود رکھیں گے۔ نیچے دی گئی فنکشن دو دیے گئے ہندسوں کے ساتھ مثبت اور منفی نمونوں کے ارے کو بھرے گی (اور وضاحت کے لیے ان ہندسوں کے نمونے بھی دکھائے گی)۔\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"براہ کرم نوٹ کریں کہ درستگی بہت تیزی سے تقریباً 100% تک پہنچ جاتی ہے۔\n",
|
||||
"\n",
|
||||
"براہ کرم، سلائیڈر کو تربیت کے اختتام کی طرف کسی مقام پر منتقل کریں، اور بائیں جانب دکھائی گئی وزن کی میٹرکس کا مشاہدہ کریں۔ یہ میٹرکس آپ کو سمجھنے میں مدد دے گی کہ پرسیپٹرون اصل میں کیسے کام کرتا ہے۔ آپ میدان کے درمیان میں وزن کی زیادہ قدریں دیکھ سکتے ہیں، جو ان پکسلز سے مطابقت رکھتی ہیں جو عام طور پر ہندسہ 1 کے لیے موجود ہوتے ہیں، اور اطراف میں کم منفی قدریں، جہاں ہندسہ 0 کے حصے ہوتے ہیں۔ لہذا، اگر پرسیپٹرون کو دکھایا گیا ہندسہ واقعی 1 ہے، تو اس کے درمیانی حصے کو زیادہ قدروں سے ضرب دی جائے گی، جس سے مثبت نتیجہ پیدا ہوگا۔ اس کے برعکس، جب پرسیپٹرون 0 کو دیکھتا ہے، تو متعلقہ پکسلز کو منفی نمبروں سے ضرب دی جائے گی۔\n",
|
||||
"براہ کرم، سلائیڈر کو تربیت کے اختتام کی طرف کسی مقام پر منتقل کریں، اور بائیں جانب دکھائی گئی وزن کی میٹرکس کا مشاہدہ کریں۔ یہ میٹرکس آپ کو سمجھنے میں مدد دے گی کہ پرسیپٹرون اصل میں کیسے کام کرتا ہے۔ آپ میدان کے درمیان میں وزن کی زیادہ قدریں دیکھ سکتے ہیں، جو ان پکسلز سے مطابقت رکھتی ہیں جو عام طور پر ہندسہ 1 کے لیے موجود ہوتے ہیں، اور اطراف میں کم منفی قدریں، جہاں ہندسہ 0 کے حصے ہوتے ہیں۔ لہذا، اگر پرسیپٹرون کو پیش کیا گیا ہندسہ واقعی 1 ہے، تو اس کے درمیانی حصے کو زیادہ قدروں سے ضرب دی جائے گی، جس سے مثبت نتیجہ پیدا ہوگا۔ اس کے برعکس، جب پرسیپٹرون 0 کو دیکھتا ہے، تو متعلقہ پکسلز کو منفی نمبروں سے ضرب دی جائے گی۔\n",
|
||||
"\n",
|
||||
"> آپ یہ نوٹ کر سکتے ہیں کہ اگر ہم اپنے پرسیپٹرون کو ہندسہ 1 تھوڑا افقی طور پر منتقل کر کے دیں، تاکہ اس کے پکسلز اس جگہ پر ہوں جہاں 0 کے عمودی حصے ہوں، تو ہمیں غلط نتیجہ مل سکتا ہے۔ چونکہ ہمارے MNIST ڈیٹا سیٹ کی نوعیت ایسی ہے کہ تمام ہندسے مرکز میں اور صحیح طور پر پوزیشن میں ہوتے ہیں، اور پرسیپٹرون اسی پر انحصار کرتا ہے تاکہ ہندسوں کے درمیان فرق کر سکے۔\n",
|
||||
"> آپ یہ نوٹ کر سکتے ہیں کہ اگر ہم اپنے پرسیپٹرون کو ہندسہ 1 تھوڑا افقی طور پر منتقل کر کے دیں، تاکہ اس کے پکسلز اس جگہ پر ہوں جہاں 0 کے عمودی حصے ہوں، تو ہمیں غلط نتیجہ مل سکتا ہے۔ چونکہ ہمارے MNIST ڈیٹا سیٹ کی نوعیت ایسی ہے کہ تمام ہندسے مرکز میں اور مناسب طریقے سے پوزیشن میں ہوتے ہیں، اور پرسیپٹرون اسی پر انحصار کرتا ہے تاکہ ہندسوں کے درمیان فرق کر سکے۔\n",
|
||||
"\n",
|
||||
"اب آئیے مختلف ہندسوں کو آزماتے ہیں:\n"
|
||||
]
|
||||
|
|
@ -915,9 +1041,9 @@
|
|||
"\n",
|
||||
"کسی وجہ سے، 2 اور 5 کو اتنی آسانی سے الگ نہیں کیا جا سکتا۔ حالانکہ ہمیں نسبتاً زیادہ درستگی (85% سے زیادہ) حاصل ہوتی ہے، ہم واضح طور پر دیکھ سکتے ہیں کہ perceptron ایک وقت کے بعد سیکھنا بند کر دیتا ہے۔\n",
|
||||
"\n",
|
||||
"یہ سمجھنے کے لیے کہ ایسا کیوں ہوتا ہے، ہم [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) استعمال کرنے کی کوشش کر سکتے ہیں۔ یہ ایک مشین لرننگ تکنیک ہے جو ان پٹ ڈیٹا سیٹ کی dimensionality کو کم کرنے کے لیے استعمال ہوتی ہے، اس طرح کہ کلاسز کے درمیان بہترین علیحدگی حاصل کی جا سکے۔\n",
|
||||
"یہ سمجھنے کے لیے کہ ایسا کیوں ہوتا ہے، ہم [Principal Component Analysis](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) استعمال کرنے کی کوشش کر سکتے ہیں۔ یہ ایک مشین لرننگ تکنیک ہے جو ان پٹ ڈیٹا سیٹ کی dimensionality کو کم کرنے کے لیے استعمال ہوتی ہے، تاکہ کلاسز کے درمیان بہترین علیحدگی حاصل کی جا سکے۔\n",
|
||||
"\n",
|
||||
"ہمارے معاملے میں، ایک ان پٹ تصویر میں 784 پکسلز (ان پٹ فیچرز) ہوتے ہیں، اور ہم PCA استعمال کرنا چاہتے ہیں تاکہ پیرامیٹرز کی تعداد کو صرف 2 تک کم کیا جا سکے، تاکہ ہم انہیں گراف پر پلاٹ کر سکیں۔ یہ دو پیرامیٹرز اصل فیچرز کا ایک linear combination ہوں گے، اور ہم اس عمل کو اس طرح دیکھ سکتے ہیں جیسے ہم اپنی اصل 784-dimensional space کو \"rotate\" کر رہے ہوں اور اس کی projection کو 2D-space میں دیکھ رہے ہوں، جب تک کہ ہمیں کلاسز کو الگ کرنے کے لیے بہترین منظر نہ مل جائے۔\n"
|
||||
"ہمارے کیس میں، ایک ان پٹ تصویر میں 784 پکسلز (ان پٹ فیچرز) ہوتے ہیں، اور ہم PCA استعمال کرنا چاہتے ہیں تاکہ پیرامیٹرز کی تعداد کو صرف 2 تک کم کیا جا سکے، تاکہ ہم انہیں گراف پر پلاٹ کر سکیں۔ یہ دو پیرامیٹرز اصل فیچرز کا linear combination ہوں گے، اور ہم اس عمل کو اس طرح دیکھ سکتے ہیں جیسے ہم اپنے اصل 784-dimensional space کو \"rotate\" کر رہے ہوں اور اس کی projection کو 2D-space میں دیکھ رہے ہوں، جب تک کہ ہمیں کلاسز کو الگ کرنے کے لیے بہترین منظر نہ مل جائے۔\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,7 +1153,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"جیسا کہ آپ دیکھ سکتے ہیں، 0 اور 1 کو ایک سیدھی لائن کے ذریعے واضح طور پر الگ کیا جا سکتا ہے۔ اس سے ظاہر ہوتا ہے کہ اصل 784-ابعادی جگہ میں وہ نقاط جو ہندسوں سے متعلق ہیں، وہ بھی خطی طور پر الگ کیے جا سکتے ہیں۔ لیکن 2 اور 5 کے معاملے میں، ہم ایسی اچھی پروجیکشن نہیں ڈھونڈ سکتے جو ہندسوں کو واضح طور پر الگ کرے، اور اسی وجہ سے کچھ غلط درجہ بندی کے معاملات سامنے آتے ہیں۔\n",
|
||||
"جیسا کہ آپ دیکھ سکتے ہیں، 0 اور 1 کو ایک سیدھی لائن کے ذریعے واضح طور پر الگ کیا جا سکتا ہے۔ اس سے ظاہر ہوتا ہے کہ اصل 784-ابعادی جگہ میں وہ نقاط جو ہندسوں سے متعلق ہیں، وہ بھی خطی طور پر الگ کیے جا سکتے ہیں۔ لیکن 2 اور 5 کے معاملے میں، ہم ایسا اچھا پروجیکشن نہیں ڈھونڈ سکتے جو ہندسوں کو واضح طور پر الگ کرے، اور اسی وجہ سے کچھ غلط درجہ بندی کے معاملات سامنے آتے ہیں۔\n",
|
||||
"\n",
|
||||
"> اس کورس میں آگے چل کر ہم سیکھیں گے کہ نیورل نیٹ ورکس کا استعمال کرتے ہوئے غیر خطی درجہ بندی کرنے والے ماڈلز کیسے بنائے جاتے ہیں، اور ان مسائل سے کیسے نمٹا جاتا ہے جہاں ہندسے مناسب طریقے سے ترتیب نہیں دیے گئے ہوں۔ بہت جلد ہم MNIST ہندسوں کی درجہ بندی میں 99% سے زیادہ درستگی حاصل کریں گے، جبکہ انہیں 10 مختلف کلاسز میں تقسیم کریں گے۔\n",
|
||||
"\n",
|
||||
|
|
@ -1035,9 +1161,9 @@
|
|||
"\n",
|
||||
" * ہم نے سب سے سادہ نیورل نیٹ ورک آرکیٹیکچر کے بارے میں سیکھا - ایک پرت والا پرسیپٹرون۔\n",
|
||||
" * ہم نے پرسیپٹرون کو \"خود سے\" نافذ کیا، ایک سادہ تربیتی طریقہ کار استعمال کرتے ہوئے جو گریڈینٹ ڈیسنٹ پر مبنی ہے۔\n",
|
||||
" * سادگی کے باوجود، ایک پرت والا پرسیپٹرون ہاتھ سے لکھے گئے ہندسوں کی پہچان کے نسبتاً پیچیدہ مسائل حل کر سکتا ہے۔\n",
|
||||
" * سادگی کے باوجود، ایک پرت والا پرسیپٹرون ہاتھ سے لکھے گئے ہندسوں کی پہچان جیسے پیچیدہ مسائل کو حل کر سکتا ہے۔\n",
|
||||
" * ایک پرت والا پرسیپٹرون ایک خطی درجہ بندی کرنے والا ماڈل ہے، اور اس طرح یہ لاجسٹک ریگریشن کے برابر درجہ بندی کی صلاحیت فراہم کرتا ہے۔\n",
|
||||
" * نمونہ جگہ میں، پرسیپٹرون ان پٹ ڈیٹا کی دو کلاسز کو ہائپرپلین کے ذریعے الگ کر سکتا ہے۔\n"
|
||||
" * نمونہ جگہ میں، پرسیپٹرون دو کلاسز کے ان پٹ ڈیٹا کو ہائپرپلین کے ذریعے الگ کر سکتا ہے۔\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,7 +1172,7 @@
|
|||
"source": [
|
||||
"## کریڈٹس\n",
|
||||
"\n",
|
||||
"یہ نوٹ بک [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) کا حصہ ہے، اور اسے [دیمتری سوشنیکوف](http://soshnikov.com) نے تیار کیا ہے۔ یہ مائیکروسافٹ ریسرچ کیمبرج میں نیورل نیٹ ورک ورکشاپ سے متاثر ہے۔ کچھ کوڈ اور وضاحتی مواد [کاتجا ہوفمین](https://www.microsoft.com/en-us/research/people/kahofman/)، [میتھیو جانسن](https://www.microsoft.com/en-us/research/people/matjoh/) اور [ریوٹو تومیوکا](https://www.microsoft.com/en-us/research/people/ryoto/) کی پریزنٹیشنز سے لیا گیا ہے، اور [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) ریپوزیٹری سے بھی۔\n"
|
||||
"یہ نوٹ بک [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) کا حصہ ہے، اور اسے [Dmitry Soshnikov](http://soshnikov.com) نے تیار کیا ہے۔ یہ Microsoft Research Cambridge میں نیورل نیٹ ورک ورکشاپ سے متاثر ہے۔ کچھ کوڈ اور وضاحتی مواد [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)، [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) اور [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) کی پریزنٹیشنز سے لیا گیا ہے، اور [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) ریپوزیٹری سے بھی۔\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:11:57+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:57:45+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "ur"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"source": [
|
||||
"## Perceptron\n",
|
||||
"\n",
|
||||
"> Notebook này là một phần của [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Hãy truy cập kho lưu trữ để xem đầy đủ tài liệu học tập.\n",
|
||||
"> Notebook này là một phần của [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Truy cập kho lưu trữ để xem toàn bộ tài liệu học tập.\n",
|
||||
"\n",
|
||||
"Như chúng ta đã thảo luận, perceptron cho phép bạn giải quyết **vấn đề phân loại nhị phân**, tức là phân loại các ví dụ đầu vào thành hai lớp - chúng ta có thể gọi chúng là **tích cực** và **tiêu cực**.\n",
|
||||
"\n",
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Lưu ý về Tốc độ Học**: Tham số `learning_rate` (mặc định là `0.01`) kiểm soát mức độ điều chỉnh trọng số trong mỗi bước huấn luyện. Điều này thực hiện công thức cập nhật của gradient descent:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- Tốc độ học lớn hơn (ví dụ, `1.0`) giúp perceptron học nhanh hơn nhưng có thể vượt quá giải pháp tối ưu\n",
|
||||
"- Tốc độ học nhỏ hơn (ví dụ, `0.001`) học chậm hơn nhưng có thể hội tụ chính xác hơn\n",
|
||||
"- Bạn có thể thử nghiệm bằng cách gọi: `train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Thử nghiệm với các mức học\n",
|
||||
"\n",
|
||||
"Bây giờ hãy khám phá cách các mức học khác nhau ảnh hưởng đến quá trình huấn luyện. Mức học điều chỉnh kích thước bước trong gradient descent - một siêu tham số quan trọng ảnh hưởng đến cả tốc độ hội tụ và sự ổn định.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Thử nghiệm Tương tác với Tốc độ Học\n",
|
||||
"\n",
|
||||
"Sử dụng thanh trượt bên dưới để thử nghiệm tương tác với các tốc độ học khác nhau và xem chúng ảnh hưởng đến ranh giới quyết định như thế nào:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -531,7 +657,7 @@
|
|||
"\n",
|
||||
"Như bạn đã thấy ở trên, perceptron là một **bộ phân loại tuyến tính**. Nó có thể phân biệt tốt giữa hai lớp nếu chúng **có thể tách tuyến tính**, tức là có thể được phân tách bằng một đường thẳng. Nếu không, quá trình huấn luyện perceptron sẽ không hội tụ.\n",
|
||||
"\n",
|
||||
"Một ví dụ rõ ràng nhất về một vấn đề mà perceptron không thể giải quyết là vấn đề **XOR**. Chúng ta muốn perceptron học hàm boolean XOR, hàm này có bảng chân lý như sau:\n",
|
||||
"Một ví dụ rõ ràng nhất về một vấn đề mà perceptron không thể giải quyết là vấn đề **XOR**. Chúng ta muốn perceptron học hàm boolean XOR, với bảng chân lý như sau:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
|
|
@ -613,11 +739,11 @@
|
|||
"\n",
|
||||
"Mặc dù perceptron không thể giải quyết vấn đề XOR, nhưng nó có thể giải quyết nhiều vấn đề phức tạp hơn, chẳng hạn như nhận dạng ký tự viết tay.\n",
|
||||
"\n",
|
||||
"Một tập dữ liệu thường được sử dụng khi học máy được gọi là [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Tập dữ liệu này được tạo bởi Viện Tiêu chuẩn và Công nghệ Quốc gia Sửa đổi (Modified National Institute of Standards and Technology), và chứa một tập huấn luyện gồm 60.000 chữ số viết tay, được thu thập từ khoảng 250 sinh viên và nhân viên của viện. Ngoài ra còn có một tập dữ liệu kiểm tra gồm 10.000 chữ số, được thu thập từ các cá nhân khác nhau.\n",
|
||||
"Một tập dữ liệu thường được sử dụng khi học máy là [MNIST](https://en.wikipedia.org/wiki/MNIST_database). Tập dữ liệu này được tạo bởi Viện Tiêu chuẩn và Công nghệ Quốc gia Sửa đổi (Modified National Institute of Standards and Technology), và chứa một tập huấn luyện gồm 60.000 chữ số viết tay, được thu thập từ khoảng 250 sinh viên và nhân viên của viện. Ngoài ra còn có một tập dữ liệu kiểm tra gồm 10.000 chữ số, được thu thập từ các cá nhân khác nhau.\n",
|
||||
"\n",
|
||||
"Tất cả các chữ số được biểu diễn bằng hình ảnh thang độ xám có kích thước 28x28 pixel.\n",
|
||||
"\n",
|
||||
"> Tập dữ liệu MNIST có sẵn dưới dạng một cuộc thi huấn luyện trên [Kaggle](https://www.kaggle.com/c/digit-recognizer), một trang web tổ chức các cuộc thi và thử thách về học máy. Sau khi bạn học cách phân loại chữ số MNIST, bạn có thể gửi giải pháp của mình lên Kaggle để xem cách nó được đánh giá so với các người tham gia khác.\n",
|
||||
"> Tập dữ liệu MNIST có sẵn dưới dạng một cuộc thi huấn luyện trên [Kaggle](https://www.kaggle.com/c/digit-recognizer), một trang web tổ chức các cuộc thi và thử thách về học máy. Sau khi bạn học cách phân loại chữ số MNIST, bạn có thể gửi giải pháp của mình lên Kaggle để xem nó được xếp hạng như thế nào so với các người tham gia khác.\n",
|
||||
"\n",
|
||||
"Chúng ta bắt đầu bằng cách tải tập dữ liệu MNIST:\n"
|
||||
]
|
||||
|
|
@ -644,7 +770,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Bây giờ hãy vẽ biểu đồ tập dữ liệu:\n"
|
||||
"Bây giờ chúng ta hãy vẽ biểu đồ tập dữ liệu:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,7 +959,7 @@
|
|||
"source": [
|
||||
"Xin lưu ý rằng độ chính xác tăng lên gần 100% rất nhanh.\n",
|
||||
"\n",
|
||||
"Vui lòng di chuyển thanh trượt đến một vị trí gần cuối quá trình huấn luyện và quan sát ma trận trọng số được vẽ ở bên trái. Ma trận này sẽ giúp bạn hiểu cách perceptron thực sự hoạt động. Bạn có thể thấy các giá trị trọng số cao ở giữa trường, tương ứng với các pixel thường xuất hiện ở chữ số 1, và các giá trị âm thấp ở hai bên, nơi các phần của chữ số 0 nằm. Vì vậy, nếu chữ số được đưa vào perceptron thực sự là 1, phần giữa của nó sẽ được nhân với các giá trị cao, tạo ra kết quả dương. Ngược lại, khi perceptron quan sát chữ số 0, các pixel tương ứng sẽ được nhân với các số âm.\n",
|
||||
"Vui lòng di chuyển thanh trượt đến một vị trí gần cuối quá trình huấn luyện và quan sát ma trận trọng số được hiển thị ở bên trái. Ma trận này sẽ giúp bạn hiểu cách perceptron thực sự hoạt động. Bạn có thể thấy các giá trị trọng số cao ở giữa trường, tương ứng với các pixel thường xuất hiện ở chữ số 1, và các giá trị âm thấp ở hai bên, nơi các phần của chữ số 0 nằm. Vì vậy, nếu chữ số được đưa vào perceptron thực sự là 1, phần giữa của nó sẽ được nhân với các giá trị cao, tạo ra kết quả dương. Ngược lại, khi perceptron quan sát chữ số 0, các pixel tương ứng sẽ được nhân với các số âm.\n",
|
||||
"\n",
|
||||
"> Bạn có thể nhận thấy rằng nếu chúng ta đưa cho perceptron một chữ số 1 hơi lệch sang ngang, sao cho các pixel của nó chiếm vị trí nơi có các phần dọc của chữ số 0, chúng ta có thể nhận được kết quả không chính xác. Vì bản chất của tập dữ liệu MNIST là tất cả các chữ số đều được căn giữa và định vị đúng cách, và perceptron dựa vào điều này để phân biệt giữa các chữ số.\n",
|
||||
"\n",
|
||||
|
|
@ -915,7 +1041,7 @@
|
|||
"\n",
|
||||
"Vì lý do nào đó, số 2 và số 5 không dễ dàng được phân tách. Mặc dù chúng ta đạt được độ chính xác tương đối cao (trên 85%), nhưng có thể thấy rõ rằng perceptron ngừng học tại một thời điểm nào đó.\n",
|
||||
"\n",
|
||||
"Để hiểu tại sao điều này xảy ra, chúng ta có thể thử sử dụng [Phân tích thành phần chính](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Đây là một kỹ thuật học máy được sử dụng để giảm số chiều của tập dữ liệu đầu vào, nhằm đạt được khả năng phân tách tốt nhất giữa các lớp.\n",
|
||||
"Để hiểu tại sao điều này xảy ra, chúng ta có thể thử sử dụng [Phân tích Thành phần Chính](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA). Đây là một kỹ thuật học máy được sử dụng để giảm số chiều của tập dữ liệu đầu vào, nhằm đạt được khả năng phân tách tốt nhất giữa các lớp.\n",
|
||||
"\n",
|
||||
"Trong trường hợp của chúng ta, một hình ảnh đầu vào có 784 pixel (các đặc trưng đầu vào), và chúng ta muốn sử dụng PCA để giảm số lượng tham số xuống chỉ còn 2, để có thể vẽ chúng trên biểu đồ. Hai tham số này sẽ là sự kết hợp tuyến tính của các đặc trưng ban đầu, và chúng ta có thể xem quy trình này như việc \"xoay\" không gian 784 chiều ban đầu và quan sát sự chiếu của nó lên không gian 2 chiều, cho đến khi đạt được góc nhìn tốt nhất để phân tách các lớp.\n"
|
||||
]
|
||||
|
|
@ -1044,9 +1170,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Tín dụng\n",
|
||||
"## Ghi nhận\n",
|
||||
"\n",
|
||||
"Notebook này là một phần của [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) và được chuẩn bị bởi [Dmitry Soshnikov](http://soshnikov.com). Nó được lấy cảm hứng từ Hội thảo Mạng Nơ-ron tại Microsoft Research Cambridge. Một số mã và tài liệu minh họa được lấy từ các bài thuyết trình của [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) và [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), cũng như từ kho lưu trữ [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
"Notebook này là một phần của [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), và được chuẩn bị bởi [Dmitry Soshnikov](http://soshnikov.com). Nó được lấy cảm hứng từ Hội thảo Mạng Neural tại Microsoft Research Cambridge. Một số mã và tài liệu minh họa được lấy từ các bài thuyết trình của [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) và [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), cũng như từ kho lưu trữ [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:36:44+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T17:24:24+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "vi"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"source": [
|
||||
"## 玩具问题\n",
|
||||
"\n",
|
||||
"首先,让我们从一个玩具问题开始,这个问题有两个输入特征。例如,在医学领域,我们可能希望根据肿瘤的大小和年龄将其分类为良性或恶性。\n",
|
||||
"首先,让我们从一个玩具问题开始,这里我们有两个输入特征。例如,在医学领域,我们可能希望根据肿瘤的大小和年龄将其分类为良性或恶性。\n",
|
||||
"\n",
|
||||
"我们将使用 SciKit Learn 库中的 `make_classification` 函数生成一个随机分类数据集:\n"
|
||||
]
|
||||
|
|
@ -152,13 +152,13 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## 感知器\n",
|
||||
"## 感知机\n",
|
||||
"\n",
|
||||
"由于感知器是一个二分类器,对于每个输入向量 $x$,感知器的输出将是 +1 或 -1,具体取决于所属类别。输出通过以下公式计算:\n",
|
||||
"由于感知机是一个二分类器,对于每个输入向量 $x$,感知机的输出将根据类别为 +1 或 -1。输出通过以下公式计算:\n",
|
||||
"\n",
|
||||
"$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n",
|
||||
"\n",
|
||||
"其中 $\\mathbf{w}$ 是权重向量,$f$ 是阶跃激活函数:\n",
|
||||
"其中,$\\mathbf{w}$ 是权重向量,$f$ 是阶跃激活函数:\n",
|
||||
"$$\n",
|
||||
"f(x) = \\begin{cases}\n",
|
||||
" +1 & x \\geq 0 \\\\\n",
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
" \\end{cases} \\\\\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"然而,一个通用的线性模型通常还需要一个偏置项,即理想情况下我们应该计算 $y$ 为 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$。为了简化模型,我们可以通过在输入特征中添加一个始终等于 1 的维度来去掉这个偏置项:\n"
|
||||
"然而,一个通用的线性模型通常还需要一个偏置项,即理想情况下我们应该通过 $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}+\\mathbf{b})$ 来计算 $y$。为了简化我们的模型,我们可以通过在输入特征中添加一个始终等于 1 的维度来去掉这个偏置项:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" \n",
|
||||
" # Initialize weights. \n",
|
||||
|
|
@ -251,11 +251,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0: # positive example was classified as negative\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0: # negative example was classified as positive\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" # Periodically, print out the current accuracy on all examples \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
|
|
@ -268,6 +268,19 @@
|
|||
" return weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**关于学习率的说明**: `learning_rate` 参数(默认值为 `0.01`)控制我们在每次训练步骤中调整权重的幅度。这实现了梯度下降更新公式:\n",
|
||||
"\n",
|
||||
"$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n",
|
||||
"\n",
|
||||
"- 较大的学习率(例如 `1.0`)会使感知器学习速度更快,但可能会超出最优解\n",
|
||||
"- 较小的学习率(例如 `0.001`)学习速度较慢,但可能更精确地收敛\n",
|
||||
"- 你可以通过调用以下代码进行实验:`train(pos_examples, neg_examples, learning_rate=0.1)`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -311,9 +324,9 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"如你所见,初始准确率约为50%,但很快就提升到接近90%的较高值。\n",
|
||||
"如你所见,初始准确率大约为50%,但很快就提升到接近90%的较高值。\n",
|
||||
"\n",
|
||||
"让我们来可视化类的分隔情况。我们的分类函数形式为 $\\mathbf{w}^Tx$,对于一个类别,它的值大于0;对于另一个类别,它的值小于0。因此,类别分隔线由 $\\mathbf{w}^Tx = 0$ 定义。由于我们只有两个维度 $x_0$ 和 $x_1$,该直线的方程为 $w_0x_0+w_1x_1+w_2 = 0$(记住我们显式定义了一个额外维度 $x_2=1$)。让我们绘制这条直线:\n"
|
||||
"我们来可视化一下类别是如何分开的。我们的分类函数形式为 $\\mathbf{w}^Tx$,对于一个类别,它的值大于0;对于另一个类别,它的值小于0。因此,类别分隔线由 $\\mathbf{w}^Tx = 0$ 定义。由于我们只有两个维度 $x_0$ 和 $x_1$,这条线的方程可以写成 $w_0x_0+w_1x_1+w_2 = 0$(记住我们显式定义了一个额外维度 $x_2=1$)。现在我们来绘制这条线:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -371,6 +384,119 @@
|
|||
"plot_boundary(pos_examples,neg_examples,wts)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 探索学习率\n",
|
||||
"\n",
|
||||
"现在让我们研究不同学习率如何影响训练过程。学习率控制梯度下降中的步长——这是一个关键的超参数,影响收敛速度和稳定性。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Compare different learning rates\n",
|
||||
"learning_rates = [0.001, 0.01, 0.1, 1.0]\n",
|
||||
"fig, axes = pylab.subplots(2, 2, figsize=(12, 10))\n",
|
||||
"fig.suptitle('Effect of Different Learning Rates', fontsize=16)\n",
|
||||
"\n",
|
||||
"for idx, lr in enumerate(learning_rates):\n",
|
||||
" ax = axes[idx // 2, idx % 2]\n",
|
||||
" \n",
|
||||
" # Train with this learning rate\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=lr)\n",
|
||||
" \n",
|
||||
" # Plot decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax.set_xlim(-6, 6)\n",
|
||||
" ax.set_ylim(-6, 6)\n",
|
||||
" ax.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', alpha=0.7)\n",
|
||||
" ax.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', alpha=0.7)\n",
|
||||
" ax.plot(x, y, 'g-', linewidth=2)\n",
|
||||
" ax.set_title(f'Learning Rate = {lr}')\n",
|
||||
" ax.set_xlabel('Feature 1')\n",
|
||||
" ax.set_ylabel('Feature 2')\n",
|
||||
" ax.legend()\n",
|
||||
" ax.grid(True, alpha=0.3)\n",
|
||||
"\n",
|
||||
"pylab.tight_layout()\n",
|
||||
"pylab.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 交互式学习率实验\n",
|
||||
"\n",
|
||||
"使用下面的滑块,交互式地尝试不同的学习率,观察它们如何影响决策边界:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_and_plot_with_lr(learning_rate=0.01):\n",
|
||||
" \"\"\"Train perceptron with specified learning rate and plot results\"\"\"\n",
|
||||
" weights_lr = train(pos_examples, neg_examples, num_iterations=100, learning_rate=learning_rate)\n",
|
||||
" \n",
|
||||
" fig, (ax1, ax2) = pylab.subplots(1, 2, figsize=(14, 5))\n",
|
||||
" \n",
|
||||
" # Plot 1: Decision boundary\n",
|
||||
" if np.isclose(weights_lr[1], 0):\n",
|
||||
" if np.isclose(weights_lr[0], 0):\n",
|
||||
" x = y = np.array([-6, 6], dtype='float32')\n",
|
||||
" else:\n",
|
||||
" y = np.array([-6, 6], dtype='float32')\n",
|
||||
" x = -(weights_lr[1] * y + weights_lr[2])/weights_lr[0]\n",
|
||||
" else:\n",
|
||||
" x = np.array([-6, 6], dtype='float32')\n",
|
||||
" y = -(weights_lr[0] * x + weights_lr[2])/weights_lr[1]\n",
|
||||
" \n",
|
||||
" ax1.set_xlim(-6, 6)\n",
|
||||
" ax1.set_ylim(-6, 6)\n",
|
||||
" ax1.plot(pos_examples[:, 0], pos_examples[:, 1], 'bo', label='Positive', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(neg_examples[:, 0], neg_examples[:, 1], 'ro', label='Negative', s=100, alpha=0.6)\n",
|
||||
" ax1.plot(x, y, 'g-', linewidth=3, label='Decision Boundary')\n",
|
||||
" ax1.set_title(f'Decision Boundary (lr={learning_rate})', fontsize=14)\n",
|
||||
" ax1.set_xlabel('Feature 1')\n",
|
||||
" ax1.set_ylabel('Feature 2')\n",
|
||||
" ax1.legend()\n",
|
||||
" ax1.grid(True, alpha=0.3)\n",
|
||||
" \n",
|
||||
" # Plot 2: Weight values\n",
|
||||
" ax2.bar(['w0', 'w1', 'bias'], weights_lr.flatten(), color=['blue', 'green', 'red'], alpha=0.7)\n",
|
||||
" ax2.set_title('Final Weight Values', fontsize=14)\n",
|
||||
" ax2.set_ylabel('Weight Value')\n",
|
||||
" ax2.grid(True, alpha=0.3, axis='y')\n",
|
||||
" ax2.axhline(y=0, color='black', linestyle='-', linewidth=0.5)\n",
|
||||
" \n",
|
||||
" pylab.tight_layout()\n",
|
||||
" pylab.show()\n",
|
||||
" \n",
|
||||
" print(f\"Final weights: {weights_lr.flatten()}\")\n",
|
||||
"\n",
|
||||
"# Create interactive widget\n",
|
||||
"interact(train_and_plot_with_lr, \n",
|
||||
" learning_rate=widgets.FloatSlider(value=0.01, min=0.001, max=1.0, step=0.001, \n",
|
||||
" description='Learning Rate:', continuous_update=False))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
|
@ -381,7 +507,7 @@
|
|||
"source": [
|
||||
"## 在测试数据集上评估\n",
|
||||
"\n",
|
||||
"一开始,我们将部分数据分离出来作为测试数据集。现在来看看我们的分类器在这个测试数据集上的准确性。为此,我们需要将测试数据集扩展一个额外的维度,与权重矩阵相乘,并确保得到的值与标签的符号一致(+1 或 -1)。然后将所有布尔值相加,并除以测试样本的长度,得到准确率:\n"
|
||||
"一开始,我们将部分数据分离出来作为测试数据集。现在来看看我们的分类器在这个测试数据集上的准确性。为此,我们需要将测试数据集扩展一个额外的维度,与权重矩阵相乘,并确保得到的值与标签的符号一致(+1 或 -1)。然后将所有布尔值相加,并除以测试样本的长度,以计算准确率:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -422,7 +548,7 @@
|
|||
"source": [
|
||||
"## 观察训练过程\n",
|
||||
"\n",
|
||||
"我们之前已经看到,训练过程中准确率会下降。能够观察分割线在训练过程中的变化会很有趣。下面的代码会将所有内容可视化到一个图表上,你可以通过移动滑块来“穿越时间”,查看训练过程中的变化。\n"
|
||||
"我们之前已经看到,训练过程中准确率会下降。能够观察分割线在训练过程中的变化会很有趣。下面的代码将把所有内容可视化到一个图表上,你可以通过移动滑块来“时光穿梭”查看训练过程。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -435,7 +561,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100):\n",
|
||||
"def train_graph(positive_examples, negative_examples, num_iterations = 100, learning_rate = 0.01):\n",
|
||||
" num_dims = positive_examples.shape[1]\n",
|
||||
" weights = np.zeros((num_dims,1)) # initialize weights\n",
|
||||
" \n",
|
||||
|
|
@ -451,11 +577,11 @@
|
|||
"\n",
|
||||
" z = np.dot(pos, weights) \n",
|
||||
" if z < 0:\n",
|
||||
" weights = weights + pos.reshape(weights.shape)\n",
|
||||
" weights = weights + learning_rate * pos.reshape(weights.shape)\n",
|
||||
"\n",
|
||||
" z = np.dot(neg, weights)\n",
|
||||
" if z >= 0:\n",
|
||||
" weights = weights - neg.reshape(weights.shape)\n",
|
||||
" weights = weights - learning_rate * neg.reshape(weights.shape)\n",
|
||||
" \n",
|
||||
" if i % report_frequency == 0: \n",
|
||||
" pos_out = np.dot(positive_examples, weights)\n",
|
||||
|
|
@ -527,18 +653,18 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"## 感知机的局限性\n",
|
||||
"## 感知器的局限性\n",
|
||||
"\n",
|
||||
"如上所述,感知机是一种**线性分类器**。如果两个类别是**线性可分的**,即可以用一条直线分开,那么感知机可以很好地区分它们。否则,感知机的训练过程将无法收敛。\n",
|
||||
"如上所述,感知器是一种**线性分类器**。如果两个类别是**线性可分的**,即可以用一条直线分开,那么感知器可以很好地区分它们。否则,感知器的训练过程将无法收敛。\n",
|
||||
"\n",
|
||||
"一个最明显的例子是感知机无法解决的**XOR问题**。我们希望感知机学习XOR布尔函数,其真值表如下:\n",
|
||||
"一个最明显的例子是感知器无法解决的所谓**XOR问题**。我们希望感知器学习 XOR 布尔函数,其真值表如下:\n",
|
||||
"\n",
|
||||
"| | 0 | 1 |\n",
|
||||
"|---|---|---|\n",
|
||||
"| 0 | 0 | 1 | \n",
|
||||
"| 1 | 1 | 0 |\n",
|
||||
"\n",
|
||||
"让我们试试看!我们将手动填充所有正样本和负样本,然后调用我们上面定义的训练函数:\n"
|
||||
"让我们试试吧!我们将手动填充所有正样本和负样本,然后调用我们上面定义的训练函数:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -607,7 +733,7 @@
|
|||
"source": [
|
||||
"正如上图所示,准确率从未超过75%,因为不可能画出一条直线来正确分类所有可能的样本。\n",
|
||||
"\n",
|
||||
"XOR问题是感知机局限性的经典例子,这一问题由Marvin Minsky和Seymour Papert在1969年的著作[《感知机》](https://en.wikipedia.org/wiki/Perceptrons_(book))中指出。这一观察限制了神经网络领域的研究近10年,尽管——我们将在课程的下一部分看到——多层感知机完全能够解决此类问题。\n",
|
||||
"XOR问题是感知机局限性的经典例子,这一问题由Marvin Minsky和Seymour Papert在1969年他们的书籍[《感知机》](https://en.wikipedia.org/wiki/Perceptrons_(book))中指出。这一观察限制了神经网络领域的研究近10年,尽管——我们将在课程的下一部分看到——多层感知机完全能够解决此类问题。\n",
|
||||
"\n",
|
||||
"## 复杂示例 - MNIST\n",
|
||||
"\n",
|
||||
|
|
@ -617,7 +743,7 @@
|
|||
"\n",
|
||||
"所有数字都以28x28像素的灰度图像表示。\n",
|
||||
"\n",
|
||||
"> MNIST数据集作为一个训练竞赛可在[Kaggle](https://www.kaggle.com/c/digit-recognizer)上找到,Kaggle是一个举办机器学习竞赛和比赛的网站。一旦你学会如何分类MNIST数字,可以将你的解决方案提交到Kaggle,看看它在其他参与者中的排名。\n",
|
||||
"> MNIST数据集在[Kaggle](https://www.kaggle.com/c/digit-recognizer)上作为一个训练竞赛提供。Kaggle是一个举办机器学习竞赛和比赛的网站。一旦你学会如何分类MNIST数字,可以将你的解决方案提交到Kaggle,看看它在其他参与者中的排名。\n",
|
||||
"\n",
|
||||
"我们从加载MNIST数据集开始:\n"
|
||||
]
|
||||
|
|
@ -695,7 +821,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"因为感知器是一个二分类器,我们将把问题限制为只识别两个数字。下面的函数将用两个给定的数字填充正样本和负样本数组(并且还会显示这些数字的样本以便于理解)。\n"
|
||||
"因为感知器是一个二分类器,我们将把问题限制为仅识别两个数字。下面的函数将用两个给定的数字填充正样本和负样本数组(并且还会显示这些数字的样本以便于理解)。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -833,9 +959,9 @@
|
|||
"source": [
|
||||
"请注意,准确率会非常快地接近100%。\n",
|
||||
"\n",
|
||||
"请将滑块移动到训练后期的某个位置,并观察左侧绘制的权重矩阵。通过这个矩阵,您可以了解感知器的实际工作原理。您会看到字段中间的权重值较高,这些值对应于数字1通常出现的像素,而两侧的权重值较低甚至为负,这些区域通常是数字0的一部分。因此,如果呈现给感知器的数字确实是1,中间部分的像素会与高权重值相乘,产生正结果。相反,当感知器观察到数字0时,相应的像素会与负数相乘。\n",
|
||||
"请将滑块移动到训练接近尾声的位置,并观察左侧绘制的权重矩阵。通过这个矩阵,你可以理解感知器的实际工作原理。你会看到在字段中间的权重值很高,这些对应于数字1通常出现的像素,而在两侧的权重值较低甚至为负,这些对应于数字0的部分。因此,如果呈现给感知器的数字确实是1,中间部分的像素会与高权重值相乘,产生正结果。相反,当感知器观察到数字0时,相应的像素会与负数相乘。\n",
|
||||
"\n",
|
||||
"> 您可能会注意到,如果我们给感知器一个稍微水平偏移的数字1,使其像素占据了数字0的垂直部分位置,我们可能会得到错误的结果。由于MNIST数据集的特点是所有数字都居中且位置正确,感知器依赖这一点来区分数字。\n",
|
||||
"> 你可能会注意到,如果我们给感知器一个稍微水平偏移的数字1,使其像素占据了数字0的垂直部分位置,我们可能会得到错误的结果。这是因为我们的MNIST数据集的特点是所有数字都居中且位置正确,而感知器依赖这一点来区分数字。\n",
|
||||
"\n",
|
||||
"现在让我们尝试不同的数字:\n"
|
||||
]
|
||||
|
|
@ -913,11 +1039,11 @@
|
|||
"source": [
|
||||
"## 讨论\n",
|
||||
"\n",
|
||||
"由于某些原因,数字2和数字5并不容易区分。尽管我们获得了相对较高的准确率(超过85%),但我们可以明显看到感知器在某个点停止了学习。\n",
|
||||
"由于某些原因,数字 2 和 5 并不容易区分。尽管我们获得了相对较高的准确率(超过 85%),但我们可以清楚地看到感知机在某个点停止了学习。\n",
|
||||
"\n",
|
||||
"为了理解为什么会发生这种情况,我们可以尝试使用[主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)。这是一种机器学习技术,用于降低输入数据集的维度,以便获得类别之间的最佳可分性。\n",
|
||||
"为了理解为什么会发生这种情况,我们可以尝试使用[主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA)。这是一种机器学习技术,用于降低输入数据集的维度,以便在类之间获得最佳的可分性。\n",
|
||||
"\n",
|
||||
"在我们的例子中,输入图像有784个像素(输入特征),我们希望使用PCA将参数数量减少到仅2个,以便可以在图表上绘制它们。这两个参数将是原始特征的线性组合,我们可以将这个过程视为“旋转”原始的784维空间,并观察其在二维空间上的投影,直到获得最佳视图以区分类别。\n"
|
||||
"在我们的例子中,一张输入图像有 784 个像素(输入特征),我们希望使用 PCA 将参数数量减少到仅 2 个,这样我们就可以在图表上绘制它们。这两个参数将是原始特征的线性组合,我们可以将这一过程视为“旋转”我们原本的 784 维空间,并观察其在二维空间中的投影,直到我们获得能够最好地区分类别的视图为止。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1027,17 +1153,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"正如你所见,0 和 1 可以通过一条直线清晰地分开。这表明在原始的784维空间中,与数字对应的点也是线性可分的。而对于数字2和5,我们无法找到能够清晰分开这些数字的良好投影,因此会出现一些错误分类的情况。\n",
|
||||
"正如你所见,数字 0 和 1 可以通过一条直线清晰地分开。这表明在原始的 784 维空间中,与数字对应的点也是线性可分的。而对于数字 2 和 5,我们无法找到能够清晰分开这两个数字的良好投影,因此会出现一些错误分类的情况。\n",
|
||||
"\n",
|
||||
"> 在后续课程中,我们将学习如何使用神经网络创建非线性分类器,以及如何解决数字未正确对齐的问题。很快我们将在 MNIST 数字分类中达到超过99%的准确率,同时将数字分类为10个不同的类别。\n",
|
||||
"> 在后续课程中,我们将学习如何使用神经网络创建非线性分类器,以及如何解决数字未正确对齐的问题。很快我们将在 MNIST 数字分类中达到超过 99% 的准确率,同时将数字分类为 10 个不同的类别。\n",
|
||||
"\n",
|
||||
"## 关键点\n",
|
||||
"\n",
|
||||
" * 我们学习了最简单的神经网络架构——单层感知机。\n",
|
||||
" * 我们通过手动实现了感知机,使用基于梯度下降的简单训练过程。\n",
|
||||
" * 我们通过简单的基于梯度下降的训练过程,手动实现了感知机。\n",
|
||||
" * 尽管简单,单层感知机可以解决相当复杂的手写数字识别问题。\n",
|
||||
" * 单层感知机是一个线性分类器,因此它提供了与逻辑回归相同的分类能力。\n",
|
||||
" * 在样本空间中,感知机可以使用超平面分隔输入数据的两个类别。\n"
|
||||
" * 在样本空间中,感知机可以通过超平面分开两类输入数据。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1046,14 +1172,14 @@
|
|||
"source": [
|
||||
"## 致谢\n",
|
||||
"\n",
|
||||
"本笔记本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分,由 [Dmitry Soshnikov](http://soshnikov.com) 编写。灵感来源于微软剑桥研究院的神经网络工作坊。一些代码和示例材料来自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示文稿,以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 仓库。\n"
|
||||
"本笔记本是 [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners) 的一部分,由 [Dmitry Soshnikov](http://soshnikov.com) 编写。其灵感来源于微软剑桥研究院的神经网络工作坊。一些代码和示例材料来自 [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)、[Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) 和 [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) 的演示文稿,以及 [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) 仓库。\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**免责声明**: \n本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而引起的任何误解或误读,我们概不负责。\n"
|
||||
"\n---\n\n**免责声明**: \n本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。因使用本翻译而产生的任何误解或误读,我们概不负责。\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1082,8 +1208,8 @@
|
|||
"start_slideshow_at": "selected"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "b600be2562eb99fec12d87868192c1c3",
|
||||
"translation_date": "2025-10-03T15:12:47+00:00",
|
||||
"original_hash": "8626517d9b717736ebab28b78cc7d377",
|
||||
"translation_date": "2025-10-03T16:58:42+00:00",
|
||||
"source_file": "lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb",
|
||||
"language_code": "zh"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue