开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

首页   >   博客   >   3yangyang9

让游戏变得更有趣Unity的神经网络+遗传算法,让你的Npc能学习能训练(一) ... ... .. ...

个人分类: Unity | 2017-10-13 14:16

最近在研究神经网络+遗传算法在UnityNPC用(一个可以学习训练的NPC是不是很酷)

 

说一下神经网络真的不复杂,多看一看是能理解的;如果有不对的地方欢迎指出批评。立马修改以免误人;

 

神经网络定义的东西我就浅表的谈一谈:

   计算机的人工神经网络简单分为三层:输入层、隐藏层、输出层;

   这三个层的用意用形象的实例描述一下:

      输入层就代表人的感官;

      隐藏层(其实也是多了一层输出变成了下一组的输入)大脑中的神经元;

      输出层用来接收处理后的信息进行分类反应;

   简单的说输入和输出两层连,中间过程执行一个公式:

加权

   进行激活函数(f())

假设

输入:一局王者荣耀里

1、  你看见对面5人调戏大龙:

2、  其中3人残血;

3、  自身满血;

隐藏层:

1也就是输出层 就是下一层的输入层;

 隐藏层就是再分类再判断比如队友距离、队友血量、队友支援、敌方支援再和上一次的输出进行处理;(一般情况下一层就够了)

最后输出层:

1、  如果判断过去: 你将会操作人物移动靠近

2、  如果判断不过去:你将操作人物离开;

这么讲应该能理解这三个层的用意把;神经网络这个词我就不解释了 麻烦,想当初我看的时候废话一大堆,然后我并没看明白;

 

 

其实人的行为就是受到神经的刺激而产生的;在我的理解中权重就是这个人的情绪偏向;

一张图看一下:

   其实人工的神经网络很难真正实现生物神经网络;

 

看一下输入层的 图例中输入值为(1011);权重就是这个参数影响判断的绝对能力:取决主观意向;

假设第一层的权重为(0.3-0.50.91);

根据激励函数求出(不加偏移)=0.3+0+0.9+1=2.2D  有人会问 这个2.2D有什么作用;这个是这个激励函数对于输入函数和每个输入函数在神经中的重要性来得出的;在输出函数中需要一个阈值来判断这些值需要执行的动作;可能大于2.2D需要执行一系列动作;

 

 

 

看图讲什么原理什么都太虚;我直接贴代码讲解代码实现 (毕竟我是一个连复制粘贴都嫌麻烦的人)

神经网络铺建:

 public class NeuralNetwork {
        public double[][][] weights;  权重
        public int[] layers;    长度是层数,值是每个层的神经细胞数
        public double[][] bias;   偏移值
        public double[][] neuronsOutputs;    每一层的输出值;(因为计算需要用到上一层的输出值)
        public IActivationFunction[][] activateFunctions;    (输出分类函数)(阶段激励,和S激励还有双曲切吧啦吧啦的百度一下吧)

        public NeuralNetwork(params int[] layers) {   //构造函数需要填写的就是每个层的神经细胞数(2层的话就是直接做函数运算输出到输出层)
            //下面就是各种赋值了  哎有看不懂的评论区留言吧  我有时间会给大家解释一下的
            var layersLength = layers.Length;
            this.layers = layers;

            neuronsOutputs = new double[layersLength][];
            activateFunctions = new IActivationFunction[layersLength - 1][];
            weights = new double[layersLength - 1][][];
            bias = new double[layersLength - 1][];

            for (var i = 0; i < layersLength; i++) {
                neuronsOutputs[i] = new double[this.layers[i]];
            }
            
            var func = new SigmoidFunction();
            for (var i = 0; i < layersLength - 1; i++) {
                weights[i] = new double[this.layers[i]][];
                activateFunctions[i] = new IActivationFunction[this.layers[i]];
                for (var j = 0; j < this.layers[i]; j++) {
                    weights[i][j] = new double[this.layers[i + 1]];
                    activateFunctions[i][j] = func;
                }
                bias[i] = new double[this.layers[i + 1]];
            }
        }
  public double[] Compute(double[] input) {
            var res = new double[layers[layers.Length - 1]];
            for (var i = 0; i < layers[0]; i++) {
                neuronsOutputs[0][i] = input[i];
            }
            for (var i = 1; i < layers.Length; i++) {
                for (var j = 0; j < layers[i]; j++) {
                    double beforeActivation = 0;
                    for (var k = 0; k < layers[i - 1]; k++) { // 3
                        beforeActivation += neuronsOutputs[i - 1][k] * weights[i - 1][k][j];//权重这个J
                    }
                    beforeActivation += bias[i - 1][j];
                    neuronsOutputs[i][j] = activateFunctions[i - 1][j].Compute(beforeActivation);
                }
            }
            res = neuronsOutputs[layers.Length - 1];
            return res;
        }

        public List<double> Serialize() {
            var res = new List<double>();
            for (var i = 0; i < layers.Length - 1; i++) {
                res.AddRange(bias[i]);
            }
            for (var i = 0; i < layers.Length - 1; i++) {
                for (var j = 0; j < layers[i]; j++) {
                    res.AddRange(weights[i][j]);
                }
            }
            return res;
        }

        public void Deserialize(List<double> data) {
            var id = 0;
            for (var i = 0; i < layers.Length - 1; i++) {
                for (var j = 0; j < layers[i + 1]; j++) {
                    bias[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++) {
                        weights[i][j][k] = data[id];
                        id++;
                    }
                }
            }
        }

     
    }

输出处理类+接口:

public interface IActivationFunction {
		double Compute(double x);
	}
	
	public class ThersholdFunction : IActivationFunction {
		public double Compute(double x) {
			return  x > 0.0 ? 1.0 : -1.0;
		}
	}
	
	public class SigmoidFunction : IActivationFunction {
		public double Compute(double x) {
			return  1.0 / (1.0 + Math.Exp(-x));
		}
	}
	
	public class TanhFunction : IActivationFunction {
		public double Compute(double x) {
			return  Math.Tanh(x);
		}
	}

如有不懂欢迎指正;后续我会好好整理一下再把遗传算法结合的探讨一下
0 0

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册帐号
返回顶部