сряда, 3 април 2013 г.

Представяне на дефиницията на AI във вид удобен за инженера



Абстракт

Тази статия разглежда някой технически въпроси свързани с дефиницията на AI. Това са формата на данните, символите Undef и Nothing, различни възможности за дефинирането на смисъла на живота и въвеждането на понятието "некоректен ход". Тези въпроси не са съществени, ако се интересуваме от дефиницията на AI чисто теоретично, но ако искаме да създадем реална програма удовлетворяваща тази дефиниция, то тези въпроси са важни.


Въведение

Ако искате да отговорите на въпроса: "Какво е това AI?" то първо трябва да се съобразите, на кого отговаряте и каква е целта на вашия отговор. Дали искате да убедите читателя, че AI съществува и че притежава едни или други интересни от теоретична гледна точка качества или искате да напишете инструкция за създаването му, в която вашият читател ще открие редица полезни практически съвети и технически трикове, които биха му били полезни при реален опит за написване на програмата, която наричаме AI.

Нека вземем като пример едно друго устройство наречено "компютър". Ако искаме да кажем какво е "компютър", първо трябва да решим за кого е предназначен нашият отговор. Може нашите читатели да са математици и да се интересуват от въпросите: "Съществува ли такова устройство?", "Какви свойства притежава то?", "Можем ли да го сведем до друго познато ни устройство? (т.е. да сведем нещата до предишния случай)". Математиците биха се зарадвали на дефиниция от вида "Машина на Тюринг" или "Машина с неограничени регистри", защото на тях им е нужно едно максимално просто описание, с което може лесно да се работи. Ако искате да проведете едно доказателство по индукция ще трябва да проверите за всяка от командите на Машината на Тюринг дали запазва индукционното предположение. Хубавото е, че всичките команди на Машината на Тюринг са от един и същи вид. Ако решите да проведете подобно доказателство използвайки модела на реален компютър, то ще се сблъсквате с проблема, че там възможните команди са стотици и е почти невъзможно да проверите за всяка една от тях дали запазва индукционното предположение.

Ако искате да отговорите на въпросът: "Какво е компютър?" и ако отговора ви е предназначен за инженери, то ще трябва да кажете нещо за процесор и памет, за шини по които се предават данните, за бройна система по която тези данни се кодират и т.н.

Разликата между математиците и инженерите е първо в начина им на мислене и второ в целта, която те преследват. За математика понятието е интересно от теоретична гледна точка, а инженера иска да създаде реален продукт и затова него го вълнуват редица технически детайли, които за математика са несъществени.

Ето едно типично математическо разсъждение: "Искам да звънна на моя приятел Пешо, но съм забравил какъв беше телефонният му номер. Няма проблем, множеството на всички телефони номера е крайно, ще звънна на всички и един от тях е номера на Пешо." Подобно разсъждение много често се среща в математическите доказателства. За математика въпросът е: "Мога ли да звънна на Пешо?" и отговорът е: "Да, може. Съществува алгоритъм, който след краен брой стъпки ще даде желания резултат". Разбира се, инженерите не използват подобни доказателства, защото тях не ги интересува въпросът: "Това теоретично възможно ли е?". Инженерите търсят реално работещо решение. Дори и да не знаят защо това работи, не се притесняват, защото важното за тях е решението да работи, а защо работи не е чак толкова важно.

В статиите [1, 2, 4] ние се опитахме да се харесаме на математиците и предложихме дефиниция на Изкуствен Интелект, която е удобна от теоретична гледна точка, но за целите на практиката е нужно да влезем в детайли, които са нужни за създаването не реална програма удовлетворяваща дефиницията.

Тоест, целта на тази статия е да се хареса на инженерите и да им каже какво е Изкуствен Интелект по начин, който би им бил полезен за създаването на реална работеща програма.


Формат на данните

Както казахме в статиите [1 - 4], Изкуственият Интелект е стъпково устройство, което на всяка стъпка въвежда и извежда някаква информация. Естествено изниква въпросът какъв е формата на тази информация.

В [1] входните и изходните данни бяха булеви вектори. Там оценката беше изразена чрез два специални бита от входа, които нарекохме "победа" и "загуба". Тоест, в [1] данните имат някаква структура, докато в [2] входните данни са просто букви от някаква крайна азбука (аналогично и изходните). Победата и загубата са просто някакви подмножества на множеството на входните символи. Тоест, в [2] данните нямат никаква структура.

Статията [1] беше публикувана в научно-популярно списание и по тази причина тя е написана за по-широката публика, докато статията [2] е предназначена за математическо списание и там техническите детайли са изчистени. Сметнато е, че за математиците формата на данните е без значение.

В [3] се разглежда един конкретен свят. Това е играта Tic-tac-toe. Формата на данните е същия като в [1], но е добавен един бит, който нарекохме "некоректен ход". В [3] се вижда, че булевият вектор не е най-подходящият възможен формат, защото там входа показва какво има в текущото квадратче от таблото на играта. Възможностите са три: празно, кръгче и кръстче. Тези три възможности се кодират в два бита, като една от четирите комбинации на двата бита просто не се използва, т.е. такъв вход никога не идва. Подобно е и положението с изхода. Там възможните действия са шест, което се кодира в три бита, като две от осемте комбинации на трите бита просто не се използват, т.е. когато устройството пробва да играе такава комбинация, винаги получава отговор "некоректен ход".

Това, че с помощта на кодиране можем да прехвърлим данните от един формат в друг означава, че от теоретична гледна точка формата на данните е без значение, но от гледна точка на практиката е важно да сме избрали правилния формат, за да се избегне нуждата от кодиране. Целта на AI е да разбере света и за да бъде тази цел лесно достижима е добре този свят да е максимално прост и лесен за разбиране. Ако сложим едно кодиране на входа и на изхода, по този начин ние може така да усложним света, че нашето устройство да не успее да го разбере.

Да вземем като пример цифрите от 0 до 9. Какво ще стане, ако вземе да ги разбъркаме? Ами, нищо особено. Щом сме успели да ги научим в този ред, ще успеем да ги научим и по новия начин. Да вземе сега числата от 0 до 99 и да ги разбъркаме. Нека започнем с едно леко разбъркване, като сменим само местата на двете цифри. Това разбъркване също няма да е проблем, защото щом сме успели да научим да пишем цифрите от ляво на дясно, можем да се научим да ги пишем и на обратно. Нека сега към числата от 0 до 99 да приложим една напълно произволна пермутация. Това вече ще е сериозен проблем, защото ще нарушим естествената логика, по която тези числа са подредени. Нека новият ред да изглежда приблизително така: 38, 12, 76 и т.н. В този нов ред няма никаква логика и ако искаме да се научим да броим от 0 до 99, то това би било едно много сериозно предизвикателство.

Аналогично е положението с булевите вектори. Предполагаме, че в тях света е представен по естествен начин и едно евентуално кодиране само ще усложни света и ще затрудни задачата този свят да бъде разбран. Ако разбъркаме нулата и единицата, то няма да е проблем, ако това са два символа, които произволно са кодирани с 0 и с 1, но ако предполагаме, че между тези символи има някаква наредба (т.е. че 0 е по-малко от 1), тогава разбъркването може да усложни света. Ако разменим местата на координатите във вектора, това също не би трябвало да е проблем, ако няма логика в подреждането на тези координати, но ако близките координати са свързани повече от далечните, то подобно разбъркване също може да е усложни света. Ако приложим произволна пермутация върху векторите, то това почти сигурно би било проблем, защото това ще скрие логиката, по която този формат е избран (стига да има такава логика разбира се).

Както казахме в [5], ще искаме светът да бъде сума от действието на различни фактори, които могат да бъдат независими, но могат и да си влияят един на друг. За подобен свят представянето на данните чрез вектори е особено подходящо. С вектори ще представяме и вътрешното състояние на света. (Светът е нещо външно за нашето устройство и за нас създателите на устройството няма значение какъв е формата на вътрешните състояния на света, но устройството ще търси можел на света и в този модел вътрешните състояния на света трябва да се опишат. За целите на това описание векторният формат е много подходящ, защото ако имаме два независими модела на света, много лесно можем да ги обединим в един, като новите състояния ще бъдат конкатенация от векторите на състоянията на двата модела.)


Сигнали

Дефиниция: Функция на един аргумент (времето), която връща скалар ще наричаме сигнал.

Тоест, координатите на векторите са сигнали. Ще разглеждаме четири вида сигнали: входящи, изходящи, оценъчни и вътрешни. Изходящите сигнали, това са координатите на изходния вектор. Входящите и оценъчните сигнали, това да координатите на входящия вектор.

Забележка: Тук изрично сме разделили входа на две: оценъчна част, която ни дава смисъла и чисто информационна част. По същия начин е направено в [1]. Там оценката беше изразена чрез два сигнала, които нарекохме "победа" и "загуба". Така е и в [3], но там има още един оценъчен сигнал наречен "некоректен ход". По-различно е в [2], където сме избрали да има само един входен сигнал, в който да са кодирани и информационната и оценъчната част на входа.

Освен сигналите участващи във входния и изходния вектор, имаме и много вътрешни сигнали, с които устройството ще работи и които ще използва, за да построи модел на света. Ще предполагаме, че устройството търси представяне на вътрешното състояние на света с вектор, чиито координати са вътрешни сигнали. Множеството на всевъзможните вътрешни сигнали е безкрайно, но във всеки конкретен момент, устройството е съсредоточило вниманието си върху краен брой вътрешни сигнали, които му се струват интересни и адекватни за света, в който е попаднало.


Небулеви вектори

Добре, след като решихме, че формата на данните и на вътрешните състояния на света ще е векторен, да си зададем въпросът дали можем да се ограничим в множеството на булевите вектори? Отговорът е, не. В [3] видяхме, че ако използваме само булеви вектори това налага допълнително кодиране.

Ако се ограничим само до булевите вектори, то тогава входните и изходните сигнали ще са булеви функции. Нека да допуснем и други по-сложни сигнали. Ще разрешим сигналът да връща k възможни стойности от множеството {0, 1, ... , k-1} вместо да има само две възможни стойности от множеството {0, 1}. Ще предполагаме още, че редът на тези стойности не е случаен (тоест, че наредбата "по-голямо" в множеството {0, 1, ... , k-1} кореспондира на някаква естествена наредба характерна за света, ако такава наредба има, разбира се). Предполагаме, че редът на възможните стойности на сигнала не е случаен, защото предполагаме, че света ни е предоставен по максимално естествения начин без да бъдем обременявани с никакво ненужно кодиране.

