Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I plot/check the trained neural network. #51

Open
TorkelE opened this issue Feb 24, 2025 · 3 comments
Open

How do I plot/check the trained neural network. #51

TorkelE opened this issue Feb 24, 2025 · 3 comments
Labels
question Further information is requested

Comments

@TorkelE
Copy link
Member

TorkelE commented Feb 24, 2025

Considering the example in https://sciml.github.io/ModelingToolkitNeuralNets.jl/dev/friction/, it is shown how to plot the friction over time, and compared that to the tru value.

However, we also started with friction as a function of velocity:

function friction(v)
    sqrt(2 * MathConstants.e) * (Fbrk - Fc) * exp(-(v / vst)^2) * (v / vst) +
    Fc * tanh(v / vcol)
end

Would it be possible to evaluate the trained neural network (representing the friction) at various velocity values? Furthermore, could than the plot the real and trained frictions functions?

@TorkelE TorkelE added the question Further information is requested label Feb 24, 2025
@SebastianM-C
Copy link
Collaborator

If you want to just look at the inputs and outputs of the neural network block, you can use

plot(res_sol, idxs=(sys.nn.input.u[1], sys.nn.output.u[1]))

which should show something like

Image

which looks similar to the plot for sys.nn.output.u since the velocity is linear.

You can also leverage the plotting interface for comparing the friction with the results from the neural network

plot(res_sol, idxs=(sys.nn.input.u[1], sys.nn.output.u[1]))
plot!(res_sol, idxs=(sys.nn.input.u[1], friction(sys.nn.input.u[1])))

Image

Bonus: now what if you want to evaluate the embedded neural network at arbitrary values?
You can actually recover the Lux network embedded in the equations

julia> arguments(arguments(equations(sys.nn)[1].rhs[1])[1])[1]
Chain(
    layer_1 = Dense(1 => 10, mish, use_bias=false),  # 10 parameters
    layer_2 = Dense(10 => 10, mish, use_bias=false),  # 100 parameters
    layer_3 = Dense(10 => 1, use_bias=false),  # 10 parameters
)         # Total: 120 parameters,
          #        plus 0 states.

and you can call this with whatever inputs are needed

julia> LuxCore.stateless_apply(arguments(arguments(equations(sys.nn)[1].rhs[1])[1])[1], [1.23], convert(res_sol.ps[sys.nn.T], res_sol.ps[sys.nn.p]))
1-element Vector{Float64}:
 18.04731050719053

but note that you also have to reconstruct the ComponentArray structure of the NN parameters.

We should make this easier by storing the network as a callable parameter, I don't consider the above "official recommendations" 😅 , but I wanted to point out that it's possible. Since it relies on implementation details of the NN block, this is not public API in any form, use at your own risk.

@TorkelE
Copy link
Member Author

TorkelE commented Mar 4, 2025

Thanks a lot! Yeah, something like this would be really useful. Especially when evaluating it, and there is a known function from which the data is fetched. Then I could check if this function is recovered (which is a lot more intuitive then just checking what it is evaluated for across the simulation.

Just checking so I get it right. Say that I want to evaluate the friction NN at velocity = 1.5, then I would do:

velocity = 1.5
friction = LuxCore.stateless_apply(arguments(arguments(equations(sys.nn)[1].rhs[1])[1])[1], [velocity], convert(res_sol.ps[sys.nn.T], res_sol.ps[sys.nn.p]))

?

@SebastianM-C
Copy link
Collaborator

yes, if you have access to the neural network from the "outside" of the model it's much easier and that's the recommended thing to do for now, but I wanted to point out that it should be technically possible even if you just have the model.

if you save the Lux model separately, you can just call it with LuxCore.stateless_apply(lux_model, nn_input, convert(res_sol.ps[sys.nn.T], res_sol.ps[sys.nn.p]). You can make it even easier if you have the neural network parameters on the "outside" too, as you can just convert res_sol.ps[sys.nn.p] to their type. Essentially lux models can use ComponentArrays to store the neural network parameters, so you just need to convert the vector of plain numbers to that type to restore the layer structure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants