콘텐츠로 바로가기

now0930 일지

이런저런 생각

  • 홈
  • 비공개
  • 강좌
  • 잔여 작업 조회
  • 위치

CarpPole Deep Q Network 이해

강아지 책에 나온 예제를 실행했다. 책 실행 환경과 내 그것이 달라 실행할 수 없었다. 나는 docker로 tensorflow를 사용한다. 그것도 cpu가 avx 등 을 지원하지 않아 직접 컴파일했다. openAi gym은 GUI 환경에서 실행되어 docker로 구동하기 힘들다. 데스크탑을 거실에 설치하여 다른 노트북에서 ssh로 접속하여 사용한다. 이런 모든 문제를 jypyter notebook로 해결했다. 전 글에 설명한대로 docker를 아래 명령으로 구동한다.

docker run -it -v /run/user/1000:/run/user/1000 -v /dev:/dev -v /tmp/.X11-unix:/tmp/.X11-unix:ro --privileged --ipc=host --shm-size=256m --net=host -e DISPLAY=$DISPLAY -e XDG_RUNTIME_DIR=/run/user/1000 --runtime=nvidia -e LC_ALL=C.UTF-8 -v /home/now0930/tensorflow/:/home/mnt tensorflow/tensorflow:1.12.0-rc2-gpu-py3-keras /bin/bash

jupyter notebook을 실행한다. uid 1000으로 실행하는 방법을 모르겠다.

docker exec -w /home/mnt/gym vibrant_banach /usr/bin/xvfb-run -s "-screen 0 1400x600x24" jupyter notebook --allow-root

책 코드를 실행하기 위해 아래와 같이 수정했다.

import sys
import gym
import pylab
import random
import numpy as np
from collections import deque
from keras.layers import Dense
from keras.optimizers import Adam
from keras.models import Sequential
from gym import wrappers

EPISODES = 300


# 카트폴 예제에서의 DQN 에이전트
class DQNAgent:
    def __init__(self, state_size, action_size):
        self.render = False
        self.load_model = False

        # 상태와 행동의 크기 정의
        self.state_size = state_size
        self.action_size = action_size
        print("self.state_size는", self.state_size)
        print("self.action_size는", self.action_size)
        # DQN 하이퍼파라미터
        self.discount_factor = 0.99
        self.learning_rate = 0.001
        self.epsilon = 1.0
        self.epsilon_decay = 0.999
        self.epsilon_min = 0.01
        self.batch_size = 64
        #self.batch_size = 1
        self.train_start = 1000

        # 리플레이 메모리, 최대 크기 2000
        self.memory = deque(maxlen=2000)

        # 모델과 타깃 모델 생성
        self.model = self.build_model()
        self.target_model = self.build_model()

        # 타깃 모델 초기화
        self.update_target_model()

        if self.load_model:
            self.model.load_weights("./save_model/cartpole_dqn_trained.h5")

    # 상태가 입력, 큐함수가 출력인 인공신경망 생성
    def build_model(self):
        model = Sequential()
        model.add(Dense(24, input_dim=self.state_size, activation='relu',
                        kernel_initializer='he_uniform'))
        model.add(Dense(24, activation='relu',
                        kernel_initializer='he_uniform'))
        model.add(Dense(self.action_size, activation='linear',
                        kernel_initializer='he_uniform'))
        model.summary()
        model.compile(loss='mse', optimizer=Adam(lr=self.learning_rate))
        return model

    # 타깃 모델을 모델의 가중치로 업데이트
    def update_target_model(self):
        self.target_model.set_weights(self.model.get_weights())

    # 입실론 탐욕 정책으로 행동 선택
    def get_action(self, state):
        if np.random.rand() <= self.epsilon:
            return random.randrange(self.action_size)
        else:
            q_value = self.model.predict(state)
            #print("q_value는", q_value)
            #print("argamx(q_value)는", np.argmax(q_value[0]))
            #print("State는", state)
            return np.argmax(q_value[0])

    # 샘플 <s, a, r, s'>을 리플레이 메모리에 저장
    def append_sample(self, state, action, reward, next_state, done):
        self.memory.append((state, action, reward, next_state, done))

    # 리플레이 메모리에서 무작위로 추출한 배치로 모델 학습
    def train_model(self):
        if self.epsilon > self.epsilon_min:
            self.epsilon *= self.epsilon_decay

        # 메모리에서 배치 크기만큼 무작위로 샘플 추출
        mini_batch = random.sample(self.memory, self.batch_size)
        states = np.zeros((self.batch_size, self.state_size))
        next_states = np.zeros((self.batch_size, self.state_size))
        actions, rewards, dones = [], [], []

        for i in range(self.batch_size):
            states[i] = mini_batch[i][0]
            actions.append(mini_batch[i][1])
            rewards.append(mini_batch[i][2])
            next_states[i] = mini_batch[i][3]
            dones.append(mini_batch[i][4])

        # 현재 상태에 대한 모델의 큐함수
        # 다음 상태에 대한 타깃 모델의 큐함수
        target = self.model.predict(states)
        target_val = self.target_model.predict(next_states)

        # 벨만 최적 방정식을 이용한 업데이트 타깃
        for i in range(self.batch_size):
            #print("target은", target[i])
            if dones[i]:
                target[i][actions[i]] = rewards[i]
            else:
                target[i][actions[i]] = rewards[i] + self.discount_factor * (
                    np.amax(target_val[i]))

        self.model.fit(states, target, batch_size=self.batch_size,
                       epochs=10, verbose=0)


