2019年5月17日 星期五

[筆記][tensorflow]Batch Normalization Layer用法(Key Variable not found in checkpoint)

最近在改寫3D Faster RCNN時遇到了一些使用上的問題 ,
因此稍微筆記一下。

首先介紹一下Batch Normalization~
Batch Normalization 最早是在2015年被提出,
主要是解決network在訓練過程中遇到的Covariate shift問題
透過正規化minibatch,加速網絡訓練及穩定性。

最常用來解釋Batch nomalization對於增加訓練網絡的穩定性的方式為下圖:


圖片中我們可以看到,
加入Batch normalization的每一層網絡輸出的分布比較常態,
沒有發生有效值被shift到兩個極端,
這對於使用tanh或sigmoid兩種activation function的網絡來說有很大的幫助,
因為這兩個函數最敏感(變化最大)的區域有一定的範圍,
輸入的分佈超過範圍就會有飽和的問題。


因此如果加入Batch normalization,
會讓訓練避免陷入飽和的狀態。

而ReLU雖然不會遇到飽和的問題,
但是使用Batch Normalization還是可以避免梯度爆炸與加速訓練。

目前我謹了解其物理意義,
對於Batch Normalization的數學模型與詳細細節有興趣的朋友也可以去找他的原始paper或是其他資源來看。
或是之後我有空看完也會來努力補上。

接下來是Batch Normalization的tensorflow用法,
我使用的tensorflow版本是1.12。

要將Batch Normalization layer加在convolution layer的activation function之前,
這邊我用的是tf.layers.batch_normalization,
beta值、gamma值、mean與variance等超參數都使用預設值,
這些值可以自己調整,
(另外如果用的是tf.nn.batch_normalization,
就要自己先定義存超參數的tensor。)

要正確的訓練記得將training這個argument設為true。

接下來就是我遇到問題的地方。
因為batch_normalization的參數不屬於trainable variables,
若沒有設定tf.train.Saver儲存global_variable,
儲存的model將不包含訓練好的batch_normalization layer,
inference的時候會出現找不到的錯誤:Key Variable not found in checkpoint
因此在宣告saver時要加入save global variable的設定 var_list=tf.global_variables()



就可以解決了~~


本篇主要是筆記一下
(1) batch normalization的物理意義
(2) tensorflow的寫法
(3) save batch normalization model時的注意事項

參考資料:





https://www.tensorflow.org/api_docs/python/tf/layers/batch_normalization

https://www.tensorflow.org/api_docs/python/tf/nn/batch_normalization

2019年3月18日 星期一

[筆記][Git/Github][存參] 檔案過大 error: File ******** is 527.84 MB; this exceeds GitHub's file size limit of 100.00 MB

最近開始把一些時作放到github上
今天遇到了一個問題
就是我的pretrainied model太大了沒辦法push
但是刪掉了之後
error message還是一直出現

後來搜尋了解決辦法
這裡筆記下來
應該會記的比較清楚
(雖然之後會注意檔案大小不要再亂上傳一通)

Error message:
$ git push origin master
Enumerating objects: 20, done.
Counting objects: 100% (20/20), done.
Delta compression using up to 8 threads
Compressing objects: 100% (14/14), done.
Writing objects: 100% (17/17), 489.89 MiB | 14.18 MiB/s, done.
Total 17 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), done.
remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
remote: error: Trace: 4d46485696166b616f2204cef94eef80
remote: error: See http://git.io/iEPt8g for more information.
remote: error: File xxxxx is 527.84 MB; this exceeds GitHub's file size limit of 100.00 MB
To https://github.com/j6079633/CrossModalDistillation_Keras.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://github.com/j6079633/CrossModalDistillation_Keras.git'

Solution:
$ git filter-branch --tree-filter 'rm -rf path/to/your file' HEAD

這一個指令是過濾過去提交紀錄中超出限制大小的檔案移除。

結束後再下一個push的指令即可

但是因為前面整個流程我亂試一通變得有點亂
所以我有先下一個pull rebase的指令

$ git pull --rebase

如果是只有自己的project
很清楚明白有哪些地方被修改的話
可以使用force pull

$ git push -f

最後進行push就可以了

git 是專案管理滿重要的工具
CP值滿高的技能值
雖然大學時有稍微學一下但後來不常用就忘了
不過現在撿回來磨一下應該還來得及><

參考資料:

https://andy6804tw.github.io/2018/12/09/git-exceeds-size/

https://gitbook.tw/chapters/github/fail-to-push.html

https://blog.yorkxin.org/2011/07/29/git-rebase.html


2019年1月14日 星期一

[筆記][Python] XML檔案讀寫(ElementTree and Minidom)

