caffe源码分析--SyncedMemory 内存管理机制

caffe源码分析–SyncedMemory 内存管理机制

​ SyncedMemory 是caffe中用来管理内存分配和CPU、GPU数据及同步的类,只服务于Blob类。SyncedMemory 对象管理的是一个tensor的数据对象,这个对象可能只存在CPU上,也有可能存在GPU上,或者同时在两个位置上,如何保证在CPU和GPU上的数据能同步呢?

1. 自动机模型管理

​ SyncedMemory 使用自动机模型对内存和显存进行管理。对每个SyncedMemory 对象都包含了一个*head_*的枚举变量。*head_*变量是SyncedMemory 对象内部变量,标志着目前被管理的数据对象的同步情况,定义如下:

private:
  void to_cpu(); //数据由显存同步到内存
  void to_gpu(); //数据由内存同步到显存
  void* cpu_ptr_;//内存指针
  void* gpu_ptr_;//显存指针
  size_t size_;  //数据大小
  SyncedHead head_;//当前数据状态,UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED

  //own_cpu_data_和own_gpu_data_这两个变量。这两个变量主要是用来记录是否使用了共享的数据还是自己的数据
  // 这里own_cpu_data_和own_gpu_data_不是互斥的关系,可以同时own两个地方的数据
  // 有一种可能是SyncedMemory对象所包含的数据指针,是指向的另外一段内存空间,而不由自己申请
  bool own_cpu_data_;
  bool cpu_malloc_use_cuda_;
  bool own_gpu_data_;
  int gpu_device_;

其中:*cpu_ptr_*指向CPU上的数据单元,gpu_ptr_*指向GPU上的数据单元。

SyncedHead定义如下:

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

SyncedHead是一个枚举类型,所以*head_*可取的值为:UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED

  • UNINITIALIZED:表示这个数据对象的存储空间没有被初始化,即SyncedMemory 最早的状态,内存和显存都没有被分配,当CPU或者GPU申请内存时该状态终结。

  • HEAD_AT_CPU:表明最近一次数据修改是由CPU引起的,CPU上的数据时最新的,此时CPU和GPU的数据还没有同步,CPU和GPU数据可能不同。

  • HEAD_AT_GPU:表明最近一次数据修改是由GPU引起的,GPU上的数据时最新的,此时CPU和GPU的数据还没有同步,CPU和GPU数据可能不同。

  • SYNCED:同步状态,表明CPU和GPU的数据一致。

    自动机的四个状态是如何转换呢?

    参考下图:

在这里插入图片描述

​ 他们会被相应的状态转移函数触发: to_cpu()、to_gpu()、mutable_cpu_data()、mutable_gpu_data()。 其中mutable_cpu_data()、mutable_gpu_data()函数主要目的是为了得到可修改的cpu和gpu指针,具体实现如下:

void* SyncedMemory::mutable_cpu_data() {
  to_cpu();
  head_ = HEAD_AT_CPU;
  return cpu_ptr_;
}

void* SyncedMemory::mutable_gpu_data() {
#ifndef CPU_ONLY
  to_gpu();
  head_ = HEAD_AT_GPU;
  return gpu_ptr_;
#else
  NO_GPU;
  return NULL;
#endif
}

​ mutable_cpu_data()调用to_cpu()函数、mutable_gpu_data()调用to_gpu()函数,并将*head_*修改为相应的值。

to_cpu()函数实现如下:

//函数作用是让现在数据最新备份至少出现在cpu上
//函数执行过程中,如果最新的数据在GPU上,那么把GPU的数据同步到CPU上
//这时候CPU和GPU都有最新的同步数据
//返回状态机结果是HEAD_AT_CPU或者SYNCED
//HEAD_AT_CPU -- 代表数据备份最新出现在CPU上, GPU上的数据不是最新的备份
//SYNCED -- 代表CPU和GPU数据都是最新
inline void SyncedMemory::to_cpu() {
  switch (head_) {
  case UNINITIALIZED:
  //如果SyncedMemory对象所对应的这段内存没有被初始化,那么在host上申请内存
    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: //表示目前数据是在GPU上
#ifndef CPU_ONLY
// 首先在Host上申请这么一段内存,然后把GPU上的数据,同步到CPU上,然后把head状态更新为同步
    if (cpu_ptr_ == NULL) {
      CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);
      own_cpu_data_ = true;
    }
    caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_);
    head_ = SYNCED;