По този начин разширихме множеството на сигналите до множеството на крайните функции. Ще го разширим допълнително като разрешим сигналът да връща и безкрайни скалари като цяло, естествено или реално число. Отново ще предполагаме, че представянето на данните като цяло или като реално число не е случайно, а е свързано с вътрешната структура на света. Следователно ще очакваме при реалните числа да имаме свойството непрекъснатост (т.е. малките промени да не са съществени). Ще очакваме още релацията "по-голямо" при естествените и реалните числа да не е случайна, а да е свързана с естествената структура на света.


Представяне на безкрайните обекти като крайни

Ще разглеждаме устройство, което на входа и изхода си въвежда (съответно извежда) вектори от скалари, където някои от скаларите са крайни, но може да има и безкрайни скалари. При това положение излизаме от практическото решение, при което имаме програма, която на всяка стъпка въвежда и извежда крайно количество информация. Допускането, че можем да имаме изброими скалари, води до резултата, че информацията въведена на входа и изведена на изхода няма да е крайна. Щом допускаме и неизброими скалари (като реалните числа) това води до резултата, че входните и изходните вектори въобще не могат да се кодират като крайно последователност от битове.

Тоест, допускането на безкрайни обекти като част от входа и изхода води до теоретичен модел, който не съответства напълно на практиката. Все пак, можем да предположим, че естествените и реалните числа участващи във входните и изходните вектори не са истински, а са компютърно представени (например, че са представени в 64 бита, кодирани със стандартното компютърно кодиране). Така получаваме два модела. Първият модел е теоретичен, където устройството работи с вход и изход съдържащи реални и естествени числа. При втория модел, тези числа не са реални и естествени, а са псевдо-реалните и псевдо-естествените числа, с които работи компютъра.

С кой от тези два модела ще работим? Ще работим с теоретичния, като резултатите ще ги приложим в практиката използвайки практическия модел. По същия начин постъпват хората, които се занимават с машини на Тюринг. Там те работят с теоретичния модел на компютър с безкрайна памет (защото машината на Тюринг има безкрайна лента). След това те прилагат получените резултати върху реалните компютри, чиято памет е крайна.

Единствения случай, когато вместо теоретичния модел ще използваме практическия, това е когато искаме да използваме това, че множествата на възможните входове и изходи са крайни. Това ще ни трябва, за да направим някое безсмислено доказателство за съществуване от типа "Телефонните номера са крайно много, следователно мога да звънна на Пешо."


Символите Undef и Nothing

В много езици за програмиране се въвежда един специален символ за случая, когато нямаме стойност или не знаем каква е стойността. Този символ ще е полезен и в нашия случай. Ще го наречем символа Undef.

Друг специален символ ще бъде Nothing. Той ще ни е нужен за случая, когато нищо не се случва. Няма да даваме точно определение на това, кога в света нищо не се случва, а ще считаме, че един от входните символи е натоварен с допълнителен смисъл и че това е съвсем неформално и ориентировъчно без да означава нещо конкретно. Например, в реалния свят тишината може да бъде приета за символа Nothing. Интересно е, че когато човек спи на шум, той се събужда, ако шума рязко спре. Тоест, внезапно появилата се тишина се възприема като интересно събитие. Това означава, че символа Nothing е символ като всички останали и неговия смисъл като "нищо" е съвсем ориентировъчен.

Необходимо ли е, един определен символ да бъде натоварен с особен смисъл. От теоретична гледан точка не е нужно, но тук в тази статия се занимаваме с въпроса за практическото решение на задачата и искаме максимално да улесним устройството да разбере света и затова предполагаме, че сме му дали някаква предварителна информация. Такава информация е особения смисъл на символа Nothing.

Кога ще използваме символа Nothing? Например при входа, когато няма вход. Разбира се, нямането на вход, също е вход, но това е един по-специален вход.

Кога ще използваме символа Undef? Това ще бъде, когато входа е неизвестен (например някой датчик не е сработил или е закъснял с подаването на информацията си). Дори можем да предположим, че има възможност липсващата информация да се появи със закъснение (тоест, след още една стъпка да постъпи информация, че на предишната стъпка стойността на Undef е трябвало да бъде еди-коя-си.) Разбира се, нашето устройство трябва да може да приеме и обработи подобна информация, иначе тя не би имала никакъв смисъл.

От всеки сигнал може да получим нов като кажем "този сигнал преди k стъпки". Тоест, това е памет за сигнала. Естествено възниква въпроса, как да дефинираме тази памет за моментите когато t-k е отрицателно. Тоест, какво да си спомняме за момент преди раждането. Естествената стойност подходяща за този случай е символа Undef.

