Beispiel #1
0
        /// <summary>
        /// Return the inference value from one input sample. The actual learning happens in compute().
        /// </summary>
        /// <param name="patternNz">list of the active indices from the output below</param>
        /// <param name="classification">
        /// dict of the classification information:
        /// - bucketIdx: index of the encoder bucket
        /// - actValue:  actual value going into the encoder
        /// </param>
        /// <returns>
        /// dict containing inference results, one entry for each step in
        /// self.steps.The key is the number of steps, the value is an
        /// array containing the relative likelihood for each bucketIdx
        /// starting from bucketIdx 0.
        ///
        ///        for example:
        ///          {'actualValues': [0.0, 1.0, 2.0, 3.0]
        ///            1 : [0.1, 0.3, 0.2, 0.7]
        ///            4 : [0.2, 0.4, 0.3, 0.5]
        ///         }
        /// </returns>
        public Classification <T> Infer <T>(int[] patternNz, IDictionary <string, object> classification)
        {
            // Return value dict. For buckets which we don't have an actual value
            // for yet, just plug in any valid actual value. It doesn't matter what
            // we use because that bucket won't have non-zero likelihood anyways.
            //
            // NOTE: If doing 0-step prediction, we shouldn't use any knowledge
            // of the classification input during inference.
            object defaultValue;

            if (Steps[0] == 0 || classification == null)
            {
                defaultValue = 0;
            }
            else
            {
                defaultValue = classification["actValue"];
            }
            var actValues             = _actualValues.Select(x => (T)(x ?? TypeConverter.Convert <T>(defaultValue))).ToArray();
            Classification <T> retVal = new Classification <T>();

            retVal.SetActualValues(actValues);
            //NamedTuple retVal = new NamedTuple(new[] { "actualValues" }, new object[] { actValues});

            foreach (var nSteps in Steps)
            {
                var predictDist = InferSingleStep(patternNz, _weightMatrix[nSteps]);
                retVal.SetStats(nSteps, predictDist);
                //retVal[nSteps.ToString()] = predictDist;
            }

            return(retVal);
        }
