2016年6月26日 星期日

Synology NAS在雙路由器下的port forwarding設定方法

    在安裝好NAS之後,若要使用像是Synology在手持裝置上提供的DS file,可能需要對路由器做port forwarding設定。如果今天我們的NAS是經過兩個路由器連接後才進入網際網路,那就要對兩個路由器都設定port forwarding。
    我的網路連接狀況如下(圖1)

圖1

    首先我們要先弄清楚我們機器的IP。在DSM 6.0.1下,NAS的IP可以在控制台->網路->網路
介面->區域網路->IP位址
下找到(圖2)

圖2

這個位址(192.168.0.101)就是Router 1分配給NAS的位址。若我們打開電腦上控制台->網路和網際網路->網路和共用中心->變更介面卡設定->乙太網路->狀態->詳細資料->IPv4位址,我們可以看到我們電腦的位址(圖3)

圖3

可以看到這個位址(192.168.0.100)和NAS的位址只差了1號,這是因為router在分配位址時習慣相差1號。
    接下來我們要知道Router 1的位址,這可以在Router 1的管理頁面找到。我們可以在NAS上的控制台->網路->一般->一般->預設閘道器(gateway)(圖4)或是電腦上的控制台->網路和網際網路->網路和共用中心->變更介面卡設定->乙太網路->狀態->詳細資料->IPv4 預設閘道(圖5)看到

 圖4

圖5

我們在瀏覽器上輸入這個位址(192.168.0.1)即可登入Router 1的管理頁面(圖6)

圖6

這個畫面每家路由器都不太一樣,我是以TP-LINK為例。在狀態->網際網路(WAN)找到IP位址以及預設閘道(圖7),IP位址(192.168.1.111)就是Router 2給Router 1分配的位址,預設閘道(192.168.1.1)即為我們登入Router 2管理畫面的位址。

圖7

在瀏覽器輸入預設閘道位址(192.168.1.1),進入Router 2的管理畫面。可以在IP位址找到網際網路的IP位址(圖8)

圖8

現在我們可以知道我們網路整體的位址狀況了(圖9)

圖9

port forwarding的目的就是讓路由器看到特定port的封包時,可以按照設定的方式轉送給特定的區域網路IP。我們進入Router 1的管理畫面,並進入通訊埠導向(圖10)

圖10

點選新增,照圖11的方式進行設定

圖11

