1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
type activation = Sigmoid | Tanh | Relu | Linear
let squash (f : activation) (z : float) : float =
match f with
| Sigmoid -> 1. /. (1. +. exp (-.z))
| Tanh -> tanh z
| Relu -> if z > 0. then z else 0.
| Linear -> z
let slope (f : activation) ~(z : float) ~(a : float) : float =
match f with
| Sigmoid -> a *. (1. -. a)
| Tanh -> 1. -. (a *. a)
| Relu -> if z > 0. then 1. else 0.
| Linear -> 1.
type layer = { w : Matrix.t; b : Matrix.t; f : activation }
type t = layer list
let make ~(seed : int) ?(hidden = Tanh) ?(last = Sigmoid) (sizes : int list) : t =
let rec go seed sizes =
match sizes with
| inputs :: outputs :: rest ->
let spread = sqrt (6. /. float_of_int (inputs + outputs)) in
let f = if rest = [] then last else hidden in
{ w = Matrix.random ~seed ~spread outputs inputs; b = Matrix.create outputs 1; f }
:: go (seed + 1) (outputs :: rest)
| _ -> []
in
go seed sizes
type pass = { input : Matrix.t; steps : (Matrix.t * Matrix.t) list }
let forward_pass (net : t) (x : float array) : pass =
let input = Matrix.vector x in
let (_, steps) =
List.fold_left
(fun (a', steps) (l : layer) ->
let z = Matrix.add (Matrix.mul l.w a') l.b in
let a = Matrix.map (squash l.f) z in
(a, (z, a) :: steps))
(input, []) net
in
{ input; steps = List.rev steps }
let output (p : pass) : float array =
match List.rev p.steps with (_, a) :: _ -> Matrix.to_vector a | [] -> Matrix.to_vector p.input
let forward (net : t) (x : float array) : float array = output (forward_pass net x)
let sizes (net : t) : int list =
match net with [] -> [] | first :: _ -> first.w.cols :: List.map (fun (l : layer) -> l.w.rows) net
let weights (net : t) : int =
List.fold_left (fun n (l : layer) -> n + Array.length l.w.data + Array.length l.b.data) 0 net