cnn突破三

cnn,是卷积核神经网络,前面讲的没有卷积核,所以这里,我们在前面三层bpnet网络的基础上,增加卷积核试一试!

所有的启发来自,28*28变14*14的那个常用的高斯卷积核,我们前面的网络实际是:28*28->3*3卷积后,隔行隔列抠图(相当于池化)->14*14->128->10

下面,我们就是仿照上面,我们不再使用高斯核,而是让他自己产生四个卷积核(看看是什么鬼!):

即14*14->4*10*10->4*5*5->80->10,结论是:

改成14*14*4-10*10*4-5*5*4-80-10,学习6万次,均分大于90,小于95,我们先看结果:

我们训练学习了12万次,达到95分,用鼠标画了个2,识别出来了,得分99,不错,说明四个卷积核有了,我们把mnist原图的2,用学到的卷积核处理后的四个图像也有了,太神奇!

下面是c#实现源码,请对比前面三层bpnet网络看:

先初始化了四个卷积核:

   double[,] w1cnn = new double[25, 4]; double[,] w12cnn = new double[100, 80];

  double[,] w2cnn = new double[80, 10];

 //for cnn202409181004
              for (int i = 0; i <25; i++)
                  for (int j = 0; j < 4; j++)
                  {
                      w1cnn[i, j] = ran.Next(-100, 100) / 100f;
                 
                  }
         
              for (int i = 0; i <100; i++)
               
                  for (int j = 0; j < 80; j++)
                  {               
                      w12cnn[i, j] = ran.Next(-100, 100) / 100f;                    
                  }
            
              for (int i = 0; i < 80; i++)
                  for (int j = 0; j < 10; j++)
                  {
                      w2cnn[i, j] = ran.Next(-100, 100) / 100f;
                  }

然后,你对比前头的三层网络:forward()函数中增加如下:

