معاينة مختبر آمنة
Animals
هذي معاينة منقّحة للقراءة فقط؛ ما فيه أي شيء يشتغل داخل الصفحة.
قراءة فقط
معاينة الدفتر
Animals
> **ملاحظة بيئة التشغيل المدمجة:** هالمعاينة تستخدم عيّنة صغيرة وثابتة وآمنة من ناحية الحقوق عشان تكون النتايج قابلة للتكرار. النتايج بالحجم الكامل تحتاج مجموعة البيانات أو النموذج الموثّق بالدرس داخل بيئة خارجية معتمدة.
# بناء النظام الخبير للتعرّف على الحيوانات
هالمثال جزء من منهج AI for Beginners.
في هالمثال بنبني **نظام خبير** (Expert System) بسيط قائم على المعرفة، عشان يحدد الحيوان من بعض صفاته الجسدية. نقدر نمثّل النظام بشجرة AND-OR التالية. هذي مب الشجرة كاملة، ونقدر نضيف لها قواعد أكثر بسهولة:
> **وصف الشكل:** جزء من شجرة AND-OR للتعرّف على الحيوانات
## إطار (shell) لنظام خبير من بنائنا بالاستدلال الخلفي
خلّونا نعرّف لغة بسيطة لـ**تمثيل المعرفة** (Knowledge Representation, KR) مبنية على قواعد الإنتاج. بنستخدم فئات Python كأنها كلمات مفتاحية لتعريف القواعد. عندنا 3 أنواع أساسية من الفئات:
* `Ask` تمثّل سؤالًا نطرحه على المستخدم، وتحتوي مجموعة الإجابات الممكنة.
* `If` تمثّل قاعدة، وهي صياغة مختصرة تخزّن محتوى القاعدة.
* `AND` و`OR` تمثّلان فرعي AND وOR في الشجرة، وكل وحدة تخزّن قائمة الوسائط اللي داخلها. ولتبسيط الشفرة، عرّفنا الوظائف كلها في الفئة الأم `Content`.
class Ask():
def __init__(self,choices=['y','n']):
self.choices = choices
def ask(self):
if max([len(x) for x in self.choices])>1:
for i,x in enumerate(self.choices):
print("{0}. {1}".format(i,x),flush=True)
x = int(input())
return self.choices[x]
else:
print("/".join(self.choices),flush=True)
return input()
class Content():
def __init__(self,x):
self.x=x
class If(Content):
pass
class AND(Content):
pass
class OR(Content):
passفي نظامنا، تحتوي ذاكرة العمل على قائمة **حقائق** ممثّلة على هيئة **أزواج سمة–قيمة**. ونعرّف قاعدة المعرفة بقاموس كبير يربط الإجراءات — الحقائق الجديدة اللي نضيفها إلى ذاكرة العمل — بالشروط المعبّر عنها بتعابير AND-OR. ونقدر بعد نستخدم `Ask` للسؤال عن بعض الحقائق.
rules = {
'default': Ask(['y','n']),
'color' : Ask(['red-brown','black and white','other']),
'pattern' : Ask(['dark stripes','dark spots']),
'mammal': If(OR(['hair','gives milk'])),
'carnivor': If(OR([AND(['sharp teeth','claws','forward-looking eyes']),'eats meat'])),
'ungulate': If(['mammal',OR(['has hooves','chews cud'])]),
'bird': If(OR(['feathers',AND(['flies','lies eggs'])])),
'animal:monkey' : If(['mammal','carnivor','color:red-brown','pattern:dark spots']),
'animal:tiger' : If(['mammal','carnivor','color:red-brown','pattern:dark stripes']),
'animal:giraffe' : If(['ungulate','long neck','long legs','pattern:dark spots']),
'animal:zebra' : If(['ungulate','pattern:dark stripes']),
'animal:ostrich' : If(['bird','long nech','color:black and white','cannot fly']),
'animal:pinguin' : If(['bird','swims','color:black and white','cannot fly']),
'animal:albatross' : If(['bird','flies well'])
}عشان ننفّذ الاستدلال الخلفي، بنعرّف فئة قاعدة المعرفة `Knowledgebase`. وبتحتوي على:
* ذاكرة العمل `memory`: قاموس يربط السمات بقيمها.
* قواعد قاعدة المعرفة `rules` بالصيغة اللي عرّفناها فوق.
والطريقتان الرئيسيتان هما:
* `get` تجيب قيمة سمة وتنفّذ الاستدلال إذا احتاجت. مثلًا، `get('color')` تجيب قيمة خانة اللون؛ وتسأل عنها إذا لزم، ثم تحفظها في ذاكرة العمل للاستخدام لاحقًا. وإذا طلبنا `get('color:blue')`، بتسأل عن اللون ثم ترجع `y` أو `n` بحسب الإجابة.
* `eval` تنفّذ الاستدلال نفسه؛ يعني تمر على شجرة AND/OR وتقيّم الأهداف الفرعية وغيرها.
class KnowledgeBase():
def __init__(self,rules):
self.rules = rules
self.memory = {}
def get(self,name):
if ':' in name:
k,v = name.split(':')
vv = self.get(k)
return 'y' if v==vv else 'n'
if name in self.memory.keys():
return self.memory[name]
for fld in self.rules.keys():
if fld==name or fld.startswith(name+":"):
# print(" + proving {}".format(fld))
value = 'y' if fld==name else fld.split(':')[1]
res = self.eval(self.rules[fld],field=name)
if res!='y' and res!='n' and value=='y':
self.memory[name] = res
return res
if res=='y':
self.memory[name] = value
return value
# field is not found, using default
res = self.eval(self.rules['default'],field=name)
self.memory[name]=res
return res
def eval(self,expr,field=None):
# print(" + eval {}".format(expr))
if isinstance(expr,Ask):
print(field)
return expr.ask()
elif isinstance(expr,If):
return self.eval(expr.x)
elif isinstance(expr,AND) or isinstance(expr,list):
expr = expr.x if isinstance(expr,AND) else expr
for x in expr:
if self.eval(x)=='n':
return 'n'
return 'y'
elif isinstance(expr,OR):
for x in expr.x:
if self.eval(x)=='y':
return 'y'
return 'n'
elif isinstance(expr,str):
return self.get(expr)
else:
print("Unknown expr: {}".format(expr))الحين بنعرّف قاعدة معرفة الحيوانات ونبدأ الاستشارة. الاستدعاء بيسألكم عدة أسئلة: اكتبوا `y` أو `n` لأسئلة نعم ولا، أو اختاروا رقمًا من (0..N) إذا كان السؤال متعدد الخيارات.
kb = KnowledgeBase(rules)
course_answers = {
"hair": "y",
"sharp teeth": "y",
"claws": "y",
"forward-looking eyes": "y",
"color": "red-brown",
"pattern": "dark stripes",
}
kb.memory.update(course_answers)
animal = kb.get("animal")
print(f"Deterministic course example: {animal}")
assert animal == "tiger"## استخدام Experta للاستدلال الأمامي
في المثال الجاي بننفّذ الاستدلال الأمامي باستخدام مكتبة تمثيل المعرفة [Experta](https://github.com/nilp0inter/experta). مكتبة **Experta** مخصصة لبناء أنظمة الاستدلال الأمامي في Python، وصُممت بطريقة تشبه النظام الكلاسيكي [CLIPS](https://www.clipsrules.net/).
نقدر نبني الاستدلال الأمامي بأنفسنا، لكن التنفيذ البسيط عادة يكون قليل الكفاءة. لمطابقة القواعد بكفاءة أعلى تُستخدم خوارزمية خاصة اسمها [Rete](https://en.wikipedia.org/wiki/Rete_algorithm).
import sys
# Dependencies are provisioned by this course edition's pinned runtime profile.from experta import *
#import expertaبنعرّف نظامنا على هيئة فئة فرعية من `KnowledgeEngine`. لكل قاعدة دالة مستقلة ومعها المزخرف `@Rule`، وهو اللي يحدد متى تنطلق القاعدة. وداخل القاعدة نقدر نضيف حقائق جديدة بالدالة `declare`؛ وإضافة هالحقائق يمكن تخلّي محرك الاستدلال الأمامي يشغّل قواعد ثانية.
class Animals(KnowledgeEngine):
@Rule(OR(
AND(Fact('sharp teeth'),Fact('claws'),Fact('forward looking eyes')),
Fact('eats meat')))
def cornivor(self):
self.declare(Fact('carnivor'))
@Rule(OR(Fact('hair'),Fact('gives milk')))
def mammal(self):
self.declare(Fact('mammal'))
@Rule(Fact('mammal'),
OR(Fact('has hooves'),Fact('chews cud')))
def hooves(self):
self.declare('ungulate')
@Rule(OR(Fact('feathers'),AND(Fact('flies'),Fact('lays eggs'))))
def bird(self):
self.declare('bird')
@Rule(Fact('mammal'),Fact('carnivor'),
Fact(color='red-brown'),
Fact(pattern='dark spots'))
def monkey(self):
self.declare(Fact(animal='monkey'))
@Rule(Fact('mammal'),Fact('carnivor'),
Fact(color='red-brown'),
Fact(pattern='dark stripes'))
def tiger(self):
self.declare(Fact(animal='tiger'))
@Rule(Fact('ungulate'),
Fact('long neck'),
Fact('long legs'),
Fact(pattern='dark spots'))
def giraffe(self):
self.declare(Fact(animal='giraffe'))
@Rule(Fact('ungulate'),
Fact(pattern='dark stripes'))
def zebra(self):
self.declare(Fact(animal='zebra'))
@Rule(Fact('bird'),
Fact('long neck'),
Fact('cannot fly'),
Fact(color='black and white'))
def straus(self):
self.declare(Fact(animal='ostrich'))
@Rule(Fact('bird'),
Fact('swims'),
Fact('cannot fly'),
Fact(color='black and white'))
def pinguin(self):
self.declare(Fact(animal='pinguin'))
@Rule(Fact('bird'),
Fact('flies well'))
def albatros(self):
self.declare(Fact(animal='albatross'))
@Rule(Fact(animal=MATCH.a))
def print_result(self,a):
print('Animal is {}'.format(a))
def factz(self,l):
for x in l:
self.declare(x)بعد ما نعرّف قاعدة المعرفة، نملأ ذاكرة العمل ببعض الحقائق الأولية ثم نستدعي `run` لتنفيذ الاستدلال. بتشوفون حقائق جديدة استنتجها النظام وانضافت إلى ذاكرة العمل، ومنها النتيجة النهائية عن الحيوان إذا ضبطنا الحقائق الأولية بالشكل الصحيح.
ex1 = Animals()
ex1.reset()
ex1.factz([
Fact(color='red-brown'),
Fact(pattern='dark stripes'),
Fact('sharp teeth'),
Fact('claws'),
Fact('forward looking eyes'),
Fact('gives milk')])
ex1.run()
ex1.factsحذفنا المخرجات وعدّادات التشغيل والودجات والمحتوى النشط وقت الاستيراد. شغّل الدفاتر بس في بيئة خارجية تثق فيها.
سجّل تطبيقك
التسجيل اختياري، يفيدك تتذكر وش طبّقت، ولا يمنع إكمال الدورة.