IP位址的部分填上要導向的IP位址,因為Router 1要導向NAS,因此填入NAS的IP(192.168.0.101)。服務通訊埠和內部通訊埠兩個選項,在有些路由器中稱為通訊埠開始以及通訊埠結束,就填上服務的port編號,以Synology的DS file為例,是5000。兩個都填一樣就可以了。通訊協定是TCP。這些在Synology的說明網站可以找到(https://www.synology.com/zh-tw/knowledgebase/DSM/tutorial/General/What_network_ports_are_used_by_Synology_services)。
接下來在Router 2的管理畫面,一樣找到類似port forwarding的選項(圖12)

圖12

點Add,照圖13的方式進行設定

圖13

這個路由器多了可以輸入服務名稱的功能,不過應該不是很重要就是了。因為Router 2要轉送封包給Router 1,因此IP位址輸入Router 1的位址(192.168.1.111),External Port Start和External Port End和剛才的服務通訊埠和內部通訊埠意思相同,填入5000,這樣設定就完成了。
    現在我們可以在DS file中輸入我們的網際網路IP位址,以及NAS的帳號和密碼(圖14
)。這樣當我們的Router 2接收到port為5000的封包時,就會自動轉送到Router 1,Router 1接著會再將封包送到我們的NAS中。

圖14

[2016/6/29]更新: 固定IP設定
    我們的路由器為了方便多台電腦使用,通常是設定DHCP,也就是浮動IP。這樣的設定可以讓電腦在接上網路線後,自動偵測使用的IP位址,而不用再多做設定。我們可以在圖7中看到,Router 1的IP顯示為浮動IP。這樣的設定有個嚴重的缺點,就是這個位址可能會變換。假如哪天Router 1的IP變成了192.168.1.150,那麼Router 2的封包將會轉送到原來的192.168.1.111位址,而這不是我們想要的結果。第一種解決方法就是,當Router 1的位址改變時,就到Router 2更改轉送的設定,將所有的位址都改成新位址。這當然是個很爛的方法,因此更好的方法應該是使用固定IP。如圖15,到Router 1的網路設定,將連線類型從浮動IP改為固定IP。接下來輸入你想要的IP位址,這個位址可以參考Router 2的設定資訊(圖16),在範圍內的位址都可以使用,例如我選擇192.168.1.150。接下來在Router 2的設定轉送的封包到這個位置(192.168.1.150)就完成了(圖17)。

圖15

圖16

圖17






2016年4月10日 星期日

ERB Transforms

\begin{figure}
\begin{center}
\epsfig{file=Figures/hearing.ps, width=4in} \end{center} \vspace{-0.25in}
\end{figure}

人內耳中的basilar membrane(基底膜)有許多的聽覺神經,而這些神經對於不同頻率的聲波各有其敏感度。因此,根據研究,德國科學家巴克豪森(Barkhausen)透過實驗,將聲波區分為24個關鍵頻帶(Critical Bands),並稱之為巴克刻度(Bark scale)。人耳對於相鄰頻帶會有相同距離的感覺。我們知道,人耳對於聲波能量強度的感受大致是對數變化的,但實際上,這個感受可能比單純的對數還要更複雜,因此才會有科學家進一步去研究這種更精緻的對應關係。這種對應是根據主觀實驗得來的,因此不同人的感受會有些微差距。關鍵頻帶之所以稱為'頻帶',就是因為它並不是一個數值,而是一個範圍,同一個範圍內的頻率大致上感受都會差不多。

Bark scale critical bands
NumberCenter Frequency (Hz)Cut-off Frequency (Hz)Bandwidth (Hz)
20
16010080
2150200100
3250300100
4350400100
5450510110
6570630120
7700770140
8840920150
910001080160
1011701270190
1113701480210
1216001720240
1318502000280
1421502320320
1525002700380
1629003150450
1734003700550
1840004400700
1948005300900
20580064001100
21700077001300
22850095001800
2310500120002500
2413500155003500
參考: https://en.wikipedia.org/wiki/Bark_scale
其中,center frequency表示每個頻帶的中間值,也就是說,若想只用一個頻率值代表一個頻帶的話,就是用center frequency。cut-off frequency就是頻帶的最大和最小值。bandwidth是頻寬,表示一個頻帶的寬度(最大值-最小值)。

Bark scale只定義了24種頻率的對應方式,但是到底要如何對每個頻率f都找到一個對應的Bark scale值呢?研究人員開始試著找出一些數學式來近似這種對應,而ERB(Equivalent Rectangular Bandwidth)就是其中的一種對應方式。


\mathrm{ERB}(f) = 6.23 \cdot f^2 + 93.39 \cdot f + 28.52

ERB scale指的是有幾個ERB在給定的頻率f以下


\mathrm{ERBS}(f) = 21.4 \cdot log_{10}(1 + 0.00437 \cdot f)

2016年3月27日 星期日

使用python解minimization問題

使用scipy的函數scipy.optimize.fmin_l_bfgs_b

官方說明
http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.optimize.fmin_l_bfgs_b.html

簡易使用法
http://stackoverflow.com/questions/8672005/correct-usage-of-fmin-l-bfgs-b-for-fitting-model-parameters

python multiprocessing卡住解決辦法

使用python開多個process平行運算時,可能要將最終結果放入某個list、dictionary或queue之類的回傳至主程式,這時候有機會出現子程序無法結束(terminate)的問題,不知道這是否和官方文件所說的問題一樣
https://docs.python.org/2/library/multiprocessing.html#pipes-and-queues
總之,若出現這種問題,不妨將所使用的list、dictionary或是queue改成manager版本的,用法上差不多,儘量使用class的界面來操作的話問題會比較少(例如不能使用ls=ls+[...],應該使用正常的ls.append(...)),因為manager是專門用來處理multiprocessing的module,大致上可以解決這些問題。

關於thread的簡易用法
http://puremonkey2010.blogspot.tw/2012/05/python-python.html

2016年3月16日 星期三

工作站安裝Caffe

這次安裝是在實驗室的工作站上,除了環境設定和自己電腦稍有不同外,權限也較低,所以不能隨便想裝什麼就裝什麼。

首先是為什麼現在會突然想到工作站上安裝,原因是因為我自己寫了一個layer,因此要重新編譯caffe,所以才想說順便裝一下以前在工作站上沒裝成功的pycaffe。

筆記一下要如何自己寫一個layer:基本上只要在自己的layer.cpp最後加上
INSTANTIATE_CLASS(xxxLayer);
REGISTER_LAYER_CLASS(xxx);
即可,當然還要有自己的header檔,看是要自己新增一個,還是加到原本就有的裡面。

接下來是如何在工作站上安裝pycaffe。由於工作站無法自己安裝新的python module,但幸好python可以整個安裝成自己的,所以我下載了anaconda2 python,安裝完即可使用。當然還是要記得將build/CMakeCache.txt中python的路徑設定為新裝的anaconda的位置,不然他還是會找到系統原始的python。完成後,原本以為照著之前的做法,
cd build/
cmake ..
make all
就好了,結果卻發現工作站的OpenCV library有問題,不知道是版本問題還是什麼,總之這個library我一定也沒有權限可以修改,想要編譯自己的版本來安裝又太麻煩了,因此我想說能不能跳過OpenCV,因為需要使用OpenCV的檔案其實只是附加功能,而且我根本就沒有使用到這個功能。但這個cmake的設定似乎就是要嘛你根本沒裝OpenCV,他也不幫你裝相關功能,要嘛就他自己找到OpenCV就一定會安裝,就是沒有可以自己關掉的選項,最後只好放棄使用cmake,使用原始的makefile版本。基本上也不會太難,將Makefile.config.example改成Makefile.config,並且使用裡面的ANACONDA_HOME以及相關的python路徑即可,#註解記得該取消的要取消乾淨。接下來手動使用
make lib
make tools
make py
即可,example不需要編譯。
若出現缺少python module的問題,執行
cd python
for req in $(cat requirements.txt); do pip install $req; done
將相關python module安裝好即可。這裡我發現其實leveldb是沒有安裝成功的,因此若要使用pycaffe,應該使用lmdb或是hdf5。

更新:
後來發現雖然pytest是成功的,但是shell的caffe卻不能用,而且不知道為什麼,cmake所找到的python library一直是系統的,推測可能因此有些相關的library發生衝突。總之目前還是回到原始沒有pycaffe的狀態,之後有空再研究。

有關cmake的find_package()到底會找哪些資料夾,這篇網站有介紹
https://cmake.org/Wiki/CMake:How_To_Find_Libraries#How_package_finding_works

2016年2月16日 星期二

Matlab同時使用多核CPU和多張GPU加速

CPU的Multi-thread用法類似

p = gcp();
for i = 1 : iter
    f(i) = parfeval(p, @myFunc, ...);
end
for i = 1 : iter
    fetchNext(f);
end

而GPU則只需將陣列使用gpuArray宣告即可。但因為要使用多GPU,因此先使用

nGPU = gpuDeviceCount;

得到GPU的個數,然後呼叫數學函數前記得先用gpuDevice()選擇要用哪張GPU

gpuDevice(GPU_index) % 1 <= GPU_index <= nGPU
math_func(...)
...

搭配前面的CPU multi-thread即可同時使用多張GPU運算。


注意事項:
    使用Multi-thread CPU + Multi-GPU時,記得[1]要自己安排讓#(nGPU)個函式用CPU+GPU執行,[2]剩下#(nCPU-nGPU)個只使用CPU單獨。[1]可避免太容易出現GPU out of memory,[2]可增加效能。

2016年2月14日 星期日

mac上使用multi-thread(OpenMP)

OpenMP是常見的multi-thread library,他有不同的實作。而Mac使用的compiler有gcc或clang,因此OpenMP也有相對應的實作。

參考:
gcc: https://gcc.gnu.org/projects/gomp/
clang: http://clang-omp.github.io/

2016年1月28日 星期四

AMD顯示卡玩Diablo 3閃退/畫面卡住問題

用AMD的顯示卡玩暗黑3第二章淒涼砂地時,容易發生閃退或是畫面停住不動的情形,這是因為某次暗黑改版後開始發生和新的AMD驅動程式(15.x)不相容的情形。官方的解法是將顯示卡驅動程式版本降到13.12,只是不是每個作業系統都可以這麼容易的降版本(e.g Windows 10),且為了玩暗黑而降低驅動版本聽起來也是怪怪的。因此,一個比較好的解法是,仍然降低驅動版本,但不是改變整個系統的驅動,而是只改變暗黑自己使用的驅動版本。方法是將AMD驅動的動態函式庫直接放到遊戲安裝目錄下,這樣遊戲就會優先讀取安裝目錄下的驅動了。

可以從以下網址
https://mega.nz/#F!8tlAhDyQ!2AkAQukJKAYuIWEzDTGtFA!IslFkTSL
選擇13.12.zip來下載,將目錄下的.dll檔都丟進遊戲安裝目錄就可以了。

2016年1月26日 星期二

小技巧

使用numpy的array時,若我們想取出其中一個值,且使用類似
ary[1,2]
的方式,結果會是一個ndim為0的array。若我們希望可以維持結果的ndim還是和原本一樣,但又不想用
ary[1,2,None,None]
這種自己添加singleton的方式的話,還可以使用
ary[1:2,2:3]
另外,就算array的某個維度的大小是1,使用ary[..., :, ...]的方式取值(而不是
ary[..., 0, ...])的話,就能保持該維度1的大小。

在python中,若要判斷一個值是否為零,應該使用
if not val
而不是像C的
if ~val
因為~是binary的complement

使用numpy的array時,若要複製一個array到另一個變數,而不只是指向相同instant的話,應該使用
A = np.copy(B)
而不是
A = B

使用terminal連到其他電腦時,若要運行一個要跑很久的程式,可能會想在執行後將terminal關掉,將來再連回去,這時可以使用screen指令。首先在執行程式之前,執行
screen
然後接下來正常執行要跑的程式即可。當想要離開時,按下
Ctrl+a
然後在按
d
即可detach這個screen。想要回復screen,只要使用
screen -r
即可。更多使用可參考
http://blogger.gtwang.org/2013/11/screen-command-examples-to-manage-linux-terminals.html
Ctrl+a [ 可進入游標移動模式

ipython實用快捷鍵
http://cmdlinetips.com/2013/01/eleven-ipython-keyboard-shortcuts-to-move-around-easily/

python中print參數的方法
http://www.python-course.eu/python3_formatted_output.php

我們可以使用x=gpuArray(...)來建立一個儲存在GPU中的矩陣,若要確定這個變數是存在GPU中,可以使用class(x),會發現他確實是一個gpuArray的物件。此外,可以使用whos指令來查看目前工作區的變數資訊,可以發現gpuArray的物件大小都固定是108個Bytes,這是因為此變數確實是占用gpu的記憶體。



2016年1月24日 星期日

使用caffe.Net創建和讀取model

我們可以使用
caffe.Net('net.prototxt', caffe.TRAIN)
來創建新的網路,也可以使用
caffe.Net('net.prototxt', 'pretrain.caffemodel', caffe.TRAIN)
來讀取已經train過的model。其中有兩點事項:

(1)最後一個參數caffe.TRAIN或是caffe.TEST指的是要讀取net.prototxt中的phase TRAIN還是phase TEST的網路,兩個網路的差別就在於那些include不同phase的layer。而若使用solver來讀取網路,他會幫我們兩個都讀取,並分別放在solver.net和solver.test_nets裡面。
(2)當我們讀進預先訓練好的網路時,若我們使用
net.blobs['layer_name'].data
查看blobs資料時,會發現全部都是0。這並不是表示我們的model檔沒有儲存成功,因為其實網路裡面儲存資料的部分除了有layer和layer間的資料,layer本身也有許多參數要儲存,而我們訓練一個網路實際上是在修正layer本身的參數(forward改變layer和layer間的資料,backward改變layer本身的參數),因此需要儲存的資料也就是layer的參數,而不是layer和layer間的資料。若想要確認,應該要使用[1]
net.params['layer_name'][0].data
但這些參數對我們來說其實也沒什麼特別的意義,因此通常我們在讀進網路資料後,就是先forward某筆測試資料,然後再將某層blob的資料取出。

2016年1月23日 星期六

一些筆記2

可以直接使用matlab的mat檔來當作caffe網路輸入的資料庫資料,但有注意事項:
(1) caffe和python中numpy的array是相同的格式(row major),和matlab(column major)不同。因此,在用matlab輸出mat檔前,記得要用permute()將資料dimension的order倒過來。且若要使用reshape(),維度順序也要注意不要弄錯。(應該是先permute後再做reshape)
(2)在caffe的prototxt中,資料層記得要使用HDF5Data,參數使用hdf5_data_param,source一個.txt檔,裡面放真正hdf5檔(也就是matlab的mat檔)的位置。
(3)python的h5py可以直接讀取matlab的mat檔,因為mat檔本身是hdf5格式。但如果是從python創建hdf5檔首先要注意(i)我們要將檔案關閉後他才會寫進硬碟裡,再來是(ii)matlab必須要使用
python:
f = h5py.File('filename')
f.create_dataset('datasetname', data=data_ary)
f.close()

matlab:
data = hdf5read('filename','datasetname')
才能讀取[3][5]。


python界面使用caffe的方法:
(1)首先我們當然要先定義我們網路的內容,除了直接手寫prototxt檔之外,也可以使用python界面來產生。根據caffenet.py的範例,首先是將layers和params這兩個modules import進來,接下來就可以用
[top layer] = [layer type]([bottom layer], [parameters ...])
的形式一層層連接layer,最後完成我們的網路。接下來import net_spec.py中的to_proto功能,將剛才定義的網路的頂層輸入這個函數,他就會回傳一個proto資料結構,我們可以使用print功能來查看剛才定義的網路長相,也可以將print的結果導出到文字檔中,就完成我們的prototxt檔了。

(2)有了網路的定義,接下來就是產生真正的網路資料結構。import pycaffe的Net(或直接import caffe),使用
net = caffe.Net('proto_name.prototxt', caffe.TEST)
就可以產生一個網路資料的變數了。也可以在中間加入train過的model檔路徑來得到train過的model變數
net = caffe.Net('proto_name.prototxt', 'model.caffemodel', caffe.TEST)

net中的blobs包含了每層的資料資訊,使用net.blobs.items()可以列出所有blobs名稱。使用blob = net.blobs['blob_name']得到blob後,可用blob.data得到blob中的資料。
此外,也可以使用
solver = caffe.SGDSolver('solver_name.prototxt')
solver中除了也包含了solver.net的資訊外,也可以利用solver.solve()來自動forward、backward網路。若要使用之前的snapshot來回復solver的資訊,可以使用
solver.restore('snapshot.solverstate')
若是想要直接使用train好的model來finetune,可使用
net.copy_from('modelname. caffemodel')
solver.net.copy_from('modelname. caffemodel')

net的forward()和backward()所需要的參數中,blobs是一個list的字串,start和end都是一個字串,這些字串都是layer的名稱(使用net.blobs.keys()可以查看)。因為呼叫forward()和backward()後,會回傳某些layer中的資料回來,blobs參數就是讓我們自定義還想"多"回傳哪些layer的blob。start和end用來表示要forward和backward的layer區間。kwargs是一個dict,可以讓我們指定某個layer要使用什麼樣的資料,我們可以使用
{'data1':val1, 'data2':val2, ...}
來創建dict。其中'data1'、'data2'是資料的名稱,也就是data layer中的那些top名稱。而val1、val2則是資料本體。我們也可以使用另一種寫法:
net.forward_all(data1=val1, data2=val2, ...)


caffe的layer中有一個叫做HDF5Output,用處是將我們網路的結果輸出。若要使用,要注意他的input要有兩個[4](通常是一個data、一個label),然後使用
hdf5_output_param {
    file_name: "result.h5"
}
指定輸出檔案名稱。看起來很方便,其實沒什麼用,因為他一筆訓練資料只能輸出一個數字,可能是分類結果、精確度或誤差,但若想要把一個大blob輸出是不行的。


pycaffe中,forward、backward的參數kwargs其實是python中的keyword arguments,可以自己指定input,並會以dict的方式傳入函數[6]。


在caffe中使用dummy_layer的方式
layer {
  name: "dummy"
  type: "DummyData"
  top: "dummy"
  dummy_data_param {
    shape {
      dim: ...
      dim: ...
    }
    data_filler {
      type: "uniform"
      min: ...
      max: ...
    }
  }
}
小心網路上的範例把layer打成layers,會出錯誤。

2016年1月16日 星期六

2016年1月11日 星期一

一些筆記

http://nbviewer.ipython.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb
官方推薦的pycaffe教學

http://wubinblog.com/deep%20learning/2015/07/13/Use_Caffe_For_Classification/
http://blog.csdn.net/deeplearninglc007/article/details/40086503
http://closure11.com/caffe%E5%9C%A8python%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%86%85%E5%AD%98%E6%95%B0%E6%8D%AEmemorydata%E8%BF%9B%E8%A1%8C%E8%AE%AD%E7%BB%83/
Caffe中文文章

http://deepdish.io/2015/04/28/creating-lmdb-in-python/
用python創建LMDB的教學,但label只能一個數字

https://groups.google.com/forum/#!topic/caffe-users/6OOcM-XfvOI
提到如何將testing時最後的label輸出

http://blog.csdn.net/visionfans/article/details/48400147
reshape時發現blob的維度超過上限了

https://github.com/Russell91/nlpcaffe/issues/2
https://github.com/BVLC/caffe/issues/2006
遇到儲存snapshot時發生錯誤,可能是因為資料太大,要將維度降低

http://dirlt.com/caffe.html
http://www.cnblogs.com/dupuleng/articles/4370296.html
中文教學,有提到train_val.prototxt和deploy.prototxt的差別,基本上train_val需要指定訓練資料路徑,表示是用來訓練(改變)model的,而deploy則只有指定輸入資料的大小形狀,是model訓練完後拿來用的(不改變model)。

https://groups.google.com/forum/#!topic/caffe-users/8J_J8tc1ZHc
什麼是lr_mult和decay_mult,以及為何有兩個(一個是weight,一個是bias)

https://www.quora.com/Is-there-a-recurrent-neural-networks-toolkit
提到有哪些RNN的工具

http://jeffdonahue.com/lrcn/
caffe有RNN的版本
https://github.com/BVLC/caffe/pull/2033
介紹

https://developer.apple.com/library/mac/documentation/Accelerate/Reference/BLAS_Ref/#//apple_ref/c/func/cblas_sgemm
一些blas的api

http://deeplearning.net/tutorial/lstm.html
LSTM介紹

http://openhome.cc/Gossip/Python/WithAs.html
python中with as的教學。基本上就是簡化讀寫檔案時所需的try...except...final。

http://tech.seety.org/python/python_imaging.html
python PIL影像處理函式庫

http://stackoverflow.com/questions/874461/read-mat-files-in-python
python讀matlab的mat檔的方式

http://stackoverflow.com/questions/120656/directory-listing-in-python
在python中使用os列出目錄資訊的方法。其中,os.walk回傳的generator是種有iterator功能的東西
https://wiki.python.org/moin/Generators
可利用他enumerate的功能來做快速迭代
http://stackoverflow.com/questions/522563/accessing-the-index-in-python-for-loops
http://www.cnblogs.com/vivilisa/archive/2009/03/19/1417083.html

http://www.tutorialspoint.com/python/python_tuples.htm
在python中,使用[1,2,3]是list,使用(1,2,3)是tuple,兩者的差異在於tuple是不能改變其內容的(immutable),其他用法

http://stackoverflow.com/questions/4344017/how-can-i-get-the-concatenation-of-two-lists-in-python-without-modifying-either
可利用list1+list2將兩個list接起來

http://stackoverflow.com/questions/4151128/what-are-the-differences-between-numpy-arrays-and-matrices-which-one-should-i-u
numpy中,array和matrix的差別在於:matrix只能是二維的,而array可以是任意d維的。

http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.matrix.html
宣告一個matrix的方法

http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.concatenate.html
將兩個array接起來的方法

找出array中非零個數的方法
http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.nonzero.html

PIL Image儲存影像的方法
http://stackoverflow.com/questions/14452824/how-can-i-save-an-image-with-pil

http://effbot.org/imagingbook/decoder.htm
http://stackoverflow.com/questions/16720682/pil-cannot-write-mode-f-to-jpeg
影像的mode種類,有RGB、grayscale等,及其設定方法

array增加singleton的方法(singleton就是大小只有1的維度,它應該可以刪除,但有時候array形狀有限定時會需要增加這個維度)
http://stackoverflow.com/questions/9510252/efficient-way-to-add-a-singleton-dimension-to-a-numpy-vector-so-that-slice-assig

http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.reshape.html
reshape的用法。array中resize和reshape的差別:reshape是回傳resize後的array,resize是直接改變array本身

http://stackoverflow.com/questions/53162/how-can-i-do-a-line-break-line-continuation-in-python
python要將一行code打成多行,只要直接換行就好了,但是縮排還是要縮

http://mathesaurus.sourceforge.net/matlab-numpy.html
python和matlab函式的對應表

2016年1月4日 星期一

easy_install & pip

非常不錯的教學網站

http://www.openfoundry.org/tw/tech-column/8536-introduction-of-python-extension-management-tools

筆記:在Mac上安裝Caffe(後續)

接著我打算開始使用python界面的pycaffe。從基本的開始,先將caffe根目錄下的python資料夾加入環境變數PYTHONPATH
export PYTHONPATH="/path/to/caffe-master/python"
記得"不是"
export PYTHONPATH="/path/to/caffe-master/build/python"
也"不是"
export PYTHONPATH="/path/to/caffe-master/python/caffe"

接著進入python的shell(or prompt),並執行
import caffe
過程中出現錯誤訊息
Segmentation fault: 11
並且直接跳出python程式。Mac系統比較容易出現這個問題,根據網路上的資料[1],原因是Mac系統有內建python,但我們是用自己下載的版本(brew python or anaconda python),而在build pycaffe的時候,很容易混入系統內建python,造成連結錯誤。
    打開build資料夾下的CMakeCache.txt,檢查裡面所有有關python的資訊,果然發現兩行
PYTHON_INCLUDE_DIR:PATH=/System/Library/Frameworks/Python.framework/Headers
PYTHON_LIBRARY:FILEPATH=/usr/lib/libpython2.7.dylib
表示python的include資料夾以及函式庫都聯結到系統的了。將其改為
PYTHON_INCLUDE_DIR:PATH=/Users/lindol/anaconda/include/python2.7
PYTHON_LIBRARY:FILEPATH=/Users/lindol/anaconda/lib/libpython2.7.dylib
並且重新編譯
make clean
make all -j4
結束後再次執行
import caffe
錯誤資訊改變:
ImportError: No module named google.protobuf.internal
表示我python的搜尋路徑中並沒有包含這個module。由於protobuf是由brew安裝的,若今天使用的是同樣brew安裝的python的話,這個module是會被找到的,但問題我們使用的是anaconda python,因此這個library的搜尋路徑並沒有被設定好。有關於設定python的搜尋路徑有許多方法,根據網路上的資料,我選擇使用增加usercustomize.py的方式[2][3]。在目錄下新增usercustomize.py:
/path/to/caffe-master/python/usercustomize.py
且內容是讓python找到protobuf的方法
import site; site.addsitedir('/usr/local/Cellar/protobuf/2.6.1/libexec/lib/python2.7/site-packages')
再次執行
import caffe
終於沒有錯誤。

在import caffe時,若出現
No module named skimage.io
可使用
pip install scikit-image
安裝相關模組[4]。

參考:



2016年1月3日 星期日

python import

import是python用來將其他modules匯入目前modules的功能。

我們想要import進來的東西應該可以分為兩種
ㄧ)獨立的module,其路徑應該長得像
/path/m1.py
二)包在package裡面的module,其路徑應該長得像
/path/pkg_path/m2.py
在第二種case中,pkg_path之所以可以顯得和一般的path不同,是因為我們在資料夾下手動加入了一個檔案
/path/pkg_path/__init__.py
有了這個檔案,python就會知道這個資料夾下是放了屬於同一個package的module。這個檔案是可以沒有內容的。
    接下來,不管是哪種case,假如我們想要每次打開python都可以直接import,都應該要將他的路徑加到環境變數中[1]:
