using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
/*有时候我们会自定义一些单独的class/struct,
由于这些类并没有从 MonoBehavior 派生所以默认并不被Unity3D识别为可以Serialize的结构。
自然也就不会在Inspector中显示。
我们可以通过添加 [System.Serializable]这个Attribute使Unity3D检测并注册这些类为可Serialize的类型。*/
public class TraingSet
{
public double[] input;
public double output;
}
public class PercePtron : MonoBehaviour
{
public TraingSet[] ts;
double[] weights = { 0, 0 };//输入端的参数
double bias = 0;//偏差参数
double totalError = 0;//输出端的错误差值
/// <summary>
/// 计算他们的公式
/// f(x)={1 if w*x+b>0
/// 0 else
///input1*weight1+input2*weight2+bias
/// </summary>
/// <param name="v1">输入端参数</param>
/// <param name="v2">输入端</param>
/// <returns></returns>
double DotProductBias(double[] v1, double[] v2)
{
if (v1 == null || v2 == null)
return -1;
if (v1.Length != v2.Length)
return -1;
double d = 0;
//d=input1*weight1+input2*weight2+bias
for (int x = 0; x < v1.Length; x++)
{
d += v1[x] * v2[x];
}
d += bias;
return d;
}
/// <summary>
/// 计算输出端
/// </summary>
/// <param name="i">当前计算的or表达式</param>
/// <returns></returns>
double CalcOutPut(int i)
{
double dp = DotProductBias(weights, ts[i].input);
if (dp > 0) return (1);
return (0);
}
/// <summary>
/// 初始化输入端的参数和偏差参数
/// </summary>
void InitialiseWeights()
{
for (int i = 0; i < weights.Length; i++)
{
weights[i] = Random.Range(-1.0f, 1.0f);
}
bias = Random.Range(-1.0f, 1.0f);
}
void UpdateWeights(int j)
{
double error = ts[j].output - CalcOutPut(j);
totalError += Mathf.Abs((float)error);
for (int i = 0; i < weights.Length; i++)
{
//根据error的差值信息更新参数的值
weights[i] = weights[i] + error * ts[j].input[i];
}
bias += error;
}
void Train(int epochs)
{
InitialiseWeights();
for (int e = 0; e < epochs; e++)
{
totalError = 0;
for (int t = 0; t < ts.Length; t++)
{
UpdateWeights(t);
Debug.Log("W1" + (weights[0]) + "W2" + (weights[1]) + "B:" + bias);
}
Debug.Log("TOTAL ERROR:" + totalError);
}
}
void Start()
{
Train(8);
}
}
将上面的脚本添加到场景内的空物体,
然后再将属性栏面板里的数值改成如下形式(此为计算或运算):
然后点击运行按钮,可以看到控制台有类似的输出:
因为我们是最开始是随机生成的三个参数,所以数值显示可能不同,但是当TOTALERROT为0的时候,即表示最优的三个参数已经得到了,此时可以在
脚本Start()回调函数中,加上如下一句话
Debug.Log("Test:0 0" + "结果" + CalcOutput(0, 0));
Debug.Log("Test:0 1" + "结果" + CalcOutput(0, 1));
Debug.Log("Test:1 0" + "结果" + CalcOutput(1, 0));
Debug.Log("Test:1 1" + "结果" + CalcOutput(1, 1));
如果你用的是VisualStudio,此时应该会报错,所以你需要写一个CalcOutput()的重载,
和上面代码的差不过,最后应该是这样的。
目前案例一已经结束了,有点抽象,理解起来可能有些困难。�但是他的核心意思已经表达清楚了。
通过一部分训练数据,训练出最优的参数,当训练出最优的参数之后,这个神经元就可以处理想过的问题了。
目前这还只是一个神经元,并没有组成神经网络,下一个案例将带给大家一个具体点的例子,但是还是只有一个单一的神经元。
今天的内容就是这些,希望能帮助到需要的各位。