电竞比分网-中国电竞赛事及体育赛事平台

分享

專家系統(tǒng)

 昵稱4389 2006-01-06

在本章以及下面幾章,我將詳細介紹一下使用prolog設(shè)計專家系統(tǒng)的技術(shù)。首先讓我們來看看什么是專家系統(tǒng),以及它的基本設(shè)計方法和技術(shù),然后再使用prolog設(shè)計幾個微型專家系統(tǒng)。

什么是專家系統(tǒng)

專家系統(tǒng)是人工智能最重要的應(yīng)用之一,它的目的是讓電腦在某種程度上幫助或者替代某個領(lǐng)域的專家解決問題。例如醫(yī)療診斷系統(tǒng)、投資風險分析系統(tǒng)、家居設(shè)計系統(tǒng)等等。

一個典型的專家系統(tǒng)的構(gòu)成方式如下圖所示:

 

Domain Expert就是某個領(lǐng)域的專家,他提供原始的知識。Knowledge Engineer是把專家的知識翻譯成電腦所能夠識別的知識的工程師。某領(lǐng)域的專家把他所知道的知識告訴knowlegde engineer以后,由knowlegde engineer對這些知識進行處理,最后做成知識庫knowledge base。System Engineer是設(shè)計專家系統(tǒng)的程序員,他的主要任務(wù)是編寫專家系統(tǒng)的推理機構(gòu)inferface engine,和用戶界面user interface。用戶使用用戶界面和專家系統(tǒng)打交道,他和專家系統(tǒng)之間的交流的一些信息由工作空間working storage儲存。推理機構(gòu)根據(jù)用戶信息和知識庫中的信息為用戶提供服務(wù)。

在設(shè)計專家系統(tǒng)時候有目標驅(qū)動和數(shù)據(jù)驅(qū)動兩種方式。下面我們通過實例來說明一下如何使用prolog編寫目標驅(qū)動的專家系統(tǒng)。

一個可以識別鳥類的專家系統(tǒng)

這個系統(tǒng)的目的是通過用戶對某種鳥類的描述,推斷出用戶描述的是何種鳥。由于prolog的規(guī)則就是一種非常好的表達知識的方法,而其內(nèi)建的回溯功能和模式匹配功能則是很好的推理機構(gòu),所以使用prolog來編寫這樣的專家系統(tǒng)是再容易不過的了。

首先讓我們來看看如何是使用prolog的規(guī)則來表達知識吧。我們可以從鳥類專家那里得到如下的知識:

如果某種鳥是屬于信天翁科,并且其顏色是白色的,那么這種叫就是laysan信天翁。(我是翻譯的外文教材,所以這里關(guān)于鳥類的知識翻譯的并不是太準確)

當然我們要用英語來表這個規(guī)則:

IF
family is albatross and
color is white
THEN
bird is laysan_albatross

如果使用prolog的規(guī)則來表達就是:

bird(laysan_albatross) :-
family(albatross),
color(white).

同樣我們還可以加入下面的規(guī)則:

bird(laysan_albatross):-
family(albatross),
color(white).

bird(black_footed_albatross):-
family(albatross),
color(dark).

bird(whistling_swan) :-
family(swan),
voice(muffled_musical_whistle).

bird(trumpeter_swan) :-
family(swan),
voice(loud_trumpeting).

為了能夠讓這些規(guī)則能夠分辨不同的鳥類,我們必須儲存關(guān)于某種鳥的特定的信息。例如,如果我們加入下面兩個事實的話:

family(albatross).
color(dark).

然后在解釋器中進行如下的詢問:

- bird(X).
X = black_footed_albatross

很自然的我們就得到了答案。

現(xiàn)在我們看到了一個再簡單不過的專家系統(tǒng)了。他具備了前面所說的專家系統(tǒng)的幾個構(gòu)造部分。

四條關(guān)于識別鳥的規(guī)則就是知識庫knowledge base。

兩條關(guān)于某種鳥的特性的事實就是工作空間working storage中存儲的信息。

prolog的內(nèi)建的模式匹配和回溯功能就是推理機構(gòu)。

prolog的解釋器就是用戶界面。

當然,上面的這四個部分都還只是雛形,下面我們就要分解介紹如何慢慢的添加功能。

增加層次關(guān)系

