From 176f311f6b4b2048dd05e0304d66ae5c61a4506e Mon Sep 17 00:00:00 2001
From: Patrick Simianer
Date: Fri, 8 Apr 2016 21:20:29 +0200
Subject: dtrain: adadelta, fix output, max input, batch learning
---
training/dtrain/dtrain.cc | 111 +++++++++++++++++++++++++++++++++++++++-------
training/dtrain/dtrain.h | 15 ++++++-
training/dtrain/update.h | 36 +++++++--------
3 files changed, 125 insertions(+), 37 deletions(-)
diff --git a/training/dtrain/dtrain.cc b/training/dtrain/dtrain.cc
index 3e9902ab..53e8cd50 100644
--- a/training/dtrain/dtrain.cc
+++ b/training/dtrain/dtrain.cc
@@ -41,6 +41,13 @@ main(int argc, char** argv)
const bool output_updates = output_updates_fn!="";
const string output_raw_fn = conf["output_raw"].as();
const bool output_raw = output_raw_fn!="";
+ const bool use_adadelta = conf["adadelta"].as();
+ const weight_t adadelta_decay = conf["adadelta_decay"].as();
+ const weight_t adadelta_eta = 0.000001;
+ const string adadelta_input = conf["adadelta_input"].as();
+ const string adadelta_output = conf["adadelta_output"].as();
+ const size_t max_input = conf["stop_after"].as();
+ const bool batch = conf["batch"].as();
// setup decoder
register_feature_functions();
@@ -89,8 +96,8 @@ main(int argc, char** argv)
vector > buffered_lengths; // (just once)
size_t input_sz = 0;
- cerr << setprecision(4);
// output configuration
+ cerr << fixed << setprecision(4);
cerr << "Parameters:" << endl;
cerr << setw(25) << "bitext " << "'" << input_fn << "'" << endl;
cerr << setw(25) << "k " << k << endl;
@@ -109,10 +116,10 @@ main(int argc, char** argv)
cerr << setw(25) << "chiang decay " << chiang_decay << endl;
cerr << setw(25) << "N " << N << endl;
cerr << setw(25) << "T " << T << endl;
- cerr << setw(25) << "learning rate " << eta << endl;
+ cerr << scientific << setw(25) << "learning rate " << eta << endl;
cerr << setw(25) << "margin " << margin << endl;
if (!structured) {
- cerr << setw(25) << "cut " << round(cut*100) << "%" << endl;
+ cerr << fixed << setw(25) << "cut " << round(cut*100) << "%" << endl;
cerr << setw(25) << "adjust " << adjust_cut << endl;
} else {
cerr << setw(25) << "struct. obj " << structured << endl;
@@ -124,7 +131,7 @@ main(int argc, char** argv)
if (noup)
cerr << setw(25) << "no up. " << noup << endl;
cerr << setw(25) << "average " << average << endl;
- cerr << setw(25) << "l1 reg. " << l1_reg << endl;
+ cerr << scientific << setw(25) << "l1 reg. " << l1_reg << endl;
cerr << setw(25) << "decoder conf " << "'"
<< conf["decoder_conf"].as() << "'" << endl;
cerr << setw(25) << "input " << "'" << input_fn << "'" << endl;
@@ -133,8 +140,17 @@ main(int argc, char** argv)
cerr << setw(25) << "weights in " << "'"
<< conf["input_weights"].as() << "'" << endl;
}
+ cerr << setw(25) << "batch " << batch << endl;
if (noup)
cerr << setw(25) << "no updates!" << endl;
+ if (use_adadelta) {
+ cerr << setw(25) << "adadelta " << use_adadelta << endl;
+ cerr << setw(25) << " decay " << adadelta_decay << endl;
+ if (adadelta_input != "")
+ cerr << setw(25) << "-input " << adadelta_input << endl;
+ if (adadelta_output != "")
+ cerr << setw(25) << "-output " << adadelta_output << endl;
+ }
cerr << "(1 dot per processed input)" << endl;
// meta
@@ -153,10 +169,23 @@ main(int argc, char** argv)
*out_up << setprecision(numeric_limits::digits10+1);
}
+ // adadelta
+ SparseVector gradient_accum, update_accum;
+ if (use_adadelta && adadelta_input!="") {
+ vector grads_tmp;
+ Weights::InitFromFile(adadelta_input+".gradient", &grads_tmp);
+ Weights::InitSparseVector(grads_tmp, &gradient_accum);
+ vector update_tmp;
+ Weights::InitFromFile(adadelta_input+".update", &update_tmp);
+ Weights::InitSparseVector(update_tmp, &update_accum);
+ }
for (size_t t = 0; t < T; t++) // T iterations
{
+ // batch update
+ SparseVector batch_update;
+
time_t start, end;
time(&start);
weight_t gold_sum=0., model_sum=0.;
@@ -194,6 +223,9 @@ main(int argc, char** argv)
next = ieffective_size;
if (output_raw)
- output_sample(sample, *out_raw, i);
+ output_sample(sample, out_raw, i);
// update model
if (!noup) {
@@ -233,21 +265,46 @@ main(int argc, char** argv)
SparseVector updates;
if (structured)
num_up += update_structured(sample, updates, margin,
- output_updates, *out_up, i);
+ out_up, i);
else if (all_pairs)
num_up += updates_all(sample, updates, max_up, threshold,
- output_updates, *out_up, i);
+ out_up, i);
else if (pro)
num_up += updates_pro(sample, updates, cut, max_up, threshold,
- output_updates, *out_up, i);
+ out_up, i);
else
num_up += updates_multipartite(sample, updates, cut, margin,
max_up, threshold, adjust_cut,
- output_updates, *out_up, i);
+ out_up, i);
+
SparseVector lambdas_copy;
if (l1_reg)
lambdas_copy = lambdas;
- lambdas.plus_eq_v_times_s(updates, eta);
+
+ if (use_adadelta) { // adadelta update
+ SparseVector squared;
+ for (auto it: updates)
+ squared[it.first] = pow(it.second, 2.0);
+ gradient_accum *= adadelta_decay;
+ squared *= 1.0-adadelta_decay;
+ gradient_accum += squared;
+ SparseVector u = gradient_accum + update_accum;
+ for (auto it: u)
+ u[it.first] = -1.0*(
+ sqrt(update_accum[it.first]+adadelta_eta)
+ /
+ sqrt(gradient_accum[it.first]+adadelta_eta)
+ ) * updates[it.first];
+ lambdas += u;
+ update_accum *= adadelta_decay;
+ for (auto it: u)
+ u[it.first] = pow(it.second, 2.0);
+ update_accum = update_accum + (u*(1.0-adadelta_decay));
+ } else if (batch) {
+ batch_update += updates;
+ } else { // regular update
+ lambdas.plus_eq_v_times_s(updates, eta);
+ }
// update context for Chiang's approx. BLEU
if (score_name == "chiang") {
@@ -290,23 +347,47 @@ main(int argc, char** argv)
if (t == 0)
input_sz = i; // remember size of input (# lines)
+ // batch
+ if (batch) {
+ batch_update /= (weight_t)num_up;
+ lambdas.plus_eq_v_times_s(batch_update, eta);
+ lambdas.init_vector(&decoder_weights);
+ }
+
// update average
if (average)
w_average += lambdas;
+ if (adadelta_output != "") {
+ WriteFile g(adadelta_output+".gradient.gz");
+ for (auto it: gradient_accum)
+ *g << FD::Convert(it.first) << " " << it.second << endl;
+ WriteFile u(adadelta_output+".update.gz");
+ for (auto it: update_accum)
+ *u << FD::Convert(it.first) << " " << it.second << endl;
+ }
+
// stats
weight_t gold_avg = gold_sum/(weight_t)input_sz;
- cerr << setiosflags(ios::showpos) << "WEIGHTS" << endl;
- for (auto name: print_weights)
+ cerr << setiosflags(ios::showpos) << scientific << "WEIGHTS" << endl;
+ for (auto name: print_weights) {
cerr << setw(18) << name << " = "
- << lambdas.get(FD::Convert(name)) << endl;
+ << lambdas.get(FD::Convert(name));
+ if (use_adadelta) {
+ weight_t rate = -1.0*(sqrt(update_accum[FD::Convert(name)]+adadelta_eta)
+ / sqrt(gradient_accum[FD::Convert(name)]+adadelta_eta));
+ cerr << " {" << rate << "}";
+ }
+ cerr << endl;
+ }
cerr << " ---" << endl;
cerr << resetiosflags(ios::showpos)
<< " 1best avg score: " << gold_avg*100;
- cerr << setiosflags(ios::showpos) << " ("
+ cerr << setiosflags(ios::showpos) << fixed << " ("
<< (gold_avg-gold_prev)*100 << ")" << endl;
- cerr << " 1best avg model score: "
+ cerr << scientific << " 1best avg model score: "
<< model_sum/(weight_t)input_sz << endl;
+ cerr << fixed;
cerr << " avg # updates: ";
cerr << resetiosflags(ios::showpos) << num_up/(float)input_sz << endl;
cerr << " non-0 feature count: " << lambdas.num_nonzero() << endl;
diff --git a/training/dtrain/dtrain.h b/training/dtrain/dtrain.h
index b07edfdf..ce5b2101 100644
--- a/training/dtrain/dtrain.h
+++ b/training/dtrain/dtrain.h
@@ -57,11 +57,18 @@ dtrain_init(int argc,
"learning rate [only meaningful if margin>0 or input weights are given]")
("l1_reg,r", po::value()->default_value(0.),
"l1 regularization strength [see Tsuruoka, Tsujii and Ananiadou (2009)]")
+ ("adadelta,D", po::bool_switch()->default_value(false),
+ "use AdaDelta dynamic learning rates")
+ ("adadelta_decay", po::value()->default_value(0.9),
+ "decay for AdaDelta algorithm")
+ ("adadelta_input", po::value()->default_value(""),
+ "input for AdaDelta's parameters, two files: file.gradient, and file.update")
+ ("adadelta_output", po::value()->default_value(""),
+ "prefix for outputting AdaDelta's parameters")
("margin,m", po::value()->default_value(1.0),
"margin for margin perceptron [set =0 for standard perceptron]")
("cut,u", po::value()->default_value(0.1),
- "use top/bottom 10% (default) of k-best as 'good' and 'bad' for \
-pair sampling, 0 to use all pairs TODO")
+ "use top/bottom 10% (default) of k-best as 'good' and 'bad' for pair sampling, 0 to use all pairs TODO")
("adjust,A", po::bool_switch()->default_value(false),
"adjust cut for optimal pos. in k-best to cut")
("score,s", po::value()->default_value("nakov"),
@@ -87,6 +94,8 @@ pair sampling, 0 to use all pairs TODO")
("max_pairs",
po::value()->default_value(numeric_limits::max()),
"max. number of updates/pairs")
+ ("batch,B", po::bool_switch()->default_value(false),
+ "perform batch updates")
("output,o", po::value()->default_value("-"),
"output weights file, '-' for STDOUT")
("disable_learning,X", po::bool_switch()->default_value(false),
@@ -95,6 +104,8 @@ pair sampling, 0 to use all pairs TODO")
"output updates (diff. vectors) [to filename]")
("output_raw,R", po::value()->default_value(""),
"output raw data (e.g. k-best lists) [to filename]")
+ ("stop_after", po::value()->default_value(numeric_limits::max()),
+ "only look at this number of segments")
("print_weights,P", po::value()->default_value("EgivenFCoherent SampleCountF CountEF MaxLexFgivenE MaxLexEgivenF IsSingletonF IsSingletonFE Glue WordPenalty PassThrough LanguageModel LanguageModel_OOV"),
"list of weights to print after each iteration");
po::options_description clopts("Command Line Options");
diff --git a/training/dtrain/update.h b/training/dtrain/update.h
index f6aa9842..405a3f76 100644
--- a/training/dtrain/update.h
+++ b/training/dtrain/update.h
@@ -20,9 +20,8 @@ updates_multipartite(vector* sample,
size_t max_up,
weight_t threshold,
bool adjust,
- bool output=false,
- ostream& os=cout,
- size_t id=0)
+ WriteFile& output,
+ size_t id)
{
size_t up = 0;
size_t sz = sample->size();
@@ -50,7 +49,7 @@ updates_multipartite(vector* sample,
|| (threshold && (first.gold-second.gold < threshold)))
continue;
if (output)
- os << id << "\t" << first.f-second.f << endl;
+ *output << id << "\t" << first.f-second.f << endl;
updates += first.f-second.f;
if (++up==max_up)
return up;
@@ -70,7 +69,7 @@ updates_multipartite(vector* sample,
|| (threshold && (first.gold-second.gold < threshold)))
continue;
if (output)
- os << id << "\t" << first.f-second.f << endl;
+ *output << id << "\t" << first.f-second.f << endl;
updates += first.f-second.f;
if (++up==max_up)
break;
@@ -91,9 +90,8 @@ updates_all(vector* sample,
SparseVector& updates,
size_t max_up,
weight_t threshold,
- bool output=false,
- ostream& os=cout,
- size_t id=0)
+ WriteFile output,
+ size_t id)
{
size_t up = 0;
size_t sz = sample->size();
@@ -108,7 +106,7 @@ updates_all(vector* sample,
|| (threshold && (first.gold-second.gold < threshold)))
continue;
if (output)
- os << id << "\t" << first.f-second.f << endl;
+ *output << id << "\t" << first.f-second.f << endl;
updates += first.f-second.f;
if (++up==max_up)
break;
@@ -127,9 +125,8 @@ inline size_t
update_structured(vector* sample,
SparseVector& updates,
weight_t margin,
- bool output=false,
- ostream& os=cout,
- size_t id=0)
+ WriteFile output,
+ size_t id)
{
// hope
sort(sample->begin(), sample->end(), [](Hyp first, Hyp second)
@@ -147,13 +144,13 @@ update_structured(vector* sample,
if (hope.gold != fear.gold) {
updates += hope.f - fear.f;
if (output)
- os << id << "\t" << hope.f << "\t" << fear.f << endl;
+ *output << id << "\t" << hope.f << "\t" << fear.f << endl;
return 1;
}
if (output)
- os << endl;
+ *output << endl;
return 0;
}
@@ -172,9 +169,8 @@ updates_pro(vector* sample,
size_t maxs,
size_t max_up,
weight_t threshold,
- bool output=false,
- ostream& os=cout,
- size_t id=0)
+ WriteFile& output,
+ size_t id)
{
size_t sz = sample->size(), s;
@@ -202,7 +198,7 @@ updates_pro(vector* sample,
for (auto i: g) {
if (output)
- os << id << "\t" << i.first->f-i.second->f << endl;
+ *output << id << "\t" << i.first->f-i.second->f << endl;
updates += i.first->f-i.second->f;
}
@@ -215,7 +211,7 @@ updates_pro(vector* sample,
*/
inline void
output_sample(vector* sample,
- ostream& os=cout,
+ WriteFile& output,
size_t id=0,
bool sorted=true)
{
@@ -227,7 +223,7 @@ output_sample(vector* sample,
}
size_t j = 0;
for (auto k: *sample) {
- os << id << "\t" << j << "\t" << k.gold << "\t" << k.model
+ *output << id << "\t" << j << "\t" << k.gold << "\t" << k.model
<< "\t" << k.f << endl;
j++;
}
--
cgit v1.2.3