#else
    NO_GPU;
#endif
    break;
  case HEAD_AT_CPU:
  case SYNCED:
    break;
  }
}

own_cpu_data_ 的作用是什么?

​ 如前注释:*own_cpu_data_own_gpu_data_这两个变量,这两个变量主要是用来记录是否使用了共享的数据还是自己的数据,to_cpu()代码中为cpu分配了内存,此时own_cpu_data_*设置为true,表示使用了当前自己的数据。而在set_cpu_date函数中:

void SyncedMemory::set_cpu_data(void* data) {
  CHECK(data);
  if (own_cpu_data_) {
    CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_);
  }
  cpu_ptr_ = data;
  head_ = HEAD_AT_CPU;
  own_cpu_data_ = false;
}

​ 可以看到set_cpu_data释放了当前的cpu内存,把指针指向data所指的内存中,own_cpu_data_ 设置为了false,表明当前使用的是宿主(data)的内存。

​ 我们对own_cpu_data_ 进行标记是有必要的,因为当使用的是宿主的内存的时候,当这个类被释放而调用析构函数时,需要检查共享标记,不能释放宿主的内存,这样可以保证自己申请的内存只能由自己释放。

to_gpu()函数实现如下:

//函数作用是让现在数据最新备份至少出现在GPU上
//函数执行过程中,如果最新的数据在CPU上,那么把CPU的数据同步到GPU上
//这时候CPU和GPU都有最新的同步数据
//返回状态机结果是HEAD_AT_CPU或者SYNCED
//HEAD_AT_GPU -- 代表数据备份最新出现在CPU上, CPU上的数据不是最新的备份
//SYNCED -- 代表CPU和GPU数据都是最新的
inline void SyncedMemory::to_gpu() {
#ifndef CPU_ONLY
  switch (head_) {
    //如果指针数据没有被分配,那么在GPU上重新分配
  case UNINITIALIZED:
    CUDA_CHECK(cudaGetDevice(&gpu_device_));
    CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_));
    caffe_gpu_memset(size_, 0, gpu_ptr_);
    head_ = HEAD_AT_GPU;
    own_gpu_data_ = true;
    break;
    //如果目前数据在CPU head上,那么把CPU上的数据,拷贝到GPU上
  case HEAD_AT_CPU:
    if (gpu_ptr_ == NULL) {
      CUDA_CHECK(cudaGetDevice(&gpu_device_));
      CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_));
      own_gpu_data_ = true;
    }
    caffe_gpu_memcpy(size_, cpu_ptr_, gpu_ptr_);
    head_ = SYNCED;
    break;
  case HEAD_AT_GPU:
  case SYNCED:
    break;
  }
#else
  NO_GPU;
#endif
}

什么时候改变状态机变量的值,即什么时候调用to_cpu, to_gpu函数

在blob对象访问CPU或者GPU数据指针的时候。

参考下面的调用关系:

​ 在conv_layer.cpp中Forward_cpu函数调用的是blob的cpu_data()函数,这个函数返回的是数据的实际指针。

