이미지 데이터 스케일링은 어떻게 진행되고 각 모델에 맞게 스케일링을 어떻게 해야할까?

 

목차

  1. Cat&Dog Data Load
  2. image data의 scaling preprocessing 유형
  3. tf 또는 torch 유형으로 변경하는 함수 생성
  4. scale 된 이미지 pixel값의 histogram 시각화
  5. 그러나 논문에 나와있는 pretrained 모델들은 고유한 scaling 방법이 있다 : preprocess_input()
  6. ImageDataGenerator에 preprocess_input()을 적용시 preprocessing_function 파라미터를 사용

1. Data Load

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

import os
for dirname, _, filenames in os.walk('/kaggle/input'): 
    for filename in filenames:
        print(os.path.join(dirname, filename))

 

paths = []
dataset_gubuns = []
label_gubuns = []
# os.walk()를 이용하여 특정 디렉토리 밑에 있는 모든 하위 디렉토리를 모두 조사한다.
# cat-and-dog 하위 디렉토리 밑에 jpg 확장자를 가진 파일이 모두 이미지 파일이다.
# cat-and-dog 밑으로 /train, /test 하위 디렉토리가 존재한다.(학습, 테스트용 이미지 파일을 가진다.)

for dirname, _, filenames in os.walk('/kaggle/input/cat-and-dog'):
    for filename in filenames:
        # 이미지 파일이 아닌 파일도 해당 디렉토리에 있다.
        if '.jpg' in filename: # jpg 파일을 가지고 있다면
            # 파일의 절대경로를 file_path 변수에 할당한다.
            file_path = dirname+'/'+filename
            paths.append(file_path)
            
            # 파일의 절대 경로에 training_set, test_set이 포함되어 있으면 데이터셋 구분을 train, test로 분류한다.
            if '/training_set/' in file_path:
                dataset_gubuns.append('train')
            elif '/test_set/' in file_path:
                dataset_gubuns.append('test')
            else:
                dataset_gubuns.append('N/A')
            
            # 파일의 절대 경로에 dogs가 있을 경우 해당 파일은 dog 이미지이고 cat일 경우 cat 이미지 파일이다.
            if 'dogs' in file_path:
                label_gubuns.append('DOG')
            elif 'cats' in file_path:
                label_gubuns.append('CAT')
            else: 
                label_gubuns.append('N/A')

 

pd.set_option('display.max_colwidth', 200)

data_df = pd.DataFrame({'path':paths, 'dataset':dataset_gubuns, 'label':label_gubuns})
print('data_df shape:', data_df.shape)
print(data_df['dataset'].value_counts())
data_df.head(10)

 

# 개와 고양이의 이미지 파일 절대 경로를 cv2.imread()로 읽어서 image array로 로드하고 시각화
# 이미지별로 서로 다른 이미지 사이즈를 가지고 있다.
import matplotlib.pyplot as plt
import cv2
%matplotlib inline

def show_grid_images(image_path_list, ncols=8, augmentor=None, title=None):
    figure, axs = plt.subplots(figsize=(22,6), nrows=1, ncols=ncols)
    for i in range(ncols):
        image = cv2.cvtColor(cv2.imread(image_path_list[i]), cv2.COLOR_BGR2RGB)
        axs[i].imshow(image)
        axs[i].set_title(title)

# 강아지와 고양이인 것들의 path컬람을 가져와서 이미지 리스트를 만든다.
dog_image_list = data_df[data_df['label']=='DOG']['path'].iloc[:6].tolist()
show_grid_images(dog_image_list, ncols=6, title='DOG')

cat_image_list = data_df[data_df['label']=='CAT']['path'].iloc[:6].tolist()
show_grid_images(cat_image_list, ncols=6, title='CAT')

 


2. image data의 scaling preprocessing 유형

  • 0 ~ 1 사이, -1 ~ 1 사이, z-score 변환 중에 선택한다.
  • pretrained 모델은 주로 tf와 torch 프레임웍으로 생성된다.
  • tf는 -1 ~ 1 로 변환.
  • torch는 전통적으로 z-score 변환(0 ~ 1로 scaling 후 ImageNet 데이터 세트의 이미지 채널별 평균값, 표준편차값을 이용하여 z score 변환 적용)

 

import cv2

# 임의의 이미지 한개 선택. 
image = cv2.cvtColor(cv2.imread(data_df['path'].iloc[0]), cv2.COLOR_BGR2RGB)
plt.imshow(image)


