Commit 0b81560a090350cda281c177e1daefe742b45717

Authored by Brendan Klare
2 parents 0ecab0f9 f60a7d57

Merge turk

openbr/core/plot.cpp
... ... @@ -219,6 +219,7 @@ bool Plot(const QStringList &files, const File &destination, bool show)
219 219 qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination));
220 220  
221 221 const bool minimalist = destination.getBool("minimalist");
  222 + const bool uncertainty = destination.get<bool>("uncertainty");
222 223  
223 224 // Use a br::file for simple storage of plot options
224 225 File cmcOpts;
... ... @@ -268,7 +269,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
268 269 QString(" + theme(aspect.ratio=1)\n\n")));
269 270  
270 271 p.file.write(qPrintable(QString("ggplot(CMC, aes(x=X, y=Y%1%2)) + ggtitle(\"%3\") + xlab(\"Rank\") + ylab(\"Retrieval Rate\")").arg(p.major.size > 1 ? QString(" ,colour=factor(%1)").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString(), cmcOpts.get<QString>("title",QString())) +
271   - QString(((p.major.smooth || p.minor.smooth) ? (minimalist ? " + stat_summary(geom=\"line\", fun.y=mean, size=%1)" : " + stat_summary(geom=\"line\", fun.y=min, aes(linetype=\"Min/Max\"), size=%1) + stat_summary(geom=\"line\", "
  272 + QString(((p.major.smooth || p.minor.smooth) ? (!uncertainty ? " + stat_summary(geom=\"line\", fun.y=mean, size=%1)" : " + stat_summary(geom=\"line\", fun.y=min, aes(linetype=\"Min/Max\"), size=%1) + stat_summary(geom=\"line\", "
272 273 "fun.y=max, aes(linetype=\"Min/Max\"), size=%1) + stat_summary(geom=\"line\", fun.y=mean, aes(linetype=\"Mean\"), size=%1) + scale_linetype_manual(\"Legend\", values=c(\"Mean\"=1, \"Min/Max\"=2))") : " + geom_line(size=%1)")).arg(QString::number(cmcOpts.get<float>("thickness",1))) +
273 274 (minimalist ? "" : " + scale_x_log10(labels=c(1,5,10,50,100), breaks=c(1,5,10,50,100)) + annotation_logticks(sides=\"b\")") +
274 275 (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
... ... @@ -283,7 +284,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
283 284 QString(", ylab=\"True Accept Rate%1\") + theme_minimal()").arg(p.minor.size > 1 ? " / " + p.minor.header : QString()) +
284 285 (p.major.size > 1 ? getScale("fill", p.major.header, p.major.size) : QString()) +
285 286 (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minor.header) : QString(" + facet_grid(. ~ X, labeller=far_labeller)")) +
286   - QString(" + scale_y_continuous(labels=percent) + theme(legend.position=\"none\", axis.text.x=element_text(angle=-90, hjust=0))%1").arg((p.major.smooth || p.minor.smooth) ? "" : " + geom_text(data=BC, aes(label=Y, y=0.05))\n\n")));
  287 + QString(" + scale_y_continuous(labels=percent) + theme(legend.position=\"none\", axis.text.x=element_text(angle=-90, hjust=0))%1").arg((p.major.smooth || p.minor.smooth) ? "" : " + geom_text(data=BC, aes(label=Y, y=0.05))") + "\n\n"));
287 288  
288 289 p.file.write(qPrintable(QString("qplot(X, Y, data=ERR%1, linetype=Error").arg((p.major.smooth || p.minor.smooth) ? ", geom=\"smooth\", method=loess, level=0.99" : ", geom=\"line\"") +
289 290 ((p.flip ? p.major.size : p.minor.size) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.major.header : p.minor.header) : QString()) +
... ...
openbr/plugins/misc.cpp
... ... @@ -366,6 +366,29 @@ BR_REGISTER(Transform, RegexPropertyTransform)
366 366  
367 367 /*!
368 368 * \ingroup transforms
  369 + * \brief Create matrix from metadata values.
  370 + * \author Josh Klontz \cite jklontz
  371 + */
  372 +class ExtractMetadataTransform : public UntrainableMetaTransform
  373 +{
  374 + Q_OBJECT
  375 + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
  376 + BR_PROPERTY(QStringList, keys, QStringList())
  377 +
  378 + void project(const Template &src, Template &dst) const
  379 + {
  380 + dst.file = src.file;
  381 + QList<float> values;
  382 + foreach (const QString &key, keys)
  383 + values.append(src.file.get<float>(key));
  384 + dst.append(OpenCVUtils::toMat(values, 1));
  385 + }
  386 +};
  387 +
  388 +BR_REGISTER(Transform, ExtractMetadataTransform)
  389 +
  390 +/*!
  391 + * \ingroup transforms
369 392 * \brief Store the last matrix of the input template as a metadata key with input property name.
370 393 * \author Charles Otto \cite caotto
371 394 */
... ...
openbr/plugins/output.cpp
... ... @@ -365,15 +365,22 @@ BR_REGISTER(Output, EmptyOutput)
365 365 class evalOutput : public MatrixOutput
366 366 {
367 367 Q_OBJECT
  368 + Q_PROPERTY(QString target READ get_target WRITE set_target RESET reset_target STORED false)
  369 + Q_PROPERTY(QString query READ get_query WRITE set_query RESET reset_query STORED false)
368 370 Q_PROPERTY(bool crossValidate READ get_crossValidate WRITE set_crossValidate RESET reset_crossValidate STORED false)
369 371 BR_PROPERTY(bool, crossValidate, true)
  372 + BR_PROPERTY(QString, target, QString())
  373 + BR_PROPERTY(QString, query, QString())
370 374  
371 375 ~evalOutput()
372 376 {
  377 + if (!target.isEmpty()) targetFiles = TemplateList::fromGallery(target).files();
  378 + if (!query.isEmpty()) queryFiles = TemplateList::fromGallery(query).files();
  379 +
373 380 if (data.data) {
374 381 const QString csv = QString(file.name).replace(".eval", ".csv");
375 382 if ((Globals->crossValidate == 0) || (!crossValidate)) {
376   - Evaluate(data,targetFiles, queryFiles, csv);
  383 + Evaluate(data, targetFiles, queryFiles, csv);
377 384 } else {
378 385 QFutureSynchronizer<float> futures;
379 386 for (int i=0; i<Globals->crossValidate; i++)
... ...
openbr/plugins/turk.cpp
... ... @@ -13,10 +13,6 @@ namespace br
13 13 class turkGallery : public Gallery
14 14 {
15 15 Q_OBJECT
16   - Q_PROPERTY(bool flat READ get_flat WRITE set_flat RESET reset_flat STORED false)
17   - Q_PROPERTY(bool normalize READ get_normalize WRITE set_normalize RESET reset_normalize STORED false)
18   - BR_PROPERTY(bool, flat, false)
19   - BR_PROPERTY(bool, normalize, false)
20 16  
21 17 struct Attribute : public QStringList
22 18 {
... ... @@ -40,7 +36,8 @@ class turkGallery : public Gallery
40 36 }
41 37  
42 38 Attribute normal(name);
43   - const float sum = Common::Sum(values);
  39 + float sum = Common::Sum(values);
  40 + if (sum == 0) sum = 1;
44 41 for (int i=0; i<values.size(); i++)
45 42 normal.append(QString::number(values[i] / sum));
46 43 return normal;
... ... @@ -50,38 +47,28 @@ class turkGallery : public Gallery
50 47 TemplateList readBlock(bool *done)
51 48 {
52 49 *done = true;
53   - TemplateList templates;
54 50 QStringList lines = QtUtils::readLines(file);
55   - if (lines.empty())
56   - qFatal(".turk Gallery missing header.");
57   - QList<Attribute> types;
58   - foreach (const QString &header, parse(lines.takeFirst()))
59   - types.append(header);
  51 + QList<Attribute> headers;
  52 + if (!lines.isEmpty())
  53 + foreach (const QString &header, parse(lines.takeFirst()))
  54 + headers.append(header);
60 55  
  56 + TemplateList templates;
61 57 foreach (const QString &line, lines) {
62   - const QStringList words = parse(line);
63   - if (words.size() != types.size())
64   - qFatal(".turk Gallery incorrect column count.");
65   -
66   - File f(words[0], words[0].mid(0,5));
67   - for (int i=1; i<words.size(); i++) {
68   - Attribute &type = types[i];
69   - Attribute rating(words[i]);
70   - if (type.size() != rating.size())
71   - qFatal(".turk Gallery incorrect ratings count.");
  58 + QStringList words = parse(line);
  59 + if (words.size() != headers.size())
  60 + qFatal("turkGallery invalid column count");
72 61  
73   - if (normalize)
74   - rating = rating.normalized();
  62 + File f;
  63 + f.name = words[0];
  64 + f.set("Label", words[0].mid(0,5));
75 65  
76   - if (flat) {
77   - for (int j=0; j<type.size(); j++)
78   - f.set(type.name + "_" + type[j], rating[j]);
79   - } else {
80   - QMap<QString,QVariant> categoryMap;
81   - for (int j=0; j<type.size(); j++)
82   - categoryMap.insert(type[j], rating[j]);
83   - f.set(type.name, categoryMap);
84   - }
  66 + for (int i=1; i<words.size(); i++) {
  67 + Attribute ratings = Attribute(words[i]).normalized();
  68 + if (headers[i].size() != ratings.size())
  69 + qFatal("turkGallery invalid attribute count");
  70 + for (int j=0; j<ratings.size(); j++)
  71 + f.set(headers[i].name + "_" + headers[i][j], ratings[j]);
85 72 }
86 73 templates.append(f);
87 74 }
... ... @@ -97,58 +84,6 @@ class turkGallery : public Gallery
97 84  
98 85 BR_REGISTER(Gallery, turkGallery)
99 86  
100   -static Template unmap(const Template &t, const QString& variable, const float maxVotes, const float maxRange, const float minRange, const bool classify, const bool consensusOnly) {
101   - // Create a new template matching the one containing the votes in the map structure
102   - // but remove the map structure
103   - Template expandedT = t;
104   - expandedT.file.remove(variable);
105   -
106   - QMap<QString,QVariant> map = t.file.get<QMap<QString,QVariant> >(variable);
107   - QMapIterator<QString, QVariant> i(map);
108   - bool ok;
109   -
110   - while (i.hasNext()) {
111   - i.next();
112   - // Normalize to [minRange,maxRange]
113   - float value = i.value().toFloat(&ok)*(maxRange-minRange)/maxVotes - minRange;
114   - if (!ok) qFatal("Failed to expand Turk votes for %s", qPrintable(variable));
115   - if (classify) (value > maxRange-((maxRange-minRange)/2)) ? value = maxRange : value = minRange;
116   - else if (consensusOnly && (value != maxRange && value != minRange)) continue;
117   - expandedT.file.set(i.key(),value);
118   - }
119   -
120   - return expandedT;
121   -}
122   -
123   -/*!
124   - * \ingroup transforms
125   - * \brief Converts Amazon MTurk labels to a non-map format for use in a transform
126   - * \author Scott Klum \cite sklum
127   - */
128   -class TurkTransform : public UntrainableTransform
129   -{
130   - Q_OBJECT
131   - Q_PROPERTY(QString HIT READ get_HIT WRITE set_HIT RESET reset_HIT STORED false)
132   - Q_PROPERTY(float maxVotes READ get_maxVotes WRITE set_maxVotes RESET reset_maxVotes STORED false)
133   - Q_PROPERTY(float maxRange READ get_maxRange WRITE set_maxRange RESET reset_maxRange STORED false)
134   - Q_PROPERTY(float minRange READ get_minRange WRITE set_minRange RESET reset_minRange STORED false)
135   - Q_PROPERTY(bool classify READ get_classify WRITE set_classify RESET reset_classify STORED false)
136   - Q_PROPERTY(bool consensusOnly READ get_consensusOnly WRITE set_consensusOnly RESET reset_consensusOnly STORED false)
137   - BR_PROPERTY(QString, HIT, QString())
138   - BR_PROPERTY(float, maxVotes, 1)
139   - BR_PROPERTY(float, maxRange, 1)
140   - BR_PROPERTY(float, minRange, 0)
141   - BR_PROPERTY(bool, classify, false)
142   - BR_PROPERTY(bool, consensusOnly, false)
143   -
144   - void project(const Template &src, Template &dst) const
145   - {
146   - dst = unmap(src, HIT, maxVotes, maxRange, minRange, classify, consensusOnly);
147   - }
148   -};
149   -
150   -BR_REGISTER(Transform, TurkTransform)
151   -
152 87 /*!
153 88 * \ingroup transforms
154 89 * \brief Convenience class for training turk attribute regressors
... ... @@ -159,27 +94,21 @@ class TurkClassifierTransform : public Transform
159 94 Q_OBJECT
160 95 Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key STORED false)
161 96 Q_PROPERTY(QStringList values READ get_values WRITE set_values RESET reset_values STORED false)
162   - Q_PROPERTY(float maxVotes READ get_maxVotes WRITE set_maxVotes RESET reset_maxVotes STORED false)
163 97 Q_PROPERTY(bool isMeta READ get_isMeta WRITE set_isMeta RESET reset_isMeta STORED false)
164 98 BR_PROPERTY(QString, key, QString())
165 99 BR_PROPERTY(QStringList, values, QStringList())
166   - BR_PROPERTY(float, maxVotes, 1)
167 100 BR_PROPERTY(bool, isMeta, false)
168 101  
169 102 Transform *child;
170 103  
171 104 void init()
172 105 {
173   - QString algorithm = QString("Turk(%1, %2)+").arg(key, QString::number(maxVotes));
174 106 QStringList classifiers;
175 107 foreach (const QString &value, values)
176   - classifiers.append(QString("SVM(RBF,EPS_SVR,returnDFVal=true,inputVariable=%1,outputVariable=predicted_%1)").arg(value));
177   - algorithm += classifiers.join("/");
178   - if (values.size() > 1)
179   - algorithm += "+Cat";
  108 + classifiers.append(QString("SVM(RBF,EPS_SVR,returnDFVal=true,inputVariable=%1,outputVariable=predicted_%1)").arg(key + "_" + value));
  109 + child = Transform::make(classifiers.join("/") + (classifiers.size() > 1 ? "+Cat" : ""));
180 110 if (isMeta)
181 111 algorithm += QsString("+Average+SaveMat(predicted_%1)").arg(value);
182   - child = Transform::make(algorithm);
183 112 }
184 113  
185 114 void train(const QList<TemplateList> &data)
... ... @@ -206,44 +135,6 @@ class TurkClassifierTransform : public Transform
206 135 BR_REGISTER(Transform, TurkClassifierTransform)
207 136  
208 137 /*!
209   - * \ingroup transforms
210   - * \brief Converts metadata into a map structure
211   - * \author Scott Klum \cite sklum
212   - */
213   -class MapTransform : public UntrainableTransform
214   -{
215   - Q_OBJECT
216   - Q_PROPERTY(QStringList inputVariables READ get_inputVariables WRITE set_inputVariables RESET reset_inputVariables STORED false)
217   - Q_PROPERTY(QString outputVariable READ get_outputVariable WRITE set_outputVariable RESET reset_outputVariable STORED false)
218   - BR_PROPERTY(QStringList, inputVariables, QStringList())
219   - BR_PROPERTY(QString, outputVariable, QString())
220   -
221   - void project(const Template &src, Template &dst) const
222   - {
223   - dst = map(src);
224   - }
225   -
226   - Template map(const Template &t) const {
227   - Template mappedT = t;
228   - QMap<QString,QVariant> map;
229   -
230   - foreach(const QString &s, inputVariables) {
231   - if (t.file.contains(s)) {
232   - map.insert(s,t.file.value(s));
233   - mappedT.file.remove(s);
234   - }
235   - }
236   -
237   - if (!map.isEmpty()) mappedT.file.set(outputVariable,map);
238   -
239   - return mappedT;
240   - }
241   -};
242   -
243   -BR_REGISTER(Transform, MapTransform)
244   -
245   -
246   -/*!
247 138 * \ingroup distances
248 139 * \brief Unmaps Turk HITs to be compared against query mats
249 140 * \author Scott Klum \cite sklum
... ... @@ -251,33 +142,17 @@ BR_REGISTER(Transform, MapTransform)
251 142 class TurkDistance : public Distance
252 143 {
253 144 Q_OBJECT
254   - Q_PROPERTY(QString HIT READ get_HIT WRITE set_HIT RESET reset_HIT)
255   - Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false)
256   - Q_PROPERTY(float maxVotes READ get_maxVotes WRITE set_maxVotes RESET reset_maxVotes STORED false)
257   - Q_PROPERTY(float maxRange READ get_maxRange WRITE set_maxRange RESET reset_maxRange STORED false)
258   - Q_PROPERTY(float minRange READ get_minRange WRITE set_minRange RESET reset_minRange STORED false)
259   - Q_PROPERTY(bool classify READ get_classify WRITE set_classify RESET reset_classify STORED false)
260   - Q_PROPERTY(bool consensusOnly READ get_consensusOnly WRITE set_consensusOnly RESET reset_consensusOnly STORED false)
261   - BR_PROPERTY(QString, HIT, QString())
262   - BR_PROPERTY(QStringList, keys, QStringList())
263   - BR_PROPERTY(float, maxVotes, 1)
264   - BR_PROPERTY(float, maxRange, 1)
265   - BR_PROPERTY(float, minRange, 0)
266   - BR_PROPERTY(bool, classify, false)
267   - BR_PROPERTY(bool, consensusOnly, false)
  145 + Q_PROPERTY(QString key READ get_key WRITE set_key RESET reset_key)
  146 + Q_PROPERTY(QStringList values READ get_values WRITE set_values RESET reset_values STORED false)
  147 + BR_PROPERTY(QString, key, QString())
  148 + BR_PROPERTY(QStringList, values, QStringList())
268 149  
269 150 float compare(const Template &target, const Template &query) const
270 151 {
271   - Template t = unmap(target, HIT, maxVotes, maxRange, minRange, classify, consensusOnly);
272   -
273   - QList<float> targetValues;
274   - foreach(const QString &s, keys) targetValues.append(t.file.get<float>(s));
275   -
276   - float stddev = .75;
277   -
  152 + const float stddev = .75;
278 153 float score = 0;
279   - for (int i=0; i<targetValues.size(); i++) score += 1/(stddev*sqrt(2*CV_PI))*exp(-0.5*pow((query.m().at<float>(0,i)-targetValues[i])/stddev, 2));
280   -
  154 + for (int i=0; i<values.size(); i++)
  155 + score += 1 / (stddev*sqrt(2*CV_PI)) * exp(-0.5*pow((query.m().at<float>(0,i)-target.file.get<float>(key + "_" + values[i]))/stddev, 2));
281 156 return score;
282 157 }
283 158 };
... ...