export PYTHONPATH="/path:$PYTHONPATH"
注意這裡第二種case"不應該"使用
export PYTHONPATH="/path/pkg_path:$PYTHONPATH"
因為pkg_path整個資料夾算一個單位,若使用後面這種方式import,會使得python可以獨立找到其中的module,也就是下面這種用法會被允許:
m2.func()
,但較正確的用法應該是
pkg_path.m2.func()
也就是說,可以使這些module有pkg_path這個命名空間。
    當我們設定好環境變數,我們可以進入python,看他是不是真的會將PYTHONPATH底下的路徑加入搜尋路徑:
import sys
sys.path

接下來就是import我們的module了,使用
import m1
就可以使用m1裡的功能了
m1.func()
直接執行
m1
就能發現他確實將m1變數連接到m1.pyc這個編譯好的檔案。
    由於我們在pkg_path中有加入__init__.py,因此我們可以執行
import pkg_path
若執行
pkg_path
可以發現變數連接到的就是__init__.pyc。但目前只有將pkg_path這個命名空間加入,還沒有真正將module匯入。執行
import pkg_path.m2
會幫我們加入pkg_path這個命名空間,以及pkg_path.m2這個module。此時才能夠使用
pkg_path.m2.func()

接下來是from ... import ... [3]
我們可以使用
from namespace import module (等同import namespace.module)
from namespace.module import mem
from module import mem
但不能使用
from namespace import module.mem
簡單來說就是要from目前python可以找到的路徑開始,然後import後面的東西,不論是namespace、module(module其實也是一種namespace)或mem。但是mem都要等到他所屬的module存在sys.modules中,才能被使用,只有module以上的namespace被加入是不能使用mem的。

from m1 import func1
from pkg_path.m2 import func1, func2, func3
上面程式具體行為其實類似
func1 = m1.func1
func1 = pkg_path.m2.func1
...
(python中也可以使用變數指向一個function)
也就是說,其實我們是在自己這個module裡面新增一個變數指向import後面的東西,from後面的東西並沒有特別用一個變數去指它。而python會將import時所經過的所有module(namespace)都加入sys.modules。我們之所以在import之後就可以直接使用import後面的東西,是因為新增了一個local變數存這個東西(module、function等),而將module匯入其實是另一件事了,因為即使目前sys.modules中確實是有這個module存在,但若這個指向他的變數不見了,我們依然無法使用這個module。
    因此回去看上面的程式其實會發現有個問題,就是func1被assign了兩次,因此我們最後其實只能使用到pkg_path.m2.func1。這也是為什麼我們不推薦使用
from ... import *
也就是import namespace下所有的東西進來。這樣做可能會造成衝突,因為很有可能有東西的名稱是重複的。
    但如果我們要import的東西名稱真的是重複的,我們可以使用
import name1 as name2
這樣import進來時所新增的變數名稱就能變成name2。最後,這個用法是可以和上面混合的:
from ... import ... as ...

新增:
from .module import ...
這個用法中,.module的那個點代表的是目前的module[8]。比如說,在一個package中可能有很多.py檔,.module就是代表同一個package中的其他module。

