지금까지는 tensorflow에서 제공된 이미지 데이터를 사용했는데, 실제 환경에서는 원하는 데이터를 충분히 확보하기는 힘들다. 그래서 필요한 방법이 데이터 증폭이다.
해당 방법은 제한된 데이터셋에 회전, 늘림, 방향 조정 등과 같이 조작을 하여, 많은 데이터셋을 확보하는 방법이다.
from tensorflow.keras.preprocessing.image import ImageDataGenerator 으로 라이브러리를 불러온다.
기본적으로 사용되는 매개변수
aug = ImageDataGenerator(rotation_range=50, # 이미지 회전
width_shift_range=0.3, # 이미지 좌우 이동
height_shift_range=0.3, # 이미지 상하 이동
zoom_range=0.5, # 확대/축소 범위
shear_range=0.4, # 비스듬히 늘림
horizontal_flip=True, # 가로 전환
vertical_flip=True, # 세로 전환
fill_mode='nearest') # 마지막 옵션 주의하자. 이미지 회전, 이동, 축소할 때 발생하는 공간을 채우는 방식
매개변수 중, zca_whitening = True를 입력하면, fit을 추가적으로 해줘야 한다.
data augment를 사용한다면, train 데이터 셋에서 validation data를 따로 형성해줘야 한다.
model.fit(x_train, y_train)이 들어갔지만, model.fit(trainIDG, validation_data=valIDG) 가 대신해서 들어간다.
# 1) 데이터 확인 x.shape, y.shape <출력> ((28, 28, 18724), (18724,)) # 2) 데이터 reshape r, w, c = x.shape x = x.reshape(c, r, w, -1) <출력> (18724, 28, 28, 1)
# 1) 데이터 분리 from sklearn.model_selection import train_test_split x_train, test_x, y_train, test_y = train_test_split(x, y, test_size=0.2, random_state=2023) train_x, validation_x, train_y, validation_y = train_test_split(x_train, y_train, test_size=0.2, random_state=2023) # 2) minmax스케일링 max_n, min_n = train_x.max(), train_x.min() train_x = (train_x - min_n) / (max_n - min_n) test_x = (test_x - min_n) / (max_n - min_n) validation_x = (validation_x - min_n) / (max_n - min_n) # 3) 원핫인코딩 - 주의할 점이 하나 있는데, class_n이 100과 같이 너무 크다면, - 원핫인코딩을 하지 않고 model.compile(loss = 'sparse_categorical_crossentropy')로 두는 것이 더 좋다. from keras.utils import to_categorical class_n = len(np.unique(train_y)) train_y = to_categorical(train_y, class_n) test_y = to_categorical(test_y, class_n) validation_y = to_categorical(validation_y, class_n) train_x.shape, validation_x.shape, train_y.shape,test_y.shape <출력> ((11983, 28, 28, 1), (2996, 28, 28, 1), (11983, 100), (3745, 100))
# 1) 데이터 제너레이터 선언(x_train) from tensorflow.keras.preprocessing.image import ImageDataGenerator trainIDG = ImageDataGenerator(rescale=1./255, # 사실 이 부분은 전처리 과정에서 했다. 0~1 사이로 만들어줌 zca_whitening=True, # apply ZCA whitening rotation_range=30, # randomly rotate images in the range (degrees, 0 to 180) zoom_range = 0.2, # randomly zoom image width_shift_range=0.1, # randomly shift images horizontally (fraction of total width) height_shift_range=0.1, # randomly shift images vertically (fraction of total height) horizontal_flip=True, # randomly flip images vertical_flip=True) # randomly flip images - 매개변수는 너무 과하면 오히려 학습에 좋지 않다. - 특히 flip의 경우 안쓴만 못할 수 있다. # 2) fit ( whitening이 없으면 안함) trainIDG.fit(train_x) # 3) flow(x_train) - 학습 할 때마다, '실시간'으로 데이터를 생성하여 학습에 활용하고, 버리고를 반복할 준비! flow_trainIDG = trainIDG.flow(train_x, train_y, batch_size=128, # save_to_dir='output', # 생성하면 저장하는 거임. # save_prefix='train', # save_format='png' ) # 4) 데이터 제너레이터 선언(x_val) valIDG = ImageDataGenerator(rescale=1./255) # 5) flow(x_val) flow_valIDG = valIDG.flow(validation_x, validation_y) # 위에 처럼 저장 변수 넣을 수 있음.
# 1. 메모리 초기화 tf.keras.backend.clear_session() # 2. 입력 il = tf.keras.layers.Input(shape=[32, 32, 3]) # 3. 입력-2 h = tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), strides=(1,1), padding='same', activation='relu')(il) h = tf.keras.layers.BatchNormalization()(h) h = tf.keras.layers.Conv2D(filters=64, kernel_size=(3,3), strides=(1,1), padding='same', activation='relu')(h) h = tf.keras.layers.BatchNormalization()(h) h = tf.keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2))(h) h = tf.keras.layers.Dropout(0.25)(h) h = tf.keras.layers.Conv2D(filters=128, kernel_size=(3,3), strides=(1,1), padding='same', activation='relu')(h) h = tf.keras.layers.BatchNormalization()(h) h = tf.keras.layers.Conv2D(filters=128, kernel_size=(3,3), strides=(1,1), padding='same', activation='relu')(h) h = tf.keras.layers.BatchNormalization()(h) h = tf.keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2))(h) h = tf.keras.layers.Dropout(0.25)(h) h = tf.keras.layers.Conv2D(filters=256, kernel_size=(3,3), strides=(1,1), padding='same', activation='relu')(h) h = tf.keras.layers.BatchNormalization()(h) h = tf.keras.layers.Conv2D(filters=256, kernel_size=(3,3), strides=(1,1), padding='same', activation='relu')(h) h = tf.keras.layers.BatchNormalization()(h) h = tf.keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2))(h) h = tf.keras.layers.Dropout(0.25)(h) h = tf.keras.layers.Conv2D(filters=512, kernel_size=(3,3), strides=(1,1), padding='same', activation='relu')(h) h = tf.keras.layers.BatchNormalization()(h) h = tf.keras.layers.Conv2D(filters=512, kernel_size=(3,3), strides=(1,1), padding='same', activation='relu')(h) h = tf.keras.layers.BatchNormalization()(h) h = tf.keras.layers.Dropout(0.25)(h) # 4. 출력 h = tf.keras.layers.Flatten()(h) h = tf.keras.layers.Dense(1024, activation='relu')(h) ol = tf.keras.layers.Dense(100, activation='softmax')(h) # 5. 모델 model= tf.keras.models.Model(il, ol) model.compile(optimizer='adam', loss = tf.keras.losses.categorical_crossentropy, metrics='accuracy') model.summary()
# early stopping 설정 from tensorflow.keras.callbacks import EarlyStopping es = EarlyStopping(patience = 3, verbose = 1, restore_best_weights=True) model.fit(flow_trainIDG, verbose=1, epochs=1, validation_data=flow_valIDG, callbacks=[es],) - train_x, train_y를 안넣고 DataGenerator한 변수를 넣어준다. - model 평가는 동일함.