Предыдущая статья в Цзяньшу была перемещена ^-^
Данная статья является оригинальной работой автора, если есть какие-либо недоразумения, пожалуйста, укажите на них, если необходимо процитировать, пожалуйста, укажите источник.
#Анализ управления памятью BLOB-объектов
В иерархической структуре caffe Blob играет роль управления памятью, защищая восприятие логическим кодом верхнего уровня приложения и выпуска данных, а также экранируя влияние нижележащего устройства на логику верхнего уровня.Эта статья в основном анализирует Механизм управления и практическое применение Blob Механизм запроса памяти блока SyncedMemory. Во-первых, давайте посмотрим на отношения между Blob и SyncedMemory.Схема классов выглядит следующим образом:
На самом деле реализация всего BLOB-объекта заключается в инкапсуляции слоя в SyncedMemory, поэтому сначала необходимо проанализировать механизм реализации SyncedMemory.
##Механизм реализации SyncedMemory Целью SyncedMemory является защита восприятия кодом верхнего уровня распределения памяти различных аппаратных устройств и скрытие процесса синхронизации между CPU и GPU. В то же время, когда SyncedMemory реализуется, он принимает «ленивый» режим, то есть фактическая синхронизация приложений памяти осуществляется при ее первом использовании. Имея общее представление, разберем его подробно. Ниже приведен набор интерфейсов, предоставляемых SyncedMemory,
| название | Функции |
|---|---|
| cpu_data() | Получить указатель данных ЦП |
| gpu_data() | Получить указатель данных графического процессора |
Реализованный код выглядит следующим образом:
const void* SyncedMemory::cpu_data() {
to_cpu();
return (const void*)cpu_ptr_;
}
const void* SyncedMemory::gpu_data() {
#ifdef USE_CUDA
to_gpu();
return (const void*)gpu_ptr_;
#else
NO_GPU;
return NULL;
#endif // USE_CUDA
}
Видно, что при каждом вызове интерфейса будут выполняться операции to_cpu() и to_gpu(), так что же представляют собой функции этих двух операций, давайте взглянем на некоторые ключевые параметры в SyncedMemory:
| название | Функции |
|---|---|
| cpu_ptr_ | указатель данных процессора |
| gpu_ptr_ | указатель данных графического процессора |
| size_ | Количество данных, которые должна поддерживать текущая SyncedMemory. |
| head_ | Текущее состояние SyncedMemory |
Первые три понятны, а последний особенный, он поддерживает текущее состояние SyncedMemory, которое делится на четыре состояния: UNINITIALIZED, HEAD_AT_GPU, HEAD_AT_CPU и SYNCED. Теперь давайте представим конкретный процесс.Когда to_cpu() вызывается в первый раз, head_ находится в состоянии UNINITIALIZED, тогда система вызывает метод памяти приложения ЦП для получения области памяти, а затем устанавливаетhead_ = HEAD_AT_CPU, Если в промежуточном процессе нет GPU-устройства, изменения состояния не будет.Если в середине есть код, который вызывает to_gpu(), будет обнаружено, что head_ находится в состоянии HEAD_AT_CPU.В это время синхронизация будет вызвана функция для синхронизации данных от ЦП к ГП После этого, если вернувшись к ЦП, вы также обнаружите, что head_ находится в состоянии HEAD_AT_GPU, то будет вызван соответствующий код синхронизации для синхронизации данных обратно к ЦП, а разница в приложении и переключении между ГП и ЦП экранируется с помощью параметра состояния, такого как head_.
Поэтому бизнесу верхнего уровня нужно только знать, нужны ли ему данные ЦП или ГП, а затем вызывать различные интерфейсы для завершения операции сбора данных.
##Анализ реализации BLOB-объектов Разобравшись с реализацией SyncedMemory, можно относительно просто взглянуть на Blob, поскольку он выполняет некоторую логику управления верхнего уровня и предоставляет несколько ключевых интерфейсов для внешнего мира:
| название | Функции |
|---|---|
| cpu_data() | Получить указатель данных ЦП, содержимое данных не может быть изменено |
| mutable_cpu_data() | Получите указатель данных ЦП, вы можете изменить содержимое данных |
| gpu_data() | Получите указатель данных графического процессора, содержимое данных не может быть изменено |
| mutable_gpu_data() | Получите указатель данных GPU, вы можете изменить содержимое данных |
| Reshape() | Отрегулируйте информацию об измерении данных |
Первые четыре являются инкапсуляцией cpu_data() и gpu_data() SyncedMemory, просто обязательно вызывайте относительную функцию to_cpu или to_gpu перед каждым сбором данных. Последняя функция Reshape в основном предназначена для корректировки информации о размерах и может использоваться для адаптации к различным форматам данных, поэтому предоставляются три перегруженные функции, как показано ниже:
void Blob::Reshape(const int num, const int channels,const int height, const int width);
void Blob::Reshape(const BlobShape& shape) ;
void Blob::Reshape(const vector<int>& shape);
Первые две перегруженные функции только преобразуют формат данных, а затем вызывают третью функцию, поэтомуvoid Blob::Reshape(const vector<int>& shape);Это собственно исполнитель, здесь нам нужно ввести несколько ключевых параметров в Blob:
| название | Функции |
|---|---|
| data_ | Фактическое место хранения данных |
| shape_data_ | Размер места хранения информации о данных (NCHW) |
| capacity_ | Размер текущего блока данных |
| count_ | Размер блока данных после изменения формы |
Нетрудно прочитать код, чтобы обнаружить, что то, что хранится в cout_, является произведением всех измерений, то есть размера данных, которые должны быть изменены в данный момент.Весь процесс изменения формы выглядит следующим образом:
##Заканчивать Вышеизложенное является частью моего понимания Blob, я надеюсь помочь вам.