#javascript #нейронные_сети
Много начитался теории, вроде как-то понимаю, но без практики в голове одна абстрактная
каша.
Нашел на гитхабе пример сети, и как обычно стал комментровать каждую строчку кода
чтоб разобраться в нем.
function NeuralNet (settings, network) {
// Выставляем настройки сети
this.settings = this.normalizeSettings(settings);
// Создаем сеть
this.network = JSON.parse(JSON.stringify(network || this.randomNetwork()));
}
// Настроки по умолчанию
NeuralNet.prototype.defaultSettings = {
hiddenLayers: 1, // Кол-во скрытых слоев сети
nodesPerLayer: 4, // Кол-во узлов в скрытой сети
inputNodes: 2, // Кол-во входов сети
outputNodes: 1, // Кол-во выходов сети
mutationRate: 0.04 // Смещение
};
// Заполняем массив стандартными значениями, если они не указаны
NeuralNet.prototype.normalizeSettings = function normalizeSettings (target) {
target = target || {}; // Настройки
target = JSON.parse(JSON.stringify(target)); // Нафиг не нужно
// Заполняем стандартными значениями каждый пустой элемент
for (var k in this.defaultSettings) {
target[k] = target[k] || this.defaultSettings[k];
}
return target;
};
// Мутировать сеть
NeuralNet.prototype.mutateNetwork = function mutateNetwork () {
var copyNetwork = JSON.parse(JSON.stringify(this.network)); // Упростить
// --- Проходимся по каждому слою сети
for (var layer = 0, lenLayer = copyNetwork.length; layer < lenLayer; layer++) {
// --- Выбираем каждый отдельный нейрон
for (var node = 0, lenNode = copyNetwork[layer].length; node < lenNode; node++) {
// Рандомно меняем смещение
copyNetwork[layer][node].bias += (Math.random() * 2 - 1) * this.settings.mutationRate;
// Выбирыем каждый вес
for (var weight = 0, lenWeight = copyNetwork[layer][node].weights.length;
weight < lenWeight; weight++) {
// Рандомно меняем вес
copyNetwork[layer][node].weights[weight] += (Math.random() * 2 -
1) * this.settings.mutationRate;
}
}
}
return copyNetwork;
};
// Создадим сеть с рандомными значениями
NeuralNet.prototype.randomNetwork = function randomNetwork () {
var nodesLayerCount, // Кол-во нейронов в слое
network = [], // Создаваемая сеть
previousNodeCount = this.settings.inputNodes; // Число нейронов в предидущем
цикле
// --- Проходимся по каждому слою сети
for (var layer = 0; layer < this.settings.hiddenLayers + 1; layer++) {
// Пока цикл не дашел до последенго такта это - скрытый слой
if (layer != this.settings.hiddenLayers){
nodesLayerCount = this.settings.nodesPerLayer; // скрытый слой
}else{
nodesLayerCount = this.settings.outputNodes; // Выходной слой
}
// --- Заполняем каждый нейрон в слое
network[layer] = [];
for (var node = 0; node < nodesLayerCount; node++) {
// Структура нейрона
var nodeObj = {
bias: Math.random() * 2 - 1, // Смещение
weights: [] // Массив весов связи
};
// Рандомно заполняем связи нейронов в стуктуре
for (var weight = 0; weight < previousNodeCount; weight++) {
nodeObj.weights[weight] = Math.random() * 2 - 1;
}
network[layer][node] = nodeObj; // Присваиваем созданую структуру
}
// Сохраняем текущее кол-во нейронов в слое (в слейдущем такте оно станет
предыдущим)
previousNodeCount = nodesLayerCount;
}
return network;
};
// Запускаем сеть
NeuralNet.prototype.runNetwork = function runNetwork (inputNodes) {
// --- Проходимся по каждому слою сети
for (var layer = 0, layerCount = this.network.length; layer < layerCount; layer++) {
// --- Проходимся по каждому нейрону в слое
var outputs = [];
for (var node = 0, nodeCount = this.network[layer].length; node < nodeCount;
node++) {
// Смещение нейрона
var sum = this.network[layer][node].bias;
// Проходимя по каждому весу
for (var weight = 0, weightCount = this.network[layer][node].weights.length;
weight < weightCount; weight++) {
// Вычисляем сумму
sum += this.network[layer][node].weights[weight] * inputNodes[weight];
}
// Пороговая фугкция
outputs[node] = 1 / (1 + Math.exp(-sum));
}
// Присваиваем полученые слой, теперь он - входной (предыдущий)
inputNodes = outputs;
}
// В конце-концов доходим до выходного слоя
return inputNodes;
};
// Проверяем
var neuralNet = new NeuralNet();
console.log(neuralNet.network);
Как её правильно обучить и запустить? На примере обычного XOR
Ответы
Ответ 1
Какой-то гибрид с генетическим алгоритмом. Такое ощущение, что мутатор просто создаёт новую рандомную сеть с той же структурой. Как вариант - вызываем мутацию и смотрим, стало лучше или нет. Когда случайно получили нужное качество, останавливаемся. Но лучше взять нормальный алгоритм обучения, типа обратного распространения ошибки, и реализовать его. Ничего похожего в имеющемся коде не вижу. PS: Детально не изучал. UPDATE: В мутации есть лимит на отклонение от оригинальной сети. Соответственно, мутируем сеть, запускаем снова на тестовом наборе и выбираем из имеющейся и новой лучшую. Её снова мутируем. Даже если выберется та же сеть, за счёт случайности мутация должна получиться новая. И так до достижения желаемой точности. У меня очень большие сомнения по поводу работоспособности этого подхода, но, наверное, может как-то работать, особенно на небольших сетях. А может, я опять чего-то в коде не заметил.
Комментариев нет:
Отправить комментарий