最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

【神经网络

运维笔记admin103浏览0评论

【神经网络

【神经网络


读代码学编程、读代码学理论、读代码学技术、读代码学专业英语


样本数据

蓝莓

草莓(好想吃啊)

训练神经网络-四步

InitializeData();//初始化训练集和测试集InitializeLayers();//初始化神经网络RunNetwork(1250, false);//运行神经网络TestNetwork(1000);//测试神经网络

初始化训练集和测试集

//蓝莓图片目录string BlueberryDirectory = @"D:\test/Image Data/Blueberries";//草莓图片目录string StrawberryDirectory = @"D:\test/Image Data/Strawberries";List<Data> STImageData = new List<Data>();//草莓图片映射的数据列表List<Data> BLImageData = new List<Data>();//蓝莓图片映射的数据列表List<Data> NewTrainingImageData = new List<Data>();//新训练图像数据列表List<Data> NewTestingImageData = new List<Data>();//新测试图像数据列表foreach (string BLimage in Directory.GetFiles(BlueberryDirectory))//遍历所有蓝莓图像{List<float> PixelValues = new List<float>(); //归一化的像素的R通道值列表//从指定的现有图像初始化Bitmap,缩放到指定的大小。Bitmap image = new Bitmap(Image.FromFile(BLimage), newSize: new Size(ImageResolution, ImageResolution));Data newData = new Data();//创建图像映射数据//获取所有for (int i = 0; i < ImageResolution; i++){for (int j = 0; j < ImageResolution; j++){float ColorValue = image.GetPixel(i, j).R;//读取像素的R通道值  红色PixelValues.Add(Remap(ColorValue, 0, 255, 0, 1));//将R值映射到【0,1】区间}}newData.IsBlueBerry = 1;//蓝莓设置为1newData.Values = PixelValues.ToArray();//归一化的R通道值数组BLImageData.Add(newData);//添加到  图像映射数据 列表}foreach (string STimage in Directory.GetFiles(StrawberryDirectory))//遍历所有草莓图像{List<float> PixelValues = new List<float>();//创建像素值列表//  Bitmap image = new Bitmap(STimage);//读取草莓图像 225x225像素。这里应该需要缩放到统一大小  //分辨率16x16 :  网络精度 92.8%  90.6%    分辨率225x225 :Bitmap image = new Bitmap(Image.FromFile(STimage), newSize: new Size(ImageResolution, ImageResolution));//78.7%  73.9%Data newData = new Data();for (int i = 0; i < ImageResolution; i++){for (int j = 0; j < ImageResolution; j++){float ColorValue = image.GetPixel(i, j).R;PixelValues.Add(Remap(ColorValue, 0, 255, 0, 1));//获取草莓 归一化的R通道像素值列表}}newData.IsBlueBerry = 0;//草莓设置为0newData.Values = PixelValues.ToArray();//草莓图像归一化的R通道像素值数组STImageData.Add(newData);//添加到 草莓图像映射数据列表}int BLSeparationNumber = Convert.ToInt32((float)BLImageData.Count * 0.26f);//分割蓝莓样本数据:训练集  测试集int STSeparationNumber = Convert.ToInt32((float)STImageData.Count * 0.26f);//分割草莓样本数据:26%测试集 for (int i = 0; i < STImageData.Count; i++){if (i < STSeparationNumber){NewTestingImageData.Add(STImageData[i]);//草莓测试集添加到总的测试集}else{NewTrainingImageData.Add(STImageData[i]);//添加其余的到训练集}}for (int i = 0; i < BLImageData.Count; i++){if (i < BLSeparationNumber){NewTestingImageData.Add(BLImageData[i]);//蓝莓测试集添加到总的测试集}else{NewTrainingImageData.Add(BLImageData[i]);// 其余添加到训练集}}TrainingData = NewTrainingImageData.ToArray();//所有训练集TestingData = NewTestingImageData.ToArray();//所有测试集RandomizeTrainingData();//打乱顺序RandomizeTestingData();

