Skip to content

Data Format

nyanp edited this page May 31, 2015 · 14 revisions

interfaces

Tiny-cnn has following interfaces to train networks.

template<typename LossFunction, typename Optimizer>
class network {
    ...
    /**
     * training conv-net
     *
     * @param in                 array of input data
     * @param t                  array of training signals(label or vector)
     * @param epoch              number of training epochs
     * @param on_batch_enumerate callback for each mini-batch enumerate
     * @param on_epoch_enumerate callback for each epoch 
     */
    template <typename OnBatchEnumerate, typename OnEpochEnumerate, typename T>
    void train(const std::vector<vec_t>& in,
               const std::vector<T>&     t,
               size_t                    batch_size,
               int                       epoch,
               OnBatchEnumerate          on_batch_enumerate,
               OnEpochEnumerate          on_epoch_enumerate);

    /**
     * training conv-net without callback
     **/
    template<typename T>
    void train(const std::vector<vec_t>& in,
               const std::vector<T>& t,
               size_t batch_size = 1,
               int epoch = 1);
    ...
};

"in" is array of input data, and "t" is array of training signal. Actual type of T depends on your task.

task T
classification label_t (typedef of size_t)
regression vec_t (typedef of std::vector<double>)
using namespace tiny_cnn;

void classification() {
    auto mlp = make_mlp<mse, adagrad, tan_h>({2, 10, 2});

    std::vector<vec_t> data = { {0.1, 0.9}, {0.9, 0.1} };
    std::vector<label_t> labels = { 1, 0 };

    mlp.train(data, labels); // T == label_t
}

void regression() {
    auto mlp = make_mlp<mse, adagrad, tan_h>({ 2, 10, 2 });

    std::vector<vec_t> data = { { 0.1, 0.9 }, { 0.9, 0.1 } };
    std::vector<vec_t> target = { { 0.3, 0.2 }, { 1.0, 0.0 } };

    mlp.train(data, target); // T == vec_t
}

If you want to train network by your original data, You have to convert your data to vec_t, i.e. std::vector<double>. If your input is image data, pixels should be organized by row-wise.

how to convert my data into vector?

Here are some examples.

1. using opencv (image file => vec_t)

#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
using namespace boost::filesystem;

// convert image to vec_t
void convert_image(const std::string& imagefilename,
                   double scale,
                   int w,
                   int h,
                   std::vector<vec_t>& data)
{
    auto img = cv::imread(imagefilename, cv::IMREAD_GRAYSCALE);
    if (img.data == nullptr) return; // cannot open, or it's not an image

    cv::Mat_<uint8_t> resized;
    cv::resize(img, resized, cv::Size(w, h));
    vec_t d;

    std::transform(resized.begin(), resized.end(), std::back_inserter(d),
                   [=](uint8_t c) { return c * scale; });
    data.push_back(d);
}

// convert all images found in directory to vec_t
void convert_images(const std::string& directory,
                    double scale,
                    int w,
                    int h,
                    std::vector<vec_t>& data)
{
    path dpath(directory);

    BOOST_FOREACH(const path& p, 
                  std::make_pair(directory_iterator(dpath), directory_iterator())) {
        if (is_directory(p)) continue;
        convert_image(p.string(), scale, w, h, data);
    }
}

Another example can be found in issue#16, which can treat color channels.

2. using mnisten (image file => idx format)

mnisten is a library to convert image files to idx format.

mnisten -d my_image_files_directory_name -o my_prefix -s 32x32

After generating idx files, you can use parse_mnist_images / parse_mnist_labels utilities in mnist_parser.h

3. from levelDB (caffe style => [vec_t, label_t])

Caffe supports levelDB data format. Following code can convert levelDB created by Caffe into data/label arrays.

#include "leveldb/db.h"

void convert_leveldb(const std::string& dbname,
                     double scale,
                     std::vector<vec_t>& data,
                     std::vector<label_t>& label)
{
    leveldb::DB *db;
    leveldb::Options options;
    options.create_if_missing = false;
    auto status = leveldb::DB::Open(options, dbname, &db);

    leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        const char* src = it->value().data();
        size_t sz = it->value().size();
        vec_t d;
        std::transform(src, src + sz - 1, std::back_inserter(d),
                       [=](char c){ return c * scale; });
        data.push_back(d);
        label.push_back(src[sz - 1]);
    }
    delete it;
    delete db;
}