人工智能开发,Unity的神经网络+遗传算法(一)
发表于2017-12-19
最近在研究神经网络+遗传算法在Unity给NPC用,其实神经网络不复杂,大家多看看就可以理解。
神经网络定义:
计算机的人工神经网络简单分为三层:输入层、隐藏层、输出层;
这三个层的用意用形象的实例描述一下:
输入层就代表人的感官;
隐藏层(其实也是多了一层输出变成了下一组的输入)大脑中的神经元;
输出层用来接收处理后的信息进行分类反应;
简单的说输入和输出两层连,中间过程执行一个公式:
[url=][/url]加权
[url=][/url]进行激活函数(f())
假设
输入:一局王者荣耀里
1、 你看见对面5人调戏大龙:
2、 其中3人残血;
3、 自身满血;
隐藏层:
1也就是输出层 就是下一层的输入层;
隐藏层就是再分类再判断比如队友距离、队友血量、队友支援、敌方支援再和上一次的输出进行处理;(一般情况下一层就够了)
最后输出层:
1、 如果判断过去: 你将会操作人物移动靠近
2、 如果判断不过去:你将操作人物离开;
这么讲应该能理解这三个层的用意把;神经网络这个词我就不解释了 麻烦,想当初我看的时候废话一大堆,然后我并没看明白;
其实人的行为就是受到神经的刺激而产生的;在我的理解中权重就是这个人的情绪偏向;
[url=][/url]
一张图看一下:
其实人工的神经网络很难真正实现生物神经网络;
看一下输入层的 图例中输入值为(1、0、1、1);权重就是这个参数影响判断的绝对能力:取决主观意向;
来自:http://blog.csdn.net/m0_37283423/article/details/78333623
假设第一层的权重为(0.3、-0.5、0.9、1);
根据激励函数求出(不加偏移)=0.3+0+0.9+1=2.2D 有人会问 这个2.2D有什么作用;这个是这个激励函数对于输入函数和每个输入函数在神经中的重要性来得出的;在输出函数中需要一个阈值来判断这些值需要执行的动作;可能大于2.2D需要执行一系列动作;
看图讲什么原理什么都太虚;我直接贴代码讲解代码实现 (毕竟我是一个连复制粘贴都嫌麻烦的人)
神经网络铺建:
using System; using System.Collections.Generic; public class NeNetwork { public double[][][] _NetWeights; public int[] _Layers; public double[][] _Offset; public double[][] _Outputs; public NeurFunction[][] Functions; public NeNetwork(params int[] Layers) {//(5,3) 5输入 3输出 var layersLength = Layers.Length; this._Layers = Layers;//各层数量={5,3} _Outputs = new double[layersLength][];//输出={[5个],[3个]} for (var i = 0; i < layersLength; i++) { _Outputs[i] = new double[this._Layers[i]]; } Functions = new NeurFunction[layersLength - 1][];//方法={[5个]} _NetWeights = new double[layersLength - 1][][];//权重={[[3个][3个][3个][3个][3个]]} _Offset = new double[layersLength - 1][];//偏移={[3个]} var func = new SiFunction(); for (var i = 0; i < layersLength - 1; i++) { _NetWeights[i] = new double[this._Layers[i]][]; Functions[i] = new NeurFunction[this._Layers[i]]; for (var j = 0; j < this._Layers[i]; j++) { _NetWeights[i][j] = new double[this._Layers[i + 1]]; Functions[i][j] = func; } _Offset[i] = new double[this._Layers[i + 1]]; } } public void SetFunction(int layerIndex, NeurFunction func) { for (var j = 0; j < _Layers[layerIndex + 1]; j++) { Functions[layerIndex][j] = func; } } public double[] GetOut(double[] inputs) { for (var i = 0; i < _Layers[0]; i++) { _Outputs[0][i] = inputs[i]; } var qqsout = new double[_Layers[_Layers.Length - 1]]; for (var i = 1; i < _Layers.Length; i++) { for (var j = 0; j < _Layers[i]; j++) {// 3 double before = 0; for (var k = 0; k < _Layers[i - 1]; k++) { // 5 before += _Outputs[i - 1][k] * _NetWeights[i - 1][k][j];//权重这个J } before += _Offset[i - 1][j]; _Outputs[i][j] = Functions[i - 1][j].Compute(before);//把三个输出层的结果发送到输出层方便调用 } } qqsout = _Outputs[_Layers.Length - 1]; return qqsout; } public List<double> GetWeightsList() { var qws = new List<double>(); for (var i = 0; i < _Layers.Length - 1; i++) { qws.AddRange(_Offset[i]); } for (var i = 0; i < _Layers.Length - 1; i++) { for (var j = 0; j < _Layers[i]; j++) { qws.AddRange(_NetWeights[i][j]); } } return qws; } public void UpdateWeights(List<double> data) { var id = 0; for (var i = 0; i < _Layers.Length - 1; i++) { for (var j = 0; j < _Layers[i + 1]; j++) { _Offset[i][j] = data[id]; id++; } } for (var i = 0; i < _Layers.Length - 1; i++) { for (var j = 0; j < _Layers[i]; j++) { for (var k = 0; k < _Layers[i + 1]; k++) { _NetWeights[i][j][k] = data[id]; id++; } } } } //瞎JB写了 public double[] ShowTimes() { //反向传播权重更新 List<double> currentList = new List<double>(); for (int i = 0; i < _Layers[0]; i++) { currentList.Add(_Outputs[0][i]); } double a= -(_Outputs[0][1] - 0.5f) * _Outputs[0][1] * (1 - _Outputs[0][1]); //-(输出-样本)*输出*(1-输出); 反向传播加权 double b= 1 / 1 - Math.Exp(-_Outputs[0][1]); //非线性阶段函数 double c = Math.Tanh(_Outputs[0][1]); //切函数 return currentList.ToArray(); //返回更新权重 然后数值更新 *学习率 } }
输出处理类+接口:
using System; public interface NeurFunction { double Compute(double x); } public class SiFunction : NeurFunction { public double Compute(double x) { return 1.0 / (1.0 + Math.Exp(-x)); //非线性激活函数 } } public class ThFunction : NeurFunction { public double Compute(double x) { return x > 0.0 ? 1.0 : -1.0; } }