alglib 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (255) hide show
  1. data/History.txt +7 -0
  2. data/Manifest.txt +253 -0
  3. data/README.txt +33 -0
  4. data/Rakefile +27 -0
  5. data/ext/Rakefile +24 -0
  6. data/ext/alglib.i +24 -0
  7. data/ext/alglib/Makefile +157 -0
  8. data/ext/alglib/airyf.cpp +372 -0
  9. data/ext/alglib/airyf.h +81 -0
  10. data/ext/alglib/alglib.cpp +8558 -0
  11. data/ext/alglib/alglib_util.cpp +19 -0
  12. data/ext/alglib/alglib_util.h +14 -0
  13. data/ext/alglib/ap.cpp +877 -0
  14. data/ext/alglib/ap.english.html +364 -0
  15. data/ext/alglib/ap.h +666 -0
  16. data/ext/alglib/ap.russian.html +442 -0
  17. data/ext/alglib/apvt.h +754 -0
  18. data/ext/alglib/bdss.cpp +1500 -0
  19. data/ext/alglib/bdss.h +251 -0
  20. data/ext/alglib/bdsvd.cpp +1339 -0
  21. data/ext/alglib/bdsvd.h +164 -0
  22. data/ext/alglib/bessel.cpp +1226 -0
  23. data/ext/alglib/bessel.h +331 -0
  24. data/ext/alglib/betaf.cpp +105 -0
  25. data/ext/alglib/betaf.h +74 -0
  26. data/ext/alglib/bidiagonal.cpp +1328 -0
  27. data/ext/alglib/bidiagonal.h +350 -0
  28. data/ext/alglib/binomialdistr.cpp +247 -0
  29. data/ext/alglib/binomialdistr.h +153 -0
  30. data/ext/alglib/blas.cpp +576 -0
  31. data/ext/alglib/blas.h +132 -0
  32. data/ext/alglib/cblas.cpp +226 -0
  33. data/ext/alglib/cblas.h +57 -0
  34. data/ext/alglib/cdet.cpp +138 -0
  35. data/ext/alglib/cdet.h +92 -0
  36. data/ext/alglib/chebyshev.cpp +216 -0
  37. data/ext/alglib/chebyshev.h +76 -0
  38. data/ext/alglib/chisquaredistr.cpp +157 -0
  39. data/ext/alglib/chisquaredistr.h +144 -0
  40. data/ext/alglib/cholesky.cpp +285 -0
  41. data/ext/alglib/cholesky.h +86 -0
  42. data/ext/alglib/cinverse.cpp +298 -0
  43. data/ext/alglib/cinverse.h +111 -0
  44. data/ext/alglib/clu.cpp +337 -0
  45. data/ext/alglib/clu.h +120 -0
  46. data/ext/alglib/correlation.cpp +280 -0
  47. data/ext/alglib/correlation.h +77 -0
  48. data/ext/alglib/correlationtests.cpp +726 -0
  49. data/ext/alglib/correlationtests.h +134 -0
  50. data/ext/alglib/crcond.cpp +826 -0
  51. data/ext/alglib/crcond.h +148 -0
  52. data/ext/alglib/creflections.cpp +310 -0
  53. data/ext/alglib/creflections.h +165 -0
  54. data/ext/alglib/csolve.cpp +312 -0
  55. data/ext/alglib/csolve.h +99 -0
  56. data/ext/alglib/ctrinverse.cpp +387 -0
  57. data/ext/alglib/ctrinverse.h +98 -0
  58. data/ext/alglib/ctrlinsolve.cpp +297 -0
  59. data/ext/alglib/ctrlinsolve.h +81 -0
  60. data/ext/alglib/dawson.cpp +234 -0
  61. data/ext/alglib/dawson.h +74 -0
  62. data/ext/alglib/descriptivestatistics.cpp +436 -0
  63. data/ext/alglib/descriptivestatistics.h +112 -0
  64. data/ext/alglib/det.cpp +140 -0
  65. data/ext/alglib/det.h +94 -0
  66. data/ext/alglib/dforest.cpp +1819 -0
  67. data/ext/alglib/dforest.h +316 -0
  68. data/ext/alglib/elliptic.cpp +497 -0
  69. data/ext/alglib/elliptic.h +217 -0
  70. data/ext/alglib/estnorm.cpp +429 -0
  71. data/ext/alglib/estnorm.h +107 -0
  72. data/ext/alglib/expintegrals.cpp +422 -0
  73. data/ext/alglib/expintegrals.h +108 -0
  74. data/ext/alglib/faq.english.html +258 -0
  75. data/ext/alglib/faq.russian.html +272 -0
  76. data/ext/alglib/fdistr.cpp +202 -0
  77. data/ext/alglib/fdistr.h +163 -0
  78. data/ext/alglib/fresnel.cpp +211 -0
  79. data/ext/alglib/fresnel.h +91 -0
  80. data/ext/alglib/gammaf.cpp +338 -0
  81. data/ext/alglib/gammaf.h +104 -0
  82. data/ext/alglib/gqgengauss.cpp +235 -0
  83. data/ext/alglib/gqgengauss.h +92 -0
  84. data/ext/alglib/gqgenhermite.cpp +268 -0
  85. data/ext/alglib/gqgenhermite.h +63 -0
  86. data/ext/alglib/gqgenjacobi.cpp +297 -0
  87. data/ext/alglib/gqgenjacobi.h +72 -0
  88. data/ext/alglib/gqgenlaguerre.cpp +265 -0
  89. data/ext/alglib/gqgenlaguerre.h +69 -0
  90. data/ext/alglib/gqgenlegendre.cpp +300 -0
  91. data/ext/alglib/gqgenlegendre.h +62 -0
  92. data/ext/alglib/gqgenlobatto.cpp +305 -0
  93. data/ext/alglib/gqgenlobatto.h +97 -0
  94. data/ext/alglib/gqgenradau.cpp +232 -0
  95. data/ext/alglib/gqgenradau.h +95 -0
  96. data/ext/alglib/hbisinv.cpp +480 -0
  97. data/ext/alglib/hbisinv.h +183 -0
  98. data/ext/alglib/hblas.cpp +228 -0
  99. data/ext/alglib/hblas.h +64 -0
  100. data/ext/alglib/hcholesky.cpp +339 -0
  101. data/ext/alglib/hcholesky.h +91 -0
  102. data/ext/alglib/hermite.cpp +114 -0
  103. data/ext/alglib/hermite.h +49 -0
  104. data/ext/alglib/hessenberg.cpp +370 -0
  105. data/ext/alglib/hessenberg.h +152 -0
  106. data/ext/alglib/hevd.cpp +247 -0
  107. data/ext/alglib/hevd.h +107 -0
  108. data/ext/alglib/hsschur.cpp +1316 -0
  109. data/ext/alglib/hsschur.h +108 -0
  110. data/ext/alglib/htridiagonal.cpp +734 -0
  111. data/ext/alglib/htridiagonal.h +180 -0
  112. data/ext/alglib/ialglib.cpp +6 -0
  113. data/ext/alglib/ialglib.h +9 -0
  114. data/ext/alglib/ibetaf.cpp +960 -0
  115. data/ext/alglib/ibetaf.h +125 -0
  116. data/ext/alglib/igammaf.cpp +430 -0
  117. data/ext/alglib/igammaf.h +157 -0
  118. data/ext/alglib/inv.cpp +274 -0
  119. data/ext/alglib/inv.h +115 -0
  120. data/ext/alglib/inverseupdate.cpp +480 -0
  121. data/ext/alglib/inverseupdate.h +185 -0
  122. data/ext/alglib/jacobianelliptic.cpp +164 -0
  123. data/ext/alglib/jacobianelliptic.h +94 -0
  124. data/ext/alglib/jarquebera.cpp +2271 -0
  125. data/ext/alglib/jarquebera.h +80 -0
  126. data/ext/alglib/kmeans.cpp +356 -0
  127. data/ext/alglib/kmeans.h +76 -0
  128. data/ext/alglib/laguerre.cpp +94 -0
  129. data/ext/alglib/laguerre.h +48 -0
  130. data/ext/alglib/lbfgs.cpp +1167 -0
  131. data/ext/alglib/lbfgs.h +218 -0
  132. data/ext/alglib/lda.cpp +434 -0
  133. data/ext/alglib/lda.h +133 -0
  134. data/ext/alglib/ldlt.cpp +1130 -0
  135. data/ext/alglib/ldlt.h +124 -0
  136. data/ext/alglib/leastsquares.cpp +1252 -0
  137. data/ext/alglib/leastsquares.h +290 -0
  138. data/ext/alglib/legendre.cpp +107 -0
  139. data/ext/alglib/legendre.h +49 -0
  140. data/ext/alglib/linreg.cpp +1185 -0
  141. data/ext/alglib/linreg.h +380 -0
  142. data/ext/alglib/logit.cpp +1523 -0
  143. data/ext/alglib/logit.h +333 -0
  144. data/ext/alglib/lq.cpp +399 -0
  145. data/ext/alglib/lq.h +160 -0
  146. data/ext/alglib/lu.cpp +462 -0
  147. data/ext/alglib/lu.h +119 -0
  148. data/ext/alglib/mannwhitneyu.cpp +4490 -0
  149. data/ext/alglib/mannwhitneyu.h +115 -0
  150. data/ext/alglib/minlm.cpp +918 -0
  151. data/ext/alglib/minlm.h +312 -0
  152. data/ext/alglib/mlpbase.cpp +3375 -0
  153. data/ext/alglib/mlpbase.h +589 -0
  154. data/ext/alglib/mlpe.cpp +1369 -0
  155. data/ext/alglib/mlpe.h +552 -0
  156. data/ext/alglib/mlptrain.cpp +1056 -0
  157. data/ext/alglib/mlptrain.h +283 -0
  158. data/ext/alglib/nearunityunit.cpp +91 -0
  159. data/ext/alglib/nearunityunit.h +17 -0
  160. data/ext/alglib/normaldistr.cpp +377 -0
  161. data/ext/alglib/normaldistr.h +175 -0
  162. data/ext/alglib/nsevd.cpp +1869 -0
  163. data/ext/alglib/nsevd.h +140 -0
  164. data/ext/alglib/pca.cpp +168 -0
  165. data/ext/alglib/pca.h +87 -0
  166. data/ext/alglib/poissondistr.cpp +143 -0
  167. data/ext/alglib/poissondistr.h +130 -0
  168. data/ext/alglib/polinterpolation.cpp +685 -0
  169. data/ext/alglib/polinterpolation.h +206 -0
  170. data/ext/alglib/psif.cpp +173 -0
  171. data/ext/alglib/psif.h +88 -0
  172. data/ext/alglib/qr.cpp +414 -0
  173. data/ext/alglib/qr.h +168 -0
  174. data/ext/alglib/ratinterpolation.cpp +134 -0
  175. data/ext/alglib/ratinterpolation.h +72 -0
  176. data/ext/alglib/rcond.cpp +705 -0
  177. data/ext/alglib/rcond.h +140 -0
  178. data/ext/alglib/reflections.cpp +504 -0
  179. data/ext/alglib/reflections.h +165 -0
  180. data/ext/alglib/rotations.cpp +473 -0
  181. data/ext/alglib/rotations.h +128 -0
  182. data/ext/alglib/rsolve.cpp +221 -0
  183. data/ext/alglib/rsolve.h +99 -0
  184. data/ext/alglib/sbisinv.cpp +217 -0
  185. data/ext/alglib/sbisinv.h +171 -0
  186. data/ext/alglib/sblas.cpp +185 -0
  187. data/ext/alglib/sblas.h +64 -0
  188. data/ext/alglib/schur.cpp +156 -0
  189. data/ext/alglib/schur.h +102 -0
  190. data/ext/alglib/sdet.cpp +193 -0
  191. data/ext/alglib/sdet.h +101 -0
  192. data/ext/alglib/sevd.cpp +116 -0
  193. data/ext/alglib/sevd.h +99 -0
  194. data/ext/alglib/sinverse.cpp +672 -0
  195. data/ext/alglib/sinverse.h +138 -0
  196. data/ext/alglib/spddet.cpp +138 -0
  197. data/ext/alglib/spddet.h +96 -0
  198. data/ext/alglib/spdgevd.cpp +842 -0
  199. data/ext/alglib/spdgevd.h +200 -0
  200. data/ext/alglib/spdinverse.cpp +509 -0
  201. data/ext/alglib/spdinverse.h +122 -0
  202. data/ext/alglib/spdrcond.cpp +421 -0
  203. data/ext/alglib/spdrcond.h +118 -0
  204. data/ext/alglib/spdsolve.cpp +275 -0
  205. data/ext/alglib/spdsolve.h +105 -0
  206. data/ext/alglib/spline2d.cpp +1192 -0
  207. data/ext/alglib/spline2d.h +301 -0
  208. data/ext/alglib/spline3.cpp +1264 -0
  209. data/ext/alglib/spline3.h +290 -0
  210. data/ext/alglib/srcond.cpp +595 -0
  211. data/ext/alglib/srcond.h +127 -0
  212. data/ext/alglib/ssolve.cpp +895 -0
  213. data/ext/alglib/ssolve.h +139 -0
  214. data/ext/alglib/stdafx.h +0 -0
  215. data/ext/alglib/stest.cpp +131 -0
  216. data/ext/alglib/stest.h +94 -0
  217. data/ext/alglib/studenttdistr.cpp +222 -0
  218. data/ext/alglib/studenttdistr.h +115 -0
  219. data/ext/alglib/studentttests.cpp +377 -0
  220. data/ext/alglib/studentttests.h +178 -0
  221. data/ext/alglib/svd.cpp +620 -0
  222. data/ext/alglib/svd.h +126 -0
  223. data/ext/alglib/tdbisinv.cpp +2608 -0
  224. data/ext/alglib/tdbisinv.h +228 -0
  225. data/ext/alglib/tdevd.cpp +1229 -0
  226. data/ext/alglib/tdevd.h +115 -0
  227. data/ext/alglib/tridiagonal.cpp +594 -0
  228. data/ext/alglib/tridiagonal.h +171 -0
  229. data/ext/alglib/trigintegrals.cpp +490 -0
  230. data/ext/alglib/trigintegrals.h +131 -0
  231. data/ext/alglib/trinverse.cpp +345 -0
  232. data/ext/alglib/trinverse.h +98 -0
  233. data/ext/alglib/trlinsolve.cpp +926 -0
  234. data/ext/alglib/trlinsolve.h +73 -0
  235. data/ext/alglib/tsort.cpp +405 -0
  236. data/ext/alglib/tsort.h +54 -0
  237. data/ext/alglib/variancetests.cpp +245 -0
  238. data/ext/alglib/variancetests.h +134 -0
  239. data/ext/alglib/wsr.cpp +6285 -0
  240. data/ext/alglib/wsr.h +96 -0
  241. data/ext/ap.i +97 -0
  242. data/ext/correlation.i +24 -0
  243. data/ext/extconf.rb +6 -0
  244. data/ext/logit.i +89 -0
  245. data/lib/alglib.rb +71 -0
  246. data/lib/alglib/correlation.rb +26 -0
  247. data/lib/alglib/linearregression.rb +63 -0
  248. data/lib/alglib/logit.rb +42 -0
  249. data/test/test_alglib.rb +52 -0
  250. data/test/test_correlation.rb +44 -0
  251. data/test/test_correlationtest.rb +45 -0
  252. data/test/test_linreg.rb +35 -0
  253. data/test/test_logit.rb +43 -0
  254. data/test/test_pca.rb +27 -0
  255. metadata +326 -0
@@ -0,0 +1,312 @@
1
+ /*************************************************************************
2
+ Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are
6
+ met:
7
+
8
+ - Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ - Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer listed
13
+ in this license in the documentation and/or other materials
14
+ provided with the distribution.
15
+
16
+ - Neither the name of the copyright holders nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ *************************************************************************/
32
+
33
+ #ifndef _minlm_h
34
+ #define _minlm_h
35
+
36
+ #include "ap.h"
37
+ #include "ialglib.h"
38
+
39
+ #include "blas.h"
40
+ #include "trinverse.h"
41
+ #include "cholesky.h"
42
+ #include "spdsolve.h"
43
+ #include "lbfgs.h"
44
+
45
+
46
+ struct lmstate
47
+ {
48
+ bool wrongparams;
49
+ int n;
50
+ int m;
51
+ double epsf;
52
+ double epsx;
53
+ int maxits;
54
+ int flags;
55
+ int usermode;
56
+ ap::real_1d_array x;
57
+ double f;
58
+ ap::real_1d_array fi;
59
+ ap::real_2d_array j;
60
+ ap::real_2d_array h;
61
+ ap::real_1d_array g;
62
+ bool needf;
63
+ bool needfg;
64
+ bool needfgh;
65
+ bool needfij;
66
+ bool xupdated;
67
+ lbfgsstate internalstate;
68
+ lbfgsreport internalrep;
69
+ ap::real_1d_array xprec;
70
+ ap::real_1d_array xbase;
71
+ ap::real_1d_array xdir;
72
+ ap::real_1d_array gbase;
73
+ ap::real_2d_array rawmodel;
74
+ ap::real_2d_array model;
75
+ ap::real_1d_array work;
76
+ ap::rcommstate rstate;
77
+ int repiterationscount;
78
+ int repterminationtype;
79
+ int repnfunc;
80
+ int repnjac;
81
+ int repngrad;
82
+ int repnhess;
83
+ int repncholesky;
84
+ };
85
+ struct lmreport
86
+ {
87
+ int iterationscount;
88
+ int terminationtype;
89
+ int nfunc;
90
+ int njac;
91
+ int ngrad;
92
+ int nhess;
93
+ int ncholesky;
94
+ };
95
+
96
+
97
+ /*************************************************************************
98
+ LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION
99
+
100
+ Optimization using function gradient and Hessian. Algorithm - Levenberg-
101
+ Marquardt modification with L-BFGS pre-optimization and internal
102
+ pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step.
103
+
104
+ Function F has general form (not "sum-of-squares"):
105
+
106
+ F = F(x[0], ..., x[n-1])
107
+
108
+ EXAMPLE
109
+
110
+ See HTML-documentation.
111
+
112
+ INPUT PARAMETERS:
113
+ N - dimension, N>1
114
+ X - initial solution, array[0..N-1]
115
+ EpsF - stopping criterion. Algorithm stops if
116
+ |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}
117
+ EpsX - stopping criterion. Algorithm stops if
118
+ |X(k+1)-X(k)| <= EpsX*(1+|X(k)|)
119
+ MaxIts - stopping criterion. Algorithm stops after MaxIts iterations.
120
+ MaxIts=0 means no stopping criterion.
121
+
122
+ �������� ���������:
123
+ State - structure which stores algorithm state between subsequent
124
+ calls of MinLMIteration. Used for reverse communication.
125
+ This structure should be passed to MinLMIteration subroutine.
126
+
127
+ See also MinLMIteration, MinLMResults.
128
+
129
+ NOTE
130
+
131
+ Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic
132
+ stopping criterion selection (small EpsX).
133
+
134
+ -- ALGLIB --
135
+ Copyright 30.03.2009 by Bochkanov Sergey
136
+ *************************************************************************/
137
+ void minlmfgh(const int& n,
138
+ const ap::real_1d_array& x,
139
+ const double& epsf,
140
+ const double& epsx,
141
+ const int& maxits,
142
+ lmstate& state);
143
+
144
+
145
+ /*************************************************************************
146
+ LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION
147
+
148
+ Optimization using function gradient and Jacobian. Algorithm - Levenberg-
149
+ Marquardt modification with L-BFGS pre-optimization and internal
150
+ pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step.
151
+
152
+ Function F is represented as sum of squares:
153
+
154
+ F = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1])
155
+
156
+ EXAMPLE
157
+
158
+ See HTML-documentation.
159
+
160
+ INPUT PARAMETERS:
161
+ N - dimension, N>1
162
+ M - number of functions f[i]
163
+ X - initial solution, array[0..N-1]
164
+ EpsF - stopping criterion. Algorithm stops if
165
+ |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}
166
+ EpsX - stopping criterion. Algorithm stops if
167
+ |X(k+1)-X(k)| <= EpsX*(1+|X(k)|)
168
+ MaxIts - stopping criterion. Algorithm stops after MaxIts iterations.
169
+ MaxIts=0 means no stopping criterion.
170
+
171
+ �������� ���������:
172
+ State - structure which stores algorithm state between subsequent
173
+ calls of MinLMIteration. Used for reverse communication.
174
+ This structure should be passed to MinLMIteration subroutine.
175
+
176
+ See also MinLMIteration, MinLMResults.
177
+
178
+ NOTE
179
+
180
+ Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic
181
+ stopping criterion selection (small EpsX).
182
+
183
+ -- ALGLIB --
184
+ Copyright 30.03.2009 by Bochkanov Sergey
185
+ *************************************************************************/
186
+ void minlmfgj(const int& n,
187
+ const int& m,
188
+ const ap::real_1d_array& x,
189
+ const double& epsf,
190
+ const double& epsx,
191
+ const int& maxits,
192
+ lmstate& state);
193
+
194
+
195
+ /*************************************************************************
196
+ CLASSIC LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR OPTIMIZATION
197
+
198
+ Optimization using Jacobi matrix. Algorithm - classic Levenberg-Marquardt
199
+ method.
200
+
201
+ Function F is represented as sum of squares:
202
+
203
+ F = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1])
204
+
205
+ EXAMPLE
206
+
207
+ See HTML-documentation.
208
+
209
+ INPUT PARAMETERS:
210
+ N - dimension, N>1
211
+ M - number of functions f[i]
212
+ X - initial solution, array[0..N-1]
213
+ EpsF - stopping criterion. Algorithm stops if
214
+ |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}
215
+ EpsX - stopping criterion. Algorithm stops if
216
+ |X(k+1)-X(k)| <= EpsX*(1+|X(k)|)
217
+ MaxIts - stopping criterion. Algorithm stops after MaxIts iterations.
218
+ MaxIts=0 means no stopping criterion.
219
+
220
+ �������� ���������:
221
+ State - structure which stores algorithm state between subsequent
222
+ calls of MinLMIteration. Used for reverse communication.
223
+ This structure should be passed to MinLMIteration subroutine.
224
+
225
+ See also MinLMIteration, MinLMResults.
226
+
227
+ NOTE
228
+
229
+ Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic
230
+ stopping criterion selection (small EpsX).
231
+
232
+ -- ALGLIB --
233
+ Copyright 30.03.2009 by Bochkanov Sergey
234
+ *************************************************************************/
235
+ void minlmfj(const int& n,
236
+ const int& m,
237
+ const ap::real_1d_array& x,
238
+ const double& epsf,
239
+ const double& epsx,
240
+ const int& maxits,
241
+ lmstate& state);
242
+
243
+
244
+ /*************************************************************************
245
+ One Levenberg-Marquardt iteration.
246
+
247
+ Called after inialization of State structure with MinLMXXX subroutine.
248
+ See HTML docs for examples.
249
+
250
+ Input parameters:
251
+ State - structure which stores algorithm state between subsequent
252
+ calls and which is used for reverse communication. Must be
253
+ initialized with MinLMXXX call first.
254
+
255
+ If subroutine returned False, iterative algorithm has converged.
256
+
257
+ If subroutine returned True, then:
258
+ * if State.NeedF=True, - function value F at State.X[0..N-1]
259
+ is required
260
+ * if State.NeedFG=True - function value F and gradient G
261
+ are required
262
+ * if State.NeedFiJ=True - function vector f[i] and Jacobi matrix J
263
+ are required
264
+ * if State.NeedFGH=True - function value F, gradient G and Hesian H
265
+ are required
266
+
267
+ One and only one of this fields can be set at time.
268
+
269
+ Results are stored:
270
+ * function value - in LMState.F
271
+ * gradient - in LMState.G[0..N-1]
272
+ * Jacobi matrix - in LMState.J[0..M-1,0..N-1]
273
+ * Hessian - in LMState.H[0..N-1,0..N-1]
274
+
275
+ -- ALGLIB --
276
+ Copyright 10.03.2009 by Bochkanov Sergey
277
+ *************************************************************************/
278
+ bool minlmiteration(lmstate& state);
279
+
280
+
281
+ /*************************************************************************
282
+ Levenberg-Marquardt algorithm results
283
+
284
+ Called after MinLMIteration returned False.
285
+
286
+ Input parameters:
287
+ State - algorithm state (used by MinLMIteration).
288
+
289
+ Output parameters:
290
+ X - array[0..N-1], solution
291
+ Rep - optimization report:
292
+ * Rep.TerminationType completetion code:
293
+ * -1 incorrect parameters were specified
294
+ * 1 relative function improvement is no more than
295
+ EpsF.
296
+ * 2 relative step is no more than EpsX.
297
+ * 4 gradient norm is no more than EpsG
298
+ * 5 MaxIts steps was taken
299
+ * Rep.IterationsCount contains iterations count
300
+ * Rep.NFunc - number of function calculations
301
+ * Rep.NJac - number of Jacobi matrix calculations
302
+ * Rep.NGrad - number of gradient calculations
303
+ * Rep.NHess - number of Hessian calculations
304
+ * Rep.NCholesky - number of Cholesky decomposition calculations
305
+
306
+ -- ALGLIB --
307
+ Copyright 10.03.2009 by Bochkanov Sergey
308
+ *************************************************************************/
309
+ void minlmresults(const lmstate& state, ap::real_1d_array& x, lmreport& rep);
310
+
311
+
312
+ #endif
@@ -0,0 +1,3375 @@
1
+ /*************************************************************************
2
+ Copyright (c) 2007-2008, Sergey Bochkanov (ALGLIB project).
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are
6
+ met:
7
+
8
+ - Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ - Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer listed
13
+ in this license in the documentation and/or other materials
14
+ provided with the distribution.
15
+
16
+ - Neither the name of the copyright holders nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ *************************************************************************/
32
+
33
+ #include <stdafx.h>
34
+ #include "mlpbase.h"
35
+
36
+ static const int mlpvnum = 7;
37
+ static const int nfieldwidth = 4;
38
+ static const int chunksize = 32;
39
+
40
+ static void addinputlayer(int ncount,
41
+ ap::integer_1d_array& lsizes,
42
+ ap::integer_1d_array& ltypes,
43
+ ap::integer_1d_array& lconnfirst,
44
+ ap::integer_1d_array& lconnlast,
45
+ int& lastproc);
46
+ static void addbiasedsummatorlayer(int ncount,
47
+ ap::integer_1d_array& lsizes,
48
+ ap::integer_1d_array& ltypes,
49
+ ap::integer_1d_array& lconnfirst,
50
+ ap::integer_1d_array& lconnlast,
51
+ int& lastproc);
52
+ static void addactivationlayer(int functype,
53
+ ap::integer_1d_array& lsizes,
54
+ ap::integer_1d_array& ltypes,
55
+ ap::integer_1d_array& lconnfirst,
56
+ ap::integer_1d_array& lconnlast,
57
+ int& lastproc);
58
+ static void addzerolayer(ap::integer_1d_array& lsizes,
59
+ ap::integer_1d_array& ltypes,
60
+ ap::integer_1d_array& lconnfirst,
61
+ ap::integer_1d_array& lconnlast,
62
+ int& lastproc);
63
+ static void mlpcreate(int nin,
64
+ int nout,
65
+ const ap::integer_1d_array& lsizes,
66
+ const ap::integer_1d_array& ltypes,
67
+ const ap::integer_1d_array& lconnfirst,
68
+ const ap::integer_1d_array& lconnlast,
69
+ int layerscount,
70
+ bool isclsnet,
71
+ multilayerperceptron& network);
72
+ static void mlpactivationfunction(double net,
73
+ int k,
74
+ double& f,
75
+ double& df,
76
+ double& d2f);
77
+ static void mlphessianbatchinternal(multilayerperceptron& network,
78
+ const ap::real_2d_array& xy,
79
+ int ssize,
80
+ bool naturalerr,
81
+ double& e,
82
+ ap::real_1d_array& grad,
83
+ ap::real_2d_array& h);
84
+ static void mlpinternalcalculategradient(multilayerperceptron& network,
85
+ const ap::real_1d_array& neurons,
86
+ const ap::real_1d_array& weights,
87
+ ap::real_1d_array& derror,
88
+ ap::real_1d_array& grad,
89
+ bool naturalerrorfunc);
90
+ static void mlpchunkedgradient(multilayerperceptron& network,
91
+ const ap::real_2d_array& xy,
92
+ int cstart,
93
+ int csize,
94
+ double& e,
95
+ ap::real_1d_array& grad,
96
+ bool naturalerrorfunc);
97
+ static double safecrossentropy(double t, double z);
98
+
99
+ /*************************************************************************
100
+ Creates neural network with NIn inputs, NOut outputs, without hidden
101
+ layers, with linear output layer. Network weights are filled with small
102
+ random values.
103
+
104
+ -- ALGLIB --
105
+ Copyright 04.11.2007 by Bochkanov Sergey
106
+ *************************************************************************/
107
+ void mlpcreate0(int nin, int nout, multilayerperceptron& network)
108
+ {
109
+ ap::integer_1d_array lsizes;
110
+ ap::integer_1d_array ltypes;
111
+ ap::integer_1d_array lconnfirst;
112
+ ap::integer_1d_array lconnlast;
113
+ int layerscount;
114
+ int lastproc;
115
+
116
+ layerscount = 1+2;
117
+
118
+ //
119
+ // Allocate arrays
120
+ //
121
+ lsizes.setbounds(0, layerscount-1);
122
+ ltypes.setbounds(0, layerscount-1);
123
+ lconnfirst.setbounds(0, layerscount-1);
124
+ lconnlast.setbounds(0, layerscount-1);
125
+
126
+ //
127
+ // Layers
128
+ //
129
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
130
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
131
+
132
+ //
133
+ // Create
134
+ //
135
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
136
+ }
137
+
138
+
139
+ /*************************************************************************
140
+ Same as MLPCreate0, but with one hidden layer (NHid neurons) with
141
+ non-linear activation function. Output layer is linear.
142
+
143
+ -- ALGLIB --
144
+ Copyright 04.11.2007 by Bochkanov Sergey
145
+ *************************************************************************/
146
+ void mlpcreate1(int nin, int nhid, int nout, multilayerperceptron& network)
147
+ {
148
+ ap::integer_1d_array lsizes;
149
+ ap::integer_1d_array ltypes;
150
+ ap::integer_1d_array lconnfirst;
151
+ ap::integer_1d_array lconnlast;
152
+ int layerscount;
153
+ int lastproc;
154
+
155
+ layerscount = 1+3+2;
156
+
157
+ //
158
+ // Allocate arrays
159
+ //
160
+ lsizes.setbounds(0, layerscount-1);
161
+ ltypes.setbounds(0, layerscount-1);
162
+ lconnfirst.setbounds(0, layerscount-1);
163
+ lconnlast.setbounds(0, layerscount-1);
164
+
165
+ //
166
+ // Layers
167
+ //
168
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
169
+ addbiasedsummatorlayer(nhid, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
170
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
171
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
172
+
173
+ //
174
+ // Create
175
+ //
176
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
177
+ }
178
+
179
+
180
+ /*************************************************************************
181
+ Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons)
182
+ with non-linear activation function. Output layer is linear.
183
+ $ALL
184
+
185
+ -- ALGLIB --
186
+ Copyright 04.11.2007 by Bochkanov Sergey
187
+ *************************************************************************/
188
+ void mlpcreate2(int nin,
189
+ int nhid1,
190
+ int nhid2,
191
+ int nout,
192
+ multilayerperceptron& network)
193
+ {
194
+ ap::integer_1d_array lsizes;
195
+ ap::integer_1d_array ltypes;
196
+ ap::integer_1d_array lconnfirst;
197
+ ap::integer_1d_array lconnlast;
198
+ int layerscount;
199
+ int lastproc;
200
+
201
+ layerscount = 1+3+3+2;
202
+
203
+ //
204
+ // Allocate arrays
205
+ //
206
+ lsizes.setbounds(0, layerscount-1);
207
+ ltypes.setbounds(0, layerscount-1);
208
+ lconnfirst.setbounds(0, layerscount-1);
209
+ lconnlast.setbounds(0, layerscount-1);
210
+
211
+ //
212
+ // Layers
213
+ //
214
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
215
+ addbiasedsummatorlayer(nhid1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
216
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
217
+ addbiasedsummatorlayer(nhid2, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
218
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
219
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
220
+
221
+ //
222
+ // Create
223
+ //
224
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
225
+ }
226
+
227
+
228
+ /*************************************************************************
229
+ Creates neural network with NIn inputs, NOut outputs, without hidden
230
+ layers with non-linear output layer. Network weights are filled with small
231
+ random values.
232
+
233
+ Activation function of the output layer takes values:
234
+
235
+ (B, +INF), if D>=0
236
+
237
+ or
238
+
239
+ (-INF, B), if D<0.
240
+
241
+
242
+ -- ALGLIB --
243
+ Copyright 30.03.2008 by Bochkanov Sergey
244
+ *************************************************************************/
245
+ void mlpcreateb0(int nin,
246
+ int nout,
247
+ double b,
248
+ double d,
249
+ multilayerperceptron& network)
250
+ {
251
+ ap::integer_1d_array lsizes;
252
+ ap::integer_1d_array ltypes;
253
+ ap::integer_1d_array lconnfirst;
254
+ ap::integer_1d_array lconnlast;
255
+ int layerscount;
256
+ int lastproc;
257
+ int i;
258
+
259
+ layerscount = 1+3;
260
+ if( d>=0 )
261
+ {
262
+ d = 1;
263
+ }
264
+ else
265
+ {
266
+ d = -1;
267
+ }
268
+
269
+ //
270
+ // Allocate arrays
271
+ //
272
+ lsizes.setbounds(0, layerscount-1);
273
+ ltypes.setbounds(0, layerscount-1);
274
+ lconnfirst.setbounds(0, layerscount-1);
275
+ lconnlast.setbounds(0, layerscount-1);
276
+
277
+ //
278
+ // Layers
279
+ //
280
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
281
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
282
+ addactivationlayer(3, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
283
+
284
+ //
285
+ // Create
286
+ //
287
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
288
+
289
+ //
290
+ // Turn on ouputs shift/scaling.
291
+ //
292
+ for(i = nin; i <= nin+nout-1; i++)
293
+ {
294
+ network.columnmeans(i) = b;
295
+ network.columnsigmas(i) = d;
296
+ }
297
+ }
298
+
299
+
300
+ /*************************************************************************
301
+ Same as MLPCreateB0 but with non-linear hidden layer.
302
+
303
+ -- ALGLIB --
304
+ Copyright 30.03.2008 by Bochkanov Sergey
305
+ *************************************************************************/
306
+ void mlpcreateb1(int nin,
307
+ int nhid,
308
+ int nout,
309
+ double b,
310
+ double d,
311
+ multilayerperceptron& network)
312
+ {
313
+ ap::integer_1d_array lsizes;
314
+ ap::integer_1d_array ltypes;
315
+ ap::integer_1d_array lconnfirst;
316
+ ap::integer_1d_array lconnlast;
317
+ int layerscount;
318
+ int lastproc;
319
+ int i;
320
+
321
+ layerscount = 1+3+3;
322
+ if( d>=0 )
323
+ {
324
+ d = 1;
325
+ }
326
+ else
327
+ {
328
+ d = -1;
329
+ }
330
+
331
+ //
332
+ // Allocate arrays
333
+ //
334
+ lsizes.setbounds(0, layerscount-1);
335
+ ltypes.setbounds(0, layerscount-1);
336
+ lconnfirst.setbounds(0, layerscount-1);
337
+ lconnlast.setbounds(0, layerscount-1);
338
+
339
+ //
340
+ // Layers
341
+ //
342
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
343
+ addbiasedsummatorlayer(nhid, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
344
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
345
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
346
+ addactivationlayer(3, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
347
+
348
+ //
349
+ // Create
350
+ //
351
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
352
+
353
+ //
354
+ // Turn on ouputs shift/scaling.
355
+ //
356
+ for(i = nin; i <= nin+nout-1; i++)
357
+ {
358
+ network.columnmeans(i) = b;
359
+ network.columnsigmas(i) = d;
360
+ }
361
+ }
362
+
363
+
364
+ /*************************************************************************
365
+ Same as MLPCreateB0 but with two non-linear hidden layers.
366
+
367
+ -- ALGLIB --
368
+ Copyright 30.03.2008 by Bochkanov Sergey
369
+ *************************************************************************/
370
+ void mlpcreateb2(int nin,
371
+ int nhid1,
372
+ int nhid2,
373
+ int nout,
374
+ double b,
375
+ double d,
376
+ multilayerperceptron& network)
377
+ {
378
+ ap::integer_1d_array lsizes;
379
+ ap::integer_1d_array ltypes;
380
+ ap::integer_1d_array lconnfirst;
381
+ ap::integer_1d_array lconnlast;
382
+ int layerscount;
383
+ int lastproc;
384
+ int i;
385
+
386
+ layerscount = 1+3+3+3;
387
+ if( d>=0 )
388
+ {
389
+ d = 1;
390
+ }
391
+ else
392
+ {
393
+ d = -1;
394
+ }
395
+
396
+ //
397
+ // Allocate arrays
398
+ //
399
+ lsizes.setbounds(0, layerscount-1);
400
+ ltypes.setbounds(0, layerscount-1);
401
+ lconnfirst.setbounds(0, layerscount-1);
402
+ lconnlast.setbounds(0, layerscount-1);
403
+
404
+ //
405
+ // Layers
406
+ //
407
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
408
+ addbiasedsummatorlayer(nhid1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
409
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
410
+ addbiasedsummatorlayer(nhid2, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
411
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
412
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
413
+ addactivationlayer(3, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
414
+
415
+ //
416
+ // Create
417
+ //
418
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
419
+
420
+ //
421
+ // Turn on ouputs shift/scaling.
422
+ //
423
+ for(i = nin; i <= nin+nout-1; i++)
424
+ {
425
+ network.columnmeans(i) = b;
426
+ network.columnsigmas(i) = d;
427
+ }
428
+ }
429
+
430
+
431
+ /*************************************************************************
432
+ Creates neural network with NIn inputs, NOut outputs, without hidden
433
+ layers with non-linear output layer. Network weights are filled with small
434
+ random values. Activation function of the output layer takes values [A,B].
435
+
436
+ -- ALGLIB --
437
+ Copyright 30.03.2008 by Bochkanov Sergey
438
+ *************************************************************************/
439
+ void mlpcreater0(int nin,
440
+ int nout,
441
+ double a,
442
+ double b,
443
+ multilayerperceptron& network)
444
+ {
445
+ ap::integer_1d_array lsizes;
446
+ ap::integer_1d_array ltypes;
447
+ ap::integer_1d_array lconnfirst;
448
+ ap::integer_1d_array lconnlast;
449
+ int layerscount;
450
+ int lastproc;
451
+ int i;
452
+
453
+ layerscount = 1+3;
454
+
455
+ //
456
+ // Allocate arrays
457
+ //
458
+ lsizes.setbounds(0, layerscount-1);
459
+ ltypes.setbounds(0, layerscount-1);
460
+ lconnfirst.setbounds(0, layerscount-1);
461
+ lconnlast.setbounds(0, layerscount-1);
462
+
463
+ //
464
+ // Layers
465
+ //
466
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
467
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
468
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
469
+
470
+ //
471
+ // Create
472
+ //
473
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
474
+
475
+ //
476
+ // Turn on outputs shift/scaling.
477
+ //
478
+ for(i = nin; i <= nin+nout-1; i++)
479
+ {
480
+ network.columnmeans(i) = 0.5*(a+b);
481
+ network.columnsigmas(i) = 0.5*(a-b);
482
+ }
483
+ }
484
+
485
+
486
+ /*************************************************************************
487
+ Same as MLPCreateR0, but with non-linear hidden layer.
488
+
489
+ -- ALGLIB --
490
+ Copyright 30.03.2008 by Bochkanov Sergey
491
+ *************************************************************************/
492
+ void mlpcreater1(int nin,
493
+ int nhid,
494
+ int nout,
495
+ double a,
496
+ double b,
497
+ multilayerperceptron& network)
498
+ {
499
+ ap::integer_1d_array lsizes;
500
+ ap::integer_1d_array ltypes;
501
+ ap::integer_1d_array lconnfirst;
502
+ ap::integer_1d_array lconnlast;
503
+ int layerscount;
504
+ int lastproc;
505
+ int i;
506
+
507
+ layerscount = 1+3+3;
508
+
509
+ //
510
+ // Allocate arrays
511
+ //
512
+ lsizes.setbounds(0, layerscount-1);
513
+ ltypes.setbounds(0, layerscount-1);
514
+ lconnfirst.setbounds(0, layerscount-1);
515
+ lconnlast.setbounds(0, layerscount-1);
516
+
517
+ //
518
+ // Layers
519
+ //
520
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
521
+ addbiasedsummatorlayer(nhid, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
522
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
523
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
524
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
525
+
526
+ //
527
+ // Create
528
+ //
529
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
530
+
531
+ //
532
+ // Turn on outputs shift/scaling.
533
+ //
534
+ for(i = nin; i <= nin+nout-1; i++)
535
+ {
536
+ network.columnmeans(i) = 0.5*(a+b);
537
+ network.columnsigmas(i) = 0.5*(a-b);
538
+ }
539
+ }
540
+
541
+
542
+ /*************************************************************************
543
+ Same as MLPCreateR0, but with two non-linear hidden layers.
544
+
545
+ -- ALGLIB --
546
+ Copyright 30.03.2008 by Bochkanov Sergey
547
+ *************************************************************************/
548
+ void mlpcreater2(int nin,
549
+ int nhid1,
550
+ int nhid2,
551
+ int nout,
552
+ double a,
553
+ double b,
554
+ multilayerperceptron& network)
555
+ {
556
+ ap::integer_1d_array lsizes;
557
+ ap::integer_1d_array ltypes;
558
+ ap::integer_1d_array lconnfirst;
559
+ ap::integer_1d_array lconnlast;
560
+ int layerscount;
561
+ int lastproc;
562
+ int i;
563
+
564
+ layerscount = 1+3+3+3;
565
+
566
+ //
567
+ // Allocate arrays
568
+ //
569
+ lsizes.setbounds(0, layerscount-1);
570
+ ltypes.setbounds(0, layerscount-1);
571
+ lconnfirst.setbounds(0, layerscount-1);
572
+ lconnlast.setbounds(0, layerscount-1);
573
+
574
+ //
575
+ // Layers
576
+ //
577
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
578
+ addbiasedsummatorlayer(nhid1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
579
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
580
+ addbiasedsummatorlayer(nhid2, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
581
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
582
+ addbiasedsummatorlayer(nout, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
583
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
584
+
585
+ //
586
+ // Create
587
+ //
588
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, false, network);
589
+
590
+ //
591
+ // Turn on outputs shift/scaling.
592
+ //
593
+ for(i = nin; i <= nin+nout-1; i++)
594
+ {
595
+ network.columnmeans(i) = 0.5*(a+b);
596
+ network.columnsigmas(i) = 0.5*(a-b);
597
+ }
598
+ }
599
+
600
+
601
+ /*************************************************************************
602
+ Creates classifier network with NIn inputs and NOut possible classes.
603
+ Network contains no hidden layers and linear output layer with SOFTMAX-
604
+ normalization (so outputs sums up to 1.0 and converge to posterior
605
+ probabilities).
606
+
607
+ -- ALGLIB --
608
+ Copyright 04.11.2007 by Bochkanov Sergey
609
+ *************************************************************************/
610
+ void mlpcreatec0(int nin, int nout, multilayerperceptron& network)
611
+ {
612
+ ap::integer_1d_array lsizes;
613
+ ap::integer_1d_array ltypes;
614
+ ap::integer_1d_array lconnfirst;
615
+ ap::integer_1d_array lconnlast;
616
+ int layerscount;
617
+ int lastproc;
618
+
619
+ ap::ap_error::make_assertion(nout>=2, "MLPCreateC0: NOut<2!");
620
+ layerscount = 1+2+1;
621
+
622
+ //
623
+ // Allocate arrays
624
+ //
625
+ lsizes.setbounds(0, layerscount-1);
626
+ ltypes.setbounds(0, layerscount-1);
627
+ lconnfirst.setbounds(0, layerscount-1);
628
+ lconnlast.setbounds(0, layerscount-1);
629
+
630
+ //
631
+ // Layers
632
+ //
633
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
634
+ addbiasedsummatorlayer(nout-1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
635
+ addzerolayer(lsizes, ltypes, lconnfirst, lconnlast, lastproc);
636
+
637
+ //
638
+ // Create
639
+ //
640
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, true, network);
641
+ }
642
+
643
+
644
+ /*************************************************************************
645
+ Same as MLPCreateC0, but with one non-linear hidden layer.
646
+
647
+ -- ALGLIB --
648
+ Copyright 04.11.2007 by Bochkanov Sergey
649
+ *************************************************************************/
650
+ void mlpcreatec1(int nin, int nhid, int nout, multilayerperceptron& network)
651
+ {
652
+ ap::integer_1d_array lsizes;
653
+ ap::integer_1d_array ltypes;
654
+ ap::integer_1d_array lconnfirst;
655
+ ap::integer_1d_array lconnlast;
656
+ int layerscount;
657
+ int lastproc;
658
+
659
+ ap::ap_error::make_assertion(nout>=2, "MLPCreateC1: NOut<2!");
660
+ layerscount = 1+3+2+1;
661
+
662
+ //
663
+ // Allocate arrays
664
+ //
665
+ lsizes.setbounds(0, layerscount-1);
666
+ ltypes.setbounds(0, layerscount-1);
667
+ lconnfirst.setbounds(0, layerscount-1);
668
+ lconnlast.setbounds(0, layerscount-1);
669
+
670
+ //
671
+ // Layers
672
+ //
673
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
674
+ addbiasedsummatorlayer(nhid, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
675
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
676
+ addbiasedsummatorlayer(nout-1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
677
+ addzerolayer(lsizes, ltypes, lconnfirst, lconnlast, lastproc);
678
+
679
+ //
680
+ // Create
681
+ //
682
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, true, network);
683
+ }
684
+
685
+
686
+ /*************************************************************************
687
+ Same as MLPCreateC0, but with two non-linear hidden layers.
688
+
689
+ -- ALGLIB --
690
+ Copyright 04.11.2007 by Bochkanov Sergey
691
+ *************************************************************************/
692
+ void mlpcreatec2(int nin,
693
+ int nhid1,
694
+ int nhid2,
695
+ int nout,
696
+ multilayerperceptron& network)
697
+ {
698
+ ap::integer_1d_array lsizes;
699
+ ap::integer_1d_array ltypes;
700
+ ap::integer_1d_array lconnfirst;
701
+ ap::integer_1d_array lconnlast;
702
+ int layerscount;
703
+ int lastproc;
704
+
705
+ ap::ap_error::make_assertion(nout>=2, "MLPCreateC2: NOut<2!");
706
+ layerscount = 1+3+3+2+1;
707
+
708
+ //
709
+ // Allocate arrays
710
+ //
711
+ lsizes.setbounds(0, layerscount-1);
712
+ ltypes.setbounds(0, layerscount-1);
713
+ lconnfirst.setbounds(0, layerscount-1);
714
+ lconnlast.setbounds(0, layerscount-1);
715
+
716
+ //
717
+ // Layers
718
+ //
719
+ addinputlayer(nin, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
720
+ addbiasedsummatorlayer(nhid1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
721
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
722
+ addbiasedsummatorlayer(nhid2, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
723
+ addactivationlayer(1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
724
+ addbiasedsummatorlayer(nout-1, lsizes, ltypes, lconnfirst, lconnlast, lastproc);
725
+ addzerolayer(lsizes, ltypes, lconnfirst, lconnlast, lastproc);
726
+
727
+ //
728
+ // Create
729
+ //
730
+ mlpcreate(nin, nout, lsizes, ltypes, lconnfirst, lconnlast, layerscount, true, network);
731
+ }
732
+
733
+
734
+ /*************************************************************************
735
+ Copying of neural network
736
+
737
+ INPUT PARAMETERS:
738
+ Network1 - original
739
+
740
+ OUTPUT PARAMETERS:
741
+ Network2 - copy
742
+
743
+ -- ALGLIB --
744
+ Copyright 04.11.2007 by Bochkanov Sergey
745
+ *************************************************************************/
746
+ void mlpcopy(const multilayerperceptron& network1,
747
+ multilayerperceptron& network2)
748
+ {
749
+ int i;
750
+ int ssize;
751
+ int ntotal;
752
+ int nin;
753
+ int nout;
754
+ int wcount;
755
+
756
+
757
+ //
758
+ // Unload info
759
+ //
760
+ ssize = network1.structinfo(0);
761
+ nin = network1.structinfo(1);
762
+ nout = network1.structinfo(2);
763
+ ntotal = network1.structinfo(3);
764
+ wcount = network1.structinfo(4);
765
+
766
+ //
767
+ // Allocate space
768
+ //
769
+ network2.structinfo.setbounds(0, ssize-1);
770
+ network2.weights.setbounds(0, wcount-1);
771
+ if( mlpissoftmax(network1) )
772
+ {
773
+ network2.columnmeans.setbounds(0, nin-1);
774
+ network2.columnsigmas.setbounds(0, nin-1);
775
+ }
776
+ else
777
+ {
778
+ network2.columnmeans.setbounds(0, nin+nout-1);
779
+ network2.columnsigmas.setbounds(0, nin+nout-1);
780
+ }
781
+ network2.neurons.setbounds(0, ntotal-1);
782
+ network2.chunks.setbounds(0, 3*ntotal, 0, chunksize-1);
783
+ network2.nwbuf.setbounds(0, ap::maxint(wcount, 2*nout)-1);
784
+ network2.dfdnet.setbounds(0, ntotal-1);
785
+ network2.x.setbounds(0, nin-1);
786
+ network2.y.setbounds(0, nout-1);
787
+ network2.derror.setbounds(0, ntotal-1);
788
+
789
+ //
790
+ // Copy
791
+ //
792
+ for(i = 0; i <= ssize-1; i++)
793
+ {
794
+ network2.structinfo(i) = network1.structinfo(i);
795
+ }
796
+ ap::vmove(&network2.weights(0), &network1.weights(0), ap::vlen(0,wcount-1));
797
+ if( mlpissoftmax(network1) )
798
+ {
799
+ ap::vmove(&network2.columnmeans(0), &network1.columnmeans(0), ap::vlen(0,nin-1));
800
+ ap::vmove(&network2.columnsigmas(0), &network1.columnsigmas(0), ap::vlen(0,nin-1));
801
+ }
802
+ else
803
+ {
804
+ ap::vmove(&network2.columnmeans(0), &network1.columnmeans(0), ap::vlen(0,nin+nout-1));
805
+ ap::vmove(&network2.columnsigmas(0), &network1.columnsigmas(0), ap::vlen(0,nin+nout-1));
806
+ }
807
+ ap::vmove(&network2.neurons(0), &network1.neurons(0), ap::vlen(0,ntotal-1));
808
+ ap::vmove(&network2.dfdnet(0), &network1.dfdnet(0), ap::vlen(0,ntotal-1));
809
+ ap::vmove(&network2.x(0), &network1.x(0), ap::vlen(0,nin-1));
810
+ ap::vmove(&network2.y(0), &network1.y(0), ap::vlen(0,nout-1));
811
+ ap::vmove(&network2.derror(0), &network1.derror(0), ap::vlen(0,ntotal-1));
812
+ }
813
+
814
+
815
+ /*************************************************************************
816
+ Serialization of MultiLayerPerceptron strucure
817
+
818
+ INPUT PARAMETERS:
819
+ Network - original
820
+
821
+ OUTPUT PARAMETERS:
822
+ RA - array of real numbers which stores network,
823
+ array[0..RLen-1]
824
+ RLen - RA lenght
825
+
826
+ -- ALGLIB --
827
+ Copyright 29.03.2008 by Bochkanov Sergey
828
+ *************************************************************************/
829
+ void mlpserialize(const multilayerperceptron& network,
830
+ ap::real_1d_array& ra,
831
+ int& rlen)
832
+ {
833
+ int i;
834
+ int ssize;
835
+ int ntotal;
836
+ int nin;
837
+ int nout;
838
+ int wcount;
839
+ int sigmalen;
840
+ int offs;
841
+
842
+
843
+ //
844
+ // Unload info
845
+ //
846
+ ssize = network.structinfo(0);
847
+ nin = network.structinfo(1);
848
+ nout = network.structinfo(2);
849
+ ntotal = network.structinfo(3);
850
+ wcount = network.structinfo(4);
851
+ if( mlpissoftmax(network) )
852
+ {
853
+ sigmalen = nin;
854
+ }
855
+ else
856
+ {
857
+ sigmalen = nin+nout;
858
+ }
859
+
860
+ //
861
+ // RA format:
862
+ // LEN DESRC.
863
+ // 1 RLen
864
+ // 1 version (MLPVNum)
865
+ // 1 StructInfo size
866
+ // SSize StructInfo
867
+ // WCount Weights
868
+ // SigmaLen ColumnMeans
869
+ // SigmaLen ColumnSigmas
870
+ //
871
+ rlen = 3+ssize+wcount+2*sigmalen;
872
+ ra.setbounds(0, rlen-1);
873
+ ra(0) = rlen;
874
+ ra(1) = mlpvnum;
875
+ ra(2) = ssize;
876
+ offs = 3;
877
+ for(i = 0; i <= ssize-1; i++)
878
+ {
879
+ ra(offs+i) = network.structinfo(i);
880
+ }
881
+ offs = offs+ssize;
882
+ ap::vmove(&ra(offs), &network.weights(0), ap::vlen(offs,offs+wcount-1));
883
+ offs = offs+wcount;
884
+ ap::vmove(&ra(offs), &network.columnmeans(0), ap::vlen(offs,offs+sigmalen-1));
885
+ offs = offs+sigmalen;
886
+ ap::vmove(&ra(offs), &network.columnsigmas(0), ap::vlen(offs,offs+sigmalen-1));
887
+ offs = offs+sigmalen;
888
+ }
889
+
890
+
891
+ /*************************************************************************
892
+ Unserialization of MultiLayerPerceptron strucure
893
+
894
+ INPUT PARAMETERS:
895
+ RA - real array which stores network
896
+
897
+ OUTPUT PARAMETERS:
898
+ Network - restored network
899
+
900
+ -- ALGLIB --
901
+ Copyright 29.03.2008 by Bochkanov Sergey
902
+ *************************************************************************/
903
+ void mlpunserialize(const ap::real_1d_array& ra,
904
+ multilayerperceptron& network)
905
+ {
906
+ int i;
907
+ int ssize;
908
+ int ntotal;
909
+ int nin;
910
+ int nout;
911
+ int wcount;
912
+ int sigmalen;
913
+ int offs;
914
+
915
+ ap::ap_error::make_assertion(ap::round(ra(1))==mlpvnum, "MLPUnserialize: incorrect array!");
916
+
917
+ //
918
+ // Unload StructInfo from IA
919
+ //
920
+ offs = 3;
921
+ ssize = ap::round(ra(2));
922
+ network.structinfo.setbounds(0, ssize-1);
923
+ for(i = 0; i <= ssize-1; i++)
924
+ {
925
+ network.structinfo(i) = ap::round(ra(offs+i));
926
+ }
927
+ offs = offs+ssize;
928
+
929
+ //
930
+ // Unload info from StructInfo
931
+ //
932
+ ssize = network.structinfo(0);
933
+ nin = network.structinfo(1);
934
+ nout = network.structinfo(2);
935
+ ntotal = network.structinfo(3);
936
+ wcount = network.structinfo(4);
937
+ if( network.structinfo(6)==0 )
938
+ {
939
+ sigmalen = nin+nout;
940
+ }
941
+ else
942
+ {
943
+ sigmalen = nin;
944
+ }
945
+
946
+ //
947
+ // Allocate space for other fields
948
+ //
949
+ network.weights.setbounds(0, wcount-1);
950
+ network.columnmeans.setbounds(0, sigmalen-1);
951
+ network.columnsigmas.setbounds(0, sigmalen-1);
952
+ network.neurons.setbounds(0, ntotal-1);
953
+ network.chunks.setbounds(0, 3*ntotal, 0, chunksize-1);
954
+ network.nwbuf.setbounds(0, ap::maxint(wcount, 2*nout)-1);
955
+ network.dfdnet.setbounds(0, ntotal-1);
956
+ network.x.setbounds(0, nin-1);
957
+ network.y.setbounds(0, nout-1);
958
+ network.derror.setbounds(0, ntotal-1);
959
+
960
+ //
961
+ // Copy parameters from RA
962
+ //
963
+ ap::vmove(&network.weights(0), &ra(offs), ap::vlen(0,wcount-1));
964
+ offs = offs+wcount;
965
+ ap::vmove(&network.columnmeans(0), &ra(offs), ap::vlen(0,sigmalen-1));
966
+ offs = offs+sigmalen;
967
+ ap::vmove(&network.columnsigmas(0), &ra(offs), ap::vlen(0,sigmalen-1));
968
+ offs = offs+sigmalen;
969
+ }
970
+
971
+
972
+ /*************************************************************************
973
+ Randomization of neural network weights
974
+
975
+ -- ALGLIB --
976
+ Copyright 06.11.2007 by Bochkanov Sergey
977
+ *************************************************************************/
978
+ void mlprandomize(multilayerperceptron& network)
979
+ {
980
+ int i;
981
+ int nin;
982
+ int nout;
983
+ int wcount;
984
+
985
+ mlpproperties(network, nin, nout, wcount);
986
+ for(i = 0; i <= wcount-1; i++)
987
+ {
988
+ network.weights(i) = ap::randomreal()-0.5;
989
+ }
990
+ }
991
+
992
+
993
+ /*************************************************************************
994
+ Randomization of neural network weights and standartisator
995
+
996
+ -- ALGLIB --
997
+ Copyright 10.03.2008 by Bochkanov Sergey
998
+ *************************************************************************/
999
+ void mlprandomizefull(multilayerperceptron& network)
1000
+ {
1001
+ int i;
1002
+ int nin;
1003
+ int nout;
1004
+ int wcount;
1005
+ int ntotal;
1006
+ int istart;
1007
+ int offs;
1008
+ int ntype;
1009
+
1010
+ mlpproperties(network, nin, nout, wcount);
1011
+ ntotal = network.structinfo(3);
1012
+ istart = network.structinfo(5);
1013
+
1014
+ //
1015
+ // Process network
1016
+ //
1017
+ for(i = 0; i <= wcount-1; i++)
1018
+ {
1019
+ network.weights(i) = ap::randomreal()-0.5;
1020
+ }
1021
+ for(i = 0; i <= nin-1; i++)
1022
+ {
1023
+ network.columnmeans(i) = 2*ap::randomreal()-1;
1024
+ network.columnsigmas(i) = 1.5*ap::randomreal()+0.5;
1025
+ }
1026
+ if( !mlpissoftmax(network) )
1027
+ {
1028
+ for(i = 0; i <= nout-1; i++)
1029
+ {
1030
+ offs = istart+(ntotal-nout+i)*nfieldwidth;
1031
+ ntype = network.structinfo(offs+0);
1032
+ if( ntype==0 )
1033
+ {
1034
+
1035
+ //
1036
+ // Shifts are changed only for linear outputs neurons
1037
+ //
1038
+ network.columnmeans(nin+i) = 2*ap::randomreal()-1;
1039
+ }
1040
+ if( ntype==0||ntype==3 )
1041
+ {
1042
+
1043
+ //
1044
+ // Scales are changed only for linear or bounded outputs neurons.
1045
+ // Note that scale randomization preserves sign.
1046
+ //
1047
+ network.columnsigmas(nin+i) = ap::sign(network.columnsigmas(nin+i))*(1.5*ap::randomreal()+0.5);
1048
+ }
1049
+ }
1050
+ }
1051
+ }
1052
+
1053
+
1054
+ /*************************************************************************
1055
+ Internal subroutine.
1056
+
1057
+ -- ALGLIB --
1058
+ Copyright 30.03.2008 by Bochkanov Sergey
1059
+ *************************************************************************/
1060
+ void mlpinitpreprocessor(multilayerperceptron& network,
1061
+ const ap::real_2d_array& xy,
1062
+ int ssize)
1063
+ {
1064
+ int i;
1065
+ int j;
1066
+ int jmax;
1067
+ int nin;
1068
+ int nout;
1069
+ int wcount;
1070
+ int ntotal;
1071
+ int istart;
1072
+ int offs;
1073
+ int ntype;
1074
+ ap::real_1d_array means;
1075
+ ap::real_1d_array sigmas;
1076
+ double s;
1077
+
1078
+ mlpproperties(network, nin, nout, wcount);
1079
+ ntotal = network.structinfo(3);
1080
+ istart = network.structinfo(5);
1081
+
1082
+ //
1083
+ // Means/Sigmas
1084
+ //
1085
+ if( mlpissoftmax(network) )
1086
+ {
1087
+ jmax = nin-1;
1088
+ }
1089
+ else
1090
+ {
1091
+ jmax = nin+nout-1;
1092
+ }
1093
+ means.setbounds(0, jmax);
1094
+ sigmas.setbounds(0, jmax);
1095
+ for(j = 0; j <= jmax; j++)
1096
+ {
1097
+ means(j) = 0;
1098
+ for(i = 0; i <= ssize-1; i++)
1099
+ {
1100
+ means(j) = means(j)+xy(i,j);
1101
+ }
1102
+ means(j) = means(j)/ssize;
1103
+ sigmas(j) = 0;
1104
+ for(i = 0; i <= ssize-1; i++)
1105
+ {
1106
+ sigmas(j) = sigmas(j)+ap::sqr(xy(i,j)-means(j));
1107
+ }
1108
+ sigmas(j) = sqrt(sigmas(j)/ssize);
1109
+ }
1110
+
1111
+ //
1112
+ // Inputs
1113
+ //
1114
+ for(i = 0; i <= nin-1; i++)
1115
+ {
1116
+ network.columnmeans(i) = means(i);
1117
+ network.columnsigmas(i) = sigmas(i);
1118
+ if( network.columnsigmas(i)==0 )
1119
+ {
1120
+ network.columnsigmas(i) = 1;
1121
+ }
1122
+ }
1123
+
1124
+ //
1125
+ // Outputs
1126
+ //
1127
+ if( !mlpissoftmax(network) )
1128
+ {
1129
+ for(i = 0; i <= nout-1; i++)
1130
+ {
1131
+ offs = istart+(ntotal-nout+i)*nfieldwidth;
1132
+ ntype = network.structinfo(offs+0);
1133
+
1134
+ //
1135
+ // Linear outputs
1136
+ //
1137
+ if( ntype==0 )
1138
+ {
1139
+ network.columnmeans(nin+i) = means(nin+i);
1140
+ network.columnsigmas(nin+i) = sigmas(nin+i);
1141
+ if( network.columnsigmas(nin+i)==0 )
1142
+ {
1143
+ network.columnsigmas(nin+i) = 1;
1144
+ }
1145
+ }
1146
+
1147
+ //
1148
+ // Bounded outputs (half-interval)
1149
+ //
1150
+ if( ntype==3 )
1151
+ {
1152
+ s = means(nin+i)-network.columnmeans(nin+i);
1153
+ if( s==0 )
1154
+ {
1155
+ s = ap::sign(network.columnsigmas(nin+i));
1156
+ }
1157
+ if( s==0 )
1158
+ {
1159
+ s = 1.0;
1160
+ }
1161
+ network.columnsigmas(nin+i) = ap::sign(network.columnsigmas(nin+i))*fabs(s);
1162
+ if( network.columnsigmas(nin+i)==0 )
1163
+ {
1164
+ network.columnsigmas(nin+i) = 1;
1165
+ }
1166
+ }
1167
+ }
1168
+ }
1169
+ }
1170
+
1171
+
1172
+ /*************************************************************************
1173
+ Returns information about initialized network: number of inputs, outputs,
1174
+ weights.
1175
+
1176
+ -- ALGLIB --
1177
+ Copyright 04.11.2007 by Bochkanov Sergey
1178
+ *************************************************************************/
1179
+ void mlpproperties(const multilayerperceptron& network,
1180
+ int& nin,
1181
+ int& nout,
1182
+ int& wcount)
1183
+ {
1184
+
1185
+ nin = network.structinfo(1);
1186
+ nout = network.structinfo(2);
1187
+ wcount = network.structinfo(4);
1188
+ }
1189
+
1190
+
1191
+ /*************************************************************************
1192
+ Tells whether network is SOFTMAX-normalized (i.e. classifier) or not.
1193
+
1194
+ -- ALGLIB --
1195
+ Copyright 04.11.2007 by Bochkanov Sergey
1196
+ *************************************************************************/
1197
+ bool mlpissoftmax(const multilayerperceptron& network)
1198
+ {
1199
+ bool result;
1200
+
1201
+ result = network.structinfo(6)==1;
1202
+ return result;
1203
+ }
1204
+
1205
+
1206
+ /*************************************************************************
1207
+ Procesing
1208
+
1209
+ INPUT PARAMETERS:
1210
+ Network - neural network
1211
+ X - input vector, array[0..NIn-1].
1212
+
1213
+ OUTPUT PARAMETERS:
1214
+ Y - result. Regression estimate when solving regression task,
1215
+ vector of posterior probabilities for classification task.
1216
+ Subroutine does not allocate memory for this vector, it is
1217
+ responsibility of a caller to allocate it. Array must be
1218
+ at least [0..NOut-1].
1219
+
1220
+ -- ALGLIB --
1221
+ Copyright 04.11.2007 by Bochkanov Sergey
1222
+ *************************************************************************/
1223
+ void mlpprocess(multilayerperceptron& network,
1224
+ const ap::real_1d_array& x,
1225
+ ap::real_1d_array& y)
1226
+ {
1227
+
1228
+ mlpinternalprocessvector(network.structinfo, network.weights, network.columnmeans, network.columnsigmas, network.neurons, network.dfdnet, x, y);
1229
+ }
1230
+
1231
+
1232
+ /*************************************************************************
1233
+ Error function for neural network, internal subroutine.
1234
+
1235
+ -- ALGLIB --
1236
+ Copyright 04.11.2007 by Bochkanov Sergey
1237
+ *************************************************************************/
1238
+ double mlperror(multilayerperceptron& network,
1239
+ const ap::real_2d_array& xy,
1240
+ int ssize)
1241
+ {
1242
+ double result;
1243
+ int i;
1244
+ int k;
1245
+ int nin;
1246
+ int nout;
1247
+ int wcount;
1248
+ double e;
1249
+
1250
+ mlpproperties(network, nin, nout, wcount);
1251
+ result = 0;
1252
+ for(i = 0; i <= ssize-1; i++)
1253
+ {
1254
+ ap::vmove(&network.x(0), &xy(i, 0), ap::vlen(0,nin-1));
1255
+ mlpprocess(network, network.x, network.y);
1256
+ if( mlpissoftmax(network) )
1257
+ {
1258
+
1259
+ //
1260
+ // class labels outputs
1261
+ //
1262
+ k = ap::round(xy(i,nin));
1263
+ if( k>=0&&k<nout )
1264
+ {
1265
+ network.y(k) = network.y(k)-1;
1266
+ }
1267
+ }
1268
+ else
1269
+ {
1270
+
1271
+ //
1272
+ // real outputs
1273
+ //
1274
+ ap::vsub(&network.y(0), &xy(i, nin), ap::vlen(0,nout-1));
1275
+ }
1276
+ e = ap::vdotproduct(&network.y(0), &network.y(0), ap::vlen(0,nout-1));
1277
+ result = result+e/2;
1278
+ }
1279
+ return result;
1280
+ }
1281
+
1282
+
1283
+ /*************************************************************************
1284
+ Natural error function for neural network, internal subroutine.
1285
+
1286
+ -- ALGLIB --
1287
+ Copyright 04.11.2007 by Bochkanov Sergey
1288
+ *************************************************************************/
1289
+ double mlperrorn(multilayerperceptron& network,
1290
+ const ap::real_2d_array& xy,
1291
+ int ssize)
1292
+ {
1293
+ double result;
1294
+ int i;
1295
+ int j;
1296
+ int k;
1297
+ int nin;
1298
+ int nout;
1299
+ int wcount;
1300
+ double e;
1301
+ double t;
1302
+ double z;
1303
+
1304
+ mlpproperties(network, nin, nout, wcount);
1305
+ result = 0;
1306
+ for(i = 0; i <= ssize-1; i++)
1307
+ {
1308
+
1309
+ //
1310
+ // Process vector
1311
+ //
1312
+ ap::vmove(&network.x(0), &xy(i, 0), ap::vlen(0,nin-1));
1313
+ mlpprocess(network, network.x, network.y);
1314
+
1315
+ //
1316
+ // Update error function
1317
+ //
1318
+ if( network.structinfo(6)==0 )
1319
+ {
1320
+
1321
+ //
1322
+ // Least squares error function
1323
+ //
1324
+ ap::vsub(&network.y(0), &xy(i, nin), ap::vlen(0,nout-1));
1325
+ e = ap::vdotproduct(&network.y(0), &network.y(0), ap::vlen(0,nout-1));
1326
+ result = result+e/2;
1327
+ }
1328
+ else
1329
+ {
1330
+
1331
+ //
1332
+ // Cross-entropy error function
1333
+ //
1334
+ k = ap::round(xy(i,nin));
1335
+ if( k>=0&&k<nout )
1336
+ {
1337
+ result = result+safecrossentropy(double(1), network.y(k));
1338
+ }
1339
+ }
1340
+ }
1341
+ return result;
1342
+ }
1343
+
1344
+
1345
+ /*************************************************************************
1346
+ Classification error
1347
+
1348
+ -- ALGLIB --
1349
+ Copyright 04.11.2007 by Bochkanov Sergey
1350
+ *************************************************************************/
1351
+ int mlpclserror(multilayerperceptron& network,
1352
+ const ap::real_2d_array& xy,
1353
+ int ssize)
1354
+ {
1355
+ int result;
1356
+ int i;
1357
+ int j;
1358
+ int nin;
1359
+ int nout;
1360
+ int wcount;
1361
+ ap::real_1d_array workx;
1362
+ ap::real_1d_array worky;
1363
+ int nn;
1364
+ int ns;
1365
+ int nmax;
1366
+
1367
+ mlpproperties(network, nin, nout, wcount);
1368
+ workx.setbounds(0, nin-1);
1369
+ worky.setbounds(0, nout-1);
1370
+ result = 0;
1371
+ for(i = 0; i <= ssize-1; i++)
1372
+ {
1373
+
1374
+ //
1375
+ // Process
1376
+ //
1377
+ ap::vmove(&workx(0), &xy(i, 0), ap::vlen(0,nin-1));
1378
+ mlpprocess(network, workx, worky);
1379
+
1380
+ //
1381
+ // Network version of the answer
1382
+ //
1383
+ nmax = 0;
1384
+ for(j = 0; j <= nout-1; j++)
1385
+ {
1386
+ if( worky(j)>worky(nmax) )
1387
+ {
1388
+ nmax = j;
1389
+ }
1390
+ }
1391
+ nn = nmax;
1392
+
1393
+ //
1394
+ // Right answer
1395
+ //
1396
+ if( mlpissoftmax(network) )
1397
+ {
1398
+ ns = ap::round(xy(i,nin));
1399
+ }
1400
+ else
1401
+ {
1402
+ nmax = 0;
1403
+ for(j = 0; j <= nout-1; j++)
1404
+ {
1405
+ if( xy(i,nin+j)>xy(i,nin+nmax) )
1406
+ {
1407
+ nmax = j;
1408
+ }
1409
+ }
1410
+ ns = nmax;
1411
+ }
1412
+
1413
+ //
1414
+ // compare
1415
+ //
1416
+ if( nn!=ns )
1417
+ {
1418
+ result = result+1;
1419
+ }
1420
+ }
1421
+ return result;
1422
+ }
1423
+
1424
+
1425
+ /*************************************************************************
1426
+ Relative classification error on the test set
1427
+
1428
+ INPUT PARAMETERS:
1429
+ Network - network
1430
+ XY - test set
1431
+ NPoints - test set size
1432
+
1433
+ RESULT:
1434
+ percent of incorrectly classified cases. Works both for
1435
+ classifier networks and general purpose networks used as
1436
+ classifiers.
1437
+
1438
+ -- ALGLIB --
1439
+ Copyright 25.12.2008 by Bochkanov Sergey
1440
+ *************************************************************************/
1441
+ double mlprelclserror(multilayerperceptron& network,
1442
+ const ap::real_2d_array& xy,
1443
+ int npoints)
1444
+ {
1445
+ double result;
1446
+
1447
+ result = double(mlpclserror(network, xy, npoints))/double(npoints);
1448
+ return result;
1449
+ }
1450
+
1451
+
1452
+ /*************************************************************************
1453
+ Average cross-entropy (in bits per element) on the test set
1454
+
1455
+ INPUT PARAMETERS:
1456
+ Network - neural network
1457
+ XY - test set
1458
+ NPoints - test set size
1459
+
1460
+ RESULT:
1461
+ CrossEntropy/(NPoints*LN(2)).
1462
+ Zero if network solves regression task.
1463
+
1464
+ -- ALGLIB --
1465
+ Copyright 08.01.2009 by Bochkanov Sergey
1466
+ *************************************************************************/
1467
+ double mlpavgce(multilayerperceptron& network,
1468
+ const ap::real_2d_array& xy,
1469
+ int npoints)
1470
+ {
1471
+ double result;
1472
+ int nin;
1473
+ int nout;
1474
+ int wcount;
1475
+
1476
+ if( mlpissoftmax(network) )
1477
+ {
1478
+ mlpproperties(network, nin, nout, wcount);
1479
+ result = mlperrorn(network, xy, npoints)/(npoints*log(double(2)));
1480
+ }
1481
+ else
1482
+ {
1483
+ result = 0;
1484
+ }
1485
+ return result;
1486
+ }
1487
+
1488
+
1489
+ /*************************************************************************
1490
+ RMS error on the test set
1491
+
1492
+ INPUT PARAMETERS:
1493
+ Network - neural network
1494
+ XY - test set
1495
+ NPoints - test set size
1496
+
1497
+ RESULT:
1498
+ root mean square error.
1499
+ Its meaning for regression task is obvious. As for
1500
+ classification task, RMS error means error when estimating posterior
1501
+ probabilities.
1502
+
1503
+ -- ALGLIB --
1504
+ Copyright 04.11.2007 by Bochkanov Sergey
1505
+ *************************************************************************/
1506
+ double mlprmserror(multilayerperceptron& network,
1507
+ const ap::real_2d_array& xy,
1508
+ int npoints)
1509
+ {
1510
+ double result;
1511
+ int nin;
1512
+ int nout;
1513
+ int wcount;
1514
+
1515
+ mlpproperties(network, nin, nout, wcount);
1516
+ result = sqrt(2*mlperror(network, xy, npoints)/(npoints*nout));
1517
+ return result;
1518
+ }
1519
+
1520
+
1521
+ /*************************************************************************
1522
+ Average error on the test set
1523
+
1524
+ INPUT PARAMETERS:
1525
+ Network - neural network
1526
+ XY - test set
1527
+ NPoints - test set size
1528
+
1529
+ RESULT:
1530
+ Its meaning for regression task is obvious. As for
1531
+ classification task, it means average error when estimating posterior
1532
+ probabilities.
1533
+
1534
+ -- ALGLIB --
1535
+ Copyright 11.03.2008 by Bochkanov Sergey
1536
+ *************************************************************************/
1537
+ double mlpavgerror(multilayerperceptron& network,
1538
+ const ap::real_2d_array& xy,
1539
+ int npoints)
1540
+ {
1541
+ double result;
1542
+ int i;
1543
+ int j;
1544
+ int k;
1545
+ int nin;
1546
+ int nout;
1547
+ int wcount;
1548
+
1549
+ mlpproperties(network, nin, nout, wcount);
1550
+ result = 0;
1551
+ for(i = 0; i <= npoints-1; i++)
1552
+ {
1553
+ ap::vmove(&network.x(0), &xy(i, 0), ap::vlen(0,nin-1));
1554
+ mlpprocess(network, network.x, network.y);
1555
+ if( mlpissoftmax(network) )
1556
+ {
1557
+
1558
+ //
1559
+ // class labels
1560
+ //
1561
+ k = ap::round(xy(i,nin));
1562
+ for(j = 0; j <= nout-1; j++)
1563
+ {
1564
+ if( j==k )
1565
+ {
1566
+ result = result+fabs(1-network.y(j));
1567
+ }
1568
+ else
1569
+ {
1570
+ result = result+fabs(network.y(j));
1571
+ }
1572
+ }
1573
+ }
1574
+ else
1575
+ {
1576
+
1577
+ //
1578
+ // real outputs
1579
+ //
1580
+ for(j = 0; j <= nout-1; j++)
1581
+ {
1582
+ result = result+fabs(xy(i,nin+j)-network.y(j));
1583
+ }
1584
+ }
1585
+ }
1586
+ result = result/(npoints*nout);
1587
+ return result;
1588
+ }
1589
+
1590
+
1591
+ /*************************************************************************
1592
+ Average relative error on the test set
1593
+
1594
+ INPUT PARAMETERS:
1595
+ Network - neural network
1596
+ XY - test set
1597
+ NPoints - test set size
1598
+
1599
+ RESULT:
1600
+ Its meaning for regression task is obvious. As for
1601
+ classification task, it means average relative error when estimating
1602
+ posterior probability of belonging to the correct class.
1603
+
1604
+ -- ALGLIB --
1605
+ Copyright 11.03.2008 by Bochkanov Sergey
1606
+ *************************************************************************/
1607
+ double mlpavgrelerror(multilayerperceptron& network,
1608
+ const ap::real_2d_array& xy,
1609
+ int npoints)
1610
+ {
1611
+ double result;
1612
+ int i;
1613
+ int j;
1614
+ int k;
1615
+ int lk;
1616
+ int nin;
1617
+ int nout;
1618
+ int wcount;
1619
+
1620
+ mlpproperties(network, nin, nout, wcount);
1621
+ result = 0;
1622
+ k = 0;
1623
+ for(i = 0; i <= npoints-1; i++)
1624
+ {
1625
+ ap::vmove(&network.x(0), &xy(i, 0), ap::vlen(0,nin-1));
1626
+ mlpprocess(network, network.x, network.y);
1627
+ if( mlpissoftmax(network) )
1628
+ {
1629
+
1630
+ //
1631
+ // class labels
1632
+ //
1633
+ lk = ap::round(xy(i,nin));
1634
+ for(j = 0; j <= nout-1; j++)
1635
+ {
1636
+ if( j==lk )
1637
+ {
1638
+ result = result+fabs(1-network.y(j));
1639
+ k = k+1;
1640
+ }
1641
+ }
1642
+ }
1643
+ else
1644
+ {
1645
+
1646
+ //
1647
+ // real outputs
1648
+ //
1649
+ for(j = 0; j <= nout-1; j++)
1650
+ {
1651
+ if( xy(i,nin+j)!=0 )
1652
+ {
1653
+ result = result+fabs(xy(i,nin+j)-network.y(j))/fabs(xy(i,nin+j));
1654
+ k = k+1;
1655
+ }
1656
+ }
1657
+ }
1658
+ }
1659
+ if( k!=0 )
1660
+ {
1661
+ result = result/k;
1662
+ }
1663
+ return result;
1664
+ }
1665
+
1666
+
1667
+ /*************************************************************************
1668
+ Gradient calculation. Internal subroutine.
1669
+
1670
+ -- ALGLIB --
1671
+ Copyright 04.11.2007 by Bochkanov Sergey
1672
+ *************************************************************************/
1673
+ void mlpgrad(multilayerperceptron& network,
1674
+ const ap::real_1d_array& x,
1675
+ const ap::real_1d_array& desiredy,
1676
+ double& e,
1677
+ ap::real_1d_array& grad)
1678
+ {
1679
+ int i;
1680
+ int nout;
1681
+ int ntotal;
1682
+
1683
+
1684
+ //
1685
+ // Prepare dError/dOut, internal structures
1686
+ //
1687
+ mlpprocess(network, x, network.y);
1688
+ nout = network.structinfo(2);
1689
+ ntotal = network.structinfo(3);
1690
+ e = 0;
1691
+ for(i = 0; i <= ntotal-1; i++)
1692
+ {
1693
+ network.derror(i) = 0;
1694
+ }
1695
+ for(i = 0; i <= nout-1; i++)
1696
+ {
1697
+ network.derror(ntotal-nout+i) = network.y(i)-desiredy(i);
1698
+ e = e+ap::sqr(network.y(i)-desiredy(i))/2;
1699
+ }
1700
+
1701
+ //
1702
+ // gradient
1703
+ //
1704
+ mlpinternalcalculategradient(network, network.neurons, network.weights, network.derror, grad, false);
1705
+ }
1706
+
1707
+
1708
+ /*************************************************************************
1709
+ Gradient calculation (natural error function). Internal subroutine.
1710
+
1711
+ -- ALGLIB --
1712
+ Copyright 04.11.2007 by Bochkanov Sergey
1713
+ *************************************************************************/
1714
+ void mlpgradn(multilayerperceptron& network,
1715
+ const ap::real_1d_array& x,
1716
+ const ap::real_1d_array& desiredy,
1717
+ double& e,
1718
+ ap::real_1d_array& grad)
1719
+ {
1720
+ double s;
1721
+ int i;
1722
+ int nout;
1723
+ int ntotal;
1724
+
1725
+
1726
+ //
1727
+ // Prepare dError/dOut, internal structures
1728
+ //
1729
+ mlpprocess(network, x, network.y);
1730
+ nout = network.structinfo(2);
1731
+ ntotal = network.structinfo(3);
1732
+ for(i = 0; i <= ntotal-1; i++)
1733
+ {
1734
+ network.derror(i) = 0;
1735
+ }
1736
+ e = 0;
1737
+ if( network.structinfo(6)==0 )
1738
+ {
1739
+
1740
+ //
1741
+ // Regression network, least squares
1742
+ //
1743
+ for(i = 0; i <= nout-1; i++)
1744
+ {
1745
+ network.derror(ntotal-nout+i) = network.y(i)-desiredy(i);
1746
+ e = e+ap::sqr(network.y(i)-desiredy(i))/2;
1747
+ }
1748
+ }
1749
+ else
1750
+ {
1751
+
1752
+ //
1753
+ // Classification network, cross-entropy
1754
+ //
1755
+ s = 0;
1756
+ for(i = 0; i <= nout-1; i++)
1757
+ {
1758
+ s = s+desiredy(i);
1759
+ }
1760
+ for(i = 0; i <= nout-1; i++)
1761
+ {
1762
+ network.derror(ntotal-nout+i) = s*network.y(i)-desiredy(i);
1763
+ e = e+safecrossentropy(desiredy(i), network.y(i));
1764
+ }
1765
+ }
1766
+
1767
+ //
1768
+ // gradient
1769
+ //
1770
+ mlpinternalcalculategradient(network, network.neurons, network.weights, network.derror, grad, true);
1771
+ }
1772
+
1773
+
1774
+ /*************************************************************************
1775
+ Batch gradient calculation. Internal subroutine.
1776
+
1777
+ -- ALGLIB --
1778
+ Copyright 04.11.2007 by Bochkanov Sergey
1779
+ *************************************************************************/
1780
+ void mlpgradbatch(multilayerperceptron& network,
1781
+ const ap::real_2d_array& xy,
1782
+ int ssize,
1783
+ double& e,
1784
+ ap::real_1d_array& grad)
1785
+ {
1786
+ int i;
1787
+ int nin;
1788
+ int nout;
1789
+ int wcount;
1790
+
1791
+ mlpproperties(network, nin, nout, wcount);
1792
+ for(i = 0; i <= wcount-1; i++)
1793
+ {
1794
+ grad(i) = 0;
1795
+ }
1796
+ e = 0;
1797
+ i = 0;
1798
+ while(i<=ssize-1)
1799
+ {
1800
+ mlpchunkedgradient(network, xy, i, ap::minint(ssize, i+chunksize)-i, e, grad, false);
1801
+ i = i+chunksize;
1802
+ }
1803
+ }
1804
+
1805
+
1806
+ /*************************************************************************
1807
+ Batch gradient calculation (natural error function). Internal subroutine.
1808
+
1809
+ -- ALGLIB --
1810
+ Copyright 04.11.2007 by Bochkanov Sergey
1811
+ *************************************************************************/
1812
+ void mlpgradnbatch(multilayerperceptron& network,
1813
+ const ap::real_2d_array& xy,
1814
+ int ssize,
1815
+ double& e,
1816
+ ap::real_1d_array& grad)
1817
+ {
1818
+ int i;
1819
+ int nin;
1820
+ int nout;
1821
+ int wcount;
1822
+
1823
+ mlpproperties(network, nin, nout, wcount);
1824
+ for(i = 0; i <= wcount-1; i++)
1825
+ {
1826
+ grad(i) = 0;
1827
+ }
1828
+ e = 0;
1829
+ i = 0;
1830
+ while(i<=ssize-1)
1831
+ {
1832
+ mlpchunkedgradient(network, xy, i, ap::minint(ssize, i+chunksize)-i, e, grad, true);
1833
+ i = i+chunksize;
1834
+ }
1835
+ }
1836
+
1837
+
1838
+ /*************************************************************************
1839
+ Batch Hessian calculation (natural error function) using R-algorithm.
1840
+ Internal subroutine.
1841
+
1842
+ -- ALGLIB --
1843
+ Copyright 26.01.2008 by Bochkanov Sergey.
1844
+
1845
+ Hessian calculation based on R-algorithm described in
1846
+ "Fast Exact Multiplication by the Hessian",
1847
+ B. A. Pearlmutter,
1848
+ Neural Computation, 1994.
1849
+ *************************************************************************/
1850
+ void mlphessiannbatch(multilayerperceptron& network,
1851
+ const ap::real_2d_array& xy,
1852
+ int ssize,
1853
+ double& e,
1854
+ ap::real_1d_array& grad,
1855
+ ap::real_2d_array& h)
1856
+ {
1857
+
1858
+ mlphessianbatchinternal(network, xy, ssize, true, e, grad, h);
1859
+ }
1860
+
1861
+
1862
+ /*************************************************************************
1863
+ Batch Hessian calculation using R-algorithm.
1864
+ Internal subroutine.
1865
+
1866
+ -- ALGLIB --
1867
+ Copyright 26.01.2008 by Bochkanov Sergey.
1868
+
1869
+ Hessian calculation based on R-algorithm described in
1870
+ "Fast Exact Multiplication by the Hessian",
1871
+ B. A. Pearlmutter,
1872
+ Neural Computation, 1994.
1873
+ *************************************************************************/
1874
+ void mlphessianbatch(multilayerperceptron& network,
1875
+ const ap::real_2d_array& xy,
1876
+ int ssize,
1877
+ double& e,
1878
+ ap::real_1d_array& grad,
1879
+ ap::real_2d_array& h)
1880
+ {
1881
+
1882
+ mlphessianbatchinternal(network, xy, ssize, false, e, grad, h);
1883
+ }
1884
+
1885
+
1886
+ /*************************************************************************
1887
+ Internal subroutine, shouldn't be called by user.
1888
+ *************************************************************************/
1889
+ void mlpinternalprocessvector(const ap::integer_1d_array& structinfo,
1890
+ const ap::real_1d_array& weights,
1891
+ const ap::real_1d_array& columnmeans,
1892
+ const ap::real_1d_array& columnsigmas,
1893
+ ap::real_1d_array& neurons,
1894
+ ap::real_1d_array& dfdnet,
1895
+ const ap::real_1d_array& x,
1896
+ ap::real_1d_array& y)
1897
+ {
1898
+ int i;
1899
+ int j;
1900
+ int n1;
1901
+ int n2;
1902
+ int w1;
1903
+ int w2;
1904
+ int ntotal;
1905
+ int nin;
1906
+ int nout;
1907
+ int istart;
1908
+ int offs;
1909
+ double net;
1910
+ double e;
1911
+ double f;
1912
+ double df;
1913
+ double d2f;
1914
+ double mx;
1915
+ bool perr;
1916
+
1917
+
1918
+ //
1919
+ // Read network geometry
1920
+ //
1921
+ nin = structinfo(1);
1922
+ nout = structinfo(2);
1923
+ ntotal = structinfo(3);
1924
+ istart = structinfo(5);
1925
+
1926
+ //
1927
+ // Inputs standartisation and putting in the network
1928
+ //
1929
+ for(i = 0; i <= nin-1; i++)
1930
+ {
1931
+ if( columnsigmas(i)!=0 )
1932
+ {
1933
+ neurons(i) = (x(i)-columnmeans(i))/columnsigmas(i);
1934
+ }
1935
+ else
1936
+ {
1937
+ neurons(i) = x(i)-columnmeans(i);
1938
+ }
1939
+ }
1940
+
1941
+ //
1942
+ // Process network
1943
+ //
1944
+ for(i = 0; i <= ntotal-1; i++)
1945
+ {
1946
+ offs = istart+i*nfieldwidth;
1947
+ if( structinfo(offs+0)>0 )
1948
+ {
1949
+
1950
+ //
1951
+ // Activation function
1952
+ //
1953
+ mlpactivationfunction(neurons(structinfo(offs+2)), structinfo(offs+0), f, df, d2f);
1954
+ neurons(i) = f;
1955
+ dfdnet(i) = df;
1956
+ }
1957
+ if( structinfo(offs+0)==0 )
1958
+ {
1959
+
1960
+ //
1961
+ // Adaptive summator
1962
+ //
1963
+ n1 = structinfo(offs+2);
1964
+ n2 = n1+structinfo(offs+1)-1;
1965
+ w1 = structinfo(offs+3);
1966
+ w2 = w1+structinfo(offs+1)-1;
1967
+ net = ap::vdotproduct(&weights(w1), &neurons(n1), ap::vlen(w1,w2));
1968
+ neurons(i) = net;
1969
+ dfdnet(i) = 1.0;
1970
+ }
1971
+ if( structinfo(offs+0)<0 )
1972
+ {
1973
+ perr = true;
1974
+ if( structinfo(offs+0)==-2 )
1975
+ {
1976
+
1977
+ //
1978
+ // input neuron, left unchanged
1979
+ //
1980
+ perr = false;
1981
+ }
1982
+ if( structinfo(offs+0)==-3 )
1983
+ {
1984
+
1985
+ //
1986
+ // "-1" neuron
1987
+ //
1988
+ neurons(i) = -1;
1989
+ perr = false;
1990
+ }
1991
+ if( structinfo(offs+0)==-4 )
1992
+ {
1993
+
1994
+ //
1995
+ // "0" neuron
1996
+ //
1997
+ neurons(i) = 0;
1998
+ perr = false;
1999
+ }
2000
+ ap::ap_error::make_assertion(!perr, "MLPInternalProcessVector: internal error - unknown neuron type!");
2001
+ }
2002
+ }
2003
+
2004
+ //
2005
+ // Extract result
2006
+ //
2007
+ ap::vmove(&y(0), &neurons(ntotal-nout), ap::vlen(0,nout-1));
2008
+
2009
+ //
2010
+ // Softmax post-processing or standardisation if needed
2011
+ //
2012
+ ap::ap_error::make_assertion(structinfo(6)==0||structinfo(6)==1, "MLPInternalProcessVector: unknown normalization type!");
2013
+ if( structinfo(6)==1 )
2014
+ {
2015
+
2016
+ //
2017
+ // Softmax
2018
+ //
2019
+ mx = y(0);
2020
+ for(i = 1; i <= nout-1; i++)
2021
+ {
2022
+ mx = ap::maxreal(mx, y(i));
2023
+ }
2024
+ net = 0;
2025
+ for(i = 0; i <= nout-1; i++)
2026
+ {
2027
+ y(i) = exp(y(i)-mx);
2028
+ net = net+y(i);
2029
+ }
2030
+ for(i = 0; i <= nout-1; i++)
2031
+ {
2032
+ y(i) = y(i)/net;
2033
+ }
2034
+ }
2035
+ else
2036
+ {
2037
+
2038
+ //
2039
+ // Standardisation
2040
+ //
2041
+ for(i = 0; i <= nout-1; i++)
2042
+ {
2043
+ y(i) = y(i)*columnsigmas(nin+i)+columnmeans(nin+i);
2044
+ }
2045
+ }
2046
+ }
2047
+
2048
+
2049
+ /*************************************************************************
2050
+ Internal subroutine: adding new input layer to network
2051
+ *************************************************************************/
2052
+ static void addinputlayer(int ncount,
2053
+ ap::integer_1d_array& lsizes,
2054
+ ap::integer_1d_array& ltypes,
2055
+ ap::integer_1d_array& lconnfirst,
2056
+ ap::integer_1d_array& lconnlast,
2057
+ int& lastproc)
2058
+ {
2059
+
2060
+ lsizes(0) = ncount;
2061
+ ltypes(0) = -2;
2062
+ lconnfirst(0) = 0;
2063
+ lconnlast(0) = 0;
2064
+ lastproc = 0;
2065
+ }
2066
+
2067
+
2068
+ /*************************************************************************
2069
+ Internal subroutine: adding new summator layer to network
2070
+ *************************************************************************/
2071
+ static void addbiasedsummatorlayer(int ncount,
2072
+ ap::integer_1d_array& lsizes,
2073
+ ap::integer_1d_array& ltypes,
2074
+ ap::integer_1d_array& lconnfirst,
2075
+ ap::integer_1d_array& lconnlast,
2076
+ int& lastproc)
2077
+ {
2078
+
2079
+ lsizes(lastproc+1) = 1;
2080
+ ltypes(lastproc+1) = -3;
2081
+ lconnfirst(lastproc+1) = 0;
2082
+ lconnlast(lastproc+1) = 0;
2083
+ lsizes(lastproc+2) = ncount;
2084
+ ltypes(lastproc+2) = 0;
2085
+ lconnfirst(lastproc+2) = lastproc;
2086
+ lconnlast(lastproc+2) = lastproc+1;
2087
+ lastproc = lastproc+2;
2088
+ }
2089
+
2090
+
2091
+ /*************************************************************************
2092
+ Internal subroutine: adding new summator layer to network
2093
+ *************************************************************************/
2094
+ static void addactivationlayer(int functype,
2095
+ ap::integer_1d_array& lsizes,
2096
+ ap::integer_1d_array& ltypes,
2097
+ ap::integer_1d_array& lconnfirst,
2098
+ ap::integer_1d_array& lconnlast,
2099
+ int& lastproc)
2100
+ {
2101
+
2102
+ ap::ap_error::make_assertion(functype>0, "AddActivationLayer: incorrect function type");
2103
+ lsizes(lastproc+1) = lsizes(lastproc);
2104
+ ltypes(lastproc+1) = functype;
2105
+ lconnfirst(lastproc+1) = lastproc;
2106
+ lconnlast(lastproc+1) = lastproc;
2107
+ lastproc = lastproc+1;
2108
+ }
2109
+
2110
+
2111
+ /*************************************************************************
2112
+ Internal subroutine: adding new zero layer to network
2113
+ *************************************************************************/
2114
+ static void addzerolayer(ap::integer_1d_array& lsizes,
2115
+ ap::integer_1d_array& ltypes,
2116
+ ap::integer_1d_array& lconnfirst,
2117
+ ap::integer_1d_array& lconnlast,
2118
+ int& lastproc)
2119
+ {
2120
+
2121
+ lsizes(lastproc+1) = 1;
2122
+ ltypes(lastproc+1) = -4;
2123
+ lconnfirst(lastproc+1) = 0;
2124
+ lconnlast(lastproc+1) = 0;
2125
+ lastproc = lastproc+1;
2126
+ }
2127
+
2128
+
2129
+ /*************************************************************************
2130
+ Internal subroutine.
2131
+
2132
+ -- ALGLIB --
2133
+ Copyright 04.11.2007 by Bochkanov Sergey
2134
+ *************************************************************************/
2135
+ static void mlpcreate(int nin,
2136
+ int nout,
2137
+ const ap::integer_1d_array& lsizes,
2138
+ const ap::integer_1d_array& ltypes,
2139
+ const ap::integer_1d_array& lconnfirst,
2140
+ const ap::integer_1d_array& lconnlast,
2141
+ int layerscount,
2142
+ bool isclsnet,
2143
+ multilayerperceptron& network)
2144
+ {
2145
+ int i;
2146
+ int j;
2147
+ int ssize;
2148
+ int ntotal;
2149
+ int wcount;
2150
+ int offs;
2151
+ int nprocessed;
2152
+ int wallocated;
2153
+ ap::integer_1d_array localtemp;
2154
+ ap::integer_1d_array lnfirst;
2155
+ ap::integer_1d_array lnsyn;
2156
+
2157
+
2158
+ //
2159
+ // Check
2160
+ //
2161
+ ap::ap_error::make_assertion(layerscount>0, "MLPCreate: wrong parameters!");
2162
+ ap::ap_error::make_assertion(ltypes(0)==-2, "MLPCreate: wrong LTypes[0] (must be -2)!");
2163
+ for(i = 0; i <= layerscount-1; i++)
2164
+ {
2165
+ ap::ap_error::make_assertion(lsizes(i)>0, "MLPCreate: wrong LSizes!");
2166
+ ap::ap_error::make_assertion(lconnfirst(i)>=0&&(lconnfirst(i)<i||i==0), "MLPCreate: wrong LConnFirst!");
2167
+ ap::ap_error::make_assertion(lconnlast(i)>=lconnfirst(i)&&(lconnlast(i)<i||i==0), "MLPCreate: wrong LConnLast!");
2168
+ }
2169
+
2170
+ //
2171
+ // Build network geometry
2172
+ //
2173
+ lnfirst.setbounds(0, layerscount-1);
2174
+ lnsyn.setbounds(0, layerscount-1);
2175
+ ntotal = 0;
2176
+ wcount = 0;
2177
+ for(i = 0; i <= layerscount-1; i++)
2178
+ {
2179
+
2180
+ //
2181
+ // Analyze connections.
2182
+ // This code must throw an assertion in case of unknown LTypes[I]
2183
+ //
2184
+ lnsyn(i) = -1;
2185
+ if( ltypes(i)>=0 )
2186
+ {
2187
+ lnsyn(i) = 0;
2188
+ for(j = lconnfirst(i); j <= lconnlast(i); j++)
2189
+ {
2190
+ lnsyn(i) = lnsyn(i)+lsizes(j);
2191
+ }
2192
+ }
2193
+ else
2194
+ {
2195
+ if( ltypes(i)==-2||ltypes(i)==-3||ltypes(i)==-4 )
2196
+ {
2197
+ lnsyn(i) = 0;
2198
+ }
2199
+ }
2200
+ ap::ap_error::make_assertion(lnsyn(i)>=0, "MLPCreate: internal error #0!");
2201
+
2202
+ //
2203
+ // Other info
2204
+ //
2205
+ lnfirst(i) = ntotal;
2206
+ ntotal = ntotal+lsizes(i);
2207
+ if( ltypes(i)==0 )
2208
+ {
2209
+ wcount = wcount+lnsyn(i)*lsizes(i);
2210
+ }
2211
+ }
2212
+ ssize = 7+ntotal*nfieldwidth;
2213
+
2214
+ //
2215
+ // Allocate
2216
+ //
2217
+ network.structinfo.setbounds(0, ssize-1);
2218
+ network.weights.setbounds(0, wcount-1);
2219
+ if( isclsnet )
2220
+ {
2221
+ network.columnmeans.setbounds(0, nin-1);
2222
+ network.columnsigmas.setbounds(0, nin-1);
2223
+ }
2224
+ else
2225
+ {
2226
+ network.columnmeans.setbounds(0, nin+nout-1);
2227
+ network.columnsigmas.setbounds(0, nin+nout-1);
2228
+ }
2229
+ network.neurons.setbounds(0, ntotal-1);
2230
+ network.chunks.setbounds(0, 3*ntotal, 0, chunksize-1);
2231
+ network.nwbuf.setbounds(0, ap::maxint(wcount, 2*nout)-1);
2232
+ network.dfdnet.setbounds(0, ntotal-1);
2233
+ network.x.setbounds(0, nin-1);
2234
+ network.y.setbounds(0, nout-1);
2235
+ network.derror.setbounds(0, ntotal-1);
2236
+
2237
+ //
2238
+ // Fill structure: global info
2239
+ //
2240
+ network.structinfo(0) = ssize;
2241
+ network.structinfo(1) = nin;
2242
+ network.structinfo(2) = nout;
2243
+ network.structinfo(3) = ntotal;
2244
+ network.structinfo(4) = wcount;
2245
+ network.structinfo(5) = 7;
2246
+ if( isclsnet )
2247
+ {
2248
+ network.structinfo(6) = 1;
2249
+ }
2250
+ else
2251
+ {
2252
+ network.structinfo(6) = 0;
2253
+ }
2254
+
2255
+ //
2256
+ // Fill structure: neuron connections
2257
+ //
2258
+ nprocessed = 0;
2259
+ wallocated = 0;
2260
+ for(i = 0; i <= layerscount-1; i++)
2261
+ {
2262
+ for(j = 0; j <= lsizes(i)-1; j++)
2263
+ {
2264
+ offs = network.structinfo(5)+nprocessed*nfieldwidth;
2265
+ network.structinfo(offs+0) = ltypes(i);
2266
+ if( ltypes(i)==0 )
2267
+ {
2268
+
2269
+ //
2270
+ // Adaptive summator:
2271
+ // * connections with weights to previous neurons
2272
+ //
2273
+ network.structinfo(offs+1) = lnsyn(i);
2274
+ network.structinfo(offs+2) = lnfirst(lconnfirst(i));
2275
+ network.structinfo(offs+3) = wallocated;
2276
+ wallocated = wallocated+lnsyn(i);
2277
+ nprocessed = nprocessed+1;
2278
+ }
2279
+ if( ltypes(i)>0 )
2280
+ {
2281
+
2282
+ //
2283
+ // Activation layer:
2284
+ // * each neuron connected to one (only one) of previous neurons.
2285
+ // * no weights
2286
+ //
2287
+ network.structinfo(offs+1) = 1;
2288
+ network.structinfo(offs+2) = lnfirst(lconnfirst(i))+j;
2289
+ network.structinfo(offs+3) = -1;
2290
+ nprocessed = nprocessed+1;
2291
+ }
2292
+ if( ltypes(i)==-2||ltypes(i)==-3||ltypes(i)==-4 )
2293
+ {
2294
+ nprocessed = nprocessed+1;
2295
+ }
2296
+ }
2297
+ }
2298
+ ap::ap_error::make_assertion(wallocated==wcount, "MLPCreate: internal error #1!");
2299
+ ap::ap_error::make_assertion(nprocessed==ntotal, "MLPCreate: internal error #2!");
2300
+
2301
+ //
2302
+ // Fill weights by small random values
2303
+ // Initialize means and sigmas
2304
+ //
2305
+ for(i = 0; i <= wcount-1; i++)
2306
+ {
2307
+ network.weights(i) = ap::randomreal()-0.5;
2308
+ }
2309
+ for(i = 0; i <= nin-1; i++)
2310
+ {
2311
+ network.columnmeans(i) = 0;
2312
+ network.columnsigmas(i) = 1;
2313
+ }
2314
+ if( !isclsnet )
2315
+ {
2316
+ for(i = 0; i <= nout-1; i++)
2317
+ {
2318
+ network.columnmeans(nin+i) = 0;
2319
+ network.columnsigmas(nin+i) = 1;
2320
+ }
2321
+ }
2322
+ }
2323
+
2324
+
2325
+ /*************************************************************************
2326
+ Internal subroutine
2327
+
2328
+ -- ALGLIB --
2329
+ Copyright 04.11.2007 by Bochkanov Sergey
2330
+ *************************************************************************/
2331
+ static void mlpactivationfunction(double net,
2332
+ int k,
2333
+ double& f,
2334
+ double& df,
2335
+ double& d2f)
2336
+ {
2337
+ double net2;
2338
+ double arg;
2339
+ double root;
2340
+ double r;
2341
+
2342
+ f = 0;
2343
+ df = 0;
2344
+ if( k==1 )
2345
+ {
2346
+
2347
+ //
2348
+ // TanH activation function
2349
+ //
2350
+ f = tanh(net);
2351
+ df = 1-ap::sqr(f);
2352
+ d2f = -2*f*df;
2353
+ return;
2354
+ }
2355
+ if( k==3 )
2356
+ {
2357
+
2358
+ //
2359
+ // EX activation function
2360
+ //
2361
+ if( net>=0 )
2362
+ {
2363
+ net2 = net*net;
2364
+ arg = net2+1;
2365
+ root = sqrt(arg);
2366
+ f = net+root;
2367
+ r = net/root;
2368
+ df = 1+r;
2369
+ d2f = (root-net*r)/arg;
2370
+ }
2371
+ else
2372
+ {
2373
+ f = exp(net);
2374
+ df = f;
2375
+ d2f = f;
2376
+ }
2377
+ return;
2378
+ }
2379
+ if( k==2 )
2380
+ {
2381
+ f = exp(-ap::sqr(net));
2382
+ df = -2*net*f;
2383
+ d2f = -2*(f+df*net);
2384
+ return;
2385
+ }
2386
+ }
2387
+
2388
+
2389
+ /*************************************************************************
2390
+ Internal subroutine for Hessian calculation.
2391
+
2392
+ WARNING!!! Unspeakable math far beyong human capabilities :)
2393
+ *************************************************************************/
2394
+ static void mlphessianbatchinternal(multilayerperceptron& network,
2395
+ const ap::real_2d_array& xy,
2396
+ int ssize,
2397
+ bool naturalerr,
2398
+ double& e,
2399
+ ap::real_1d_array& grad,
2400
+ ap::real_2d_array& h)
2401
+ {
2402
+ int nin;
2403
+ int nout;
2404
+ int wcount;
2405
+ int ntotal;
2406
+ int istart;
2407
+ int i;
2408
+ int j;
2409
+ int k;
2410
+ int kl;
2411
+ int offs;
2412
+ int n1;
2413
+ int n2;
2414
+ int w1;
2415
+ int w2;
2416
+ double s;
2417
+ double t;
2418
+ double v;
2419
+ double et;
2420
+ bool bflag;
2421
+ double f;
2422
+ double df;
2423
+ double d2f;
2424
+ double deidyj;
2425
+ double mx;
2426
+ double net;
2427
+ double q;
2428
+ double z;
2429
+ double s2;
2430
+ double expi;
2431
+ double expj;
2432
+ ap::real_1d_array x;
2433
+ ap::real_1d_array desiredy;
2434
+ ap::real_1d_array gt;
2435
+ ap::real_1d_array zeros;
2436
+ ap::real_2d_array rx;
2437
+ ap::real_2d_array ry;
2438
+ ap::real_2d_array rdx;
2439
+ ap::real_2d_array rdy;
2440
+
2441
+ mlpproperties(network, nin, nout, wcount);
2442
+ ntotal = network.structinfo(3);
2443
+ istart = network.structinfo(5);
2444
+
2445
+ //
2446
+ // Prepare
2447
+ //
2448
+ x.setbounds(0, nin-1);
2449
+ desiredy.setbounds(0, nout-1);
2450
+ zeros.setbounds(0, wcount-1);
2451
+ gt.setbounds(0, wcount-1);
2452
+ rx.setbounds(0, ntotal+nout-1, 0, wcount-1);
2453
+ ry.setbounds(0, ntotal+nout-1, 0, wcount-1);
2454
+ rdx.setbounds(0, ntotal+nout-1, 0, wcount-1);
2455
+ rdy.setbounds(0, ntotal+nout-1, 0, wcount-1);
2456
+ e = 0;
2457
+ for(i = 0; i <= wcount-1; i++)
2458
+ {
2459
+ zeros(i) = 0;
2460
+ }
2461
+ ap::vmove(&grad(0), &zeros(0), ap::vlen(0,wcount-1));
2462
+ for(i = 0; i <= wcount-1; i++)
2463
+ {
2464
+ ap::vmove(&h(i, 0), &zeros(0), ap::vlen(0,wcount-1));
2465
+ }
2466
+
2467
+ //
2468
+ // Process
2469
+ //
2470
+ for(k = 0; k <= ssize-1; k++)
2471
+ {
2472
+
2473
+ //
2474
+ // Process vector with MLPGradN.
2475
+ // Now Neurons, DFDNET and DError contains results of the last run.
2476
+ //
2477
+ ap::vmove(&x(0), &xy(k, 0), ap::vlen(0,nin-1));
2478
+ if( mlpissoftmax(network) )
2479
+ {
2480
+
2481
+ //
2482
+ // class labels outputs
2483
+ //
2484
+ kl = ap::round(xy(k,nin));
2485
+ for(i = 0; i <= nout-1; i++)
2486
+ {
2487
+ if( i==kl )
2488
+ {
2489
+ desiredy(i) = 1;
2490
+ }
2491
+ else
2492
+ {
2493
+ desiredy(i) = 0;
2494
+ }
2495
+ }
2496
+ }
2497
+ else
2498
+ {
2499
+
2500
+ //
2501
+ // real outputs
2502
+ //
2503
+ ap::vmove(&desiredy(0), &xy(k, nin), ap::vlen(0,nout-1));
2504
+ }
2505
+ if( naturalerr )
2506
+ {
2507
+ mlpgradn(network, x, desiredy, et, gt);
2508
+ }
2509
+ else
2510
+ {
2511
+ mlpgrad(network, x, desiredy, et, gt);
2512
+ }
2513
+
2514
+ //
2515
+ // grad, error
2516
+ //
2517
+ e = e+et;
2518
+ ap::vadd(&grad(0), &gt(0), ap::vlen(0,wcount-1));
2519
+
2520
+ //
2521
+ // Hessian.
2522
+ // Forward pass of the R-algorithm
2523
+ //
2524
+ for(i = 0; i <= ntotal-1; i++)
2525
+ {
2526
+ offs = istart+i*nfieldwidth;
2527
+ ap::vmove(&rx(i, 0), &zeros(0), ap::vlen(0,wcount-1));
2528
+ ap::vmove(&ry(i, 0), &zeros(0), ap::vlen(0,wcount-1));
2529
+ if( network.structinfo(offs+0)>0 )
2530
+ {
2531
+
2532
+ //
2533
+ // Activation function
2534
+ //
2535
+ n1 = network.structinfo(offs+2);
2536
+ ap::vmove(&rx(i, 0), &ry(n1, 0), ap::vlen(0,wcount-1));
2537
+ v = network.dfdnet(i);
2538
+ ap::vmove(&ry(i, 0), &rx(i, 0), ap::vlen(0,wcount-1), v);
2539
+ }
2540
+ if( network.structinfo(offs+0)==0 )
2541
+ {
2542
+
2543
+ //
2544
+ // Adaptive summator
2545
+ //
2546
+ n1 = network.structinfo(offs+2);
2547
+ n2 = n1+network.structinfo(offs+1)-1;
2548
+ w1 = network.structinfo(offs+3);
2549
+ w2 = w1+network.structinfo(offs+1)-1;
2550
+ for(j = n1; j <= n2; j++)
2551
+ {
2552
+ v = network.weights(w1+j-n1);
2553
+ ap::vadd(&rx(i, 0), &ry(j, 0), ap::vlen(0,wcount-1), v);
2554
+ rx(i,w1+j-n1) = rx(i,w1+j-n1)+network.neurons(j);
2555
+ }
2556
+ ap::vmove(&ry(i, 0), &rx(i, 0), ap::vlen(0,wcount-1));
2557
+ }
2558
+ if( network.structinfo(offs+0)<0 )
2559
+ {
2560
+ bflag = true;
2561
+ if( network.structinfo(offs+0)==-2 )
2562
+ {
2563
+
2564
+ //
2565
+ // input neuron, left unchanged
2566
+ //
2567
+ bflag = false;
2568
+ }
2569
+ if( network.structinfo(offs+0)==-3 )
2570
+ {
2571
+
2572
+ //
2573
+ // "-1" neuron, left unchanged
2574
+ //
2575
+ bflag = false;
2576
+ }
2577
+ if( network.structinfo(offs+0)==-4 )
2578
+ {
2579
+
2580
+ //
2581
+ // "0" neuron, left unchanged
2582
+ //
2583
+ bflag = false;
2584
+ }
2585
+ ap::ap_error::make_assertion(!bflag, "MLPHessianNBatch: internal error - unknown neuron type!");
2586
+ }
2587
+ }
2588
+
2589
+ //
2590
+ // Hessian. Backward pass of the R-algorithm.
2591
+ //
2592
+ // Stage 1. Initialize RDY
2593
+ //
2594
+ for(i = 0; i <= ntotal+nout-1; i++)
2595
+ {
2596
+ ap::vmove(&rdy(i, 0), &zeros(0), ap::vlen(0,wcount-1));
2597
+ }
2598
+ if( network.structinfo(6)==0 )
2599
+ {
2600
+
2601
+ //
2602
+ // Standardisation.
2603
+ //
2604
+ // In context of the Hessian calculation standardisation
2605
+ // is considered as additional layer with weightless
2606
+ // activation function:
2607
+ //
2608
+ // F(NET) := Sigma*NET
2609
+ //
2610
+ // So we add one more layer to forward pass, and
2611
+ // make forward/backward pass through this layer.
2612
+ //
2613
+ for(i = 0; i <= nout-1; i++)
2614
+ {
2615
+ n1 = ntotal-nout+i;
2616
+ n2 = ntotal+i;
2617
+
2618
+ //
2619
+ // Forward pass from N1 to N2
2620
+ //
2621
+ ap::vmove(&rx(n2, 0), &ry(n1, 0), ap::vlen(0,wcount-1));
2622
+ v = network.columnsigmas(nin+i);
2623
+ ap::vmove(&ry(n2, 0), &rx(n2, 0), ap::vlen(0,wcount-1), v);
2624
+
2625
+ //
2626
+ // Initialization of RDY
2627
+ //
2628
+ ap::vmove(&rdy(n2, 0), &ry(n2, 0), ap::vlen(0,wcount-1));
2629
+
2630
+ //
2631
+ // Backward pass from N2 to N1:
2632
+ // 1. Calculate R(dE/dX).
2633
+ // 2. No R(dE/dWij) is needed since weight of activation neuron
2634
+ // is fixed to 1. So we can update R(dE/dY) for
2635
+ // the connected neuron (note that Vij=0, Wij=1)
2636
+ //
2637
+ df = network.columnsigmas(nin+i);
2638
+ ap::vmove(&rdx(n2, 0), &rdy(n2, 0), ap::vlen(0,wcount-1), df);
2639
+ ap::vadd(&rdy(n1, 0), &rdx(n2, 0), ap::vlen(0,wcount-1));
2640
+ }
2641
+ }
2642
+ else
2643
+ {
2644
+
2645
+ //
2646
+ // Softmax.
2647
+ //
2648
+ // Initialize RDY using generalized expression for ei'(yi)
2649
+ // (see expression (9) from p. 5 of "Fast Exact Multiplication by the Hessian").
2650
+ //
2651
+ // When we are working with softmax network, generalized
2652
+ // expression for ei'(yi) is used because softmax
2653
+ // normalization leads to ei, which depends on all y's
2654
+ //
2655
+ if( naturalerr )
2656
+ {
2657
+
2658
+ //
2659
+ // softmax + cross-entropy.
2660
+ // We have:
2661
+ //
2662
+ // S = sum(exp(yk)),
2663
+ // ei = sum(trn)*exp(yi)/S-trn_i
2664
+ //
2665
+ // j=i: d(ei)/d(yj) = T*exp(yi)*(S-exp(yi))/S^2
2666
+ // j<>i: d(ei)/d(yj) = -T*exp(yi)*exp(yj)/S^2
2667
+ //
2668
+ t = 0;
2669
+ for(i = 0; i <= nout-1; i++)
2670
+ {
2671
+ t = t+desiredy(i);
2672
+ }
2673
+ mx = network.neurons(ntotal-nout);
2674
+ for(i = 0; i <= nout-1; i++)
2675
+ {
2676
+ mx = ap::maxreal(mx, network.neurons(ntotal-nout+i));
2677
+ }
2678
+ s = 0;
2679
+ for(i = 0; i <= nout-1; i++)
2680
+ {
2681
+ network.nwbuf(i) = exp(network.neurons(ntotal-nout+i)-mx);
2682
+ s = s+network.nwbuf(i);
2683
+ }
2684
+ for(i = 0; i <= nout-1; i++)
2685
+ {
2686
+ for(j = 0; j <= nout-1; j++)
2687
+ {
2688
+ if( j==i )
2689
+ {
2690
+ deidyj = t*network.nwbuf(i)*(s-network.nwbuf(i))/ap::sqr(s);
2691
+ ap::vadd(&rdy(ntotal-nout+i, 0), &ry(ntotal-nout+i, 0), ap::vlen(0,wcount-1), deidyj);
2692
+ }
2693
+ else
2694
+ {
2695
+ deidyj = -t*network.nwbuf(i)*network.nwbuf(j)/ap::sqr(s);
2696
+ ap::vadd(&rdy(ntotal-nout+i, 0), &ry(ntotal-nout+j, 0), ap::vlen(0,wcount-1), deidyj);
2697
+ }
2698
+ }
2699
+ }
2700
+ }
2701
+ else
2702
+ {
2703
+
2704
+ //
2705
+ // For a softmax + squared error we have expression
2706
+ // far beyond human imagination so we dont even try
2707
+ // to comment on it. Just enjoy the code...
2708
+ //
2709
+ // P.S. That's why "natural error" is called "natural" -
2710
+ // compact beatiful expressions, fast code....
2711
+ //
2712
+ mx = network.neurons(ntotal-nout);
2713
+ for(i = 0; i <= nout-1; i++)
2714
+ {
2715
+ mx = ap::maxreal(mx, network.neurons(ntotal-nout+i));
2716
+ }
2717
+ s = 0;
2718
+ s2 = 0;
2719
+ for(i = 0; i <= nout-1; i++)
2720
+ {
2721
+ network.nwbuf(i) = exp(network.neurons(ntotal-nout+i)-mx);
2722
+ s = s+network.nwbuf(i);
2723
+ s2 = s2+ap::sqr(network.nwbuf(i));
2724
+ }
2725
+ q = 0;
2726
+ for(i = 0; i <= nout-1; i++)
2727
+ {
2728
+ q = q+(network.y(i)-desiredy(i))*network.nwbuf(i);
2729
+ }
2730
+ for(i = 0; i <= nout-1; i++)
2731
+ {
2732
+ z = -q+(network.y(i)-desiredy(i))*s;
2733
+ expi = network.nwbuf(i);
2734
+ for(j = 0; j <= nout-1; j++)
2735
+ {
2736
+ expj = network.nwbuf(j);
2737
+ if( j==i )
2738
+ {
2739
+ deidyj = expi/ap::sqr(s)*((z+expi)*(s-2*expi)/s+expi*s2/ap::sqr(s));
2740
+ }
2741
+ else
2742
+ {
2743
+ deidyj = expi*expj/ap::sqr(s)*(s2/ap::sqr(s)-2*z/s-(expi+expj)/s+(network.y(i)-desiredy(i))-(network.y(j)-desiredy(j)));
2744
+ }
2745
+ ap::vadd(&rdy(ntotal-nout+i, 0), &ry(ntotal-nout+j, 0), ap::vlen(0,wcount-1), deidyj);
2746
+ }
2747
+ }
2748
+ }
2749
+ }
2750
+
2751
+ //
2752
+ // Hessian. Backward pass of the R-algorithm
2753
+ //
2754
+ // Stage 2. Process.
2755
+ //
2756
+ for(i = ntotal-1; i >= 0; i--)
2757
+ {
2758
+
2759
+ //
2760
+ // Possible variants:
2761
+ // 1. Activation function
2762
+ // 2. Adaptive summator
2763
+ // 3. Special neuron
2764
+ //
2765
+ offs = istart+i*nfieldwidth;
2766
+ if( network.structinfo(offs+0)>0 )
2767
+ {
2768
+ n1 = network.structinfo(offs+2);
2769
+
2770
+ //
2771
+ // First, calculate R(dE/dX).
2772
+ //
2773
+ mlpactivationfunction(network.neurons(n1), network.structinfo(offs+0), f, df, d2f);
2774
+ v = d2f*network.derror(i);
2775
+ ap::vmove(&rdx(i, 0), &rdy(i, 0), ap::vlen(0,wcount-1), df);
2776
+ ap::vadd(&rdx(i, 0), &rx(i, 0), ap::vlen(0,wcount-1), v);
2777
+
2778
+ //
2779
+ // No R(dE/dWij) is needed since weight of activation neuron
2780
+ // is fixed to 1.
2781
+ //
2782
+ // So we can update R(dE/dY) for the connected neuron.
2783
+ // (note that Vij=0, Wij=1)
2784
+ //
2785
+ ap::vadd(&rdy(n1, 0), &rdx(i, 0), ap::vlen(0,wcount-1));
2786
+ }
2787
+ if( network.structinfo(offs+0)==0 )
2788
+ {
2789
+
2790
+ //
2791
+ // Adaptive summator
2792
+ //
2793
+ n1 = network.structinfo(offs+2);
2794
+ n2 = n1+network.structinfo(offs+1)-1;
2795
+ w1 = network.structinfo(offs+3);
2796
+ w2 = w1+network.structinfo(offs+1)-1;
2797
+
2798
+ //
2799
+ // First, calculate R(dE/dX).
2800
+ //
2801
+ ap::vmove(&rdx(i, 0), &rdy(i, 0), ap::vlen(0,wcount-1));
2802
+
2803
+ //
2804
+ // Then, calculate R(dE/dWij)
2805
+ //
2806
+ for(j = w1; j <= w2; j++)
2807
+ {
2808
+ v = network.neurons(n1+j-w1);
2809
+ ap::vadd(&h(j, 0), &rdx(i, 0), ap::vlen(0,wcount-1), v);
2810
+ v = network.derror(i);
2811
+ ap::vadd(&h(j, 0), &ry(n1+j-w1, 0), ap::vlen(0,wcount-1), v);
2812
+ }
2813
+
2814
+ //
2815
+ // And finally, update R(dE/dY) for connected neurons.
2816
+ //
2817
+ for(j = w1; j <= w2; j++)
2818
+ {
2819
+ v = network.weights(j);
2820
+ ap::vadd(&rdy(n1+j-w1, 0), &rdx(i, 0), ap::vlen(0,wcount-1), v);
2821
+ rdy(n1+j-w1,j) = rdy(n1+j-w1,j)+network.derror(i);
2822
+ }
2823
+ }
2824
+ if( network.structinfo(offs+0)<0 )
2825
+ {
2826
+ bflag = false;
2827
+ if( network.structinfo(offs+0)==-2||network.structinfo(offs+0)==-3||network.structinfo(offs+0)==-4 )
2828
+ {
2829
+
2830
+ //
2831
+ // Special neuron type, no back-propagation required
2832
+ //
2833
+ bflag = true;
2834
+ }
2835
+ ap::ap_error::make_assertion(bflag, "MLPHessianNBatch: unknown neuron type!");
2836
+ }
2837
+ }
2838
+ }
2839
+ }
2840
+
2841
+
2842
+ /*************************************************************************
2843
+ Internal subroutine
2844
+
2845
+ Network must be processed by MLPProcess on X
2846
+ *************************************************************************/
2847
+ static void mlpinternalcalculategradient(multilayerperceptron& network,
2848
+ const ap::real_1d_array& neurons,
2849
+ const ap::real_1d_array& weights,
2850
+ ap::real_1d_array& derror,
2851
+ ap::real_1d_array& grad,
2852
+ bool naturalerrorfunc)
2853
+ {
2854
+ int i;
2855
+ int j;
2856
+ int n1;
2857
+ int n2;
2858
+ int w1;
2859
+ int w2;
2860
+ int ntotal;
2861
+ int istart;
2862
+ int nin;
2863
+ int nout;
2864
+ int offs;
2865
+ double dedf;
2866
+ double dfdnet;
2867
+ double v;
2868
+ double fown;
2869
+ double deown;
2870
+ double net;
2871
+ double mx;
2872
+ bool bflag;
2873
+
2874
+
2875
+ //
2876
+ // Read network geometry
2877
+ //
2878
+ nin = network.structinfo(1);
2879
+ nout = network.structinfo(2);
2880
+ ntotal = network.structinfo(3);
2881
+ istart = network.structinfo(5);
2882
+
2883
+ //
2884
+ // Pre-processing of dError/dOut:
2885
+ // from dError/dOut(normalized) to dError/dOut(non-normalized)
2886
+ //
2887
+ ap::ap_error::make_assertion(network.structinfo(6)==0||network.structinfo(6)==1, "MLPInternalCalculateGradient: unknown normalization type!");
2888
+ if( network.structinfo(6)==1 )
2889
+ {
2890
+
2891
+ //
2892
+ // Softmax
2893
+ //
2894
+ if( !naturalerrorfunc )
2895
+ {
2896
+ mx = network.neurons(ntotal-nout);
2897
+ for(i = 0; i <= nout-1; i++)
2898
+ {
2899
+ mx = ap::maxreal(mx, network.neurons(ntotal-nout+i));
2900
+ }
2901
+ net = 0;
2902
+ for(i = 0; i <= nout-1; i++)
2903
+ {
2904
+ network.nwbuf(i) = exp(network.neurons(ntotal-nout+i)-mx);
2905
+ net = net+network.nwbuf(i);
2906
+ }
2907
+ v = ap::vdotproduct(&network.derror(ntotal-nout), &network.nwbuf(0), ap::vlen(ntotal-nout,ntotal-1));
2908
+ for(i = 0; i <= nout-1; i++)
2909
+ {
2910
+ fown = network.nwbuf(i);
2911
+ deown = network.derror(ntotal-nout+i);
2912
+ network.nwbuf(nout+i) = (-v+deown*fown+deown*(net-fown))*fown/ap::sqr(net);
2913
+ }
2914
+ for(i = 0; i <= nout-1; i++)
2915
+ {
2916
+ network.derror(ntotal-nout+i) = network.nwbuf(nout+i);
2917
+ }
2918
+ }
2919
+ }
2920
+ else
2921
+ {
2922
+
2923
+ //
2924
+ // Un-standardisation
2925
+ //
2926
+ for(i = 0; i <= nout-1; i++)
2927
+ {
2928
+ network.derror(ntotal-nout+i) = network.derror(ntotal-nout+i)*network.columnsigmas(nin+i);
2929
+ }
2930
+ }
2931
+
2932
+ //
2933
+ // Backpropagation
2934
+ //
2935
+ for(i = ntotal-1; i >= 0; i--)
2936
+ {
2937
+
2938
+ //
2939
+ // Extract info
2940
+ //
2941
+ offs = istart+i*nfieldwidth;
2942
+ if( network.structinfo(offs+0)>0 )
2943
+ {
2944
+
2945
+ //
2946
+ // Activation function
2947
+ //
2948
+ dedf = network.derror(i);
2949
+ dfdnet = network.dfdnet(i);
2950
+ derror(network.structinfo(offs+2)) = derror(network.structinfo(offs+2))+dedf*dfdnet;
2951
+ }
2952
+ if( network.structinfo(offs+0)==0 )
2953
+ {
2954
+
2955
+ //
2956
+ // Adaptive summator
2957
+ //
2958
+ n1 = network.structinfo(offs+2);
2959
+ n2 = n1+network.structinfo(offs+1)-1;
2960
+ w1 = network.structinfo(offs+3);
2961
+ w2 = w1+network.structinfo(offs+1)-1;
2962
+ dedf = network.derror(i);
2963
+ dfdnet = 1.0;
2964
+ v = dedf*dfdnet;
2965
+ ap::vmove(&grad(w1), &neurons(n1), ap::vlen(w1,w2), v);
2966
+ ap::vadd(&derror(n1), &weights(w1), ap::vlen(n1,n2), v);
2967
+ }
2968
+ if( network.structinfo(offs+0)<0 )
2969
+ {
2970
+ bflag = false;
2971
+ if( network.structinfo(offs+0)==-2||network.structinfo(offs+0)==-3||network.structinfo(offs+0)==-4 )
2972
+ {
2973
+
2974
+ //
2975
+ // Special neuron type, no back-propagation required
2976
+ //
2977
+ bflag = true;
2978
+ }
2979
+ ap::ap_error::make_assertion(bflag, "MLPInternalCalculateGradient: unknown neuron type!");
2980
+ }
2981
+ }
2982
+ }
2983
+
2984
+
2985
+ /*************************************************************************
2986
+ Internal subroutine, chunked gradient
2987
+ *************************************************************************/
2988
+ static void mlpchunkedgradient(multilayerperceptron& network,
2989
+ const ap::real_2d_array& xy,
2990
+ int cstart,
2991
+ int csize,
2992
+ double& e,
2993
+ ap::real_1d_array& grad,
2994
+ bool naturalerrorfunc)
2995
+ {
2996
+ int i;
2997
+ int j;
2998
+ int k;
2999
+ int kl;
3000
+ int n1;
3001
+ int n2;
3002
+ int w1;
3003
+ int w2;
3004
+ int c1;
3005
+ int c2;
3006
+ int ntotal;
3007
+ int nin;
3008
+ int nout;
3009
+ int offs;
3010
+ double dedf;
3011
+ double dfdnet;
3012
+ double f;
3013
+ double df;
3014
+ double d2f;
3015
+ double v;
3016
+ double s;
3017
+ double fown;
3018
+ double deown;
3019
+ double net;
3020
+ double lnnet;
3021
+ double mx;
3022
+ bool bflag;
3023
+ int istart;
3024
+ int ineurons;
3025
+ int idfdnet;
3026
+ int iderror;
3027
+ int izeros;
3028
+
3029
+
3030
+ //
3031
+ // Read network geometry, prepare data
3032
+ //
3033
+ nin = network.structinfo(1);
3034
+ nout = network.structinfo(2);
3035
+ ntotal = network.structinfo(3);
3036
+ istart = network.structinfo(5);
3037
+ c1 = cstart;
3038
+ c2 = cstart+csize-1;
3039
+ ineurons = 0;
3040
+ idfdnet = ntotal;
3041
+ iderror = 2*ntotal;
3042
+ izeros = 3*ntotal;
3043
+ for(j = 0; j <= csize-1; j++)
3044
+ {
3045
+ network.chunks(izeros,j) = 0;
3046
+ }
3047
+
3048
+ //
3049
+ // Forward pass:
3050
+ // 1. Load inputs from XY to Chunks[0:NIn-1,0:CSize-1]
3051
+ // 2. Forward pass
3052
+ //
3053
+ for(i = 0; i <= nin-1; i++)
3054
+ {
3055
+ for(j = 0; j <= csize-1; j++)
3056
+ {
3057
+ if( network.columnsigmas(i)!=0 )
3058
+ {
3059
+ network.chunks(i,j) = (xy(c1+j,i)-network.columnmeans(i))/network.columnsigmas(i);
3060
+ }
3061
+ else
3062
+ {
3063
+ network.chunks(i,j) = xy(c1+j,i)-network.columnmeans(i);
3064
+ }
3065
+ }
3066
+ }
3067
+ for(i = 0; i <= ntotal-1; i++)
3068
+ {
3069
+ offs = istart+i*nfieldwidth;
3070
+ if( network.structinfo(offs+0)>0 )
3071
+ {
3072
+
3073
+ //
3074
+ // Activation function:
3075
+ // * calculate F vector, F(i) = F(NET(i))
3076
+ //
3077
+ n1 = network.structinfo(offs+2);
3078
+ ap::vmove(&network.chunks(i, 0), &network.chunks(n1, 0), ap::vlen(0,csize-1));
3079
+ for(j = 0; j <= csize-1; j++)
3080
+ {
3081
+ mlpactivationfunction(network.chunks(i,j), network.structinfo(offs+0), f, df, d2f);
3082
+ network.chunks(i,j) = f;
3083
+ network.chunks(idfdnet+i,j) = df;
3084
+ }
3085
+ }
3086
+ if( network.structinfo(offs+0)==0 )
3087
+ {
3088
+
3089
+ //
3090
+ // Adaptive summator:
3091
+ // * calculate NET vector, NET(i) = SUM(W(j,i)*Neurons(j),j=N1..N2)
3092
+ //
3093
+ n1 = network.structinfo(offs+2);
3094
+ n2 = n1+network.structinfo(offs+1)-1;
3095
+ w1 = network.structinfo(offs+3);
3096
+ w2 = w1+network.structinfo(offs+1)-1;
3097
+ ap::vmove(&network.chunks(i, 0), &network.chunks(izeros, 0), ap::vlen(0,csize-1));
3098
+ for(j = n1; j <= n2; j++)
3099
+ {
3100
+ v = network.weights(w1+j-n1);
3101
+ ap::vadd(&network.chunks(i, 0), &network.chunks(j, 0), ap::vlen(0,csize-1), v);
3102
+ }
3103
+ }
3104
+ if( network.structinfo(offs+0)<0 )
3105
+ {
3106
+ bflag = false;
3107
+ if( network.structinfo(offs+0)==-2 )
3108
+ {
3109
+
3110
+ //
3111
+ // input neuron, left unchanged
3112
+ //
3113
+ bflag = true;
3114
+ }
3115
+ if( network.structinfo(offs+0)==-3 )
3116
+ {
3117
+
3118
+ //
3119
+ // "-1" neuron
3120
+ //
3121
+ for(k = 0; k <= csize-1; k++)
3122
+ {
3123
+ network.chunks(i,k) = -1;
3124
+ }
3125
+ bflag = true;
3126
+ }
3127
+ if( network.structinfo(offs+0)==-4 )
3128
+ {
3129
+
3130
+ //
3131
+ // "0" neuron
3132
+ //
3133
+ for(k = 0; k <= csize-1; k++)
3134
+ {
3135
+ network.chunks(i,k) = 0;
3136
+ }
3137
+ bflag = true;
3138
+ }
3139
+ ap::ap_error::make_assertion(bflag, "MLPChunkedGradient: internal error - unknown neuron type!");
3140
+ }
3141
+ }
3142
+
3143
+ //
3144
+ // Post-processing, error, dError/dOut
3145
+ //
3146
+ for(i = 0; i <= ntotal-1; i++)
3147
+ {
3148
+ ap::vmove(&network.chunks(iderror+i, 0), &network.chunks(izeros, 0), ap::vlen(0,csize-1));
3149
+ }
3150
+ ap::ap_error::make_assertion(network.structinfo(6)==0||network.structinfo(6)==1, "MLPChunkedGradient: unknown normalization type!");
3151
+ if( network.structinfo(6)==1 )
3152
+ {
3153
+
3154
+ //
3155
+ // Softmax output, classification network.
3156
+ //
3157
+ // For each K = 0..CSize-1 do:
3158
+ // 1. place exp(outputs[k]) to NWBuf[0:NOut-1]
3159
+ // 2. place sum(exp(..)) to NET
3160
+ // 3. calculate dError/dOut and place it to the second block of Chunks
3161
+ //
3162
+ for(k = 0; k <= csize-1; k++)
3163
+ {
3164
+
3165
+ //
3166
+ // Normalize
3167
+ //
3168
+ mx = network.chunks(ntotal-nout,k);
3169
+ for(i = 1; i <= nout-1; i++)
3170
+ {
3171
+ mx = ap::maxreal(mx, network.chunks(ntotal-nout+i,k));
3172
+ }
3173
+ net = 0;
3174
+ for(i = 0; i <= nout-1; i++)
3175
+ {
3176
+ network.nwbuf(i) = exp(network.chunks(ntotal-nout+i,k)-mx);
3177
+ net = net+network.nwbuf(i);
3178
+ }
3179
+
3180
+ //
3181
+ // Calculate error function and dError/dOut
3182
+ //
3183
+ if( naturalerrorfunc )
3184
+ {
3185
+
3186
+ //
3187
+ // Natural error func.
3188
+ //
3189
+ //
3190
+ s = 1;
3191
+ lnnet = log(net);
3192
+ kl = ap::round(xy(cstart+k,nin));
3193
+ for(i = 0; i <= nout-1; i++)
3194
+ {
3195
+ if( i==kl )
3196
+ {
3197
+ v = 1;
3198
+ }
3199
+ else
3200
+ {
3201
+ v = 0;
3202
+ }
3203
+ network.chunks(iderror+ntotal-nout+i,k) = s*network.nwbuf(i)/net-v;
3204
+ e = e+safecrossentropy(v, network.nwbuf(i)/net);
3205
+ }
3206
+ }
3207
+ else
3208
+ {
3209
+
3210
+ //
3211
+ // Least squares error func
3212
+ // Error, dError/dOut(normalized)
3213
+ //
3214
+ kl = ap::round(xy(cstart+k,nin));
3215
+ for(i = 0; i <= nout-1; i++)
3216
+ {
3217
+ if( i==kl )
3218
+ {
3219
+ v = network.nwbuf(i)/net-1;
3220
+ }
3221
+ else
3222
+ {
3223
+ v = network.nwbuf(i)/net;
3224
+ }
3225
+ network.nwbuf(nout+i) = v;
3226
+ e = e+ap::sqr(v)/2;
3227
+ }
3228
+
3229
+ //
3230
+ // From dError/dOut(normalized) to dError/dOut(non-normalized)
3231
+ //
3232
+ v = ap::vdotproduct(&network.nwbuf(nout), &network.nwbuf(0), ap::vlen(nout,2*nout-1));
3233
+ for(i = 0; i <= nout-1; i++)
3234
+ {
3235
+ fown = network.nwbuf(i);
3236
+ deown = network.nwbuf(nout+i);
3237
+ network.chunks(iderror+ntotal-nout+i,k) = (-v+deown*fown+deown*(net-fown))*fown/ap::sqr(net);
3238
+ }
3239
+ }
3240
+ }
3241
+ }
3242
+ else
3243
+ {
3244
+
3245
+ //
3246
+ // Normal output, regression network
3247
+ //
3248
+ // For each K = 0..CSize-1 do:
3249
+ // 1. calculate dError/dOut and place it to the second block of Chunks
3250
+ //
3251
+ for(i = 0; i <= nout-1; i++)
3252
+ {
3253
+ for(j = 0; j <= csize-1; j++)
3254
+ {
3255
+ v = network.chunks(ntotal-nout+i,j)*network.columnsigmas(nin+i)+network.columnmeans(nin+i)-xy(cstart+j,nin+i);
3256
+ network.chunks(iderror+ntotal-nout+i,j) = v*network.columnsigmas(nin+i);
3257
+ e = e+ap::sqr(v)/2;
3258
+ }
3259
+ }
3260
+ }
3261
+
3262
+ //
3263
+ // Backpropagation
3264
+ //
3265
+ for(i = ntotal-1; i >= 0; i--)
3266
+ {
3267
+
3268
+ //
3269
+ // Extract info
3270
+ //
3271
+ offs = istart+i*nfieldwidth;
3272
+ if( network.structinfo(offs+0)>0 )
3273
+ {
3274
+
3275
+ //
3276
+ // Activation function
3277
+ //
3278
+ n1 = network.structinfo(offs+2);
3279
+ for(k = 0; k <= csize-1; k++)
3280
+ {
3281
+ network.chunks(iderror+i,k) = network.chunks(iderror+i,k)*network.chunks(idfdnet+i,k);
3282
+ }
3283
+ ap::vadd(&network.chunks(iderror+n1, 0), &network.chunks(iderror+i, 0), ap::vlen(0,csize-1));
3284
+ }
3285
+ if( network.structinfo(offs+0)==0 )
3286
+ {
3287
+
3288
+ //
3289
+ // "Normal" activation function
3290
+ //
3291
+ n1 = network.structinfo(offs+2);
3292
+ n2 = n1+network.structinfo(offs+1)-1;
3293
+ w1 = network.structinfo(offs+3);
3294
+ w2 = w1+network.structinfo(offs+1)-1;
3295
+ for(j = w1; j <= w2; j++)
3296
+ {
3297
+ v = ap::vdotproduct(&network.chunks(n1+j-w1, 0), &network.chunks(iderror+i, 0), ap::vlen(0,csize-1));
3298
+ grad(j) = grad(j)+v;
3299
+ }
3300
+ for(j = n1; j <= n2; j++)
3301
+ {
3302
+ v = network.weights(w1+j-n1);
3303
+ ap::vadd(&network.chunks(iderror+j, 0), &network.chunks(iderror+i, 0), ap::vlen(0,csize-1), v);
3304
+ }
3305
+ }
3306
+ if( network.structinfo(offs+0)<0 )
3307
+ {
3308
+ bflag = false;
3309
+ if( network.structinfo(offs+0)==-2||network.structinfo(offs+0)==-3||network.structinfo(offs+0)==-4 )
3310
+ {
3311
+
3312
+ //
3313
+ // Special neuron type, no back-propagation required
3314
+ //
3315
+ bflag = true;
3316
+ }
3317
+ ap::ap_error::make_assertion(bflag, "MLPInternalCalculateGradient: unknown neuron type!");
3318
+ }
3319
+ }
3320
+ }
3321
+
3322
+
3323
+ /*************************************************************************
3324
+ Returns T*Ln(T/Z), guarded against overflow/underflow.
3325
+ Internal subroutine.
3326
+ *************************************************************************/
3327
+ static double safecrossentropy(double t, double z)
3328
+ {
3329
+ double result;
3330
+ double r;
3331
+
3332
+ if( t==0 )
3333
+ {
3334
+ result = 0;
3335
+ }
3336
+ else
3337
+ {
3338
+ if( fabs(z)>1 )
3339
+ {
3340
+
3341
+ //
3342
+ // Shouldn't be the case with softmax,
3343
+ // but we just want to be sure.
3344
+ //
3345
+ if( t/z==0 )
3346
+ {
3347
+ r = ap::minrealnumber;
3348
+ }
3349
+ else
3350
+ {
3351
+ r = t/z;
3352
+ }
3353
+ }
3354
+ else
3355
+ {
3356
+
3357
+ //
3358
+ // Normal case
3359
+ //
3360
+ if( z==0||fabs(t)>=ap::maxrealnumber*fabs(z) )
3361
+ {
3362
+ r = ap::maxrealnumber;
3363
+ }
3364
+ else
3365
+ {
3366
+ r = t/z;
3367
+ }
3368
+ }
3369
+ result = t*log(r);
3370
+ }
3371
+ return result;
3372
+ }
3373
+
3374
+
3375
+