Skip to content

Commit 6e50cc6

Browse files
committed
add neural net animation example
1 parent 8ff74b1 commit 6e50cc6

File tree

6 files changed

+257
-0
lines changed

6 files changed

+257
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env jruby
2+
require 'propane'
3+
4+
class LayeredNetwork < Propane::App
5+
# The Nature of Code
6+
# Daniel Shiffman
7+
# http://natureofcode.com
8+
9+
# An animated drawing of a Neural Network
10+
load_libraries :neural_network
11+
12+
attr_reader :network, :output
13+
14+
def setup
15+
sketch_title 'Exercise 10 05 Layered Network Animation'
16+
# Create the Network object
17+
@network = Network.new(width / 2, height / 2)
18+
layers = 3
19+
inputs = 2
20+
@output = Neuron.new 250, 0
21+
(0...layers).each do |i|
22+
inputs.times do |j|
23+
x = map1d(i, (0..layers), (-250..300))
24+
y = map1d(j, (0..inputs - 1), (-75..75))
25+
n = Neuron.new(x, y)
26+
if i > 0
27+
(0...inputs).each do |k|
28+
prev = network.neurons[network.neurons.size - inputs + k - j]
29+
network.connect(prev, n, rand)
30+
end
31+
end
32+
network.connect(n, output, rand) if (i == layers - 1)
33+
network.add_neuron(n)
34+
end
35+
end
36+
network.add_neuron(output)
37+
end
38+
39+
def draw
40+
background 255
41+
# Update and display the Network
42+
network.update
43+
network.display
44+
# Every 30 frames feed in an input
45+
network.feedforward(rand, rand) if (frame_count % 30 == 0)
46+
end
47+
48+
def settings
49+
size 640, 360
50+
end
51+
end
52+
53+
LayeredNetwork.new
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# The Nature of Code
2+
# Daniel Shiffman
3+
# http://natureofcode.com
4+
5+
# An animated drawing of a Neural Network
6+
7+
class Connection
8+
include Propane::Proxy
9+
# Connection is from A to B
10+
attr_reader :a, :b, :weight, :sending, :sender, :output
11+
12+
def initialize(from, to, w)
13+
@weight, @a, @b = w, from, to
14+
@sending = false
15+
@sender = Vec2D.new
16+
@output = 0
17+
end
18+
19+
# The Connection is active
20+
def feedforward(val)
21+
@output = val * weight # Compute output
22+
@sender = a.origin # Start animation at originating neuron
23+
@sending = true # Turn on sending
24+
end
25+
26+
# Update traveling sender
27+
def update
28+
return unless sending # favour a guard clause in ruby
29+
# Use a simple interpolation
30+
sender.lerp!(b.location, 0.1)
31+
d = sender.dist(b.location)
32+
# If we've reached the end
33+
return unless d < 1
34+
# Pass along the output!
35+
b.feedforward(output)
36+
@sending = false
37+
end
38+
39+
# Draw line and traveling circle
40+
def display
41+
stroke(0)
42+
stroke_weight(1 + weight * 4)
43+
draw_line a.location, b.location
44+
return unless sending
45+
fill(0)
46+
stroke_weight(1)
47+
ellipse(sender.x, sender.y, 16, 16)
48+
end
49+
50+
def draw_line(a, b)
51+
line a.x, a.y, b.x, b.y
52+
end
53+
end
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# The Nature of Code
2+
# Daniel Shiffman
3+
# http:#natureofcode.com
4+
# An animated drawing of a Neural Network
5+
6+
class Network
7+
include Propane::Proxy
8+
# The Network has a list of neurons
9+
attr_reader :neurons, :connections, :location
10+
11+
def initialize(x, y)
12+
@location = Vec2D.new(x, y)
13+
@neurons = []
14+
@connections = []
15+
end
16+
17+
# We can add a Neuron
18+
def add_neuron(n)
19+
neurons << n
20+
end
21+
22+
# We can connection two Neurons
23+
def connect(a, b, weight = 0.5)
24+
c = Connection.new a, b, weight
25+
a.join c
26+
# Also add the Connection here
27+
connections << c
28+
end
29+
30+
# Sending an input to the first Neuron
31+
# We should do something better to track multiple inputs
32+
def feedforward(input1, input2)
33+
n1 = neurons[0]
34+
n1.feedforward(input1)
35+
n2 = neurons[1]
36+
n2.feedforward(input2)
37+
end
38+
39+
# Update the animation
40+
def update
41+
connections.each { |c| c.update }
42+
end
43+
44+
# Draw everything
45+
def display
46+
push_matrix
47+
translate(location.x, location.y)
48+
neurons.each { |n| n.display }
49+
connections.each { |c| c.display }
50+
pop_matrix
51+
end
52+
end
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Daniel Shiffman
2+
# The Nature of Code
3+
# http://natureofcode.com
4+
# An animated drawing of a Neural Network
5+
6+
class Neuron
7+
include Propane::Proxy
8+
# Neuron has a location
9+
attr_reader :location, :connections, :sum, :r
10+
11+
def initialize(x, y)
12+
@sum = 0
13+
@r = 32
14+
@location = Vec2D.new(x, y)
15+
@connections = []
16+
end
17+
18+
# Add a Connection
19+
def join(c)
20+
connections << c
21+
end
22+
23+
def origin
24+
location.copy
25+
end
26+
27+
# Receive an input
28+
def feedforward(input)
29+
# Accumulate it
30+
@sum += input
31+
# Activate it?
32+
return sum unless sum > 1
33+
fire
34+
@sum = 0 # Reset the sum to 0 if it fires
35+
end
36+
37+
# The Neuron fires
38+
def fire
39+
@r = 64 # It suddenly is bigger
40+
# We send the output through all connections
41+
connections.each { |c| c.feedforward(sum) }
42+
end
43+
44+
# Draw it as a circle
45+
def display
46+
stroke(0)
47+
stroke_weight(1)
48+
# Brightness is mapped to sum
49+
b = map1d(sum, (0 .. 1), (255 .. 0))
50+
fill(b)
51+
ellipse(location.x, location.y, r, r)
52+
# Size shrinks down back to original dimensions
53+
@r = lerp(r, 32, 0.1)
54+
end
55+
end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# The Nature of Code
2+
# Daniel Shiffman
3+
# http://natureofcode.com
4+
5+
class StaticNetwork
6+
include Propane::Proxy
7+
attr_reader :neurons, :location
8+
9+
def initialize(layers, inputs, _outputs)
10+
@location = Vec2D.new($app.width / 2, $app.height / 2)
11+
@neurons = []
12+
output = Neuron.new(250, 0)
13+
layers.times do |i|
14+
inputs.times do |j|
15+
x = map1d(i, (0 .. layers), (-200 .. 200))
16+
y = map1d(j, (0 .. inputs-1), (-100 .. 100))
17+
puts "#{j} #{y}"
18+
n = Neuron.new(x, y)
19+
if i > 0
20+
inputs.times do |k|
21+
prev = neurons[neurons.size - inputs + k - j]
22+
prev.join(n)
23+
end
24+
end
25+
n.join(output) if (i == layers - 1)
26+
neurons << n
27+
end
28+
end
29+
neurons << output
30+
end
31+
32+
def display
33+
push_matrix
34+
translate(location.x, location.y)
35+
neurons.each { |n| n.display }
36+
pop_matrix
37+
end
38+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# This file provides access to the below listed files via ruby-processing load_library
2+
3+
require_relative 'lib/connection'
4+
require_relative 'lib/neuron'
5+
require_relative 'lib/network'
6+
require_relative 'lib/static_network'

0 commit comments

Comments
 (0)