Skip to main content

몬테카를로

원주율 구하기

import numpy as np
import matplotlib.pyplot as plt

a = b = 0
pi = []
for _ in range(10000):
x, y = np.random.uniform(size=2)
if x**2 + y**2 <= 1:
a += 1
else:
b += 1
pi.append(4 * a / (a + b))

plt.plot(pi)
pi[-1]
output
3.1788
<Figure size 640x480 with 1 Axes>

편향-분산 교환

강의자료 200쪽으로 넘어가셔서요 머신러닝에 편향분산교환이라는 개념이 있습니다

우리가 교환을 여러가지가 나오는데 앞에서 했던 교환은 기억나십니까?

탐색, 활용교환이라고 있었죠

왜 이렇게 교환이 많이 나와?

인생에 다 교환입니다 얻는게 있으면 잃은게 있는거죠 탐색, 활용교환은 새로운 것을 해보면 써먹을 기회가 줄고 아는 것만 써먹으면 새로운 것을 못해보고 약간 이런거고 편향분산교환은 뭐냐면 우리가 뭔가를 추정을 하는데 내가 특정한 방향으로 편향된 방식으로 추정을 하면 분산이 작아져요 편향이 커지면 분산이 작아져요

여기서 분산은 뭐냐면 추정치에 분산이 됩니다

추정치가 내가 어떨 때는 추정을 10이라고 하고 어떨 때는 20이라고 하고 어떨 때는 30이라고 하고 추정치가 그때그때 달라지는 것을 분산이 크다고 하는데 편향이 강하면 분산이 작아집니다

그러니까 편견이 없으면 그 얘기는 뭐냐면 보이는 대로 믿습니다 보이는 대로 믿음 보이는 대로 믿는다는 것은 내가 뭘 볼지는 복불복이란 말이에요

어쨌든 그래서 편향이 작으면 편견이 없으니까 보이는 대로 믿는데 보이는 게 우리가 데이터가 굉장히 무한이 많은지 모르겠는데 항상 데이터가 한정이 되어 있기 때문에 데이터라는 건 이럴 수도 있고 저럴 수도 있습니다

방금 몬테카롤로 얘기하면서 제가 동전 던지기를 얘기했는데 동전을 예를 들면 10개를 던졌는데 앞면이 3번 나오고 뒷면이 7번 나왔다 그럴 수 있잖아요

그렇죠?

공평한 동전이라도 근데 편견 없는 사람은 어떻게 되냐면 야 이 동전은 줄미니마니아우네 와 신기하다

이렇게 되는 거예요

아니 어떻게 급발진을 하는 거죠 편견이 없으니까 보이는 대로 믿는 거예요

근데 우리 눈에 보이는 게 사실은 다가 아닌데 그래서 이 사이에 교환이 있게 됩니다

그래서 우리가 이제 둘 다 장단점이 있어요 분산이 작다는 거는 우리가 추정치가 안정적으로 나온다는 의미에서는 장점이지만 반대로 말하면 좀 사실하고 거리가 멀 수 있다

이게 단점이고 편향이 작으면 무조건 좋은 거 같지만 그러면 너무 눈에 보이는 대로 데이터에 흔들릴 수가 있다

우리가 데이터라고 해서 그게 다 사실은 아니거든요

물론 데이터가 무한이 많으면 데이터에 보이는 대로 믿어야 되는데 우리가 이제 성급한 일반화 이런 얘기 하잖아요

유한한 데이터는 뭔가 정확하지 않은 부분이 있을 수 있기 때문에 그걸 그대로 보인다고 보인 대로 믿으면 또 곤란합니다 어떤 균형을 주고를 해야 돼요

우리도 그렇잖아요

이상한 현상을 봤으면 예를 들어 우리가 과학적 지식이라든지 그것도 일종의 편견이거든요

왜냐하면 우리가 과학적 지식이라는 걸 다 우리 내 눈으로 보고 믿은 게 아니라 그냥 다 학교에서 배운 거잖아요

근데 일단 과학적으로 생각을 해보는 거죠

이게 말이 되나 그래서 이제 다 믿지 않고 약간 좀 반만 믿는다든가 어이구 좀 신기하네 좀 한번 두고 볼까

