自己的初心,在bpnet基础上自研cnn

网上有cnn的源码(lenet),也有原理!(cpu版本的,很原始的那种,但还是比我的自研cnn好!)

所以改he凯明初始化,softmax,批处理,vgg,残差都实验成功了!

以及cudnn下也实现了bn和残差,自然也实现了并发!

但是自己的初心还是放不下,mnist下,应该有一个自己安心的版本!毕竟是自己原创的!

基于bpnet,怎样达成cnn呢?

其实就一句话:不放弃,磕到底,最终你会意识到权重和卷积核是一回事,这件事想通了,就基本成功了!

这次修改,其实我已经透彻了cnn的数学原理,也就是读过人家的paper了!

前头极简cnn几篇博客已经分析透彻了cnn的数学原理,也做了达成!

这次是审视和修改自己的初心,肯定还是比极简cnn复杂的多!

毕竟是训练mnist数据集!

虽然batch=10,但还是cpu版本的!c#达成!使用了he初始化和softmax,以及leaky relu!

卷积时的bias不好处理,也删除了,只保留了全连接中的bias!

训练一轮6万次,上了90分,训练时间降到1分07秒,没有batch要1分37秒!learnrate=0.015

第二轮,第三轮,讲的学习率到0.01,上96没问题,继续降低学习率,成绩还能上!

lr=0.005,超过97分!其实成绩我并不关注了,手写了十个数字,正常,基本全能正确识别!

只是在正确的cnn理论下约束自己的初心,使其数学化,达成安心版本!

其实我的版本里,有一些东西不在cnn理论中,而且训练成绩不降反升!这也是我为什么做记录的原因,人工智能困扰的地方,也可能时处女地!

好,先说在cnn理论下,自己初心达成的安心版本!

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.IO;

using System.Drawing.Imaging;

namespace 自己的20核

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

Random ran = new Random();

public double randomNormalDistribution()

{

double u = 0.0, v = 0.0, w = 0.0, c = 0.0;

do

{

//获得两个(-1,1)的独立随机变量

u = ran.NextDouble() * 2 - 1.0;

v = ran.NextDouble() * 2 - 1.0;

w = u * u + v * v;

} while (w == 0.0 || w >= 1.0);

//这里就是 Box-Muller转换

c = Math.Sqrt((-2 * Math.Log(w)) / w);

return u * c;

}

double[,] w576cnn = new double[25, 4];

double[,] w1cnn = new double[25, 4];

double[,] w1cnn2 = new double[25, 4];

double[,] w1cnn3 = new double[25, 4];

double[,] w1cnn4 = new double[25, 4];

double[,] delw1cnn = new double[25, 4];

double[,] delw1cnn2 = new double[25, 4];

double[,] delw1cnn3 = new double[25, 4];

double[,] delw1cnn4 = new double[25, 4];

double[,] w12cnn = new double[16 * 16, 80];

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

//double[] bIOcnn = new double[256];//不用B和deltaB,降低难度

//double[] bI2Ocnn = new double[80];

//double[] bycnn = new double[10];

void init()

{

//lenet-1

for (int i = 0; i < 25; i++)

for (int j = 0; j < 4; j++)

{

w576cnn[i, j] = randomNormalDistribution() / Math.Sqrt(25*batch_size / 2f);

}

for (int i = 0; i < 25; i++)

for (int j = 0; j < 4; j++)

{

w1cnn[i, j] = randomNormalDistribution() / Math.Sqrt(25 * batch_size / 2f);

w1cnn2[i, j] = randomNormalDistribution() / Math.Sqrt(25 * batch_size / 2f);

w1cnn4[i, j] = randomNormalDistribution() / Math.Sqrt(25 * batch_size / 2f);

w1cnn3[i, j] = randomNormalDistribution() / Math.Sqrt(25 * batch_size / 2f);

}

for (int i = 0; i < 16 * 16; i++)

for (int j = 0; j < 80; j++)

{

w12cnn[i, j] = randomNormalDistribution() / Math.Sqrt(256 * batch_size / 2f);

}

for (int i = 0; i < 80; i++)

for (int j = 0; j < 10; j++)

{

w2cnn[i, j] = randomNormalDistribution() / Math.Sqrt(80 * batch_size / 2f);

}

//for (int i = 0; i < 256; i++)

//{ bIOcnn[i] = randomNormalDistribution() / Math.Sqrt(256 / 2f); }

//for (int i = 0; i < 80; i++)

//{ bI2Ocnn[i] = randomNormalDistribution() / Math.Sqrt(80 / 2f); }

//for (int i = 0; i < 10; i++)

//{ bycnn[i] = randomNormalDistribution() / Math.Sqrt(10 / 2f); }

}

List<byte[]> alltraindataorg = new List<byte[]>();

double[][] hello28 = new double[60000][];

List<int> labels = new List<int>();

void ReadMnistImages(string filePath)

{

alltraindataorg.Clear();

using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))

using (BinaryReader reader = new BinaryReader(fileStream))

{

// 跳过文件头的前16个字节

reader.ReadBytes(16);

while (fileStream.Position < fileStream.Length)

{

byte[] image = reader.ReadBytes(28 * 28); // MNIST图像大小为28x28

alltraindataorg.Add(image);

}

}

}

void ReadMnistLabels(string filePath)

{

labels.Clear();

using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))

using (BinaryReader reader = new BinaryReader(fileStream))

{

// 跳过文件头的前8个字节

reader.ReadBytes(8);

while (fileStream.Position < fileStream.Length)

{

byte label = reader.ReadByte(); // 读取标签

// 处理标签数据

// ...

labels.Add(label);

}

}

}

double learnRate = 0.2f; //学习率

private void button29_Click(object sender, EventArgs e)

{

init();

////////////duqu mnist shujuji ,DuQu Mnist ShuJuJi//2024090111004

string imagesFilePath = "c:\\train-images.idx3-ubyte";

string labelsFilePath = "c:\\train-labels.idx1-ubyte";

ReadMnistImages(imagesFilePath);

ReadMnistLabels(labelsFilePath);

for (int xx = 0; xx < 60000; xx++)

{

hello28[xx] = new double[28 * 28];

for (int i = 0; i < 28 * 28; i++)

{

hello28[xx][i] = alltraindataorg[xx][i] / 255f;

}

}//上头的初始化应该独立出去

//learnRate = 0.015f;//不错,上96了202502272143

learnRate = 0.015f;

showbuffer2pictmod4(new Byte[28 * 28], 28, 28, pictureBox20);

}

void showbuffer2pictmod4(byte[] buffer, int ww, int hh, PictureBox destImg)

