Last active
December 13, 2015 21:18
-
-
Save m0a0t0/4976438 to your computer and use it in GitHub Desktop.
An implementation of artificial neural network and back-propagation in Clojure.
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
(ns ann.core) | |
; usage: | |
; (train-many (generate-neural-network 2 3 1) [[0 0] [1 1] [1 0] [0 1]] [[0] [0] [1] [1]] 0.1 900000) | |
; for XOR | |
(defn sum | |
[col] | |
(reduce + col)) | |
(defn sigmoid | |
[x] | |
(/ 1 (+ 1 (Math/exp (- x))))) | |
(defn generate-layer | |
[weights? n-neurons n-neurons-next] | |
(vec | |
(for [i (range n-neurons)] | |
(let [m (-> {} (assoc :activation -1))] | |
(if weights? | |
(assoc m :weights (vec (map (fn [x] (rand)) (replicate n-neurons-next 0)))) | |
m))))) | |
(defn generate-network | |
[n-inputs n-hidden n-outputs] | |
(-> | |
{} | |
(assoc :inputs (generate-layer true n-inputs n-hidden)) | |
(#(assoc % :inputs (conj (:inputs %) {:weights (vec (map (fn [x] (rand)) (replicate n-hidden 0))) :activation 1}))) | |
(assoc :hidden (generate-layer true n-hidden n-outputs)) | |
(assoc :outputs (generate-layer false n-outputs 0)))) | |
(defn activate-inputs | |
[neural-network inputs] | |
(let [new-inputs | |
(vec (for [i (range (count inputs))] | |
(assoc (get (:inputs neural-network) i) :activation (get inputs i))))] | |
(assoc neural-network :inputs (conj new-inputs (last (:inputs neural-network)))))) | |
(defn activate-layer | |
[neural-network layer-index previous-layer-index] | |
(assoc neural-network layer-index | |
(let [layer (get neural-network layer-index) | |
previous-layer (get neural-network previous-layer-index)] | |
(vec (for [i (range (count layer))] | |
(assoc (get layer i) :activation | |
(sigmoid (sum (for [neuron previous-layer] (* (:activation neuron) (get (:weights neuron) i))))))))))) | |
(defn forward-pass | |
[neural-network inputs] | |
(-> | |
(activate-inputs neural-network inputs) | |
(activate-layer :hidden :inputs) | |
(activate-layer :outputs :hidden))) | |
(defn calculate-output-deltas | |
[neural-network expected] | |
(loop [i 0 | |
neural-net neural-network] | |
(if (< i (count (:outputs neural-network))) | |
(let [activation (get-in neural-net [:outputs i :activation]) | |
target (get expected i) | |
delta (* activation (- 1 activation) (- target activation))] | |
(recur (inc i) (assoc-in neural-net [:outputs i :delta] delta))) | |
neural-net))) | |
(defn calculate-layer-deltas | |
[neural-network layer-index next-layer-index] | |
(let [layer (get neural-network layer-index) | |
next-layer (get neural-network next-layer-index)] | |
(loop [neuron 0 | |
net neural-network] | |
(if (< neuron (count layer)) | |
(let [s (sum | |
(for [next-neuron (range (count next-layer))] | |
(* (:delta (get next-layer next-neuron)) (get (:weights (get layer neuron)) next-neuron)))) | |
a (get-in layer [neuron :activation]) | |
v (* a (- 1 a) s)] | |
(recur (inc neuron) (assoc-in net [layer-index neuron :delta] v))) | |
net)))) | |
(defn calculate-deltas | |
[neural-network expected] | |
(-> | |
(calculate-output-deltas neural-network expected) | |
(calculate-layer-deltas :hidden :outputs) | |
(calculate-layer-deltas :inputs :hidden))) | |
(defn train-layer | |
[neural-network layer-index next-layer-index rate] | |
(let [layer (get neural-network layer-index) | |
next-layer (get neural-network next-layer-index)] | |
(loop [neuron 0 | |
net neural-network] | |
(if (< neuron (count layer)) | |
(recur (inc neuron) (loop [next-neuron 0 | |
net-1 net] | |
(if (< next-neuron (count next-layer)) | |
(let [change (* (get-in next-layer [next-neuron :delta]) (get-in layer [neuron :activation])) | |
weight (+ (get-in layer [neuron :weights next-neuron]) (* rate change))] | |
(recur (inc next-neuron) (assoc-in net-1 [layer-index neuron :weights next-neuron] weight))) | |
net-1))) | |
net)))) | |
(defn train | |
[neural-network rate] | |
(-> | |
neural-network | |
(train-layer :hidden :outputs rate) | |
(train-layer :inputs :hidden rate))) | |
(defn train-with-data | |
[neural-net inputs expected rate] | |
(-> | |
neural-net | |
(forward-pass inputs) | |
(calculate-deltas expected) | |
(train rate))) | |
(defn train-many | |
[neural-net inputs expected rate iterations] | |
(loop [data-index 0 | |
i 0 | |
net neural-net] | |
(if (>= i iterations) | |
net | |
(if (< data-index (count inputs)) | |
(recur (inc data-index) (inc i) (train-with-data net (get inputs data-index) (get expected data-index) rate)) | |
(recur 0 i net))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment