순환신경망 - RNN (Recurrent Neural Network)
Post
Cancel

# 순환신경망 - RNN (Recurrent Neural Network)

## 1. Simple RNN

### 1.1 순환 신경망

• 순서가 있는 데이터를 입력으로 받고 변화하는 입력에 대한 출력을 얻음

## 2. RNN 실습

### 2.1 간단한 Time Stamp 데이터로 RNN 실습

```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import tensorflow as tf import numpy as np X = [] Y = [] for i in range(6): lst = list(range(i, i+4)) X.append(list(map(lambda c : [c/10], lst))) Y.append((i +4)/10) X = np.array(X) Y = np.array(Y) for i in range(len(X)): print(X[i], Y[i]) print() ```
```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 [[0. ] [0.1] [0.2] [0.3]] 0.4 [[0.1] [0.2] [0.3] [0.4]] 0.5 [[0.2] [0.3] [0.4] [0.5]] 0.6 [[0.3] [0.4] [0.5] [0.6]] 0.7 [[0.4] [0.5] [0.6] [0.7]] 0.8 [[0.5] [0.6] [0.7] [0.8]] 0.9 ```
• 0.0 ~ 0.3 -> 0.4
• 0.1 ~ 0.4 -> 0.5
• 이런식의 데이터

### 2.2 Simple RNN 구성

```1 2 3 4 5 6 7 8 model = tf.keras.Sequential([ tf.keras.layers.SimpleRNN( units=10, return_sequences=False, input_shape=[4, 1]), tf.keras.layers.Dense(1) ]) model.compile(optimizer = 'adam', loss = 'mse') model.summary() ```
```1 2 3 4 5 6 7 8 9 10 11 12 Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= simple_rnn (SimpleRNN) (None, 10) 120 _________________________________________________________________ dense (Dense) (None, 1) 11 ================================================================= Total params: 131 Trainable params: 131 Non-trainable params: 0 _________________________________________________________________ ```
• input_shape이 4.1 이라는것은 timesteps가 4, input_dim이 1
• units : SimpleRNN 레이어에 존재하는 뉴런의 수
• return_sequences : 출력으로 시퀀스 전체를 출력할지 여부

### 2.4 학습

```1 model.fit(X, Y, epochs=100, verbose=0) ```
```1 <tensorflow.python.keras.callbacks.History at 0x7fd850d79d90> ```

### 2.5 예측

```1 model.predict(np.array([[[-0.1],[0.0],[0.1],[0.2]]])) ```
```1 array([[0.29263034]], dtype=float32) ```
• -0.1 ~ 0.2 다음은 0.3이 나와야하는데 0.2926이 나오는것 보니, 비슷은 해보인다

### 2.6 Simple RNN의 단점

• Long-Term Dependency : 입력 데이터가 길어지면 학습 능력이떨어짐
• 현재의 답을 얻기 위해 과거의 정보에 의존해야하는 RNN, 하지만 과거 시점이 현재와 너무 멀어지면 문제를 풀기 어려움

## 3. LSTM

### 3.1 LSTM

• Simple RNN의 장기 의존성 문제를 해결하기 위한 알고리즘
• Time Step을 가르지르며 셀 상태가 보존

## 4. LSTM 실습

### 4.1 예제

```1 2 3 4 5 6 7 8 9 10 11 12 X = [] Y = [] for i in range(1000): lst = np.random.rand(100) idx = np.random.choice(100, 2, replace = False) zeros = np.zeros(100) zeros[idx] = 1 X.append(np.array(list(zip(zeros, lst)))) Y.append(np.prod(lst[idx])) print(X[0], Y[0]) ```
```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 [[0. 0.80008966] [0. 0.30359938] [0. 0.87163122] [0. 0.7413119 ] [0. 0.11942425] [0. 0.27352657] [0. 0.76802368] [0. 0.14609984] [0. 0.18106652] [0. 0.01171455] [0. 0.92461019] [0. 0.27576429] [0. 0.8144809 ] [0. 0.15831039] [0. 0.03956734] [0. 0.74086254] [0. 0.71514832] [0. 0.05864715] [0. 0.2165122 ] [0. 0.67536621] [0. 0.83084592] [0. 0.02361978] [0. 0.96610312] [0. 0.65990591] [0. 0.97501121] [0. 0.56664119] [0. 0.98403786] [0. 0.61782982] [0. 0.98569084] [0. 0.93561593] [0. 0.06791456] [0. 0.54954407] [0. 0.49462747] [0. 0.74715515] [0. 0.31521783] [0. 0.72605368] [0. 0.62690249] [0. 0.31447398] [0. 0.15953186] [0. 0.12764518] [0. 0.07478073] [0. 0.00354316] [0. 0.28523369] [0. 0.06752979] [0. 0.83515363] [0. 0.85055375] [1. 0.88817727] [0. 0.00453563] [0. 0.30259626] [0. 0.93822272] [0. 0.10927959] [0. 0.92989588] [0. 0.47279259] [0. 0.40970746] [0. 0.32246528] [0. 0.73999216] [0. 0.62096274] [0. 0.48123822] [0. 0.78971826] [0. 0.89842873] [0. 0.87298911] [0. 0.55976035] [0. 0.82265406] [0. 0.11174719] [0. 0.00784555] [0. 0.6851193 ] [0. 0.75893765] [0. 0.50567489] [0. 0.01901901] [0. 0.7303575 ] [0. 0.68753022] [0. 0.45555408] [0. 0.47891555] [0. 0.73691181] [0. 0.05961961] [0. 0.94850333] [0. 0.79596296] [0. 0.86432501] [0. 0.49509131] [0. 0.1899921 ] [0. 0.25937904] [0. 0.52905918] [0. 0.21323525] [0. 0.41142003] [0. 0.15834983] [0. 0.52050195] [0. 0.13767634] [0. 0.67453866] [0. 0.54832447] [0. 0.4106969 ] [0. 0.57071902] [0. 0.54413813] [0. 0.16043092] [1. 0.37390211] [0. 0.6987448 ] [0. 0.31205635] [0. 0.0487809 ] [0. 0.14050364] [0. 0.69102483] [0. 0.49156883]] 0.3320913581177933 ```
• LSTM을 처음 제안한 논문에서 LSTM의 성능을 확인하기 위해서 제시한 문제

### 4.2 RNN으로

```1 2 3 4 5 6 7 8 9 model = tf.keras.Sequential([ tf.keras.layers.SimpleRNN( units=30, return_sequences=True, input_shape=[100, 2]), tf.keras.layers.SimpleRNN(units=30), tf.keras.layers.Dense(1) ]) model.compile(optimizer='adam', loss='mse') model.summary() ```
```1 2 3 4 5 6 7 8 9 10 11 12 13 14 Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= simple_rnn_1 (SimpleRNN) (None, 100, 30) 990 _________________________________________________________________ simple_rnn_2 (SimpleRNN) (None, 30) 1830 _________________________________________________________________ dense_1 (Dense) (None, 1) 31 ================================================================= Total params: 2,851 Trainable params: 2,851 Non-trainable params: 0 _________________________________________________________________ ```
• 일단 SimpleRNN으로 확인

### 4.3 SimpleRNN 훈련 후 그래프

```1 2 3 4 5 6 7 8 9 10 11 12 import matplotlib.pyplot as plt X = np.array(X) Y = np.array(Y) history = model.fit(X[:2560], Y[:2560], epochs=100, validation_split=0.2) plt.plot(history.history['loss'], 'b-', label = 'loss') plt.plot(history.history['val_loss'], 'r--', label = 'val_loss') plt.xlabel('Epoch') plt.legend() plt.show() ```
```1 2 3 4 5 6 7 8 9 10 11 Epoch 1/100 25/25 [==============================] - 1s 27ms/step - loss: 0.0806 - val_loss: 0.0600 Epoch 2/100 25/25 [==============================] - 0s 20ms/step - loss: 0.0517 - val_loss: 0.0586 Epoch 3/100 25/25 [==============================] - 0s 19ms/step - loss: 0.0512 - val_loss: 0.0581 ... Epoch 99/100 25/25 [==============================] - 0s 20ms/step - loss: 0.0100 - val_loss: 0.0821 Epoch 100/100 25/25 [==============================] - 0s 19ms/step - loss: 0.0099 - val_loss: 0.0804 ```

• Loss가 계속 벌어진다. 이것은 아까 이야기했던 Long-Term Dependency 때문임

### 4.4 LSTM

