ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • โœฑ ํ•ธ์ฆˆ์˜จ ๋จธ์‹ ๋Ÿฌ๋‹ 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, y

    parse_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์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ ์ฆ์‹์— ๊ด€ํ•œ ์ธต๋„ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค. 

    ์ด๋Ÿฐ ์ธต๋“ค์€ ํ›ˆ๋ จ ์ค‘์—๋งŒ ํ™œ์„ฑํ™”๋˜๋ฉฐ ์ž…๋ ฅ ์ด๋ฏธใ…ฃใ…ˆ์— ๋žœ๋คํ•œ ๋ณ€ํ˜•์„ ์ ์šฉํ•œ๋‹ค.

    ๋ฐ์ดํ„ฐ ์ฆ์‹์€ ์ธ๊ณต์ ์œผ๋กœ ํ›ˆ๋ จ ์„ธํŠธ์˜ ํฌ๊ธฐ๋ฅผ ์ฆ๊ฐ€์‹œ์ผœ ๋ณ€ํ˜•๋œ ์ด๋ฏธ์ง€๊ฐ€ ์‹ค์ œ (์ฆ์‹๋˜์ง€ ์•Š์€) ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ํ•œ ์ข…์ข… ์„ฑ๋Šฅ์„ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.

Designed by Tistory.