만약 custom 함수 안에 또 다른 custom 함수를 쓰는데 둘 다 같은 argument 이름을 갖는다 쳐도, 그게 제일 상위 함수에서 파라미터 값을 넣어줬을 때 안쪽 함수에 연결되어 있지 않으면 안쪽 함수의 파라미터로서 역할을 하지 않는다.
Order of .shuffle()
, .repeat()
, .batch()
matters......
아이펠 노드에서 전처리를 위해 써놓은 함수이다.
def normalize_and_resize_img(image, label):
# Normalizes images: `uint8` -> `float32`
image = tf.image.resize(image, [224, 224])
return tf.cast(image, tf.float32) / 255., label
def augment(image, label):
image = tf.image.random_flip_left_right(image)
image = tf.image.random_brightness(image, max_delta=0.2)
image = tf.clip_by_value(image, 0, 1)
return image, label
def apply_normalize_on_dataset(ds, is_test=False, batch_size=16, with_aug=False, with_cutmix=False):
ds = ds.map(
normalize_and_resize_img,
num_parallel_calls=2
)
if not is_test and with_aug:
ds = ds.map(
augment
)
ds = ds.batch(batch_size)
if not is_test and with_cutmix:
ds = ds.map(
cutmix,
num_parallel_calls=2
)
else:
ds = ds.map(
onehot,
num_parallel_calls=2
)
if not is_test:
ds = ds.repeat()
ds = ds.shuffle(200)
ds = ds.prefetch(tf.data.experimental.AUTOTUNE)
return ds
print('=3')
여기서 핵심은 cutmix, mixup이란 함수를 쓰려면 batch화가 먼저 되어야 한다는 건데
일단 나는 아래와 같이 바꿔봤다.
def preprocess_on_dataset(ds, is_test=False, batch_size=16, with_cutmix=False, with_mixup=False):
# 전체 다 실행하는 normalize_and_resize(+라벨 one-hot)
ds = ds.map(normalize_and_resize_img, num_parallel_calls=tf.data.AUTOTUNE)
if is_test:
ds = ds.prefetch(tf.data.AUTOTUNE)
return ds
else:
ds = ds.map(augment, num_parallel_calls=tf.data.AUTOTUNE) # train일 경우 기본 augmentation은 다 적용
ds = ds.batch(batch_size) # batch화 해야지 cutmix 및 mixup을 할 수 있음
if with_cutmix:
ds = ds.map(cutmix, num_parallel_calls=tf.data.AUTOTUNE)
elif with_mixup:
ds = ds.map(mixup, num_parallel_calls=tf.data.AUTOTUNE)
ds = ds.repeat().shuffle(1020).prefetch(tf.data.AUTOTUNE)
return ds
그런데 이렇게 하니까 어떤 건 cutmix
, mixup
이 아니지만 is_test=False
이 아닌 전처리가 처리된 데이터셋은 shape이 (None, 224, 224, 3)
과 같이 떴다((64, 224, 224, 3)
이런 거 기대했는데)
왜 그럴까 찾아보니 batch, repeat, shuffle의 순서 때문인 것 같다...
아 사실 위에는 repeat, shuffle 들의 순서에 관련한 것이지만, 내 문제에 대한 해답은 알 수 없었다.
((64, 224, 224, 3))
같은 shape을 나타내주는 게 왜인지 모르겠지만 정상인 것 같다.tf.data.experimental.cardinality(ds_train_norm)
fit()
에 쓰는 steps_per_epoch
도 용도가 있었다.
repeat()
을 걸어서 무한대로 가주니까 steps_per_epoch
를 명시해줘야 한단다.(아니면 어디가 한 에포크의 기준선인지 모르단다.)요즘 Tensorflow를 많이 써가면서 이것저것 그 안에 있는 것들의 용도와 원리들을 깨달아가고 있다. 참 감사한 순간이다.