其他:
global():列出module namespace。(Note. 在command line(prompt)中直接import的都算global)
local():列出目current namespace。[4]

其他學習:[5][6][7]

參考:
[1] http://stackoverflow.com/questions/3144089/expand-python-search-path-to-other-source
[2] http://stackoverflow.com/questions/448271/what-is-init-py-for
[3] http://stackoverflow.com/questions/9439480/from-import-vs-import
[4] http://stackoverflow.com/questions/7969949/whats-the-difference-between-globals-locals-and-vars
[5] http://openhome.cc/Gossip/Python/ModuleABC.html
[6] http://openhome.cc/Gossip/Python/ImportModule.html
[7] http://openhome.cc/Gossip/Python/ImportImportAsFrom.html
[8] http://stackoverflow.com/questions/7279810/what-does-a-in-an-import-statement-in-python-mean

2016年1月2日 星期六

cmake腳本中印出訊息的方法

message(STATUS "${var}")
message(STATUS "abc")

筆記:在Mac上安裝Caffe(CPU only)

這篇文章其實不算安裝Caffe的教學,比較像是我自己在安裝的過程中遇到的問題以及所學知識的筆記。

根據官方教學

在Mac上需要做的事
http://caffe.berkeleyvision.org/install_osx.html

編譯Caffe需要做的事
http://caffe.berkeleyvision.org/installation.html#compilation

brew tap指令用來增加brew對資源庫的搜尋[1]。
brew tap <user/repo> <URL>
可以讓brew安裝特定URL的repo下的軟體

若要移除tap過的repo,可使用
brew untap user/repo [user/repo user/repo ...]

brew install option介紹
brew install -vd
-v: verbose
-d: debug

Homebrew是使用git來管理你所下載的repo,local的repo可以在電腦的/usr/local/裡面找到(.git/.gitignore)。以opencv為例,我們可以使用
brew edit opencv
來編輯brew對opencv安裝及編譯的腳本。我們可以利用git來查看我們對腳本所做過的修改,也可以復原我們所做的修改。首先,要使用git查看我們所安裝過的repo前,應該先執行
brew update
更新brew的local repo資訊,接下來就可以
cd /usr/local/

cd $(brew --prefix)
進入repo所在資料夾,然後用
git status
查看修改過的項目了。若要將修改復原,也是使用git,利用reset、checkout等指令將repo回復[17][18]。

snappy: 快速壓縮/解壓縮軟體[2]
leveldb: 資料庫軟體[3]
lmdb: 資料庫軟體[4]
gflags : Commandline flags module for C++[5]
glog : Logging library for C++[6]
szip: HDF裡面使用的壓縮程式[7]
hdf5: 一種儲存和管理資料的格式和函式庫[8]
opencv: 影像處理函式庫
protobuf: 一種輕便高效的結構化數據儲存格式,可將數據進行序列化和反序列化[9][10]
boost: 一群有廣泛功能的函式庫[11]
BLAS: Basic Linear Algebra Subprograms(基礎線性代數程式集),用於線性代數計算的界面規範(or API)[12]
OpenBLAS: Open source的BLAS實作[13]
MKL: Math Kernel Library,Intel的數學函式庫[14]
Clang: 由蘋果公司贊助開發的編譯器前端,以LLVM為後端,希望作為GCC的替代品[15]
Atlas: Automatically Tuned Linear Algebra Software,一個以BLAS API開發的線性代數函式庫[16]


其中OpenBLAS、MKL和Atlas都是BLAS API的實作。Mac OS中本身也有包含BLAS的實作,也就是Accelerate和vecLib函式庫。在安裝Caffe時可以根據情況設定使用上述不同的BLAS函式庫。
    leveldb、lmdb和hdf5都是用來儲存大量數據時使用的資料庫,他們在記憶體使用量及效能上有些差異[24][25],但都能在caffe中使用。
    protobuf是一種儲存格式,在caffe中就是用來制訂每個layer的種類、關係等。


homebrew/science是homebrew收納的函式庫中其中的一個來源。全部函式庫來源可參考homebrew的github首頁:
https://github.com/Homebrew


想要查看所有安裝過的python package,可在python shell/prompt下執行
help('modules')
或是直接在普通command line下執行
pydoc modules

在python中查看當前python使用的版本
import sys
print (sys.version)

pip指令是python下的套件管理工具[19]

Anaconda python是python眾多發行版本中的其中一個,此版本包含了許多好用的功能在裡面。在Mac中會安裝在使用者的Home目錄下(~/anaconda),刪掉此資料夾就可以移除。因為每個版本的python執行檔都是獨立分開的,因此互相不會衝突,但是要使用特定版本時也要指定對應的路徑。

根據官方教學,在brew編譯及安裝python版opencv的腳本中(執行brew edit opencv),有兩行類似
-DPYTHON_LIBRARY=#{py_prefix}/lib/libpython2.7.dylib 
-DPYTHON_INCLUDE_DIR=#{py_prefix}/include/python2.7
(我們可以在vim中用"/"來搜尋)
這兩行是用來規範我們將要用來編譯opencv的python的路徑。在這兩行上方可以找到py_prefix的定義
py_prefix = `python-config --prefix`.chomp
這表示真正py_prefix其實是由一個python-config檔來決定。若我們cd進入系統python的執行檔目錄下,真的可以看到這個python-config檔
cd /usr/bin | grep python
且這個檔本身也是個腳本。因為若打開這個檔,我們可以看到這個"--prefix"確實是這個腳本中的一個參數。順便一提,在Mac中的python-config是沒有"--configdir"這個參數選項的,所以brew的腳本中才會寫到"OS.linux?"這個判斷式吧。
    回到原本的問題,我們這裡要做到的是利用官方很推薦的Anaconda python來幫我們的opencv編譯,但是根據brew的腳本,系統首先會找到的是/usr/bin/下的python-config檔,因此最終會使用的python也是/usr/bin/下的python,而不是我們家目錄的Anaconda python。因此我們需要做的就是改變環境變數,使得家目錄下的Anaconda python優先被找到。
