Dump intermediate results to PNG images.

This commit is contained in:
2017-10-12 17:09:43 +02:00
parent 672649cfd0
commit 492d84fab0
8 changed files with 164 additions and 9 deletions

View File

@@ -41,4 +41,4 @@ target_link_libraries(fmri ${GLOG_LIBRARIES})
# Require png++
find_package(png++ REQUIRED)
include_directories(${png++_INCLUDE_DIRS})
target_link_libraries(fmri ${png++-LIBRARIES})
target_link_libraries(fmri ${png++_LIBRARIES})

View File

@@ -50,7 +50,7 @@ find_path(png++_INCLUDE_DIR
src)
set(png++_INCLUDE_DIRS ${png++_INCLUDE_DIR} ${PNG_INCLUDE_DIRS})
set(png++_LIBRARIES ${PNG_LIBRARIES})
set(png++_LIBRARY ${PNG_LIBRARIES})
find_package_handle_standard_args(png++ DEFAULT_MSG
png++_INCLUDE_DIR)

View File

@@ -17,7 +17,8 @@ Options:
-n (required) the model file to simulate
-w (required) the trained weights
-m means file. Will be substracted from input if available.
-l labels file. Will be used to print prediction labels if available.)END" << endl;
-l labels file. Will be used to print prediction labels if available.
-d Image dump dir. Will be filled with PNG images of intermediate results.)END" << endl;
exit(exitcode);
}
@@ -33,11 +34,12 @@ Options Options::parse(const int argc, char *const argv[]) {
string model;
string weights;
string means;
string dump;
string labels;
char c;
while ((c = getopt(argc, argv, "hm:w:n:l:")) != -1) {
while ((c = getopt(argc, argv, "hm:w:n:l:d:")) != -1) {
switch (c) {
case 'h':
show_help(argv[0], 0);
@@ -63,6 +65,10 @@ Options Options::parse(const int argc, char *const argv[]) {
labels = optarg;
break;
case 'd':
dump = optarg;
break;
case '?':
show_help(argv[0], 1);
break;
@@ -91,14 +97,15 @@ Options Options::parse(const int argc, char *const argv[]) {
show_help(argv[0], 1);
}
return Options(move(model), move(weights), move(means), move(labels), move(inputs));
return Options(move(model), move(weights), move(means), move(labels), move(dump), move(inputs));
}
Options::Options(string &&model, string &&weights, string&& means, string&& labels, vector<string> &&inputs) noexcept:
Options::Options(string &&model, string &&weights, string&& means, string&& labels, string&& dumpPath, vector<string> &&inputs) noexcept:
modelPath(move(model)),
weightsPath(move(weights)),
meansPath(means),
labelsPath(labels),
dumpPath(dumpPath),
inputPaths(move(inputs))
{
}
@@ -124,3 +131,8 @@ const string& Options::labels() const
{
return labelsPath;
}
const string &Options::imageDump() const
{
return dumpPath;
}

View File

@@ -16,6 +16,7 @@ namespace fmri {
const string& weights() const;
const string& means() const;
const string& labels() const;
const string& imageDump() const;
const vector<string>& inputs() const;
@@ -24,8 +25,9 @@ namespace fmri {
const string weightsPath;
const string meansPath;
const string labelsPath;
const string dumpPath;
const vector<string> inputPaths;
Options(string &&, string &&, string&&, string&&, vector<string> &&) noexcept;
Options(string &&, string &&, string&&, string&&, string&&, vector<string> &&) noexcept;
};
}

89
src/PNGDumper.cpp Normal file
View File

@@ -0,0 +1,89 @@
#include <cstring>
#include <glog/logging.h>
#include <sys/stat.h>
#include <png++/png.hpp>
#include "PNGDumper.hpp"
using namespace fmri;
using namespace std;
static void ensureDir(const string& dir)
{
struct stat s;
if (stat(dir.c_str(), &s) == 0) {
CHECK(S_ISDIR(s.st_mode)) << dir << " already exists and is not a directory." << endl;
return;
}
switch (errno) {
case ENOENT:
PCHECK(mkdir(dir.c_str(), 0777) == 0) << "Couldn't create directory";
return;
default:
perror("Unusable dump dir");
break;
}
}
PNGDumper::PNGDumper(string_view baseDir) :
baseDir_(baseDir)
{
ensureDir(baseDir_);
}
void PNGDumper::dump(const LayerData &layerData)
{
if (layerData.shape().size() == 4) {
// We have a series of images.
dumpImageSeries(layerData);
} else {
LOG(INFO) << "Unable to dump this type of layer to png.";
}
}
void PNGDumper::dumpImageSeries(const LayerData &layer)
{
const auto& shape = layer.shape();
const auto imagePixels = shape[2] * shape[3];
// Buffer for storing the current image data.
vector<DType> buffer(imagePixels);
auto data = layer.data();
for (int i = 0; i < shape[0]; ++i) {
for (int j = 0; j < shape[1]; ++j) {
memcpy(buffer.data(), data, imagePixels * sizeof(DType));
// advance the buffer;
data += imagePixels;
clamp(buffer.begin(), buffer.end(), 0.0, 255.0);
png::image<png::gray_pixel> image(shape[2], shape[3]);
for (int y = 0; y < shape[2]; ++y) {
for (int x = 0; x < shape[3]; ++x) {
image[x][y] = png::gray_pixel((int) buffer[x + y * shape[3]]);
}
}
image.write(getFilename(layer.name(), i, j));
}
}
}
string PNGDumper::getFilename(const string &layerName, int i, int j)
{
stringstream nameBuilder;
nameBuilder << baseDir_
<< "/" << layerName
<< "-" << i
<< "-" << j << ".png";
return nameBuilder.str();
}

28
src/PNGDumper.hpp Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <string_view>
#include "LayerData.hpp"
#include "utils.hpp"
namespace fmri
{
using std::string;
using std::string_view;
class PNGDumper
{
public:
PNGDumper(string_view baseDir);
void dump(const LayerData& layerData);
private:
const string baseDir_;
void dumpImageSeries(const LayerData &data);
string getFilename(const string &basic_string, int i, int j);
};
}

View File

@@ -1,8 +1,9 @@
#include <algorithm>
#include <iostream>
#include <memory>
#include "Options.hpp"
#include "Simulator.hpp"
#include "utils.hpp"
#include "PNGDumper.hpp"
using namespace std;
using namespace fmri;
@@ -12,10 +13,15 @@ int main(int argc, char *const argv[]) {
Options options = Options::parse(argc, argv);
vector<string> labels;
if (options.labels() != "") {
if (!options.labels().empty()) {
labels = read_vector<string>(options.labels());
}
unique_ptr<PNGDumper> pngDumper;
if (!options.imageDump().empty()) {
pngDumper.reset(new PNGDumper(options.imageDump()));
}
Simulator simulator(options.model(), options.weights(), options.means());
for (const auto &image : options.inputs()) {
@@ -33,6 +39,10 @@ int main(int argc, char *const argv[]) {
} else {
LOG(INFO) << "Best result: " << *(resultRow.data(), resultRow.data() + resultRow.numEntries()) << endl;
}
for (auto& layer : res) {
pngDumper->dump(layer);
}
}
google::ShutdownGoogleLogging();

View File

@@ -86,4 +86,18 @@ namespace fmri
return res;
}
template<class It>
void clamp(It begin, It end,
typename std::iterator_traits<It>::value_type minimum,
typename std::iterator_traits<It>::value_type maximum)
{
const auto extremes = std::minmax(begin, end);
const auto diff = *extremes.second - *extremes.first;
const auto offset = minimum - *extremes.first;
const auto scaling = diff / (maximum - minimum);
std::for_each(begin, end, [offset, scaling] (typename std::iterator_traits<It>::reference v) { v = (v + offset) * scaling;});
}
}