初始化神经网络

//将每一层附加到前一层,然后随机化这些层static void InitializeLayers(){Console.WriteLine("\n\nInitializing Layers...");//初始化所有层:偏置,权重数组if (Layers.Length >= 3)//4层{for (int i = 1; i < Layers.Length; i++){Layers[i].AppendToLayer(Layers[i - 1]);//初始化所有神经元权重数组}for (int i = 0; i < Layers.Length; i++){Layers[i].Randomize();//将所有神经元偏置 和 权重数组里的值 设置为随机浮点数}}}

前馈神经网络算法

//将数据输入网络以获得输出   Feed Data into the Network to get an outputstatic void FeedForward()//前馈{Inputs.SetValues(data.Values);//输入层:映射数据。测试时需要给全局变量data赋值for (int i = 1; i < Layers.Length; i++)//遍历非输入层的所有层{Layer layer = Layers[i]; // 第i层,下一层int index = 0;foreach (Neuron neuron in layer.Neurons)//遍历下一层的神经元,计算神经元的输出值{float newValue = 0;//foreach (Neuron prevNeuron in Layers[i - 1].Neurons)//遍历前一层神经元{newValue += prevNeuron.Value * prevNeuron.Weights[index];//前一层神经元值的加权和if (Double.IsNaN(Sigmoid((newValue + neuron.Bias))))//判断加权和的非线性变换   是否不为数字{throw new Exception("NaN value was found in network.");// LearnRate 0.5, BiasLeranRate 0.1 = 1:20s : NaN; LearnRate 0.005, BiasLearningRate 0.001 = 4:31s : 61.8% no ch;}}newValue += neuron.Bias;//加权和+偏置neuron.Value = Sigmoid(newValue);//非线性变换后得到神经元的输出值index++; //计算下一神经元的输出}}}

反向传播算法

//调整偏置和权重--反向传播   Adjust the biases and weightsstatic void BackPropagate(){float LearningRate = 0.005f;//学习率float BiasLearningRate = 0.001f;//偏置学习率float[] expectedAnswer;//期望输出数组if (data.IsBlueBerry == 1)expectedAnswer = new float[] { 1, 0 };//蓝莓elseexpectedAnswer = new float[] { 0, 1 };//草莓//Begin with changing the Weights connected to the output layer//首先更改连接到输出层的权重//foreach Neuron in Outputs  遍历输出层的神经元,计算输出层神经元的gamma,调整上一层神经元的权重和偏置。for (int NeuronNum = 0; NeuronNum < Outputs.Length; NeuronNum++) //遍历输出层的神经元{Neuron neuron = Outputs[NeuronNum];//取输出层的一个神经元//   Gamma= (实际输出-期望输出)*激活函数的导数     可以把导数理解为该神经元对残差的贡献比例 。也可理解为连续激活的概率。float Gamma = (neuron.Value - expectedAnswer[NeuronNum]) * (1 - (neuron.Value) * (neuron.Value));//残差*该神经元sigmoid导数neuron.Gamma = Gamma;//分到输出层神经元的锅,//遍历倒数第二层神经元   foreach Neuron in Previous Layerfor (int PrevLayerNum = 0; PrevLayerNum < Layers[Layers.Length - 2].Length; PrevLayerNum++){//计算要减去的新值 Calculate a New Value to Subtractfloat Delta = Gamma * Layers[Layers.Length - 2][PrevLayerNum].Value;//为降低代价函数 计算每一神经元调整量//应用新值来调整指向神经元的权重   Apply the New Value to Adjust the Weight thats pointing to the neuronLayers[Layers.Length - 2][PrevLayerNum].Weights[NeuronNum] -= Delta * LearningRate;//调整权重     减去所需调整量*学习率//应用新值来调整先前权重的偏差 Apply the New Value to Adjust the Bias of the Previous WeightLayers[Layers.Length - 2][PrevLayerNum].Bias -= Delta * BiasLearningRate;//调整偏置   }}for (int LayerNum = Layers.Length - 2; LayerNum > 0; LayerNum--)//反向遍历所有层  ,从倒数第二层开始计算。{Layer layer = Layers[LayerNum];//取一层神经元,第一次执行为倒数第二层for (int NeuronNum = 0; NeuronNum < layer.Length; NeuronNum++)//遍历该层所有神经元{Neuron neuron = layer[NeuronNum];//取一个神经元float Gamma = 0;//初始化神经元改分的锅   第一次执行为倒数第二层的神经元for (int NeuronNum2 = 0; NeuronNum2 < Layers[LayerNum + 1].Length; NeuronNum2++)//遍历后一层神经元-  相对的输出层。第一次执行是最后一层即输出层。{Gamma += Layers[LayerNum + 1][NeuronNum2].Gamma * Layers[LayerNum][NeuronNum].Weights[NeuronNum2];//后一层的NeuronNum2神经元的gamma * 该神经元的NeuronNum2权重 再求和。加权残差 }Gamma *= (1 - neuron.Value * neuron.Value);//加权残差 * sigmoid导数neuron.Gamma = Gamma;//神经元分到的锅。第一次执行为倒数第二层//遍历前一层神经元   计算其新的权重和偏置      foreach Neuron in Previous Layerfor (int PrevLayerNum = 0; PrevLayerNum < Layers[LayerNum - 1].Length; PrevLayerNum++){//计算要减去的新值float Delta = Gamma * Layers[LayerNum - 1][PrevLayerNum].Value;//应用新值来调整指向神经元的权重Layers[LayerNum - 1][PrevLayerNum].Weights[NeuronNum] -= Delta * LearningRate;//应用新值来调整先前权重的偏置Layers[LayerNum - 1][PrevLayerNum].Bias -= Delta * BiasLearningRate;}}}}

