org.numenta.nupic.RunLayer.java Source code

Java tutorial

Introduction

Here is the source code for org.numenta.nupic.RunLayer.java

Source

/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2016, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */
package org.numenta.nupic;

import static org.numenta.nupic.algorithms.Anomaly.KEY_MODE;
import static org.numenta.nupic.algorithms.Anomaly.KEY_USE_MOVING_AVG;
import static org.numenta.nupic.algorithms.Anomaly.KEY_WINDOW_SIZE;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.numenta.nupic.Parameters.KEY;
import org.numenta.nupic.algorithms.Anomaly;
import org.numenta.nupic.algorithms.Anomaly.Mode;
import org.numenta.nupic.algorithms.CLAClassifier;
import org.numenta.nupic.algorithms.Classification;
import org.numenta.nupic.algorithms.SpatialPooler;
import org.numenta.nupic.algorithms.TemporalMemory;
import org.numenta.nupic.encoders.DateEncoder;
import org.numenta.nupic.encoders.Encoder;
import org.numenta.nupic.encoders.EncoderTuple;
import org.numenta.nupic.encoders.MultiEncoder;
import org.numenta.nupic.encoders.ScalarEncoder;
import org.numenta.nupic.model.ComputeCycle;
import org.numenta.nupic.model.Connections;
import org.numenta.nupic.model.SDR;
import org.numenta.nupic.network.Network;
import org.numenta.nupic.util.ArrayUtils;
import org.numenta.nupic.util.Tuple;
import org.numenta.nupic.util.UniversalRandom;

public class RunLayer {
    public static boolean IS_VERBOSE = true;
    public static boolean LEARN = true;
    public static boolean TM_ONLY = true;
    public static boolean SP_ONLY = false;
    public static boolean NETWORK = false;

    public static class MakeshiftLayer {
        private Connections connections;
        private MultiEncoder encoder;
        private SpatialPooler sp;
        private TemporalMemory tm;
        private CLAClassifier classifier;
        @SuppressWarnings("unused")
        private Anomaly anomaly;

        private int recordNum;
        private int[] prevPredictedCols;
        private Map<String, Object> classification;

        private Network network;

        //        private static String INPUT_PATH = "/Users/cogmission/git/NAB/data/artificialNoAnomaly/art_daily_no_noise.csv";
        //        private static String readFile = "/Users/cogmission/git/NAB/data/artificialNoAnomaly/art_daily_sp_output.txt";
        private static String INPUT_PATH = "/Users/cogmission/git/NAB/data/realTraffic/TravelTime_387.csv";
        private static String readFile = "/Users/cogmission/git/newtm/htm.java/src/test/resources/TravelTime_sp_output.txt";

        private static List<int[]> input;
        private static List<String> raw;

        @SuppressWarnings("unused")
        private static String encFilePath = "/Users/cogmission/git/lscheinkman/NAB/art_daily_encoder_output_java.txt";
        private PrintWriter encFile = null;

        /**
         * Makeshift Layer to contain and operate on algorithmic entities
         * 
         * @param c         the {@link Connections} object.
         * @param encoder   the {@link MultiEncoder}
         * @param sp        the {@link SpatialPooler}
         * @param tm        the {@link TemporalMemory}
         * @param cl        the {@link CLAClassifier}
         */
        public MakeshiftLayer(Connections c, MultiEncoder encoder, SpatialPooler sp, TemporalMemory tm,
                CLAClassifier cl, Anomaly anomaly) {

            this.connections = c;
            this.encoder = encoder;
            this.sp = sp;
            this.tm = tm;
            this.classifier = cl;

            //            Parameters parameters = getParameters();
            // 2015-08-31 18:22:00,90
            //            network = Network.create("NAB Network", parameters)
            //                .add(Network.createRegion("NAB Region")
            //                    .add(Network.createLayer("NAB Layer", parameters)
            //                        .add(Anomaly.create())
            //                        .add(new TemporalMemory())));
            //            
            //            network.observe().subscribe((inference) -> {
            //                double score = inference.getAnomalyScore();
            //                int record = inference.getRecordNum();
            //                
            //                recordNum = record;
            //                
            //                printHeader();
            //                
            //                Set<Cell> act = ((ManualInput)inference).getActiveCells();
            //                int[] activeColumnIndices = SDR.cellsAsColumnIndices(act, connections.getCellsPerColumn());
            //                Set<Cell> prev = ((ManualInput)inference).getPreviousPredictiveCells();
            //                int[] prevPredColumnIndices = prev == null ? null : SDR.cellsAsColumnIndices(prev, connections.getCellsPerColumn());
            //                String input = Arrays.toString((int[])((ManualInput)inference).getLayerInput());
            //                String prevPred = prevPredColumnIndices == null ? "null" : Arrays.toString(prevPredColumnIndices);
            //                String active = Arrays.toString(activeColumnIndices);
            //                System.out.println("          TemporalMemory Input: " + input);
            //                System.out.println("TemporalMemory prev. predicted: " + prevPred);
            //                System.out.println("         TemporalMemory active: " + active);
            //                System.out.println("Anomaly Score: " + score + "\n");
            //                
            //            }, (error) -> {
            //                error.printStackTrace();
            //            }, () -> {
            //                // On Complete
            //            });
        }