template <typename Dtype>
void ConvolutionLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  const Dtype* weight = this->blobs_[0]->cpu_data();

  for (int i = 0; i < bottom.size(); ++i) {
    const Dtype* bottom_data = bottom[i]->cpu_data();
    Dtype* top_data = top[i]->mutable_cpu_data();

在blob的cpu_data()函数如下:

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

SyncedMemory对象的cpu_data()函数定义如下:

const void* SyncedMemory::cpu_data() {
  to_cpu();                 // 首先完成数据同步,第一次访问时会申请存储空间
  return (const void*)cpu_ptr_;
}

blob中*data_ *的定义如下:

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

2.源码注释

syncedmem.hpp

#ifndef CAFFE_SYNCEDMEM_HPP_
#define CAFFE_SYNCEDMEM_HPP_

#include <cstdlib>

#include "caffe/common.hpp"

namespace caffe {

// If CUDA is available and in GPU mode, host memory will be allocated pinned,
// using cudaMallocHost. It avoids dynamic pinning for transfers (DMA).
// The improvement in performance seems negligible in the single GPU case,
// but might be more significant for parallel training. Most importantly,
// it improved stability for large models on many GPUs.
//CUDA使用memory pinned技术,使用cudaMallocHost分配的内存,这样可以加速CPU和GPU数据的传输速度
//在多GPU训练下能起到大的作用
inline void CaffeMallocHost(void** ptr, size_t size, bool* use_cuda) {
#ifndef CPU_ONLY
  if (Caffe::mode() == Caffe::GPU) {
    CUDA_CHECK(cudaMallocHost(ptr, size));//GPU下使用cuda分配内存
    *use_cuda = true;
    return;
  }
#endif
  *ptr = malloc(size); //如果只是用cpu则用c的malloc分配内存
  *use_cuda = false;
  CHECK(*ptr) << "host allocation of size " << size << " failed";
}
//释放内存
inline void CaffeFreeHost(void* ptr, bool use_cuda) {
#ifndef CPU_ONLY
  if (use_cuda) {
    CUDA_CHECK(cudaFreeHost(ptr));
    return;
  }
#endif
  free(ptr);
}


/**
 * @brief Manages memory allocation and synchronization between the host (CPU)
 *        and device (GPU).
 *
 * TODO(dox): more thorough description.
 */
class SyncedMemory {
 public:
  //构造函数,参数列表初始化
  SyncedMemory()
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED),
        own_cpu_data_(false), cpu_malloc_use_cuda_(false), own_gpu_data_(false),
        gpu_device_(-1) {}
  explicit SyncedMemory(size_t size)
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(size), head_(UNINITIALIZED),
        own_cpu_data_(false), cpu_malloc_use_cuda_(false), own_gpu_data_(false),
        gpu_device_(-1) {}
  ~SyncedMemory(); //析构函数,调用CaffeFreeHost释放内存
  const void* cpu_data();        //获得cpu数据指针
  void set_cpu_data(void* data); //设置cpu使用共享数据
  const void* gpu_data();        //获得gpu数据指针
  void set_gpu_data(void* data); //设置gpu使用共享数据
  void* mutable_cpu_data();      //获取可更改的cpu数据指针
  void* mutable_gpu_data();      //获取可更改的gpu数据指针
  enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED }; //自动状态转换机状态
  SyncedHead head() { return head_; } //获取当前数据状态
  size_t size() { return size_; }

#ifndef CPU_ONLY
  void async_gpu_push(const cudaStream_t& stream);
#endif

 private:
  void to_cpu(); //数据由显存同步到内存
  void to_gpu(); //数据由内存同步到显存
  void* cpu_ptr_;//内存指针
  void* gpu_ptr_;//显存指针
  size_t size_;  //数据大小
  SyncedHead head_;//当前数据状态,UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED

  // 这里own_cpu_data_和own_gpu_data_不是互斥的关系,可以同时own两个地方的数据
  // own_cpu_data_和own_gpu_data_这两个变量。这两个变量主要是用来记录是否使用了共享的数据还是自己的数据
  // 有一种可能是SyncedMemory对象所包含的数据指针,是指向的另外一段内存空间,而不由自己申请
  bool own_cpu_data_; //共享标记,是否使用的是自己的cpu数据
  bool cpu_malloc_use_cuda_;
  bool own_gpu_data_; //共享标记,是否使用的是自己的gpu数据
  int gpu_device_;    //gpu设备

  DISABLE_COPY_AND_ASSIGN(SyncedMemory);
};  // class SyncedMemory

}  // namespace caffe

#endif  // CAFFE_SYNCEDMEM_HPP_

syncedmem.cpp

