2018년 4월 11일 수요일

축약형 ILSVRC2012_img_train_t3.tar을 이용한 training dataset 준비

원래 tensorflow로 inception v3를 테스트할 때는 보통 128만장의 사진을 담은 138GB짜리 ILSVRC2012_img_train.tar를 씁니다만, 요즘 image-net.org의 서버 사정이 안 좋은지 download가 제대로 되지 않습니다.  대신 강아지들의 사진만 따로 담은 훨씬 작은 760MB 정도의 ILSVRC2012_img_train_t3.tar을 써서 동일한 테스트를 할 수 있습니다.

테스트에 필요한 파일들은 ILSVRC2012_img_train_t3.tar와 ILSVRC2012_img_val.tar, 그리고 bounding_box를 위한 xml 파일들을 담은 Annotation.tar.gz 입니다.

[user1@ac922 raw-data]$ pwd
/home/user1/ilsvrc2012/raw-data

[user1@ac922 raw-data]$ ls -l ../../files/IL*.tar
-rw-rw-r--. 1 user1 user1  762460160 Jul  4  2012 ../../files/ILSVRC2012_img_train_t3.tar
-rw-rw-r--. 1 user1 user1 6744924160 Jun 15  2012 ../../files/ILSVRC2012_img_val.tar

[user1@ac922 raw-data]$ wget http://image-net.org/Annotation/Annotation.tar.gz

다음과 같이 ILSVRC2012_img_train_t3.tar을 train directory에 풀어놓습니다.  n02085620 등의 이름으로 된 sub-directory별로 사진들이 들어 있습니다.

[user1@ac922 raw-data]$ cd train

[user1@ac922 train]$ tar -xf ../../../files/ILSVRC2012_img_train_t3.tar

[user1@ac922 train]$ for i in `ls n*.tar | cut -d. -f1`
> do
> mkdir ${i}
> tar -xf ${i}.tar -C ${i}
> rm ${i}.tar
> done

원래의 ILSVRC2012_img_train.tar라면 총 1000개의 directory가 생기겠으나, 이 ILSVRC2012_img_train_t3.tar는 120개입니다.

[user1@ac922 train]$ ls -1 | wc -l
120

[user1@ac922 train]$ ls | head
n02085620
n02085782
n02085936
n02086079
n02086240
n02086646
n02086910
n02087046
n02087394
n02088094

[user1@ac922 train]$ du -sm .
753     .

6GB 정도되는 ILSVRC2012_img_val.tar는 일단 validation directory에 그냥 풀어넣습니다.  이건 총 50000장의 사진입니다.

[user1@ac922 validation]$ tar -xf ../../../files/ILSVRC2012_img_val.tar

[user1@ac922 validation]$ ls | head
ILSVRC2012_val_00000001.JPEG
ILSVRC2012_val_00000002.JPEG
ILSVRC2012_val_00000003.JPEG
ILSVRC2012_val_00000004.JPEG
ILSVRC2012_val_00000005.JPEG
ILSVRC2012_val_00000006.JPEG
ILSVRC2012_val_00000007.JPEG
ILSVRC2012_val_00000008.JPEG
ILSVRC2012_val_00000009.JPEG
ILSVRC2012_val_00000010.JPEG

[user1@ac922 validation]$ ls | wc -l
50000

[user1@ac922 validation]$ du -sm .
6496    .

이제 bounding_boxes를 위해 Annotation.tar.gz을 풀어놓습니다.  이 속에도 directory별로 tar.gz 파일들이 들어있습니다.

[user1@ac922 validation]$ cd ..

[user1@ac922 raw-data]$ tar -zxf ./Annotation.tar.gz

[user1@ac922 raw-data]$ for i in `ls n*.tar.gz`
> do
> tar -zxf ${i}
> rm ${i}
> done

이제 이 Annotation이라는 이름의 directory를 bounding_boxes라는 이름으로 바꿉니다.

[user1@ac922 raw-data]$ mv Annotation bounding_boxes

[user1@ac922 bounding_boxes]$ ls | head
n00007846
n00015388
n00017222
n00021265
n00439826
n00440039
n00440941
n00441824
n00443692
n00445351

