日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

caffe blob操作

發(fā)布時(shí)間:2023/12/4 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 caffe blob操作 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

http://blog.luoyetx.com/2015/10/reading-caffe-2/

Blob 在 Caffe 中扮演了重要的角色,用于存儲(chǔ)數(shù)據(jù)和網(wǎng)絡(luò)參數(shù),同時(shí)也在 CPU 和 GPU 之間做了數(shù)據(jù)同步。Blob 原本在 Caffe 中被表示為一個(gè) 4 維數(shù)組 (num x channel x height x width),現(xiàn)在可以表示多維數(shù)組,最高維數(shù)由宏?kMaxBlobAxes?確定,目前 blob.hpp 中設(shè)置了?const int kMaxBlobAxes = 32;。Blob 類的代碼主要集中在 blob.hpp 和 blob.cpp 中。

數(shù)據(jù)與相關(guān)操作函數(shù)

Blob 類主要包括如下成員

1 2 3 4 5 6 shared_ptr<SyncedMemory> data_; // data 數(shù)據(jù) shared_ptr<SyncedMemory> diff_; // diff 數(shù)據(jù) shared_ptr<SyncedMemory> shape_data_; // 每一維數(shù)據(jù)的大小 vector<int> shape_; // 跟 shape_data_ 一樣 int count_; // 當(dāng)前容納的數(shù)據(jù)大小 int capacity_; // 最大能夠容納的數(shù)據(jù)大小

其中 SyncedMemory 主要用來(lái)實(shí)現(xiàn)數(shù)據(jù)在 CPU 和 GPU 上的管理。同時(shí) Blob 類提供一組函數(shù)來(lái)操作這些數(shù)據(jù)。

1 2 3 4 5 6 7 8 9 10 const Dtype* cpu_data() const; void set_cpu_data(Dtype* data); const int* gpu_shape() const; const Dtype* gpu_data() const; const Dtype* cpu_diff() const; const Dtype* gpu_diff() const; Dtype* mutable_cpu_data(); Dtype* mutable_gpu_data(); Dtype* mutable_cpu_diff(); Dtype* mutable_gpu_diff();

我們可以通過這些函數(shù)拿到 Blob 內(nèi)部的數(shù)據(jù)包括修改 Blob 的內(nèi)部數(shù)據(jù)。其中的 Dtype 是泛型類型,在定義 Blob 變量時(shí)設(shè)置的,一般為 float 或者 double。

Blob 類在內(nèi)部所存儲(chǔ)的數(shù)據(jù)是一塊連續(xù)的內(nèi)存,為了表示多維數(shù)組,shape_ 和 shapedata?記錄了每一維的大小,這樣就能夠很輕松地從給出的坐標(biāo)中計(jì)算出 offset 從而得到那個(gè)點(diǎn)的數(shù)據(jù)。由于 Blob 主要還是用來(lái)表示 4 維數(shù)組 (最初就是這樣的),Blob 類中仍使用了?int num(); int channels(); int height(); int width();?這些函數(shù),其實(shí) num 等價(jià)于 shape()[0],channels 等價(jià)于 shape()[1],height 等價(jià)于 shape()[2],width 等價(jià)于 shape()[3]。計(jì)算 offset 時(shí)可以使用這四個(gè)數(shù)字或者直接給出坐標(biāo)。

1 2 int offset(const int n, const int c = 0, const int h = 0, const int w = 0); int offset(const vector<int>& indices);

有了 Blob 提供的這組函數(shù)和上一組函數(shù),我們就可以輕易地操作 Blob 內(nèi)部的數(shù)據(jù)了。

動(dòng)態(tài)多維數(shù)組

Blob 類可以動(dòng)態(tài)改變數(shù)組的尺寸,當(dāng)拓展數(shù)組導(dǎo)致原有內(nèi)存空間不足以存放下數(shù)據(jù)時(shí) (count?> capacity),就會(huì)重新分配內(nèi)存。Blob 提供了一組 Reshape 函數(shù)來(lái)完成這個(gè)功能。

1 2 3 4 void Reshape(const int num, const int channels, const int height, const int width); // Deprecated void Reshape(const vector<int>& shape); void Reshape(const BlobShape& shape); void ReshapeLike(const Blob& other);

