1+ %% Import data
2+ rng(0 );
3+ data = table2array(readtable(" trajectory_training.csv" ));
4+ ds = arrayDatastore(dlarray(data ' ," BC" ));
5+ %% Define Network
6+
7+ hiddenSize = 200 ;
8+ inputSize = 2 ;
9+ outputSize = 1 ;
10+ net = [
11+ featureInputLayer(inputSize )
12+ fullyConnectedLayer(hiddenSize )
13+ tanhLayer()
14+ fullyConnectedLayer(hiddenSize )
15+ tanhLayer()
16+ fullyConnectedLayer(outputSize )];
17+ % Create a dlnetwork object from the layer array.
18+ net = dlnetwork(net );
19+ %% Specify Training Options
20+
21+ numEpochs = 300 ;
22+ miniBatchSize = 750 ;
23+ executionEnvironment = " auto" ;
24+ initialLearnRate = 0.001 ;
25+ decayRate = 1e-4 ;
26+
27+ %% Create a minibatchque
28+ mbq = minibatchqueue(ds , ...
29+ ' MiniBatchSize' ,miniBatchSize , ...
30+ ' MiniBatchFormat' ,' BC' , ...
31+ ' OutputEnvironment' ,executionEnvironment );
32+ averageGrad = [];
33+ averageSqGrad = [];
34+
35+ accfun = dlaccelerate(@modelGradients );
36+
37+ figure
38+ C = colororder ;
39+ lineLoss = animatedline(' Color' ,C(2 ,: ));
40+ ylim([0 inf ])
41+ xlabel(" Iteration" )
42+ ylabel(" Loss" )
43+ grid on
44+ set(gca , ' YScale' , ' log' );
45+ hold off
46+ %% Train model
47+ start = tic ;
48+
49+ iteration = 0 ;
50+ for epoch = 1 : numEpochs
51+ shuffle(mbq );
52+ while hasdata(mbq )
53+ iteration = iteration + 1 ;
54+
55+ dlXT = next(mbq );
56+ dlX = dlXT(1 : 2 ,: );
57+ dlT = dlXT(3 : 4 ,: );
58+
59+ % Evaluate the model gradients and loss using dlfeval and the
60+ % modelGradients function.
61+ [gradients ,loss ] = dlfeval(accfun ,net ,dlX ,dlT );
62+ % Update learning rate.
63+ learningRate = initialLearnRate / (1 + decayRate * iteration );
64+
65+ % Update the network parameters using the adamupdate function.
66+ [net ,averageGrad ,averageSqGrad ] = adamupdate(net ,gradients ,averageGrad , ...
67+ averageSqGrad ,iteration ,learningRate );
68+ end
69+
70+ % Plot training progress.
71+ loss = double(gather(extractdata(loss )));
72+ addpoints(lineLoss ,iteration , loss );
73+
74+ drawnow
75+ end
76+ %% Test model
77+ % To make predictions with the Hamiltonian NN we need to solve the ODE system:
78+ % dp/dt = -dH/dq, dq/dt = dH/dp
79+
80+ accOde = dlaccelerate(@predmodel );
81+ t0 = dlarray(0 ," CB" );
82+ x = dlarray([1 ,0 ]," BC" );
83+ dlfeval(accOde ,t0 ,x ,net );
84+
85+ % Since the original ode45 can't use dlarray we need to write an ODE
86+ % function that wraps accOde by converting the inputs to dlarray, and
87+ % extracting them again after accOde is applied.
88+ f = @(t ,x ) extractdata(accOde(dlarray(t ," CB" ),dlarray(x ," CB" ),net ));
89+
90+ % Now solve with ode45
91+ x = single([1 ,0 ]);
92+ t_span = linspace(0 ,20 ,2000 );
93+ noise_std = 0.1 ;
94+ % Make predictions.
95+ t_span = t_span .*(1 + .9 * noise_std );
96+ [~ ,dlqp ] = ode45(f ,t_span ,x );
97+ qp = squeeze(double(dlqp ));
98+ qp = qp .' ;
99+ figure ,plot(qp(1 ,: ),qp(2 ,: ))
100+ hold on
101+ load qp_baseline.mat
102+ plot(qp(1 ,: ),qp(2 ,: ))
103+ hold off
104+ legend([" Hamiltonian NN" ," Baseline" ])
105+ xlim([-1.1 1.1 ])
106+ ylim([-1.1 1.1 ])
107+ %% Supporting Functions
108+ % modelGradients Function
109+ function [gradients ,loss ] = modelGradients(net ,dlX ,dlT )
110+
111+ % Make predictions with the initial conditions.
112+ dlU = forward(net ,dlX );
113+ [dq ,dp ] = dlderivative(dlU ,dlX );
114+ loss_dq = l2loss(dq ,dlT(1 ,: ));
115+ loss_dp = l2loss(dp ,dlT(2 ,: ));
116+ loss = loss_dq + loss_dp ;
117+ gradients = dlgradient(loss ,net .Learnables );
118+ end
119+
120+ % predmodel Function
121+ function dlT_pred = predmodel(t ,dlX ,net )
122+ dlU = forward(net ,dlX );
123+ [dq ,dp ] = dlderivative(dlU ,dlX );
124+ dlT_pred = [dq ;dp ];
125+ end
126+
127+ % dlderivative Function
128+ function [dq ,dp ] = dlderivative(F1 ,dlX )
129+ dF1 = dlgradient(sum(F1 ," all" ),dlX );
130+ dq = dF1(2 ,: );
131+ dp = - dF1(1 ,: );
132+ end
133+ %%
134+ % _Copyright 2023 The MathWorks, Inc._
0 commit comments