이미지 로딩 중...
AI Generated
2025. 11. 24. · 4 Views
LSTM으로 텍스트 생성 및 감정 분석 실전 가이드
LSTM 신경망을 활용한 텍스트 생성과 감정 분석의 기초부터 실전까지. 자연어 처리의 핵심 기술을 쉽고 친근하게 배워보세요.
목차
- LSTM 기본 개념
- 텍스트 데이터 전처리
- LSTM 모델 구조 설계
- 텍스트 생성 모델 학습
- 텍스트 자동 생성 구현
- 감정 분석 데이터셋 준비
- 감정 분석 LSTM 모델
- 감정 분석 모델 학습 및 평가
1. LSTM 기본 개념
시작하며
여러분이 책을 읽을 때를 생각해보세요. 앞부분에 나온 중요한 인물이나 사건을 기억하면서 뒷부분을 이해하죠?
만약 앞부분을 잊어버린다면 이야기의 맥락을 놓치게 됩니다. 컴퓨터도 마찬가지입니다.
문장을 이해하거나 만들 때 앞에 나온 단어들을 기억해야 합니다. "날씨가 좋아서 기분이"라는 문장 다음에 무엇이 올까요?
앞부분을 기억해야 "좋다"라는 단어를 예측할 수 있습니다. 바로 이럴 때 필요한 것이 LSTM(Long Short-Term Memory)입니다.
LSTM은 중요한 정보는 오래 기억하고, 불필요한 정보는 잊어버리는 똑똑한 기억 장치를 가진 신경망입니다.
개요
간단히 말해서, LSTM은 순차적인 데이터에서 중요한 패턴을 기억하고 학습하는 인공 신경망입니다. 일반적인 신경망은 데이터를 독립적으로 처리합니다.
하지만 텍스트, 시계열 데이터, 음성 같은 순차 데이터는 순서가 중요하죠. LSTM은 이전 정보를 "기억"하면서 현재 정보를 처리할 수 있어서, 문맥을 이해하거나 시간에 따른 패턴을 파악하는 데 매우 유용합니다.
기존 RNN(Recurrent Neural Network)은 먼 과거의 정보를 잊어버리는 문제가 있었습니다. LSTM은 "게이트"라는 특별한 구조를 통해 이 문제를 해결했습니다.
LSTM의 핵심은 세 가지 게이트입니다: 잊기 게이트(어떤 정보를 잊을지), 입력 게이트(어떤 새 정보를 저장할지), 출력 게이트(어떤 정보를 출력할지). 이 게이트들이 마치 교통 신호등처럼 정보의 흐름을 조절합니다.
코드 예제
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Embedding
# LSTM 모델 기본 구조
model = Sequential([
# 임베딩 레이어: 단어를 벡터로 변환 (vocab_size=1000, 벡터 차원=128)
Embedding(input_dim=1000, output_dim=128, input_length=10),
# LSTM 레이어: 64개의 메모리 셀로 순차 패턴 학습
# return_sequences=True: 다음 LSTM 레이어를 위해 전체 시퀀스 반환
LSTM(64, return_sequences=True),
# 두 번째 LSTM 레이어: 더 복잡한 패턴 학습
LSTM(32),
# 출력 레이어: 최종 예측값 생성
Dense(1, activation='sigmoid')
])
설명
LSTM이 하는 일은 마치 여러분이 드라마를 보면서 중요한 장면은 기억하고 광고는 잊어버리는 것과 비슷합니다. 첫 번째로, Embedding 레이어는 단어를 컴퓨터가 이해할 수 있는 숫자 벡터로 변환합니다.
"사과"라는 단어를 [0.2, 0.5, 0.1, ...] 같은 128개의 숫자로 바꿔주죠. 이렇게 하면 비슷한 의미의 단어들이 비슷한 숫자 패턴을 갖게 됩니다.
그 다음으로, 첫 번째 LSTM 레이어가 64개의 메모리 셀을 사용해서 순차적인 패턴을 학습합니다. 각 메모리 셀은 특정 패턴을 기억하는 역할을 하죠.
return_sequences=True는 각 시간 단계마다 출력을 생성해서 다음 레이어에 전달합니다. 두 번째 LSTM 레이어는 32개의 셀로 더 추상적이고 복잡한 패턴을 학습합니다.
마지막으로 Dense 레이어가 최종 예측을 만들어냅니다. sigmoid 활성화 함수는 0과 1 사이의 값을 출력해서 확률처럼 해석할 수 있게 해줍니다.
여러분이 이 코드를 사용하면 문장의 다음 단어를 예측하거나, 문장의 감정을 분석하거나, 새로운 텍스트를 생성하는 다양한 작업을 수행할 수 있습니다. LSTM은 문맥을 이해하기 때문에 단순한 단어 빈도 분석보다 훨씬 정교한 결과를 만들어냅니다.
실전 팁
💡 LSTM 레이어를 너무 많이 쌓으면 학습이 느려지고 과적합될 수 있습니다. 대부분의 경우 1-3개 레이어면 충분합니다.
💡 return_sequences 매개변수를 주의하세요. 다음에 LSTM 레이어가 있으면 True, 마지막 LSTM이면 False로 설정해야 합니다.
💡 메모리 셀 개수(예: 64, 32)는 데이터의 복잡도에 따라 조절하세요. 간단한 작업은 32개, 복잡한 작업은 128-256개가 적당합니다.
💡 학습이 느리다면 GPU를 사용하세요. LSTM은 계산량이 많아서 CPU로는 시간이 오래 걸립니다.
💡 Bidirectional LSTM을 사용하면 앞뒤 문맥을 모두 고려할 수 있어 감정 분석 같은 작업에서 성능이 향상됩니다.
2. 텍스트 데이터 전처리
시작하며
여러분이 외국인 친구에게 한국 음식을 설명한다고 상상해보세요. "김치"라는 단어를 그대로 말해도 친구는 이해하지 못할 겁니다.
"발효된 양배추"처럼 친구가 이해할 수 있는 말로 바꿔야 하죠. 컴퓨터도 마찬가지입니다.
"안녕하세요"라는 문장을 그대로는 이해하지 못합니다. 컴퓨터는 오직 숫자만 이해하거든요.
그래서 텍스트를 숫자로 바꾸는 과정이 필요합니다. 바로 이 과정이 텍스트 전처리입니다.
텍스트를 정제하고, 토큰으로 나누고, 숫자 시퀀스로 변환하는 모든 과정을 포함합니다.
개요
간단히 말해서, 텍스트 전처리는 원본 텍스트를 신경망이 학습할 수 있는 숫자 형태로 변환하는 과정입니다. 실제 텍스트 데이터는 매우 지저분합니다.
특수문자, 이모지, 불필요한 공백, 대소문자 혼용 등이 섞여 있죠. 이런 노이즈를 제거하고 일관된 형태로 만드는 것이 첫 단계입니다.
예를 들어, "HELLO!!!"와 "hello"를 같은 단어로 인식하게 만들어야 합니다. 전통적인 방법에서는 단어 사전을 수작업으로 만들었다면, 이제는 Tokenizer를 사용해서 자동으로 단어를 숫자로 매핑할 수 있습니다.
전처리의 핵심 단계는 토큰화(문장을 단어로 분리), 정규화(대소문자 통일, 특수문자 제거), 인코딩(단어를 숫자로 변환), 패딩(문장 길이를 동일하게 맞춤)입니다. 이 단계들이 데이터의 품질을 결정하고, 결국 모델 성능에 직접적인 영향을 미칩니다.
코드 예제
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
# 샘플 텍스트 데이터
texts = [
"오늘 날씨가 정말 좋아요",
"기분이 좋아요 날씨 때문에",
"날씨가 안 좋아서 우울해요"
]
# 토크나이저 생성 및 학습 (상위 100개 단어만 사용)
tokenizer = Tokenizer(num_words=100, oov_token="<OOV>")
tokenizer.fit_on_texts(texts)
# 텍스트를 숫자 시퀀스로 변환
sequences = tokenizer.texts_to_sequences(texts)
# 모든 시퀀스를 동일한 길이로 맞춤 (최대 길이 10, 부족하면 0으로 채움)
padded = pad_sequences(sequences, maxlen=10, padding='post')
print(f"원본: {texts[0]}")
print(f"시퀀스: {sequences[0]}")
print(f"패딩: {padded[0]}")
설명
이것이 하는 일은 마치 도서관에서 책마다 고유번호를 부여하는 것과 비슷합니다. "해리포터" 책에 123번, "반지의 제왕"에 456번을 부여하듯이, 각 단어에 숫자를 할당합니다.
첫 번째로, Tokenizer를 만들고 fit_on_texts로 학습시킵니다. 이 과정에서 텍스트에 등장하는 모든 단어를 찾아서 빈도순으로 번호를 매깁니다.
num_words=100은 가장 자주 나오는 100개 단어만 사용하겠다는 의미이고, oov_token="<OOV>"는 사전에 없는 단어를 만났을 때 특별한 토큰으로 대체하겠다는 뜻입니다. 그 다음으로, texts_to_sequences가 실제 변환 작업을 수행합니다.
"날씨"라는 단어가 사전에서 2번이면, "날씨"를 만날 때마다 2로 바꿔줍니다. 결과적으로 "오늘 날씨가 좋아요"는 [5, 2, 1, 3] 같은 숫자 리스트가 됩니다.
마지막으로 pad_sequences가 모든 문장의 길이를 동일하게 맞춥니다. 신경망은 입력 크기가 일정해야 하기 때문이죠.
짧은 문장은 0으로 채우고(패딩), 긴 문장은 잘라냅니다. padding='post'는 뒤쪽에 0을 채우라는 의미입니다.
여러분이 이 전처리 과정을 거치면 불규칙한 텍스트 데이터를 일정한 형태의 숫자 배열로 만들 수 있습니다. 이렇게 만들어진 데이터는 LSTM 모델이 바로 학습할 수 있는 형태가 되죠.
전처리 품질이 좋을수록 모델의 성능도 향상되고, 이상한 패턴을 학습하는 것을 방지할 수 있습니다.
실전 팁
💡 num_words는 너무 작으면 중요한 단어를 놓치고, 너무 크면 노이즈가 많아집니다. 실험을 통해 적절한 값을 찾으세요(보통 5000-20000).
💡 oov_token을 반드시 설정하세요. 테스트 데이터에 학습 때 보지 못한 단어가 나타날 수 있습니다.
💡 padding='pre'와 'post' 중 선택할 때, LSTM에서는 보통 'post'가 더 좋습니다. 실제 내용이 앞쪽에 몰려있기 때문이죠.
💡 maxlen은 데이터의 90-95 백분위수 길이로 설정하면 좋습니다. 대부분의 문장을 보존하면서 너무 긴 이상치는 제거할 수 있습니다.
💡 한국어는 형태소 분석기(KoNLPy, mecab)를 사용하면 더 정확한 토큰화가 가능합니다. "좋아요"를 "좋다 + 아요"로 분리할 수 있죠.
3. LSTM 모델 구조 설계
시작하며
여러분이 레고로 집을 짓는다고 상상해보세요. 기초 블록, 벽 블록, 지붕 블록을 순서대로 쌓아야 튼튼한 집이 만들어집니다.
순서를 바꾸거나 필요한 블록을 빼먹으면 집이 무너지겠죠? 딥러닝 모델도 마찬가지입니다.
Embedding 레이어, LSTM 레이어, Dense 레이어를 올바른 순서로 쌓아야 제대로 작동하는 모델이 만들어집니다. 각 레이어는 특정한 역할을 담당하고, 함께 협력해서 최종 목표를 달성합니다.
바로 이것이 모델 구조 설계입니다. 텍스트 생성 작업에 맞는 레이어들을 선택하고, 적절한 크기와 매개변수를 설정하는 과정입니다.
개요
간단히 말해서, LSTM 모델 구조 설계는 입력 텍스트에서 다음 단어를 예측할 수 있도록 여러 레이어를 조합하는 과정입니다. 텍스트 생성 모델은 크게 세 부분으로 구성됩니다.
첫째, 단어를 벡터로 변환하는 Embedding 레이어. 둘째, 순차 패턴을 학습하는 LSTM 레이어들.
셋째, 최종 예측을 만드는 Dense 레이어. 각 부분이 제대로 연결되어야 정보가 흐르고 학습이 일어납니다.
기존에는 규칙 기반으로 텍스트를 생성했다면, 이제는 LSTM이 데이터에서 패턴을 자동으로 학습해서 자연스러운 문장을 만들어낼 수 있습니다. 핵심은 각 레이어의 크기를 적절히 설정하는 것입니다.
너무 작으면 복잡한 패턴을 학습하지 못하고, 너무 크면 과적합되거나 학습이 느려집니다. Dropout을 추가하면 과적합을 방지할 수 있고, 여러 LSTM 레이어를 쌓으면 더 추상적인 패턴을 학습할 수 있습니다.
코드 예제
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout
# 하이퍼파라미터 설정
vocab_size = 5000 # 어휘 사전 크기
embedding_dim = 128 # 단어 벡터 차원
max_length = 20 # 최대 시퀀스 길이
# 텍스트 생성을 위한 LSTM 모델 구조
model = Sequential([
# 1. 단어를 128차원 벡터로 변환
Embedding(vocab_size, embedding_dim, input_length=max_length-1),
# 2. 첫 번째 LSTM: 150개 셀로 순차 패턴 학습
LSTM(150, return_sequences=True),
Dropout(0.2), # 과적합 방지를 위해 20% 뉴런 무작위 제거
# 3. 두 번째 LSTM: 더 복잡한 패턴 학습
LSTM(100),
# 4. 최종 출력: vocab_size 크기로 다음 단어 확률 예측
Dense(vocab_size, activation='softmax')
])
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
print(model.summary())
설명
이것이 하는 일은 마치 작곡가가 이전 음표들을 듣고 다음 음표를 예측하는 것과 비슷합니다. 모델은 이전 단어들을 보고 다음에 올 단어를 추측합니다.
첫 번째로, Embedding 레이어가 각 단어를 128개의 숫자로 이루어진 벡터로 변환합니다. "사랑"이라는 단어와 "좋아"라는 단어가 비슷한 문맥에서 사용되면, 벡터도 비슷한 값을 갖게 됩니다.
input_length=max_length-1인 이유는 입력 시퀀스에서 마지막 단어를 예측 대상으로 사용하기 때문입니다. 그 다음으로, 첫 번째 LSTM 레이어가 150개의 메모리 셀을 사용해서 단어 순서의 패턴을 학습합니다.
return_sequences=True로 설정해서 각 시간 단계의 출력을 모두 다음 레이어로 전달합니다. Dropout(0.2)은 학습 중에 랜덤하게 20%의 연결을 끊어서 모델이 특정 패턴에 과도하게 의존하지 않도록 합니다.
두 번째 LSTM 레이어는 100개의 셀로 더 높은 수준의 패턴을 학습합니다. 예를 들어, 첫 번째 레이어가 "형용사 + 명사" 패턴을 학습한다면, 두 번째 레이어는 "주어 + 서술어" 같은 문장 구조를 학습할 수 있습니다.
마지막 Dense 레이어는 vocab_size 크기의 출력을 만들어서 각 단어가 다음에 올 확률을 계산합니다. softmax 활성화 함수는 모든 확률의 합이 1이 되도록 만들어줍니다.
여러분이 이 모델을 사용하면 "오늘 날씨가"라는 입력에 대해 "좋다"가 70%, "나쁘다"가 20%, "흐리다"가 10% 같은 확률을 얻을 수 있습니다. 이 확률을 바탕으로 가장 그럴듯한 다음 단어를 선택하거나, 랜덤하게 샘플링해서 다양한 문장을 생성할 수 있습니다.
두 개의 LSTM 레이어를 쌓았기 때문에 단순한 단어 조합이 아닌 문맥을 고려한 자연스러운 문장을 만들어냅니다.
실전 팁
💡 embedding_dim은 보통 vocab_size의 제곱근 정도로 설정합니다. vocab_size가 10000이면 100-200 정도가 적당합니다.
💡 LSTM 셀 개수는 점진적으로 줄이는 것이 좋습니다(예: 150 → 100). 이렇게 하면 모델이 점점 더 추상적인 표현을 학습합니다.
💡 Dropout 비율은 0.2-0.5 사이가 일반적입니다. 과적합이 심하면 높이고, 과소적합이면 낮추세요.
💡 categorical_crossentropy는 다중 클래스 분류에 사용되는 손실 함수입니다. 각 단어를 하나의 클래스로 보는 것이죠.
💡 모델이 너무 크면 학습 시간이 오래 걸립니다. 처음에는 작은 모델로 시작해서 점진적으로 키우는 것이 효율적입니다.
4. 텍스트 생성 모델 학습
시작하며
여러분이 피아노를 배운다고 상상해보세요. 처음에는 틀린 음을 많이 치지만, 선생님이 "이 음이 아니라 저 음을 쳐야 해"라고 계속 알려주면 점점 정확해집니다.
수천 번 연습하면 자연스럽게 연주할 수 있게 되죠. LSTM 모델도 똑같은 방식으로 배웁니다.
처음에는 이상한 단어를 예측하지만, 정답과 비교하면서 예측을 조금씩 개선합니다. "날씨가 좋은" 다음에 "사과"가 아니라 "날"이 와야 한다는 것을 수천 번의 예시를 통해 학습합니다.
바로 이것이 모델 학습입니다. 입력 시퀀스와 정답 단어 쌍을 반복적으로 보여주면서 모델이 올바른 패턴을 찾도록 만드는 과정입니다.
개요
간단히 말해서, 텍스트 생성 모델 학습은 대량의 텍스트 데이터로부터 단어 순서의 패턴을 반복적으로 학습하는 과정입니다. 학습 데이터는 특별한 방식으로 준비됩니다.
하나의 문장에서 여러 개의 학습 샘플을 만들어냅니다. 예를 들어, "오늘 날씨가 정말 좋다"라는 문장에서 "오늘 → 날씨가", "오늘 날씨가 → 정말", "오늘 날씨가 정말 → 좋다" 같은 입력-출력 쌍을 만듭니다.
이렇게 하면 적은 문장으로도 많은 학습 데이터를 확보할 수 있습니다. 기존에는 n-gram 같은 통계적 방법을 사용했다면, 이제는 LSTM이 더 긴 문맥을 고려해서 자연스러운 문장을 생성할 수 있습니다.
학습의 핵심은 손실 함수(loss)를 최소화하는 것입니다. 모델의 예측과 실제 정답 사이의 차이를 계산하고, 역전파 알고리즘으로 가중치를 조금씩 조정합니다.
이 과정을 수십, 수백 번 반복(epoch)하면 모델이 점점 정확해집니다. 조기 종료(early stopping)를 사용하면 과적합을 방지할 수 있습니다.
코드 예제
import numpy as np
from tensorflow.keras.utils import to_categorical
# 샘플 텍스트 데이터
text = "오늘 날씨가 정말 좋다 날씨가 좋으면 기분이 좋다"
# 시퀀스 생성 함수
def create_sequences(text, tokenizer, max_length):
sequences = []
for line in text.split('.'):
token_list = tokenizer.texts_to_sequences([line])[0]
# 누적 시퀀스 생성: [1,2], [1,2,3], [1,2,3,4] ...
for i in range(2, len(token_list)+1):
seq = token_list[:i]
sequences.append(seq)
return sequences
# 학습 데이터 준비
sequences = create_sequences(text, tokenizer, max_length)
sequences = pad_sequences(sequences, maxlen=max_length, padding='pre')
# 입력(X)과 출력(y) 분리
X = sequences[:, :-1] # 마지막 단어 제외
y = sequences[:, -1] # 마지막 단어만
# 출력을 원-핫 인코딩으로 변환
y = to_categorical(y, num_classes=vocab_size)
# 모델 학습
history = model.fit(X, y, epochs=100, batch_size=32, validation_split=0.2, verbose=1)
설명
이것이 하는 일은 마치 선생님이 학생에게 빈칸 채우기 문제를 반복해서 풀게 하는 것과 비슷합니다. "오늘 날씨가 ___" 같은 문제를 수천 개 풀면서 패턴을 익히는 거죠.
첫 번째로, create_sequences 함수가 하나의 문장을 여러 학습 샘플로 변환합니다. "오늘 날씨가 좋다"라는 문장에서 [오늘, 날씨가], [오늘, 날씨가, 좋다] 같은 점진적으로 길어지는 시퀀스들을 만듭니다.
이렇게 하면 모델이 짧은 문맥부터 긴 문맥까지 다양한 경우를 학습할 수 있습니다. 그 다음으로, pad_sequences로 모든 시퀀스를 같은 길이로 맞춥니다.
그리고 각 시퀀스의 마지막 단어를 정답(y)으로, 나머지를 입력(X)으로 분리합니다. 예를 들어, [1, 2, 3, 4]라는 시퀀스에서 [1, 2, 3]이 입력이 되고, 4가 정답이 됩니다.
to_categorical은 정답을 원-핫 인코딩으로 변환합니다. 단어 4가 정답이면 [0, 0, 0, 1, 0, 0, ...] 같은 벡터로 만들어서 모델이 확률 분포를 학습하기 쉽게 만듭니다.
마지막으로 model.fit으로 실제 학습을 시작합니다. epochs=100은 전체 데이터를 100번 반복 학습하겠다는 의미이고, batch_size=32는 한 번에 32개 샘플씩 묶어서 처리한다는 뜻입니다.
validation_split=0.2는 데이터의 20%를 검증용으로 분리해서 과적합을 모니터링합니다. 여러분이 이 코드를 실행하면 각 epoch마다 손실(loss)과 정확도(accuracy)가 출력됩니다.
손실이 점점 줄어들고 정확도가 올라가면 모델이 잘 학습되고 있다는 신호입니다. 검증 손실이 증가하기 시작하면 과적합의 징조이니 학습을 멈춰야 합니다.
학습이 완료되면 모델은 주어진 단어들의 다음에 어떤 단어가 올지 예측할 수 있게 됩니다.
실전 팁
💡 epochs는 너무 많으면 과적합됩니다. EarlyStopping 콜백을 사용해서 검증 손실이 개선되지 않으면 자동으로 멈추게 하세요.
💡 batch_size는 GPU 메모리에 따라 조절하세요. 크면 학습이 빠르지만 메모리를 많이 사용합니다. 32-128 사이가 일반적입니다.
💡 validation_split 대신 별도의 검증 데이터를 준비하면 더 정확한 평가가 가능합니다.
💡 학습 중간에 모델을 저장하려면 ModelCheckpoint 콜백을 사용하세요. 최고 성능 모델을 자동으로 저장할 수 있습니다.
💡 데이터가 적으면 data augmentation을 고려하세요. 동의어 치환이나 역번역으로 데이터를 늘릴 수 있습니다.
5. 텍스트 자동 생성 구현
시작하며
여러분이 시인이 되어 시를 쓴다고 상상해보세요. "푸른 하늘"이라는 시작 구절을 정하면, 머릿속으로 어울리는 다음 단어를 떠올립니다.
"아래", "구름", "별" 중에서 가장 자연스러운 단어를 선택하죠. 그 다음 단어도 같은 방식으로 선택하면서 시를 완성합니다.
학습된 LSTM 모델도 정확히 같은 방식으로 텍스트를 생성합니다. 시작 단어를 주면 다음 단어를 예측하고, 그 단어를 다시 입력으로 사용해서 또 다음 단어를 예측합니다.
이 과정을 반복하면 완전한 문장이나 문단이 만들어집니다. 바로 이것이 텍스트 자동 생성입니다.
학습된 패턴을 활용해서 새로운 문장을 만드는 과정입니다.
개요
간단히 말해서, 텍스트 자동 생성은 학습된 모델에 시드(seed) 텍스트를 입력하고, 반복적으로 다음 단어를 예측해서 이어 붙이는 과정입니다. 생성 과정은 시작 단어 몇 개만 있으면 됩니다.
"오늘 날씨가"라는 시드를 주면 모델이 "좋다"를 예측하고, "오늘 날씨가 좋다"가 다시 입력이 되어 다음 단어 "밖에"를 예측하는 식입니다. 원하는 길이만큼 이 과정을 반복하면 긴 문장을 생성할 수 있습니다.
기존 템플릿 기반 생성과 달리, LSTM은 학습한 데이터의 스타일과 패턴을 반영한 자연스러운 문장을 만들어냅니다. 핵심은 예측 확률을 어떻게 사용할지 결정하는 것입니다.
가장 높은 확률의 단어만 선택하면(greedy) 안전하지만 반복적인 문장이 됩니다. 확률 분포에서 샘플링하면 더 다양하고 창의적인 결과를 얻을 수 있습니다.
온도(temperature) 매개변수로 창의성을 조절할 수도 있습니다.
코드 예제
import numpy as np
def generate_text(seed_text, next_words, model, tokenizer, max_length):
"""
시드 텍스트로부터 새로운 텍스트를 생성하는 함수
"""
for _ in range(next_words):
# 시드 텍스트를 숫자 시퀀스로 변환
token_list = tokenizer.texts_to_sequences([seed_text])[0]
# 패딩 적용
token_list = pad_sequences([token_list], maxlen=max_length-1, padding='pre')
# 다음 단어 예측 (각 단어의 확률 분포 반환)
predicted_probs = model.predict(token_list, verbose=0)
# 가장 높은 확률의 단어 선택
predicted_word_index = np.argmax(predicted_probs, axis=-1)[0]
# 인덱스를 실제 단어로 변환
predicted_word = ""
for word, index in tokenizer.word_index.items():
if index == predicted_word_index:
predicted_word = word
break
# 시드 텍스트에 예측 단어 추가
seed_text += " " + predicted_word
return seed_text
# 사용 예시
seed = "오늘 날씨가"
generated = generate_text(seed, 10, model, tokenizer, max_length)
print(generated)
설명
이것이 하는 일은 마치 자동 완성 기능이 여러 번 연속으로 작동하는 것과 비슷합니다. 여러분이 문자를 쓸 때 "안녕"을 입력하면 "하세요"를 제안하는 것처럼, 계속 다음 단어를 추천받는 거죠.
첫 번째로, 시드 텍스트를 토크나이저로 숫자 시퀀스로 변환합니다. "오늘 날씨가"가 [5, 2, 1]로 바뀌고, 패딩을 적용해서 모델 입력 크기에 맞춥니다.
이 과정은 학습할 때와 정확히 동일해야 합니다. 그 다음으로, model.predict가 다음 단어의 확률 분포를 계산합니다.
예를 들어, "좋다" 70%, "나쁘다" 20%, "흐리다" 10% 같은 결과가 나옵니다. np.argmax는 이 중에서 가장 높은 확률을 가진 단어의 인덱스를 선택합니다.
선택된 인덱스를 실제 단어로 변환하기 위해 tokenizer.word_index 사전을 역으로 검색합니다. 인덱스 3이 "좋다"에 해당하면 "좋다"를 찾아냅니다.
이 단어를 시드 텍스트 뒤에 붙이고, 전체 과정을 next_words 횟수만큼 반복합니다. 여러분이 이 코드를 실행하면 "오늘 날씨가"에서 시작해서 "오늘 날씨가 정말 좋다 기분이 좋아진다 밖에 나가고 싶다" 같은 완전한 문장이 생성됩니다.
모델이 학습한 데이터의 스타일과 패턴을 반영하기 때문에, 시 데이터로 학습했다면 시 같은 문장이, 뉴스 데이터로 학습했다면 뉴스 같은 문장이 나옵니다. 생성된 텍스트의 품질은 학습 데이터의 양과 질, 그리고 모델의 크기에 따라 결정됩니다.
실전 팁
💡 greedy 방식 대신 확률적 샘플링을 사용하면 더 다양한 결과를 얻을 수 있습니다. np.random.choice(predicted_probs)를 활용하세요.
💡 온도(temperature) 매개변수를 추가하면 창의성을 조절할 수 있습니다. 높은 온도는 더 창의적(무작위)하고, 낮은 온도는 더 보수적입니다.
💡 생성 중에 반복되는 단어가 나타나면 penalty를 적용하거나 beam search를 사용하세요.
💡 시드 텍스트가 학습 데이터와 비슷한 스타일이면 더 좋은 결과가 나옵니다. 완전히 다른 주제는 이상한 결과를 만들 수 있습니다.
💡 길이를 너무 길게 설정하면 문맥이 흐려지고 의미 없는 문장이 나올 수 있습니다. 20-50 단어 정도가 적당합니다.
6. 감정 분석 데이터셋 준비
시작하며
여러분이 고객 리뷰를 읽는 직원이라고 상상해보세요. "이 제품 정말 좋아요!"는 긍정적이고, "실망했어요"는 부정적이라는 것을 쉽게 알 수 있죠.
하지만 하루에 수천 개의 리뷰를 읽는다면? 사람이 하기엔 너무 힘든 작업입니다.
컴퓨터가 이 작업을 대신할 수 있다면 얼마나 좋을까요? 하지만 컴퓨터는 "좋아요"가 긍정인지 부정인지 모릅니다.
그래서 우리가 예시를 보여주며 가르쳐야 합니다. 바로 이것이 감정 분석 데이터셋 준비입니다.
문장과 그에 해당하는 감정 레이블(긍정/부정)을 쌍으로 만들어 모델이 학습할 수 있게 준비하는 과정입니다.
개요
간단히 말해서, 감정 분석 데이터셋 준비는 텍스트와 감정 레이블을 수집하고, 전처리하고, 학습에 적합한 형태로 변환하는 과정입니다. 감정 분석은 분류(classification) 문제입니다.
텍스트가 주어졌을 때 긍정, 부정, 중립 같은 카테고리 중 하나를 선택하는 것이죠. 이를 위해서는 레이블이 달린 데이터가 필요합니다.
영화 리뷰, 상품 리뷰, SNS 댓글 등 다양한 소스에서 데이터를 수집할 수 있습니다. 기존 키워드 기반 방법("좋다", "나쁘다" 같은 단어 찾기)과 달리, LSTM은 문맥을 고려해서 "좋지 않다"가 부정임을 이해할 수 있습니다.
준비 과정의 핵심은 균형 잡힌 데이터셋을 만드는 것입니다. 긍정 리뷰가 90%, 부정이 10%면 모델이 편향됩니다.
각 클래스의 비율을 비슷하게 맞춰야 하고, 데이터를 학습/검증/테스트 세트로 나눠야 합니다. 텍스트 전처리(불용어 제거, 정규화)도 중요합니다.
코드 예제
import pandas as pd
from sklearn.model_selection import train_test_split
# 샘플 데이터 생성 (실제로는 파일에서 로드)
data = {
'review': [
'이 영화 정말 재미있어요 강추합니다',
'시간 낭비였어요 별로입니다',
'배우들의 연기가 훌륭했습니다',
'스토리가 지루하고 졸렸어요',
'최고의 영화 다시 보고 싶어요',
'돈이 아깝습니다 비추천',
],
'sentiment': [1, 0, 1, 0, 1, 0] # 1=긍정, 0=부정
}
df = pd.DataFrame(data)
# 데이터 분할: 학습 80%, 테스트 20%
X_train, X_test, y_train, y_test = train_test_split(
df['review'], df['sentiment'], test_size=0.2, random_state=42, stratify=df['sentiment']
)
# 토크나이저로 텍스트 전처리
tokenizer = Tokenizer(num_words=5000, oov_token="<OOV>")
tokenizer.fit_on_texts(X_train)
# 시퀀스 변환 및 패딩
X_train_seq = tokenizer.texts_to_sequences(X_train)
X_test_seq = tokenizer.texts_to_sequences(X_test)
max_length = 20
X_train_pad = pad_sequences(X_train_seq, maxlen=max_length, padding='post')
X_test_pad = pad_sequences(X_test_seq, maxlen=max_length, padding='post')
print(f"학습 데이터: {len(X_train_pad)}, 테스트 데이터: {len(X_test_pad)}")
설명
이것이 하는 일은 마치 시험 문제집을 만드는 것과 비슷합니다. 문제와 정답을 쌍으로 만들고, 연습용과 실전용으로 나누는 거죠.
첫 번째로, pandas DataFrame에 텍스트와 레이블을 저장합니다. 실제 프로젝트에서는 CSV 파일이나 데이터베이스에서 로드하겠지만, 여기서는 간단한 예시로 직접 만들었습니다.
'review' 칼럼에는 리뷰 텍스트가, 'sentiment' 칼럼에는 1(긍정) 또는 0(부정) 레이블이 들어갑니다. 그 다음으로, train_test_split으로 데이터를 학습용과 테스트용으로 분리합니다.
test_size=0.2는 전체의 20%를 테스트용으로 사용한다는 의미입니다. stratify=df['sentiment']는 긍정과 부정의 비율을 학습과 테스트 세트에서 동일하게 유지하라는 뜻이죠.
이렇게 하면 테스트 세트가 전체 데이터를 대표할 수 있습니다. 토크나이저는 학습 데이터로만 학습시켜야 합니다.
테스트 데이터를 사용하면 데이터 누수(data leakage)가 발생해서 평가가 정확하지 않습니다. texts_to_sequences로 텍스트를 숫자로 변환하고, pad_sequences로 길이를 맞춥니다.
여러분이 이 코드를 실행하면 학습에 사용할 준비가 완료된 데이터셋을 얻게 됩니다. X_train_pad는 패딩된 숫자 시퀀스 배열이고, y_train은 각 샘플의 레이블입니다.
이제 이 데이터를 LSTM 모델에 넣어서 학습시킬 수 있습니다. 데이터가 많을수록, 품질이 좋을수록 모델의 성능이 향상됩니다.
실제 프로젝트에서는 수천에서 수만 개의 레이블된 샘플이 필요합니다.
실전 팁
💡 실제 데이터에는 노이즈가 많습니다. HTML 태그, 이모지, URL 등을 제거하는 전처리가 필수입니다.
💡 클래스 불균형이 심하면 SMOTE 같은 오버샘플링이나 class_weight 매개변수를 사용하세요.
💡 stratify 매개변수를 꼭 사용하세요. 안 그러면 테스트 세트에 긍정만 있거나 부정만 있을 수 있습니다.
💡 validation_split 대신 별도의 검증 세트를 만들면 더 정확한 하이퍼파라미터 튜닝이 가능합니다.
💡 한국어 데이터는 형태소 분석(KoNLPy)을 적용하면 성능이 크게 향상됩니다. "좋아요"를 "좋다"로 정규화할 수 있습니다.
7. 감정 분석 LSTM 모델
시작하며
여러분이 친구의 표정과 목소리를 듣고 기분을 파악한다고 상상해보세요. "괜찮아"라는 말도 밝은 톤이면 긍정이지만, 낮은 톤이면 부정일 수 있습니다.
문맥과 뉘앙스를 읽는 능력이 필요하죠. 감정 분석도 마찬가지입니다.
"좋지 않다"는 "좋다"라는 단어를 포함하지만 부정입니다. 단순히 단어를 세는 것이 아니라 순서와 문맥을 이해해야 정확한 감정을 파악할 수 있습니다.
바로 이럴 때 LSTM이 빛을 발합니다. LSTM은 문장의 순서를 기억하면서 전체 맥락을 파악해서 감정을 정확하게 분류할 수 있습니다.
개요
간단히 말해서, 감정 분석 LSTM 모델은 텍스트 시퀀스를 입력받아 긍정 또는 부정의 이진 분류를 수행하는 신경망입니다. 감정 분석 모델의 구조는 텍스트 생성 모델과 비슷하지만 목적이 다릅니다.
텍스트 생성은 다음 단어를 예측하지만, 감정 분석은 전체 문장의 감정을 분류합니다. 따라서 마지막 LSTM 레이어에서 return_sequences=False로 설정해서 최종 출력만 사용합니다.
기존 규칙 기반 방법("좋다" +1점, "나쁘다" -1점)과 달리, LSTM은 "그다지 좋지 않다" 같은 복잡한 표현도 올바르게 처리할 수 있습니다. 핵심은 양방향 LSTM(Bidirectional)을 사용하는 것입니다.
일반 LSTM은 왼쪽에서 오른쪽으로만 읽지만, Bidirectional은 양방향으로 읽어서 전체 문맥을 더 잘 이해합니다. "아주 좋지는 않다"에서 "않다"를 먼저 보면 부정임을 쉽게 파악할 수 있죠.
코드 예제
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout, Bidirectional
# 감정 분석용 LSTM 모델
vocab_size = 5000
embedding_dim = 128
max_length = 20
model = Sequential([
# 1. 단어를 128차원 벡터로 변환
Embedding(vocab_size, embedding_dim, input_length=max_length),
# 2. 양방향 LSTM: 앞뒤 문맥을 모두 고려
# 64셀 x 2방향 = 128차원 출력
Bidirectional(LSTM(64, return_sequences=True)),
Dropout(0.3),
# 3. 두 번째 LSTM: 최종 표현 추출
LSTM(32),
Dropout(0.3),
# 4. 완전 연결 레이어: 추상적 특징 학습
Dense(24, activation='relu'),
# 5. 출력 레이어: 긍정 확률 출력 (0~1)
Dense(1, activation='sigmoid')
])
model.compile(
loss='binary_crossentropy', # 이진 분류 손실 함수
optimizer='adam',
metrics=['accuracy']
)
print(model.summary())
설명
이것이 하는 일은 마치 영화 평론가가 리뷰를 읽고 별점을 매기는 것과 비슷합니다. 전체 내용을 읽고 종합적으로 판단하는 거죠.
첫 번째로, Embedding 레이어가 각 단어를 128차원 벡터로 변환합니다. 비슷한 감정을 가진 단어들("훌륭하다", "멋지다")은 비슷한 벡터 값을 갖게 됩니다.
input_length=max_length로 입력 크기를 고정합니다. 그 다음으로, Bidirectional LSTM이 핵심 역할을 합니다.
일반 LSTM은 "이 영화 좋지 않다"를 왼쪽에서 오른쪽으로만 읽어서 "좋지"까지 읽었을 때 긍정으로 오해할 수 있습니다. 하지만 양방향은 오른쪽에서 왼쪽으로도 읽어서 "않다"를 먼저 파악하고 부정임을 알아냅니다.
64개 셀이 양방향으로 작동해서 총 128차원의 출력을 만듭니다. 두 번째 LSTM 레이어는 return_sequences=False(기본값)로 설정되어 마지막 시간 단계의 출력만 반환합니다.
전체 문장을 읽은 후의 최종 표현이죠. Dropout(0.3)은 30%의 연결을 무작위로 끊어서 과적합을 방지합니다.
Dense(24)는 추가적인 비선형 변환을 수행해서 더 복잡한 패턴을 학습할 수 있게 합니다. relu 활성화 함수는 음수를 0으로 만들어 비선형성을 추가합니다.
마지막 Dense(1)은 하나의 값을 출력하고, sigmoid는 이를 0과 1 사이의 확률로 변환합니다. 0.5보다 크면 긍정, 작으면 부정으로 분류하면 됩니다.
여러분이 이 모델을 사용하면 "이 제품 정말 마음에 들어요"라는 입력에 대해 0.92 같은 높은 확률을 출력해서 강한 긍정임을 알려줍니다. binary_crossentropy 손실 함수는 이진 분류에 최적화되어 있어서 모델이 0 또는 1에 가까운 명확한 예측을 하도록 유도합니다.
Bidirectional LSTM 덕분에 부정어가 뒤에 오는 복잡한 문장도 정확하게 처리할 수 있습니다.
실전 팁
💡 Bidirectional은 메모리와 계산량이 2배 필요하지만, 감정 분석에서는 성능 향상이 크므로 사용할 가치가 있습니다.
💡 Dropout 비율을 0.3-0.5로 설정하면 과적합을 효과적으로 방지할 수 있습니다. 데이터가 적으면 높게, 많으면 낮게 설정하세요.
💡 Dense 레이어를 추가하면 모델 용량이 늘어나지만, 너무 많으면 과적합 위험이 있습니다. 1-2개면 충분합니다.
💡 class_weight 매개변수를 사용하면 불균형 데이터에서도 좋은 성능을 낼 수 있습니다.
💡 GlobalMaxPooling1D나 Attention 레이어를 추가하면 더 중요한 단어에 집중할 수 있어 성능이 향상됩니다.
8. 감정 분석 모델 학습 및 평가
시작하며
여러분이 시험을 준비한다고 상상해보세요. 문제집을 풀고, 틀린 문제를 다시 공부하고, 모의고사로 실력을 확인합니다.
점수가 오르면 제대로 공부한 것이고, 안 오르면 방법을 바꿔야 합니다. 딥러닝 모델도 똑같습니다.
학습 데이터로 패턴을 배우고, 검증 데이터로 성능을 확인하고, 테스트 데이터로 최종 평가를 받습니다. 정확도, 정밀도, 재현율 같은 지표로 모델의 능력을 객관적으로 측정합니다.
바로 이것이 모델 학습 및 평가입니다. 데이터를 학습시키고, 성능을 측정하고, 개선점을 찾는 전체 과정입니다.
개요
간단히 말해서, 모델 학습 및 평가는 준비된 데이터로 모델을 훈련시키고, 다양한 지표로 성능을 측정하고, 결과를 분석하는 과정입니다. 학습 과정은 반복적입니다.
모델이 예측을 하고, 틀린 정도(손실)를 계산하고, 가중치를 조정하는 과정을 수천 번 반복합니다. epoch마다 학습 데이터와 검증 데이터의 성능을 확인하면서 과적합 여부를 모니터링합니다.
기존 머신러닝 모델과 달리, LSTM은 학습 시간이 길지만 문맥을 이해하는 능력이 뛰어나서 더 높은 정확도를 달성할 수 있습니다. 평가의 핵심은 단순 정확도만 보지 않는 것입니다.
긍정 데이터가 90%라면 모든 것을 긍정으로 예측해도 90% 정확도가 나옵니다. 혼동 행렬(confusion matrix), 정밀도(precision), 재현율(recall), F1 점수 같은 다양한 지표를 함께 봐야 합니다.
조기 종료(early stopping)와 학습률 스케줄링으로 학습 효율을 높일 수 있습니다.
코드 예제
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np
# 콜백 설정
early_stop = EarlyStopping(
monitor='val_loss', # 검증 손실을 모니터링
patience=5, # 5 epoch 동안 개선 없으면 중단
restore_best_weights=True # 최고 성능 가중치로 복원
)
checkpoint = ModelCheckpoint(
'best_sentiment_model.h5', # 최고 모델 저장 경로
monitor='val_accuracy',
save_best_only=True
)
# 모델 학습
history = model.fit(
X_train_pad, y_train,
epochs=50,
batch_size=32,
validation_split=0.2,
callbacks=[early_stop, checkpoint],
verbose=1
)
# 테스트 데이터로 평가
test_loss, test_acc = model.evaluate(X_test_pad, y_test, verbose=0)
print(f"\n테스트 정확도: {test_acc:.4f}")
# 예측 수행
y_pred_probs = model.predict(X_test_pad)
y_pred = (y_pred_probs > 0.5).astype(int) # 0.5 임계값으로 이진 분류
# 상세 평가 리포트
print("\n분류 리포트:")
print(classification_report(y_test, y_pred, target_names=['부정', '긍정']))
# 혼동 행렬
print("\n혼동 행렬:")
print(confusion_matrix(y_test, y_pred))
설명
이것이 하는 일은 마치 운동선수가 코치의 피드백을 받으며 훈련하고, 시합에서 실력을 검증받는 것과 비슷합니다. 첫 번째로, EarlyStopping 콜백이 학습을 자동으로 관리합니다.
검증 손실(val_loss)이 5 epoch 동안 개선되지 않으면 학습을 멈춥니다. 이렇게 하면 과적합을 방지하고 시간을 절약할 수 있습니다.
restore_best_weights=True는 학습을 멈출 때 가장 성능이 좋았던 시점의 가중치로 되돌립니다. ModelCheckpoint는 학습 중 최고 성능의 모델을 자동으로 저장합니다.
나중에 이 파일을 로드해서 바로 사용할 수 있죠. save_best_only=True로 최고 모델만 저장해서 디스크 공간을 절약합니다.
model.fit으로 실제 학습을 시작합니다. validation_split=0.2는 학습 데이터의 20%를 검증용으로 분리합니다.
각 epoch마다 학습 손실, 학습 정확도, 검증 손실, 검증 정확도가 출력되어 학습 진행 상황을 모니터링할 수 있습니다. 학습 완료 후 evaluate로 테스트 데이터의 최종 성능을 측정합니다.
그리고 predict로 실제 예측값을 생성합니다. 모델은 확률을 출력하므로 0.5를 기준으로 0 또는 1로 변환합니다.
classification_report는 각 클래스별로 정밀도(예측한 긍정 중 실제 긍정 비율), 재현율(실제 긍정 중 찾아낸 긍정 비율), F1 점수(정밀도와 재현율의 조화평균)를 보여줍니다. confusion_matrix는 실제/예측 조합을 표로 보여줘서 어떤 종류의 오류가 많은지 파악할 수 있습니다.
여러분이 이 코드를 실행하면 모델이 자동으로 학습되고, 최적의 성능을 찾으며, 상세한 평가 결과를 얻을 수 있습니다. 예를 들어, 정확도 85%, 정밀도 87%, 재현율 83% 같은 결과가 나오면 모델이 대부분의 감정을 올바르게 분류한다는 의미입니다.
혼동 행렬에서 오분류 패턴을 분석하면 모델의 약점을 파악하고 개선할 수 있습니다. 실무에서는 이 지표들을 바탕으로 하이퍼파라미터를 조정하거나 데이터를 보강해서 성능을 계속 향상시킵니다.
실전 팁
💡 patience 값은 데이터셋 크기에 따라 조절하세요. 큰 데이터셋은 10-20, 작은 데이터셋은 3-5가 적당합니다.
💡 학습 곡선(history)을 시각화하면 과적합 여부를 쉽게 파악할 수 있습니다. matplotlib로 loss와 accuracy를 그래프로 그려보세요.
💡 임계값 0.5 대신 ROC 곡선으로 최적 임계값을 찾으면 더 나은 성능을 얻을 수 있습니다.
💡 클래스 불균형이 있다면 F1 점수가 정확도보다 더 신뢰할 수 있는 지표입니다.
💡 cross-validation을 사용하면 데이터가 적을 때도 안정적인 성능 측정이 가능합니다. StratifiedKFold를 활용하세요.
댓글 (0)
함께 보면 좋은 카드 뉴스
범주형 변수 시각화 완벽 가이드 Bar Chart와 Count Plot
데이터 분석에서 가장 기본이 되는 범주형 변수 시각화 방법을 알아봅니다. Matplotlib의 Bar Chart부터 Seaborn의 Count Plot까지, 실무에서 바로 활용할 수 있는 시각화 기법을 배워봅니다.
이변량 분석 완벽 가이드: 변수 간 관계 탐색
두 변수 사이의 관계를 분석하는 이변량 분석의 핵심 개념과 기법을 배웁니다. 상관관계, 산점도, 교차분석 등 데이터 분석의 필수 도구들을 실습과 함께 익혀봅시다.
단변량 분석 분포 시각화 완벽 가이드
데이터 분석의 첫걸음인 단변량 분석과 분포 시각화를 배웁니다. 히스토그램, 박스플롯, 밀도 그래프 등 다양한 시각화 방법을 초보자도 쉽게 이해할 수 있도록 설명합니다.
데이터 타입 변환 및 정규화 완벽 가이드
데이터 분석과 머신러닝에서 가장 기초가 되는 데이터 타입 변환과 정규화 기법을 배워봅니다. 실무에서 자주 마주치는 데이터 전처리 문제를 Python으로 쉽게 해결하는 방법을 알려드립니다.
이상치 탐지 및 처리 완벽 가이드
데이터 속에 숨어있는 이상한 값들을 찾아내고 처리하는 방법을 배워봅니다. 실무에서 자주 마주치는 이상치 문제를 Python으로 해결하는 다양한 기법을 소개합니다.