运行神经网络

static void RunNetwork(int Iterations, bool log){Console.WriteLine("\n\nRunning Network...\n\n");for (int i = 0; i < Iterations; i++){print($"Iteration {i + 1} / {Iterations} Completed\n");GetNextTrainingData();//获取打乱顺序的训练数据集FeedForward();//前馈BackPropagate();//反向传播}void print(string str){if (log){Console.WriteLine(str);//控制台输出  准确率百分比}}}

测试神经网络

static void TestNetwork(int Iterations){int CorrectAnswers = 0;//正确答案数for (int i = 0; i < Iterations; i++)//反复测试不同图像  Iterations{GetNextTestingData();//获取下一 测试数据,修改全局变量dataFeedForward();//前馈:输入图像映射数据 计算神经网络输出Console.WriteLine("\n\nImage: " + data.IsBlueBerry);//标签Console.WriteLine("0: " + Outputs[0].Value);// 是蓝莓的答案。1是,0否Console.WriteLine("1: " + Outputs[1].Value);//是草莓的答案。1是,0否//判断神经网络输出是否与标签一致if ((data.IsBlueBerry == 1 && Outputs[0].Value > Outputs[1].Value) || (data.IsBlueBerry == 0 && Outputs[1].Value > Outputs[0].Value)){Console.WriteLine("\nCorrect");//输出与标签一致,打印正确 CorrectAnswers++;//正确数量}else{Console.WriteLine("\nIncorrect");}}Console.WriteLine($"\n\nNetwork Accuracy: {(float)CorrectAnswers / (float)Iterations * 100f}%");//打印正确率  92.8}

该BP神经网络仅把输入图像缩放后的像素R通道归一化后的值作为特征向量(图像映射数据),随着缩放尺寸不同,训练后的神经网络准确度也不同,缩放尺寸越大,训练时间越长,识别精度越差。加上样本数量有限,试验了几次识别率最高不到93% 。图像目标识别还得用卷积神经网络。

运行效果


笔记:

Sigmoid函数

Sigmoid函数导数最大值为0.25,因链式法则需要连乘,故进行反向传播时容易导致梯度消失。前边神经元的权重可能得不到更改。

BP神经网络

卷积神经网络

下面我们来看一下卷积神经网络中神经元所代表的实质含义。下面的gif图展示了size为3X3 ,strides为2的filter (分别有蓝绿两个filters)对一个 5X5 的输入图像做卷积的情形。

在该示例中,蓝色和绿色的 3X3  filter就是神经元。仍然套用上面所提到的3个步骤来分析这个卷积过程:

1.输入:接收前一层的输入数据,即 5X5X3 的图像。可以看出,此时的输入数据已经不是传统机器学习中所定义的高维向量了,而是一个多维的张量(Tensor)。

2. 操作

1.   注意到,神经元内的参数个数(本例中为 3X3X3 )通常小于输入数据的个数(本例中为 5x5x3 ),神经元会和在输入数据上进行滑动计算,直到扫过输入数据中的每个部分,并求出多个值,最终产生一个二维矩阵,通常也被称为feature map。(补充一下:三维张量经过卷积后变成了二维矩阵是因为原始尺寸只有长宽不同,而深度是相同的。假如filter和输入数据的尺寸在深度上也不同,那么输出的结果还是一个三维张量)

2.   在上述大框架的基础上,我们还需要引入bias和非线性变换。关于bias,仍然是一个神经元配备一个bias。以绿色神经元为例,对于其4个输出值,均加上相同的bias值 b0 。在加完bias之后,再对这4个输出值apply非线性变换,通常会是ReLU(Rectified Linear Unit)整流线性单元

3. 输出:经过卷积、加bias、非线性变换操作之后的feature map(特征映射).

通过对比BP神经元和卷积神经元的异同,我们似乎可以得出以下总结:

·       神经元的存在形式是一系列参数,并且是可学习的参数。

·       神经元可以接受不同尺寸的输入,也可以将输入与内部参数进行任意运算/操作(但操作方式应予输入尺寸相匹配)。

·       神经元的输出大小取决于输入数据的大小和神经元操作方式

·       神经元在输出前需要apply非线性函数

·       一个神经元配备一个bias

另一个思考的角度是:经过神经元的处理,输出通常都会比输入数据的尺寸要小,这其实是一种信息整合的体现。具体而言:

·       BP的神经元一次性就能够看见前一层传递过来的所有信息(正因此被称为全连接),因此操作时能将全部信息整合在一起,产生的输出为一个数。

·       而卷积神经元一次只能看到前一层传递过来信息的一个局部,需要通过滑动来将信息cover全,因此其产生的输出不止一个数,并且输出的信息凝聚程度也不如全链接。尽管如此,CNN还是更适合用来处理图像的,因为它保留了图像的二维结构,且所需神经元参数个数相对少、计算也相对少。和BP相比,相同的网络参数个数情形下,CNN可以更深,也就意味着非线性变换可以更多。


深入理解神经网络

1.   MP神经元

2.   感知机

来源:《机器学习》——周志华

3.   多层前馈神经网络

来源:《机器学习》——周志华

4.   误差逆传播算法(BP算法)

参考:

1> 反向传播之二:sigmoid函数 - 知乎 (zhihu)

2> 人工神经网络中的神经元 - 知乎 (zhihu)

3>/  归档 | Magina的个人小站 (wasedamagina.github.io)

4> 深入理解神经网络 - 知乎 (zhihu)

5> .html [Deep Learning] 神经网络基础 - Poll的笔记 - 博客园 (cnblogs)

6>  机器学习笔记丨神经网络的反向传播原理及过程(图文并茂+浅显易懂)_アルゴノゥト的博客-CSDN博客_神经网络反向传播原理

发布评论

评论列表(0)

  1. 暂无评论