BP单隐层神经网络介绍

在上一篇博客的基础上,研究了下单隐层神经网络,下面详细的说下步骤:

上一篇博客中,不管是加没加激励函数,都是输入后直接输出.

而单隐层神经网络就是输入和输出中间有一个隐层,

即 输入层的输出是隐层的输入 ,隐层的输出和对应权重的乘积是输出层的输入 ,输出层的输出才是最终的输出.

有点拗口,下面理一下上面的话: (以下加粗变量都是向量)


如上图

输入层的输入 就是 N个样本的Hog特征维度(A) : 记做 X0

输入层的输出(隐层的输入)  就是 X0 和W0 的乘积: 记做 y0

通过隐层的激励函数 tanh(), 隐层的输出 为 tanh(y0) : 记做X1

输出层的输入 就是 隐层的输出和对应权重的乘积,即X1*W1 : 记做 y1

通过对输出层的输入进行挤压后即为输出层的输出 tanh(y1) : 记做Y

总计下就是:

y0  =  X0 * W0

X1 = tanh(y0)

y1 = X1 * W1

Y = tanh(y1)

损失函数公式不变:


因为单层神经网络有两个权重W0W1,所以这两个权重都是要更新的,

更新权重是从右往左更新,先更新W1再更新W0,下面是更新两个权重的公式:


当然,重点就是求这两个 ,

这两个求起来也不是很难,上面说了先更新W1然后W0,下面是简单的步骤:



这两个结果,因为要分别和W1,W2的矩阵维度对应,所以根据各个之间的相乘相减什么的,

得出下面两个式子:

上面的式子有2点要注意的:

1. 符号 * 相乘是矩阵相乘, 符号 · 是矩阵点乘,其中平方也是矩阵点乘

2. 矩阵相乘是有左右顺序的,所以就是上图的顺序.

这样求出的结果才是和W0,W1的维度相对应的,才能进行两个权重的更新,不然会报错.

详细步骤说差不多了,更新2个权重的式子也都求出来了,下面上代码:

