专栏首页用户2442861的专栏caffe源码分析-SyncedMemory

caffe源码分析-SyncedMemory

本文主要分析caffeBlob内存管理类SyncedMemory,主要内容包括:

  1. SyncedMemoryBlob的关系
  2. SyncedMemory中的方法,如内存的分配、释放
  3. SyncedMemory中内存的申请,是在数据访问时才分配而不是立马分配(通过enum SyncedHead状态实现)

SyncedMemoryBlob的关系

Blob中的主要数据成员如下,实际是在SyncedMemory上做了一层包装:

template<typename Dtype>
class Blob{    
   protected:
        shared_ptr<SyncedMemory> data_; //存储前向传递数据
        shared_ptr<SyncedMemory> diff_; //存储反向传递梯度
        vector<int> shape_;  //参数维度
        int count_; //Blob存储的元素个数(shape_所有元素乘积)
        int capacity_;//当前Blob的元素个数(控制动态分配)
};

SyncedMemory

SyncedMemory 的主要数据成员如下:

class SyncedMemory {
   private:
        void* cpu_ptr_;//内存指针
        void* gpu_ptr_;//显存指针
        size_t size_;  //数据大小
        SyncedHead head_;//当前数据状态
        bool own_cpu_data_;
        bool cpu_malloc_use_cuda_;
        bool own_gpu_data_;
        int gpu_device_;
};
  1. SyncedMemory屏蔽了代码对不同硬件设备的内存分配的感知,同时隐藏了CPU和GPU之间的同步过程。
  2. SyncedMemory采用“lazy”的模式,就是内存的实际申请时机是在第一次使用时进行的(通过枚举状态)。

首先看如下两个函数cpu_data, gpu_data获取cpu,gpu数据指针:

const void* SyncedMemory::cpu_data() {
    to_cpu();   // 首先完成数据同步,第一次访问时会申请存储空间
    return (const void*)cpu_ptr_;
}
const void* SyncedMemory::gpu_data() {
    #ifndef CPU_ONLY
            to_gpu();
            return (const void*)gpu_ptr_;
    #else
            NO_GPU;
      return NULL;
    #endif
    return nullptr;
}

以cpu_data为例, 如果数据尚未分配(通过如下枚举判断),则分配数据,如果已经分配则什么也不做:

enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };

inline void SyncedMemory::to_cpu() {
    switch (head_) {
        case UNINITIALIZED://数据尚未分配
            CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);
            caffe_memset(size_, 0, cpu_ptr_);
            head_ = HEAD_AT_CPU;//更新枚举状态
            own_cpu_data_ = true;
            break;
        case HEAD_AT_GPU:
#ifndef CPU_ONLY
//     ........
            ;
#else
            NO_GPU;
#endif
            break;
        case HEAD_AT_CPU:
        case SYNCED:
            break;
    }
}

SyncedMemory有如下接口,获取cpu中的数据指针(gpu同理):

//获取CPU数据指针,不能改变数据内容
const void* cpu_data();
//获取CPU数据指针,可以改变数据内容
void* mutable_cpu_data();

Blob中调用:

// 调用SyncedMemory的数据访问函数cpu_data(),并返回内存指针
template <typename Dtype>
const Dtype* Blob<Dtype>::cpu_data() const {
    CHECK(data_);
    return (const Dtype*)data_->cpu_data();
}
template <typename Dtype>
Dtype* Blob<Dtype>::mutable_cpu_data() {
    CHECK(data_);
    return static_cast<Dtype*>(data_->mutable_cpu_data());
}

内存分配与释放

内存分配与释放由两个(不属于SyncedMemory类)的内联函数完成. 代码简单直观: 如果是CPU模式, 那么调用malloc和free来申请/释放内存, 否则调用CUDA的cudaMallocHost和cudaFreeHost来申请/释放显存.

inline void CaffeMallocHost(void** ptr, size_t size, bool* use_cuda) {
    *ptr = malloc(size);
    *use_cuda = false;
    CHECK(*ptr) << "host allocation of size " << size << " failed";
}

inline void CaffeFreeHost(void* ptr, bool use_cuda) {
    free(ptr);
}

caffe系列源码分析介绍

本系列深度学习框架caffe 源码分析主要内容如下:

1. caffe源码分析-cmake 工程构建:

caffe源码分析-cmake 工程构建主要内容:

自己从头构建一遍工程,这样能让我更好的了解大型的项目的构建。当然原始的caffe的构建感觉还是比较复杂(主要是cmake),我这里仅仅使用cmake构建,而且简化点,当然最重要的是支持CLion直接运行调试(如果需要这个工程可以评论留下你的邮箱,我给你发送过去)。

2. caffe的数据内存分配类SyncedMemory, 以及类Blob数据传输的媒介.

主要内容: caffe源码分析-SyncedMemory caffe源码分析-Blob 其中Blob分析给出了其直接与opencv的图片相互转化以及操作,可以使得我们更好的理解Blob.

3. caffe layer的源码分析,包括从整体上说明了layer类别以及其proto定义与核心函数.

内容如下: caffe源码分析-layer caffe源码分析-ReLULayer caffe源码分析-inner_product_layer caffe源码分析-layer_factory

首先分析了最简单的layer Relu,然后在是inner_product_layer全连接层, 最后是layer_factorycaffe中 以此工厂模式create各种Layer.

4. 数据输入层,主要是多线程+BlockingQueue的方式读取数据训练:

内容如下: caffe源码分析-BlockingQueue caffe源码分析-InternalThread caffe源码分析-DataReader

5. IO处理例如读取proto文件转化为网络,以及网络参数的序列化

内容如下: caffe源码分析-DataTransformer caffe源码分析-db, io

6. 最后给出了使用纯C++结合多层感知机网络训练mnist的示例

内容如下:

caffe c++示例(mnist 多层感知机c++训练,测试)

类似与caffe一样按照layer、solver、loss、net等模块构建的神经网络实现可以见下面这篇blog,相信看懂了这个python的代码理解caffe框架会更简单点.

神经网络python实现


最后如果需要cmake + CLion直接运行调试caffe的代码工程,可以评论留下你的邮箱,我给你发送过去.

参考: https://www.jianshu.com/p/2e99bb0421c5 https://www.jianshu.com/p/b105578b214b

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • caffe源码分析-DataTransformer

    下面仅仅给出将Datum类型转化为caffe的Blob, cv::Mat的转化同理.

    bear_fish
  • Caffe学习:Blobs, Layers, and Nets

    -注意:网络结构是设备无关的,Blob和Layer=隐藏了模型定义的具体实现细节。定义网络结构后,可以通过Caffe::mode()或者Caffe::set_m...

    bear_fish
  • caffe源码分析-db, io

    主要内容: caffe源码分析-SyncedMemory caffe源码分析-Blob 其中Blob分析给出了其直接与opencv的图片相互转化以及操作,...

    bear_fish
  • [PYTHON] 核心编程笔记(16.P

    套接字只有两种一种是面向连接套接字,即在通讯之前一定要建立一条连接,这种通讯方式提供了顺序的,可靠的不会重复的数据传输,每一份要发送的信息都会拆分成多份,每份都...

    py3study
  • zephyr笔记 2.5.4 消息队列

    消息队列是实现简单消息队列的内核对象,允许线程和ISR异步发送和接收固定大小的数据项。

    twowinter
  • 进程间的通信

    py3study
  • Python--生成Wav格式文件

    scipy下载链接: http://www.scipy.org/Download#head-0dfc04e10313d2e70988c6cb3bef7a9e09...

    py3study
  • AI技术加持,让协作机器人更安全

    来自众家新创公司与实验室的碰撞侦测与追踪技术,将使得在人类与其他移动物体周边的协作机器人更安全。一个美国圣地亚哥大学(University of San Die...

    机器人网
  • 深入理解Java8并发工具类StampedLock

    StampedLock类是JDK8里面新增的一个并发工具类,这个类比较特殊,在此之前我们先简单的了解一下关于数据库或者存储系统的锁策略和机制。

    我是攻城师
  • HttpComponents HttpClient连接池(8)-SSL支持

    在上一篇文章里我们介绍了 httpclient 连接池的重试机制,在这里我们主要介绍连接池对于SSL的支持。

    TA码字

扫码关注云+社区

领取腾讯云代金券