我最近刚编写了一个感知器,它将一个OR门作为其值。然而,目前我的代码只能训练一个点,而我想让它训练OR门的四个点。这是我的附件代码,我还在学习如何编程,所以请原谅我的一些错误。
using System;using ActivationFunction;namespace Perceptron{ class Point { private double input1; //创建私有字段 public double Input1 { get => input1; set => input1 = value; } //创建公共属性(数据封装的重要性) private double input2; public double Input2 { get => input2; set => input2 = value; } private double desiredOutput; public double DesiredOutput { get => desiredOutput; set => desiredOutput = value; } public Point() /*创建一个空构造函数,以便可以实例化类的对象以引用变量*/ { } public Point(int input1, int input2, int desiredOutput) //接受感知器的输入 { this.input1 = input1; this.input2 = input2; this.desiredOutput = desiredOutput; Console.WriteLine("输入 1 => " + Input1); Console.WriteLine("输入 2 => " + Input2); Console.WriteLine("期望输出 => " + desiredOutput); } } class NeuralNetwork { readonly Point point = new Point(); //用于从点引用变量到类 private double[] weights = new double[3]; private double output; private const double bias = 1; //创建常量偏置 private double error; private const double learningRate = 0.25; //常量学习率 public NeuralNetwork(Point point) //可能是不必要的... { this.point = point; } public void RandomiseWeightsAndBias() { Random rand = new Random(); for (int i = 0; i < weights.Length; i++) //循环遍历权重 { weights[i] = rand.NextDouble(); weights[i] -= 0.5; //预期范围现在是-0.5到+0.5 weights[i] *= 2; //预期范围现在是-1到1 Console.WriteLine("起始突触权重 => " + weights[i]); } Console.WriteLine("偏置是 => " + bias); } public double DotProductBias() //将输入和权重相加 { return point.Input1 * weights[0] + point.Input2 * weights[1] + bias * weights[2]; } public double ActivationFunction() //应用激活函数 { DotProductBias(); output = ActivationFunctions.StepActivation(DotProductBias()); //激活函数是另一个类的部分,有一个内置的静态函数,接受一个静态的double作为输入 return output; } public void CalculateError() //计算错误 { error = point.DesiredOutput - output; Console.WriteLine("错误是 => " + error); } public void AdjustWeights() //执行梯度下降 { weights[0] += learningRate * weights[0] + error * point.Input1; //我知道我可以使用for循环使其更简洁和清晰,但目前这样可以工作 weights[1] += learningRate * weights[1] + error * point.Input2; weights[2] += learningRate * weights[2] + error * bias; for (int i = 0; i < weights.Length; i++) { Console.WriteLine("调整后的权重是 => " + weights[i]); } } public void Train(int epochs) //训练或“反向传播权重” { for (int i = 0; i < epochs; i++) { AdjustWeights(); } } } class Program { static void Main(string[] args) { var point = new Point(0, 1, 1); /* var point2 = new Point(0, 1, 0); var point3 = new Point(1, 0, 0); var point4 = new Point(1, 1, 1); */ var neuralNetwork = new NeuralNetwork(point); neuralNetwork.RandomiseWeightsAndBias(); neuralNetwork.ActivationFunction(); neuralNetwork.CalculateError(); neuralNetwork.Train(8); Console.WriteLine("最终输出是 " + neuralNetwork.ActivationFunction()); } }}
从代码来看,很明显我需要更改Point类构造函数的值,可能需要将输入改为数组或列表?请帮助我!
回答:
在我看来,这里有几个可能的问题,首先看起来你想训练的点不是OR门,而是XOR门,而单个感知器无法实现XOR。原因是XOR的类别不是线性可分的。你无法画一条直线来分隔点(0,0),(1,1)和点(0,1),(1,0)。OR门的点应该是[0,0,0] [1,0,1] [1,1,1] [0,1,1],更多信息请阅读这里 https://en.wikipedia.org/wiki/OR_gate 。
其次,看起来你的权重调整似乎有误——在感知器中调整权重时,我们使用这个公式:新权重 = 权重 + 错误 * 输入 * 学习率,而在你的例子中,你多乘了一次权重。
在这样简单的例子中,使用阈值激活函数是方便的,基本原理是——如果输出 < 0 则返回0,否则返回1。