僅僅使用上面的四條知識構(gòu)成專家系統(tǒng)的知識結(jié)構(gòu)是遠遠不夠的。下面我們就來添加一些新的知識。動物界為動物分了科、目、屬、種、類等幾個層次,這些層次構(gòu)成一個樹狀結(jié)構(gòu),下面的幾條規(guī)則就描述了其中的一些層次結(jié)構(gòu)。

order(tubenose) :-
nostrils(external_tubular),
live(at_sea),
bill(hooked).

order(waterfowl) :-
feet(webbed),
bill(flat).

family(albatross) :-
order(tubenose),
size(large),
wings(long_narrow).

family(swan) :-
order(waterfowl),
neck(long),
color(white),
flight(ponderous).

 

其中的第二個規(guī)則:order的中文意思是動物學的目,waterfowl的意思是水鳥,所以第二個規(guī)則描述的就是,水鳥這個目的動物具有“腳有蹼”“bill扁平”這兩個特點。

再解釋一下最后一個規(guī)則,他的意思是天鵝這個科的的特點是:“屬于水鳥目”“頸部很長”“顏色是白色”“飛行起來比較沉重”。

注意前面我們bird的規(guī)則中使用了family,而在此對family的規(guī)則進行了定義,定義family的過程中,又使用了order。作為有強大回溯功能的prolog可以很容易的把這些規(guī)則串起來,而不需要我們做更多的工作。下面我們來看一個例子。

假如我們在系統(tǒng)中添加了如下的描述鳥的事實:

nostrils(external_tubular).
live(at_sea).
bill(hooked).
size(large).
wings(long_narrow).
color(dark).

那么我們就可以用來識別具有這些特征的是什么鳥了。

- bird(X).
X = black_footed_albatross

更加復(fù)雜的規(guī)則

要識別加拿大鵝就需要比較復(fù)雜的規(guī)則。因為加拿大鵝夏天在加拿大度過,而冬天在美國度過。我們在識別的時候需要知道是在什么地方,什么時候看到這種鳥的。在此我們僅需要加入兩個規(guī)則來描述它就行了。

bird(canada_goose):-
family(goose),
season(winter),
country(united_states),
head(black),
cheek(white).

bird(canada_goose):-
family(goose),
season(summer),
country(canada),
head(black),
cheek(white).

我們再加入一些關(guān)于地方的謂詞:

country(united_states):-
region(mid_west).

country(united_states):-
region(south_west).

country(united_states):-
region(north_west).

country(united_states):-
region(mid_atlantic).

country(canada):- province(ontario).

country(canada):- province(quebec).

region(new_england):-
state(X), member(X, [massachusetts, vermont, ....]).

region(south_east):- state(X), member(X, [florida, mississippi, ....]).

還有許多需要多個規(guī)則的鳥類。例如雄野鴨的頭是綠色的,而雌野鴨是雜褐色的。

bird(mallard):- family(duck), voice(quack), head(green). bird(mallard):- family(duck), voice(quack), color(mottled_brown).

好了,作為一個例子,我們的關(guān)于鳥類的知識夠多的了。只要你手上有一本這方面的專業(yè)書籍,你應(yīng)該很容易的把書上的知識翻譯成prolog的規(guī)則吧。

用戶界面

前面我們一直是使用prolog的事實來儲存有關(guān)用戶掌握的信息,作為一個真正的專家系統(tǒng),系統(tǒng)應(yīng)該主動的向用戶提問以收集信息,而不是讓用戶自己把所有的信息手工輸入。

所以這里當我們遇到需要向用戶收集信息的時候,就應(yīng)該向用戶提出問題。

前面的有關(guān)鳥的屬性都是需要從用戶那里獲得的信息。所以我們就把他們改寫成下面這種規(guī)則:

eats(X):- ask(eats, X).
feet(X):- ask(feet, X).
wings(X):- ask(wings, X).
neck(X):- ask(neck, X).
color(X):- ask(color, X).

ask(Attr, Val):- write(Attr:Val), write(‘? ‘), read(yes).

有了上面的這些規(guī)則,當系統(tǒng)需要尋找color(white)這個目標的時候,他就會調(diào)用ask規(guī)則,如果ask(color,white)目標成立的話,那么color(white)就成功了。

ask/2中的最后一個目標read(yes),只有當用戶輸入yes的時候才成功,而用戶輸入別的東西都會是失敗。

現(xiàn)在我們不需要事先添加用戶信息就可以運行了,系統(tǒng)會在需要的時候?qū)τ脩暨M行詢問。下面是一次對話的例子:

- bird(X).
nostrils : external_tubular? yes.
live : at_sea? yes.
bill : hooked? yes.
size : large? yes.
wings : long_narrow? yes.
color : white? yes.
X = laysan_albatross

這里還有一個問題,如果用戶最后一個問題回答no的話,那么bird(laysan_albatross)規(guī)則就會失敗,然后回溯,將會測試下一個規(guī)則bird(black_footed_albatross),它的第一個子目標又會引起系統(tǒng)詢問一些以前曾經(jīng)詢問過的問題。這的確是個比較笨的系統(tǒng),下面我們將介紹如何保存詢問的信息,以免重復(fù)詢問。

記住答案

我們使用新的謂詞known/3來記住用戶對問題的回答。這個謂詞的子句不是直接寫在程序中的,而是通過assert動態(tài)的加入到系統(tǒng)中的,這也就是專家系統(tǒng)的工作空間working storage。

每次調(diào)用ask謂詞要做的第一件事情,就是檢查known謂詞是否已經(jīng)保存了這個問題的信息。如果還沒有保存過這樣的問題的信息,就會在用戶回答以后,把回答的答案加入到系統(tǒng)中。known/3的三個參數(shù)分別是yes/no,屬性,屬性值。 新版本的ask謂詞如下:

ask(A, V):-
known(yes, A, V), % 如果這個問題已經(jīng)有答案yes,那么ask目標就成功。
!. % 不需要考察其它的ask子句。

ask(A, V):-
known(_, A, V), % 如果答案是no,ask目標就失敗。
!, fail.

ask(A, V):-
write(A:V), % 詢問用戶
write(‘? : ‘),
read(Y), % 得到答案
asserta(known(Y, A, V)), % 把答案記錄下來。
Y == yes. % 判斷用戶的回答。

具有多值的回答

我們還可以對known謂詞進行改進。到目前為止,ask謂詞所詢問的問題都是是非問題。這意味著用戶可能會對color-white和color-black這樣的問題同時回答yes,這顯然是不合理的,當系統(tǒng)知道color-white是真的時候,就應(yīng)該同時知道color-black是假。這就是說color屬性只能是單值的,不過對于voice這樣的屬性就可以多值的。所以我們在專家系統(tǒng)中應(yīng)該對這些屬性進行說明。

我們使用最簡單的方法來解決這個問題---加一個用來描述屬性的謂詞。

multivalued(voice).
multivalued(feed).

這兩個句子說明voice和feed屬性可以是多值的。

同時我們需要對ask謂詞進行修改:

ask(A, V):-
not multivalued(A),
known(yes, A, V2),
V \== V2, !, fail.

我們添加上面一條ask子句,它應(yīng)該放在其他ask子句之前。這個子句首先檢查屬性A是否為多值屬性,如果不是,就在已知的屬性值中查找是否已經(jīng)有其他的值, 如果有的話,就不需要詢問用戶,而直接失敗了。

例如,如果用戶已經(jīng)對size-large這個問題回答了yes,系統(tǒng)就不會詢問size-small這樣的問題了。

用戶菜單

我們可以進一步的改進用戶的界面,例如可以添加讓用戶選擇答案的菜單功能。

我們使用menuask謂詞來完成這個功能。它和ask很相像,不過多了一個用來保存所有可能的屬性值的列表參數(shù)。把原來的ask謂詞出現(xiàn)的地方用menuask來替代:

size(X):- menuask(size, X, [large, plump, medium, small]).
flight(X):- menuask(flight, X, [ponderous, agile, flap_glide]).

menuask的具體程序如下:

menuask(A, V, MenuList) :-
write(‘What is the value for‘), write(A), write(‘?‘), nl,
write(MenuList), nl,
read(X),
check_val(X, A, V, MenuList),
asserta( known(yes, A, X) ),
X == V.

check_val(X, A, V, MenuList) :- %如果用戶輸入的值在列表中可以找到。
member(X, MenuList), !.

check_val(X, A, V, MenuList) :- %如果找不到。
write(X), write(‘ is not a legal value, try again.‘), nl,
menuask(A, V, MenuList).

這是一個最最簡單的menuask的例子,用戶需要輸入屬性值的內(nèi)容,而不能通過輸入1、2、3或者是a、b、c來選擇屬性值。

一個簡單的外殼程序

很明顯這個識別鳥類的專家系統(tǒng)由兩個完全不同的部分組成,一個是知識庫,另一個是控制用戶界面的。

