안 쓰던 블로그
다중 슬롯머신 문제 (Multi-Amred Bandits, MAB) with Epsilon-Greedy 본문
다중 슬롯머신 문제 (Multi-Amred Bandits, MAB)
여러 개의 팔을 가진 슬롯머신이 있다. 슬롯머신의 팔마다 코인이 나오는 확률은 정해져 있지만, 확률값은 미리 알 수 없다. 제한된 횟수 안에서 가장 많은 코인을 얻으려면 어떤 순서로 팔을 선택해야 할까?
어떤 슬롯머신의 팔을 당겨야 가장 많은 돈을 벌 것인지에 대한 문제를 푸는 다중 슬롯머신 문제는 강화 학습의 예시로 흔히 알려져 있다. 이 글에서는 Epsilon-Greedy 입실론 그리디 학습 방법으로 이 문제를 해결해 본다.
'알파제로를 분석하며 배우는 인공지능' 책을 참고한 글임을 밝힌다.
강화 학습 사이클
다중 슬롯머신 문제의 목적은 '코인은 많이 얻는다'이고, 행동은 '어떤 팔을 선택하는가?', 보상은 '코인이 나오면 +1'이다. 행동 1회마다 파라미터를 변경한다.
코인이 나올 확률이 높은 팔은 처음부터 알 수 없으므로 정보 수집을 위한 탐색(exploration)이 필요하다. 또한 탐색한 정보를 가지고 보상이 높다고 판단한 팔을 선택하는 이용(exploitation)이 있다.
이익을 최대화하기 위해서는 탐색과 이용의 균형을 맞추어야 한다. 탐색만 계속하면 보상이 높은 팔을 알 수 있지만 실제로 이용하지 않는다. 이용만 계속하면 현시점보다 더 높은 보상의 팔이 있을 가능성이 있다.
E-greedy 계산 처리
#Calculation epsilon-Greedy
class EpsilonGreedy():
#init e-greedy
def __init__(self, epsilon):
self.epsilon = epsilon #Probability of exploration
#init n, v (n_arms: number of arms)
def initialize(self, n_arms):
self.n = np.zeros(n_arms) #number of attempts for each arm - list
self.v = np.zeros(n_arms) #value of each arm - list (평균보상)
#Select arm
def select_arm(self):
if self.epsilon > random.random():
return np.random.randint(0, len(self.v)) #select random
else:
return np.argmax(self.v) #select high value arm
탐색과 이용의 균형을 잡는 방법으로 Epsilon-Greedy를 사용한다.
E-greedy는 E 확률(0 이상 1이하의 정수)로 랜덤하게 행동을 선택, 1-E 확률로 초기 보상이 최대가 되는 행동을 선택한다. 그리고 팔의 번호를 반환한다.
파라미터 업데이트
#Update parameter
def update(self, chosen_arm, reward, t):
self.n[chosen_arm] += 1 #number of attempts of the selected arm + 1
#update the value of the selected arm
n = self.n[chosen_arm]
v = self.v[chosen_arm]
self.v[chosen_arm] = ((n-1) / float(n)) * v + (1 / float(n)) * reward
#get string info
def label(self):
return 'E-greedy('+str(self.epsilon)+')'
파라미터를 다음 순서에 따라 갱신한다
(1) 선택한 팔의 시행 횟수+1
(2) 선택한 팔의 가치 갱신
선택한 팔의 가치(평균 보상)는 수식에 따라 갱신한다.
$$V_t = \frac{n-1}{n} \times V_{t-1} + \frac{1}{n} \times R_t$$
(이번 시행의 가치:평균 보상) = (시행횟수-1)/(시행횟수) * (이전 시행의 가치 :평균 보상) + 1/시행횟수 * (이번 시행의 보상)
슬롯 게임 생성
#Make slot arm
class SlotArm():
def __init__(self, p):
self.p = p #Probability of getting a coin
#Get a reward for choosing an arm
def draw(self):
if self.p > random.random():
return 1.0
else:
return 0.0
코인이 나올 확률인 p를 생성자 인수로 둔다. 팔을 선택했을 때의 보상을 취득한다.
시뮬레이션 실행
#run
def play(algo, arms, num_sims,num_time):
times = np.zeros(num_sims*num_time) #game times
rewards = np.zeros(num_sims*num_time) #rewards
#roop simulation
for sim in range(num_time):
algo.initialize(len(arms))
#roop game
for time in range(num_time):
#calculate index
index = sim * num_time + time
times[index] = time + 1
chosen_arm = algo.select_arm()
reward = arms[chosen_arm].draw()
rewards[index] = reward
#update parameter
algo.update(chosen_arm, reward, time+1)
return [times, rewards]
play()는 시뮬레이션을 실행한 뒤 게임 횟수 중 몇 번째인지와 보상을 반환한다.
다중 슬롯머신 문제는 결정된 게임 회수 내에서 가능한 많은 보상을 얻어내는 문제이다. 결정된 게임 횟수를 몇 번 시뮬레이션할지를 인수 num_times로, 결정된 게임 횟수가 인수 num_time이다. 시뮬레이션 횟수가 많을수록 정밀도가 올라간다.
코드 실행 및 그래프 표시
#select arm
arms = (SlotArm(0.3), SlotArm(0.5), SlotArm(0.9))
#set algorithm
algo = EpsilonGreedy(0.1)
#run
result = play(algo, arms, 1000, 250)
#draw graph
df = pd.DataFrame({'times': result[0], 'rewards': result[1]})
mean = df['rewards'].groupby(df['times']).mean()
plt.plot(mean, label = algo.label())
plt.xlabel('Step')
plt.ylabel('Average Reward')
plt.legend(loc = 'best')
plt.show()
확률이 0.3, 0.5, 0.9인 팔 3개를 준비한다. 250회를 1세트로, 1000세트의 시뮬레이션을 실행한다.
시뮬레이션 결과는 다음과 같다.
전체 코드
https://github.com/proqk/MAB-with-Epsilon-Greedy-and-UCB1
'머신러닝 > 머신러닝' 카테고리의 다른 글
model.summary() 의 ValueError: This model has not yet been built 에러 (0) | 2021.07.16 |
---|---|
다중 슬롯머신 문제 (Multi-Amred Bandits, MAB) with UCB1(Upper Confidence Bound1) (0) | 2021.06.24 |
소규모 데이터셋에서 CNN 훈련하기(Kaggle - Dogs vs. Cats) (1) | 2021.05.12 |
CNN(convolutional neural network - 합성곱 신경망) (2) | 2021.04.08 |
머신 러닝의 기본 개념들 (1) | 2021.04.05 |