0:00:00.030,0:00:03.200 이번 강의에서는 [br]RNN에 대해 배워보도록 하겠습니다 0:00:03.200,0:00:06.429 이건 아주 흥미로운[br]학습 아키텍쳐 중 하나죠 0:00:06.429,0:00:09.819 이전 강의에서는[br]DNN에 대해 배웠습니다 0:00:09.819,0:00:12.740 네트워크의 레이어가 있고 0:00:12.740,0:00:16.410 주어진 입력값을[br]앞으로 넘겨주기만 하면 0:00:16.410,0:00:19.210 예상 출력값을 얻을 수 있죠 0:00:19.210,0:00:20.770 또는 예측값을 말이죠 0:00:20.770,0:00:22.790 그리고 CNN은[br]약간 달랐습니다 0:00:22.790,0:00:24.765 CNN은 주어진 입력값에 대해서 0:00:24.765,0:00:27.580 모든 입력값을 사용하는 대신 0:00:27.580,0:00:30.330 특정 부분에 대해서만 적용합니다 0:00:30.330,0:00:32.719 특성을 자동으로 추출하고 0:00:32.719,0:00:34.860 그 다음 레이어로 이동하죠 0:00:34.860,0:00:39.040 따라서 이미지에 대해[br]굉장히 효율적으로 작동합니다 0:00:39.040,0:00:42.360 RNN은 [br]순환신경망을 의미하는데 0:00:42.360,0:00:43.730 굉장히 특이합니다 0:00:43.730,0:00:47.020 여기에서도 마찬가지로[br]x를 입력으로 넣으면 0:00:47.020,0:00:49.129 출력값을 생성합니다 0:00:49.129,0:00:51.720 하지만 그와 동시에[br]또 다른 출력값이 생기는데요 0:00:51.720,0:00:54.470 이것을 대개 은닉 단계 [br]또는 은닉 상태라고 합니다 0:00:54.470,0:00:58.170 이 값은 다음 셀로 넘겨지게 됩니다 0:00:58.170,0:01:00.970 이것을 펼쳐서 보도록 하겠습니다 0:01:00.970,0:01:07.930 여기서 x₁, x₂와 같은[br]입력값을 가집니다 0:01:07.930,0:01:13.450 그리고 출력값을[br]차례로 생성하죠 0:01:13.450,0:01:16.460 여기서 아주 흥미로운 점은[br] 0:01:16.460,0:01:20.040 이 첫 번째 셀에 대해서 0:01:20.040,0:01:24.240 출력값이 다음 셀의[br]입력값으로 전달된다는 점입니다 0:01:24.240,0:01:27.720 이 셀에서의 입력값은 0:01:27.720,0:01:31.020 이전의 데이터와[br]이 입력값이 되는 것이죠 0:01:31.020,0:01:34.030 이 값들로[br]이 출력값을 생성합니다 0:01:34.030,0:01:35.780 그리고 주어진 셀 중에서[br] 0:01:35.780,0:01:39.260 이 셀을 예로 들자면 0:01:39.260,0:01:43.579 여기서 입력값을 x라고 하죠 0:01:43.579,0:01:49.530 또한 이전 단계의[br]은닉 상태도 입력 값으로 사용하죠 0:01:49.530,0:01:51.409 그리고 이것으로[br]출력값을 생성합니다 0:01:51.409,0:01:56.919 이 부분 때문에 우리는[br]이전의 상태를 기억하는 것과 같죠 0:01:56.919,0:01:58.860 이것들을 사용해서 0:01:58.860,0:02:00.530 다음의 출력값을 생성합니다 0:02:00.530,0:02:02.410 왜 이 방법이 좋은 것일까요? 0:02:02.410,0:02:09.149 우리가 가진 많은 양의 데이터를[br]데이터열 또는 시계열이라고 하죠 0:02:09.149,0:02:11.489 우리는 다양한 시계열을 가질 수 있는데 0:02:11.489,0:02:15.040 주가를 예측하는 것도 그중 하나입니다 0:02:15.040,0:02:19.600 이것을 RNN에 [br]굉장히 유용하게 사용할 수 있죠 0:02:19.600,0:02:21.540 또는 RNN이 여기에[br]유용하다고 할 수도 있을 겁니다 0:02:21.540,0:02:23.100 언어 모델링도 그중 하나입니다 0:02:23.100,0:02:25.000 언어를 이해하는 부분은 0:02:25.000,0:02:28.490 제가 이전에 내용을[br]모두 이해하고 있어야 하겠죠 0:02:28.490,0:02:31.580 그렇게 해야 지금 제가 말하는[br]내용을 이해할 수 있게 됩니다 0:02:31.580,0:02:36.710 제가 지금 말하고 있는 [br]내용 또는 발음만 이해하는 것은 0:02:36.710,0:02:39.240 언어를 제대로[br]이해한 것이 아니죠 0:02:39.240,0:02:42.560 따라서 언어 모델링에도[br]RNN이 유용하게 사용됩니다 0:02:42.560,0:02:46.000 또한 텍스트를 [br]다룰 때에도 비슷합니다 0:02:46.000,0:02:47.750 텍스트 감성 분석이라고 하죠 0:02:47.750,0:02:51.440 개체명 인식도 포함됩니다 0:02:51.440,0:02:55.940 번역, 음성 인식 등도 포함되죠 0:02:55.940,0:03:00.140 RNN을 다양한 방법으로[br]합성할 수 있는데요 0:03:00.140,0:03:02.360 굉장히 다양한 모델이 있죠 0:03:02.360,0:03:06.060 예를 들어 여기서는[br]한 개의 입력으로 시작합니다 0:03:06.060,0:03:09.960 그리고 이 RNN은[br]여러 개의 출력값을 만들어내죠 0:03:09.960,0:03:12.550 예를 들어 한 개의 이미지를[br]입력으로 넣고 0:03:12.550,0:03:16.760 신경망이 이미지에[br]캡션을 달도록 한다고 해 봅시다 0:03:16.760,0:03:18.740 따라서 각각의 출력값은[br]단어가 되겠죠 0:03:18.740,0:03:22.690 이것으로 우리는 이 이미지가[br]무엇인지 알 수 있게 됩니다 0:03:22.690,0:03:28.050 또한 RNN을[br]다대일의 형태로 만들 수도 있습니다 0:03:28.050,0:03:34.140 그러면 문장에 포함되는[br]여러 개의 단어를 사용할 수 있겠죠 0:03:34.140,0:03:37.330 이렇게 문장의[br]감성 분석을 할 수 있습니다 0:03:37.330,0:03:38.950 출력은 한 개가 될 것이고 0:03:38.950,0:03:42.110 슬픔, 행복, 행복하지 않음 등의[br]결과가 나오겠죠 0:03:42.110,0:03:46.190 또한 RNN을 다대다의[br]형태로 구성할 수 있습니다 0:03:46.190,0:03:49.850 이 형태는 번역에 자주 사용됩니다 0:03:49.850,0:03:52.420 예를 들어 [br]한국어로 된 문장들을 입력하면 0:03:52.420,0:03:56.290 영어로 된 새로운[br]문장으로 번역하는 것이죠 0:03:56.290,0:03:59.250 이런 형태를 가지는 RNN 모델이[br]자주 사용됩니다 0:03:59.250,0:04:03.210 RNN에 대해 이야기해야 할[br]주제가 여러 가지 있는데요 0:04:03.210,0:04:05.740 먼저 기본적인 내용을 공부하고 0:04:05.740,0:04:11.420 이 RNN으로 매우 간단한[br]언어 모델을 학습시킬 겁니다 0:04:11.420,0:04:14.050 'hello'를 말할 수 있게[br]학습시켜 보도록 하죠 0:04:14.050,0:04:18.338 RNN으로 분류도 해볼 겁니다 0:04:18.338,0:04:22.028 또 더 나은 언어 모델을[br]만들어 보고 0:04:22.028,0:04:25.510 마지막으로 시퀀스에서[br]시퀀스 만드는 것을 해보겠습니다 0:04:25.510,0:04:28.660 이 강의에서 하나씩[br]해보도록 하겠습니다 0:04:28.660,0:04:31.139 이 RNN을 사용해보기 전에 0:04:31.139,0:04:33.220 이것에 대해 약간[br]더 자세히 알아보도록 하죠 0:04:33.220,0:04:37.310 보통 RNN을 표현하기 위해[br]이러한 다이어그램을 사용합니다 0:04:37.310,0:04:39.860 이건 여기 굉장히 유명한[br]블로그에서 가져왔고요 0:04:39.860,0:04:43.169 내부를 보면[br]굉장히 간단합니다 0:04:43.169,0:04:46.160 한 개의 입력을 x라고 한다면 0:04:46.160,0:04:49.330 여기서 출력을 생성하게 되죠 0:04:49.330,0:04:52.630 이 출력값을 얻기 위해서[br]우리가 해야 하는 것은 0:04:52.630,0:04:57.120 이전 셀의 은닉 상태를[br]알아내는 것입니다 0:04:57.120,0:04:58.530 그리고 이것을 연결시키죠 0:04:58.530,0:05:01.330 이제 여기서 행렬곱을 계산합니다 0:05:01.330,0:05:03.940 h₁₀이 나올 때까지 말이죠 0:05:03.940,0:05:08.750 그리고 이 값을 분리해서[br]한 개는 출력값으로 하고 0:05:08.750,0:05:11.580 다른 값은 다음 셀에 넘겨줍니다 0:05:11.580,0:05:14.800 이것이 굉장히 간단하고[br]일반적인 형태의 RNN입니다 0:05:14.800,0:05:18.420 PyTorch를 이용해 [br]RNN을 사용하기 위해서는 0:05:18.420,0:05:20.760 세부적인 내용을[br]모두 이해할 필요는 없습니다 0:05:20.760,0:05:25.930 단순하게 RNN을 [br]이런 방식으로 사용하면 되죠 0:05:25.930,0:05:28.580 우리가 설정해야 하는 부분은[br] 0:05:28.580,0:05:32.250 입력의 개수와[br]출력의 개수입니다 0:05:32.250,0:05:35.690 여기에서는 출력의 개수를[br]hidden_size라고 표현합니다 0:05:35.690,0:05:38.760 그리고 어떻게 데이터를[br]정렬할 것인지를 정해주는데요 0:05:38.760,0:05:42.180 이 부분은 batch_first라는[br]옵션을 통해 정할 수 있습니다 0:05:42.180,0:05:46.510 여기에선 이 batch_first를[br]포함시키도록 하겠습니다 0:05:46.510,0:05:48.149 RNN을 사용하는 것뿐만 아니라 0:05:48.149,0:05:50.130 GRU을 사용할 수도 있고 0:05:50.130,0:05:53.820 LSTM이라고 부르는 아주 유명한[br]RNN을 사용할 수도 있습니다 0:05:53.820,0:05:57.039 모두 동일한 상태에서[br]이름만 바꿔서 사용할 수 있습니다 0:05:57.039,0:06:02.550 따라서 다양한 형태의 RNN을[br]모두 사용할 수 있죠 0:06:02.550,0:06:06.850 예시로 RNN을 사용해 봅시다 0:06:06.850,0:06:09.300 여기서 input_size는 4로 설정하고 0:06:09.300,0:06:12.190 출력값의 개수인[br]hidden_size는 2로 설정하겠습니다 0:06:12.190,0:06:16.730 이것은 각 입력 벡터의[br]크기가 4가 되고 0:06:16.730,0:06:20.050 출력은 2개의 값을 가지게 되므로 0:06:20.050,0:06:21.640 벡터의 크기는 2가 되겠죠 0:06:21.640,0:06:24.040 여기서 입력을 정하는데요 0:06:24.040,0:06:28.260 이 RNN은 [br]은닉 입력값도 필요로 합니다 0:06:28.260,0:06:30.030 초기값으로 말이죠 0:06:30.030,0:06:33.219 초기 hidden 값을[br]만들어주어야 합니다 0:06:33.219,0:06:36.339 여기에 넣어주면 됩니다 0:06:36.339,0:06:38.969 inputs는 여기에 넣고[br]hidden은 여기에 넣으면 되죠 0:06:38.969,0:06:42.069 이제 cell이 우리가 사용할 [br]RNN이 되겠죠 0:06:42.069,0:06:47.730 이 hidden은 일단 한번[br]cell을 실행하고 나면 0:06:47.730,0:06:50.739 한 개의 출력값을 생성하고 0:06:50.739,0:06:52.270 이 경우엔 이 값이 되겠죠 0:06:52.270,0:06:54.290 여기가 출력값이 되고 0:06:54.290,0:06:57.999 이 부분은[br]은닉 상태로 사용하는 것이죠 0:06:57.999,0:07:01.839 이 hidden은 다음 셀에서 사용됩니다 0:07:01.839,0:07:07.499 여기서 이것을 한 번 더 호출할 때[br]이 hidden 값이 사용되는 것이죠 0:07:07.499,0:07:11.809 예를 들자면 또 다른 입력값들과[br] 0:07:11.809,0:07:15.549 이 hidden이 여기에[br]다시 사용됩니다 0:07:15.549,0:07:19.760 이것이 RNN에[br]일반적으로 사용되는 개념이죠 0:07:19.760,0:07:24.480 이 hidden 값은 다음 셀로[br]넘어가서 사용된다는 것입니다 0:07:24.480,0:07:29.599 실제 예시로[br]실제로 글자를 넣어보겠습니다 0:07:29.599,0:07:32.479 h, e, l, l, o를 RNN에 넣어 봅시다 0:07:32.479,0:07:36.229 이 글자들을 [br]입력값으로 설정하는 거죠 0:07:36.229,0:07:37.479 어떻게 해야 할까요? 0:07:37.479,0:07:43.639 각 글자를 다루는[br]간단한 방법 한가지는[br] 0:07:43.639,0:07:47.139 원-핫 인코딩으로 바꾸는 방법입니다 0:07:47.139,0:07:50.339 먼저 모든 글자를 한번에 모은 후 0:07:50.339,0:07:51.689 각각에 식별자를 부여합니다 0:07:51.689,0:07:55.869 0, 1, 2가 되겠죠 0:07:55.869,0:07:59.059 고유한 식별자이기 때문에[br]이건 동일한 값을 가집니다 0:07:59.059,0:08:00.349 그리고 여기는 3이 되죠 0:08:00.349,0:08:02.849 이제 각각에[br]원-핫 인코딩을 해 봅시다 0:08:02.849,0:08:05.189 예를 들어 여기에서[br]h는 0이기 때문에 0:08:05.189,0:08:06.679 이것은 0 원-핫이 됩니다 0:08:06.679,0:08:09.219 따라서 [1, 0, 0, 0]이 되죠 0:08:09.219,0:08:13.989 e는 1이므로[br][0, 1, 0, 0]이 됩니다 0:08:13.989,0:08:18.019 이렇게 각 글자를[br]원-핫 인코딩으로 정의할 수 있죠 0:08:18.019,0:08:19.869 이제 이것을 사용해 봅시다 0:08:19.869,0:08:24.209 여기서 단순하게 어떤 값을[br]넣어주는 것이 아니라 0:08:24.209,0:08:27.709 입력에 원-핫으로 [br]만들어진 값을 넣어줍니다 0:08:27.709,0:08:31.049 이 경우에 [br]입력 벡터의 차원은 4가 됩니다 0:08:31.049,0:08:35.219 각 벡터에 4개의 값이[br]포함됨을 의미하죠 0:08:35.219,0:08:36.599 이 값을 넣어주는 겁니다 0:08:36.599,0:08:38.029 이런 방식을 사용합니다 0:08:38.029,0:08:43.190 이제 이 셀의 출력값이[br]두 개임을 알고 있습니다[br] 0:08:43.190,0:08:45.389 hidden_size를 [br]2로 설정했기 때문이죠 0:08:45.389,0:08:46.550 따라서 출력값의 개수는[br]2개가 됩니다 0:08:46.550,0:08:52.860 따라서 이 셀에서는[br]2개의 값을 얻게 되죠 0:08:52.860,0:08:58.809 이 RNN 셀을 사용하는[br]기본적인 방법이라고 할 수 있죠 0:08:58.809,0:09:00.669 이제 코드를 한 번 봅시다 0:09:00.669,0:09:04.750 먼저 RNN을 사용해서[br]cell을 생성합니다 0:09:04.750,0:09:10.039 입력 개수와 출력 개수만[br]설정해주면 되죠 0:09:10.039,0:09:12.430 그리고 이제 입력값을 만듭니다 0:09:12.430,0:09:18.460 여기서 h를 [br]원-핫 벡터로 정의했었죠 0:09:18.460,0:09:21.650 따라서 여기서 변수 h를 넣어줍니다 0:09:21.650,0:09:25.719 그리고 이것을[br]벡터로 만들어줍니다 0:09:25.719,0:09:28.220 지금 하려고 하는 것은[br]rank를 만들고자 하는 건데요 0:09:28.220,0:09:30.180 (1, 1, 4)로 만들겁니다 0:09:30.180,0:09:32.250 여기서 가장 중요한 부분은 0:09:32.250,0:09:33.710 입력의 개수가 4이므로[br] 0:09:33.710,0:09:36.890 원-핫으로 만들어진[br]h는 네 개의 백터라는 것입니다 0:09:36.890,0:09:40.650 이렇게 inputs를 만들었고요 0:09:40.650,0:09:44.040 이제 hidden을 만들어보겠습니다 0:09:44.040,0:09:48.800 초기 hidden 값을 입력해야 하죠 0:09:48.800,0:09:53.259 이것은 이러한 방법으로 할 건데요 0:09:53.259,0:09:56.160 hidden_size를 가지고[br]레이어의 개수를 구할 수 있습니다 0:09:56.160,0:09:57.550 여기서는 디렉션의 개수가 되죠 0:09:57.550,0:10:00.349 batch의 크기와[br]hidden_size를 이용합니다 0:10:00.349,0:10:02.000 이건 출력의 개수와 같죠 0:10:02.000,0:10:06.700 이 경우에는 레이어 한 개와[br]디렉션 한 개만 사용할 겁니다 0:10:06.700,0:10:08.229 따라서 1이 되죠 0:10:08.229,0:10:12.550 이 예시에서 batch 또한 1이 됩니다 0:10:12.550,0:10:15.509 한 개의 배치만 사용하는 거죠 0:10:15.509,0:10:17.569 그리고 출력의 개수인[br]hidden_size는 2가 되죠 0:10:17.569,0:10:19.369 따라서 이렇게 만들 수 있습니다 0:10:19.369,0:10:22.690 초기값이므로 단순히[br]임의의 값을 만들고 0:10:22.690,0:10:24.200 그 값을 넣어줍니다 0:10:24.200,0:10:27.329 이제 이 cell을 호출하겠습니다 0:10:27.329,0:10:32.670 방금 만들었던 inputs와[br]초기 hidden값을 이용하죠 0:10:32.670,0:10:38.069 이렇게 넣어주면[br]출력값과 hidden값이 생깁니다 0:10:38.069,0:10:40.470 hidden의 경우[br]이 cell을 다시 호출하게 되면 0:10:40.470,0:10:42.089 이 hidden값을 사용하게 되죠 0:10:42.089,0:10:44.490 따라서 다음 셀과 연결시키는 것이죠 0:10:44.490,0:10:47.199 이것을 출력해보면[br]우리가 알고 있듯이 0:10:47.199,0:10:52.160 hidden_size가 2이므로[br]두 개의 값을 얻게 됩니다[br] 0:10:52.160,0:10:55.620 여기서 두 개의 벡터 값이[br]나오는 이유가 그것이죠 0:10:55.620,0:11:00.509 이제부터 할 것은[br]굉장히 쉬운 내용인데요 0:11:00.509,0:11:05.209 어떻게 이 RNN 셀이[br]작동하는지 보도록 하죠 0:11:05.209,0:11:09.680 우리는 한 글자씩[br]일일이 넣는 것을 원하지 않죠 0:11:09.680,0:11:12.760 굉장히 느리고 비효율적입니다 0:11:12.760,0:11:13.719 따라서 여기서 할 것은[br] 0:11:13.719,0:11:17.210 동시에 여러 글자를[br]넣어주는 것입니다 0:11:17.210,0:11:20.780 RNN에서는 이러한 것을[br]시퀀스라고 부릅니다 0:11:20.780,0:11:23.310 이전의 시퀀스 크기는 1이었지만 0:11:23.310,0:11:26.660 지금 우리가 하려고 하는 것에는[br]한 글자만 넣는 것이 아니라 0:11:26.660,0:11:30.230 h, e, l, l, o를 넣게 되는 거죠 0:11:30.230,0:11:31.580 총 5개의 글자입니다 0:11:31.580,0:11:34.420 따라서 시퀀스의 크기가[br]5라고 할 수 있죠 0:11:34.420,0:11:37.580 시퀀스 사이즈가 5인 [br]이 경우에는 어떻게 해야 할까요? 0:11:37.580,0:11:39.640 다른 것들은 바꿀 필요 없이 0:11:39.640,0:11:42.310 입력의 형태만 바꿔주면 됩니다 0:11:42.310,0:11:45.650 이전에는 (1, 1, 4)의 형태였죠 0:11:45.650,0:11:49.219 배치가 1이고[br]시퀀스도 한 개였습니다 0:11:49.219,0:11:51.129 글자 한 개였죠 0:11:51.129,0:11:52.770 한 개의 글자는[br]벡터의 크기가 4였습니다 0:11:52.770,0:11:56.089 하지만 지금 보는 것에서는[br]이 부분이 바뀌어야 합니다 0:11:56.089,0:11:58.060 시퀀스가 들어가는 부분이죠 0:11:58.060,0:12:01.840 이런 형태의[br]데이터셋을 준비하고 0:12:01.840,0:12:03.720 이것들을 우리가 만든[br]셀에 넣어줍니다 0:12:03.720,0:12:06.369 바로 이렇게 됩니다 0:12:06.369,0:12:08.290 소스 코드를 한 번 보죠 0:12:08.290,0:12:12.720 이전과 비슷하게[br]이 RNN 셀을 만듭니다 0:12:12.720,0:12:15.680 input_size가 4이고[br]hidden_size는 2가 됩니다 0:12:15.680,0:12:21.869 여기서 차이점은 [br]더 많은 데이터를 넣는 것인데요 0:12:21.869,0:12:24.339 한 글자만 넣는 것이 아니라 0:12:24.339,0:12:26.040 여러 개의 글자를 넣는 것이죠 0:12:26.040,0:12:29.870 크기가 5인 시퀀스가 됩니다 0:12:29.870,0:12:38.090 따라서 이것의 형태는[br](1, 5, 4)가 될 겁니다 0:12:38.090,0:12:43.549 그리고 이제 [br]이 hidden값을 생성하죠 0:12:43.549,0:12:45.400 이것은 이전과 동일합니다 0:12:45.400,0:12:46.760 이것을 셀에 넘겨주고 0:12:46.760,0:12:48.970 출력값들을 보면 0:12:48.970,0:12:53.380 여기가 시퀀스 크기가 되고 0:12:53.380,0:12:55.040 2는 출력값의 크기가[br]되는 것을 알 수 있습니다 0:12:55.040,0:12:58.750 따라서 이 값들을 그대로[br]셀에 넘겨주면 되죠 0:12:58.750,0:13:03.029 여기서 차이점은[br]다른 형태의 입력값을 만든 건데요 0:13:03.029,0:13:06.470 따라서 이 RNN이[br]이것을 잘 다룰 수 있게 되는 것이죠 0:13:06.470,0:13:10.710 마지막으로 한 번에 [br]한 개의 글자만 다루거나 0:13:10.710,0:13:12.830 한 단어만 다루는 것은[br]부족할 겁니다 0:13:12.830,0:13:14.720 따라서 여러 개의[br]단어를 한 번에 넣고자 하는데요 0:13:14.720,0:13:20.110 예를 들어 여기에서는[br]hello, eolll, lleel을 넣는 거죠 0:13:20.110,0:13:23.170 여러 개를 한 번에 넣고자 하는 겁니다 0:13:23.170,0:13:25.780 이러한 경우를 배치라고 합니다 0:13:25.780,0:13:28.020 여기에서도 [br]다른 것은 모두 동일합니다 0:13:28.020,0:13:30.760 입력의 형태만 바뀌게 되는데요 0:13:30.760,0:13:35.790 이전엔 이 값이 1이었지만[br]이제 3이 됩니다 0:13:35.790,0:13:38.680 3개의 배치를 가진다는 의미죠 0:13:38.680,0:13:41.320 소스 코드에서 [br]어떻게 되는지 보겠습니다 0:13:41.320,0:13:43.070 이전과 굉장히 비슷한데요 0:13:43.070,0:13:47.860 이렇게 세 개의 배치가 있을 겁니다 0:13:47.860,0:13:49.850 그리고 이것들을 넣어줄 건데요 0:13:49.850,0:13:51.930 이 rank에 집중해봅시다 0:13:51.930,0:13:54.720 3은 배치의 개수를 뜻하죠 0:13:54.720,0:14:00.020 5는 시퀀스 크기를 의미합니다 0:14:00.020,0:14:05.370 이것은 원-핫의 크기를 뜻하죠 0:14:05.370,0:14:06.890 따라서 이 배치를[br]넣을 수 있게 됩니다 0:14:06.890,0:14:09.700 이 옵션을 사용한 이유가[br]여기에 있습니다 0:14:09.700,0:14:12.080 batch_first를 True로 설정했죠 0:14:12.080,0:14:15.410 따라서 이 값을 inputs로 사용하게 됩니다 0:14:15.410,0:14:17.540 hidden에서 다른 점은 [br] 0:14:17.540,0:14:20.630 이 batch 값에 [br]3을 넣는 다는 건데요 0:14:20.630,0:14:24.780 따라서 3개의 배치를[br]사용하는 것으로 바꿔줍니다 0:14:24.780,0:14:30.640 그리고 이제 이전과 동일하게[br]cell을 호출합니다 0:14:30.640,0:14:33.770 그렇게 되면 예측값은 0:14:33.770,0:14:39.060 배치의 크기는 3[br]시퀀스 크기는 5가 되고 0:14:39.060,0:14:45.340 그리고 이 부분이[br]은닉 출력값이 되는 것이죠 0:14:45.340,0:14:47.280 이런 형태를 얻게 될 겁니다 0:14:47.280,0:14:49.370 이제부터 보실 내용은 0:14:49.370,0:14:56.860 각 셀에서 데이터를 RNN 셀에게[br]어떻게 넘겨주는지를 이해하는 부분인데요 0:14:56.860,0:15:01.310 여기서 하려는 것은[br]실제로 이 모델을 훈련시켜서 0:15:01.310,0:15:03.470 의미있는 작업을 [br]할 수 있도록 하는 겁니다 0:15:03.470,0:15:05.980 이 예시는 매우 간단합니다 0:15:05.980,0:15:10.730 여기서 학습시키고자 하는 것은[br]'hihello'를 말하도록 하는 것인데요 0:15:10.730,0:15:15.210 이 RNN 셀들에 [br]한 글자씩을 넣어줍니다 0:15:15.210,0:15:19.280 그러면 이 RNN은 [br]다음 글자가 i라고 예측하는 것이죠 0:15:19.280,0:15:21.100 그리고 i를 넣어주면[br] 0:15:21.100,0:15:24.220 그것에 대한 다음 글자를 예측합니다 0:15:24.220,0:15:26.350 이 경우엔 h가 되겠죠 0:15:26.350,0:15:31.120 주어진 글자에 대해 0:15:31.120,0:15:35.740 다음 글자가 무엇이 될지[br]예측하는 동작을 합니다 0:15:35.740,0:15:38.779 그러면 이 RNN을[br]어떻게 디자인해야 할까요? 0:15:38.779,0:15:40.730 기본적으로 입력값들은 0:15:40.730,0:15:43.880 이 경우에는[br]단어가 몇 개 더 있죠 0:15:43.880,0:15:47.690 h, i, e, l, o[br]다섯 개의 글자가 있고요 0:15:47.690,0:15:52.750 이것들을 5개의[br]원-핫으로 만들 수 있습니다[br] 0:15:52.750,0:15:56.430 따라서 입력의 크기는 [br]5가 될 것입니다 0:15:56.430,0:15:58.570 출력도 동일하겠죠 0:15:58.570,0:16:00.100 따라서 출력의 크기도 5가 됩니다 0:16:00.100,0:16:02.260 여기에서 예측하고자 하는 것은 0:16:02.260,0:16:06.020 5개의 글자 중 [br]어떠한 한 개이기 때문이죠 0:16:06.020,0:16:09.860 따라서 이건 5가지 중에서의[br]다중 분류가 되겠네요 0:16:09.860,0:16:13.580 따라서 이건 5가지 중에서의[br]다중 분류가 되겠네요 0:16:13.580,0:16:16.670 따라서 출력값도[br]5개가 나올 것이라 생각할 수 있죠 0:16:16.670,0:16:18.750 우리가 만든 신경망은 이렇게 되겠죠 0:16:18.750,0:16:21.229 그러면 이제 손실 함수는[br]어떻게 디자인해야 할까요? 0:16:21.229,0:16:25.220 손실 함수를 디자인하면[br]역전파를 할 수 있죠 0:16:25.220,0:16:28.540 따라서 이 신경망을[br]훈련시킬 수 있습니다 0:16:28.540,0:16:32.400 간단하게 입력의 차원이 5라면 0:16:32.400,0:16:36.820 출력 또한 5개의 차원을 가지고 생성됩니다 0:16:36.820,0:16:38.180 이것은 레이블인데요 0:16:38.180,0:16:39.970 이 값이 y값이 되는 거죠 0:16:39.970,0:16:41.149 정답일 수도 있고요 0:16:41.149,0:16:43.659 y의 예측값이 됩니다 0:16:43.659,0:16:47.480 이제 이것으로[br]차이를 계산할 수 있습니다 0:16:47.480,0:16:49.520 그것을 손실이라고 부르는데요 0:16:49.520,0:16:53.280 이 경우는[br]다중 분류이기 때문에 0:16:53.280,0:16:55.459 다중 분류의 경우는 0:16:55.459,0:16:58.330 크로스 엔트로피를 사용합니다 0:16:58.330,0:17:02.360 이것뿐만 아니라 0:17:02.360,0:17:05.579 각 글자에 대해[br]손실 함수를 적용하고 0:17:05.579,0:17:08.309 이 손실을 모두 더해서 0:17:08.309,0:17:11.189 손실 값을 최소화하도록 하는 겁니다 0:17:11.189,0:17:13.460 소스 코드를 한번 보도록 하죠 0:17:13.460,0:17:19.028 가장 먼저 각 글자에 대해[br]고유한 인덱스를 만들어야 합니다 0:17:19.028,0:17:22.879 여기서는 h, i, e, l, o가 있죠 0:17:22.879,0:17:28.619 각각 0, 1, 2, 3, 4가 됩니다 0:17:28.619,0:17:34.960 여기서 이 x_data로[br]hihell를 표현하겠습니다 0:17:34.960,0:17:39.470 인덱스를 사용해서 [br]0, 1, 0, 2, 3, 3으로 표현할 수 있습니다 0:17:39.470,0:17:42.160 그리고 이것을 원-핫으로 표현합니다 0:17:42.160,0:17:44.640 이렇게 원-핫을 만들고 0:17:44.640,0:17:46.950 y_data는 레이블 값입니다 0:17:46.950,0:17:49.289 이 값이 예측하고자 하는 값이죠 0:17:49.289,0:17:52.649 hiello가 올바른 값이죠 0:17:52.649,0:17:55.239 h가 주어지면[br]예측값은 i가 됩니다 0:17:55.239,0:17:57.569 i에 대해서는[br]h가 예측값이 되죠 0:17:57.569,0:18:01.070 따라서 이것을 각각의[br]id로 표현하면 이렇게 됩니다 0:18:01.070,0:18:06.719 1은 i가 되고 [br]0은 h, ... 등등이 되겠죠 0:18:06.719,0:18:10.179 그리고 Variable을[br]이용해 입력값을 만들어줍니다 0:18:10.179,0:18:15.139 또한 레이블도 만들어줍니다 0:18:15.139,0:18:18.469 원-핫 룩업을 만드는 [br]더 좋은 방법은 0:18:18.469,0:18:21.819 룩업 테이블처럼 만드는 것입니다 0:18:21.819,0:18:23.760 파이썬에서의 표현을 이용하는데요 0:18:23.760,0:18:29.950 이 x_data를 나눠서[br]각 x 값을 얻어냅니다 0:18:29.950,0:18:32.430 그리고 이 원-핫 룩업 테이블을 사용해 0:18:32.430,0:18:33.899 각 원-핫을 만들어낼 수 있습니다 0:18:33.899,0:18:39.629 원-핫 벡터를 얻는[br]약간 더 좋은 방법이죠 0:18:39.629,0:18:42.119 이제 나머지 부분은 동일합니다 0:18:42.119,0:18:44.730 몇 가지 매개변수를 설정해야 하는데요 0:18:44.730,0:18:46.420 클래스의 개수는 5가 되고 0:18:46.420,0:18:49.559 입력의 크기도 5가 됩니다 0:18:49.559,0:18:51.770 그리고 hidden_size [br]즉 출력의 크기도 5가 됩니다 0:18:51.770,0:18:55.090 배치는 한 개가 될 것이고[br]시퀀스의 길이도 1이 됩니다 0:18:55.090,0:18:56.320 레이어의 개수도 1개가 되죠 0:18:56.320,0:19:00.570 한 곳에 모든 매개변수를 [br]선언하면 매우 좋은데요 0:19:00.570,0:19:03.970 필요할 때 값을 [br]바꾸기만 하면 되기 때문이죠 0:19:03.970,0:19:07.089 우리의 모델은[br]PyTorch를 사용할 겁니다 0:19:07.089,0:19:09.680 클래스를 하나 만들고 0:19:09.680,0:19:13.820 먼저 초기화 함수 부분을 보도록 하죠 0:19:13.820,0:19:17.690 여기서 먼저 하는 것은[br]RNN을 생성하는 것입니다 0:19:17.690,0:19:20.210 주어진 input_size와[br]hidden_size로 생성하죠 0:19:20.210,0:19:24.690 새로운 RNN 셀을 한 개 생성합니다 0:19:24.690,0:19:26.380 forward 함수에서는 0:19:26.380,0:19:29.160 입력값으로 x값을 받고 0:19:29.160,0:19:32.890 두 번째 입력값으로[br]hidden을 받습니다 0:19:32.890,0:19:36.840 이 값들을 여기에 넣어줄 겁니다 0:19:36.840,0:19:38.330 이게 기본적인 개념인데요 0:19:38.330,0:19:42.690 이것을 하기 전에 x가 어떤 형태인지[br]확실히 보도록 합시다[br] 0:19:42.690,0:19:45.660 batch size, sequence length[br]input size를 통해서 말이죠 0:19:45.660,0:19:49.570 x가 올바른 형태인지 확인한 후에 0:19:49.570,0:19:52.050 이 x를 여기로 넘겨줄 겁니다 0:19:52.050,0:19:54.160 따라서 hidden을 얻을 수 있습니다 0:19:54.160,0:19:55.640 그리고 출력값의 경우에는 0:19:55.640,0:19:58.280 일단 RNN에서[br]출력값을 얻게 되면 0:19:58.280,0:20:01.530 이제 손실값을 [br]계산해야 합니다 0:20:01.530,0:20:07.690 따라서 출력 rank의 실제 크기가 어떻게 될지[br]생각해보아야 하죠 0:20:07.690,0:20:10.190 우리가 디자인해야 할[br]출력의 형태를 생각해야 하는 거죠 0:20:10.190,0:20:11.750 생각해 봅시다 0:20:11.750,0:20:13.490 우리가 여기서[br]하고자 하는 것은 0:20:13.490,0:20:17.050 다섯 개의 값들 중에서[br]한 개를 에측하는 것이죠 0:20:17.050,0:20:21.830 출력에서 몇 개의 글자가 있는지 모르고 있죠 0:20:21.830,0:20:23.940 또는 몇 개의 시퀀스가 있는지 말이죠 0:20:23.940,0:20:25.370 물론 이 값은 N이 되겠죠 0:20:25.370,0:20:29.420 하지만 지금 예측하려는[br]실제 값은 1과 5가 될 겁니다 0:20:29.420,0:20:37.590 따라서 y 예측값은[br]N × 5 행렬이 됩니다 0:20:37.590,0:20:40.490 따라서 이 출력값들에 대해[br]알아두셔야 할 부분은 0:20:40.490,0:20:43.190 reshape를 사용할 것이라는 점이죠 0:20:43.190,0:20:44.940 이렇게 5를 넣어서 말이죠 0:20:44.940,0:20:49.700 이 값에 n을 넣고[br] 0:20:49.700,0:20:52.890 그리고 벡터의 크기에는[br]5를 넣는 것이죠 0:20:52.890,0:20:56.030 이러한 방법으로 출력값을 만듭니다 0:20:56.030,0:20:59.000 손실값을 더 효율적으로[br]계산하기 위해서죠 0:20:59.000,0:21:03.950 이렇게 해서 출력값이[br]이 형태를 가지도록 하는 겁니다 0:21:03.950,0:21:08.130 이 출력값을 이용해[br]손실을 계산할 수 있습니다 0:21:08.130,0:21:12.300 손실은 [br]크로스-엔트로피를 사용할 건데요 0:21:12.300,0:21:14.540 이전 강의에서도 사용했었죠 0:21:14.540,0:21:18.080 여태까지 본 것이 기본이 되고 0:21:18.080,0:21:23.630 이제 하려는 것은[br]이 글자들을 한 개씩 넣어서 0:21:23.630,0:21:29.390 출력값을 얻고[br]손실을 계산하는 것이죠 0:21:29.390,0:21:31.850 이것을 하면서[br] 0:21:31.850,0:21:35.540 이전 셀로부터[br]은닉 상태를 계속 넘겨줍니다[br] 0:21:35.540,0:21:39.600 모든 은닉 상태는[br]이전 셀에서 얻을 수 있죠 0:21:39.600,0:21:40.770 이것을 해볼 텐데요 0:21:40.770,0:21:46.079 for문을 사용해서[br]간단하게 구현할 수 있습니다 0:21:46.079,0:21:49.729 먼저 손실은 0에서 시작합니다 0:21:49.729,0:21:54.130 그리고 이 모델에 대한[br]초기 은닉 상태 값을 얻습니다 0:21:54.130,0:21:58.000 for문에서 [br]각 입력값을 얻어내는데요 0:21:58.000,0:21:59.679 각 한 글자씩을 얻고 0:21:59.679,0:22:02.329 각 레이블을 한 개씩 얻습니다 0:22:02.329,0:22:06.780 그리고 이 모델을 실행시키죠 0:22:06.780,0:22:09.950 inputs와 hidden을 넣어줍니다 0:22:09.950,0:22:13.209 그렇게 output과[br]hidden을 생성하죠 0:22:13.209,0:22:17.450 그리고 이 output은[br]레이블 값을 이용해서 0:22:17.450,0:22:20.180 손실을 계산하기[br]위해 사용됩니다 0:22:20.180,0:22:21.950 그리고 손실 값을[br]계속해서 누적되죠 0:22:21.950,0:22:24.340 그리고 다음 루프에서[br]이 hidden을 보면 0:22:24.340,0:22:28.340 이 hidden은[br]다음 셀의 입력으로 사용됩니다 0:22:28.340,0:22:29.350 다음 모델에 이용되죠 0:22:29.350,0:22:31.870 여기서 사용되는 거죠 0:22:31.870,0:22:38.080 다음 셀의 hidden 값으로[br]이용되는 것입니다 0:22:38.080,0:22:42.270 손실을 계산한 후에[br]backward()를 호출하여 0:22:42.270,0:22:45.160 이 모델을 다시 훈련시킵니다 0:22:45.160,0:22:47.049 한 번에 하나씩 이루어지죠 0:22:47.049,0:22:50.580 전체적인 코드입니다 0:22:50.580,0:22:53.300 각 반복, 즉 각 훈련마다 0:22:53.300,0:22:57.960 모델이 실제로 예측할 것이[br]무엇인지 알 수 있습니다 0:22:57.960,0:23:00.630 이 출력은 예측값을 포함하고 있죠 0:23:00.630,0:23:04.520 이 값을 출력해서[br] 0:23:04.520,0:23:06.500 모델이 어떻게 [br]동작하는지 볼 수 있겠죠[br] 0:23:06.500,0:23:09.279 예상하시는 것처럼[br]처음 시작 부분에는 0:23:09.279,0:23:10.840 손실값은 상당히 높습니다 0:23:10.840,0:23:14.000 그리고 예측값은[br]거의 무작위 상태입니다 0:23:14.000,0:23:18.070 시간이 지날수록[br]다음 글자를 잘 예측하게 되죠 0:23:18.070,0:23:20.749 상당히 좋지만[br]한 가지 문제가 있습니다 0:23:20.749,0:23:24.630 여기에서 각 글자마다 반복문을 [br]실행하고 싶지 않다는 것이죠 0:23:24.630,0:23:29.549 이전에 했던 것과 같이[br]한 번에 모두 넣을 수 있어야 합니다 0:23:29.549,0:23:31.629 이건 쉬운데요 0:23:31.629,0:23:35.200 기본적으로 이전과 같이[br]모델을 만들 수도 있습니다 0:23:35.200,0:23:39.050 하지만 한 글자씩을[br]넣고 루프를 실행하는 것보다 0:23:39.050,0:23:41.420 전체 입력을[br]한 번에 넣을 수도 있습니다 0:23:41.420,0:23:44.720 이전 예시에서[br]했던 것과 완전히 똑같죠 0:23:44.720,0:23:48.000 다른 것은 모두 동일하면서 [br]입력값만 바뀝니다 0:23:48.000,0:23:50.080 그리고 레이블도 넣어줍니다 0:23:50.080,0:23:53.020 따라서 손실값을 얻을 수 있죠 0:23:53.020,0:23:58.350 여기서 모든 inputs와 [br]초기 은닉 값으로 모델을 수행하고 0:23:58.350,0:23:59.900 출력값을 생성합니다 0:23:59.900,0:24:02.810 그리고 이 출력값과[br]레이블 값을 이용해서 0:24:02.810,0:24:04.070 손실값을 얻을 수 있습니다 0:24:04.070,0:24:05.580 정확히 동일한 형태죠 0:24:05.580,0:24:10.500 반복문을 사용하지 않고[br]전체 입력을 한번에 넣어줍니다 0:24:10.500,0:24:12.840 이렇게 손실 함수를[br]계산할 수 있습니다 0:24:12.840,0:24:15.120 좋습니다[br]설명은 여기까지고요 0:24:15.120,0:24:18.390 연습을 위해서[br]해보아야 할 것은 0:24:18.390,0:24:23.380 이제 다중 소프트맥스 분류기를[br]구현할 수 있기 때문에 0:24:23.380,0:24:28.230 주어진 글자에 대해[br]다음 글자를 예측하도록 만들 수 있죠 0:24:28.230,0:24:30.460 다음 글자를 예측할 때 0:24:30.460,0:24:32.390 소프트맥스 분류를 사용하면 됩니다 0:24:32.390,0:24:32.980 가능할까요? 0:24:32.980,0:24:35.060 이게 이번에 할 연습입니다 0:24:35.060,0:24:36.560 시도해보신다면 0:24:36.560,0:24:39.700 잘 동작하지 않는[br]이유를 설명할 수 있을 겁니다 0:24:39.700,0:24:41.460 그 이유 중 하나는[br] 0:24:41.460,0:24:45.770 각 소프트맥스가[br]이전 데이터를 받지 않기 때문이죠 0:24:45.770,0:24:47.950 이전 데이터는[br]전혀 알 수가 없어요 0:24:47.950,0:24:49.030 주어진 상태만 가지고[br] 0:24:49.030,0:24:51.990 다음 상태를[br]예측하는 것은 어려운 일이죠 0:24:52.000,0:24:59.830 다음 연습 문제는[br]이 RNN과 0:24:59.830,0:25:04.050 소프트맥스 분류기를[br]결합하는 것입니다 0:25:04.050,0:25:06.410 이건 굉장히[br]일반적인 모델인데요 0:25:06.410,0:25:08.080 이 RNN을 사용하면서 0:25:08.080,0:25:13.060 이 RNN 위에[br]또 다른 완전 연결 층을 추가합니다 0:25:13.060,0:25:14.300 이 문제는 굉장히 어렵습니다 0:25:14.300,0:25:15.880 이것을 직접 해보시면[br] 0:25:15.880,0:25:17.070 좀 더 빠르게 [br]훈련시킬 수 있습니다 0:25:17.070,0:25:21.860 왜 이것이 더 빠르고[br]안정적인지 생각해보아야겠죠 0:25:21.860,0:25:25.809 우리가 사용한 예시에서는[br]원-핫 인코딩을 사용했죠 0:25:25.809,0:25:28.770 굉장히 간단했습니다 0:25:28.770,0:25:31.200 또 다른 방법이 있는데요 0:25:31.200,0:25:33.470 가끔 이게 더 좋은 방법이기도 하죠 0:25:33.470,0:25:35.780 임베딩이라는 [br]개념을 사용하는 건데요 0:25:35.780,0:25:38.320 원-핫 방식과 동일한데요 0:25:38.320,0:25:41.509 원-핫의 경우 [br]고정된 값을 사용합니다 0:25:41.509,0:25:42.770 하지만 임베딩의 경우[br] 0:25:42.770,0:25:45.280 예를 들어 여기에[br]몇 가지 인덱스가 있을 때 0:25:45.280,0:25:46.910 각각에 값을 부여합니다 0:25:46.910,0:25:51.170 이 값은 훈련시킬 수 있는 값인데요 0:25:51.170,0:25:57.159 이 훈련 가능한 값은[br]향상된 모델을 만들도록 도와줍니다 0:25:57.159,0:25:59.330 이것을 사용하는 방법은[br]굉장히 간단합니다 0:25:59.330,0:26:01.740 이렇게 단순히[br]임베딩을 생성하면 되죠 0:26:01.740,0:26:06.780 단어의 크기와[br]출력의 크기를 넣어주면 됩니다 0:26:06.780,0:26:08.520 이렇게 정의한 후에 0:26:08.520,0:26:11.130 이 x 입력값을 넣어주면[br] 0:26:11.130,0:26:13.860 임베딩을 생성해주죠 0:26:13.860,0:26:16.920 예시로 이러한[br]임베딩을 만들 수 있는 거죠 0:26:16.920,0:26:19.830 단어 크기와 임베딩 크기는 이렇습니다 0:26:19.830,0:26:21.920 굉장히 간단하죠 0:26:21.920,0:26:27.470 다른 연습 문제에서[br]임베딩을 사용해볼 수 있습니다 0:26:27.470,0:26:28.640 임베딩을 사용해서[br] 0:26:28.640,0:26:33.330 RNN와 완전 연결층을[br]그대로 구현할 수 있습니다 0:26:33.330,0:26:39.310 원-핫 인코딩 대신에[br]여기에 임베딩을 넣는 것이죠 0:26:39.310,0:26:42.459 마지막으로 보게될 부분은 0:26:42.459,0:26:45.260 RNN이 내부적으로[br]어떻게 동작하는지에 대한 것입니다 0:26:45.260,0:26:47.419 RNN은 이런 방식으로[br]표현할 수 있죠 0:26:47.419,0:26:48.900 x를 입력값으로 하고 0:26:48.900,0:26:51.590 이전의 은닉 상태도[br]또 다른 입력값으로 가집니다 0:26:51.590,0:26:54.150 그리고 새로운 은닉 상태와[br] 0:26:54.150,0:26:55.660 출력값을 만들어 냅니다 0:26:55.660,0:26:59.830 이것을 식으로[br]표현해볼 수 있는데요 0:26:59.830,0:27:04.039 이 일반 (vanila) RNN 또는[br]간단한 형태의 RNN은 0:27:04.039,0:27:05.840 매우 간단합니다 0:27:05.840,0:27:07.560 주어진 x에 대해서 0:27:07.560,0:27:10.990 웨이트 U를 가지고 0:27:10.990,0:27:14.940 이전 은닉 상태에 대해서[br]웨이트 W를 가집니다 0:27:14.940,0:27:19.260 이 두 값과[br]편향 값을 더해 줍니다 0:27:19.260,0:27:22.870 그리고 여기서[br]이 값은 훈련 가능한 값입니다 0:27:22.870,0:27:25.990 여기 이 값을 a라고 하고 0:27:25.990,0:27:30.520 은닉 상태는 간단하게[br]tanh(a)로 계산합니다 0:27:30.520,0:27:34.860 출력값의 계산에는[br]또 다른 변수를 사용하는데요 0:27:34.860,0:27:36.459 이 값도 물론 훈련 가능한데 0:27:36.459,0:27:42.080 이 Vh에 [br]또 다른 편향값 c를 더해줍니다 0:27:42.080,0:27:43.680 이 값이 출력값이 되죠 0:27:43.680,0:27:47.930 여기까지가 기본적인[br]RNN이 됩니다 0:27:47.930,0:27:50.070 그리고 이 y 예측값은[br] 0:27:50.070,0:27:53.419 이 출력값에 소프트맥스를[br]통과시킨 값이 됩니다 0:27:53.419,0:27:56.569 이렇게 RNN이 동작합니다 0:27:56.569,0:27:58.979 LSTM은 약간 복잡한데요 0:27:58.979,0:28:02.550 기본적으로 여러 개가[br]연결되어있는 것이라고 할 수 있죠 0:28:02.550,0:28:04.930 이 블로그를 참고하시면 됩니다 0:28:04.930,0:28:09.770 또 다른 RNN인 [br]GRU에 대해서도 0:28:09.770,0:28:16.990 이 식을 보면 어떻게 [br]연결되어있는지 이해할 수 있습니다 0:28:16.990,0:28:21.020 연습 문제에서 작동하는 원리를 [br]확실히 이해하고 싶다면 0:28:21.020,0:28:22.430 이것을 직접 구현해보면 됩니다 0:28:22.430,0:28:25.710 새로운 클래스를 만들고 0:28:25.710,0:28:28.820 은닉 상태를 정의하죠 0:28:28.820,0:28:30.330 이 부분이 은닉 상태죠 0:28:30.330,0:28:35.010 이 식을 사용해서 은닉 상태와[br]출력을 정의할 수 있습니다 0:28:35.010,0:28:38.580 이것을 한번 구현해보시면[br]훨씬 더 잘 이해할 수 있을 겁니다 0:28:38.580,0:28:41.450 GRU도 똑같이 구현해볼 수 있습니다 0:28:41.450,0:28:43.840 이렇게 첫 번째[br]RNN 강의를 마치겠습니다 0:28:43.840,0:28:46.530 다음 강의에서[br]더 배워보도록 하죠