Updated not incremental dictionary approach for save/reload (can set a database path as dictionary for convenience)

This commit is contained in:
matlabbe
2018-05-08 18:50:39 -04:00
parent 41e93ac6f0
commit bb0b12be27
7 changed files with 173 additions and 131 deletions

View File

@@ -155,7 +155,7 @@ public:
void executeNoResult(const std::string & sql) const;
// Load objects
void load(VWDictionary * dictionary) const;
void load(VWDictionary * dictionary, bool lastStateOnly = true) const;
void loadLastNodes(std::list<Signature *> & signatures) const;
void loadSignatures(const std::list<int> & ids, std::list<Signature *> & signatures, std::set<int> * loadedFromTrash = 0);
void loadWords(const std::set<int> & wordIds, std::list<VisualWord *> & vws);
@@ -255,7 +255,7 @@ private:
cv::Mat * textures) const = 0;
// Load objects
virtual void loadQuery(VWDictionary * dictionary) const = 0;
virtual void loadQuery(VWDictionary * dictionary, bool lastStateOnly = true) const = 0;
virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const = 0;
virtual void loadSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const = 0;
virtual void loadWordsQuery(const std::set<int> & wordIds, std::list<VisualWord *> & vws) const = 0;

View File

@@ -436,7 +436,7 @@ void DBDriver::saveOrUpdate(const std::vector<Signature *> & signatures)
void DBDriver::saveOrUpdate(const std::vector<VisualWord *> & words) const
{
ULOGGER_DEBUG("");
ULOGGER_DEBUG("words.size=%d", (int)words.size());
std::list<VisualWord *> toSave;
std::list<VisualWord *> toUpdate;
if(this->isConnected() && words.size())
@@ -511,10 +511,10 @@ void DBDriver::updateDepthImage(int nodeId, const cv::Mat & image)
_dbSafeAccessMutex.unlock();
}
void DBDriver::load(VWDictionary * dictionary) const
void DBDriver::load(VWDictionary * dictionary, bool lastStateOnly) const
{
_dbSafeAccessMutex.lock();
this->loadQuery(dictionary);
this->loadQuery(dictionary, lastStateOnly);
_dbSafeAccessMutex.unlock();
}

View File

@@ -3077,7 +3077,7 @@ void DBDriverSqlite3::loadLastNodesQuery(std::list<Signature *> & nodes) const
}
}
void DBDriverSqlite3::loadQuery(VWDictionary * dictionary) const
void DBDriverSqlite3::loadQuery(VWDictionary * dictionary, bool lastStateOnly) const
{
ULOGGER_DEBUG("");
if(_ppDb && dictionary)
@@ -3087,26 +3087,25 @@ void DBDriverSqlite3::loadQuery(VWDictionary * dictionary) const
timer.start();
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
std::string query;
std::stringstream query;
std::list<VisualWord *> visualWords;
// Get the visual words
if(uStrNumCmp(_version, "0.11.11") >= 0)
query << "SELECT id, descriptor_size, descriptor FROM Word ";
if(lastStateOnly)
{
query = "SELECT id, descriptor_size, descriptor "
"FROM Word "
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Info) "
"ORDER BY id;";
}
else
{
query = "SELECT id, descriptor_size, descriptor "
"FROM Word "
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics) "
"ORDER BY id;";
if(uStrNumCmp(_version, "0.11.11") >= 0)
{
query << "WHERE time_enter >= (SELECT MAX(time_enter) FROM Info) ";
}
else
{
query << "WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics) ";
}
}
query << "ORDER BY id;";
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
rc = sqlite3_prepare_v2(_ppDb, query.str().c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// Process the result if one

View File

@@ -124,7 +124,7 @@ private:
cv::Mat * textures) const;
// Load objects
virtual void loadQuery(VWDictionary * dictionary) const;
virtual void loadQuery(VWDictionary * dictionary, bool lastStateOnly = true) const;
virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const;
virtual void loadSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const;
virtual void loadWordsQuery(const std::set<int> & wordIds, std::list<VisualWord *> & vws) const;

View File

@@ -279,25 +279,32 @@ void Memory::loadDataFromDb(bool postInitClosingEvents)
}
UDEBUG("load words %d", (int)wordIds.size());
if(wordIds.size())
if(_vwd->isIncremental())
{
std::list<VisualWord*> words;
_dbDriver->loadWords(wordIds, words);
for(std::list<VisualWord*>::iterator iter = words.begin(); iter!=words.end(); ++iter)
if(wordIds.size())
{
_vwd->addWord(*iter);
std::list<VisualWord*> words;
_dbDriver->loadWords(wordIds, words);
for(std::list<VisualWord*>::iterator iter = words.begin(); iter!=words.end(); ++iter)
{
_vwd->addWord(*iter);
}
// Get Last word id
int id = 0;
_dbDriver->getLastWordId(id);
_vwd->setLastWordId(id);
}
// Get Last word id
int id = 0;
_dbDriver->getLastWordId(id);
_vwd->setLastWordId(id);
}
else
{
_dbDriver->load(_vwd, false);
}
}
else
{
UDEBUG("load words");
// load the last dictionary
_dbDriver->load(_vwd);
_dbDriver->load(_vwd, _vwd->isIncremental());
}
UDEBUG("%d words loaded!", _vwd->getUnusedWordsSize());
_vwd->update();
@@ -649,7 +656,10 @@ void Memory::parseParameters(const ParametersMap & parameters)
void Memory::preUpdate()
{
_signaturesAdded = 0;
this->cleanUnusedWords();
if(_vwd->isIncremental())
{
this->cleanUnusedWords();
}
if(_vwd && !_parallelized)
{
//When parallelized, it is done in CreateSignature
@@ -1584,7 +1594,7 @@ std::map<int, float> Memory::computeLikelihood(const Signature * signature, cons
{
// "Inverted index" - Pour chaque endroit contenu dans chaque mot
vw = _vwd->getWord(*i);
UASSERT(vw!=0);
UASSERT_MSG(vw!=0, uFormat("Word %d not found in dictionary!?", *i).c_str());
const std::map<int, int> & refs = vw->getReferences();
nw = refs.size();
@@ -2055,7 +2065,7 @@ void Memory::moveToTrash(Signature * s, bool keepLinkedToGraph, std::list<int> *
}
this->disableWordsRef(s->id());
if(!keepLinkedToGraph)
if(!keepLinkedToGraph && _vwd->isIncremental())
{
std::list<int> keys = uUniqueKeys(s->getWords());
for(std::list<int>::const_iterator i=keys.begin(); i!=keys.end(); ++i)
@@ -4217,25 +4227,22 @@ void Memory::disableWordsRef(int signatureId)
void Memory::cleanUnusedWords()
{
if(_vwd->isIncremental())
std::vector<VisualWord*> removedWords = _vwd->getUnusedWords();
UDEBUG("Removing %d words (dictionary size=%d)...", removedWords.size(), _vwd->getVisualWords().size());
if(removedWords.size())
{
std::vector<VisualWord*> removedWords = _vwd->getUnusedWords();
UDEBUG("Removing %d words (dictionary size=%d)...", removedWords.size(), _vwd->getVisualWords().size());
if(removedWords.size())
{
// remove them from the dictionary
_vwd->removeWords(removedWords);
// remove them from the dictionary
_vwd->removeWords(removedWords);
for(unsigned int i=0; i<removedWords.size(); ++i)
for(unsigned int i=0; i<removedWords.size(); ++i)
{
if(_dbDriver)
{
if(_dbDriver)
{
_dbDriver->asyncSave(removedWords[i]);
}
else
{
delete removedWords[i];
}
_dbDriver->asyncSave(removedWords[i]);
}
else
{
delete removedWords[i];
}
}
}
@@ -4270,6 +4277,11 @@ void Memory::enableWordsRef(const std::list<int> & signatureIds)
}
}
if(!_vwd->isIncremental() && oldWordIds.size())
{
UWARN("Dictionary is fixed, but some words retrieved have not been found!?");
}
UDEBUG("oldWordIds.size()=%d, getOldIds time=%fs", oldWordIds.size(), timer.ticks());
// the words were deleted, so try to math it with an active word

View File

@@ -142,79 +142,119 @@ void VWDictionary::setFixedDictionary(const std::string & dictionaryPath)
if((!_incrementalDictionary && _dictionaryPath.compare(dictionaryPath) != 0) ||
_visualWords.size() == 0)
{
std::ifstream file;
file.open(dictionaryPath.c_str(), std::ifstream::in);
if(file.good())
UDEBUG("incremental=%d, oldPath=%s newPath=%s, visual words=%d",
_incrementalDictionary?1:0, _dictionaryPath.c_str(), dictionaryPath.c_str(), (int)_visualWords.size());
if(UFile::getExtension(dictionaryPath).compare("db") == 0)
{
UDEBUG("Deleting old dictionary and loading the new one from \"%s\"", dictionaryPath.c_str());
UTimer timer;
// first line is the header
std::string str;
std::list<std::string> strList;
std::getline(file, str);
strList = uSplitNumChar(str);
unsigned int dimension = 0;
for(std::list<std::string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
UDEBUG("Loading fixed vocabulary \"%s\", this may take a while...", dictionaryPath.c_str());
DBDriver * driver = DBDriver::create();
if(driver->openConnection(dictionaryPath, false))
{
if(uIsDigit(iter->at(0)))
driver->load(this, false);
for(std::map<int, VisualWord*>::iterator iter=_visualWords.begin(); iter!=_visualWords.end(); ++iter)
{
dimension = std::atoi(iter->c_str());
break;
iter->second->setSaved(false);
}
}
if(dimension == 0 || dimension > 1000)
{
UERROR("Invalid dictionary file, visual word dimension (%d) is not valid, \"%s\"", dimension, dictionaryPath.c_str());
_incrementalDictionary = _visualWords.size()==0;
driver->closeConnection(false);
}
else
{
// Process all words
while(file.good())
{
std::getline(file, str);
strList = uSplit(str);
if(strList.size() == dimension+1)
{
//first one is the visual word id
std::list<std::string>::iterator iter = strList.begin();
int id = std::atoi(iter->c_str());
cv::Mat descriptor(1, dimension, CV_32F);
++iter;
unsigned int i=0;
//get descriptor
for(;i<dimension && iter != strList.end(); ++i, ++iter)
{
descriptor.at<float>(i) = uStr2Float(*iter);
}
if(i != dimension)
{
UERROR("");
}
VisualWord * vw = new VisualWord(id, descriptor, 0);
_visualWords.insert(_visualWords.end(), std::pair<int, VisualWord*>(id, vw));
_notIndexedWords.insert(_notIndexedWords.end(), id);
}
else
{
UWARN("Cannot parse line \"%s\"", str.c_str());
}
}
this->update();
_incrementalDictionary = false;
UERROR("Could not load dictionary from database %s", dictionaryPath.c_str());
}
UDEBUG("Time changing dictionary = %fs", timer.ticks());
delete driver;
}
else
{
UERROR("Cannot open dictionary file \"%s\"", dictionaryPath.c_str());
UWARN("Loading fixed vocabulary \"%s\", this may take a while...", dictionaryPath.c_str());
std::ifstream file;
file.open(dictionaryPath.c_str(), std::ifstream::in);
if(file.good())
{
UDEBUG("Deleting old dictionary and loading the new one from \"%s\"", dictionaryPath.c_str());
UTimer timer;
// first line is the header
std::string str;
std::list<std::string> strList;
std::getline(file, str);
strList = uSplitNumChar(str);
int dimension = 0;
for(std::list<std::string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
{
if(uIsDigit(iter->at(0)))
{
dimension = std::atoi(iter->c_str());
break;
}
}
UDEBUG("descriptor dimension = %d", dimension);
if(dimension <= 0 || dimension > 1000)
{
UERROR("Invalid dictionary file, visual word dimension (%d) is not valid, \"%s\"", dimension, dictionaryPath.c_str());
}
else
{
// Process all words
while(file.good())
{
std::getline(file, str);
strList = uSplit(str);
if(strList.size() == dimension+1)
{
//first one is the visual word id
std::list<std::string>::iterator iter = strList.begin();
int id = std::atoi(iter->c_str());
cv::Mat descriptor(1, dimension, CV_32F);
++iter;
int i=0;
//get descriptor
for(;i<dimension && iter != strList.end(); ++i, ++iter)
{
descriptor.at<float>(i) = uStr2Float(*iter);
}
if(i != dimension)
{
UERROR("Loaded word has not the same size (%d) than descriptor size previously detected (%d).", i, dimension);
}
VisualWord * vw = new VisualWord(id, descriptor, 0);
_visualWords.insert(_visualWords.end(), std::pair<int, VisualWord*>(id, vw));
_notIndexedWords.insert(_notIndexedWords.end(), id);
_unusedWords.insert(_unusedWords.end(), std::pair<int, VisualWord*>(id, vw));
}
else if(!str.empty())
{
UWARN("Cannot parse line \"%s\"", str.c_str());
}
}
if(_visualWords.size())
{
UWARN("Loaded %d words!", (int)_visualWords.size());
}
}
}
else
{
UERROR("Cannot open dictionary file \"%s\"", dictionaryPath.c_str());
}
file.close();
}
if(_visualWords.size() == 0)
{
_incrementalDictionary = _visualWords.size()==0;
UWARN("No words loaded, cannot set a fixed dictionary.", (int)_visualWords.size());
}
else
{
this->update();
_incrementalDictionary = false;
UDEBUG("Loaded %d words!", (int)_visualWords.size());
}
file.close();
}
else if(!_incrementalDictionary)
{
@@ -225,14 +265,14 @@ void VWDictionary::setFixedDictionary(const std::string & dictionaryPath)
UERROR("Cannot change to a fixed dictionary if there are already words (%d) in the incremental one.", _visualWords.size());
}
}
else if(_visualWords.size() == 0)
{
_incrementalDictionary = false;
}
else if(_incrementalDictionary)
else if(_incrementalDictionary && _visualWords.size())
{
UWARN("Cannot change to fixed dictionary, %d words already loaded as incremental", (int)_visualWords.size());
}
else
{
_incrementalDictionary = false;
}
_dictionaryPath = dictionaryPath;
}
@@ -568,7 +608,7 @@ void VWDictionary::addWordRef(int wordId, int signatureId)
}
else
{
UERROR("Not found word %d", wordId);
UERROR("Not found word %d (dict size=%d)", wordId, (int)_visualWords.size());
}
}
}
@@ -1220,26 +1260,17 @@ VisualWord * VWDictionary::getUnusedWord(int id) const
std::vector<VisualWord*> VWDictionary::getUnusedWords() const
{
if(!_incrementalDictionary)
{
ULOGGER_WARN("This method does nothing on a fixed dictionary");
return std::vector<VisualWord*>();
}
return uValues(_unusedWords);
}
std::vector<int> VWDictionary::getUnusedWordIds() const
{
if(!_incrementalDictionary)
{
ULOGGER_WARN("This method does nothing on a fixed dictionary");
return std::vector<int>();
}
return uKeys(_unusedWords);
}
void VWDictionary::removeWords(const std::vector<VisualWord*> & words)
{
UDEBUG("Removing %d words from dictionary (current size=%d)", (int)words.size(), (int)_visualWords.size());
for(unsigned int i=0; i<words.size(); ++i)
{
_visualWords.erase(words[i]->id());