# The Nature of Code # Daniel Shiffman # http://natureofcode.com # XOR Multi-Layered Neural Network Example # Neural network java code is all in the "src" folder load_library :nn require_relative './landscape' include_package 'nn' ITERATIONS_PER_FRAME = 5 attr_reader :inputs, :nn, :count, :land, :theta, :f, :result, :known def setup size(400, 400, P3D) @theta = 0.0 # Create a landscape object @land = Landscape.new(20, 300, 300) @f = create_font("Courier", 12, true) @nn = Network.new(2, 4) @count = 0 # Create a list of 4 training inputs @inputs = [] inputs << [1.0, 0] inputs << [0, 1.0] inputs << [1.0, 1.0] inputs << [0, 0.0] end def draw lights ITERATIONS_PER_FRAME.times do |i| inp = inputs.sample # Compute XOR @known = ((inp[0] > 0.0 && inp[1] > 0.0) || (inp[0] < 1.0 && inp[1] < 1.0))? 0 : 1.0 # Train that sucker! @result = nn.train(inp, known) @count += 1 end # Ok, visualize the solution space background(175) push_matrix translate(width / 2, height / 2 + 20, -160) rotate_x(Math::PI / 3) rotate_z(theta) # Put a little BOX on screen push_matrix stroke(50) no_fill translate(-10, -10, 0) box(280) land.calculate(nn) land.render # Draw the landscape pop_matrix @theta += 0.0025 pop_matrix # Display overal neural net stats network_status end def network_status mse = 0.0 text_font(f) fill(0) text("Your friendly neighborhood neural network solving XOR.", 10, 20) text("Total iterations: #{count}", 10, 40) mse += (result - known) * (result - known) rmse = Math::sqrt(mse / 4.0) out = "Root mean squared error: #{format("%.5f", rmse)}" hint DISABLE_DEPTH_SORT text(out, 10, 60) hint ENABLE_DEPTH_SORT end

# The Nature of Code # Daniel Shiffman # http://natureofcode.com # "Landscape" example class Landscape include Processing::Proxy attr_reader :scl, :w, :h, :rows, :cols, :z, :zoff def initialize(scl, w, h) @scl, @w, @h = scl, w, h @cols = w / scl @rows = h / scl @z = Array.new(cols, Array.new(rows, 0.0)) end # Calculate height values (based off a neural network) def calculate(nn) val = ->(curr, nn, x, y){curr * 0.95 + 0.05 * (nn.feed_forward([x, y]) * 280.0 - 140.0)} @z = (0 ... cols).map{|i| (0 ... rows).map{|j| val.call(z[i][j], nn, i * 1.0/ cols, j * 1.0/cols) } } end # Render landscape as grid of quads def render # Every cell is an individual quad # (could use quad_strip here, but produces funny results, investigate this) (0 ... z.size - 1).each do |x| (0 ... z[0].size - 1).each do |y| # one quad at a time # each quad's color is determined by the height value at each vertex # (clean this part up) no_stroke push_matrix begin_shape(QUADS) translate(x * scl - w * 0.5, y * scl - h * 0.5, 0) fill(z[x][y]+127, 220) vertex(0, 0, z[x][y]) fill(z[x+1][y]+127, 220) vertex(scl, 0, z[x+1][y]) fill(z[x+1][y+1]+127, 220) vertex(scl, scl, z[x+1][y+1]) fill(z[x][y+1]+127, 220) vertex(0, scl, z[x][y+1]) end_shape pop_matrix end end end end

## No comments:

## Post a Comment