if __name__ == "__main__":
    # CartPole-v1 환경, 최대 타임스텝 수가 500
    env = gym.make('CartPole-v1')
    env = wrappers.Monitor(env, "./gym-results-Cart", force=True, video_callable=lambda episode_id: episode_id%20==0)

    state_size = env.observation_space.shape[0]
    action_size = env.action_space.n

    # DQN 에이전트 생성
    agent = DQNAgent(state_size, action_size)

    scores, episodes = [], []

    for e in range(EPISODES):
        done = False
        score = 0
        # env 초기화
        #env = wrappers.Monitor(env, "./gym-results-Cart", force=True)
        state = env.reset()
        state = np.reshape(state, [1, state_size])
        #print("state reshape는",state)

        while not done:
            
            if agent.render:
                env.render()

            # 현재 상태로 행동을 선택
            action = agent.get_action(state)
            # 선택한 행동으로 환경에서 한 타임스텝 진행
            next_state, reward, done, info = env.step(action)
            next_state = np.reshape(next_state, [1, state_size])
            # 에피소드가 중간에 끝나면 -100 보상
            reward = reward if not done or score == 499 else -100

            # 리플레이 메모리에 샘플 <s, a, r, s'> 저장
            agent.append_sample(state, action, reward, next_state, done)
            # 매 타임스텝마다 학습
            if len(agent.memory) >= agent.train_start:
                agent.train_model()

            score += reward
            state = next_state

            if done:
                # 각 에피소드마다 타깃 모델을 모델의 가중치로 업데이트
                agent.update_target_model()

                score = score if score == 500 else score + 100
                # 에피소드마다 학습 결과 출력
                scores.append(score)
                episodes.append(e)
                #pylab.plot(episodes, scores, 'b')
                #pylab.savefig("./save_graph/cartpole_dqn.png")
                print("episode:", e, "  score:", score, "  memory length:",
                      len(agent.memory), "  epsilon:", agent.epsilon)

                # 이전 10개 에피소드의 점수 평균이 490보다 크면 학습 중단
                if np.mean(scores[-min(10, len(scores)):]) > 490:
                    agent.model.save_weights("./save_model/cartpole_dqn.h5")
                    sys.exit()

다음 내용을 수정했다.

  • 10 행: from gym import wrappers: wrappers 사용.
  • 120 행: env = wrappers.Monitor(env, “./gym-results-Cart”, force=True, video_callable=lambda episode_id: episode_id%20==0): 20번마다 동영상으로 저장. 여기를 설정하지 않으면 64번째 에피소드 동영상을 저장하고, 1,000번째 에피소드로 넘어간다. 학습 과정을 알 수 없다.

cartPole-v1은 10초 동안 막대기가 넘어지지 않으면 끝나는 모델이다. 10초 전 막대기가 12도 넘게 기울어지면 끝난다. Q-learning은 아래 식으로 정의된다. \alpha 는 learning rate, \gamma 는 discount factor.

