深度学习 Caffe 内存管理机制理解

栏目: 数据库 · 发布时间: 5年前

内容简介:之前在简书的文章,搬迁过来 ^-^本文是作者原创,如有理解错误,恳请大家指出,如需引用,请注明出处。#Blob内存管理分析

之前在简书的文章,搬迁过来 ^-^

本文是作者原创,如有理解错误,恳请大家指出,如需引用,请注明出处。

#Blob内存管理分析

在caffe的分层结构中,Blob充当了内存管理的角色,屏蔽了上层逻辑代码对于数据的申请释放的感知,同时也屏蔽了底层设备对上层逻辑的影响,本文主要分析Blob的管理机制和实际内存申请单元SyncedMemory 的机制。 首先我们看一下Blob和SyncedMemory的关系,类图如下:

深度学习 Caffe 内存管理机制理解

实际上整个Blob的实现就是在SyncedMemory上封装了一层,所以首先需要分析一下SyncedMemory的实现机制。

##SyncedMemory的实现机制 SyncedMemory的目的是为了屏蔽上层代码对不同硬件设备的内存分配的感知,同时隐藏了CPU和GPU之间的同步过程。同时,SyncedMemory实现时,采用的是 “lazy”的模式,就是内存的实际申请时机是在第一次使用时进行的。有了大体的了解,下面我们来详细分析一下。 下面是SyncedMemory 提供的一组接口,

名称 功能
cpu_data() 获取CPU数据指针
gpu_data() 获取GPU数据指针

实现的代码如下:

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_ cpu数据指针
gpu_ptr_ gpu数据指针
size_ 当前SyncedMemory需要维护的数据个数
head_ 当前 SyncedMemory处于的状态

前三个都比较好理解,最后一个比较特殊,它维护的是 SyncedMemory 当前的状态,分为 UNINITIALIZED,HEAD_AT_GPU,HEAD_AT_CPU ,SYNCED 四中状态。现在介绍一下具体的流程,当第一次调用 to_cpu()时, head_处于UNINITIALIZED状态,那么系统会调用 CPU的申请内存的方式去获得内存区域,之后设置 head_ = HEAD_AT_CPU ,如果中间过程没有GPU设备则不会有状态变动,如果中间有代码调用了 to_gpu() ,则会发现 head_处于 HEAD_AT_CPU 状态,此时会调用同步函数,将数据从CPU同步到GPU, 之后如果又回到CPU上,则同样会发现 head_ 处于HEAD_AT_GPU的状态,那么又会调用相应的同步代码,将数据同步回CPU,通过 head_这样一个状态参数屏蔽了GPU和CPU间的申请和切换的不同。

所以上层业务只需要知道当前自己需要的是CPU还是GPU的数据,然后调用不同的接口,就可以完成数据获取的操作。

##Blob的实现分析 了解了SyncedMemory的实现,再来看Blob 就较为简单了,它仅仅做了一些上层的管理逻辑,向外界提供了几个关键的接口:

名称 功能
cpu_data() 获取CPU数据指针,不能改变数据内容
mutable_cpu_data() 获取CPU数据指针,可以改变数据内容
gpu_data() 获取GPU数据指针,不能改变数据内容
mutable_gpu_data() 获取GPU数据指针,可以改变数据内容
Reshape() 调整数据的维度信息

前四个就是对 SyncedMemory 的 cpu_data() 和 gpu_data()的封装,只需要确保每次获取数据前都调用相对的 to_cpu 或者 to_gpu就可以了。对于最后一个Reshape函数,主要是为了调整维度信息,同时可能是出于适配多种数据格式的目的,所以提供3个重载函数,如下:

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_ reshape后的数据块的大小

阅读代码不难发现,cout_中所存储的就是所有维度的的乘积,也就是当前要reshape到的数据大小,整个的reshape 过程如下:

深度学习 Caffe 内存管理机制理解

##结束 以上就是我对Blob的一些理解,希望对大家有帮助。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Dive Into Python 3

Dive Into Python 3

Mark Pilgrim / Apress / 2009-11-6 / USD 44.99

Mark Pilgrim's Dive Into Python 3 is a hands-on guide to Python 3 (the latest version of the Python language) and its differences from Python 2. As in the original book, Dive Into Python, each chapter......一起来看看 《Dive Into Python 3》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具