예를 들면 무슨 요즘에 살 빼는 신약이 나왔는데 그 위곱인가?

그걸 맞으면 심장에도 좋고 살만 빠지는 게 아니라 심장에도 좋고 혈관에도 좋고 뭐 심지어 코로나 걸려도 잘 중증화가 안 된대요

약간 만병통치약이냐

이런 얘기가 나오는데 좀 의심을 해봐야지 우리가 그래도 어느 정도 의학을 잘 모르긴 하지만 상식적으로 생각했을 때 살 빠진 약을 먹는다고 코로나...

를 안 걸린다고?

약간 이상한데 이런 생각이 좀 들면서 약간 반신반의를 하거나 아니면 에이 그냥 그거는 살이 빠지니까 당연히 건강이 좋아지지

그 말이라고 그 약 효과가 좋은 게 아니고 약을 먹으니까 살이 빠져서 뭐 이것도 좋아지고 저것도 좋아지고 우리가 다이어트 하면 다 좋잖아요

그렇죠

그런 거겠지 뭐 라고 생각한다든가 그러니까 보이는 대로 100% 믿지 않나 우리가 어느 정도 일종의 편견이라면 편견 사전 지식이라면 사전 지식이 있어서 그거에 따라서 약간 감에서 듣는 거죠

그래서 이 사이에 균형이 중요합니다

그래서 이제 편향 분산, 교환 이렇게 얘기를 하게 되고요 그래서 우리가 이제 어떤 모델이 있을 때 모델이 너무 편향이 강하면 강한 편향 우리가 데이터가 예를 들면 동그라미가 있고 X가 있는데 얘네를 구별을 해야 돼요

그래서 어떤 경계선을 그어야 되는데 경계선은 오름직이 직선이지

뭐 약간 이런 굉장히 강한 편향이 있어요

그러면 분명히 이렇게 튀어나오는 데가 있어도 아휴 야 헛소리 하지마 경계선은 무조건 직선이야 이렇게 하면은 뭐가 잘 안 맞는 데가 생깁니다

그래서 편향이 너무 강하면 언더피팅, 과소적합이 생기죠

데이터에 잘 핏하지 않은 거예요

그다음에 또 너무 편향이 약하면 우리가 이제 어떤 동그라미 X가 있는데 X2개가 이렇게 실수로 여기 잘못 떨어졌어요

그러면은 우리가 이제 상식적으로 생각하면 에이 뭐 이거 잘못 떨어졌겠지

이렇게 생각을 해야 되는데 분산이 너무 커요

그러니까 보이는 대로 믿습니다

아이고 이거 경계선이 이렇게 복잡하구만

이렇게 되는 거야

그러면은 너무 오버해서 데이터에 핏하게 맞춰 준 거죠

그러니까 예를 들면은 여러분이 옷 사러 갔는데 그날 좀 어제 저녁에 술 먹고 자가지고 몸이 좀 부었는데 그럼 하루 부은 거잖아요

그거에 맞춰 가지고 옷을 핏팅을 시켜버리면 옷이 너무 벙벙하게 되겠죠

나중에는 아니면은 어제 좀 점심 굶고 가가지고 배가 좀 쏙 들어갔는데 하루 그런 거잖아요

내 배는 계속 허리둘레 32란 말이에요

그러면 근데 거기에 맞춰 가지고 옷을 사면은 나중에는 바지가 안 맞겠죠

너무 오버해서 핏팅하면 안 된단 말이에요

보이는 대로 믿으면 안 돼요 보이는 게 다가 아니기 때문에 보이는 대로 믿으면 안 되는데 또 이렇게 되면은 편향은 작은데 분산이 너무 커서 오버핏팅이 되고 반대로 이제 편향이 강하면 분산이 작은 건 좋은데 언더핏팅 되기가 쉽다

이거 그래서 이 사이에서 균형을 맞추는 게 중요합니다

근데 다시 199쪽으로 넘어가서 이제 몬테카를로로 넘어가면 몬테카를로로는 편향 분산 교환의 측면에서 보면 편향되지 않은 추정치를 줘요 편향이 작습니다

