1 (ns neural-net.backprop
3 (:use [clojure.contrib math]))
5 (defn make-neuron "Make a simple neuron"
6 ([] (make-neuron sigmoid)) ([phi] (ref {:phi phi})))
8 (defn initial-weight "A random initial weight." [] (- (rand 0.4) 0.2))
11 "Create a fully connected feed-forward network of neurons. Layers
12 should specify the number of neurons in each layer."
16 (map (fn [_] (ref {:y nil})) (range (first layers)))
18 (map (comp (partial map (fn [_] (make-neuron))) range) (rest layers)))]
25 ;; hash of weights and inputs
27 (when (not (empty? in))
30 {:n (ref {:y 1}) :w (initial-weight)}
32 (map #(hash-map :n % :w (initial-weight)) in)))
34 (cons '() (butlast net)) net (concat (rest net) (list '()))))
38 "Reset the activation of the neurons in a network." [net]
41 (dosync (ref-set n (dissoc @n :v :y :phi-p :e :grad)))))
44 (defn set-inputs "Set the input values of a network." [net inputs]
45 (dorun (map (fn [n i] (dosync (ref-set n (assoc @n :y i)))) (first net) inputs))
48 (defn set-outputs "Set the output values of a network." [net outputs]
50 (map (fn [n d] (dosync (ref-set n (assoc @n :d d)))) (last net) outputs))
53 (defn eval-neuron "Calculate v phi-p and y for the neuron." [n]
57 v (reduce + (map (fn [d] (* (d :w) (@(eval-neuron (d :n)) :y)))
59 y (phi v) phi-p (phi v 'prime)]
60 (dosync (ref-set n (assoc @n :v v :y y :phi-p phi-p))) n)))
62 (defn eval-network "Evaluate an entire neuroal network." [net]
63 (doseq [row net] (doseq [n row] (eval-neuron n)))
66 (defn back-prop-neuron
67 "Calculate the weight change for a neruon." [n eta]
68 ;; when not an input neuron and already back-prop'd
69 (when (not (or (not (@n :phi))
71 (cons (@n :grad) (map (comp :delta-w deref :n)
77 (let [e (- (@n :d) (@n :y))
78 grad (* e (@n :phi-p))
79 dendrite (map (fn [d] (assoc d :delta-w (* eta grad (@(d :n) :y))))
81 (dosync (ref-set n (assoc @n :e e :grad grad :dendrite dendrite))))
82 ;; hidden neuron -- input neurons have no dendrites or phi
83 (and (@n :dendrite) (@n :phi))
84 (let [grad (* (@n :phi-p)
87 (back-prop-neuron a eta)
90 (filter (fn [d] (= n (d :n)))
91 (@a :dendrite))) :w)))
93 dendrite (map (fn [d] (assoc d :delta-w (* eta grad (@(d :n) :y))))
95 (dosync (ref-set n (assoc @n :grad grad :dendrite dendrite))))))
98 (defn back-prop-network "Back-propagate an entire neuroal network." [net eta]
99 (doseq [row (reverse net)] (doseq [n row] (back-prop-neuron n eta)))
102 (defn apply-delta-weights "Apply delta weights across a network." [net]
105 (dosync (ref-set n (assoc @n
108 (fn [d] (assoc d :w (+ (d :delta-w) (d :w))))
109 (@n :dendrite))))))))
111 (defn train "Train a network on an epic." [net eta epic]
112 (doseq [train-pt epic]
114 ;; clamp down inputs and outputs
115 (set-inputs net (first train-pt))
116 (set-outputs net (second train-pt))
119 ;; back-prop and re-weight
120 (back-prop-network net eta)
121 (apply-delta-weights net)))
124 "Run an epic without re-weighting and report the error." [net epic]
128 ;; clean out the network
130 ;; clamp down inputs and outputs
131 (set-inputs net (first train-pt))
132 (set-outputs net (second train-pt))
136 (reduce + (map (fn [n] (expt (- (@n :d) (@n :y)) 2))
139 (* (count epic) (count (last net))))))
141 (defn classification-error
142 "Return the percent of trials in the epic classified correctly." [net epic]
145 ;; network inspection
146 (defn weights "Return the weights of each neuron in the network." [net]
147 (map (partial map (comp (partial map :w) :dendrite deref)) net))
150 "Return the weight delta of each neuron in the network." [net]
151 (map (partial map (comp (partial map :delta-w) :dendrite deref)) net))