内容简介:之前在简书的文章,搬迁过来 ^-^本文是作者原创,如有理解错误,恳请大家指出,如需引用,请注明出处。#Blob内存管理分析
之前在简书的文章,搬迁过来 ^-^
本文是作者原创,如有理解错误,恳请大家指出,如需引用,请注明出处。
#Blob内存管理分析
在caffe的分层结构中,Blob充当了内存管理的角色,屏蔽了上层逻辑代码对于数据的申请释放的感知,同时也屏蔽了底层设备对上层逻辑的影响,本文主要分析Blob的管理机制和实际内存申请单元SyncedMemory 的机制。 首先我们看一下Blob和SyncedMemory的关系,类图如下:
实际上整个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 过程如下:
##结束 以上就是我对Blob的一些理解,希望对大家有帮助。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Istio流量管理实现机制深度解析
- 深度学习中的注意力机制
- 深度特征合成:自动化特征工程的运作机制
- 史上最全Android渲染机制讲解(长文源码深度剖析)
- 史上最全 Android 渲染机制讲解(长文源码深度剖析)
- 深度CTR预估模型中的特征自动组合机制演化简史
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。