Я не могу понять, что не так с моим классом нейронной сети (Lua) - PullRequest
0 голосов
/ 04 января 2019
local matrix = require("matrixx")
local Class = require("class")
NeuralNetwork = Class{}

function NeuralNetwork:init(input_nodes, hidden_nodes, output_nodes)
    self.input_nodes = input_nodes
    self.hidden_nodes = hidden_nodes
    self.output_nodes = output_nodes

    self.weights_ih = matrix(self.hidden_nodes, self.input_nodes, math.random())
    self.weights_ho = matrix(self.output_nodes, self.hidden_nodes, math.random())

    self.bias_h = matrix(self.hidden_nodes, 1, math.random())
    self.bias_o = matrix(self.output_nodes, 1, math.random())


    self.learning_rate = 0.1
end

function NeuralNetwork:feedforward(input_array)
    --Generating the Hidden Outputs
    local inputs = matrix(input_array)
    for i=1, #input_array do
        inputs[i][1] = input_array[i]
    end

    local hidden = self.weights_ih * inputs
    hidden = hidden + self.bias_h

    --Activation Function
    hidden = matrix.map(hidden, tanh)

    --Generating the output's output
    local output = self.weights_ho * hidden
    output = output + self.bias_o
    output = matrix.map(output, tanh)

    return output
end

function NeuralNetwork:train(input_array, target_array)

    --Generating the Hidden Outputs
    local inputs = matrix(input_array)
    for i=1, #input_array do
        inputs[i][1] = input_array[i]
    end

    local hidden = self.weights_ih * inputs
    hidden = hidden + self.bias_h

    --Activation Function
    hidden = matrix.map(hidden, tanh)

    --Generating the output's output
    local outputs = self.weights_ho * hidden
    outputs = outputs + self.bias_o
    outputs = matrix.map(outputs, tanh)

    --Convert Targets Array to Matrix object
    local targets = matrix(#target_array, 1)
    for i=1, #target_array do
        targets[i][1] = target_array[i]
    end

    --Calculate the error
    local output_errors = targets - outputs

    --Calculate gradient
    local gradients = matrix.map(outputs, tanhd)
    gradients = gradients * output_errors
    gradients = gradients * self.learning_rate

    -- Calculate deltas
    local hidden_T = matrix.transpose(hidden)

    local weight_ho_deltas = gradients * hidden_T

    -- Adjust the weights by deltas
    self.weights_ho = self.weights_ho + weight_ho_deltas
    -- Adjust the bias by its deltas (which is just the gradients)
    self.bias_o = self.bias_o + gradients

    -- Calculate the hidden layer errors
    local who_t = matrix.transpose(self.weights_ho)
    local hidden_errors = who_t * output_errors

    -- Calculate hidden gradient
    local hidden_gradient = matrix.map(hidden, tanhd)
    hidden_gradient = hidden_gradient * hidden_errors * self.learning_rate

    -- Calcuate input->hidden deltas
    local inputs_T = matrix.transpose(inputs)
    local weight_ih_deltas = hidden_gradient * inputs_T

    self.weights_ih = self.weights_ih + weight_ih_deltas
    -- Adjust the bias by its deltas (which is just the gradients)
    self.bias_h = self.bias_h + hidden_gradient

    self.weights_ih:print()
    print()
    self.weights_ho:print()
    print()
end

function sigmoid(x)
    return 1 / (1 + math.exp(-x))
end

function dsigmoid(x)
    return sigmoid(x) * (1 - sigmoid(x))
end

function tanh(x)
    return (math.exp(x) - math.exp(-x)) / (math.exp(x) + math.exp(-x))
end

function tanhd(x)
    return 1 / math.cosh(x)^2
end

--MAIN
local nn = NeuralNetwork(2, 2, 1)
local training_data = {
    {
        inputs = {0, 1},
        target = {1}
    },
    {
        inputs = {1, 1},
        target = {0}
    },
    {
        inputs = {1, 0},
        target = {1}
    },
    {
        inputs = {0, 0},
        target = {0}
    }
}

for i = 1, 30 do
    local data = training_data[math.floor(math.random(#training_data))]
    nn:train(data.inputs, data.target)
end
nn:feedforward({0, 1}):print()
nn:feedforward({1, 1}):print()
nn:feedforward({0, 0}):print()
nn:feedforward({1, 0}):print()

Я написал этот класс NeuralNetwork.Я использовал библиотеку классов и матричную библиотеку. Соответственно class matrix

Кажется, что все это правильно для меня (в идеале, по крайней мере), кстати, когда я создаю новый экземплярNN с 2 входами, 2 скрытыми нейронами и 1 выходом и попыткой решить XOR, это не работает.

Чего мне не хватает?Может быть, я неправильно понял матричную библиотеку, надеюсь, кто-нибудь может мне помочь

РЕДАКТИРОВАТЬ: я добавил функцию карты в библиотеку, чтобы применить математическую функцию к каждому числу в матрице.

function matrix.map( m1, func )
    local mtx = {}

    for i = 1,#m1 do
        mtx[i] = {}
        for j = 1,#m1[1] do
            mtx[i][j] = func(m1[i][j])
        end
    end
    return setmetatable( mtx, matrix_meta )
end
...