19#include "tiny-dnn/tiny_dnn/tiny_dnn.h"
24#include <opencv2/imgproc/imgproc.hpp>
27#include <opencv2/imgcodecs/imgcodecs.hpp>
29#include <opencv2/highgui/highgui.hpp>
47 using conv = tiny_dnn::convolutional_layer;
48 using pool = tiny_dnn::max_pooling_layer;
49 using fc = tiny_dnn::fully_connected_layer;
50 using relu = tiny_dnn::relu_layer;
51 using softmax = tiny_dnn::softmax_layer;
53 const size_t n_fmaps = 10;
54 const size_t n_fc = 64;
55 int const n_categ = 5;
57 (*net) << conv(32, 32, 5, 3, n_fmaps, tiny_dnn::padding::same)
58 << pool(32, 32, n_fmaps, 2)
59 << relu(16, 16, n_fmaps)
60 << conv(16, 16, 5, n_fmaps, n_fmaps * 2, tiny_dnn::padding::same)
61 << pool(16, 16, n_fmaps * 2, 2)
62 << relu(8, 8, n_fmaps)
63 << conv(8, 8, 5, n_fmaps * 2, n_fmaps * 4, tiny_dnn::padding::same)
64 << pool(8, 8, n_fmaps * 4, 2)
65 << relu(4, 4, n_fmaps * 42)
66 << fc(4 * 4 * n_fmaps * 4, n_fc)
67 << fc(n_fc, n_categ) << softmax(n_categ);
73 void load_compiled(std::string
const & fname, std::vector<tiny_dnn::label_t> & labels,
74 std::vector<tiny_dnn::vec_t> & images)
76 float const scale_min = -1.0F;
77 float const scale_max = 1.0F;
78 int const w = 32,
h = 32;
80 std::ifstream ifs(fname, std::ios::in | std::ios::binary);
81 if (ifs.is_open() ==
false)
LFATAL(
"Failed to open load " << fname);
88 std::ifstream file(fname, std::ios::binary | std::ios::ate);
89 siz = file.tellg() / (w *
h * 3 + 1);
90 LINFO(
"File has " << siz <<
" entries");
93 std::vector<size_t> idx;
for (
size_t i = 0; i < siz; ++i) idx.push_back(i);
94 std::random_shuffle(idx.begin(), idx.end());
95 labels.resize(siz); images.resize(siz);
98 std::vector<unsigned char> buf(w * h * 3);
100 for (
size_t i = 0; i < siz; ++i)
102 unsigned char label; ifs.read((
char *)(&label), 1);
103 if (!ifs)
LFATAL(
"Error reading " << fname);
104 labels[idx[i]] = label;
106 ifs.read((
char *)(&buf[0]), buf.size());
107 if (!ifs)
LFATAL(
"Error reading " << fname);
110 std::transform(buf.begin(), buf.end(), std::back_inserter(img),
111 [&](
unsigned char c) { return scale_min + (scale_max - scale_min) * c / 255.0F; });
113 images[idx[i]] = img;
116 LINFO(
"Loaded " << siz <<
" images and labels from file " << fname);
120 void create_compiled(std::string
const & fname,
size_t startinst,
size_t numinst)
122 static std::vector<std::string>
const categs = {
"car",
"equip",
"plane",
"boat",
"mil" };
124 LINFO(
"Create " << fname <<
" using " << numinst <<
" instances starting at " << startinst);
126 std::ofstream ofs(fname, std::ios::out | std::ios::binary);
127 if (ofs.is_open() ==
false)
LFATAL(
"Error trying to write file " << fname);
129 for (
unsigned char categ = 0; categ < categs.size(); ++categ)
130 for (
size_t inst = startinst; inst < startinst + numinst; ++inst)
134 snprintf(tmp, 2048,
"/lab/tmp10b/u/iLab-20M-Cropped-Jiaping-Augments/%s/%s-i%04zu-b0000-cropped.png",
135 categs[categ].c_str(), categs[categ].c_str(), inst);
136 LINFO(
"... adding 1320 images from " << tmp);
139 cv::Mat bigimg = cv::imread(tmp);
142 int const cw = bigimg.cols / 44;
143 int const ch = bigimg.rows / 30;
144 LINFO(
"cw="<<cw<<
" ch="<<ch);
147 for (
int cam = 0; cam < 11; ++cam)
148 for (
int rot = 0; rot < 8; ++rot)
149 for (
int lig = 0; lig < 5; ++lig)
150 for (
int foc = 0; foc < 3; ++foc)
152 cv::Mat imgcrop = bigimg(cv::Rect(x, y, cw, ch));
153 cv::Mat obj; cv::resize(imgcrop, obj, cv::Size(32, 32), 0, 0, cv::INTER_AREA);
155#ifndef JEVOIS_PLATFORM
156 cv::imshow(
"conversion", obj); cv::waitKey(1);
158 cv::Mat rgbobj; cv::cvtColor(obj, rgbobj, cv::COLOR_BGR2RGB);
160 ofs.write((
char const *)(&categ), 1);
161 ofs.write((
char const *)(rgbobj.data), 32*32*3);
163 x += cw;
if (x >= bigimg.cols) { x = 0; y += ch; }
172 LINFO(
"Load training data from directory " << path);
174 float learning_rate = 0.01F;
175 size_t const ntrain = 18;
176 size_t const ntest = 4;
179 std::vector<tiny_dnn::label_t> train_labels, test_labels;
180 std::vector<tiny_dnn::vec_t> train_images, test_images;
183 std::string
const trainpath = path +
"/ilab5-train.bin";
184 std::string
const testpath = path +
"/ilab5-test.bin";
186 std::ifstream ifs(trainpath);
187 if (ifs.is_open() ==
false)
190 create_compiled(trainpath, 1, ntrain);
191 create_compiled(testpath, ntrain + 2, ntest);
195 load_compiled(trainpath, train_labels, train_images);
196 load_compiled(testpath, test_labels, test_images);
198 LINFO(
"Start training...");
199 int const n_minibatch = 48;
200 int const n_train_epochs = 100;
205 auto on_enumerate_epoch = [&](){
206 LINFO(t.elapsed() <<
"s elapsed.");
207 tiny_dnn::result res =
net->test(test_images, test_labels);
208 LINFO(res.num_success <<
"/" << res.num_total <<
" success/total validation score so far");
214 auto on_enumerate_minibatch = [&](){
219 tiny_dnn::adam optimizer;
220 optimizer.alpha *=
static_cast<tiny_dnn::float_t
>(sqrt(n_minibatch) * learning_rate);
221 net->train<tiny_dnn::cross_entropy>(optimizer, train_images, train_labels, n_minibatch, n_train_epochs,
222 on_enumerate_minibatch, on_enumerate_epoch);
224 LINFO(
"Training complete");
227 net->test(test_images, test_labels).print_detail(std::cout);
233 static std::vector<std::string>
const names = {
"car",
"equip",
"plane",
"boat",
"mil" };
235 if (idx >= names.size())
LFATAL(
"Category index out of bounds");
ObjectRecognitionILAB(std::string const &instance)
Constructor, loads the given CNN, its sizes must match our (fixed) internal network structure.
virtual std::string const & category(size_t idx) const override
Return the name of a given category (0-based index in the vector of results)
virtual ~ObjectRecognitionILAB()
Destructor.
virtual void define() override
Define the network structure.
virtual void train(std::string const &path) override
Train the network.
Wrapper around a neural network implemented by with the tiny-dnn framework by Taiga Nomi.
tiny_dnn::network< tiny_dnn::sequential > * net