Нека вземем друг вътрешен сигнал. Нека имаме модел на света състоящ се от краен недетерминиран автомат. Нека имаме сигнал, който ни връща състоянието на този автомат в момента t. Ако автомата беше детерминиран, то и съответния му сигнал щеше да е детерминиран. Но при недетерминирания автомат може в даден момент да не знаем в кое състояние той се намира. Тогава естествено е сигнала да връща символа Undef. След още няколко стъпки, може да разберем в кое състояние сме били. Тогава може да постъпи допълнителна информация, която да ни каже, че стойността на сигнала на онази стъпка, е била еди-коя-си, а не Undef.

Както виждате, допускането на символите Undef и Nothing е много подходящо при входните сигнали и още по-подходящо при вътрешните сигнали.

При изходните сигнали също ще използваме символа Nothing. Представете си, че в даден момент, не знаете какво да правите. В този случай най-подходящо е нищо да не правите, но вие трябва нещо да направите, защото вашето устройство трябва да изведе някакъв изход, защото в противен случай то би увиснало безмълвно, а това предполагаме, че не трябва да се случва.

Кой да бъде изхода съответстващ на "не правя нищо". Нека това да бъде символа Nothing. Всеки друг символ може да играе тази роля, но ние предполагаме, че сме опростили и стандартизирали света в известна степен така, че да е по-лесно разбираем.

Естествено е символа Nothing да бъде котвата, за която устройството ще се захване, когато се появява (ражда) в един нов непознат свят. Първата му стъпка ще бъде да пробва, какво ще се случи когато играе Nothing по всичките координати на изходния вектор. После ще опита да даде стойност на една от координатите, а останалите да остави да бъдат Nothing.

Можем да допуснем, че при изходящите сигнали имаме право да използваме и символа Undef като предполагаме, че със закъснение от няколко стъпки устройството ще има право да уточни стойността на изхода и да каже какво е трябвало да стои на мястото на символа Undef. Това допускане много би усложнило нещата и затова няма да го правим. Тоест, символа Undef няма да участва в изходящите сигнали.

Нужен ли е символа Nothing при оценъчните сигнали? Отговорът е да. В статиите [1,3,4] предполагаме, че оценката се дава от два булеви сигнала наречени "победа" и "загуба". Когато тези два сигнала едновременно са единица, това го приемаме за "реми", а когато двата сигнала са едновременно нула, тогава приемаме, че нямаме никаква оценка. Както виждате, добавено е едно излишно кодиране. В [4] се изчислява успеха на устройството, като се смята средното аритметично от победите, загубите и ремитата, но в това средно аритметично не участват случаите когато не сме получили никаква оценка.

Не е логично да предполагаме, че на всяка стъпка нашето устройство ще получава  някаква оценка. По-добре е да предположим, че на повечето стъпки никаква оценка не се получава и за тези случаи нека използваме символа Nothing.

За да бъдат нещата прости и логични нека предположим, че оценката се дава от един сигнал, който има стойност 1, 0 и 1/2 съответно при случаите на победа, загуба и реми, а когато няма оценка сигнала да има стойност Nothing. Тогава успеха на устройството ще бъде средното аритметично на тези стойности на този сигнал, които са различни от Nothing.

За да опростим нещата ще предположим, че за случаите на входящи, изходящи и вътрешни сигнали символа Nothing съвпада със символа нула. Решихме един от символите да бъде натоварен с особен смисъл и най-подходящия за целта е символа нула. Другото предимство на нулата е, че тя присъства във всички формати. Има я и в булевия формат и в крайния и в естествените числа и в реалните и т.н.

Единствени случай, когато ще предполагаме, че нулата и Nothing са различни символи, това ще е в оценъчните сигнали. Там правим средно аритметично между всички стойности различни от Nothing, а нулата е нормално число, което спокойно може да участва в средното аритметично. Ние бихме искали специално да подчертаем, че Nothing не участва в изчисляването на средното аритметично и затова ще приемен, че то не е нула, а е нещо различно.


Възможни оценки

В [1] казахме, че за Изкуствен Интелект признаваме такава програма, която в произволен свят би се справила не по-зле от човек. За да можем да сравняваме и да казваме кой се е справил по-добре и кой по-зле, трябва да имаме някаква наредба да животите, която да ни казва кой живот е по-добър и кой е по-лош.

Тази наредба ще наричаме "смисъла на живота". За да дефинираме тази наредба, първо ще дефинираме смисъла на живота за случаите на краен живот, а след това ще разширим наредбата и за случаите на безкраен живот.

Нека имаме произволна линейна наредба на крайните животи. (Да припомним, че живот наричаме последователността от входните и изходните вектори от момента на раждането, до определен момент или до безкрайност)

За всяка линейна наредба между крайните животи има съответстваща на тази наредба, оценъчна функция (тази функция ще я наречем Succes). Тоест, ако един живот е по-добър от друг, то функцията Succes за по-добрия живот връща по-голяма стойност, отколкото за по-лошия.

Как по естествен начин да продължим дефиницията на смисъла на живота, така че тя да включи и безкрайните животи. Нека вземем редицата от началата на един безкраен живот. Нека за всяко едно начало да изчислим стойността на функцията Succes. Получаваме една редица от реални числа и ако тази редица е сходяща, то естествено е да дефинираме функцията Succes за този безкраен живот да бъде равна на тази граница (тук плюс и минус безкрайност също са възможни граници). Ако редицата не е сходяща, то ще считаме, че функцията Succes за този безкраен живот не е определена точно, но че нейната стойност е някъде между точната долна и точната горна граница на тази редица. По този начин получаваме една нова функция Succes, която за някои животи връща точна стойност, а за други връща интервал от възможно най-малката до възможно най-голямата стойност.

