머신러닝의 꽃 RNN (순환 신경망)

RNN은 Recurrent Neural Network의 약자입니다. 이는 입력 데이터의 시퀀스를 처리하는 데 적합한 인공 신경망 구조를 나타내며, 이전 스텝의 출력값이 다음 스텝의 입력값으로 이어지는 구조를 가지고 있습니다.

음악 작곡은 시계열 데이터를 다루는 문제이기 때문에 RNN이 자연스럽게 적합합니다. 또 RNN은 자연어 처리 분야에서 많이 사용되며, 예를 들어 문장 내 단어의 시퀀스를 입력으로 받아 문장의 감정을 판단하는 것과 같은 작업에 활용됩니다. 예를 들어 “I love you”와 “I hate you”는 전체 문장은 동일하지만 단어의 순서에 따라 전혀 다른 의미를 가지고 있습니다. RNN은 이러한 문맥 정보를 학습하여 이전 시퀀스의 정보를 현재 시퀀스에 반영함으로써 감정 분류 작업과 같은 문제를 처리할 수 있습니다.

다른 예시로는 주가 예측과 같은 시계열 데이터 분석 문제에서 RNN을 활용할 수 있습니다. 주가 데이터는 이전 주가 데이터에 영향을 받아 현재 주가가 결정되기 때문에 RNN을 사용하면 이전 시점의 주가 데이터를 반영하여 더욱 정확한 예측을 할 수 있습니다.

따라서, RNN은 머신러닝에서 시계열 데이터를 다루는 데 있어서 핵심적인 역할을 수행하며, 이를 바탕으로 다양한 분야에서 활용되고 있기 때문에 “머신러닝의 꽃”이라 불리게 된 것입니다.

RNN(Recurrent Neural Network)은 딥러닝의 일종으로, 인공신경망 모델 중 하나입니다. 따라서 RNN은 머신러닝과 딥러닝 모두에 해당합니다. 다만, RNN은 딥러닝의 한 종류인 심층 순환 신경망(Deep Recurrent Neural Network)의 일부분으로 더 넓은 범주에 속하게 됩니다.

이처럼 RNN은 순서가 있는 데이터를 다루는데 강점을 가지는 딥러닝 모델 중 하나입니다. 예를 들어, 텍스트 데이터나 시계열 데이터 등 순차적으로 입력되는 데이터를 처리할 때 자주 사용됩니다.

개와 원숭이의 관계를 예로 들어보겠습니다. 우리는 개와 원숭이를 쉽게 구분할 수 있습니다. 하지만 컴퓨터에게 개와 원숭이를 구분하라고 하면 어떻게 할까요? 개와 원숭이를 구분하는 데 필요한 정보를 컴퓨터에게 어떻게 전달할 수 있을까요?

이때 RNN을 사용할 수 있습니다. RNN은 과거의 입력 데이터를 기억하고, 현재 입력 데이터와 함께 처리합니다. 예를 들어, 개와 원숭이를 구분하는 문제에서 RNN은 과거에 입력된 데이터(예를 들어, 눈의 색, 귀의 크기 등)를 기억하고, 현재 입력된 데이터(예를 들어, 다리의 길이, 꼬리의 길이 등)와 함께 처리합니다. 이렇게 RNN은 과거의 정보를 활용하여 현재 입력 데이터를 처리하므로, 개와 원숭이를 구분하는 데 좀 더 효과적인 결과를 얻을 수 있습니다.

아래는 RNN을 이용한 텍스트 생성 예시입니다. 이 예시는 CorlLab에서 실행할 수 있습니다. 예시 코드에서는 RNN 모델을 학습하여 새로운 텍스트를 생성합니다.
이 코드는 니체의 글을 읽어들이고, 그것을 기반으로 RNN 모델을 학습시켜 니체 스타일의 글을 생성하는 것입니다. 학습된 모델을 사용하여 새로운 글을 생성할 수 있습니다. 이 모델은 이전에 학습된 텍스트의 특징을 파악하고 그 특징을 기반으로 새로운 글을 생성하는 방식으로 작동합니다.

