 ;; 4) update weights
 ;;  * multiply gradient by the learning-rate to smooth out jitter in updates.
 (defn backprop
-  [{:keys [biases weights cost-fn n-layers] :as net} input expected-output]
+  [{:keys [biases weights loss-fn n-layers] :as net} input expected-output]
   (let [bias-gradients (map #(mat/zero-array (mat/shape %)) biases)
         weight-gradients (map #(mat/zero-array (mat/shape %)) weights)
         [activations zs] (reduce

  (delta [this activation z target]
    (mat/sub activation target)))

(defn costs
  []
  (let [a [0.2, 0.3, 0.1, 0.9]
        b [0.0, 0.0, 0.0, 1.0]
        qc (QuadraticCost.)
        ce (CrossEntropyCost.)]
    (println "QuadraticCost: " (cost qc a b))
    (println "CrossEntropyCost: " (cost ce a b))))

;; K-sparse autoencoder
;0) setup

          ;(println (format "sample score: %5.2f" (float (/ sample-score sample-size))))
          (recur new-net (inc epoch)))))))

(defn network
  [layer-sizes & opts]
  {:n-layers (count layer-sizes)
   :biases (map rand-vector (next layer-sizes))
   :weights (map weight-matrix (rest layer-sizes) (drop-last layer-sizes))
   :loss-fn (get opts :loss-fn (QuadraticLoss.))})

(def trained* (atom nil))

(defn mnist-labels