{

int mod = ww % 4;//解决四位对齐问题20150716

int temproiw = ww + (4 - mod) % 4;//其实这都是和显示相关,处理图像其实不必考虑,

//顯示

byte[] cutvalues = new byte[temproiw * hh * 3];

int bytes = temproiw * hh * 3;

Bitmap cutPic24 = new Bitmap(temproiw, hh, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

BitmapData _cutPic = cutPic24.LockBits(new Rectangle(0, 0, temproiw, hh), ImageLockMode.ReadWrite,

cutPic24.PixelFormat);

IntPtr ptr = _cutPic.Scan0;//得到首地址

for (int i = 0; i < hh; i++)

{

for (int j = 0; j < ww; j++)

{

int n = i * ww + j;

//int m = 3 * n;

int m = 3 * (i * temproiw + j);

cutvalues[m] = buffer[n];

cutvalues[m + 1] = buffer[n];

cutvalues[m + 2] = buffer[n];

}

}

System.Runtime.InteropServices.Marshal.Copy(cutvalues, 0, ptr, bytes);

cutPic24.UnlockBits(_cutPic);

destImg.Image = cutPic24;

}

int[] last = new int[60000];

int batch_size = 10;

public void updatesumresult()

{

//最后更新d

for (int j = 0; j < 10; j++)//10

for (int i = 0; i < 80; i++)//15

{

w2cnn[i, j] -= learnRate * 临时dzw2[i, j] / batch_size;

}

for (int j = 0; j < 80; j++)//15

for (int i = 0; i < 16 * 16; i++)//256

{

w12cnn[i, j] -= learnRate * 临时dzw12[i, j] / batch_size;

}

//for (int i = 0; i < 10; i++)

//{

// bycnn[i] -= learnRate * 临时记录dby[i];

//}

//for (int i = 0; i < 80; i++)

//{

// bI2Ocnn[i] -= learnRate * 临时记录dbhI2O[i];

//}

//for (int i = 0; i < 256; i++)

//{

// bIOcnn[i] -= learnRate * 临时记录dbhIO[i];

//}

//卷积核[k * 5 + z, (tidai) % 4] -= delta * learnRate;

for (int i = 0; i < 25; i++)

for(int j=0;j<4;j++)

{

w1cnn[i, j] -= delw1cnn[i, j] * learnRate/batch_size;

w1cnn2[i, j] -= delw1cnn2[i, j] * learnRate / batch_size;

w1cnn3[i, j] -= delw1cnn3[i, j] * learnRate / batch_size;

w1cnn4[i, j] -= delw1cnn4[i, j] * learnRate / batch_size;

}

//图像变了10次了,怎么会对?

for (int i = 0; i < 25; i++)

{

w576cnn[i, 0] -= (delta576w03[i] + delta576w02[i] + delta576w01[i] + delta576w00[i]) * learnRate / batch_size;

}

for (int i = 0; i < 25; i++)

{

w576cnn[i, 1] -= (delta576w13[i] + delta576w12[i] + delta576w11[i] + delta576w10[i]) * learnRate / batch_size;

}

for (int i = 0; i < 25; i++)

{

w576cnn[i, 2] -= (delta576w23[i] + delta576w22[i] + delta576w21[i] + delta576w20[i]) * learnRate / batch_size;

}

for (int i = 0; i < 25; i++)

{

w576cnn[i, 3] -= (delta576w33[i] + delta576w32[i] + delta576w31[i] + delta576w30[i]) * learnRate / batch_size;

}

}

public void reset_update_all()

{

for (int j = 0; j < 10; j++)//10

{

for (int i = 0; i < 80; i++)//15

{

临时dzw2[i, j] = 0;

}

}

for (int j = 0; j < 80; j++)//

{

for (int i = 0; i < 16 * 16; i++)//256

{

临时dzw12[i, j] = 0;

}

}

//for (int i = 0; i < 16; i++)

//{

// deltacnn[i] = 0;

// deltacnn1[i] = 0;

// deltacnn2[i] = 0;

// deltacnn3[i] = 0;

// deltacnn5[i] = 0;

// deltacnn6[i] = 0;

// deltacnn7[i] = 0;

// deltacnn8[i] = 0;

// deltacnn9[i] = 0;

// deltacnn10[i] = 0;

// deltacnn11[i] = 0;

// deltacnn12[i] = 0;

// deltacnn13[i] = 0;

// deltacnn14[i] = 0;

// deltacnn15[i] = 0;

// deltacnn16[i] = 0;

//}

for (int i = 0; i < 25; i++)

{

delw1cnn[i, 0] = 0; delw1cnn[i, 1] = 0; delw1cnn[i, 2] = 0; delw1cnn[i, 3] = 0;

delw1cnn2[i, 0] = 0; delw1cnn2[i, 1] = 0; delw1cnn2[i, 2] = 0; delw1cnn2[i, 3] = 0;

delw1cnn3[i, 0] = 0; delw1cnn3[i, 1] = 0; delw1cnn3[i, 2] = 0; delw1cnn3[i, 3] = 0;

delw1cnn4[i, 0] = 0; delw1cnn4[i, 1] = 0; delw1cnn4[i, 2] = 0; delw1cnn4[i, 3] = 0;

delta576w00[i] = 0;

delta576w01[i] = 0;

delta576w02[i] = 0;

delta576w03[i] = 0;

delta576w10[i] = 0;

delta576w11[i] = 0;

delta576w12[i] = 0;

delta576w13[i] = 0;

delta576w20[i] = 0;

delta576w21[i] = 0;

delta576w22[i] = 0;

delta576w23[i] = 0;

delta576w30[i] = 0;

delta576w31[i] = 0;

delta576w32[i] = 0;

delta576w33[i] = 0;

}

}

private void button30cnn_Click(object sender, EventArgs e)

{

last=new int[60000];

DateTime dt = DateTime.Now;

for (int cas = 0; cas < 6000; cas++)

{

reset_update_all();

for (int j = 0;j < 10; j++)

{

int n = cas * batch_size + j;

traincnn(n);//改minibatch,要把更新单独出来,10次一更新,要累加,就要改变初始化值202507130503

}

updatesumresult();//10次一更新

}

int P = 100;

int he = 59100;

float junzhi = 0;

for (int n = 0; n < 9; n++)

{

int hh = 0;

for (int i = 0; i < P; i++)

{

hh += last[he + i];

}

textBox47.Text += he.ToString() + "," + hh.ToString() + "\r\n";

he += 100;

junzhi += hh;

}

junzhi = junzhi / 9f;

TimeSpan sp = DateTime.Now - dt;

textBox47.Text += "均值:" + junzhi.ToString() + "\r\n";

textBox48.Text = sp.ToString();

}

double[] hIcnntemp1 = new double[576]; double[] hIcnntemp = new double[576];

double[] hIcnntemp2 = new double[576]; double[] hIcnntemp3 = new double[576];

List<Point> jilumn1na = new List<Point>(); List<Point> jilumnna = new List<Point>();

List<Point> jilumn2na = new List<Point>(); List<Point> jilumn3na = new List<Point>();

double[] hIcnn1na = new double[144]; double[] hIcnnna = new double[144];

double[] hIcnn2na = new double[144]; double[] hIcnn3na = new double[144];

double[] hI遗忘1 = new double[144]; double[] hI遗忘 = new double[144];

double[] hI遗忘2 = new double[144]; double[] hI遗忘3 = new double[144];

public double NDrelu(double x)

{

return x > 0 ? x : 0.01f * x;//=max(0.1x,x)

}

public double dNDrelu(double x)

{

// return x * (1 - x);

return x > 0 ? 1f : 0.01f;

}

List<double[]> hebingbackImg = new List<double[]>();

List<List<Point>> hebingpos = new List<List<Point>>();

double[] hocnnhebing = new double[16 * 16];

void maxpooling(int p后h, int p后w,int 前图h,int 前图w,double[] 前图,double[] p后图,ref List<Point> maxP相对位置)//24*24->12*12,2*2取最大

{

for (int i = 0; i < p后h; i++)

for (int j = 0; j < p后w; j++)//

{

int l = (i) * p后w + 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) * 前图w+ j * 2 + n;

if (前图[k] > tempb)

{

tempb = 前图[k];//如果是最大值,核就变得没有意义,back怎么办?202409170727

tempPt = new Point(n, m);//m是h,n是w,这个要小心用错

}

}

maxP相对位置.Add(tempPt);//25个数据,就有25组m,n,序号一一对应

p后图[l] = tempb;//25个数据,通过这个关系,就能找到14*14matrix中去。202409181038

}

}

public void cnnforward()//202409180943使用4层网络,抄过来(这里还是三层网络),14*14->5*5->15->10

{

hIcnntemp = new double[576];

hIcnntemp1 = new double[576]; hIcnntemp2 = new double[576]; hIcnntemp3 = new double[576];

hIcnn1na = new double[144]; hIcnn2na = new double[144]; hIcnn3na = new double[144];

hIcnnna = new double[144];//每一幅图片都要重置

hI遗忘 = new double[144]; hI遗忘2 = new double[144]; hI遗忘3 = new double[144];

hI遗忘1 = new double[144];//每一幅图片都要重置

jilumnna.Clear();//forwardcnn执行一次,就是换一张图片

jilumn1na.Clear();

jilumn2na.Clear(); jilumn3na.Clear();

for (int i = 0; i < 24; i++)

for (int j = 0; j < 24; j++)//

{

int l = (i) * 24 + j;

for (int m = 0; m < 5; m++)

for (int n = 0; n < 5; n++)

{

int k = (i + m) * 28 + j + n;

hIcnntemp[l] += xI[k] * w576cnn[m * 5 + n, 0];//始终用零组,其他三个组不用

//为了方便,如此设计202409181006

hIcnntemp1[l] += xI[k] * w576cnn[m * 5 + n, 1];

hIcnntemp2[l] += xI[k] * w576cnn[m * 5 + n, 2];

hIcnntemp3[l] += xI[k] * w576cnn[m * 5 + n, 3];

}

}

////第二步,24*24》12*12

maxpooling(12, 12, 24, 24, hIcnntemp, hIcnnna, ref jilumnna);

maxpooling(12, 12, 24, 24, hIcnntemp1, hIcnn1na, ref jilumn1na);

maxpooling(12, 12, 24, 24, hIcnntemp2, hIcnn2na, ref jilumn2na);

maxpooling(12, 12, 24, 24, hIcnntemp3, hIcnn3na, ref jilumn3na);

//4*12*12 //第一次maxpooling返回位置

for (int i = 0; i < 144; i++)//12*12时才做sigmod,挺有意思202507120618

{

hI遗忘[i] = NDrelu(hIcnnna[i]);

hI遗忘1[i] = NDrelu(hIcnn1na[i]);

hI遗忘2[i] = NDrelu(hIcnn2na[i]);

hI遗忘3[i] = NDrelu(hIcnn3na[i]);

}

/////////

// 上面已经达成12*12的四张特征图202409211852,下面每张特征图再卷积成8*8,下采样,生成4张4*4

hebingbackImg = new List<double[]>(); //16*4*4

hebingpos = new List<List<Point>>();//第二次maxpooling返回位置

List<double[]> tempbackImg = new List<double[]>();

List<List<Point>>

temp = chongfu(hI遗忘, w1cnn, ref tempbackImg);//重复一次,生成4张4*4特征图和16个位置记录要返回,4次就是,16张图,64个位置记录

for (int i = 0; i < 4; i++)

{

hebingpos.Add(temp[i]);

hebingbackImg.Add(tempbackImg[i]);

}

tempbackImg.Clear();

temp.Clear();

temp = chongfu(hI遗忘1, w1cnn2, ref tempbackImg);//重复一次,生成4张4*4特征图和16个位置记录要返回,4次就是,16张图,64个位置记录

for (int i = 0; i < 4; i++)

{

hebingpos.Add(temp[i]);

hebingbackImg.Add(tempbackImg[i]);

}

tempbackImg.Clear();

temp.Clear();

temp = chongfu(hI遗忘2, w1cnn3, ref tempbackImg);//重复一次,生成4张4*4特征图和16个位置记录要返回,4次就是,16张图,64个位置记录

for (int i = 0; i < 4; i++)

{

hebingpos.Add(temp[i]);

hebingbackImg.Add(tempbackImg[i]);

}

tempbackImg.Clear();

temp.Clear();

temp = chongfu(hI遗忘3, w1cnn4, ref tempbackImg);//重复一次,生成4张4*4特征图和16个位置记录要返回,4次就是,16张图,64个位置记录

for (int i = 0; i < 4; i++)

{

hebingpos.Add(temp[i]);

hebingbackImg.Add(tempbackImg[i]);

}

hocnnhebing = new double[16 * 16];

for (int i = 0; i < 16; i++)

for (int j = 0; j < 16; j++)//4*4

{

int n = i * 16 + j;

// hocnnhebing[n] = NDrelu(hebingbackImg[i][j] + bIOcnn[n]);//4*4时才做sigmod,挺有意思202507120618

hocnnhebing[n] = NDrelu(hebingbackImg[i][j] );

}

//下面开始全连接202409181044

hI2cnn = new double[80];//15gai 25

for (int i = 0; i < 16 * 16; i++)//128

for (int j = 0; j < 80; j++)//60

hI2cnn[j] += (hocnnhebing[i]) * w12cnn[i, j];//75,25

//通过激活函数对隐藏层进行计算

for (int i = 0; i < 80; i++)

// hO2cnn[i] = NDrelu(hI2cnn[i] + bI2Ocnn[i]);

hO2cnn[i] = NDrelu(hI2cnn[i] );

yicnn = new double[10];

//通过w2计算隐藏层-输出层

for (int i = 0; i < 80; i++)

for (int j = 0; j < 10; j++)

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

//通过激活函数求yo

for (int i = 0; i < 10; i++)

// yOcnn[i] = NDrelu(yicnn[i] + bycnn[i]);

yOcnn[i] = NDrelu(yicnn[i] );

////////////////////////////

//下面是softmax,//yo相当与zi

double maxtemp = yOcnn[0];

for (int i = 1; i < 10; i++)

{

if (yOcnn[i] > maxtemp)

maxtemp = yOcnn[i];

}

double sum = 0;

// 首先找出yo中最大,然后softmax

for (int i = 0; i < 10; i++)

{

sum += Math.Exp(yOcnn[i] - maxtemp);

}

for (int i = 0; i < 10; i++)

{

softm[i] = Math.Exp(yOcnn[i] - maxtemp) / sum;//概率计算完毕

}

}

double[] hI2cnn = new double[80];

double[] hO2cnn = new double[80];

double[] yicnn = new double[10];

double[] yOcnn = new double[10];

double[] ThIcnntemp = new double[64];

double[] ThIcnntemp1 = new double[64]; double[] ThIcnntemp2 = new double[64]; double[] ThIcnntemp3 = new double[64];

double[] ThIcnn1na = new double[16]; double[] ThIcnn2na = new double[16]; double[] ThIcnn3na = new double[16];

double[] ThIcnnna = new double[16];//每一幅图片都要重置

List<Point> Tjilumn1na = new List<Point>(); List<Point> Tjilumnna = new List<Point>();

List<Point> Tjilumn2na = new List<Point>(); List<Point> Tjilumn3na = new List<Point>();

public List<List<Point>> chongfu(double[] 输入图像, double[,] 卷积核,ref List<double[]> fanhuituxiang)

{

List<List<Point>> templlp = new List<List<Point>>();

// 上面已经达成12*12的四张特征图202409211852,下面每张特征图再卷积成8*8,下采样,生成4张4*4

ThIcnntemp = new double[64];

ThIcnntemp1 = new double[64]; ThIcnntemp2 = new double[64]; ThIcnntemp3 = new double[64];

ThIcnn1na = new double[16]; ThIcnn2na = new double[16]; ThIcnn3na = new double[16];

ThIcnnna = new double[16];//每一幅图片都要重置

Tjilumnna.Clear();//forwardcnn执行一次,就是换一张图片

Tjilumn1na.Clear();

Tjilumn2na.Clear(); Tjilumn3na.Clear();

for (int i = 0; i < 8; i++)

for (int j = 0; j < 8; j++)//

{

int l = (i) * 8 + j;

for (int m = 0; m < 5; m++)

for (int n = 0; n < 5; n++)

{

int k = (i + m) * 12 + j + n;

ThIcnntemp[l] += 输入图像[k] * 卷积核[m * 5 + n, 0];//始终用零组,其他三个组不用

//为了方便,如此设计202409181006

ThIcnntemp1[l] += 输入图像[k] * 卷积核[m * 5 + n, 1];

ThIcnntemp2[l] += 输入图像[k] * 卷积核[m * 5 + n, 2];

ThIcnntemp3[l] += 输入图像[k] * 卷积核[m * 5 + n, 3];//一个图像用四个卷积核生成4个特征图*8*8

}

}

//第二步,8*8-》4*4

maxpooling(4, 4, 8, 8, ThIcnntemp, ThIcnnna, ref Tjilumnna);

templlp.Add(Tjilumnna); fanhuituxiang.Add(ThIcnnna);

maxpooling(4, 4, 8, 8, ThIcnntemp1, ThIcnn1na, ref Tjilumn1na);

templlp.Add(Tjilumn1na); fanhuituxiang.Add(ThIcnn1na);

maxpooling(4, 4, 8, 8, ThIcnntemp2, ThIcnn2na, ref Tjilumn2na);

templlp.Add(Tjilumn2na); fanhuituxiang.Add(ThIcnn2na);

maxpooling(4, 4, 8, 8, ThIcnntemp3, ThIcnn3na, ref Tjilumn3na); //程序中的0初始化值,已经核实过,是ok的20250712

templlp.Add(Tjilumn3na); fanhuituxiang.Add(ThIcnn3na);

return templlp;

}

double[] softm = new double[10];

double[] xI = new double[28 * 28];

int[] d = new int[10];

void traincnn(int cas)

{

//是否需要重置deltaB?deltaW?在minibatch中?要

xI = hello28[cas];//28*28

int num = labels[cas];

d = new int[10];

d[num] = 1;

cnnforward();

int ans = getAnsSoftmaxcnn();

if (num == ans)

last[cas] = 1;

softm[num] = softm[num] - 1;

backcnn();

}

public double[] 更新卷积核(double[] 中间值, int 卷积核序号, double[] 图像, double[,] 卷积核)//=4,=5,卷积核序号从1开始

{

//第四个卷积核202409191112

double[] deltacnn3 = new double[16];//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核

int kk = 0;

int tidai = 卷积核序号 - 1;

int temp = (tidai) * 16;

for (int i = temp; i < temp + 16; i++)

{

for (int j = 0; j < 80; j++)//15

{

// deltacnn3[kk] = 中间值[j] * w12cnn[i, j] * dsigmoid(hocnnhebing[i]);

// 临时记录dbhIO[i] =?这个怎么办?202502271112

deltacnn3[kk] += 中间值[j] * w12cnn[i, j] * dNDrelu(hocnnhebing[i]);

}

// deltacnn3[kk] /= 80;

kk++;

}

//for (int i = 0; i < 16; i++)

//{

// Point temppt = 求二维(i, hebingpos[tidai][i].Y, hebingpos[tidai][i].X);//3代表第si波16个

// for (int k = 0; k < 5; k++)

// for (int z = 0; z < 5; z++)

// {

// int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);

// double delta = 图像[newIndex] * deltacnn3[i];//一共25个

// // w1cnn1[k * 5 + z, 卷积核序号 - 1] -= delta * learnRate;

// 卷积核[k * 5 + z, (tidai) % 4] -= delta * learnRate;

// }

// }

return deltacnn3;

}

