Created
February 22, 2017 19:01
-
-
Save cronokirby/257adc4612e57e2e956de20debbecd3f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Linear do | |
@moduledoc """ | |
Various useful functions for linear algebra operations | |
""" | |
@doc ~S""" | |
Zips every element in a, with every element in b, applying a function | |
at the same time | |
## Examples | |
iex> Linear.zip_with([1, 2], [1, 2], &(&1 + &2)) |> Enum.to_list | |
[2, 4] | |
""" | |
def zip_with(enum1, enum2, func) do | |
Stream.zip(enum1, enum2) | |
|> Stream.map(fn {a, b} -> func.(a, b) end) | |
end | |
@doc """ | |
Adds 2 vectors together | |
## Examples | |
iex> Linear.add([123, 34], [45, 67]) | |
[168, 101] | |
""" | |
def add(vec1, vec2) do | |
zip_with(vec1, vec2, &(&1 + &2)) | |
|> Enum.to_list | |
end | |
@doc """ | |
Applies a linear transformation to a vector | |
## Examples | |
iex> Linear.mul([[1, 1], [2, 2]], [3, 4]) | |
[7, 14] | |
""" | |
def mul(mat, vec) do | |
Enum.map(mat, fn row -> | |
zip_with(row, vec, &(&1 * &2)) | |
|> Enum.sum | |
end) | |
end | |
@doc """ | |
The sigmoid activation function | |
""" | |
def sigmoid(z) when is_list z do | |
Enum.map(z, &sigmoid/1) | |
end | |
def sigmoid(z) do | |
1 / (1 + :math.exp(-z)) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Network do | |
alias Statistics.Distributions.Normal | |
import Linear | |
@moduledoc """ | |
A basic CNN used for image recognition | |
""" | |
defmodule State do | |
defstruct [:layers, :dimensions, :biases, :weights] | |
end | |
defp distribution({cols, rows}) do | |
for _ <- 1..rows do | |
Enum.map(1..cols, fn _ -> Normal.rand() end) | |
end | |
end | |
defp distribution(n) do | |
for _ <- 1..n, do: Normal.rand() | |
end | |
@doc """ | |
Initialise a neural network, using standard distribution. | |
Takes a list of dimensions i.e. `[784, 15, 10]` | |
""" | |
def init(dimensions) do | |
inner_layers = Stream.drop(dimensions, 1) | |
%State{ | |
layers: length(dimensions), | |
dimensions: dimensions, | |
biases: Enum.map(inner_layers, &distribution/1), | |
weights: Enum.slice(dimensions, 0..-2) | |
|> Stream.zip(inner_layers) | |
|> Enum.map(&distribution/1) | |
} | |
end | |
def feed_forward(network, input) do | |
Stream.zip(network.biases, network.weights) | |
|> Enum.reduce(input, fn {b, w}, a -> | |
mul(w, a) |> add(b) |> sigmoid | |
end) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment