2017年7月12日 星期三

Boost.Python 小記

建構子

沒有建構子的 class 要在宣告 mapping 的時候給建構子的 prototype

std::vector<>

跟 python 對接的陣列,要用  boost::python::list 

Overloading function

使用「明確轉型」來指定特定的 overloading 版本

import_array()

使用 numpy 要  import_array()  ,不然執行期用  PyArray_SimpleNewFromData()  建立陣列的時候會 segmentation fault。特別注意的是  import_array()  其實是一個陣列,他會去初始化一個 static variable 叫做  PyArray_APIPyArray_API  是一個 compile unit static variable,所以每一個 .cpp 檔自己都要  import_array() ,但重複 import 又會錯,所以呼叫前要先檢查  PyArray_API  這個變數是否已經被設定。

if (PyArray_API == NULL) {
    import_array();
}


2017年6月28日 星期三

tf.slim deploy trained model

用 tf.slim train 好了 model 以後,要拿來做 inference 才發現腦袋不大清楚不知道怎麼弄,查了一下,看到這邊,原來 tensorflow 本身就有提供 freeze 的工具,slim 也有 script 讓使用者可以方便的 export model。

照著註解裡面步驟做就可以了,兩步,橫簡單,連我都會。

昨天浪費了我幾個小時在那邊摸索,真的很笨。不知道昨天為什麼突然忘記「開始動手做之前先看看別人怎麼做」我的天哪...

[0] https://github.com/tensorflow/models/blob/master/slim/export_inference_graph.py

2017年6月22日 星期四

TF.slim 吃自訂格式的 data

Tensorflow.slim 預設是吃他 TFRecord。但我的圖很多,我不想全部轉成 TFRecord,這樣會吃掉很多硬碟,我想要保留 .jpg 的檔案在硬碟裡,然後有一個文字檔,裡面描述了哪些檔案有哪些 label。

0.jpg -1:* 1:0,7  
1.jpg -1:* 1:1,2,4...

表示 0.jpg 這張圖,有第 0 個 label 跟第 7 個 label。這兩個 label 是 1,其他都是 0。然後 1.jpg 這張圖,有第 1 第 2 第 4 個 label,其他都沒有。至於總共有多少 label,在描述 dataset 的 .py 檔會有寫。

slim 有自己的 reader class,有做了 parallel reader,對於需要大量訓練的時候可以加快 read data 的時間,但是 reader 讀進來之後,decoder 卻只有一個人。如果 decoding 需要很多時間,那這邊就會有問題。為了繞過這個問題,我決定把 reader 跟 decoder 合併在一起。

我根據 slim 的 parallel_reader.py 加了一個 parallel_reader_decoder.py,multi-thread 在讀取檔案以後,同時就會去 decode,之後才放進一個 common queue 讓之後的 node 取用。

這邊註記幾點:
  1. 寫 decoder 的時候,真的要注意效能問題,本來我用很 python 的方法在處理 numpy 陣列,後來發現效能慘不忍睹,改用 numpy style 以後 performance 快了幾百倍。
  2. tf.py_func() 就很好用,不一定要用 C++ 去寫 Op,當然如果真的需要就不要偷懶。
  3. tf.losses 會幫忙把 loss 登錄到 GraphKey.LOSSES,之後會有人去取用,所以不要覺得好奇怪為什麼這個 loss 都沒有人用到
  4. 記得把 slim 的 preprocessing thread 的數量也開到對,不然你會發現 reading 夠快,decoding 夠快,GPU 的 forward computation 跟 backward propagation 也夠快,但是 throughput 就是有夠低。最後發現是死在 preprocessing thread 數量太少。這個數值跟你的 model 所需要的 preprocessing 複雜度有關。mnist 的 preprocessing 很簡單,一個說不定就夠了,inception 可能要 4(或 8?)。
  5. slim 裡面有幾個 queue,queue capacity 記得要改到夠大,pop 以後的 min-size 也要調整(小),不然你會發現他一批一批的做,比方說你 queue capacity 是 16,min-size 卻是 8,但是你有 8 個 clone,這樣他一次要吃掉 8 個,吃完以後這個 queue 的 producer 才會做事,很不方便。這樣這個 queue 等於沒有 buffering 的效果。
    1. Filename Queue (after enumerate files)
    2. Parallel Reading Queue (after read)
    3. Prefetch Queue (after preprocessing)
    4. Batch Queue (after batch packing)
  6. 開太多 preprocessor 的話,tensorboard 秀 graph 會 gg =_=||
  7. sigmoid_cross_entropy 不要亂餵,他的值域就是 0 ~ 1,雖然我自己的 multi-label 標注方法是 1 positive, -1 negative, 0 don't care,但計算的時候,不要去把 logit 轉換到 -1 ~ 1,而是要把 label 從 -1 ~ 1 轉換成 0 ~ 1(但是 label 真的是 0 的時候,要記得 don't care)用tf.abs 跟 tf.maximum 可以做到。不難。
腦子不管用了,剩下的等想到再寫

2017年6月18日 星期日

tensorflow 自訂 operator

考慮開發速度的話,先使用  tf.py_func  [0]
如果遇到限制,或是考慮執行效能的話,再去看 Adding a New Op [1]

雖說 [1] 比 [0] 麻煩,但其實也相當簡單,不用害怕,進去看著照做就可以了,半個小時的事情

[0] https://www.tensorflow.org/api_docs/python/tf/py_func
[1] https://www.tensorflow.org/extend/adding_an_op

2017年5月31日 星期三

undefined symbol: _ZN10tensorflow8internal21CheckOpMessageBuilder9NewStringB5cxx11Ev

解法

編譯的時候加上  -D_GLIBCXX_USE_CXX11_ABI=0  [0]

說明

gcc 5.3 以後導入了新的 ABI,如果你去 link 一個用 5.3 之前的版本編譯的 library,用的還是舊的 ABI,這個時候就會發生錯誤 [1]

參考

[0] https://github.com/tensorflow/tensorflow/issues/1569#issuecomment-200021340
[1] https://stackoverflow.com/questions/34970607/g-new-abi-problems

2017年4月6日 星期四

mysql utf8

原來要 mysql 支援 utf8 不是這麼預設的,好煩 = =||

好吧,歷史因素,可以體諒。

首先看這邊[1]看看怎麼設定(或是變更現有的 database)mysql 支援 unicode

看就好,先不要動手!

注意你要的 collate 是啥。「collate」指的是 DB 用來比對字串的時候所使用的準則,utf8mb4 預設的 collate 是「utf8mb4_general_ci」,這個很有可能不是你要的,因為他會把「ç」跟「c」當作同一個字元,你需要的可能是「utf8mb4_bin」。

然後如果你用的是 docker,不用去寫 my.cnf,run image 的時候直接下命令[2]。

$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

好,如果你不是用 docker,那現在你可以動手了。去 alter 你的 DB 跟寫你的 my.cnf。
用 docker 的人只要 alter DB 就好,然後 run image 的時候用下指令的。

Note: MySQL 的 utf8 charset 不是真的 utf8,他只支援到 unicode 的一個子集,最多三個 byte。到了 5.5.忘了 版之後才有 utf8mb4 charset 支援整個 unicode codepoint。

[1] https://mathiasbynens.be/notes/mysql-utf8mb4
[2] https://hub.docker.com/_/mysql/

mysql -h localhost 失敗

一直無法使用
mysql -h localhost -P 3306 -u root -pkerker
連線到我 local 的 mysql server,氣死我老百姓,錯誤訊息:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
結果最後發現是要用
mysql -h 127.0.0.1 -P 3306 -u root -pkerker
原來 127.0.0.1 跟 localhost 還是不一樣的 XD

reference
[1] http://stackoverflow.com/questions/9714899/php-mysql-difference-between-127-0-0-1-and-localhost
[2] https://dev.mysql.com/doc/refman/5.6/en/can-not-connect-to-server.html