```1 2 3 4 5 6 7 8 9 model = tf.keras.Sequential([ tf.keras.layers.LSTM(units=30, return_sequences=True, input_shape=[100, 2]), tf.keras.layers.LSTM(units=30), tf.keras.layers.Dense(1) ]) model.compile(optimizer = 'adam', loss = 'mse') model.summary() ```
```1 2 3 4 5 6 7 8 9 10 11 12 13 14 Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= lstm (LSTM) (None, 100, 30) 3960 _________________________________________________________________ lstm_1 (LSTM) (None, 30) 7320 _________________________________________________________________ dense_2 (Dense) (None, 1) 31 ================================================================= Total params: 11,311 Trainable params: 11,311 Non-trainable params: 0 _________________________________________________________________ ```

### 4.5 LSTM 훈련 후 그래프

```1 2 3 4 5 6 7 8 9 import matplotlib.pyplot as plt history = model.fit(X[:2560], Y[:2560], epochs=100, validation_split=0.2) plt.plot(history.history['loss'], 'b-', label = 'loss') plt.plot(history.history['val_loss'], 'r--', label = 'val_loss') plt.xlabel('Epoch') plt.legend() plt.show() ```
```1 2 3 4 5 6 7 8 9 Epoch 1/100 25/25 [==============================] - 1s 46ms/step - loss: 0.0620 - val_loss: 0.0558 Epoch 2/100 25/25 [==============================] - 1s 29ms/step - loss: 0.0507 - val_loss: 0.0539 Epoch 3/100 25/25 [==============================] - 1s 29ms/step - loss: 0.0508 - val_loss: 0.0543 ... Epoch 100/100 25/25 [==============================] - 1s 29ms/step - loss: 0.0510 - val_loss: 0.0543 ```

• SimpleRNN과는 다르게 Loss와 Val Loss가 같이 떨어진다.

## 5. GRU 레이어 (Gated Recurrent Unit)

### 5.1 GRU의 셀 구조

• LSTM에 비해 연산량이 작고, 성능이 어떤 경우는 괜찮은것으로 나타난다.

### 5.2 GRU 생성

```1 2 3 4 5 6 7 8 mdoel = tf.keras.Sequential([ tf.keras.layers.GRU(units=30, return_sequences=True, input_shape=[100, 2]), tf.keras.layers.GRU(units=30), tf.keras.layers.Dense(1) ]) model.compile(optimizer = 'adam', loss = 'mse') model.summary() ```
```1 2 3 4 5 6 7 8 9 10 11 12 13 14 Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= lstm (LSTM) (None, 100, 30) 3960 _________________________________________________________________ lstm_1 (LSTM) (None, 30) 7320 _________________________________________________________________ dense_2 (Dense) (None, 1) 31 ================================================================= Total params: 11,311 Trainable params: 11,311 Non-trainable params: 0 _________________________________________________________________ ```

### 5.3 GRU 훈련 후 그래프 그리기

```1 2 3 4 5 6 7 8 9 import matplotlib.pyplot as plt history = model.fit(X[:2560], Y[:2560], epochs=100, validation_split=0.2) plt.plot(history.history['loss'], 'b-', label = 'loss') plt.plot(history.history['val_loss'], 'r--', label = 'val_loss') plt.xlabel('Epoch') plt.legend() plt.show() ```
```1 2 3 4 5 6 7 8 Epoch 1/100 25/25 [==============================] - 1s 52ms/step - loss: 0.0506 - val_loss: 0.0550 Epoch 2/100 25/25 [==============================] - 1s 29ms/step - loss: 0.0497 - val_loss: 0.0555 Epoch 3/100 ... Epoch 100/100 25/25 [==============================] - 1s 30ms/step - loss: 6.9079e-04 - val_loss: 9.3052e-04 ```

• 이것도 마찬가지로 Loss와 Val Loss가 엄청 잘 떨어진다.

## 6. 감성 분석 실습

### 6.1 감성분석

• 입력된 자연어 안의 주관적 의견, 감정등을 찾아내는 문제
• 문장의 긍정/부정 등을 구분하는 경우가 많음

```1 2 3 4 import tensorflow as tf path_to_train_file = tf.keras.utils.get_file('train_txt', 'https://raw.githubusercontent.com/hmkim312/datas/main/navermoviereview/ratings_train.txt') path_to_test_file = tf.keras.utils.get_file('test_txt', 'https://raw.githubusercontent.com/hmkim312/datas/main/navermoviereview/ratings_test.txt') ```
```1 2 3 4 Downloading data from https://raw.githubusercontent.com/hmkim312/datas/main/navermoviereview/ratings_train.txt 14630912/14628807 [==============================] - 4s 0us/step Downloading data from https://raw.githubusercontent.com/hmkim312/datas/main/navermoviereview/ratings_test.txt 4898816/4893335 [==============================] - 2s 0us/step ```

