This repository was archived by the owner on Jun 18, 2025. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 69
Feature/add benchmarks [in progress] #385
Draft
adamhaber
wants to merge
7
commits into
sicmutils:main
Choose a base branch
from
adamhaber:feature/add-benchmarks
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
0db01eb
update gitignore
adamhaber c24b5e3
update gitignore
adamhaber 75ff8e3
add criterium dep
adamhaber fed73a0
initial benchmarks implementation
adamhaber ade550c
add docs and timings
adamhaber 6ac5222
remove one more flatten
adamhaber 3ff189c
fix typo in filename
adamhaber File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,3 +14,7 @@ out | |
node_modules | ||
**.shadow-cljs | ||
package-lock.json | ||
/.clj-kondo | ||
/.lsp | ||
/.cpcache | ||
/.calva |
This file contains hidden or 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
;; | ||
;; Copyright © 2021 Adam Haber. | ||
;; This work is based on the Scmutils system of MIT/GNU Scheme: | ||
;; Copyright © 2002 Massachusetts Institute of Technology | ||
;; | ||
;; This is free software; you can redistribute it and/or modify | ||
;; it under the terms of the GNU General Public License as published by | ||
;; the Free Software Foundation; either version 3 of the License, or (at | ||
;; your option) any later version. | ||
;; | ||
;; This software is distributed in the hope that it will be useful, but | ||
;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
;; General Public License for more details. | ||
;; | ||
;; You should have received a copy of the GNU General Public License | ||
;; along with this code; if not, see <http://www.gnu.org/licenses/>. | ||
;; | ||
|
||
(ns benchmarks | ||
"This namespace contains various AD benchmarks, based on Sisnkind and Pearlmutter's work on Stalingrad. | ||
- An overview of the different benchmarks - https://engineering.purdue.edu/~qobi/papers/ad2008.pdf | ||
- Implementions of the benchmarks in different languages - https://engineering.purdue.edu/~qobi/stalingrad-examples2009/ | ||
- NIPS 2017 presentation on the benchmarks - https://autodiff-workshop.github.io/slides/JeffreyMarkSiskind.pdf | ||
Only forward AD benchmarks are implemented." | ||
(:refer-clojure :exclude [partial zero? + - * / ref]) | ||
(:require [sicmutils.env :refer :all] | ||
[sicmutils.generic :as g] | ||
[criterium.core :as crit] | ||
[clojure.core.reducers :as reducers])) | ||
|
||
(defn multivariate-argmin [f x] | ||
"A function which finds the multivariate argmin x of f. | ||
Implements a multivariate optimizer using adaptive naive gradient descent. | ||
This iterates xi+1 = xi − η∇*f(xi) until either ∇f(x) or |xi+1 − xi| is small, | ||
increasing η when progress is made and decreasing η when no progress is made." | ||
(let [g (D f)] | ||
(loop [x x | ||
fx (f x) | ||
gx (g/transpose (g x)) | ||
eta 1e-5 | ||
i 0] | ||
(cond (<= (compare (g/abs gx) 1e-5) 0) | ||
x | ||
|
||
(= i 10) | ||
(recur x fx gx (g/* 2.0 eta) 0) | ||
|
||
:else | ||
(let [x-prime (g/- x (g/* eta gx))] | ||
(if (<= (compare (g/abs (- x x-prime)) 1e-5) 0) | ||
x | ||
(let [fx-prime (f x-prime)] | ||
(if (< (compare fx-prime fx) 0) | ||
(recur x-prime fx-prime (g/transpose (g x-prime)) eta (+ i 1)) | ||
(recur x fx gx (/ eta 2.0) 0))))))))) | ||
|
||
(defn naive-euler [w] | ||
"Naive Euler ODE integration of a particle's path. | ||
The charged particle is traveling non-relativistically in a plane with position x(t) | ||
and velocity x'(t) and accelerated by an electric field formed by a pair of repulsive bodies | ||
at positions (10, 10-w) and (10, 0) where w is a modifiable control parameter of the system." | ||
(let [charges [[10.0 (- 10.0 w)] [10.0 0.0]] | ||
x-initial [0.0 8.0] | ||
xdot-initial [0.75 0.0] | ||
delta-t 1e-1 | ||
p (fn [x] | ||
(transduce (map (fn [c] (/ 1.0 (g/abs (- x c))))) | ||
g/+ | ||
0.0 | ||
charges))] | ||
(loop [x x-initial | ||
xdot xdot-initial] | ||
(let [[x' y' :as x-new] (g/+ x (g/* delta-t xdot))] | ||
(if (g/negative? y') | ||
(let [delta-t-f (g// (g/- 0.0 (second x)) | ||
(second xdot)) | ||
x-t-f (g/+ x (g/* delta-t-f xdot))] | ||
(g/square (first x-t-f))) | ||
(let [xddot (g/* -1.0 (g/transpose ((D p) x)))] | ||
(recur x-new (g/+ xdot (g/* delta-t xddot))))))))) | ||
|
||
(defn multivariate-argmax [f x] | ||
"A function which finds the multivariate argmax x of f." | ||
(multivariate-argmin (fn [x] (g/- (f x))) x)) | ||
|
||
(defn multivariate-max [f x] | ||
"A function which finds the maximum of a multivariate function f." | ||
(f (multivariate-argmax f x))) | ||
|
||
(defn particle-FF [] | ||
"Finding a value for w that causes the particle’s path to intersect the origin." | ||
(multivariate-argmin naive-euler 0.0)) | ||
|
||
;; Evaluation count : 6 in 6 samples of 1 calls. | ||
;; Execution time mean : 28.701592 sec | ||
;; Execution time std-deviation : 77.929896 ms | ||
;; Execution time lower quantile : 28.600724 sec ( 2.5%) | ||
;; Execution time upper quantile : 28.769411 sec (97.5%) | ||
;; Overhead used : 2.172762 ns | ||
(crit/quick-bench (particle-FF)) | ||
|
||
(defn saddle-FF [] | ||
"Computes a saddle point: min(x1,y1) max(x2,y2) f(x,y) | ||
for the function f(x,y)= (x1^2 + y1^2) - (x2^2 + y2^2)." | ||
(let [start [1.0 1.0] | ||
f (fn [[x1 y1] [x2 y2]] | ||
(- (+ (g/square x1) (g/square y1)) | ||
(+ (g/square x2) (g/square y2)))) | ||
x1* (multivariate-argmin | ||
(fn [x1] | ||
(multivariate-max | ||
(fn [x2] (f x1 x2)) | ||
start)) | ||
start) | ||
x2* (multivariate-argmax | ||
(fn [x2] (f x1* x2)) start)] | ||
[x1* x2*])) | ||
|
||
;; Evaluation count : 6 in 6 samples of 1 calls. | ||
;; Execution time mean : 11.263608 sec | ||
;; Execution time std-deviation : 27.629932 ms | ||
;; Execution time lower quantile : 11.226264 sec ( 2.5%) | ||
;; Execution time upper quantile : 11.297167 sec (97.5%) | ||
;; Overhead used : 2.172762 ns | ||
(crit/quick-bench (saddle-FF)) | ||
|
||
;; initial implementation of the backprop benchmark | ||
(def xor-ws0 | ||
"Initial weights and biases for a 1-hidden layer neural network." | ||
[[[1.16054 -0.284227 0] [1.30467 0.617194 0]] | ||
[[0.648461 -0.084395 0]]]) | ||
|
||
(def xor-data-with-targets | ||
"Inputs and outputs for a XOR function." | ||
[[[0 0] [0]] | ||
[[0 1] [1]] | ||
[[1 0] [1]] | ||
[[1 1] [0]]]) | ||
|
||
(def xor-data | ||
"Extracts a vectors of inputs from the XOR dataset" | ||
(mapv peek (mapv pop xor-data-with-targets))) | ||
|
||
(defn sum-activities [activities] | ||
"Compute the activation of a neuron in the network given the inputs | ||
it receives, their weights and its bias." | ||
(fn [bias-ws] | ||
(let [bias (peek bias-ws) | ||
ws (pop bias-ws)] | ||
(g/+ bias (g/dot-product ws activities))))) | ||
|
||
(defn sum-layer [activities ws-layer] | ||
"Compute the activations of all neurons in a given layer." | ||
(mapv (sum-activities activities) ws-layer)) | ||
|
||
(defn sigmoid [x] | ||
"Implements sigmoid activation function." | ||
(#(g// 1 (g/+ (g/exp (g/negate %)) 1)) x)) | ||
|
||
(defn sum-layer-with-nonlinearity [activities ws-layer] | ||
"Compose the non-linear function with the activations of all neurons in a given layer." | ||
(mapv sigmoid (mapv (sum-activities activities) ws-layer))) | ||
|
||
(defn forward-pass [ws-layers] | ||
"Compute the outputs of a neural network to a given datasets" | ||
(fn [input] | ||
(vec (mapcat #(reducers/reduce sum-layer-with-nonlinearity % ws-layers) input)))) | ||
|
||
(defn error-on-dataset [dataset] | ||
"Compute the half of the sum of squares between the networks predictions and the targets." | ||
(fn [ws-layers] | ||
(let [inputs (mapv first dataset) | ||
predictions ((forward-pass ws-layers) inputs) | ||
targets (mapv peek (mapv peek xor-data-with-targets))] | ||
(* 0.5 (apply + (mapv g/square (g/- predictions targets))))))) | ||
|
||
;; Evaluation count : 6756 in 6 samples of 1126 calls. | ||
;; Execution time mean : 90.044636 µs | ||
;; Execution time std-deviation : 1.265485 µs | ||
;; Execution time lower quantile : 88.763128 µs ( 2.5%) | ||
;; Execution time upper quantile : 91.422184 µs (97.5%) | ||
;; Overhead used : 2.172762 ns | ||
(crit/quick-bench ((error-on-dataset xor-data-with-targets) xor-ws0)) |
This file contains hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding this here will make criterium a dependency of the whole project, which we don't want. Can you add a separate build target that adds this to dependencies? There should be some model out there, though I don't have my head around deps.edn style yet. But imagine that this is the same problem as a testing target, where you don't want to ship the testing framework out to folks that are consuming the library.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand this guide correctly, we should be able to do something like this in
deps.edn
,right?