def train_model(self, sars, done): (state, action, reward, next_state) = sars state = u.t_float32(state) action = u.t_float32(action) reward = u.t_float32(reward) next_state = u.t_float32(next_state) value = self.critic(state) next_value = self.critic(next_state) if done: advantage = reward - value target = reward else: advantage = (reward + self.discount_factor * next_value) - value target = reward + self.discount_factor * next_value self.actor_optimizer.zero_grad() probs = self.actor(state) actor_loss = -Categorical(probs).log_prob(action) * advantage actor_loss.backward() self.actor_optimizer.step() self.critic_optimizer.zero_grad() critic_loss = torch.mean((target.detach() - self.critic(state))**2) critic_loss.backward() self.critic_optimizer.step() if done: TrainerMetadata().log(critic_loss, 'critic_loss') TrainerMetadata().log(actor_loss, 'actor_loss')
def train_model(self, i_episode, current_step, current_sars, current_done): s, a, ext_reward, next_s = current_sars TrainerMetadata().log(ext_reward, 'ext_reward', show_only_last=True, compute_maxmin=True) int_reward = 0 if self.use_intrinsic: int_reward = self.algorithm_im.get_reward(i_episode, current_step, current_sars, current_done) TrainerMetadata().log(int_reward, 'int_reward', show_only_last=True, compute_maxmin=True) if current_done: self.algorithm_im.scale_annealing() int_ext_reward, weighted_int, weighted_ext = self.algorithm_im.weighted_reward( int_reward, ext_reward) TrainerMetadata().log(int_ext_reward, 'int_ext_reward', show_only_last=True, compute_maxmin=True) current_sars = (s, a, int_ext_reward, next_s) self.algorithm_rl.train_model(current_sars, current_done)
def get_weighted_reward(self, i_epoch, current_step, current_sars, current_done): current_state, current_action, ext_reward, next_state = current_sars TrainerMetadata().log(ext_reward, 'ext_reward', show_only_last=True, compute_maxmin=True) int_reward = 0 if self.use_intrinsic: int_reward = self.algorithm_im.get_reward(i_epoch, current_step, current_sars, current_done) TrainerMetadata().log(int_reward, 'int_reward', show_only_last=True, compute_maxmin=True) if current_done: self.algorithm_im.scale_annealing() int_ext_reward, weighted_int, weighted_ext = self.algorithm_im.weighted_reward( int_reward, ext_reward) TrainerMetadata().log(int_ext_reward, 'int_ext_reward', show_only_last=True, compute_maxmin=True) return int_ext_reward
def train_model(self): # 메모리에서 일정 크기만큼 기억을 불러온다 # 그 후 기억을 모아 각 변수별로 모은다. (즉, 전치행렬) transitions = self.memory.sample(self.batch_size) batch = self.transition_structure(*zip(*transitions)) # 텐서의 집합에서 고차원 텐서로 # tuple(tensor, ...) -> tensor() state_batch = torch.cat(batch.state).to(device) action_batch = torch.cat(batch.action).to(device) reward_batch = torch.cat(batch.reward).to(device) next_state_batch = torch.cat(batch.next_state).to(device) # <평가망 최적화> # (무엇을, 어디서, 어떻게, 왜) # 각각의 기억에 대해, 타겟 정책망에, 다음 상태를 넣어서, 다음 타겟 액션을 구한다. # 각각의 기억에 대해, 타겟 평가망에, 다음 상태와 타겟 액션을 넣어서, 다음 타겟 보상을 구한다. target_actions = self.target_actor(next_state_batch) target_rewards = self.target_critic(next_state_batch, target_actions) # 현재 보상에 타겟 보상을 더해서 예측한 보상을 구한다. expected_rewards = reward_batch.unsqueeze( dim=1) + self.discount_factor * target_rewards predicted_rewards = self.critic(state_batch, action_batch) # 평가망의 예측 보상과 타겟 평가망의 예측 보상을 MSE 비교 후 업데이트 self.critic_optimizer.zero_grad() critic_loss = nn.MSELoss().to(device) critic_loss = critic_loss(expected_rewards, predicted_rewards) critic_loss.backward() self.critic_optimizer.step() # <정책망 최적화> self.actor_optimizer.zero_grad() predicted_actions = self.actor(state_batch) q_output = self.critic(state_batch, predicted_actions) # actor_loss = -1*torch.sum(q_output).to(device) # sum 이 아니라 mean 인 이유 # -> sum이든 mean이든 똑같으나 (N은 같으므로) # -> sum 했을 때 값이 많이 커지니까 그냥 보기 좋게 mean으로.. actor_loss = -1 * torch.mean(q_output).to(device) # 정책망의 예측 보상을 정책 그라디언트로 업데이트 actor_loss.backward() self.actor_optimizer.step() # 현재 평가망, 정책망의 가중치를 타겟 평가망에다 덮어쓰기 u.soft_update_from_to(src_nn=self.critic, dst_nn=self.target_critic, tau=self.soft_target_update_tau) u.soft_update_from_to(src_nn=self.actor, dst_nn=self.target_actor, tau=self.soft_target_update_tau) TrainerMetadata().log(critic_loss, 'critic_loss') TrainerMetadata().log(actor_loss, 'actor_loss')
def _line_search(self, old_loss, loss_grad, step_vector_x, advantage_batch, s_batch, old_policy, a_batch): old_actor = copy.deepcopy(self.actor) actor_flat_params = parameters_to_vector(self.actor.parameters()) expected_improve = (loss_grad * step_vector_x).sum(0, keepdim=True) expected_improve = expected_improve.cpu().numpy() i, line_search_succeed = -1, False for i in range(self.backtrack_iters): # 라인 서치로 정책 업데이트 backtrack_ratio = self.backtrack_coeff**i constraint_params = actor_flat_params + backtrack_ratio * step_vector_x vector_to_parameters(constraint_params, self.actor.parameters()) # 바꾼 actor를 기반으로 다시 평균(log정책(a|s)*A) 구해봄 meow, logstd, std = self.actor(s_batch) new_policy = self._log_density(a_batch, meow, std, logstd) constraint_loss = self._surrogate_loss( old_policy=old_policy, new_policy=new_policy, advantage_batch=advantage_batch) loss_improve = (constraint_loss - old_loss).detach().cpu().numpy() weighted_expected_improve = backtrack_ratio * expected_improve kl = kl_divergence(new_actor=self.actor, old_actor=old_actor, s_batch=s_batch) kl = kl.mean() TrainerMetadata().log(kl, 'KL', 'current_kl', compute_maxmin=True) TrainerMetadata().log(self.max_kl, 'KL', 'max_kl') TrainerMetadata().log(loss_improve / weighted_expected_improve, 'real / expected (improve)', 'real_ratio', compute_maxmin=True) TrainerMetadata().log(0.5, 'real / expected (improve)', 'threshold ') # TrainerMetadata().log(expected_improve, 'expected_improve', compute_maxmin=True) # see https://en.wikipedia.org/wiki/Backtracking_line_search # TODO: 0.5 인 이유? 1.0 보다 커야 개선된 것 아닌가 # 일단 Armijo used 1⁄2 for both c and tau in a paper he published in 1966 if kl < self.max_kl and (loss_improve / weighted_expected_improve) > 0.5: line_search_succeed = True break TrainerMetadata().console_log('KL_iter', i) if not line_search_succeed: self.actor = copy.deepcopy(old_actor) print('policy update does not impove the surrogate')
def train_model(self, i_episode, step, done): # 메모리에서 일정 크기만큼 기억을 불러온다 # 그 후 기억을 모아 각 변수별로 모은다. (즉, 전치행렬) # TODO: random과 zip func 글카에서 하기 transitions = self.memory.sample(self.batch_size) # SARS = State, Action, Reward, next State sars_batch = self.transition_structure(*zip(*transitions)) # TODO: 이거 튜플로 묶으면 다시 GPU에서 CPU로 오나? # 텐서의 집합에서 고차원 텐서로 # tuple(tensor, ...) -> tensor() s = torch.cat(sars_batch.state).to(self.device) a = torch.cat(sars_batch.action).to(self.device) ext_r = torch.cat(sars_batch.reward).to(self.device) next_s = torch.cat(sars_batch.next_state).to(self.device) # int_r = self.algorithm_im.get_reward(i_episode, step, s, a, next_s) int_r = self.im.get_reward(i_episode, step, transitions, s, a, next_s) ext_r = self.im.weighted_reward_batch(int_r, ext_r) critic_loss, actor_loss = self.ddpg.train_model(s, a, ext_r, next_s) if done: TrainerMetadata().log(critic_loss, 'critic_loss') TrainerMetadata().log(actor_loss, 'actor_loss') TrainerMetadata().log(torch.max(int_r), 'int_reward', 'max') TrainerMetadata().log(torch.mean(int_r), 'int_reward', 'mean') TrainerMetadata().log(torch.min(int_r), 'int_reward', 'min') TrainerMetadata().log(torch.max(ext_r), 'ext_reward', 'max') TrainerMetadata().log(torch.mean(ext_r), 'ext_reward', 'mean') TrainerMetadata().log(torch.min(ext_r), 'ext_reward', 'min')
def __init__(self, state_size, action_size): super().__init__() self._set_hyper_parameters() self.device = TrainerMetadata().device # 기본 설정 self.state_size, self.action_size = state_size, action_size self.value_size = 1 # 모델 빌드 self.actor = Actor(self.state_size, self.action_size).to(self.device) self.critic = Critic(self.state_size, self.value_size).to(self.device) # Optimizer self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=self.learning_rate_actor) # critic 에만 L2 weight decay 넣음 self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=self.learning_rate_critic) self.register_serializable([ 'self.actor', 'self.critic', 'self.actor_optimizer', 'self.critic_optimizer', ])
def __init__(self, algorithm_im, algorithm_rl, state_size, action_size, action_range, use_intrinsic=True): super().__init__() self._set_hyper_parameters() self.device = TrainerMetadata().device # 기본 설정 self.state_size, self.action_size = state_size, action_size # TODO: 정규화된 입력인지 검사 문구 넣고 range 빼기 self.action_low, self.action_high = action_range self.algorithm_im, self.algorithm_rl = algorithm_im, algorithm_rl self.use_intrinsic = use_intrinsic if self.use_intrinsic is False: self.algorithm_im.intrinsic_reward_ratio = 0 self.register_serializable([ 'algorithm_im', 'algorithm_rl', ])
def __init__(self, state_size, action_size): super().__init__() self._set_hyper_parameters() self.device = TrainerMetadata().device # 기본 설정 self.state_size, self.action_size = state_size, action_size # 모델 빌드 self.actor = Actor(self.state_size, self.action_size).to(self.device) self.critic = Critic(self.state_size).to(self.device) # Optimizer # critic 에만 L2 weight decay 넣음 self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=self.learning_rate_critic, weight_decay=self.l2_weight_decay) self.transition_structure = Transition self.memory = list() self.gae = GAE(gamma=self.gamma) self.register_serializable([ 'self.actor', 'self.critic', 'self.critic_optimizer', ])
def conjugate_gradient(func_Ax, s_batch, loss_grad_data, cg_iters=10, residual_tol=1e-10): """ Demmel p 312 공역 구배법 = 켤레 기울기법 == 설명 (from 위키피디아 한국어판) == Ax = b 를 풀고 싶다고 하자. 이 때 A는 (대칭행렬)이며 (대칭행렬의 이차형식 > 0)이어야 한다. 켤레 벡터 뜻은 대충 A의 이차형식을 0으로 만드는 두 벡터임.. 아무튼 정답벡터 x를 (x = α*켤레벡터들의 합)으로 나타낼 수 있다고 하면 어찌어찌 잘 하면 α = <p, b> / |p|^2 으로 나타낼 수 있다고 함 근데 차원이 커지면 이거 풀기 귀찮으니까 대충 때려 맞추고 점점 해답에 접근하는 방법을 씀 즉 r0 = b - Ax0 라 하고 이걸로 α 구함 이 α를 기준으로 x와 r을 다시 나타냄 다시 나타낸 r로 잘 구함... (반복) 대충 이런 개념 z = Ax v = r*r ----- p*(Ax) new_x = old_x + v * p new_r = old_r + v * Ax meow = new_r * new_r ------------- r * r new_p = r + (meow * p) """ device = TrainerMetadata().device p = loss_grad_data.clone().to(device) r = loss_grad_data.clone().to(device) x = torch.zeros_like(loss_grad_data).to(device) dot_rr = torch.dot(r, r).to(device) for i in range(cg_iters): # 원래 여기서 z = Ax를 계산해야 한다 # 그런데 A를 갖고 있기 힘드니깐 대충 Ax 예상해서 던져주는 놈을 사용할 것이다 # z = A * p # z = func_Ap z = func_Ax((p, s_batch)) alpha = dot_rr / torch.dot(p, z).to(device) x += alpha * p r -= alpha * z new_dot_rr = torch.dot(r, r).to(device) meow = new_dot_rr / dot_rr p = r + (meow * p) dot_rr = new_dot_rr if dot_rr < residual_tol: break return x
def __init__(self, state_size, action_size): super(Actor, self).__init__() self.device = TrainerMetadata().device self.layer_sizes = [state_size, 24, action_size] self.linear1 = nn.Linear(self.layer_sizes[0], self.layer_sizes[1]) self.linear2 = nn.Linear(self.layer_sizes[1], self.layer_sizes[2]) self.head = nn.Softmax(dim=-1) u.fanin_init(self.linear1.weight) u.fanin_init(self.linear2.weight)
def __init__(self, state_size, action_size): super().__init__() self._set_hyper_parameters() self.device = TrainerMetadata().device self.region_head = Region(state_size, action_size) self.register_serializable([ 'self.region_head', ])
def __init__(self, state_size, action_size, action_range=(-1, 1)): super().__init__() self._set_hyper_parameters() self.device = TrainerMetadata().device # 기본 설정 self.state_size, self.action_size = state_size, action_size # TODO: 정규화된 입력인지 검사 문구 넣고 range 빼기 self.action_low, self.action_high = action_range # 모델 빌드 self.actor = Actor(self.state_size, self.action_size).to(self.device) self.critic = Critic(self.state_size, self.action_size).to(self.device) self.target_actor = Actor(self.state_size, self.action_size).to(self.device) self.target_critic = Critic(self.state_size, self.action_size).to(self.device) # 타겟 정책망, 타겟 평가망 가중치를 각각 정책망, 평가망 가중치로 초기화 self.target_actor.load_state_dict(self.actor.state_dict()) self.target_critic.load_state_dict(self.critic.state_dict()) # 타겟망들은 오차계산 및 업데이트 안 하는 평가 전용모드임을 선언 self.target_actor.eval() self.target_critic.eval() # Optimizer self.actor_optimizer = optim.Adam( self.actor.parameters(), lr=self.learning_rate_actor ) # critic 에만 L2 weight decay 넣음 self.critic_optimizer = optim.Adam( self.critic.parameters(), lr=self.learning_rate_critic, weight_decay=self.l2_weight_decay ) # 리플레이 메모리 # DQN, DDPG에서 제안하고 쓰는 개념이므로 정의는 따로 두더라도 인스턴스는 알고리즘 내부에서 갖고 있는다 self.transition_structure = Transition self.memory = ReplayMemory(self.memory_maxlen, self.transition_structure) # 오른스타인-우렌벡 과정 self.noise = OrnsteinUhlenbeckNoise(self.action_size) self.register_serializable([ 'self.actor', 'self.critic', 'self.target_actor', 'self.target_critic', 'self.actor_optimizer', 'self.critic_optimizer', 'self.memory', 'self.noise', ])
def __init__(self, state_size, value_size): super(Critic, self).__init__() self.device = TrainerMetadata().device self.layer_sizes = [state_size, 24, 24, value_size] self.linear1 = nn.Linear(self.layer_sizes[0], self.layer_sizes[1]) self.linear2 = nn.Linear(self.layer_sizes[1], self.layer_sizes[2]) self.head = nn.Linear(self.layer_sizes[2], self.layer_sizes[3]) u.fanin_init(self.linear1.weight) u.fanin_init(self.linear2.weight) nn.init.uniform_(self.head.weight, a=-3 * 10e-4, b=3 * 10e-4)
def __init__(self, state_size, action_size): self._set_hyper_parameters() self.device = TrainerMetadata().device self.state_size = state_size self.action_size = action_size self.value_size = 1 self.actor = self.build_actor() self.critic = self.build_critic() self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=self.learning_rate_actor) self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=self.learning_rate_critic)
def _surrogate_loss(self, old_policy, new_policy, advantage_batch): # CPI = Conservative Policy Iteration improve_ratio = self._improve_ratio(old_policy, new_policy) clipped_ratio = torch.clamp(improve_ratio, 1 - self.epsilon, 1 + self.epsilon) TrainerMetadata().log(torch.max(improve_ratio), 'improve_ratio', 'max', show_only_last=True, compute_maxmin=True) TrainerMetadata().log(torch.min(improve_ratio), 'improve_ratio', 'min', show_only_last=True, compute_maxmin=True) # TODO: advantage 나중에 곱해보기? loss_cpi = improve_ratio * advantage_batch loss_clip = clipped_ratio * advantage_batch loss = torch.min(loss_cpi, loss_clip).mean() return loss.to(self.device)
def __init__(self, state_size, action_size): super().__init__() self.device = TrainerMetadata().device # 64, 64는 논문 저자 공식 레포지토리 self.layer_sizes = [state_size, 64, 64, action_size] self.linear1 = nn.Linear(self.layer_sizes[0], self.layer_sizes[1]) self.linear2 = nn.Linear(self.layer_sizes[1], self.layer_sizes[2]) self.head = nn.Linear(self.layer_sizes[2], self.layer_sizes[3]) # TODO: (개선) 초기화 이해 안 감 -> 공식 레포가 이렇지만 다른 초기화는? self.head.weight.data.mul_(0.1) self.head.bias.data.mul_(0.0)
def __init__(self, state_size, action_size, action_range=(-1, 1)): super(DQNNetwork, self).__init__() self.device = TrainerMetadata().device self.layer_sizes = [state_size, 24, 24, action_size] # TODO: 정규화된 입력인지 검사 문구 넣고 range 빼기 self.action_low, self.action_high = action_range self.linear1 = nn.Linear(self.layer_sizes[0], self.layer_sizes[1]) self.linear2 = nn.Linear(self.layer_sizes[1], self.layer_sizes[2]) self.head = nn.Linear(self.layer_sizes[2], self.layer_sizes[3]) u.fanin_init(self.linear1.weight) u.fanin_init(self.linear2.weight) nn.init.uniform_(self.head.weight, a=-3 * 10e-3, b=3 * 10e-3)
def __init__(self, algorithm_rl, state_size, action_size): super().__init__() self._set_hyper_parameters() self.device = TrainerMetadata().device # 기본 설정 self.state_size, self.action_size = state_size, action_size self.algorithm_rl = algorithm_rl self.register_serializable([ 'algorithm_rl', ])
def train_model(self, sars, done): # 메모리에서 일정 크기만큼 기억을 불러온다 # 그 후 기억을 모아 각 변수별로 모은다. (즉, 전치행렬) # TODO: random과 zip func 글카에서 하기 transitions = self.memory.sample(self.batch_size) # SARS = State, Action, Reward, next State sars_batch = self.transition_structure(*zip(*transitions)) # TODO: 이거 튜플로 묶으면 다시 GPU에서 CPU로 오나? # 텐서의 집합에서 고차원 텐서로 # tuple(tensor, ...) -> tensor() s_batch = torch.stack(sars_batch.state).to(self.device) a_batch = torch.stack(sars_batch.action).to(self.device) r_batch = torch.stack(sars_batch.reward).to(self.device) next_s_batch = torch.stack(sars_batch.next_state).to(self.device) self.critic_optimizer.zero_grad() critic_loss = self.get_critic_loss(s_batch, a_batch, r_batch, next_s_batch) # 예측한 보상과 향후 기대하는 보상을 MSE 비교 후 업데이트 # ||r' - [r + (r+1)']|| = 0 # ∴ ||r' - (r+1)' || = r (현재 Q함수와 다음 Q함수 차이가 딱 실제 보상이 되도록 학습) critic_loss.backward() self.critic_optimizer.step() self.actor_optimizer.zero_grad() actor_loss = self.get_actor_loss(s_batch) # 정책망의 예측 보상을 정책 그라디언트로 업데이트 # ∇θµ[Q(s,a|θ)] ∇θµ[µ(s|θµ)] actor_loss.backward() self.actor_optimizer.step() # 현재 평가망, 정책망의 가중치를 타겟 평가망에다 덮어쓰기 u.soft_update_from_to(src_nn=self.critic, dst_nn=self.target_critic, tau=self.soft_target_update_tau) u.soft_update_from_to(src_nn=self.actor, dst_nn=self.target_actor, tau=self.soft_target_update_tau) if done: TrainerMetadata().log(critic_loss, 'critic_loss', show_only_last=False) TrainerMetadata().log(actor_loss, 'actor_loss', show_only_last=False)
def __init__(self, state_size, action_size): super().__init__() self._set_hyper_parameters() self.device = TrainerMetadata().device self.state_size, self.action_size = state_size, action_size self.register_serializable([ 'self.intrinsic_reward_ratio', 'self.intrinsic_reward_ratio_annealing', 'self.intrinsic_reward_ratio_decay', 'self.intrinsic_reward_ratio_min', ])
def train_model(self, sars, done): if self.epsilon > self.epsilon_min: self.epsilon *= self.epsilon_decay # 메모리에서 일정 크기만큼 기억을 불러온다 # 그 후 기억을 모아 각 변수별로 모은다. (즉, 전치행렬) # TODO: random과 zip func 글카에서 하기 transitions = self.memory.sample(self.batch_size) # SARS = State, Action, Reward, next State sars_batch = self.transition_structure(*zip(*transitions)) # TODO: 이거 튜플로 묶으면 다시 GPU에서 CPU로 오나? # 텐서의 집합에서 고차원 텐서로 # tuple(tensor, ...) -> tensor() s_batch = torch.stack(sars_batch.state).to(self.device) a_batch = torch.stack(sars_batch.action).to(self.device) r_batch = torch.stack(sars_batch.reward).to(self.device) next_s_batch = torch.stack(sars_batch.next_state).to(self.device) done_batch = torch.stack(sars_batch.done).to(self.device) # 정책망에 각각의 기억에 대해 상태를 넣어서 각각의 액션 보상을 구한다. # 그 다음에 선택한 액션 쪽의 보상을 가져온다. state_action_values = self.policy(s_batch).gather(1, a_batch) # 타겟망 예측에서, 아직 안 죽은 거에만 큐함수 추정을 더해주기 위해 마스크를 만들기 # 어렵게 마스크를 만드는 이유? 한번에 모아서 신경망에 보내면 실행 속도가 빨라짐.. # 안 죽었을 때의 상태들만 가져오기 not_done = [not i for i in done_batch] non_final_mask = u.t_uint8(not_done).squeeze().to(self.device) non_final_next_states = torch.stack( list(compress(next_s_batch, not_done))) # 안 죽었을 때의 타겟망 보상 추정하기 next_state_values = torch.zeros(len(s_batch), device=self.device) next_state_values[non_final_mask] = self.target_policy( non_final_next_states).max(1)[0].detach() next_state_values = next_state_values.unsqueeze(dim=1) # 기존 보상에 안 죽었을 때만 큐함수 추정을 더하기 expected_state_action_values = r_batch + (self.discount_factor * next_state_values) # 정책망의 예측 보상과 타겟망의 예측 보상을 MSE 비교 self.policy_optimizer.zero_grad() loss = nn.MSELoss().to(self.device) loss = loss(state_action_values, expected_state_action_values) loss.backward() self.policy_optimizer.step() if done: TrainerMetadata().log(loss, 'policy_loss')
def kl_divergence(new_actor, old_actor, s_batch): device = TrainerMetadata().device meow, logstd, std = new_actor(s_batch) meow_old, logstd_old, std_old = old_actor(s_batch) meow_old = meow_old.detach() std_old = std_old.detach() logstd_old = logstd_old.detach() # kl divergence between old policy and new policy : D( pi_old || pi_new ) # pi_old -> mu0, logstd0, std0 / pi_new -> mu, logstd, std # be careful of calculating KL-divergence. It is not symmetric metric kl = logstd_old - logstd + (std_old.pow(2) + (meow_old - meow).pow(2)) / \ (2.0 * std.pow(2)) - 0.5 return kl.sum(1, keepdim=True)
def __init__(self, state_size): super().__init__() self.device = TrainerMetadata().device # 액션 크기는 안 받는 이유는? Q(s, a) 아닌가? # Q 함수 추정이 아니라 V (Value) 추정이다 # 나중에 GAE 에서 이득(A) 계산할 때 V가 필요 self.layer_sizes = [state_size, 64, 64, 1] self.linear1 = nn.Linear(self.layer_sizes[0], self.layer_sizes[1]) self.linear2 = nn.Linear(self.layer_sizes[1], self.layer_sizes[2]) self.head = nn.Linear(self.layer_sizes[2], self.layer_sizes[3]) # TODO: 초기화 이해 안 감 -> 공식 레포가 이렇지만 다른 초기화는? self.head.weight.data.mul_(0.1) self.head.bias.data.mul_(0.0)
def __init__(self, state_size, action_size): self._set_hyper_parameters() self.device = TrainerMetadata().device self.state_size = state_size self.action_size = action_size self.policy_model = self.build_model() self.target_model = self.build_model() self.update_target_model() self.target_model.eval() self.policy_optimizer = optim.Adam(self.policy_model.parameters(), lr=self.learning_rate_dqn) self.transition_structure = Transition self.memory = ReplayMemory(self.memory_maxlen, self.transition_structure)
def train_model(self): if self.epsilon > self.epsilon_min: self.epsilon *= self.epsilon_decay # 메모리에서 일정 크기만큼 기억을 불러온다 # 그 후 기억을 모아 각 변수별로 모은다. (즉, 전치행렬) transitions = self.memory.sample(self.batch_size) batch = self.transition_structure(*zip(*transitions)) target = [] target_val = [] # 정책망에 각각의 기억에 대해 상태를 넣어서 각각의 액션 보상을 구한다. # 그 다음에 선택한 액션 쪽의 보상을 가져온다. for i in range(self.batch_size): state = batch.state[i] action = batch.action[i] target.append(self.policy_model(state).squeeze()[action]) # 안 죽었을 때의 타겟망 보상 추정하기 for i in range(self.batch_size): next_state = batch.next_state[i] target_val.append(self.target_model(next_state)) # 기존 보상에 안 죽었을 때만 큐함수 추정을 더하기 for i in range(self.batch_size): done = batch.done[i] reward = batch.reward[i] if done: target_val[i] = u.t_float32(reward).squeeze() else: target_val[i] = reward + self.discount_factor * torch.max( target_val[i]).to(self.device) # 정책망의 예측 보상과 타겟망의 예측 보상을 MSE 비교 self.policy_optimizer.zero_grad() loss = nn.MSELoss().to(self.device) loss = loss(torch.stack(target), torch.stack(target_val)) loss.backward() self.policy_optimizer.step() TrainerMetadata().log(loss, 'policy_loss')
def __init__(self, state_size, action_size, action_range=(-1, 1)): super().__init__() self._set_hyper_parameters() self.device = TrainerMetadata().device # 기본 설정 self.state_size, self.action_size = state_size, action_size # TODO: 정규화된 입력인지 검사 문구 넣고 range 빼기 self.action_low, self.action_high = action_range # 모델 빌드 self.policy = DQNNetwork(self.state_size, self.action_size).to(self.device) self.target_policy = DQNNetwork(self.state_size, self.action_size).to(self.device) # 타겟 정책망을 정책망 가중치로 초기화 self.target_policy.load_state_dict(self.policy.state_dict()) # 타겟망은 오차계산 및 업데이트 안 하는 평가 전용모드임을 선언 self.target_policy.eval() # Optimizer self.policy_optimizer = optim.Adam(self.policy.parameters(), lr=self.learning_rate_policy) # 리플레이 메모리 # DQN, DDPG에서 제안하고 쓰는 개념이므로 정의는 따로 두더라도 인스턴스는 알고리즘 내부에서 갖고 있는다 self.transition_structure = Transition self.memory = ReplayMemory(self.memory_maxlen, self.transition_structure) self.register_serializable([ 'self.policy', 'self.target_policy', 'self.policy_optimizer', 'self.memory', 'self.epsilon', 'self.epsilon_decay', 'self.epsilon_min', ])
def __init__(self, state_size, action_size, action_range=(-1, 1)): self._set_hyper_parameters() self.device = TrainerMetadata().device # 기본 설정 self.state_size = state_size self.action_size = action_size # TODO: 정규화된 입력인지 검사 문구 넣고 range 빼기 self.action_low, self.action_high = action_range self.ddpg = DDPG(self.state_size, self.action_size, action_range) self.im = PredictiveSurpriseMotivation(self.state_size, self.action_size) # TODO: 리플레이 메모리를 DDPG 알고리즘에서 분리해서 저장하는 게 아름다운가? # 리플레이 메모리 self.transition_structure = Transition self.memory = ReplayMemory(self.memory_maxlen, self.transition_structure)
def draw_line(self, y, x=None, x_auto_increment=None, interval=None, env=None, win=None, variable=None): if x is None or x == 0: if x_auto_increment == 'global_step': x = TrainerMetadata().global_step elif x_auto_increment == 'per_variable_step': x = self.per_variable_step[win] self.per_variable_step[win] += 1 interval = interval if interval else self.default_interval env = env if env else self.default_env win = win if win else self.default_win variable = variable if variable else self.default_variable if x % interval == 0: # Visdom은 numpy array를 입력으로 받음 x = x if isinstance(x, np.ndarray) else np.array([x]) y = y if isinstance(y, np.ndarray) else np.array([y]) win = self._abbreviate_win_name(env, win) self.viz.line(X=np.array([x]), Y=np.array([y]), name=variable, win=win, update='append', opts={'title': win})
def execute(X, n_clusters, device=None, tol=1e-4): """lloyd algorithm_rl Args: X: n차원 Numpy 배열 (float 가정) n_clusters: 클러스터 갯수 device: PyTorch device 오브젝트 tol: 계산 도중 중심 이동 간격 최소 기대치 Returns: choice_cluster: X가 속한 클러스터 인덱스 (0~n-1) initial_state: 초기 좌표 """ device = device if device else TrainerMetadata().device X = torch.from_numpy(X).float().to(device) initial_state = get_initial_state(X, n_clusters) while True: # Expectation dis = _pairwise_distance(X, initial_state) choice_cluster = torch.argmin(dis, dim=1) initial_state_pre = initial_state.clone() for index in range(n_clusters): selected = torch.nonzero(choice_cluster == index).squeeze() selected = torch.index_select(X, 0, selected) # Maximization initial_state[index] = selected.mean(dim=0) center_shift = torch.sum(torch.sqrt(torch.sum((initial_state - initial_state_pre) ** 2, dim=1))) if center_shift ** 2 < tol: break return choice_cluster, initial_state