下面是基於我自己的接口,我是用來分類一維數據的,可能不具通用性:
(前提,你已經編譯了caffe的python的接口)
添加 caffe塻塊的搜索路徑,當我們import caffe時,可以找到。
對於這一步,一般我們都會把 cafffe 模塊的搜索路經永久地加到先加$PYTHONPATH中去,如可以把 export PYTHONPATH=/path/to/caffe/python:$PYTHONPATH 寫到 .bashrc中。而下面的做法,只是臨時的做法哦;
improt sys #sys.path為一個列表,用什么方法加入都好啊,我用insert直接插到首位 sys.path.insert(0, ‘caffe_python的路徑,我的為~/down/caffe/python/')
設置使用的設備:
在用顯卡並行運算算的時候,如果多顯卡的時候,輸入它們的序號表示使用哪一塊卡,如果單顯卡的話(比如我的筆記本電腦,應該都為0,表示第一塊)。
caffe.set_device(0)
caffe.set_mode_gpu()
caffe.set_mode_cpu() #使用caffe的GPU模式
設定網絡的solver:
選中我們的solver_prototxt文件,里面就是設定了網絡的訓練次數啦,各參數的值啦等啦。
solver = None #選用SGD算法來進行運算; solver = caffe.SGDSolver('你的網絡的lenet_solver.prototxt 文件‘)
# 執行完上面的語句以后,網絡的相應的權值與偏置會根據我們的定義進行賦值的;
caffe中的數據保存及調用:
在caffe中,我們的網絡可以分為訓練網絡與測試網絡哦,訓練網絡用solver.net.blobs、solver.net.params;對面測試網絡,用solver.test_nets[i].blobs、solver.test_nets[i].params(其中 i 表示 第幾個測試網絡,從0開始。例如,我們就一個測試網絡的話,我們就寫為:solver.test_nets[0].blobs。)
下面,我們以訓練網絡為例子,看看caffe中的數據的存儲與調用方法。 caffe的 數據都是放在 blobs塊中的,我覺得這個好牛逼啊,太統一了。
solver.net.blobs 里面放的為每一層layer輸出的data、對輸出結點求的導數 diff,另外還有幾個如count等參數,不過我們基本用不到的,不要關注一下data數據就可以了。
#solver.net.blobs為一個字典的數據類型,里面的key值為各個layer 的名字,value為caffe的blob塊;
solver.net.blobs
#輸出:
rderedDict([('data', <caffe._caffe.Blob at 0x7f7bde968398>), ('label', <caffe._caffe.Blob at 0x7f7bde968488>), ('conv1', <caffe._caffe.Blob at 0x7f7bde968578>), ('pool1', <caffe._caffe.Blob at 0x7f7bde968e60>), ('conv2', <caffe._caffe.Blob at 0x7f7bde9686e0>), ('pool2', <caffe._caffe.Blob at 0x7f7bde968cf8>), ('ip1', <caffe._caffe.Blob at 0x7f7bde968c80>), ('ip2', <caffe._caffe.Blob at 0x7f7bde968c08>), ('loss', <caffe._caffe.Blob at 0x7f7bde968b90>)]) #我們可以訪問Blob塊里的內容了,通過看Blob塊的源碼你會發現里面有data, diff,count等內容的。
#我們以conv1層為例子,我們訪問 conv1的輸出的數據,可以通過下面的語句:
solver.net.blobs['data'].data
solver.net.blobs['data'].diff
#如果想看它們的數據結構,可以通過下面的語句得到:
solver.net.blobs['data'].data.shape
solver.net.blobs['data'].diff.shape
#另外,還可以通過reshape()transpose()等操作對它們變形,應該是對數組的操作之類的吧。
solver.net.params為一個字典的數據類型,里面放的是與連接的權值及偏置相關的數據,如:data(表示權值的大小),diff(對於權值的導數),還有 count 之類的,我們只關注一個 data 就可以了吧。
solver.net.params[網絡的名字][0]
#solver.net.params為一個字典的數據類型,key值為layer 的名字,value為caffe的blob塊的容器哦; solver.net.forward() #輸出為: solver.net.params orderedDict([ ('conv1', <caffe._caffe.BlobVec at 0x7f7bffd68578>), ('conv2', <caffe._caffe.BlobVec at 0x7f7bde9ff6e0>), ('ip1', <caffe._caffe.BlobVec at 0x7f7bde968f80>), ('ip2', <caffe._caffe.BlobVec at 0x7f7bde968408>)])
#下面,我們可以訪問Blob塊里的內容了。#們以conv1層為例子,具體如下:
#sover.net.params['conv1'][0]里面放是與連接權值相關的數據;可以通過下面方式訪問:
solver.net.params['conv1'][0].data
solver.net.params['conv1'][0].diff
#solver.net.params['conv1'][1]里面放的是與偏置相關的的值、導數等;可以通過下面方式訪問:
solver.net.params['conv1'][1].data
solver.net.params['conv1'][1].diff
#同樣,我們可以還可以通過它們進行 shape()、reshape()、transpose()等操作
前向傳播與反向傳播
進行一次前向傳播:使用 solver.net.forward或 solver.test_nets[i].forward 語句: 它干了點什么呢?它把數據從輸入層到最后的輸出層傳播了一個遍,把相應的每一層網絡的輸出值賦於blobs,網絡輸入的的數據個數為你的net的定義文件里的patch_size的大小。
#訓練數據作為輸入,進行一次前向傳播: solver.net.forward()
#假如有300個數據,我們的patch_size的大小為100,那么:
solver.net.forward() #數據為1-100;
solver.net.forward() #數據為101-200
solver.net.forward() #數據為201-300
solver.net.forward() #數據為1-100
#另外,我們可以設置forward開始的地方,如下面所示:
solver.net.forward(start ='conv1') #表示從conv1開始,這樣的話,data層這不用傳用新的數據了。
進行反向傳播:使用:solver.net.forward,基本是都是我們的訓練網絡會進行反向傳播的。反向傳播做了點什么事呢?把會求出相應的導數啦,即blobs塊里面的diff變量。
記住:它不會去更新權值與偏置的;
# 進行一次反向傳播
solver.net.forward()
進行完整的一次計算(minibatch):solver.step(1):(包括數據的前向傳播,誤差反向傳播,以及網絡權值的update)
#當我們完整地進行一次權值更新地時候,我們可以調用下面的語句 #把意思就是:訓練網絡進行一次正向與反向傳播,並進行更新權值與偏置; sover.step(n)表示進行n次訓練。 # 表示進行n次訓練。 sover.step(n)
注意:當我們用python接口運行caffe時,我們就可以控制它的Loop過程了,然后跟蹤很多變量,干點自己想干的事啦等。 除此之外,與直接用caffe的C++代碼且沒有什么差別,並且在sover prototxt定義的相關操作都會進行的,如logging, snapshot, test等。
2017年3月10日添加,有點亂,沒有整理:
solver.solve(), 會進行完整的梯度訓練,直至在solver中規定的max_iter.
用 caffe_root/python/draw_net.py 畫出 網絡的結構圖:
第一點:需要安裝:graphviz, 可以直接通過 sudo apt-get install graphviz,安裝就可以了。
第二點:安裝pydot 模塊,可以通過 pip pydot安裝,注意:pydot 不支持python3, 所以,我們也可以安裝 pydotplus來代替, pip install pydotplus;
現在,就可以運行 draw_net.py 畫圖了,例子如下:
./draw_net.py my_net.prototxt my_picture.png
caffe中,在訓練過程中,關於進行snapshot的相關問題:
除了我們可以在solver.prototxt 文件里定義相關的snapshot外,我們呢,也可以在訓練過程中,進行手動 保存;在進行snapshot時,會保存下面兩個文件:
.caffemodel :
The caffemodel, which is output at a specified interval while training, is a binary contains the current state of the weights for each layer of the network.
.solverstate:
The solverstate, which is generated alongside, is a binary contains the information required to continue training the model from where it last stopped.
方法一: solver.snapshot(), 可以在訓練過程中,手動進行snapshot.,它會保存 .caffenodel與 .solverstate兩個文件;常用於進行恢復訓練過程;(保存的路徑為solver.prototxt 文件里面定義的路徑)
方法二:net.save(), 它只會保存一下 .caffemodel文件,常用於進行測試時。 使用方法:如, net. save(‘my_path/my_weights.caffemodel’);
關於在pycaffe中載入solver.ptototxt 文件的問題:
兩個方法:
第一,當使用 caffe.SGDSolver(‘solver文件’)時,無論你的solver文件中定義的solver_type是什么,都會用SGD方法;
第二,solver = caffe.get_solver(‘里面是solver.prototxt文件’);
怎么導入網絡以及它的相關權值進行測試呢,可以這么做:
第一,直接進行導入權值進行測試時,我們可能用到:
net = caffe.Net(網絡的定義文件, caffemodel的權值保存文件,選擇:caffe.TEST) ,因為一個.prototxt文件中可以即定義train,也定義test,對應的caffe.TRAIN與caffe.TEST.
如一個例子:
net = caffe.Net('models/bvlc_reference_caffenet/deploy.prototxt', 'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel', caffe.TEST)
第二,在預訓練的基礎上再訓練網絡時,我們不僅僅導入了預訓練的權值,還導入 solver.prototxt
如果我們要在預訓練的基礎上再用新定義的solver.prototxt文件訓練我們的網絡,我們可以這么做:(區別就是我們不會隨機初始化權值,而是直接導入pretrained的權值)
my_solver = caffe.get_solver(net_solver.prototxt)
my_solver.net.copy_from(pretraind.caffemodel)
2017年8月14日補:
solver.iter : 這是一個變量,它會標識了迭代次數;
。