Beispiel #2
0
        /// <summary>
        /// Process one input sample.
        /// This method is called by outer loop code outside the nupic-engine. We
        /// use this instead of the nupic engine compute() because our inputs and
        /// outputs aren't fixed size vectors of reals.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="recordNum">Record number of this input pattern. Record numbers should
        /// normally increase sequentially by 1 each time unless there
        /// are missing records in the dataset. Knowing this information
        /// insures that we don't get confused by missing records.</param>
        /// <param name="classification">Map of the classification information:
        /// bucketIdx: index of the encoder bucket
        /// actValue:  actual value going into the encoder</param>
        /// <param name="patternNZ">list of the active indices from the output below</param>
        /// <param name="learn">if true, learn this sample</param>
        /// <param name="infer">if true, perform inference</param>
        /// <returns>dict containing inference results, there is one entry for each
        /// step in steps, where the key is the number of steps, and
        /// the value is an array containing the relative likelihood for
        /// each bucketIdx starting from bucketIdx 0.
        ///
        /// There is also an entry containing the average actual value to
        /// use for each bucket. The key is 'actualValues'.
        ///
        /// for example:
        /// {
        ///     1 :             [0.1, 0.3, 0.2, 0.7],
        ///     4 :             [0.2, 0.4, 0.3, 0.5],
        ///     'actualValues': [1.5, 3,5, 5,5, 7.6],
        /// }
        /// </returns>
        public Classification <T> Compute <T>(int recordNum, IDictionary <string, object> classification, int[] patternNZ, bool learn, bool infer)
        {
            Classification <T> retVal = new Classification <T>();

            //List<T> actualValues = this.actualValues.Select(av => av == null ? default(T) : (T)av).ToList();

            // Save the offset between recordNum and learnIteration if this is the first
            // compute
            if (_recordNumMinusLearnIteration == -1)
            {
                _recordNumMinusLearnIteration = recordNum - _learnIteration;
            }

            // Update the learn iteration
            _learnIteration = recordNum - _recordNumMinusLearnIteration;

            if (Verbosity >= 1)
            {
                Console.WriteLine(String.Format("\n{0}: compute ", g_debugPrefix));
                Console.WriteLine(" recordNum: " + recordNum);
                Console.WriteLine(" learnIteration: " + _learnIteration);
                Console.WriteLine(String.Format(" patternNZ({0}): {1}", patternNZ.Length, Arrays.ToString(patternNZ)));
                Console.WriteLine(" classificationIn: " + classification);
            }

            _patternNzHistory.Append(new Tuple(_learnIteration, patternNZ));

            //------------------------------------------------------------------------
            // Inference:
            // For each active bit in the activationPattern, get the classification
            // votes
            //
            // Return value dict. For buckets which we don't have an actual value
            // for yet, just plug in any valid actual value. It doesn't matter what
            // we use because that bucket won't have non-zero likelihood anyways.
            if (infer)
            {
                // NOTE: If doing 0-step prediction, we shouldn't use any knowledge
                //		 of the classification input during inference.
                object defaultValue = null;
                if (Steps[0] == 0)
                {
                    defaultValue = 0;
                }
                else
                {
                    defaultValue = classification.GetOrDefault("actValue", null);
                }

                T[] actValues = new T[this._actualValues.Count];
                for (int i = 0; i < _actualValues.Count; i++)
                {
                    //if (EqualityComparer<T>.Default.Equals(actualValues[i], default(T)))  //actualValues[i] == default(T))
                    if (_actualValues[i] == null)
                    {
                        actValues[i] = defaultValue != null?TypeConverter.Convert <T>(defaultValue) : default(T);

                        //(T) (defaultValue ?? default(T));
                    }
                    else
                    {
                        actValues[i] = (T)_actualValues[i];
                    }
                    //actValues[i] = actualValues[i].CompareTo(default(T)) == 0 ? defaultValue : actualValues[i];
                }

                retVal.SetActualValues(actValues);

                // For each n-step prediction...
                foreach (int nSteps in Steps.ToArray())
                {
                    // Accumulate bucket index votes and actValues into these arrays
                    double[] sumVotes = new double[_maxBucketIdx + 1];
                    double[] bitVotes = new double[_maxBucketIdx + 1];

                    foreach (int bit in patternNZ)
                    {
                        Tuple      key     = new Tuple(bit, nSteps);
                        BitHistory history = _activeBitHistory.GetOrDefault(key, null);
                        if (history == null)
                        {
                            continue;
                        }

                        history.Infer(_learnIteration, bitVotes);

                        sumVotes = ArrayUtils.Add(sumVotes, bitVotes);
                    }

                    // Return the votes for each bucket, normalized
                    double total = ArrayUtils.Sum(sumVotes);
                    if (total > 0)
                    {
                        sumVotes = ArrayUtils.Divide(sumVotes, total);
                    }
                    else
                    {
                        // If all buckets have zero probability then simply make all of the
                        // buckets equally likely. There is no actual prediction for this
                        // timestep so any of the possible predictions are just as good.
                        if (sumVotes.Length > 0)
                        {
                            Arrays.Fill(sumVotes, 1.0 / (double)sumVotes.Length);
                        }
                    }

                    retVal.SetStats(nSteps, sumVotes);
                }
            }

            // ------------------------------------------------------------------------
            // Learning:
            // For each active bit in the activationPattern, store the classification
            // info. If the bucketIdx is None, we can't learn. This can happen when the
            // field is missing in a specific record.
            if (learn && classification.GetOrDefault("bucketIdx", null) != null)
            {
                // Get classification info
                int    bucketIdx = (int)(classification["bucketIdx"]);
                object actValue  = classification["actValue"];

                // Update maxBucketIndex
                _maxBucketIdx = Math.Max(_maxBucketIdx, bucketIdx);

                // Update rolling average of actual values if it's a scalar. If it's
                // not, it must be a category, in which case each bucket only ever
                // sees one category so we don't need a running average.
                while (_maxBucketIdx > _actualValues.Count - 1)
                {
                    _actualValues.Add(null);
                }
                if (_actualValues[bucketIdx] == null)
                {
                    _actualValues[bucketIdx] = TypeConverter.Convert <T>(actValue);
                }
                else
                {
                    if (typeof(double).IsAssignableFrom(actValue.GetType()))
                    {
                        Double val = ((1.0 - _actValueAlpha) * (TypeConverter.Convert <double>(_actualValues[bucketIdx])) +
                                      _actValueAlpha * (TypeConverter.Convert <double>(actValue)));
                        _actualValues[bucketIdx] = TypeConverter.Convert <T>(val);
                    }
                    else
                    {
                        _actualValues[bucketIdx] = TypeConverter.Convert <T>(actValue);
                    }
                }

                // Train each pattern that we have in our history that aligns with the
                // steps we have in steps
                int   nSteps         = -1;
                int   iteration      = 0;
                int[] learnPatternNZ = null;
                foreach (int n in Steps.ToArray())
                {
                    nSteps = n;
                    // Do we have the pattern that should be assigned to this classification
                    // in our pattern history? If not, skip it
                    bool found = false;
                    foreach (Tuple t in _patternNzHistory)
                    {
                        iteration = TypeConverter.Convert <int>(t.Get(0));

                        var tuplePos1 = t.Get(1);
                        if (tuplePos1 is JArray)
                        {
                            JArray arr = (JArray)tuplePos1;
                            learnPatternNZ = arr.Values <int>().ToArray();
                        }
                        else
                        {
                            learnPatternNZ = (int[])t.Get(1);
                        }

                        if (iteration == _learnIteration - nSteps)
                        {
                            found = true;
                            break;
                        }
                        iteration++;
                    }
                    if (!found)
                    {
                        continue;
                    }

                    // Store classification info for each active bit from the pattern
                    // that we got nSteps time steps ago.
                    foreach (int bit in learnPatternNZ)
                    {
                        // Get the history structure for this bit and step
                        Tuple      key     = new Tuple(bit, nSteps);
                        BitHistory history = _activeBitHistory.GetOrDefault(key, null);
                        if (history == null)
                        {
                            _activeBitHistory.Add(key, history = new BitHistory(this, bit, nSteps));
                        }
                        history.Store(_learnIteration, bucketIdx);
                    }
                }
            }

            if (infer && Verbosity >= 1)
            {
                Console.WriteLine(" inference: combined bucket likelihoods:");
                Console.WriteLine("   actual bucket values: " + Arrays.ToString((T[])retVal.GetActualValues()));

                foreach (int key in retVal.StepSet())
                {
                    if (retVal.GetActualValue(key) == null)
                    {
                        continue;
                    }

                    Object[] actual = new Object[] { (T)retVal.GetActualValue(key) };
                    Console.WriteLine(String.Format("  {0} steps: {1}", key, PFormatArray(actual)));
                    int bestBucketIdx = retVal.GetMostProbableBucketIndex(key);
                    Console.WriteLine(String.Format("   most likely bucket idx: {0}, value: {1} ", bestBucketIdx,
                                                    retVal.GetActualValue(bestBucketIdx)));
                }
            }

            return(retVal);
        }