public void last更新卷积核minibatch(double[] 更新卷积核ret, int 卷积核序号, double[] 图像, double[,] 卷积核)//=4,=5,卷积核序号从1开始

{

int tidai = 卷积核序号 - 1;

for (int i = 0; i < 16; i++)

{

Point temppt = 求二维(i, hebingpos[tidai][i].Y, hebingpos[tidai][i].X);//3代表第si波16个

for (int k = 0; k < 5; k++)

for (int z = 0; z < 5; z++)

{

int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);

// 更新卷积核ret[i] += 图像[newIndex] * 更新卷积核ret[i];//一共25个

卷积核[k * 5 + z, (tidai) % 4] += 图像[newIndex] * 更新卷积核ret[i];

//// w1cnn1[k * 5 + z, 卷积核序号 - 1] -= delta * learnRate;

//卷积核[k * 5 + z, (tidai) % 4] -= delta * learnRate;

}

}

//// 更新卷积核ret[i] = 更新卷积核ret[i] / 25f;

// for (int k = 0; k < 25; k++)

// { 卷积核[k, (tidai) % 4] /= 16; }

}

public void last更新卷积核(double[] 更新卷积核ret, int 卷积核序号, double[] 图像, double[,] 卷积核)//=4,=5,卷积核序号从1开始

{

int tidai = 卷积核序号 - 1;

for (int i = 0; i < 16; i++)

{

Point temppt = 求二维(i, hebingpos[tidai][i].Y, hebingpos[tidai][i].X);//3代表第si波16个

for (int k = 0; k < 5; k++)

for (int z = 0; z < 5; z++)

{

int newIndex = (temppt.Y + k) * 12 + (temppt.X + z);

double delta = 图像[newIndex] * 更新卷积核ret[i];//一共25个

// w1cnn1[k * 5 + z, 卷积核序号 - 1] -= delta * learnRate;

卷积核[k * 5 + z, (tidai) % 4] -= delta * learnRate;

}

}

}

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;

}

void 求deltaW576( double[] deltacnnx, double[,] w1cnnx,int 指定核, List<Point> 记录mn,double[] deltaW576, double[] hI遗忘图,int pool1W=12,int pool1前原图W=28)

{

double[] deltacnnXx = new double[16];

for (int i = 0; i < 16; i++)//16

{

for (int j = 0; j < 25; j++)//25

{

deltacnnXx[i] += deltacnnx[i] * w1cnnx[j, 指定核];

}

// deltacnnXx[i] /= 25;//图像中有25个位置导致

}

// double[] delta576w0 = new double[25];

for (int i = 0; i < 16; i++)

{

Point temppt = 求二维(i, 记录mn[i].Y, 记录mn[i].X);

for (int k = 0; k < 5; k++)

for (int z = 0; z < 5; z++)

{

int newIndex = (temppt.Y + k) * pool1前原图W + (temppt.X + z);

int biasIndex = (temppt.Y / 2 + k) * pool1W + temppt.X / 2 + z;

//double delta = deltacnnX[i] * dNDrelu(hI遗忘[biasIndex]) * learnRate;//一共25个 ,12*12=hI遗忘

//w576cnn[k * 5 + z, 0] -= xI[newIndex] * delta;//28*28,更新四个卷积核,先不更新,想用minibatch,10次运算,更新一次

double delta = deltacnnXx[i] * dNDrelu(hI遗忘图[biasIndex]);//一共25个 ,12*12=hI遗忘

deltaW576[k * 5 + z] += xI[newIndex] * delta;//28*28,更新四个卷积核,先不更新,想用minibatch,10次运算,更新一次

//deltaW576[k * 5 + z] = xI[newIndex] * delta;//28*28,更新四个卷积核,先不更新,想用minibatch,10次运算,更新一次

}

}

//for (int k = 0; k < 25; k++)

//{

// deltaW576[k] /= 16f;

//}

}

//反向传播函数

double[,] 临时dzw2 = new double[80, 10];

double[,] 临时dzw12 = new double[16 * 4 * 4, 80];

double[] delta576w00 = new double[25];

double[] delta576w01 = new double[25];

double[] delta576w02 = new double[25];

double[] delta576w03 = new double[25];

double[] delta576w10 = new double[25];

double[] delta576w11 = new double[25];

double[] delta576w12 = new double[25];

double[] delta576w13 = new double[25];

double[] delta576w20 = new double[25];

double[] delta576w21 = new double[25];

double[] delta576w22 = new double[25];

double[] delta576w23 = new double[25];

double[] delta576w30 = new double[25];

double[] delta576w31 = new double[25];

double[] delta576w32 = new double[25];

double[] delta576w33 = new double[25];

void backcnn()//应该引入结局b的更新,这样可以加快收敛速度202409140818

{

double[] 替代 = new double[10];

//double[,] 临时dzw2 = new double[80, 10];

//double[,] 临时dzw12 = new double[16*4*4, 80];

////更新delta w1cnn【25,4】《--来自临时dzw12【0-63,80】,第一4*4*4

////更新delta w2cnn【25,4】《--来自临时dzw12【64-127,80】,第二4*4*4

////更新delta w3cnn【25,4】《--来自临时dzw12【128-191,80】,第三4*4*4

////更新delta w4cnn【25,4】《--来自临时dzw12【191-255,80】,第四4*4*4

//double[] 临时记录dby = new double[10];

//double[] 临时记录dbhI2O = new double[80];

//double[] 临时记录dbhIO = new double[256];

//////double[] 临时记录db = new double[144];

//////double[] 临时记录db1 = new double[144];

//////double[] 临时记录db2 = new double[144];

//////double[] 临时记录db3 = new double[144];

double[] deltacnn = new double[16];

double[] deltacnn1 = new double[16];

double[] deltacnn2 = new double[16];

double[] deltacnn3 = new double[16];

double[] deltacnn5 = new double[16];

double[] deltacnn6 = new double[16];

double[] deltacnn7 = new double[16];

double[] deltacnn8 = new double[16];

double[] deltacnn9 = new double[16];

double[] deltacnn10 = new double[16];

double[] deltacnn11 = new double[16];

double[] deltacnn12 = new double[16];

double[] deltacnn13 = new double[16];//卷积核w1cnn4[25,0],5*5的卷积核

double[] deltacnn14 = new double[16];//卷积核w1cnn4[25,1]

double[] deltacnn15 = new double[16];//卷积核w1cnn4[25,2]

double[] deltacnn16 = new double[16];//卷积核w1cnn4[25,3]

for (int j = 0; j < 10; j++)//10

{

// 临时记录dby[j] =

替代[j] = softm[j] * dNDrelu(yOcnn[j]);

for (int i = 0; i < 80; i++)//15

{

临时dzw2[i, j] += 替代[j] * hO2cnn[i];//这里出现+的原因是batch导致的20260401

}

}

double[] W3 = new double[80];//

for (int j = 0; j < 80; j++)//

for (int k = 0; k < 10; k++)//10

W3[j] += 替代[k] * w2cnn[j, k];

double[] 替代2 = new double[80];

for (int j = 0; j < 80; j++)//

{

// 临时记录dbhI2O[j] =

替代2[j] = dNDrelu(hO2cnn[j]) * W3[j];

for (int i = 0; i < 16 * 16; i++)//256

{

临时dzw12[i, j] += 替代2[j] * (hocnnhebing[i]); //这里出现+的原因是batch导致的20260401

}

}

//上头是全连接

//下头是卷积核,处理变得不一样,头4个与与w1cnn有关,

//即第一4*4*4=64,更新deltaw1cnn【25,0】,更新deltaw1cnn【25,1】,

//更新deltaw1cnn【25,2】,更新deltaw1cnn【25,3】

//卷积核中一个元素,在图像中可以找到很多位置,这个问题怎么办?202507121726

//取均值,有80,求和后,除80,如果有25,求和后,除以25,试试看,公式中没给出表达,办法比问题多。

for (int i = 0; i < 16; i++)//25

{

for (int j = 0; j < 80; j++)//

{

// 临时记录dbhIO[i] =

deltacnn[i] += 替代2[j] * w12cnn[i, j] * dNDrelu(hocnnhebing[i]);//与w1cnn有关

}//全连接还是好处理202409200708

// deltacnn[i]/= 80;//80次,取个均值

}

//另一个卷积核202409191112

//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核

for (int i = 16; i < 32; i++)//25

{

for (int j = 0; j < 80; j++)//

{

// 临时记录dbhIO[i] =

deltacnn1[i - 16] += 替代2[j] * w12cnn[i, j] * dNDrelu(hocnnhebing[i]);//与w1cnn有关

}

// deltacnn1[i - 16] /= 80;//80次,取个均值

}

//第三个卷积核202409191112

//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核

for (int i = 32; i < 48; i++)//25

{

for (int j = 0; j < 80; j++)//

{

// 临时记录dbhIO[i] =

deltacnn2[i - 32] += 替代2[j] * w12cnn[i, j] * dNDrelu(hocnnhebing[i]);//与w1cnn有关

}

// deltacnn2[i - 32] /= 80;//80次,取个均值

}

//第四个卷积核202409191112

//每一个deltacnn,都对应25个14*14中的数据元素,以及一个5*5的卷积核

for (int i = 48; i < 64; i++)//25

{

for (int j = 0; j < 80; j++)//15

{

// 临时记录dbhIO[i] =

deltacnn3[i - 48] += 替代2[j] * w12cnn[i, j] * dNDrelu(hocnnhebing[i]);//与w1cnn有关

}

// deltacnn3[i - 48] /= 80;//80次,取个均值

}

//4个卷积核已经更新完,下面第5个到16

deltacnn5 = 更新卷积核(替代2, 5, hIcnn1na, w1cnn2);//5->0,w1cnn2[25,(5 - 1) % 4]->w1cnn2[25,(6 - 1) % 4]->w1cnn2[25,(7 - 1) % 4]->w1cnn2[25,(8 - 1) % 4]

deltacnn6 = 更新卷积核(替代2, 6, hIcnn1na, w1cnn2);

deltacnn7 = 更新卷积核(替代2, 7, hIcnn1na, w1cnn2);

deltacnn8 = 更新卷积核(替代2, 8, hIcnn1na, w1cnn2);

deltacnn9 = 更新卷积核(替代2, 9, hIcnn2na, w1cnn3);//9->0,w1cnn3[25,(9- 1) % 4]->w1cnn3[25,(10 - 1) % 4]->w1cnn3[25,(11- 1) % 4]->w1cnn3[25,(12 - 1) % 4]

deltacnn10 = 更新卷积核(替代2, 10, hIcnn2na, w1cnn3);

deltacnn11 = 更新卷积核(替代2, 11, hIcnn2na, w1cnn3);

deltacnn12 = 更新卷积核(替代2, 12, hIcnn2na, w1cnn3);

deltacnn13 = 更新卷积核(替代2, 13, hIcnn3na, w1cnn4);//卷积核w1cnn4[25,0],5*5的卷积核

deltacnn14 = 更新卷积核(替代2, 14, hIcnn3na, w1cnn4);//卷积核w1cnn4[25,1]

deltacnn15 = 更新卷积核(替代2, 15, hIcnn3na, w1cnn4);//卷积核w1cnn4[25,2]

deltacnn16 = 更新卷积核(替代2, 16, hIcnn3na, w1cnn4);//卷积核w1cnn4[25,3]//hIcnn3na是12*12的图像《-8**《-4*4,backup

//for (int i = 0; i < 16; i++)//四个没有更新,发现一个delta|B错误202507130520,为改正,屏蔽

//{

// 临时记录dbhIO[64 + i] = deltacnn5[i];

// 临时记录dbhIO[64 + 16 + i] = deltacnn6[i];

// 临时记录dbhIO[64 + 16 * 2 + i] = deltacnn7[i];

// 临时记录dbhIO[64 + 16 * 3 + i] = deltacnn8[i];

// 临时记录dbhIO[64 + 16 * 4 + i] = deltacnn9[i];

// 临时记录dbhIO[64 + 16 * 5 + i] = deltacnn10[i];

// 临时记录dbhIO[64 + 16 * 6 + i] = deltacnn11[i];

// 临时记录dbhIO[64 + 16 * 7 + i] = deltacnn12[i];

// 临时记录dbhIO[64 + 16 * 8 + i] = deltacnn13[i];

// 临时记录dbhIO[64 + 16 * 9 + i] = deltacnn14[i];

// 临时记录dbhIO[64 + 16 * 10 + i] = deltacnn15[i];

// 临时记录dbhIO[64 + 16 * 11 + i] = deltacnn16[i];

//}

////继续向上,四个卷积核刚好对应一副原始图像,即四个卷积核向上对应一个卷积核28*28-》24*24-》12*12

////卷积核w1cnn[25,4]对应xI[k] * w576cnn[m * 5 + n, 0]

////卷积核w1cnn1[25,4]对应xI[k] * w576cnn[m * 5 + n, 1]

// double[] deltacnnX = new double[16];//每一个deltacnnx,都对应25个28*28中的数据元素,以及一个5*5的卷积核

求deltaW576( deltacnn, w1cnn, 0, jilumnna, delta576w00, hI遗忘);

求deltaW576( deltacnn1, w1cnn, 1, jilumnna, delta576w01, hI遗忘);

求deltaW576( deltacnn2, w1cnn, 2, jilumnna, delta576w02, hI遗忘);

求deltaW576( deltacnn3, w1cnn, 3, jilumnna, delta576w03, hI遗忘);

//第二轮开

求deltaW576( deltacnn5, w1cnn2, 0, jilumn1na, delta576w10, hI遗忘1);

求deltaW576( deltacnn6, w1cnn2, 1, jilumn1na, delta576w11, hI遗忘1);

求deltaW576( deltacnn7, w1cnn2, 2, jilumn1na, delta576w12, hI遗忘1);

求deltaW576( deltacnn8, w1cnn2, 3, jilumn1na, delta576w13, hI遗忘1);

//第san轮开始

求deltaW576( deltacnn9, w1cnn3, 0, jilumn2na, delta576w20, hI遗忘2);

求deltaW576( deltacnn10, w1cnn3, 1, jilumn2na, delta576w21, hI遗忘2);

求deltaW576( deltacnn11, w1cnn3, 2, jilumn2na, delta576w22, hI遗忘2);

求deltaW576( deltacnn12, w1cnn3, 3, jilumn2na, delta576w23, hI遗忘2);

////最后yilun

求deltaW576( deltacnn13, w1cnn4, 0, jilumn3na, delta576w30, hI遗忘3);

求deltaW576( deltacnn14, w1cnn4, 1, jilumn3na, delta576w31, hI遗忘3);

求deltaW576( deltacnn15, w1cnn4, 2, jilumn3na, delta576w32, hI遗忘3);

求deltaW576( deltacnn16, w1cnn4, 3, jilumn3na, delta576w33, hI遗忘3);

////最后更新d

//for (int j = 0; j < 10; j++)//10

// for (int i = 0; i < 80; i++)//15

// {

// w2cnn[i, j] -= learnRate * 临时dzw2[i, j];

// }

//for (int j = 0; j < 80; j++)//15

// for (int i = 0; i < 16 * 16; i++)//256

// {

// w12cnn[i, j] -= learnRate * 临时dzw12[i, j];

// }

////for (int i = 0; i < 10; i++)

////{

//// bycnn[i] -= learnRate * 临时记录dby[i];

////}

////for (int i = 0; i < 80; i++)

////{

//// bI2Ocnn[i] -= learnRate * 临时记录dbhI2O[i];

////}

////for (int i = 0; i < 256; i++)

////{

//// bIOcnn[i] -= learnRate * 临时记录dbhIO[i];

////}

//last更新卷积核(deltacnn, 1, hIcnnna, w1cnn);

//last更新卷积核(deltacnn1, 2, hIcnnna, w1cnn);

//last更新卷积核(deltacnn2, 3, hIcnnna, w1cnn);

//last更新卷积核(deltacnn3, 4, hIcnnna, w1cnn);

//last更新卷积核(deltacnn5, 5, hIcnn1na, w1cnn2);

//last更新卷积核(deltacnn6, 6, hIcnn1na, w1cnn2);

//last更新卷积核(deltacnn7, 7, hIcnn1na, w1cnn2);

//last更新卷积核(deltacnn8, 8, hIcnn1na, w1cnn2);

//last更新卷积核(deltacnn9, 9, hIcnn2na, w1cnn3);

//last更新卷积核(deltacnn10, 10, hIcnn2na, w1cnn3);

//last更新卷积核(deltacnn11, 11, hIcnn2na, w1cnn3);

//last更新卷积核(deltacnn12, 12, hIcnn2na, w1cnn3);

//last更新卷积核(deltacnn13, 13, hIcnn3na, w1cnn4);

//last更新卷积核(deltacnn14, 14, hIcnn3na, w1cnn4);

//last更新卷积核(deltacnn15, 15, hIcnn3na, w1cnn4);

//last更新卷积核(deltacnn16, 16, hIcnn3na, w1cnn4);

//for (int i = 0; i < 25; i++)

//{

// w576cnn[i, 0] -= (delta576w03[i] + delta576w02[i] + delta576w01[i] + delta576w00[i]) / 4 * learnRate;

//}

//for (int i = 0; i < 25; i++)

//{

// w576cnn[i, 1] -= (delta576w13[i] + delta576w12[i] + delta576w11[i] + delta576w10[i]) / 4 * learnRate;

//}

//for (int i = 0; i < 25; i++)

//{

// w576cnn[i, 2] -= (delta576w23[i] + delta576w22[i] + delta576w21[i] + delta576w20[i]) / 4 * learnRate;

//}

//for (int i = 0; i < 25; i++)

//{

// w576cnn[i, 3] -= (delta576w33[i] + delta576w32[i] + delta576w31[i] + delta576w30[i]) / 4 * learnRate;

//}

last更新卷积核minibatch(deltacnn, 1, hIcnnna, delw1cnn);

last更新卷积核minibatch(deltacnn1, 2, hIcnnna, delw1cnn);

last更新卷积核minibatch(deltacnn2, 3, hIcnnna, delw1cnn);

last更新卷积核minibatch(deltacnn3, 4, hIcnnna, delw1cnn);

last更新卷积核minibatch(deltacnn5, 5, hIcnn1na, delw1cnn2);

last更新卷积核minibatch(deltacnn6, 6, hIcnn1na, delw1cnn2);

last更新卷积核minibatch(deltacnn7, 7, hIcnn1na, delw1cnn2);

last更新卷积核minibatch(deltacnn8, 8, hIcnn1na, delw1cnn2);

last更新卷积核minibatch(deltacnn9, 9, hIcnn2na, delw1cnn3);

last更新卷积核minibatch(deltacnn10, 10, hIcnn2na, delw1cnn3);

last更新卷积核minibatch(deltacnn11, 11, hIcnn2na, delw1cnn3);

last更新卷积核minibatch(deltacnn12, 12, hIcnn2na, delw1cnn3);

last更新卷积核minibatch(deltacnn13, 13, hIcnn3na, delw1cnn4);

last更新卷积核minibatch(deltacnn14, 14, hIcnn3na, delw1cnn4);

last更新卷积核minibatch(deltacnn15, 15, hIcnn3na, delw1cnn4);

last更新卷积核minibatch(deltacnn16, 16, hIcnn3na, delw1cnn4);

}

