AI-For-Beginners/translations/he/lessons/2-Symbolic/Animals.ipynb

479 lines
19 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"# יישום מערכת מומחה לבעלי חיים\n",
"\n",
"דוגמה מתוך [תכנית הלימודים ב-AI למתחילים](http://github.com/microsoft/ai-for-beginners).\n",
"\n",
"בדוגמה זו, ניישם מערכת מבוססת ידע פשוטה כדי לזהות בעל חיים בהתבסס על כמה תכונות פיזיות. המערכת ניתנת לייצוג בעץ AND-OR הבא (זהו חלק מהעץ כולו, ניתן להוסיף בקלות עוד כללים):\n",
"\n",
"![](../../../../../../translated_images/he/AND-OR-Tree.5592d2c70187f283.webp)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## מעטפת מערכות מומחים משלנו עם הסקה לאחור\n",
"\n",
"בואו ננסה להגדיר שפה פשוטה לייצוג ידע המבוססת על כללי ייצור. נשתמש במחלקות פייתון כמילות מפתח להגדרת כללים. בעצם יהיו שלושה סוגים של מחלקות:\n",
"* `Ask` מייצגת שאלה שצריך לשאול את המשתמש. היא מכילה את קבוצת התשובות האפשריות.\n",
"* `If` מייצגת כלל, והיא סוכר תחבירי לאחסון תוכן הכלל.\n",
"* `AND`/`OR` הן מחלקות שמייצגות ענפי AND/OR של העץ. הן פשוט מאכסנות את רשימת הטיעונים בפנים. לפישוט הקוד, כל הפונקציונליות מוגדרת במחלקת האב `Content`.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"class Ask():\n",
" def __init__(self,choices=['y','n']):\n",
" self.choices = choices\n",
" def ask(self):\n",
" if max([len(x) for x in self.choices])>1:\n",
" for i,x in enumerate(self.choices):\n",
" print(\"{0}. {1}\".format(i,x),flush=True)\n",
" x = int(input())\n",
" return self.choices[x]\n",
" else:\n",
" print(\"/\".join(self.choices),flush=True)\n",
" return input()\n",
"\n",
"class Content():\n",
" def __init__(self,x):\n",
" self.x=x\n",
" \n",
"class If(Content):\n",
" pass\n",
"\n",
"class AND(Content):\n",
" pass\n",
"\n",
"class OR(Content):\n",
" pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"במערכת שלנו, זיכרון העבודה יכיל את רשימת ה**עובדות** כ**זוגות תכונה-ערך**. מאגר הידע ניתן להגדיר כמילון גדול אחד שממפה פעולות (עובדות חדשות שיש להכניס לזיכרון העבודה) לתנאים, המתוארים כביטויי AND-OR. בנוסף, ניתן לבצע `Ask` על כמה עובדות.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"rules = {\n",
" 'default': Ask(['y','n']),\n",
" 'color' : Ask(['red-brown','black and white','other']),\n",
" 'pattern' : Ask(['dark stripes','dark spots']),\n",
" 'mammal': If(OR(['hair','gives milk'])),\n",
" 'carnivor': If(OR([AND(['sharp teeth','claws','forward-looking eyes']),'eats meat'])),\n",
" 'ungulate': If(['mammal',OR(['has hooves','chews cud'])]),\n",
" 'bird': If(OR(['feathers',AND(['flies','lies eggs'])])),\n",
" 'animal:monkey' : If(['mammal','carnivor','color:red-brown','pattern:dark spots']),\n",
" 'animal:tiger' : If(['mammal','carnivor','color:red-brown','pattern:dark stripes']),\n",
" 'animal:giraffe' : If(['ungulate','long neck','long legs','pattern:dark spots']),\n",
" 'animal:zebra' : If(['ungulate','pattern:dark stripes']),\n",
" 'animal:ostrich' : If(['bird','long nech','color:black and white','cannot fly']),\n",
" 'animal:pinguin' : If(['bird','swims','color:black and white','cannot fly']),\n",
" 'animal:albatross' : If(['bird','flies well'])\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"כדי לבצע הסקת מסקנות לאחור, נגדיר את המחלקה `Knowledgebase`. היא תכלול:\n",
"* `memory` פעילה - מילון שממפה תכונות לערכים\n",
"* `rules` של בסיס הידע בפורמט שהוגדר למעלה\n",
"\n",
"שיטות עיקריות הן:\n",
"* `get` לקבלת ערך של תכונה, תוך ביצוע הסקה במידת הצורך. לדוגמה, `get('color')` יקבל את הערך של חריץ הצבע (ישאל אם נדרש, ויאחסן את הערך לשימוש מאוחר יותר בזיכרון הפעיל). אם נשאל `get('color:blue')`, הוא ישאל לגבי הצבע, ואז יחזיר ערך `y`/`n` בהתאם לצבע.\n",
"* `eval` מבצע את הסקת המסקנות בפועל, כלומר עובר על עץ AND/OR, מעריך תת-מטרות וכו'.\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"class KnowledgeBase():\n",
" def __init__(self,rules):\n",
" self.rules = rules\n",
" self.memory = {}\n",
" \n",
" def get(self,name):\n",
" if ':' in name:\n",
" k,v = name.split(':')\n",
" vv = self.get(k)\n",
" return 'y' if v==vv else 'n'\n",
" if name in self.memory.keys():\n",
" return self.memory[name]\n",
" for fld in self.rules.keys():\n",
" if fld==name or fld.startswith(name+\":\"):\n",
" # print(\" + proving {}\".format(fld))\n",
" value = 'y' if fld==name else fld.split(':')[1]\n",
" res = self.eval(self.rules[fld],field=name)\n",
" if res!='y' and res!='n' and value=='y':\n",
" self.memory[name] = res\n",
" return res\n",
" if res=='y':\n",
" self.memory[name] = value\n",
" return value\n",
" # field is not found, using default\n",
" res = self.eval(self.rules['default'],field=name)\n",
" self.memory[name]=res\n",
" return res\n",
" \n",
" def eval(self,expr,field=None):\n",
" # print(\" + eval {}\".format(expr))\n",
" if isinstance(expr,Ask):\n",
" print(field)\n",
" return expr.ask()\n",
" elif isinstance(expr,If):\n",
" return self.eval(expr.x)\n",
" elif isinstance(expr,AND) or isinstance(expr,list):\n",
" expr = expr.x if isinstance(expr,AND) else expr\n",
" for x in expr:\n",
" if self.eval(x)=='n':\n",
" return 'n'\n",
" return 'y'\n",
" elif isinstance(expr,OR):\n",
" for x in expr.x:\n",
" if self.eval(x)=='y':\n",
" return 'y'\n",
" return 'n'\n",
" elif isinstance(expr,str):\n",
" return self.get(expr)\n",
" else:\n",
" print(\"Unknown expr: {}\".format(expr))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"כעת נגדיר את בסיס הידע שלנו על חיות ונבצע את הייעוץ. שים לב שקראה זו תשאל אותך שאלות. תוכל לענות על ידי הקלדת `y`/`n` לשאלות כן-לא, או על ידי ציון מספר (0..N) לשאלות עם תשובות מרובות אפשרויות ארוכות יותר.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hair\n",
"y/n\n",
"sharp teeth\n",
"y/n\n",
"claws\n",
"y/n\n",
"forward-looking eyes\n",
"y/n\n",
"color\n",
"0. red-brown\n",
"1. black and white\n",
"2. other\n",
"has hooves\n",
"y/n\n",
"long neck\n",
"y/n\n",
"long legs\n",
"y/n\n",
"pattern\n",
"0. dark stripes\n",
"1. dark spots\n"
]
},
{
"data": {
"text/plain": [
"'giraffe'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"kb = KnowledgeBase(rules)\n",
"kb.get('animal')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## שימוש ב-Experta להסקת מסקנות קדימה\n",
"\n",
"בדוגמה הבאה, ננסה לממש הסקת מסקנות קדימה באמצעות אחת הספריות לייצוג ידע, [Experta](https://github.com/nilp0inter/experta). **Experta** היא ספרייה ליצירת מערכות הסקת מסקנות קדימה בפייתון, אשר מעוצבת בדומה למערכת הקלאסית הישנה [CLIPS](http://www.clipsrules.net/index.html). \n",
"\n",
"יכולנו גם לממש שרשור קדימה בעצמנו ללא בעיות רבות, אך מימושים פשוטים לרוב אינם יעילים מאוד. לצורך התאמה יעילה יותר של חוקים נעשה שימוש באלגוריתם מיוחד [Rete](https://en.wikipedia.org/wiki/Rete_algorithm).\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting git+https://github.com/nilp0inter/experta\n",
" Cloning https://github.com/nilp0inter/experta to /tmp/pip-req-build-7qurtwk3\n",
" Running command git clone --filter=blob:none --quiet https://github.com/nilp0inter/experta /tmp/pip-req-build-7qurtwk3\n",
" Resolved https://github.com/nilp0inter/experta to commit c6d5834b123861f5ae09e7d07027dc98bec58741\n",
" Installing build dependencies ... \u001b[?25ldone\n",
"\u001b[?25h Getting requirements to build wheel ... \u001b[?25ldone\n",
"\u001b[?25h Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n",
"\u001b[?25hRequirement already satisfied: frozendict~=2.4.6 in /opt/conda/envs/ai4beg/lib/python3.12/site-packages (from experta==1.9.5.dev1) (2.4.7)\n",
"Collecting schema~=0.6.7 (from experta==1.9.5.dev1)\n",
" Downloading schema-0.6.8-py2.py3-none-any.whl.metadata (14 kB)\n",
"Downloading schema-0.6.8-py2.py3-none-any.whl (14 kB)\n",
"Building wheels for collected packages: experta\n",
" Building wheel for experta (pyproject.toml) ... \u001b[?25ldone\n",
"\u001b[?25h Created wheel for experta: filename=experta-1.9.5.dev1-py3-none-any.whl size=34804 sha256=888c459512a5e713f4b674caa9a0f96cfdf07ec0d6eb56cc318ce0653d218014\n",
" Stored in directory: /tmp/pip-ephem-wheel-cache-1eeii9zy/wheels/3d/e8/bb/22d7956359603fa8dd679aa09f5b8efb3f29991c3986fdc787\n",
"Successfully built experta\n",
"Installing collected packages: schema, experta\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2/2\u001b[0m [experta]\n",
"\u001b[1A\u001b[2KSuccessfully installed experta-1.9.5.dev1 schema-0.6.8\n"
]
}
],
"source": [
"import sys\n",
"!{sys.executable} -m pip install git+https://github.com/nilp0inter/experta"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"from experta import *\n",
"#import experta"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```he\n",
"נגדיר את המערכת שלנו כקטגוריה שיורשת מ-`KnowledgeEngine`. כל כלל מוגדר על ידי פונקציה נפרדת עם אנוטציית `@Rule`, שמגדירה מתי הכלל יתבצע. בתוך הכלל, אנחנו יכולים להוסיף עובדות חדשות באמצעות הפונקציה `declare`, והוספת אותן עובדות תגרום לכך שיעודכנו כללים נוספים על ידי מנוע ההסקה ה'קדמי'.\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"trusted": true
},
"outputs": [],
"source": [
"class Animals(KnowledgeEngine):\n",
" @Rule(OR(\n",
" AND(Fact('sharp teeth'),Fact('claws'),Fact('forward looking eyes')),\n",
" Fact('eats meat')))\n",
" def cornivor(self):\n",
" self.declare(Fact('carnivor'))\n",
" \n",
" @Rule(OR(Fact('hair'),Fact('gives milk')))\n",
" def mammal(self):\n",
" self.declare(Fact('mammal'))\n",
"\n",
" @Rule(Fact('mammal'),\n",
" OR(Fact('has hooves'),Fact('chews cud')))\n",
" def hooves(self):\n",
" self.declare('ungulate')\n",
" \n",
" @Rule(OR(Fact('feathers'),AND(Fact('flies'),Fact('lays eggs'))))\n",
" def bird(self):\n",
" self.declare('bird')\n",
" \n",
" @Rule(Fact('mammal'),Fact('carnivor'),\n",
" Fact(color='red-brown'),\n",
" Fact(pattern='dark spots'))\n",
" def monkey(self):\n",
" self.declare(Fact(animal='monkey'))\n",
"\n",
" @Rule(Fact('mammal'),Fact('carnivor'),\n",
" Fact(color='red-brown'),\n",
" Fact(pattern='dark stripes'))\n",
" def tiger(self):\n",
" self.declare(Fact(animal='tiger'))\n",
"\n",
" @Rule(Fact('ungulate'),\n",
" Fact('long neck'),\n",
" Fact('long legs'),\n",
" Fact(pattern='dark spots'))\n",
" def giraffe(self):\n",
" self.declare(Fact(animal='giraffe'))\n",
"\n",
" @Rule(Fact('ungulate'),\n",
" Fact(pattern='dark stripes'))\n",
" def zebra(self):\n",
" self.declare(Fact(animal='zebra'))\n",
"\n",
" @Rule(Fact('bird'),\n",
" Fact('long neck'),\n",
" Fact('cannot fly'),\n",
" Fact(color='black and white'))\n",
" def straus(self):\n",
" self.declare(Fact(animal='ostrich'))\n",
"\n",
" @Rule(Fact('bird'),\n",
" Fact('swims'),\n",
" Fact('cannot fly'),\n",
" Fact(color='black and white'))\n",
" def pinguin(self):\n",
" self.declare(Fact(animal='pinguin'))\n",
"\n",
" @Rule(Fact('bird'),\n",
" Fact('flies well'))\n",
" def albatros(self):\n",
" self.declare(Fact(animal='albatross'))\n",
" \n",
" @Rule(Fact(animal=MATCH.a))\n",
" def print_result(self,a):\n",
" print('Animal is {}'.format(a))\n",
" \n",
" def factz(self,l):\n",
" for x in l:\n",
" self.declare(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ברגע שהגדרנו בסיס ידע, אנחנו ממלאים את זיכרון העבודה שלנו בכמה עובדות התחלתיות, ואז קוראים למתודת `run()` כדי לבצע את המסקנות. ניתן לראות כתוצאה מעובדות חדשות שהוסקו מתווספות לזיכרון העבודה, כולל העובדה הסופית על החיה (אם הגדרנו נכון את כל העובדות ההתחלתיות).\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"trusted": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Animal is tiger\n"
]
},
{
"data": {
"text/plain": [
"FactList([(0, InitialFact()),\n",
" (1, Fact(color='red-brown')),\n",
" (2, Fact(pattern='dark stripes')),\n",
" (3, Fact('sharp teeth')),\n",
" (4, Fact('claws')),\n",
" (5, Fact('forward looking eyes')),\n",
" (6, Fact('gives milk')),\n",
" (7, Fact('mammal')),\n",
" (8, Fact('carnivor')),\n",
" (9, Fact(animal='tiger'))])"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ex1 = Animals()\n",
"ex1.reset()\n",
"ex1.factz([\n",
" Fact(color='red-brown'),\n",
" Fact(pattern='dark stripes'),\n",
" Fact('sharp teeth'),\n",
" Fact('claws'),\n",
" Fact('forward looking eyes'),\n",
" Fact('gives milk')])\n",
"ex1.run()\n",
"ex1.facts"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**כתב ויתור**: \nמסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית [Co-op Translator](https://github.com/Azure/co-op-translator). למרות שאנו שואפים לדייק, יש להיות מודעים לכך כי תרגומים אוטומטיים עלולים להכיל שגיאות או אי־דיוקים. המסמך המקורי בשפתו המקורית הוא המקור המוסמך. עבור מידע קריטי מומלץ להיעזר בתרגום מקצועי ואנושי. אנו לא אחראים לכל אי הבנה או פרשנות שגויה הנובעים משימוש בתרגום זה.\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.7.4 64-bit (conda)",
"metadata": {
"interpreter": {
"hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
}
},
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
},
"coopTranslator": {
"original_hash": "8ef43db4b9182239fd150a76bd494fdb",
"translation_date": "2026-01-16T03:29:02+00:00",
"source_file": "lessons/2-Symbolic/Animals.ipynb",
"language_code": "he"
}
},
"nbformat": 4,
"nbformat_minor": 2
}