        public void printHeader() {
            System.out.println("--------------------------------------------");
            System.out.println("Record #: " + recordNum + "\n");
            System.out.println("Raw Input: " + MakeshiftLayer.raw.get(recordNum + 1));
        }

        /**
         * Input through Encoder
         * 
         * @param timestamp
         * @param value
         * @param isVerbose
         * @return Tuple { encoding, bucket index }
         */
        Encoder<?> valueEncoder = null;

        public Tuple encodingStep(DateTime timestamp, double value, boolean isVerbose) {
            if (valueEncoder == null) {
                List<EncoderTuple> encoderTuples = encoder.getEncoders(encoder);
                valueEncoder = encoderTuples.get(0).getEncoder();
            }

            Map<String, Object> encodingInput = new HashMap<String, Object>();
            encodingInput.put("value", value);
            encodingInput.put("timestamp", timestamp);
            int[] encoding = encoder.encode(encodingInput);
            if (isVerbose) {
                System.out.println("ScalarEncoder Output = " + Arrays.toString(encoding));
            }

            int bucketIdx = valueEncoder.getBucketIndices((double) value)[0];
            //            writeEncOutput(encoding);
            return new Tuple(encoding, bucketIdx);
        }

        /**
         * Input through the spatial pooler 
         * 
         * @param encoding
         * @param isVerbose
         * @return Tuple { dense output, sparse output }
         */
        public Tuple spStep(int[] encoding, boolean learn, boolean isVerbose) {
            // Input through Spatial Pooler
            int[] output = new int[connections.getNumColumns()];
            sp.compute(connections, encoding, output, true);
            int[] sparseSPOutput = ArrayUtils.where(output, ArrayUtils.WHERE_1);
            if (isVerbose) {
                System.out.println("SpatialPooler Output = " + Arrays.toString(sparseSPOutput) + "\n");
            }

            return new Tuple(output, sparseSPOutput);
        }

        public void networkStep(int[] sparseSPOutput, boolean learn) {
            network.compute(sparseSPOutput);
        }

        /**
         * Input through the Temporal Memory
         * @param sparseSPOutput
         * @param learn
         * @param isVerbose
         * @return Tuple { active cell indices, previous predicted column indices, predicted column indices }
         */
        public Tuple tmStep(int[] sparseSPOutput, boolean learn, boolean isVerbose) {
            // Input into the Temporal Memory
            ComputeCycle cc = tm.compute(connections, sparseSPOutput, learn);
            int[] activeCellIndices = cc.activeCells().stream().mapToInt(c -> c.getIndex()).sorted().toArray();
            int[] predColumnIndices = SDR.cellsAsColumnIndices(cc.predictiveCells(),
                    connections.getCellsPerColumn());
            int[] activeColumns = Arrays.stream(activeCellIndices)
                    .map(cell -> cell / connections.getCellsPerColumn()).distinct().sorted().toArray();
            if (isVerbose) {
                System.out.println("          TemporalMemory Input: " + Arrays.toString(sparseSPOutput));
                System.out.println("TemporalMemory prev. predicted: " + Arrays.toString(prevPredictedCols));
                System.out.println("         TemporalMemory active: " + Arrays.toString(activeColumns));
            }

            return new Tuple(activeCellIndices, prevPredictedCols, predColumnIndices);
        }

        /**
         * Run classification step
         * 
         * @param activeCellIndices
         * @param bucketIdx
         * @param inputValue
         * @param learn
         * @param isVerbose
         * @return  the {@link Classification}
         */
        public Classification<Double> classificationStep(int[] activeCellIndices, int bucketIdx, Object inputValue,
                boolean learn, boolean isVerbose) {
            classification.put("bucketIdx", bucketIdx);
            classification.put("actValue", inputValue);

            Classification<Double> result = classifier.compute(recordNum, classification, activeCellIndices, true,
                    true);
            if (isVerbose) {
                System.out.print("CLAClassifier Prediction = " + result.getMostProbableValue(1));
                System.out
                        .println("  |  CLAClassifier 1 step prob = " + Arrays.toString(result.getStats(1)) + "\n");
            }

            return result;
        }

        /**
         * Run Anomaly computer step
         * @param sparseSPOutput
         * @param prevPredictedCols
         * @param isVerbose
         * @return  the raw anomaly score
         */
        public double anomalyStep(int[] sparseSPOutput, int[] prevPredictedCols, boolean isVerbose) {
            double anomalyScore = Anomaly.computeRawAnomalyScore(sparseSPOutput, prevPredictedCols);
            if (isVerbose) {
                System.out.println("Anomaly Score: " + anomalyScore + "\n");
            }

            return anomalyScore;
        }

        /**
         * Increment the record number
         */
        public void incRecordNum() {
            recordNum++;
        }

        /**
         * Returns the current record number
         * @return
         */
        public int getRecordNum() {
            return recordNum;
        }

        /**
         * At the end of a cycle, stores the current prediction
         * as the previous prediction.
         * 
         * @param predColumnIndices
         */
        public void storeCyclePrediction(int[] predColumnIndices) {
            prevPredictedCols = predColumnIndices;
        }

