/// <summary> /// Initializes a new instance of the <see cref="ProximalSynapse"/> class and /// sets its input source and initial permanance values. /// </summary> /// <param name="proximalSeg"> /// </param> /// <param name="inputSource"> /// An <see cref="InputCell"/> providing source of the input to this synapse. /// </param> /// <param name="permanence">Initial permanence value.</param> internal ProximalSynapse(ProximalSegment proximalSeg, InputCell inputSource, float permanence) { // Set fields this.ProximalSegment = proximalSeg; this.InputSource = inputSource; this.Permanence = permanence; SelectablelType = SelectableObjectType.ProximalSynapse; }
/// <summary> /// Initializes a new instance of the <see cref="ProximalSynapse"/> class and /// sets its input source and initial permanance values. /// </summary> /// <param name="proximalSeg"> /// </param> /// <param name="inputSource"> /// An <see cref="InputCell"/> providing source of the input to this synapse. /// </param> /// <param name="permanence">Initial permanence value.</param> internal ProximalSynapse(ProximalSegment proximalSeg, InputCell inputSource, float permanence) { // Set fields this.ProximalSegment = proximalSeg; this.InputSource = inputSource; this.Permanence = permanence; SelectablelType = SelectableObjectType.ProximalSynapse; }
/// <summary> /// For each (position in inputSpaceRandomPositions): /// 1. Create a new InputCell with input bit = position /// 2. Attach a new ProximalSynapse /// 3. Add the synapse to the synapse update list. /// </summary> /// <remarks> /// Prior to receiving any inputs, the region is initialized by computing a list of /// initial potential synapses for each column. This consists of a random set of inputs /// selected from the input space. Each input is represented by a synapse and assigned /// a random permanence value. The random permanence values are chosen with two /// criteria. First, the values are chosen to be in a small range around connectedPerm /// (the minimum permanence value at which a synapse is considered "connected"). This /// enables potential synapses to become connected (or disconnected) after a small /// number of training iterations. Second, each column has a natural center over the /// input region, and the permanence values have a bias towards this center (they /// have higher values near the center). /// /// The concept of Locality Radius is an additional parameter to control how /// far away synapse connections can be made instead of allowing connections anywhere. /// The reason for this is that in the case of video images I wanted to experiment /// with forcing each Column to only learn on a small section of the total input to /// more effectively learn lines or corners in a small section. /// </remarks> internal void CreateProximalSegments() { // Calculates inputRadius for Columns from localityRadius //var inputRadius = (int)Math.Round ( this.Region.LocalityRadius * this.Region.InputProportionX ); // JS // JS - should there be 2 inputRadiae, for X and Y, to allow for non-square input fields? //(1) var inputRadius = (int) Math.Max( 1, Math.Round(this.Region.LocalityRadius * this.Region.InputProportionX)); //inputRadius = (int)Math.Max ( 1, Math.Round ( this.Region.PercentageInputPerColumn * this.Region.InputSize.Height * this.Region.InputSize.Width ) / 2 ); //var inputRadius = (int)Math.Max ( 1, Math.Round ( this.Region.LocalityRadius * Math.Max ( this.Region.InputProportionX, this.Region.InputProportionY ) ) ); // The coordinates of the input space for the Column // Think of input space like a 'imaginary' square below the column center. int minY, maxY, minX, maxX; //(2) if (this.Region.LocalityRadius > 0) { // Compute values of input square and cut radius on edges minX = Math.Max ( 0, this.CentralPositionInInput.X - inputRadius); maxX = Math.Min(this.Region.InputSize.Width - 1, this.CentralPositionInInput.X + inputRadius); minY = Math.Max ( 0, this.CentralPositionInInput.Y - inputRadius); maxY = Math.Min(this.Region.InputSize.Height - 1, this.CentralPositionInInput.Y + inputRadius); } else { minX = 0; minY = 0; maxX = this.Region.InputSize.Width - 1; maxY = this.Region.InputSize.Height - 1; } // Compute input area // (3) int inputArea = (maxX - minX + 1) * (maxY - minY + 1); // Proximal synapses per Column (input segment) // TODO: give user some control over the number of synapses per segment //var synapsesPerSegment = //debug js // (int) (inputArea * this.Region.PercentageInputPerColumn); // (4) var synapsesPerSegment = Math.Max(1, (int)(inputArea * this.Region.PercentageInputPerColumn)); // JS //synapsesPerSegment = Math.Max ( 1, (int)(inputArea * this.Region.InputProportionX) ); // Updates minimum overlap value, i.e. the minimum number of inputs that must // be active for a column to be considered during the inhibition step. //debug js //this.MinOverlap = // (int) Math.Round(synapsesPerSegment * this.Region.PercentageMinOverlap); // (5) this.MinOverlap = Math.Max(1, (int)Math.Round ( synapsesPerSegment * this.Region.PercentageMinOverlap )); // Create all possible x,y positions for this column input space // (6) var inputPositions = new List<Point>(); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { var inputPosition = new Point(x, y); inputPositions.Add(inputPosition); } } // Random sample of unique input positions (no duplicates). // Tie the random seed to this Column's position for reproducibility int randomSeed = (this.PositionInRegion.Y * this.Region.Size.Width) + this.PositionInRegion.X; // (7) IEnumerable<Point> inputRandomPositions = inputPositions.RandomSample(synapsesPerSegment, randomSeed, false); // Initialize the gaussian normal distribution // The values are chosen to be in a small range around connectedPerm // (the minimum permanence value at which a synapse is considered "connected") var gausianNormalDistribution = new Normal ( Synapse.InitialPermanence, Synapse.PermanenceIncrement ); gausianNormalDistribution.RandomSource = new Random ( randomSeed ); // Create proximal synapses to ramdom positions in input int longerSide = Math.Max(this.Region.InputSize.Width, this.Region.InputSize.Height); foreach (var position in inputRandomPositions) { var newInputCell = new InputCell(this.Region, position.X, position.Y); if (this.Region.FullDefaultSpatialPermanence) { // Create new synapse and add it to segment this.ProximalSegment.CreateSynapse(newInputCell, 1.0f); } else { // Get new value for permanence from distribution double permanence = gausianNormalDistribution.Sample(); // Distance from 'center' of this column to the current position in the input space // JS - replaced with more precise code from Ultrafast //var distanceInputFromColumn = new Point (); //distanceInputFromColumn.X = this.CentralPositionInInput.X - position.X; //distanceInputFromColumn.Y = this.CentralPositionInInput.Y - position.Y; //double distanceToInput = Math.Sqrt ( // (distanceInputFromColumn.X * distanceInputFromColumn.X) + // (distanceInputFromColumn.Y * distanceInputFromColumn.Y) ); double distanceX = this.CentralPositionInInput.X - position.X; double distanceY = this.CentralPositionInInput.Y - position.Y; double distanceToInput = Math.Sqrt ( distanceX * distanceX + distanceY * distanceY ); // Each column has a natural center over the input region, and the // permanence values have a bias towards this center (they have higher values near // the center) int radiusBiasPeak = 2; double radiusBiasStandardDeviation = 2.0; // 0.25; double localityBias = radiusBiasPeak / 2.0 * Math.Exp(Math.Pow(distanceToInput / (longerSide * radiusBiasStandardDeviation), 2) / -2); //StreamWriter file = new StreamWriter ( "localityBias.txt", false ); //for (float longSide = 1f; longSide < 10.0f; longSide += 1f) //{ // file.WriteLine ( "RadiusBiasPeak,distToInput,longerSide,SD,localityBias" ); // for (float distToInput = 0.0f; distToInput < 2.0f; distToInput += 0.1f) // { // localityBias = radiusBiasPeak / 2.0f * // Math.Exp ( Math.Pow ( distToInput / // (longSide * radiusBiasStandardDeviation), 2 ) / -2 ); // file.WriteLine ( String.Format ( "{0:0.00},{1:0.00},{2:0.00},{3:0.00},{4:0.0000000}", radiusBiasPeak, distToInput, longSide, radiusBiasStandardDeviation, localityBias ) ); // } //} //file.Close (); double permanenceBias = Math.Min(1.0f, permanence * localityBias); // Create new synapse and add it to segment this.ProximalSegment.CreateSynapse(newInputCell, permanenceBias); } } }
/// <summary> /// For each (position in inputSpaceRandomPositions): /// 1. Create a new InputCell with input bit = position /// 2. Attach a new ProximalSynapse /// 3. Add the synapse to the synapse update list. /// </summary> /// <remarks> /// Prior to receiving any inputs, the region is initialized by computing a list of /// initial potential synapses for each column. This consists of a random set of inputs /// selected from the input space. Each input is represented by a synapse and assigned /// a random permanence value. The random permanence values are chosen with two /// criteria. First, the values are chosen to be in a small range around connectedPerm /// (the minimum permanence value at which a synapse is considered "connected"). This /// enables potential synapses to become connected (or disconnected) after a small /// number of training iterations. Second, each column has a natural center over the /// input region, and the permanence values have a bias towards this center (they /// have higher values near the center). /// /// The concept of Locality Radius is an additional parameter to control how /// far away synapse connections can be made instead of allowing connections anywhere. /// The reason for this is that in the case of video images I wanted to experiment /// with forcing each Column to only learn on a small section of the total input to /// more effectively learn lines or corners in a small section. /// </remarks> internal void CreateProximalSegments() { // Calculates inputRadius for Columns from localityRadius //var inputRadius = (int)Math.Round ( this.Region.LocalityRadius * this.Region.InputProportionX ); // JS // JS - should there be 2 inputRadiae, for X and Y, to allow for non-square input fields? //(1) var inputRadius = (int)Math.Max(1, Math.Round(this.Region.LocalityRadius * this.Region.InputProportionX)); //inputRadius = (int)Math.Max ( 1, Math.Round ( this.Region.PercentageInputPerColumn * this.Region.InputSize.Height * this.Region.InputSize.Width ) / 2 ); //var inputRadius = (int)Math.Max ( 1, Math.Round ( this.Region.LocalityRadius * Math.Max ( this.Region.InputProportionX, this.Region.InputProportionY ) ) ); // The coordinates of the input space for the Column // Think of input space like a 'imaginary' square below the column center. int minY, maxY, minX, maxX; //(2) if (this.Region.LocalityRadius > 0) { // Compute values of input square and cut radius on edges minX = Math.Max(0, this.CentralPositionInInput.X - inputRadius); maxX = Math.Min(this.Region.InputSize.Width - 1, this.CentralPositionInInput.X + inputRadius); minY = Math.Max(0, this.CentralPositionInInput.Y - inputRadius); maxY = Math.Min(this.Region.InputSize.Height - 1, this.CentralPositionInInput.Y + inputRadius); } else { minX = 0; minY = 0; maxX = this.Region.InputSize.Width - 1; maxY = this.Region.InputSize.Height - 1; } // Compute input area // (3) int inputArea = (maxX - minX + 1) * (maxY - minY + 1); // Proximal synapses per Column (input segment) // TODO: give user some control over the number of synapses per segment //var synapsesPerSegment = //debug js // (int) (inputArea * this.Region.PercentageInputPerColumn); // (4) var synapsesPerSegment = Math.Max(1, (int)(inputArea * this.Region.PercentageInputPerColumn)); // JS //synapsesPerSegment = Math.Max ( 1, (int)(inputArea * this.Region.InputProportionX) ); // Updates minimum overlap value, i.e. the minimum number of inputs that must // be active for a column to be considered during the inhibition step. //debug js //this.MinOverlap = // (int) Math.Round(synapsesPerSegment * this.Region.PercentageMinOverlap); // (5) this.MinOverlap = Math.Max(1, (int)Math.Round(synapsesPerSegment * this.Region.PercentageMinOverlap)); // Create all possible x,y positions for this column input space // (6) var inputPositions = new List <Point>(); for (int y = minY; y <= maxY; y++) { for (int x = minX; x <= maxX; x++) { var inputPosition = new Point(x, y); inputPositions.Add(inputPosition); } } // Random sample of unique input positions (no duplicates). // Tie the random seed to this Column's position for reproducibility int randomSeed = (this.PositionInRegion.Y * this.Region.Size.Width) + this.PositionInRegion.X; // (7) IEnumerable <Point> inputRandomPositions = inputPositions.RandomSample(synapsesPerSegment, randomSeed, false); // Initialize the gaussian normal distribution // The values are chosen to be in a small range around connectedPerm // (the minimum permanence value at which a synapse is considered "connected") var gausianNormalDistribution = new Normal(Synapse.InitialPermanence, Synapse.PermanenceIncrement); gausianNormalDistribution.RandomSource = new Random(randomSeed); // Create proximal synapses to ramdom positions in input int longerSide = Math.Max(this.Region.InputSize.Width, this.Region.InputSize.Height); foreach (var position in inputRandomPositions) { var newInputCell = new InputCell(this.Region, position.X, position.Y); if (this.Region.FullDefaultSpatialPermanence) { // Create new synapse and add it to segment this.ProximalSegment.CreateSynapse(newInputCell, 1.0f); } else { // Get new value for permanence from distribution double permanence = gausianNormalDistribution.Sample(); // Distance from 'center' of this column to the current position in the input space // JS - replaced with more precise code from Ultrafast //var distanceInputFromColumn = new Point (); //distanceInputFromColumn.X = this.CentralPositionInInput.X - position.X; //distanceInputFromColumn.Y = this.CentralPositionInInput.Y - position.Y; //double distanceToInput = Math.Sqrt ( // (distanceInputFromColumn.X * distanceInputFromColumn.X) + // (distanceInputFromColumn.Y * distanceInputFromColumn.Y) ); double distanceX = this.CentralPositionInInput.X - position.X; double distanceY = this.CentralPositionInInput.Y - position.Y; double distanceToInput = Math.Sqrt(distanceX * distanceX + distanceY * distanceY); // Each column has a natural center over the input region, and the // permanence values have a bias towards this center (they have higher values near // the center) int radiusBiasPeak = 2; double radiusBiasStandardDeviation = 2.0; // 0.25; double localityBias = radiusBiasPeak / 2.0 * Math.Exp(Math.Pow(distanceToInput / (longerSide * radiusBiasStandardDeviation), 2) / -2); //StreamWriter file = new StreamWriter ( "localityBias.txt", false ); //for (float longSide = 1f; longSide < 10.0f; longSide += 1f) //{ // file.WriteLine ( "RadiusBiasPeak,distToInput,longerSide,SD,localityBias" ); // for (float distToInput = 0.0f; distToInput < 2.0f; distToInput += 0.1f) // { // localityBias = radiusBiasPeak / 2.0f * // Math.Exp ( Math.Pow ( distToInput / // (longSide * radiusBiasStandardDeviation), 2 ) / -2 ); // file.WriteLine ( String.Format ( "{0:0.00},{1:0.00},{2:0.00},{3:0.00},{4:0.0000000}", radiusBiasPeak, distToInput, longSide, radiusBiasStandardDeviation, localityBias ) ); // } //} //file.Close (); double permanenceBias = Math.Min(1.0f, permanence * localityBias); // Create new synapse and add it to segment this.ProximalSegment.CreateSynapse(newInputCell, permanenceBias); } } }
/// <summary> /// Create a new synapse for this segment attached to the specified input cell. /// </summary> /// <param name="inputSource">the input source of the synapse to create.</param> /// <param name="initialPermanence">the initial permanence of the synapse.</param> internal void CreateSynapse(InputCell inputSource, double initialPermanence) { var newSynapse = new ProximalSynapse(this, inputSource, (float)initialPermanence); this.Synapses.Add(newSynapse); }
/// <summary> /// Create a new synapse for this segment attached to the specified input cell. /// </summary> /// <param name="inputSource">the input source of the synapse to create.</param> /// <param name="initialPermanence">the initial permanence of the synapse.</param> internal void CreateSynapse(InputCell inputSource, double initialPermanence) { var newSynapse = new ProximalSynapse(this, inputSource, (float)initialPermanence); this.Synapses.Add(newSynapse); }