#include "caffe/common.hpp"
#include "caffe/syncedmem.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

SyncedMemory::~SyncedMemory() {
  if (cpu_ptr_ && own_cpu_data_) {
    CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_);  //own_cpu_data_为true时释放cpu内存,保证不释放宿主数据
  }

#ifndef CPU_ONLY
  if (gpu_ptr_ && own_gpu_data_) {
    int initial_device;
    cudaGetDevice(&initial_device);
    if (gpu_device_ != -1) {
      CUDA_CHECK(cudaSetDevice(gpu_device_));
    }
    CUDA_CHECK(cudaFree(gpu_ptr_)); //释放gpu内存
    cudaSetDevice(initial_device);
  }
#endif  // CPU_ONLY
}
//函数作用是让现在数据最新备份至少出现在cpu上
//函数执行过程中,如果最新的数据在GPU上,那么把GPU的数据同步到CPU上
//这时候CPU和GPU都有最新的同步数据
//返回状态机结果是HEAD_AT_CPU或者SYNCED
//HEAD_AT_CPU -- 代表数据备份最新出现在CPU上, GPU上的数据不是最新的备份
//SYNCED -- 代表CPU和GPU数据都是最新
inline void SyncedMemory::to_cpu() {
  switch (head_) {
  case UNINITIALIZED:
  //如果SyncedMemory对象所对应的这段内存没有被初始化,那么在host上申请内存
    CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);
    caffe_memset(size_, 0, cpu_ptr_); //将分配的内存全部初始化为0
    head_ = HEAD_AT_CPU;
    own_cpu_data_ = true;
    break;
  case HEAD_AT_GPU: //表示目前数据是在GPU上
#ifndef CPU_ONLY
// 首先在Host上申请这么一段内存,然后把GPU上的数据,同步到CPU上,然后把head状态更新为同步
    if (cpu_ptr_ == NULL) {
      CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);
      own_cpu_data_ = true;
    }
    caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_);
    head_ = SYNCED;
#else
    NO_GPU;
#endif
    break;
  case HEAD_AT_CPU:
  case SYNCED:
    break;
  }
}

//函数作用是让现在数据最新备份至少出现在GPU上
//函数执行过程中,如果最新的数据在CPU上,那么把CPU的数据同步到GPU上
//这时候CPU和GPU都有最新的同步数据
//返回状态机结果是HEAD_AT_CPU或者SYNCED
//HEAD_AT_GPU -- 代表数据备份最新出现在CPU上, CPU上的数据不是最新的备份
//SYNCED -- 代表CPU和GPU数据都是最新的
inline void SyncedMemory::to_gpu() {
#ifndef CPU_ONLY
  switch (head_) {
    //如果指针数据没有被分配,那么在GPU上重新分配
  case UNINITIALIZED:
    CUDA_CHECK(cudaGetDevice(&gpu_device_));
    CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_));
    caffe_gpu_memset(size_, 0, gpu_ptr_);
    head_ = HEAD_AT_GPU;
    own_gpu_data_ = true;
    break;
    //如果目前数据在CPU head上,那么把CPU上的数据,拷贝到GPU上
  case HEAD_AT_CPU:
    if (gpu_ptr_ == NULL) {
      CUDA_CHECK(cudaGetDevice(&gpu_device_));
      CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_));
      own_gpu_data_ = true;
    }
    caffe_gpu_memcpy(size_, cpu_ptr_, gpu_ptr_);
    head_ = SYNCED;
    break;
  case HEAD_AT_GPU:
  case SYNCED:
    break;
  }
#else
  NO_GPU;
