Skip to content

Commit 6aeffb8

Browse files
committed
[NeoML] CDnnBlob less memory consumption
Signed-off-by: Kirill Golikov <[email protected]>
1 parent 91e6979 commit 6aeffb8

File tree

5 files changed

+130
-80
lines changed

5 files changed

+130
-80
lines changed

NeoML/Python/src/PyCustomLossLayer.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright © 2017-2021 ABBYY Production LLC
1+
/* Copyright © 2017-2024 ABBYY
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -60,16 +60,14 @@ static CArchive& operator >>( CArchive& archive, py::object& obj )
6060

6161
//------------------------------------------------------------------------------------------------------------
6262

63-
class CTempBlob : public CDnnBlob {
63+
// CPyTempDnnBlob does not own the handler data
64+
class CPyTempDnnBlob : public CDnnBlobView {
6465
public:
65-
CTempBlob( IMathEngine& mathEngine, const CConstFloatHandle& data, const CBlobDesc& dataDesc );
66+
CPyTempDnnBlob( IMathEngine& mathEngine, const CConstFloatHandle& data, const CBlobDesc& dataDesc ) :
67+
CDnnBlobView( mathEngine, dataDesc, data )
68+
{}
6669
};
6770

68-
CTempBlob::CTempBlob( IMathEngine& mathEngine, const CConstFloatHandle& data, const CBlobDesc& dataDesc ) :
69-
CDnnBlob( mathEngine, dataDesc, data, false )
70-
{
71-
}
72-
7371
//------------------------------------------------------------------------------------------------------------
7472

7573
class CPythonLossLayer : public CLossLayer {
@@ -89,11 +87,11 @@ class CPythonLossLayer : public CLossLayer {
8987

9088
CPtr<CPyMathEngineOwner> mathEngineOwner = new CPyMathEngineOwner( &MathEngine(), false );
9189

92-
CPtr<const CDnnBlob> dataBlob = new CTempBlob( mathEngineOwner->MathEngine(), data, inputBlobs[0]->GetDesc() );
90+
CPtr<const CDnnBlob> dataBlob = new CPyTempDnnBlob( mathEngineOwner->MathEngine(), data, inputBlobs[0]->GetDesc() );
9391
CPtr<const CDnnBlob> var = tape.Variable( *dataBlob.Ptr() );
9492
CPyBlob dataPyBlob( *mathEngineOwner, const_cast<CDnnBlob*>(var.Ptr()) );
9593

96-
CPtr<CDnnBlob> labelBlob( new CTempBlob( mathEngineOwner->MathEngine(), label, inputBlobs[1]->GetDesc() ) );
94+
CPtr<CDnnBlob> labelBlob( new CPyTempDnnBlob( mathEngineOwner->MathEngine(), label, inputBlobs[1]->GetDesc() ) );
9795
CPyBlob labelPyBlob( *mathEngineOwner, labelBlob );
9896

9997
CPtr<CDnnBlob> value;
@@ -121,7 +119,7 @@ class CPythonLossLayer : public CLossLayer {
121119
CheckArchitecture( false, GetName(), "The custom loss layer doesn't support int labels!" );
122120
}
123121

124-
void Serialize( CArchive& archive )
122+
void Serialize( CArchive& archive ) override
125123
{
126124
archive.SerializeVersion( PythonLossLayerVersion, 1 );
127125
CLossLayer::Serialize( archive );

NeoML/Python/src/PyDnnBlob.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright © 2017-2021 ABBYY Production LLC
1+
/* Copyright © 2017-2024 ABBYY
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -115,7 +115,10 @@ static CBlobDesc createBlobDesc( TBlobType type, std::initializer_list<int> dime
115115
return desc;
116116
}
117117

118-
class CPyDnnBlob : public CDnnBlob {
118+
//------------------------------------------------------------------------------------------------------------
119+
120+
// CPyDnnBlob does not own the handler data
121+
class CPyDnnBlob : public CDnnBlobView {
119122
public:
120123
CPyDnnBlob( IMathEngine& mathEngine, TBlobType type, std::initializer_list<int> dimension, py::buffer_info&& _info );
121124
virtual ~CPyDnnBlob();
@@ -128,7 +131,7 @@ class CPyDnnBlob : public CDnnBlob {
128131
};
129132

130133
CPyDnnBlob::CPyDnnBlob( IMathEngine& mathEngine, TBlobType type, std::initializer_list<int> dimension, py::buffer_info&& _info ) :
131-
CDnnBlob( mathEngine, createBlobDesc( type, dimension ), CPyMemoryHandle( &mathEngine, _info.ptr ), false ),
134+
CDnnBlobView( mathEngine, createBlobDesc( type, dimension ), CPyMemoryHandle( &mathEngine, _info.ptr ) ),
132135
info( new py::buffer_info( std::move( _info ) ) )
133136
{
134137
}

NeoML/include/NeoML/Dnn/DnnBlob.h

Lines changed: 96 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ namespace NeoML {
3434

3535
class NEOML_API CDnnBlob : public IObject {
3636
public:
37-
explicit CDnnBlob( IMathEngine& mathEngine );
37+
explicit CDnnBlob( IMathEngine& mathEngine ) : mathEngine( mathEngine ) {}
3838

39-
// Move other's Blob state to this Blob and transfer its data (if dataOwned) to this thread
39+
// Move other's Blob state to this Blob and transfer its data to this thread
4040
CDnnBlob( CDnnBlob&& other );
4141
CDnnBlob& operator=( CDnnBlob&& other );
4242

@@ -65,7 +65,7 @@ class NEOML_API CDnnBlob : public IObject {
6565
static CDnnBlob* CreateBlob(IMathEngine& mathEngine, TBlobType type, const CBlobDesc& pattern);
6666

6767
// Checks if the dimensions of another blob are the same
68-
bool HasEqualDimensions(const CDnnBlob* other) const;
68+
bool HasEqualDimensions( const CDnnBlob* other ) const { return desc.HasEqualDimensions( other->desc ); }
6969

7070
// Gets the blob size along the specified dimension
7171
int DimSize(int d) const { return desc.DimSize(d); }
@@ -143,7 +143,7 @@ class NEOML_API CDnnBlob : public IObject {
143143
// Transfers CDnnBlob data from other thread owner to this thread.
144144
// By default memory underneath each blob is associated with the thread on which its allocation has occurred.
145145
// This method switches this association to the calling thread.
146-
void TransferDataToThisThread();
146+
virtual void TransferDataToThisThread();
147147

148148
// Elementwise adds a blob of the same dimensions
149149
void Add(const CDnnBlob* other);
@@ -165,7 +165,7 @@ class NEOML_API CDnnBlob : public IObject {
165165
// Changes the blob dimensions "names" without moving the data
166166
// In effect, only the blob description is changed
167167
// As the data is unaffected, the total blob size specified by the new descriptor should be the same
168-
void ReinterpretDimensions( const CBlobDesc& newDesc );
168+
virtual void ReinterpretDimensions( const CBlobDesc& newDesc );
169169

170170
// Merges blobs along the given dimension
171171
static void MergeByDim( IMathEngine& mathEngine, TBlobDim d, const CObjectArray<CDnnBlob>& from, const CPtr<CDnnBlob>& to );
@@ -193,31 +193,31 @@ class NEOML_API CDnnBlob : public IObject {
193193

194194
// Gets the pointer to the MathEngine on which the blob was created
195195
IMathEngine& GetMathEngine() const { return mathEngine; }
196-
197196
// Gets the blob descriptor
198197
const CBlobDesc& GetDesc() const { return desc; }
199198
// Gets the type of data in the blob
200199
TBlobType GetDataType() const { return desc.GetDataType(); }
201200

201+
// All methods below are just the interface for the CDnnWindowBlob representation
202+
202203
// Gets the parent blob
203-
CDnnBlob* GetParent() { return parent; }
204-
const CDnnBlob* GetParent() const { return parent; }
204+
virtual CDnnBlob* GetParent() { return nullptr; }
205+
const CDnnBlob* GetParent() const { return const_cast<CDnnBlob*>( this )->GetParent(); }
205206
// Gets the blob that owns the data (and has no parent)
206-
CDnnBlob* GetOwner();
207-
const CDnnBlob* GetOwner() const { return const_cast<CDnnBlob*>(this)->GetOwner(); }
208-
207+
virtual CDnnBlob* GetOwner() { return this; }
208+
const CDnnBlob* GetOwner() const { return const_cast<CDnnBlob*>( this )->GetOwner(); }
209209
// Gets the shift in data relative to the parent blob
210210
// The position in the parent blob is calculated along the BatchLength dimension
211211
// The position equal to N would correspond to a N*BatchWidth*ListSize*Height*Width*Depth*Channels shift in the one-dimensional array
212-
int GetParentPos() const;
213-
void SetParentPos( int pos );
214-
void ShiftParentPos( int shift );
212+
virtual int GetParentPos() const { return 0; }
213+
virtual void SetParentPos( int /*pos*/ ) { NeoAssert( false ); }
214+
virtual void ShiftParentPos( int /*shift*/ ) { NeoAssert( false ); }
215215