目前用Pascal VOC的格式來存取我的資料,所以python讀寫XML檔就變成是重要的一環,以下紀錄是XML檔的讀寫,也方便自己複習,不用每次都還要問google先生。
以下皆使用ElementTree與Minidom這兩個XML的Python API

  • Import ElementTree
    用cElementTree會比較快因為它是C語言寫的,可以直接使用硬體,下面的import方式就是主要import cElementTree,若沒有C語言base的,才改用python base的套件
    try:
        import xml.etree.cElementTree as ET
    except ImportError:
        import xml.etree.ElementTree as ET
  • 讀取檔案與解析node
    ElementTree讀取檔案的方式也很簡單,只要在建立ElementTree物件的時候給他XML檔案位置即可
    file_name = 'path_to_file'
    tree = ET.ElementTree(file=file_name)

    至於為什麼物件的命名是用tree呢?這是因為XML的格式就好像一棵樹一樣,由一個跟節點延伸出分支,然後各分支又可延伸出更多分支
    以PascalVOC為例
    root
            |--folder
            |--filename
            |--source
                   |--database
                   |--annotation
                   |--image
                   |--flickrid
            |--owner
                   |--flickrid
                   |--name
            |--size
                   |--width
                   |--height
                   |--depth
            |--segmented
            |--object
                   |--name
                   |--pose
                   |--truncated
                   |--difficult
                   |--bndbox
                           |--xmin
                           |--ymin
                           |--xmax
                           |--ymax
            |--object
            ...
    有了xml tree物件之後,便可以開始讀取裡面的node。我自己會用到的為以下3種
    1. 直接遍歷屬於root的節點(不過需要事先知道要找的node在哪一層,才能再更進去找)
    root = tree.getroot()
    for elem in root:
        print(elem.tag, elem.attrib, elem.text)
    
    2. 利用iter()進行節點遍歷
    for elem in tree.iter():
        print(elem.tag, elem.attrib, elem.text)
    
    3.利用iter(tag="node_name")針對特定節點遍歷
    for elem in tree.iter(tag='bndbox'):
        print(elem.tag, elem.attrib, elem.text)
  • 寫入XML檔案
    要製作自己的資料集,寫入xml檔其實是最快的方式,接下來的紀錄是我用xml.dom.minidom來寫檔(VOC格式)
    1. 建立root
    import xml.dom.minidom    
    #create empty root
    doc = xml.dom.minidom.Document() 
    #create root node
    root = doc.createElement('annotation')
    doc.appendChild(root)
    2. 建立子節點並幫子節點接上文字節點(text部分視為末端點)
    nodeFolder = doc.createElement('folder')
    nodeFolder.appendChild(doc.createTextNode(folder))
    3. 建立將子節點接到根結點或其他子節點上
    root.appendChild(nodeFolder)
    4. 開檔以及將建立好的xml tree寫入
    f_n = "file_name.xml"
    fp = open(f_n, 'w')
    doc.writexml(fp, indent='\t', addindent='\t', newl='\n',
                                            encoding="utf-8")

    到這邊就完成了
    不過要注意的一點是節點順序,建立的順序錯誤,檔案的節點順序就會錯誤
以上就是有關於xml讀寫方式的小小記錄,不過我覺得寫入的方式有點冗長,或許用ElemntTree可以更快也更統一,之後有空會來研究看看。



參考資料:
https://pycoders-weekly-chinese.readthedocs.io/en/latest/issue6/processing-xml-in-python-with-element-tree.html

https://docs.python.org/2/library/xml.etree.elementtree.html

http://note.qidong.name/2017/11/write-xml-with-minidom/

https://docs.python.org/2/library/xml.dom.minidom.html

2019年1月4日 星期五

[筆記][電腦] Anaconda 安裝 Intel RealSense Python package

沒想到重新開始寫部落格竟然寫這個XD

目前碩二,實作的東西是利用深度學習模型來完成電腦視覺相關的任務,要做電腦視覺當然要有眼(攝)睛(影機)。因為要做的是堆疊物體的偵測,需要深度影像,但是kinect停產了...所以我們改用Intel RealSense D435~

不過RealSense的python package要裝在Anaconda,或是windows OS上,有點複雜,花了一點時間才裝好...也害怕以後忘記怎麼裝,因此在這裡紀錄一下

[6/12更新]
已經測試在anaconda直接使用pip安裝pyrealsense2不會有問題
應該是該團隊已經修正為可以簡單安裝的方式
如果使用
pip install pyrealsense2
指令安裝後使用有問題的話
再考慮自己make source的方式

好了廢話完畢,開始安裝

1. Git clone source code
首先去librealsense的github頁面下載或clone source code
(建議用git clone的方式,因為之後make的時候也會需要git,乾脆一次裝好)



2. Make source code
這裡要使用CMake,記得下載CMake Windows Source,解壓縮後打開<cmake path>/bin/cmake-gui.exe


source code的部分是剛剛clone下來的librealsense src code
build的destination則在librealsense src code的root directory下新建一個build
Group與Advanced兩個option要記得check
接下進行Configure


我之後會使用VS2015來build,也可以使用自己習慣的IDE來build
Finish之後進行第一次Configure
(這邊可能會發生CMake Error could not find git for clone of libusb,解決方式一是我一開始提到的安裝git,另一個方式是在error發生之後,在BUILD中,取消勾選BUILD_WITH_TM2,不過因為有看到有人說取消勾選並不會解決問題,所以我安裝git)