forward第一步:14*14的图像用5*5的四个卷积核操作,变成4*10*10

  for (int i = 0; i < 10; i++)
                for (int j = 0; j < 10; j++)//
                {
                    int l = (i) * 10 + j;
                  
                    for (int m = 0; m < 5; m++)
                        for (int n = 0; n < 5; n++)
                        {
                            int k = (i + m) * 14 + j + n;
                            hIcnntemp[l] += xI[k] * w1cnn[m * 5 + n, 0];
                         
                            hIcnntemp1[l] += xI[k] * w1cnn[m * 5 + n, 1];

                            hIcnntemp2[l] += xI[k] * w1cnn[m * 5 + n, 2];
                            hIcnntemp3[l] += xI[k] * w1cnn[m * 5 + n, 3];
                        }
                }

  //forward第二步,10*10-》5*5
            jilumn.Clear();//forward执行一次,就是换一张图片
            jilumn1na.Clear();
            jilumn2na.Clear(); jilumn3na.Clear();
            for (int i = 0; i < 5; i++)
                for (int j = 0; j < 5; j++)//
                {
                    int l = (i) * 5 + j;
                    double tempb = 0;
                    Point tempPt = new Point();
                    for (int m = 0; m < 2; m++)
                        for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
                        {
                            int k = (i * 2 + m) * 10 + j * 2 + n;
                            //取最大值
                            if (hIcnntemp[k] > tempb)
                            {
                                tempb = hIcnntemp[k];
                                tempPt = new Point(n, m);//m是h,n是w,这个要小心用错

                            }
                        }
                
                    jilumn.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
                    hIcnn[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
                }

上面这段代码要重复三次,一共处理四副图像,即4@10*10-》4@5*5

  for (int i = 0; i < 5; i++)
                for (int j = 0; j < 5; j++)//
                {
                    int l = (i) * 5 + j;
                    double tempb = 0;
                    Point tempPt = new Point();
                    for (int m = 0; m < 2; m++)
                        for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
                        {
                            int k = (i * 2 + m) * 10 + j * 2 + n;
                            //  tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
                            if (hIcnntemp1[k] > tempb)
                            {
                                tempb = hIcnntemp1[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
                                tempPt = new Point(n, m);//m是h,n是w,这个要小心用错

                            }
                        }
                    //   C1[l] = (byte)(tempb/4f);
                    jilumn1na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
                    hIcnn1na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
                }
            for (int i = 0; i < 5; i++)
                for (int j = 0; j < 5; j++)//
                {
                    int l = (i) * 5 + j;
                    double tempb = 0;
                    Point tempPt = new Point();
                    for (int m = 0; m < 2; m++)
                        for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
                        {
                            int k = (i * 2 + m) * 10 + j * 2 + n;
                            //  tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
                            if (hIcnntemp2[k] > tempb)
                            {
                                tempb = hIcnntemp2[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
                                tempPt = new Point(n, m);//m是h,n是w,这个要小心用错

                            }
                        }
                    //   C1[l] = (byte)(tempb/4f);
                    jilumn2na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
                    hIcnn2na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
                }
            for (int i = 0; i < 5; i++)
                for (int j = 0; j < 5; j++)//
                {
                    int l = (i) * 5 + j;
                    double tempb = 0;
                    Point tempPt = new Point();
                    for (int m = 0; m < 2; m++)
                        for (int n = 0; n < 2; n++)//需要记住m,n和序号L,202409181018
                        {
                            int k = (i * 2 + m) * 10 + j * 2 + n;
                            //  tempb += B1[k] * Wb2c[m * 2 + n, l];//取均值?还是取最大值?
                            if (hIcnntemp3[k] > tempb)
                            {
                                tempb = hIcnntemp3[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727
                                tempPt = new Point(n, m);//m是h,n是w,这个要小心用错

                            }
                        }
                    //   C1[l] = (byte)(tempb/4f);
                    jilumn3na.Add(tempPt);//25个数据,就有25组m,n,序号一一对应
                    hIcnn3na[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038
                }

第三步关于forward,把处理后的图像合并起来,4@5*5=100

     hocnnhebing = new double[100];
            for (int i = 0; i < 25; i++)
            {
           
               hocnnhebing[i] =  hocnn[i] = sigmoid(hIcnn[i]);
                  hocnnhebing[i+25] =  hocnn1na[i] = sigmoid(hIcnn1na[i]);
                  hocnnhebing[i + 50] = sigmoid(hIcnn2na[i]);
                  hocnnhebing[i + 75] = sigmoid(hIcnn3na[i]);
            }

forward第四步,全连接:

  //下面开始全连接202409181044
            hI2 = new double[80];//
        
            for (int i = 0; i < 100; i++)//              
                for (int j = 0; j < 80; j++)//
                    hI2[j] += (hocnnhebing[i]) * w12cnn[i, j];//
              

            //通过激活函数对隐藏层进行计算 
            for (int i = 0; i < 80; i++)
                hO2[i] = sigmoid(hI2[i]);

            yicnn = new double[10];
            //通过w2计算隐藏层-输出层
            for (int i = 0; i < 80; i++)
                for (int j = 0; j < 10; j++)

               yicnn[j] += hO2[i] * w2cnn[i, j];

            //通过激活函数求yo
            for (int i = 0; i <10; i++)           
                yOcnn[i] = sigmoid(yicnn[i]);

上面就完成了forward()函数。下面再看backward()函数

   for (int i = 0; i < 80; i++)//
                for (int j = 0; j < 10; j++)//10
                {
                    double delta = (yOcnn[j] - d[j]) * dsigmoid(yOcnn[j]) * hO2[i];
                    w2cnn[i, j] -= delta * learnRate;
                }      
            double[] W3 = new double[80];//
       
            for (int j = 0; j < 80; j++)//
                for (int k = 0; k < 10; k++)//10
                    W3[j] += (yOcnn[k] - d[k]) * dsigmoid(yOcnn[k]) * w2cnn[j, k];
                   
            for (int i = 0; i <100; i++)//        
                for (int j = 0; j < 80; j++)//
                {                                
                    double delta = dsigmoid(hO2[j]) * (hocnnhebing[i]) * W3[j];//这里要的是系数
                    w12cnn[i, j] -= delta * learnRate;
                }

//对比三层bpnet,上面比较好理解,下面是对四个卷积核的backward:

//backward中第一个卷积核5*5的处理:

    double[] deltacnn = new double[25];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
             for (int i = 0; i < 25; i++)//25             
                 for (int j = 0; j < 80; j++)//           
                 {              
                     deltacnn[i] = dsigmoid(hO2[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
                 }//全连接还是好处理202409200708
             for (int i= 0; i< 25; i++)
             {
               Point temppt= 求二维(i, jilumn[i].Y, jilumn[i].X);
               for (int k = 0; k < 5; k++)
                   for (int z = 0; z < 5; z++)
                   {                                       
                      int newIndex = (temppt.Y + k) * 14 + (temppt.X + z);
                      double delta = xI[newIndex] * deltacnn[i];//一共25个
                      w1cnn[k * 5 + z, 0] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
                   }
             }

  //第二个卷积核202409191112

             double[] deltacnn1 = new double[25];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
             for (int i = 25; i < 50; i++)//25
             
                 for (int j = 0; j < 80; j++)//
                 {
                  
                     deltacnn1[i - 25] = dsigmoid(hO2[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
                 }
             for (int i = 0; i < 25; i++)
             {
                 Point temppt = 求二维(i, jilumn1na[i].Y, jilumn1na[i].X);
                 for (int k = 0; k < 5; k++)
                     for (int z = 0; z < 5; z++)
                     {
                    

                         int newIndex = (temppt.Y + k) * 14 + (temppt.X + z);
                         double delta = xI[newIndex] * deltacnn1[i];//一共25个
                         w1cnn[k * 5 + z, 1] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
                     }
             }
             //第三个卷积核202409191112

             double[] deltacnn2 = new double[25];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
             for (int i = 50; i < 75; i++)//25
             
                 for (int j = 0; j < 80; j++)//
                 {
                
                     deltacnn2[i - 50] = dsigmoid(hO2[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
                 }
             for (int i = 0; i < 25; i++)
             {
                 Point temppt = 求二维(i, jilumn2na[i].Y, jilumn2na[i].X);
                 for (int k = 0; k < 5; k++)
                     for (int z = 0; z < 5; z++)
                     {
                    

                         int newIndex = (temppt.Y + k) * 14 + (temppt.X + z);
                         double delta = xI[newIndex] * deltacnn2[i];//一共25个
                         w1cnn[k * 5 + z, 2] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
                     }
             }
            //第四个卷积核202409191112
             double[] deltacnn3 = new double[25];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核
             for (int i = 75; i < 100; i++)//25
            
                 for (int j = 0; j <80; j++)//
                 {
                  
                     deltacnn3[i - 75] = dsigmoid(hO2[j]) * W3[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);
                 }
             for (int i = 0; i < 25; i++)
             {
                 Point temppt = 求二维(i, jilumn3na[i].Y, jilumn3na[i].X);
                 for (int k = 0; k < 5; k++)
                     for (int z = 0; z < 5; z++)
                     {
                      

                         int newIndex = (temppt.Y + k) * 14 + (temppt.X + z);
                         double delta = xI[newIndex] * deltacnn3[i];//一共25个
                         w1cnn[k * 5 + z, 3] -= delta * learnRate;//只用一个卷积核,核forward就对应上了202409181430
                     }
             }

以上就处理完了。哦,还有一个函数:

 public Point 求二维(int index, int mm, int nn)
        {
            Point rePt = new Point();
            for (int i = 0; i < 5; i++)
                for (int j = 0; j < 5; j++)
                {
                    int n = i * 5 + j;
                    if (index == n)
                    {
                        int h = i * 2 + mm;
                        int w = j * 2 + nn;
                        rePt.X = w;
                        rePt.Y = h;

                    
                        i = 5;
                        j = 5;//end 2 for loop;
                    }
                }
            return rePt;
        }

或许,我这个cnn与你想的高大上的不同,但刨根问底,就是一回事!

也就是,你自学懂了,想怎么实现就怎么实现!

这几个核,在训练达到95分后,竟然自己生成了,太神奇!

想一想我们在图像处理里,用了那么多的卷积核,重来没有说是让计算机自己生成的,震惊到了吧!虽然这几个核,不那么好看,但的的确确,是计算机自己学习到的!

这是什么,这就是人工智能,这就是有学习能力的机器,太厉害了!所以人能做到的高斯核,机器在不断改进和进化中,一定会生成,更震惊的,他可能生成的卷积核,你都没见过,但他确实效果好,所以,他得到的结果,还有可能超过你!

本程序中,我们只生成了4个卷积核,那么使用8个卷积核,是不是效果更好?留作思考。

本节到此结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值