-- Neural Network Layer.NNLayer = {};-- Init.function NNLayer:init( parent, child ) -- Variables. self.values = {}; self.desired = {}; self.errors = {}; -- Save parent/child layer. self.parent = parent; self.child = child; -- If we have a child, init weights. if( child ) then -- Init weights tables. self.weights = {}; for i = 1, self.nodes do self.weights[i] = {}; end -- Init bias values. self.bias_weights = {}; end -- Init information for i = 1, self.nodes do -- Zero out values, errors, desired values. self.values[i] = 0; self.desired[i] = 0; self.errors[i] = 0; -- Seed the generator. math.randomseed( _CurTime() ); -- If we have a child, init it too. if( child ) then for j = 1, child.nodes do -- Randommize weights. self.weights[i][j] = math.random() * 2 - 1; self.bias_weights[j] = math.random() * 2 - 1; end end endend-- New layer.function NNLayer:new( nodes ) -- Init object. local obj = {}; setmetatable( obj, self ); self.__index = self; -- Nodes. obj.nodes = nodes; -- Return object. return obj;end-- Calculate neuron values.function NNLayer:calcValues( ) if( self.parent ) then for j = 1, self.nodes do -- Activation. local x = 0; for i = 1, self.parent.nodes do x = x + self.parent.values[i] * self.parent.weights[i][j]; end x = x + 1 * self.parent.bias_weights[j]; -- Run sigmoid filter. self.values[j] = 1 / ( 1 + math.exp( -x ) ); end endend-- Calculate errors.function NNLayer:calcErrors( ) if( not self.child ) then -- Output layer. for i = 1, self.nodes do self.errors[i] = ( self.desired[i] - self.values[i] ) * self.values[i] * ( 1 - self.values[i] ); end elseif( not self.parent ) then -- No errors, input layer. for i = 1, self.nodes do self.errors[i] = 0; end else -- Hidden layer. for i = 1, self.nodes do local sum = 0; for j = 1, self.child.nodes do sum = sum + self.child.errors[j] * self.weights[i][j]; end self.errors[i] = sum * self.values[i] * ( 1 - self.values[i] ); end endend-- Adjust weights.function NNLayer:adjustWeights( ) local t = 0; if( self.child ) then for i = 1, self.nodes do for j = 1, self.child.nodes do t = 0.33 * self.child.errors[j] * self.values[i]; self.weights[i][j] = self.weights[i][j] + t; end end for i = 1, self.child.nodes do self.bias_weights[i] = self.bias_weights[i] + 0.33 * self.child.errors[i] * 1; end endend-- Neural Network.NNetwork = {};-- New.function NNetwork:new( input, hidden, layers, output ) -- Create object. local obj = {}; setmetatable( obj, self ); self.__index = self; -- Need at least 1 hidden layer. if( layers < 1 ) then layers = 1; end -- Create the layers. local inLayer = NNLayer:new( input ); -- Create the hidden layers. local hiddenLayers = {}; for i = 1, layers do hiddenLayers[i] = NNLayer:new( hidden ); end local outLayer = NNLayer:new( output ); -- Init the layers. inLayer:init( nil, hiddenLayers[1] ); -- Attach hidden layers. if( table.getn( hiddenLayers ) == 1 ) then -- Just link directly with the output layer. hiddenLayers[1]:init( inLayer, outLayer ); -- Setup output. outLayer:init( hiddenLayers[1], nil ); else -- Link with the next hidden layer. hiddenLayers[1]:init( inLayer, hiddenLayers[2] ); -- Loop through rest. for i = 2, table.getn( hiddenLayers ) - 1 do hiddenLayers[i]:init( hiddenLayers[ i - 1 ], hiddenLayers[ i + 1 ] ); end -- Link last hidden layer to output layer. hiddenLayers[ table.getn( hiddenLayers ) ]:init( hiddenLayers[ table.getn( hiddenLayers ) - 1 ], outLayer ); -- Setup output. outLayer:init( hiddenLayers[ table.getn( hiddenLayers ) ], nil ); end -- Save layers. obj.inLayer = inLayer; obj.hiddenLayers = hiddenLayers; obj.outLayer = outLayer; -- Return object. return obj;end-- Set input.function NNetwork:setInput( node, val ) self.inLayer.values[node] = val;end-- Get output.function NNetwork:getOutput( node ) return self.outLayer.values[node];end-- Set desired output.function NNetwork:setDesiredOutput( node, val ) self.outLayer.desired[node] = val;end-- Feed forward.function NNetwork:feedForward( ) -- Input. self.inLayer:calcValues(); -- Run hidden layers. for i = 1, table.getn( self.hiddenLayers ) do self.hiddenLayers[i]:calcValues(); end -- Output. self.outLayer:calcValues();end-- Back propagate.function NNetwork:backPropagate( ) -- Output. self.outLayer:calcErrors(); -- Hidden. local i = table.getn( self.hiddenLayers ); while( i >= 1 ) do self.hiddenLayers[i]:calcErrors(); i = i - 1; end -- Hidden Adjust i = table.getn( self.hiddenLayers ); while( i >= 1 ) do self.hiddenLayers[i]:adjustWeights(); i = i - 1; end -- Input adjust. self.inLayer:adjustWeights();end-- Calculate error.function NNetwork:calculateError( ) local err = 0; for i = 1, self.outLayer.nodes do err = err + math.pow( self.outLayer.values[i] - self.outLayer.desired[i], 2 ); end err = err / self.outLayer.nodes; return err;end-- Save network.function NNetwork:saveNetwork( filename ) local data = ""; -- Create the weight tables. data = data .. "InputWeights = {};\r\n"; data = data .. "HiddenWeights = {};\r\n"; -- Create the bias tables. data = data .. "InputBiasWeights = {};\r\n"; data = data .. "HiddenBiasWeights = {};\r\n\r\n"; -- Save input weights. for i = 1, self.inLayer.nodes do data = data .. "InputWeights[" .. i .. "] = {};\r\n"; for j = 1, self.inLayer.child.nodes do data = data .. "InputWeights[" .. i .. "][" .. j .. "] = " .. self.inLayer.weights[i][j] .. ";\r\n"; end end -- Empty line. data = data .. "\r\n"; -- Save hidden weights. for i = 1, table.getn( self.hiddenLayers ) do data = data .. "HiddenWeights[" .. i .. "] = {};\r\n"; for j = 1, self.hiddenLayers[i].nodes do data = data .. "HiddenWeights[" .. i .. "][" .. j .. "] = {};\r\n"; for k = 1, self.hiddenLayers[i].child.nodes do data = data .. "HiddenWeights[" .. i .. "][" .. j .. "][" .. k .. "] = " .. self.hiddenLayers[i].weights[j][k] .. ";\r\n"; end end end -- Empty line. data = data .. "\r\n"; -- Save input bias weights. for j = 1, self.inLayer.child.nodes do data = data .. "InputBiasWeights[" .. j .. "] = " .. self.inLayer.bias_weights[j] .. ";\r\n"; end -- Empty line. data = data .. "\r\n"; -- Save hidden bias weights. for i = 1, table.getn( self.hiddenLayers ) do data = data .. "HiddenBiasWeights[" .. i .. "] = {};\r\n"; for k = 1, self.hiddenLayers[i].child.nodes do data = data .. "HiddenBiasWeights[" .. i .. "][" .. k .. "] = " .. self.hiddenLayers[i].bias_weights[k] .. ";\r\n"; end end -- Write to file _file.Write( filename, data );end-- Load network.function NNetwork:loadNetwork( filename ) _RunString( _file.Read( filename ) ); -- Restore input weights. self.inLayer.weights = InputWeights; self.inLayer.bias_weights = InputBiasWeights; -- Restore hidden weights. for i = 1, table.getn( HiddenWeights ) do self.hiddenLayers[i].weights = HiddenWeights[i]; self.hiddenLayers[i].bias_weights = HiddenBiasWeights[i]; endend