int getAnsSoftmaxcnn()

{

int ans = 0;

for (int i = 1; i <10; i++)

if (softm[i] > softm[ans]) ans = i;

return ans;

}

private void button31_Click(object sender, EventArgs e)

{

Bitmap curBitmap = (Bitmap)pictureBox20.Image;

Rectangle rc = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);

System.Drawing.Imaging.BitmapData bmpdata = curBitmap.LockBits(rc,

System.Drawing.Imaging.ImageLockMode.ReadWrite,

curBitmap.PixelFormat);

IntPtr imageptr = bmpdata.Scan0;

int ww = curBitmap.Width;

int hh = curBitmap.Height;

int bytes = 0;

if (curBitmap.PixelFormat == PixelFormat.Format24bppRgb)

{

bytes = ww * hh * 3;//此处针对的是24位位图

}

byte[] rgbValues = new byte[bytes];

System.Runtime.InteropServices.Marshal.Copy(imageptr, rgbValues, 0, bytes);

curBitmap.UnlockBits(bmpdata);

// showbuffer2pictmod4(showoutput14, 14, 14, pictureBox10);

byte[] buffer8 = new byte[28 * 28];

double[] buffer8d = new double[28 * 28];

if (curBitmap.PixelFormat == PixelFormat.Format24bppRgb)