이 속에는 총 3627개의 directory가 있으며, 그 각각마다 xml 파일들이 들어있습니다.

[user1@ac922 bounding_boxes]$ ls | wc -l
3627

[user1@ac922 bounding_boxes]$ ls n00007846 | head
n00007846_103856.xml
n00007846_104163.xml
n00007846_104414.xml
n00007846_105689.xml
n00007846_106069.xml
n00007846_107024.xml
n00007846_109518.xml
n00007846_109796.xml
n00007846_110945.xml
n00007846_111865.xml

이 xml 파일들과 raw image들을 TFRecord 포맷으로 변환하겠습니다. 거기에는 아래 github에서 제공되는 script tool과 label 들을 사용합니다.

[user1@ac922 ~]$ git clone https://github.com/tensorflow/models.git

[user1@ac922 ~]$ cd ~/models/research/inception/inception/data

이 속에 들어있는 imagenet_metadata.txt 등의 각종 label 파일들은 모두 ILSVRC2012_img_train_t3.tar가 아니라 ILSVRC2012_img_train.tar를 기준으로 만들어진 것입니다.  이것을 그대로 사용하면 TFRecord로 변환할 때 error가 생길 것이므로, 이 중에서 ILSVRC2012_img_train_t3.tar에 들어있는 label들만 골라내어 새로 만드는 작업을 해야 합니다.

먼저 backup을 떠놓습니다.

[user1@ac922 data]$ cp imagenet_metadata.txt imagenet_metadata.txt.org

[user1@ac922 data]$ head imagenet_metadata.txt
n00004475       organism, being
n00005787       benthos
n00006024       heterotroph
n00006484       cell
n00007846       person, individual, someone, somebody, mortal, soul
n00015388       animal, animate being, beast, brute, creature, fauna
n00017222       plant, flora, plant life
n00021265       food, nutrient
n00021939       artifact, artefact
n00120010       hop

[user1@ac922 data]$ wc -l imagenet_metadata.txt
21842 imagenet_metadata.txt

다음과 같이 실제로 ~/ilsvrc2012/raw-data/train directory 속에 들어있는 이름들만 골라서 새로  imagenet_metadata.txt.new를 만든 뒤, 그것을  imagenet_metadata.txt에 overwrite합니다.

[user1@ac922 data]$ for i in `ls ~/ilsvrc2012/raw-data/train`
> do
> grep $i imagenet_metadata.txt >> imagenet_metadata.txt.new
> done

총 120개만 골라진 것을 볼 수 있고, 또 거기 들어간 이름들은 모두 멍멍이 종류인 것을 볼 수 있습니다.

[user1@ac922 data]$ wc -l imagenet_metadata.txt.new
120 imagenet_metadata.txt.new

[user1@ac922 data]$ head imagenet_metadata.txt.new
n02085620       Chihuahua
n02085782       Japanese spaniel
n02085936       Maltese dog, Maltese terrier, Maltese
n02086079       Pekinese, Pekingese, Peke
n02086240       Shih-Tzu
n02086646       Blenheim spaniel
n02086910       papillon
n02087046       toy terrier
n02087394       Rhodesian ridgeback
n02088094       Afghan hound, Afghan


imagenet_lsvrc_2015_synsets.txt에 대해서도 동일한 작업을 해줍니다.

[user1@ac922 data]$ wc -l imagenet_lsvrc_2015_synsets.txt
1000 imagenet_lsvrc_2015_synsets.txt.org

[user1@ac922 data]$ cp imagenet_lsvrc_2015_synsets.txt imagenet_lsvrc_2015_synsets.txt.org

[user1@ac922 data]$ head imagenet_lsvrc_2015_synsets.txt
n01440764
n01443537
n01484850
n01491361
n01494475
n01496331
n01498041
n01514668
n01514859
n01518878

[user1@ac922 data]$ for i in `ls ~/ilsvrc2012/raw-data/train`
> do
> grep $i imagenet_lsvrc_2015_synsets.txt >> imagenet_lsvrc_2015_synsets.txt.new
> done

[user1@ac922 data]$ wc -l imagenet_lsvrc_2015_synsets.txt.new
120 imagenet_lsvrc_2015_synsets.txt.new