```1 2 3 4 5 6 7 train_text = open(path_to_train_file, 'rb').read().decode(encoding='utf-8') test_text = open(path_to_test_file, 'rb').read().decode(encoding='utf-8') print(f'Length of text : {len(train_text)} characters') print(f'Length of text : {len(test_text)} characters') print() print(train_text[:100]) ```
```1 2 3 4 5 6 7 Length of text : 6937271 characters Length of text : 2318260 characters id document label 9976970 아 더빙.. 진짜 짜증나네요 목소리 0 3819312 흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나 1 10265843 ```
• 일전에 사용했던 영화 리뷰 감성분석 https://hmkim312.github.io/posts/네이버영화평점을_이용한_감정분석/
• id: 리뷰한 관객의 id 고유값
• document: 실제 리뷰
• label: 감정 (0: 부정, 1: 긍정)
• 총 200K의 감정분석(20만)
• ratings_test.txt: 5만개의 테스트용 리뷰
• ratings_train.txt: 15만개의 훈련용 리뷰
• 모든 리뷰는 140자 미만
• 100k(10만) 부정 리뷰 (평점이 0점 ~ 4점)
• 100K(10만) 긍정 리뷰 (평점이 9점 ~ 10점)
• 평점이 5점 ~ 8점은 중립리뷰점수로 로 제외시킴

### 6.3 데이터가 깨끗하지 않음

```1 train_text[:300] ```
```1 'id\tdocument\tlabel\n9976970\t아 더빙.. 진짜 짜증나네요 목소리\t0\n3819312\t흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나\t1\n10265843\t너무재밓었다그래서보는것을추천한다\t0\n9045019\t교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정\t0\n6483659\t사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 던스트가 너무나도 이뻐보였다\t1\n5403919\t막 걸음마 뗀 3세부터 초등학교 1학년생인 8살용영화.ㅋㅋㅋ...별반개도 아까움.\t0\n7797314\t원작의' ```

### 6.4 데이터 전처리

```1 train_text.split('\n') ```
```1 2 3 4 5 6 7 ['id\tdocument\tlabel', '9976970\t아 더빙.. 진짜 짜증나네요 목소리\t0', '3819312\t흠...포스터보고 초딩영화줄....오버연기조차 가볍지 않구나\t1', '10265843\t너무재밓었다그래서보는것을추천한다\t0', '9045019\t교도소 이야기구먼 ..솔직히 재미는 없다..평점 조정\t0', '6483659\t사이몬페그의 익살스런 연기가 돋보였던 영화!스파이더맨에서 늙어보이기만 했던 커스틴 던스트가 너무나도 이뻐보였다\t1', ...] ```
• split을 하여 리뷰별로 가져옴

```1 train_text.split('\n')[3].split('\t') ```
```1 ['10265843', '너무재밓었다그래서보는것을추천한다', '0'] ```
• 리뷰 한줄을 탭으로 split하면 id, review, target이 나옴

### 6.5 Target 데이터 정리

```1 2 3 4 5 6 7 import numpy as np train_Y = np.array([[int(row.split('\t')[2])] for row in train_text.split('\n')[1:] if row.count('\t') >0]) test_Y = np.array([[int(row.split('\t')[2])] for row in test_text.split('\n')[1:] if row.count('\t') >0]) print(train_Y.shape, test_Y.shape) print(train_Y[:5]) ```
```1 2 3 4 5 6 (150000, 1) (50000, 1) [[0] [1] [0] [0] [1]] ```
• 일단 타겟이 되는 0(부정), 1(긍정) 데이터를 따로 모아놨음

### 6.6 Tokenization, Cleaning

• Tokenization : 자연어 처리 가능한 최소의 단위로 나누는 것, 이번에는 띄어쓰기
• Cleaning : 불필요한 기호를 제거

### 6.7 Cleaning 함수 생성 및 데이터 전처리

```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import re def clean_str(string): string = re.sub(r"[^가-힣A-Za-z0-9(),!?\'\`]", " ", string) string = re.sub(r"\'s", " \'s", string) string = re.sub(r"\'ve", " \'ve", string) string = re.sub(r"n\'t", " n\'t", string) string = re.sub(r"\'re", " \'re", string) string = re.sub(r"\'d", " \'d", string) string = re.sub(r"\'ll", " \'ll", string) string = re.sub(r",", " , ", string) string = re.sub(r"!", " ! ", string) string = re.sub(r"\(", " \( ", string) string = re.sub(r"\)", " \) ", string) string = re.sub(r"\?", " \? ", string) string = re.sub(r"\s{2,}", " ", string) string = re.sub(r"\'{2,}", "\'", string) string = re.sub(r"\'", "", string) return string.lower() ```
• 불필요한 특수문자를 제거하는 함수 생성

```1 2 3 4 5 train_text_X = [row.split('\t')[1] for row in train_text.split('\n')[1:] if row.count('\t') > 0] train_text_X = [clean_str(sentence) for sentence in train_text_X] sentences = [sentence.split(' ') for sentence in train_text_X] for i in range(5): print(sentences[i]) ```
```1 2 3 4 5 ['아', '더빙', '진짜', '짜증나네요', '목소리'] ['흠', '포스터보고', '초딩영화줄', '오버연기조차', '가볍지', '않구나'] ['너무재밓었다그래서보는것을추천한다'] ['교도소', '이야기구먼', '솔직히', '재미는', '없다', '평점', '조정'] ['사이몬페그의', '익살스런', '연기가', '돋보였던', '영화', '!', '스파이더맨에서', '늙어보이기만', '했던', '커스틴', '던스트가', '너무나도', '이뻐보였다'] ```
• train_text 리뷰에 ‘\t’가 있다면 split하는 코드
• 위에서 만든 clean_str을 적용하는 코드
• 공백(띄어쓰기)로 split하는 코드

### 6.8 리뷰의 길이

```1 2 3 4 5 6 7 8 import matplotlib.pyplot as plt sentence_len = [len(sentence) for sentence in sentences] sentence_len.sort() plt.plot(sentence_len) plt.show() print('리뷰의 길이가 25자 미만인것 : ', sum([int(l <= 25)for l in sentence_len])) ```

```1 리뷰의 길이가 25자 미만인것 : 142587 ```
• 학습을 위해 네트워크에 입력을 넣을땐 입력 데이터는 그 크기가 같아야함
• 입력 벡터의 크기를 맞추기위해 긴 문장을 줄이고, 짧은 문장은 공백으로 채우는 방법을 사용
• 15만개의 문장중에 대부분이 25단어 이하로 되어있음, 142587개

### 6.9 데이터 전처리 25개 단어까지 넣기

```1 2 3 4 5 6 7 sentences_new = [] for sentence in sentences: sentences_new.append([word[:5] for word in sentence][:25]) sentences = sentences_new for i in range(5): print(sentences_new[i]) ```
```1 2 3 4 5 ['아', '더빙', '진짜', '짜증나네요', '목소리'] ['흠', '포스터보고', '초딩영화줄', '오버연기조', '가볍지', '않구나'] ['너무재밓었'] ['교도소', '이야기구먼', '솔직히', '재미는', '없다', '평점', '조정'] ['사이몬페그', '익살스런', '연기가', '돋보였던', '영화', '!', '스파이더맨', '늙어보이기', '했던', '커스틴', '던스트가', '너무나도', '이뻐보였다'] ```

### 6.10 토크나이징과 패딩

```1 2 3 4 5 6 7 8 from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences tokenizer = Tokenizer(num_words=20000) tokenizer.fit_on_texts(sentences) train_X = tokenizer.texts_to_sequences(sentences) train_X = pad_sequences(train_X, padding= 'post') print(train_X[:3]) ```
```1 2 3 4 5 6 [[ 25 884 8 5795 1111 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [ 588 5796 6697 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]] ```

### 6.11 모델 구성

