Keras:데이터 전처리
1 개요[편집 | 원본 편집]
케라스 자체적으로도 데이터 전처리를 제공한다.
1.1 배치사이즈[편집 | 원본 편집]
한 번에 몇 개의 데이터를 교육할 것인가. 숫자가 크면 계산이 빨라지지만, 메모리 부하가 커진다. 때문에 양날의 검.
2 전처리 예시[편집 | 원본 편집]
의도 | 설명 | 방법 |
---|---|---|
정규화 | 평균 0, 표준편차 1로 정규화한다. | from tensorflow.keras.layers import Normalization
training_data = np.random.randint(0, 256, size=(64, 200, 200, 3)).astype("float32") # 예시데이터
normalizer = Normalization(axis=-1) # 정규화 객체 생성.
normalizer.adapt(training_data) # 정규화 방법 지정.
normalized_data = normalizer(training_data) # 데이터에 정규화 진행.
|
이미지 전처리 | 이미지를 처리할 땐 이미지를 자르거나 수치의 제한을 설정하는 과정이 필요할 때가 있다.
|
from tensorflow.keras.layers import CenterCrop
from tensorflow.keras.layers import Rescaling
# Example image data, with values in the [0, 255] range
training_data = np.random.randint(0, 256, size=(64, 200, 200, 3)).astype("float32")
cropper = CenterCrop(height=150, width=150)
scaler = Rescaling(scale=1.0 / 255)
output_data = scaler(cropper(training_data))
print("shape:", output_data.shape) # 64개의 150,150 크기의 3채널 데이터임을 알려준다.
print("min:", np.min(output_data)) # 가장 작은 데이터는 0
print("max:", np.max(output_data)) # 가장 큰 데이터는 1
|
이미지 | 사진파일을 읽고, 컨텐츠를 RGB로 디코딩, 텐서로 변환, 픽셀 정규화를 한번에 해주는 도구가 있다. | from keras.preprocessing.image import ImageDataGenerator
# 모든 이미지를 1/255로 스케일을 조정합니다
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_dir, # 타깃 디렉터리
target_size=(150, 150), # 모든 이미지를 150 × 150 크기로 바꿉니다
batch_size=20,
class_mode='binary') # binary_crossentropy 손실을 사용할 땐 이진 레이블.
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary')
|
이미지 증식 | 이미지의 학습엔 많은 이미지가 필요한데, 천당 단위의 수준으론 너무 적다. 때문에 회전, 반전 등을 통해 이미지를 증폭한다.
(나중에 이용할 때 제대로 찾아 정리하자...)
|
datagen = ImageDataGenerator(
rotation_range=40, # 회전
width_shift_range=0.2, # 가로이동
height_shift_range=0.2, # 세로이동
shear_range=0.2, # 전단변환
zoom_range=0.2, # 확대
horizontal_flip=True, # 좌우반전
fill_mode='nearest') # 빈 공간을 어떻게 채울지.(nearest는 주변픽셀로 채운다.)
|
3 데이터 제너레이터[편집 | 원본 편집]
데이터의 크기가 커지면 이게 RAM에 다 안올라가서 에러가 뜬다.(시계열 데이터는 window의 수많큼 데이터가 커지고, image같은 것들은 하드에 저장했던걸 불러오는데, 이걸 RAM에 올리는 건..힘들다.)
때문에 제너레이터로 데이터를 입력해주는 편이 제한된 RAM을 잘 활용할 수 있다.
게다가 GPU의 작업과 쓰레드로 분리되어 데이터 처리는 CPU에서 동시에 처리된다. 즉, 더 빠른 처리를 기대할 수 있다.
3.1 유의[편집 | 원본 편집]
- 제너레이터는 다 쓰면 학습이 이루어지지 않기에, 다 쓰게 되면 다시 처음으로 loopback 해주는 기능을 함께 넣는 편이 좋다.
- 사용자가 처음부터 임의로 짠 제너레이터는... 끝지점을 설정하기도 어렵고, 기타 세부사항을 놓치는 경우가 많다.
- 최근엔 케라스에서 제너레이터의 기본 틀을 제공한다. tf.keras.utils.Sequence를 상속하는 클레스를 만들어주는 것으로부터 시작한다.(멀티프로세싱이나 이런저런 세부사항을 지키기에 안전하기에 권장된다.)
3.2 케라스 제공 클래스로 만들기[편집 | 원본 편집]
쓰레드로 진행되어 CPU나 GPU에 바로 먹여진다.
3.2.1 필수 메서드[편집 | 원본 편집]
__getitem__과 __len__ 메서드가 필수적으로 정의되어야 한다. 아, __init__은 클래서에선 기본이고.
메서드 | 설명 | 코드예시 |
---|---|---|
__init__
|
객체가 처음 만들어질 때 변수를 어떻게 할당할지. 딱히 이렇다 할 제약은 없다. | class CIFAR10Sequence(Sequence):
def __init__(self, x_set, y_set, batch_size):
self.x, self.y = x_set, y_set
self.batch_size = batch_size
|
__getitem__
|
배치 하나의 데이터를 뱉어낼 수 있어야 한다.
x, y 형태로. x는 넘파이 배열 (배치사이즈, 인풋) 형태로, y는 2개의 배열이 합쳐진 튜플로.(예시를 보니 그냥 레이블을 뱉어내면 되는듯.) |
def __getitem__(self, idx):
batch_x = self.x[idx * self.batch_size:(idx + 1) *
self.batch_size]
batch_y = self.y[idx * self.batch_size:(idx + 1) *
self.batch_size]
return np.array([
resize(imread(file_name), (200, 200))
for file_name in batch_x]), np.array(batch_y)
|
__len__
|
제너레이터의 길이를 반환한다.
일반적으로 총 길이를 배치사이즈로 나눈 후 숫자 올림 한 것. 항상 int 타입을 반환해야 한다. |
def __len__(self):
return math.ceil(len(self.x) / self.batch_size)
|
3.2.2 정의된 메서드[편집 | 원본 편집]
메서드 | 설명 | 코드예시 |
---|---|---|
on_epoch_end | 각 에폭의 끝에서 수행할 일을 지정한다. 데이터셋을 바꾼다든가... | def on_epoch_end(self):
if self.shuffle:
self.df = self.df.sample(frac=1).reset_index(drop=True)
|
3.2.3 사용[편집 | 원본 편집]
x, y = generator[133] 형태로 사용할 수 있다. 확인에도 직관적이어서 좋다.
generator = DataGenerator(각종 파라미터.)
import matplotlib.pyplot as plt
for i, (x, y) in enumerate(generator):
if(i <= 1):
x_first = x[0]
plt.title(y[0])
plt.imshow(x_first)