From 5081af69731aa18e98cde1efdcae3e4636e4eddb Mon Sep 17 00:00:00 2001 From: Alexandre Lairan Date: Mon, 24 Sep 2018 12:20:54 +0200 Subject: [PATCH] Add neural network --- shard.lock | 6 ++++++ shard.yml | 4 ++++ src/deep_learning.cr | 7 +++++++ src/neural/builder.cr | 23 +++++++++++++++++++++++ src/neural/network.cr | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+) create mode 100644 shard.lock create mode 100644 src/neural/builder.cr diff --git a/shard.lock b/shard.lock new file mode 100644 index 0000000..ef19d6c --- /dev/null +++ b/shard.lock @@ -0,0 +1,6 @@ +version: 1.0 +shards: + linalg: + github: konovod/linalg + commit: 3467699ad720d5f4c2e55cbfe925bec5addce227 + diff --git a/shard.yml b/shard.yml index 222e2e7..e9b10e7 100644 --- a/shard.yml +++ b/shard.yml @@ -11,3 +11,7 @@ targets: crystal: 0.26.1 license: MIT + +dependencies: + linalg: + github: konovod/linalg diff --git a/src/deep_learning.cr b/src/deep_learning.cr index f33b133..f012266 100644 --- a/src/deep_learning.cr +++ b/src/deep_learning.cr @@ -1,4 +1,7 @@ +require "linalg" + require "./mnist/**" +require "./neural/**" module DeepLearning VERSION = "0.1.0" @@ -11,3 +14,7 @@ labels = File.open("./data/train-labels.idx1-ubyte") loader = Mnist::Loader.new(images, labels) data = loader.call + +network = Neural::Builder.new([28 * 28, 16, 16, 10]).call(Neural::Builder::RANDOM_VALUE) +image = LA::GMat.new(28 * 28, 1) { |i, _| data.first.image[i] } +pp network.call(image) diff --git a/src/neural/builder.cr b/src/neural/builder.cr new file mode 100644 index 0000000..7f41045 --- /dev/null +++ b/src/neural/builder.cr @@ -0,0 +1,23 @@ +require "./network" + +module Neural + class Builder + DEFAULT_VALUE = Proc(Float64).new { 0.0 } + RANDOM_VALUE = Proc(Float64).new { rand(-1.0..1.0) } + + def initialize(@levels : Array(Int32)) + end + + def call(default_value = DEFAULT_VALUE) : Network + nodes = Array.new(@levels.size) do |i| + LA::GMat.new(@levels[i], 1) { default_value.call } + end + + links = Array.new(@levels.size - 1) do |i| + LA::GMat.new(@levels[i + 1], @levels[i]) { default_value.call } + end + + Network.new(nodes, links) + end + end +end diff --git a/src/neural/network.cr b/src/neural/network.cr index c8a0025..ba1cce9 100644 --- a/src/neural/network.cr +++ b/src/neural/network.cr @@ -1,4 +1,38 @@ module Neural class Network + getter nodes, links + + def initialize(@nodes : Array(LA::GMat), @links : Array(LA::GMat)) + end + + def call(image : LA::GMat) + vector_for(@nodes.size - 1, image) + end + + private def vector_for(x : Int32, image : LA::GMat) + if x == 0 + bias = @nodes[x] + matrix = image + matrix_sigmoid(matrix + bias) + else + matrix = @links[x - 1] + bias = @nodes[x] + + matrix_sigmoid(matrix * vector_for(x - 1, image) + bias) + end + end + + private def sigmoid(x) + 1 / (1 + Math.exp(-x)) + end + + private def matrix_sigmoid(matrix) + matrix.map { |val| sigmoid(val) } + end + + private def matrix_sigmoid_derivative(matrix) + ones = Matrix.build(matrix.column_size, matrix.row_size) { 1 } + matrix_sigmoid(matrix) * (ones - matrix_sigmoid(matrix)) + end end end