1 /**********************************************************************
2 FILE : %W%
3
4 SHORTNAME :
5 SNNS VERSION : 4.2
6
7 PURPOSE : Implement Kindermann/Linden-inversion-method
8
9 NOTES : The functions implemented here closely resemble the
10 the functions propagateNetForward and propagateNetBackward2
11 in the file learn_f.c.
12 FUNCTIONS : -- kr_initInversion
13 Purpose : initialize net for inversion algorithm
14 Calls : int kr_topoCheck();
15 int kr_IOCheck();
16 int kr_topoSort();
17
18 -- kr_inv_forwardPass
19 Purpose : topological forward propagation
20 Calls : nothing
21
22 -- kr_inv_backwardPass
23 Purpose : Backward error propagation (topological)
24 Calls : nothing
25
26 AUTHOR : Guenter Mamier
27 DATE : 04.02.92
28
29 CHANGED BY : Sven Doering, Michael Vogt
30 RCS VERSION : $Revision: 2.8 $
31 LAST CHANGE : $Date: 1998/03/13 16:23:56 $
32
33 Copyright (c) 1990-1995 SNNS Group, IPVR, Univ. Stuttgart, FRG
34 Copyright (c) 1996-1998 SNNS Group, WSI, Univ. Tuebingen, FRG
35
36 **********************************************************************/
37 #include <config.h>
38 #include <stdio.h>
39 #include <math.h>
40 #ifdef HAVE_VALUES_H
41 #include <values.h>
42 #endif
43
44 #include "kr_typ.h"
45 #include "kr_const.h"
46 #include "kernel.h"
47 #include "kr_def.h"
48 #include "kr_mac.h"
49 #include "kr_inversion.ph"
50
51 extern FlintType ACT_Custom_Python(struct Unit * unit_ptr);
52 extern FlintType ACT_DERIV_Custom_Python(struct Unit * unit_ptr);
53 extern FlintType ACT_2_DERIV_Custom_Python(struct Unit * unit_ptr);
54
55
56
57 /*****************************************************************************
58 FUNCTION : kr_initInversion
59
60 PURPOSE : initialize net for inversion algorithm
61 NOTES :
62 UPDATE : 06.02.92
63 ******************************************************************************/
kr_initInversion(void)64 int kr_initInversion(void)
65 {
66 int ret_code = KRERR_NO_ERROR;
67
68 if (NetModified || (TopoSortID != TOPOLOGICAL_FF &&
69 TopoSortID != TOPOLOGIC_LOGICAL)){
70 /* Net has been modified or topologic array isn't initialized */
71 /* check the topology of the network */
72 ret_code = kr_topoCheck();
73 if (ret_code < KRERR_NO_ERROR)
74 return( ret_code ); /* an error has occured */
75 if (ret_code < 2)
76 return( KRERR_NET_DEPTH ); /* the network has less then 2 layers */
77
78
79 /* count the no. of I/O units and check the patterns */
80 ret_code = kr_IOCheck();
81 if(ret_code < KRERR_NO_ERROR)
82 return( ret_code );
83
84 /* sort units by topology and by topologic type */
85
86 ret_code = kr_topoSort( TOPOLOGICAL_FF );
87 }
88 return(ret_code);
89 }
90
91
92
93 /*****************************************************************************
94 FUNCTION : kr_inv_forwardPass
95
96 PURPOSE : topological forward propagation
97 NOTES :
98 UPDATE : 29.01.92
99 ******************************************************************************/
100 extern FlintType OUT_Custom_Python(FlintType act);
101
kr_inv_forwardPass(struct UnitList * inputs)102 void kr_inv_forwardPass(struct UnitList *inputs)
103 {
104
105 register struct Unit *unit_ptr;
106 register TopoPtrArray topo_ptr; /* points to a topological sorted */
107 /* unit stucture (input units first) */
108 struct UnitList *IUnit; /* working list of input units */
109
110
111 /* initialize the topological pointer */
112
113 topo_ptr = topo_ptr_array;
114
115
116 /* calculate the activation and output value of the input units */
117
118 IUnit = inputs;
119 while((unit_ptr = *++topo_ptr) != NULL){
120
121 /* clear error values */
122 unit_ptr->Aux.flint_no = 0.0;
123
124 if(unit_ptr->out_func == OUT_IDENTITY)
125 unit_ptr->Out.output = unit_ptr->act = IUnit->act;
126 else if(unit_ptr->out_func == OUT_Custom_Python) /* no identity output function: calculate unit's output also */
127 unit_ptr->Out.output =
128 kr_PythonOutFunction(unit_ptr->python_out_func,
129 unit_ptr->act = IUnit->act);
130 else /* no identity output function: calculate unit's output also */
131 unit_ptr->Out.output = (*unit_ptr->out_func)(unit_ptr->act = IUnit->act);
132 IUnit = IUnit->next;
133 }
134
135
136 /* popagate hidden units */
137
138 while((unit_ptr = *++topo_ptr) != NULL){
139
140 /* clear error values */
141 unit_ptr->Aux.flint_no = 0.0;
142
143 /* calculate the activation value of the unit:
144 call the activation function if needed */
145 unit_ptr->act = ((unit_ptr->act_func == ACT_Custom_Python) ?
146 kr_PythonActFunction(unit_ptr->python_act_func,
147 unit_ptr) :
148 (unit_ptr->act_func) (unit_ptr)) ;
149
150 if(unit_ptr->out_func == OUT_IDENTITY)
151 unit_ptr->Out.output = unit_ptr->act;
152 else if(unit_ptr->out_func == OUT_Custom_Python)
153 unit_ptr->Out.output =
154 kr_PythonOutFunction(unit_ptr->python_out_func,
155 unit_ptr->act);
156 else
157 /* no identity output function: calculate unit's output also */
158 unit_ptr->Out.output = (*unit_ptr->out_func) (unit_ptr->act);
159 }
160
161
162 /* popagate output units */
163
164 while((unit_ptr = *++topo_ptr) != NULL){
165
166 /* clear error values */
167 unit_ptr->Aux.flint_no = 0.0;
168
169 /* calculate the activation value of the unit:
170 call the activation function if needed */
171 unit_ptr->act = ((unit_ptr->act_func == ACT_Custom_Python) ?
172 kr_PythonActFunction(unit_ptr->python_act_func,
173 unit_ptr) :
174 (unit_ptr->act_func) (unit_ptr)) ;
175
176 if(unit_ptr->out_func == OUT_IDENTITY)
177 unit_ptr->Out.output = unit_ptr->act;
178 else if(unit_ptr->out_func == OUT_Custom_Python) /* no identity output function: calculate unit's output also */
179 unit_ptr->Out.output =
180 kr_PythonOutFunction(unit_ptr->python_out_func,
181 unit_ptr->act);
182 else /* no identity output function: calculate unit's output also */
183 unit_ptr->Out.output = (*unit_ptr->out_func) (unit_ptr->act);
184 }
185 }
186
187
188
189 /*****************************************************************************
190 FUNCTION : kr_inv_backwardPass
191
192 PURPOSE : Backward error propagation (topological)
193 NOTES :
194 UPDATE : 04.02.92
195 *****************************************************************************/
kr_inv_backwardPass(float learn,float delta_max,int * err_units,float ratio,struct UnitList * inputs,struct UnitList * outputs)196 double kr_inv_backwardPass(float learn, float delta_max, int *err_units,
197 float ratio, struct UnitList *inputs,
198 struct UnitList *outputs)
199 {
200 register struct Link *link_ptr;
201 register struct Site *site_ptr;
202 register struct Unit *unit_ptr;
203 register float error, sum_error, eta, devit;
204 register TopoPtrArray topo_ptr;
205 struct UnitList *IUnit, *OUnit;
206
207
208 sum_error = 0.0; /* reset network error */
209 *err_units = 0; /* reset error units */
210 eta = learn; /* store learn_parameter in CPU register */
211
212
213 /* add 3 to no_of_topo_units because topologic array contains 4 NULL
214 pointers */
215
216 topo_ptr = topo_ptr_array + (no_of_topo_units + 3);
217
218
219 /* calculate output units only */
220
221 OUnit = outputs;
222 while(OUnit->next != NULL)OUnit = OUnit->next;
223 while((unit_ptr = *--topo_ptr) != NULL){
224
225
226 /* calc. devitation */
227 devit = OUnit->i_act - unit_ptr->Out.output;
228 OUnit->act = unit_ptr->Out.output;
229 OUnit = OUnit->prev;
230 if ( (devit > -delta_max) && (devit < delta_max) ){
231 continue;
232 }else{
233 *err_units += 1;
234 }
235
236 /* sum up the error of the network */
237 sum_error += devit * devit;
238
239 /* calc. error for output units */
240 error = devit * ((unit_ptr->act_deriv_func == ACT_DERIV_Custom_Python) ?
241 kr_PythonActFunction(unit_ptr->python_act_deriv_func,
242 unit_ptr) :
243 (unit_ptr->act_deriv_func) (unit_ptr)) ;
244 /* error = devit;*/
245
246 /* Calculate sum of errors of predecessor units */
247 if(UNIT_HAS_DIRECT_INPUTS( unit_ptr )){
248 FOR_ALL_LINKS( unit_ptr, link_ptr )
249 link_ptr->to->Aux.flint_no += link_ptr->weight * error;
250 }else{ /* the unit has sites */
251 FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr )
252 link_ptr->to->Aux.flint_no += link_ptr->weight * error;
253 }
254 }
255
256
257 /* calculate hidden units only */
258
259 while((unit_ptr = *--topo_ptr) != NULL){
260
261 /* calc. the error of the (hidden) unit */
262 error = ((unit_ptr->act_deriv_func == ACT_DERIV_Custom_Python) ?
263 kr_PythonActFunction(unit_ptr->python_act_deriv_func,
264 unit_ptr) :
265 (unit_ptr->act_deriv_func) (unit_ptr)) * unit_ptr->Aux.flint_no;
266 error = unit_ptr->Aux.flint_no;
267
268 /* Calculate sum of errors of predecessor units */
269 if(UNIT_HAS_DIRECT_INPUTS( unit_ptr )){
270 FOR_ALL_LINKS( unit_ptr, link_ptr )
271 link_ptr->to->Aux.flint_no += link_ptr->weight * error;
272 }else{ /* the unit has sites */
273 FOR_ALL_SITES_AND_LINKS( unit_ptr, site_ptr, link_ptr )
274 link_ptr->to->Aux.flint_no += link_ptr->weight * error;
275 }
276 unit_ptr->act = unit_ptr->i_act;
277 }
278
279
280 /* calculate input units only */
281
282 IUnit = inputs;
283 while(IUnit->next != NULL)IUnit = IUnit->next;
284 while((unit_ptr = *--topo_ptr) != NULL){
285
286 /* calc. the error of the (input) unit */
287 error = ((unit_ptr->act_deriv_func == ACT_DERIV_Custom_Python) ?
288 kr_PythonActFunction(unit_ptr->python_act_deriv_func,
289 unit_ptr) :
290 (unit_ptr->act_deriv_func) (unit_ptr)) * unit_ptr->Aux.flint_no;
291 error = unit_ptr->Aux.flint_no;
292
293 /* Calculate the new activation for the input units */
294 IUnit->im_act += eta * error + ratio*(IUnit->i_act - (float)unit_ptr->act);
295 unit_ptr->act = 1.0 / (1.0 + exp((double)(-IUnit->im_act)));
296 IUnit->act = unit_ptr->act;
297 IUnit = IUnit->prev;
298 }
299
300
301 /* return the error of the network */
302
303 sum_error *= 0.5;
304 return( sum_error );
305
306
307 }
308
309
310
311
312
313