По този начин новата функция Succes определя една частична наредба в множеството на всички животи (тази наредба няма да е линейна). Един живот е по-добър от друг, ако стойността на функцията Succes за този живот е по-голяма от стойността на Succes за другия или ако интервала, в който се намира тази стойност е в дясно (т.е. е по-голям) от интервала, в който се намира другата стойност.

Изкуствения Интелект е устройство, което сме го оставили само да разбере света, но смисъла на живота трябва предварително да сме му го задали. Няма как да искаме от него да се справя добре, при положение, че той не знае кой резултат е добър и кой е лош. Устройството трябва да може във всеки момент само да изчисли функцията Succes и тя трябва да зависи само от оценъчните сигнали, защото входните и изходните сигнали са само информативни и не ни дават директен смисъл.

Най-простото решение е да предположим, че имаме един оценъчен сигнал, който ни връща стойността на функцията Succes. Това решение не е много добро, защото по този начин натоварваме света да помни какво се е случило с устройството до момента, за да може да даде цялостна оценка за целия му живот. По-добре е да имаме един оценъчен сигнал и функцията Succes да бъде средното аритметично от всичките стойности на този сигнал. По този начин света ще оценява устройството за последната му стъпка, а не за целия му живот до момента. Когато на поредната стъпка нищо интересно не се е случило и функцията Succes няма нужда да се променя, то можем да предположим, че сигнала връща предишната стойност на Succes и така средното аритметично ще се запази, но пак обременяваме света да помни какво е станало до момента и затова в този случай ще върнем символа Nothing. Това е един по-прост начин, за да запазим средното аритметично.

Каквато и да е функцията Succes можем да намерим оценъчен сигнал, чието средно аритметично да е точно тази функция. Този оценъчен сигнал не е определен еднозначно, защото на моменти имаме избор дали сигнала да върне символа Nothing или да върне своето средното аритметично получено до момента. Трябва да отбележим още, че предполагаме, че функцията Succes връща нула за празния живот (за живота с дължина нула). Това последното не е проблем, защото ако добавим константа към функцията Succes или ако я умножим с положителна константа няма да променим наредбата, която тя определя.

Следователно, произволен смисъл на живота може да се представи като средното аритметично на оценъчен сигнал, който връща реално число. Въпреки всичко, ние не харесваме това решение, защото бихме искали светът да е устойчив и оценката (функцията Succes) да не може да скача неконтролируемо. Затова ще предполагаме, че оценъчния сигнал е крайна функция и връща стойност от множеството {Nothing, 0, 1, ... , k}. Тоест, ще предполагаме, че има k+2 възможни стойности. Следователно функцията Succes ще бъде в интервала [0, k].

Това решение също не е перфектно, защото може да искаме да имаме различни нива на приоритет. Например, важно е да не закъснееш за училище, но много по-важно е да не загинеш в автомобилна катастрофа. Тук под много по-важно разбираме безкрайно по-важно. Искаме нашата дефиниция да разрешава светът да има N нива на приоритет. За целта ще предполагаме, че имаме N оценъчни сигнала и че функцията Succes връща не число, а вектор. Този вектор се получава, като се сметне средното аритметично покоординатно. (Като за всяка координата сумата се дели на броя пъти когато тази координата е била различна от символа Nothing.) Сравнението на два такива вектора ще става покоординатно. Тоест, гледа се координатата на най-високото ниво на приоритет. Ако за тази координата стойностите на двата вектора са равни, се гледа следващата координата и така нататък.

Можем ли да емулираме свят с две нива на приоритет, когато оценъчният сигнал не е ограничен? Да, нека малкия приоритет да връща 0 или 1, а големия приоритет да връща 0 или 2 умножено по броя пъти до момента, когато стойността на сигнала е била различна от символа Nothing. Допълнително света трябва да запомни момента, когато е дал 2 умножено по нещо-си и от този момент нататък към всяка оценка да прибавя 2. По този начин, ако е получена оценка само по малкия приоритет, то функцията Succes ще бъде в интервала [0, 1], но ако имаме оценка от високия приоритет, то функцията Succes ще бъде по-голяма или равна на 2. Тук при тази емулация се отказахме от ограничението на оценъчния сигнал и обременихме света да помни какво е станало до момента.

Има ли смисъл на живота, който не може да бъде представен с N нива на приоритет? Отговорът е да. Нека вземем смисъл на живота, който има изброимо много нива на приоритет. Това може да се емулира с един неограничен оценъчен сигнал, но не може да се представи с N ограничени оценъчни сигнала за никое N. Тоест, избирайки тази дефиниция на оценката ние се ограничаваме и по този начин не всеки смисъл на живота ще е възможен, но считаме, че световете с N нива на приоритет са достатъчни за практиката и че не е нужно да разглеждаме светове с изброимо много нива на приоритет. Дори, за практиката, в повечето случаи, достатъчно е нивото на приоритет да е едно.

Освен N-те оценъчни сигнала, от които се изчислява функцията Succes ще имаме още един булев оценъчен сигнал, който ще наречем "некоректен ход". Този сигнал ще разгледаме в следващата секция.


Некоректен ход

Какво е "некоректен ход"? Например в шаха, ако се опиташ да играеш с коня като с царица, то това е некоректен ход. Също така в шаха нямаш право да дадеш на противника да ти вземе царя, тоест некоректен е всеки твой ход след който ти си шах. Има много игри в които взимането е задължително. В тези игри некоректен ход е когато можеш да вземеш, но не взимаш.

Ясно е, че в повечето светове има некоректни ходове. При положение, че сме фиксирали множеството на изходящите вектори, то естествено е да предполагаме, че не всички техни стойности са коректен ход. Нормално е в един конкретен момент един конкретен изходящ вектор да е коректен ход, а в друг момент същият вектор вече да е некоректен ход.

За да позволим в света да има некоректни ходове, трябва да си отговорим на два въпроса: "Какво става със света когато устройството играе некоректен ход?" и "Как света връща към устройството информация за това, че последния ход е бил некоректен?"

В статиите [1, 2] въобще не се говори за некоректни ходове. Там се предполага, че светът наказва устройството за всеки негов некоректен ход, като го пляска през ръцете (т.е. като му дава лоша оценка). Например в света, където играете шах, какво ще стане, когато се опитате да играете некоректен ход? Едно възможно решение е да дефинираме света така, че при некоректен ход да губите партията, която играете в момента и да автоматично да започвате нова партия.

В статията [3] е въведен отделен сигнал наречен "некоректен ход". Там се предполага, че опитите на устройството да играе некоректен ход не водят до промяна на света. Резултата е, че светът си остава в същото вътрешно състояние, но връща сигнала некоректен ход към устройството. Грешката в [3] е, че некоректния ход се приема за наказание и се предполага, че устройството ще се научи да играе само коректни ходове и ще избягва некоректните, за да не бъде наказано.

Информацията за това кой ход е коректен и кой не е, е много важна за разбирането на света. Да вземем като пример случая, когато в тъмното намираме пътя си като опипваме с ръце стените. Опипването на стените може да бъде прието за некоректен ход, защото ние се опитваме да прекараме ръката си през пространство през което тя не може да мине, защото там има стена. Въпреки това, ние съзнателно правим този некоректен ход, за да разберем къде е стената.

Може би е добре да променим дефиницията на свят дадена в статиите [1, 2] и към функциите World и View, които описват света да добавим още една функция наречена Correct, която за всяко вътрешно състояние на света да връща множеството на възможните ходове.

Ние искаме да направим задачата на устройството максимално проста и така да дефинираме света, че той да е колкото се може по-лесен за разбиране. Затова, разумно е да предполагаме, че на всяка стъпка, устройството получава като вход не само стойността на функцията View, но също така, то да получава и стойността на функцията Correct.

По този начин изкачат два проблема:

Първият проблем е, че информацията, която ще ни върне функцията Correct може да е прекалено много. Ако възможните изходи са k на брой, то възможните стойности на функцията Correct са 2k. Съответно, ако изходите са изброимо много, то стойности на функцията Correct са континиум много и т.н.

Вторият проблем е в това, че по този начин ние ще усложним света, като наложим изискването на всяка стъпка той да изчислява функцията Correct, да кодира резултата в подходящ формат и да го подава към устройството.

От тези проблеми ще се отървем, ако предположим, че света не казва на устройството експлицитно кои отговори са коректни, а при всеки некоректен ход той връща информация за това, че ходът е некоректен.

Тоест, предполагаме, че имаме един булев сигнал наречен "некоректен ход". Ще разрешим на устройството да прави некоректни ходове и когато се получи единица на този сигнал, това няма да го разглеждаме като наказание за устройството, а просто като полезна информация.

Все пак  ще направим четири предположения:

1. Ще предполагаме, че некоректния ход не променя вътрешното състояние на света. Тоест, играейки некоректен ход, устройството не губи нищо. Може да се каже, че и не печели нищо. Единствената печалба е информацията, която получава. Тоест, играейки един ход, ако този ход се окаже некоректен, устройството получава информацията, че този ход е некоректен, което може да се окаже полезна информация.

2. Ще предполагаме, че ако сме опитали един ход и света ни е казал, че той е некоректен, то няма нужда да го пробваме повторно докато състоянието на света е същото. Разбира се, ако предполагаме, че функцията Correct е фиксирана и се знае кои са коректните ходове още преди да сме опитали, то горното е така, но ние може да искаме да допуснем и нещо по-слабо. Например, представете си свят с вграден в него часовник, който отчита колко време устройството е мислило. В този свят функцията Correct зависи не само от състоянието на света, но и от това колко сме се забавили преди да играем даден ход. Е, ще предполагаме, че дори и функцията Correct да се променя в зависимост от забавянето, то некоректните ходове само се увеличават. Т.е. ще предполагаме, че ако един ход е некоректен, то и да го повторим, пак ще е некоректен.