3. tf 또는 torch 유형으로 변경하는 함수 생성

def preprocessing_scaling(x, mode='tf'):
    if mode == 'tf': # 텐서플로우
        x = x/127.5
        x -= 1. # 여기까지하면 -1~1 값이 만들어진다.
    
    elif mode == 'torch': # 파이토치
        x = x/255. # 255로 나눠서 0~1 값으로 바꾼다.
        mean = [0.485, 0.456, 0.406] # 데이터의 평균이 아니라 imageNet의 평균이다.
        std = [0.229, 0.224, 0.225]
        
        x[:, :, 0] = (x[:, :, 0] - mean[0])/std[0]
        x[:, :, 1] = (x[:, :, 1] - mean[1])/std[1]
        x[:, :, 2] = (x[:, :, 2] - mean[2])/std[2]
        
    return x

scaled_image_tf = preprocessing_scaling(image, mode='tf')
scaled_image_torch = preprocessing_scaling(image, mode='torch')

4. scale 된 이미지 pixel값의 histogram 시각화

def show_pixel_histogram(image):
    fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(16, 6))

    for i in range(3):
        # i값 0 일때 Red 채널, i값 1일때 Green Channel, i값 2일때 Blue Channel Histogram 표현 
        axs[i].hist(image[:, :, i].flatten(), bins=100, alpha=0.5) # 사진 옵션들
        axs[i].legend(loc='upper right') # 어디에 달거냐
        if i==0:
            title_str = 'Red'
        elif i==1:
            title_str = 'Green'
        else: 
            title_str = 'Blue'
        axs[i].set(title=title_str)
        
show_pixel_histogram(scaled_image_tf)
show_pixel_histogram(scaled_image_torch)

 

텐서플로우는 -1~1 변환 되었고, 토치는 z-score 변환 되었다. 그래서 -2~2 정도까지 간다.

전반적인 히스토그램 자체는 다르지 않다.

 

 

그럼 왜 이 방법으로 안해?

그냥 255.0 으로 나누는 것이 가장 편하다. 쉽다. 

그냥 0~1로 변환하는게 편하다.

 

show_pixel_histogram(image/255.0)

 


5. 그러나 논문에 나와있는 pretrained 모델들은 고유한 scaling 방법이 있다.

케라스에서는 preprocess_input 만 갖다쓰면 그냥 알아서 바뀐다.

 

xception 모델

from tensorflow.keras.applications.xception import preprocess_input

# Xception의 scaling 방식은 tf : -1 ~ +1
scaled_image_xception = preprocess_input(image)
show_pixel_histogram(scaled_image_xception)

-1 ~ 1

 

DenseNet 모델

from tensorflow.keras.applications.densenet import preprocess_input

# DenseNet의 scaling 방식은 torch 스타일
scaled_image_densenet = preprocess_input(image)
show_pixel_histogram(scaled_image_densenet)

-2 ~ 2

 


6. ImageDataGenerator에 preprocess_input()을 적용시 preprocessing_function 파라미터를 사용

from tensorflow.keras.applications.xception import preprocess_input

#tr_generator = ImageDataGenerator(horizontal_flip=True, rescale=1/255.)
tr_generator = ImageDataGenerator(horizontal_flip=True, preprocessing_function=preprocess_input)
tr_flow_gen = tr_generator.flow_from_dataframe(dataframe=tr_df # image file이 있는 디렉토리
                                      ,x_col='path'
                                      ,y_col='label'
                                      ,target_size=(IMAGE_SIZE, IMAGE_SIZE) # 원본 이미지를 최종 resize할 image size
                                      ,class_mode='binary' # 문자열 label을 자동 Encoding. 
                                      ,batch_size=BATCH_SIZE
                                      ,shuffle=True
                                      )

 

 

images_array = next(tr_flow_gen)[0]
labels_array = next(tr_flow_gen)[1]

show_pixel_histogram(images_array[0])

'🖼 Computer Vision > CNN' 카테고리의 다른 글

CNN - VGGNet  (0) 2022.04.01
CNN - AlexNet  (0) 2022.03.31
OpenCV 이미지 로딩시 BGR을 RGB로 변환해야 하는 이유  (0) 2022.03.27
CNN - Data Augmentation  (0) 2022.03.04
CNN - Global Average Pooling  (0) 2022.03.04
복사했습니다!