Q(S_{t},A_{t})\leftarrow Q(S_{t},A_{t})+\alpha \left [R_{t+1}+\gamma\max_{a}Q(S_{t+1},a)-Q(S_{t},A_{t}) \right ]

위 식에서 Q(S_{t},A_{t})와 R_{t+1}+\gamma \max_{a}Q(S_{t+1},a) 로 오차를 줄여 나간다. 오차는 MSE = ( 정답 – 예측 ) ^{2} = (R_{t+1} + \gamma Q(S_{t+1},A_{t+1}) - Q(S_{t},A_{t}) 로 정의한다. keras.fit에서 state에 따른 예측Q(S_{t},A_{t}) 과 정답인 target[i]로 학습한다. keras.fit을 부르기 전에 miniBatch 크기 모든 target[size]를 업데이트한다. print로 taget[i]값을 확인할 수 있다.

episode: 73   score: 64.0   memory length: 2000   epsilon: 0.2699131774597243
update전 target[20] [41.376812 37.715374]
update후 target[20] [41.376812 40.977367]
#action에 따른 정확한 Q 값을 수정.
##여기에서 무작위로 다시 뽑음.
update전 target[20] [46.597427 39.114082]
update후 target[20] [46.597427 42.882465]
...
episode: 132   score: 419.0   memory length: 2000   epsilon: 0.009998671593271896
update전 target[20] [113.11228 112.72044]
update후 target[20] [113.11228 113.5387 ]
update전 target[20] [109.97069 109.24642]
update후 target[20] [109.97069 109.48601]
update전 target[20] [112.96742 112.18164]
update후 target[20] [112.92011 112.18164]
# 132번 episode가 73번 episode보다 정답에 더 근접하여 업데이트 량이 줄었다.

이렇게 10개 평균 score가 490 이상이면 학습을 중단한다. 적당한 Q 값을 찾는 문제라 value based Reinforce Learning이라 한다. 모델을 정의할 때 Q 값을 제한하지 않으려 activation을 linear로 설정했다.

300번 학습 결과,스코어 vs 횟수.

정책을 직접 근사하는 방법은 policy based Reinforce Learning인데, 마지막에 softmax 로 확율을 나오도록 해야 한다.

Sutton & Barto 가 쓴 책을 보면 잘 이해가지 않는데, 직접 돌려 확인하면 이해했다 착각한다.

이 글 공유하기:

  • Tweet
발행일 2019-12-21글쓴이 이대원
카테고리 tensorflow 태그 gym, openAi, reinforcementLearning, 체육관, 카트폴

댓글 남기기응답 취소

이 사이트는 Akismet을 사용하여 스팸을 줄입니다. 댓글 데이터가 어떻게 처리되는지 알아보세요.

글 내비게이션

이전 글

openai gym cart pole 설정

다음 글

노트북 대용 PC 조립

2025 5월
일 월 화 수 목 금 토
 123
45678910
11121314151617
18192021222324
25262728293031
4월    

최신 글

  • common mode, differential mode 2025-05-11
  • signal conditioner, 신호 처리기 2025-05-10
  • strain gage 2025-05-09
  • 칼만 필터 2025-05-01
  • positioner(I/P) 2025-04-26

카테고리

  • 산업계측제어기술사
  • 삶 자국
    • 책과 영화
    • 투자
  • 생활코딩
    • LEGO
    • ROS
    • tensorflow
  • 전기기사
  • 피아노 악보

메타

  • 로그인
  • 엔트리 피드
  • 댓글 피드
  • WordPress.org

페이지

  • 소개
  • 잔여 작업 조회
    • 작업 추가
    • 작업의 사진 조회
    • 작업 수정 페이지
  • 사진
    • GPS 입력된 사진
    • 사진 조회
  • 위치
    • 하기 휴가 방문지
    • 해외 출장

태그

android bash c docker driver FSM gps java kernel LEGO linux mysql network program opcua open62541 plc programmers python raspberry reinforcementLearning ros state space system program tensorflow transfer function 경제 미국 민수 삼국지 세계사 실기 에너지 역사 유전자 일본 임베디드 리눅스 전기기사 조선 중국 채윤 코딩 테스트 통계 한국사 한국어

팔로우하세요

  • Facebook
now0930 일지
WordPress로 제작.
 

댓글 로드중...