2008-05-15 12:35:56 +04:00
|
|
|
/*
|
|
|
|
* Data.cpp
|
2012-02-20 03:29:53 +04:00
|
|
|
* mert - Minimum Error Rate Training
|
2008-05-15 12:35:56 +04:00
|
|
|
*
|
|
|
|
* Created by Nicola Bertoldi on 13/05/08.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2011-11-14 14:52:21 +04:00
|
|
|
#include <algorithm>
|
2011-11-18 16:07:41 +04:00
|
|
|
#include "util/check.hh"
|
2011-11-14 10:15:30 +04:00
|
|
|
#include <cmath>
|
2008-05-15 12:35:56 +04:00
|
|
|
#include <fstream>
|
2011-09-15 21:45:35 +04:00
|
|
|
|
2011-11-12 06:44:39 +04:00
|
|
|
#include "Data.h"
|
|
|
|
#include "FileStream.h"
|
2008-05-15 12:35:56 +04:00
|
|
|
#include "Scorer.h"
|
2011-09-15 21:45:35 +04:00
|
|
|
#include "ScorerFactory.h"
|
2008-05-15 12:35:56 +04:00
|
|
|
#include "Util.h"
|
|
|
|
|
2011-11-14 07:20:04 +04:00
|
|
|
Data::Data()
|
|
|
|
: theScorer(NULL),
|
|
|
|
number_of_scores(0),
|
|
|
|
_sparse_flag(false),
|
2012-02-08 21:11:56 +04:00
|
|
|
scoredata(),
|
|
|
|
featdata() {}
|
2011-11-14 07:20:04 +04:00
|
|
|
|
2011-11-12 17:04:22 +04:00
|
|
|
Data::Data(Scorer& ptr)
|
|
|
|
: theScorer(&ptr),
|
|
|
|
score_type(theScorer->getName()),
|
|
|
|
number_of_scores(0),
|
|
|
|
_sparse_flag(false),
|
|
|
|
scoredata(new ScoreData(*theScorer)),
|
|
|
|
featdata(new FeatureData)
|
2008-05-15 12:35:56 +04:00
|
|
|
{
|
2011-02-24 15:42:19 +03:00
|
|
|
TRACE_ERR("Data::score_type " << score_type << std::endl);
|
|
|
|
TRACE_ERR("Data::Scorer type from Scorer: " << theScorer->getName() << endl);
|
2011-11-11 14:11:10 +04:00
|
|
|
}
|
|
|
|
|
2011-12-12 17:48:42 +04:00
|
|
|
//ADDED BY TS
|
|
|
|
void Data::remove_duplicates() {
|
|
|
|
|
2011-12-12 20:27:27 +04:00
|
|
|
size_t nSentences = featdata->size();
|
2011-12-12 17:48:42 +04:00
|
|
|
assert(scoredata->size() == nSentences);
|
|
|
|
|
2011-12-12 20:27:27 +04:00
|
|
|
for (size_t s=0; s < nSentences; s++) {
|
2011-12-12 17:48:42 +04:00
|
|
|
|
|
|
|
FeatureArray& feat_array = featdata->get(s);
|
|
|
|
ScoreArray& score_array = scoredata->get(s);
|
|
|
|
|
|
|
|
assert(feat_array.size() == score_array.size());
|
|
|
|
|
|
|
|
//serves as a hash-map:
|
2011-12-12 20:27:27 +04:00
|
|
|
std::map<double, std::vector<size_t> > lookup;
|
2011-12-12 17:48:42 +04:00
|
|
|
|
2011-12-12 20:27:27 +04:00
|
|
|
size_t end_pos = feat_array.size() - 1;
|
2011-12-12 17:48:42 +04:00
|
|
|
|
2011-12-12 20:27:27 +04:00
|
|
|
size_t nRemoved = 0;
|
|
|
|
for (size_t k=0; k <= end_pos; k++) {
|
2011-12-12 17:48:42 +04:00
|
|
|
|
|
|
|
const FeatureStats& cur_feats = feat_array.get(k);
|
|
|
|
|
|
|
|
double sum = 0.0;
|
2011-12-12 20:27:27 +04:00
|
|
|
for (size_t l=0; l < cur_feats.size(); l++)
|
2011-12-12 17:48:42 +04:00
|
|
|
sum += cur_feats.get(l);
|
|
|
|
|
|
|
|
if (lookup.find(sum) != lookup.end()) {
|
|
|
|
|
|
|
|
//std::cerr << "hit" << std::endl;
|
|
|
|
|
2011-12-12 20:27:27 +04:00
|
|
|
std::vector<size_t>& cur_list = lookup[sum];
|
2011-12-12 17:48:42 +04:00
|
|
|
|
2011-12-12 20:27:27 +04:00
|
|
|
size_t l=0;
|
2011-12-12 17:48:42 +04:00
|
|
|
for (l=0; l < cur_list.size(); l++) {
|
2012-03-07 02:01:28 +04:00
|
|
|
|
2011-12-12 20:27:27 +04:00
|
|
|
size_t j=cur_list[l];
|
2011-12-12 17:48:42 +04:00
|
|
|
|
|
|
|
if (cur_feats == feat_array.get(j)
|
|
|
|
&& score_array.get(k) == score_array.get(j)) {
|
|
|
|
|
|
|
|
if (k < end_pos) {
|
2012-03-07 02:01:28 +04:00
|
|
|
|
2011-12-12 17:48:42 +04:00
|
|
|
feat_array.swap(k,end_pos);
|
|
|
|
score_array.swap(k,end_pos);
|
2012-03-07 02:01:28 +04:00
|
|
|
|
2011-12-12 17:48:42 +04:00
|
|
|
k--;
|
|
|
|
}
|
2012-03-07 02:01:28 +04:00
|
|
|
|
2011-12-12 17:48:42 +04:00
|
|
|
end_pos--;
|
|
|
|
nRemoved++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l == lookup[sum].size())
|
|
|
|
cur_list.push_back(k);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lookup[sum].push_back(k);
|
|
|
|
|
2011-12-12 20:27:27 +04:00
|
|
|
// for (size_t j=0; j < k; j++) {
|
2011-12-12 17:48:42 +04:00
|
|
|
|
|
|
|
// if (feat_array.get(k) == feat_array.get(j)
|
|
|
|
// && score_array.get(k) == score_array.get(j)) {
|
|
|
|
|
|
|
|
// if (k < end_pos) {
|
|
|
|
|
|
|
|
// feat_array.swap(k,end_pos);
|
|
|
|
// score_array.swap(k,end_pos);
|
|
|
|
|
|
|
|
// k--;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// end_pos--;
|
|
|
|
// nRemoved++;
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (nRemoved > 0) {
|
|
|
|
|
|
|
|
feat_array.resize(end_pos+1);
|
|
|
|
score_array.resize(end_pos+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//END_ADDED
|
|
|
|
|
|
|
|
|
2008-05-15 12:35:56 +04:00
|
|
|
void Data::loadnbest(const std::string &file)
|
|
|
|
{
|
2011-02-24 15:42:19 +03:00
|
|
|
TRACE_ERR("loading nbest from " << file << std::endl);
|
2008-05-15 12:35:56 +04:00
|
|
|
|
2011-02-24 15:42:19 +03:00
|
|
|
ScoreStats scoreentry;
|
2008-05-15 12:35:56 +04:00
|
|
|
|
2011-02-24 15:42:19 +03:00
|
|
|
inputfilestream inp(file); // matches a stream with a file. Opens the file
|
2008-05-15 12:35:56 +04:00
|
|
|
|
2011-02-24 15:42:19 +03:00
|
|
|
if (!inp.good())
|
|
|
|
throw runtime_error("Unable to open: " + file);
|
2008-05-15 12:35:56 +04:00
|
|
|
|
2012-03-07 02:01:28 +04:00
|
|
|
std::string subsubstring, stringBuf;
|
|
|
|
std::string sentence_index, sentence, feature_str;
|
2011-02-24 15:42:19 +03:00
|
|
|
std::string::size_type loc;
|
2008-05-15 12:35:56 +04:00
|
|
|
|
2011-02-24 15:42:19 +03:00
|
|
|
while (getline(inp,stringBuf,'\n')) {
|
|
|
|
if (stringBuf.empty()) continue;
|
2011-11-12 04:24:19 +04:00
|
|
|
// adding statistics for error measures
|
2011-02-24 15:42:19 +03:00
|
|
|
scoreentry.clear();
|
|
|
|
|
2012-03-07 02:01:28 +04:00
|
|
|
getNextPound(stringBuf, sentence_index, "|||"); // first field
|
|
|
|
getNextPound(stringBuf, sentence, "|||"); // second field
|
|
|
|
getNextPound(stringBuf, feature_str, "|||"); // third field
|
2011-02-24 15:42:19 +03:00
|
|
|
|
2012-03-07 02:01:28 +04:00
|
|
|
theScorer->prepareStats(sentence_index, sentence, scoreentry);
|
2011-02-24 15:42:19 +03:00
|
|
|
scoredata->add(scoreentry, sentence_index);
|
|
|
|
|
2011-09-07 20:37:33 +04:00
|
|
|
// examine first line for name of features
|
2011-02-24 15:42:19 +03:00
|
|
|
if (!existsFeatureNames()) {
|
2012-03-07 02:01:28 +04:00
|
|
|
InitFeatureMap(feature_str);
|
2011-02-24 15:42:19 +03:00
|
|
|
}
|
2012-03-07 02:01:28 +04:00
|
|
|
AddFeatures(feature_str, sentence_index);
|
|
|
|
}
|
|
|
|
inp.close();
|
|
|
|
}
|
2011-02-24 15:42:19 +03:00
|
|
|
|
2012-03-07 02:01:28 +04:00
|
|
|
void Data::InitFeatureMap(const string& str) {
|
|
|
|
string buf = str;
|
|
|
|
string substr;
|
|
|
|
string features = "";
|
|
|
|
string tmp_name = "";
|
|
|
|
size_t tmp_index = 0;
|
|
|
|
string::size_type loc;
|
|
|
|
char tmp[64]; // for snprintf();
|
|
|
|
|
|
|
|
while (!buf.empty()) {
|
|
|
|
getNextPound(buf, substr);
|
|
|
|
|
|
|
|
// string ending with ":" are skipped, because they are the names of the features
|
|
|
|
if ((loc = substr.find_last_of(":")) != substr.length()-1) {
|
|
|
|
snprintf(tmp, sizeof(tmp), "%s_%lu ", tmp_name.c_str(), tmp_index);
|
|
|
|
features.append(tmp);
|
|
|
|
|
|
|
|
tmp_index++;
|
|
|
|
} else if (substr.find("_") != string::npos) {
|
|
|
|
// ignore sparse feature name and its value
|
|
|
|
getNextPound(buf, substr);
|
|
|
|
} else { // update current feature name
|
|
|
|
tmp_index = 0;
|
|
|
|
tmp_name = substr.substr(0, substr.size() - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
featdata->setFeatureMap(features);
|
|
|
|
}
|
2008-05-20 18:15:30 +04:00
|
|
|
|
2012-03-07 02:01:28 +04:00
|
|
|
void Data::AddFeatures(const string& str,
|
|
|
|
const string& sentence_index) {
|
|
|
|
string::size_type loc;
|
|
|
|
string buf = str;
|
|
|
|
string substr;
|
|
|
|
FeatureStats feature_entry;
|
|
|
|
feature_entry.reset();
|
|
|
|
|
|
|
|
while (!buf.empty()) {
|
|
|
|
getNextPound(buf, substr);
|
|
|
|
|
|
|
|
// no ':' -> feature value that needs to be stored
|
|
|
|
if ((loc = substr.find_last_of(":")) != substr.length()-1) {
|
|
|
|
feature_entry.add(ConvertStringToFeatureStatsType(substr));
|
|
|
|
} else if (substr.find("_") != string::npos) {
|
2011-09-07 20:37:33 +04:00
|
|
|
// sparse feature name? store as well
|
2012-03-07 02:01:28 +04:00
|
|
|
std::string name = substr;
|
|
|
|
getNextPound(buf, substr);
|
|
|
|
feature_entry.addSparse(name, atof(substr.c_str()));
|
|
|
|
_sparse_flag = true;
|
2011-02-24 15:42:19 +03:00
|
|
|
}
|
|
|
|
}
|
2012-03-07 02:01:28 +04:00
|
|
|
featdata->add(feature_entry, sentence_index);
|
2008-06-24 23:27:18 +04:00
|
|
|
}
|
|
|
|
|
2011-09-07 20:37:33 +04:00
|
|
|
// TODO
|
2011-11-12 04:24:19 +04:00
|
|
|
void Data::mergeSparseFeatures() {
|
2011-09-07 20:37:33 +04:00
|
|
|
std::cerr << "ERROR: sparse features can only be trained with pairwise ranked optimizer (PRO), not traditional MERT\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2011-09-15 21:45:35 +04:00
|
|
|
void Data::createShards(size_t shard_count, float shard_size, const string& scorerconfig,
|
2011-11-14 09:00:47 +04:00
|
|
|
std::vector<Data>& shards)
|
2011-09-15 21:45:35 +04:00
|
|
|
{
|
2011-11-18 16:07:41 +04:00
|
|
|
CHECK(shard_count);
|
|
|
|
CHECK(shard_size >= 0);
|
|
|
|
CHECK(shard_size <= 1);
|
2011-09-15 21:45:35 +04:00
|
|
|
|
|
|
|
size_t data_size = scoredata->size();
|
2011-11-18 16:07:41 +04:00
|
|
|
CHECK(data_size == featdata->size());
|
2011-09-15 21:45:35 +04:00
|
|
|
|
2011-11-14 09:00:47 +04:00
|
|
|
shard_size *= data_size;
|
2011-09-15 21:45:35 +04:00
|
|
|
|
|
|
|
for (size_t shard_id = 0; shard_id < shard_count; ++shard_id) {
|
|
|
|
vector<size_t> shard_contents;
|
|
|
|
if (shard_size == 0) {
|
|
|
|
//split into roughly equal size shards
|
2012-02-01 12:17:58 +04:00
|
|
|
const size_t shard_start = floor(0.5 + shard_id * static_cast<float>(data_size) / shard_count);
|
|
|
|
const size_t shard_end = floor(0.5 + (shard_id + 1) * static_cast<float>(data_size) / shard_count);
|
2011-09-15 21:45:35 +04:00
|
|
|
for (size_t i = shard_start; i < shard_end; ++i) {
|
|
|
|
shard_contents.push_back(i);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//create shards by randomly sampling
|
|
|
|
for (size_t i = 0; i < floor(shard_size+0.5); ++i) {
|
|
|
|
shard_contents.push_back(rand() % data_size);
|
|
|
|
}
|
|
|
|
}
|
2011-11-11 15:40:59 +04:00
|
|
|
|
|
|
|
Scorer* scorer = ScorerFactory::getScorer(score_type, scorerconfig);
|
2011-09-15 21:45:35 +04:00
|
|
|
|
|
|
|
shards.push_back(Data(*scorer));
|
|
|
|
shards.back().score_type = score_type;
|
|
|
|
shards.back().number_of_scores = number_of_scores;
|
|
|
|
shards.back()._sparse_flag = _sparse_flag;
|
|
|
|
for (size_t i = 0; i < shard_contents.size(); ++i) {
|
|
|
|
shards.back().featdata->add(featdata->get(shard_contents[i]));
|
|
|
|
shards.back().scoredata->add(scoredata->get(shard_contents[i]));
|
|
|
|
}
|
|
|
|
//cerr << endl;
|
|
|
|
}
|
|
|
|
}
|