/***************************************************************************** FILE : $Source: /projects/higgs1/SNNS/CVS/SNNS/kernel/sources/stochastic_learn_f.c,v $ SHORTNAME : stochastic_learn_f.c SNNS VERSION : 4.2 PURPOSE : SNNS-Kernel Learning Functions NOTES : with following learning functions: - Monte-Carlo - Simulated Annealing AUTHOR : Joachim Danz DATE : 27.04.1994 CHANGED BY : Guenter Mamier RCS VERSION : $Revision: 1.9 $ LAST CHANGE : $Date: 1998/03/13 16:24:03 $ Copyright (c) 1994-95 Joachim Danz, TH Darmstadt, FRG Copyright (c) 1996-1998 SNNS Group, WSI, Univ. Tuebingen, FRG ******************************************************************************/ #include #include #include #ifdef HAVE_VALUES_H #include #endif #include "kr_typ.h" /* Kernel Types and Constants */ #include "kr_const.h" /* Constant Declarators for SNNS-Kernel */ #include "kr_def.h" /* Default Values */ #include "kernel.h" /* kernel function prototypes */ #include "kr_mac.h" /* Kernel Macros */ #include "glob_typ.h" #include "kr_art.h" #include "kr_art1.h" #include "kr_art2.h" #include "kr_amap.h" #include "krart_df.h" #include "learn_f.h" #include "stochastic_learn_f.ph" #include "random.h" #include "kr_newpattern.h" #define NOT_MODIFIED 0 #define LAST_MODIFIED 1 /***************************************************************************** FUNCTION : LEARN_MonteCarlo PURPOSE : Monte Carlo adjustment of weights and bias RETURNS : error NOTES : UPDATE : 19.02.1995 ******************************************************************************/ krui_err LEARN_MonteCarlo(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams) { static float OutParameter[1]; /* OutParameter[0] stores the * learning error */ int ret_code, pattern_no, sub_pat_no; float error; register FlagWord flags; register struct Link *link_ptr; register struct Unit *unit_ptr; register struct Site *site_ptr; if (NoOfInParams < 2) return (KRERR_PARAMETERS); /* Not enough input parameters */ *NoOfOutParams = 1; /* One return value is available (the * learning error) */ *parameterOutArray = OutParameter; /* set the output parameter reference */ ret_code = KRERR_NO_ERROR; /* reset return code */ if (NetModified) { /* Net has been modified */ /* count the no. of I/O units and check the patterns */ ret_code = kr_IOCheck(); if (ret_code < KRERR_NO_ERROR) return (ret_code); /* sort units by topology and by topologic type */ ret_code = kr_topoSort(TOPOLOGICAL_FF); if ((ret_code != KRERR_NO_ERROR) && (ret_code != KRERR_DEAD_UNITS)) return (ret_code); MinimumError = 10000000; NetModified = FALSE; } if (NetInitialize || LearnFuncHasChanged) { /* Net has been modified */ MinimumError = 10000000; } /* randomize weigths and bias */ FOR_ALL_UNITS(unit_ptr) { unit_ptr->bias = (FlintType) drand48() * (LEARN_PARAM2(parameterInArray) - LEARN_PARAM1(parameterInArray)) + LEARN_PARAM1(parameterInArray); flags = unit_ptr->flags; if ((flags & UFLAG_IN_USE) == UFLAG_IN_USE) { /* unit is in use */ unit_ptr->value_a = (FlintType) 0; if (flags & UFLAG_SITES) { /* unit has sites */ FOR_ALL_SITES_AND_LINKS(unit_ptr, site_ptr, link_ptr) link_ptr->weight = (FlintType) drand48() * (LEARN_PARAM2(parameterInArray) - LEARN_PARAM1(parameterInArray)) + LEARN_PARAM1(parameterInArray); } else { /* unit has no sites */ if (flags & UFLAG_DLINKS) { /* unit has direct links */ FOR_ALL_LINKS(unit_ptr, link_ptr) link_ptr->weight = (FlintType) drand48() * (LEARN_PARAM2(parameterInArray) - LEARN_PARAM1(parameterInArray)) + LEARN_PARAM1(parameterInArray); } } } } /* compute the necessary sub patterns */ KernelErrorCode = kr_initSubPatternOrder(start_pattern, end_pattern); if (KernelErrorCode != KRERR_NO_ERROR) return (KernelErrorCode); NET_ERROR(OutParameter) = 0.0; /* reset network error value */ /* calculate performance of new net */ while (kr_getSubPatternByOrder(&pattern_no, &sub_pat_no)) { propagateNetForward(pattern_no, sub_pat_no); /* Forward propagation */ if ((error = calculate_SS_error(pattern_no, sub_pat_no)) == -1) return (-1); NET_ERROR(OutParameter) += error; } /* store weights and bias if error decreased */ if (NET_ERROR(OutParameter) < MinimumError) { MinimumError = NET_ERROR(OutParameter); FOR_ALL_UNITS(unit_ptr) { flags = unit_ptr->flags; unit_ptr->value_b = unit_ptr->bias; if ((flags & UFLAG_IN_USE) == UFLAG_IN_USE) { /* unit is in use */ if (flags & UFLAG_SITES) { /* unit has sites */ FOR_ALL_SITES_AND_LINKS(unit_ptr, site_ptr, link_ptr) link_ptr->value_b = link_ptr->weight; } else { /* unit has no sites */ if (flags & UFLAG_DLINKS) { /* unit has direct links */ FOR_ALL_LINKS(unit_ptr, link_ptr) link_ptr->value_b = link_ptr->weight; } } } } } /* restore best net */ FOR_ALL_UNITS(unit_ptr) { flags = unit_ptr->flags; unit_ptr->bias = unit_ptr->value_b; if ((flags & UFLAG_IN_USE) == UFLAG_IN_USE) { /* unit is in use */ if (flags & UFLAG_SITES) { /* unit has sites */ FOR_ALL_SITES_AND_LINKS(unit_ptr, site_ptr, link_ptr) link_ptr->weight = link_ptr->value_b; } else { /* unit has no sites */ if (flags & UFLAG_DLINKS) { /* unit has direct links */ FOR_ALL_LINKS(unit_ptr, link_ptr) link_ptr->weight = link_ptr->value_b; } } } } return (ret_code); } /***************************************************************************** FUNCTION : TEST_MonteCarlo PURPOSE : Monte Carlo adjustment of weights and bias RETURNS : error NOTES : UPDATE : 17.02.1995 *****************************************************************************/ krui_err TEST_MonteCarlo(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams) { static float OutParameter[1]; /* OutParameter[0] stores the * learning error */ int ret_code, pattern_no, sub_pat_no; float error; *NoOfOutParams = 1; /* One return value is available (the * learning error) */ *parameterOutArray = OutParameter; /* set the output parameter reference */ ret_code = KRERR_NO_ERROR; /* reset return code */ /* compute the necessary sub patterns */ KernelErrorCode = kr_initSubPatternOrder(start_pattern, end_pattern); if (KernelErrorCode != KRERR_NO_ERROR) return (KernelErrorCode); NET_ERROR(OutParameter) = 0.0; /* reset network error value */ /* calculate performance of new net */ while (kr_getSubPatternByOrder(&pattern_no, &sub_pat_no)) { propagateNetForward(pattern_no, sub_pat_no); /* Forward propagation */ if ((error = calculate_SS_error(pattern_no, sub_pat_no)) == -1) return (-1); NET_ERROR(OutParameter) += error; } return (ret_code); } /***************************************************************************** FUNCTION : calculate_WTA_errror PURPOSE : Winner Takes All error calculation for one pattern RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ float calculate_WTA_error(int pattern_no, int sub_pat_no) { int j, wta_pos, out_pat_pos, size; float wta_value, out_pat_value; register struct Unit *unit_ptr; register Patterns out_pat; register TopoPtrArray topo_ptr; /* calculate address of the output pattern (with number pattern_no + 1) */ out_pat = kr_getSubPatData(pattern_no, sub_pat_no, OUTPUT, &size); if (out_pat == NULL) { KernelErrorCode = KRERR_NP_NO_SUCH_PATTERN; return (-1); } out_pat += size; /* * add 3 to no_of_topo_units because the topologic array contains 4 NULL * pointers */ topo_ptr = topo_ptr_array + (no_of_topo_units + 3); wta_value = 0; wta_pos = 0; out_pat_value = 0; out_pat_pos = 0; j = 0; /* Winner Takes All - error computation */ if (NoOfOutputUnits > 1) { /* calculate output units only */ while ((unit_ptr = *--topo_ptr) != NULL) { j++; if (wta_value < unit_ptr->Out.output) { wta_value = unit_ptr->Out.output; wta_pos = j; } if (out_pat_value < *(--out_pat)) { out_pat_value = *(out_pat); out_pat_pos = j; } } if (wta_pos != out_pat_pos) { return ((float) 1.0); } } else { unit_ptr = *--topo_ptr; if ((float) unit_ptr->Out.output > 0.5) { if (*(--out_pat) < 0.5) return ((float) 1.0); } else { if (*(--out_pat) > 0.5) return ((float) 1.0); } } return ((float) 0.0); } /***************************************************************************** FUNCTION : calculate_w_WTA_errror PURPOSE : weighted Winner Takes All error calculation for one pattern RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ float calculate_w_WTA_error(int pattern_no, int sub_pat_no) { int j, wta_pos, out_pat_pos, size; float wta_value, out_pat_value, sum_value; register struct Unit *unit_ptr; register Patterns out_pat; register TopoPtrArray topo_ptr; /* calculate address of the output pattern (with number pattern_no + 1) */ out_pat = kr_getSubPatData(pattern_no, sub_pat_no, OUTPUT, &size); if (out_pat == NULL) { KernelErrorCode = KRERR_NP_NO_SUCH_PATTERN; return (-1); } out_pat += size; /* * add 3 to no_of_topo_units because the topologic array contains 4 NULL * pointers */ topo_ptr = topo_ptr_array + (no_of_topo_units + 3); wta_value = 0; wta_pos = 0; sum_value = 0; out_pat_value = 0; out_pat_pos = 0; j = 0; /* weighted Winner Takes All - error computation */ if (NoOfOutputUnits > 1) { /* calculate output units only */ while ((unit_ptr = *--topo_ptr) != NULL) { j++; sum_value += unit_ptr->Out.output; if (wta_value < unit_ptr->Out.output) { wta_value = unit_ptr->Out.output; wta_pos = j; } if (out_pat_value < *(--out_pat)) { out_pat_value = *(out_pat); out_pat_pos = j; } } if (wta_pos != out_pat_pos) return ((float) 1.0); else return ((float) fabs(wta_value - (sum_value - wta_value) / (--j))); } else { unit_ptr = *--topo_ptr; if ((float) unit_ptr->Out.output > 0.5) { if (*(--out_pat) < 0.5) return ((float) 1.0); else return ((float) fabs(unit_ptr->Out.output - *(out_pat)) / 2); } else { if (*(--out_pat) > 0.5) return ((float) 1.0); else return ((float) fabs(*(out_pat) - unit_ptr->Out.output) / 2); } } return ((float) 0.0); } /***************************************************************************** FUNCTION : calculate_SS_errror PURPOSE : sum squared error for one pattern RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ float calculate_SS_error(int pattern_no, int sub_pat_no) { int size; float sum_error, error; register struct Unit *unit_ptr; register Patterns out_pat; register TopoPtrArray topo_ptr; /* calculate address of the output pattern (with number pattern_no + 1) */ out_pat = kr_getSubPatData(pattern_no, sub_pat_no, OUTPUT, &size); if (out_pat == NULL) { KernelErrorCode = KRERR_NP_NO_SUCH_PATTERN; return (-1); } out_pat += size; /* * add 3 to no_of_topo_units because the topologic array contains 4 NULL * pointers */ topo_ptr = topo_ptr_array + (no_of_topo_units + 3); sum_error = 0; /* calculate output units only */ while ((unit_ptr = *--topo_ptr) != NULL) { error = *(--out_pat) - unit_ptr->Out.output; sum_error += error * error; } /* calc. devitation */ return ((float) sum_error); } /***************************************************************************** FUNCTION : LEARN_SimulatedAnnealingSS PURPOSE : Simulated Annealing adjustment of weights and bias RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ krui_err LEARN_SimulatedAnnealingSS(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams) { return (LEARN_SimulatedAnnealing(start_pattern, end_pattern, parameterInArray, NoOfInParams, parameterOutArray, NoOfOutParams, SS_ERROR)); } /***************************************************************************** FUNCTION : LEARN_SimulatedAnnealingWTA PURPOSE : Simulated Annealing adjustment of weights and bias RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ krui_err LEARN_SimulatedAnnealingWTA(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams) { return (LEARN_SimulatedAnnealing(start_pattern, end_pattern, parameterInArray, NoOfInParams, parameterOutArray, NoOfOutParams, WTA_ERROR)); } /***************************************************************************** FUNCTION : LEARN_SimulatedAnnealingWWTA PURPOSE : Simulated Annealing adjustment of weights and bias RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ krui_err LEARN_SimulatedAnnealingWWTA(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams) { return (LEARN_SimulatedAnnealing(start_pattern, end_pattern, parameterInArray, NoOfInParams, parameterOutArray, NoOfOutParams, WWTA_ERROR)); } /***************************************************************************** FUNCTION : LEARN_SimulatedAnnealing PURPOSE : Simulated Annealing adjustment of weights and bias RETURNS : error NOTES : UPDATE : 19.02.1995 ******************************************************************************/ krui_err LEARN_SimulatedAnnealing(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams, int errorFunction) { static float OutParameter[1]; /* OutParameter[0] stores the * learning error */ int ret_code, pattern_no, sub_pat_no; float error; long int NextParameter; register FlagWord flags; register struct Link *link_ptr; register struct Unit *unit_ptr; register struct Site *site_ptr; if (NoOfInParams < 4) return (KRERR_PARAMETERS); /* Not enough input parameters */ *NoOfOutParams = 1; /* One return value is available (the * learning error) */ *parameterOutArray = OutParameter; /* set the output parameter reference */ ret_code = KRERR_NO_ERROR; /* reset return code */ NextParameter = FALSE; if (NetModified || NetInitialize || LearnFuncHasChanged) { /* Net has been modified */ /* count the no. of I/O units and check the patterns */ ret_code = kr_IOCheck(); if (ret_code < KRERR_NO_ERROR) return (ret_code); /* sort units by topology and by topologic type */ ret_code = kr_topoSort(TOPOLOGIC_TYPE); if ((ret_code != KRERR_NO_ERROR) && (ret_code != KRERR_DEAD_UNITS)) return (ret_code); FOR_ALL_UNITS(unit_ptr) { flags = unit_ptr->flags; unit_ptr->value_b = NOT_MODIFIED; if ((flags & UFLAG_IN_USE) == UFLAG_IN_USE) { /* unit is in use */ if (flags & UFLAG_SITES) { /* unit has sites */ FOR_ALL_SITES_AND_LINKS(unit_ptr, site_ptr, link_ptr) link_ptr->value_b = NOT_MODIFIED; } else { /* unit has no sites */ if (flags & UFLAG_DLINKS) { /* unit has direct links */ FOR_ALL_LINKS(unit_ptr, link_ptr) link_ptr->value_b = NOT_MODIFIED; } } } } Temperature = LEARN_PARAM3(parameterInArray); MinimumError = 99999; NetModified = FALSE; NextParameter = TRUE; } /* randomize one weigth or one bias */ do { FOR_ALL_UNITS(unit_ptr) { flags = unit_ptr->flags; if (((flags & UFLAG_IN_USE) == UFLAG_IN_USE) && ((flags & UFLAG_TTYP_IN) != UFLAG_TTYP_IN) && !(IS_SPECIAL_UNIT(unit_ptr))) { /* unit is in use */ if (NextParameter == TRUE) { unit_ptr->value_c = unit_ptr->bias; unit_ptr->bias = (FlintType) drand48() * (LEARN_PARAM2(parameterInArray) - LEARN_PARAM1(parameterInArray)) + LEARN_PARAM1(parameterInArray); NextParameter = FALSE; unit_ptr->value_b = LAST_MODIFIED; } else { if (unit_ptr->value_b == LAST_MODIFIED) { unit_ptr->value_b = NOT_MODIFIED; NextParameter = TRUE; } } if (flags & UFLAG_SITES) { /* unit has sites */ FOR_ALL_SITES_AND_LINKS(unit_ptr, site_ptr, link_ptr) if (NextParameter == TRUE) { link_ptr->value_c = link_ptr->weight; link_ptr->weight = (FlintType) drand48() * (LEARN_PARAM2(parameterInArray) - LEARN_PARAM1(parameterInArray)) + LEARN_PARAM1(parameterInArray); NextParameter = FALSE; link_ptr->value_b = LAST_MODIFIED; } else { if (link_ptr->value_b == LAST_MODIFIED) { link_ptr->value_b = NOT_MODIFIED; NextParameter = TRUE; } } } else { /* unit has no sites */ if (flags & UFLAG_DLINKS) { /* unit has direct links */ FOR_ALL_LINKS(unit_ptr, link_ptr) if (NextParameter == TRUE) { link_ptr->value_c = link_ptr->weight; link_ptr->weight = (FlintType) drand48() * (LEARN_PARAM2(parameterInArray) - LEARN_PARAM1(parameterInArray)) + LEARN_PARAM1(parameterInArray); NextParameter = FALSE; link_ptr->value_b = LAST_MODIFIED; } else { if (link_ptr->value_b == LAST_MODIFIED) { link_ptr->value_b = NOT_MODIFIED; NextParameter = TRUE; } } } } } } } while (NextParameter == TRUE); /* compute the necessary sub patterns */ KernelErrorCode = kr_initSubPatternOrder(start_pattern, end_pattern); if (KernelErrorCode != KRERR_NO_ERROR) return (KernelErrorCode); NET_ERROR(OutParameter) = 0.0; /* reset network error value */ /* calculate performance of new net */ while (kr_getSubPatternByOrder(&pattern_no, &sub_pat_no)) { propagateNetForward(pattern_no, sub_pat_no); /* Forward propagation */ switch (errorFunction) { case SS_ERROR: if ((error = calculate_SS_error(pattern_no, sub_pat_no)) == -1) return (-1); break; case WTA_ERROR: if ((error = calculate_WTA_error(pattern_no, sub_pat_no)) == -1) return (-1); break; case WWTA_ERROR: if ((error = calculate_w_WTA_error(pattern_no, sub_pat_no)) == -1) return (-1); break; } NET_ERROR(OutParameter) += error; } /* * throw away new weight or bias if error decreased or propability is to * low */ if ((NET_ERROR(OutParameter) > MinimumError) && (Temperature > 0) && (drand48() > exp((MinimumError - NET_ERROR(OutParameter)) / ((end_pattern - start_pattern) * Temperature)))) { FOR_ALL_UNITS(unit_ptr) { flags = unit_ptr->flags; if ((flags & UFLAG_IN_USE) == UFLAG_IN_USE) { /* unit is in use */ if (unit_ptr->value_b == LAST_MODIFIED) { unit_ptr->bias = unit_ptr->value_c; break; } if (flags & UFLAG_SITES) { /* unit has sites */ FOR_ALL_SITES_AND_LINKS(unit_ptr, site_ptr, link_ptr) if (link_ptr->value_b == LAST_MODIFIED) link_ptr->weight = link_ptr->value_c; } else { /* unit has no sites */ if (flags & UFLAG_DLINKS) { /* unit has direct links */ FOR_ALL_LINKS(unit_ptr, link_ptr) if (link_ptr->value_b == LAST_MODIFIED) link_ptr->weight = link_ptr->value_c; } } } } } else { MinimumError = NET_ERROR(OutParameter); } /* decrease Temperature */ Temperature *= LEARN_PARAM4(parameterInArray); return (ret_code); } /***************************************************************************** FUNCTION : TEST_SimulatedAnnealingSS Squared Sum Error PURPOSE : Test Performance of the Network during Simulated Annealing Learning RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ krui_err TEST_SimulatedAnnealingSS(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams) { return (TEST_SimulatedAnnealing(start_pattern, end_pattern, parameterInArray, NoOfInParams, parameterOutArray, NoOfOutParams, SS_ERROR)); } /***************************************************************************** FUNCTION : TEST_SimulatedAnnealingWTA Winner Takes All Error PURPOSE : Test Performance of the Network during Simulated Annealing Learning RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ krui_err TEST_SimulatedAnnealingWTA(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams) { return (TEST_SimulatedAnnealing(start_pattern, end_pattern, parameterInArray, NoOfInParams, parameterOutArray, NoOfOutParams, WTA_ERROR)); } /***************************************************************************** FUNCTION : TEST_SimulatedAnnealingWWTA Weighted Winner Takes All Error PURPOSE : Test Performance of the Network during Simulated Annealing Learning RETURNS : error NOTES : UPDATE : 06.10.1994 ******************************************************************************/ krui_err TEST_SimulatedAnnealingWWTA(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams) { return (TEST_SimulatedAnnealing(start_pattern, end_pattern, parameterInArray, NoOfInParams, parameterOutArray, NoOfOutParams, WWTA_ERROR)); } /***************************************************************************** FUNCTION : TEST_SimulatedAnnealing PURPOSE : Test Performance of the Network during Simulated Annealing Learning RETURNS : error NOTES : UPDATE : 19.02.1995 ******************************************************************************/ krui_err TEST_SimulatedAnnealing(int start_pattern, int end_pattern, float *parameterInArray, int NoOfInParams, float **parameterOutArray, int *NoOfOutParams, int errorFunction) { static float OutParameter[1]; /* OutParameter[0] stores the * learning error */ int ret_code, pattern_no, sub_pat_no; float error; if (NoOfInParams < 4) return (KRERR_PARAMETERS); /* Not enough input parameters */ *NoOfOutParams = 1; /* One return value is available (the * learning error) */ *parameterOutArray = OutParameter; /* set the output parameter reference */ ret_code = KRERR_NO_ERROR; /* reset return code */ /* compute the necessary sub patterns */ KernelErrorCode = kr_initSubPatternOrder(start_pattern, end_pattern); if (KernelErrorCode != KRERR_NO_ERROR) return (KernelErrorCode); NET_ERROR(OutParameter) = 0.0; /* reset network error value */ /* calculate performance of new net */ while (kr_getSubPatternByOrder(&pattern_no, &sub_pat_no)) { propagateNetForward(pattern_no, sub_pat_no); /* Forward propagation */ switch (errorFunction) { case SS_ERROR: if ((error = calculate_SS_error(pattern_no, sub_pat_no)) == -1) return (-1); break; case WTA_ERROR: if ((error = calculate_WTA_error(pattern_no, sub_pat_no)) == -1) return (-1); break; case WWTA_ERROR: if ((error = calculate_w_WTA_error(pattern_no, sub_pat_no)) == -1) return (-1); break; } NET_ERROR(OutParameter) += error; } return (ret_code); }