Dump intermediate results to PNG images.
This commit is contained in:
@@ -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})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
89
src/PNGDumper.cpp
Normal 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
28
src/PNGDumper.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
14
src/main.cpp
14
src/main.cpp
@@ -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();
|
||||
|
||||
@@ -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;});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user