#endif
}
//获得cpu数据指针
const void* SyncedMemory::cpu_data() {
  to_cpu();                 // 首先完成数据同步,第一次访问时会申请存储空间
  return (const void*)cpu_ptr_;
}
//设置cpu共享数据
void SyncedMemory::set_cpu_data(void* data) {
  CHECK(data);
  if (own_cpu_data_) {
    CaffeFreeHost(cpu_ptr_, cpu_malloc_use_cuda_);
  }
  cpu_ptr_ = data;
  head_ = HEAD_AT_CPU;
  own_cpu_data_ = false;
}
//获得gpu数据指针
const void* SyncedMemory::gpu_data() {
#ifndef CPU_ONLY
  to_gpu();
  return (const void*)gpu_ptr_;
#else
  NO_GPU;
  return NULL;
#endif
}
//设置gpu共享数据
void SyncedMemory::set_gpu_data(void* data) {
#ifndef CPU_ONLY
  CHECK(data);
  if (own_gpu_data_) {
    int initial_device;
    cudaGetDevice(&initial_device);
    if (gpu_device_ != -1) {
      CUDA_CHECK(cudaSetDevice(gpu_device_));
    }
    CUDA_CHECK(cudaFree(gpu_ptr_));
    cudaSetDevice(initial_device);
  }
  gpu_ptr_ = data;
  head_ = HEAD_AT_GPU;
  own_gpu_data_ = false;
#else
  NO_GPU;
#endif
}

void* SyncedMemory::mutable_cpu_data() {
  to_cpu();
  head_ = HEAD_AT_CPU;
  return cpu_ptr_;
}

void* SyncedMemory::mutable_gpu_data() {
#ifndef CPU_ONLY
  to_gpu();
  head_ = HEAD_AT_GPU;
  return gpu_ptr_;
#else
  NO_GPU;
  return NULL;
#endif
}

//async_gpu_push 这个函数的作用是异步同步数据流,就是实现cpu的数据复制到gpu里面。使用异步方式可以有效的防止主进程阻塞。
#ifndef CPU_ONLY
void SyncedMemory::async_gpu_push(const cudaStream_t& stream) {
  CHECK(head_ == HEAD_AT_CPU);
  if (gpu_ptr_ == NULL) {
    CUDA_CHECK(cudaGetDevice(&gpu_device_));
    CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_));
    own_gpu_data_ = true;
  }
  const cudaMemcpyKind put = cudaMemcpyHostToDevice;
  CUDA_CHECK(cudaMemcpyAsync(gpu_ptr_, cpu_ptr_, size_, put, stream));
  // Assume caller will synchronize on the stream before use
  head_ = SYNCED;
}
#endif

}  // namespace caffe


参考:

1.https://blog.csdn.net/qq_28660035/article/details/80347208

