『MXNet』im2rec腳本使用以及數據讀取


一、im2rec用法簡介

首先看文檔:

usage: im2rec.py [-h] [--list] [--exts EXTS [EXTS ...]] [--chunks CHUNKS]
                 [--train-ratio TRAIN_RATIO] [--test-ratio TEST_RATIO]
                 [--recursive] [--no-shuffle] [--pass-through]
                 [--resize RESIZE] [--center-crop] [--quality QUALITY]
                 [--num-thread NUM_THREAD] [--color {-1,0,1}]
                 [--encoding {.jpg,.png}] [--pack-label]
                 prefix root

Create an image list or make a record database by reading from an image list

positional arguments:
  prefix                prefix of input/output lst and rec files.
  root                  path to folder containing images.

optional arguments:
  -h, --help            show this help message and exit

Options for creating image lists:
  --list                If this is set im2rec will create image list(s) by
                        traversing root folder and output to <prefix>.lst.
                        Otherwise im2rec will read <prefix>.lst and create a
                        database at <prefix>.rec (default: False)
  --exts EXTS [EXTS ...]
                        list of acceptable image extensions. (default:
                        ['.jpeg', '.jpg', '.png'])
  --chunks CHUNKS       number of chunks. (default: 1)
  --train-ratio TRAIN_RATIO
                        Ratio of images to use for training. (default: 1.0)
  --test-ratio TEST_RATIO
                        Ratio of images to use for testing. (default: 0)
  --recursive           If true recursively walk through subdirs and assign an
                        unique label to images in each folder. Otherwise only
                        include images in the root folder and give them label
                        0. (default: False)
  --no-shuffle          If this is passed, im2rec will not randomize the image
                        order in <prefix>.lst (default: True)

Options for creating database:
  --pass-through        whether to skip transformation and save image as is
                        (default: False)
  --resize RESIZE       resize the shorter edge of image to the newsize,
                        original images will be packed by default. (default:
                        0)
  --center-crop         specify whether to crop the center image to make it
                        rectangular. (default: False)
  --quality QUALITY     JPEG quality for encoding, 1-100; or PNG compression
                        for encoding, 1-9 (default: 95)
  --num-thread NUM_THREAD
                        number of thread to use for encoding. order of images
                        will be different from the input list if >1. the input
                        list will be modified to match the resulting order.
                        (default: 1)
  --color {-1,0,1}      specify the color mode of the loaded image. 1: Loads a
                        color image. Any transparency of image will be
                        neglected. It is the default flag. 0: Loads image in
                        grayscale mode. -1:Loads image as such including alpha
                        channel. (default: 1)
  --encoding {.jpg,.png}
                        specify the encoding of the images. (default: .jpg)
  --pack-label          Whether to also pack multi dimensional label in the
                        record file (default: False)

必須要填寫的參數有prefix、和root兩個路徑參數,

prefix:生成文件文件夾目錄

     可以指定為.lst的路徑,這樣生成文件會和.lst同一級別,且會根據.lst中的條目生成二進制文件

root:圖片文件目錄,默認的話里面是類別文件夾,類別名做label,每個文件夾存儲圖像

          如果指定了.lst,則每個圖片路徑變為root路徑+.lst中每個圖片的路徑

--pack-label:在指定了.lst后很有用,此時允許label為高維度(主要是label可以設置為數組)

實際上我們之前也介紹過,.lst文件並不是必須的,僅有.rec和.idx就可以滿足需要(標簽存儲在.rec中),它是一個輔助(人工生成.lst指導.rec生成),或者作為一個結果展示(自動生成.rec時選擇同時生成.lst)。

【注意】,最新版本的pack-label等bool參數已經變成了開關型參數,即輸入--pack-label表示原意True。

使用簡介

二、通用圖像數據存儲以及迭代讀取方式

1、生成.lst文件

具體格式如下,各列之間使用'\t'分隔第一列為索引最后一列為文件路徑,這兩列是固定的,中間為標簽列,列數不固定。

0    2    5    0    0.0    0.0    0.3    0.3    2007_000129.jpg
1    2    5    1    0.1    0.1    0.4    0.4    2007_000027.jpg
2    2    5    2    0.2    0.2    0.5    0.5    2007_000123.jpg
3    2    5    3    0.3    0.3    0.6    0.6    2007_000063.jpg
4    2    5    4    0.4    0.4    0.7    0.7    2007_000033.jpg
5    2    5    5    0.5    0.5    0.8    0.8    2007_000121.jpg
6    2    5    6    0.6    0.6    0.9    0.9    2007_000042.jpg
7    2    5    7    0.7    0.7    1.0    1.0    2007_000039.jpg
8    2    5    8    0.8    0.8    1.1    1.1    2007_000032.jpg
9    2    5    9    0.9    0.9    1.2    1.2    2007_000061.jpg
10    2    5    10    1.0    1.0    1.3    1.3    2007_000068.jpg
11    2    5    11    1.1    1.1    1.4    1.4    2007_000170.jpg

代碼如下,

import os
name_list = [f for f in os.listdir('./') if f.endswith('jpg')]
with open('my_test.lst', 'w+') as f:  
    for i, n in enumerate(name_list):  
        f.write(  
            str(i) + '\t' +  # idx
            '2' + '\t' + '5' + '\t' +  # 頭信息長度(不含索引), 每個obj長度
            str(i) + '\t' +  # class  
            str((i / 10)) + '\t' + str((i / 10)) + '\t' + str(((i + 3) / 10)) + '\t' +str(((i + 3) / 10)) + '\t' +  
            # xmin, ymin, xmax, ymax  
            n + '\n'
            # image path
        )

2、創建.rec

調用子進程創建rec文件:

import subprocess
import mxnet as mx

im2rec_path = os.path.join(mx.__path__[0], 'tools/im2rec.py')  # 尋找im2rec.py路徑
# final validation - sometimes __path__ (or __file__) gives 'mxnet/python/mxnet' instead of 'mxnet'
if not os.path.exists(im2rec_path):
    im2rec_path = os.path.join(os.path.dirname(os.path.dirname(mx.__path__[0])), 'tools/im2rec.py')
    
subprocess.check_call(["python", im2rec_path,
        os.path.abspath('my_test.lst'), os.path.abspath('./'), "--pack-label"])

返回0表示進程順利結束。

3、讀取.rec

這里我門介紹一下幾種讀取API使用方式,ImageIter要求標簽列數固定,label_width=7表示中間7列為標簽列,我們打印了標簽作示范:

data_iter = mx.image.ImageIter(batch_size=4, 
                              resize=30,
                              label_width=7,
                              data_shape=(3, 30, 60),# depth,height,width
                              path_imgrec="./my_test.rec",
                              path_imgidx="./my_test.idx" )
data_iter.reset()
batch = data_iter.next()
img, labels = batch.data[0], batch.label[0]
print(labels)
[[ 2.          5.          0.          0.          0.          0.30000001  0.30000001]
 [ 2.          5.          1.          0.1         0.1         0.40000001  0.40000001]
 [ 2.          5.          2.          0.2         0.2         0.5         0.5       ]
 [ 2.          5.          3.          0.30000001  0.30000001  0.60000002  0.60000002]]
<NDArray 4x7 @cpu(0)>

簡明易懂,不過對於很多目標檢測任務來說,object數目並不一致,中間的label列也就不一致,此時下面的API泛用性更好:

rec = mx.image.ImageDetIter(
            path_imgrec     = './my_test.rec',
            path_imglist    = '',
            batch_size      = 4,
            data_shape      = (3, 300, 300))
rec.next().label[0]

 InageDetIter沒有label_width參數,其扣除首末兩列,中間都作為待定標簽列:0列-索引列,1列-頭信息列數,2列-每個對象信息列數,3~(n-1)列-標簽列,n列-圖像路徑。

輸出時會在1~n-1列中先扣除第二列數字的列數(本例中1、2兩列被扣除),之后的列數才是標簽:

[[[ 0.          0.          0.          0.30000001  0.30000001]]

 [[ 1.          0.1         0.1         0.40000001  0.40000001]]

 [[ 2.          0.2         0.2         0.5         0.5       ]]

 [[ 3.          0.30000001  0.30000001  0.60000002  0.60000002]]]
<NDArray 4x1x5 @cpu(0)>

下面我們測試一下各張圖片label長度不等的情況:

im2rec_path = os.path.join(mx.__path__[0], 'tools/im2rec.py')  # 尋找im2rec.py路徑
# final validation - sometimes __path__ (or __file__) gives 'mxnet/python/mxnet' instead of 'mxnet'
if not os.path.exists(im2rec_path):
    im2rec_path = os.path.join(os.path.dirname(os.path.dirname(mx.__path__[0])), 'tools/im2rec.py')
    
subprocess.check_call(["python", im2rec_path,
        os.path.abspath('my_test.lst'), os.path.abspath('./'), "--pack-label"])

rec = mx.image.ImageDetIter(
            path_imgrec     = './my_test.rec',
            path_imglist    = '',
            batch_size      = 4,
            data_shape      = (3, 300, 300))
rec.next().label[0]

label長度不足的圖片使用-1進行了補齊:

[[[ 0.          0.          0.          0.30000001  0.30000001]
  [ 1.          2.          3.          4.          5.        ]]

 [[ 1.          0.1         0.1         0.40000001  0.40000001]
  [-1.         -1.         -1.         -1.         -1.        ]]

 [[ 2.          0.2         0.2         0.5         0.5       ]
  [-1.         -1.         -1.         -1.         -1.        ]]

 [[ 3.          0.30000001  0.30000001  0.60000002  0.60000002]
  [-1.         -1.         -1.         -1.         -1.        ]]]
<NDArray 4x2x5 @cpu(0)>

這一點上反倒是TensorFlow寬松一點,如果是None位置,在同一個會話中也可以通過不同的形狀:

import tensorflow as tf

input_ = tf.placeholder(dtype=tf.int8, shape=(None,))

with tf.Session() as sess:
    print(sess.run(input_, feed_dict={input_:(10,1)}))
    print(sess.run(input_, feed_dict={input_:(10,1,5)}))

[10 1]

[10 1 5] 

也即是說在標簽讀取中,TensorFlow不需要補全-1,不同圖片的標簽形狀不需要進行統一(見前面的TensorFlow-SSD標簽處理一節)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM