#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: В мутации есть лимит на отклонение от оригинальной сети. Соответственно, мутируем сеть, запускаем снова на тестовом наборе и выбираем из имеющейся и новой лучшую. Её снова мутируем. Даже если выберется та же сеть, за счёт случайности мутация должна получиться новая. И так до достижения желаемой точности. У меня очень большие сомнения по поводу работоспособности этого подхода, но, наверное, может как-то работать, особенно на небольших сетях. А может, я опять чего-то в коде не заметил.
Комментариев нет:
Отправить комментарий