From 203493ed26060af36b44d7b354b264cd95e5c02f Mon Sep 17 00:00:00 2001 From: Luiz Scheinkman Date: Sun, 8 Apr 2018 08:23:06 -0700 Subject: [PATCH 1/2] NUP-2506: Add missing state fields to serialization --- src/nupic/algorithms/Cells4.cpp | 227 ++++++++++++++++++++++-- src/nupic/algorithms/Segment.hpp | 1 + src/nupic/proto/Cells4.capnp | 15 +- src/test/unit/algorithms/Cells4Test.cpp | 110 +++++++++++- 4 files changed, 338 insertions(+), 15 deletions(-) diff --git a/src/nupic/algorithms/Cells4.cpp b/src/nupic/algorithms/Cells4.cpp index 2327d7d794..beb7c8a8d3 100644 --- a/src/nupic/algorithms/Cells4.cpp +++ b/src/nupic/algorithms/Cells4.cpp @@ -93,6 +93,15 @@ Cells4::~Cells4() { delete[] _tmpInputBuffer; } +//-------------------------------------------------------------------------------- +/** + * Simple helper function for allocating our numerous state variables + */ +template void allocateState(It *&state, const UInt numElmts) { + state = new It[numElmts]; + memset(state, 0, numElmts * sizeof(It)); +} + //-------------------------------------------------------------------------------- // Utility routines used in this file to print list of active columns and cell // indices @@ -1920,6 +1929,53 @@ void Cells4::write(Cells4Proto::Builder &proto) const { auto learnPredictedStateT1Proto = proto.initLearnPredictedStateT1(); _learnPredictedStateT1.write(learnPredictedStateT1Proto); + if (_ownsMemory) { + auto infActiveStateT = proto.initInfActiveStateT(); + _infActiveStateT.write(infActiveStateT); + auto infActiveStateT1 = proto.initInfActiveStateT1(); + _infActiveStateT1.write(infActiveStateT1); + + auto infPredictedStateT = proto.initInfPredictedStateT(); + _infPredictedStateT.write(infPredictedStateT); + auto infPredictedStateT1 = proto.initInfPredictedStateT1(); + _infPredictedStateT1.write(infPredictedStateT1); + + auto cellConfidenceT = proto.initCellConfidenceT(_nCells); + for (UInt i = 0; i < _nCells; ++i) { + cellConfidenceT.set(i, _cellConfidenceT[i]); + } + auto cellConfidenceT1 = proto.initCellConfidenceT1(_nCells); + for (UInt i = 0; i < _nCells; ++i) { + cellConfidenceT1.set(i, _cellConfidenceT1[i]); + } + auto colConfidenceT = proto.initColConfidenceT(_nColumns); + for (UInt i = 0; i < _nColumns; ++i) { + colConfidenceT.set(i, _colConfidenceT[i]); + } + auto colConfidenceT1 = proto.initColConfidenceT1(_nColumns); + for (UInt i = 0; i < _nColumns; ++i) { + colConfidenceT1.set(i, _colConfidenceT1[i]); + } + } + + auto prevInfPatterns = proto.initPrevInfPatterns(_prevInfPatterns.size()); + for (UInt i = 0; i < _prevInfPatterns.size(); ++i) { + const auto &pattern = _prevInfPatterns[i]; + auto row = prevInfPatterns.init(i, pattern.size()); + for (UInt j = 0; j < pattern.size(); j++) { + row.set(j, pattern[j]); + } + } + auto prevLrnPatterns = proto.initPrevLrnPatterns(_prevLrnPatterns.size()); + for (UInt i = 0; i < _prevLrnPatterns.size(); ++i) { + const auto &pattern = _prevLrnPatterns[i]; + auto row = prevLrnPatterns.init(i, pattern.size()); + for (UInt j = 0; j < pattern.size(); j++) { + row.set(j, pattern[j]); + } + } + + NTA_CHECK(_nCells == _cells.size()); auto cellListProto = proto.initCells(_nCells); for (UInt i = 0; i < _nCells; ++i) { auto cellProto = cellListProto[i]; @@ -1984,6 +2040,59 @@ void Cells4::read(Cells4Proto::Reader &proto) { _cells[i].read(cellProto); } + if (proto.getOwnsMemory()) { + _infActiveStateT.initialize(_nCells); + _infActiveStateT1.initialize(_nCells); + _infPredictedStateT.initialize(_nCells); + _infPredictedStateT1.initialize(_nCells); + auto infActiveStateT = proto.getInfActiveStateT(); + _infActiveStateT.read(infActiveStateT); + auto infActiveStateT1 = proto.getInfActiveStateT1(); + _infActiveStateT1.read(infActiveStateT1); + auto infPredictedStateT = proto.getInfPredictedStateT(); + _infPredictedStateT.read(infPredictedStateT); + auto infPredictedStateT1 = proto.getInfPredictedStateT1(); + _infPredictedStateT1.read(infPredictedStateT1); + + allocateState(_cellConfidenceT, _nCells); + allocateState(_cellConfidenceT1, _nCells); + allocateState(_colConfidenceT, _nColumns); + allocateState(_colConfidenceT1, _nColumns); + auto cellConfidenceT = proto.getCellConfidenceT(); + for (UInt i = 0; i < cellConfidenceT.size(); i++) { + _cellConfidenceT[i] = cellConfidenceT[i]; + } + auto cellConfidenceT1 = proto.getCellConfidenceT1(); + for (UInt i = 0; i < cellConfidenceT1.size(); i++) { + _cellConfidenceT1[i] = cellConfidenceT1[i]; + } + auto colConfidenceT = proto.getColConfidenceT(); + for (UInt i = 0; i < colConfidenceT.size(); i++) { + _colConfidenceT[i] = colConfidenceT[i]; + } + auto colConfidenceT1 = proto.getColConfidenceT1(); + for (UInt i = 0; i < colConfidenceT1.size(); i++) { + _colConfidenceT1[i] = colConfidenceT1[i]; + } + } + + _prevInfPatterns.clear(); + auto prevInfPatterns = proto.getPrevInfPatterns(); + for (UInt i = 0; i < prevInfPatterns.size(); i++) { + _prevInfPatterns.emplace_back(prevInfPatterns[i].size()); + for (UInt j = 0; j < prevInfPatterns[i].size(); j++) { + _prevInfPatterns[i][j] = prevInfPatterns[i][j]; + } + } + + _prevLrnPatterns.clear(); + auto prevLrnPatterns = proto.getPrevLrnPatterns(); + for (UInt i = 0; i < prevLrnPatterns.size(); i++) { + _prevLrnPatterns.emplace_back(prevLrnPatterns[i].size()); + for (UInt j = 0; j < prevLrnPatterns[i].size(); j++) { + _prevLrnPatterns[i][j] = prevLrnPatterns[i][j]; + } + } auto segmentUpdatesListProto = proto.getSegmentUpdates(); _segmentUpdates.clear(); _segmentUpdates.resize(segmentUpdatesListProto.size()); @@ -2006,7 +2115,7 @@ void Cells4::save(std::ostream &outStream) const { if (_checkSynapseConsistency || (_nCells * _maxSegmentsPerCell < 100000)) { NTA_CHECK(invariants(true)); } - + outStream.precision(std::numeric_limits::digits10); outStream << version() << " " << _ownsMemory << " " << _rng << " " << _nColumns << " " << _nCellsPerCol << " " << _activationThreshold << " " << _minThreshold << " " << _newSynapseCount << " " @@ -2036,10 +2145,37 @@ void Cells4::save(std::ostream &outStream) const { NTA_CHECK(_nCells == _cells.size()); for (UInt i = 0; i != _nCells; ++i) { _cells[i].save(outStream); + } + + if (_ownsMemory) { + outStream << _infActiveStateT << " " << _infActiveStateT1 << " " + << _infPredictedStateT << " " << _infPredictedStateT1 << " " + << std::endl; + for (UInt i = 0; i != _nCells; ++i) { + outStream << _cellConfidenceT[i] << " " << _cellConfidenceT1[i] << " "; + } + outStream << std::endl; + + for (UInt i = 0; i != _nColumns; ++i) { + outStream << _colConfidenceT[i] << " " << _colConfidenceT1[i] << " "; + } outStream << std::endl; } - outStream << " out "; + outStream << _prevLrnPatterns.size(); + for (auto &elem : _prevLrnPatterns) { + outStream << std::endl << elem.size() << " "; + std::copy(elem.begin(), elem.end(), + std::ostream_iterator(outStream, " ")); + } + outStream << std::endl << _prevInfPatterns.size(); + for (auto &elem : _prevInfPatterns) { + outStream << std::endl << elem.size() << " "; + std::copy(elem.begin(), elem.end(), + std::ostream_iterator(outStream, " ")); + } + + outStream << std::endl << "out" << std::endl; } //---------------------------------------------------------------------------- @@ -2121,8 +2257,8 @@ void Cells4::load(std::istream &inStream) { _learnPredictedStateT1.load(inStream); } + UInt n; if (v >= 2) { - UInt n; _segmentUpdates.clear(); inStream >> n; for (UInt i = 0; i < n; ++i) { @@ -2135,6 +2271,43 @@ void Cells4::load(std::istream &inStream) { _cells[i].load(inStream); } + if (_ownsMemory) { + _infActiveStateT.load(inStream); + _infActiveStateT1.load(inStream); + _infPredictedStateT.load(inStream); + _infPredictedStateT1.load(inStream); + + allocateState(_cellConfidenceT, _nCells); + allocateState(_cellConfidenceT1, _nCells); + allocateState(_colConfidenceT, _nColumns); + allocateState(_colConfidenceT1, _nColumns); + for (UInt i = 0; i != _nCells; ++i) { + inStream >> _cellConfidenceT[i] >> _cellConfidenceT1[i]; + } + for (UInt i = 0; i != _nColumns; ++i) { + inStream >> _colConfidenceT[i] >> _colConfidenceT1[i]; + } + } + inStream >> n; + std::vector pattern; + size_t size; + _prevLrnPatterns.clear(); + for (UInt i = 0; i < n; i++) { + pattern.clear(); + inStream >> size; + std::copy_n(std::istream_iterator(inStream), size, + std::back_inserter(pattern)); + _prevLrnPatterns.push_back(pattern); + } + inStream >> n; + _prevInfPatterns.clear(); + for (UInt i = 0; i < n; i++) { + pattern.clear(); + inStream >> size; + std::copy_n(std::istream_iterator(inStream), size, + std::back_inserter(pattern)); + _prevInfPatterns.push_back(pattern); + } std::string marker; inStream >> marker; NTA_CHECK(marker == "out"); @@ -2282,15 +2455,6 @@ void Cells4::updateSegment( _segmentUpdates.push_back(update); } -//-------------------------------------------------------------------------------- -/** - * Simple helper function for allocating our numerous state variables - */ -template void allocateState(It *&state, const UInt numElmts) { - state = new It[numElmts]; - memset(state, 0, numElmts * sizeof(It)); -} - void Cells4::setCellSegmentOrder(bool matchPythonOrder) { Cell::setSegmentOrder(matchPythonOrder); } @@ -2850,6 +3014,45 @@ bool Cells4::operator==(const Cells4 &other) const { if (_learnPredictedStateT1 != other._learnPredictedStateT1) { return false; } + if (_infActiveStateT != other._infActiveStateT) { + return false; + } + if (_infActiveStateT1 != other._infActiveStateT1) { + return false; + } + if (_infPredictedStateT != other._infPredictedStateT) { + return false; + } + if (_infPredictedStateT1 != other._infPredictedStateT1) { + return false; + } + if (_prevInfPatterns != other._prevInfPatterns) { + return false; + } + if (_prevLrnPatterns != other._prevLrnPatterns) { + return false; + } + if (_nCells > 0) { + if (memcmp(_cellConfidenceT, other._cellConfidenceT, + _nCells * sizeof(Real)) != 0) { + return false; + } + if (memcmp(_cellConfidenceT1, other._cellConfidenceT1, + _nCells * sizeof(Real)) != 0) { + return false; + } + } + if (_nColumns > 0) { + if (memcmp(_colConfidenceT, other._colConfidenceT, + _nColumns * sizeof(Real)) != 0) { + return false; + } + if (memcmp(_colConfidenceT1, other._colConfidenceT1, + _nColumns * sizeof(Real)) != 0) { + return false; + } + } + return true; } diff --git a/src/nupic/algorithms/Segment.hpp b/src/nupic/algorithms/Segment.hpp index df3386c8fc..93a2cc8329 100644 --- a/src/nupic/algorithms/Segment.hpp +++ b/src/nupic/algorithms/Segment.hpp @@ -314,6 +314,7 @@ class CStateIndexed : public CState { UInt nCellsOn; inStream >> nCellsOn; UInt v; + _cellsOn.clear(); for (UInt i = 0; i < nCellsOn; ++i) { inStream >> v; _cellsOn.push_back(v); diff --git a/src/nupic/proto/Cells4.capnp b/src/nupic/proto/Cells4.capnp index 045b3f7fd1..1d159c32d2 100644 --- a/src/nupic/proto/Cells4.capnp +++ b/src/nupic/proto/Cells4.capnp @@ -5,7 +5,7 @@ using import "/nupic/proto/RandomProto.capnp".RandomProto; using import "/nupic/proto/Segment.capnp".CStateProto; using import "/nupic/proto/SegmentUpdate.capnp".SegmentUpdateProto; -# Next ID: 39 +# Next ID: 49 struct Cells4Proto { version @0 :UInt16; ownsMemory @1 :Bool; @@ -50,6 +50,19 @@ struct Cells4Proto { learnPredictedStateT @35 :CStateProto; learnPredictedStateT1 @36 :CStateProto; + infActiveStateT @39 :CStateProto; + infActiveStateT1 @40 :CStateProto; + infPredictedStateT @41 :CStateProto; + infPredictedStateT1 @42 :CStateProto; + + cellConfidenceT @43 :List(Float32); + cellConfidenceT1 @44 :List(Float32); + colConfidenceT @45 :List(Float32); + colConfidenceT1 @46 :List(Float32); + + prevInfPatterns @47 :List(List(UInt32)); + prevLrnPatterns @48 :List(List(UInt32)); + cells @37 :List(CellProto); segmentUpdates @38 :List(SegmentUpdateProto); } diff --git a/src/test/unit/algorithms/Cells4Test.cpp b/src/test/unit/algorithms/Cells4Test.cpp index 011fbf4535..dcce9fa519 100644 --- a/src/test/unit/algorithms/Cells4Test.cpp +++ b/src/test/unit/algorithms/Cells4Test.cpp @@ -104,6 +104,81 @@ bool checkCells4Attributes(const Cells4 &c1, const Cells4 &c2) { return true; } +TEST(Cells4Test, pickleSerialization) { + Cells4 cells(10, 2, 1, 1, 1, 1, 0.5, 0.8, 1, 0.1, 0.1, 0, false, -1, true, + false); + std::vector input1(10, 0.0); + input1[1] = 1.0; + input1[4] = 1.0; + input1[5] = 1.0; + input1[9] = 1.0; + std::vector input2(10, 0.0); + input2[0] = 1.0; + input2[2] = 1.0; + input2[5] = 1.0; + input2[6] = 1.0; + std::vector input3(10, 0.0); + input3[1] = 1.0; + input3[3] = 1.0; + input3[6] = 1.0; + input3[7] = 1.0; + std::vector input4(10, 0.0); + input4[2] = 1.0; + input4[4] = 1.0; + input4[7] = 1.0; + input4[8] = 1.0; + std::vector output(10 * 2); + for (UInt i = 0; i < 10; ++i) { + cells.compute(&input1.front(), &output.front(), true, true); + cells.compute(&input2.front(), &output.front(), true, true); + cells.compute(&input3.front(), &output.front(), true, true); + cells.compute(&input4.front(), &output.front(), true, true); + cells.reset(); + } + + Cells4 secondCells; + { + std::stringstream ss; + cells.save(ss); + ss.seekg(0); + secondCells.load(ss); + } + ASSERT_TRUE(cells == secondCells); + + std::vector secondOutput(10 * 2); + cells.compute(&input1.front(), &output.front(), true, true); + secondCells.compute(&input1.front(), &secondOutput.front(), true, true); + ASSERT_TRUE(cells == secondCells); + + for (UInt i = 0; i < 10; ++i) { + ASSERT_EQ(output[i], secondOutput[i]) << "Outputs differ at index " << i; + } + + // Check serialization of cells4 before calling reset + cells.compute(&input1.front(), &output.front(), true, true); + cells.compute(&input2.front(), &output.front(), true, true); + cells.compute(&input3.front(), &output.front(), true, true); + cells.compute(&input4.front(), &output.front(), true, true); + + Cells4 secondCellsNoReset; + { + std::stringstream ss; + cells.save(ss); + ss.seekg(0); + secondCellsNoReset.load(ss); + } + ASSERT_TRUE(cells == secondCellsNoReset); + + cells.compute(&input1.front(), &output.front(), true, true); + secondCellsNoReset.compute(&input1.front(), &secondOutput.front(), true, + true); + ASSERT_TRUE(cells == secondCellsNoReset); + + for (UInt i = 0; i < 10; ++i) { + ASSERT_EQ(output[i], secondOutput[i]) << "Outputs differ at index " << i; + } +} + TEST(Cells4Test, capnpSerialization) { Cells4 cells(10, 2, 1, 1, 1, 1, 0.5, 0.8, 1, 0.1, 0.1, 0, false, -1, true, false); @@ -151,7 +226,7 @@ TEST(Cells4Test, capnpSerialization) { secondCells.read(cells4Reader); } - NTA_CHECK(checkCells4Attributes(cells, secondCells)); + ASSERT_TRUE(cells == secondCells); std::vector secondOutput(10 * 2); cells.compute(&input1.front(), &output.front(), true, true); @@ -159,7 +234,38 @@ TEST(Cells4Test, capnpSerialization) { for (UInt i = 0; i < 10; ++i) { ASSERT_EQ(output[i], secondOutput[i]) << "Outputs differ at index " << i; } - NTA_CHECK(checkCells4Attributes(cells, secondCells)); + ASSERT_TRUE(cells == secondCells); + + // Check serialization of cells4 before calling reset + cells.compute(&input1.front(), &output.front(), true, true); + cells.compute(&input2.front(), &output.front(), true, true); + cells.compute(&input3.front(), &output.front(), true, true); + cells.compute(&input4.front(), &output.front(), true, true); + + Cells4 secondCellsNoReset; + { + capnp::MallocMessageBuilder message1; + Cells4Proto::Builder cells4Builder = message1.initRoot(); + cells.write(cells4Builder); + std::stringstream ss; + kj::std::StdOutputStream out(ss); + capnp::writeMessage(out, message1); + + kj::std::StdInputStream in(ss); + capnp::InputStreamMessageReader message2(in); + Cells4Proto::Reader cells4Reader = message2.getRoot(); + secondCellsNoReset.read(cells4Reader); + } + + ASSERT_TRUE(cells == secondCellsNoReset); + + cells.compute(&input1.front(), &output.front(), true, true); + secondCellsNoReset.compute(&input1.front(), &secondOutput.front(), true, + true); + for (UInt i = 0; i < 10; ++i) { + ASSERT_EQ(output[i], secondOutput[i]) << "Outputs differ at index " << i; + } + ASSERT_TRUE(cells == secondCellsNoReset); } /* From cae1a4ce2e3a2607b5d93d4699e7a03f9903acc1 Mon Sep 17 00:00:00 2001 From: Luiz Scheinkman Date: Tue, 10 Apr 2018 10:02:05 -0700 Subject: [PATCH 2/2] Fix circleci buid --- ci/circle/before_install-osx.sh | 42 --------------------------------- circle.yml | 6 +++-- 2 files changed, 4 insertions(+), 44 deletions(-) delete mode 100755 ci/circle/before_install-osx.sh diff --git a/ci/circle/before_install-osx.sh b/ci/circle/before_install-osx.sh deleted file mode 100755 index 31f3728f82..0000000000 --- a/ci/circle/before_install-osx.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# ---------------------------------------------------------------------- -# Numenta Platform for Intelligent Computing (NuPIC) -# Copyright (C) 2013-5, 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/ -# ---------------------------------------------------------------------- - -echo -echo Running before_install-osx.sh... -echo - -#if [ $CC = 'gcc' ]; then -# export CC='gcc-4.8' -# export CXX='g++-4.8' -#fi - -#if [ $CC = 'clang' ]; then -# export CC='clang' -# export CXX='clang++' -#fi - -echo "Installing pip, setuptools, and wheel" -sudo pip install --upgrade pip -pip install --upgrade --user --ignore-installed setuptools wheel - -echo "Installing Python dependencies" -pip install --use-wheel --user -r bindings/py/requirements.txt --quiet || exit diff --git a/circle.yml b/circle.yml index 3d856fd3fd..c1d123f30d 100644 --- a/circle.yml +++ b/circle.yml @@ -11,7 +11,8 @@ machine: PATH: "$HOME/Library/Python/2.7/bin:$PATH" PYBIN: "$HOME/Library/Python/2.7/bin" pre: - - sudo pip install --ignore-installed --upgrade --verbose virtualenv + - curl https://bootstrap.pypa.io/get-pip.py | sudo -H python + - sudo -H pip install --ignore-installed --upgrade --verbose virtualenv # Link virtualenv to /usr/local/bin if it doesn't exist and always give exit status of 0. - "([ ! -e /usr/local/bin/virtualenv ] && ln -s ~/Library/Python/2.7/bin/virtualenv /usr/local/bin/virtualenv) || true" - if [[ "$OSTYPE" != "darwin"* ]]; then echo "Must set option to use OS X in CircleCI Web UI" && exit 1; fi @@ -19,7 +20,8 @@ machine: dependencies: override: # Install all dependencies - - ./ci/circle/before_install-osx.sh + - pip install --user --upgrade --verbose setuptools setuptools-scm + - pip install --use-wheel --no-cache-dir --user -r bindings/py/requirements.txt --verbose || exit compile: override: