<jupyter_start><jupyter_text>TensorFlow 튜토리얼 16 강화 학습 (Q-Learning)원저자 [<NAME>](http://www.hvass-labs.org/)/ [GitHub](https://github.com/Hvass-Labs/TensorFlow-Tutorials) / [Videos on YouTube](https://www.youtube.com/playlist?list=PL9Hr9sNUjfsmEu1ZniY0XpHSzl5uihcXZ) / 번역 곽병권  개요이 튜토리얼은 에이전트가 주어진 환경 (이 경우에는 1970-80 년대 Atari 게임)을 탐색하는 방법을 배우는 강화 학습 (Reinforcement Learning)에 관한 것 입니다. 에이전트는 게임에 대해 아무 것도 모르고 시행 착오를 통해 게임하는 법을 배워야 합니다. 에이전트가 사용할 수 있는 유일한 정보는 게임의 화면 출력과 이전 액션으로 인해 보상 또는 벌칙이 부과되었는지 여부입니다.이것은 기계학습/인공지능에서 매우 어려운 문제입니다. 왜냐하면 에이전트는 게임 이미지에서 feature를 찾아내고 게임 이미지의 특정 feature에 대해서 스스로 행한 액션과 앞으로 수행할 많은 단계 이후에 받을지도 모를 보상 또는 벌칙과 연결해야 하기 때문입니다.이 문제는 Google DeepMind의 연구원이 먼저 해결했습니다. 이 튜토리얼은 초기 연구 논문의 주요 아이디어, 특히 [https://arxiv.org/abs/1312.5602](https://arxiv.org/abs/1312.5602) 및 [네이쳐 논문](http://www.nature.com/nature/journal/v518/n7540/full/nature14236.html)를 기반으로 합니다. 원래 DeepMind 알고리즘이 어떤면에서는 어색하고 지나치게 복잡했기 때문에 몇 가지 변경을 했습니다. 그러나 에이전트 교육을 안정화하기 위해서는 몇 가지 트릭이 여전히 필요하므로 이 튜토리얼의 구현은 불행히도 다소 복잡합니다.기본 개념은 게임 환경에서 이미지를 볼 때마다 에이전트가 일명 Q-value를 추정하도록 하는 것입니다. Q-value는 에이전트에게 미래에 누적 보상이 가장 많이 발생할 가능성이 있는 행동을 알려줍니다. 그런 다음 이 Q-value를 찾는 함수 근사를 사용하여 나중에 사용 할 수 있도록 저장하는 것으로 문제를 해결합니다.이 튜토리얼은 이전 튜토리얼 중 일부를 기반으로 합니다. 튜토리얼 01 및 02의 TensorFlow 및 컨볼루션 신경망(Convolutional Neural Networks)에 익숙해야 합니다. 튜토리얼 03 또는 03-B의 빌더 API 중 하나에 익숙하다면 도움이 될 것입니다.  주어진 문제이 튜토리얼에서는 아타리 게임 브레이크 아웃을 사용합니다.이 게임에서는 플레이어나 에이전트가 패들로 공을 받아쳐 공이 벽을 부술 때 점수를 얻고 죽음을 피해야 합니다.사람이 이와 같은 게임을 하는 것을 배울 때 가장 먼저 알아야 할 것은 게임 환경의 어떤 부분을 제어하는지 입니다.이 경우 하단의 패들입니다. 조이스틱을 오른쪽으로 움직이면 패들이 오른쪽으로 이동하고 왼쪽으로 움직이면 왼쪽으로 이동합니다. 다음은 게임의 목표가 무엇인지 파악하는 것입니다. 이 경우 점수를 최대화하기 위해 가능한 한 많은 벽돌을 부딪쳐 부술 수 있습니다. 마지막으로 피하는 법을 배워야 합니다.이 경우에는 패들이 공을 놓쳐서 죽는 것을 피해야합니다.아래는 에이전트가 학습해야 할 게임의 3가지 이미지입니다. 왼쪽 이미지에서 볼은 아래로 내려 가고 에이전트는 공을 치고 죽음을 피하기 위해 패들을 움직이는 법을 배워야 합니다. 중간에 있는 이미지는 공을 치는 패들을 보여 주며, 결국 볼이 벽돌과 부딪쳐 점수를 내는 오른쪽 이미지로 연결됩니다. 그런 다음 공은 아래쪽으로 계속 진행되며 과정이 반복됩니다. ![Illustration of the problem](images/16_problem.png) 문제는 볼이 아래로 내려가는 것과 공을 치는 패들 사이에 10개의 상태가 있고, 공이 벽에 부딪 치고 벽돌이 부셔져서 보상이 획득되기 전에 18개의 추가 상태가 있다는 것입니다. 에이전트가 이 세 가지 상황을 연결하고 유사한 상황으로 일반화하도록 가르 칠 수 있는 방법은 무엇일까요? 그 답은 이 튜토리얼에서 설명하는 신경망과 함께 강화 학습을 사용하는 것입니다.  Q-Learning 강화 학습을 하는 가장 간단한 방법 중 하나는 Q-learning이라고 합니다. 여기서 우리는 게임 환경의 상태를 에이전트가 취할 수있는 각 가능한 동작에 대한 숫자 값으로 매핑하기 때문에 액션 값이라고도 하는 Q-value를 추정하려고 합니다. Q-value는 어떤 행위가 가장 높은 미래의 보상으로 이어질 것으로 예상되는지를 나타내 에이전트에게 취할 행동을 알려줍니다.불행히도 우리는 Q-value가 무엇인지 알지 못하기 때문에 어떻게 든 추정해야 합니다. Q-value는 모두 0으로 초기화 된 다음 게임을 진행하는 에이전트로부터 새로운 정보가 수집 될 때 반복적으로 업데이트됩니다. 에이전트가 점수를 얻으면 Q-value를 새 정보로 업데이트 해야 합니다.Q-value를 업데이트 하는 방법에는 여러가지가 있지만 가장 간단한 방법은 새로운 Q-value를 관찰 된 보상과 게임의 다음 상태에 대한 최대 Q-value로 설정하는 것 입니다. 이것은 에이전트가 현재 게임 상태에서 기대할 수 있는 총 보상으로 연결됩니다. 일반적으로 다음의 상태에 대한 최대 Q-value는 1보다 약간 작은  할인 요인을 곱 합니다. 이로 인해 더 먼 보상이 Q-value에 덜 기여하게 되므로 에이전트가 더 가까운 보상에 더 많은 영향을 받도록 합니다.Q-value를 업데이트하는 공식은 다음과 같습니다.:    Q-value for state and action = reward + discount * max Q-value for next state학술 논문에서는 일반적으로 다음과 같은 수학 기호로 작성됩니다.:$$    Q(s_{t},a_{t}) \leftarrow \underbrace{r_{t}}_{\rm reward} + \underbrace{\gamma}_{\rm discount} \cdot \underbrace{\max_{a}Q(s_{t+1}, a)}_{\rm estimate~of~future~rewards}$$게다가 에이전트가 죽으면 미래의 보상이 0이라는 것을 알기 때문에 그 상태에 대한 Q-value를 0으로 설정합니다.  간단한 예제아래 이미지는 이전에 방문한 게임 상태를 통해 역방향으로 Q-value가 어떻게 업데이트 되는지 보여줍니다. 이 간단한 예제에서 우리는 모든 Q-value가 0으로 초기화되었다고 가정합니다. 에이전트는 가장 오른쪽 이미지에서 1점의 보상을 받습니다. 이 보상은 이전 게임 상태로 거꾸로 전달됩니다. 그래서 우리는 앞으로 비슷한 게임 상태를 볼 때, 주어진 행동으로 인해 보상이 생겼음을 알게됩니다.할인은 기하 급수적으로 감소하는 기능입니다. 이 예제에서는 discount-factor 0.97을 사용하므로 세 번째 이미지에 대한 Q-value는 보상을 실제로 받은 상태보다 4단계 이전 상태이기 때문에 약 $0.885 \simeq 0.97^4$입니다. 다른 상태에서도 마찬가지입니다. 이 예는 상태 당 하나의 Q-value만을 보여 주지만 실제로는 상태에 있는 각 가능한 액션에 대해 하나의 Q-value가 있으며 위의 수식을 사용하여 역방향으로 진행하며 Q-value가 업데이트 됩니다. 이것은 다음 섹션에 표시됩니다. ![Q-values Simple Example](images/16_q-values-simple.png)  상세한 예제게임 환경의 두 가지 연속 상태에 대한 Q-value와 이를 업데이트하는 방법을 보여주는 보다 자세한 예입니다. ![Q-values Detailed Example](images/16_q-values-details.png) 가능한 동작에 대한 Q-value는 신경망에 의해 추정합니다. 상태 *t* 에서의 행동 NOOP에 대해 Q-value가 그 상태에서 가장 높은 Q-value인 2.900으로 추정되었고 에이전트는 그 행동을 취합니다. 즉, 에이전트는 상태 *t* 와 *t+1*에서 아무것도 하지 않습니다. NOOP는 "No Operation"을 의미합니다.상태 *t+1* 에서 에이전트는 4점을 얻지만,이 구현에서는 1점으로 제한되어 있으므로 훈련이 빠르게 안정됩니다. 상태 *t+1* 에 대한 최대 Q-value는 RIGHTFIRE 액션의 경우 1.830입니다. 따라서 우리가 그 행동을 선택하고 뉴럴 네트워크에 의해 추정 된 Q-value에 의해 제안 된 행동을 계속 선택한다면, 모든 미래 보상의 할인 된 합은 1.830이 될 것으로 예상됩니다.이제 상태 *t* 에서 *t+1* 로 NOOP 동작을 취한 보상을 알게 되었으므로 이 새로운 정보를 통합하기 위해 Q-value를 업데이트 할 수 있습니다. 위 공식을 사용합니다:$$    Q(state_{t},NOOP) \leftarrow \underbrace{r_{t}}_{\rm reward} + \underbrace{\gamma}_{\rm discount} \cdot \underbrace{\max_{a}Q(state_{t+1}, a)}_{\rm estimate~of~future~rewards} = 1.0 + 0.97 \cdot 1.830 \simeq 2.775$$새로운 Q-value는 2.775로 기존 추정치인 2.900보다 약간 낮습니다. 이 뉴럴 네트워크는 이미 150시간 동안 학습을 받았으므로 Q-value를 추정하는데는 능숙하지만 이전에는 학습 중에 예상 Q-value는 다를 수 있습니다.보상과 벌칙에 대한 더 자세한 정보가 제공됨에 따라 에이전트가 많은 수의 게임을 플레이하고 Q-value의 추정치를 반복적으로 업데이트 하도록 하는 것이 아이디어 입니다. 아래에 설명 된대로 학습이 수치적으로 안정적이면 Q-value의 좋은 추정치로 이어질 것입니다. 이렇게 함으로써 우리는 보상과 이전 액션을 연결합니다.  모션의 추적게임 환경의 이미지 하나만 사용해서는 볼이 어느 방향으로 움직이는 지 알 수 없습니다. 일반적인 해결책은 게임 환경의 상태를 나타 내기 위해 여러 개의 연속적인 이미지를 사용하는 것입니다.이 구현은 아래에 표시된 것처럼 두 개의 이미지를 출력하는 모션 추적기에서 게임 환경의 이미지를 처리하는 다른 접근 방식을 사용합니다. 왼쪽 이미지는 게임 환경의 이미지이고 오른쪽 이미지는 처리 된 이미지이며 게임 환경에서 최근 움직임의 흔적을 보여줍니다. 이 경우 우리는 공이 아래쪽으로 가고 오른쪽 벽에서 튀어 오르고 패들이 화면의 왼쪽에서 오른쪽으로 움직 였음을 볼 수 있습니다.동작 추적기는 브레이크 아웃 테스트를 거쳤으며 부분적으로 스페이스 인베이더용으로 테스트 해보았지만 Doom과 같은 더 복잡한 그래픽이있는 게임에서는 작동하지 않을 수 있습니다. ![Motion Trace](images/16_motion-trace.png)  학습 안정성우리는 게임 환경의 상태를 입력으로 받아들이고 그 상태에 대한 Q-value의 추정값을 출력으로 생성 할 수있는 함수 근사자가 필요합니다. 우리는 이것을 위해 컨벌루션 신경망(Convolutional Neural Network)을 사용할 것입니다. 최근 몇 년 동안 큰 명성을 쌓았지만 실제로는 많은 문제가 있는 상당히 오래된 기술입니다. 그 중 하나는 학습의 안정성입니다. 이 튜토리얼에 대한 연구의 상당 부분은 신경망 학습을 조정하고 안정화하는 데 사용되었습니다.학습 안정성이 왜 중요한지 이해하려면 게임 환경을 3가지 연속 상태로 보여주는 아래의 3가지 이미지를 생각해 보겠습니다. 상태 $t$ 에서 에이전트는 그 다음 상태 $t+1$에서 발생할 1점의 점수를 획득하려고 합니다. 이전에 모든 Q-value가 0이라고 가정하고 $t+1$ 상태의 Q-value를 1.0으로 설정해야 하며 할인율이 0.97이면 상태 $t$에 대해 위의 수식을 사용하여 Q-value를 업데이트 한다면 0.97이 됩니다. ![Training Stability](images/16_training_stability.png) 신경망을 훈련시켜 Q-value 0.97과 1.0을 가진 두 상태 $t$ 와 $t+1$ 에 대한 Q-value를 각각 추정한다면 신경망은 다음과 같이 이 두 상태의 이미지에 대해서 적절하게 구별 할 수 없을 것입니다. 결론적으로 신경망에게는 두 이미지가 너무 유사하기 때문에 상태 $t+2$에 대해 1.0에 가까운 Q-value를 추정합니다. 그러나 이것은 분명히 잘못되었습니다. 왜냐하면 이 시점에서 미래의 보상에 대해 알지 못하기 때문에 상태 $t+2$에 대한 Q-value는 0이어야 합니다.학습을 반복하면 새로운 게임 상태가 관찰 된 후에 신경 네트워크가 예상하는 Q-value가 빠르게 발산하게됩니다. 이것은 충분히 크고 다양한 학습 세트를 가져야하는 신경망 훈련의 특성입니다. 이러한 이유 때문에 우리는 소위 Replay Memory를 사용하여 많은 수의 게임 상태를 수집한뒤에 나중에 각 상태를 섞어서 훈련할 것 입니다.  흐름도이 순서도는 강화 학습이 이 튜토리얼에서 어떻게 구현되는지 대략적으로 보여줍니다. 신경망이 Q-value를 추정하는데 충분히 정확할 때까지 순차적으로 실행되는 두 개의 주요 과정이 있습니다.첫 번째 과정은 게임을 하고 데이터를 기록하기 위한 것입니다. 이것은 신경망을 사용하여 게임 상태에서 Q-value를 추정합니다. 그런 다음 나중에 사용하기 위해 Replay Memory에 해당 Q-value를 보상/벌칙과 함께 게임 상태를 저장합니다.Replay Memory가 충분히 꽉 차면 다른 과정이 활성화됩니다. 먼저 Replay Memory를 통해 뒤에서부터 반복하면서 Q-value를 관찰된 새로운 보상과 벌칙으로 업데이트 합니다. 그런 다음 최적화 실행을 수행하여 신경망을 학습시켜 이러한 업데이트 된 Q-value를 보다 정확하게 예측합니다.학습 과정에서 사용되는 Replay-Memory의 비율을 높이거나 학습률을 낮추는 등 구현에 대한 자세한 내용이 많이 있지만 이 흐름도는 주요 아이디어를 보여줍니다. ![Flowchart](images/16_flowchart.png)  신경망 아키텍쳐이 구현에 사용 된 신경망은 3 개의 컨볼루션 레이어를 가지며, 모두 필터 크기가 3x3입니다. 레이어에는 각각 16, 32 및 64 개의 출력 채널이 있습니다. stride는 처음 두 개의 컨볼루션 레이어에서 2이고 마지막 레이어에서 1입니다.3개의 컨볼루션 레이어 다음에는 1024개의 유닛과 ReLU 활성화가 있는 4개의 완전히 연결된 레이어가 있습니다. 그런 다음 신경망의 출력으로 사용되는 선형 활성화가있는 단일 완전 연결 계층이 있습니다.이 아키텍처는 DeepMind 및 다른 연구 논문에서 전형적으로 사용되는 아키텍처와는 다릅니다. 그들은 종종 높은 보폭 값을 갖는 8x8 및 4x4의 큰 컨볼루션 필터 크기를 가집니다. 이는 게임 상태 이미지를 보다 적극적으로 다운 샘플링합니다. 또한 일반적으로 256개 또는 512개의 ReLU 장치가 있는 단 하나의 완전 연결된 레이어만 있습니다.이 튜토리얼을 위해 연구하는 동안, 충분히 정확한 Q-value를 갖기 위해서는 컨볼루션 레이어에서 더 작은 필터 크기와 보폭 및 더 많은 단위가 있는 여러 개의 완전히 연결된 레이어와 함께 필요하다는 것이 발견되었습니다. 원래 DeepMind에서 사용한 신경망 아키텍처는 Q-value를 상당히 크게 왜곡하는 것처럼 보입니다. 그들의 접근법이 여전히 효과가 있었던 이유는 아마도 백만 개의 상태를 가진 매우 큰 Replay Memory를 사용했기 때문일 것이며 신경망은 게임 환경의 각 단계마다 하나의 mini-batch를 사용해 학습을 수행했고 다른 일부 트릭을 사용했습니다.여기에 사용 된 아키텍처는 아마도 과도하지만 각 아키텍처를 테스트하는 데는 며칠의 훈련이 필요하므로 독자가 잘 수행 할 수 있는 더 작은 신경망 아키텍처를 찾기위한 연습으로 남겨 둡니다.  설치 OpenAI Gym의 [문서](https://github.com/openai/gym)는 현재 설치하기 위해 소스를 받아서 빌드해야 한다고 설명합니다. 그러나 Atari 게임을 설치하려면 터미널에 다음 명령을 입력하여 단일 패키지만 설치하면 됩니다. - conda create --name tf-gym --clone tf- source activate tf-gym- pip install gym[atari] 이것은 TensorFlow가 설치된 `tf`라는 Anaconda 환경을 이미 가지고 있다고 가정하고 OpenAI Gym이 설치된 `tf-gym`이라는 다른 환경에 복제 될 것입니다. 이렇게 하면 일반 TensorFlow환경과 OpenAI Gym이 포함된 환경 사이를 쉽게 전환 할 수 있습니다. TensorFlow의 GPU버전을 위해서 `tf-gpu`와 `tf-gpu-gym`이라는 같은 환경을 만들어 놓으면 편리합니다.  Imports<jupyter_code>%matplotlib inline
import matplotlib.pyplot as plt
import tensorflow as tf
import gym
import numpy as np
import math<jupyter_output><empty_output><jupyter_text>강화 학습을 위한 주요 소스 코드는 다음 모듈에 있습니다:<jupyter_code>import reinforcement_learning as rl<jupyter_output><empty_output><jupyter_text>이것은 Python 3.6.0 (Anaconda)을 사용하여 개발되었습니다:<jupyter_code># TensorFlow
tf.__version__
# OpenAI Gym
gym.__version__<jupyter_output><empty_output><jupyter_text>게임 환경OpenAI Gym에서 사용하기를 원하는 게임 환경의 이름입니다.<jupyter_code>env_name = 'Breakout-v0'
# env_name = 'SpaceInvaders-v0'<jupyter_output><empty_output><jupyter_text>이것은 TensorFlow 체크 포인트 및 다양한 로그 파일의 기본 디렉토리입니다.<jupyter_code>rl.checkpoint_base_dir = 'checkpoints_tutorial16/'<jupyter_output><empty_output><jupyter_text>base-dir이 설정되면 이 함수를 호출하여 사용할 모든 경로를 설정합니다. checkpoint-dir이 아직 없으면 만들어집니다.<jupyter_code>rl.update_paths(env_name=env_name)<jupyter_output><empty_output><jupyter_text>선행 학습 모델 다운로드신경망에 대한 사전 학습 된 변수를 모두 보유하고 있는 TensorFlow 체크 포인트를 다운로드 할 수 있습니다. 두 개의 체크 포인트가 제공되며, 하나는 브레이크 아웃을 위한 것이고 다른 하나는 스페이스 인베이더를 위한 것입니다. 그들은 모두 2.6GHz CPU와 GTX 1070 GPU가 장착 된 노트북에서 약 150시간 동안 학습을 받았습니다. 경고!이 검사 점은 각각 280-360MB입니다. 그들은 현재 Google 드라이브에 대용량 파일을 자동으로 다운로드하기 때문에 [www.hvass-labs.org](www.hvass-labs.org)에서 사용하는 웹 서버에서 호스팅됩니다. 웹 서버의 트래픽을 줄이려면이 줄이 주석 처리되어 있으므로 수동으로 활성화해야 합니다. 다운로드 할 수는 있지만 이 노트북을 간단히 실행하려는 모든 사용자가 자동으로 다운로드하지 않기를 바랍니다.<jupyter_code># rl.maybe_download_checkpoint(env_name=env_name)<jupyter_output><empty_output><jupyter_text>제가 알기로 웹 서버가 덴마크에 있습니다. 위의 자동 기능을 사용하여 파일을 다운로드하는 데 문제가 있는 경우 웹 브라우저에서 수동으로 다운로드하거나 `wget` 또는 `curl`을 사용하여 파일을 다운로드 할 수 있습니다. 또는 자동으로 우회하는 바이러스 백신 경고가 표시되는 Google 드라이브에서 다운로드 할 수 있습니다.* [구글 드라이브에서 브레이크아웃 체크포인트 다운로드](https://drive.google.com/uc?export=download&id=0B2aDiIly76ZvUjZTcXRuRFY0RjQ)* [구글 드라이브에서 스페이스 인베이더 체크포인트 다운로드](https://drive.google.com/uc?export=download&id=0B2aDiIly76ZvWDR4TExwdmw1RVE)체크섬을 사용하여 다운로드 한 파일이 완전한지 확인할 수 있습니다:* [SHA256 Checksum](http://www.hvass-labs.org/projects/tensorflow/tutorial16/sha256sum.txt)  에이전트 만들기에이전트 클래스는 게임을 플레이하거나 데이터를 기록하고 신경망을 최적화하기 위한 기본 과정을 구현합니다. 우리는 객체 인스턴스를 생성하고 `training=True`를 설정해야 합니다. 왜냐하면 replay memory를 사용하여 상태를 기록하고 Q-Value를 기록하여 나중에 그림으로 그릴것이기 때문입니다. 우리는 이전에 수행 된 실제 학습에서 로그를 손상시키지 않도록 로깅을 비활성화합니다. `render=True`도 설정할 수 있지만 `training==True` 인 동안은 효과가 없습니다.<jupyter_code>agent = rl.Agent(env_name=env_name,
                 training=True,
                 render=True,
                 use_logging=False)<jupyter_output>Trying to restore last checkpoint ...
