Страницы

Поиск по вопросам

понедельник, 16 декабря 2019 г.

Как можно обучить собственную нейронную сеть?

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

Комментариев нет:

Отправить комментарий