我們應(yīng)該盡量把這兩部分分離開來,這樣我們就可以制作出一個外殼程序,使用這個外殼程序和不同的知識庫聯(lián)接,就可以快速的開發(fā)不同的專家系統(tǒng)了。

為了能夠把這兩部分分開,就要定義統(tǒng)一的接口。由于不同的專家系統(tǒng)要完成的目標不一樣,例如識別鳥的系統(tǒng)的目標是bird(X),而識別魚的系統(tǒng)則是fish(X),因此在每個知識庫中都定一個相同的最頂層目標top_goal(X)。對于識別鳥的系統(tǒng)這個目標為:

top_goal(X):-bird(X).

在外殼程序中我們可以定義solve謂詞做一些初始化工作,以及調(diào)用知識庫的頂層目標top_goal:

solve :-
abolish(known, 3),
define(known, 3),
top_goal(X),
write(‘The answer is ‘), write(X), nl.

solve :-
write(‘No answer found.‘), nl.

內(nèi)部謂詞abolish是用來刪除系統(tǒng)中所有的known子句的。這樣用戶就可以使用solve來解決不同的問題,而不至于把兩次對話的內(nèi)容搞混淆。

由于一開始系統(tǒng)中沒有known子句,所以需要使用define來定義一下,這樣系統(tǒng)再找不到known子句的時候就不會報告錯誤了。不同的prolog系統(tǒng)的這種內(nèi)部謂詞不一定相同。

現(xiàn)在總結(jié)一下:

solve ask menuask謂詞都是外殼程序中的謂詞,也就是說它們對于所有的類似的專家系統(tǒng)都是相同的。

top_goal bird order family region size color eats wings multivalue這樣的謂詞都是屬于知識庫的謂詞,它們是和具體的知識掛鉤的。top_goal是外殼程序和知識庫之間的橋梁。

如果我們把這些謂詞分別保存在不同的文件中,例如外殼程序保存在文件native中,而鳥類的知識庫保存在birds.kb中的話,我們只要在解釋器中進行如下的對話就可以使用專家系統(tǒng)了。

- consult(native).
yes

- consult(‘birds.kb‘).
yes

- solve.
nostrils : external_tubular?
... ...

命令循環(huán)

我們還可以增強外殼程序的功能,增加一個叫做go的謂詞,go可以識別三種命令:load consult和quit。

load命令用來調(diào)入某個知識庫,consult命令用來調(diào)用知識庫的top_goal從而開始對話,quit用來退出外殼程序。

下面是go謂詞的具體程序:

go :-
greeting,
repeat,
write(‘> ‘),
read(X),
do(X),
X == quit.

greeting :-
write(‘This is the Native Prolog shell.‘), nl,
write(‘Enter load, consult, or quit at the prompt.‘), nl.

do(load) :- load_kb, !.

do(consult) :- solve, !.

do(quit).

do(X) :-
write(X),
write(‘is not a legal command.‘), nl,
fail.

go謂詞使用repeat循環(huán)不停的從用戶取得命令。do謂詞用來識別用戶的命令。這里的load_kb謂詞的具體程序如下:

load_kb :-
write(‘Enter file name: ‘),
read(F),
reconsult(F).

我們還可以增加一些其他的外殼命令,例如:help,用來顯示所有的命令的使用方法,list用來列出所有的known子句以供調(diào)試之用。

最后我們的專家系統(tǒng)和用戶之間的對話如下:

- consult(native).
yes

- go.
This is the native Prolog shell.
Enter load, consult, or quit at the prompt.
>load.
Enter file name: ‘birds.kb‘.
>consult.
nostrils : external_tubular ? yes.
...
The answer is black_footed_albatross
>quit.
-

通過使用外殼程序,我們可以屏蔽一些prolog編程的難點。讓開發(fā)人員在編寫專家系統(tǒng)的時候只需要把注意力集中在知識庫的表達上面,而使用prolog表達知識庫是很容易的,就和我們平時說話沒有什么兩樣。

到這里,你應(yīng)該對專家系統(tǒng)的編寫有個初步的了解了吧,下一章我們將研究一些比較深的專家系統(tǒng)的知識了。

(由于本章介紹的專家系統(tǒng)還只是雛形,所以沒有提供完整的程序,你可以自己把上面的程序片斷拼湊起來,在解釋器中測試一下。)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多