본문 바로가기
딥러닝

Keras로 CartPole 강화학습

by 초특급하품 2019. 12. 8.

OpenAI Gym으로 이미 구현되어있는 환경을 이용할 수 있다.
가장 단순해 보이는 CartPole 환경을 가져와서 강화 학습을 시켜보자.

 

cart위에 막대기가 있고 한 끝이 cart에 고정되어 있다. 중력에 의해 막대기는 바닥으로 떨어지려 할 테니 cart를 좌우로 움직여 최대한 오래 지탱하는 것이 목표이다.

OpenAI Gym에서는 environment로 cart의 위치, 속도와 막대기의 각도, 속도가 주어지고 이를 판단해서 cart의 움직임을 구해야 한다.

 

environment로 주어지는 모든 상태에 대해 Q-Value를 구한다면 좋겠지만 경우의 수가 무한하기 때문에 구할 수 없다. 따라서 deep learning으로 학습시켜 모델을 만들어 입력으로 주어지는 environment에 대해 cart의 움직임을 예측하도록 구현한다.

 

순서는 다음과 같다.

  1. 맨 처음에는 아무 지식이 없으니 랜덤으로 좌우로 움직여서 가장 오래 지탱한 방법을 몇 개 골라 학습시킨다.
  2. 어느 정도 괜찮아지면 self-play로 더 좋은 방법을 찾아 학습시킨다.

구현

환경 설정

CartPole-v1환경을 가져온다. v0도 있는데 max_episode_steps, reward_threshold와 같은 기본 설정값이 다르다. 더 오래 버틸 수 있음에도 불구하고 환경이 끝내버리지 않도록 v1로 구성한다.

import gym
env = gym.make("CartPole-v1")

 

모델 설정

적당한 모델인지는 모르겠지만 구현이 완성되면 후에 보완하면 되기 때문에 일단 fully connected로만 구성했다.

def create_model():
    model = Sequential()
    model.add(Dense(128, input_shape=(4,), activation="relu"))
    model.add(Dropout(0.4))

    model.add(Dense(256, activation="relu"))
    model.add(Dropout(0.4))

    model.add(Dense(256, activation="relu"))
    model.add(Dropout(0.4))

    model.add(Dense(128, activation="relu"))
    model.add(Dropout(0.4))
    model.add(Dense(2, activation="softmax"))

    model.compile(
      loss="categorical_crossentropy",
      optimizer="adam",
      metrics=["accuracy"])
    return model

 

학습 데이터 만들기

모델을 학습시킬 데이터를 만드는 함수이다.

def generate_training_data(env, action_function, trial, top_k):
    training_x, training_y = [], []
    data = []

    for _ in range(trial):
        obs = env.reset()
        score = 0
        training_sample_x, training_sample_y = [], []
        for _ in range(SIMULATION_MAX_STEP):
            action = action_function(obs)
            training_sample_x.append(obs)
            training_sample_y.append(keras.utils.to_categorical(action, 2))

            observation, reward, done, _ = env.step(action)
            score += reward
            if done:
                break
        data.append((score, (training_sample_x, training_sample_y)))

    data.sort(key=lambda x: -x[0])

    for i in range(top_k):
        training_x += data[i][1][0]
        training_y += data[i][1][1]

    return np.array(training_x), np.array(training_y)

 

처음에는 action_function을 모르기 때문에 랜덤으로 넘길거고, self play에서는 모델에서 구한 함수를 넘길 것이다. 이렇게 받은 action_function으로 총 trial횟수만큼 시뮬레이션해서 상위 top_k개의 데이터만 리턴한다.

 

학습하기

위에서 구현한 generate_traning_data로 양질의 데이터를 받아 모델에 학습시키는 함수까지 만들었다.

def train(env, action_function, model, trial, top_k):
    training_x, training_y = generate_training_data(env, action_function, trial, top_k)
    model.fit(training_x, training_y, epochs=15)

 

처음에는 cart를 랜덤으로 움직여 10000번 해보고 가장 오래 버틴 100개의 데이터만 학습시켜본다.

train(env, lambda x: np.random.randint(2), model, 10000, 100)

 

이렇게만 하고 실제 render로 출력해봐도 그럴싸하게 움직인다.

그럼 이제 self-play로 양질의 데이터를 얻을 수 있고 이를 또 학습시킨다.

for _ in range(SELF_PLAY_COUNT):
    train(env, lambda x: np.random.choice([0, 1], p=model.predict(x.reshape(-1, 4))[0]), model, 100, 10)

action_functionnp.random.choice는 [0, 1] 을 model에서 예측한 p의 확률로 선택한다는 뜻이다.

 

각종 파라미터는 임의로 넣었기 때문에 튜닝하는 과정이 남았지만, 이렇게 OpenAI Gym의 환경을 손쉽게 구성할 수 있다.

'딥러닝' 카테고리의 다른 글

딥러닝에 사용하는 확률분포 함수  (0) 2020.03.30
Keras로 모델 저장, 불러오기  (0) 2019.11.16
Keras로 간단한 CNN 구현하기  (0) 2019.11.13
알파고의 몬테카를로 방법  (0) 2019.11.10
알파고의 강화학습  (0) 2019.11.03

댓글