물론 생성된 글이 니체 스타일인지 여부를 정확히 평가하는 것은 어렵습니다. 하지만 생성된 글이 니체 스타일을 잘 따르고 있는지의 정도를 평가할 수는 있습니다.

만약 이 모델이 잘 학습되었다면, 생성된 글은 니체의 특징을 따를 것입니다. 예를 들어, 니체의 글은 많은 경우 길고 복잡한 문장 구조를 가지고 있으며, 생각의 흐름이 길게 이어지는 경우가 많습니다. 또한, 니체는 독창적인 어휘와 문장 구조를 사용하여 그의 작품을 특별하게 만들었습니다. 따라서, 생성된 글에서 이러한 니체의 특징이 나타난다면, 그 글이 니체 스타일의 글일 가능성이 높습니다.

예를 들어, 다음과 같은 문장이 생성된다면 니체 스타일의 글로 간주될 수 있습니다: “세상은 끊임없이 새로워지고 우리의 삶도 변화를 거듭합니다.” 이 문장은 길고 복잡한 문장 구조를 가지고 있으며, 새로운 개념을 소개하면서 생각의 흐름이 연결되어 있습니다. 또한, “세상”, “끊임없이”, “새로워지고”, “우리의 삶도”, “변화를 거듭합니다”와 같은 니체 특유의 어휘와 문장 구조가 사용되었습니다.

# 필요한 패키지 import
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import Dense, LSTM
import numpy as np

# 데이터셋 로드
path = keras.utils.get_file(
    'nietzsche.txt',
    origin='https://s3.amazonaws.com/text-datasets/nietzsche.txt')

with open(path, encoding='utf-8') as f:
    text = f.read().lower()

# 문자열을 숫자로 변환
chars = sorted(list(set(text)))
char_indices = dict((c, i) for i, c in enumerate(chars))
indices_char = dict((i, c) for i, c in enumerate(chars))

# 입력 시퀀스와 타깃 시퀀스 생성
maxlen = 40
step = 3
sentences = []
next_chars = []
for i in range(0, len(text) - maxlen, step):
    sentences.append(text[i:i + maxlen])
    next_chars.append(text[i + maxlen])
x = np.zeros((len(sentences), maxlen, len(chars)), dtype=np.bool)
y = np.zeros((len(sentences), len(chars)), dtype=np.bool)
for i, sentence in enumerate(sentences):
    for t, char in enumerate(sentence):
        x[i, t, char_indices[char]] = 1
    y[i, char_indices[next_chars[i]]] = 1

# 모델 구성
model = keras.models.Sequential()
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
model.add(Dense(len(chars), activation='softmax'))

# 모델 컴파일
optimizer = keras.optimizers.RMSprop(lr=0.01)
model.compile(loss='categorical_crossentropy', optimizer=optimizer)

# 모델 학습
model.fit(x, y, batch_size=128, epochs=20)

# 모델 사용
def sample(preds, temperature=1.0):
    preds = np.asarray(preds).astype('float64')
    preds = np.log(preds) / temperature
    exp_preds = np.exp(preds)
    preds = exp_preds / np.sum(exp_preds)
    probas = np.random.multinomial(1, preds, 1)
    return np.argmax(probas)

start_index = np.random.randint(0, len(text) - maxlen - 1)
for temperature in [0.2, 0.5, 1.0, 1.2]:
    generated_text = text[start_index: start_index + maxlen]
    print('--- temperature:', temperature)
    sys.stdout.write(generated_text)

    for i in range(400):
        x_pred = np.zeros((1, maxlen, len(chars)))
        for t, char in enumerate(generated_text):
            x_pred[0, t, char_indices[char]] = 1.

        preds = model.predict(x_pred, verbose=0)[0]
        next_index = sample(preds, temperature)
        next_char = indices_char[next_index]

        generated_text += next_char
        generated_text = generated_text[1:]

        sys.stdout.write(next_char)
        sys.stdout.flush()
    print()

위의 코드는 RNN 모델을 사용하여 텍스트 생성을 수행합니다. 먼저, 텍스트 데이터셋을 로드하고, 문자열을 숫자로 변환합니다. 그 다음, 입력 시퀀스와 타깃 시퀀스를 생성합니다.

이 모델은 LSTM 레이어를 사용하여 시퀀스 데이터를 학습합니다. LSTM 레이어는 이전 상태를 기억하고 새로운 입력에 대한 출력을 생성하는 방법으로 시퀀스 데이터를 모델링합니다.

모델은 컴파일되고 학습됩니다. 이 모델은 categorical crossentropy 손실함수와 RMSprop 옵티마이저를 사용하여 컴파일합니다. 그 다음, 학습 데이터를 사용하여 모델을 학습합니다.

마지막으로, 모델은 텍스트를 생성하는 데 사용됩니다. 시작 인덱스를 무작위로 선택하고, 다양한 온도를 사용하여 샘플링된 텍스트를 출력합니다. 이를 통해 모델이 생성한 텍스트가 온도에 따라 어떻게 달라지는지 확인할 수 있습니다.

여기서 말하는 “온도(temperature)”는 날씨의 온도와는 다른 개념입니다. 이전에 말씀드린 것처럼, RNN 모델이 다음 문자를 예측할 때 확률 분포를 사용합니다. 이때, softmax 함수를 사용하면 각 문자에 대한 확률 분포를 구할 수 있습니다. 이 확률 분포를 사용해 다음 문자를 샘플링하게 되는데, 이때 온도(temperature)가 사용됩니다.

온도는 샘플링할 때 생성되는 텍스트의 다양성을 제어하는 역할을 합니다. 온도가 높을수록 모델이 덜 확신하는 경우가 더 자주 발생하므로 샘플링된 텍스트의 다양성이 높아집니다. 반대로, 온도가 낮을수록 모델이 더 확신하는 경우가 더 자주 발생하므로 샘플링된 텍스트의 다양성이 낮아집니다.

예를 들어, 온도가 1.0 이하인 경우 모델이 높은 확률을 가진 문자를 더 자주 선택하게 되므로 생성된 텍스트의 일관성이 높아집니다. 반면에, 온도가 1.0을 초과하는 경우 모델이 낮은 확률을 가진 문자도 선택할 가능성이 높아지므로 생성된 텍스트의 다양성이 높아집니다. 따라서, 온도를 사용하여 샘플링할 때 적절한 값을 선택하여 모델이 생성하는 텍스트의 다양성을 조절할 수 있습니다.

즉, 온도(temperature)는 샘플링 과정에서 생성되는 텍스트의 다양성을 조절하는 하이퍼파라미터입니다.

온도가 낮으면 생성되는 텍스트가 좀 더 일관성 있고, 예측되는 확률이 높은 문자열을 출력합니다. 반면에, 온도가 높을수록 생성되는 텍스트가 더 다양해지고, 예측되는 확률이 낮은 문자열도 출력됩니다. 이렇게 다양성을 조절할 수 있기 때문에, 온도를 적절하게 설정하는 것은 텍스트 생성 모델에서 중요한 문제 중 하나입니다.

예를 들어, 온도가 0.2 이하인 경우에는 확률이 가장 높은 문자를 계속해서 출력하게 됩니다. 이렇게 되면 텍스트가 반복되는 경향이 있어 일관성 있고 예측 가능한 텍스트가 생성됩니다. 반면에, 온도가 1.0 이상인 경우에는 예측된 확률에 따라서 문자열이 더 다양하게 생성됩니다. 예측된 확률이 낮은 문자열도 출력되기 때문에, 일관성 없고 무작위적인 텍스트가 생성될 가능성이 높아집니다.

따라서, 적절한 온도를 선택하여 텍스트 생성 모델의 출력을 조절하는 것은 중요한 과제 중 하나입니다.

 

 

 

 

“머신러닝의 꽃 RNN (순환 신경망)”의 한가지 생각

  1. 순환신경망 Recurrent Neural Networks(RNN) 은 외부의 입력값과 자신의 이전 값을 통해) 자신의 상태를 갱신합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다