started the TensorView class by adding header and CPP to math lib

This commit is contained in:
Frank Seide 2015-12-15 15:02:43 -08:00
Родитель a75265ca49
Коммит c918f3b6b8
6 изменённых файлов: 97 добавлений и 43 удалений

Просмотреть файл

@ -8,7 +8,9 @@
#pragma once
#include "Basics.h"
#include "File.h"
#include <vector>
#include <string>
namespace Microsoft { namespace MSR { namespace CNTK {
@ -84,81 +86,121 @@ namespace Microsoft { namespace MSR { namespace CNTK {
struct TensorShape
{
public:
// BUGBUG: This initialization is not correct. This must match GetNumRows(). We probably cannot have all three members here.
// Idea: We could construct this thing with a ref to the enclosing ComputationNode, and replace 'width' by an expression.
TensorShape() : m_tensorDims(3, 1) { }
template<class VEC>
TensorShape(const VEC & dims) { m_tensorDims.reserve(dims.size()); m_tensorDims.assign(dims.begin(), dims.end()); }
TensorShape(std::vector<size_t> && dims) : m_tensorDims(std::move(dims)) { }
TensorShape(const VEC & dims)
{
m_dims.reserve(dims.size());
m_dims.assign(dims.begin(), dims.end());
InitAsNoSlice();
}
// convenience constructors, e,g. for test code
TensorShape(size_t I) : TensorShape(std::vector<size_t> { I }) { }
TensorShape(size_t I, size_t J) : TensorShape(std::vector<size_t> { I, J }) { }
TensorShape(size_t I, size_t J, size_t K) : TensorShape(std::vector<size_t> { I, J, K }) { }
TensorShape(size_t I, size_t J, size_t K, size_t L) : TensorShape(std::vector<size_t> { I, J, K, L }) { }
TensorShape(size_t I, size_t J, size_t K, size_t L, size_t M) : TensorShape(std::vector<size_t> { I, J, K, L, M }) { }
// BUGBUG: This default initialization is not correct. This must match GetNumRows(). We probably cannot have all three members here.
TensorShape() : TensorShape(1, 1, 1) { }
void Invalidate() { m_tensorDims.assign(3, SIZE_MAX); } // TODO: clean up the valid/invalid situation (this is currently done inconsistently)
// boilerplate
TensorShape(std::vector<size_t> && dims) : m_dims(std::move(dims)) { }
bool operator==(const TensorShape & other) const { return m_dims == other.m_dims; }
void Invalidate() { m_dims.assign(3, SIZE_MAX); } // TODO: clean up the valid/invalid situation (this is currently done inconsistently). Also this object is immutable.
// TODO: need move constructor/assignment?
bool operator==(const TensorShape & other) const { return m_tensorDims == other.m_tensorDims; }
void Save(File& fstream) const
{
#if 1
if (m_offset != 0)
LogicError("TensorShape::Save(): Cannot serialize TensorShape for slices.");
// saving as 32-bit ints. This allows to continue to support the old format (size_t W, H, C)
fstream << (uint32_t)m_tensorDims.size();
for (auto dim : m_tensorDims)
fstream << (uint32_t)m_dims.size();
size_t mul = 1;
for (size_t k = 0; k < m_dims.size(); k++)
{
auto dim = m_dims[k];
if (dim > UINT32_MAX)
LogicError("TensorShape::Save(): Tensor dimension out of bounds (> 4G).");
LogicError("TensorShape::Save(): Tensor dimensions %s out of bounds (> 4G).", string(*this).c_str());
fstream << (uint32_t)dim;
if (m_multipliers[k] != dim)
LogicError("TensorShape::Save(): Cannot serialize TensorShape for slices.");
mul *= dim;
}
#else
// TODO: need to use a generic format
assert(m_tensorDims.size() == 3); // current format does not understand anything else
fstream << m_tensorDims[1] << m_tensorDims[2] << m_tensorDims[0]; // currently stored in order W, H, C. TODO: general tensor format will be different
#endif
}
void Load(File& fstream)
{
#if 1
// format: uint32_t n, dim[0], dim[1], ..., dim[n-1]
// We are also able to read (but not write) an older format, which stores 3-dimensional tensors as size_t W, H, C
uint32_t n, dim;
fstream >> n >> dim;
if (dim) // heuristic to detect the old format. Old format stores a size_t, i.e. the second uint32_t is 0 (no dimensions are > 4G)
{
m_tensorDims.resize(n);
m_tensorDims[0] = dim;
m_dims.resize(n);
m_dims[0] = dim;
for (size_t i = 1; i < n; i++)
{
fstream >> dim;
m_tensorDims[i] = dim;
m_dims[i] = dim;
}
assert(n == m_tensorDims.size());
assert(n == m_dims.size());
}
else // detected the old size_t W, H, C format
{
m_tensorDims.resize(3); // current format is hard-coded for 3, for back compat
m_tensorDims[1] = n;
fstream >> m_tensorDims[2] >> m_tensorDims[0]; // currently stored in order W, H, C. TODO: general tensor format will be different
}
#else
// TODO: need to use a generic format
m_tensorDims.resize(3); // current format is hard-coded for 3, for back compat
fstream >> m_tensorDims[1] >> m_tensorDims[2] >> m_tensorDims[0]; // currently stored in order W, H, C. TODO: general tensor format will be different
#endif
m_dims.resize(3); // current format is hard-coded for 3, for back compat
m_dims[1] = n;
fstream >> m_dims[2] >> m_dims[0]; // currently stored in order W, H, C. TODO: general tensor format will be different
}
}
// accessors
size_t GetDim(size_t k) const { return m_tensorDims[k]; }
size_t GetNumDims() const { return m_tensorDims.size(); }
size_t GetNumElements() const { size_t res = 1; for (auto & dim : m_tensorDims) res *= dim; return res; }
size_t GetDim(size_t k) const { return m_dims[k]; }
size_t GetNumDims() const { return m_dims.size(); }
size_t GetNumElements() const { size_t res = 1; for (auto & dim : m_dims) res *= dim; return res; }
size_t size() const { return GetNumDims(); }
const std::vector<size_t> & GetDims() const { return m_tensorDims; } // get all, e.g. for logging or for constructing derived tensors with edited dimensions
// vector-like accessors
size_t operator[](size_t k) const { return GetDim(k); }
const std::vector<size_t> & GetDims() const { return m_dims; } // get all, e.g. for logging or for constructing derived tensors with edited dimensions
// interpretation as an image tensor
size_t GetNumChannels() const { return m_tensorDims[0]; }
size_t GetWidth() const { return m_tensorDims[1]; }
size_t GetHeight() const { return m_tensorDims[2]; }
size_t GetNumChannels() const { return m_dims[0]; }
size_t GetWidth() const { return m_dims[1]; }
size_t GetHeight() const { return m_dims[2]; }
// pretty-printing. Returns tensor dims in the form "I x J x K".
operator std::string() const
{
std::string s;
for (const auto & dim : m_dims)
{
if (!s.empty())
s.append(" x ");
s.append(std::to_string(dim));
}
return s;
}
private:
std::vector<size_t> m_tensorDims;
//
void InitAsNoSlice()
{
m_multipliers.resize(m_dims.size());
size_t mul = 1;
for (size_t k = 0; k < m_dims.size(); k++)
{
m_multipliers.push_back(mul);
mul *= m_dims[k];
}
m_storageSize = mul;
}
private:
std::vector<size_t> m_dims; // dimensions of tensor or tensor slice
size_t m_offset; // offset to first element (may be non-0 in case of slice)
std::vector<size_t> m_multipliers; // dimension gets multiplied by this for computing the index offset. Note this may be used for stride magic.
size_t m_storageSize; // size of underlying storage object
};
// When constructing an image tensor with the usual W, H, C format, use the following function instead.
@ -168,12 +210,12 @@ namespace Microsoft { namespace MSR { namespace CNTK {
// This will get fixed once we get more complete arbitrary tensor support throughout, including better-defined inference rules.
static inline TensorShape ImageLayoutWHC(size_t width, size_t height, size_t channels)
{
return TensorShape(std::vector<size_t> { channels, width, height });
return TensorShape(channels, width, height);
}
// and use this one when the data is a plain vector
static inline TensorShape ImageLayoutVector(size_t n)
{
return TensorShape(std::vector<size_t> { 1, 1, n }); // for now storing it as a 3D object as well --TODO: fix this
return TensorShape(1, 1, n); // for now storing it as a 3D object as well --TODO: fix this
}
// TODO: we need a constructor from config; that will allow us to generalize

Просмотреть файл

@ -7,6 +7,7 @@
#include "Basics.h"
#include "Matrix.h"
#include "TensorView.h"
#include "ScriptableObjects.h"
#include "Sequences.h"
#include "DataTensor.h"

Просмотреть файл

@ -226,6 +226,7 @@ MATH_SRC =\
Math/Math/MatrixQuantizerCPU.cpp \
Math/Math/QuantizedMatrix.cpp \
Math/Math/Matrix.cpp \
Math/Math/TensorView.cpp \
Math/Math/CUDAPageLockedMemAllocator.cpp \
Math/Math/ConvolutionEngine.cpp \

Просмотреть файл

@ -162,6 +162,7 @@
<ClInclude Include="CommonMatrix.h" />
<ClInclude Include="ConvolutionEngine.h" />
<ClInclude Include="CPUMatrix.h" />
<ClInclude Include="TensorView.h" />
<None Include="ClassDiagram.cd" />
<None Include="GPUWatcher.cu" />
<None Include="GPUWatcher.h">
@ -210,6 +211,7 @@
<PrecompiledHeader>
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="TensorView.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="GPUMatrix.h" />

Просмотреть файл

@ -31,6 +31,9 @@
<Filter>GPU\1bitSGD</Filter>
</ClCompile>
<ClCompile Include="ConvolutionEngine.cpp" />
<ClCompile Include="TensorView.cpp">
<Filter>Tensors</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CommonMatrix.h" />
@ -64,6 +67,9 @@
</ClInclude>
<ClInclude Include="..\..\Common\Include\DebugUtil.h" />
<ClInclude Include="ConvolutionEngine.h" />
<ClInclude Include="TensorView.h">
<Filter>Tensors</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="GPUMatrix.h">
@ -99,5 +105,8 @@
<Filter Include="CPU\1bitSGD">
<UniqueIdentifier>{af1f6489-f531-4338-a4c5-ebe52b884e5c}</UniqueIdentifier>
</Filter>
<Filter Include="Tensors">
<UniqueIdentifier>{70fb07cf-603e-4444-bc10-f0add4920fd2}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,4 +1,4 @@
// Matrix.cpp -- main CPP file that contains all functions exported by the CNTKMath.dll
// Matrix.cpp -- main CPP file that contains all Matrix functions exported by the CNTKMath.dll
//
// <copyright file="Matrix.cpp" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
@ -27,7 +27,6 @@
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
//before calling the following macro the current matrix location and matrix type on MatrixPointerToCheck must have been set correctly
#define DISPATCH_MATRIX_ON_FLAG(MatrixPointerToCheck, MatrixPointerToSetFlag, CPUDense, GPUDense, CPUSparse, GPUSparse) \
{ \