BASHA TECH

4. Reinforcement Learning - 신경망 에이전트 사용 본문

Computer/Reinforcement Learning

4. Reinforcement Learning - 신경망 에이전트 사용

Basha 2022. 11. 23. 12:38
728x90
<정책 신경망: action을 찾아내는 것 => policy network를 찾는다. 정책을 찾아내는 신경망. 정책에 따라 행위가 달라짐.>
1단계
- 카트폴 게임은 분류 문제로 풀 수도 있다.
- 4개의 환경 상태값은 특징값이 되고, 해당 특징값에 대응하는 올바른 라벨값은 행위가 된다.
- 신경망 에이전트는 환경(ex. 게임, 주식시장)과 상화작용하면서 특징값 및 라벨값을 수집한다.
- 이 데이터셋이 점차적으로 증가하면서 신경망 에이전트는 환경 상태에 대한 올바른 행위를 학습할 수 있게 된다.
- 이런 경우 신경망은 정책에 대해 기술하고, 에이전트는 새로운 경험을 기반으로 정책을 수정한다.
import logging # 실행되는 상태를 저장
import tensorflow as tf
tf.get_logger().setLevel(logging.ERROR) # Error가 났을 때, error를 저장.
# 만약, warning을 넣으면 warning을 저장한다.
from tensorflow.python.framework.ops import disable_eager_execution
disable_eager_execution() # 즉시 실행을 멈추겠다.

eager_execution을 disable을 해야하는 이유, 즉시 실행하면 안됨. 단독 실행하면 안되기 때문.

환경도 받아야하고, 모든 것을 받은 이후 최종적으로 완성이 되었을 때 실행이 되어야한다. (tensorflow도 pytorch도.)

이거 안 하면 에러 뜸

from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam, RMSprop
from sklearn.metrics import accuracy_score # 정확도 가져오기
def set_seeds(seed=100):
# numpy의 random tensorflow의 random, action
    random.seed(seed) 
    np.random.seed(seed) 
    tf.random.set_seed(seed)
    # env.seed(seed)
    env.action_space.seed(seed)
2 단계
- 두 번째로 에이전트의 주요 요소인 신경망 정책, 정책에 따른 행위 선택, 정책의 업데이트, 에피소드에서 학습하기 등을 모두 포함하는 NNAgent 클래스를 구현한다.
- 이 에이전트는 행위를 선택하기 위해 탐색(exploration)과 이용(exploitation)을 모두 사용한다.
- '탐색'은 현재의 정책과 관계없이 **무작위로** 행위를 하는 것을 말하고, '이용'은 현재의 정책에 따른 행위를 하는 것을 말한다. (탐색은 무작위다)
(신경이 어느정도 weight를 찾아내게 되면 탐색은 줄고 이용은 늘어난다.)
- 어느 정도의 탐색을 해야지 더 많은 경험을 통해 에이전트는 학습을 할 수 있다.
class NNAgent:
    # 1) max : 최대 보상 
    def __init__(self): # __init__ => 생성자
        # 3개의 변수가 생성됨
        self.max = 0 # 멤버 변수 선언
        self.scores = list() # 멤버 변수 선언
        self.memory = list() # 멤버 변수 선언
        # w와 신경망이 돌아갈 때 episode의 상태를 저장하는 memeory
        self.model = self._build_model()

    # 2) 정책을 나타내는 신경망 분류 모형
    def _build_model(self):
        model = Sequential()
        model.add(Dense(24, input_dim=4, #핵심 input_dim => 상태가 4개를 받기 때문.
                        # trading 이면, input_dim이 feature값과 동일하겠다.
                        # 24는 node의 순위값. node의 갯수는 상관x 
                        activation='relu'))
        model.add(Dense(1, activation='sigmoid')) # 1: 이진분류. 
        model.compile(loss='binary_crossentropy', 
                      optimizer=RMSprop(learning_rate=0.001)) 
                      # Adam을 써도 되고 RMS 써도 되고.
        return model # 아직 fitting 안 함. 이 신경망 하나로 끝나는 게 아님.
    # 신경망은 계속 돌아야함. 그래서 execution 하면 안된다.
    # compile까지 되어있는 모델을 돌림. fitting 할 수 있는 모델.

    # 3) 정책 행위를 고르는 메소드   
    def act(self, state):
        if random.random() <= 0.5: # 탐색이다 (무작위)
            return env.action_space.sample() # 탐색 (무작위) (sample 하게끔 return 아직까지 계속 무작위다.)
        action = np.where(self.model.predict( # 이용 (0.5가 기준이다.)
            state, batch_size=None)[0, 0] > 0.5, 1, 0) # 반은 탐색, 반은 이용하겠다.
        '''
        *** 이것이 핵심! 탐색할 것인지 이용할 것인지.
        action = np.where(self.model.predict(  
            state, batch_size=None)[0, 0] > 0.5 => 조건문 얘 때문에 학습이 된다. 이것이 강화 학습의 핵심
            0.5 를 기준으로 0.5보다 작으면 뱉어내고, 0.5보다 크면 학습해라.
            threshold(한계점)가 0.5임. 그전 까지는 무작위임. 그전 까지는 신경망을 타고.. 이전에는 이용~
            따라서 나중에 0.5 가 입실론이 된다.
        '''
        return action # action값을 return 받음. action_space 자체가 0아니면 1이기땜에 spance 값도 0 or 1의 값이 나옴.

    # 4) 정책을 업데이트하는 메소드
    def train_model(self, state, action): 
        # train_model : 정책을 업데이트 / model만 train함. 강화학습 하지 않았음.
        # fitting 하기 위해. fitting 하기 위해 train data와 원래 답이 들어가야함
        # train data : state, 원래 답 : action(action 값이 아직까진 random 함)
        self.model.fit(state, np.array([action,]), 
                    # action값을 받을 땐 ndarray가 들어간다. list 아님.
                    # list는 array로 변환 후 집어넣어야 함.    
                       epochs=1, verbose=False) # epoch 1 : 한번만 돌리겠다. 
    
    # 5) 환경과 상호작용하며 학습하는 메소드
    def learn(self, episodes): # episoes : 게임수 (게임 몇번 할 거야?) 대신 초기값이 없다. 
        for e in range(1, episodes + 1):
            state = env.reset()
            state = np.reshape(state[0], [1, 4]) # reshape이 중요/ 신경망을 2차원으로 reshape. 신경망에 train_data가 되어서 집어넣어야하기때문.
            # 이전엔 데이터가 한 행씩 들어갔다. 신경망에.. (Neural Net) 한 행마다 리스트가 됨. 
            # state는 1차원 배열. 하지만 1개가 들어갈 지라도 1차원 배열이여야함.
            # 만약 reshape을 하지 않으면 한 데이터씩 들어감. 하지만 상태는 한 묶음이기때문에 2차원으로 들어가야함.
            for i in range(201): # i 반복 횟수. (reward 값) range 값이 0 시작
                action = self.act(state) # act에 state 집어넣어줌
                next_state, reward, done, _, _ = env.step(action) # act를 돌리면 action이 나옴.
                # action을 돌리면 step이 됨.
                if done: # True면, 게임 종료
                    score = i + 1 # reward
                    self.scores.append(score)
                    self.max = max(score, self.max) # 점수 중에 최고 값을 구함.
                    print('episode: {:4d}/{} | score: {:3d} | max: {:3d}'
                          .format(e, episodes, score, self.max), end='\r')
                    break 
                self.memory.append((state, action)) # 종료가 안되면 메모리에 저장함. 어떤 상태였는지 action인지.
                self.train_model(state, action) # 게임이 아직 안 끝났기 때문에 신경망에 저장함. 그리고 이 action이 아직 랜덤하다
                state = next_state # state를 다음 state에 대입하고
                state = np.reshape(state, [1, 4]) # reshape하고... 그리고 계속 돌림. => 학습이 계속 돌아감. 그래서 epoch1을 준것. 
                # 한 번 끝나면 결과를 봐야하니까.
set_seeds(100)
agent = NNAgent()
episodes = 1000
agent.learn(episodes)

# 평균 보상
sum(agent.scores) / len(agent.scores)

위 학습의 문제점
- 잘못된 행동을 하지 않지만 게임에서 이기는 것을 배우지 않는다.
- 수집된 상태와 행위를 보면 신경망의 정확도는 56% 수준
- 이기는 정책과 연결되지 않는다.
=> 답이 랜덤함. 이기는 방법을 배우지 못함. 따라서 이기는 정책을 찾아서 연결 시켜놔야함.
# 특징(상태) 데이터
f = np.array([m[0][0] for m in agent.memory])
f
# 라벨(행위) 데이터
l = np.array([m[1] for m in agent.memory])
l
accuracy_score(np.where(agent.model.predict(f) > 0.5, 1, 0), l)

 

728x90
반응형
Comments