INFO:tensorflow:Restoring parameters from checkpoints_tutorial16/Breakout-v0/checkpoint-127639066
Failed to restore checkpoint from: checkpoints_tutorial16/Breakout-v0
Initializing variables instead.<jupyter_text>Neural Network는 에이전트 클래스에 의해 자동으로 인스턴스화 됩니다. 우리는 편의를 위해 직접적인 참조를 만들 것입니다.<jupyter_code>model = agent.model<jupyter_output><empty_output><jupyter_text>마찬가지로 에이전트 클래스는 `training==True` 일 때 replay memory를 할당합니다. replay memory에는 3GB 이상의 메모리가 필요하므로 필요할 때만 할당해야 합니다. 우리가 관찰 한 상태와 Q-value 값을 기록하고 나중에 그림으로 표시하기 위해 이 노트북 문서에 replay memory가 필요합니다.<jupyter_code>replay_memory = agent.replay_memory<jupyter_output><empty_output><jupyter_text>학습에이전트의 `run()`함수는 게임을 플레이하는 데 사용됩니다. 이것은 신경망을 사용하여 Q-value를 추정고 에이전트의 동작을 결정합니다. `training==True` 인 경우 replay memory의 상태와 Q-value를 수집하고 replay memory가 충분히 가득차면 신경망을 학습합니다. `ctrl-c`를 사용하여 수동으로 멈출 무한 루프를 원한다면 `num_episodes=None`을 설정하면 됩니다. 여기서는 신경망 학습을 할 것이 아니므로 `num_episodes=1`을 설정하기 만하면 replay memory리에 일부 상태와 Q-value를 수집하여 아래에 그려 줄 수 있습니다.<jupyter_code>agent.run(num_episodes=1)<jupyter_output>87584:127639721	 Epsilon: 0.10	 Reward: 12.0	 Episode Mean: 12.0<jupyter_text>학습 모드에서 이 기능은 각 에피소드 마다 한 행을 출력합니다. 첫 번째 카운터는 처리 된 에피소드의 수 입니다. 두 번째 카운터는 처리 된 상태 수 입니다. 이 두 카운터는 신경망의 가중치와 함께 TensorFlow 체크 포인트에 저장되므로 훈련을 다시 시작할 수 있습니다. 컴퓨터 한 대 밖에 없다면 야간에 학습하는게 좋습니다.에피소드의 수는 거의 90k입니다. 이 노트북에서 많은 행을 인쇄하는 것은 비현실적이므로 다음 명령을 실행하여 단말기 창에서 더 잘 수행 할 수 있습니다:```source activate tf-gpu-gym   Activate your Python environment with TF and Gym.python reinforcement-learning.py --env Breakout-v0 --training```  학습 진행율 학습 중에 데이터가 기록되므로 나중에 진행 상황을 표시 할 수 있습니다. 각 에피소드에 대한 보상과 마지막 30개 에피소드의 실행 평균이 파일에 기록됩니다. replay memory의 Q 값에 대한 기본 통계는 각 최적화 실행 전에 파일에 기록됩니다.TensorFlow 및 TensorBoard를 사용하여 기록 할 수 있지만 이는 TensorFlow 그래프의 변수 및 그래프를 통해서만 흐르는 데이터를 기록하도록 설계되었습니다. 이 경우 우리가 기록하고자하는 데이터는 텐서 그래프에 존재하지 않으므로 TensorFlow를 사용하여이 데이터를 기록하는 것은 약간 어색합니다.따라서 우리는 이러한 로그를 읽고 쓸 수있는 몇 가지 작은 클래스를 구현했습니다.<jupyter_code>log_q_values = rl.LogQValues()
log_reward = rl.LogReward()<jupyter_output><empty_output><jupyter_text>파일에서 로그를 읽어들입니다.<jupyter_code>log_q_values.read()
log_reward.read()<jupyter_output><empty_output><jupyter_text>학습 진행: 보상이 차트는 훈련 중 각 에피소드에 대한 보상과 마지막 30개 에피소드의 실행 평균을 보여줍니다. 보상이 한 에피소드에서 다른 에피소드로 크게 달라지는 점에 유의하십시오. 따라서 실행 평균이 약간 위로 올라가는 것처럼 보일지라도 에이전트가 실제로 훈련 중에 개선되고 있는지 여부는 이 플롯만으로는 설명하기가 어렵습니다.<jupyter_code>plt.plot(log_reward.count_states, log_reward.episode, label='Episode Reward')
plt.plot(log_reward.count_states, log_reward.mean, label='Mean of 30 episodes')
plt.xlabel('State-Count for Game Environment')
plt.legend()
plt.show()<jupyter_output><empty_output><jupyter_text>학습 진행: Q-Values다음 차트는 신경망에 대한 최적화 프로그램을 실행할 때마다 replay memory의 평균 Q-value를 보여줍니다. Q-value의 평균 값이 처음에는 급격히 증가한 다음 4천만개의 상태에 다다를 때에는 상당히 느리게 증가하는 경향에 주목하십시오. 그 후에도 계속 상승하지만 다소 불규칙적으로 증가합니다.초기의 빠른 개선은 (1)학습 초기에 작은 replay memory를 사용하여 신경 네트워크가 더 자주 최적화되고 새로운 정보가 더 빨리 사용되는 것, (2)replay-memory에 대한 후진 탐색을 해서 보상이 단일 상태에 대한 Q-value를 업데이트하는 대신 여러 상태에 대한 Q-value를 업데이트 하도록 한점, (3)replay memory의 균형을 유지하여 최소한 절반 이상의 mini-batch에는 Q-value가 신경망에 대한 높은 추정 오류를 갖는 상태로 유지한 점 때문입니다.[DeepMind의 원본 논문](https://arxiv.org/abs/1312.5602)에서는 첫 번째 교육 단계에서 훨씬 느린 진행률을 보여줍니다. 그 논문의 그림 2를 참고하십시오. 하지만 Q-value는 직접 비교할 수 없습니다. 왜냐하면 우리는 여기에서 0.97만을 사용하는 반면 그들은 0.99라는 더 높은 할인률을 사용했기 때문입니다.<jupyter_code>plt.plot(log_q_values.count_states, log_q_values.mean, label='Q-Value Mean')
plt.xlabel('State-Count for Game Environment')
plt.legend()
plt.show()<jupyter_output><empty_output><jupyter_text>테스트에이전트와 뉴럴 네트워크가 훈련 될 때, 소위 엡실론 확률은 일반적으로 많은 단계에 걸쳐 1.0에서 0.1로 감소되고 그 후에 확률은 0.1로 고정됩니다. 즉, 에이전트가 각 단계에서 임의의 작업을 선택하는 확률은 0.1 또는 10%입니다. 그렇지 않으면 가장 높은 Q-value를 갖는 작업을 선택합니다. 이것은 E-greedy 정책이라고 합니다. 엡실론 확률에 대한 0.1의 선택은 이미 좋은 것으로 알려진 행동을 취하는 것보다 더 높은 보상을 초래하거나 에이전트의 사망으로 이어질 수있는 새로운 행동을 탐구하는 것 사이의 절충안입니다.테스트 중에는 엡실론 확률을 더 낮추는 것이 일반적입니다. 여기에 표시된대로 0.01로 설정했습니다:<jupyter_code>agent.epsilon_greedy.epsilon_testing<jupyter_output><empty_output><jupyter_text>이제 에이전트가 학습을 수행하지 않도록 지시합니다:<jupyter_code>agent.training = False<jupyter_output><empty_output><jupyter_text>또한 이전 에피소드 보상을 재설정 했습니다.<jupyter_code>agent.reset_episode_rewards()<jupyter_output><empty_output><jupyter_text>이 값을 설정하여 에이전트가 게임을 하는 것을 볼 수 있도록 게임 환경을 화면에 렌더링 할 수 있습니다:<jupyter_code>agent.render = True<jupyter_output><empty_output><jupyter_text>`run()`함수를 다시 호출하여 단일 에피소드를 실행할 수 있습니다. 에이전트가 실행중인 게임을 보여주는 새로운 창이 열립니다. 이 글을 쓰는 당시에는 이 작은 창 크기를 조정할 수 없었고 OpenAI의 개발자는 분명히 있어야 할이 기능을 신경 쓰지 않았습니다.<jupyter_code>agent.run(num_episodes=1)<jupyter_output>87586:127639767	Q-min: 1.765	Q-max: 1.783	Lives: 5	Reward: 1.0	Episode Mean: 0.0
87586:127639820	Q-min: 1.608	Q-max: 1.619	Lives: 5	Reward: 2.0	Episode Mean: 0.0
87586:127639882	Q-min: 1.712	Q-max: 1.734	Lives: 5	Reward: 3.0	Episode Mean: 0.0
87586:127639931	Q-min: 1.968	Q-max: 1.998	Lives: 5	Reward: 4.0	Episode Mean: 0.0
87586:127639963	Q-min: 1.953	Q-max: 1.988	Lives: 5	Reward: 5.0	Episode Mean: 0.0
87586:127639985	Q-min: 0.013	Q-max: 0.184	Lives: 4	Reward: 5.0	Episode Mean: 0.0
87586:127640039	Q-min: 1.651	Q-max: 1.664	Lives: 4	Reward: 6.0	Episode Mean: 0.0
87586:127640090	Q-min: 1.902	Q-max: 1.919	Lives: 4	Reward: 7.0	Episode Mean: 0.0
87586:127640130	Q-min: 1.960	Q-max: 1.968	Lives: 4	Reward: 8.0	Episode Mean: 0.0
87586:127640166	Q-min: 1.915	Q-max: 1.929	Lives: 4	Reward: 9.0	Episode Mean: 0.0
87586:127640197	Q-min: 2.002	Q-max: 2.022	Lives: 4	Reward: 10.0	Episode Mean: 0.0
87586:127640228	Q-min: 1.952	Q-max: 1.982	Lives: 4	Reward: 11.0	Episode Mean: 0.0
87586:127640260	Q-min: 2.0[...]<jupyter_text>평균 보상 게임 플레이는 E-greedy 정책을 사용하여 액션을 선택하므로 약간의 무작위 플레이를 합니다. 또한 OpenAI Gym 환경이 무작위로 선택된 숫자로 2~4번 사이의 액션을 반복하기 때문에 게임 플레이가 다소 임의적입니다. 따라서 한 에피소드에 대한 보상은 이 에이전트에서 일반적으로 기대할 수있는 보상에 대한 정확한 추정치가 아닙니다.예상할 수 있는 보상에 대한 보다 정확한 추정치를 얻기 위해서는 30회 또는 50회의 에피소드를 운영해야합니다.우리는 먼저 이전 에피소드 보상을 재설정 할 것입니다.<jupyter_code>agent.reset_episode_rewards()<jupyter_output><empty_output><jupyter_text>게임 환경의 수행을 빠르게 하기 위해 화면 표시를 막습니다.<jupyter_code>agent.render = False<jupyter_output><empty_output><jupyter_text>이제 30개의 에피소드를 실행합니다. 그리고 각 에피소드에 대한 보상을 기록합니다. 출력을 비활성화하여 모든 줄을 인쇄하지 않도록하는 것이 좋습니다. 연습문제에서 한번 해보세요.<jupyter_code>agent.run(num_episodes=30)<jupyter_output>87588:127641897	Q-min: 1.755	Q-max: 1.774	Lives: 5	Reward: 1.0	Episode Mean: 0.0
87588:127641950	Q-min: 1.634	Q-max: 1.650	Lives: 5	Reward: 2.0	Episode Mean: 0.0
87588:127642002	Q-min: 1.849	Q-max: 1.872	Lives: 5	Reward: 3.0	Episode Mean: 0.0
87588:127642037	Q-min: 1.930	Q-max: 1.966	Lives: 5	Reward: 4.0	Episode Mean: 0.0
87588:127642067	Q-min: 1.936	Q-max: 1.970	Lives: 5	Reward: 5.0	Episode Mean: 0.0
87588:127642101	Q-min: 1.950	Q-max: 1.963	Lives: 5	Reward: 9.0	Episode Mean: 0.0
87588:127642136	Q-min: 2.189	Q-max: 2.341	Lives: 5	Reward: 13.0	Episode Mean: 0.0
87588:127642159	Q-min: 1.926	Q-max: 2.292	Lives: 5	Reward: 14.0	Episode Mean: 0.0
87588:127642178	Q-min: 1.976	Q-max: 2.286	Lives: 5	Reward: 15.0	Episode Mean: 0.0
87588:127642199	Q-min: 2.169	Q-max: 2.290	Lives: 5	Reward: 16.0	Episode Mean: 0.0
87588:127642218	Q-min: 2.243	Q-max: 2.338	Lives: 5	Reward: 17.0	Episode Mean: 0.0
87588:127642240	Q-min: 2.127	Q-max: 2.307	Lives: 5	Reward: 24.0	Episode Mean: 0.0
87588:127642261	Q-min:[...]<jupyter_text>이제 에피소드 보상에 대한 통계를 인쇄 할 수 있습니다.이 통계는 각 에피소드에서 다음 에피소드 사이에 크게 다릅게 나타납니다.<jupyter_code>rewards = agent.episode_rewards
print("Rewards for {0} episodes:".format(len(rewards)))
print("- Min:   ", np.min(rewards))
print("- Mean:  ", np.mean(rewards))
print("- Max:   ", np.max(rewards))
print("- Stdev: ", np.std(rewards))<jupyter_output>Rewards for 30 episodes:
- Min:    40.0
- Mean:   145.166666667
- Max:    386.0
- Stdev:  105.131372842<jupyter_text>에피소드 보상으로 히스토그램을 그려 봅니다.<jupyter_code>_ = plt.hist(rewards, bins=30)<jupyter_output><empty_output><jupyter_text>상태의 예제뉴럴 네트워크 (Neural Network)에 의해 추정 된 게임 환경 및 Q-value로부터 상태의 일부를 도식화 할 수 있습니다.이 도움 함수는 replay memory에서 주어진 색인에 대한 Q-value를 인쇄합니다.<jupyter_code>def print_q_values(idx):
    """Print Q-values and actions from the replay-memory at the given index."""

    # Get the Q-values and action from the replay-memory.
    q_values = replay_memory.q_values[idx]
    action = replay_memory.actions[idx]

    print("Action:     Q-Value:")
    print("====================")

    # Print all the actions and their Q-values.
    for i, q_value in enumerate(q_values):
        # Used to display which action was taken.
        if i == action:
            action_taken = "(Action Taken)"
        else:
            action_taken = ""

        # Text-name of the action.
        action_name = agent.get_action_name(i)
            
        print("{0:12}{1:.3f} {2}".format(action_name, q_value,
                                        action_taken))

    # Newline.
    print()<jupyter_output><empty_output><jupyter_text>이 도움 함수는 replay-memory에서 상태를 표시하고 옵션에 따라 Q-value를 인쇄합니다.<jupyter_code>def plot_state(idx, print_q=True):
    """Plot the state in the replay-memory with the given index."""

    # Get the state from the replay-memory.
    state = replay_memory.states[idx]
    
    # Create figure with a grid of sub-plots.
    fig, axes = plt.subplots(1, 2)

    # Plot the image from the game-environment.
    ax = axes.flat[0]
    ax.imshow(state[:, :, 0], vmin=0, vmax=255,
              interpolation='lanczos', cmap='gray')

    # Plot the motion-trace.
    ax = axes.flat[1]
    ax.imshow(state[:, :, 1], vmin=0, vmax=255,
              interpolation='lanczos', cmap='gray')

    # This is necessary if we show more than one plot in a single Notebook cell.
    plt.show()
    
    # Print the Q-values.
    if print_q:
        print_q_values(idx=idx)<jupyter_output><empty_output><jupyter_text>Replay-memory는 200k 상태를 위한 공간이 있지만 위의 호출에서 `agent.run(num_episodes=1)` 부분적으로 만 채워집니다. 이는 실제로 사용된 상태에 따라 달라집니다.<jupyter_code>num_used = replay_memory.num_used
num_used<jupyter_output><empty_output><jupyter_text>실제 사용된 replay-memory에서 Q-value를 가져옵니다.<jupyter_code>q_values = replay_memory.q_values[0:num_used, :]<jupyter_output><empty_output><jupyter_text>각 상태에 대해 최소/최대 Q-value와 그 차이를 계산합니다. 이것은 다음 섹션에서 흥미로운 상태를 찾는 데 사용될 것입니다.<jupyter_code>q_values_min = q_values.min(axis=1)
q_values_max = q_values.max(axis=1)
q_values_dif = q_values_max - q_values_min<jupyter_output><empty_output><jupyter_text>상태 예제: 최상의 보상이 예는 가장 높은 보상을 가진 상태를 둘러싼 상태를 보여줍니다.훈련 도중 [-1, 1] 범위로 보상을 제한하기 때문에 기본적으로 1의 보상을 받는 첫 번째 상태가됩니다.<jupyter_code>idx = np.argmax(replay_memory.rewards)
idx<jupyter_output><empty_output><jupyter_text>이 상태는 공이 벽에 닿아 에이전트가 점수를 얻는 곳입니다.이 상태까지 이어지는 주변 상태를 보여줄 수 있습니다. 이 시점에서 보상이 이미 보장되어 있기 때문에 에이전트가 수행하는 작업이 실제로 중요하지 않으므로 Q-value가 다른 작업에 대해 매우 근접한 점에 유의하십시오. 그러나 공이 벽을 치고 점수를 획득한 후에 Q-value가 어떻게 크게 감소하는지 주목하십시오.또한 에이전트는 E-greedy 정책을 사용하여 작업을 수행하므로 가장 높은 Q-value를 갖는 작업 대신 임의의 작업이 수행 될 약간의 가능성도 있습니다.<jupyter_code>for i in range(-5, 3):
    plot_state(idx=idx+i)<jupyter_output><empty_output><jupyter_text>예제: 최고의 Q-value이 예는 가장 높은 Q-value를 가진 상태와 이를 둘러싼 상태를 보여줍니다. 이는 에이전트가 다음 단계에서 몇 가지 점수를 기록 할 것이라는 높은 기대치를 가짐을 의미합니다. 포인트가 획득되면 Q-value가 크게 감소합니다.<jupyter_code>idx = np.argmax(q_values_max)
idx
for i in range(0, 5):
    plot_state(idx=idx+i)<jupyter_output><empty_output><jupyter_text>예제: 사망이 예에서는 에이전트가 죽은 경우의 상태를 보여줍니다.<jupyter_code>idx = np.argmax(replay_memory.end_life)
idx
for i in range(-10, 0):
    plot_state(idx=idx+i)<jupyter_output><empty_output><jupyter_text>예제: Q-value의 가장 큰 차이이 예는 Q-value가 가장 큰 차이가 있는 상태를 나타내며, 이는 에이전트가 한 동작이 다른 동작보다 훨씬 유익하다고 믿는다는 것을 의미합니다. 그러나 에이전트가 E-greedy 정책을 사용하기 때문에 때로는 임의의 작업을 선택합니다.<jupyter_code>idx = np.argmax(q_values_dif)
idx
for i in range(0, 5):
    plot_state(idx=idx+i)<jupyter_output><empty_output><jupyter_text>예제: Q-value의 작은 차이이 예는 Q-value에 가장 작은 차이가 있는 상태를 보여줍니다. 즉, 에이전트는 어떤 조치를 선택하든 실제로 미래의 보상에 대한 기대치가 거의 같아서 중요하지 않다고 생각합니다.신경망(Neural Network)은 이러한 Q-value를 추정하며 정확하지 않습니다. Q-value의 차이는 예상치의 오차 범위 내에 속할 정도로 작을 수 있습니다.<jupyter_code>idx = np.argmin(q_values_dif)
idx
for i in range(0, 5):
    plot_state(idx=idx+i)<jupyter_output><empty_output><jupyter_text>컨볼루션 레이어의 출력컨볼루션 레이어의 출력은 그림으로 표시할 수 있으므로 게임 환경의 이미지가 신경망에서 처리되는 방식을 볼 수 있습니다.아래는  replay-memory에서 주어진 상태를 입력 할 때 주어진 이름으로 컨볼루션 레이어의 출력을 표시하기 위한 도움 함수입니다.<jupyter_code>def plot_layer_output(model, layer_name, state_index, inverse_cmap=False):
    """
    Plot the output of a convolutional layer.

    :param model: An instance of the NeuralNetwork-class.
    :param layer_name: Name of the convolutional layer.
    :param state_index: Index into the replay-memory for a state that
                        will be input to the Neural Network.
    :param inverse_cmap: Boolean whether to inverse the color-map.
    """

    # Get the given state-array from the replay-memory.
    state = replay_memory.states[state_index]
    
    # Get the output tensor for the given layer inside the TensorFlow graph.
    # This is not the value-contents but merely a reference to the tensor.
    layer_tensor = model.get_layer_tensor(layer_name=layer_name)
    
    # Get the actual value of the tensor by feeding the state-data
    # to the TensorFlow graph and calculating the value of the tensor.
    values = model.get_tensor_value(tensor=layer_tensor, state=state)

    # Number of image channels output by the convolutional layer.
    num_images = values.shape[3]

    # Number of grid-cells to plot.
    # Rounded-up, square-root of the number of filters.
    num_grids = math.ceil(math.sqrt(num_images))

    # Create figure with a grid of sub-plots.
    fig, axes = plt.subplots(num_grids, num_grids, figsize=(10, 10))

    print("Dim. of each image:", values.shape)
    
    if inverse_cmap:
        cmap = 'gray_r'
    else:
        cmap = 'gray'

    # Plot the outputs of all the channels in the conv-layer.
    for i, ax in enumerate(axes.flat):
        # Only plot the valid image-channels.
        if i < num_images:
            # Get the image for the i'th output channel.
            img = values[0, :, :, i]

            # Plot image.
            ax.imshow(img, interpolation='nearest', cmap=cmap)

        # Remove ticks from the plot.
        ax.set_xticks([])
        ax.set_yticks([])

    # Ensure the plot is shown correctly with multiple plots
    # in a single Notebook cell.
    plt.show()<jupyter_output><empty_output><jupyter_text>게임 상태이것은 신경망에 입력되는 상태입니다. 왼쪽 이미지는 게임 환경의 마지막 이미지입니다. 오른쪽 이미지는 게임 환경에서 오브젝트의 궤적을 보여주는 처리 된 모션 추적 이미지입니다.<jupyter_code>idx = np.argmax(q_values_max)
plot_state(idx=idx, print_q=False)<jupyter_output><empty_output><jupyter_text>컨볼루션 레이어 1의 출력이것은 뉴런 네트워크에 위의 상태를 입력 할 때 첫 번째 컨볼루션 계층에 의해 출력되는 이미지를 보여줍니다. 이 컨볼루션 계층에는 16개의 출력 채널이 있습니다.이 함수의 매개 변수에서 `inverse_cmap=True`를 설정하여 색상을 반전시킬 수 있습니다.<jupyter_code>plot_layer_output(model=model, layer_name='layer_conv1', state_index=idx, inverse_cmap=False)<jupyter_output>Dim. of each image: (1, 53, 40, 16)<jupyter_text>두번째 컨볼루션 레이어의 출력이것들은 신경망에 위의 상태를 입력 할 때 2번째 컨벌루션 레이어에 의해 출력된 이미지입니다. 이 컨볼루션 레이어에는 32개의 출력 채널이 있습니다.<jupyter_code>plot_layer_output(model=model, layer_name='layer_conv2', state_index=idx, inverse_cmap=False)<jupyter_output>Dim. of each image: (1, 27, 20, 32)<jupyter_text>세번째 컨볼루션 레이어의 출력이들은 신경망에 위의 상태를 입력 할 때 세번째 컨볼루션 레이어에 의해 출력된 이미지입니다. 이 컨볼루션 계층에는 64개의 출력 채널이 있습니다.이 모든 이미지는 1 차원배열(또는 텐서)로 평탄화되어 신경망의 완전히 연결된 레이어의 입력으로 사용됩니다.학습 과정에서 신경망은 Q-value를 추정 할 때 유용하기 때문에 이미지 환경에서 이미지에 적용 할 컨볼루션 필터를 학습했습니다.신경망이 이 이미지에서 탐지한 것이 무엇인지를 알 수 있나요?<jupyter_code>plot_layer_output(model=model, layer_name='layer_conv3', state_index=idx, inverse_cmap=False)<jupyter_output>Dim. of each image: (1, 27, 20, 64)<jupyter_text>컨볼루션 레이어의 가중치또한 우리는 신경망에서 컨볼루션 레이어의 가중치를 플로팅 할 수 있습니다. 이것은 신경망이 Q-value를 추정하는 능력을 향상시키기 위해 최적화되는 가중치입니다. 튜토리얼 02에서는 컨볼루션의 가중치에 대해서 자세히 설명되어 있습니다.완전히 연결된 레이어의 가중치도 있지만 여기에는 표시되지 않습니다.이것은 컨볼루션 레이어의 가중치를 플로팅하기 위한 도움 함수입니다.<jupyter_code>def plot_conv_weights(model, layer_name, input_channel=0):
    """
    Plot the weights for a convolutional layer.
    
    :param model: An instance of the NeuralNetwork-class.
    :param layer_name: Name of the convolutional layer.
    :param input_channel: Plot the weights for this input-channel.
    """

    # Get the variable for the weights of the given layer.
    # This is a reference to the variable inside TensorFlow,
    # not its actual value.
    weights_variable = model.get_weights_variable(layer_name=layer_name)
    
    # Retrieve the values of the weight-variable from TensorFlow.
    # The format of this 4-dim tensor is determined by the
    # TensorFlow API. See Tutorial #02 for more details.
    w = model.get_variable_value(variable=weights_variable)

    # Get the weights for the given input-channel.
    w_channel = w[:, :, input_channel, :]
    
    # Number of output-channels for the conv. layer.
    num_output_channels = w_channel.shape[2]

    # Get the lowest and highest values for the weights.
    # This is used to correct the colour intensity across
    # the images so they can be compared with each other.
    w_min = np.min(w_channel)
    w_max = np.max(w_channel)

    # This is used to center the colour intensity at zero.
    abs_max = max(abs(w_min), abs(w_max))

    # Print statistics for the weights.
    print("Min:  {0:.5f}, Max:   {1:.5f}".format(w_min, w_max))
    print("Mean: {0:.5f}, Stdev: {1:.5f}".format(w_channel.mean(),
                                                 w_channel.std()))

    # Number of grids to plot.
    # Rounded-up, square-root of the number of output-channels.
    num_grids = math.ceil(math.sqrt(num_output_channels))

    # Create figure with a grid of sub-plots.
    fig, axes = plt.subplots(num_grids, num_grids)

    # Plot all the filter-weights.
    for i, ax in enumerate(axes.flat):
        # Only plot the valid filter-weights.
        if i < num_output_channels:
            # Get the weights for the i'th filter of this input-channel.
            img = w_channel[:, :, i]

            # Plot image.
            ax.imshow(img, vmin=-abs_max, vmax=abs_max,
                      interpolation='nearest', cmap='seismic')

        # Remove ticks from the plot.
        ax.set_xticks([])
        ax.set_yticks([])

    # Ensure the plot is shown correctly with multiple plots
    # in a single Notebook cell.
    plt.show()<jupyter_output><empty_output><jupyter_text>첫번째 컨볼루션 레이어의 가중치이것은 상태의 첫 번째 입력 채널과 관련하여 신경망의 첫 번째 컨볼루션 레이어의 가중치입니다. 즉, 게임 환경의 이미지에 사용되는 가중치입니다. 몇 가지 기본 통계도 표시됩니다.가중치가 음수(파랑)가 양수(빨강) 더 많은 점에 유의하십시오. 이러한 가중치가 최적화를 통해 발견되는 이유는 확실하지 않습니다. 다만 첫번째 계층의 이어지는 레이어에서보다 더 많은 음수의 가중치를 갖는 것이 유익할 것임은 분명합니다.<jupyter_code>plot_conv_weights(model=model, layer_name='layer_conv1', input_channel=0)<jupyter_output>Min:  -0.68262, Max:   0.14787
Mean: -0.05167, Stdev: 0.11923<jupyter_text>두 번째 입력 채널의 컨볼루션 가중치, 즉 게임 환경의 모션 추적을 플로팅 할 수도 있습니다. 다시 한번 우리는 음의 가중치 (파란색)가 양의 가중치 (빨간색)보다 훨씬 큰 것을 볼 수 있습니다.<jupyter_code>plot_conv_weights(model=model, layer_name='layer_conv1', input_channel=1)<jupyter_output>Min:  -0.95588, Max:   0.09746
Mean: -0.03578, Stdev: 0.15025<jupyter_text>두번째 컨볼루션 레이어의 가중치이것들은 신경망에서 두 번째 컨볼루션 레이어의 가중치입니다. 이 레이어에는 16개의 입력 채널과 32개의 출력 채널이 있습니다. 입력 채널의 수를 변경하여 연관된 가중치를 볼 수 있습니다.위의 첫 번째 컨볼루션 레이어에 대한 가중치와 비교하여 양수(빨간색)와 음수(파란색) 사이의 가중치 균형을 확인하십시오.<jupyter_code>plot_conv_weights(model=model, layer_name='layer_conv2', input_channel=0)<jupyter_output>Min:  -0.30984, Max:   0.24492
Mean: -0.02332, Stdev: 0.09427<jupyter_text>세번째 컨볼루션 레이어의 가중치이것들은 신경 회로망에서의 세번째 컨볼루션 층의 가중치이다. 이 레이어에는 32개의 입력 채널과 64개의 출력 채널이 있습니다. 입력 채널의 수를 변경하여 연관된 가중치를 볼 수 있습니다.위의 첫 번째 컨볼루션 레이어의 가중치와 비교하여 양수(빨간색)와 음수(파란색) 사이의 가중치 균형을 다시 확인하십시오.<jupyter_code>plot_conv_weights(model=model, layer_name='layer_conv3', input_channel=0)<jupyter_output>Min:  -0.33228, Max:   0.24060
Mean: -0.02068, Stdev: 0.09566
{'fraction_non_alphanumeric': 0.08550039401103231, 'fraction_numerical': 0.040878644602048854, 'mean_word_length': 3.6943588162762024, 'pattern_counts': {'":': 0, '<': 176, '<?xml version=': 0, '>': 174, 'https://': 8, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '46', 'dir': 'jupyter-structured-clean-dedup', 'id': '409412', 'license': 'MIT', 'n_tokens_mistral': 21177, 'n_tokens_neox': 25215, 'n_words': 4375, 'path': '16_Reinforcement_Learning.ipynb', 'repo_name': 'Steven-A3/TensorFlow-Tutorials', 'size': '30476'}