//private void DoWidths(double[][] centroids) //{ // // this version uses a common width which is dmax / sqrt(2*numHidden) // double maxDist = double.MinValue; // for (int i = 0; i < centroids.Length - 1; ++i) // { // for (int j = i + 1; j < centroids.Length; ++j) // { // double dist = EuclideanDist(centroids[i], centroids[j], centroids[i].Length); // if (dist > maxDist) // maxDist = dist; // } // } // double width = maxDist / Math.Sqrt(2.0 * numHidden); // Console.WriteLine("The common width is: " + width.ToString("F4")); // for (int i = 0; i < this.widths.Length; ++i) // all widths the same // this.widths[i] = width; //} private double[] DoWeights(double[][] trainData, int maxIterations) { // use PSO to find weights and bias values that produce a RBF network // that best matches training data int numberParticles = trainData.Length / 3; int Dim = (numHidden * numOutput) + numOutput; // dimensions is num weights + num biases double minX = -10.0; // implicitly assumes data has been normalizzed double maxX = 10.0; double minV = minX; double maxV = maxX; Particle[] swarm = new Particle[numberParticles]; double[] bestGlobalPosition = new double[Dim]; // best solution found by any particle in the swarm. implicit initialization to all 0.0 double smallesttGlobalError = double.MaxValue; // smaller values better // initialize swarm for (int i = 0; i < swarm.Length; ++i) // initialize each Particle in the swarm { double[] randomPosition = new double[Dim]; for (int j = 0; j < randomPosition.Length; ++j) { double lo = minX; double hi = maxX; randomPosition[j] = (hi - lo) * rnd.NextDouble() + lo; // } double err = MeanSquaredError(trainData, randomPosition); // error associated with the random position/solution double[] randomVelocity = new double[Dim]; for (int j = 0; j < randomVelocity.Length; ++j) { double lo = -1.0 * Math.Abs(maxV - minV); double hi = Math.Abs(maxV - minV); randomVelocity[j] = (hi - lo) * rnd.NextDouble() + lo; } swarm[i] = new Particle(randomPosition, err, randomVelocity, randomPosition, err); // does current Particle have global best position/solution? if (swarm[i].error < smallesttGlobalError) { smallesttGlobalError = swarm[i].error; swarm[i].position.CopyTo(bestGlobalPosition, 0); } } // initialization // main PSO algorithm // compute new velocity -> compute new position -> check if new best double w = 0.729; // inertia weight double c1 = 1.49445; // cognitive/local weight double c2 = 1.49445; // social/global weight double r1, r2; // cognitive and social randomizations int[] sequence = new int[numberParticles]; // process particles in random order for (int i = 0; i < sequence.Length; ++i) { sequence[i] = i; } int iteration = 0; while (iteration < maxIterations) { if (smallesttGlobalError < 0.060) { break; // early exit (MSE) } double[] newVelocity = new double[Dim]; // step 1 double[] newPosition = new double[Dim]; // step 2 double newError; // step 3 Shuffle(sequence); // move particles in random sequence for (int pi = 0; pi < swarm.Length; ++pi) // each Particle (index) { int i = sequence[pi]; Particle currP = swarm[i]; // for coding convenience // 1. compute new velocity for (int j = 0; j < currP.velocity.Length; ++j) // each x value of the velocity { r1 = rnd.NextDouble(); r2 = rnd.NextDouble(); // velocity depends on old velocity, best position of parrticle, and // best position of any particle newVelocity[j] = (w * currP.velocity[j]) + (c1 * r1 * (currP.bestPosition[j] - currP.position[j])) + (c2 * r2 * (bestGlobalPosition[j] - currP.position[j])); if (newVelocity[j] < minV) { newVelocity[j] = minV; } else if (newVelocity[j] > maxV) { newVelocity[j] = maxV; // crude way to keep velocity in range } } newVelocity.CopyTo(currP.velocity, 0); // 2. use new velocity to compute new position for (int j = 0; j < currP.position.Length; ++j) { newPosition[j] = currP.position[j] + newVelocity[j]; // compute new position if (newPosition[j] < minX) { newPosition[j] = minX; } else if (newPosition[j] > maxX) { newPosition[j] = maxX; } } newPosition.CopyTo(currP.position, 0); // 3. use new position to compute new error // consider cross-entropy error instead of MSE newError = MeanSquaredError(trainData, newPosition); // makes next check a bit cleaner currP.error = newError; if (newError < currP.smallestError) // new particle best? { newPosition.CopyTo(currP.bestPosition, 0); currP.smallestError = newError; } if (newError < smallesttGlobalError) // new global best? { newPosition.CopyTo(bestGlobalPosition, 0); smallesttGlobalError = newError; } // consider using weight decay, particle death here } // each Particle ++iteration; } // while (main PSO processing loop) //Console.WriteLine("\n\nFinal training MSE = " + smallesttGlobalError.ToString("F4") + "\n\n"); // copy best weights found into RBF network, and also return them this.SetWeights(bestGlobalPosition); double[] returnResult = new double[(numHidden * numOutput) + numOutput]; Array.Copy(bestGlobalPosition, returnResult, bestGlobalPosition.Length); Console.WriteLine("The best weights and bias values found are:\n"); Helpers.ShowVector(bestGlobalPosition, 3, 10, true); return(returnResult); } // DoWeights