顯示具有 Python 標籤的文章。 顯示所有文章
顯示具有 Python 標籤的文章。 顯示所有文章

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年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