⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bpnet.txt

📁 和好的算法
💻 TXT
📖 第 1 页 / 共 2 页
字号:
        //累加梯度
        for(j=0; j<=nIn; j++)
        for(k=1; k<=nHidd; k++)
        ...{
            pGradIn[j][k] += pNet->hidd_delta[k] * pNet->in_unit[j];
        }
        for(j=0; j<=nHidd; j++)
        for(k=1; k<=nOut; k++)
        ...{
            pGradH[j][k] += pNet->out_delta[k] * pNet->hidd_unit[j];
        }
    }

    //权值调整//////////////////////////
    for(j=0; j<=nIn; j++)
    for(k=1; k<=nHidd; k++)
    ...{
        pNet->in_w[j][k] += eta * pGradIn[j][k];
    }
    for(j=0; j<=nHidd; j++)
    for(k=1; k<=nOut; k++)
    ...{
        pNet->hidd_w[j][k] += eta * pGradH[j][k];
    }

    esqrsum = 0.0;
    //计算权值更新后的平方误差
    for(p=0; p<np; p++)
    ...{
        //输入数据
        pNet->in_unit[0] = 0.0;  //无偏移
        for(i=1; i<=nIn; i++)
            pNet->in_unit[i] = indata[p][i-1];
        for(i=1; i<=nOut; i++)
            pNet->target[i] = targetdata[p][i-1];

        bpnn_nnforward(pNet);
        
        esqr = 0.0;
        for(i=1; i<=nOut; i++)
        ...{
            esqr += pNet->target[i] - pNet->out_unit[i] ; //计算累积平方误差
        }
        esqrsum += esqr*esqr;
    }

    bpnn_mfree2d(pGradIn, nIn+1);
    bpnn_mfree2d(pGradH, nHidd+1);
    
    return esqrsum;
}


/**//////////////////////////////////////////////////////////////////////
// Levenberg-Marquardt的BP网络训练(全部样本)
//    参数
//        pNet       -- 已初始化的神经网络
//        indata       -- 输入的样本数组
//        targetdata -- 输出期望
//      np           -- 样本个数
//      lamda      -- lamda系数
//    返回
//        返回更新后的平方误差
//      更新pNet
/**//////////////////////////////////////////////////////////////////////
double bpnn_train_lm(BPNN_t *pNet, double **indata, double **targetdata, int np, double *lamda)
...{
    int i,j,k,p,pos;
    double errout, errh;
    double esqrsum, esqr;
    double *pGrad;     //合并的梯度向量
    double **pGradIn, **pGradH;    //每一层的梯度矩阵
    double **pGradIn2, **pGradH2;
    double *pHess;      //H矩阵
    double *pAlpha, *pBeta;    //用于计算逆矩阵       
    int nIn,nHidd,nOut;
    int vecsize;

    nIn = pNet->in_n;
    nHidd = pNet->hidd_n;
    nOut = pNet->out_n;

    vecsize = (nIn+1)*(nHidd) + (nHidd+1)*(nOut);
    pGrad = bpnn_malloc1d(vecsize );
    pHess = bpnn_malloc1d(vecsize * vecsize);
    pAlpha = bpnn_malloc1d(vecsize * vecsize);
    pBeta = bpnn_malloc1d(vecsize);
    pGradIn = bpnn_malloc2d(nIn+1, nHidd+1);
    pGradH = bpnn_malloc2d(nHidd+1, nOut+1);
    pGradIn2 = bpnn_malloc2d(nIn+1, nHidd+1);
    pGradH2 = bpnn_malloc2d(nHidd+1, nOut+1);

    //每一层梯度清0
    for(j=0; j<=nIn; j++)
    for(k=0; k<=nHidd; k++)
    ...{
        pGradIn[j][k] = 0.0;
        pGradIn2[j][k] = 0.0;
    }
    for(j=0; j<=nHidd; j++)
    for(k=0; k<=nOut; k++)
    ...{
        pGradH[j][k] = 0.0;
        pGradH2[j][k] = 0.0;
    }

    //计算梯度向量
    for(p=0; p<np; p++)
    ...{
        //输入数据
        pNet->in_unit[0] = 0.0;  //无偏移
        for(i=1; i<=nIn; i++)
            pNet->in_unit[i] = indata[p][i-1];
        for(i=1; i<=nOut; i++)
            pNet->target[i] = targetdata[p][i-1];
    
        bpnn_nnforward(pNet);
        bpnn_out_error(pNet->out_delta, pNet->out_dfda, pNet->target, pNet->out_unit, nOut, &errout);
        bpnn_hidd_error(pNet->hidd_delta, pNet->out_delta, pNet->hidd_dfda, pNet->out_dfda,
                nHidd, nOut, pNet->hidd_w, pNet->hidd_unit,&errh);
            
        pos = 0;
        //累加梯度
        for(j=0; j<=nIn; j++)
        for(k=1; k<=nHidd; k++)
        ...{
            pGradIn[j][k] += pNet->hidd_dfda[k] * pNet->in_unit[j];
            pGradIn2[j][k] += pNet->hidd_delta[k] * pNet->in_unit[j];
            pGrad[pos] = pGradIn[j][k];   //归并到梯度向量
            pBeta[pos] = pGradIn2[j][k];
            ++pos;
        }
        for(j=0; j<=nHidd; j++)
        for(k=1; k<=nOut; k++)
        ...{
            pGradH[j][k] += pNet->out_dfda[k] * pNet->hidd_unit[j];
            pGradH2[j][k] += pNet->out_delta[k] * pNet->hidd_unit[j];
            pGrad[pos] = pGradH[j][k];    //归并到梯度向量
            pBeta[pos] = pGradH2[j][k];
            ++pos;
        }
    }//end for

    //构造H矩阵
    for(j=0; j<vecsize; j++)
    ...{
        for(i=0; i<vecsize; i++)
        ...{
            pHess[i+j*vecsize] = pGrad[j] * pGrad[i];
            pAlpha[i+j*vecsize] = pHess[i+j*vecsize];
        }
        //添加对角线
        pAlpha[j+j*vecsize] = pHess[j+j*vecsize] * (1.0 + *lamda);
    }
    
    //算出权值增量
    gauss_jordan(pAlpha, pBeta, vecsize);
    
    pos = 0;
    //权值调整//////////////////////////
    for(j=0; j<=nIn; j++)
    for(k=1; k<=nHidd; k++)
    ...{
        pNet->prev_in_w[j][k] = pNet->in_w[j][k];
        pNet->in_w[j][k] += pBeta[pos];
        ++pos;
    }
    for(j=0; j<=nHidd; j++)
    for(k=1; k<=nOut; k++)
    ...{
        pNet->prev_hidd_w[j][k] = pNet->hidd_w[j][k];
        pNet->hidd_w[j][k] += pBeta[pos];
        ++pos;
    }

    //计算权值更新后的平方误差
    esqrsum = 0.0;
    for(p=0; p<np; p++)
    ...{
        //输入数据
        pNet->in_unit[0] = 0.0;  //无偏移
        for(i=1; i<=nIn; i++)
            pNet->in_unit[i] = indata[p][i-1];
        for(i=1; i<=nOut; i++)
            pNet->target[i] = targetdata[p][i-1];

        bpnn_nnforward(pNet);
        
        esqr = 0.0;
        for(i=1; i<=nOut; i++)
        ...{
            esqr += pNet->target[i] - pNet->out_unit[i] ; //计算累积平方误差
        }
        esqrsum += esqr*esqr;
    }

    //释放内存
    bpnn_mfree2d(pGradIn, nIn+1);
    bpnn_mfree2d(pGradH, nHidd+1);
    bpnn_mfree2d(pGradIn2, nIn+1);
    bpnn_mfree2d(pGradH2, nHidd+1);
    free(pHess);
    free(pBeta);
    free(pAlpha);
    free(pGrad);

    return esqrsum;    
}



