Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

edgarriba
Copy link
Member

@edgarriba edgarriba commented Nov 12, 2016

Add the Tensor structure:

  • data hold by std::vector<> with 64bytes alignment
  • three different data accessors: t.ptr<float_t>(), t.at<float_t>() and t[idx]
  • basic reshape() and resize() routines
  • basic toDevice() and fromDevice() routines
  • implement element-wise add, sub, mul, div

}

U* value = &host_data_->at(shape_[1] * shape_[2] *
( shape_[3] * batch + depth ) + height + width);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really OK to calculate data position in this way?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you unroll the formula you will see that corresponds to access data with following shape: NxWxHxD

void init_data(const cnn_size_t batch, const cnn_size_t width,
const cnn_size_t height, const cnn_size_t depth) {
host_data_ = data_ptr(new std::vector<U>(
batch * width * height * depth, float_t(0.0)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everyone loves bacon and C-style casts.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean here? probably this method could be public and implemented a resize routine

const cnn_size_t height, const cnn_size_t depth) {
shape_[0] = batch; shape_[1] = width;
shape_[2] = height; shape_[3] = depth;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[0] : batch
[1] : width
[2] : height
[3] : depth
If so, what about using enum?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would you do it?

@beru
Copy link
Contributor

beru commented Nov 12, 2016

@edgarriba
I checked the Tensor class.
I'm not sure why Tensor class has b,w,h,d template parameters since they should be dynamic and not compile-time fixed-size. Can you please tell me the reason?
What about adding getter methods to return batch, width, height, depth?

// Checked version (throw exceptions for out-of-range error)
template<typename T>
T& at(const cnn_size_t batch,
const cnn_size_t width,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think width parameter should be renamed to x.

template<typename T>
T& at(const cnn_size_t batch,
const cnn_size_t width,
const cnn_size_t height,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think height argument should be renamed to y.


template<typename T>
const T& at(const cnn_size_t batch,
const cnn_size_t width,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, width parameter should be renamed to x.

template<typename T>
const T& at(const cnn_size_t batch,
const cnn_size_t width,
const cnn_size_t height,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my perspective, height parameter should be renamed to y in here.

T* ptr(const cnn_size_t batch,
const cnn_size_t width,
const cnn_size_t height,
const cnn_size_t depth) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose to rename argument names width to x and height to y in here.

template<typename T>
const T* ptr(const cnn_size_t batch,
const cnn_size_t width,
const cnn_size_t height,
Copy link
Contributor

@beru beru Nov 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename width to x and height to y.

// zero-overhead version (same performance to raw pointer access.
// have an assertion for out-of-range error)
template<typename T>
T& operator[] (cnn_size_t index) {
Copy link
Contributor

@beru beru Nov 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add assert statement to check index parameter.

}

template<typename T>
const T& operator[] (cnn_size_t index) const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add assert statement to check index parameter.

T* access_data(const cnn_size_t batch,
const cnn_size_t width,
const cnn_size_t height,
const cnn_size_t depth) const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renaming width to x and height to y would be good.

const cnn_size_t height,
const cnn_size_t depth) const {
if (batch > shape_[0] || width > shape_[1] ||
height > shape_[2] || depth > shape_[3]) {
Copy link
Contributor

@beru beru Nov 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using shape_[magic_number_index], what about using getter methods such as batch(), width(), height(), depth()?

if (batch >= batch()
    || x >= width()
    || y >= height()
    || depth >= depth()
) {
    nn_error("Fool! You have just ensured the doom of this world.");
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

batch or N? width or w or x? ...

@bhack bhack mentioned this pull request Nov 13, 2016
@edgarriba
Copy link
Member Author

@beru
regarding template parameters you are right, I was just playing with templates :-)

Besides, what do you think about the data container ? E.g. in Caffe2 they use void* to store it maybe to have a more general case? https://github.com/caffe2/caffe2/blob/master/caffe2/core/tensor.h#L538

@bhack bhack mentioned this pull request Nov 13, 2016
@edgarriba edgarriba force-pushed the tensor branch 2 times, most recently from acffaa0 to 146ae6f Compare November 14, 2016 16:36
const cnn_size_t d2,
const cnn_size_t d3) const {
if (d0 > shape_[0] || d1 > shape_[1] ||
d2 > shape_[2] || d3 > shape_[3]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think comparison operators should be >= instead of >.

void resize(const U value = 0) {
if (!host_data_) {
host_data_ = std::unique_ptr<std::vector<U> >(
new std::vector<U>(size(), value));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probablly, you can use std::make_unique in here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

// Returns the tensor shape
std::vector<cnn_size_t> shape() const { return shape_; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess const std::vector<cnn_size_t>& shape() const { return shape_; } would be better.
But I'm wondering type of shape_ needs to be std::vector container..
An alternative type is std::array<cnn_size_t, 4>.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we return here a reference it means that a user could "reshape" the tensor just modifying this vector but we also need to resize and copy data in case that we want a real reshape. Do we want this feature now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you return const reference, caller cannot modify the returned vector without using const_cast.
Besides, if you return vector container instance by value, another heap allocation and copy occurs inside (without return value optimization).

T& at(const cnn_size_t d0,
const cnn_size_t d1,
const cnn_size_t d2,
const cnn_size_t d3) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are const type qualifiers for arguments really absolutely necessary?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@beru not really needed since we are passing arguments by value. However, for sanity and readability/maintenance I think it's a good practice to mark non-mutable arguments.

}

// Move constructor
Tensor(Tensor<U>&& other) = default;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*
* Data will be hold by a std::vector with 64bytes alignment.
*/
explicit Tensor(const cnn_size_t d0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use size_t here. cc @nyanp

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but before that: are we going to support tensors serialization? (could be cool this feature :D) If so, I think that cnn_size_t a.k.a std::uint32_t should be okay. Otherwise, I'll move to standard size_t.

@Randl
Copy link
Contributor

Randl commented Nov 16, 2016

Looks like VS somewhere tries to copy unique_ptr:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xstddef(316): error C2280: 'std::unique_ptr<std::vector<tiny_dnn::float_t,tiny_dnn::aligned_allocator<tiny_dnn::float_t,0x040>>,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function [C:\projects\build\test\tiny_dnn_test.vcxproj]          with          [              _Ty=std::vector<tiny_dnn::float_t,tiny_dnn::aligned_allocator<tiny_dnn::float_t,0x040>>          ] (C:\projects\tiny-dnn\test\test.cpp)          C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\memory(1486) : see declaration of 'std::unique_ptr<std::vector<tiny_dnn::float_t,tiny_dnn::aligned_allocator<tiny_dnn::float_t,0x040>>,std::default_delete<_Ty>>::unique_ptr'          with          [              _Ty=std::vector<tiny_dnn::float_t,tiny_dnn::aligned_allocator<tiny_dnn::float_t,0x040>>          ]          This diagnostic occurred in the compiler generated function 'tiny_dnn::Tensor<tiny_dnn::float_t>::Tensor(const tiny_dnn::Tensor<tiny_dnn::float_t> &)'

for_i(true, res.size(), [&](size_t i) {
const U tmp = src[i];
res[i] = tmp == U(0.0) ? std::numeric_limits<U>::quiet_NaN() :
this->operator[](i) / (tmp + std::numeric_limits<U>::min());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you don't need addition

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like VS somewhere tries to copy unique_ptr:

maybe because the destructor is missing ? I don't have a MS environment to test :(

Now you don't need addition

thx!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a destructor might not suffice. If you add a destructor, copy constructor and copy assignment are still generated (for backward compatibility with pre-C++11).

See here: http://stackoverflow.com/questions/3734247/what-are-all-the-member-functions-created-by-compiler-for-a-class-does-that-hap

In your case, if unique_ptr is a member, when a copy (constructor|assignment) is generated, it will invoke the copy (constructor|assignment) from unique_ptr, resulting in an error (since unique_optr is uncopiable).

The only way is to implement your custom copy constructor and copy assignment, or delete them if you want to make your class uncopiable.

Copy link
Contributor

@bhack bhack Nov 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Randl
Copy link
Contributor

Randl commented Nov 16, 2016

on first glance the problem is that VS tries to copy unique pointer in copy constructor

@Randl
Copy link
Contributor

Randl commented Nov 16, 2016

Custom copy constructor seems necessary anyway. @edgarriba @bhack @nyanp

@bhack
Copy link
Contributor

bhack commented Nov 16, 2016

@Randl
Copy link
Contributor

Randl commented Nov 16, 2016

@bhack Correct me if I'm wrong, but enforcing rule of zero together with unique_ptr results in non-copyable class, and that's not what we want

@bhack
Copy link
Contributor

bhack commented Nov 16, 2016

Yes exactly: "By using a unique_ptr we make our class non-copyable/assignable and identical in behavior to the previous examples."
And we need to avoid this here.

@Randl
Copy link
Contributor

Randl commented Nov 16, 2016

You can still make a custom copy constructor which will work the unique_ptr. That's what I suggested

@bhack
Copy link
Contributor

bhack commented Nov 16, 2016

Yes was a documentation enforcing this. And also http://stackoverflow.com/questions/29124592/copy-constructor-to-transfer-ownership-of-a-unique-ptr

@bhack
Copy link
Contributor

bhack commented Nov 17, 2016

/off topic/ @keryell Any news from the United Nations conference on "Bringing About HPC Open-Standards World Peace" ;)

@bhack
Copy link
Contributor

bhack commented Nov 17, 2016

/cc @gfursin We are designing Tensor here before integrating GPU and then go to CK. If you have any design advertise you are welcome.

@pansk pansk mentioned this pull request Nov 17, 2016
@edgarriba
Copy link
Member Author

I close this. You can find the valid pull request in #41

@edgarriba edgarriba closed this Nov 20, 2016
@bhack
Copy link
Contributor

bhack commented Nov 20, 2016

The new tensor PR is #411

@beru
Copy link
Contributor

beru commented Nov 23, 2016

bhack wrote:
@beru As you see R3 in the description section point to P0367 implemented at https://github.com/keryell/accessors

@bhack Thank you for specifying the proposal for C++ standard.
Even if it can survive under a fluid situation and will be adopted into the standard, it will may take a few years so I guess we need to build or find different one.

@keryell
Copy link

keryell commented Nov 23, 2016

@beru: array_ref was well received. Probably for C++20, but anyway there is a special department in the C++ committee dedicated to bike-sheding, so it will be probably slightly different... :-)

@bhack : stop asking off-topic questions all over GitHub threads :-) But yes, everybody survived to this SC16 panel...

@bhack
Copy link
Contributor

bhack commented Nov 23, 2016

@keryell We are living in a too covered tecnological roadmaps era that create fragmentation. HPC standard domain it is only part of this trend. Probably after C++20 all this discussions will be so useless like discussing an if statement. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants