Diversity is All You Need : Learning Skills without a Reward Function
(https://arxiv.org/abs/1802.06070)
위 논문에서 바라보고자 하는 점은 똑똑한 사람들은 지시자의 지시가 없이도 스스로 다양한 시도들을 통하여 스스로 유용한 기술들을 학습한다는 일상의 일들을 강화학습에 적용해 보자는 의도를 가지고 작성되었다.
이를 강화학습으로 풀어보자면 어떻게 하면 보상이 없이도 유용한 기술들을 스스로 배워서 학습할 수 있을까 이를 구현하기 위해서 필요한 건 무엇일까? 이다.
reward function이 없이 useful skills를 학습한다. 이를 기술적으로 풀어보자면 maximum entropy policy를 이용하여 information theoretic objective를 최대화하는 방법을 통해 skills를 학습하는 방법론이라고 보면 된다.
여기서 중요한 키워드는 maximum entropy policy이다.
딥러닝에서 가장 중요한 것은 Data와 Optimization인데 최적화에 maximum entropy policy를 적용한다는 건 noise를 통한 smooth 효과의 적용을 통하여 단기적 보상보다는 장기적인 보상에 대한 기대값을 높이기 위함이다.
Entropy를 정보 이론에서는 이벤트에 포함된 예상 정보 비트 수로 정의할 수 있고 위 논문에서의 Maximum Entropy라는 것은 에이전트가 가장 높은 보상 합계와 장기 Entropy 합계를 받을 수 있는 가장 올바른 작업을 선택하기 위해 Policy 최적화를 수행한다는데 있다고 보면 된다.
이 최적화 함수를 통해 Agent는 더 많은 것을 탐색하고 Local Optimization을 피할 수 있다.
Maximum Entropy 원리의 목표는 Maximum Entropy의 분포를 찾는 것이다.
많은 강화학습 알고리즘에서 Agent는 Local Optimization에 수렴할 수 밖에 없는 구조적 한계를 가지고 있다.
이를 극복하기 위해 목적 함수에 Maximum Entropy를 추가하여 Agent가 Maximum Entropy를 갖는 분포를 검색할 수 있다. 앞 서도 말한바와 같이 Maximum Entropy의 목표는 가장 높은 누적 보상과 Maximum Entropy를 달성할 수 있는 최적의 정책을 학습하는 것이다. 이 최적의 정책은 바로 장기 보상 및 장기 엔트로피에 대한 가장 높은 기대치이다.
본 논문에서는 pretrained skills가 어떻게 downstream tasks에 대해 좋은 parameter initialization을 제공할 수 있는지와, complex하고 sparse reward tasks를 풀기 위해 계층적 구성을 통해 문제를 풀어가는 방법을 보여주고 있다.
Downstream task는 pretrained model 혹은 feature를 supervised-learning task에 적용시키는 것이다.
Transfer learning에서 대규모 데이터 셋으로 모델을 학습한 후, 해당 모델에 대한 neural network architecture를 일부 변형하여 뒷단의 부분만 일부 학습을 통하여 다양한 서비스를 수행할 수 있도록 하는 것을 downstream task라고 한다. 이는 복잡한 게임 같은 경우 전략을 학습시키기 위해 사람이 직접 reward를 설계하는 것이 어렵다.
reward engineering단계에서 연구자의 의도가 들어가더라도 그 의도를 학습에 제대로 반영하는 것이 까다롭고, 사람의 개입없이 agent끼리 학습을 하는 과정에서 agent가 창의적인 전략을 찾아내는 경우도 있기 때문에 대전형 게임은 주로 게임이 끝난 뒤 승패에 따라 reward를 제공한다.
Agent의 학습 episode에서 단 한번의 reward만이 주어지기 때문에 위와 같은 경우에서는 sparse reward problem이 존재한다. 이 논문에서는 이를 해결하기 위한 방법론으로 계층적 구성을 통해 문제를 풀어가는 방법을 보여주려 한다.
Introduction
강화학습은 playing games, controlling robots, navigating complex environment를 포함, 다양한 reward driven skills를 효율적으로 학습하는 방법론이다. 하지만 intelligent creatures는 supervision없이도 useful skills를 잘 학습하고 환경을 explore할 수 있다.
따라서 intelligent creature는 이후에 다른 goal이 생겼을 때, skills를 활용하여 빠르고 효율적으로 학습할 수 있다.
reward없이 skills를 학습하는 practical applications가 있다.
이는 sparse rewards가 존재하는 환경에서 agent가 goal state에 무작위로 도달할 때까지의 보상이 없다.
supervision없이 useful skills를 학습하는 경우 exploration의 어려움을 해결하는데에 도움을 주는데 이런 내역에 대하여 보상을 설계하는 것은 매우 어렵고 이를 기반으로 agent로 부터 원하는 행동을 유도하는 reward function을 설계하는 것은 더욱 어렵다. 그렇기 때문에 익숙하지 않은 환경이 주어졌을 때, agent가 어떤 tasks를 학습할 수 있는지 결정하는 것이 challenging이다. 그리고 보상없이 useful skills를 학습하는 것 또한 매우 어려운 문제이다.
결론적으로 말하자면 보상을 디자인하는 것은 매우 어렵지만 보상없이 학습하는 것 또한 매우 어려운 문제이다.
위에서 계속 언급하는 Skill이란 환경의 state를 consistent way(일관된 방식)로 변화시키는 latent conditioned policy이다. reward function을 모를 때도 ‘set’의 utility를 최대화하여 skills의 set을 학습하고 싶다.
상호 정보(mutual information)에 기반한 간단한 목표를 통해 강화학습 agent가 이런 skills를 자율적으로 발견할 수 있는 방법을 볼 수 있다고 한다. 이런 skills는 hierarchical reinforcement learning이나 imitation learning등에 활용되고 있다.
본 논문에서는 useful skills를 얻기 위해, 가능한 행동의 set들을 최대한 커버할 수 있도록 skills를 훈련해야 한다고 가정한다. 훈련방법으로는 objective로서의 skills 사이의 차별성(discriminability)을 이용하는 것이다.
문제를 해결하기 위해서는 discriminability하면서 다양한 skills를 학습해야 한다.
본 논문에서는 총 5가지의 contribution이 있다.
1> Maximum entropy policy로 정보이론의 목표를 극대화하는 것으로 차별된 goal을 공식화한다. 즉 여러 강화학습 연구에서 bench mark로 사용하는 환경들에서도 true reward를 받지 않고 잘 학습하는 것을 보여준다.
2> 어떠한 보상없이 useful skills를 학습하는 방법
달리기, 점핑과 같은 다양한 skills의 unsupervised emergence(비지도 출현)에서 간단한 탐험 목표의 결과를 보여준다.
3> Hierarchical RL에 대해 학습된 skills를 사용하기 위한 간단한 방법을 제안하고 이런 방법들이 challenging tasks를 해결함을 보이고 있다.
각 state마다 적절한 action을 취할 것이다. 즉 사람은 액션을 정함에 있어서 hierarchy가 있어서 먼저 상위 액션을 결정하고 상위 액션을 취하기 위해 하위 액션들을 결정하게 된다. 이것이 바로 Hierarchical RL(HRL)이다.
4> Skills가 얼마나 빨리 새로운 task에 잘 적응하는지를 보여준다.
5> 발견된 skills가 imitation learning에 어떻게 사용될 수 있는지를 보여준다.
imitation learning을 사용하는 이유는 일반적인 MDP에서는, 좋은 policy를 찾기 위해서는 굉장히 많은 양의 sample들이 필요하다. 예를 들자면, DQN같은 경우 최대한 많은 양의 sample을 가지고 오랜 training을 해야만 좋은 성능을 낼 수 있었다. 하지만, 현실 상에서는 실제 강화 학습을 수행할 만한 많은 양의 sample들을 얻기란 쉽지 않다.
만약 우리가 우주선을 발사하는 강화학습 agent를 만들어야 한다고 가정해 보자. 수없이 많은 우주선 발사를 실패해야만 진짜 제대로 된 우주선 발사를 볼 수 있을 것이다. 이렇게 되면 천문학적인 비용이 소요될 것이고, 사실상 이런 방식의 RL로는 우주선 발사는 불가능 하다는 것을 알 수 있다. 자율주행 자동차의 경우도 마찬가지다. 스스로 운전하는 자동차를 만들어야 하는데, 수없이 많은 사고 이후에야 운전을 제대로 할 수 있다면, 아무도 그 비용을 감수하려 하지 않을 것이다.
그렇다면 sample의 갯수를 줄 일 수 있지 않을까? 그냥 아무것도 알려주지 않은 상태로 Optimal Policy를 얻기를 기대하기 보다는, 이 강화 학습 과정을 도와줄 추가적인 정보나 구조들을 알려준 뒤에 훈련을 하면 되지 않을까 바로 이런 가정에서 출발한 것이 imitation learning이다.
지금까지의 강화학습은 Reward를 통해 Agent를 학습하였다. DQN, Q-learning, Monte Carlo 등등 모두 다 reward function을 사용하여 최대의 reward를 얻을 수 있도록 하는 것이 주요 포인트였다. 이 방식은 매우 간단한 방식으로 훈련이 가능하다는 점에서 좋지만, 너무 많은 sample을 요구한다는 단점이 있다.
자율 주행 자동차의 reward를 산정하려면 어떻게 해야할까? 만약 이 reward값을 사고가 나면 -10, 사고가 발생하지 않으면 +0.1 이런식으로 설계한다면 어떨까? 그렇게 되면 설계가 된 agent가 어떻게 해야 사고가 나고 어떻게 해야 사고가 나지 않을지 알아내는 것에 많은 비용이 들어갈 것이다. 그렇다면 모든 상황에 대하여 적절한 reward를 대입해주면 어떨까? 우선 이 방식은 너무 오랜 시간이 걸리고, 이렇게 reward를 정해준다고 해도 reward의 상태가 매우 불안정해질 수 있다. 이를 보완하기 위한 대안책으로, 바로 reward를 demonstration, 즉 실제로 어떻게 하는지 보여주면서 reward를 implicit하게 주는 것이다. 이렇게 demonstration으로 reward를 산정하려면 어떻게 해야할까? 바로 학습시킬 분야의 전문가와 함께 demonstration trajectory를 만들어 학습시키는 것이다.
자율 주행 자동차를 만든다고 하면, 운전을 매우 잘하는 사람을 데려와서 실제로 한번 운전하는 모습을 보는 것이다.
그렇게 얻은 State/Action Sequence들을 바탕으로 강화 학습 agent를 학습시키면 된다.
imitation learning방식은 reward를 일일히 부여하거나 특정 policy를 따르도록 하게 하려는 것이 아닐 경우에 효율적이다.
이런 imitation learning의 기본적인 setting은 우선 입력값은 지금까지와 비슷하게 State와 Action space로 이뤄져 있고, Transition model P가 주어진다. 다른 점은, reward function R은 주어지지 않는 대신 (s0, a0, s1, a1, …..)과 같은 demonstration이 주어진다.
Diversity is all you need
본 논문은 unsupervised RL 패러다임을 agent가 unsupervised “exploration” stage에 이어서 supervised stage도 허용된 work에서 고려한다. Unsupervised stage의 목적은 궁극적으로 supervised stage의 task reward를 쉽게 최대화하는 skills를 학습하는 것이다.
편리하게도 이러한 skills는 tasks에 대한 사전 지식없이 skills를 학습하기 때문에 많은 다른 tasks에서 사용될 수 있다.
How it works
unsupervised skill의 발견을 위한 방법은 세 가지 아이디어로 구성된다.
1> Agent가 visit하는 state에 영항을 주는 skill이 있어야 한다. ( for skills to be useful )
다른 skills는 서로 다른 states에 방문해야만 하며, 그래서 구분될 수 있다.
2> Skills를 구분하기 위해 action이 아닌 state를 이용한다.
환경에 영향을 주지 않는 actions은 outside observer에게 보이지 않기 때문이다.
예를 들어, outside observer는 컵이 움직이지 않으면 컵을 잡을 때 로봇 팔이 얼마나 많은 힘을 가하는지 알 수 없다.
마지막으로, 가능한 한 랜덤하게 행동하는 skills을 학습하는 것을 통해 skills이 가능한 다양해지도록 한다.
3> 구분 가능한 높은 entropy를 가진 skills는 다른 skills로부터 멀리 떨어진 state space의 일부를 꼭 exploration해서 action의 랜덤성이 구별할 수 없는 state로 이끌지 않도록 한다.
Objective를 위한 notation은 정보이론으로부터 가져와 사용한다.
– 고정된 Z를 조건으로 하는 policy를 skill이라고 한다.
– I와 H는 상호 정보(mutual information)와 Shannon entropy의 개념에서 착안하였으며, 둘 다 base e로 계산된다.
– S와 A는 각각 States, Actions에 대한 임의의 변수이다.
– Z ~ p(z)는 latent 변수이다.
– 본 논문의 objective는, skill이 agent가 visit하는 state를 제어해야만 하는 아이디어를 인코딩하기 위해 skills와 states간의 상호 정보( I(A;Z) )를 최대화한다.
– 편리하게도, 이 상호 정보는 agent가 visit한 state에서 skill을 추론할 수 있음을 나타낸다.
– actions이 아닌 states가 skills를 구분하는데 사용되도록 하기 위해, 주어진 state의 skill과 action간의 상호 정보( I(A;Z | S) )를 최소화한다.
Policies의 mixture로 p(z)와 함께 모든 skills를 볼 때 이 mixture policy의 엔트로피 H[A | S]를 최대화한다.
요약하자면, 아래의 g(theta)를 최대화하는 것이다.
Implementation
본 논문에서는 SAC(Soft Actor Critic)을 이용하였고, latent 변수 z를 조건으로 하는 정책을 학습한다.
SAC는 actions에 대한 policy’s entropy를 최대화하여 object g에서 엔트로피 텀을 처리한다.
task reward를 대체하는 방법으로 skill reward로는 g의 expectation을 이용한다.
– 위 그림에서 logq – logp에 해당하는 부분
– p(z) 위해 categorical distribution 이용하였다.
Unsupervised learning동안 각 에피소드의 시작부분에서 skill z ~ p(z)를 샘플링하고 에피소드내내 해당 skill을 따라 행동한다.
Agent는 구분하기 쉬운 states를 방문하면 보상을 받는 반면에, discriminator는 방문한 states로부터 skill z를 더 잘 추론하기 위하여 업데이트 된다.
그리고 SAC 업데이트의 일부로서 엔트로피 정규화가 진행된다.
[추가] 만약 모든 tasks와 연관되어 있는 주어진 latent variable z~p(z)가 있다고 가정했을 때, 해당 값을 이용하여 reward function을 정의할 수 있다.
reward function = logD(z|s), 여기서 D는 discriminator 함수인데 state로부터 latent variable을 뽑는데 사용한다.
D(z|s) = q(z|s)
[추가] 한번 discriminator function이 학습되면, training을 위한 새로운 MDP를 sampling하는 것은 매우 직관적이 된다. 우선 latent variable z~p(z)를 샘플링하고 이를 이용해서 reward function r(s) =logD(z|s)를 만들어낸다.
(위 추가내용 출처 : talkingaboutme.tistory.com/entry/RL-Meta-Reinforcement-Learning)
Conclusion
본 논문에서는 reward function없이 skills를 학습하는 방법으로 DIAYN을 제안하고 있다.
DIAYN은 복잡한 tasks에 대해 다양한 skills를 학습하고, 실제로 task reward를 받는 과정없이 bench mark tasks를 해결하였다.
1) 빠르게 새로운 task에 적용하는 방법
2) HRL을 이용하여 복잡한 tasks를 해결하는 방법
3) 전문가를 모방하여 학습하는 방법
위 3가지 방법들을 제안하고 있다.
일반적으로 DIAYN은 task의 복잡한 action space를 useful skills의 set으로 대체하여 task를 더 쉽게 학습할 수 있도록 한다. DIAYN은 observation space와 reward function을 증가시키기 위한 방법들과 결합될 수 있다.
결론적으로 task reward function을 skill reward function으로 대체하여 사용한다는 것이다.
CODE
코드 구현 내역에 대하여 설명해 보도록 하겠다
기본적인 골격은 SAC를 참고하면 되는 부분인지라 SAC 코드를 먼저 살펴본 후 DIAYN에서 개선된 코드 내역을 살펴보는 것으로 진행하도록 하겠다.
SAC CODE
import gym
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.optim import Adam
from torch.distributions import Normal
import numpy as np
import random
import matplotlib.pyplot as plt
#===============================================================================
# global variables
#===============================================================================
seed = 1
gamma = 0.99
tau = 0.005
alpha = 0.2
lr = 0.0003
hidden_size = 256
epsilon = 1e-6
replay_size = 1000000
start_steps = 10000
updates_per_step = 1
batch_size = 256
num_steps = 1000000
def weights_init_(m):
if isinstance(m, nn.Linear):
torch.nn.init.xavier_uniform_(m.weight, gain=1)
torch.nn.init.constant_(m.bias, 0)
def hard_update(target, source):
for target_param, param in zip(target.parameters(), source.parameters()):
target_param.data.copy_(param.data)
def soft_update(target, source, tau):
for target_param, param in zip(target.parameters(), source.parameters()):
target_param.data.copy_(target_param.data * (1.0 - tau) + param.data * tau)
class ReplayMemory:
def __init__(self, capacity, seed):
random.seed(seed)
self.capacity = capacity
self.buffer = []
self.position = 0
def push(self, state, action, reward, next_state, done):
if len(self.buffer) < self.capacity:
self.buffer.append(None)
self.buffer[self.position] = (state, action, reward, next_state, done)
self.position = (self.position + 1) % self.capacity
def sample(self, batch_size):
batch = random.sample(self.buffer, batch_size)
state, action, reward, next_state, done = map(np.stack, zip(*batch))
return state, action, reward, next_state, done
def __len__(self):
return len(self.buffer)
class QNetwork(nn.Module):
def __init__(self, num_inputs, num_actions, hidden_dim):
super(QNetwork, self).__init__()
# Q1 architecture
self.linear1 = nn.Linear(num_inputs + num_actions, hidden_dim)
self.linear2 = nn.Linear(hidden_dim, hidden_dim)
self.linear3 = nn.Linear(hidden_dim, 1)
# Q2 architecture
self.linear4 = nn.Linear(num_inputs + num_actions, hidden_dim)
self.linear5 = nn.Linear(hidden_dim, hidden_dim)
self.linear6 = nn.Linear(hidden_dim, 1)
self.apply(weights_init_)
def forward(self, state, action):
xu = torch.cat([state, action], 1)
x1 = F.relu(self.linear1(xu))
x1 = F.relu(self.linear2(x1))
x1 = self.linear3(x1)
x2 = F.relu(self.linear4(xu))
x2 = F.relu(self.linear5(x2))
x2 = self.linear6(x2)
return x1, x2
class ValueNetwork(nn.Module):
def __init__(self, num_inputs, hidden_dim):
super(ValueNetwork, self).__init__()
self.linear1 = nn.Linear(num_inputs, hidden_dim)
self.linear2 = nn.Linear(hidden_dim, hidden_dim)
self.linear3 = nn.Linear(hidden_dim, 1)
self.apply(weights_init_)
def forward(self, state):
x = F.relu(self.linear1(state))
x = F.relu(self.linear2(x))
x = self.linear3(x)
return x
class GaussianPolicy(nn.Module):
def __init__(self, num_inputs, num_actions, hidden_dim):
super(GaussianPolicy, self).__init__()
self.linear1 = nn.Linear(num_inputs, hidden_dim)
self.linear2 = nn.Linear(hidden_dim, hidden_dim)
self.mean_linear = nn.Linear(hidden_dim, num_actions)
self.log_std_linear = nn.Linear(hidden_dim, num_actions)
self.apply(weights_init_)
def forward(self, state):
x = F.relu(self.linear1(state))
x = F.relu(self.linear2(x))
mean = self.mean_linear(x)
log_std = self.log_std_linear(x)
log_std = torch.clamp(log_std, min=-20, max=2)
return mean, log_std
def sample(self, state):
mean, log_std = self.forward(state)
std = log_std.exp()
normal = Normal(mean, std)
x_t = normal.rsample() # for reparameterization trick (mean + std * N(0,1))
action = torch.tanh(x_t)
log_prob = normal.log_prob(x_t)
# Enforcing Action Bound
log_prob -= torch.log(1 - action.pow(2) + epsilon)
log_prob = log_prob.sum(1, keepdim=True)
return action, log_prob, mean, log_std
class SAC(object):
def __init__(self, num_inputs, action_space):
self.gamma = gamma
self.tau = tau
self.alpha = alpha
self.action_range = [action_space.low, action_space.high]
self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
self.critic = QNetwork(num_inputs, action_space.shape[0], hidden_size).to(device=self.device)
self.critic_optim = Adam(self.critic.parameters(), lr=lr)
self.value = ValueNetwork(num_inputs, hidden_size).to(device=self.device)
self.value_target = ValueNetwork(num_inputs, hidden_size).to(self.device)
self.value_optim = Adam(self.value.parameters(), lr=lr)
hard_update(self.value_target, self.value)
self.policy = GaussianPolicy(num_inputs, action_space.shape[0], hidden_size).to(self.device)
self.policy_optim = Adam(self.policy.parameters(), lr=lr)
def select_action(self, state):
state = torch.FloatTensor(state).to(self.device).unsqueeze(0)
action, _, _, _ = self.policy.sample(state)
action = action.detach().cpu().numpy()[0]
return self.rescale_action(action)
def rescale_action(self, action):
return action * (self.action_range[1] - self.action_range[0]) / 2.0 +\
(self.action_range[1] + self.action_range[0]) / 2.0
def update_parameters(self, memory, batch_size, updates):
# Sample a batch from memory
state_batch, action_batch, reward_batch, next_state_batch, mask_batch = memory.sample(batch_size=batch_size)
state_batch = torch.FloatTensor(state_batch).to(self.device)
next_state_batch = torch.FloatTensor(next_state_batch).to(self.device)
action_batch = torch.FloatTensor(action_batch).to(self.device)
reward_batch = torch.FloatTensor(reward_batch).to(self.device).unsqueeze(1)
mask_batch = torch.FloatTensor(mask_batch).to(self.device).unsqueeze(1)
with torch.no_grad():
vf_next_target = self.value_target(next_state_batch)
next_q_value = reward_batch + mask_batch * self.gamma * (vf_next_target)
qf1, qf2 = self.critic(state_batch, action_batch)
qf1_loss = F.mse_loss(qf1, next_q_value)
qf2_loss = F.mse_loss(qf2, next_q_value)
qf_loss = qf1_loss + qf2_loss
self.critic_optim.zero_grad()
qf_loss.backward()
self.critic_optim.step()
pi, log_pi, mean, log_std = self.policy.sample(state_batch)
qf1_pi, qf2_pi = self.critic(state_batch, pi)
min_qf_pi = torch.min(qf1_pi, qf2_pi)
policy_loss = ((self.alpha * log_pi) - min_qf_pi).mean()
# Regularization Loss (optional)
reg_loss = 0.001 * (mean.pow(2).mean() + log_std.pow(2).mean())
policy_loss += reg_loss
self.policy_optim.zero_grad()
policy_loss.backward()
self.policy_optim.step()
vf = self.value(state_batch)
with torch.no_grad():
vf_target = min_qf_pi - (self.alpha * log_pi)
vf_loss = F.mse_loss(vf, vf_target)
self.value_optim.zero_grad()
vf_loss.backward()
self.value_optim.step()
soft_update(self.value_target, self.value, self.tau)
return vf_loss.item(), qf1_loss.item(), qf2_loss.item(), policy_loss.item()
def main():
env = gym.make('Pendulum-v1')
env.seed(seed)
env.action_space.seed(seed)
torch.manual_seed(seed)
np.random.seed(seed)
agent = SAC(env.observation_space.shape[0], env.action_space)
memory = ReplayMemory(replay_size, seed)
# Training Loop
total_numsteps = 0
updates = 0
ep_r_store = []
for i_episode in range(1000):
episode_reward = 0
episode_steps = 0
done = False
state = env.reset()
while not done:
if start_steps > total_numsteps:
action = env.action_space.sample()
else:
action = agent.select_action(state) # Sample action from policy
if len(memory) > batch_size:
for i in range(updates_per_step): # Number of updates per step in environment
# Update parameters of all the networks
value_loss, critic_1_loss, critic_2_loss, policy_loss = agent.update_parameters(memory, batch_size, updates)
updates += 1
next_state, reward, done, _ = env.step(action) # Step
episode_steps += 1
total_numsteps += 1
episode_reward += reward
# Ignore the "done" signal if it comes from hitting the time horizon.
# (https://github.com/openai/spinningup/blob/master/spinup/algos/sac/sac.py)
mask = 1 if episode_steps == env._max_episode_steps else float(not done)
memory.push(state, action, reward, next_state, mask) # Append transition to memory
state = next_state
if done:
ep_r_store.append(episode_reward)
if total_numsteps > num_steps:
break
print("Episode: {}, total numsteps: {}, episode steps: {}, reward: {}".format(
i_episode, total_numsteps, episode_steps, round(episode_reward, 2)))
env.close()
plt.plot(ep_r_store)
plt.title('SAC')
plt.xlabel('episode number')
plt.ylabel('return')
plt.grid(True)
plt.savefig("sac.png")
if __name__ == '__main__':
main()
hard_update와 soft_update의 차이를 잘 알아야 한다. 이를 이해하기 위해서는 full batch와 mini batch차이를 아는 것이 도움이 된다. hard_update를 full batch로 soft_update를 mini batch로 이해하면 된다.
replay buffer를 사용하여 Environment에서 Policy을 실행할 때 경험의 궤적을 저장합니다. 훈련 중에, 에이전트의 경험을 “replay”하기 위해 궤적의 서브 세트(순차 서브 세트 또는 샘플)에 대해 재현 버퍼가 조회됨
Value Network를 Q-Network로 구현한 내역이다.
Value Network의 구현체는 아래와 같다.
Actor network
– SAC내에서 continuous action space내에 stochastic policy를 사용한다.
– actor network는 각각의 action에 대해 평균과 표준편차를 생성한다.
– action은 주어진 평균과 표준편차를 가지고 gaussian distribution으로부터 sample되어진 것으로 본다.
– 계산된 표준편차 대신에, 우리는 network 연산된 로그 편차와 그리고 이를 추후에 표준편차로 변환한다
Actor network
– 상태가 주어지고, actor network는 평균과 log_std를 생성한다.
– log_std는 매우 크고 매우 작은 std를 생성하지 않도록 고정해 둔다.
SAC agent
DIAYN CODE