簡(jiǎn)介
Blob用于存儲(chǔ)和交換一個(gè)network中所有需要用到的數(shù)據(jù), 包括:
- 每一層的輸入和輸出數(shù)據(jù)
- 每一層的參數(shù)(如果該層含可訓(xùn)練參數(shù)的話(huà))
對(duì)于實(shí)際操作的數(shù)據(jù), blob提供了良好的封裝, 并且保證了CPU和GPU之間的數(shù)據(jù)同步. 直觀(guān)來(lái)說(shuō), blob是一個(gè)行優(yōu)先的N維數(shù)組. 以常用的 4D 數(shù)據(jù)舉例, 每一維為 N number * K channels * H height * W width, 那么(n, k, h, w)的物理地址為 ((n * K + k) * H + h) * W + w.
注意雖然常用的圖片數(shù)據(jù)是4D的, 但是caffe也支持其他維度的blob.
成員變量
Blob類(lèi)的成員變量如下,
shared_ptr<SyncedMemory> data_; \\ 數(shù)據(jù)本身
shared_ptr<SyncedMemory> diff_; \\ 數(shù)據(jù)的derivative
shared_ptr<SyncedMemory> shape_data_; \\ 老版本的shape_數(shù)據(jù)
vector<int> shape_; \\ 當(dāng)前blob的數(shù)據(jù)形狀, e.g. shape_[0]: num, shape_[1]: channels
int count_; \\ 當(dāng)前blob的數(shù)據(jù)元素總個(gè)數(shù): count_ = shape_[0]*shape_[1]*...*shape_[end]
int capacity_; \\ 當(dāng)前blob的物理元素個(gè)數(shù)
下面我們來(lái)看Blob中的幾個(gè)主要方法
Reshape
void Blob<Dtype>::Reshape(const vector<int>& shape)
Reshape函數(shù)根據(jù)輸入shape更新count_
. 如果需要的元素個(gè)數(shù) count_
> 當(dāng)前實(shí)際物理元素個(gè)數(shù) capacity_
, 那么就需要重新分配內(nèi)存空間, 并且更新capacity_
值. 否則僅僅更新shape_, shape_data_, count_
值. 這樣做的好處是, 如果實(shí)際物理容量足夠, 那么就不會(huì)頻繁重新分配物理空間.
獲取data, diff指針
Blob提供了data_, diff_
的指針, 其中cpu_data()
獲取的指針是const
, 不能夠改變數(shù)據(jù)內(nèi)容. 如需要改變數(shù)據(jù)內(nèi)容, 需要使用mutable_cpu_data()
.
注意mutable_cpu_data()
獲取的是GPU memory中的數(shù)據(jù)指針, 不同在cpu程序中直接訪(fǎng)問(wèn)讀寫(xiě), 需要通過(guò)kernel函數(shù)訪(fǎng)問(wèn).
update
如果Blob保存的是layer 參數(shù), 在backpropagation時(shí), 需要對(duì)參數(shù)進(jìn)行更新, update執(zhí)行下面的操作
caffe_axpy<Dtype>(count_, Dtype(-1),
static_cast<const Dtype*>(diff_->cpu_data()),
static_cast<Dtype*>(data_->mutable_cpu_data()));
這里調(diào)用的是 caffe_axpy
函數(shù), 這個(gè)函數(shù)的數(shù)學(xué)表達(dá)為: a*x+y
, 即 a multiply by x plus y (因此叫axpy). 這里 a=-1
, 因此實(shí)際意義就是梯度下降里的參數(shù)更新公式:
data = -diff + data