-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
CNTKLibrary.h
6674 lines (5642 loc) · 305 KB
/
CNTKLibrary.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
//
// This is the main header of the CNTK library API containing the entire public API definition.
//
#pragma once
#include <memory>
#include <vector>
#include <array>
#include <stdarg.h>
#include <assert.h>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include <sstream>
#include <iosfwd>
#include <algorithm>
#include <mutex>
#include <future>
#include <cstddef>
#include <cmath>
#ifdef SWIG
#define final
#define explicit
#define static_assert(condition, message)
#endif
#include "CNTKLibraryInternals.h"
#include "HalfConverter.hpp"
// undef max in the rest of the file to avoid conflicts with the max macro defined in windows.h.
#pragma push_macro("max")
#undef max
namespace CNTK
{
class float16
{
protected:
unsigned short __x;
public:
float16() = default;
float16(const float16& other) { __x = other.__x; }
#ifndef SWIG
// construction from build-in types
float16(float f) { floatToFloat16(&f, &__x); }
float16(double d) : float16((float)d) {}
float16(int i) : float16((float)i) {}
float16(size_t u) : float16((float)u) {}
// cast to build-in types
operator float() const { float f; float16ToFloat(&__x, &f); return f; }
// compare functions
inline bool operator==(const float16& rhs) const { return (__x == rhs.__x); }
inline bool operator!=(const float16& rhs) const { return (__x != rhs.__x); }
#endif
static float16 create(float f)
{
float16 v;
floatToFloat16(&f, &v.__x);
return v;
}
static float16 create(double d)
{
return create((float)d);
}
};
///
/// Enumeration type denoting data type of symbolic data entities or actual data.
///
enum class DataType : unsigned int
{
Unknown = 0,
Float = 1,
Double = 2,
UChar = 3, // So far only used internally in deserializers.
Float16 = 4,
Int8 = 5,
Int16 = 6,
/* TODO:
Bit,
Char,
Short,
UShort,
Int,
UInt,
Long,
ULong,
Float8,
Float16,
Complex,
String,
*/
};
///
/// Get the 'DataType' corresponding to the ElementType template type argument.
///
template <typename ElementType>
inline DataType AsDataType()
{
if (std::is_same<ElementType, float>())
return DataType::Float;
else if (std::is_same<ElementType, double>())
return DataType::Double;
else if (std::is_same<ElementType, float16>())
return DataType::Float16;
else if (std::is_same<ElementType, int8_t>())
return DataType::Int8;
else if (std::is_same<ElementType, char>())
return DataType::Int8;
else if (std::is_same<ElementType, int16_t>())
return DataType::Int16;
else if (std::is_same<ElementType, uint16_t>()) // In ONNX, float16 values must be converted to an uint16_t to prior writing to the buffer.
return DataType::Float16;
else
NOT_IMPLEMENTED;
}
inline const char* DataTypeName(DataType dataType)
{
if (dataType == DataType::Float)
return "Float";
else if (dataType == DataType::Double)
return "Double";
else if (dataType == DataType::Float16)
return "Float16";
else if (dataType == DataType::Int8)
return "Int8";
else if (dataType == DataType::Int16)
return "Int16";
else
LogicError("Unknown DataType.");
}
inline size_t DataTypeSize(DataType dataType)
{
if (dataType == DataType::Float)
return sizeof(float);
else if (dataType == DataType::Double)
return sizeof(double);
else if (dataType == DataType::Float16)
return sizeof(float16);
else if (dataType == DataType::Int8)
return sizeof(int8_t);
else if (dataType == DataType::Int16)
return sizeof(int16_t);
else
LogicError("Unknown DataType.");
}
///
/// Enumeration type denoting the format of storage underlying an instance of a NDArrayView.
///
enum class StorageFormat
{
Dense,
SparseCSC,
SparseBlockCol,
};
inline bool IsSparseStorageFormat(StorageFormat storageFormat)
{
return (storageFormat != StorageFormat::Dense);
}
///
/// Enumeration type denoting the type of a compute device.
///
enum class DeviceKind : unsigned int
{
CPU,
GPU,
// TODO: FPGA
};
inline const wchar_t* DeviceKindName(DeviceKind deviceKind)
{
switch (deviceKind)
{
case DeviceKind::CPU:
return L"CPU";
case DeviceKind::GPU:
return L"GPU";
default:
LogicError("Unknown DeviceKind.");
}
}
///
/// Enumeration type representing logging verbosity levels.
///
enum class TraceLevel : unsigned int
{
Error = 0,
Warning = 1,
Info = 2
};
///
/// Denotes a multi-dimensional rectangular shape.
///
class NDShape final
{
friend bool operator==(const NDShape& first, const NDShape& second);
friend class PrimitiveFunction;
static const size_t SentinelDimValueForUnknownShape = (size_t)-2;
public:
enum : size_t
{
///
/// A placeholder value to use for an axis whose dimension is unknown and is to be inferred by the system.
///
InferredDimension = (size_t)-1,
///
/// A placeholder value to use for an axis whose dimension is unbound and is only determined
/// when actual data is bound to the variable. Note that since the actual dimension is bound
/// from actual minibatch data, the dimension can vary across different evaluations.
///
FreeDimension = (size_t)-3,
};
///
/// A placeholder shape to use to denote an unknown shape
///
inline static const NDShape& Unknown()
{
const static NDShape unknown(1, SentinelDimValueForUnknownShape);
return unknown;
}
public:
///
/// Construct a NDShape with 0 axes, which denotes a scalar.
///
NDShape() {}
///
/// Construct a NDShape instance with the specified rank and dimensionality in each axis.
///
explicit NDShape(size_t numAxes, size_t dimension = InferredDimension)
: m_shapeDims(numAxes, dimension)
{}
///
/// Construct a NDShape instance with specified dimensions.
///
NDShape(const std::vector<size_t>& dimensions)
: m_shapeDims(dimensions)
{}
///
/// Construct a NDShape instance with specified dimensions.
///
NDShape(const std::initializer_list<size_t>& dimensions)
: m_shapeDims(dimensions)
{}
///
/// Returns the dimensions of 'this' shape as a std::vector<size_t>
///
const std::vector<size_t>& Dimensions() const { return m_shapeDims; }
///
/// Returns a boolean indicating if 'this' shape is the special Unknown shape
///
bool IsUnknown() const { return (*this == NDShape::Unknown()); }
///
/// Returns a boolean indicating if 'this' shape is scalar
///
bool IsScalar() const
{
return (Rank() == 0) || (Rank() == 1 && m_shapeDims[0] == 1);
}
///
/// Returns the rank of 'this' shape.
///
size_t Rank() const { return m_shapeDims.size(); }
///
/// Returns a reference to dimension size for the specified axis.
///
size_t& operator[](size_t axisId)
{
return m_shapeDims.at(axisId);
}
///
/// Returns the dimension size for the specified axis.
///
size_t operator[](size_t axisId) const
{
return m_shapeDims.at(axisId);
}
///
/// Creates and returns a new NDShape instance with the same dimensions as 'this' shape's specified axis range [beginAxisId, endAxisId).
///
NDShape SubShape(size_t beginAxisId = 0, size_t endAxisId = SIZE_MAX) const
{
endAxisId = (endAxisId == SIZE_MAX) ? Rank() : endAxisId;
if ((endAxisId < beginAxisId) || (endAxisId > Rank()))
InvalidArgument("NDShape::SubShape: The specified endAxisId (%zu) must not exceed the rank (%zu) of 'this' NDShape and must be >= than the specified beginAxisId (%zu)", endAxisId, Rank(), beginAxisId);
std::vector<size_t> subShapeDims(m_shapeDims.begin() + beginAxisId, m_shapeDims.begin() + endAxisId);
return subShapeDims;
}
///
/// Returns a boolean value indicating if the dimension size for any of the axes of 'this' shape is unknown/inferred (aka == NDShape::InferredDimension).
///
bool HasInferredDimension() const
{
return (std::find(m_shapeDims.begin(), m_shapeDims.end(), (size_t)InferredDimension) != m_shapeDims.end());
}
///
/// Returns a boolean value indicating if the dimension size for any of the axes of 'this' shape is free (aka == NDShape::FreeDimension).
///
bool HasFreeDimension() const
{
return (std::find(m_shapeDims.begin(), m_shapeDims.end(), (size_t)FreeDimension) != m_shapeDims.end());
}
///
/// Returns a boolean value indicating if the dimension size for any of the axes of 'this' shape is free or inferred
/// i.e. (== NDShape::FreeDimension or == NDShape::InferredDimension).
///
bool HasUnboundDimension() const
{
return HasFreeDimension() || HasInferredDimension();
}
///
/// Returns the total size of the rectangular shape that 'this' shape denotes.
///
size_t TotalSize() const
{
if (HasUnboundDimension())
RuntimeError("NDShape::TotalSize: TotalSize cannot be determined for a NDShape '%S' with one or more dimensions being InferredDimension or FreeDimension.", AsString().c_str());
size_t totalSize = 1;
for (auto dim : m_shapeDims)
totalSize *= dim;
return totalSize;
}
///
/// Creates and returns a new shape constructed by appending the dimensions of the specified 'shape' to 'this' shape's dimensions.
///
NDShape AppendShape(const NDShape& shape) const
{
std::vector<size_t> newShapeDims(Rank() + shape.Rank());
std::copy(m_shapeDims.begin(), m_shapeDims.end(), newShapeDims.begin());
std::copy(shape.m_shapeDims.begin(), shape.m_shapeDims.end(), newShapeDims.begin() + m_shapeDims.size());
return newShapeDims;
}
///
/// Create a string representation of 'this' NDShape for display/printing purposes
///
std::wstring AsString() const
{
if (IsUnknown())
{
return L"[???]";
}
else
{
bool reverseShape = Internal::IsReversingTensorShapesInErrorMessagesEnabled();
auto displayShape = *this;
if (reverseShape)
{
for (size_t i = 0, j = Rank() - 1; i < Rank(); ++i, --j)
displayShape[i] = (*this)[j];
}
std::wstringstream wStrStream;
wStrStream << L"[";
for (size_t i = 0; i < Rank(); i++)
{
if (i != 0)
wStrStream << L" x ";
if (displayShape[i] == InferredDimension)
wStrStream << "?";
else if (displayShape[i] == FreeDimension)
wStrStream << "*";
else
wStrStream << displayShape[i];
}
wStrStream << L"]";
return wStrStream.str();
}
}
private:
std::vector<size_t> m_shapeDims;
};
inline bool operator==(const NDShape& first, const NDShape& second)
{
return first.m_shapeDims == second.m_shapeDims;
}
inline bool operator!=(const NDShape& first, const NDShape& second)
{
return !(first == second);
}
typedef int SparseIndexType;
static const unsigned long SentinelValueForAutoSelectRandomSeed = std::numeric_limits<unsigned long>::max() - 2; // An arbitrary choice of sentinel value
///
/// Describes an input stream: its name, element type, storage, etc.
///
struct StreamInformation
{
StreamInformation() : m_id(0), m_storageFormat(StorageFormat::Dense), m_elementType(DataType::Unknown),
m_sampleLayout(NDShape::Unknown())
{}
std::wstring m_name; // Unique name of the stream
size_t m_id; // Unique identifier of the stream
StorageFormat m_storageFormat; // Storage format of the stream
DataType m_elementType; // Element type of the stream
NDShape m_sampleLayout; // Layout of the sample for the stream
bool m_definesMbSize = false; // Flag indicating whether this stream defines minibatch size.
bool m_isBinary = false; // Whether this is an opaque binary stream. Currently in use only for lattices.
std::wstring AsString() const
{
return m_name + L"(" + m_sampleLayout.AsString() + L")";
}
};
inline bool operator==(const StreamInformation& left, const StreamInformation& right)
{
return ((left.m_id == right.m_id) &&
(left.m_name == right.m_name) &&
(left.m_storageFormat == right.m_storageFormat) &&
(left.m_elementType == right.m_elementType) &&
(left.m_sampleLayout == right.m_sampleLayout));
}
// Some projects require only some generic data types/interfaces from this file, and do not want to link explicitly to CNTKv2Library.
// In this case they have to define CNTK_HEADERONLY_DEFINITIONS before including CNTKLibrary.h
#ifndef CNTK_HEADERONLY_DEFINITIONS
///
/// Checked mode enables additional runtime verification such as:
/// - Tracking NaN occurrences in sequence gaps.
/// - Function graph verification after binding of free static axes to actual values at runtime
///
/// Enabling checked mode incurs additional runtime costs and is meant to be used as a debugging aid.
///
CNTK_API void SetCheckedMode(bool enable);
bool GetCheckedMode();
///
/// Specifies global logging verbosity level.
///
CNTK_API void SetTraceLevel(TraceLevel value);
///
/// Returns current logging verbosity level.
///
CNTK_API TraceLevel GetTraceLevel();
/// A collection of additional information needed for the distributed trainer to aggregate the gradients
struct MinibatchInfo
{
bool atEndOfData;
bool atEndOfSweep;
size_t numberOfSamples;
NDArrayViewPtr trainingLossValue;
NDArrayViewPtr evalCriterionValue;
bool IsEmpty() const { return numberOfSamples == 0; }
};
///
/// Additional GPU-specific device information.
///
struct GPUProperties final
{
unsigned int deviceId;
int versionMajor;
int versionMinor;
int cudaCores;
std::string name;
size_t totalMemory;
};
///
/// Denotes a compute device instance.
///
class DeviceDescriptor final
{
friend bool operator==(const DeviceDescriptor& first, const DeviceDescriptor& second);
friend struct Test::DeviceSelectionTestFixture;
static std::mutex s_mutex;
static bool s_defaultDeviceFrozen;
static std::unique_ptr<DeviceDescriptor> s_defaultDevice;
static std::vector<DeviceDescriptor> s_excludedDevices;
static std::vector<DeviceDescriptor> s_allDevices;
static std::vector<GPUProperties> s_gpuProperties;
public:
///
/// Returns the Id of 'this' device.
///
unsigned int Id() const { return m_deviceId; }
///
/// Returns the DeviceKind of 'this' device.
///
DeviceKind Type() const { return m_deviceType; }
///
/// Returns true if another CNTK process already holds an exclusive lock on this device.
///
CNTK_API bool IsLocked() const;
///
/// Static method to get the descriptor of the CPU device on the local system.
///
static DeviceDescriptor CPUDevice() { return{ 0, DeviceKind::CPU }; }
///
/// Static method to get the descriptor of the GPU device on the local system with the specified CUDA device ID.
///
CNTK_API static DeviceDescriptor GPUDevice(unsigned int deviceId);
///
/// This static method freezes the default device of the current CNTK process disallowing further changes
/// through calls to TrySetDefaultDevice. This default device will used for all CNTK operations
/// where a device needs to be specified and where none was explicitly provided. If no default device has been specified
/// with a call to TrySetDefaultDevice, on the first invocation, this methods will auto-select one
/// of the available (non-locked) devices as the default. Returns a descriptor of the globally default device.
///
CNTK_API static DeviceDescriptor UseDefaultDevice();
///
/// This static method tries to set the specified device as the globally default, optionally acquiring an exclusive
/// (cooperative) lock on the device (GPU). The default device can only be changed if it has not yet been frozen by being
/// implicitly used in any previous CNTK operation.
///
/// CNTK uses cooperative locking for the device access, whereby only a single process can acquire
/// a device lock. This locking mechanism allows CNTK processes to avoid device oversubscription only if they collectively
/// choose so. In other words, the device locked by one CNTK process, can still be accessed by another CNTK process without
/// acquiring any locks (i.e, the existing device lock can be ignored by other CNTK processes). This cooperative
/// locking mechanism does not guarantee any kind of exclusive access to the device. The proper way to ensure exclusivity
/// is to use tools provided by NVIDIA (nvidia smi).
///
/// This methods returns false if
/// * the specified device appears in the list of excluded devices;
/// * 'acquireDeviceLock' is true and another process already holds a lock on the device;
/// * 'acquireDeviceLock' is true and 'newDefaultDevice' corresponds to a CPU device (which cannot be locked).
///
CNTK_API static bool TrySetDefaultDevice(const DeviceDescriptor& newDefaultDevice, bool acquireDeviceLock = false);
///
/// Static method to retrieve additional properties (total memory, number of CUDA cores, etc.) for the specified GPU
/// device. This method will raise an exception if a CPU device is specified as an argument.
///
CNTK_API static const GPUProperties& GetGPUProperties(const DeviceDescriptor& device);
///
/// Static method to specify a list of excluded devices that cannot be used as globally default (neither auto-selected
/// nor explicitly specified by 'TrySetDefaultDevice'). For example, to avoid auto-selecting the CPU, invoke
/// 'SetExcludedDevices({DeviceDescriptor::CPUDevice()})'. However, after the default device has been selected and
/// frozen (by a call to UseDefaultDevice()), invoking this methods has no effect, it becomes essentially a no-op.
///
CNTK_API static void SetExcludedDevices(const std::vector<DeviceDescriptor>& excluded);
///
/// Static method to get a list of descriptors of all available/supported devices.
///
CNTK_API static const std::vector<DeviceDescriptor>& AllDevices();
///
/// Return a string summary of this device
///
CNTK_API std::wstring AsString() const;
private:
DeviceDescriptor(unsigned int deviceId, DeviceKind deviceType)
: m_deviceId(deviceId), m_deviceType(deviceType)
{}
/// Resets static properties, needed for unit-tests.
CNTK_API static void Reset();
private:
unsigned int m_deviceId;
DeviceKind m_deviceType;
};
inline bool operator==(const DeviceDescriptor& left, const DeviceDescriptor& right)
{
return ((left.Type() == right.Type()) && (left.Id() == right.Id()));
}
inline bool operator!=(const DeviceDescriptor& left, const DeviceDescriptor& right)
{
return !(left == right);
}
///
/// An interface denoting an entity that can serialize its state into a Dictionary.
///
class IDictionarySerializable
{
public:
///
/// Save the state of 'this' object into a dictionary.
///
CNTK_API virtual Dictionary Serialize() const = 0;
///
/// Returns the current version (e.g. model, checkpoint version) of the class
/// implementing this interface. The version number must be incremented each time
/// when Serialize() implementation is modified (for instance, when a new field is added to
/// the class that needs to be captured in the dictionary generated by the Serialize method).
///
CNTK_API virtual size_t CurrentVersion() const = 0;
protected:
virtual ~IDictionarySerializable() {}
};
///
/// Denotes a multi-dimensional writable or read-only array of elemental values.
/// This type denotes a view and there may be multiple simultaneous views of the data underlying a NDArrayView instance.
/// The underlying data is stored in sparse or dense format, and is located on a specific device.
/// The actual underlying storage is either external or internal in which case its lifetime is managed through reference counting.
///
class NDArrayView final : public std::enable_shared_from_this<NDArrayView>
{
friend class CompositeFunction;
friend class Utils;
friend class LearnerBase;
friend class Variable;
friend class Value;
friend class Accumulator;
friend class PackedValue;
friend class MPICommunicatorImpl;
friend class BlockMomentumDistributedLearner;
friend class Internal::VariableResolver;
friend class Trainer;
template <typename T, typename ...CtorArgTypes>
friend inline std::shared_ptr<T> MakeSharedObject(CtorArgTypes&& ...ctorArgs);
public:
///
/// Construct a NDArrayView with the specified 'dataBuffer' as the backing storage.
/// The 'dataBuffer' must have been allocated on the specified 'device', must be at least
/// as large as the total size of the specified 'viewShape' and must outlive the created NDArrayView object.
///
CNTK_API NDArrayView(::CNTK::DataType dataType, const NDShape& viewShape, void* dataBuffer, size_t bufferSizeInBytes, const DeviceDescriptor& device, bool readOnly = false);
///
/// Construct a read-only NDArrayView with the specified 'dataBuffer' as the backing storage.
/// The 'dataBuffer' must have been allocated on the specified 'device', must be at least
/// as large as the total size of the specified 'viewShape' and must outlive the created NDArrayView object.
///
NDArrayView(::CNTK::DataType dataType, const NDShape& viewShape, const void* dataBuffer, size_t bufferSizeInBytes, const DeviceDescriptor& device)
: NDArrayView(dataType, viewShape, const_cast<void*>(dataBuffer), bufferSizeInBytes, device, /*readOnly =*/ true)
{}
///
/// Construct a NDArrayView with newly allocated sparse storage in SparseCSC format on the specified 'device' and initialize its contents
/// with the specified Sparse CSC format data.
///
CNTK_API NDArrayView(::CNTK::DataType dataType, const NDShape& viewShape, const SparseIndexType* colStarts, const SparseIndexType* rowIndices, const void* nonZeroValues, size_t numNonZeroValues, const DeviceDescriptor& device, bool readOnly = false);
///
/// Construct a NDArrayView over newly allocated storage in the specified format on the specified 'device'.
///
CNTK_API NDArrayView(::CNTK::DataType dataType, ::CNTK::StorageFormat storageType, const NDShape& viewShape, const DeviceDescriptor& device);
///
/// Construct a NDArrayView over newly allocated dense storage on the specified 'device'.
///
NDArrayView(::CNTK::DataType dataType, const NDShape& viewShape, const DeviceDescriptor& device)
: NDArrayView(dataType, StorageFormat::Dense, viewShape, device)
{}
///
/// Construct a NDArrayView with the specified 'dataBuffer' as the backing storage.
/// The 'dataBuffer' must have been allocated on the specified 'device', must be at least
/// as large as the total size of the specified 'viewShape' and must outlive the created NDArrayView object.
///
template <typename ElementType>
NDArrayView(const NDShape& viewShape, ElementType* dataBuffer, size_t numBufferElements, const DeviceDescriptor& device, bool readOnly = false)
: NDArrayView(AsDataType<ElementType>(), viewShape, dataBuffer, numBufferElements * sizeof(ElementType), device, readOnly)
{}
///
/// Construct a read-only NDArrayView with the specified 'dataBuffer' as the backing storage.
/// The 'dataBuffer' must have been allocated on the specified 'device', must be at least
/// as large as the total size of the specified 'viewShape' and must outlive the created NDArrayView object.
///
template <typename ElementType>
NDArrayView(const NDShape& viewShape, const ElementType* dataBuffer, size_t numBufferElements, const DeviceDescriptor& device)
: NDArrayView(AsDataType<ElementType>(), viewShape, dataBuffer, numBufferElements * sizeof(ElementType), device)
{}
///
/// Construct a NDArrayView with the buffer underlying the specified std::vector or std::array being the underlying storage.
/// The container must be at least as large as the total size of the specified 'viewShape' and should outlive the created NDArrayView object.
///
template <typename ContainerType, typename std::enable_if<std::is_same<ContainerType, std::vector<typename ContainerType::value_type>>::value ||
std::is_same<ContainerType, std::array<typename ContainerType::value_type, sizeof(ContainerType) / sizeof(typename ContainerType::value_type)>>::value>::type* = nullptr>
NDArrayView(const NDShape& viewShape, ContainerType& sourceContainer, bool readOnly = false)
: NDArrayView(viewShape, sourceContainer.data(), sourceContainer.size(), DeviceDescriptor::CPUDevice(), readOnly)
{}
///
/// Construct a read-only NDArrayView with the buffer underlying the specified std::vector or std::array being the underlying storage.
/// The container must be the same size as the total size of the specified 'viewShape' and should outlive the created NDArrayView object.
///
template <typename ContainerType, typename std::enable_if<std::is_same<ContainerType, std::vector<typename ContainerType::value_type>>::value ||
std::is_same<ContainerType, std::array<typename ContainerType::value_type, sizeof(ContainerType) / sizeof(typename ContainerType::value_type)>>::value>::type* = nullptr>
NDArrayView(const NDShape& viewShape, const ContainerType& sourceContainer)
: NDArrayView(viewShape, sourceContainer.data(), sourceContainer.size(), DeviceDescriptor::CPUDevice())
{
if (sourceContainer.size() != viewShape.TotalSize())
InvalidArgument("The size (%zu) of the STL container does not match the size (%zu) of the specified viewShape '%S'.",
sourceContainer.size(), viewShape.TotalSize(), viewShape.AsString().c_str());
}
///
/// Construct a NDArrayView over newly allocated dense storage on the specified device and
/// assign the specified value to each element of the view.
///
template <typename ElementType>
explicit NDArrayView(const ElementType& value, const NDShape& viewShape = { 1 }, const DeviceDescriptor& device = DeviceDescriptor::UseDefaultDevice(), bool readOnly = false)
: NDArrayView(AsDataType<ElementType>(), viewShape, device)
{
SetValue(value);
m_isReadOnly = readOnly;
}
///
/// Construct a NDArrayView over newly allocated dense storage on the specified device and assign the specified value to each element of the view.
/// The specified value is cast to the specified DataType.
///
explicit NDArrayView(double value, DataType dataType = DataType::Float, const NDShape& viewShape = { 1 }, const DeviceDescriptor& device = DeviceDescriptor::UseDefaultDevice(), bool readOnly = false)
: NDArrayView(dataType, viewShape, device)
{
switch (m_dataType)
{
case DataType::Float:
SetValue((float)value);
break;
case DataType::Double:
SetValue(value);
break;
case DataType::Float16:
SetValue(float16::create(value));
break;
case DataType::Int8:
SetValue((int8_t)value);
break;
case DataType::Int16:
SetValue((int16_t)value);
break;
default:
LogicError("Unsupported DataType %s.", DataTypeName(m_dataType));
break;
}
m_isReadOnly = readOnly;
}
///
/// Destruct 'this' NDArrayView object
///
CNTK_API ~NDArrayView();
///
/// Returns a writable pointer to the data buffer underlying 'this' view
/// Throws an exception if 'this' view is read-only
///
template <typename ElementType>
CNTK_API ElementType* WritableDataBuffer();
///
/// Returns a read-only pointer to the data buffer underlying 'this' view
///
template <typename ElementType>
CNTK_API const ElementType* DataBuffer() const;
///
/// Returns a read-only pointer to the data buffer in sparse CSC format underlying 'this' view
///
template <typename ElementType>
CNTK_API std::tuple<const ElementType *, const SparseIndexType*, const SparseIndexType*, size_t> SparseCSCDataBuffers() const;
///
/// Returns a read-only pointer to the data buffer in sparse block column format underlying 'this' view
///
template <typename ElementType>
CNTK_API std::tuple<const void*, const SparseIndexType*, const SparseIndexType*, size_t, size_t, size_t> SparseBlockColumnDataBuffers() const;
///
/// adjusts the sparse block column matrix with the new Col2BlockId
/// For each column, if new Col2BlockId contains valid index, a corresponding block exists at the index
/// if old col2BlockId[i] contains value at that column, it would be copied over; otherwise the block would be filled with zeros
///
CNTK_API void AdjustSparseBlockColumn(const SparseIndexType* cpuCol2BlockId, size_t numBlocks, bool useBlockId2Col);
///
/// Returns the descriptor of the device that 'this' view resides on
///
DeviceDescriptor Device() const { return m_device; }
///
/// Returns the data type of 'this' view's contents.
///
DataType GetDataType() const { return m_dataType; }
///
/// Returns the storage format of 'this' view.
///
StorageFormat GetStorageFormat() const { return m_storageFormat; }
///
/// Returns the shape 'this' view.
///
const NDShape& Shape() const { return m_viewShape; }
///
/// Returns a boolean indicating if 'this' view contains data in sparse storage format.
///
bool IsSparse() const
{
return (GetStorageFormat() != StorageFormat::Dense);
}
///
/// Returns a boolean indicating if 'this' view is read-only.
///
bool IsReadOnly() const { return m_isReadOnly; }
///
/// Returns a boolean indicating if 'this' view is slice.
///
CNTK_API bool IsSliceView();
// TODO: The set methods should be offered in template from
///
/// Fill 'this' NDArrayView with the specified value. The underlying DataType of 'this' view should be DataType::Float.
///
CNTK_API void SetValue(float value);
///
/// Fill 'this' NDArrayView with the specified value. The underlying DataType of 'this' view should be DataType::Double.
///
CNTK_API void SetValue(double value);
///
/// Fill 'this' NDArrayView with the specified value. The underlying DataType of 'this' view should be DataType::Double.
///
CNTK_API void SetValue(float16 value);
///
/// Fill 'this' NDArrayView with the specified value. The underlying DataType of 'this' view should be DataType::Int8.
///
CNTK_API void SetValue(int8_t value);
///
/// Fill 'this' NDArrayView with the specified value. The underlying DataType of 'this' view should be DataType::Int16.
///
CNTK_API void SetValue(int16_t value);
///
/// Creates a new NDArrayView with newly allocated storage on the specified device and copies 'this' view's contents into the newly allocated view.
///
CNTK_API NDArrayViewPtr DeepClone(const DeviceDescriptor& device, bool readOnly = false) const;
///
/// Creates a new NDArrayView with newly allocated storage on the same device as 'this' view and copies 'this' view's contents into the newly allocated view.
///
inline NDArrayViewPtr DeepClone(bool readOnly) const
{
return DeepClone(this->Device(), readOnly);
}
///
/// Creates a new NDArrayView with newly allocated storage on the same device as 'this' view and copies 'this' view's contents into the newly allocated view.
///
inline NDArrayViewPtr DeepClone() const
{
return DeepClone(this->IsReadOnly());
}
///
/// Creates a new NDArrayView which is an alias of 'this' view; i.e. a new view of the same shape as 'this' over the same underlying data.
///
CNTK_API NDArrayViewPtr Alias(bool readOnly = false) const;
///
/// Creates a new NDArrayView which is an alias of a slice of 'this' view; i.e. a new view over the underlying data
/// corresponding to the specified slice of 'this' view.
///
CNTK_API NDArrayViewPtr SliceView(const std::vector<size_t>& startOffset, const std::vector<size_t>& extent, bool readOnly = false) const;
///
/// Creates a new NDArrayView which is an alias of 'this' view but with a new shape.
///
CNTK_API NDArrayViewPtr AsShape(const NDShape& newShape) const;
///
/// Copies the contents of the 'source' NDArrayView to 'this' view.
/// The shapes of the 'source' view and 'this' view must be identical.
///
CNTK_API void CopyFrom(const NDArrayView& source);
///
/// Change the device of 'this' NDArrayView to the specified device
///
CNTK_API void ChangeDevice(const DeviceDescriptor& device);
///
/// Static method to construct a new NDArrayView object whose contents are drawn from a normal distribution with the specified mean and standard deviation..
///
template <typename ElementType>
CNTK_API static NDArrayViewPtr RandomNormal(const NDShape& shape, double mean, double stdDev, unsigned long seed = SentinelValueForAutoSelectRandomSeed, const DeviceDescriptor& device = DeviceDescriptor::UseDefaultDevice());
///
/// Static method to construct a new NDArrayView object whose contents are drawn from a uniform distribution in the specified value range.
///
template <typename ElementType>
CNTK_API static NDArrayViewPtr RandomUniform(const NDShape& shape, double rangeStart, double rangeEnd, unsigned long seed = SentinelValueForAutoSelectRandomSeed, const DeviceDescriptor& device = DeviceDescriptor::UseDefaultDevice());
///
/// If the value stored is a scalar, returns it. Otherwise, throws an error.
///
template<typename ElementType>
ElementType AsScalar() const;
///
/// Return a string summary of the NDArrayView.
///
CNTK_API std::wstring AsString() const;
private:
// Disallow copy and move construction and assignment
NDArrayView(const NDArrayView&) = delete; NDArrayView& operator=(const NDArrayView&) = delete; NDArrayView& operator=(NDArrayView&&) = delete; NDArrayView(NDArrayView&& other) = delete;
// template functions connecting V1ElemType and ElementType
template <typename ElementType, typename V1ElemType>
const ElementType* _DataBuffer() const;
template <typename ElementType, typename V1ElemType>
std::tuple<const ElementType *, const SparseIndexType*, const SparseIndexType*, size_t> _SparseCSCDataBuffers() const;
template <typename ElementType, typename V1ElemType>
std::tuple<const void*, const SparseIndexType*, const SparseIndexType*, size_t, size_t, size_t> _SparseBlockColumnDataBuffers() const;
template <typename ElementType, typename V1ElemType>
static NDArrayViewPtr _RandomNormal(const NDShape& shape, double mean, double stdDev, unsigned long seed, const DeviceDescriptor& device);
template <typename ElementType, typename V1ElemType>
static NDArrayViewPtr _RandomUniform(const NDShape& shape, double rangeStart, double rangeEnd, unsigned long seed, const DeviceDescriptor& device);
template<typename ElementType, typename V1ElemType>
ElementType _AsScalar() const;
private:
static const size_t AutoSelectRowColSplitPoint = SIZE_MAX;
private:
CNTK_API NDArrayView(::CNTK::DataType dataType, const DeviceDescriptor& device, ::CNTK::StorageFormat storageType, const NDShape& viewShape, bool readOnly, void* tensorView);