然後會出現一堆紅色底的configuration,


將BUILD>BUILD_PYTHON_BINDINGS勾選起來,再按一次Configure
然後又有error!!


在Ungrouped Entries>PYTHON_EXCUTABLE欄位中
填上你的conda environment中的python.exe路徑
以我電腦上的路徑就是C:\Users\(User name)\Anaconda3\envs\(Env name)\python.exe

然後就可以Generate VS專案
Generate好之後,點Open Project,VS就會被開啟,直接按Debug/Compile


等一段時間之後就make好了~

3. Install package to Anaconda virtual environment
make完成後,在librealsense/build/Debug中會有下列幾個檔案
"pybackend2.cp36-win_amd64.pyd"
"pyrealsense2.cp36-win_amd64.pyd" 
將這兩個檔案的檔名更改成
"pybackend2.pyd" 
"pyrealsense2.pyd"

接下來將這兩個檔案和"realsense2.dll"複製到C:\Users\(User name)\Anaconda3\envs\(Env name)\DLLs
還有"realsense2.lib"複製至C:\Users\(User name)\Anaconda3\envs\(Env name)\libs

4. Test installation
實際跑librealsense的python example看看有沒有裝成功
(env_name) D:\RealSense\librealsense\wrappers\python\examples>python python-tutorial-1-depth.py


出現以下畫面就是成功了!


感覺以後就會常常用到,因此做個紀錄,也希望幫助到大家

Reference: https://github.com/IntelRealSense/librealsense/issues/1657


2017年5月29日 星期一

[日本東北旅遊]青森小旅行part 2~弘前一日遊:餒菩噠村


搭乘100元循環巴士,我來到了餒濮噠村(ねぷた村),也就是我們常說的睡魔村。會被稱作睡魔村是因為裡面展示了青森名祭-睡魔季會用的燈籠還有鼓跟笛。睡魔祭是什麼呢?每年八月初在青森各地區會有睡魔祭遊行,而祭典中的主體是20多個超大的睡魔燈籠,燈籠上會畫上歌舞伎或神話故事相關的繪飾,並與短笛和太鼓樂隊以及跳人舞者的一起遊行。

在入口前面有很多小攤販兜售他們的商品,感覺很像宜蘭的””,當然很多都是跟蘋果相關的產品,蘋果派阿蘋果醋阿之類的。也有一個大型的紀念品店,不過因為紀念品店是直接跟睡魔村的出口連在一起地所以可以出來再逛

門票是550円,門票本身做得滿精緻的適合當書籤,一進去之後就能看到兩座主燈以及很多面太鼓,有趣的是大約半小時就有一次睡魔祭的太鼓表演及解說,所以錯過的話可以先去繞繞再走下來聽一遍,在震耳欲聾的太鼓聲中,看著緩緩旋轉的睡魔燈籠,彷彿真的置身於睡魔祭現場。


現場也有跳人舞者的服裝可以免費試穿拍照,不過因為我到的時候工作人員在忙我就沒有擅自拿來穿了。走上樓可以看到牆面上掛著各式各樣睡魔燈籠的圖案,也有小型的睡魔燈籠,例如給小朋友拿的金魚睡魔燈籠。

當然還有繪師們的介紹,其實一直很佩服繪師們有畫那麼大的圖案的能力,除了畫工很好以外,很難想像無法綜觀全圖的情況下為什麼有辦法不畫歪哈哈。

接下來是睡魔祭歷史的展示區,不過我最感興趣的是這個鬼女,根本是美與暴力的完美結合(?)

牆上有掛著各地區睡魔祭的舉辦日期,不管事大城市還是小村落都有屬於自己的睡魔祭。而最好的歐咪呀給就是這個金魚睡魔燈籠了,其實他也有出十二生肖版,而我去的時候是櫻花季,當然期間限定(日本人最愛期間限定)的櫻花版金魚睡魔燈籠也誕生了,如果比較想要特別版的話,記得到出口的紀念品店再下手喔。



如果你有時()()的話,也可以報名他們的體驗活動。像是可以自己畫金魚睡魔燈籠,還有做筷子、津輕鈴、津輕燒、蘋果鈴等。不過不要忘了事先預約。當然如果沒那麼多時間親自體驗,也可以看師傅們現場製作,看著他們聚精會神地盯著手中的半成品,一生懸命的想將眼前的作品雕成最好的傑作,就是一種超棒的享受!


我去的時候剛好遇到特殊活動期間,可以免費看三味弦表演,一天有三場表演而我剛好趕上第二場,一場會有兩個三味弦達人表演,有合奏也有solo,演奏者靈活的手指不停的換著壓弦的位置,右手用壓版拍打著弦,不僅奏出旋律也產生節奏,讓整場表演的層次非常豐富。


雖然睡魔村不大,但是內容物卻很豐富,而且交通方便不管是做一百元循環公車或一般市公車,甚至是日租腳踏車都可以,而且就位於弘前城的旁邊,很適合在行程中跟弘前城排在一起喔~