{

for (int ii = 0; ii < 28; ii++)

{

for (int j = 0; j < 28; j++)

{

int n = ii * 28 + j;

int k = (ii) * 28 + j;

// int m = 3 * k;

buffer8[k] = rgbValues[n * 3];//这里都是灰度图像20221209

// buffer8[k] = (byte)(0.3 * rgbValues[n * 3 + 2] + 0.59 * rgbValues[n * 3 + 1] + 0.11 * rgbValues[n * 3]);//这里是1024*768图像

buffer8d[k] = rgbValues[n * 3] / 255f;//这里都是灰度图像20221209

}

}

}

showbuffer2pictmod4(buffer8, 28, 28, pictureBox20);

textBox51.Text = "";

xI = buffer8d;

cnnforward();

// int ans = getAnscnn();

int ans = getAnsSoftmaxcnn();

for (int i = 0; i < 10; i++)

textBox51.Text += ((float)softm[i]).ToString() + "\r\n";

textBox49.Text = ans.ToString() + ";" + ((float)yOcnn[ans]).ToString();

}

private void button30_Click(object sender, EventArgs e)

{

showbuffer2pictmod4(new byte[28 * 28], 28, 28, pictureBox20);

}

Bitmap weitu28;

float bilix28 = 0; float biliy28 = 0;

private void pictureBox20_MouseMove(object sender, MouseEventArgs e)

{

if (huax28)

{

Graphics g = pictureBox20.CreateGraphics();

g.DrawLine(new Pen(Color.White, 12f), qidianx28, new Point(e.X, e.Y));//huabi gao kuai yidian

// Bitmap curBitmap = (Bitmap)pictureBox9.Image;

//curBitmap.SetPixel(e.X, e.Y, Color.White);

//weitu28.SetPixel((int)(e.X * bilix28), (int)(e.Y * biliy28), Color.White); ;

try

{

weitu28.SetPixel((int)(qidianx28.X * bilix28), (int)(qidianx28.Y * biliy28 - 1), Color.FromArgb(255, 255, 255));

weitu28.SetPixel((int)(qidianx28.X * bilix28), (int)(qidianx28.Y * biliy28 + 1), Color.FromArgb(255, 255, 255));

weitu28.SetPixel((int)(qidianx28.X * bilix28), (int)(qidianx28.Y * biliy28), Color.FromArgb(255, 255, 255));

weitu28.SetPixel((int)(qidianx28.X * bilix28 - 1), (int)(qidianx28.Y * biliy28), Color.FromArgb(255, 255, 255));

weitu28.SetPixel((int)(qidianx28.X * bilix28 + 1), (int)(qidianx28.Y * biliy28), Color.FromArgb(255, 255, 255));

qidianx28 = new Point(e.X, e.Y);

weitu28.SetPixel((int)(e.X * bilix28 - 1), (int)(e.Y * biliy28 - 1), Color.FromArgb(255, 255, 255));

weitu28.SetPixel((int)(e.X * bilix28 + 1), (int)(e.Y * biliy28 + 1), Color.FromArgb(255, 255, 255));

weitu28.SetPixel((int)(e.X * bilix28), (int)(e.Y * biliy28), Color.FromArgb(255, 255, 255));

weitu28.SetPixel((int)(e.X * bilix28 - 1), (int)(e.Y * biliy28 + 1), Color.FromArgb(255, 255, 255));

weitu28.SetPixel((int)(e.X * bilix28 + 1), (int)(e.Y * biliy28 - 1), Color.FromArgb(255, 255, 255));

}

catch (Exception ee)

{ }

}

}

private void pictureBox20_MouseDown(object sender, MouseEventArgs e)

{

weitu28 = (Bitmap)pictureBox20.Image;

bilix28 = weitu28.Width * 1f / pictureBox20.Width;

biliy28 = weitu28.Height * 1f / pictureBox20.Height;

if (MouseButtons.Left == e.Button)

{

qidianx28.X = e.X;

qidianx28.Y = e.Y;

// e.Button

huax28 = true;

}

}

Point qidianx28 = new Point();

bool huax28 = false;

private void pictureBox20_MouseUp(object sender, MouseEventArgs e)

{

huax28 = false;

}

private void textBox1_TextChanged(object sender, EventArgs e)

{

this.learnRate = Convert.ToDouble(textBox1.Text);

}

}

}

相关推荐
cyyt1 小时前
深度学习周报(3.30~4.5)
人工智能·深度学习
一颗青果1 小时前
机器学习三大核心分支全解
人工智能
CoderJia程序员甲2 小时前
GitHub 热榜项目 - 日榜(2026-04-05)
人工智能·ai·大模型·github·ai教程
LaughingZhu2 小时前
Anthropic 收购 Oven 后,Claude Code 用运行时写了一篇护城河文章
大数据·人工智能·经验分享·搜索引擎·语音识别
Devil枫2 小时前
AI+地图:一句话,实现智能周边推荐与路线规划
人工智能
茫茫人海一粒沙2 小时前
Function Calling vs Tool Calling:从机制到架构的统一认知框架
人工智能
qq_571099352 小时前
学习周报三十九
人工智能·深度学习·机器学习
陈天伟教授2 小时前
Hugging Face 快速入门手册(实操案例-心电心音同步分析)
人工智能
H Journey2 小时前
openCV学习之-腐蚀
人工智能·opencv·学习