[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cv.h>  
  4. #include <cxcore.h>  
  5. #include <time.h>  
  6. #include <highgui.h>  
  7. #include <direct.h>  
  8. #include <io.h>  
  9. #include <math.h>  
  10.   
  11. #define PI 3.14  
  12. #define FILE_NVM 4  
  13. #define MaxLearnRate  0.00008 // 定义的学习速率, 这个数字不一定是最合适你的样本的  
  14. #define BIN_SIZE 20  
  15. #define BIN_NVM 9  
  16. #define NORM_WIDTH 22  
  17. #define NORM_HEIGHT 22  
  18. #define CELL_SIZE 2  
  19. #define BLOCK_SIZE 2  
  20. #define PIC_CELL_WH 50  
  21. #define HIDE_NVM 400 // 隐层定义的为 400个, 这个可以手动修改  
  22. #define CELL_W_NVM  ((NORM_WIDTH-2) / CELL_SIZE)  
  23. #define CELL_H_NVM  ((NORM_HEIGHT-2) / CELL_SIZE)  
  24. #define BLOCK_W_NVM  (CELL_W_NVM - BLOCK_SIZE + 1)  
  25. #define BLOCK_H_NVM  (CELL_H_NVM - BLOCK_SIZE + 1)  
  26. #define CELL_NVM (CELL_W_NVM * CELL_H_NVM)  
  27. #define BLOCK_NVM (BLOCK_W_NVM * BLOCK_H_NVM)  
  28. #define ARRAY_ALL (BLOCK_W_NVM * BLOCK_H_NVM * BLOCK_SIZE * BLOCK_SIZE * BIN_NVM)  
  29.   
  30.   
  31. typedef struct _SampleInfo // 每个样本对应的 data 以及目标值, 图片缩放到20*20  
  32. {  
  33.     float iTarget[FILE_NVM];  
  34.     float pdImageData[ARRAY_ALL];  
  35. }SampleInfo;  
  36.   
  37. static SampleInfo pstTrainSampleInfo[3942]; // 存放样本的数组,一共1770个样本  
  38. static SampleInfo pstTestSampleInfo[9249]; // 存放样本的数组,一共3981个样本  
  39. static int iTotalTrainSample; //所有训练样本的数量  
  40. static int iTotalTestSample; //所有测试样本的数量  
  41. static int iTotalIteNvm = 1000; // 训练的轮数  
  42. static double pdLearnRate = MaxLearnRate; // 学习速率  
  43.   
  44.   
  45.   
  46. void  func(int i_x, int i_y, int i_w, IplImage* Img_in, float* fbin)  
  47. {  
  48.     memset(fbin, 0, 9*sizeof(float));  
  49.     float f_x = 0.0f, f_y = 0.0f, f_Nvm = 0.0f, f_theta = 0.0f;  
  50.     for (int ii = i_y; ii < i_y + i_w; ii++)  
  51.     {  
  52.         for (int jj = i_x; jj < i_x + i_w; jj++)  
  53.         {  
  54.             uchar* pData = (uchar*)(Img_in->imageData + ii * Img_in->widthStep + jj);  
  55.             f_x = pData[1] - pData[-1];  
  56.             f_y = pData[Img_in->widthStep]- pData[-Img_in->widthStep];  
  57.             f_Nvm = pow( f_x*f_x + f_y*f_y,  0.5f);   
  58.   
  59.             float fAngle = 90.0f;  
  60.             if (f_x == 0.0f)  
  61.             {  
  62.                 if (f_y > 0)  
  63.                 {  
  64.                     fAngle = 90.0f;  
  65.                 }  
  66.             }  
  67.             else if (f_y == 0.0f)  
  68.             {  
  69.                 if (f_x > 0)  
  70.                 {  
  71.                     fAngle == 0.0f;  
  72.                 }  
  73.                 else if (f_x < 0)  
  74.                 {  
  75.                     fAngle == 180.0f;  
  76.                 }  
  77.             }  
  78.             else  
  79.             {  
  80.                 f_theta = atan(f_y/f_x);  atan() 范围为 -Pi/2 到 pi/2 所有9个bin范围是 0~180°  
  81.                 fAngle = (BIN_SIZE*BIN_NVM * f_theta)/PI;  
  82.             }  
  83.   
  84.             if (fAngle < 0)  
  85.             {  
  86.                 fAngle += 180;  
  87.             }  
  88.   
  89.             int iWhichBin = fAngle/BIN_SIZE;  
  90.             fbin[iWhichBin] += f_Nvm;  
  91.         }  
  92.     }  
  93. }  
  94.   
  95. static void sigmoid(CvMat* pResult)  
  96. {  
  97.     float* pfData = pResult->data.fl;  
  98.     for (int ii=0; ii<pResult->rows * pResult->cols; ii++)  
  99.     {  
  100.         *pfData = tanh( *pfData );  
  101.         pfData++;  
  102.     }  
  103. }  
  104.   
  105. static void InitWeight(CvMat* pWeight)  
  106. {  
  107.     float* pfData = pWeight->data.fl;  
  108.     for(int ii = 0; ii < pWeight->rows*pWeight->cols; ii++)  
  109.     {  
  110.         *pfData = ( rand() % 1000 ) / 10000.0 - 0.05;  
  111.         pfData++;  
  112.     }  
  113. }  
  114.   
  115. static int GetTrainSumNvm(char* pSrcPath, int iFlag) // 获取所有样本个数  
  116. {  
  117.     char pSrcSubFilePath[256];  
  118.     struct _finddata_t FileInfo;  
  119.     IplImage* pImgSrc = NULL;  
  120.     intptr_t lHandle;  
  121.     int ii, iTrainNvm=0;  
  122.     IplImage* pResizeImage = cvCreateImage(cvSize(NORM_WIDTH,NORM_HEIGHT), 8, 1);  
  123.     uchar* pucImgData = (uchar*)pResizeImage->imageData;  
  124.   
  125.     for (ii=0; ii<FILE_NVM; ii++)// 有 4 个文件夹装有样本  
  126.     {  
  127.         sprintf_s( pSrcSubFilePath, 256, "%s\\%d\\*.bmp", pSrcPath, ii );  
  128.   
  129.         lHandle = _findfirst( pSrcSubFilePath, &FileInfo );  
  130.   
  131.         if ( -1 == lHandle )  
  132.         {  
  133.             printf( "%s 路径不正确, 或者没有bmp的文件!请核实\n", pSrcSubFilePath );  
  134.             continue;  
  135.         }  
  136.   
  137.         do{  
  138.             if( !( FileInfo.attrib & _A_SUBDIR ) )  
  139.             {  
  140.                 sprintf_s(pSrcSubFilePath, 256, "%s\\%d\\%s", pSrcPath, ii, FileInfo.name);  
  141.                 pImgSrc = cvLoadImage(pSrcSubFilePath, CV_LOAD_IMAGE_GRAYSCALE);  
  142.                 cvResize(pImgSrc, pResizeImage,CV_INTER_LINEAR);  
  143.   
  144.                  计算每个cell每个梯度的大小和方向  
  145.                 int i_binNvm = 0;  
  146.                 float f_bin_out[CELL_NVM][BIN_NVM];  
  147.                 float i_AllbinNvm[][BLOCK_SIZE*BLOCK_SIZE*BIN_NVM] = {0.0f};  
  148.                 int ii_nvm1 = 0, ii_nvm2 = 0;  
  149.                 for (int tt = 1; tt + CELL_SIZE < pResizeImage->height; tt+=CELL_SIZE)  
  150.                 {  
  151.                     for (int dd = 1; dd + CELL_SIZE < pResizeImage->width; dd+=CELL_SIZE)  
  152.                     {  
  153.                         func(dd, tt, CELL_SIZE, pResizeImage, f_bin_out[i_binNvm++]);  
  154.                     }  
  155.                 }  
  156.   
  157.                  归一化每个block 并输出一个表示特征的大数组  
  158.                 int iBlockWhichCell = 0;  
  159.                 int uu = 0;  
  160.                 float  f_max = 0.0f;  
  161.                 float f_Ether_Block[BLOCK_SIZE*BLOCK_SIZE][BIN_NVM];  
  162.                 float f_Last_Array[ARRAY_ALL];  
  163.                 for (int tt = 0; tt < BLOCK_W_NVM; tt++ )  
  164.                 {  
  165.                     for (int dd = 0; dd < BLOCK_H_NVM; dd++)  
  166.                     {  
  167.                         for (int kk = 0; kk < BIN_NVM; kk++ )  
  168.                         {  
  169.                             f_Ether_Block[0][kk] = f_bin_out[tt*CELL_W_NVM+dd][kk];  
  170.                             f_Ether_Block[1][kk] = f_bin_out[tt*CELL_W_NVM+dd+1][kk];  
  171.                             f_Ether_Block[2][kk] = f_bin_out[tt*CELL_W_NVM+dd+ CELL_W_NVM][kk];  
  172.                             f_Ether_Block[3][kk] = f_bin_out[tt*CELL_W_NVM+dd+ CELL_W_NVM+1][kk];  
  173.                         }  
  174.   
  175.                         for (int ss = 0; ss < BLOCK_SIZE * BLOCK_SIZE; ss++ )  
  176.                         {  
  177.                             for (int mm = 0; mm < BIN_NVM; mm++)  
  178.                             {  
  179.                                 f_max = (f_Ether_Block[ss][mm] > f_max) ? f_Ether_Block[ss][mm] : f_max;  
  180.                             }  
  181.                         }  
  182.   
  183.   
  184.                         for (int ss = 0; ss < BLOCK_SIZE * BLOCK_SIZE; ss++ )  
  185.                         {  
  186.                             for (int mm = 0; mm < BIN_NVM; mm++)  
  187.                             {  
  188.   
  189.                                 if (f_max < 0.000001f)  
  190.                                 {  
  191.                                     f_Ether_Block[ss][mm] = 0.0f;  
  192.                                 }  
  193.                                 else  
  194.                                 {  
  195.                                     f_Ether_Block[ss][mm] /= f_max;  
  196.                                 }  
  197.   
  198.                                 if (iFlag == 1)   
  199.                                 {  
  200.                                     pstTrainSampleInfo[iTrainNvm].pdImageData[uu++] = f_Ether_Block[ss][mm];  
  201.   
  202.                                     for (int gg = 0; gg < FILE_NVM; gg++)  
  203.                                     {  
  204.                                         pstTrainSampleInfo[iTrainNvm].iTarget[gg] = -1.0f;  
  205.                                     }  
  206.                                     pstTrainSampleInfo[iTrainNvm].iTarget[ii] = 1.0f;  
  207.                                 }  
  208.                                 else  
  209.                                 {  
  210.                                     pstTestSampleInfo[iTrainNvm].pdImageData[uu++] = f_Ether_Block[ss][mm];  
  211.                                     for (int gg = 0; gg < FILE_NVM; gg++)  
  212.                                     {  
  213.                                         pstTestSampleInfo[iTrainNvm].iTarget[gg] = -1.0f;  
  214.                                     }  
  215.                                     pstTestSampleInfo[iTrainNvm].iTarget[ii] = 1.0f;  
  216.                                 }  
  217.                             }  
  218.                         }  
  219.                     }  
  220.                 }  
  221.   
  222.                 iTrainNvm++;  
  223.                 cvReleaseImage(&pImgSrc);  
  224.             }  
  225.         } while ( _findnext( lHandle, &FileInfo ) == 0 );  
  226.   
  227.     }  
  228.   
  229.     return iTrainNvm;  
  230.     cvReleaseImage(&pResizeImage);  
  231. }  
  232.   
  233. int GradientDescend()   
  234. {  
  235.     // 样本个数 N  ; Hog数组维度 A  
  236.     CvMat* cmTrainData = cvCreateMat(iTotalTrainSample, ARRAY_ALL+1, CV_32FC1); // N * A  
  237.     CvMat* cmTrainDataT = cvCreateMat(ARRAY_ALL+1, iTotalTrainSample, CV_32FC1); // A * N  
  238.     CvMat* cmTrainTarget = cvCreateMat(iTotalTrainSample, FILE_NVM, CV_32FC1); // N* 4  
  239.     CvMat* cmWeight = cvCreateMat(ARRAY_ALL+1, HIDE_NVM, CV_32FC1); // A* 400  
  240.     CvMat* cmWeightT = cvCreateMat(HIDE_NVM, ARRAY_ALL+1, CV_32FC1); // 400 * A  
  241.     CvMat* cmResult = cvCreateMat(iTotalTrainSample, HIDE_NVM, CV_32FC1); // N * 400  
  242.     CvMat* cmResultT = cvCreateMat(HIDE_NVM, iTotalTrainSample, CV_32FC1); // 400 * N  
  243.     CvMat* cmHideWeight = cvCreateMat(HIDE_NVM, FILE_NVM, CV_32FC1); // 400 * 4  
  244.     CvMat* cmHideWeightT = cvCreateMat(FILE_NVM, HIDE_NVM, CV_32FC1); // 4 * 400  
  245.     CvMat* cmHideResult = cvCreateMat(iTotalTrainSample, FILE_NVM, CV_32FC1); // N * 4  
  246.     CvMat* cmHideResultT = cvCreateMat(FILE_NVM, iTotalTrainSample, CV_32FC1); // 4 * N  
  247.     CvMat* cmHResultTarSub = cvCreateMat(iTotalTrainSample, FILE_NVM, CV_32FC1); // N * 4  
  248.     CvMat* cmHideDerivation = cvCreateMat(HIDE_NVM, FILE_NVM, CV_32FC1); // N * 4  
  249.     CvMat* cmOneDerivation = cvCreateMat(ARRAY_ALL+1, HIDE_NVM, CV_32FC1); // N * 4  
  250.     CvMat* cmHideTempResult = cvCreateMat(iTotalTrainSample, HIDE_NVM, CV_32FC1); // N * 4  
  251.   
  252.     // 初始化权重  
  253.     InitWeight(cmWeight);  
  254.     InitWeight(cmHideWeight);  
  255.   
  256.     // 将样本中的数据转化到矩阵中  
  257.     for (int mm=0; mm<iTotalTrainSample; mm++)  
  258.     {  
  259.         memcpy_s(cmTrainData->data.fl + mm *( ARRAY_ALL+1), sizeof(float)*ARRAY_ALL, pstTrainSampleInfo[mm].pdImageData, sizeof(float)*ARRAY_ALL);  
  260.         //cmTrainTarget->data.fl[mm] = pstTrainSampleInfo[mm].iTarget;  
  261.         cmTrainData->data.fl[mm*(ARRAY_ALL+1) + ARRAY_ALL] = 1.0f; // 将所有样本中的 b 赋值成 1  
  262.         for(int qq = 0; qq < FILE_NVM; qq++)  
  263.         {  
  264.             cmTrainTarget->data.fl[mm*FILE_NVM + qq] = pstTrainSampleInfo[mm].iTarget[qq];  
  265.         }  
  266.     }  
  267.   
  268.     int iPosError = 0, iNegError = 0, iLastErrorSum=0;   
  269.     //cvTranspose(cmWeight, cmWeightT);  
  270.     for (int ii = 0; ii < iTotalIteNvm; ii++)   
  271.     {  
  272.         iPosError = iNegError = 0;  
  273.   
  274.          下面的步骤就是更新权重,  
  275.         cvMatMul(cmTrainData, cmWeight, cmResult); // 求出隐层输入  
  276.         sigmoid(cmResult);  
  277.   
  278.         cvMatMul(cmResult, cmHideWeight, cmHideResult); // 隐层输入 * W1 求出输出层的输入  
  279.         sigmoid(cmHideResult);  
  280.   
  281.         cvTranspose(cmResult, cmResultT); // Y0(T)   
  282.         cvTranspose(cmTrainData, cmTrainDataT); // X(T) cmHideWeight  
  283.         cvTranspose(cmHideWeight, cmHideWeightT); // W1(T)  
  284.   
  285.          更新 W1 = W1 - 1/N*MaxLearnRate * ( Y0(T) x (Y1 - T)(1 - Y1^2) )  
  286.          更新 W0 = W0 - 1/N*MaxLearnRate * ( X(T) x ( ( (Y1 - T)(1 - Y1^2) x W1(T) ) * ( 1 - Y0^2 ) ) )  
  287.         cvSub(cmHideResult, cmTrainTarget, cmHResultTarSub); // (Y1 - T)  
  288.         for (int yy = 0; yy < iTotalTrainSample *FILE_NVM ; yy++)  
  289.         {  
  290.             // (Y1 - T)(1 - Y1^2)  
  291.             cmHideResult->data.fl[yy] = (1 - cmHideResult->data.fl[yy] * cmHideResult->data.fl[yy]) * cmHResultTarSub->data.fl[yy];   
  292.         }   
  293.   
  294.         // Y0(T) x (Y1 - T)(1 - Y1^2)  
  295.         cvMatMul(cmResultT, cmHideResult,cmHideDerivation);  
  296.         // (Y1 - T)(1 - Y1^2) x W1(T)  
  297.         cvMatMul(cmHideResult, cmHideWeightT, cmHideTempResult);  
  298.   
  299.         for (int yy = 0; yy < iTotalTrainSample*HIDE_NVM; yy++)  
  300.         {  
  301.             // ( (Y1 - T)(1 - Y1^2) x W1(T) ) * ( 1 - Y0^2 )  
  302.             cmHideTempResult->data.fl[yy] = (1 - cmResult->data.fl[yy] * cmResult->data.fl[yy] ) * cmHideTempResult->data.fl[yy];  
  303.         }   
  304.   
  305.         // X(T) x ( ( (Y1 - T)(1 - Y1^2) x W1(T) ) * ( 1 - Y0^2 ) )   
  306.         cvMatMul(cmTrainDataT, cmHideTempResult, cmOneDerivation);  
  307.   
  308.         cvConvertScale(cmHideDerivation, cmHideDerivation, pdLearnRate, 0);  
  309.         cvConvertScale(cmOneDerivation, cmOneDerivation, pdLearnRate, 0);  
  310.   
  311.         cvSub(cmHideWeight, cmHideDerivation, cmHideWeight, NULL); // 更新权重 W1  
  312.         cvSub(cmWeight, cmOneDerivation, cmWeight, NULL); // 更新权重 W0  
  313.   
  314.         // (训练集) 更新完的W0和W1权重再从左到右进行输出,其结果与目标值进行比较得出错误样本的个数  
  315.         cvMatMul(cmTrainData, cmWeight, cmResult);   
  316.         sigmoid(cmResult);  
  317.   
  318.         cvMatMul(cmResult, cmHideWeight, cmHideResult);   
  319.         sigmoid(cmHideResult);  
  320.   
  321.         // 求出的实际值 和 目标值进行比较, 得出训练集的错误样本的个数  
  322.         for (int mm=0; mm<iTotalTrainSample; mm++)  
  323.         {  
  324.             int iWhichNvm = 0;  
  325.             for (int zz = 1; zz < FILE_NVM; zz++)  
  326.             {  
  327.                 if (cmHideResult->data.fl[mm*FILE_NVM + zz] > cmHideResult->data.fl[mm*FILE_NVM + iWhichNvm] )  
  328.                 {  
  329.                     iWhichNvm = zz;  
  330.                 }     
  331.             }  
  332.   
  333.             if ( cmTrainTarget->data.fl[mm*FILE_NVM + iWhichNvm] != 1 )  
  334.             {  
  335.                 iPosError++;  
  336.             }  
  337.         }  
  338.         printf("train %d ------  %d  -> %d   -> %f \n", ii, iTotalTrainSample, iPosError,  ((float)(iPosError+iNegError))/(float)iTotalTrainSample);  
  339.   
  340.         //这一轮训练的误差比上一轮大,此时应该降低学习速率。  
  341.         if ( ii!=0 && (iPosError+iNegError)>=iLastErrorSum)  
  342.         {  
  343.             pdLearnRate = (pdLearnRate<MaxLearnRate/100000) ? MaxLearnRate: pdLearnRate / 2;  
  344.         }  
  345.         iLastErrorSum = iPosError + iNegError;  
  346.     }  
  347.   
  348.     printf("============================================================\n" );  
  349.     // 下面是根据上面求出的 cmWeightT(权重) 得出测试集的错误个数  
  350.     CvMat* cmTestData = cvCreateMat(iTotalTestSample, ARRAY_ALL+1, CV_32FC1); // 401 是因为 还有一个 a0*1, 即 Y = ax + b 中的 b  
  351.     CvMat* cmTestResult = cvCreateMat(iTotalTestSample, HIDE_NVM, CV_32FC1); // N * 400  
  352.     CvMat* cmTestHideResult = cvCreateMat(iTotalTestSample, FILE_NVM, CV_32FC1); // N * 4  
  353.     CvMat* cmTestTarget = cvCreateMat(iTotalTestSample, FILE_NVM, CV_32FC1);  
  354.   
  355.     for (int mm=0; mm<iTotalTestSample; mm++)  
  356.     {  
  357.         memcpy_s(cmTestData->data.fl + mm *( ARRAY_ALL+1), sizeof(float)*ARRAY_ALL, pstTestSampleInfo[mm].pdImageData, sizeof(float)*ARRAY_ALL);  
  358.         cmTestData->data.fl[mm*(ARRAY_ALL+1) + ARRAY_ALL] = 1.0f; // 将所有样本中的 b 赋值成 1  
  359.         for(int qq = 0; qq < FILE_NVM; qq++)  
  360.         {  
  361.             cmTestTarget->data.fl[mm*FILE_NVM + qq] = pstTestSampleInfo[mm].iTarget[qq];  
  362.         }  
  363.     }  
  364.   
  365.     cvMatMul(cmTestData, cmWeight, cmTestResult);   
  366.     sigmoid(cmTestResult);  
  367.   
  368.     cvMatMul(cmTestResult, cmHideWeight, cmTestHideResult);   
  369.     sigmoid(cmTestHideResult);  
  370.     int iPosError_t = 0, iNegError_t = 0;  
  371.     iPosError_t = iNegError_t = 0;  
  372.   
  373.     // 求出的实际值 和 目标值进行比较, 得出错误样本的个数  
  374.     for (int mm=0; mm<iTotalTestSample; mm++)  
  375.     {  
  376.         int iWhichNvm = 0;  
  377.         for (int zz = 1; zz < FILE_NVM; zz++)  
  378.         {  
  379.             if (cmTestHideResult->data.fl[mm*FILE_NVM + zz] > cmTestHideResult->data.fl[mm*FILE_NVM + iWhichNvm] )  
  380.             {  
  381.                 iWhichNvm = zz;  
  382.             }     
  383.         }  
  384.   
  385.         if ( cmTestTarget->data.fl[mm*FILE_NVM + iWhichNvm] != 1 )  
  386.         {  
  387.             iPosError_t++;  
  388.         }  
  389.     }  
  390.     printf("Test ------  %d  ->  %d  -> %f \n",iTotalTestSample, iPosError_t, ((float)(iPosError_t+iNegError_t))/(float)iTotalTestSample );  
  391.   
  392.     return 0;  
  393. }  
  394.   
  395. int main()  
  396. {  
  397.     // 样本放在桌面  
  398.     iTotalTrainSample = GetTrainSumNvm("C:\\Users\\Administrator\\Desktop\\Train", 1);  
  399.     iTotalTestSample = GetTrainSumNvm("C:\\Users\\Administrator\\Desktop\\Test", 0);  
  400.   
  401.     srand((int)time(0));  
  402.   
  403.     GradientDescend();  
  404.   
  405.     system("pause");  
  406.     return 0;  
  407. }  

下面是训练结果,和上一篇博客( C 实现最小二乘,步骤以及代码)中训练样本是一样的,虽然这次的速度慢,

但是和上篇博客中后面几次的效果比起来,还是有很大优势的~

因为速度慢,所以就训练1000次,也是很费时间,后面基本上好久都不收敛一下...

一开始的收敛效果:

训练集1000次效果:

因为写测试集训练代码的时候,粗心,把矩阵的维度给弄错了一个,所以到这就崩掉了,

所以说上面提到的矩阵相乘和矩阵点乘,还有位置啥的,必须注意!

后来改了后运行起来就搁那吃饭去了,就上一个训练集和测试集的结果图吧:

可以和上一篇博客中的效果对比一下,还是很不错的~

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值