首先利用
export PATH="$HOME/anaconda/bin:$PATH"
將bin資料夾加入PATH,然後
export DYLD_FALLBACK_LIBRARY_PATH="$HOME/anaconda/lib:/usr/local/lib:/usr/lib:$DYLD_FALLBACK_LIBRARY_PATH"
將其他的lib資料夾也加一加。
    這裡有幾點事項,以Mac來說,這兩行應該寫到家目錄下~/.bash_profile中,這樣每次開新terminal才不用再加一次。再來是其實我們安裝anaconda時它其實已經會自動幫我們把export bin的指令加入~/.bash_profile中,所以也不用自己加。最後,export lib資料夾到DYLD_FALLBACK_LIBRARY其實是官方網站的建議,但根據brew編譯opencv的腳本,其實它自己會找的到anaconda的lib,所以理論上我們也不用自己加入...anyway,現在應該已經可以開始編譯anaconda版的opencv了,因為我之前已經先安裝過一次普通版的,所以先執行
brew uninstall opencv
將原先的移除,然後再安裝一次。附帶一提,這時突然出現一個很跳tone的問題,就是brew提示我的一個函式庫numpy的link有問題,要執行
brew link numpy
來修復,但修復到一半又出現什麼f2py已經存在,等等等問題。這裡的重點是,在brew出現這些奇怪提示時,非常建議使用
brew doctor
這個指令,他會幫我們列出許多潛在可能出現的問題,幫助我們解決這些疑難雜症。

依賴函式庫都裝完後,就可以開始正式編譯Caffe了。有兩種方式:
一)先修改目錄底下的Makefile.config.example文件符合自己的電腦系統配備,並將其檔名改為Makefile.config,再執行make
二)直接執行cmake,他會偵測我們的電腦配備,並自動產生合適的Makefile[23]。接下來我們再執行make就好了
這裡我選擇第二種方式。執行下列指令:
mkdir build 
cd build 
cmake .. 
make all -j4
出現下列問題
問題1:
error: expected function body after function declarator
extern void ATLU_DestroyThreadMemory() __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_9, __IPHONE_4_0, __IPHONE_NA);
原因:
是不知道為何,一個在10.9 sdk中的header檔A,include另一個header檔B,而這個B竟然是include到10.8 sdk中的檔。其實在10.9中也有和B同名的header檔,但不知道為何系統會優先去找10.8的。

解法:暫時先利用將xcode目錄下
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk
這個資料夾名稱改掉(前面加個底線就好),但是不確定這樣是否系統會接著找10.9 sdk,但至少這樣改錯誤資訊不一樣了...

問題2[20]:
Building with 'Xcode Clang++'.
ld: library not found for -lpython2
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我以為這個問題是出在我的python library路徑沒有設對,所以去查看了cmake檔中的設定
build/CMakeCache.txt
真的發現不知為何PYTHON_INCLUDE_DIR和PYTHON_LIBRARY這兩個的位置都指到系統的python位置,而不是我所用的anaconda python,所以手動將兩個改掉:
PYTHON_INCLUDE_DIR:PATH=/Users/lindol/anaconda/include/python2.7
PYTHON_LIBRARY:FILEPATH=/Users/lindol/anaconda/lib/libpython2.7.dylib
再次make,發現錯誤資訊回到問題2,表示問題2可能和python路徑沒有關...(*更新)。後來發現其實這個步驟是在build matlab的東西時發生的錯誤,目前也不知道該如何處理,但因為已經花太多時間在build環境,暫時先關閉build matcaffe,讓make能順利跑完。

後續:在runtest時跑出HDF5 library版本不符的問題,但因為我裝的(1.8.16)其實比他要求的(1.8.15)更新,所以我覺得應該沒有問題。在環境變數中設定
export HDF5_DISABLE_VERSION_CHECK="1"
來跳過錯誤訊息。

其他安裝教學[21][22]

*(2016/1/21 更新)後來安裝別人發佈的RNN版caffe,發現將這兩個路徑更改正確非常重要,不然會很容易出現
Segmentation fault 11
的錯誤

參考:
[1] https://github.com/Homebrew/homebrew/blob/master/share/doc/homebrew/brew-tap.md
[2] http://brewformulas.org/Snappy
[3] https://zh.wikipedia.org/wiki/LevelDB
[4] http://symas.com/mdb/
[5] http://brewformulas.org/Gflags
[6] http://brewformulas.org/Glog
[7] https://www.hdfgroup.org/doc_resource/SZIP/
[8] https://www.hdfgroup.org/HDF5/
[9] https://www.ibm.com/developerworks/cn/linux/l-cn-gpb/
[10] http://www.searchtb.com/2012/09/protocol-buffers.html
[11] http://blog.monkeypotion.net/gameprog/note/first-touch-of-boost-cpp-libraries
[12] https://zh.wikipedia.org/wiki/BLAS
[13] http://www.openblas.net/
[14] https://software.intel.com/en-us/intel-mkl
[15] https://zh.wikipedia.org/wiki/Clang
[16] https://en.wikipedia.org/wiki/Automatically_Tuned_Linear_Algebra_Software
[17] http://stackoverflow.com/questions/9369519/reset-homebrew-formula
[18] http://stackoverflow.com/questions/3987683/homebrew-install-specific-version-of-formula
[19] https://blog.longwin.com.tw/2014/08/python-setup-pip-package-2014/
[20] https://github.com/BVLC/caffe/issues/915
[21] http://hoondy.com/2015/04/03/how-to-install-caffe-on-mac-os-x-10-10-for-dummies-like-me/
[22] http://coldmooon.github.io/2015/08/03/caffe_install/
[23] https://github.com/BVLC/caffe/pull/1667
[24] http://wubinblog.com/deep%20learning/2015/07/13/Use_Caffe_For_Classification/
[25] https://www.readability.com/articles/u2ejbfkc