n2p2 - A neural network potential package
KalmanFilter.cpp
Go to the documentation of this file.
1// n2p2 - A neural network potential package
2// Copyright (C) 2018 Andreas Singraber (University of Vienna)
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17#include "KalmanFilter.h"
18#include "utility.h"
19#include <Eigen/LU>
20#include <iostream>
21#include <stdexcept>
22
23using namespace Eigen;
24using namespace std;
25using namespace nnp;
26
27KalmanFilter::KalmanFilter(size_t const sizeState,
28 KalmanType const type) :
29 Updater(sizeState),
30 sizeObservation(0 ),
31 numUpdates (0 ),
32 epsilon (0.0 ),
33 q (0.0 ),
34 q0 (0.0 ),
35 qtau (0.0 ),
36 qmin (0.0 ),
37 eta (0.0 ),
38 eta0 (0.0 ),
39 etatau (0.0 ),
40 etamax (0.0 ),
41 lambda (0.0 ),
42 nu (0.0 ),
43 gamma (0.0 ),
44 w (NULL),
45 xi (NULL),
46 H (NULL)
47{
48 if (!(type == KT_STANDARD ||
50 {
51 throw runtime_error("ERROR: Unknown Kalman filter type.\n");
52 }
53
54 if (sizeState < 1)
55 {
56 throw runtime_error("ERROR: Wrong Kalman filter dimensions.\n");
57 }
58
59 this->type = type;
61
62 w = new Map<VectorXd >(0, sizeState);
63 xi = new Map<VectorXd const>(0, sizeObservation);
64 H = new Map<MatrixXd const>(0, sizeState, sizeObservation);
65 P.resize(sizeState, sizeState);
66 P.setIdentity();
67 // Prevent problems with unallocated K when log starts.
69 K.setZero();
70}
71
73{
74}
75
76void KalmanFilter::setSizeObservation(size_t const size)
77{
78 sizeObservation = size;
79
80 return;
81}
82
83void KalmanFilter::setState(double* state)
84{
85 new (w) Map<VectorXd>(state, sizeState);
86
87 return;
88}
89
90void KalmanFilter::setError(double const* const error)
91{
93
94 return;
95}
96
97void KalmanFilter::setError(double const* const error, size_t const size)
98{
99 new (xi) Map<VectorXd const>(error, size);
100
101 return;
102}
103
104void KalmanFilter::setJacobian(double const* const jacobian)
105{
106 setJacobian(jacobian, sizeObservation);
107
108 return;
109}
110
111void KalmanFilter::setJacobian(double const* const jacobian,
112 size_t const columns)
113{
114 new (H) Map<MatrixXd const>(jacobian, sizeState, columns);
115
116 return;
117}
118
120{
122
123 return;
124}
125
126void KalmanFilter::update(size_t const sizeObservation)
127{
128 sw[prefix].start(timingReset);
129
130 X.resize(sizeState, sizeObservation);
131
132 // Calculate temporary result.
133 // X = P . H
134 X = P.selfadjointView<Lower>() * (*H);
135
136 // Calculate scaling matrix.
137 // A = H^T . X
138 MatrixXd A = H->transpose() * X;
139
140 // Increase learning rate.
141 // eta(n) = eta(0) * exp(n * tau)
142 if (type == KT_STANDARD && eta < etamax) eta *= exp(etatau);
143
144 // Add measurement noise.
145 // A = A + R
146 if (type == KT_STANDARD)
147 {
148 A.diagonal() += VectorXd::Constant(sizeObservation, 1.0 / eta);
149 }
150 else if (type == KT_FADINGMEMORY)
151 {
152 A.diagonal() += VectorXd::Constant(sizeObservation, lambda);
153 }
154
155 // Calculate Kalman gain matrix.
156 // K = X . A^-1
157 K.resize(sizeState, sizeObservation);
158 K = X * A.inverse();
159
160 // Update error covariance matrix.
161 // P = P - K . X^T
162 P.noalias() -= K * X.transpose();
163
164 // Apply forgetting factor.
165 if (type == KT_FADINGMEMORY)
166 {
167 P *= 1.0 / lambda;
168 }
169 // Add process noise.
170 // P = P + Q
171 P.diagonal() += VectorXd::Constant(sizeState, q);
172
173 // Update state vector.
174 // w = w + K . xi
175 (*w) += K * (*xi);
176
177 // Anneal process noise.
178 // q(n) = q(0) * exp(-n * tau)
179 if (q > qmin) q *= exp(-qtau);
180
181 // Update forgetting factor.
182 if (type == KT_FADINGMEMORY)
183 {
184 lambda = nu * lambda + 1.0 - nu;
185 gamma = 1.0 / (1.0 + lambda / gamma);
186 }
187
188 numUpdates++;
189
190 if (timingReset) timingReset = false;
191 sw[prefix].stop();
192
193 return;
194}
195
196void KalmanFilter::setParametersStandard(double const epsilon,
197 double const q0,
198 double const qtau,
199 double const qmin,
200 double const eta0,
201 double const etatau,
202 double const etamax)
203{
204 this->epsilon = epsilon;
205 this->q0 = q0 ;
206 this->qtau = qtau ;
207 this->qmin = qmin ;
208 this->eta0 = eta0 ;
209 this->etatau = etatau ;
210 this->etamax = etamax ;
211
212 q = q0;
213 eta = eta0;
214 P /= epsilon;
215
216 return;
217}
218
220 double const q0,
221 double const qtau,
222 double const qmin,
223 double const lambda,
224 double const nu)
225{
226 this->epsilon = epsilon;
227 this->q0 = q0 ;
228 this->qtau = qtau ;
229 this->qmin = qmin ;
230 this->lambda = lambda ;
231 this->nu = nu ;
232
233 q = q0;
234 P /= epsilon;
235 gamma = 1.0;
236
237 return;
238}
239
240string KalmanFilter::status(size_t epoch) const
241{
242
243 double Pasym = 0.5 * (P - P.transpose()).array().abs().mean();
244 double Pdiag = P.diagonal().array().abs().sum();
245 double Poffdiag = (P.array().abs().sum() - Pdiag)
246 / (sizeState * (sizeState - 1));
247 Pdiag /= sizeState;
248 double Kmean = K.array().abs().mean();
249
250 string s = strpr("%10zu %10zu %16.8E %16.8E %16.8E %16.8E %16.8E",
251 epoch, numUpdates, Pdiag, Poffdiag, Pasym, Kmean, q);
252 if (type == KT_STANDARD)
253 {
254 s += strpr(" %16.8E", eta);
255 }
256 else if (type == KT_FADINGMEMORY)
257 {
258 s += strpr(" %16.8E %16.8E", lambda, numUpdates * gamma);
259 }
260 s += '\n';
261
262 return s;
263}
264
265vector<string> KalmanFilter::statusHeader() const
266{
267 vector<string> header;
268
269 vector<string> title;
270 vector<string> colName;
271 vector<string> colInfo;
272 vector<size_t> colSize;
273 title.push_back("Kalman filter status report.");
274 colSize.push_back(10);
275 colName.push_back("epoch");
276 colInfo.push_back("Training epoch.");
277 colSize.push_back(10);
278 colName.push_back("nupdates");
279 colInfo.push_back("Number of updates performed.");
280 colSize.push_back(16);
281 colName.push_back("Pdiag");
282 colInfo.push_back("Mean of absolute diagonal values of error covariance "
283 "matrix P.");
284 colSize.push_back(16);
285 colName.push_back("Poffdiag");
286 colInfo.push_back("Mean of absolute off-diagonal values of error "
287 "covariance matrix P.");
288 colSize.push_back(16);
289 colName.push_back("Pasym");
290 colInfo.push_back("Asymmetry of P, i.e. mean of absolute values of "
291 "asymmetric part 0.5*(P - P^T).");
292 colSize.push_back(16);
293 colName.push_back("Kmean");
294 colInfo.push_back("Mean of abolute compontents of Kalman gain matrix K.");
295 colSize.push_back(16);
296 colName.push_back("q");
297 colInfo.push_back("Magnitude of process noise (= diagonal entries of Q).");
298 if (type == KT_STANDARD)
299 {
300 colSize.push_back(16);
301 colName.push_back("eta");
302 colInfo.push_back("Learning rate.");
303 }
304 else if (type == KT_FADINGMEMORY)
305 {
306 colSize.push_back(16);
307 colName.push_back("lambda");
308 colInfo.push_back("Forgetting factor for fading memory KF.");
309 colSize.push_back(16);
310 colName.push_back("kgamma");
311 colInfo.push_back("Forgetting gain k * gamma(k).");
312 }
313 header = createFileHeader(title, colSize, colName, colInfo);
314
315 return header;
316}
317
318vector<string> KalmanFilter::info() const
319{
320 vector<string> v;
321
322 if (type == KT_STANDARD)
323 {
324 v.push_back(strpr("KalmanType::KT_STANDARD (%d)\n", type));
325 v.push_back(strpr("sizeState = %zu\n", sizeState));
326 v.push_back(strpr("sizeObservation = %zu\n", sizeObservation));
327 v.push_back(strpr("epsilon = %12.4E\n", epsilon));
328 v.push_back(strpr("q0 = %12.4E\n", q0 ));
329 v.push_back(strpr("qtau = %12.4E\n", qtau ));
330 v.push_back(strpr("qmin = %12.4E\n", qmin ));
331 v.push_back(strpr("eta0 = %12.4E\n", eta0 ));
332 v.push_back(strpr("etatau = %12.4E\n", etatau ));
333 v.push_back(strpr("etamax = %12.4E\n", etamax ));
334 }
335 else if (type == KT_FADINGMEMORY)
336 {
337 v.push_back(strpr("KalmanType::KT_FADINGMEMORY (%d)\n", type));
338 v.push_back(strpr("sizeState = %zu\n", sizeState));
339 v.push_back(strpr("sizeObservation = %zu\n", sizeObservation));
340 v.push_back(strpr("epsilon = %12.4E\n", epsilon));
341 v.push_back(strpr("q0 = %12.4E\n", q0 ));
342 v.push_back(strpr("qtau = %12.4E\n", qtau ));
343 v.push_back(strpr("qmin = %12.4E\n", qmin ));
344 v.push_back(strpr("lambda = %12.4E\n", lambda));
345 v.push_back(strpr("nu = %12.4E\n", nu ));
346 }
347 v.push_back(strpr("OpenMP threads used: %d\n", nbThreads()));
348
349 return v;
350}
void update()
Update error covariance matrix and state vector.
void setParametersStandard(double const epsilon, double const q0, double const qtau, double const qmin, double const eta0, double const etatau, double const etamax)
Set parameters for standard Kalman filter.
double eta0
Learning rate initial value .
Definition: KalmanFilter.h:214
Eigen::Map< Eigen::MatrixXd const > * H
Derivative matrix.
Definition: KalmanFilter.h:230
double nu
Parameter for fading memory Kalman filter.
Definition: KalmanFilter.h:222
double qtau
Process noise exponential decay parameter .
Definition: KalmanFilter.h:208
std::string status(std::size_t epoch) const
Status report.
std::size_t sizeObservation
Size of observation (measurement) vector.
Definition: KalmanFilter.h:198
KalmanType type
Kalman filter type.
Definition: KalmanFilter.h:196
Eigen::Map< Eigen::VectorXd > * w
State vector.
Definition: KalmanFilter.h:226
double q0
Process noise initial value .
Definition: KalmanFilter.h:206
double lambda
Forgetting factor for fading memory Kalman filter.
Definition: KalmanFilter.h:220
void setParametersFadingMemory(double const epsilon, double const q0, double const qtau, double const qmin, double const lambda, double const nu)
Set parameters for fading memory Kalman filter.
Eigen::MatrixXd X
Intermediate result X = P . H.
Definition: KalmanFilter.h:236
void setState(double *state)
Set pointer to current state.
std::vector< std::string > statusHeader() const
Header for status report file.
double etatau
Learning rate exponential increase parameter .
Definition: KalmanFilter.h:216
double etamax
Learning rate maximum value .
Definition: KalmanFilter.h:218
double gamma
Forgetting gain factor gamma for fading memory Kalman filter.
Definition: KalmanFilter.h:224
std::vector< std::string > info() const
Information about Kalman filter settings.
void setError(double const *const error)
Set pointer to current error vector.
std::size_t numUpdates
Total number of updates performed.
Definition: KalmanFilter.h:200
KalmanType
Enumerate different Kalman filter types.
Definition: KalmanFilter.h:36
@ KT_STANDARD
Regular Kalman filter.
Definition: KalmanFilter.h:38
@ KT_FADINGMEMORY
Kalman filtering with fading memory modification.
Definition: KalmanFilter.h:40
double q
Process noise .
Definition: KalmanFilter.h:204
double qmin
Process noise minimum value .
Definition: KalmanFilter.h:210
void setSizeObservation(std::size_t const sizeObservation)
Set observation vector size.
Eigen::MatrixXd K
Kalman gain matrix.
Definition: KalmanFilter.h:234
double eta
Learning rate .
Definition: KalmanFilter.h:212
double epsilon
Error covariance initialization parameter .
Definition: KalmanFilter.h:202
Eigen::Map< Eigen::VectorXd const > * xi
Error vector.
Definition: KalmanFilter.h:228
Eigen::MatrixXd P
Error covariance matrix.
Definition: KalmanFilter.h:232
virtual ~KalmanFilter()
Destructor.
void setJacobian(double const *const jacobian)
Set pointer to current Jacobi matrix.
Base class for different weight update methods.
Definition: Updater.h:32
std::string prefix
Prefix for timing stopwatches.
Definition: Updater.h:112
std::size_t sizeState
Number of neural network connections (weights + biases).
Definition: Updater.h:110
bool timingReset
Internal loop timer reset switch.
Definition: Updater.h:108
std::map< std::string, Stopwatch > sw
Stopwatch map for timing.
Definition: Updater.h:114
Definition: Atom.h:28
string strpr(const char *format,...)
String version of printf function.
Definition: utility.cpp:90
vector< string > createFileHeader(vector< string > const &title, vector< size_t > const &colSize, vector< string > const &colName, vector< string > const &colInfo, char const &commentChar)
Definition: utility.cpp:104