왜냐하면 그냥 우리가 보이는 대로 내가 해보니까 내가 이걸 100번 해보니까 보상이 이만큼 나오고 그 다음에 이런 상태로 가더라라는 거를 보이는 그대로 다 더했기 때문에 편향이 안 됩니다

내가 보이는 대로 다 믿는 거예요

편향이 별로 없죠

그래서 몬테카를로법은 편향되지 않은 추정치를 줍니다

우리가 이제 무한히 하면 이 짓을 무한히 하면 진짜 가치로 수렴을 하게 돼 있어요 편향이 안 돼 있으니까 편향이 있으면 무한히 해도 수렴을 안 합니다

반드시 안 하는 건 아닌데 편향을 극복할 정도로 무한히 하면 결국에는 수렴을 하는데 오히려 좀 느릴 수가 있어요

근데 이제 편향되지 않으면 무한히 반복하면 진짜 가치로 수렴을 합니다

이게 이제 뭐가 장점 이렇게 얘기하면 뒤에 단점이 주르륵 나오겠죠

너는 참 애가 착해

그래서 누가 갑자기 불러서 좀 보자

내가 보니까 너는 참 착한 것 같다 하면 그럼

이 자식이 도대체 무슨 소리 하려고 이렇게 긴장이 되잖아요

몬테카를로법이 굉장히 큰 장점인데 반점들이 있습니다

첫 번째는 우리가 이제 상태가치 함수는 결국에는 이 지를 가지고 계산을 하는 거거든요

그래서 공식이 어디 있죠?

앞으로 쭉 가서 여기 182쪽으로 가시면 결국에 이 지를 구해 가지고 이 지하고 현재 추정한 가치를 차이를 구해서 이게 이제 1분의 1 하면 평균식이죠

그래서 평균을 낸단 말이에요

그럼 이 지를 구해야 되는데 이 지라는 거는 처음부터 끝까지 쭉 따라간 다음에 그 보상들을 다 더한 겁니다

그래서 우리가 끝까지 가봐야 저 지를 구할 수가 있어요

그래서 이 지라는 거는 기본적으로 R 더하기, R 더하기, R 더하기 점점점점 해서 끝까지 더하는 거죠

여기다 할인도 해줘도 되고 R1, R2, R3 이렇게 그래서 이걸 끝까지 가야 되니까 일단 좀 지루하죠

예를 들면 내가 회사 생활을 어떻게 잘해야 되는지를 은퇴할 때까지 가봐야 아, 회사 생활을 이렇게 하는 거구나 그럼 뭐 해요?

이제 다 끝났는데, 그렇죠?

은퇴 다 했는데 내가 신입사원 때 이렇게 했어야 되는 것은 이미 후회해도 늦었죠

너무 오래 기다려야 된단 말이에요

뭔가 배우려면 우리 보통 그렇게 살지 않잖아요

바로바로 안단 말이에요

아, 이렇게 살면 안 되는구나

바로바로 안단 말이에요

그래서 이 지를 얻을 때까지 기다려야 되기 때문에 에피소드가 너무 길면 사용하기가 좀 어렵습니다

학습이 너무 느려서 그다음에 또 하나는 분산이 굉장히 크게 됩니다

이 편향이 작기 때문에 분산이 커지는데 특히 이제 우리가 R을 계속 다 더하잖아요

그러면 내가 행동을 어떻게 똑같은 행동을 해도 예를 들면 뒤에 가서 어떤 R은 되게 크게 나올 수도 있고 어떤 R은 되게 작게 나올 수도 있고 그러면 이제 분산이 커질 수밖에 없습니다

왜냐면 내가 똑같은 행동을 한다고 해서 똑같은 R을 받는다는 보장이 없거든요

근데 예를 들면 한 스텝까지는 비슷하겠지만 2스텝, 3스텝, 4스텝까지 갔을 때도 똑같냐

이런 거는 보장이 힘든단 말이에요

이거는 약간 주식 생각해 보시면 됩니다

여러분이 어떤 주식을 샀어요 주식을 사는 행동을 했잖아요

그럼 그 주가가 당장은 요만큼 오르거나 요만큼 오르겠지만 장기적으로는 이만큼 갈 수도 있고 이만큼 갈 수도 있단 말이에요

장기적으로 그러면 내가 똑같은 행동을 해도 결과가 지가, 나의 리턴이 크게 왔다 갔다 하는 거죠

그래서 주식 같은 거 하면 장기 투자해라

이런 얘기 하잖아요

그러니까 장기 투자하라는 얘기는 이렇게 안 내려가게 장기 투자를 하면 많이 올라갈 수 있으니까 오래 들고 버텨라

이런 얘기죠

근데 무조건 장기 투자하시면 반대로도 많이 갈 수 있습니다 분산이 크기 때문에 그래서 장기로만 투자하시면 안 되고 장기로 올라갈 만한 걸 사셔야 되는 거죠

그래서 이게 크다는 거는 결국 분산이 크다는 겁니다

내가 똑같은 행동을 했는데 여기 갈 수도 있고 여기 갈 수도 있고 그럼

이제 추정치를 잘 구하려면 이걸 되게 많이 해가지고 해야지

내가 한 번만 해보면 내가 예를 들어서 내가 여기 갈 수도 있고 여기 갈 수도 있다 그러면은 평균적으로는 여기로 가겠죠

평균적으로는 여기로 가는데 이 평균이 정확하려면 굉장히 많이 해봐야 된단 말이에요

안 그러면은 내가 한두 번 해보면 한두 번은 이렇게 위로 갈 수 있잖아요

그래서 주식 투자 초자들이 어쩌다가 한두 개 주식 되게 대박나가지고 야 주식 투자 쉽구만

이러고 막 집 팔아서 주식 투자다가 망하고 이런단 말이에요

분산이 크기 때문에 추정치가 막 들쭉날쭉 합니다

그래서 이렇게 분산이 크면은 샘플링의 효율성이 떨어진다는 게 우리가 샘플이 굉장히 많이 필요하고 작은 샘플로는 좋은 추정치를 얻기가 어렵다

첫방문 몬테카를로

from collections import defaultdict

import gymnasium as gym
import numpy as np

class MCPrediction:
def __init__(self, env, gamma=0.9):
self.gamma = gamma
self.env = env
self.V = np.zeros(env.observation_space.n)
self.returns = defaultdict(list)

def select_action(self, policy, state):
return policy[state]

def generate_episode(self, policy):
episode = []
state, info = self.env.reset()
done = False
while not done:
action = self.select_action(policy, state)
next_state, reward, done, _, _ = self.env.step(action)
episode.append((state, action, reward, next_state, done))
state = next_state
return episode

def update_value(self, episode):
G = 0
for t in reversed(range(len(episode))):
state, action, reward, next_state, done = episode[t]
G = self.gamma * G + reward
if state not in [x[0] for x in episode[:t]]:
self.returns[state].append(G)
self.V[state] = np.mean(self.returns[state])

def evaluate_policy(self, policy, num_episodes=1000):
nS = self.env.observation_space.n
self.V_track = np.zeros((nS, num_episodes))
for e in range(num_episodes):
episode = self.generate_episode(policy)
self.update_value(episode)
self.V_track[:, e] = self.V.copy()
return self.V, self.V_track

실험

env = SlipperyWalk(9)
init_state, info = env.reset()
gamma = 1.0
n_episodes = 500
P = env.unwrapped.P

pi = {i: 0 for i in range(env.observation_space.n)}
agent = MCPrediction(env)
V, V_track = agent.evaluate_policy(pi)

RMSE

def rmse(x, y):
return np.sqrt(np.mean((x - y)**2))

V_true = policy_evaluation(pi, P)
V_true[-1] -= 1

rmse(V, V_true)
output
0.07512387561176827

수렴 과정

import matplotlib.pyplot as plt
def plot_value_track(V_track, V_true, env):
colors = plt.cm.viridis(np.linspace(0, 1, env.length - 2))

for i in range(env.length - 2):
j = i + 1
plt.plot(V_track[j], color=colors[i])
plt.hlines(V_true[j], 0, 1000, colors=colors[i], linestyles='dashed')
plt.text(0, V_true[j], f'{i}')

plot_value_track(V_track, V_true, env)

output
<Figure size 640x480 with 1 Axes>

퀴즈