美文网首页
如何利用 C# 实现 Delta 学习规则?

如何利用 C# 实现 Delta 学习规则?

作者: 老马的程序人生 | 来源:发表于2019-03-21 15:26 被阅读0次

感知器是最简单的人工神经网络,它的激活函数通常是符号函数或阈值函数,这类激活函数是不可导的。为了计算和推导的方便,人们引入了 Sigmoid 函数,其中最著名的是 Logistic 函数。通常写程序的时候加入一个alpha参数,通过调整这个参数来调整函数f(x)趋向于1或0的速度。

                1
 f(x) = ------------------
        1 + exp(-alpha * x)

           alpha * exp(-alpha * x )
 f'(x) = ---------------------------- 
           (1 + exp(-alpha * x))^2

       = alpha * f(x) * (1 - f(x))

今天我们介绍的 Delta 学习规则就是采用这样的激活函数,通过梯度下降的方式来调整权值和阈值,以使得网络总误差最小。

需要注意的是,这篇图文是基于以往两篇图文的,在往下看之前最好复习一下。


Delta学习规则

该学习规则用于训练具有连续激活功能的神经元的单层神经网络,常用的激活函数是 Sigmoid 函数。详细介绍可以参见维基百科相应部分。

https://en.wikipedia.org/wiki/Delta_rule

delta学习规则

Sigmoid 函数

详细介绍可以参见维基百科相应部分。

https://en.wikipedia.org/wiki/Sigmoid_function

Sigmoid function

通过以上的介绍,大家对 Delta 学习规则应该有了基本了解,下面我们进行代码实现以及具体应用。

1. 实现神经元的激活函数 IActivationFunction

public class SigmoidFunction : IActivationFunction
{
    // alpha值,用于控制函数的光滑程度
    public double Alpha { get; set; } = 2;

    // 构造函数
    public SigmoidFunction()
    {
    }

    // 构造函数
    public SigmoidFunction(double alpha)
    {
        Alpha = alpha;
    }

    // 计算输出
    public double Function(double x)
    {
        return 1/(1 + Math.Exp(-Alpha*x));
    }

    // 求导数1
    public double Derivative(double x)
    {
        double y = Function(x);

        return Alpha*y*(1 - y);
    }

    // 求导数2
    public double Derivative2(double y)
    {
        return Alpha*y*(1 - y);
    }
}

2. 实现监督学习算法 ISupervisedLearning

// Delta 学习规则
public class DeltaRuleLearning : ISupervisedLearning
{
    private readonly ActivationNetwork _network;
    private double _learningRate = 0.1;

    // 学习率 0到1
    public double LearningRate
    {
        get { return _learningRate; }
        set
        {
            _learningRate = Math.Max(0.0, Math.Min(1.0, value));
        }
    }

    // 构造函数
    public DeltaRuleLearning(ActivationNetwork network)
    {
        if (network.Layers.Length != 1)
        {
            throw new ArgumentException("无效的神经网络,它应该只有一层。");
        }
        _network = network;
    }

    // 调整权值阈值,返回误差。
    public double Run(double[] input, double[] output)
    {
        double[] networkOutput = _network.Compute(input);
        Layer layer = _network.Layers[0];
        double error = 0.0;

        for (int j = 0; j < layer.Neurons.Length; j++)
        {

            ActivationNeuron neuron = layer.Neurons[j] as ActivationNeuron;

            if (neuron == null)
                throw new Exception("神经元为null。");

            double e = output[j] - networkOutput[j];
            double functionDerivative = neuron.ActivationFunction.Derivative2(networkOutput[j]);

            for (int i = 0; i < neuron.Weights.Length; i++)
            {
                neuron.Weights[i] += _learningRate * e * functionDerivative * input[i];
            }
            neuron.Threshold += _learningRate * e * functionDerivative;
            error += e * e;
        }
        return error / 2;
    }

    // 训练神经网络,返回总体误差
    public double RunEpoch(double[][] input, double[][] output)
    {
        double error = 0.0;
        
        for (int i = 0, n = input.Length; i < n; i++)
        {
            error += Run(input[i], output[i]);
        }
        return error;
    }
}

3. Delta 学习规则的应用。

首先,我们利用 Delta 学习规则解决 And 问题。

double[][] inputs = new double[4][];
double[][] outputs = new double[4][];

//(0,0);(0,1);(1,0)
inputs[0] = new double[] {0, 0};
inputs[1] = new double[] {0, 1};
inputs[2] = new double[] {1, 0};

outputs[0] = new double[] {0};
outputs[1] = new double[] {0};
outputs[2] = new double[] {0};

//(1,1)
inputs[3] = new double[] {1, 1};
outputs[3] = new double[] {1};

ActivationNetwork network = new ActivationNetwork(
    new SigmoidFunction(), 2, 1);

DeltaRuleLearning teacher = new DeltaRuleLearning(network);
teacher.LearningRate = 0.1;

int iteration = 1;
while (true)
{
    double error = teacher.RunEpoch(inputs, outputs)/4;
    Console.WriteLine(@"迭代次数:{0},错误率:{1}", iteration, error);

    if (error <= 0.1 || iteration >= 1000)
        break;
    iteration++;
}

Console.WriteLine();
ActivationNeuron neuron = network.Layers[0].Neurons[0] as ActivationNeuron;
Console.WriteLine(@"Weight 1:{0}", neuron.Weights[0].ToString("F3"));
Console.WriteLine(@"Weight 2:{0}", neuron.Weights[1].ToString("F3"));
Console.WriteLine(@"Threshold:{0}", neuron.Threshold.ToString("F3"));

训练结果如下:

And问题

其次,我们利用 Delta 学习规则解决 Or 问题。

double[][] inputs = new double[4][];
double[][] outputs = new double[4][];

//(0,0)
inputs[0] = new double[] {0, 0};
outputs[0] = new double[] {0};

//(1,1);(0,1);(1,0)
inputs[1] = new double[] {0, 1};
inputs[2] = new double[] {1, 0};
inputs[3] = new double[] {1, 1};

outputs[1] = new double[] {1};
outputs[2] = new double[] {1};
outputs[3] = new double[] {1};

ActivationNetwork network = new ActivationNetwork(
    new SigmoidFunction(), 2, 1);

DeltaRuleLearning teacher = new DeltaRuleLearning(network);
teacher.LearningRate = 0.1;

int iteration = 1;

while (true)
{
    double error = teacher.RunEpoch(inputs, outputs)/4;
    Console.WriteLine(@"迭代次数:{0},错误率:{1}", iteration, error);

    if (error <= 0.06 || iteration >= 1000)
        break;
        
    iteration++;
}

Console.WriteLine();
ActivationNeuron neuron = network.Layers[0].Neurons[0] as ActivationNeuron;
Console.WriteLine(@"Weight 1:{0}", neuron.Weights[0].ToString("F3"));
Console.WriteLine(@"Weight 2:{0}", neuron.Weights[1].ToString("F3"));
Console.WriteLine(@"Threshold:{0}", neuron.Threshold.ToString("F3"));

训练结果如下:

Or问题

接着,我们利用 Delta 学习规则处理一个通常的二分类问题。

double[][] inputs = new double[8][];
double[][] outputs = new double[8][];

//(0,0,0);(0,0,1);(0,1,0);(0,1,1)
inputs[0] = new double[] {0, 0, 0};
inputs[1] = new double[] {0, 0, 1};
inputs[2] = new double[] {0, 1, 0};
inputs[3] = new double[] {0, 1, 1};

outputs[0] = new double[] {0};
outputs[1] = new double[] {0};
outputs[2] = new double[] {0};
outputs[3] = new double[] {0};

//(1,0,0);(1,0,1);(1,1,0);(1,1,1)
inputs[4] = new double[] {1, 0, 0};
inputs[5] = new double[] {1, 0, 1};
inputs[6] = new double[] {1, 1, 0};
inputs[7] = new double[] {1, 1, 1};

outputs[4] = new double[] {1};
outputs[5] = new double[] {1};
outputs[6] = new double[] {1};
outputs[7] = new double[] {1};

ActivationNetwork network = new ActivationNetwork(
    new SigmoidFunction(), 3, 1);

DeltaRuleLearning teacher = new DeltaRuleLearning(network);
teacher.LearningRate = 0.1;

int iteration = 1;
while (true)
{
    double error = teacher.RunEpoch(inputs, outputs)/8;
    Console.WriteLine(@"迭代次数:{0},错误率:{1}", iteration, error);

    if (error <= 0.1 || iteration >= 1000)
        break;

    iteration++;
}

Console.WriteLine();
ActivationNeuron neuron = network.Layers[0].Neurons[0] as ActivationNeuron;
Console.WriteLine(@"Weight 1:{0}", neuron.Weights[0].ToString("F3"));
Console.WriteLine(@"Weight 2:{0}", neuron.Weights[1].ToString("F3"));
Console.WriteLine(@"Threshold:{0}", neuron.Threshold.ToString("F3"));

训练结果如下:

普通二分类问题

最后,我们利用 Delta 学习规则处理一个稍微复杂的多分类问题。

double[][] inputs = new double[15][];
double[][] outputs = new double[15][];

//(0.1,0.1);(0.2,0.3);(0.3,0.4);(0.1,0.3);(0.2,0.5)
inputs[0] = new double[] {0.1, 0.1};
inputs[1] = new double[] {0.2, 0.3};
inputs[2] = new double[] {0.3, 0.4};
inputs[3] = new double[] {0.1, 0.3};
inputs[4] = new double[] {0.2, 0.5};

outputs[0] = new double[] {1, 0, 0};
outputs[1] = new double[] {1, 0, 0};
outputs[2] = new double[] {1, 0, 0};
outputs[3] = new double[] {1, 0, 0};
outputs[4] = new double[] {1, 0, 0};

//(0.1,1.0);(0.2,1.1);(0.3,0.9);(0.4,0.8);(0.2,0.9)
inputs[5] = new double[] {0.1, 1.0};
inputs[6] = new double[] {0.2, 1.1};
inputs[7] = new double[] {0.3, 0.9};
inputs[8] = new double[] {0.4, 0.8};
inputs[9] = new double[] {0.2, 0.9};

outputs[5] = new double[] {0, 1, 0};
outputs[6] = new double[] {0, 1, 0};
outputs[7] = new double[] {0, 1, 0};
outputs[8] = new double[] {0, 1, 0};
outputs[9] = new double[] {0, 1, 0};

//(1.0,0.4);(0.9,0.5);(0.8,0.6);(0.9,0.4);(1.0,0.5)
inputs[10] = new double[] {1.0, 0.4};
inputs[11] = new double[] {0.9, 0.5};
inputs[12] = new double[] {0.8, 0.6};
inputs[13] = new double[] {0.9, 0.4};
inputs[14] = new double[] {1.0, 0.5};

outputs[10] = new double[] {0, 0, 1};
outputs[11] = new double[] {0, 0, 1};
outputs[12] = new double[] {0, 0, 1};
outputs[13] = new double[] {0, 0, 1};
outputs[14] = new double[] {0, 0, 1};

ActivationNetwork network = new ActivationNetwork(
    new SigmoidFunction(), 2, 3);

DeltaRuleLearning teacher = new DeltaRuleLearning(network);
teacher.LearningRate = 0.1;

int iteration = 1;
while (true)
{
    double error = teacher.RunEpoch(inputs, outputs)/15;
    Console.WriteLine(@"迭代次数:{0},错误率:{1}", iteration, error);

    if (error <= 0.05 || iteration >= 1000)
        break;
    iteration++;
}

Console.WriteLine();
ActivationLayer layer = network.Layers[0] as ActivationLayer;
for (int i = 0; i < 3; i++)
{
    Console.WriteLine(@"神经元:{0}", i + 1);
    Console.WriteLine(@"Weight 1:{0}", layer.Neurons[i].Weights[0]);
    Console.WriteLine(@"Weight 2:{0}", layer.Neurons[i].Weights[1]);
    Console.WriteLine(@"Threshold:{0}",
        ((ActivationNeuron) layer.Neurons[i]).Threshold);
}

训练结果如下:

多分类问题

到此为止,有关 Delta 学习规则的神经网络实现就全部介绍完了。后面我计划把 BPSOM 神经网络写完就结束这个系列。还是我一直强调的观点,在学习阶段最好是自己动手来具体实现,到了真正工程应用的时候再来用 PythonMatlab 这样的工具,配参数调 Package啊!当然写论文就无所谓了,可以编啊!

今天就到这里吧!See You!


相关阅读

相关文章

网友评论

      本文标题:如何利用 C# 实现 Delta 学习规则?

      本文链接:https://www.haomeiwen.com/subject/vrytvqtx.html