public:
static constexpr const size_t MAXDIM = 4;
+ /**
+ * @brief Tensor Formant : Default is NCHW
+ */
+ enum class Format { NCHW, NHWC };
+
/**
* @brief Get the Num Dim object
*
/**
* @brief Construct a new Tensor Dim object
*
+ * @param fm format NCHW | HNWC
* @param eff_dim_flag_ effective dimension flag (1 means it's effective)
* @param dyn_dim_flag_ dynamic dimension flag (1 means it's unspecified)
*/
- explicit TensorDim(const std::bitset<MAXDIM> &eff_dim_flag_ = 0b1111,
+ explicit TensorDim(Format fm = Format::NCHW,
+ const std::bitset<MAXDIM> &eff_dim_flag_ = 0b1111,
const std::bitset<MAXDIM> &dyn_dim_flag_ = 0b0000);
/**
* @brief Construct a new Tensor Dim object
*
* @param dims std::initialize_list
+ * @param fm format NCHW | HNWC
*
- * formats of {w}, {h, w}, {c, h, w}, {b, c, h, w} are accepted
+ * formats of {w}, {h, w}, {c, h, w}, {b, c, h, w} for the NCHW are accepted
+ * formats of {c}, {w, c}, {h, w, c}, {b, h, w, c} for the NHWC are accepted
*/
- TensorDim(std::initializer_list<size_t> dims);
+ TensorDim(std::initializer_list<size_t> dims, Format fm = Format::NCHW);
/**
* @brief Construct a new Tensor Dim object without batch dimension
*
* @param shapes shapes without batch dimension
+ * @param fm format NCHW | HNWC
*/
- TensorDim(const std::array<size_t, 3> &shapes);
+ TensorDim(const std::array<size_t, 3> &shapes, Format fm = Format::NCHW);
/**
* @brief Construct a new Tensor Dim object
* @param c channel
* @param h height
* @param w width
+ * @param fm format NCHW | HNWC
* @param eff_dim_flag_ dimension bit flag to calculate the dynamic
* dimension, rightmost is width
*/
- TensorDim(size_t b, size_t c, size_t h, size_t w,
+ TensorDim(size_t b, size_t c, size_t h, size_t w, Format fm = Format::NCHW,
const std::bitset<MAXDIM> &eff_dim_flag_ = 0b1111,
const std::bitset<MAXDIM> &dyn_dim_flag_ = 0b0000);
/**
* @brief Construct a new Tensor Dim object
*
- * @param shape shape of format N:C:H:W
+ * @param shape shape of format
+ * @param fm format NCHW | HNWC
*/
- TensorDim(const std::string &shape);
+ TensorDim(const std::string &shape, Format fm = Format::NCHW);
/**
* @brief Destroy the Tensor Dim object
/**
* @brief Set the Tensor Dim object
*
- * @param input_shape input_shape of format `N:C:H:W`
+ * @param input_shape input_shape
+ * @param fm NCHW | NHWC
* @return int ML_ERROR_NONE if successs
*/
- int setTensorDim(const std::string &input_shape);
+ int setTensorDim(const std::string &input_shape, Format fm = Format::NCHW);
/**
* @brief copy assign a dimension
*/
bool is_dynamic() const;
+ /**
+ * @brief getFormat
+ *
+ */
+ TensorDim::Format getFormat() const { return format; };
+
+ /**
+ * @brief setFormat
+ *
+ */
+ void setFormat(TensorDim::Format fm) { format = fm; };
+
private:
/**
* @brief reset length
*/
void resetLen();
+ Format format;
+
std::bitset<MAXDIM> eff_dim_flag; /**< dimension bit flag to define effective
dimension size */
context.setOutputDimensions(output_dims);
/** set weight specifications */
- TensorDim bias_dim(1, 1, 1, unit, 0b0001);
- TensorDim weight_dim(1, 1, in_dim.width(), unit, 0b0011);
+ // @todo : This NCHW format setting is just temporal, it needs to be set by
+ // global configuration
+ TensorDim bias_dim(1, 1, 1, unit, ml::train::TensorDim::Format::NCHW, 0b0001);
+ TensorDim weight_dim(1, 1, in_dim.width(), unit,
+ ml::train::TensorDim::Format::NCHW, 0b0011);
weight_idx[FCParams::weight] = context.requestWeight(
weight_dim, weight_initializer, weight_regularizer,
namespace ml {
namespace train {
-TensorDim::TensorDim(const std::bitset<MAXDIM> &eff_dim_flag_,
+TensorDim::TensorDim(TensorDim::Format fm,
+ const std::bitset<MAXDIM> &eff_dim_flag_,
const std::bitset<MAXDIM> &dyn_dim_flag_) :
+ format(fm),
eff_dim_flag(eff_dim_flag_),
dyn_dim_flag(dyn_dim_flag_) {
for (size_t i = 0; i < MAXDIM; ++i) {
feature_len = 0;
}
-TensorDim::TensorDim(std::initializer_list<size_t> dims) : TensorDim() {
+TensorDim::TensorDim(std::initializer_list<size_t> dims, Format fm) :
+ TensorDim() {
int shift_size = MAXDIM - dims.size();
if (shift_size < 0) {
setTensorDim(shift_size + cnt, i);
cnt += 1;
}
+ format = fm;
}
-TensorDim::TensorDim(const std::array<size_t, 3> &shapes) :
- TensorDim({shapes[0], shapes[1], shapes[2]}) {}
+TensorDim::TensorDim(const std::array<size_t, 3> &shapes, Format fm) :
+ TensorDim({shapes[0], shapes[1], shapes[2]}, fm) {}
-TensorDim::TensorDim(size_t b, size_t c, size_t h, size_t w,
+TensorDim::TensorDim(size_t b, size_t c, size_t h, size_t w, Format fm,
const std::bitset<MAXDIM> &eff_dim_flag_,
const std::bitset<MAXDIM> &dyn_dim_flag_) :
- TensorDim(eff_dim_flag_, dyn_dim_flag_) {
+ TensorDim(fm, eff_dim_flag_, dyn_dim_flag_) {
+
setTensorDim(0, b);
- setTensorDim(1, c);
- setTensorDim(2, h);
- setTensorDim(3, w);
+ if (fm == Format::NHWC) {
+ setTensorDim(1, h);
+ setTensorDim(2, w);
+ setTensorDim(3, c);
+ } else {
+ setTensorDim(1, c);
+ setTensorDim(2, h);
+ setTensorDim(3, w);
+ }
feature_len = c * h * w;
len = b * feature_len;
}
-TensorDim::TensorDim(const std::string &shape) : TensorDim() {
- if (setTensorDim(shape) != ML_ERROR_NONE) {
+TensorDim::TensorDim(const std::string &shape, Format fm) : TensorDim() {
+ if (setTensorDim(shape, fm) != ML_ERROR_NONE) {
throw std::invalid_argument("[TensorDim] Setting TensorDim failed");
}
}
resetLen();
}
-int TensorDim::setTensorDim(const std::string &input_shape) {
+int TensorDim::setTensorDim(const std::string &input_shape, Format fm) {
int status = ML_ERROR_NONE;
static const std::regex words_regex("[^\\s.,:;!?]+");
auto words_begin =
for (std::sregex_iterator i = words_begin; i != words_end; ++i, ++cn) {
setTensorDim(MAXDIM - cur_dim + cn, std::stoul((*i).str()));
}
-
+ format = fm;
return status;
}
std::swap(lhs.feature_len, rhs.feature_len);
std::swap(lhs.eff_dim_flag, rhs.eff_dim_flag);
std::swap(lhs.dyn_dim_flag, rhs.dyn_dim_flag);
+ std::swap(lhs.format, rhs.format);
}
size_t TensorDim::batch() const { return dim[0]; };
-size_t TensorDim::channel() const { return dim[1]; };
+size_t TensorDim::channel() const {
+ return format == Format::NCHW ? dim[1] : dim[3];
+};
-size_t TensorDim::height() const { return dim[2]; };
+size_t TensorDim::height() const {
+ return format == Format::NCHW ? dim[2] : dim[1];
+};
-size_t TensorDim::width() const { return dim[3]; };
+size_t TensorDim::width() const {
+ return format == Format::NCHW ? dim[3] : dim[2];
+};
size_t TensorDim::getDataLen() const { return len; };
void TensorDim::batch(size_t b) { setTensorDim(0, b); }
-void TensorDim::channel(size_t c) { setTensorDim(1, c); }
+void TensorDim::channel(size_t c) {
+ uint i = (format == Format::NCHW) ? 1 : 3;
+ setTensorDim(i, c);
+}
-void TensorDim::height(size_t h) { setTensorDim(2, h); }
+void TensorDim::height(size_t h) {
+ uint i = (format == Format::NCHW) ? 2 : 1;
+ setTensorDim(i, h);
+}
-void TensorDim::width(size_t w) { setTensorDim(3, w); }
+void TensorDim::width(size_t w) {
+ uint i = (format == Format::NCHW) ? 3 : 2;
+ setTensorDim(i, w);
+}
const size_t *TensorDim::getDim() const { return dim; }
}
bool TensorDim::operator==(const TensorDim &rhs) const {
+ if (this->format != rhs.format)
+ return false;
+
for (size_t i = 0; i < MAXDIM; ++i) {
if (this->dim[i] != rhs.dim[i]) {
return false;
new_weights.push_back(filter);
auto &bias_weight = *old_weights[1];
- TensorDim bias_dim{std::bitset<4>(0b0001)};
+ TensorDim bias_dim{ml::train::TensorDim::Format::NCHW,
+ std::bitset<4>(0b0001)};
bias_dim.setTensorDim(
3 /** index **/,
bias_weight
new_inputs.reserve(inputs.size() + 1 /** perm **/);
new_inputs.push_back(*inputs[0]);
// create "perm" tensor for Transpose operator
- TensorDim perm_dim{std::bitset<4>(0b0001)};
+ // @todo : This NCHW format setting is just temporal, it needs to be set by
+ // global configuration
+ TensorDim perm_dim{ml::train::TensorDim::Format::NCHW,
+ std::bitset<4>(0b0001)};
perm_dim.setTensorDim(3 /** index **/,
4 /** value **/); // effective dimension = {4}
new_inputs.emplace_back(perm_dim);