Blob 類在初始化時(shí)并沒有分配內(nèi)存,也是通過調(diào)用 Reshape 來(lái)分配內(nèi)存的。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 template <typename Dtype> void Blob<Dtype>::Reshape(const vector<int>& shape) { CHECK_LE(shape.size(), kMaxBlobAxes); // 檢查維數(shù) count_ = 1; // 用于計(jì)算新的多維數(shù)組的大小 shape_.resize(shape.size()); // 更新維數(shù) if (!shape_data_ || shape_data_->size() < shape.size() * sizeof(int)) { // shape_data_ 未初始化或者內(nèi)存太小 shape_data_.reset(new SyncedMemory(shape.size() * sizeof(int))); } int* shape_data = static_cast<int*>(shape_data_->mutable_cpu_data()); for (int i = 0; i < shape.size(); ++i) { CHECK_GE(shape[i], 0); CHECK_LE(shape[i], INT_MAX / count_) << "blob size exceeds INT_MAX"; count_ *= shape[i]; shape_[i] = shape[i]; shape_data[i] = shape[i]; } if (count_ > capacity_) { // 內(nèi)存不夠 capacity_ = count_; data_.reset(new SyncedMemory(capacity_ * sizeof(Dtype))); diff_.reset(new SyncedMemory(capacity_ * sizeof(Dtype))); } }

SyncedMemory

Blob 事實(shí)上是對(duì) SyncedMemory 的封裝。SyncedMemory 完成了對(duì)內(nèi)存的實(shí)際操作,包括數(shù)據(jù)在 CPU 和 GPU 上的同步。

1 2 3 4 5 6 7 8 9 10 enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED }; void* cpu_ptr_; // cpu 數(shù)據(jù) void* gpu_ptr_; // gpu 數(shù)據(jù) size_t size_; // 數(shù)據(jù)大小 SyncedHead head_; // 數(shù)據(jù)同步狀態(tài) bool own_cpu_data_; // 是否擁有當(dāng)前 cpu 數(shù)據(jù) bool cpu_malloc_use_cuda_; // 是否采用 CUDA 來(lái)分配 CPU 數(shù)據(jù),默認(rèn)不用 bool own_gpu_data_; // 是否擁有當(dāng)前 gpu 數(shù)據(jù) int gpu_device_; // gpu 數(shù)據(jù)所在的顯卡號(hào)

SyncedMemory 內(nèi)部存放了兩份數(shù)據(jù),分別位于 CPU 和 GPU 上,用 cpu_ptr 和 gpu_ptr 表示。同時(shí) SyncedMemory 也給出了一組函數(shù)來(lái)獲取和設(shè)置實(shí)際數(shù)據(jù)。

1 2 3 4 5 6 const void* cpu_data(); void set_cpu_data(void* data); const void* gpu_data(); void set_gpu_data(void* data); void* mutable_cpu_data(); void* mutable_gpu_data();

head_ 表示了數(shù)據(jù)的同步狀態(tài),通過調(diào)用?to_cpu()?和?to_gpu()?來(lái)做同步。如果 head_ = UNINITIALIZED 則分配相應(yīng)的內(nèi)存。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 inline void SyncedMemory::to_cpu() { switch (head_) { case UNINITIALIZED: CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_); // 分配內(nèi)存 caffe_memset(size_, 0, cpu_ptr_); // 初始化為 0 head_ = HEAD_AT_CPU; own_cpu_data_ = true; break; case HEAD_AT_GPU: #ifndef CPU_ONLY if (cpu_ptr_ == NULL) { // 如果未初始化,則分配內(nèi)存 CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_); own_cpu_data_ = true; } // 復(fù)制 GPU 數(shù)據(jù)到 CPU caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_); head_ = SYNCED; #else NO_GPU; #endif break; case HEAD_AT_CPU: case SYNCED: break; } } inline void SyncedMemory::to_gpu() { #ifndef CPU_ONLY switch (head_) { case UNINITIALIZED: CUDA_CHECK(cudaGetDevice(&gpu_device_)); // 獲取顯卡號(hào) CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); // 在指定顯卡上分配內(nèi)存 caffe_gpu_memset(size_, 0, gpu_ptr_); // 初始化為 0 head_ = HEAD_AT_GPU; own_gpu_data_ = true; break; case HEAD_AT_CPU: if (gpu_ptr_ == NULL) { // 未初始化就在指定顯卡上分配內(nèi)存 CUDA_CHECK(cudaGetDevice(&gpu_device_)); CUDA_CHECK(cudaMalloc(&gpu_ptr_, size_)); own_gpu_data_ = true; } caffe_gpu_memcpy(size_, cpu_ptr_, gpu_ptr_); // 復(fù)制數(shù)據(jù) head_ = SYNCED; break; case HEAD_AT_GPU: case SYNCED: break; } #else NO_GPU; #endif }

數(shù)據(jù)序列化

Blob 數(shù)據(jù)可以通過 Protobuf 來(lái)做相應(yīng)的序列化操作,ToProto?和?FromProto?完成相應(yīng)的序列化操作。

1 2 3 4 5 6 7 8 9 10 11 12 13 message BlobProto { optional BlobShape shape = 7; repeated float data = 5 [packed = true]; repeated float diff = 6 [packed = true]; repeated double double_data = 8 [packed = true]; repeated double double_diff = 9 [packed = true]; // 4D dimensions -- deprecated. Use "shape" instead. optional int32 num = 1 [default = 0]; optional int32 channels = 2 [default = 0]; optional int32 height = 3 [default = 0]; optional int32 width = 4 [default = 0]; }

小結(jié)

Caffe 通過 SyncedMemory 和 Blob 封裝了底層數(shù)據(jù),為 Caffe 框架上的其他組件提供最基礎(chǔ)的數(shù)據(jù)抽象,后面的 Layer 參數(shù),Net 參數(shù)以及 Solver 的參數(shù)等都是 Blob 數(shù)據(jù),所以理解 Blob 抽象和管理數(shù)據(jù)的實(shí)現(xiàn)方式有助于后續(xù) Caffe 源碼的閱讀,也是閱讀 Caffe 源碼的第一步。


總結(jié)

以上是生活随笔為你收集整理的caffe blob操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。