Я пытаюсь описать одну концепцию ИИ, сам ее пока понимаю плохо. Думаю суть этой концепции в том, чтобы создавать различные переменные в системе нейросетей, которые отвечают за различные действия, процессы. В этой статье я расскажу про идею, суть которой в том, что все знания программы, такие как команды или слова, рассматриваются как переменные, и немного про эту концепцию ИИ (в конце статьи). Чтобы лучше понять идею описанную в этой статье, нужно прочитать предыдущую статью про систему команд.
Все знания программы представляются в виде переменных. Все переменные программы работают асинхронно — обработка каждой переменной происходит независимо друг от друга. Входные данные (стимулы) активируют какие-то переменные в программе. На основе активированных переменных от входных данных или каких-то других внутренних переменных происходит активация переменных каких-то команд. Переменные могут активироваться не только от входных данных, но и от внутренних процессов. Активные процессы обозначаются переменными активных процессов, выполненные процессы обозначаются переменными выполненных процессов, процесс может быть неактивен, активен, либо завершен.
Триггеры — это переменные, которые должны быть активными, на основе их активности могут активироваться другие переменные или процессы.
Ссылка на папку с программой (в репозитории, название «variabled-command-system»), описанной в статье. Я сделал пример того, как может выглядеть простая реализация системы команд на основе переменных, но я не сделал рабочую программу, это лишь пример, чтобы можно было понять хотя бы идею. В реализации есть много нюансов, которые нужно продумывать и которые я пока не придумал как обойти, поэтому реализация не рабочая.
В этой программе переменные представлены в виде строк. В качестве переменных в более общем понимании можно рассматривать один нейрон, группу нейронов (массив нейронов), нейронную структуру, вектор-представление (эмбеддинг, образ), нейропуть (последовательная активация цепочки нейронов) или что-то еще.
Переменные хранятся в словаре variables, ключ — название переменной, значение ключа — значение переменной.
variables = {
"program run": "true",
"true": "false",
"false": "false"
}
Каждую переменную можно изменить (включить или выключить). Для их активации нужны определенные стимулы. После того, как программа получит стимул, соответствующая переменная будет активирована.
variables_conditions = {
"true": ["true", "1"],
"false": ["false", "0"],
"variable": ["variable", "var"]
}
Для активации переменной «true» нужно, чтобы в строке присутствовало слово «true» или «1», это условия (conditions), при которых переменная активируется.
Для активации команд теперь тоже нужны определенные условия (стимулы). Такие команды я назвал абстрактными, так как их можно вызывать разными ключевыми словами. Только в этой программе не учитывается последовательность. Абстрактная команда — аналог стимулов, на которые активируются слова, только вместо слов будут последовательности слов и переменные, которые отвечают за выполнение команд (триггерные переменные):
abstract_commands_conditions = {
"make input": [["make", "input"]],
"change var": [["change", "variable"]],
"exit program": [["run", "to", "false"], ["set", "run", "false"],
["exit", "program"]]
}
Чтобы выключить программу через команду «exit program», нужно ввести одну из представленных в словаре abstract_commands_conditions комбинаций слов. Если она введена, то активируется переменная команды. Когда переменная команды активна, сама команда выполняется, будет выполняться команда под названием «exit program» в словаре base_commands:
base_commands = {
"make enter": ["output", "input", "end of make enter"],
"make input": ["input msg", "make enter", "end of make input"],
"exit program": ["program run", "false", "sys change var",
"end of exit program"]
}
Выполнение команды должно происходить асинхронно, но я этого не сделал, так как не разбираюсь в этом (и это усложнит пример кода). Выполнение не должно происходить так, как это происходит в предыдущей статье. Вместо этого каждая подкоманда в команде будет выполняться тогда, когда будут выполнены определенные условия, описанные в словаре commands_conditions:
commands_conditions = {
"make enter": [["make input", "input msg cond"]],
"output": [["make enter"]],
"input": [["make enter", "output cond"]],
"input msg": [["make input"]]
}
Слово «cond» означает «condition», условие, что предыдущая подкоманда была выполнена. Чтобы команда «input msg» начала выполняться, должна активироваться переменная «make input», потом, должна выполняться команда «make enter», она начнет выполняться тогда, когда будут активны переменные «make input» и «input msg cond», то есть, будет активна команда «make input» и будет выполнена команда «input msg».
Слева входные переменные, а справа выходное значение переменной.
Выполнение команд похоже на генерацию последовательности токенов нейросетью в глубоком обучении.
На вход программы подается строка, которая разделяется по словам и каждое слово активирует в программе соответствующую переменную. Асинхронно это может выглядеть как ввод каждого слова по одному или ввод каждой буквы, при вводе определенной последовательности букв будут активироваться определенные переменные слов, и, со временем, эти переменные будут выключаться, затухать. Активация переменных:
def activate_variables():
command = buffer["input stack"][-1] # извлечь введенную строку
for word in command.split():
for variable_name in variables_conditions.keys():
# если есть такое слово в списке, то включить переменную слова
if word in variables_conditions[variable_name]:
variables[variable_name] = "true"
activated_variables.append(variable_name)
def activate_abstract_commands():
# просмотреть активированные переменные слов
# для активации переменных команд
for command_name, conditions in abstract_commands_conditions.items():
for condition_list in conditions:
# активировалась ли команда?
if does_conditions_true(condition_list):
variables[command_name] = "true"
Метод activate имитирует активацию нейронов, увеличение потенциала действия. Активированные переменные слов нужно записать в список activated_variables, чтобы потом их отключить. После того, как все переменные слов будут введены активируется переменная команды и она начинает выполняться. При выполнении команд происходит как бы реакция программы на стимулы, на введенную строку. Начинают последовательно активироваться переменные подкоманд и подкоманды выполняются.
Для выполнения последовательности действий (команды) каждая подкоманда активируется при выполнении определенных условий, если переменные для этой подкоманды активны, то она выполняется. Одна такая переменная — это активация самой команды, другая — индикатор того, что предыдущая подкоманда была выполнена. Если оба условия выполнены, то можно выполнять следующую подкоманду.
Таким образом все переменные и команды будут обрабатываться асинхронно — независимо друг от друга. Но выполняться что-то будет только при активации нужных для этого переменных (условий). Обработка команд:
def process_commands():
run = True
# если есть активные переменные команд, то обрабатывать команды
while run:
run = False
for command in all_commands:
if variables[command] == "true":
run = True
perform_command(command)
process_commands_conditions()
Прямоугольник на картинке - подкоманда или команда, круги - переменные-индикаторы окончания выполнения подкоманды или переменные-условия, которые активируют выполнение подкоманды.
После ввода «make input» активируются входные переменные, потом переменная команды. Команда начинает выполняться, выполняется подкоманда «imput msg» и активируется переменная «imput msg cond», что эта подкоманда выполнилась. Когда выполняются условия «make input» и «input msg cond», начинает выполняться подкоманда «make enter». И так далее.
# выполнение базовых исходов
def perform_command(command: str):
# если это название команды, то пропустить
if command in base_commands.keys():
return
# если это название функции, то выполнить ее
elif command in functional_commands:
functional_commands[command]()
variables[command + " cond"] = "true"
variables[command] = "false"
return
# если это название соответствия, то вывести значение соответсвия
# соответствие - это вопрос-ответ
elif command in match_commands:
buffer["output stack"].append(match_commands[command])
variables[command + " cond"] = "true"
variables[command] = "false"
return
# если это символ конца команды, то сделать переменную команды неактивной
elif command.startswith("end of"):
parrent_command_name = command[7:]
variables[parrent_command_name] = "false"
variables[parrent_command_name + " cond"] = "true"
return
# активация переменных команд, у которых условия были выполнены:
def process_commands_conditions():
for command in commands_conditions:
for condition_list in commands_conditions[command]:
# если условия выполнены, то переменная команды активируется
if does_conditions_true(condition_list):
variables[command] = "true"
Чтобы выполнить команду "exit program" можно сделать дополнительный системный стек в buffer, который называется "system stack". В это стек будет записываться название переменной "program run" и "false" в функции perform_command:
if command in variables:
buffer["system stack"].append(command)
Еще нужно добавить новую функцию:
def sys_change_var():
variables[buffer["system stack"][-2]] = buffer["system stack"][-1]
Затем для этой функции создать поле в словаре functional_commands и добавить название этого поля в команду "exit program" в словаре base_commands. Таким образом можно будет изменить значение переменной.
Все команды обрабатываются в цикле, пока не останется активных переменных команд, пока все команды не выполнятся. Обрабатываются все команды сразу, но выполняются только те, у которых активны условия для выполнения. Потом нужно отключить активированные переменные. Метод deactivate имитирует то, что нейроны приходят в нормальное состояние, испускают потенциал.
def deactivate_variables():
while len(activated_variables) > 0:
variable_name = activated_variables.pop()
variables[variable_name] = "false"
def deactivate_commands_conditions():
for command in all_commands:
variables[command + " cond"] = "false"
Это похоже на то, как должны работать импульсные нейросети. Там можно создавать новые нейроны (нейроны-переменные) или группы нейронов, которые отвечают за определенные переменные. В импульсных нейросетях (в биологических) нейроны работают асинхронно, каждый нейрон обрабатывает сигналы независимо от других.
Я описал общую идею и попытался сделать простой пример реализации системы команд на основе переменных. В этой концепции можно создавать любые переменные, слова, команды. Для распознавания слов можно сделать классификацию слов нейросетью или для каждого слова небольшую нейросеть, которая будет распознавать только одно слово (бинарная классификация). Для выходных нейронов и команд можно сделать что-то похожее.
Основные идеи, описанные выше:
Все знания хранятся как переменные. Переменные могут выглядеть по-разному: строка, нейрон, группа нейронов, вектор-представление.
Все переменные должны обрабатываться асинхронно.
Все переменные работают по одинаковому принципу: сначала происходит активация, распознавание стимулов, выполнение условий активации, потом происходит выполнение каких-то процессов, команд.
Команды выполняются на основе активации переменных команд и подкоманд. У каждой подкоманды или команды есть свои условия для активации.
Через определенное время или определенным образом переменные входных данных выключаются. После выполнения команды ее переменная выключается. Переменные условий выполненных команд тоже выключаются определенным образом или через какое-то время.
На основе идеи о системе команд, в программе можно создавать различные переменные и команды во время работы программы — я думаю, эта идея лежит в основе самостоятельного создания команд программой, таких команд, которые не были заданы изначально (вручную). И, развивая эту идею дальше, возможно, получится описать различные механизмы, на основе которых переменные в программе будут появляться автоматически, а затем и на основе целенаправленного поведения программы.
У программы появляется возможность создавать новые переменные, программа может делать это в автоматическом режиме, нужно только задать специальные установки, правила, когда эти переменные должны создаваться.
Теперь нужно представить, что программа работает сама, во время работы у системы могут появляться те же самые проблемы (задачи), которые появляются, когда происходит ручной ввод данных. Например, она не распознала переменную, что нужно сделать? Программа должна добавить новое слово или создать новую переменную. И она должна определить, что именно ей нужно добавить или создать. Когда команду вводит пользователь, то он сам указывает какие-то параметры, названия, модификаторы и так далее. Когда система работает сама, то она должна это делать самостоятельно, на основе различных механизмов обработки данных и их манипуляции.
Переменные команд похожи на параметры функциональных систем (ФС). Про ФС можно почитать в учебнике по нейрофизиологии "Нейрофизиология В. И. Циркин, С. И. Трухина, А. Н. Трухин Физиология ЦНС часть 1, 2-е издание 2020" в разделе «Тема 1». Немного про них я написал в своей «теории» (в корневой папке репозитория в «tdi.pdf»). Во время работы программы постоянно появляются новые функциональные системы. Задача ФС состоит в том, чтобы регулировать параметры, то есть выполнять процессы, которые приводят параметр в определенное состояние.
Скорее всего, для реализации этой концепции, нужно будет использовать импульсные нейросети (ну, или как-то делать это в глубоком обучении). Для того, чтобы понять эту концепцию ИИ, просто понять программу, описанную в статье, возможно, будет недостаточно. Нужно еще иметь представления о том, как работают нейросети в глубоком обучении, а не только импульсные. Например, то, как происходит генерация данных, как можно обрабатывать последовательности, что такое автоматический кодировщик, обучение представлениям, GAN и другие понятия, которые нужно понимать, чтобы на их основе можно было мыслить о том, как система нейросетей может обучаться самостоятельно.
Нужно создать различные механизмы, которые будут автоматически создавать нужные переменные, но, в самом простом варианте, переменные можно создавать вручную - ручное обучение нейросетей, ручная разметка, обучение нейросетей каждому действию и так далее.
Я описываю эту «теорию» для того, чтобы можно было представить все в виде одной общей структуры, как система может выглядеть и обучаться самостоятельно. Система должна прибавлять положительные действия и убавлять отрицательные, учиться генерировать действия (команды), сохранять информацию. На основе того, что она может отличать положительные или отрицательные действия, она может генерировать новые до тех пор, пока не будет сгенерированно положительное для данной ситуации (для данной задачи, команды). Потом нужно сделать возможность анализа действий, почему то или иное действие является положительным или отрицательным, на основе совершаемых действий тоже нужно производить анализ.
На основе идеи о оценке действий, анализе и системы команд на основе переменных, можно увидеть, что система с такими свойствами сможет хранить знания, создавать новые знания и самостоятельно обучаться.
В глубоком обучении обучение происходит сразу на всем наборе данных и, тем более, суть обучения сводится к оптимизации функции — это следует из определения того, что такое обучение в машинном обучении. В этой концепции я рассматриваю обучение как способность системы изучать информацию самостоятельно, а не как задачу оптимизации функции (функции ошибки). Деятельность системы основывается на неких параметрах, которые могут быть заданы на базовом уровне или постоянно появляться с течением времени. И задача сводится не к оптимизации функции, а к созданию нейронных структур, которые смогут решать эти параметры.
Система должна обучаться самостоятельно, изучать примеры по одному, а не сразу на всем наборе данных. Для решения каждого нового примера, в нем должны содержаться данные, которые система уже изучила. Во время обучения происходит формирование новых нейронных структур, нейросеть постоянно будет меняться, нейроны рассматриваются как отдельные вычислительные единицы и они обладают свойством выводить спайки.