/***************************************************************************** FILE : $Source: /projects/higgs1/SNNS/CVS/SNNS/kernel/sources/cc_learn.c,v $ SHORTNAME : SNNS VERSION : 4.2 PURPOSE : Functions of CC NOTES : AUTHOR : Michael Schmalzl, modified by Christian Wehrfritz (PCC) DATE : 5.2.93 CHANGED BY : Michael Schmalzl, Juergen Gatter RCS VERSION : $Revision: 2.18 $ LAST CHANGE : $Date: 1998/04/20 11:54:44 $ Copyright (c) 1990-1995 SNNS Group, IPVR, Univ. Stuttgart, FRG Copyright (c) 1996-1998 SNNS Group, WSI, Univ. Tuebingen, FRG ******************************************************************************/ #include #include #include #include #include #include #ifdef HAVE_VALUES_H #include #endif #include "random.h" #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 "kr_ui.h" #include "cc_type.h" #include "cc_mac.h" #include "cc_learn.ph" #include "cc_glob.h" #include "kr_newpattern.h" #include "cc_modify.h" #include "cc_prune.h" #include "cc_display.h" #include "tacoma_learn.h" /***************************************************************************** FUNCTION : cc_initVariables PURPOSE : read some Parameters and global dates. NOTES : UPDATE : 30.03.96 ******************************************************************************/ krui_err cc_initVariables(float* ParameterInArray, int StartPattern,int EndPattern) { int i; cc_LayerCorrectnessTest(ParameterInArray,StartPattern,EndPattern); srand48((long)time(NULL)); /* now read the parameters from the window to global variables */ cc_printOnOff = (int)ParameterInArray[8]; cc_backfittingOnOff = (int)ParameterInArray[18]; cc_MaxSpecialUnitNo = (int)ParameterInArray[12]; cc_modification = (int)ParameterInArray[21]; for (i=0;i<5;i++){ cc_Parameter[i]=ParameterInArray[22+i]; } cc_fastmode=(int)ParameterInArray[27]; cc_fse=((LEARNING_FUNCTION==BACKPROP)? PARAM3 : 0.1); KernelErrorCode=cc_InitModificationVariables(); ERROR_CHECK; KernelErrorCode=cc_TestWhetherParametersAreValid(); ERROR_CHECK; cc_end=FALSE; cc_cascade=1; KernelErrorCode = cc_GetTrainFunctions(LEARNING_FUNCTION); ERROR_CHECK; if (NoOfHiddenUnits==0) KernelErrorCode = cc_calculateNetParameters(); ERROR_CHECK; KernelErrorCode = cc_generateLayerList(); ERROR_CHECK; if(strcmp(krui_getUpdateFunc(),"CC_Order")){ return(KRERR_CC_ERROR10); } if(strcmp(krui_getInitialisationFunc(),"CC_Weights")){ return(KRERR_CC_ERROR11); } return KRERR_NO_ERROR; } /***************************************************************************** FUNCTION : cc_calculateCorrelation PURPOSE : Calculates the correlation of the pool of candidate units and returns the high score. NOTES : UPDATE : 30.3.96 ******************************************************************************/ float cc_calculateCorrelation(int StartPattern, int EndPattern, int counter) { int s,o,n; double highScore, unchangedhighScore, scoreBuffer; float bestSpecialUnitScore = -0.1 , bestSpecialUnitUnchangedScore=0.0; struct Unit *SpecialUnitPtr = NULL,*OutputUnitPtr; int start, end; cc_getPatternParameter(StartPattern,EndPattern,&start,&end,&n); ERROR_CHECK; if(cc_printOnOff) printf("Cycle %d ",counter); FOR_ALL_SPECIAL_UNITS(SpecialUnitPtr,s) { unchangedhighScore = 0.0; FOR_ALL_OUTPUT_UNITS(OutputUnitPtr,o) { scoreBuffer = (CorBetweenSpecialActAndOutError[s][o] - (MeanOutputUnitError[o] * SpecialUnitSumAct[s] )) / SumSqError; unchangedhighScore += fabs(scoreBuffer); SIGN_OF_THE_CORRELATION[s][o] = SIGN(scoreBuffer); } highScore = cc_modifyHighScore(SpecialUnitPtr,s,unchangedhighScore); cc_actualizeGroupHighscores(highScore,s,SpecialUnitPtr); if(highScore> bestSpecialUnitScore){ bestSpecialUnitScore = highScore; bestSpecialUnitUnchangedScore = unchangedhighScore; bestSpecialUnitPtr = SpecialUnitPtr; } if(cc_printOnOff) printf("S[%d]: %.4f ",s,unchangedhighScore); } if(cc_printOnOff) { printf("Best : %d:%.4f \n",GET_UNIT_NO(bestSpecialUnitPtr), bestSpecialUnitScore); } return(bestSpecialUnitUnchangedScore); } /***************************************************************************** FUNCTION : cc_GetTrainFunctions PURPOSE : Assigns the trainings functions. NOTES : UPDATE : 10.10.95 ******************************************************************************/ krui_err cc_GetTrainFunctions(int learnFunc) { cc_learningFunction = learnFunc; cc_propagateOutputUnitsBackward = cc_propagateOutput; cc_propagateSpecialUnitsBackward = cc_propagateSpecial; switch(learnFunc) { case BACKPROP: cc_SpecialUnitUpdate = cc_OutputUnitUpdate = BackPropOfflinePart; break; case BACKPROP_ONLINE: cc_SpecialUnitUpdate = cc_OutputUnitUpdate = OnlineBackPropOfflinePart; cc_propagateOutputUnitsBackward = cc_propagateOutputOnlineCase; cc_propagateSpecialUnitsBackward = cc_propagateSpecialOnlineCase; break; case QUICKPROP: cc_SpecialUnitUpdate = cc_OutputUnitUpdate = QuickPropOfflinePart; break; case RPROP: cc_SpecialUnitUpdate = cc_OutputUnitUpdate = RPropOfflinePart; break; default: CC_ERROR(KRERR_CC_ERROR3); } return(KRERR_NO_ERROR); } /***************************************************************************** FUNCTION : cc_trainSpecialUnits PURPOSE : Trains the special units. NOTES : UPDATE : 5.2.93 ******************************************************************************/ void cc_trainSpecialUnits(int maxNoOfCovarianceUpdateCycles, float minCovarianceChange, int specialPatience,int StartPattern, int EndPattern,float param1, float param2, float param3,int MaxSpecialUnitNo) { struct Unit* UnitPtr; struct Link* LinkPtr; int s; int counter,start,end,n; float oldHighScore=0.0,newHighScore; float Error; cc_printHeadline("Training of the candidates",LENGTH_HEADLINE); cc_calculateOutputUnitError(StartPattern,EndPattern); if (SumSqError==0.0){ Error = cc_getErr(StartPattern,EndPattern); /* calc SumSqError */ if (SumSqError==0.0) return; } for (counter=0;counterbias += (*cc_SpecialUnitUpdate)(UnitPtr->bias, &BIAS_PREVIOUS_SLOPE(UnitPtr), &BIAS_CURRENT_SLOPE(UnitPtr), &BIAS_LAST_WEIGHT_CHANGE(UnitPtr), param1,param2,param3); FOR_ALL_LINKS(UnitPtr,LinkPtr){ LinkPtr->weight += (*cc_SpecialUnitUpdate)(LinkPtr->weight, &LN_PREVIOUS_SLOPE(LinkPtr), &LN_CURRENT_SLOPE(LinkPtr), &LN_LAST_WEIGHT_CHANGE(LinkPtr), param1, param2, param3); } } cc_initActivationArrays(); if ((counter % specialPatience)==0){ if(fabs(newHighScore-oldHighScore) < minCovarianceChange*oldHighScore) return; else oldHighScore = newHighScore; } } } /***************************************************************************** FUNCTION : cc_trainOutputUnits PURPOSE : Trains the output units. NOTES : UPDATE : 5.2.93 ******************************************************************************/ void cc_trainOutputUnits(int maxNoOfErrorUpdateCycles, int backfittPatience, float minErrorChange, int outPatience,int StartPattern,int EndPattern, float param1, float param2, float param3, float **ParameterOutArray,int *NoOfOutParams) { int p,pat,sub,counter=0; float oldNetError=FLOAT_MAX; int start,end,n; struct Unit* UnitPtr; struct Link* LinkPtr; int s,dummy; static float OutParameter[1]; cc_printHeadline("Training of the output units",LENGTH_HEADLINE); *NoOfOutParams = 1; *ParameterOutArray = OutParameter; cc_initOutputUnits(); cc_actualNetSaved=FALSE; /* compute the necessary sub patterns */ KernelErrorCode = kr_initSubPatternOrder(StartPattern,EndPattern); if(KernelErrorCode != KRERR_NO_ERROR) return; for (counter=0;counter< maxNoOfErrorUpdateCycles;counter++){ cc_getPatternParameter(StartPattern,EndPattern,&start,&end,&n); for(p=start; p<=end;p++){ cc_getActivationsForActualPattern(p,start,&pat,&sub); PROPAGATE_THROUGH_OUTPUT_LAYER(UnitPtr,dummy,p); (*cc_propagateOutputUnitsBackward)(pat,sub,param1,param2,param3); } cc_actualNetSaved=TRUE; FOR_ALL_OUTPUT_UNITS(UnitPtr,s){ UnitPtr->bias += (*cc_OutputUnitUpdate)(UnitPtr->bias, &BIAS_PREVIOUS_SLOPE(UnitPtr), &BIAS_CURRENT_SLOPE(UnitPtr), &BIAS_LAST_WEIGHT_CHANGE(UnitPtr), param1,param2,param3); FOR_ALL_LINKS(UnitPtr,LinkPtr){ LinkPtr->weight += (*cc_OutputUnitUpdate)(LinkPtr->weight, &LN_PREVIOUS_SLOPE(LinkPtr), &LN_CURRENT_SLOPE(LinkPtr), &LN_LAST_WEIGHT_CHANGE(LinkPtr), param1,param2,param3); } } NET_ERROR(OutParameter)=cc_getErr(StartPattern,EndPattern); /* otherways, it's not the actual error */ if(cc_printOnOff) printf("Epoch: %d NetError: %f \n",counter+1, NET_ERROR(OutParameter)); if ((counter % outPatience)==0){ if(fabs(NET_ERROR(OutParameter)-oldNetError) < minErrorChange * oldNetError) return; else oldNetError=NET_ERROR(OutParameter); } } } /***************************************************************************** FUNCTION : cc_calculateOutputUnitError PURPOSE : Calculates the error of all output units and stores the result in the array OutputUnitError NOTES : UPDATE : 5.2.93 ******************************************************************************/ void cc_calculateOutputUnitError(int StartPattern,int EndPattern) { register struct Unit *UnitPtr; register Patterns out_pat; register TopoPtrArray topo_ptr; register int o,p; int start, end,pat,sub,n; FOR_ALL_OUTPUT_UNITS(UnitPtr,o) OUTPUT_UNIT_SUM_ERROR[o] = 0.0; cc_getPatternParameter(StartPattern,EndPattern,&start,&end,&n); ERROR_CHECK_WRC; for(p=start; p<=end;p++){ topo_ptr = topo_ptr_array; cc_getActivationsForActualPattern(p,start,&pat,&sub); out_pat = kr_getSubPatData(pat,sub,OUTPUT,NULL); ERROR_CHECK_WRC; FOR_ALL_OUTPUT_UNITS(UnitPtr,o) { CALCULATE_ACTIVATION_AND_OUTPUT(UnitPtr, (*UnitPtr->act_func)(UnitPtr),p); OUTPUT_UNIT_SUM_ERROR[o] += (OutputUnitError[p][o] = (UnitPtr->Out.output-(*out_pat++))* ((*UnitPtr->act_deriv_func)(UnitPtr)+cc_fse)); } } FOR_ALL_OUTPUT_UNITS(UnitPtr,o) MeanOutputUnitError[o] = (OUTPUT_UNIT_SUM_ERROR[o] / n); cc_actualNetSaved=TRUE; } /***************************************************************************** FUNCTION : cc_calculateSpecialUnitActivation PURPOSE : Calculates the covariance between the output units and the special units and stores the result the array CorBetweenSpecialActAndOutError. NOTES : UPDATE : 5.2.93 ******************************************************************************/ void cc_calculateSpecialUnitActivation(int StartPattern, int EndPattern) { register struct Unit *specialUnitPtr,*outputUnitPtr; register int o,s,p; int pat,sub; int start,end,n; cc_getPatternParameter(StartPattern,EndPattern,&start,&end,&n); ERROR_CHECK_WRC; for(p=start; p<=end;p++){ cc_getActivationsForActualPattern(p,start,&pat,&sub); FOR_ALL_SPECIAL_UNITS(specialUnitPtr,s) { CALCULATE_ACTIVATION_AND_OUTPUT(specialUnitPtr, (*specialUnitPtr->act_func) (specialUnitPtr),p); SpecialUnitSumAct[s] += SpecialUnitAct[p][s] = specialUnitPtr->Out.output; FOR_ALL_OUTPUT_UNITS(outputUnitPtr,o) { CorBetweenSpecialActAndOutError[s][o] += SpecialUnitAct[p][s] * OutputUnitError[p][o]; } } } cc_actualNetSaved=TRUE; } /***************************************************************************** FUNCTION : cc_propagateOutput PURPOSE : Propagates a pattern backward through the net. NOTES : UPDATE : 5.2.93 ******************************************************************************/ float cc_propagateOutput(int PatternNo, int sub_pat_no, float param1, float param2, float param3) { struct Link *LinkPtr; struct Site *site_ptr; struct Unit *OutputUnitPtr; Patterns out_pat; float error,devit; int dummy; out_pat = kr_getSubPatData(PatternNo,sub_pat_no,OUTPUT,NULL); ERROR_CHECK; FOR_ALL_OUTPUT_UNITS(OutputUnitPtr,dummy){ devit = OutputUnitPtr->Out.output - *(out_pat++); error = devit * ((*OutputUnitPtr->act_deriv_func)(OutputUnitPtr) + cc_fse); BIAS_CURRENT_SLOPE(OutputUnitPtr) += error; if (UNIT_HAS_DIRECT_INPUTS(OutputUnitPtr)) { FOR_ALL_LINKS(OutputUnitPtr,LinkPtr) { LN_CURRENT_SLOPE(LinkPtr) += error * LinkPtr->to->Out.output; } }else{ FOR_ALL_SITES_AND_LINKS(OutputUnitPtr,site_ptr,LinkPtr) { LN_CURRENT_SLOPE(LinkPtr) += error * LinkPtr->to->Out.output; } } } return(0); /* not used anymore, since result isn't valid when used */ } /***************************************************************************** FUNCTION : cc_propagateOutputOnlineCase PURPOSE : Propagates a pattern backward through the net. NOTES : UPDATE : 5.2.93 ******************************************************************************/ float cc_propagateOutputOnlineCase(int PatternNo, int sub_pat_no, float eta,float mu,float dummy1) { struct Link *LinkPtr; struct Site *site_ptr; struct Unit *OutputUnitPtr; Patterns out_pat; float error,sum_error,devit; int dummy; float lastChange; sum_error = 0.0; out_pat = kr_getSubPatData(PatternNo,sub_pat_no,OUTPUT,NULL); ERROR_CHECK; FOR_ALL_OUTPUT_UNITS(OutputUnitPtr,dummy){ devit = OutputUnitPtr->Out.output - *(out_pat++); sum_error += devit * devit; error = devit * ((*OutputUnitPtr->act_deriv_func)(OutputUnitPtr) + dummy1); lastChange = BIAS_LAST_WEIGHT_CHANGE(OutputUnitPtr); OutputUnitPtr->bias -= ((BIAS_LAST_WEIGHT_CHANGE(OutputUnitPtr) = error * eta + lastChange * mu)); if (UNIT_HAS_DIRECT_INPUTS(OutputUnitPtr)) { FOR_ALL_LINKS(OutputUnitPtr,LinkPtr) { lastChange = LN_LAST_WEIGHT_CHANGE(LinkPtr); LinkPtr->weight -= ((LN_LAST_WEIGHT_CHANGE(LinkPtr) = error*LinkPtr->to->Out.output*eta+lastChange*mu)); } }else{ FOR_ALL_SITES_AND_LINKS(OutputUnitPtr,site_ptr,LinkPtr) { lastChange = LN_LAST_WEIGHT_CHANGE(LinkPtr); LinkPtr->weight -= ((LN_LAST_WEIGHT_CHANGE(LinkPtr) = error*LinkPtr->to->Out.output*eta+lastChange*mu)); } } } return(sum_error); } /***************************************************************************** FUNCTION : cc_propagateSpecial PURPOSE : Propagation in Case of Special Units, no BackProp NOTES : UPDATE : 30.3.96 ******************************************************************************/ krui_err cc_propagateSpecial(int start,int end,int n,int counter, float param1, float param2,float param3) { float change=0.0,actPrime; int s,o,p,pat,sub; struct Unit *SpecialUnitPtr,*OutputUnitPtr; struct Link *LinkPtr; for(p=start; p<=end;p++){ cc_getActivationsForActualPattern(p,start,&pat,&sub); FOR_ALL_SPECIAL_UNITS(SpecialUnitPtr,s) { change = 0.0; SpecialUnitPtr->act = SpecialUnitAct[p][s]; actPrime = (*SpecialUnitPtr->act_deriv_func)(SpecialUnitPtr); FOR_ALL_OUTPUT_UNITS(OutputUnitPtr,o) if(UNITS_IN_SAME_GROUP(s,o)){ change -= SIGN_OF_THE_CORRELATION[s][o] * (OutputUnitError[p][o]-MeanOutputUnitError[o]); } change *= actPrime/SumSqError; BIAS_CURRENT_SLOPE(SpecialUnitPtr) += change; FOR_ALL_LINKS(SpecialUnitPtr,LinkPtr) LN_CURRENT_SLOPE(LinkPtr) += change * LinkPtr->to->Out.output; } } cc_actualNetSaved=TRUE; return(KRERR_NO_ERROR); } /***************************************************************************** FUNCTION : cc_propagateSpecialOnlineCase PURPOSE : Propagation in Case of Special Units for BackProp NOTES : UPDATE : 30.3.96 ******************************************************************************/ krui_err cc_propagateSpecialOnlineCase(int start,int end,int n,int counter, float eta, float mu, float dummy) { float change=0.0,actPrime; int s,o,p,pat,sub; struct Unit *SpecialUnitPtr,*OutputUnitPtr; struct Link *LinkPtr; float lastChange; for(p=start; p<=end;p++){ cc_getActivationsForActualPattern(p,start,&pat,&sub); FOR_ALL_SPECIAL_UNITS(SpecialUnitPtr,s) { change = 0.0; SpecialUnitPtr->act = SpecialUnitAct[p][s]; actPrime = (*SpecialUnitPtr->act_deriv_func)(SpecialUnitPtr); FOR_ALL_OUTPUT_UNITS(OutputUnitPtr,o) if(UNITS_IN_SAME_GROUP(s,o)){ change += SIGN_OF_THE_CORRELATION[s][o] * (OutputUnitError[p][o]-MeanOutputUnitError[o]); } change *= actPrime/SumSqError; lastChange = BIAS_LAST_WEIGHT_CHANGE(SpecialUnitPtr); SpecialUnitPtr->bias += (BIAS_LAST_WEIGHT_CHANGE(SpecialUnitPtr) = (change * eta + lastChange * mu)); FOR_ALL_LINKS(SpecialUnitPtr,LinkPtr) { lastChange = LN_LAST_WEIGHT_CHANGE(LinkPtr); LinkPtr->weight += (LN_LAST_WEIGHT_CHANGE(LinkPtr) = change*LinkPtr->to->Out.output*eta+lastChange*mu); } } } cc_actualNetSaved=TRUE; return(KRERR_NO_ERROR); } /***************************************************************************** FUNCTION : LEARN_CC PURPOSE : The main routine of CC NOTES : UPDATE : 5.2.93 ******************************************************************************/ krui_err LEARN_CC(int StartPattern, int EndPattern, float *ParameterInArray, int NoOfInParams, float **ParameterOutArray, int *NoOfOutParams) { NetLearnAlgorithm = CC; return(LEARN_CasCor(StartPattern,EndPattern,ParameterInArray,NoOfInParams, ParameterOutArray,NoOfOutParams)); } /***************************************************************************** FUNCTION : LEARN_CasCor PURPOSE : The main learn routine of CC NOTES : UPDATE : 5.2.93 ******************************************************************************/ krui_err LEARN_CasCor(int StartPattern, int EndPattern, float *ParameterInArray, int NoOfInParams, float **ParameterOutArray, int *NoOfOutParams) { static int GroupNo; static float LeTe; int TempErrorCode; /* Used by the macro ERROR_CHECK_WITH_MEM_DEALLOC */ if(cc_allButtonIsPressed == 1) { KernelErrorCode = cc_initVariables(ParameterInArray, StartPattern, EndPattern); ERROR_CHECK; } if(cc_end){ cc_deleteAllSpecialUnits(); return(cc_freeStorage(StartPattern,EndPattern,0)); } cc_allocateStorage(StartPattern,EndPattern,MAX_SPECIAL_UNIT_NUMBER); ERROR_CHECK_WITH_MEMORY_DEALLOCATION; /* it's easier to delete and reconstruct the Units, than to change them */ KernelErrorCode = cc_deleteAllSpecialUnits(); ERROR_CHECK_WITH_MEMORY_DEALLOCATION; KernelErrorCode = cc_generateSpecialUnits(SPECIAL_FUNCTION_TYPE); ERROR_CHECK_WITH_MEMORY_DEALLOCATION; KernelErrorCode = cc_initSpecialUnitLinks(); ERROR_CHECK_WITH_MEMORY_DEALLOCATION; if(cc_storageFree){ CC_ERROR(KRERR_CC_ERROR2); } /* If this is the first run, train the output connections */ if (NoOfHiddenUnits<1) { if((OUT_PATIEN != 0) && (MAX_NO_ERROR_UPDATE_CYCLES != 0)) { cc_trainOutputUnits(MAX_NO_ERROR_UPDATE_CYCLES, BACKFITT_PATIENCE, MINIMAL_ERROR_CHANGE, OUT_PATIEN, StartPattern, EndPattern, PARAM1, PARAM2, PARAM3, ParameterOutArray, NoOfOutParams); } } /* compute the selection criterion before the new hidden is installed */ if (CC_PRUNE_ONOFF) { LeTe=cc_getPruningError(PRUNE_FUNC,StartPattern,EndPattern,1); } /* train the candidates */ if(cc_test(StartPattern,EndPattern,MAX_PIXEL_ERR) == CONTINUE_LEARNING) { if((SPEC_PATIENCE != 0) && (MAX_NO_OF_COVAR_UPDATE_CYCLES != 0)) { cc_trainSpecialUnits(MAX_NO_OF_COVAR_UPDATE_CYCLES, MIN_COVAR_CHANGE,SPEC_PATIENCE, StartPattern,EndPattern, PARAM4,PARAM5,PARAM6,MAX_SPECIAL_UNIT_NUMBER); } }else { /* STOP_LEARNING */ cc_end = TRUE; return(cc_freeStorage(StartPattern,EndPattern,0)); } cc_actualNetSaved=FALSE; /* install new hidden unit(s) */ for (GroupNo=0;GroupNo