```1 2 3 4 5 6 7 8 model = tf.keras.Sequential([ tf.keras.layers.Embedding(20000, 300, input_length = 25), tf.keras.layers.LSTM(units = 50), tf.keras.layers.Dense(2, activation = 'softmax') ]) model.compile(optimizer = 'adam', loss = 'sparse_categorical_crossentropy', metrics = ['accuracy']) model.summary() ```
```1 2 3 4 5 6 7 8 9 10 11 12 13 14 Model: "sequential_4" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding (Embedding) (None, 25, 300) 6000000 _________________________________________________________________ lstm_2 (LSTM) (None, 50) 70200 _________________________________________________________________ dense_4 (Dense) (None, 2) 102 ================================================================= Total params: 6,070,302 Trainable params: 6,070,302 Non-trainable params: 0 _________________________________________________________________ ```

### 6.12 임베딩 레이어(Embedding Layer)

• 임베딩 레이어 : 자연어를 수치화된 정보로 바꾸기 위한 레이어
• 자연어는 시간의 흐름에 따라 정보가 연속적으로 이어지는 스퀀스 데이터
• 영어는 문자 단위, 한글은 문자를 넘어 자소 단위로도 쪼개기도 함, 혹은 형태소, 띄어쓰기로도 하기도함
• 여러 단어로 묶어서 사용하는 n-gram 방식도 있음
• 원핫인코딩까지 포함

### 6.13 학습

```1 history = model.fit(train_X, train_Y, epochs=5, batch_size = 120, validation_split= 0.2) ```
```1 2 3 4 5 6 7 8 9 10 Epoch 1/5 1000/1000 [==============================] - 50s 50ms/step - loss: 0.4301 - accuracy: 0.7884 - val_loss: 0.3805 - val_accuracy: 0.8224 Epoch 2/5 1000/1000 [==============================] - 51s 51ms/step - loss: 0.3263 - accuracy: 0.8467 - val_loss: 0.3903 - val_accuracy: 0.8211 Epoch 3/5 1000/1000 [==============================] - 47s 47ms/step - loss: 0.2766 - accuracy: 0.8662 - val_loss: 0.4175 - val_accuracy: 0.8196 Epoch 4/5 1000/1000 [==============================] - 47s 47ms/step - loss: 0.2357 - accuracy: 0.8836 - val_loss: 0.4570 - val_accuracy: 0.8113 Epoch 5/5 1000/1000 [==============================] - 47s 47ms/step - loss: 0.2016 - accuracy: 0.8990 - val_loss: 0.5628 - val_accuracy: 0.8102 ```

### 6.14 테스트

```1 2 3 4 5 6 7 8 9 10 11 12 13 14 test_sentence = '재미있을 줄 알았는데 완전 실망했다. 너무 졸리고 돈이 아까웠다' test_sentence = test_sentence.split(' ') test_sentences =[] now_sentence = [] for word in test_sentence: now_sentence.append(word) test_sentences.append(now_sentence[:]) test_X_1 = tokenizer.texts_to_sequences(test_sentences) test_X_1 = pad_sequences(test_X_1, padding = 'post', maxlen=25) prediction = model.predict(test_X_1) for idx, sentence in enumerate(test_sentences): print(sentence) print(prediction[idx]) ```
```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ['재미있을'] [0.33282876 0.66717124] ['재미있을', '줄'] [0.3296478 0.67035216] ['재미있을', '줄', '알았는데'] [0.41936734 0.5806327 ] ['재미있을', '줄', '알았는데', '완전'] [0.36908486 0.6309151 ] ['재미있을', '줄', '알았는데', '완전', '실망했다.'] [0.36908486 0.6309151 ] ['재미있을', '줄', '알았는데', '완전', '실망했다.', '너무'] [0.375071 0.624929] ['재미있을', '줄', '알았는데', '완전', '실망했다.', '너무', '졸리고'] [0.989423 0.01057698] ['재미있을', '줄', '알았는데', '완전', '실망했다.', '너무', '졸리고', '돈이'] [0.9979898 0.00201018] ['재미있을', '줄', '알았는데', '완전', '실망했다.', '너무', '졸리고', '돈이', '아까웠다'] [0.9983991 0.00160098] ```
• 처음에는 `재미있을` 이라는 단어 떄문에 긍정으로 판단되다가, `졸리고`가 나오자 바로 부정으로 바뀌었다.
• 앞에가 0(부정), 뒤에가 1(긍정)일 확률임

## 7. 요약

### 7.1 요약

• RNN의 종류와 이를 활용하여 감성분석을 진행했다.
• 솔직히 아직 공부가 부족해서 무슨 이야기인지 이해가 안가는 부분이 있음
• 딥러닝은 따로 인강을 들으며 더 공부를 해야겠다.