/**/////////////////////////////////////////////////////////////////
//  gauss-jordan消元法解线性方程组Ax = B
//  参数
//        a -- 输入系数矩阵,输出被其逆矩阵代替(n*n)
//      b -- 等号右边的矩阵B, 输出时被对应解向量代替(n*1)
//        n --  a的维数
//
/**//////////////////////////////////////////////////////////////////
void gauss_jordan(double *a, double *b, int n)
...{
    int i,j,k,l,ll;
    int icol, irow;
    double big, dum, pivinv;
    int *ipiv = NULL;
    double *inva = NULL;
    
    ipiv = (int*)malloc( n*sizeof(int));
    inva = (double*)malloc(n*n*sizeof(double));
    
    for(j=0; j<n; j++)
    ...{
        ipiv[j] = 0;
    }
    SetEye(inva,n);
    
    for(i=0; i<n; i++)
    ...{
        big = 0.0;
        for(j=0; j<n; j++)     //寻找主元(最大数)
        ...{
            if( ipiv[j] != 1)
                for(k=0; k<n; k++)
                ...{
                    if(ipiv[k] == 0)
                    ...{
                        if(fabs(a[k+j*n]) >= big)
                        ...{
                            big = fabs( a[k+j*n] );
                            irow = j;
                            icol = k;
                        }
                    }//end if ipiv
                }
        }//end for j
        ++(ipiv[icol]);

        //实施消元
        if(irow != icol)
        ...{
            SWAP(b[irow], b[icol] );
            for(l=0; l<n; l++)
            ...{
                SWAP(a[l+irow*n], a[l+icol*n]);
                SWAP(inva[l+irow*n], inva[l+icol*n]);
            }
        }

        if (fabs(a[icol+icol*n]) < EPSILON)
        ...{
            return;                    //error 奇异矩阵
        }
        pivinv = 1.0 / a[icol+icol*n];
        b[icol] *= pivinv;
        for(l=0; l<n; l++)
        ...{
            a[l+icol*n] *= pivinv;
            inva[l+icol*n] *= pivinv;
        }
        for(ll=0; ll<n; ll++)
        ...{
            if(ll != icol)
            ...{
                dum = a[icol+ll*n];
                b[ll] -= b[icol] * dum;
                for(l=0; l<n; l++)
                ...{
                    a[l+ll*n] -= a[l+icol*n] * dum;
                    inva[l+ll*n] -= inva[l+icol*n] * dum;
                }
            }
        }//end for
    }//end for whole

    //更新a为逆矩阵
    for(i=0; i<n*n; i++)
        a[i] = inva[i];

    free(ipiv);
    free(inva);
}

//设置单位矩阵
void SetEye(double *mat, int n)
...{
    int i,j;
    for(i=0; i<n; i++)
    for(j=0; j<n; j++)
    ...{
        if(i==j)
            mat[j+i*n] = 1.0;
        else
            mat[j+i*n] = 0.0;
    }
}
 

测试程序

 

//test program
int main(int argc, char* argv[])
...{
    const double prec = 0.001;  //精度
    int maxtry = 5000;
    int cnt = 0;
    int i,j,k;
    double lamda = 0.1;
    BPNN_t *pNNet;
    double **x;
    double **y;
    double esqr,oesqr,res;
    int nIn, nHidd, nOut;
    int nsample = 20;   //样本数

    //初始化样本数据
    x = bpnn_malloc2d(nsample, 1);
    y = bpnn_malloc2d(nsample, 1);
    for(i=0; i<nsample; i++)
    ...{
        x[i][0] = (double)i / (double)nsample;
        //用正弦曲线验证
        y[i][0] = 0.5 * sin(x[i][0]*PI*0.5 ) + 0.5;
        //y[i][0] = -0.4 * x[i][0] + 1;
        //y[i][0] = 0.25*(x[i][0]-2)*(x[i][0]-2);
    }

    //初始化神经网络
    pNNet = bpnn_create(1, 8, 1);
    nIn = pNNet->in_n;
    nHidd = pNNet->hidd_n;
    nOut = pNNet->out_n;
    oesqr = 9999;     //infinite
    
    while(cnt++ < maxtry)
    ...{
        esqr = bpnn_train_lm(pNNet,x,y,nsample, &lamda);
        if(esqr < prec)
            break;
        else
        ...{
            if(esqr < oesqr)  //接受新解
            ...{
                lamda *= 0.1;  //缩小lamda
                oesqr = esqr;
            }
            else
            ...{
                lamda *= 10.0;  //扩大lamda
                //恢复旧权值
                for(j=0; j<=nIn; j++)
                for(k=1; k<=nHidd; k++)
                ...{
                    pNNet->in_w[j][k] = pNNet->prev_in_w[j][k];
                }
                for(j=0; j<=nHidd; j++)
                for(k=1; k<=nOut; k++)
                ...{
                    pNNet->hidd_w[j][k] = pNNet->prev_hidd_w[j][k];
                }

            }
        }
        
    /**//* 传统BP
        esqr = bpnn_train_steepest(pNNet,0.1, x,y,nsample);
            if(esqr < prec)
                break;
        */
    }

    //输出测试数据
    printf("输入样本 : 期望值     训练后的结果 ");
    for(i=0; i<nsample; i++)
    ...{
        pNNet->in_unit[1] = x[i][0];
        bpnn_nnforward(pNNet);
        res = pNNet->out_unit[1];
        printf("%5f  :  %5f  %6f ",x[i][0],y[i][0],res);
    }
    printf("  esqr: %5f  ", esqr);
    
    bpnn_destroy(pNNet);
    bpnn_mfree2d(x,nsample);
    bpnn_mfree2d(y,nsample);
    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -