Как динамически задать количество и поведение входов/выходов в нейронной сети?

Как можно реализовать нейронную сеть с прямой связью с настраиваемым числом и динамическим поведением входов и выходов?

Я пытаюсь добавить нейронные сети к объектам в игре, над которой я работаю. Однако для каждого типа объекта, который я добавляю, мне приходится создавать новую нейронную сеть с разным количеством входов и выходов, а затем жестко кодировать, как устанавливаются входы и как выходные данные используются для управления поведением.

Я хотел бы найти способ динамически устанавливать все это, чтобы мне не приходилось переписывать новую нейронную сеть для каждого типа сущности.

Поскольку я использую С++, в настоящее время у меня есть вектор двойников в качестве контейнеров ввода и вывода. В настоящее время мой алгоритм NN перебирает каждый элемент в слое (включая входной «слой») и передает информацию на следующий слой, я считаю, что сейчас это будет работать нормально (хотя я открыт для предложений). Однако моя реальная проблема заключается в том, как иметь различное поведение для каждого типа сущности, не ограничивая количество входов/выходов или типов чувств/поведений, которыми может обладать сущность.

В качестве примера, скажем, я хочу добавить в игру существо, которое может видеть других существ, чувствовать запах еды, кусаться в качестве атаки и двигаться по земле. Каждый глаз будет входом, наряду с обонянием; кусание будет выходом, наряду с движением по осям x и y. Мне нужен способ вычисления входных значений и извлечения значения из выходных значений в нейронной сети.

Теперь, если бы я также хотел добавить существо, которое может чувствовать запах других существ, определять их направление относительно себя, стрелять шипами и летать по воздуху, мне потребовалось бы другое количество входных и выходных вычислений (ввод: запах, местоположение; вывод: стрелять, движение x, y, z).

Я хотел бы, чтобы каждый тип объекта имел свою собственную структуру нейронной сети, но при этом имел общий стандартный интерфейс для работы системы ИИ при обработке и повторении каждой отдельной сети. В частности, при обработке игровых ощущений для преобразования ввода и вывода для преобразования игрового поведения.

Мне нужно эмерджентное поведение существ, которых я добавляю, поэтому я не знаю, каким будет «правильный» вывод. По этой причине я использую простой генетический алгоритм для управления изменением веса.

Поскольку мне не удалось найти много информации по моей проблеме, единственная идея, которая пришла мне в голову, — реализовать чувства и поведение каждой сущности в виде вектора указателей на функции, где каждая функция соответствует определенному входу или выход. Хотя это позволяет мне настраивать работу каждой сущности и сохранять единую систему для ИИ, я не уверен, что это самый эффективный способ добиться того, чего я хочу.

Функция процесса выполняет всю работу в классе LearningSystem:

void LearningSystem::process(int const last_frame_time) {
    std::set<unsigned int> const& learning_list = eManager->getAllEntitiesPossessingComponent(ComponentType::intelligence);

    vector<double> outputs, inputs;
    for (auto entity : learning_list) {
        Intelligence& intel = eManager->getComponent<Intelligence>(entity, ComponentType::intelligence);
        Sensors& sensor = eManager->getComponent<Sensors>(entity, ComponentType::sensors);
        Behavior& behavior = eManager->getComponent<Behavior>(entity, ComponentType::behavior);

        // calculate each input value
        for (unsigned int i = 0; i < sensor.sensor_list.size(); ++i) {
            sensor.triggers[i](sensor.sensor_list[i]);
        }

        // retrieve the inputs from the sensors...
        inputs = sensor.sensor_list;
        // ...and add the bias
        inputs.push_back(bias);

        // for each layer
        for (auto i : intel.vecLayers) {
            // clear the internal outputs
            outputs.clear();

            // for each neuron
            for (auto j : i.vecNeurons) {
                // reset the neuron value
                double neuronValue = 0.0;

                // for each weight/input pair, sum the weights * inputs
                for (auto k = j.vecWeights.begin(), in = inputs.begin(); k != j.vecWeights.end(); ++k, ++in) {
                    neuronValue += (*k) * (*in);
                }

                // store the internal outputs for use by the next layer
                outputs.push_back(sigmoid(neuronValue));
            }

            // assign the inputs for the next layer...
            inputs = outputs;
            // ...and add the bias
            inputs.push_back(bias);
        }

        behavior.values = outputs;

        // calculate actions based on output values
        for (unsigned int i = 0; i < behavior.values.size(); ++i) {
            behavior.actions[i](behavior.values[i]);
        }
    }
}

Мне любопытны другие способы реализации этой идеи, и есть ли какие-либо ресурсы, которые решают эту проблему. Любая помощь будет принята с благодарностью.


person SethSR    schedule 07.06.2012    source источник
comment
Нейронная сеть — очень широкое понятие. Какую архитектуру NN вы реализуете?   -  person Fred Foo    schedule 07.06.2012
comment
Очень неясно, что вы пытаетесь сделать imo. Вы просто подключаете все компоненты сущности к ИНС? Каков ожидаемый результат?   -  person Torious    schedule 07.06.2012
comment
Можете ли вы как-то показать нам, какие данные у вас есть? И можете ли вы сказать мне, какую структуру нейронной сети вы используете? Как видите, вычисление обратной матрицы Гессе в нейронной сети делает адаптивное обучение немного невозможным, но есть умные способы.   -  person Hotloo Xiranood    schedule 07.06.2012
comment
Похоже, вы уже реализовали эскизный проект. Я предлагаю вам показать часть текущего кода, чтобы мы могли лучше понять проблему.   -  person Gnosophilon    schedule 08.06.2012


Ответы (1)


Я писал что-то подобное давно, поэтому, к сожалению, у меня нет исходников, но я помню, что определял структуру сети как массив, который передавался в функцию, которая будет создавать сеть. Каждый элемент массива был целым числом, которое описывало количество нейронов в сетевом слое, поэтому [2,3,2], например, создало бы нейронную сеть с 2 входными нейронами, 3 в скрытом слое и 2 выходными нейронами. Синапсы создавались автоматически путем связывания каждого нейрона в соседних слоях. Это было очень просто, поэтому установка/получение значений из входных/выходных слоев выполнялась с помощью вызова функции, подобного этому

double getValue(int layer, int neuron);

Извините, это немного расплывчато, но это все, что я могу вспомнить.

person NickD    schedule 08.06.2012
comment
Я не думаю, что это именно то, что я искал, но это хорошая идея, по крайней мере, для упрощения моего дизайна. И я, вероятно, попробую вашу функцию «getValue» с моей конструкцией указателя на функцию, чтобы увидеть, какая из них работает лучше. В любом случае, спасибо за ответ! - person SethSR; 10.06.2012