Ver3.5 ๐ง TensorFlow๋ก ๋๋ฑ! ํ ์คํธ ๋ถ๋ฅ ๋ชจ๋ธ ์ฒ์๋ถํฐ ๋๊น์ง ๋ง๋ค์ด๋ณด๊ธฐ

๐ง TensorFlow๋ก ๋๋ฑ! ํ ์คํธ ๋ถ๋ฅ ๋ชจ๋ธ ์ฒ์๋ถํฐ ๋๊น์ง ๋ง๋ค์ด๋ณด๊ธฐ
๋ฅ๋ฌ๋์ด ์ฒ์์ด์ด๋ ๊ด์ฐฎ์ โ ์ฝ๋ ํ ์ค์ฉ ๊ฐ์ด ๋ฐ๋ผ๊ฐ ๋ณด์ ๐
์๋
! ์ค๋์ TensorFlow๋ฅผ ์ด์ฉํด์ ํ
์คํธ ๋ถ๋ฅ ๋ชจ๋ธ์ ์ฒ์๋ถํฐ ๋๊น์ง ๋ง๋ค์ด๋ณผ ๊ฑฐ์ผ.
"ํ
์คํธ ๋ถ๋ฅ"๋ผ๊ณ ํ๋ฉด ๋ญ๊ฐ ์ด๋ ต๊ฒ ๋ค๋ฆด ์ ์๋๋ฐ, ์ฌ์ค ์ฐ๋ฆฌ ์ผ์์์ ์์ฒญ ๋ง์ด ์ฐ์ด๋ ๊ธฐ์ ์ด์ผ. ๐ค
์๋ฅผ ๋ค์ด๋ณผ๊ฒ:
๐ฌ ์ํ ๋ฆฌ๋ทฐ ๊ฐ์ฑ ๋ถ์ โ "์ด ๋ฆฌ๋ทฐ๊ฐ ๊ธ์ ์ ์ธ๊ฐ, ๋ถ์ ์ ์ธ๊ฐ?"
๐ฐ ๋ด์ค ์นดํ ๊ณ ๋ฆฌ ๋ถ๋ฅ โ "์ด ๊ธฐ์ฌ๊ฐ ์คํฌ์ธ ์ธ๊ฐ, ์ ์น์ธ๊ฐ, ๊ฒฝ์ ์ธ๊ฐ?"
๐ฌ ๊ณ ๊ฐ ๋ฌธ์ ์๋ ๋ถ๋ฅ โ "์ด ๋ฌธ์๊ฐ ํ๋ถ ์์ฒญ์ธ๊ฐ, ๋ฐฐ์ก ๋ฌธ์์ธ๊ฐ?"
์ด ๋ชจ๋ ๊ฒ ๋ค ํ
์คํธ ๋ถ๋ฅ(Text Classification)์ผ!
ํ
์คํธ๋ฅผ ์
๋ ฅ๋ฐ์์ ๋ฏธ๋ฆฌ ์ ํด์ง ์นดํ
๊ณ ๋ฆฌ ์ค ํ๋๋ก ๋ถ๋ฅํ๋ ์์
์ด์ง.
๊ทธ๋ฆฌ๊ณ ์ด๊ฑธ ๋ฅ๋ฌ๋์ผ๋ก ๊ตฌํํ๋ฉด ์ฌ๋์ด ์ผ์ผ์ด ๊ท์น์ ์ง์ง ์์๋ ๋ชจ๋ธ์ด ์์์ ํจํด์ ํ์ตํด์ ๋ถ๋ฅํด์ค. ์์ ์ ๊ธฐํ์ง? ๐
์ฝ๋๋ฅผ ์ง๊ธฐ ์ ์ ํ๊ฒฝ๋ถํฐ ๋ง์ถฐ์ผ๊ฒ ์ง? ๊ฑฑ์ ๋ง, ์์ฒญ ๊ฐ๋จํด.
์์ฆ์ Google Colab์ ์ฐ๋ฉด ๋ณ๋ ์ค์น ์์ด ๋ฐ๋ก TensorFlow๋ฅผ ์ธ ์ ์์ด์ ์ง์ง ํธํด. ๐
| ๋๊ตฌ | ๋ฒ์ | ์ค๋ช |
|---|---|---|
| Python | 3.8 ์ด์ | ๊ธฐ๋ณธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด |
| TensorFlow | 2.10 ์ด์ | ๋ฅ๋ฌ๋ ํ๋ ์์ํฌ (Keras ํฌํจ) |
| NumPy | 1.21 ์ด์ | ์์น ์ฐ์ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ |
| Matplotlib | 3.5 ์ด์ | ํ์ต ๊ฒฐ๊ณผ ์๊ฐํ |
๋ก์ปฌ ํ๊ฒฝ์์ ์์ ํ๋ค๋ฉด ํฐ๋ฏธ๋์์ ์ด๋ ๊ฒ ์ ๋ ฅํด:
pip install tensorflow numpy matplotlib
Google Colab์ ์ด๋ค๋ฉด? ์ด๋ฏธ ๋ค ์ค์น๋์ด ์์ด! ๊ทธ๋ฅ ๋ฐ๋ก importํ๋ฉด ๋ผ. ๐
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
print(f"TensorFlow ๋ฒ์ : {tf.__version__}")
# ์ถ๋ ฅ ์์: TensorFlow ๋ฒ์ : 2.13.0
tf.keras๋ก ๋ฐ๋ก ์ ๊ทผ ๊ฐ๋ฅํด!
์ค๋ ์ฌ์ฉํ ๋ฐ์ดํฐ์
์ IMDB Movie Reviews Dataset์ด์ผ.
์ด๊ฑด ์ํ ๋ฆฌ๋ทฐ 50,000๊ฐ๋ก ๊ตฌ์ฑ๋ ๋ฐ์ดํฐ์
์ธ๋ฐ, TensorFlow์ ๊ธฐ๋ณธ์ผ๋ก ๋ด์ฅ๋์ด ์์ด์ ๋ฐ๋ก ๋ค์ด๋ฐ์ ํ์๊ฐ ์์ด. ์์ ํธํ์ง? ๐
๐ ํ๋ จ ๋ฐ์ดํฐ: 25,000๊ฐ (๊ธ์ 12,500๊ฐ + ๋ถ์ 12,500๊ฐ)
๐งช ํ ์คํธ ๋ฐ์ดํฐ: 25,000๊ฐ (๊ธ์ 12,500๊ฐ + ๋ถ์ 12,500๊ฐ)
๐ท๏ธ ๋ ์ด๋ธ: 0 = ๋ถ์ (Negative), 1 = ๊ธ์ (Positive)
๋ฐ์ดํฐ๋ ์ด๋ฏธ ์ซ์๋ก ์ธ์ฝ๋ฉ๋์ด ์์ด.
์ฆ, ๊ฐ ๋จ์ด๊ฐ ์ ์ ์ธ๋ฑ์ค๋ก ๋ณํ๋ ์ํ์ผ. ์๋ฅผ ๋ค์ด "the"๋ 1, "movie"๋ 17 ์ด๋ฐ ์์ผ๋ก.
์ด๋ ๊ฒ ํ๋ฉด ์ปดํจํฐ๊ฐ ํ
์คํธ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ํจ์ฌ ์ฌ์์ ธ!
from tensorflow.keras.datasets import imdb
# ์์ 10,000๊ฐ ๋จ์ด๋ง ์ฌ์ฉ (๋น๋ ๊ธฐ์ค)
vocab_size = 10000
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(
num_words=vocab_size
)
print(f"ํ๋ จ ๋ฐ์ดํฐ ์: {len(train_data)}")
print(f"ํ
์คํธ ๋ฐ์ดํฐ ์: {len(test_data)}")
print(f"์ฒซ ๋ฒ์งธ ๋ฆฌ๋ทฐ (์ซ์ ์ธ์ฝ๋ฉ): {train_data[0][:20]}...")
print(f"์ฒซ ๋ฒ์งธ ๋ฆฌ๋ทฐ ๋ ์ด๋ธ: {train_labels[0]}")
# ์ถ๋ ฅ:
# ํ๋ จ ๋ฐ์ดํฐ ์: 25000
# ํ
์คํธ ๋ฐ์ดํฐ ์: 25000
# ์ฒซ ๋ฒ์งธ ๋ฆฌ๋ทฐ (์ซ์ ์ธ์ฝ๋ฉ): [1, 14, 22, 16, 43, 530, 973, ...]
# ์ฒซ ๋ฒ์งธ ๋ฆฌ๋ทฐ ๋ ์ด๋ธ: 1 (๊ธ์ !)
์ซ์๋ก๋ง ๋ณด๋ฉด ๋ญ์ง ๋ชจ๋ฅด๋๊น, ์ค์ ๋จ์ด๋ก ๋ณต์ํด์ ํ์ธํด๋ณด์!
# ๋จ์ด ์ธ๋ฑ์ค ๋์
๋๋ฆฌ ๊ฐ์ ธ์ค๊ธฐ
word_index = imdb.get_word_index()
# ์ธ๋ฑ์ค โ ๋จ์ด ์ญ๋ฐฉํฅ ๋์
๋๋ฆฌ ๋ง๋ค๊ธฐ
# ์ค์ ์ธ๋ฑ์ค๋ 3์ฉ ์คํ์
์ด ์์ด (0=ํจ๋ฉ, 1=์์, 2=์์์์)
reverse_word_index = {value + 3: key for key, value in word_index.items()}
reverse_word_index[0] = "<PAD>"
reverse_word_index[1] = "<START>"
reverse_word_index[2] = "<UNK>"
# ์ฒซ ๋ฒ์งธ ๋ฆฌ๋ทฐ ๋ณต์
def decode_review(encoded_review):
return " ".join([reverse_word_index.get(i, "?") for i in encoded_review])
print(decode_review(train_data[0][:50]))
# ์ถ๋ ฅ: <START> this film was just brilliant casting location scenery...
๊ฐ ๋ฆฌ๋ทฐ์ ๊ธธ์ด๊ฐ ๋ค ๋ฌ๋ผ. ์ด๋ค ๊ฑด ์งง๊ณ ์ด๋ค ๊ฑด ์์ฒญ ๊ธธ์ด.
์ด๊ฑธ ํ์ธํด์ผ ๋์ค์ ํจ๋ฉ ๊ธธ์ด๋ฅผ ๊ฒฐ์ ํ ์ ์์ด!
lengths = [len(review) for review in train_data]
print(f"ํ๊ท ๋ฆฌ๋ทฐ ๊ธธ์ด: {np.mean(lengths):.0f} ๋จ์ด")
print(f"์ต๋ ๋ฆฌ๋ทฐ ๊ธธ์ด: {max(lengths)} ๋จ์ด")
print(f"์ต์ ๋ฆฌ๋ทฐ ๊ธธ์ด: {min(lengths)} ๋จ์ด")
print(f"์ค์๊ฐ: {np.median(lengths):.0f} ๋จ์ด")
# ์ถ๋ ฅ:
# ํ๊ท ๋ฆฌ๋ทฐ ๊ธธ์ด: 238 ๋จ์ด
# ์ต๋ ๋ฆฌ๋ทฐ ๊ธธ์ด: 2494 ๋จ์ด
# ์ต์ ๋ฆฌ๋ทฐ ๊ธธ์ด: 11 ๋จ์ด
# ์ค์๊ฐ: 178 ๋จ์ด
๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ๋ชจ๋ ์
๋ ฅ ๋ฐ์ดํฐ์ ํฌ๊ธฐ๊ฐ ๊ฐ์์ผ ํด.
๊ทผ๋ฐ ๋ฆฌ๋ทฐ๋ง๋ค ๊ธธ์ด๊ฐ ๋ค๋ฅด์์? ์ด๋ค ๊ฑด 20๋จ์ด, ์ด๋ค ๊ฑด 2000๋จ์ด.
์ด๊ฑธ ํด๊ฒฐํ๋ ๊ฒ ๋ฐ๋ก ํจ๋ฉ(Padding)์ด์ผ! ๐ฏ
ํจ๋ฉ์ ์งง์ ์ํ์ค์ 0์ ์ฑ์์ ๊ธธ์ด๋ฅผ ๋ง์ถ๋ ๊ฑฐ์ผ.
๋ฐ๋๋ก ๋๋ฌด ๊ธด ์ํ์ค๋ ์๋ผ๋ด๊ธฐ๋ ํด. ์ด๊ฑธ ํธ๋ฐ์ผ์ด์
(Truncation)์ด๋ผ๊ณ ํด.
from tensorflow.keras.preprocessing.sequence import pad_sequences
# ์ต๋ ๊ธธ์ด ์ค์ (ํ๊ท ๊ธธ์ด ๊ทผ์ฒ๋ก ์ค์ ํ๋ ๊ฒ ์ผ๋ฐ์ )
max_length = 256
# ํจ๋ฉ ์ฒ๋ฆฌ
# padding='post': ๋ค์ 0์ ์ฑ์
# truncating='post': ๋ค๋ฅผ ์๋ผ๋
train_data_padded = pad_sequences(
train_data,
maxlen=max_length,
padding='post',
truncating='post'
)
test_data_padded = pad_sequences(
test_data,
maxlen=max_length,
padding='post',
truncating='post'
)
print(f"ํจ๋ฉ ํ ํ๋ จ ๋ฐ์ดํฐ shape: {train_data_padded.shape}")
print(f"ํจ๋ฉ ํ ํ
์คํธ ๋ฐ์ดํฐ shape: {test_data_padded.shape}")
# ์ถ๋ ฅ:
# ํจ๋ฉ ํ ํ๋ จ ๋ฐ์ดํฐ shape: (25000, 256)
# ํจ๋ฉ ํ ํ
์คํธ ๋ฐ์ดํฐ shape: (25000, 256)
pre: ์์ 0์ ์ฑ์ โ [0, 0, 0, 14, 17, 43]-
post: ๋ค์ 0์ ์ฑ์ โ [14, 17, 43, 0, 0, 0]LSTM ๊ณ์ด ๋ชจ๋ธ์
pre๊ฐ ๋ ์ข์ ๋๋ ์๊ณ , ๋จ์ Dense ๋ชจ๋ธ์ ์ด๋ ์ชฝ์ด๋ ํฌ๊ฒ ์ฐจ์ด ์์ด. ์คํํด๋ณด๋ ๊ฒ ์ต๊ณ !
import numpy as np
# ๋ ์ด๋ธ์ numpy ๋ฐฐ์ด๋ก ๋ณํ
train_labels = np.array(train_labels)
test_labels = np.array(test_labels)
print(f"ํ๋ จ ๋ ์ด๋ธ shape: {train_labels.shape}")
print(f"๊ธ์ ๋ฆฌ๋ทฐ ์: {np.sum(train_labels == 1)}")
print(f"๋ถ์ ๋ฆฌ๋ทฐ ์: {np.sum(train_labels == 0)}")
# ์ถ๋ ฅ:
# ํ๋ จ ๋ ์ด๋ธ shape: (25000,)
# ๊ธ์ ๋ฆฌ๋ทฐ ์: 12500
# ๋ถ์ ๋ฆฌ๋ทฐ ์: 12500
์๋ฒฝํ๊ฒ ๊ท ํ ์กํ ๋ฐ์ดํฐ์
์ด์ผ! ๊ธ์ 50%, ๋ถ์ 50%.
์ด๋ฐ ๊ฒฝ์ฐ์ ํด๋์ค ๋ถ๊ท ํ ๋ฌธ์ ๋ฅผ ๊ฑฑ์ ์ ํด๋ ๋ผ. ๐
ํ๋ จ ์ค์ ๋ชจ๋ธ์ด ์ ํ์ต๋๊ณ ์๋์ง ํ์ธํ๋ ค๋ฉด ๊ฒ์ฆ ๋ฐ์ดํฐ(Validation Data)๊ฐ ํ์ํด.
ํ๋ จ ๋ฐ์ดํฐ์ ์ผ๋ถ๋ฅผ ๋ผ์ด์ ๊ฒ์ฆ์ฉ์ผ๋ก ์ฐ์!
# ํ๋ จ ๋ฐ์ดํฐ์ 20%๋ฅผ ๊ฒ์ฆ ๋ฐ์ดํฐ๋ก ์ฌ์ฉ
val_size = 5000
x_val = train_data_padded[:val_size]
y_val = train_labels[:val_size]
x_train = train_data_padded[val_size:]
y_train = train_labels[val_size:]
print(f"์ค์ ํ๋ จ ๋ฐ์ดํฐ: {x_train.shape}")
print(f"๊ฒ์ฆ ๋ฐ์ดํฐ: {x_val.shape}")
# ์ถ๋ ฅ:
# ์ค์ ํ๋ จ ๋ฐ์ดํฐ: (20000, 256)
# ๊ฒ์ฆ ๋ฐ์ดํฐ: (5000, 256)
์ด์ ์ง์ง ์ฌ๋ฐ๋ ๋ถ๋ถ์ด์ผ! ๐
ํ
์คํธ ๋ถ๋ฅ์ ์ธ ์ ์๋ ๋ชจ๋ธ ๊ตฌ์กฐ๊ฐ ์ฌ๋ฌ ๊ฐ์ง ์๋๋ฐ, ์ค๋์ ์ธ ๊ฐ์ง๋ฅผ ์๊ฐํ ๊ฒ.
๊ฐ๊ฐ ์ฅ๋จ์ ์ด ์์ผ๋๊น ์ํฉ์ ๋ง๊ฒ ๊ณจ๋ผ ์ฐ๋ฉด ๋ผ!
๊ฐ์ฅ ๋จ์ํ ๊ตฌ์กฐ์ผ. Embedding ๋ ์ด์ด๋ก ๋จ์ด๋ฅผ ๋ฒกํฐ๋ก ๋ณํํ๊ณ ,
GlobalAveragePooling์ผ๋ก ํ๊ท ์ ๋ด์ Dense ๋ ์ด์ด๋ก ๋ถ๋ฅํด.
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import (
Embedding, GlobalAveragePooling1D, Dense, Dropout
)
embedding_dim = 64 # ๊ฐ ๋จ์ด๋ฅผ 64์ฐจ์ ๋ฒกํฐ๋ก ํํ
model_dense = Sequential([
# ์๋ฒ ๋ฉ ๋ ์ด์ด: ๋จ์ด ์ธ๋ฑ์ค โ ๋ฐ์ง ๋ฒกํฐ
Embedding(
input_dim=vocab_size, # ์ดํ ํฌ๊ธฐ (10,000)
output_dim=embedding_dim, # ์๋ฒ ๋ฉ ์ฐจ์ (64)
input_length=max_length # ์
๋ ฅ ์ํ์ค ๊ธธ์ด (256)
),
# ์ํ์ค ์ ์ฒด๋ฅผ ํ๊ท ๋ด์ ๊ณ ์ ํฌ๊ธฐ ๋ฒกํฐ๋ก ๋ง๋ค๊ธฐ
GlobalAveragePooling1D(),
# ์์ ์ฐ๊ฒฐ ๋ ์ด์ด
Dense(64, activation='relu'),
Dropout(0.3), # ๊ณผ์ ํฉ ๋ฐฉ์ง
# ์ถ๋ ฅ ๋ ์ด์ด (์ด์ง ๋ถ๋ฅ โ sigmoid)
Dense(1, activation='sigmoid')
])
model_dense.summary()
๐น GlobalAveragePooling1D โ ์ถ๋ ฅ: (None, 64)
๐น Dense(64, relu) โ ์ถ๋ ฅ: (None, 64)
๐น Dropout(0.3) โ ์ถ๋ ฅ: (None, 64)
๐น Dense(1, sigmoid) โ ์ถ๋ ฅ: (None, 1)
์ด ํ๋ผ๋ฏธํฐ: ์ฝ 650,000๊ฐ
LSTM(Long Short-Term Memory)์ ํ
์คํธ์ ์์ ์ ๋ณด๋ฅผ ํ์ฉํ๋ ๋ชจ๋ธ์ด์ผ.
"๋๋ ์ํ๋ฅผ ์ข์ํด"์ "๋๋ ์ํ๋ฅผ ์ซ์ดํด"๋ ๋จ์ด ์์๊ฐ ์ค์ํ์์?
LSTM์ ์ด๋ฐ ์์ ์์กด์ฑ์ ์ ํฌ์ฐฉํด!
from tensorflow.keras.layers import LSTM, Bidirectional
model_lstm = Sequential([
Embedding(
input_dim=vocab_size,
output_dim=embedding_dim,
input_length=max_length
),
# Bidirectional LSTM: ์๋ค ๋ฐฉํฅ ๋ชจ๋ ์ฒ๋ฆฌ
Bidirectional(LSTM(64, return_sequences=False)),
Dense(64, activation='relu'),
Dropout(0.4),
Dense(1, activation='sigmoid')
])
model_lstm.summary()
1D ํฉ์ฑ๊ณฑ ์ ๊ฒฝ๋ง(Conv1D)์ ์ด๋ฏธ์ง ๋ถ๋ฅ์์ ์ฐ๋ CNN์ ํ
์คํธ์ ์ ์ฉํ ๊ฑฐ์ผ.
ํน์ ํจํด(n-gram)์ ํจ์จ์ ์ผ๋ก ํฌ์ฐฉํ๊ณ , LSTM๋ณด๋ค ํ๋ จ ์๋๊ฐ ๋นจ๋ผ!
from tensorflow.keras.layers import Conv1D, MaxPooling1D, GlobalMaxPooling1D
model_conv = Sequential([
Embedding(
input_dim=vocab_size,
output_dim=embedding_dim,
input_length=max_length
),
# 1D ํฉ์ฑ๊ณฑ: 3๊ฐ ๋จ์ด์ฉ ํจํด ํฌ์ฐฉ
Conv1D(128, 5, activation='relu'),
MaxPooling1D(pool_size=2),
Conv1D(64, 3, activation='relu'),
GlobalMaxPooling1D(),
Dense(64, activation='relu'),
Dropout(0.3),
Dense(1, activation='sigmoid')
])
model_conv.summary()
| ๋ชจ๋ธ | ์ฅ์ | ๋จ์ | ์ถ์ฒ ์ํฉ |
|---|---|---|---|
| Dense | ๋น ๋ฆ, ๋จ์ | ์์ ์ ๋ณด ๋ฌด์ | ๋น ๋ฅธ ๋ฒ ์ด์ค๋ผ์ธ |
| LSTM | ์์ ์ ๋ณด ํ์ฉ | ๋๋ฆผ, ๋ฉ๋ชจ๋ฆฌ ๋ง์ด ์ | ๊ธด ํ ์คํธ, ๋ฌธ๋งฅ ์ค์ |
| Conv1D | ๋น ๋ฆ, ํจํด ํฌ์ฐฉ ์ฐ์ | ์ฅ๊ฑฐ๋ฆฌ ์์กด์ฑ ์ฝํจ | ์งง์ ํ ์คํธ, ์๋ ์ค์ |
๋ชจ๋ธ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์์ผ๋ฉด ์ด์ ์ปดํ์ผํ๊ณ ํ๋ จ์์ผ์ผ ํด!
์ปดํ์ผ ๋จ๊ณ์์๋ ์์ค ํจ์, ์ตํฐ๋ง์ด์ , ํ๊ฐ ์งํ๋ฅผ ์ค์ ํด.
# Conv1D ๋ชจ๋ธ๋ก ์งํ (์๋์ ์ฑ๋ฅ ๊ท ํ์ด ์ข์์!)
model = model_conv
model.compile(
optimizer='adam', # Adam ์ตํฐ๋ง์ด์
loss='binary_crossentropy', # ์ด์ง ๋ถ๋ฅ ์์ค ํจ์
metrics=['accuracy'] # ์ ํ๋ ์ธก์
)
print("๋ชจ๋ธ ์ปดํ์ผ ์๋ฃ! โ
")
Adam(Adaptive Moment Estimation)์ ํ์ต๋ฅ ์ ์๋์ผ๋ก ์กฐ์ ํด์ฃผ๋ ์ค๋งํธํ ์ตํฐ๋ง์ด์ ์ผ. ๋๋ถ๋ถ์ ๊ฒฝ์ฐ Adam์ด ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ข์ ์ฑ๋ฅ์ ๋ด.
๐ loss='binary_crossentropy'
์ด์ง ๋ถ๋ฅ(0 ๋๋ 1)์ ์ฌ์ฉํ๋ ์์ค ํจ์์ผ. ๋ชจ๋ธ์ ์์ธก์ด ์ค์ ๋ ์ด๋ธ๊ณผ ์ผ๋ง๋ ๋ค๋ฅธ์ง ์ธก์ ํด. ๊ฐ์ด ๋ฎ์์๋ก ์ข์!
๐ metrics=['accuracy']
ํ๋ จ ์ค์ ์ ํ๋๋ฅผ ๋ชจ๋ํฐ๋งํด. ์ ์ฒด ์์ธก ์ค ๋ง์ ๋น์จ์ด์ผ.
์ฝ๋ฐฑ(Callback)์ ํ๋ จ ์ค์ ํน์ ์กฐ๊ฑด์์ ์๋์ผ๋ก ์คํ๋๋ ํจ์์ผ.
๋ ๊ฐ์ง ์ค์ํ ์ฝ๋ฐฑ์ ์ค์ ํด๋ณด์!
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
callbacks = [
# ๊ฒ์ฆ ์์ค์ด ๊ฐ์ ๋์ง ์์ผ๋ฉด ์กฐ๊ธฐ ์ข
๋ฃ
EarlyStopping(
monitor='val_loss', # ๊ฒ์ฆ ์์ค ๋ชจ๋ํฐ๋ง
patience=3, # 3 ์ํฌํฌ ๋์ ๊ฐ์ ์์ผ๋ฉด ์ข
๋ฃ
restore_best_weights=True # ์ต๊ณ ์ฑ๋ฅ ๊ฐ์ค์น๋ก ๋ณต์
),
# ์ต๊ณ ์ฑ๋ฅ ๋ชจ๋ธ ์ ์ฅ
ModelCheckpoint(
filepath='best_model.keras',
monitor='val_accuracy',
save_best_only=True,
verbose=1
)
]
print("์ฝ๋ฐฑ ์ค์ ์๋ฃ! ๐ฏ")
history = model.fit(
x_train, y_train,
epochs=20, # ์ต๋ 20 ์ํฌํฌ
batch_size=512, # ๋ฐฐ์น ํฌ๊ธฐ
validation_data=(x_val, y_val),
callbacks=callbacks,
verbose=1
)
# ํ๋ จ ์ถ๋ ฅ ์์:
# Epoch 1/20
# 40/40 [==============================] - 8s 180ms/step
# loss: 0.6931 - accuracy: 0.5012 - val_loss: 0.6928 - val_accuracy: 0.5024
# ...
# Epoch 8/20
# 40/40 [==============================] - 6s 150ms/step
# loss: 0.2341 - accuracy: 0.9123 - val_loss: 0.2876 - val_accuracy: 0.8834
# Epoch 11/20 - EarlyStopping ๋ฐ๋!
# ํ๋ จ ์กฐ๊ธฐ ์ข
๋ฃ (val_loss ๊ฐ์ ์์)
ํ๋ จ์ด ๋๋๋ฉด ํ์ต ๊ณก์ ์ ๊ทธ๋ ค์ ๋ชจ๋ธ์ด ์ ํ์ต๋๋์ง ํ์ธํด๋ณด์!
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# ์ ํ๋ ๊ทธ๋ํ
axes[0].plot(history.history['accuracy'], label='ํ๋ จ ์ ํ๋', color='#7eb8d4')
axes[0].plot(history.history['val_accuracy'], label='๊ฒ์ฆ ์ ํ๋', color='#f0a060')
axes[0].set_title('๋ชจ๋ธ ์ ํ๋', fontsize=14, fontweight='bold')
axes[0].set_xlabel('์ํฌํฌ')
axes[0].set_ylabel('์ ํ๋')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# ์์ค ๊ทธ๋ํ
axes[1].plot(history.history['loss'], label='ํ๋ จ ์์ค', color='#7eb8d4')
axes[1].plot(history.history['val_loss'], label='๊ฒ์ฆ ์์ค', color='#f0a060')
axes[1].set_title('๋ชจ๋ธ ์์ค', fontsize=14, fontweight='bold')
axes[1].set_xlabel('์ํฌํฌ')
axes[1].set_ylabel('์์ค')
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('training_history.png', dpi=150, bbox_inches='tight')
plt.show()
ํ๋ จ์ด ๋๋ฌ์ผ๋ฉด ํ
์คํธ ๋ฐ์ดํฐ๋ก ์ต์ข
์ฑ๋ฅ์ ํ๊ฐํด์ผ ํด!
ํ
์คํธ ๋ฐ์ดํฐ๋ ํ๋ จ ์ค์ ํ ๋ฒ๋ ๋ณธ ์ ์๋ ๋ฐ์ดํฐ๋ผ์ ์ง์ง ์ค๋ ฅ์ ์ ์ ์์ด. ๐ฏ
test_loss, test_accuracy = model.evaluate(
test_data_padded, test_labels,
verbose=1
)
print(f"\n๐ ์ต์ข
ํ
์คํธ ๊ฒฐ๊ณผ")
print(f"ํ
์คํธ ์์ค: {test_loss:.4f}")
print(f"ํ
์คํธ ์ ํ๋: {test_accuracy:.4f} ({test_accuracy*100:.2f}%)")
# ์ถ๋ ฅ ์์:
# 782/782 [==============================] - 3s 4ms/step
# ํ
์คํธ ์์ค: 0.2934
# ํ
์คํธ ์ ํ๋: 0.8876 (88.76%)
์ ํ๋ ํ๋๋ง ๋ณด๋ ๊ฑด ๋ถ์กฑํด. ๋ ์์ธํ ๋ถ์์ ํด๋ณด์!
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
# ์์ธก๊ฐ ์์ฑ
y_pred_prob = model.predict(test_data_padded)
y_pred = (y_pred_prob > 0.5).astype(int).flatten()
# ๋ถ๋ฅ ๋ฆฌํฌํธ
print(classification_report(
test_labels, y_pred,
target_names=['๋ถ์ (Negative)', '๊ธ์ (Positive)']
))
# ์ถ๋ ฅ ์์:
# precision recall f1-score support
# ๋ถ์ (Negative) 0.89 0.88 0.89 12500
# ๊ธ์ (Positive) 0.88 0.89 0.89 12500
# accuracy 0.89 25000
# macro avg 0.89 0.89 0.89 25000
# ํผ๋ ํ๋ ฌ
cm = confusion_matrix(test_labels, y_pred)
print(f"\nํผ๋ ํ๋ ฌ:")
print(f"์ง์ง ๋ถ์ โ ๋ถ์ ์์ธก: {cm[0][0]:,}๊ฐ (True Negative)")
print(f"์ง์ง ๋ถ์ โ ๊ธ์ ์์ธก: {cm[0][1]:,}๊ฐ (False Positive)")
print(f"์ง์ง ๊ธ์ โ ๋ถ์ ์์ธก: {cm[1][0]:,}๊ฐ (False Negative)")
print(f"์ง์ง ๊ธ์ โ ๊ธ์ ์์ธก: {cm[1][1]:,}๊ฐ (True Positive)")
โ ๋์์๋ก ๊ฑฐ์ง ๊ธ์ (False Positive)์ด ์ ์ด
๐ฏ Recall (์ฌํ์จ): "์ค์ ๊ธ์ ์ค ๊ธ์ ์ด๋ผ๊ณ ์์ธกํ ๋น์จ"
โ ๋์์๋ก ๋์น๋ ๊ธ์ (False Negative)์ด ์ ์ด
๐ฏ F1-Score: Precision๊ณผ Recall์ ์กฐํ ํ๊ท
โ ๋ ์งํ๋ฅผ ๊ท ํ ์๊ฒ ๋ฐ์ํ ์ข ํฉ ์ ์
์ด์ ์ง์ง ์ฌ๋ฐ๋ ๋ถ๋ถ! ์ง์ ์ํ ๋ฆฌ๋ทฐ๋ฅผ ์จ์ ๋ชจ๋ธ์ด ๊ธ์ /๋ถ์ ์ ๋ง์ถ๋์ง ํ ์คํธํด๋ณด์! ๐ฟ
def predict_sentiment(review_text, model, word_index, max_len=256):
"""
ํ
์คํธ ๋ฆฌ๋ทฐ๋ฅผ ์
๋ ฅ๋ฐ์ ๊ฐ์ฑ์ ์์ธกํ๋ ํจ์
"""
# 1. ํ
์คํธ ์ ์ฒ๋ฆฌ
review_text = review_text.lower()
words = review_text.split()
# 2. ๋จ์ด โ ์ ์ ์ธ์ฝ๋ฉ
# ๋จ์ด ์ธ๋ฑ์ค์ ์๋ ๋จ์ด๋ 2(UNK)๋ก ์ฒ๋ฆฌ
encoded = [word_index.get(word, 2) + 3 for word in words]
# 3. ํจ๋ฉ
from tensorflow.keras.preprocessing.sequence import pad_sequences
padded = pad_sequences([encoded], maxlen=max_len, padding='post')
# 4. ์์ธก
prediction = model.predict(padded, verbose=0)[0][0]
# 5. ๊ฒฐ๊ณผ ์ถ๋ ฅ
sentiment = "๐ ๊ธ์ (Positive)" if prediction > 0.5 else "๐ ๋ถ์ (Negative)"
confidence = prediction if prediction > 0.5 else 1 - prediction
print(f"๋ฆฌ๋ทฐ: {review_text[:80]}...")
print(f"์์ธก: {sentiment}")
print(f"ํ์ ๋: {confidence*100:.1f}%")
print("-" * 50)
return prediction
# ํ
์คํธํด๋ณด๊ธฐ!
test_reviews = [
"This movie was absolutely brilliant! The acting was superb and the story was captivating.",
"Terrible film. Waste of time and money. The plot made no sense at all.",
"It was okay, nothing special but not bad either. Average movie experience.",
"One of the best movies I have ever seen! Highly recommend to everyone!"
]
for review in test_reviews:
predict_sentiment(review, model, word_index)
# ์ถ๋ ฅ ์์:
# ๋ฆฌ๋ทฐ: this movie was absolutely brilliant! the acting was superb...
# ์์ธก: ๐ ๊ธ์ (Positive)
# ํ์ ๋: 97.3%
# --------------------------------------------------
# ๋ฆฌ๋ทฐ: terrible film. waste of time and money. the plot made no...
# ์์ธก: ๐ ๋ถ์ (Negative)
# ํ์ ๋: 94.8%
# --------------------------------------------------
๊ธฐ๋ณธ ๋ชจ๋ธ๋ก 88~89% ์ ํ๋๋ฅผ ๋ฌ์ฑํ๋๋ฐ, ๋ ์ฌ๋ฆฌ๊ณ ์ถ๋ค๋ฉด?
์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์๋ํด๋ณผ ์ ์์ด! ๐
์ฒ์๋ถํฐ ์๋ฒ ๋ฉ์ ํ์ตํ๋ ๋์ , ์ด๋ฏธ ์์ญ์ต ๊ฐ์ ํ
์คํธ๋ก ํ์ต๋
GloVe๋ Word2Vec ์๋ฒ ๋ฉ์ ์ฌ์ฉํ๋ฉด ์ฑ๋ฅ์ด ํฌ๊ฒ ์ฌ๋ผ!
import numpy as np
# GloVe ์๋ฒ ๋ฉ ๋ก๋ (glove.6B.100d.txt ํ์ผ ํ์)
def load_glove_embeddings(glove_path, word_index, embedding_dim=100):
embeddings_index = {}
with open(glove_path, encoding='utf-8') as f:
for line in f:
values = line.split()
word = values[0]
coefs = np.asarray(values[1:], dtype='float32')
embeddings_index[word] = coefs
print(f"GloVe ๋จ์ด ์: {len(embeddings_index):,}")
# ์๋ฒ ๋ฉ ํ๋ ฌ ์์ฑ
embedding_matrix = np.zeros((vocab_size, embedding_dim))
for word, i in word_index.items():
if i < vocab_size:
embedding_vector = embeddings_index.get(word)
if embedding_vector is not None:
embedding_matrix[i] = embedding_vector
return embedding_matrix
# ์ฌ์ ํ๋ จ ์๋ฒ ๋ฉ์ ์ฌ์ฉํ๋ ๋ชจ๋ธ
from tensorflow.keras.layers import Embedding
# embedding_matrix = load_glove_embeddings('glove.6B.100d.txt', word_index)
model_pretrained = Sequential([
Embedding(
input_dim=vocab_size,
output_dim=100,
# weights=[embedding_matrix], # ์ฌ์ ํ๋ จ ๊ฐ์ค์น
# trainable=False, # ์๋ฒ ๋ฉ ๊ณ ์ (ํ์ธํ๋ ์ ํจ)
input_length=max_length
),
Conv1D(128, 5, activation='relu'),
GlobalMaxPooling1D(),
Dense(64, activation='relu'),
Dropout(0.3),
Dense(1, activation='sigmoid')
])
# ์๋ํด๋ณผ ์ ์๋ ํ์ดํผํ๋ผ๋ฏธํฐ๋ค
hyperparams_to_try = {
'embedding_dim': [32, 64, 128, 256],
'max_length': [128, 256, 512],
'batch_size': [128, 256, 512],
'learning_rate': [0.001, 0.0005, 0.0001],
'dropout_rate': [0.2, 0.3, 0.4, 0.5],
'dense_units': [32, 64, 128]
}
# Keras Tuner๋ฅผ ์ฌ์ฉํ ์๋ ํ์ดํผํ๋ผ๋ฏธํฐ ํ์
# pip install keras-tuner
import keras_tuner as kt
def build_model(hp):
model = Sequential([
Embedding(
vocab_size,
hp.Int('embedding_dim', min_value=32, max_value=256, step=32),
input_length=max_length
),
Conv1D(
hp.Int('conv_filters', min_value=64, max_value=256, step=64),
5, activation='relu'
),
GlobalMaxPooling1D(),
Dense(
hp.Int('dense_units', min_value=32, max_value=128, step=32),
activation='relu'
),
Dropout(hp.Float('dropout', min_value=0.2, max_value=0.5, step=0.1)),
Dense(1, activation='sigmoid')
])
model.compile(
optimizer=tf.keras.optimizers.Adam(
hp.Float('learning_rate', min_value=1e-4, max_value=1e-2, sampling='log')
),
loss='binary_crossentropy',
metrics=['accuracy']
)
return model
import random
def augment_text(text_tokens, augment_prob=0.1):
"""
๊ฐ๋จํ ํ
์คํธ ์ฆ๊ฐ ๊ธฐ๋ฒ
- ๋๋ค ๋จ์ด ์ญ์
- ๋๋ค ๋จ์ด ๊ต์ฒด
"""
augmented = []
for token in text_tokens:
rand = random.random()
if rand < augment_prob:
# 10% ํ๋ฅ ๋ก ๋จ์ด ์ญ์
continue
augmented.append(token)
return augmented
# ๋์์ด ๊ต์ฒด (nlpaug ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ)
# pip install nlpaug
# import nlpaug.augmenter.word as naw
# aug = naw.SynonymAug(aug_src='wordnet')
# augmented_text = aug.augment("This movie was great!")
์ต๊ณ ์ฑ๋ฅ์ ์ํ๋ค๋ฉด? BERT(Bidirectional Encoder Representations from Transformers)๋ฅผ ์จ๋ด!
TensorFlow Hub์์ ์ฌ์ ํ๋ จ๋ BERT๋ฅผ ๋ฐ๋ก ๊ฐ์ ธ๋ค ์ธ ์ ์์ด.
import tensorflow_hub as hub
import tensorflow_text as text
# TensorFlow Hub์์ BERT ๋ชจ๋ธ ๋ก๋
bert_preprocess_model = hub.KerasLayer(
"https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3"
)
bert_encoder = hub.KerasLayer(
"https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/4",
trainable=True # ํ์ธํ๋
)
# BERT ๊ธฐ๋ฐ ๋ถ๋ฅ ๋ชจ๋ธ
text_input = tf.keras.layers.Input(shape=(), dtype=tf.string, name='text')
preprocessed_text = bert_preprocess_model(text_input)
outputs = bert_encoder(preprocessed_text)
# ํ๋ง๋ ์ถ๋ ฅ ์ฌ์ฉ
net = outputs['pooled_output']
net = tf.keras.layers.Dropout(0.1)(net)
net = tf.keras.layers.Dense(1, activation='sigmoid', name='classifier')(net)
model_bert = tf.keras.Model(text_input, net)
# BERT๋ ๋ณดํต 90% ์ด์์ ์ ํ๋๋ฅผ ๋ฌ์ฑํด!
์ด์ฌํ ๋ง๋ ๋ชจ๋ธ, ์ ์ฅํด๋๊ณ ๋์ค์ ๋ ์ฐ๊ฑฐ๋ ์๋น์ค์ ๋ฐฐํฌํด์ผ๊ฒ ์ง?
TensorFlow๋ ์ฌ๋ฌ ๊ฐ์ง ์ ์ฅ ๋ฐฉ์์ ์ง์ํด!
# ๋ฐฉ๋ฒ 1: SavedModel ํ์ (๊ถ์ฅ)
model.save('text_classifier_model')
# ํด๋ ๊ตฌ์กฐ๋ก ์ ์ฅ๋จ
# ๋ฐฉ๋ฒ 2: HDF5 ํ์ (.h5)
model.save('text_classifier_model.h5')
# ๋ฐฉ๋ฒ 3: ๊ฐ์ค์น๋ง ์ ์ฅ
model.save_weights('model_weights.h5')
# ๋ชจ๋ธ ๋ถ๋ฌ์ค๊ธฐ
loaded_model = tf.keras.models.load_model('text_classifier_model')
print("๋ชจ๋ธ ๋ก๋ ์๋ฃ! โ
")
๋ชจ๋ธ์ ์น API๋ก ๋ฐฐํฌํ๋ฉด ๋ค๋ฅธ ์๋น์ค์์๋ ์ฌ์ฉํ ์ ์์ด!
Flask๋ก ๊ฐ๋จํ REST API๋ฅผ ๋ง๋ค์ด๋ณด์.
from flask import Flask, request, jsonify
import tensorflow as tf
import numpy as np
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.datasets import imdb
app = Flask(__name__)
# ๋ชจ๋ธ ๋ฐ ์ค์ ๋ก๋
model = tf.keras.models.load_model('text_classifier_model')
word_index = imdb.get_word_index()
MAX_LENGTH = 256
@app.route('/predict', methods=['POST'])
def predict():
data = request.get_json()
review_text = data.get('text', '')
if not review_text:
return jsonify({'error': 'ํ
์คํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์!'}), 400
# ์ ์ฒ๋ฆฌ
words = review_text.lower().split()
encoded = [word_index.get(word, 2) + 3 for word in words]
padded = pad_sequences([encoded], maxlen=MAX_LENGTH, padding='post')
# ์์ธก
prediction = float(model.predict(padded, verbose=0)[0][0])
sentiment = 'positive' if prediction > 0.5 else 'negative'
confidence = prediction if prediction > 0.5 else 1 - prediction
return jsonify({
'text': review_text,
'sentiment': sentiment,
'confidence': round(confidence * 100, 2),
'raw_score': round(prediction, 4)
})
if __name__ == '__main__':
app.run(debug=True, port=5000)
# ์ฌ์ฉ ์์:
# curl -X POST http://localhost:5000/predict \
# -H "Content-Type: application/json" \
# -d '{"text": "This movie was absolutely amazing!"}'
#
# ์๋ต:
# {
# "text": "This movie was absolutely amazing!",
# "sentiment": "positive",
# "confidence": 97.3,
# "raw_score": 0.9730
# }
ํด๋ผ์ฐ๋ ๋ฐฐํฌ๋ Google Cloud Run, AWS Lambda, Heroku ๋ฑ์ ํ์ฉํด๋ด!
๋ชจ๋ธ์ด ํฌ๋ค๋ฉด TensorFlow Serving์ด๋ TensorFlow Lite๋ก ์ต์ ํํ๋ ๊ฒ๋ ๊ณ ๋ คํด๋ด.
์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ด์ฉ์ ํ๋์ ์์ฑ๋ ์ฝ๋๋ก ์ ๋ฆฌํด๋ณผ๊ฒ!
์ด๊ฑธ ๊ทธ๋๋ก ๋ณต์ฌํด์ Google Colab์ ๋ถ์ฌ๋ฃ์ผ๋ฉด ๋ฐ๋ก ์คํ๋ผ. ๐
"""
TensorFlow ํ
์คํธ ๋ถ๋ฅ ๋ชจ๋ธ - ์์ฑ ์ฝ๋
IMDB ์ํ ๋ฆฌ๋ทฐ ๊ฐ์ฑ ๋ถ์ (๊ธ์ /๋ถ์ )
"""
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import imdb
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import (
Embedding, Conv1D, GlobalMaxPooling1D,
Dense, Dropout
)
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
# ============================================
# 1. ์ค์ ๊ฐ
# ============================================
VOCAB_SIZE = 10000 # ์ดํ ํฌ๊ธฐ
MAX_LENGTH = 256 # ์ต๋ ์ํ์ค ๊ธธ์ด
EMBEDDING_DIM = 64 # ์๋ฒ ๋ฉ ์ฐจ์
BATCH_SIZE = 512 # ๋ฐฐ์น ํฌ๊ธฐ
EPOCHS = 20 # ์ต๋ ์ํฌํฌ
VAL_SIZE = 5000 # ๊ฒ์ฆ ๋ฐ์ดํฐ ํฌ๊ธฐ
print(f"TensorFlow ๋ฒ์ : {tf.__version__}")
# ============================================
# 2. ๋ฐ์ดํฐ ๋ก๋ ๋ฐ ์ ์ฒ๋ฆฌ
# ============================================
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(
num_words=VOCAB_SIZE
)
# ํจ๋ฉ
train_data_padded = pad_sequences(train_data, maxlen=MAX_LENGTH, padding='post')
test_data_padded = pad_sequences(test_data, maxlen=MAX_LENGTH, padding='post')
# ๋ ์ด๋ธ ๋ณํ
train_labels = np.array(train_labels)
test_labels = np.array(test_labels)
# ๊ฒ์ฆ ๋ฐ์ดํฐ ๋ถ๋ฆฌ
x_val = train_data_padded[:VAL_SIZE]
y_val = train_labels[:VAL_SIZE]
x_train = train_data_padded[VAL_SIZE:]
y_train = train_labels[VAL_SIZE:]
print(f"ํ๋ จ: {x_train.shape}, ๊ฒ์ฆ: {x_val.shape}, ํ
์คํธ: {test_data_padded.shape}")
# ============================================
# 3. ๋ชจ๋ธ ๊ตฌ์ฑ
# ============================================
model = Sequential([
Embedding(VOCAB_SIZE, EMBEDDING_DIM, input_length=MAX_LENGTH),
Conv1D(128, 5, activation='relu'),
GlobalMaxPooling1D(),
Dense(64, activation='relu'),
Dropout(0.3),
Dense(1, activation='sigmoid')
])
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
model.summary()
# ============================================
# 4. ์ฝ๋ฐฑ ์ค์
# ============================================
callbacks = [
EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True),
ModelCheckpoint('best_model.keras', monitor='val_accuracy', save_best_only=True)
]
# ============================================
# 5. ๋ชจ๋ธ ํ๋ จ
# ============================================
history = model.fit(
x_train, y_train,
epochs=EPOCHS,
batch_size=BATCH_SIZE,
validation_data=(x_val, y_val),
callbacks=callbacks,
verbose=1
)
# ============================================
# 6. ๋ชจ๋ธ ํ๊ฐ
# ============================================
test_loss, test_accuracy = model.evaluate(test_data_padded, test_labels)
print(f"\nโ
ํ
์คํธ ์ ํ๋: {test_accuracy*100:.2f}%")
# ============================================
# 7. ํ์ต ๊ณก์ ์๊ฐํ
# ============================================
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].plot(history.history['accuracy'], label='ํ๋ จ', color='#7eb8d4')
axes[0].plot(history.history['val_accuracy'], label='๊ฒ์ฆ', color='#f0a060')
axes[0].set_title('์ ํ๋')
axes[0].legend()
axes[1].plot(history.history['loss'], label='ํ๋ จ', color='#7eb8d4')
axes[1].plot(history.history['val_loss'], label='๊ฒ์ฆ', color='#f0a060')
axes[1].set_title('์์ค')
axes[1].legend()
plt.tight_layout()
plt.show()
# ============================================
# 8. ์ค์ ์์ธก
# ============================================
word_index = imdb.get_word_index()
def predict_sentiment(text):
words = text.lower().split()
encoded = [word_index.get(w, 2) + 3 for w in words]
padded = pad_sequences([encoded], maxlen=MAX_LENGTH, padding='post')
score = model.predict(padded, verbose=0)[0][0]
label = "๐ ๊ธ์ " if score > 0.5 else "๐ ๋ถ์ "
conf = score if score > 0.5 else 1 - score
print(f"[{label}] ํ์ ๋: {conf*100:.1f}% | {text[:60]}")
predict_sentiment("This movie was absolutely brilliant and amazing!")
predict_sentiment("Terrible film, complete waste of time and money.")
์, ์ฌ๊ธฐ๊น์ง ๋ฐ๋ผ์๋ค๋ฉด ์ง์ง ๋๋จํด! ๐
์ค๋ ์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ด ๊ฑธ ์ ๋ฆฌํด๋ณด์.
๐น IMDB ๋ฐ์ดํฐ์ ๋ก๋ ๋ฐ ํ์
๐น ํ ์คํธ ์ ์ฒ๋ฆฌ (ํ ํฐํ, ํจ๋ฉ)
๐น ์ธ ๊ฐ์ง ๋ชจ๋ธ ๊ตฌ์กฐ (Dense, LSTM, Conv1D)
๐น ๋ชจ๋ธ ์ปดํ์ผ, ํ๋ จ, ์ฝ๋ฐฑ ์ค์
๐น ๋ชจ๋ธ ํ๊ฐ ๋ฐ ์ฑ๋ฅ ์งํ ํด์
๐น ์ค์ ํ ์คํธ๋ก ์์ธกํ๊ธฐ
๐น ์ฑ๋ฅ ๊ฐ์ ๋ฐฉ๋ฒ (GloVe, BERT ๋ฑ)
๐น ๋ชจ๋ธ ์ ์ฅ ๋ฐ API ๋ฐฐํฌ
๊ฐ์ฑ ๋ถ์
๋ถ๋ฅ
Transformers
๋ชจ๋ฐ์ผ ๋ฐฐํฌ
ํ
์คํธ ๋ถ๋ฅ๋ NLP(์์ฐ์ด ์ฒ๋ฆฌ)์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํ์คํฌ์ผ.
์ด๊ฑธ ๋ง์คํฐํ๋ฉด ๊ฐ์ฑ ๋ถ์, ์คํธ ํํฐ, ๋ด์ค ๋ถ๋ฅ, ์ฑ๋ด ์๋ ๋ถ๋ฅ ๋ฑ
๋ค์ํ ์ค์ ํ๋ก์ ํธ์ ๋ฐ๋ก ์ ์ฉํ ์ ์์ด! ๐ช
| ์ฃผ์ | ์ถ์ฒ ๋ฆฌ์์ค |
|---|---|
| TensorFlow ๊ณต์ ํํ ๋ฆฌ์ผ | tensorflow.org/tutorials |
| Keras ๋ฌธ์ | keras.io |
| HuggingFace ํธ๋์คํฌ๋จธ | huggingface.co/docs |
| ํ๊ตญ์ด NLP (KoNLPy) | konlpy.org |
| ๋ฅ๋ฌ๋ ๋ ผ๋ฌธ ์ฝ๊ธฐ | arxiv.org/cs.CL |
๋ฅ๋ฌ๋์ ์ฒ์์ ์ด๋ ต๊ฒ ๋๊ปด์ง์ง๋ง, ์ง์ ์ฝ๋๋ฅผ ์ง๊ณ ์คํํด๋ณด๋ฉด์ ๋ฐฐ์ฐ๋ ๊ฒ ์ ์ผ ๋นจ๋ผ!
์ค๋ ๋ฐฐ์ด ์ฝ๋๋ฅผ ์ง์ ๋๋ ค๋ณด๊ณ , ํ๋ผ๋ฏธํฐ๋ ๋ฐ๊ฟ๋ณด๊ณ , ๋ค๋ฅธ ๋ฐ์ดํฐ์
์๋ ์ ์ฉํด๋ด.
๊ทธ๋ฌ๋ค ๋ณด๋ฉด ์ด๋์ AI ๊ฐ๋ฐ์๊ฐ ๋์ด์์ ๊ฑฐ์ผ! ๐
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.