[딥러닝첫걸음2]실전 모델의 뼈대 만들기

Tieck

·

2021. 9. 22. 11:49

사용된 개념

데이터 증강(data augmentation), flow, generator

 

 

CNN 모델의 구조

모델의 절차를 처리 순서에 따라 정리해보자.

 

첫번째 구조

새로운 개념에 접근하기 위해, 이미 알고있는 상식을 활용해보자

최초 모델의 원형은 다음과 같다.

 

 

1. 데이터 전처리하여 학습에 용이한 형태로 가공

2. 알고리즘을 바탕으로 모델 설계

3. 데이터를 모델에 넣어 학습시키기

4. 반복

 

 

이런 구조는 직관적이다.

실제로 초기에는 별문제가 없었다.

하지만 시간이 흘러 데이터의 규모가 증가하면서 문제가 발생했다.

 

 

1. 이 구조는 학습에 필요한 데이터의 전체 분량(100%)를 메모리(RAM)에 담아야 한다.

2. 학습/실전에 사용되는 데이터의 규모가 수십 GB에서 TB를 넘는다. (Bigdata)

3. 필요한 메모리의 용량이 증가한다. (=하드웨어의 비용 증가)

 

하드웨어 성능이 발전하고 고사양 하드웨어가 보급되고 있지만 일반 사용자의 데스크탑 램 용량이 많아야 64GB 정도이다. 설령 128GB, 256GB여도 TB 규모의 데이터를 모두 불러올 수 없다.

 

데이터를 나눠서 불러오면 된다. 예시는 게임에서 쉽게 찾아볼 수 있다.

게임에서 전체 맵의 데이터를 한번에 불러오지 않는다.

플레이어가 존재하는 맵, 주위 맵, 간접적으로 영향을 미치는 맵만 불러온다.

 

특정한 범위 만큼(bacth) 맵을 불러온다.

그 후 불러온 범위 내에서 정해진 동작을 실행한다

몬스터 리젠, 전투 시스템, 대화, 퀘스트 등

 

  • 맵으로 구분되는 rpg (메이플 스토리) : 캐릭터가 존재하는 맵
  • 오픈 월드 mmorpg(검은사막) : 캐릭터 주위의 정해진 범위 
    (좌)맵으로 구분되는 rpg : 메이플 스토리, (우)오픈월드 mmorpg : 검은사막

 

 

해결책

Generator & flow

  • 전처리를 나눠서 하기
  • 데이터를 나눠서 불러오기 (bacth)

 

실전 모델의 구조

Generator와 flow

  1. 데이터를 불러올 방법을 결정한다. (데이터의 위치 정보, label 정보 등)
  2. 불러온 후 어떤 전처리 작업 preprocessing 할 지 미리 정한다.
  3. 데이터를 정해진 분량 bacth 만큼 불러와 모델에 전달해 학습한다.

 

 

 

학습용 이미지 생성하기

ImageDataGenerator & flow

ImageDataGenerator는 데이터를 불러와서 학습하기 용이한 상태로 전처리 preparing하는 일을 맡는다.

 

삼겹살을 불판에 올리려면 도축부터 내장과 뼈 제거, 부위별 자르기 등 여러 과정을 통해 다 준비된 고기가 필요하다.

날것의 재료(raw data)를 손질하는 역할을 한다

 

직역하면 ImageData(이미지 데이터) + Generator(생성자) 이다.

즉, ImageData Generator는 "학습에 필요한(전처리가 끝난)" 데이터를 생성하는 역할을 한다.

 

 

 

코드

from tensorflow.keras.preprocessing.image import ImageDataGenerator

# 이미지 생성자를 통해 전처리할 작업 설정하기
train_gen = ImageDataGenerator(horizontal_flip=True, rescale=1/255.)


# 생성자에서 flow_from_xxx를 호출하여 이미지를 불러올 방법(위치 정보) 전달하기
# train 용 generator 생성
train_flow_gen = train_gen.flow_from_directory(directory='/kaggle/input/cat-and-dog/training_set/training_set' # image file이 있는 디렉토리 
                                                         ,target_size=(224, 224) # 원본 이미지 resize할 image size
                                                         ,class_mode='categorical' # 문자열 label을 자동으로 one-hot encoding
                                                         ,batch_size=64 #원하는 bacth size 설정
                                                         )
                                     
# 모델을 만들기
(생략)

# 모델에 train용 이미지 생성자 ImageDataGenerator를 전달하기
model.fit(tr_flow_gen, epochs=N_EPOCHS, callbacks=[rlr_cb, ely_cb])

# train 용 과 valid/test 용 generator를 각각 따로 선언해야한다.
# valid/test data는 augmentation을 적용할 필요 없다. 실제 데이터로 성능을 테스트해야하기 때문.

test_generator = ImageDataGenerator(rescale=1/255.)
test_flow_gen = test_generator.flow_from_dataframe(dataframe=test_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=False
                                      )
# evaluation으로 성능 검증
model.evaluate(test_flow_gen)

 

1. gen = ImageDataGenerator( )

2. tr_flow_gen = tr_gen.flow_from_directory( )

3. val(test)_flow_gen = val(test)_gen.flow_from_directory( )

4. 모델 학습 : model.fit( )에 train_flow_gen 전달

5. 모델 성능 검증 : model.evalute에 test_flow_gen 전달

 

 

 

파생되는 문제점

CPU와 GPU의 처리 속도 다름 -> cpu 병목현상 -> 전체적인 성능 저하

 

 

data input pipeline

 

 

 

 

이전글([딥러닝 첫걸음]간단한 모델 만들기)에서 포스팅한 것처럼, Numpy는 CPU에 의해 처리되고, Tensor는 GPU에 의해서 처리된다. 일반적으로 CPU의 이미지 처리 속도가 GPU에 비해 느려 병목 현상이 발생한다. GPU는 작업을 다 처리해서 유휴상태(대기상태, idle)인데 CPU는 사용량이 100%인 경우가 생긴다.

 

[ CPU가 일을 넘겨주는 속도 << GPU가 일을 처리하는 속도 ] 이면 모델의 전체 처리 속도는 GPU가 얼마나 빠르든 관계 없이 CPU의 속도에 따라 결정된다.

 

 

 

ImageDataGenrator를 사용했을 때 CPU에서 병목 현상이 발생하는 경우가 존재한다.

 

해결방법

 

  • tf.data

tensorflow2.0에서 tf.data 라는 자료형이 등장했다. gpu에서 tensor로 data를 생성할 수 있다. 처리 속도가 빠른 gpu의 유휴시간 (작업을 처리하지 않는 대기시간[a.k.a 휴식시간])을 줄여서 처리 속도를 향상시킬 수 있다.

 

 

  • Pipeline 만들기 (필요한 augmentation을 세밀하게 조절하기)

tf.keras에서 제공하는 ImageGenerator가 아닌, 파이프라인을 만들어서 필요한 데이터 증강 data augmentation 만 실행하면 병목 현상을 예방 하는 것도 시도해볼만 하다.

 

 

 

sol A. Pipline

import albumentations as A

# 사용한 augmentation을 묶어 pipline으로 만들기
# 개별 agumentation의 확률p 조절
# 파이프 라인 전체 확률 조절 p = 0.5
augmentor = A.Compose([
    A.CenterCrop(height=300, width=500, p=1),
    A.Resize(578, 1028),
    A.ColorJitter(p=1)
], p = 0.5)

 

전처리 작업의 개수를 줄인다.

전처리 작업의 적용 확률을 낮춘다.

 

 

sol B. ImageDataGenerator from tf.keras

 

전처리 작업의 개수를 줄인다.

 

from tensorflow.keras.preprocessing.image import ImageDataGenerator

train_generator = ImageDataGenerator(
    rotation_range=20,
    zoom_range=(0.7, 0.9),
    horizontal_flip=True,
    vertical_flip=True,
    rescale=1/255.0
)

valid_generator = ImageDataGenerator(rescale=1/255.0)

flow_tr_gen = train_generator.flow(tr_images, tr_oh_labels, batch_size=BATCH_SIZE, shuffle=True)
flow_val_gen = valid_generator.flow(val_images, val_oh_labels, batch_size=BATCH_SIZE, shuffle=False)

 

 

 

 

 

fin. 생성된 generator를 model에 전달하기

[generator 만들기] sol. A or B 

-> [generator를 모델에 전달] model.fit(generator, ... )

# custom model 생성
model = create_model() 
model.compile(optimizer=Adam(lr=0.001), loss='categorical_crossentropy', metrics=['accuracy'])

# 5번 iteration내에 validation loss가 향상되지 않으면 learning rate을 기존 learning rate * 0.2로 줄임.  
rlr_cb = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, mode='min', verbose=1)

# 10번 iteration내에 validation loss가 향상되지 않으면 더 이상 학습하지 않고 종료
ely_cb = EarlyStopping(monitor='val_loss', patience=10, mode='min', verbose=1)

history = model.fit(flow_tr_gen, epochs=40, 
                    validation_data=flow_val_gen, 
                    callbacks=[rlr_cb, ely_cb], verbose=1)

 

 

 

 

 

 

 

 

 

 

파이썬의 generator

  • return : 호출 시 반복을 멈추고 데이터 반환 + 메모리에서 할당 해제(다시 호출 불가)
  • yield : 호출 시 함수는 그 시점에서 일시 정지 + 그 시점의 함수 안에 선언되어 있는 변수 기억

 

  • next( )를 통해 실행되면 yield 바로 다음라인부터 다음 yield까지 실행
  • 함수를 재활용 가능한 형태로 만드는 것이 특징

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Reference

https://medium.datadriveninvestor.com/generative-adversarial-network-gan-using-keras-ce1c05cfdfd3

 

Generative Adversarial Network(GAN) using Keras

In this post we will use GAN, a network of Generator and Discriminator to generate images for digits using keras library and MNIST datasets

medium.datadriveninvestor.com

 

https://towardsdatascience.com/how-to-reduce-training-time-for-a-deep-learning-model-using-tf-data-43e1989d2961

 

How to Reduce Training Time for a Deep Learning Model using tf.data

Learn to create an input pipeline for images to efficiently use CPU and GPU resources to process the image dataset and reduce the training…

towardsdatascience.com

https://yeomko.tistory.com/11

 

갈아먹는 파이썬 [1] generator와 yield

들어가며 파이썬을 주로 사용하시는 분들이라면 한번쯤 generator에 대해서 들어보셨을 겁니다. 하지만 딱이 몰라도 코딩하는데 큰 지장이 없어서 그냥 지나치신 분들이 많으실 것으로 생각합니

yeomko.tistory.com

 

'딥러닝' 카테고리의 다른 글

[딥러닝 첫걸음]간단한 모델 만들기  (0) 2021.09.04