|
6 | 6 | [](https://codecov.io/gh/JuliaGNI/SymbolicNeuralNetworks.jl)
|
7 | 7 | [](https://JuliaCI.github.io/NanosoldierReports/pkgeval_badges/S/SymbolicNeuralNetworks.html)
|
8 | 8 |
|
9 |
| -SymbolicNeuralNetworks.jl was created to take advantage of [Symbolics.jl](https://symbolics.juliasymbolics.org/stable/) for training neural networks by accelarating their evaluation and by simplifing the computation of some derivatives of the neural network that may be needed for loss functions. This package is based on [AbstractNeuralNetwork.jl](https://github.com/JuliaGNI/AbstractNeuralNetworks.jl) and can be applied to [GeometricMachineLearning.jl](https://github.com/JuliaGNI/GeometricMachineLearning.jl). |
| 9 | +In a perfect world we probably would not need `SymbolicNeuralNetworks`. Its motivation mainly comes from [`Zygote`](https://github.com/FluxML/Zygote.jl)'s inability to handle second-order derivatives in a decent way[^1]. We also note that if [`Enzyme`](https://github.com/EnzymeAD/Enzyme.jl) matures further, there may be no need for `SymoblicNeuralNetworks` anymore in the future. For now (December 2024) `SymbolicNeuralNetworks` offer a good way to incorporate derivatives into the loss function. |
10 | 10 |
|
11 |
| -To accelerate the evaluation of the neural network, we change its evaluation method with its code generated by [Symbolics.jl](https://symbolics.juliasymbolics.org/stable/), performs some otpmizations on it, and generate the associate function with [RuntimeGeneratedFunctions.jl](https://github.com/SciML/RuntimeGeneratedFunctions.jl). |
| 11 | +[^1]: In some cases it is possible to perform second-order differentiation with `Zygote`, but when this is possible and when it is not is not entirely clear. |
12 | 12 |
|
13 |
| -One can easily symbolize its neural network which will create another neural networks with the symbolize method |
| 13 | +`SymbolicNeuralNetworks` was created to take advantage of [`Symbolics`](https://symbolics.juliasymbolics.org/stable/) for training neural networks by accelerating their evaluation and by simplifying the computation of arbitrary derivatives of the neural network. This package is based on [`AbstractNeuralNetwork`](https://github.com/JuliaGNI/AbstractNeuralNetworks.jl) and can be applied to [`GeometricMachineLearning`](https://github.com/JuliaGNI/GeometricMachineLearning.jl). |
| 14 | + |
| 15 | +`SymbolicNeuralNetworks` creates a symbolic expression of the neural network, computes arbitrary combinations of derivatives and uses [`RuntimeGeneratedFunctions`](https://github.com/SciML/RuntimeGeneratedFunctions.jl) to compile a `Julia` function. |
| 16 | + |
| 17 | +To create a symbolic neural network, we first design a `model` with [`AbstractNeuralNetwork`](https://github.com/JuliaGNI/AbstractNeuralNetworks.jl): |
14 | 18 | ```julia
|
15 |
| -symbolize(neuralnet, dim) |
| 19 | +using AbstractNeuralNetworks |
| 20 | + |
| 21 | +c = Chain(Dense(2, 2, tanh), Linear(2, 1)) |
16 | 22 | ```
|
17 |
| -where neuralnet is a neural network in the framework of [AbstractNeuralNetwork.jl](https://github.com/JuliaGNI/AbstractNeuralNetworks.jl) and dim the dimension of the input. |
18 | 23 |
|
19 |
| -## Example |
| 24 | +We now call `SymbolicNeuralNetwork`: |
20 | 25 |
|
21 |
| -```Julia |
| 26 | +```julia |
22 | 27 | using SymbolicNeuralNetworks
|
23 |
| -using GeometricMachineLearning |
24 |
| -using Symbolics |
25 | 28 |
|
26 |
| -@variables sx[1:2] |
27 |
| -@variables nn(sx)[1:1] |
28 |
| -Dx1 = Differential(sx[1]) |
29 |
| -Dx2 = Differential(sx[2]) |
30 |
| -vectorfield = [0 1; -1 0] * [Dx1(nn[1]), Dx2(nn[1])] |
31 |
| -eqs = (x = sx, nn = nn, vectorfield = vectorfield) |
| 29 | +nn = SymbolicNeuralNetwork(c) |
| 30 | +``` |
32 | 31 |
|
33 |
| -arch = HamiltonianNeuralNetwork(2) |
34 |
| -shnn = SymbolicNeuralNetwork(arch; eqs = eqs) |
| 32 | +## Example |
35 | 33 |
|
36 |
| -hnn = NeuralNetwork(arch, Float64) |
37 |
| -fun_vectorfield = functions(shnn).vectorfield |
38 |
| -``` |
| 34 | +We now train the neural network by using `SymbolicPullback`[^2]: |
39 | 35 |
|
40 |
| -## Performance |
| 36 | +[^2]: This example is discussed in detail in the docs. |
41 | 37 |
|
42 |
| -Let see the performance to compute the vectorfield between SymbolicNeuralNetwork's version and Zygote's one: |
43 |
| -```Julia |
44 |
| -using Zygote |
| 38 | +```julia |
| 39 | +pb = SymbolicPullback(nn) |
| 40 | + |
| 41 | +using GeometricMachineLearning |
45 | 42 |
|
46 |
| -ω∇ₓnn(x, params) = [0 1; -1 0] * Zygote.gradient(x->hnn(x, params)[1], x)[1] |
| 43 | +# we generate the data and process them with `GeometricMachineLearning.DataLoader` |
| 44 | +x_vec = -1.:.1:1. |
| 45 | +y_vec = -1.:.1:1. |
| 46 | +xy_data = hcat([[x, y] for x in x_vec, y in y_vec]...) |
| 47 | +f(x::Vector) = exp.(-sum(x.^2)) |
| 48 | +z_data = mapreduce(i -> f(xy_data[:, i]), hcat, axes(xy_data, 2)) |
47 | 49 |
|
48 |
| -println("Comparison of performances between Zygote and SymbolicNeuralNetwork for ω∇ₓnn") |
49 |
| -x = [0.5, 0.8] |
50 |
| -@time ω∇ₓnn(x, hnn.params)[1] |
51 |
| -@time fun_vectorfield(x, hnn.params) |
| 50 | +dl = DataLoader(xy_data, z_data) |
| 51 | + |
| 52 | +nn_cpu = NeuralNetwork(c, CPU()) |
| 53 | +o = Optimizer(AdamOptimizer(), nn_cpu) |
| 54 | +n_epochs = 1000 |
| 55 | +batch = Batch(10) |
| 56 | +o(nn_cpu, dl, batch, n_epochs, pb.loss, pb) |
52 | 57 | ```
|
53 | 58 |
|
54 |
| -Let see another example of the training of a SympNet (an intrasec structure preserving architecture present in [GeometricMachineLearning.jl](https://github.com/JuliaGNI/GeometricMachineLearning.jl)) on an harmonic oscillator the data of which come from [GeometricProblem.jl](https://github.com/JuliaGNI/GeometricProblems.jl) : |
| 59 | +We can also train the neural network with `Zygote`-based[^3] automatic differentiation (AD): |
55 | 60 |
|
| 61 | +[^3]: Note that here we can actually use `Zygote` without problems as it does not involve any complicated derivatives. |
56 | 62 |
|
| 63 | +```julia |
| 64 | +pb_zygote = GeometricMachineLearning.ZygotePullback(FeedForwardLoss()) |
| 65 | +o(nn_cpu, dl, batch, n_epochs, pb_zygote.loss, pb_zygote) |
| 66 | +``` |
| 67 | + |
| 68 | +## Development |
| 69 | + |
| 70 | +We are using git hooks, e.g., to enforce that all tests pass before pushing. In order to activate these hooks, the following command must be executed once: |
| 71 | +``` |
| 72 | +git config core.hooksPath .githooks |
| 73 | +``` |
0 commit comments