Как можно реализовать нейронную сеть с прямой связью с настраиваемым числом и динамическим поведением входов и выходов?
Я пытаюсь добавить нейронные сети к объектам в игре, над которой я работаю. Однако для каждого типа объекта, который я добавляю, мне приходится создавать новую нейронную сеть с разным количеством входов и выходов, а затем жестко кодировать, как устанавливаются входы и как выходные данные используются для управления поведением.
Я хотел бы найти способ динамически устанавливать все это, чтобы мне не приходилось переписывать новую нейронную сеть для каждого типа сущности.
Поскольку я использую С++, в настоящее время у меня есть вектор двойников в качестве контейнеров ввода и вывода. В настоящее время мой алгоритм 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]);
}
}
}
Мне любопытны другие способы реализации этой идеи, и есть ли какие-либо ресурсы, которые решают эту проблему. Любая помощь будет принята с благодарностью.