Dump intermediate results to PNG images.
This commit is contained in:
@@ -41,4 +41,4 @@ target_link_libraries(fmri ${GLOG_LIBRARIES})
|
|||||||
# Require png++
|
# Require png++
|
||||||
find_package(png++ REQUIRED)
|
find_package(png++ REQUIRED)
|
||||||
include_directories(${png++_INCLUDE_DIRS})
|
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)
|
src)
|
||||||
|
|
||||||
set(png++_INCLUDE_DIRS ${png++_INCLUDE_DIR} ${PNG_INCLUDE_DIRS})
|
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
|
find_package_handle_standard_args(png++ DEFAULT_MSG
|
||||||
png++_INCLUDE_DIR)
|
png++_INCLUDE_DIR)
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ Options:
|
|||||||
-n (required) the model file to simulate
|
-n (required) the model file to simulate
|
||||||
-w (required) the trained weights
|
-w (required) the trained weights
|
||||||
-m means file. Will be substracted from input if available.
|
-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);
|
exit(exitcode);
|
||||||
}
|
}
|
||||||
@@ -33,11 +34,12 @@ Options Options::parse(const int argc, char *const argv[]) {
|
|||||||
string model;
|
string model;
|
||||||
string weights;
|
string weights;
|
||||||
string means;
|
string means;
|
||||||
|
string dump;
|
||||||
string labels;
|
string labels;
|
||||||
|
|
||||||
char c;
|
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) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
show_help(argv[0], 0);
|
show_help(argv[0], 0);
|
||||||
@@ -63,6 +65,10 @@ Options Options::parse(const int argc, char *const argv[]) {
|
|||||||
labels = optarg;
|
labels = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
dump = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
show_help(argv[0], 1);
|
show_help(argv[0], 1);
|
||||||
break;
|
break;
|
||||||
@@ -91,14 +97,15 @@ Options Options::parse(const int argc, char *const argv[]) {
|
|||||||
show_help(argv[0], 1);
|
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)),
|
modelPath(move(model)),
|
||||||
weightsPath(move(weights)),
|
weightsPath(move(weights)),
|
||||||
meansPath(means),
|
meansPath(means),
|
||||||
labelsPath(labels),
|
labelsPath(labels),
|
||||||
|
dumpPath(dumpPath),
|
||||||
inputPaths(move(inputs))
|
inputPaths(move(inputs))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -124,3 +131,8 @@ const string& Options::labels() const
|
|||||||
{
|
{
|
||||||
return labelsPath;
|
return labelsPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const string &Options::imageDump() const
|
||||||
|
{
|
||||||
|
return dumpPath;
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace fmri {
|
|||||||
const string& weights() const;
|
const string& weights() const;
|
||||||
const string& means() const;
|
const string& means() const;
|
||||||
const string& labels() const;
|
const string& labels() const;
|
||||||
|
const string& imageDump() const;
|
||||||
|
|
||||||
const vector<string>& inputs() const;
|
const vector<string>& inputs() const;
|
||||||
|
|
||||||
@@ -24,8 +25,9 @@ namespace fmri {
|
|||||||
const string weightsPath;
|
const string weightsPath;
|
||||||
const string meansPath;
|
const string meansPath;
|
||||||
const string labelsPath;
|
const string labelsPath;
|
||||||
|
const string dumpPath;
|
||||||
const vector<string> inputPaths;
|
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 <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
#include "Options.hpp"
|
#include "Options.hpp"
|
||||||
#include "Simulator.hpp"
|
#include "Simulator.hpp"
|
||||||
#include "utils.hpp"
|
#include "PNGDumper.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace fmri;
|
using namespace fmri;
|
||||||
@@ -12,10 +13,15 @@ int main(int argc, char *const argv[]) {
|
|||||||
|
|
||||||
Options options = Options::parse(argc, argv);
|
Options options = Options::parse(argc, argv);
|
||||||
vector<string> labels;
|
vector<string> labels;
|
||||||
if (options.labels() != "") {
|
if (!options.labels().empty()) {
|
||||||
labels = read_vector<string>(options.labels());
|
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());
|
Simulator simulator(options.model(), options.weights(), options.means());
|
||||||
|
|
||||||
for (const auto &image : options.inputs()) {
|
for (const auto &image : options.inputs()) {
|
||||||
@@ -33,6 +39,10 @@ int main(int argc, char *const argv[]) {
|
|||||||
} else {
|
} else {
|
||||||
LOG(INFO) << "Best result: " << *(resultRow.data(), resultRow.data() + resultRow.numEntries()) << endl;
|
LOG(INFO) << "Best result: " << *(resultRow.data(), resultRow.data() + resultRow.numEntries()) << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& layer : res) {
|
||||||
|
pngDumper->dump(layer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
google::ShutdownGoogleLogging();
|
google::ShutdownGoogleLogging();
|
||||||
|
|||||||
@@ -86,4 +86,18 @@ namespace fmri
|
|||||||
return res;
|
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