/// <summary>
        /// Updates activations thresholds according to the Contrastive Divergence bias update rules.
        /// </summary>
        /// <param name="layer">The layer in which the units reside.</param>
        /// <param name="thresholdDelta">The threshold delta (positive phase activation probabilities - negative phase activation probabilities).</param>
        private void UpdateThresholdsCD(int layer, double[] thresholdDelta)
        {
            System.Diagnostics.Debug.Assert(
                thresholdDelta.Length == this.GetUnitCount(layer),
                "The array with the threshold deltas should have the same number of elements as there are units in the layer");
            var random = ThreadSafeRandom.GetThreadRandom();

            for (int unit = 0; unit < thresholdDelta.Length; unit++)
            {
                if (thresholdDelta[unit] != 0 && random.NextDouble() < Math.Abs(thresholdDelta[unit]) * LearningProbability)
                {
                    if (thresholdDelta[unit] > 0)
                    {
                        this.IndividualActivationThresholds[layer][unit]--;
#if DEBUG
                        //System.Diagnostics.Debug.WriteLine("Unit {0} in layer {1} lowered its threshold to {2}", unit, layer, this.IndividualActivationThresholds[layer][unit]);
#endif
                    }
                    else if (thresholdDelta[unit] < 0)
                    {
                        this.IndividualActivationThresholds[layer][unit]++;
#if DEBUG
                        //System.Diagnostics.Debug.WriteLine("Unit {0} in layer {1} increased its threshold to {2}", unit, layer, this.IndividualActivationThresholds[layer][unit]);
#endif
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Randomly shuffles a list.
        /// </summary>
        /// <typeparam name="T">The type of elements in the list.</typeparam>
        /// <param name="list">The list to shuffle.</param>
        /// <returns>An enumerator that traverses the list in a random order.</returns>
        /// <remarks>
        /// The following code is courtesy of Michael Herman (foson). See:
        /// http://stackoverflow.com/questions/375351/most-efficient-way-to-randomly-sort-shuffle-a-list-of-integers-in-c-sharp/
        /// </remarks>
        public static IEnumerable <T> AsRandom <T>(this IList <T> list)
        {
            int[]  indexes   = Enumerable.Range(0, list.Count).ToArray();
            Random generator = ThreadSafeRandom.GetThreadRandom();

            for (int i = 0; i < list.Count; ++i)
            {
                int position = generator.Next(i, list.Count);
                yield return(list[indexes[position]]);

                indexes[position] = indexes[i];
            }
        }
        /// <summary>
        /// Gets the degree of the specified unit.
        /// </summary>
        /// <param name="index">The index of the unit.</param>
        /// <param name="partition">The partition that the unit resides in.</param>
        /// <returns>
        /// The degree of the unit.
        /// </returns>
        //public abstract int GetDegree(int index, Partition partition);

        /// <summary>
        /// Stochastically generates connections (edges) according to the specified probabilities.
        /// </summary>
        /// <returns>
        /// The total number of connections (edges) created.
        /// </returns>
        public int Initialize(int minWeight, int maxWeight, double[] weightProbabilities)
        {
            int numberOfWeights = maxWeight - minWeight + 1;

            //
            // TODO: Use an exact number type for the probabilities?
            //
            if (numberOfWeights != weightProbabilities.Length)
            {
                throw new ArgumentException("The number of weights and the size of the weightProbabilities array should match", "weightProbabilities");
            }

            var cumulativeProbabilities = new double[weightProbabilities.Length];
            var runningSum = 0.0;

            for (int i = 0; i < numberOfWeights; i++)
            {
                ValidationUtils.ValidateProbability(weightProbabilities[i], "weightProbabilities[" + i + "]");
                cumulativeProbabilities[i] = weightProbabilities[i] + runningSum;
                runningSum += weightProbabilities[i];
            }

            var random = ThreadSafeRandom.GetThreadRandom();
            //
            // TODO: Clear everything first?
            // Consider all possible edges, then flip a coin (so to speak)
            //
            int edgesCreated = 0;

            for (int leftUnit = 0; leftUnit < this.unitCountLeft; leftUnit++)
            {
                for (int rightUnit = 0; rightUnit < this.unitCountRight; rightUnit++)
                {
                    var randomValue = random.NextDouble();

                    for (int weightIndex = 0; weightIndex < numberOfWeights; weightIndex++)
                    {
                        if (randomValue < cumulativeProbabilities[weightIndex])
                        {
                            this.SetEdge(leftUnit, rightUnit, minWeight + weightIndex);
                            edgesCreated++;
                            break;
                        }
                    }
                }
            }
            //
            // Return the number of edges created
            //
            return(edgesCreated);
        }
 /// <summary>
 /// Stochastically makes edges more excitatory or inhibitory according to the supplied <paramref name="changes" /> matrix.
 /// </summary>
 /// <param name="changes">A 2D matrix indicating where edges (synapses) should potentially be altered.</param>
 /// <param name="layer">The connection layer to alter.</param>
 /// <param name="joint">Should be set to <c>true</c> if joint learning is taking place, otherwise <c>false</c>.</param>
 protected virtual void UpdateEdges(double[,] changes, int layer, bool joint)
 {
     System.Diagnostics.Debug.Assert(
         changes.GetLength(0) == this.GetUnitCount(layer),
         "changes matrix size doesn't match the size of the weight matrix");
     System.Diagnostics.Debug.Assert(
         changes.GetLength(1) == this.GetUnitCount(layer + 1),
         "changes matrix size doesn't match the size of the weight matrix");
     //
     // Traverse the matrix
     //
     Parallel.For(
         0,
         changes.GetLength(0),
         (leftUnit) =>
     {
         var random = ThreadSafeRandom.GetThreadRandom();
         for (int rightUnit = 0; rightUnit < changes.GetLength(1); rightUnit++)
         {
             //
             // Flip a coin to see if we should modify this edge
             // Note that the strength of the learning signal affects the probability
             // TODO: Parameterize the pseudo-learning-rate constant
             //
             if (changes[leftUnit, rightUnit] != 0.0 && random.NextDouble() < Math.Abs(changes[leftUnit, rightUnit]) * LearningProbability)
             {
                 //
                 // Get the current type of edge and, if possible, make it either more excitatory or inhibitory,
                 // depending on the learning signal.
                 //
                 var edge = this.Connections[layer].GetEdge(leftUnit, rightUnit);
                 if (changes[leftUnit, rightUnit] > 0)
                 {
                     if (edge.Weight < this.MaxWeight)
                     {
                         this.Connections[layer].SetEdge(leftUnit, rightUnit, edge.Weight + 1);
                     }
                 }
                 else
                 {
                     if (edge.Weight > this.MinWeight)
                     {
                         this.Connections[layer].SetEdge(leftUnit, rightUnit, edge.Weight - 1);
                     }
                 }
             }
         }
     });
 }
Example #5
0
        /// <summary>
        /// Processes a training sample.
        /// </summary>
        /// <param name="connections">The inter-layer connections.</param>
        /// <param name="activatedLeft">The activated units in the left partition.</param>
        /// <param name="activatedRight">The activated units in the right partition.</param>
        public override void ProcessSample(IInterLayerConnections connections, List <int> activatedLeft, List <int> activatedRight)
        {
            var random = ThreadSafeRandom.GetThreadRandom();

            foreach (var outputUnit in activatedRight)
            {
                //
                // Find out how many strong (excitatory) edges are connected to this unit
                //
                int degree = connections.GetNeighbours(outputUnit, Partition.Right, true).Count();
                //
                // If it's equal to the target degree, move on to the next output unit
                //
                if (degree == this.targetDegree)
                {
                    ////Debug.WriteLine("Skipping output unit " + outputUnit + " because it has reached its target degree");
                    continue;
                }
                //
                // Calculate the probability of an edge strengthening/weakening
                //
                double p = (double)(this.targetDegree - degree) / (2.0 * this.MaxInputActivations);
                //
                // Stochastically modify edges which connect concurrently active units
                //
                foreach (var inputUnit in activatedLeft)
                {
                    var edge = connections.GetEdge(inputUnit, outputUnit);
                    if (edge.Weight == 0 && p > 0.0 && random.NextDouble() < p)
                    {
                        connections.SetEdge(inputUnit, outputUnit, 1);
#if DEBUG
                        Debug.WriteLine("Adding edge between " + inputUnit + " and " + outputUnit);
#endif
                    }
                    else if (edge.Weight == 1 && p < 0.0 && random.NextDouble() < -p)
                    {
                        connections.SetEdge(inputUnit, outputUnit, 0);
#if DEBUG
                        Debug.WriteLine("Removing edge between " + inputUnit + " and " + outputUnit);
#endif
                    }
                }
            }
            //
            // TODO: Prune from the left as well?
            //
        }
Example #6
0
        /// <summary>
        /// Processes a training sample.
        /// </summary>
        /// <param name="connections">The inter-layer connections.</param>
        /// <param name="activatedLeft">The activated units in the left partition.</param>
        /// <param name="activatedRight">The activated units in the right partition.</param>
        public override void ProcessSample(IInterLayerConnections connections, List <int> activatedLeft, List <int> activatedRight)
        {
            var random = ThreadSafeRandom.GetThreadRandom();

            foreach (var leftUnit in activatedLeft)
            {
                foreach (var rightUnit in activatedRight)
                {
                    if (connections.GetEdge(leftUnit, rightUnit).Weight == 0)
                    {
                        if (random.NextDouble() < this.strengtheningProbability)
                        {
                            connections.SetEdge(leftUnit, rightUnit, 1);
                        }
                    }
                }
            }
        }
Example #7
0
 /// <summary>
 /// Stochastically makes edges more excitatory or inhibitory according to the supplied <paramref name="changes"/> matrix.
 /// </summary>
 /// <param name="changes">A 2D matrix indicating where edges (synapses) should potentially be altered.</param>
 /// <param name="layer">The connection layer to alter.</param>
 private void UpdateEdges(short[,] changes, int layer)
 {
     //
     // Traverse the matrix
     //
     Parallel.For(
         0,
         changes.GetLength(0),
         (leftUnit) =>
     {
         var random = ThreadSafeRandom.GetThreadRandom();
         for (int rightUnit = 0; rightUnit < changes.GetLength(1); rightUnit++)
         {
             //
             // If the learning signal indicates that this edge should be modified, flip a coin
             // The probability of the edge being modified can be considered to be a pseudo-learning-rate
             // TODO: Parameterize the probability of an edge being updated
             //
             if (changes[leftUnit, rightUnit] != 0 && random.NextDouble() < LearningProbability)
             {
                 //
                 // Get the current type of edge and, if possible, make it either more excitatory or inhibitory,
                 // depending on the learning signal.
                 //
                 var edge = this.Connections[layer].GetEdge(leftUnit, rightUnit);
                 if (changes[leftUnit, rightUnit] > 0)
                 {
                     if (edge.Weight < this.MaxWeight)
                     {
                         this.Connections[layer].SetEdge(leftUnit, rightUnit, edge.Weight + 1);
                     }
                 }
                 else
                 {
                     if (edge.Weight > this.MinWeight)
                     {
                         this.Connections[layer].SetEdge(leftUnit, rightUnit, edge.Weight - 1);
                     }
                 }
             }
         }
     });
 }
Example #8
0
        /// <summary>
        /// Generates random XOR samples.
        /// </summary>
        /// <param name="count">The number of samples to generate.</param>
        /// <returns>The generated samples, labeled as 0 if the XOR of the two bits is false and 1 otherwise.</returns>
        /// <remarks>
        /// The visualization mechanism in the GUI assumes data to consist of square pictures. Each bit is therefore duplicated,
        /// resulting in each sample having size 4. Since the sample data is of type <code>byte[]</code>, every 1-bit is represented with
        /// <see cref="byte.MaxValue"/>.</remarks>
        private LabelledSample[] GenerateSamples(int count)
        {
            var random = ThreadSafeRandom.GetThreadRandom();
            var result = new LabelledSample[count];
            var bits   = new bool[2];

            for (int i = 0; i < count; i++)
            {
                //
                // Get two random bits
                //
                bits[0] = random.NextDouble() > 0.5 ? true : false;
                bits[1] = random.NextDouble() > 0.5 ? true : false;
                //
                // Are both bits zero?
                //
                if (!bits[0] && !bits[1])
                {
                    //
                    // The current design of our neural nets makes it impossible to recognize an all-zero data vector since no
                    // activations can result from it. For now, we work around this issue by
                    //
                    bits[0] = true;
                    bits[1] = true;
                }
                //
                // Populate the sample data array
                //
                var sampleData = new byte[4];
                sampleData[0] = sampleData[1] = bits[0] ? byte.MaxValue : byte.MinValue;
                sampleData[2] = sampleData[3] = bits[1] ? byte.MaxValue : byte.MinValue;
                //
                // Calculate the label
                //
                int label = bits[0] ^ bits[1] ? 1 : 0;
                //
                // Add this sample to the resulting array
                //
                result[i] = new LabelledSample(label, sampleData);
            }

            return(result);
        }