[user1@ac922 data]$ cp imagenet_lsvrc_2015_synsets.txt.new imagenet_lsvrc_2015_synsets.txt

[user1@ac922 data]$ head imagenet_lsvrc_2015_synsets.txt
n02085620
n02085782
n02085936
n02086079
n02086240
n02086646
n02086910
n02087046
n02087394
n02088094


[user1@ac922 data]$ wc -l imagenet_lsvrc_2015_synsets.txt
120 imagenet_lsvrc_2015_synsets.txt


그리고 validation용 label인 imagenet_2012_validation_synset_labels.txt에 대해서도 비슷한 작업을 해줍니다.

[user1@ac922 data]$ wc -l imagenet_2012_validation_synset_labels.txt
50000 imagenet_2012_validation_synset_labels.txt

[user1@ac922 data]$ cp imagenet_2012_validation_synset_labels.txt imagenet_2012_validation_synset_labels.txt.org

[user1@ac922 data]$ head imagenet_2012_validation_synset_labels.txt
n01751748
n09193705
n02105855
n04263257
n03125729
n01735189
n02346627
n02776631
n03794056
n02328150


[user1@ac922 data]$ for i in `ls ~/ilsvrc2012/raw-data/train`
> do
> grep $i imagenet_2012_validation_synset_labels.txt >> imagenet_2012_validation_synset_labels.txt.new
> done

이 작업을 통해 총 5만장이던 validation용 이미지가 이제 6천장으로 줄어든 것을 보실 수 있습니다.

[user1@ac922 data]$ wc -l imagenet_2012_validation_synset_labels.txt.new
6000 imagenet_2012_validation_synset_labels.txt.new

이제 bounding_boxes에 들어있는 것들도 비슷한 작업을 통해 개수를 줄여줍니다.

[user1@ac922 data]$ for i in `ls ~/ilsvrc2012/raw-data/bounding_boxes`
> do
> grep ${i} imagenet_lsvrc_2015_synsets.txt
> if [[ $? -ne 0 ]]
> then
> rm -rf ~/ilsvrc2012/raw-data/bounding_boxes/${i}
> fi
> done

다음과 같이 120개 directory만 남은 것을 보실 수 있습니다.

[user1@ac922 data]$ ls ~/ilsvrc2012/raw-data/bounding_boxes | wc -l
120

이제 TFRecord 파일들을 담을 directory를 만들어 줍니다.

[user1@ac922 data]$ mkdir ~/ilsvrc2012/tfrecord

원래 github에서 제공되는 download_and_preprocess_imagenet.sh를 수행하면 download 부터 TFRecord로의 변환까지 일괄적으로 수행됩니다만, 여기서는 138GB의 data를 download 받을 수도 없고 또 이런저런 환경이 다르므로, 아래와 같이 그 핵심부분만 따와서 새로 tf_preprocess.sh라는 script를 만들었습니다.

[user1@ac922 data]$ vi tf_preprocess.sh
#!/bin/bash
DATA_DIR="${1%/}"
SCRATCH_DIR="${DATA_DIR}/raw-data/"
WORK_DIR="$HOME/models/research/inception/inception"

TRAIN_DIRECTORY="${SCRATCH_DIR}train/"
VALIDATION_DIRECTORY="${SCRATCH_DIR}validation/"

BOUNDING_BOX_SCRIPT="${WORK_DIR}/data/process_bounding_boxes.py"
BOUNDING_BOX_FILE="${SCRATCH_DIR}/imagenet_2012_bounding_boxes.csv"
BOUNDING_BOX_DIR="${SCRATCH_DIR}bounding_boxes/"

# Preprocess the validation data by moving the images into the appropriate
# sub-directory based on the label (synset) of the image.
echo "Organizing the validation data into sub-directories."
PREPROCESS_VAL_SCRIPT="${WORK_DIR}/data/preprocess_imagenet_validation_data.py"
VAL_LABELS_FILE="${WORK_DIR}/data/imagenet_2012_validation_synset_labels.txt"

"${PREPROCESS_VAL_SCRIPT}" "${VALIDATION_DIRECTORY}" "${VAL_LABELS_FILE}"

# Convert the XML files for bounding box annotations into a single CSV.
echo "Extracting bounding box information from XML."
BOUNDING_BOX_SCRIPT="${WORK_DIR}/data/process_bounding_boxes.py"
BOUNDING_BOX_FILE="${SCRATCH_DIR}/imagenet_2012_bounding_boxes.csv"
BOUNDING_BOX_DIR="${SCRATCH_DIR}bounding_boxes/"
LABELS_FILE="${WORK_DIR}/data/imagenet_lsvrc_2015_synsets.txt"

"${BOUNDING_BOX_SCRIPT}" "${BOUNDING_BOX_DIR}" "${LABELS_FILE}" \
 | sort > "${BOUNDING_BOX_FILE}"
echo "Finished downloading and preprocessing the ImageNet data."

# Build the TFRecords version of the ImageNet data.
BUILD_SCRIPT="/usr/bin/python ${WORK_DIR}/data/build_imagenet_data.py"
OUTPUT_DIRECTORY="${DATA_DIR}/tfrecord"
IMAGENET_METADATA_FILE="${WORK_DIR}/data/imagenet_metadata.txt"

python $HOME/models/research/inception/inception/data/build_imagenet_data.py \
  --train_directory="${TRAIN_DIRECTORY}" \
  --validation_directory="${VALIDATION_DIRECTORY}" \
  --output_directory="${OUTPUT_DIRECTORY}" \
  --imagenet_metadata_file="${IMAGENET_METADATA_FILE}" \
  --labels_file="${LABELS_FILE}" \
  --bounding_box_file="${BOUNDING_BOX_FILE}"

이 tf_preprocess.sh는 그 속에서 build_imagenet_data.py를 불러 TFRecord로의 변환을 수행합니다.  이 script는 총 1000개의 shard에 training data를 넣는데, 이 숫자를 120으로 줄이겠습니다.  validation shard는 32개로 줄이겠습니다.

[user1@ac922 data]$ vi build_imagenet_data.py
...
#tf.app.flags.DEFINE_integer('train_shards', 1024,
tf.app.flags.DEFINE_integer('train_shards', 120,
                            'Number of shards in training TFRecord files.')
#tf.app.flags.DEFINE_integer('validation_shards', 128,
tf.app.flags.DEFINE_integer('validation_shards', 32,
                            'Number of shards in validation TFRecord files.')
...


이제 tf_preprocess.sh script에 실행 permission을 주고 실행하면 TFRecord로의 변환이 시작됩니다.

[user1@ac922 data]$ chmod a+x tf_preprocess.sh

[user1@ac922 data]$ ./tf_preprocess.sh ~/ilsvrc2012
...
2018-04-11 19:22:21.150944 [thread 2]: Wrote 2572 images to 2572 shards.
2018-04-11 19:22:21.151077 [thread 6]: Wrote 172 images to /home/user1/ilsvrc2012/tfrecord/train-00104-of-00120
2018-04-11 19:22:21.151131 [thread 6]: Wrote 2572 images to 2572 shards.
2018-04-11 19:22:21.247600 [thread 7]: Wrote 172 images to /home/user1/ilsvrc2012/tfrecord/train-00119-of-00120
2018-04-11 19:22:21.247631 [thread 7]: Wrote 2573 images to 2573 shards.
2018-04-11 19:22:21.506394: Finished writing all 20580 images in data set.

이렇게 멍멍이 사진 20580장의 변환이 완료되었습니다.

[user1@ac922 data]$ cd ~/ilsvrc2012/tfrecord/
[user1@ac922 tfrecord]$ ls train-* | wc -l
120
[user1@ac922 tfrecord]$ ls validation-* | wc -l
32
[user1@ac922 tfrecord]$ du -sm .
1475    .


이렇게 만들어진 ~/ilsvrc2012/tfrecord 디렉토리 밑의 file들을 다음 명령어로 뭉쳐서 아래 URL에 올려두었습니다.

[user1@ac922 ilsvrc2012]$ tar -zcvf tfrecord.tgz tfrecord


https://drive.google.com/open?id=1rQcxAWeNbByy0Yooj6IbROyVRsdQPn5-




댓글 없음:

댓글 쓰기