import numpy as np13wk-2: 강화학습 (1) – Bandit
1. 강의영상
2. Imports
3. 강화학습 Intro
- 강화학습(대충설명): 어떠한 “(게임)환경”이 있을때 거기서 “뭘 할지”를 학습하는 과업
- 딥마인드: breakout \(\to\) 알파고
- 강화학습 미래? (이거 잘하면 먹고 살 수 있을까?)
4. Game1: Bandit 게임
A. 게임설명 및 원시코드
- 문제설명: 두 개의 버튼이 있다. 버튼0을 누르면 1의 보상을, 버튼1을 누르면 10의 보상을 준다고 가정
- 처음에 어떤 행동을 해야 하는가?
- 처음에는 아는게 없음
- 일단 “아무거나” 눌러보자.
- 버튼을 아무거나 누르는 코드를 작성해보자.
action_space = ['버튼0','버튼1']
action = np.random.choice(action_space,p=[0.5,0.5])
action'버튼0'
action_space와action이라는 용어를 기억할 것
- 버튼을 누른 행위에 따른 보상을 구현하자.
reward = 1 if action == "버튼0" else 10
reward1
reward라는 용어를 기억할 것
- 아무버튼이나 10번정도 눌러보면서 데이터를 쌓아보자.
action_space = ['버튼0','버튼1']
for _ in range(10):
action = np.random.choice(action_space)
reward = 1 if action == "버튼0" else 10
print(action,reward)버튼1 10
버튼1 10
버튼1 10
버튼0 1
버튼1 10
버튼1 10
버튼0 1
버튼0 1
버튼1 10
버튼0 1
- 깨달았음: 버튼0을 누르면 1점을 받고, 버튼1을 누르면 10점을 받는 “환경(environment)”이구나? \(\to\) 버튼1을 누르는 “동작(=action)”을 해야하는 상황이구나?
- 여기에서 \(\to\)의 과정을 체계화 시킨 학문이 강화학습
environment라는 용어를 기억할 것
action_space = ['버튼0','버튼1']
for _ in range(10):
action = '버튼1'
reward = 1 if action == "버튼0" else 10
print(action,reward)버튼1 10
버튼1 10
버튼1 10
버튼1 10
버튼1 10
버튼1 10
버튼1 10
버튼1 10
버튼1 10
버튼1 10
- 게임 클리어
- 강화학습: 환경(environment)을 이해 \(\to\) 에이전트(agent)가 행동(action)을 결정
agent라는 용어를 기억할 것
위의 과정이 잘 되었다는 의미로 사용하는 문장들
- 강화학습이 성공적으로 잘 되었다.
- 에이전트가 환경의 과제를 완료했다.
- 에이전트가 환경에서 성공적으로 학습했다.
- 에이전트가 올바른 행동을 학습했다.
- 게임 클리어 (비공식)
- 게임이 클리어 되었다는 것을 의미하는 지표를 정하고 싶다.
- 첫 생각:
버튼1을 누르는 순간 게임클리어로 보면 되지 않나? - 두번째 생각: 아니지? 우연히 누를수도 있잖아?
- 게임클리어조건: (1) 20번은 그냥 진행 (2) 최근 20번의 보상의 평균이 9.5점 이상이면 게임이 클리어 되었다고 생각하자.1
1 버튼1을 눌러야 하는건 맞지만 몇번의 실수는 눈감아 주자는 의미
- 원시코드1: 환경을 이해하지 못한 에이전트 – 게임을 클리어할 수 없다.
action_space = [0,1]
actions = []
rewards = []
for t in range(1,51):
action = np.random.choice(action_space)
reward = 1 if action == 0 else 10
actions.append(action)
rewards.append(reward)
#--#
print(
f"시도:{t}\t"
f"행동:{action}\t"
f"보상:{reward}\t"
f"최근20번보상평균:{np.mean(rewards[-20:]):.4f}\t"
)
if t<20:
pass
elif t==20:
print("--")
else:
if np.mean(rewards[-20:]) > 9.5:
print("Game Clear")
break시도:1 행동:0 보상:1 최근20번보상평균:1.0000
시도:2 행동:0 보상:1 최근20번보상평균:1.0000
시도:3 행동:0 보상:1 최근20번보상평균:1.0000
시도:4 행동:1 보상:10 최근20번보상평균:3.2500
시도:5 행동:0 보상:1 최근20번보상평균:2.8000
시도:6 행동:1 보상:10 최근20번보상평균:4.0000
시도:7 행동:0 보상:1 최근20번보상평균:3.5714
시도:8 행동:1 보상:10 최근20번보상평균:4.3750
시도:9 행동:0 보상:1 최근20번보상평균:4.0000
시도:10 행동:0 보상:1 최근20번보상평균:3.7000
시도:11 행동:1 보상:10 최근20번보상평균:4.2727
시도:12 행동:0 보상:1 최근20번보상평균:4.0000
시도:13 행동:1 보상:10 최근20번보상평균:4.4615
시도:14 행동:1 보상:10 최근20번보상평균:4.8571
시도:15 행동:1 보상:10 최근20번보상평균:5.2000
시도:16 행동:0 보상:1 최근20번보상평균:4.9375
시도:17 행동:0 보상:1 최근20번보상평균:4.7059
시도:18 행동:0 보상:1 최근20번보상평균:4.5000
시도:19 행동:1 보상:10 최근20번보상평균:4.7895
시도:20 행동:0 보상:1 최근20번보상평균:4.6000
--
시도:21 행동:1 보상:10 최근20번보상평균:5.0500
시도:22 행동:0 보상:1 최근20번보상평균:5.0500
시도:23 행동:1 보상:10 최근20번보상평균:5.5000
시도:24 행동:1 보상:10 최근20번보상평균:5.5000
시도:25 행동:0 보상:1 최근20번보상평균:5.5000
시도:26 행동:0 보상:1 최근20번보상평균:5.0500
시도:27 행동:1 보상:10 최근20번보상평균:5.5000
시도:28 행동:1 보상:10 최근20번보상평균:5.5000
시도:29 행동:1 보상:10 최근20번보상평균:5.9500
시도:30 행동:1 보상:10 최근20번보상평균:6.4000
시도:31 행동:1 보상:10 최근20번보상평균:6.4000
시도:32 행동:1 보상:10 최근20번보상평균:6.8500
시도:33 행동:1 보상:10 최근20번보상평균:6.8500
시도:34 행동:1 보상:10 최근20번보상평균:6.8500
시도:35 행동:0 보상:1 최근20번보상평균:6.4000
시도:36 행동:0 보상:1 최근20번보상평균:6.4000
시도:37 행동:1 보상:10 최근20번보상평균:6.8500
시도:38 행동:1 보상:10 최근20번보상평균:7.3000
시도:39 행동:1 보상:10 최근20번보상평균:7.3000
시도:40 행동:1 보상:10 최근20번보상평균:7.7500
시도:41 행동:0 보상:1 최근20번보상평균:7.3000
시도:42 행동:1 보상:10 최근20번보상평균:7.7500
시도:43 행동:0 보상:1 최근20번보상평균:7.3000
시도:44 행동:0 보상:1 최근20번보상평균:6.8500
시도:45 행동:0 보상:1 최근20번보상평균:6.8500
시도:46 행동:1 보상:10 최근20번보상평균:7.3000
시도:47 행동:1 보상:10 최근20번보상평균:7.3000
시도:48 행동:0 보상:1 최근20번보상평균:6.8500
시도:49 행동:0 보상:1 최근20번보상평균:6.4000
시도:50 행동:1 보상:10 최근20번보상평균:6.4000
- 원시코드2: 환경을 깨달은 에이전트 – 게임클리어
action_space = [0,1]
actions = []
rewards = []
for t in range(1,51):
action = 1
reward = 1 if action == 0 else 10
actions.append(action)
rewards.append(reward)
#--#
print(
f"시도:{t}\t"
f"행동:{action}\t"
f"보상:{reward}\t"
f"최근20번보상평균:{np.mean(rewards[-20:]):.4f}\t"
)
if t<20:
pass
elif t==20:
print("--")
else:
if np.mean(rewards[-20:]) > 9.5:
print("Game Clear")
break시도:1 행동:1 보상:10 최근20번보상평균:10.0000
시도:2 행동:1 보상:10 최근20번보상평균:10.0000
시도:3 행동:1 보상:10 최근20번보상평균:10.0000
시도:4 행동:1 보상:10 최근20번보상평균:10.0000
시도:5 행동:1 보상:10 최근20번보상평균:10.0000
시도:6 행동:1 보상:10 최근20번보상평균:10.0000
시도:7 행동:1 보상:10 최근20번보상평균:10.0000
시도:8 행동:1 보상:10 최근20번보상평균:10.0000
시도:9 행동:1 보상:10 최근20번보상평균:10.0000
시도:10 행동:1 보상:10 최근20번보상평균:10.0000
시도:11 행동:1 보상:10 최근20번보상평균:10.0000
시도:12 행동:1 보상:10 최근20번보상평균:10.0000
시도:13 행동:1 보상:10 최근20번보상평균:10.0000
시도:14 행동:1 보상:10 최근20번보상평균:10.0000
시도:15 행동:1 보상:10 최근20번보상평균:10.0000
시도:16 행동:1 보상:10 최근20번보상평균:10.0000
시도:17 행동:1 보상:10 최근20번보상평균:10.0000
시도:18 행동:1 보상:10 최근20번보상평균:10.0000
시도:19 행동:1 보상:10 최근20번보상평균:10.0000
시도:20 행동:1 보상:10 최근20번보상평균:10.0000
--
시도:21 행동:1 보상:10 최근20번보상평균:10.0000
Game Clear
B. 수정1: Env 구현
- Bandit 클래스 선언 + .step() 구현
class Bandit:
def step(self,agent_action):
reward = 1 if agent_action == 0 else 10
return rewardenv = Bandit()
action_space = [0,1]
actions = []
rewards = []
for t in range(1,51):
action = np.random.choice(action_space)
reward = env.step(action)
actions.append(action)
rewards.append(reward)
#--#
print(
f"시도:{t}\t"
f"행동:{action}\t"
f"보상:{reward}\t"
f"최근20번보상평균:{np.mean(rewards[-20:]):.4f}\t"
)
if t<20:
pass
elif t==20:
print("--")
else:
if np.mean(rewards[-20:]) > 9.5:
print("Game Clear")
break시도:1 행동:1 보상:10 최근20번보상평균:10.0000
시도:2 행동:1 보상:10 최근20번보상평균:10.0000
시도:3 행동:0 보상:1 최근20번보상평균:7.0000
시도:4 행동:0 보상:1 최근20번보상평균:5.5000
시도:5 행동:0 보상:1 최근20번보상평균:4.6000
시도:6 행동:1 보상:10 최근20번보상평균:5.5000
시도:7 행동:0 보상:1 최근20번보상평균:4.8571
시도:8 행동:1 보상:10 최근20번보상평균:5.5000
시도:9 행동:1 보상:10 최근20번보상평균:6.0000
시도:10 행동:1 보상:10 최근20번보상평균:6.4000
시도:11 행동:1 보상:10 최근20번보상평균:6.7273
시도:12 행동:0 보상:1 최근20번보상평균:6.2500
시도:13 행동:1 보상:10 최근20번보상평균:6.5385
시도:14 행동:1 보상:10 최근20번보상평균:6.7857
시도:15 행동:1 보상:10 최근20번보상평균:7.0000
시도:16 행동:1 보상:10 최근20번보상평균:7.1875
시도:17 행동:0 보상:1 최근20번보상평균:6.8235
시도:18 행동:1 보상:10 최근20번보상평균:7.0000
시도:19 행동:0 보상:1 최근20번보상평균:6.6842
시도:20 행동:1 보상:10 최근20번보상평균:6.8500
--
시도:21 행동:0 보상:1 최근20번보상평균:6.4000
시도:22 행동:0 보상:1 최근20번보상평균:5.9500
시도:23 행동:1 보상:10 최근20번보상평균:6.4000
시도:24 행동:0 보상:1 최근20번보상평균:6.4000
시도:25 행동:0 보상:1 최근20번보상평균:6.4000
시도:26 행동:1 보상:10 최근20번보상평균:6.4000
시도:27 행동:0 보상:1 최근20번보상평균:6.4000
시도:28 행동:1 보상:10 최근20번보상평균:6.4000
시도:29 행동:1 보상:10 최근20번보상평균:6.4000
시도:30 행동:0 보상:1 최근20번보상평균:5.9500
시도:31 행동:1 보상:10 최근20번보상평균:5.9500
시도:32 행동:0 보상:1 최근20번보상평균:5.9500
시도:33 행동:0 보상:1 최근20번보상평균:5.5000
시도:34 행동:0 보상:1 최근20번보상평균:5.0500
시도:35 행동:0 보상:1 최근20번보상평균:4.6000
시도:36 행동:0 보상:1 최근20번보상평균:4.1500
시도:37 행동:1 보상:10 최근20번보상평균:4.6000
시도:38 행동:1 보상:10 최근20번보상평균:4.6000
시도:39 행동:1 보상:10 최근20번보상평균:5.0500
시도:40 행동:0 보상:1 최근20번보상평균:4.6000
시도:41 행동:1 보상:10 최근20번보상평균:5.0500
시도:42 행동:0 보상:1 최근20번보상평균:5.0500
시도:43 행동:1 보상:10 최근20번보상평균:5.0500
시도:44 행동:0 보상:1 최근20번보상평균:5.0500
시도:45 행동:0 보상:1 최근20번보상평균:5.0500
시도:46 행동:0 보상:1 최근20번보상평균:4.6000
시도:47 행동:1 보상:10 최근20번보상평균:5.0500
시도:48 행동:1 보상:10 최근20번보상평균:5.0500
시도:49 행동:0 보상:1 최근20번보상평균:4.6000
시도:50 행동:0 보상:1 최근20번보상평균:4.6000
C. 수정2: Agent 구현 (인간지능)
- Agent 클래스 설계
- 액션을 하고, 본인의 행동과 환경에서 받은 reward를 기억
.act()함수와.save_experience()함수 구현
class Agent:
def __init__(self):
self.action_space = [0,1]
self.action = None
self.reward = None
self.actions = []
self.rewards = []
def act(self):
prob = [0.5, 0.5]
self.action = 1 #np.random.choice(self.action_space,p=prob)
def save_experience(self):
self.actions.append(self.action)
self.rewards.append(self.reward)— 대충 아래와 같은 느낌으로 코드가 돌아가요 —
시점0: init
agent = Agent()
env = Bandit()agent.action, agent.reward, agent.actions, agent.rewards(None, None, [], [])
시점1: agent 가 acition을 선택
agent.act()agent.action, agent.reward, agent.actions, agent.rewards(1, None, [], [])
시점2: env가 agent에게 보상을 줌
agent.reward = env.step(agent.action)agent.action, agent.reward, agent.actions, agent.rewards(1, 10, [], [])
시점3: 경험을 저장
agent.save_experience()agent.action, agent.reward, agent.actions, agent.rewards(1, 10, [1], [10])
– 전체코드 –
env = Bandit()
agent = Agent()
for t in range(1,51):
agent.act()
agent.reward = env.step(agent.action)
agent.save_experience()
#--#
print(
f"시도:{t}\t"
f"행동:{agent.action}\t"
f"보상:{agent.reward}\t"
f"최근20번보상평균:{np.mean(agent.rewards[-20:]):.4f}\t"
)
if t<20:
pass
elif t==20:
print("--")
else:
if np.mean(agent.rewards[-20:]) > 9.5:
print("Game Clear")
break 시도:1 행동:1 보상:10 최근20번보상평균:10.0000
시도:2 행동:1 보상:10 최근20번보상평균:10.0000
시도:3 행동:1 보상:10 최근20번보상평균:10.0000
시도:4 행동:1 보상:10 최근20번보상평균:10.0000
시도:5 행동:1 보상:10 최근20번보상평균:10.0000
시도:6 행동:1 보상:10 최근20번보상평균:10.0000
시도:7 행동:1 보상:10 최근20번보상평균:10.0000
시도:8 행동:1 보상:10 최근20번보상평균:10.0000
시도:9 행동:1 보상:10 최근20번보상평균:10.0000
시도:10 행동:1 보상:10 최근20번보상평균:10.0000
시도:11 행동:1 보상:10 최근20번보상평균:10.0000
시도:12 행동:1 보상:10 최근20번보상평균:10.0000
시도:13 행동:1 보상:10 최근20번보상평균:10.0000
시도:14 행동:1 보상:10 최근20번보상평균:10.0000
시도:15 행동:1 보상:10 최근20번보상평균:10.0000
시도:16 행동:1 보상:10 최근20번보상평균:10.0000
시도:17 행동:1 보상:10 최근20번보상평균:10.0000
시도:18 행동:1 보상:10 최근20번보상평균:10.0000
시도:19 행동:1 보상:10 최근20번보상평균:10.0000
시도:20 행동:1 보상:10 최근20번보상평균:10.0000
--
시도:21 행동:1 보상:10 최근20번보상평균:10.0000
Game Clear
D. 수정3: Agent 구현 (인공지능)
- 지금까지 풀이의 한계
- 사실 강화학습은 “환경을 이해 \(\to\) 행동을 결정” 의 과정에서 “\(\to\)”의 과정을 수식화 한 것이다.
- 그런데 지금까지 했던 코드는 환경(environment)를 이해하는 순간 에이전트(agent)가 최적의 행동(action)2을 “직관적으로” 결정하였으므로 기계가 스스로 학습을 했다고 볼 수 없다.
2 버튼1을 누른다
- 에이전트가 데이터를 보고 스스로 학습할 수 있도록 설계 – 부제: agent.learn()을 설계하자.
- 데이터를 모아서
q_table를 만든다.q_table은 아래와 같은 내용을 포함한다.
| 행동 | 보상(추정값) |
|---|---|
| 버튼0 (\(=a_0\)) | 1 (\(=q_0\)) |
| 버튼1 (\(=a_1\)) | 10 (\(=q_1\)) |
q_table을 바탕으로 적절한 정책(=policy)을 설정한다.
- 이 예제에서는 버튼0과 버튼1을 각각 \(\big(\frac{q_0}{q_0+q_1},\frac{q_1}{q_0+q_1}\big)\) 의 확률로 선택하는 “정책”을 이용하면 충분할 듯
- 처음부터 이러한 확률로 선택하기보다 처음 20번정도는 데이터를 쌓기 위해서 행동을 랜덤하게 선택하고, 그 이후에 위에서 제시한 확률값으로 행동을 선택하는게 합리적인듯.
여기에서
q_table,policy라는 용어를 기억하세요.
- q_table을 계산하는 코드 예시
agent.actions = [0, 1, 1, 0, 1, 0, 0]
agent.rewards = [1, 9, 10, 1, 9.5, 1, 1.2]
actions = np.array(agent.actions)
rewards = np.array(agent.rewards)q0,q1 = rewards[actions==0].mean(), rewards[actions==1].mean()q_table = np.array([q0,q1])
q_tablearray([1.05, 9.5 ])
q_table/ q_table.sum()array([0.09952607, 0.90047393])
prob = q_table/ q_table.sum()
agent.action = np.random.choice(agent.action_space,p = prob )
agent.action1
- 최종코드정리
class Agent:
def __init__(self):
self.action_space = [0,1]
self.action = None
self.reward = None
self.actions = []
self.rewards = []
self.q_table = np.array([0.001,0.001])
self.n_experience = 0
def act(self):
if self.n_experience <= 20:
self.action = np.random.choice(self.action_space)
else:
prob = self.q_table/ self.q_table.sum()
self.action = np.random.choice(self.action_space,p = prob )
def save_experience(self):
self.actions.append(self.action)
self.rewards.append(self.reward)
self.n_experience = self.n_experience + 1
def learn(self):
if self.n_experience < 20:
pass
else:
actions = np.array(self.actions)
rewards = np.array(self.rewards)
q0,q1 = rewards[actions==0].mean(), rewards[actions==1].mean()
self.q_table = np.array([q0,q1])env = Bandit()
agent = Agent()
for t in range(1,51):
# step1: 행동
agent.act()
# step2: 보상
agent.reward = env.step(agent.action)
# step3: 저장 & 학습
agent.save_experience()
agent.learn()
#--#
print(
f"시도:{t}\t"
f"행동:{agent.action}\t"
f"보상:{agent.reward}\t"
f"최근20번보상평균:{np.mean(agent.rewards[-20:]):.4f}\t"
)
if t<20:
pass
elif t==20:
print("--")
else:
if np.mean(agent.rewards[-20:]) > 9.5:
print("Game Clear")
break 시도:1 행동:1 보상:10 최근20번보상평균:10.0000
시도:2 행동:1 보상:10 최근20번보상평균:10.0000
시도:3 행동:1 보상:10 최근20번보상평균:10.0000
시도:4 행동:1 보상:10 최근20번보상평균:10.0000
시도:5 행동:1 보상:10 최근20번보상평균:10.0000
시도:6 행동:1 보상:10 최근20번보상평균:10.0000
시도:7 행동:0 보상:1 최근20번보상평균:8.7143
시도:8 행동:1 보상:10 최근20번보상평균:8.8750
시도:9 행동:1 보상:10 최근20번보상평균:9.0000
시도:10 행동:1 보상:10 최근20번보상평균:9.1000
시도:11 행동:1 보상:10 최근20번보상평균:9.1818
시도:12 행동:1 보상:10 최근20번보상평균:9.2500
시도:13 행동:0 보상:1 최근20번보상평균:8.6154
시도:14 행동:1 보상:10 최근20번보상평균:8.7143
시도:15 행동:0 보상:1 최근20번보상평균:8.2000
시도:16 행동:1 보상:10 최근20번보상평균:8.3125
시도:17 행동:1 보상:10 최근20번보상평균:8.4118
시도:18 행동:1 보상:10 최근20번보상평균:8.5000
시도:19 행동:0 보상:1 최근20번보상평균:8.1053
시도:20 행동:1 보상:10 최근20번보상평균:8.2000
--
시도:21 행동:1 보상:10 최근20번보상평균:8.2000
시도:22 행동:0 보상:1 최근20번보상평균:7.7500
시도:23 행동:1 보상:10 최근20번보상평균:7.7500
시도:24 행동:1 보상:10 최근20번보상평균:7.7500
시도:25 행동:1 보상:10 최근20번보상평균:7.7500
시도:26 행동:1 보상:10 최근20번보상평균:7.7500
시도:27 행동:1 보상:10 최근20번보상평균:8.2000
시도:28 행동:1 보상:10 최근20번보상평균:8.2000
시도:29 행동:1 보상:10 최근20번보상평균:8.2000
시도:30 행동:1 보상:10 최근20번보상평균:8.2000
시도:31 행동:1 보상:10 최근20번보상평균:8.2000
시도:32 행동:1 보상:10 최근20번보상평균:8.2000
시도:33 행동:1 보상:10 최근20번보상평균:8.6500
시도:34 행동:1 보상:10 최근20번보상평균:8.6500
시도:35 행동:1 보상:10 최근20번보상평균:9.1000
시도:36 행동:1 보상:10 최근20번보상평균:9.1000
시도:37 행동:1 보상:10 최근20번보상평균:9.1000
시도:38 행동:1 보상:10 최근20번보상평균:9.1000
시도:39 행동:1 보상:10 최근20번보상평균:9.5500
Game Clear