开源AI系统AForge.NET学习:进化神经网络训练过程解析
进化神经网络用户调用层面样例:
//选择训练算法 var teacher = new EvolutionaryLearning( network, //神经网络 100, //初始种群的数量 fitnessFunction //适应度函数 ); //进行训练 for (int i = 0; i < 10000; i++) { var error=teacher.RunEpoch( ); var fitness = 1 / error; Console.WriteLine($"迭代:{i};fitness:{fitness}"); }
主要分为两个步骤,先生成进化学习对象(EvolutionaryLearning),再调用此对象的RunEpoch方法。
EvolutionaryLearning构造函数:保存了相关对象,比如:network、populationSize、fitnessFunction,同时计算了numberOfNetworksWeights,用于后续计算基因长度。
public EvolutionaryLearning( ActivationNetwork activationNetwork, int populationSize,IFitnessFunction fitnessFunction) { // Check of assumptions during debugging only Debug.Assert( activationNetwork != null ); Debug.Assert( populationSize > 0 ); // networks's parameters this.network = activationNetwork; this.numberOfNetworksWeights = CalculateNetworkSize( activationNetwork ); // population parameters this.populationSize = populationSize; this.chromosomeGenerator = new UniformGenerator( new Range( -1, 1 ) ); this.mutationMultiplierGenerator = new ExponentialGenerator( 1 ); this.mutationAdditionGenerator = new UniformGenerator( new Range( -0.5f, 0.5f ) ); //下面是我修改,修改为轮盘赌选择算法 //this.selectionMethod = new EliteSelection( ); this.selectionMethod=new RouletteWheelSelection(); this.crossOverRate = 0.75; this.mutationRate = 0.25; this.randomSelectionRate = 0.2; //适应度函数 this.fitnessFunction=fitnessFunction; }
EvolutionaryLearning.RunEpoch方法:先生成种群对象(Population),再调用种群对象的RunEpoch方法,然后用最好的基因计算适应度,其倒数作为偏差率返回。
public double RunEpoch( double[][] input, double[][] output ) { //Debug.Assert( input.Length > 0 ); //Debug.Assert( output.Length > 0 ); //Debug.Assert( input.Length == output.Length ); //Debug.Assert( network.InputsCount == input.Length ); // check if it is a first run and create population if so if ( population == null ) { // sample chromosome DoubleArrayChromosome chromosomeExample = new DoubleArrayChromosome( chromosomeGenerator, mutationMultiplierGenerator, mutationAdditionGenerator, numberOfNetworksWeights ); // create population ... population = new Population( populationSize, chromosomeExample, this.fitnessFunction, selectionMethod ); // ... and configure it population.CrossoverRate = crossOverRate; population.MutationRate = mutationRate; population.RandomSelectionPortion = randomSelectionRate; } // run genetic epoch population.RunEpoch( ); // get best chromosome of the population DoubleArrayChromosome chromosome = (DoubleArrayChromosome) population.BestChromosome; double[] chromosomeGenes = chromosome.Value; // put best chromosome's value into neural network's weights int v = 0; for ( int i = 0; i < network.Layers.Length; i++ ) { Layer layer = network.Layers[i]; for ( int j = 0; j < layer.Neurons.Length; j++ ) { ActivationNeuron neuron = layer.Neurons[j] as ActivationNeuron; for ( int k = 0; k < neuron.Weights.Length; k++ ) { neuron.Weights[k] = chromosomeGenes[v++]; } neuron.Threshold = chromosomeGenes[v++]; } } Debug.Assert( v == numberOfNetworksWeights ); return 1.0 / chromosome.Fitness; }
生成种群对象过程:先生成一个样板基因(DoubleArrayChromosome),此样板基因的数据是随机的。然后调用种群对象构造函数,在种群对象构造函数中,主要是靠样板基因产生种群群体,在初始化的时候,种群群体全部是随机。
public DoubleArrayChromosome( IRandomNumberGenerator chromosomeGenerator, IRandomNumberGenerator mutationMultiplierGenerator, IRandomNumberGenerator mutationAdditionGenerator, int length ) { // save parameters this.chromosomeGenerator = chromosomeGenerator; this.mutationMultiplierGenerator = mutationMultiplierGenerator; this.mutationAdditionGenerator = mutationAdditionGenerator; this.length = Math.Max( 2, Math.Min( MaxLength, length ) ); ; // allocate array val = new double[length]; // generate random chromosome Generate( ); }
public Population( int size, IChromosome ancestor, IFitnessFunction fitnessFunction, ISelectionMethod selectionMethod ) { if ( size < 2 ) throw new ArgumentException( "Too small population's size was specified." ); this.fitnessFunction = fitnessFunction; this.selectionMethod = selectionMethod; this.size = size; // add ancestor to the population ancestor.Evaluate( fitnessFunction ); population.Add( ancestor.Clone( ) ); // add more chromosomes to the population for ( int i = 1; i < size; i++ ) { // create new chromosome IChromosome c = ancestor.CreateNew( ); // calculate it's fitness c.Evaluate( fitnessFunction ); // add it to population population.Add( c ); } }
Population.RunEpoch方法:主要包括交叉、变异和选择三个过程,这些操作都是生成新的基因,然后每一个基因都通过执行Evaluate函数取得了适应度数据。在选择操作中,找到适应度最好的那个的基因,保存在属性BestChromosome中。
public void RunEpoch( ) { Crossover( ); Mutate( ); Selection( ); if ( autoShuffling ) Shuffle( ); }
保存了相关对象,比如:network、populationSize、fitnessFunction,同时计算了numberOfNetworksWeights,用于后续计算基因长度。