ACCV2020細粒度比賽記錄-資料處理和Baseline結果分享

2020-10-25 10:01:04

比賽連結:

  • accv官網:https://sites.google.com/view/webfg2020
  • 比賽網站:https://www.cvmart.net/race/9917/base

資料下載:

Linux下合併解壓:cat train.tar.gz.* | tar -zxv

1.資料淨化

訓練集:5000類,557,169張圖片

測試集:5000類,100,000張圖片

由於資料來源於網路,可以視為直接從網站上爬蟲下來且字尾全部改成了jpg格式,而從實際情況來看圖片原本包含的格式有jpg、png、gif、tiff等,這就會導致使用程式碼讀取的時候報錯(Error)或者警告(Warning),因此需要先對資料進行清洗。Warning由於不會對程式執行造成影響,需要轉換成可報錯的Error,程式碼如下。

import warnings
warnings.filterwarnings('error')

根據實際情況清理出的報錯主要有以下幾種

  • corrupt EXIFPossibly corrupt EXIF,這種是EXIF資訊缺失導致的,篩選出來再去掉其EXIF頭就可以了

    # Refer: https://blog.csdn.net/a19990412/article/details/105940446
    # pip install piexif -i https://pypi.tuna.tsinghua.edu.cn/simple/
    import piexif
    piexif.remove(img_path)
    
  • Palette images with Transparency是在PIL呼叫convert('RGB')的時候丟擲的,大概是說alpha通道的轉換問題,暫時沒有解決,先把非RGB(通道數不為3)的圖篩選出來,因為後來發現不止4通道圖,還有單通道和雙連結的圖,再單獨對這部分資料篩選報錯的,發現數量較少,直接從資料集中剔除處理。

  • image file could not be identified because WEBP,這是由於有的資料原本是webp格式,PIL讀取有問題,而且好像是conda環境下才存在,解決方案有幾種:

    • 升級PIL庫,6.x,7.x是沒有問題但是會丟擲新的問題,為了避免麻煩,就用的5.4.1版本
    pip install Pillow==5.4.1
    
    • 安裝webp庫,更新PIL解決了就沒有實測
  • 未知錯誤,在一開始排查沒有查出來,所幸用了screen儲存歷史log,未知錯誤也只有幾張,直接篩選出來了,錯誤資訊如下:

    Image size (117762898 pixels) exceeds limit of 89478485 pixels
    Metadata Warning, tag 296 had too many entries
    Image appears to be a malformed MPO file
    

完整程式碼:

step1: 遍歷所有圖片,篩選有問題的

import os
from PIL import Image
import cv2
import warnings
warnings.filterwarnings('error')

root = './train'

f1 = open('pExifError.txt', 'w')
f2 = open('rgbaError.txt', 'w')
f3 = open('ExifError.txt', 'w')
f4 = open('4chImg.txt', 'w')
f5 = open('WebpError.txt', 'w')
f6 = open('UnknownError.txt', 'w')

idx = 0
for r, d, files in os.walk(root):
    if files != []:
        for i in files:
            fp = os.path.join(r, i)
            try:
                img = Image.open(fp)
                if(len(img.split()) != 3):
                    # print('4CH:', fp)
                    f4.write('{}\n'.format(fp))
                    
            except Exception as e:
                print('Error:', str(e))
                print(fp)
                if 'Possibly corrupt EXIF data' in str(e):
                    print('Exif error')
                    f1.write('{}\n'.format(fp))
                elif 'Palette images with Transparency' in str(e):
                    print('rgba error')
                    f2.write('{}\n'.format(fp))
                elif 'Corrupt EXIF data' in str(e):
                    print('pExif error')
                    f3.write('{}\n'.format(fp))
                elif 'image file could not be identified because WEBP' in str(e):
                    print('Webp error')
                    f5.write('{}\n'.format(fp))
                else:
                    print('Unknown error')
                    f6.write('{}\n'.format(fp))
    		
            if idx % 5000 == 0:
                print('='*20, idx)
            
            idx += 1

f1.close()
f2.close()
f3.close()
f4.close()
f5.close()
f6.close()

step2: 篩選不可轉換的圖片

import warnings
from PIL import Image
warnings.filterwarnings('error')

f1 = open('rgbaError.txt', 'w')
f2 = open('rgbaOK.txt', 'w')

with open('4chImg.txt', 'r')as f:
    for i in f.readlines():
        i = i.strip()
        try:
            img = Image.open(i).convert('RGB')
            f2.write('{}\n'.format(i))
            
        except Exception as e:
            print('Error:', str(e))
            print(i)
            f1.write('{}\n'.format(i))

f1.close()
f2.close()

step3: 修改和再測試

import os
import piexif
import warnings
from PIL import Image
warnings.filterwarnings('error')

files = ['ExifError.txt', 'pExifError.txt']

for file in files:
    with open(file, 'r')as f:
        for i in f.readlines():
            i = i.strip()
            print(i.strip())
            piexif.remove(i.strip())
            # try:
            #    img = Image.open(i)
            # except Exception as e:
            #     print('Error:', str(e))
            #     print(i)

2.劃分資料集

個人習慣把路徑存到txt再在dataset載入。

from sklearn.model_selection import train_test_split
import os

if __name__ == '__main__':
    root = './train'

    fpath = []
    labels = []
    for d in os.listdir(root):
        fd = os.path.join(root, d)
        label = int(d)
        for i in os.listdir(fd):
            fp = os.path.join(fd, i)
            fpath.append(fp)
            labels.append(label)
            
    print(len(fpath), len(labels))
    
    x_train, x_val, y_train, y_val = train_test_split(fpath, labels, random_state=999, test_size=0.2)
    print(len(x_train), len(x_val))

    with open('train.txt', 'w')as f:
        for fn, l in zip(x_train, y_train):
            f.write('{},{}\n'.format(fn, l))

    with open('val.txt', 'w')as f:
        for fn, l in zip(x_val, y_val):
            f.write('{},{}\n'.format(fn, l))

3.預處理

原資料由於尺寸不一,多數是高清圖片,訓練時resize會很耗時,因此先resize到一個小尺寸儲存起來。Image.thumbnail()可以起到過濾的作用,如果hw在範圍內就不會resize,超過就會按比例放縮。影象品質和JPG壓縮問題參考部落格1,部落格2

import os
from PIL import Image
import cv2
import shutil

root = './train'
save_path = './thumbnail'
for r, d, files in os.walk(root):
    if files != []:
        for i in files:
            fp = os.path.join(r, i)
            label = i.split('_')[0]
            dst = os.path.join(save_path, label)
            if not os.path.exists(dst):
                os.makedirs(dst)
            
            img = Image.open(fp).convert('RGB')
            w, h = img.size
            if max(w, h) > 1080:
                img.thumbnail((1080, 1080), Image.ANTIALIAS)
                img.save(os.path.join(dst, i), quality=95, subsampling=0)
            else:
                shutil.copy(fp, os.path.join(dst, i))

處理前資料集大小為114G,處理後為86G。

Tesla V100 32GB*2 硬體環境下,訓練Baseline,處理前訓練時間一個epoch約為2400s(40min),處理後一個epoch約1400s(23min),極大縮小了訓練時間,精度應該沒有什麼影響,調小判別尺寸應該還能更快,畢竟訓練資料尺寸是224x224。

4.Baseline
# ls: labelsmooth
# cat: cat(gmp, gap)
{
    model: resnet50,
    pool: cat,
    init_lr: 0.01,
    schedule: cos(warm: 5),
    epochs: <60,
    loss: ls 0.2,
    result: 41.497
}
{
    model: resnext50,
    pool: cat,
    init_lr: 0.01,
    shcedule: step(step: 8, gamma: 0.5),
    epochs: 60,
    loss: ls 0.2,
    result: 42.748
}

_(:з」∠)_佛系參賽,等大佬們分享高分solution。