3. Ще предполагаме, че устройството няма право да играе едни и същи некоректни ходове до безкрайност. Тест, то ще е длъжно да помни какви некоректни ходове е играло и да не ги повтаря поне до получаването на коректен ход. След получаването на коректен ход устройството може да изчисти паметта си и да пробва ходове, които са били некоректни, защото това че един ход е бил некоректен на предишна стъпка, не значи че ще бъде некоректен и на следващата.

Горното предположение го направихме, за да не разрешим на устройството да зацикля. Разбира се, възможните некоректни ходове може да са много и дори безкрайно много, което пак да доведе до забавяне или зацикляне, но припомняйки, че възможните изходи са крайно или псевдо безкрайно (което също е крайно), ще стигнем до извода, че, поне на теория, подобно зацикляне не може да се случи.

4. Ще предполагаме, че функцията Correct никога не връща празното множество. Тоест, ще предполагаме, че винаги има поне един коректен ход. Ако допуснем съществуването на тупици, в които няма изход (т.е. функцията Correct връща празното множество), то тези моменти може да ги асоциираме със смъртта. Може да смятаме смъртта за грешка, която се опитваме да избегнем, но тази грешка винаги е фатална и затова не можем да се учим от нея. Затова по-удобно е да считаме, че в нашия свят няма такива моменти.

Все пак може, когато програмираме устройството наречено AI, да заложим в него принципа да се стреми към състояние, в което възможните ходове са повече. В играта шах ние се стремим да развием фигурите си така, че възможните ходове да са възможно най-много. Загубата на царицата силно намалява броя на възможните ходове, което прави тази загуба нежелана. В живота хората се стремят към свободата. Тоест, искат да имат колкото се може повече възможни ходове. Всеки човек затворен в прекалено малко и тясно пространство се чувства дискомфортно. Също така, човек се чувства дискомфортно когато е заключен или когато е с белезници. По този начин можем да обясним и стремежът на хората към власт и пари, защото това дава допълнителна свобода. Когато имаш пари можеш да си купиш яхта, а можеш и да не си купиш, а когато нямаш, нямаш този избор. Следователно, в човека инстинктивно е заложено да се стреми към състояние, в което възможностите са повече. Логично е този принцип да бъде заложен и в Изкуствения Интелект. Ако нашето устройство избягва случаите, когато възможните ходове са малко, то то би се опитало да избегне и смъртта, защото това е случая когато нямаме никакви възможни ходове.


Как ще използваме некоректните ходове

Добре, нашето устройство разбира света и има представа кой ход е коректен и кой не е. Как ще очакваме от него да постъпи? Когато един ход със сигурност е некоректен, то устройството няма да го пробва, за да не губи излишно процесорно време (тук със сигурност означава с много голяма вероятност, защото нищо не е абсолютно сигурно). Когато един ход почти сигурно е некоректен, то тогава устройството ще го пробва, защото нищо не губи от това, а само получава информация. Ако ходът действително е некоректен, то на следващи път това ще се знае с още по-голяма сигурност, а ако вземе случайно да се окаже коректен, то устройството може да загуби, но може и да спечели като открие нови неподозирани възможности. Когато не се знае дали хода е коректен или не е коректен устройството може да го пробва, а може и да не го пробва. От една страна ще иска да провери дали хода е коректен, но от друга ще се страхува от евентуални неприятни последици. Например, вие не се опитвате да скочите през прозореца, за да проверите дали ще успеете, защото ако случайно успеете, последствията могат да се окажат много лоши.

Въпрос: Дали некоректните ходове са част от живота? Когато опитваме некоректен ход дали се увеличава брояча на стъпките (т.е. параметъра време)? Отговорът е не. Ако разгледаме булевият сигнал "некоректен ход" ще видим, че той е нула за всяко t. Тоест, всички ходове записани в историята са коректни. Ще предполагаме, че некоректните ходове просто не се записват в историята (в живота).

Живота е последователност от входни и изходни вектори. Ако сигнала "некоректен ход" е една от координатите на входящия вектор, то тази координата винаги е нула. Ще считаме, че сигнала "некоректен ход" не е част от историята, защото е безсмислено да включваме сигнал, който е константно нула.

Все пак казахме, че искаме информацията, която се получава от некоректните ходове да може да бъде използвана. Затова, ще променим дефиницията на живота като вмъкнем множеството от векторите на некоректните ходове, които сме опитали, между входящия вектор и коректния изходящ вектор. Тоест, живота ще стане последователност от входен вектор, множество некоректни изходни вектори, коректен изходен вектор и т.н.

В следващата статия ще разгледаме зависимостите без памет. Това са зависимости от типа: "Ако виждам това и правя онова, ще се получи еди-какво-си." Тези зависимости се представят като импликации от вида: a(t-1)=1, b(t)=0, do(t)=1 => bad_move(t+1)=1. Тази импликация трябва да бъде прочетена така: Ако сигнала b на тази стъпка е нула и ако сигнала a на предишната стъпка е бил едно и ако изберем сигнала do на тази стъпка да бъде едно, то това е некоректен ход. Сигнала do го избираме какъв да бъде, защото това е изходящ сигнал, а сигналите a и b са каквито са, защото това са входящи сигнали, които не ги избираме, а ни ги дава светът.

Импликацията води към bad_move=1, но това няма да се запише в историята, защото там се записват само коректните ходове.

Горната импликация ни казва, че при някакви обстоятелства определен ход ще е некоректен. Тоест, тук виждаме как на базата на информацията събрана от некоректните ходове можем да се научим да познаваме такива ходове. В следващата статия ще видим как от това, че даден ход е некоректен може да се извлече и повече информация за това какво е състоянието на света и какво ще се случи на следващата стъпка.


Пример

Ще използваме същия пример, който разгледахме в [3]. Това е света на играта Морски Шах, където устройството не вижда цялото табло, а само едно квадратче от него (Фигура 1).


Окото на устройството се намира върху квадратчето, което се вижда. Възможните ходове са шест. Окото може да се предвижва в четирите възможни посоки, можем да сложим кръстче в квадратчето, върху което окото се намира в момента и шестата команда е да поискаме нова игра (т.е. да се изчистят всички квадратчета и да започнем отначало).

В [3] светът използваше само булеви вектори, а тук ще се откажем от това ограничение, което ще направи дефиницията на света по-проста и съответно светът ще стане по-разбираем.

Вместо два булеви сигнала, които да кодират какво вижда окото, ще имаме един входящ сигнал с три възможни стойности {0, 1, 2}, които ще съответстват на празно, кръстче и кръгче. Вместо двата оценъчни сигнала "победа" и "загуба" ще имаме един с четири възможни стойности: {Nothing, 0, 1, 2}, които ще съответстват на "няма оценка", "загуба", "реми" и "победа". Вместо трите булеви изходни сигнала, които кодираха шестте възможни изхода, сега ще имаме четири изходни сигнала. Първите два ще дават посоката на движение на окото. Ще ги наречем vertical и horizontal. Техните възможни стойности ще бъдат в множеството {0, 1, 2}, което ще отговаря на "не мърда", "нагоре" и "надолу" или съответно на "не мърда", "наляво" и "надясно". Другите два изходящи сигнала ще са булеви и ще ги наречем put_cross и new_game. Какво правят последните два сигнала е ясно.

В [3] имахме шест възможни действия и на всеки ход можехме да извършим само едно от тях. Сега можем да извършим четири действия едновременно. Ако искаме, можем да не извършим и нито едно действие (като поставим нула на четирите координати на изходящия вектор). Бихме могли да предполагаме, че имаме право да извършим само едно действие и всеки друг изход се приема от света за некоректен ход, но по-интересно е да предполагаме, че можем да извършим до четири действия на един ход. Например, можем да поставим кръстче, да мръднем на горе и наляво и да поискаме нова игра. Разбира се, и четирите действия трябва да са коректни, защото в противен случай ще получим "некоректен ход" и нищо няма да стане.

Когато разрешаваме няколко действия в един ход трябва да уточним последователността им. Все едно е дали първо ще мръднем на горе и после на ляво или обратното. Все едно е дали първо ще се движим и после ще поскаме нова игра или обратното. Единственото действие, което не може да комутира с останалите е поставянето на кръстче, затова винаги ще предполагаме, че първо сме сложили кръстчето и после сме извършили другите действия.

По този начин представяме играта Морски Шах от [3] като свят с едно ниво на приоритет, с един входящ сигнал, четири изходящи и два оценъчни. (Вторият оценъчен сигнал е "некоректен ход", който си остава същия, както беше дефиниран в [3].)

Защо тук описаното представяне на света е по-добро от направеното в [3]? Защото имаме по-малко кодиране, което прави света по-прост и по-разбираем. Да вземем като пример правилото: "Ако клетката, която виждаш не е празна и ако се опиташ да сложиш кръстче, то това е некоректен ход." Сега това правило може да се запише като импликация съдържаща само три атома:
cell(t)=/=0, put_cross(t)=1 => bad_move(t+1)=1

В [3] тази импликация щеше да се състои от шест атома, защото сигнала cell там се кодира с два булеви сигнала и изхода там се кодира с три сигнала. Когато се опитваме да намерим зависимост без памет, каквато е горната, на нас ни се налага да намалим броя на импликациите като вземем само по-късите от тях. По тази причина, колкото по-къса е една импликация, толкова по-голям е шанса нашето устройство да я открие.


Литература

[1] Dobrev D. D. AI - What is this. In: PC Magazine - Bulgaria, November'2000, pp.12-13 (www.dobrev.com/AI/definition.html).
[2] Dobrev D. D. A Definition of Artificial Intelligence. In: Mathematica Balkanica, New Series, Vol. 19, 2005, Fasc. 1-2, pp.67-74.
[3] Dobrev D. D. Testing AI in one Artificial World. Proceedings of XI International Conference "Knowledge-Dialogue-Solution", June 2005, Varna, Bulgaria, Vol.2, pp.461-464 (www.dobrev.com/AI/).
[4] Dobrev D. D. Formal Definition of Artificial Intelligence. In: International Journal "Information Theories & Applications", vol.12, Number 3, 2005, pp.277-285. (www.dobrev.com/AI/).
[5] Dobrev D. D. Comparison between the two definitions of AI. In: arXiv:1302.0216, January, 2013 (www.dobrev.com/AI/).