216216
protected:
217217
~CDnnBlob() override;
218218

219-
CDnnBlob( IMathEngine& _mathEngine, const CBlobDesc& _desc, CMemoryHandle _data, bool _dataOwned ) :
220-
mathEngine( _mathEngine ), desc( _desc ), data( _data ), dataOwned( _dataOwned ), parentPos( 0 )
219+
CDnnBlob( IMathEngine& _mathEngine, const CBlobDesc& _desc, CMemoryHandle _data ) :
220+
mathEngine( _mathEngine ), desc( _desc ), data( _data )
221221
{
222222
NeoAssert( desc.GetDataType() != CT_Invalid );
223223
NeoAssert( &mathEngine == data.GetMathEngine() );
@@ -227,20 +227,79 @@ class NEOML_API CDnnBlob : public IObject {
227227
IMathEngine& mathEngine;
228228
CBlobDesc desc;
229229
CMemoryHandle data;
230-
bool dataOwned;
231-
232-
CPtr<CDnnBlob> parent; // parent blob
233-
int parentPos;
234230

235231
void initializeBlob(TBlobType _type, int batchLength, int batchWidth, int listSize, int height, int width,
236232
int depth, int channels);
237233
void initializeTensor(TBlobType _type, std::initializer_list<int> dimensions);
238-
void initializeWindow(const CPtr<CDnnBlob>& _parent, int windowSize);
239234
void initializeByPattern(TBlobType type, const CBlobDesc& pattern);
240235

241236
friend class CDnnBlobClassRegistrar;
237+
friend class CDnnWindowBlob;
238+
friend class CDnnBlobView;
242239
};
243240

241+
//---------------------------------------------------------------------------------------------------------------------
242+
243+
// The kind of CDnnBlob does not own the data
244+
// CDnnBlobView does not clear data handler
245+
// Used in python wrappers
246+
class NEOML_API CDnnBlobView : public CDnnBlob {
247+
protected:
248+
CDnnBlobView( IMathEngine& mathEngine ) : CDnnBlob( mathEngine ) {}
249+
CDnnBlobView( IMathEngine& mathEngine, const CBlobDesc& desc, CMemoryHandle data ) :
250+
CDnnBlob( mathEngine, desc, data )
251+
{}
252+
253+
~CDnnBlobView() { if( !data.IsNull() ) { data = CMemoryHandle{}; } } // no need to free
254+
255+
// Prohibited methods
256+
//void ReinterpretDimensions( const CBlobDesc& ) override { NeoAssert( false ); } // impossible !!! USED in Python !!!
257+
//void Serialize( CArchive& ) override // !!! PICKLED in Python !!!
258+
//{ NeoAssert( false ); } // a blob that links to another may not be serialized
259+
void TransferDataToThisThread() override {} // !!! MOVED in Python !!!
260+
};
261+
262+
//---------------------------------------------------------------------------------------------------------------------
263+
264+
// The kind of CDnnBlob that is view of the some parent Blob as sequence (BatchLength > 1).
265+
// This CDnnWindowBlob do not owner of its memory, technical CDnnBlob representation.
266+
// This CDnnWindowBlob represents 1 element (BatchLength == 1) of the sequence for the recursive networks.
267+
class NEOML_API CDnnWindowBlob : public CDnnBlob {
268+
public:
269+
// Creates a "window" blob to represent a subsequence of objects from the parent blob
270+
static CDnnBlob* CreateWindowBlob( const CPtr<CDnnBlob>& parent, int windowSize = 1 );
271+
272+
// Prohibited methods
273+
void ReinterpretDimensions( const CBlobDesc& ) override { NeoAssert( false ); } // impossible
274+
void Serialize( CArchive& ) override { NeoAssert( false ); } // a blob that links to another may not be serialized
275+
void TransferDataToThisThread() override { NeoAssert( false ); }
276+
277+
// Interface of communication
278+
CDnnBlob* GetParent() override { return parent; }
279+
CDnnBlob* GetOwner() override;
280+
int GetParentPos() const override;
281+
void SetParentPos( int pos ) override;
282+
void ShiftParentPos( int shift ) override;
283+
284+
protected:
285+
CDnnWindowBlob( IMathEngine& mathEngine ) : CDnnBlob( mathEngine ) {}
286+
CDnnWindowBlob( IMathEngine& mathEngine, const CBlobDesc& desc, CMemoryHandle data ) :
287+
CDnnBlob( mathEngine, desc, data )
288+
{}
289+
CDnnWindowBlob( CDnnWindowBlob&& other ) = delete;
290+
CDnnWindowBlob& operator=( CDnnWindowBlob&& other ) = delete;
291+
292+
~CDnnWindowBlob() { if( parent != nullptr ) { data = CMemoryHandle{}; } } // no need to free
293+
294+
private:
295+
CPtr<CDnnBlob> parent; // parent blob
296+
int parentPos = 0;
297+
298+
void initializeWindow( const CPtr<CDnnBlob>& parent, int windowSize );
299+
};
300+
301+
//---------------------------------------------------------------------------------------------------------------------
302+
244303
inline void SerializeBlob( IMathEngine& mathEngine, CArchive& archive, CPtr<CDnnBlob>& blob )
245304
{
246305
if( archive.IsStoring() ) {
@@ -286,6 +345,8 @@ enum class TDnnBlobBufferAccess {
286345
ReadWrite
287346
};
288347

348+
//---------------------------------------------------------------------------------------------------------------------
349+
289350
// RAII-helper to safely work with `CDnnBlob::GetBuffer`/`CDnnBlob::ReleaseBuffer`.
290351
template<typename TBufferType = float>
291352
class CDnnBlobBuffer {
@@ -326,6 +387,8 @@ class CDnnBlobBuffer {
326387
TBufferType* ptr;
327388
};
328389

390+
//---------------------------------------------------------------------------------------------------------------------
391+
329392
inline CDnnBlob* CDnnBlob::CreateBlob( IMathEngine& mathEngine, const CBlobDesc& pattern )
330393
{
331394
return CreateBlob(mathEngine, CT_Float, pattern);
@@ -449,13 +512,15 @@ inline T* CDnnBlob::GetBuffer( int pos, int size, bool exchange )
449512
return static_cast<T*>( mathEngine.GetBuffer( data, pos * dataSize, size * dataSize, exchange ) );
450513
}
451514

452-
inline int CDnnBlob::GetParentPos() const
515+
//---------------------------------------------------------------------------------------------------------------------
516+
517+
inline int CDnnWindowBlob::GetParentPos() const
453518
{
454519
NeoAssert(parent != 0);
455520
return parentPos;
456521
}
457522

458-
inline void CDnnBlob::SetParentPos(int pos)
523+
inline void CDnnWindowBlob::SetParentPos(int pos)
459524
{
460525
int arrayPos = pos * (desc.BlobSize() / desc.BatchLength());
461526
NeoAssert(parent != 0);
@@ -473,25 +538,24 @@ inline void CDnnBlob::SetParentPos(int pos)
473538
}
474539
}
475540

476-
inline void CDnnBlob::ShiftParentPos(int shift)
541+
inline void CDnnWindowBlob::ShiftParentPos(int shift)
477542
{
478543
SetParentPos(parentPos + shift);
479544
}
480545

481-
inline bool CDnnBlob::HasEqualDimensions(const CDnnBlob* other) const
482-
{
483-
return desc.HasEqualDimensions(other->desc);
484-
}
485-
486-
inline CDnnBlob* CDnnBlob::GetOwner()
546+
inline CDnnBlob* CDnnWindowBlob::GetOwner()
487547
{
488548
CDnnBlob* result = this;
489-
while( result->parent != 0 ) {
490-
result = result->parent;
549+
CDnnWindowBlob* window = this;
550+
while( window != nullptr && window->parent != nullptr ) {
551+
result = window->parent;
552+
window = dynamic_cast<CDnnWindowBlob*>( result );
491553
}
492554
return result;
493555
}
494556

557+
//---------------------------------------------------------------------------------------------------------------------
558+
495559
template<typename TBufferType>
496560
inline CDnnBlobBuffer<TBufferType>::~CDnnBlobBuffer()
497561
{

NeoML/src/Dnn/AutoDiff.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright © 2017-2021 ABBYY Production LLC
1+
/* Copyright © 2017-2024 ABBYY
22
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
@@ -21,14 +21,14 @@ limitations under the License.
2121
namespace NeoML {
2222

2323
CTapeBlob::CTapeBlob( IGradientTape* _tape, const CDnnBlob& blob ) :
24-
CDnnBlob( blob.GetMathEngine(), blob.GetDesc(), blob.GetMathEngine().HeapAlloc( blob.GetDataSize() * sizeof(float) ), true ),
24+
CDnnBlob( blob.GetMathEngine(), blob.GetDesc(), blob.GetMathEngine().HeapAlloc( blob.GetDataSize() * sizeof(float) ) ),
2525
tape( _tape )
2626
{
2727
blob.GetMathEngine().VectorCopy( GetData(), blob.GetData(), blob.GetDataSize() );
2828
}
2929

3030
CTapeBlob::CTapeBlob( IGradientTape* _tape, IMathEngine& mathEngine, const CBlobDesc& desc ) :
31-
CDnnBlob( mathEngine, desc, mathEngine.HeapAlloc( desc.BlobSize() * sizeof(float) ), true ),
31+
CDnnBlob( mathEngine, desc, mathEngine.HeapAlloc( desc.BlobSize() * sizeof(float) ) ),
3232
tape( _tape )
3333
{
3434
}

0 commit comments

Comments
 (0)