2.https://blog.csdn.net/hnshahao/article/details/81218713

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 安装caffe-ssd-gpu在ubuntu18.04的步骤如下: 1. 安装CUDA:从Nvidia官网下载合适的CUDA安装包,按照官方文档的指引进行安装。 2. 安装依赖:运行以下命令安装所需依赖库: ``` sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev \ libopencv-dev libhdf5-serial-dev protobuf-compiler \ libgflags-dev libgoogle-glog-dev liblmdb-dev libboost-all-dev ``` 3. 下载caffe-ssd-gpu源码并编译:从Github上下载caffe-ssd-gpu的源码,按照官方文档指引进行编译。编译时需要指定编译选项为GPU模式。 4. 运行测试:安装完成后,运行测试脚本,确保安装配置成功。 以上为简要步骤,具体操作请参考对应文档和官方指引。 ### 回答2: Ubuntu18.04是目前比较常见的Linux操作系统之一,而CAFFE-SSD-GPU是深度学习的一个工具。下面是安装caffe-ssd-gpu的步骤: 1. 安装CUDA和cuDNN 首先,您需要安装CUDA和cuDNN,这是运行深度学习框架所需的必备组件。下载安装CUDA和cuDNN之前,您需要查看您的图形卡的型号,以便选择正确的CUDA版本和cuDNN版本。 在下载和安装CUDA和cuDNN之前,您需要在NVIDIA的开发者网站上注册自己,并下载适用于您机器的CUDA和cuDNN版本。此外,您还需要在命令行界面中设置以下环境变量: export PATH=/usr/local/cuda-8.0/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64:$LD_LIBRARY_PATH 2. 安装依赖项 在安装caffe之前,需要安装一些依赖项。您可以使用以下命令将这些依赖项安装到您的Ubuntu系统上: sudo apt-get update sudo apt-get install -y libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libboost-all-dev libhdf5-serial-dev protobuf-compiler gfortran libjpeg62 libfreeimage-dev libatlas-base-dev git python-dev python-pip libgoogle-glog-dev libbz2-dev libxml2-dev libxslt-dev libffi-dev libssl-dev libgflags-dev liblmdb-dev python-yaml python-numpy python-scipy 3. 下载和安装CAFFE 现在,您需要在您的系统上下载和安装CAFFE。从github上获取caffesource代码并进行安装: git clone https://github.com/weiliu89/caffe.git cd caffe git checkout ssd 4. 编译和安装CAFFE 使用以下命令编译和安装caffe: cp Makefile.config.example Makefile.config make all -j $(($(nproc) + 1)) make pycaffe 执行该命令后,您需要等待一段时间才能完成CAFFE的编译。如果出现任何编译错误,请检查您的CUDA和cuDNN版本是否正确,并重新安装依赖项。 5. 使用CAFFE-SSD-GPU 现在,您已经成功地在Ubuntu18.04操作系统上安装并编译了CAFFE-SSD-GPU,您可以开始使用该工具来执行深度学习任务了。 总结 安装CAFFE-SSD-GPU需要充分理解linux的命令行操作。需要先确认CUDA和cuDNN已经安装,并正确设置环境变量。然后需要下载和安装CAFFE, 并最后编译和安装CAFFE。在安装过程中如果存在问题,可以查看错误日志,重新检查步骤。如果对命令行操作不熟悉,则先学习linux基础操作。 ### 回答3: caffe-ssd-gpu是一种基于caffe框架的用于实现目标检测的神经网络模型,在Ubuntu18.04系统中安装caffe-ssd-gpu需要进行以下步骤: 1. 安装CUDA CUDA是NVIDIA公司推出的用于高性能计算的并行计算平台和编程模型,是使用GPU进行深度学习任务所必需的。在Ubuntu18.04上安装CUDA需要首先确认自己的显卡型号,并选择合适的CUDA版本进行安装。可以在NVIDIA官网上下载相应的CUDA安装包,也可以通过命令行方式进行安装。在安装过程中注意要按照提示完成相应的配置和设置。 2. 安装cuDNN cuDNN是用于深度神经网络的GPU加速库,也是必需的组件之一。在安装过程中同样需要确认CUDA的版本和自己的显卡型号,并下载相应的cuDNN安装包进行安装。 3. 安装依赖包 在安装caffe-ssd-gpu前需要先安装几个依赖包,包括protobuf、opencv、boost等。可以通过命令行方式进行安装,例如: ``` sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libboost-all-dev libhdf5-serial-dev libgflags-dev libgoogle-glog-dev liblmdb-dev ``` 4. 下载caffe-ssd-gpu源码 可以在GitHub上找到caffe-ssd-gpu的源码,下载后解压到自己想要的目录下。 5. 编译和安装caffe-ssd-gpu 进入caffe-ssd-gpu源码目录下,执行以下命令: ``` cd caffe-ssd-gpu mkdir build cd build cmake .. make all -j8 make install ``` 其中,make all -j8表示使用8个线程进行编译,提高编译速度。make install表示安装编译好的caffe-ssd-gpu库文件和可执行文件。 6. 测试安装是否成功 可以尝试运行caffe-ssd-gpu自带的测试程序,检查安装是否成功。在源码目录下执行以下命令: ``` ./build/tools/caffe time --model=models/VGGNet/VOC0712/SSD_300x300_ft/deploy.prototxt --gpu=0 ``` 这条命令会测试caffe-ssd-gpu在GPU上执行推断的速度,如果没有问题,则说明安装成功。 需要注意的是,在安装过程中可能会遇到各种问题,例如依赖包的版本不兼容、CUDA和cuDNN的配置出错等等。这时候需要耐心调试错误,逐个解决问题,才能确保caffe-ssd-gpu能够正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值