-
โฑ ํธ์ฆ์จ ๋จธ์ ๋ฌ๋ 13์ฅ ํ ์ํ๋ก๋ฅผ ์ฌ์ฉํ ๋ฐ์ดํฐ ์ ์ฌ์ ์ ์ฒ๋ฆฌ โฑ๐ฎ ์ด๊ฒ์ ๊ฒ ๊ณต๋ถ/โฉ ํธ์ฆ์จ ๋จธ์ ๋ฌ๋ 2026. 1. 28. 15:45
๋์ฉ๋ ๋ฐ์ดํฐ์ ์์ ํ ์ํ๋ก ๋ชจ๋ธ์ ํ๋ จํ ๋๋ ํ ์ํ๋ก ์์ฒด์ ๋ฐ์ดํฐ ๋ก๋ ๋ฐ ์ ์ฒ๋ฆฌ API์ธ tf.data๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ข๋ค.
๋งค์ฐ ํจ์จ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๊ณ ์ ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ, ๋ฉํฐ์ค๋ ๋์ ํ๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ํ์ผ์์ ๋์์ ์ฝ๊ณ , ์ํ์ ์ ํ๋งํ๊ฑฐ๋ ๋ฐฐ์น๋ก ๋ง๋๋ ๋ฑ์ ์์ ์ ์ํํ ์ ์๋ค.
GPU ๋๋ TPU๊ฐ ํ๋ จ์ ์ํด ํ์ฌ ๋ฐ์ดํฐ ๋ฐฐ์น๋ฅผ ๋ฐ์๊ฒ ์ฒ๋ฆฌํ๋ ๋์ ๋์์ ์ฌ๋ฌ CPU ์ฝ์ด์ ๊ฑธ์ณ ๋ค์ ๋ฐ์ดํฐ ๋ฐฐ์น๋ฅผ ๋ก๋ํ๊ณ ์ ์ฒ๋ฆฌํ ์ ์๋ค.
์ผ๋ผ์ค๋ ๋ชจ๋ธ์ ํฌํจ์ํฌ ์ ์๋ ์ ์ฒ๋ฆฌ ์ธต์ ์ ๊ณตํ๋ฏ๋ก, ๋ชจ๋ธ์ ์ ํ ํ๊ฒฝ์ ๋ฐฐํฌํ ๋ ๋ค๋ฅธ ์ ์ฒ๋ฆฌ ์ฝ๋๋ฅผ ์ถ๊ฐํ ํ์ ์์ด ์์ ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ฃผ์ ํ ์ ์๋ค.
๋ํ ํ๋ จ ์ค์ ์ฌ์ฉ๋ ์ ์ฒ๋ฆฌ ์ฝ๋์ ์ ํ ํ๊ฒฝ์์ ์ฌ์ฉ๋๋ ์ ์ฒ๋ฆฌ ์ฝ๋๊ฐ ๋ฌ๋ผ์ ธ ํ๋ จ/์๋น์ ์ฐจ์ด๋ฅผ ์ผ์ผํค๋ ์ํ์ ์ ๊ฑฐํ ์ ์๋ค.
13.1 ๋ฐ์ดํฐ API
์ ์ฒด์ ์ธ tf.data API์ ์ค์ฌ์๋ tf.data.Dataset ๊ฐ๋ ์ด ์์ผ๋ฉฐ, ์ด๋ ๋ฐ์ดํฐ ํญ๋ชฉ์ ์ํ์ค๋ฅผ ๋ํ๋ธ๋ค.
์ผ๋ฐ์ ์ผ๋ก ๋์คํฌ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ง์ ์ผ๋ก ์ฝ๋ ๋ฐ์ดํฐ์ ์ ์ฌ์ฉํ๋ค.
ํ์ง๋ง ๊ฐ๋จํ tf.data.Dataset.from_tensor_slices()๋ฅผ ์ฌ์ฉํด ๊ฐ๋จํ ํ ์๋ก ๋ฐ์ดํฐ์ ์ ์์ฑํ ์ ์๋ค.
import tensorflow as tf X = tf.range(10) # ์์์ ๋ฐ์ดํฐ ํ ์ dataset = if.data.Dataset.from_tensor_slices(X) dataset # <_TensorSliceDataset element_spec=TensorSpec(shape=(), dtype=tf.int32, name=None)>from_tensor__slices() ํจ์๋ ํ ์๋ฅผ ๋ฐ์ ์ฒซ ๋ฒ์งธ ์ฐจ์์ ๋ฐ๋ผ X์ ๊ฐ ์์๊ฐ ์์ดํ ์ผ๋ก ํํ๋๋ tf.data.Dataset์ ๋ง๋ ๋ค.
์ฆ, ํ ์ 0, 1, 2, ..., 9์ ํด๋นํ๋ 10๊ฐ์ ์์ดํ ์ ๊ฐ์ง๋ค. tf.data.Dataset.range(10)์ผ๋ก ๋ง๋ ๋ฐ์ดํฐ์ ๊ณผ ๋์ผํ๋ค.
dataset = tf.data.Dataset.from_tensor_slices(tf.range(10)) for item in datasets: ... print(item) ... # tf.Tensor(0, shape=(), dtype=int32) # tf.Tensor(1, shape=(), dtype=int32) # [...] # tf.Tensor(9, shape=(), dtype=int32)๋ฐ์ดํฐ์ ์ ์์ดํ ์ ์ํํ ์ ์๋ค.
X_nested = {"a": ([1, 2, 3], [4, 5, 6]), "b": [7, 8, 9]} dataset = tf.data.dataset.from_tensor_slices(X_nested) for item in dataset: ... print(item) ... # {'a': («tf.Tensor: [..J-=1>, <tf. Tensor: [..J-4>), 'b': <tf.Tensor: [..1=7)} # {'a': (<tf. Tensor: [...]=2>, <tf.Tensor: [...]=5>), 'b': <tf.Tensor: [..]=8>} # {'a': (<tf.Tensor: [...]=3>, <tf.Tensor: [...]=6>), 'b': <tf.Tensor: [..]=9>}13.1.1 ์ฐ์ ๋ณํ
๋ฐ์ดํฐ์ ์ด ์ค๋น๋๋ฉด ๋ณํ ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ฌ๋ฌ ์ข ๋ฅ์ ๋ณํ์ ์ํํ ์ ์๋ค.
๋ฉ์๋๋ ์๋ก์ด ๋ฐ์ดํฐ์ ์ ๋ฐํํ๋ฏ๋ก ๋ณํ ๋ฉ์๋๋ฅผ ์ฐ๊ฒฐํ ์ ์๋ค.
dataset = dataset.repeat(3).batch(7) for item in dataset: ... print(item) ... # tf. Tensor ([0 1 2 3 4 5 6], shape=(7,), dtype=int32) # tf. Tensor ([7 8 9 0 1 2 3], shape=(7,), dtype=int32) # tf. Tensor ([4 5 6 7 8 9 0], shape=(7,), dtype=int32) # tf. Tensor ([1 2 3 4 5 6 7], shape=(7,), dtype=int32) # tf. Tensor ([8 9], shape=(2,), dtype=int32)์๋ณธ ๋ฐ์ดํฐ์ ์์ repeat() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ์๋ณธ ๋ฐ์ดํฐ์ ์ ์์ดํ ์ ์ธ ์ฐจ๋ก ๋ฐ๋ณตํ๋ ์๋ก์ด ๋ฐ์ดํฐ์ ์ ๋ฐํํ๋ค.
๋งค๊ฐ๋ณ์ ์์ด ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ๋ฌดํ๋ฐ๋ณต๋๋ค.
์๋ก์ด ๋ฐ์ดํฐ์ ์์ batch() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ๋ค์ ์๋ก์ด ๋ฐ์ดํฐ์ ์ด ๋ง๋ค์ด์ง๋ค.
์ด์ ๋ฐ์ดํฐ์ ์ ์์ดํ ์ 7๊ฐ์ฉ ๊ทธ๋ฃน์ผ๋ก ๋ฌถ๋๋ค.

๋ง์ง๋ง ๋ฐ์ดํฐ์ ์ ์์ดํ ์ ์ํ๋๋ค.
batch() ๋ฉ์๋๋ฅผ drop_remainder=True๋ก ํธ์ถํ๋ฉด ๊ธธ์ด๊ฐ ๋ชจ์๋ ๋ง์ง๋ง ๋ฐฐ์น๋ฅผ ๋ฒ๋ฆฌ๊ณ ๋ชจ๋ ๋ฐฐ์น๋ฅผ ๋์ผํ ํฌ๊ธฐ๋ก ๋ง์ถ๋ค.
dataset = dataset.map(lambda x: x * 2) # x๋ ํ๋์ ๋ฐฐ์น์ด๋ค for item in dataset: ... print(item) ... # tf. Tensor ([ 0 2 4 6 8 10 12], shape=(7,), dtype=int32) # tf. Tensor ([14 16 18 0 2 4 6], shape=(7,), dtype=int32) # [...]map() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์์ดํ ์ ๋ณํํ ์๋ ์์ผ๋ฉฐ ์ด๋ ํ ์ ์ฒ๋ฆฌ ์์ ๋ ์ ์ฉํ ์ ์๋ค.
์ด๋ฏธ์ง ํฌ๊ธฐ ๋ณํ์ด๋ ํ์ ๊ฐ์ ๋ณต์กํ ๊ณ์ฐ์ ํฌํจํ๊ธฐ์ ์ฌ๋ฌ ์ค๋ ๋๋ก ๋๋์ด ์๋๋ฅผ ๋์ด๋ ๊ฒ์ด ์ข์๋ฐ, ์ด๋ฅผ ์ํด num_parallel_calss ๋งค๊ฐ๋ณ์์ ์คํํ ์ค๋ ๋ ๊ฐ์๋ tf.data.AUTOTUNE์ ์ง์ ํ ์ ์๋ค.
map() ๋ฉ์๋์ ์ ๋ฌํ๋ ํจ์๋ ํ ์ํ๋ก ํจ์๋ก ๋ณํ ๊ฐ๋ฅํด์ผ ํ๋ค.
dataset = dataset.filter(lambda x: tf.reduce_sum(x) > 50) for item in dataset: ... print(item) ... # tf. Tensor ([14 16 18 0 2 4 6], shape=(7,), dtype=int32) # tf. Tensor([ 8 10 12 14 16 18 0], shape=(7,), dtype=int32) # tf. Tensor ([ 2 4 6 8 10 12 14], shape=(7,), dtype=int32)filter() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ์ ์ ํํฐ๋งํ ์ ์๋ค.
for item in dataset.take(2): ... print(item) ... # tf. Tensor([14 16 18 0 2 4 6], shape=(7,), dtype=int32) # tf. Tensor ([ 8 10 12 14 16 18 0], shape=(7,), dtype=int32)take() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ์ ์ ๋ช ๊ฐ์ ์์ดํ ๋ง ํ์ธํ ์๋ ์๋ค.
13.1.2 ๋ฐ์ดํฐ ์ ํ๋ง
shuffle() ๋ฉ์๋๋ ๋จผ์ ์๋ณธ ๋ฐ์ดํฐ์ ์ ์ฒ์ ์์ดํ ์ buffer_size ๊ฐ์๋งํผ ์ถ์ถํ์ฌ ๋ฒํผ์ ์ฑ์ด๋ค.
๊ทธ๋ค์ ์๋ก์ด ์์ดํ ์ด ์์ฒญ๋๋ฉด ์ด ๋ฒํผ์์ ๋๋คํ๊ฒ ํ๋๋ฅผ ๊บผ๋ด ๋ฐํ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ณธ ๋ฐ์ดํฐ์ ์์ ์๋ก์ด ์์ดํ ์ ์ถ์ถํ์ฌ ๋น์์ง ๋ฒํผ๋ฅผ ์ฑ์ด๋ค.
์๋ณธ ๋ฐ์ดํฐ์ ์ ๋ชจ๋ ์์ดํ ์ด ์ฌ์ฉ๋ ๋๊น์ง ๋ฐ๋ณตํ๋ค.
๊ทธ๋ค์์ ๋ฒํผ๊ฐ ๋น์์ง ๋๊น์ง ๊ณ์ํ์ฌ ๋๋คํ๊ฒ ์์ดํ ์ ๋ฐํํ๋ค.
์ด ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ฒํผ ํฌ๊ธฐ๋ฅผ ์ง์ ํด์ผ ํ๋ฉฐ ์ ํ๋ง ํจ๊ณผ ๊ฐ์๋ฅผ ๋ง๊ธฐ ์ํด ์ถฉ๋ถํ ํฌ๊ฒ ํด์ผ ํ๋ค.
๋ค๋ง ๋ณด์ ํ ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ๋ฅผ ๋์ง ์์์ผ ํ๋ฉฐ, ์ถฉ๋ถํ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋๋ผ๋ ๋ฒํผ ํฌ๊ธฐ๊ฐ ๋ฐ์ดํฐ์ ํฌ๊ธฐ๋ณด๋ค ํด ํ์๋ ์๋ค.
ํ๋ก๊ทธ๋จ์ ์คํํ ๋๋ง๋ค ์ ํ๋ง๋๋ ์์๋ฅผ ๋์ผํ๊ฒ ๋ง๋ค๋ ค๋ฉด ๋๋ค ์๋๋ฅผ ๋ถ์ฌํ๋ค.
dataset = tf.data.Dataset.range(10).repeat(2) dataset = dataset.shuffle(buffer_size=4, seed=42).batch(7) for item in dataset: ... print(item) ... # tf. Tensor ([1 4 2 3 5 0 6], shape=(7,), dtype=int64) # tf. Tensor([9 8 2 0 3 1 4], shape=(7,), dtype=int64) # tf. Tensor ([5 7 9 6 7 8], shape=(6,), dtype=int64)๋ฉ๋ชจ๋ฆฌ ์ฉ๋๋ณด๋ค ํฐ ๋๊ท๋ชจ ๋ฐ์ดํฐ์ ์ ๋ฒํผ๊ฐ ๋ฐ์ดํฐ์ ์ ๋นํด ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋จํ ์ ํ๋ง ๋ฒํผ ๋ฐฉ์์ผ๋ก ์ถฉ๋ถํ์ง ์์ผ๋ฉฐ, ์๋ณธ ๋ฐ์ดํฐ ์์ฒด๋ฅผ ์๊บผ์ด์ผ ํ๋ค.
์๋ณธ ๋ฐ์ดํฐ๊ฐ ์์ฌ ์๋๋ผ๋ ์ํฌํฌ๋ง๋ค ํ ๋ฒ ๋ ์์ด, ๋์ผ ์์๊ฐ ๋ฐ๋ณต๋์ด ๋ชจ๋ธ์ ํธํฅ์ด ์ถ๊ฐ๋๋ ๊ฒ์ ๋ง๋๋ค.
์๋ณธ ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฌ ํ์ผ๋ก ๋๋ ๋ค์ ํ๋ จํ๋ ๋์ ๋๋ค์ผ๋ก ์ฝ๋ ๋ฐฉ๋ฒ๋ ์๋ค.
ํ์ผ ์ฌ๋ฌ ๊ฐ๋ฅผ ๋๋ค์ผ๋ก ์ ํํ๊ณ ํ์ผ์์ ๋์์ ์ฝ์ ๋ ์ฝ๋๋ฅผ ๋์๊ฐ๋ฉด์ ๋ฐํํ๋ค.
๊ทธ๋ฐ ๋ค์ shuffle() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๊ทธ ์ํด ์ ํ๋ง ๋ฒํผ๋ฅผ ์ถ๊ฐํ๋ค.
13.1.3 ์ฌ๋ฌ ํ์ผ์์ ํ ์ค์ฉ ๋ฒ๊ฐ์ ์ฝ๊ธฐ
filepath_dataset = tf.data.Dataset.list_files(train_filepaths, seed=42)ํ์ผ ๊ฒฝ๋ก๊ฐ ๋ด๊ธด ๋ฐ์ดํฐ์ ์ ๋ง๋ ๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก list_files() ํจ์๋ ํ์ผ ๊ฒฝ๋ก๋ฅผ ์์ ๋ฐ์ดํฐ์ ์ ๋ฐํํ๋ค. (shuffle=False๋ก ์ง์ ํด ๋ง์ ์ ์๋ค)
n_readers = 5 dataset = filepath_dataset.interleave( lambda filepath: tf.data.TextLineDataset(filepath).skip(1), cycle_length=n_readers)interleave() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ํ ๋ฒ์ ๋ค์ฏ ๊ฐ์ ํ์ผ์ ํ ์ค์ ๋ฒ๊ฐ์ ์ฝ๋๋ค.
๊ฐ ํ์ผ์ ์ฒซ ๋ฒ์งธ ์ค์ ์ด ์ด๋ฆ์ด๋ฏ๋ก skip() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๊ฑด๋๋ด๋ค.
interleave() ๋ฉ์๋๋ filepath_dataset์ ์๋ ๋ค์ฏ ๊ฐ์ ํ์ผ ๊ฒฝ๋ก์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ๋ฐ์ดํฐ์ ์ ๋ง๋ ๋ค.
์ ๋ฌํ ํจ์๋ฅผ ๊ฐ ํ์ผ์ ๋ํด ํธ์ถํ์ฌ ์๋ก์ด ๋ฐ์ดํฐ์ ์ ๋ง๋ ๋ค.
์ด ๋จ๊ณ์๋ ํ์ผ ๊ฒฝ๋ก ๋ฐ์ดํฐ์ , ์ธํฐ๋ฆฌ๋ธ ๋ฐ์ดํฐ์ , ์ธํฐ๋ฆฌ๋ธ ๋ฐ์ดํฐ์ ์ ์ํด ๋ด๋ถ์ ์ผ๋ก ์์ฑ๋ 5๊ฐ์ textLineDataset์ด ์๋ค.
์ธํฐ๋ฆฌ๋ธ ๋ฐ์ดํฐ์ ์ ๋ฐ๋ณต๋ฌธ์ ์ฌ์ฉํ๋ฉด ๋ค์ฏ ๊ฐ์ TextLineDataset์ ์ํํ๋ค. ๋ชจ๋ ๋ฐ์ดํฐ์ ์ด ์์ดํ ์ด ์์ง๋ ๋๊น์ง ํ ๋ฒ์ ํ ์ค์ฉ ์ฝ๋๋ค.
๊ทธ๋ฌ๊ณ ๋์ filepath_dataset์์ ๋ค์ ๋ค์ฏ ๊ฐ์ ํ์ผ ๊ฒฝ๋ก๋ฅผ ๊ฐ์ ธ์ค๊ณ ๋์ผํ ๋ฐฉ์์ผ๋ก ํ ์ค์ฉ ์ฝ๋๋ค. ๋ชจ๋ ํ์ผ ๊ฒฝ๋ก๊ฐ ์์ง๋ ๋๊น์ง ๊ณ์ํ๋ค.
์ธํฐ๋ฆฌ๋น์ด ์ ์๋ํ๋ ค๋ฉด ํ์ผ์ ๊ธธ์ด๊ฐ ๋์ผํ ๊ฒ์ด ์ข๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก interleave() ๋ฉ์๋๋ ๋ณ๋ ฌํ๋ฅผ ์ฌ์ฉํ์ง ์์ ๊ฐ ํ์ผ์์ ํ ๋ฒ์ ํ ์ค์ฉ ์์๋๋ก ์ฝ๋๋ค.
์ฌ๋ฌ ํ์ผ์์ ๋ณ๋ ฌ๋ก ์ฝ๊ณ ์ถ๋ค๋ฉด interleave() ๋ฉ์๋์ num_parallel_callls ๋งค๊ฐ๋ณ์์ ์ํ๋ ์ค๋ ๋ ๊ฐ์๋ฅผ ์ง์ ํ๋ค.
์ด ๋งค๊ฐ๋ณ์๋ฅผ tf.data.AUTOTUNE์ผ๋ก ์ง์ ํ๋ฉด ํ ์ํ๋ก๊ฐ ๊ฐ์ฉํ CPU๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋์ ์ผ๋ก ์ ์ ํ ์ค๋ ๋ ๊ฐ์๋ฅผ ์ ํํ ์ ์๋ค.
for line in dataset.take(5): ... print(line) ... # tf.Tensor(b' 4.5909,16.0, [...],33.63,-117.71,2.418', shape=(), dtype=string) # tf.Tensor(b'2.4792,24.0, [..],34. 18,-118.38,2.0',, shape=(), dtype=string) # tf.Tensor(b'4.2708,45.0, [...],37.48, -122.19,2.67'., shape=(), dtype=string) # tf.Tensor(b'2.1856,41.0, [...1,32.76,-117.12,1.205*, shape=(), dtype=string) # tf.Tensor(b'4. 1812,52.0, [..1,33.73, -118.31,3.215'., shape=(), dtype=string)13.1.4 ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ
X_mean, X_std = [...] n_inputs = 8 def parse_csv_line(line): defs = [0.] * n_inputs + [tf.constant([], dtype=tf.float32)] fields = tf.io.decode_csv(line, recod_defaults=def) return tf.stack(fields[:-1]), tf.stack(fields[-1:]) def preprocess(line): x, y = parse_csv_line(line) return (x - X_mean) / X_std, yparse_csv_line() ํจ์๋ CSV ํ ๋ผ์ธ์ ๋ฐ์ ํ์ฑํ๋ค.
tf.io.decode_csv() ํจ์๋ ์ด๋ง๋ค ํ ๊ฐ์ฉ ์ค์นผ๋ผ ํ ์์ ๋ฆฌ์คํธ๋ฅผ ๋ฐํํ๋ค. 1D ํ ์ ๋ฐฐ์ด์ ๋ฐํํด์ผ ํ๋ฏ๋ก ๋ง์ง๋ง ์ด(ํ๊น)์ ์ ์ธํ๊ณ ๋ชจ๋ ํ ์์ ๋ํด tf.stack() ํจ์๋ฅผ ํธ์ถํ๋ค. ์ด ํจ์๋ ๋ชจ๋ ํ ์๋ฅผ ์์ 1D ๋ฐฐ์ด์ ๋ง๋ ๋ค. ๊ทธ๋ค์ ํ๊น๊ฐ์๋ ๋์ผํ๊ฒ ์ ์ฉํ๋ฉด ์ค์นผ๋ผ ํ ์๊ฐ ์๋๋ผ ํ๋์ ๊ฐ์ ๊ฐ์ง 1D ํ ์๊ฐ ๋๋ค.
๋ฐ๋ผ์ parse_csv_line() ํจ์๊ฐ ์๋ฃ๋๋ฉด ์ ๋ ฅ ํน์ฑ๊ณผ ํ๊น์ด ๋ฐํ๋๋ค.
preprocess() ํจ์๋ parse_csv_line() ํจ์๋ฅผ ํธ์ถํ๊ณ , ์ ๋ ฅ ํน์ฑ์์ ํ๊ท ์ ๋นผ๊ณ ํ์ค ํธ์ฐจ๋ก ๋๋์ด ์ค์ผ์ผ์ ์กฐ์ ํ๋ค. ๊ทธ๋ค์ ์ค์ผ์ผ์ด ์กฐ์ ๋ ํน์ฑ๊ณผ ํ๊น์ ๋ด์ ํํ์ ๋ฐํํ๋ค.
preprocess(b' 4.2083,44.0,5.3232,0.9171,846.0,2.3370,37.47,-122.2,2.782') # (<tf. Tensor: shape=(8,), dtype=float32, numpy= # array([ 0.16579159, 1.216324, -0.05204564, -0.39215982, -0.5277444 , # -0.2633488, 0.8543046 , -1.3072058 ], dtype=float32)>, # ‹tf. Tensor: shape=(1,), dtype=float32, numpy=array([2.782], dtype=float32)>)13.1.5 ๋ฐ์ดํฐ ์ ์ฌ์ ์ ์ฒ๋ฆฌ ํฉ์น๊ธฐ
def csv_reader_dataset(filepaths, n_readers=5, n_read_threads=None, n_parse_threads=5, shuffle_buffer_size=10_000, seed=42, batch_size=32): dataset = tf.data.Dataset.list_files(filepaths, seed=seed) dataset = dataset.interleave( lambda filepath: tf.data.TextLineDataset(filepath).skip(1), cycle_legnth=n_readers, num_parallel_calls=n_read_threads) dataset = dataset.map(preprocess, num_parallel_calls=n_parse_threads) dataset = dataset.shuffle(shuffle_buffer_size, seed=seed) return dataset.batch(batch_size).prefetch(1)
13.1.6 ํ๋ฆฌํ์น
csv_reader_dataset() ํจ์ ๋ง์ง๋ง์ prefetch(1)์ ํธ์ถํ๋ฉด ๋ฐ์ดํฐ์ ์ ํญ์ ํ ๋ฐฐ์น๊ฐ ๋ฏธ๋ฆฌ ์ค๋น๋๋๋ก ์ต์ ์ ๋คํ๋ค.
ํ๋ จ ์๊ณ ๋ฆฌ์ฆ์ด ํ ๋ฐฐ์น๋ก ์์ ์ ํ๋ ๋์ ์ด ๋ฐ์ดํฐ์ ์ด ๋์์ ๋ค์ ๋ฐฐ์น๋ฅผ ์ค๋นํ๋ค.
interleave()์ map() ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ num_parallel_calls ๋งค๊ฐ๋ณ์๋ฅผ ์ง์ ํ์ฌ ๋ฉํฐ์ค๋ ๋๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฌํ๊ณ ์ ์ฒ๋ฆฌํ๋ฉด, ์ฌ๋ฌ ๊ฐ์ CPU ์ฝ์ด๋ฅผ ํ์ฉํด์ GPU์์ ํ๋ จ ์คํ ์ ์ํํ๋ ๊ฒ๋ณด๋ค ์งง์ ์๊ฐ ์์ ํ๋์ ๋ฐฐ์น ๋ฐ์ดํฐ๋ฅผ ์ค๋นํ ์ ์์ ๊ฒ์ด๋ค.

13.1.7 ์ผ๋ผ์ค์ ๋ฐ์ดํฐ์ ์ฌ์ฉํ๊ธฐ
train_set = csv_reader_dataset(train_filepaths) valid_set = csv_reader_dataset(valid_filepaths) test_set = csv_reader_dataset(test_filepathhs)ํ๋ จ ์ธํธ๋ ๊ฐ ์ํฌํฌ๋ง๋ค ์ ํ๋๋ค.
model = tf.keras.Sequential([...]) model.compile(loss="mse", optimizer="sgd") model.fit(train_set, validation_data=valid_set, epochs=5)์ผ๋ผ์ค ๋ชจ๋ธ์ผ ๋ง๋ค๊ณ ์ด ๋ฐ์ดํฐ์ ์ผ๋ก ํ๋ จํ ์ ์๋ค.
๋ชจ๋ธ์ fit() ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ X_train, y_train ๋์ ์ train_set์ ์ ๋ฌํ๊ณ , validation_data=(X_valid, y_valid) ๋์ ์ validation_data=valid_set์ ์ ๋ฌํ๋ค.
fit() ๋ฉ์๋๊ฐ ์ํฌํฌ๋ง๋ค ๋๋คํ ์์๋ก ํ๋ จ ๋ฐ์ดํฐ์ ์ ํ ๋ฒ์ฉ ๋ฐ๋ณตํ๋ค.
test_mse = model.evaluate(test_set) new_set = test_set.take(3) # ์๋ก์ด ์ํ์ด 3๊ฐ ์๋ค๊ณ ๊ฐ์ ํ๋ค. y_pred = model.predict(new_set) # ๋๋ ๋ํ์ด ๋ฐฐ์ด์ ์ ๋ฌํ ์ ์๋ค.evaluate()์ predict() ๋ฉ์๋์ ๋ฐ์ดํฐ์ ์ ์ ๋ฌํ ์ ์๋ค.
๋ค๋ฅธ ์ธํธ์ ๋ฌ๋ฆฌ new_set์ ๋ ์ด๋ธ์ ๊ฐ์ง๊ณ ์์ง ์๋ค. ํฌํจ๋์ด ์๋๋ผ๋ ์ผ๋ผ์ค๊ฐ ๋ฌด์ํ๋ค. ์ด๋ฐ ๋ชจ๋ ๊ฒฝ์ฐ์ ๋ฐ์ดํฐ์ ๋์ ๋ํ์ด ๋ฐฐ์ด์ ์ฌ์ฉํ ์ ์๋ค.
n_epochs = 5 for epoch in range(n_epochs): for X_batch, y_batch in train_set: [...] # ๊ฒฝ์ฌ ํ๊ฐ๋ฒ ๋จ๊ณ๋ฅผ ์ํํ๋ค@tf.function def train_one_epoch(model, optimizer, loss_fn, train_set): for X_batch, y_batch in train_set: with tf.GradientTape() as tape: y_pred = model(X_batch) main_loss = tf.reduce_mean(loss_fn(y_batch, y_pred)) loss = tf.add_n([main_loss] + model.losses) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) optimizer = tf.keras.optimizers.SGD(learning_rate=0.01) loss_fn = tf.keras.losses.mean_squared_error for epoch in range(n_epochs): print("\rEpoch {}/{}.format(epoch + 1, n_epochs), end="") train_one_epoch(model, optimizer, loss_fn, train_set)์ผ๋ผ์ค์์ compile() ๋ฉ์๋์ steps_per_execution ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด ํ๋ จ์ ์ฌ์ฉํ๋ tf.function์ ํธ์ถํ ๋๋ง๋ค fit() ๋ฉ์๋๊ฐ ์ฒ๋ฆฌํ ๋ฐฐ์น์ ์๋ฅผ ์ ์ํ ์ ์๋ค.
13.2 ์ผ๋ผ์ค์ ์ ์ฒ๋ฆฌ ์ธต
์ ๊ฒฝ๋ง์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฅผ ์ค๋นํ๋ ค๋ฉด ์ผ๋ฐ์ ์ผ๋ก ์์น ํน์ฑ ์ ๊ทํ, ๋ฒ์ฃผํ ํน์ฑ์ด๋ ํ ์คํธ ์ธ์ฝ๋ฉ, ์ด๋ฏธ์ง ์๋ฅด๊ธฐ์ ํฌ๊ธฐ ์กฐ์ ๋ฑ์ ์์ ์ด ํ์ํ๋ค.
ํ๋ จ ๋ฐ์ดํฐ ํ์ผ์ ์ค๋นํ ๋ ๋ํ์ด, ํ๋ค์ค, ์ฌ์ดํท๋ฐ๊ณผ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฏธ๋ฆฌ ์ ์ฒ๋ฆฌ๋ฅผ ์ํํ ์ ์๋ค.
๋ฐ์ดํฐ์ ์ map() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ์ ์ ๋ชจ๋ ์์์ ์ ์ฒ๋ฆฌ ํจ์๋ฅผ ์ ์ฉํ์ฌ tf.data๋ก ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๋ ๋์ ๋ฐ๋ก ์ ์ฒ๋ฆฌํ ์ ์๋ค.
๋ชจ๋ธ ๋ด๋ถ์ ์ ์ฒ๋ฆฌ ์ธต์ ์ง์ ํฌํจ์์ผ ํ๋ จ ์ค์ ์ฆ์ ๋ชจ๋ ์ ๋ ฅ ๋ฐ์ดํฐ๋ฅผ ์ ์ฒ๋ฆฌํ๋ค. ๊ทธ๋ฐ ๋ค์ ์ ํ ํ๊ฒฝ์์ ๋์ผํ ์ ์ฒ๋ฆฌ ์ธต์ ์ฌ์ฉํ๋ค.
13.2.1 Normalization ์ธต
norm_layer = tf.keras.layers.Normalization() model = tf.keras.models.Sequential([ norm_layer, tf.keras.layers.Dense(1) ]) model.compile(loss="mse", optimizer=tf.keras.optimizers.SGD(learning_rate=2e-3)) norm_layer.adapt(X_train) model.fit(X_train, y_train, validation_data=(X_valid, y_valid), epochs=5)
์ ์ฒ๋ฆฌ๊ฐ ํ๋ จ๋๋ ๋์ ์ฆ์ ์ ์ฉ๋๊ธฐ ๋๋ฌธ์ ์ํฌํฌ๋ง๋ค ๋งค๋ฒ ์ํ๋๋ค -> ํ๋ จ ์๋๋ฅผ ๋๋ฆฌ๊ฒ ํ๋ค.
ํ๋ จ ์ ์ ์ ์ฒด ํ๋ จ ์ธํธ๋ฅผ ํ ๋ฒ ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ๋ซ๋ค. ์ด๋ฅผ ์ํด์๋ ์ฌ์ดํท๋ฐ์ StandardScaler์ฒ๋ผ Normalization ์ธต์ ๋ ๋ฆฝ์ ๊ธ๋ก ์ฌ์ฉํ ์ ์๋ค.
norm_layer = tf.keras.layers.Normalization() norm_layer.adapt(X_train) X_train_scaled = norm_layer(X_train) X_valid_scaled = norm_layer(X_valid)model = tf.keras.models.Sequential([tf.keras.layers.Dense(1)]) model.compile(loss="mse", optimizer=tf.keras.optimizers.SGD(learning_rate=2e-3)) model.fit(X_train_scaled, y_train, epochs=5, validation_data=(X_valid_scaled, y_valid))์ด ๋ฐฉ์์ ๋ชจ๋ธ์ ์ ํ์ ๋ฐฐํฌํ์ ๋ ์ ๋ ฅ์ ์ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ค.
๋ฐ๋ผ์ adapt() ๋ฉ์๋๋ฅผ ํธ์ถํ Normalization ์ธต๊ณผ ํ๋ จ๋ ๋ชจ๋ธ์ ํฌํจํ๋ ์๋ก์ด ๋ชจ๋ธ์ ๋ง๋ค๊ณ ์ด ์ต์ข ๋ชจ๋ธ์ ์ ํ์ ๋ฐฐํฌํ๋ค.
final_model = tf.keras.Sequential([norm_layer, model]) X_new = X_test[:3] # ์ค์ผ์ผ์ ์กฐ์ ํ์ง ์์ ์๋ก์ด ์ํ y_pred = final_model(X_new) # ๋ฐ์ดํฐ๋ฅผ ์ ์ฒ๋ฆฌํ๊ณ ์์ธก์ ๋ง๋ ๋ค
์ผ๋ผ์ค ์ ์ฒ๋ฆฌ ์ธต์ tf.data API์ ํจ๊ป ์ธ ์ ์๋ค.
dataset = dataset.map(lambda X, y: (norm_layer(X), y))์ผ๋ผ์ค ์ ์ฒ๋ฆฌ ์ธต์ด ์ ๊ณตํ๋ ๊ฒ๋ณด๋ค ๋ ๋ง์ ๊ธฐ๋ฅ์ด ํ์ํ๋ค๋ฉด ์ฌ์ฉ์ ์ ์ ์ธต์ ๋ง๋ค๋ฉด ๋๋ค.
import numpy as np class MyNormalization(tf.keras.layers.Layer): def adapt(self, X): self.mean_ = np.mean(X, axis=0, keepdims=True) self.std_ = np.std(X, axis=0, keepdims=True) def call(self, inputs): eps = tf.keras.backend.epsilon() return (inputs - self.mean_) / (self.std_ + eps)13.2.2 Discretization ์ธต
๊ตฌ๊ฐ์ด๋ผ๊ณ ๋ถ๋ฆฌ๋ ๊ฐ ๋ฒ์๋ฅผ ๋ฒ์ฃผ๋ก ๋งคํํ์ฌ ์์น ํน์ฑ์ ๋ฒ์ฃผํ ํน์ฑ์ผ๋ก ๋ณํํ๋ค.
๋ค์ค๋ชจ๋ ๋ถํฌ๋ฅผ ๊ฐ์ง ํน์ฑ์ด๋ ํ๊น๊ณผ์ ๊ด๊ณ๊ฐ ๋งค์ฐ ๋น์ ํ์ ์ธ ํน์ฑ์ ์ ์ฉํ ๋๊ฐ ์๋ค.
age = tf.constant([[10.], [93.], [57.], [18.], [37.], [5.]]) discretize_layer = tf.keras.layers.Discretization(bin_boundaries=[18., 50.]) age_categories = discretize_layer(age) age_categories # ‹tf.Tensor:shape=(6, 1), dtype=int64, numpy=array([[0],[2],[2],[1],[1],[0]])>discretize_layer = tf.keras.layers.Diescretization(num_bins=3) discretize_layer.adapt(age) age_categories = discretize_layer(age) age_categories # ‹tf.Tensor:shape=(6, 1), dtype=int64, numpy=array([[1],[2],[2],[1],[2],[0]])>13.2.3 CategoryEncoding ์ธต
๋ฒ์ฃผ์ ๊ฐ์๊ฐ ์ ๋ค๋ฉด ์-ํซ ์ธ์ฝ๋ฉ์ด ์ข์ ์ต์ ์ด๋ค.
onehot_layer = tf.keras.layers.CategoryEngoding(num_tokens=3) onehot_layer(age_categories) # <tf. Tensor: shape=(6, 3), dtype=float32, numpy= # array([[0., 1., 0.1, # [0., 0., 1.], [0., 0., 1.], [0., 1., 0.], [0., 0., 1.], [1., 0., 0.]], dtype=float32)>two_age_categories = np.array([[1, 0], [2, 2], [2, 0]]) onehot_layer(two_age_categories) # <tf.Tensor: shape=(3, 3), dtype=float32, numpy= # array([[1., 1., 0.], [0., 0., 1.], [1., 0., 1.]], dtype=float32)>๋์์ ํ ๊ฐ ์ด์์ ๋ฒ์ฃผํ ํน์ฑ์ ์ธ์ฝ๋ฉํ๋ฉด ๋ฉํฐ-ํซ ์ธ์ฝ๋ฉ์ ์ํํ๋ค.
๊ฐ ๋ฒ์ฃผ๊ฐ ์ผ๋ง๋ ๋ง์ด ๋ฑ์ฅํ๋์ง ์๊ณ ์ถ๋ค๋ฉด CategoryEncoding ์ธต์ ๋ง๋ค ๋ output_mode="count"๋ฅผ ์ถ๊ฐํ๋ค.
์ด๋ ๊ฒ ํ๋ฉด ์ถ๋ ฅ ํ ์์ ๊ฐ ๋ฒ์ฃผ์ ๋ฑ์ฅ ํ์๊ฐ ํฌํจ๋๋ค.
๋ฉํฐ-ํซ ์ธ์ฝ๋ฉ๊ณผ ์นด์ดํธ ์ธ์ฝ๋ฉ์ ๋ฒ์ฃผ๋ฅผ ํ์ฑํํ ํน์ฑ์ด ์ด๋ค ๊ฒ์ธ์ง ์ ์ ์๊ธฐ ๋๋ฌธ์ ์ ๋ณด์ ์์ค์ด ์๋ค.
์ด๋ฅผ ํผํ๋ ค๋ฉด ํน์ฑ๋ง๋ค ๋ณ๋๋ก ์-ํซ ์ธ์ฝ๋ฉ์ ํ ๋ค์ ์ถ๋ ฅ์ ํฉ์ณ์ผ ํ๋ค.
๋ฒ์ฃผ ์๋ณ์๊ฐ ๊ฒน์น์ง ์๋๋ก ์กฐ์ ํ๋ฉด ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
onehot_layer = tf.keras.layers.CategoryEncoding(num_tokens=3 + 3) onehot_layer(two_age_categories + [0, 3]) # ๋ ๋ฒ์งธ ํน์ฑ์ 3์ ๋ํ๋ค # <tf.Tensor: shape=(3, 6), dtype=float32, numpy= # array([[0., 1., 0., 1., 0., 0.], [0., 0., 1., 0., 0., 1.], [0., 0., 1., 1., 0., 0.]], dtype=float32)>์ฒ์ ์ธ ๊ฐ์ ์ด์ ์ฒซ ๋ฒ์จฐ ํน์ฑ์ ํด๋นํ๊ณ ๋ง์ง๋ง ์ธ ๊ฐ์ ์ด์ ๋ ๋ฒ์งธ ํน์ฑ์ ํด๋นํ๋ค.
๋ชจ๋ธ์ ์ฃผ์ ํ ํน์ฑ์ ๊ฐ์๋ฅผ ์ฆ๊ฐ์ํค๊ธฐ ๋๋ฌธ์ ๋ชจ๋ธ ํ๋ผ๋ฏธํฐ๊ฐ ๋ ํ์ํด์ง๋ค.
13.2.4 StringLookup ์ธต
cities = ["Auckland", "Paris", "Paris", "San Francisco"] str_lookup_layer = tf.keras.layers.StringLookup() str_lookup_layer.adapt(cities) str_lookup_layer([["Paris"], ["Auckland"], ["Auckland"], ["Montreal"]]) # <tf.Tensor: shape=(4, 1), dtype=int64, numpy=array([[1], [3], [3], [0]])>๋ง์ StringLookup์ธต์ ๋ง๋ค๊ณ adapt() ๋ฉ์๋์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ์ฌ ์ธ ๊ฐ์ ๊ณ ์ ํ ๋ฒ์ฃผ๋ฅผ ์ฐพ๋๋ค.
๊ทธ๋ฐ ๋ค์ ์ด ์ธต์ ์ฌ์ฉํด ๋ช ๊ฐ์ ๋์๋ฅผ ์ธ์ฝ๋ฉํ๋ฉฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์๋ก ์ธ์ฝ๋ฉ๋๋ค. ์ ์ ์๋ ๋ฒ์ฃผ๋ 0์ผ๋ก ๋งคํ๋๋ค.
์ด๋ฏธ ์๊ณ ์๋ ๋ฒ์ฃผ๋ ๊ฐ์ฅ ์์ฃผ ๋ฑ์ฅํ๋ ๋ฒ์ฃผ์์ ๋๋ฌผ๊ฒ ๋ฑ์ฅํ๋ ๋ฒ์ฃผ์์ผ๋ก 1๋ถํฐ ๋งคํ๋๋ค.
str_lookup_layer = tf.keras.layers.StringLookup(output_mode="one-hot") str_lookup_layer.adapt(cities) str_lookup_layer([["Paris"], ["Auckland"], ["Auckland"], ["Montreal"]]) # <tf.Tensor: shape=(4, 4), dtype=float32, numpy= # array([[0., 1., 0., 0.], [0., 0., 0., 1.], [0., 0., 0., 1.], [1., 0., 0., 0.]], dtype=float32)>StringLookup ์ธต์ ๋ง๋ค ๋ output_mode="one_hot"์ผ๋ก ์ง์ ํ๋ฉด ์ ์ ๋์ ๋ฒ์ฃผ๋ง๋ค ์-ํซ ๋ฒกํฐ๋ฅผ ์ถ๋ ฅํ๋ค.
ํ๋ จ ์ธํธ๊ฐ ๋งค์ฐ ํฌ๋ฉด ํ๋ จ ์ธํธ์์ ๋๋คํ๊ฒ ์ผ๋ถ๋ฅผ ์ถ์ถํ์ฌ adapt() ๋ฉ์๋์ ์ ๋ฌํ๋ ๊ฒ์ด ํธ๋ฆฌํ ์ ์๋ค. ์ด๋ฐ ๊ฒฝ์ฐ ์ผ๋ถ ๋๋ฌธ ๋ฒ์ฃผ๋ฅผ ๋์น ์ ์๋๋ฐ ์ด๋ฅผ ํผํ๊ธฐ ์ํด num_odd_indices๋ฅผ 1๋ณด๋ค ํฐ ์ ์๋ก ์ง์ ํ ์ ์๋ค. ์ด ๊ฐ์ OOV ๋ฒํท ๊ฐ์์ด๋ค.
์ ์ ์๋ ๋ฒ์ฃผ๋ ํด์ ํจ์๋ฅผ ์ฌ์ฉํด OOV ๋ฒํท ์ค ํ๋๋ก ๋๋คํ๊ฒ ๋งคํ๋ ๊ฒ์ด๋ค.
์ด๋ ๊ฒ ํจ๋ ์ ์ด๋ ๋๋ฌธ ๋ฒ์ฃผ ์ค ์ผ๋ถ๋ฅผ ๊ตฌ๋ณํ ์ ์์ ๊ฒ์ด๋ค.
str_lookup_layer = tf.keras.layers.StringLookup(num_oov_indices=5) str_lookup_layer.adapt(cities) str_lookup_layer([["Paris"], ["Auckland"], ["Foo"], ["Bar"], ["Baz"]]) # <tf.Tensor: shape=(4, 10>, dtype=int64, numpy=array([[5], [7], [4], [3], [4]])>์ ์ ์๋ ๋ฒ์ฃผ๊ฐ OOV ๋ฒํท ์ค ํ๋์ ๋งคํ๋ ๋ ๋ค๋ฅธ ๋ฒ์ฃผ๊ฐ ๊ฐ์ ๋ฒํท์ ๋งคํ๋์ด ๋ชจ๋ธ์ด ๋์ ๊ตฌ๋ถํ ์ ์๋ ํด์ฑ ์ถฉ๋์ด ๋ฐ์ํ ์ ์๋ค. -> OOV ๋ฒํท์ ์๋ฅผ ๋๋ ค ์ํ์ ์ค์ธ๋ค.
๋ฒ์ฃผ๋ฅด ใน๋๋คํ๊ฒ ๋ฒํท์ ๋งคํํ๋ ์์ด๋์ด๋ฅผ ํด์ฑ ํธ๋ฆญ์ด๋ผ ํ๋ค.
13.2.5 Hashing ์ธต
๋ฒ์ฃผ๋ง๋ค ํด์๋ฅผ ๊ณ์ฐํ๊ณ ๋ฒํท(๋๋ ๊ตฌ๊ฐ) ๊ฐ์๋ก ๋๋ ๋๋จธ์ง๋ฅผ ๊ตฌํ๋ค. ์ด ๋งคํ์ ์ฌํ ๊ฐ๋ฅํ ๋๋ค์ด๋ฏ๋ก ์์ ์ ์ด๋ค.
๊ตฌ๊ฐ์ ๊ฐ์๊ฐ ๋ฐ๋์ง ์๋๋ค๋ฉด ๋์ผํ ๋ฒ์ฃผ๋ ํญ์ ๊ฐ์ ์ ์๋ก ๋งคํ๋๋ค.
hashing_layer = tf.keras.layers.Hashing(num_bins=10) hashing_layer([["Paris"], ["Tokyo"], ["Auckland"], ["Montreal"]]) # <tf.Tensor: shape=(4, 1), dtype=int64, numpy=array([[0], [1], [9], [1]])>13.2.6 ์๋ฒ ๋ฉ์ ์ฌ์ฉํด ๋ฒ์ฃผํ ํน์ฑ ์ธ์ฝ๋ฉํ๊ธฐ
์๋ฒ ๋ฉ์ ๋ฒ์ฃผ๋ ์ดํ ์ฌ์ ์ ๋จ์ด์ ๊ฐ์ ๊ณ ์ฐจ์ ๋ฐ์ดํฐ์ ๋ฐ์ง ํํ์ด๋ค.
๋ฅ๋ฌ๋์์ ์๋ฒ ๋ฉ์ ์ผ๋ฐ์ ์ผ๋ก ๋๋คํ๊ฒ ์ด๊ธฐํ๋๊ณ ๋ค๋ฅธ ๋ชจ๋ธ ํ๋ผ๋ฏธํฐ์ ํจ๊ป ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ผ๋ก ํ๋ จ๋๋ค.
์๋ฒ ๋ฉ์ ํ๋ จํ ์ ์๊ธฐ ๋๋ฌธ์ ํ๋ จ ๋์ค์ ์ ์ฐจ ํฅ์๋๋ค. ๋น์ทํ ๋ฒ์ฃผ๋ค์ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ด ๋ ๊ฐ๊น๊ฒ ๋ง๋ค ๊ฒ์ด๋ค.
ํํ ํ์ต : ํํ์ด ์ข์์๋ก ์ ๊ฒฝ๋ง์ด ์ ํํ ์์ธก์ ๋ง๋ค๊ธฐ ์ฝ๋ค. ๋ฒ์ฃผ๊ฐ ์ ์ฉํ๊ฒ ํํ๋๋๋ก ์๋ฒ ๋ฉ์ด ํ๋ จ๋๋ ๊ฒฝํฅ์ด ์๋ค.

์ผ๋ผ์ค๋ ์๋ฒ ๋ฉ ํ๋ ฌ์ ๊ฐ์ผ Embedding ์ธต์ ์ ๊ณตํ๋ค.
๋ฒ์ฃผ๋ง๋ค ํ๋์ ํ์, ์๋ฒ ๋ฉ ์ฐจ์๋ง๋ค ํ๋์ ์ด์ ๊ฐ์ง๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ๋๋คํ๊ฒ ์ด๊ธฐํ๋๋ค.
๋ฒ์ฃผ ID๋ฅผ ์๋ฒ ๋ฉ์ผ๋ก ๋ณํํ๊ธฐ ์ํด Embedding ์ธต์ด ๋ฒ์ฃผ์ ํด๋นํ๋ ํ์ ์ฐพ์ ๋ฐํํ๋ค.
tf.random.set_seed(42) embedding_layer = tf.keras.layers.Embedding(input_dim=5, output_dim=2) embedding_layer(np.array([2, 4, 2])) # <tf.Tensor: shape=(3, 2), dtype=float32, numpy= # array([[-0.04663396, 0.01846724], [-0.02736737, -0.02768031], [-0.04663396, 0.01846724]], dtype=float32)>๋ฒ์ฃผํ ํ ์คํธ ํน์ฑ์ ์๋ฒ ๋ฉํ๊ธฐ ์ํด StringLookup ์ธต๊ณผ Embedding ์ธต์ ๋ค์๊ณผ ๊ฐ์ด ์ฐ๊ฒฐํ ์ ์๋ค.
tf.random.set_seed(42) ocean_prox = ["<1H OCEAN", "INLAND", "NEAR OCEAN", "NEAR BAY", "ISLAND"] str_lookup_layer = tf.keras. layers.StringLookup() str_lookup_layer .adapt(ocean_prox) lookup_and _embed = tf.keras. Sequential([ ... tf.keras. layers.InputLayer(input_shape=[], dtype=tf.string), ... str_lookup_layer ... tf.keras. layers.Embedding(input_dim=str_lookup_layer.vocabulary_size), ... output_dim=2) ... ...]) ... lookup_and_embed(np.array([["«1H OCEAN"], ["ISLAND"], ["<1H OCEAN"]])) # <tf. Tensor: shape=(3, 2), dtype=float32, numpy= # array([[-0.01896119, 0.02223358], # [ 0.02401174, 0.03724445], # [-0.01896119, 0.02223358]], dtype=float32)>์๋ฒ ๋ฉ ํ๋ ฌ์ ํ ๊ฐ์๋ ์ดํ ์ฌ์ ์ ํฌ๊ธฐ์ ๊ฐ์์ผ ํ๋ค. ์๋ ค์ง ๋ฒ์ฃผ์ OOV ๋ฒํท ๊ฐ์๋ฅผ ํฌํจํ ์ด ๋ฒ์ฃผ ๊ฐ์์ด๋ค.
vocabulary_size() ๋ฉ์๋๊ฐ ์ด ์ซ์๋ฅผ ๋ฐํํ๋ค.
์ด๋ฅผ ๋ชจ๋ ์ฐ๊ฒฐํ๋ฉด ์ผ๋ฐ์ ์ธ ์์น ํน์ฑ๊ณผ ํจ๊ผ ๋ฒ์ฃผํ ํ ์คํธ ํน์ฑ์ ์ฒ๋ฆฌํ๊ณ ๊ฐ ๋ฒ์ฃผ๋ฅผ ์ํ ์๋ฒ ๋ฉ์ ํ์ตํ๋ ๋ชจ๋ธ์ ๋ง๋ค ์ ์๋ค.
X_train_num, X_train_cat, y_train = [...] X_valid_num, X_valid_cat, y_valid = [...] num_input = tf.keras.layers.Input(shape=[8], name="num") cat_input = tf.keras.layers.Input(shape=[], dtype=tf.string, name="cat") cat_embeddings = lookup_and_embed(cat_input) encoded_inputs = tf.keras.layers.concatenate([num_input, cat_enbeddings]) outputs = tf.keras.layers.Dense(1)(encoded_inputs) model = tf.keras.models.Model(inputs=[num_input, cat_input], outputs=[outputs]) model.compile(loss="mse", optimizer="sgd") history = model.fit((X_train_num, X_train_cat, y_train, epochs=5, validation_data=((X_valid_nun, X_valid_cat), y_valid))์ด ๋ชจ๋ธ์ ๋ ๊ฐ์ ์ ๋ ฅ์ ๋ฐ๋๋ค.
num_input์ ์ํ๋ง๋ค 8๊ฐ์ ์์น ํน์ฑ์ ๋ด๊ณ ์๊ณ , cat_input์ ์ํ๋ง๋ค ํ๋์ ๋ฒ์ฃผํ ํ ์คํธ ํน์ฑ์ ๋ด๊ณ ์๋ค.
concatenate() ํจ์๋ฅผ ์ฌ์ฉํด ์์น ์ ๋ ฅ๊ณผ ์๋ฒ ๋ฉ์ ์ฐ๊ฒฐํ์ฌ ์์ ํ๊ฒ ์ธ์ฝ๋ฉ๋ ์ ๋ ฅ์ ๋ง๋ค์ด ์ ๊ฒฝ๋ง์ ์ฃผ์ ํ ์ค๋น๋ฅผ ๋ง์น๋ค.
์ดํ์ ์ด๋ค ์ข ๋ฅ์ ์ ๊ฒฝ๋ง์ด๋ ์ถ๊ฐ ๊ฐ๋ฅํ๋ค.
์์ ์ ์ํ ์ ๋ ฅ๊ณผ ์ถ๋ ฅ์ผ๋ก ์ผ๋ผ์ค ๋ชจ๋ธ์ ๋ง๋ ๋ค.
์ด ๋ชจ๋ธ์ ์ปดํ์ผํ๊ณ ์์น ์ ๋ ฅ๊ณผ ๋ฒ์ฃผํ ์ ๋ ฅ์ ๋ชจ๋ ์ ๋ฌํด ํ๋ จํ๋ค.
13.2.7 ํ ์คํธ ์ ์ฒ๋ฆฌ
StringLookup ์ธต๊ณผ ๋งค์ฐ ๋น์ทํ๊ฒ ์ธต์ ๋ง๋ค ๋ vocabulary ๋งค๊ฐ๋ณ์๋ก ์ดํ ์ฌ์ ์ ์ ๋ฌํ๊ฑฐ๋ adapt() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ํ๋ จ ๋ฐ์ดํฐ๋ก๋ถํฐ ์ดํ ์ฌ์ ์ ํ์ตํ ์ ์๋ค.
train_data = ["to be", "!(to be)", "That's the question", "Be, be, be."] text_vec_layer = tf.keras.layers.TextVectorization() text_vec_layer.adapt(train_data) text_vec_layer(["Be good!", "Question: be or be?"]) # <tf.Tensor: shape=(2, 4), dtype=int64, numpy= # array([[2, 1, 0, 0], [6, 2, 1, 2]])>์ดํ ์ฌ์ ์ ๊ตฌ์ฑํ๊ธฐ ์ํด adapt() ๋ฉ์๋๋ ๋จผ์ ํ๋ จ ํ ์คํธ๋ฅผ ์๋ฌธ์๋ก ๋ฐ๊พธ๊ณ ๊ตฌ๋์ ์ ์ญ์ ํ๋ค.
๋ฌธ์ฅ์ ๊ณต๋ฐฑ์ผ๋ก ๋๋๊ณ ๋ง๋ค์ด์ง ๋จ์ด๋ฅผ ๋น๋์ ๋ฐ๋ผ ์ ๋ ฌํ์ฌ ์ต์ข ์ดํ ์ฌ์ ์ ๋ง๋ ๋ค.
๋ฌธ์ฅ์ ์ธ์ฝ๋ฉํ ๋ ์ ์ ์๋ ๋จ์ด๋ 1๋ก ์ธ์ฝ๋ฉ๋๋ค.
์ฒซ ๋ฒ์งธ ๋ฌธ์ฅ์ด ๋ ๋ฒ์งธ ๋ฌธ์ฅ๋ณด๋ค ์งง๊ธฐ ๋๋ฌธ์ 0์ผ๋ก ํจ๋ฉ๋๋ค.
๋จ์ด ID๋ ์ธ์ฝ๋ฉ๋์ด์ผ ํ๋ฉฐ ์ผ๋ฐ์ ์ผ๋ก Embedding ์ธต์ ์ฌ์ฉํ๋ค.
๋๋ TextVectorization ์ธต์ output_mode ๋งค๊ฐ๋ณ์๋ฅผ "multi_hot" ๋๋ "count"๋ก ์ง์ ํ์ฌ ๋ฉํฐ-ํซ ์ธ์ฝ๋ฉ์ด๋ ์นด์ดํธ ์ธ์ฝ๋ฉ์ ์ป์ ์ ์๋ค.
ํ์ง๋ง ๋จ์ํ ๋จ์ด ์นด์ดํ ์ ์ผ๋ฐ์ ์ผ๋ก ์ด์์ ์ด์ง ์๋ค.
์์ฃผ ๋ฑ์ฅํ๋ ๋จ์ด๋ ์ค์์ฑ์ด ๋จ์ด์ง์ง๋ง ๋๋ฌผ๊ฒ ๋ํ๋๋ ๋จ์ด๋ ํจ์ฌ ๋ง์ ์ ๋ณด๋ฅผ ๊ฐ์ง๋ค.
๋ฐ๋ผ์ output_mode๋ฅผ "multi_hot"์ด๋ "count"๋ก ์ง์ ํ๋ ๊ฒ๋ณด๋ค TF X IDF๋ฅผ ์๋ฏธํ๋ "tf_idf"๋ก ์ค์ ํ๋ ๊ฒ์ด ๋ซ๋ค.
์นด์ดํธ ์ธ์ฝ๋ฉ๊ณผ ๋น์ทํ์ง๋ ํ๋ จ ๋ฐ์ดํฐ์ ์์ฃผ ๋ฑ์ฅํ๋ ๋จ์ด์ ๊ฐ์ค์น๋ฅผ ์ค์ด๊ณ ๋๋ฌผ๊ฒ ๋ฑ์ฅํ๋ ๋จ์ด์ ๊ฐ์ค์น๋ฅผ ๋์ธ๋ค.
text_vec_layer = tf.keras.layers.TextVectorization(output_mode="tf_idf") text_vec_layer.adapt(train_data) text_vec_layer(["Be good!"m "Question: be or be?"]) # <tf.Tensor: shape=(2, 6), dtype=float32, numpy= # array([[0.96725637, 0.6931472 , 0. , 0. , 0. , 0. ], # [0.96725637, 1.3862944 , 0. , 0. , 0. , 1.0986123 ]], dtype=float32)>TextVectorization ์ธต์ ๋จ์ด ์นด์ดํธ์ log(1+d/(f+1))๋ฅผ ๊ฐ์ค์น๋ก ๊ณฑํ๋ค.
d๋ ํ๋ จ ๋ฐ์ดํฐ์ ์๋ ์ ์ฒด ๋ฌธ์ฅ(๋ฌธ์)์ ๊ฐ์์ด๊ณ f๋ ์ฃผ์ด์ง ๋จ์ด๊ฐ ํฌํจ๋ ๋ฌธ์ฅ์ ๊ฐ์์ด๋ค.
13.2.8 ์ฌ์ ํ๋ จ๋ ์ธ์ด ๋ชจ๋ธ ๊ตฌ์ฑ ์์ ์ฌ์ฉํ๊ธฐ
์ฌ์ ํ๋ จ๋ ๋ชจ๋ธ์ ๊ตฌ์ฑ ์์ ๋ชจ๋์ ์ผ๋ฐ์ ์ผ๋ก ์ ์ฒ๋ฆฌ ์ฝ๋์ ์ฌ์ ํ๋ จ๋ ๊ฐ์ค์น๋ฅผ ๋ชจ๋ ๊ฐ์ง๋ฉฐ ์ถ๊ฐ ํ๋ จ์ด ํ์ ์๋ค.
import tensorflow_hub as hub hub_layer = hub.KerasLayer("https://tfhub.dev/google/nnlm-en-dim50/2") sentence_embeddings = hub_layer(tf.constant(["To be", "Not to be"])) sentence_embeddings.numpy).round(2) # array([[-0.25, 0.28, 0.01, 0.1, [...] , 0.05, 0.31], # [-0.2, 0.2, -0.08, 0.02, [...], -0.04, 0.1511, dtype=float32)hub.KerasLayer ์ธต์ ์ฃผ์ด์ง URL์์ ๋ชจ๋์ ๋ค์ด๋ก๋ํ๋ค.
13.2.9 ์ด๋ฏธ์ง ์ ์ฒ๋ฆฌ ์ธต
tf.keras.layers.Resizing์ ์ ๋ ฅ ์ด๋ฏธ์ง๋ฅผ ์ํ๋ ํฌ๊ธฐ๋ก ๋ฐ๊พผ๋ค. crop_to_aspect_radio=True๋ก ์ค์ ํ๋ฉด ์๊ณก์ ํผํ๊ธฐ ์ํด ๋ชฉํ ์ด๋ฏธ์ง ๋น์จ์ ๋ง๊ฒ ์ด๋ฏธ์ง๋ฅผ ์๋ฅธ๋ค.
tf.keras.layers.Rescaling์ ํฝ์ ๊ฐ์ ์ค์ผ์ผ์ ์กฐ์ ํ๋ค.
tf.keras.layers.CenterCrop์ ์ํ๋ ๋์ด์ ๋๋น์ ์ค๊ฐ ๋ถ๋ถ๋ง ์ ์งํ๋ฉด์ ์ด๋ฏธ์ง๋ฅผ ์๋ฅธ๋ค.
from sklearn.datasets import load_sample_images images = load_sample_images()["images"] crop_image_layer = tf.keras.layers.CenterCrop(height=100, width=100) cropped_images = crop_image_layer(images)์ผ๋ผ์ค๋ RandomCrop, RandomFli[, RandomTranslation, RandomRotation, RandomZoom, RandomHeight, RandomWidth, RandomCotrast์ ๊ฐ์ ๋ฐ์ดํฐ ์ฆ์์ ๊ดํ ์ธต๋ ํฌํจํ๊ณ ์๋ค.
์ด๋ฐ ์ธต๋ค์ ํ๋ จ ์ค์๋ง ํ์ฑํ๋๋ฉฐ ์ ๋ ฅ ์ด๋ฏธใ ฃใ ์ ๋๋คํ ๋ณํ์ ์ ์ฉํ๋ค.
๋ฐ์ดํฐ ์ฆ์์ ์ธ๊ณต์ ์ผ๋ก ํ๋ จ ์ธํธ์ ํฌ๊ธฐ๋ฅผ ์ฆ๊ฐ์์ผ ๋ณํ๋ ์ด๋ฏธ์ง๊ฐ ์ค์ (์ฆ์๋์ง ์์) ์ด๋ฏธ์ง์ฒ๋ผ ๋ณด์ด๋ ํ ์ข ์ข ์ฑ๋ฅ์ ์ฆ๊ฐ์ํจ๋ค.
'๐ฎ ์ด๊ฒ์ ๊ฒ ๊ณต๋ถ > โฉ ํธ์ฆ์จ ๋จธ์ ๋ฌ๋' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