        public void writeEncOutput(int[] output) {
            try {
                encFile.println(Arrays.toString(output));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
    /////////////////////////////////// End Layer Class Definition ////////////////////////////////////////

    public static MultiEncoder createEncoder() {
        MultiEncoder encoder = MultiEncoder.builder().name("").build();
        ScalarEncoder se = ScalarEncoder.builder().n(50).w(21).minVal(0).maxVal(100).periodic(false).clipInput(true)
                .name("value").build();
        encoder.addEncoder("value", se);

        DateEncoder de = DateEncoder.builder().timeOfDay(21, 9.5).name("timestamp").build();
        encoder.addEncoder("timestamp", de);

        return encoder;
    }

    public static Parameters getParameters() {
        UniversalRandom random = new UniversalRandom(42);

        Parameters parameters = Parameters.getAllDefaultParameters();
        parameters.set(KEY.INPUT_DIMENSIONS, new int[] { 104 });
        parameters.set(KEY.COLUMN_DIMENSIONS, new int[] { 2048 });
        parameters.set(KEY.CELLS_PER_COLUMN, 32);
        parameters.set(KEY.RANDOM, random);

        //SpatialPooler specific
        parameters.set(KEY.POTENTIAL_RADIUS, 12);//3
        parameters.set(KEY.POTENTIAL_PCT, 0.85);//0.5
        parameters.set(KEY.GLOBAL_INHIBITION, true);
        parameters.set(KEY.LOCAL_AREA_DENSITY, -1.0);
        parameters.set(KEY.NUM_ACTIVE_COLUMNS_PER_INH_AREA, 40.0);
        parameters.set(KEY.STIMULUS_THRESHOLD, 1.0);
        parameters.set(KEY.SYN_PERM_INACTIVE_DEC, 0.0005);
        parameters.set(KEY.SYN_PERM_ACTIVE_INC, 0.0015);
        parameters.set(KEY.SYN_PERM_TRIM_THRESHOLD, 0.05);
        parameters.set(KEY.SYN_PERM_CONNECTED, 0.1);
        parameters.set(KEY.MIN_PCT_OVERLAP_DUTY_CYCLES, 0.1);
        parameters.set(KEY.MIN_PCT_ACTIVE_DUTY_CYCLES, 0.1);
        parameters.set(KEY.DUTY_CYCLE_PERIOD, 1000);
        parameters.set(KEY.MAX_BOOST, 2.0);

        //Temporal Memory specific
        parameters.set(KEY.INITIAL_PERMANENCE, 0.2);
        parameters.set(KEY.CONNECTED_PERMANENCE, 0.8);
        parameters.set(KEY.MIN_THRESHOLD, 4);
        parameters.set(KEY.MAX_NEW_SYNAPSE_COUNT, 6);
        parameters.set(KEY.PERMANENCE_INCREMENT, 0.1);//0.05
        parameters.set(KEY.PERMANENCE_DECREMENT, 0.1);//0.05
        parameters.set(KEY.ACTIVATION_THRESHOLD, 4);

        return parameters;
    }

    public static MakeshiftLayer createLayer() {
        MultiEncoder encoder = createEncoder();

        Parameters parameters = getParameters();

        //////////////////////////////////////////////////////////
        //        testRandom(random);
        //////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////
        //        int[] encoding = testEncoder(encoder);
        //////////////////////////////////////////////////////////

        Connections conn = new Connections();
        parameters.apply(conn);

        SpatialPooler sp = null;
        if (!RunLayer.TM_ONLY) {
            sp = new SpatialPooler();
            sp.init(conn);
        }

        //////////////////////////////////////////////////////////
        //        int[] sparseSdr = testSpatialPooler(sp, conn, encoding);
        //////////////////////////////////////////////////////////
        TemporalMemory tm = null;
        if (!RunLayer.SP_ONLY) {
            tm = new TemporalMemory();
            TemporalMemory.init(conn);
        }

        //////////////////////////////////////////////////////////
        // Tuple = (activeCells, predictiveCells)
        //        testTemporalMemory(tm, conn, sparseSdr);
        //////////////////////////////////////////////////////////

        //CLAClassifier cl = new CLAClassifier(new TIntArrayList(new int[] { 1 }), 0.1, 0.3, 0);

        //////////////////////////////////////////////////////////
        // Test Classifier Output
        // ...
        //////////////////////////////////////////////////////////

        Map<String, Object> params = new HashMap<>();
        params.put(KEY_MODE, Mode.PURE);
        params.put(KEY_WINDOW_SIZE, 0);
        params.put(KEY_USE_MOVING_AVG, false);

        Anomaly anomalyComputer = Anomaly.create(params);

        //////////////////////////////////////////////////////////
        // Test Anomaly Output
        // ...
        //////////////////////////////////////////////////////////

        MakeshiftLayer layer = new MakeshiftLayer(conn, encoder, sp, tm, null, anomalyComputer);
        return layer;
    }

    public static void printPreliminaryTestHeader() {
        System.out.println("--------------------------------------------");
        System.out.println("Prelimary Test of: Random, Encoder, SP, TM, Classifier, Anomaly: \n");
    }

    public static void testRandom(Random random) {
        for (int i = 0; i < 10; i++) {
            System.out.println("random[" + i + "] = " + random.nextInt());
        }

        for (int i = 0; i < 10; i++) {
            System.out.println("randomDbl[" + i + "] = " + random.nextDouble());
        }
    }

    public static int[] testEncoder(MultiEncoder encoder) {
        DateTime timestamp = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime("2014-04-01 00:00:00");
        double value = 20.0;

        Map<String, Object> d = new HashMap<String, Object>();
        d.put("value", value);
        d.put("timestamp", timestamp);
        int[] output = encoder.encode(d);
        System.out.println("ScalarEncoder Output = " + Arrays.toString(output));
        System.out.println("len = " + output.length);

        return output;
    }

    public static int[] testSpatialPooler(SpatialPooler sp, Connections conn, int[] encoding) {
        int[] dense = new int[2048];
        //sp.compute(conn, encoding, dense, true, true);
        int[] sparse = ArrayUtils.where(dense, ArrayUtils.WHERE_1);
        System.out.println("SP out = " + Arrays.toString(sparse));
        System.out.println("SP out len: " + sparse.length);
        System.out.println("");

        return sparse;
    }

    public static Tuple testTemporalMemory(TemporalMemory tm, Connections conn, int[] sparseSPOutput) {
        int[] expected = { 0, 87, 96, 128, 145, 151, 163, 180, 183, 218, 233, 242, 250, 260, 264, 289, 290, 303,
                312, 313, 334, 335, 337, 342, 346, 347, 353, 355, 356, 357, 365, 370, 376, 384, 385, 391, 392, 393,
                408, 481 };
        System.out.println("First SP Output Line == expected ? " + Arrays.equals(sparseSPOutput, expected));

        ComputeCycle cc = tm.compute(conn, sparseSPOutput, true);
        System.out.println("TM act out: " + Arrays.toString(SDR.asCellIndices(cc.activeCells())));
        System.out.println("TM act out: " + Arrays.toString(SDR.asCellIndices(cc.predictiveCells())));

        return new Tuple(cc.activeCells, cc.predictiveCells());
    }

    public static void loadSPOutputFile() {
        try (Stream<String> stream = Files.lines(Paths.get(MakeshiftLayer.readFile))) {
            MakeshiftLayer.input = stream.map(l -> {
                String line = l.replace("[", "").replace("]", "").trim();
                int[] result = Arrays.stream(line.split("[\\s]*\\,[\\s]*")).mapToInt(i -> Integer.parseInt(i))
                        .toArray();
                return result;
            }).collect(Collectors.toList());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void loadRawInputFile() {
        try (Stream<String> stream = Files.lines(Paths.get(MakeshiftLayer.INPUT_PATH))) {
            MakeshiftLayer.raw = stream.map(l -> l.trim()).collect(Collectors.toList());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        RunLayer.MakeshiftLayer layer = RunLayer.createLayer();

        System.out.println("\n===================================\n");

        loadSPOutputFile();
        loadRawInputFile();
        if (NETWORK) {
            for (int i = 0; i < MakeshiftLayer.input.size(); i++) {
                int[] sparseSPOutput = MakeshiftLayer.input.get(i);
                layer.networkStep(sparseSPOutput, LEARN);
            }
        } else if (TM_ONLY) {
            for (int i = 0; i < MakeshiftLayer.input.size(); i++) {
                layer.printHeader();
                int[] sparseSPOutput = MakeshiftLayer.input.get(i);
                Tuple tmTuple = layer.tmStep(sparseSPOutput, LEARN, IS_VERBOSE);
                double score = layer.anomalyStep(sparseSPOutput, (int[]) tmTuple.get(1), true);
                layer.incRecordNum();

                // Store the current prediction as previous
                layer.storeCyclePrediction((int[]) tmTuple.get(2));
            }
        } else if (SP_ONLY) {
            DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
            try (Stream<String> stream = Files.lines(Paths.get(MakeshiftLayer.INPUT_PATH))) {
                stream.skip(1).forEach(l -> {
                    String[] line = l.split("[\\s]*\\,[\\s]*");

                    DateTime timestamp = formatter.parseDateTime(line[0].trim());
                    double value = Double.parseDouble(line[1].trim());
                    layer.printHeader();
                    Tuple encTuple = layer.encodingStep(timestamp, value, IS_VERBOSE);
                    Tuple spTuple = layer.spStep((int[]) encTuple.get(0), LEARN, IS_VERBOSE);

                    layer.incRecordNum();
                    if (layer.recordNum == 200) {
                        System.exit(0);
                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
            try (Stream<String> stream = Files.lines(Paths.get(MakeshiftLayer.INPUT_PATH))) {
                stream.skip(1).forEach(l -> {
                    String[] line = l.split("[\\s]*\\,[\\s]*");
                    DateTime timestamp = formatter.parseDateTime(line[0].trim());
                    double value = Double.parseDouble(line[1].trim());
                    layer.printHeader();
                    Tuple encTuple = layer.encodingStep(timestamp, value, IS_VERBOSE);
                    Tuple spTuple = layer.spStep((int[]) encTuple.get(0), LEARN, IS_VERBOSE);
                    int[] spOutput = (int[]) spTuple.get(1);
                    Tuple tmTuple = layer.tmStep((int[]) spTuple.get(1), LEARN, IS_VERBOSE);
                    //Classification<Double> cla = layer.classificationStep((int[])tmTuple.get(0), (int)encTuple.get(1), value, LEARN, IS_VERBOSE);
                    double score = layer.anomalyStep(spOutput, layer.prevPredictedCols, IS_VERBOSE);

                    layer.incRecordNum();

                    // Store the current prediction as previous
                    layer.storeCyclePrediction((int[]) tmTuple.get(2));
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        System.out.println("--- " + ((System.currentTimeMillis() - start) / 1000d) + " seconds ---");
    }

}