본문으로 바로가기

Welcome to Spinning Up in Deep RL!

OpenAI Spinning UP에서 강화학습을 소개하는 부분이 있었다. 오 이거 정리해두면 좋겠는데?(불행의 시작)라는 마음으로 해석에 도전했다. 강화학습 쪽 영어는 그래도 알아들을 거라 생각해서 였는데 생각보다 고통스러운 발번역의 나날...그래도 나름 최선을 다했어 난!

원본은 Part 1: Key Concepts in RL

Table of Contents

  • Part 1: 강화학습 핵심 개념
    • 강화학습은 무엇을 할 수 있나요?
    • 핵심 개념과 용어
    • (옵션) 공식

강화학습 소개에 오신것을 환영합니다! 여기서 배울 목표는 다음과 같습니다.

  • 주제에 대해서 사용할 용어와 표기법
  • 강화학습 알고리즘이 간략하게 무엇을 하는지 (어떻게 동작하는 지에 대한 것들은 대부분 생략합니다.)
  • 그리고 이 알고리즘들을 기반으로 하고 있는 핵심적인 수학 조금

간단히 말하자면, 강화학습은 에이전트(agent)와 시행착오(trial and error)를 통해 어떻게 학습하는지에 대한 연구를 말합니다. 에이전트의 행동에 대해 보상과 처벌을 주어서 미래에 어떤 행동을 계속하게 하거나 그만두도록 만드는 것을 식으로 표현합니다.

What Can RL Do?

강화학습은 최근에 다양한 분야에서 활약하고 있습니다. 예를 들면, 시뮬레이션에서 로봇을 제어하도록 컴퓨터를 학습을 할 수 있습니다.

Your browser does not support the video element.

...그리고 현실 세계에선...

또한 아주 엄청난 AI를 만드는 데에도 사용되어서 유명하죠. 바둑, 도타, 픽셀값만으로 Atari 게임을 하도록 컴퓨터를 학습시키고 인간의 지시에 따라 학습된 시뮬레이트 로봇 등이 있습니다.

Key Concepts and Terminology

Agent-environment interaction loop

강화학습의 중요한 특징이라 할 수 있는 에이전트(Agent)환경(environment)입니다. 환경은 에이전트가 살아가면서 상호작용(interact)해가는 세계(World)라 입니다. 상호작용하는 스텝(step)마다 에이전트는 세계의 상태를 (아마 일부) observation을 보고 취할 행동(action)을 결정합니다. 환경은 에이전트가 행동할 때 변하지만 스스로 변할 때도 있습니다.

에이전트는 환경으로부터 현재 세계 상태가 좋은지 나쁜지를 얘기해주는 숫자 reward를 받습니다. 에이전트의 목표는 앞으로 받을 보상들의 합인 return을 최대화하도록 하는 것입니다. 그래서 강화학습은 에이전트가 이 목표를 위해 취해야 할 행동을 배울 수 있게하는 것이라 할 수 있습니다.

강화학습에 대해 좀 더 구체적으로 말하기 전에 추가적인 용어를 소개할 필요가 있겠네요. 다음과 같은 것들을 얘기해야할 것 같습니다.

  • states and observations
  • action spaces
  • policies
  • trajectories
  • different formulations of return
  • the RL optimization problem
  • value function

states and observations

상태(state) $s$는 세계의 상태에 대해 완전히 알려줍니다. 상태로부터 숨겨진 세계의 정보는 없습니다. 하지만 observation $o$는 정보가 생략되어 있을 수 있는 상태의 부분적인 표현입니다.

심층 강화학습(Deep RL)에서는 이러한 상태와 observation을 거의 대부분 실수 벡터, 행렬, 또는 그 이상의 고차원 텐서로 표현합니다. 예를 들어, 시각적으로 본다면 픽셀 값의 RGB 행렬로 표현할 수 있고 로봇의 상태를 표현한다면 관절의 각도나 속도로 나타낼 수 있겠죠.

에이전트가 환경의 완전한 상태를 관찰할 수 있다면, 이를 fully observed라고 하고 에이전트가 부분적으로 관찰할 수 있다면, 이를 partially observed 라고 합니다.

알아두세요

강화학습 표기법은 observation 기호 o 대신 기술적으로 좀 더 적절하다면 상태 s를 쓰기도 합니다. 특히 에이전트가 행동을 어떻게 하냐에 대해 얘기할 때 일어나는 일인데요. 행동은 상태에 따른 표기를 하지만 실제로 행동은 observation에 따라 달라집니다. 왜냐하면 에이전트는 상태를 알지 못하기 때문입니다.

이 가이드에서는 표준 표기 규칙을 따르지만, 문맥들이 의미하는 바를 이해하는 게 좋습니다. 만약 애매하다면, issue를 올려주세요! 우리 목표는 가르치는 것이지 혼란을 주는 것은 아니니까요.

Action Spaces

다른 환경은 다른 종류의 행동이 나옵니다. 주어진 환경에서의 모든 유효한 행동(valid action) 집합은 보통 행동 공간(action space) 라고 불립니다. Atari나 바둑같은 환경은 에이전트가 가능한 행동의 수가 제한된 분리된 행동 공간(discrete action space) 을 가집니다. 다른 환경, 예를 들어 물리적인 세계에서 로봇을 제어하는 에이전트 같은 경우는 연속 행동 공간 (continuous action) 을 가질 것입니다. 연속 공간에서는 행동은 실수 벡터를 가집니다.

이러한 구별을 통해 심층 강화학습의 방법들은 꽤 인상적인 결과들을 가져옵니다. 어떤 방법들은 오직 한 경우에만 적용할 수 있으며, 다른 경우에 적용하려면 보통 다시 작업해야 합니다.

Policies

정책 (policy) 은 에이전트가 취할 행동을 결정하는 규칙입니다. 결정적(deterministic)이라면 보통 $\mu$를 통해 정의됩니다.

$$ a_t = \mu(s_t). $$

또는 확률적(stochastic)이라면 $\pi$에 의해 정의됩니다.

$$ a_t \sim \pi(\cdot | s_t) $$

왜냐하면 정책은 기본적으로 에이전트의 두뇌이기 때문에, "정책"을 "agent" 대신 사용하기도 합니다. 예를 들어, "정책은 보상을 최대화 하려 한다." 같은 게 있습니다.

심층 강화학습에서는 파라미터를 가진 정책(parameterized policy) 를 사용합니다. 출력이 파라미터(예를 들어 신경망의 가중치나 바이어스)에 의존하는 계산 가능한 함수로, 어떤 최적화 알고리즘을 통해 행동을 변화시키도록 조정할 수 있습니다.

정책의 파라미터를 $\theta$나 $\phi$ 로 정의하고 연결되어 있음을 강조하기 위해 정책 기호(symbol)를 첨자로 씁니다.

$$ a_t = \mu_{\theta}(s_t) $$ $$ a_t \sim \pi_{\theta}(\cdot | s_t). $$

Deterministic Policies

예: Deterministic Policies. 텐서플로우에서 연속적인 행동 공간(continuous action space)을 위한 간단한 deterministic policy를 구현한 코드 일부가 있습니다.

obs = tf.placeholder(shape=(None, obs_dim), dtype=tf.float32)
net = mlp(obs, hidden_dims=(64, 64), activation=tf.tanh)
actions = tf.layers.dense(net, units=act_dim, activation=None)

여기서 mlp는 각각 크기와 활성화 함수가 정해진 dense layer를 여러 개 쌓은 함수입니다.

Stochastic Policies

심층 강화학습에서 stochastic polices는 대표적으로 두 종류가 있습니다. categorical policiesdiagonal Gaussian policies.

Categorical 정책은 분리된(discrete) 행동 공간에서 사용되는 반면, Gaussian은 연속적인 행동 공간에서 사용됩니다.

stochastic policy를 사용하고 학습할 때 두 가지의 계산이 아주 중요합니다.

  • 정책에서 행동을 샘플링(sampling)하기
  • 그리고 특정 동작의 log likelihoods $\log \pi_{\theta}(a|s)$를 계산하기

이어서, categorical 정책과 diaonal Gaussian 정책이 어떻게 동작하는지 설명할 것입니다.

Categorical Policies

categorical policy는 discrete action에 대한 분류자(classifier)같은 겁니다. classifier를 구현할 때 처럼 categorical 정책을 위한 신경망을 구현하는겁니다. 입력이 observation이고 뒤 이어 몇 개의 layer가 나올 것이고(아마 convolutional이나 densely-connected겠죠. 입력이 어떤 종류냐에 달려있을 겁니다) 각 행동에 대한 logits을 출력하는 마지막 레이어가 있고 뒤이어 logit을 확률로 변환하는 softmax가 나올겁니다.

샘플링 행동에 대한 각 확률이 주어졌다고 할 때, 텐서플로우 같은 프레임워크는 샘플링을 위한 도구가 내장되어 있습니다. 예를 들어 tf.distributions.Categorical 문서나 tf.multinomial를 보시면 될겁니다.

Log-Likelihood 확률을 가진 마지막 layer를 $P_\theta(s)$라고 정의하겠습니다. 행동의 수만큼 가지고 있는 벡터이기 때문에 행동을 인덱스로 사용할 수 있습니다. 행동 $a$에 대한 log likelihood는 벡터에 인덱싱 하여 얻을 수 있습니다.

$$ \log \pi_{\theta}(a|s) = \log \left[P_{\theta}(s)\right]_a $$

Diagonal Gaussian Policies

multivariate Gaussian distribution (또는 multivariate normal distribution)는 평균 벡터 $\mu$와 covariance matrix $\Sigma$에 의해 결정됩니다. diagonal Gaussian distribution은 covariance matrix가 대각선에만 요소를 가지는 특수한 경우를 말합니다. 결과적으로 이는 벡터로 나타낼 수 있죠.

diagonal Gaussian 정책은 항상 신경망을 가지고 observation을 행동 평균 $\mu_{\theta}(s)$로 맵핑합니다. covariance matrix을 나타낼 수 있는 방법이 일반적으로 두 가지가 있습니다.

첫 번째 방법: 상태의 함수가 아닌 log 표준편차 $\log \sigma$의 벡터입니다. 이는 독립적으로 존재하는 파라미터입니다. (알아두세요. 이것이 나중에 VPG, TRPO, 그리고 PPO 구현 때 이렇게 사용합니다.)

두 번째 방법: 상태로부터 log 표준편차 $\log \sigma_{\theta}(s)$로 맵핑하는 신경망입니다. 평균 네트워크로 몇 개의 층은 선택적으로 공유할수도 있습니다.

두 가지 경우 다 표준 편차를 직접 출력하는 것 대신에 log 표준 편차를 출력합니다. 왜냐하면 log 표준편차는 $(-\infty, \infty)$의 범위로 어떤 값이든 자유로운 반면, 표준 편차는 음수가 아니어야 한다는 제한이 있기 때문입니다. 제한을 두지 않는 것이 파라미터를 학습하기에 더 쉽습니다. 표준 편차는 log 표준 편차를 지수를 곱해서 바로 얻어낼 수 있기에 이를 나타내는 데 어떠한 손실도 없습니다.

샘플링(Sampling). 평균 벡터 $\mu_{\theta}(s)$와 표준 편차 $\sigma_{\theta}(s)$ 그리고 spherical Gaussian($z \sim \mathcal{N}(0, I)$)의 노이즈 벡터 $z$가 있다고 할 때, 행동 샘플은 다음과 같이 계산할 수 있습니다.

$$ a = \mu_{\theta}(s) + \sigma_{\theta}(s) \odot z $$

여기서 $\odot$는 두 벡터를 요소별로(elementwise) 곱한 것을 정의한것입니다. 표준 프레임워크는 tf.random_normal같이 노이즈 벡터를 계산해주는 내장 기능이 있습니다. 또는, 평균과 표준 편차를 tf.distributions.Normal 객체로 평균과 표준편차를 주어서 샘플링하는 데에 사용할 수도 있습니다.

Log-Likelihood. 평균이 $\mu = \mu_{\theta}(s)$이고 표준 편차가 $\sigma = \sigma_{\theta}(s)$라고 할 때, k개 차원의 행동 $a$의 log-likelihood는 다음과 같이 나타낸다.

$$\log \pi_{\theta}(a|s) = -\frac{1}{2}\left(\sum_{i=1}^k \left(\frac{(a_i - \mu_i)^2}{\sigma_i^2} + 2 \log \sigma_i \right) + k \log 2\pi \right)$$

Trajectories

trajectory $\tau$는 상태와 행동의 시퀀스입니다.

$$\tau = (s_0, a_0, s_1, a_1, ...).$$

맨 첫 번째 상태 $s_0$는 start-state distribution, 가끔 $\rho_0$로 정의되는 이것에 의해 임의로 샘플링됩니다.

$$s_0 \sim \rho_0(\cdot)$$

상태 전이(state transitions) ($t$ 시간 때의 상태 $s_t$와 $t+1$ 때의 상태 $s_{t+1}$ 간에 일어나는 일)는 환경의 자연적인 법칙에 따라 최근 행동 $a_t$에만 의존합니다. deterministic이라면 다음과 같이 될 것이고,

$$ s_{t+1} = f(s_t, a_t) $$

stochastic이라면,

$$s_{t+1} \sim P(\cdot|s_t, a_t)$$

정책에 따라 에이전트가 행동을 결정합니다.

알아두세요

Tarjectory는 종종 episoderollout이라 합니다.

Reward and Return

보상(reward) $R$은 강화학습에서 아주 중요합니다. 세계의 현재 상태, 행동 그리고 다음 상태에 따라 달라집니다.

$$ r_t = R(s_t, a_t, s_{t+1}) $$

보통 현재 상태 ($r_t=R(s_t)$)나 상태, 행동 쌍 ($r_t=R(s_t, a_t)$)으로 간단히 표현할 수 있습니다.

에이전트의 목표는 trajectory에 따라 보상 합이 최대가 되도록 하는 것이지만 위에서 본 것처럼 몇 가지로 더 표현할 수 있습니다. 그래서 모든 경우에 대해 $R(\tau)$로 표기하겠습니다. 문맥적으로 좀 더 명확하기도 하고 딱히 중요한 것은 아니니까요. (왜냐하면 모든 경우에 동일한 방정식이 적용되니까요)

return의 종류 중 하나는 finite-horizon undiscounted return입니다. 일정하게 고정된 스텝에서 얻을 수 있는 보상들의 합을 말합니다.

$$ R(\tau) = \sum_{t=0}^T r_t $$

또다른 하나는 infinite-horizon discounted return입니다. 이것 또한 에이전트가 받을 수 있는 모든 보상의 합이지만, 얼마나 먼 미래에서 받았냐에 따라 감소합니다. 그래서 보상의 식에서 discount factor $\gamma \in (0,1)$가 들어있습니다.

$$ R(\tau) = \sum_{t=0}^{\infty} \gamma^t r_t $$

근데, 왜 discount factor가 필요할까요? 그냥 보상 모두를 받으면 안되는걸까요? 그렇게 할수도 있지만, 직관적으로 그럴만하고 수학적으로 편하기 때문입니다. 직관적인 수준에서 얘기하자면 현재 받을 돈이 나중에 받을 돈보다 좋다는 얘기를 들 수 있고, 수학적으로 보자면 무한하게 보상의 합을 얻게된다고 하면 유한한 값으로 수렴이 안할 수도 있고, 수식으로 표현하기도 쉽지 않습니다. 하지만 discount factor와 어떤 적절한 조건이 만족한다면 무한한 합이 수렴할 수 있게 됩니다.

알아두세요

위에 return에 관한 두 식은 RL 형식에서는 꽤나 뚜렷한 차이가 있지만, deep RL에서는 약간 애매모호한 일이 있을 수 있습니다. 예를 들어, 보통 undiscounted return을 최적화하는 알고리즘들을 쓰지만 value function을 추정하는데 discount factor를 사용합니다.

The RL Problem

어떤 return을(infinite-horizon discounted 또는 finite-horizon undiscounted) 사용하든, 어떤 정책을 사용하든, 강화학습에 있어 목표는 에이전트가 expected return에 대하여 행동하며 이를 최대화하는 정책을 선택해야한다는 것입니다.

expected return에 대해 얘기하려면, 먼저 trajectory에 대한 확률 분포에 대해 얘기해야합니다.

환경 전이(transition)와 정책이 모두 확률적(stochastic)이라고 가정하겠습니다. 이 경우 T 스텝이 지난 trajectory의 확률은

$$ P(\tau|\pi) = \rho_0 (s_0) \prod_{t=0}^{T-1} P(s_{t+1} | s_t, a_t) \pi(a_t | s_t). $$

expected return (어떤 것을 사용하든) $J(\pi)$로 정의되어 다음과 같습니다.

$$ J(\pi) = \int_{\tau} P(\tau|\pi) R(\tau) = E_{\tau\sim \pi}{R(\tau)}. $$

그렇다면 강화학습에 있어 중요한 최적화 문제는 다음과 같이 표현할 수 있습니다.

$$ \pi^* = \arg \max_{\pi} J(\pi) $$

여기서 $\pi^*$는 최적의 정책을 말합니다.

Value Functions

가끔 상태나 상태-행동 쌍의 가치(value)를 알면 유용합니다. 이는 상태 또는 상태-행동 쌍에서 시작하여 어떤 특정 정책에 따라 쭈욱 계속 행동했을 때 얻을 수 있는 expected return을 의미합니다. 가치 함수(Value function)는 거의 모든 RL 알고리즘에서 사용됩니다.

여기 알아야할 4가지 함수가 있습니다.

1. On-Policy Value Function

상태 $s$에서 시작해서 정책 $\pi$에 따라 항상 행동할 때 얻을 수 있는 expected return입니다.

$$ V^{\pi}(s) = E_{\tau \sim \pi}{R(\tau)\left| s_0 = s\right.} $$

2. On-Policy Action-Value Function

어떤 상태 $s$에서 행동 $a$를 한 이후, 정책 $\pi$에 따라 항상 행동할 때 얻을 수 있는 expected return입니다.

$$ Q^{\pi}(s,a) = E_{\tau \sim \pi}{R(\tau)\left| s_0 = s, a_0 = a\right.} $$

3. Optimal Value Function

상태에서 $s$ 최적의 정책을 따를 때 얻을 수 있는 expected return입니다.

$$ V^*(s) = \max_{\pi} E_{\tau \sim \pi}{R(\tau)\left| s_0 = s\right.} $$

4. Optimal Action-Value Function

어떤 상태 $s$에서 행동 $a$를 한 이후, 최적의 정책을 따를 때 얻을 수 있는 expected return입니다.

$$ Q^*(s,a) = \max_{\pi} E_{\tau \sim \pi}{R(\tau)\left| s_0 = s, a_0 = a\right.} $$

알아두세요

가치 함수에 대해 얘기할 때, 시간 의존에 대한 언급이 딱히 없다면, infinite-horizon discounted return을 의미할 것입니다. finite-horizon discounted return은 매개변수로 시간이 필요합니다. 왜 그럴까요? 힌트 : 시간이 다 되면 어떻게 되나요?

알아두세요

종종 나타나는 가치 함수와 행동 가치 함수간의 중요한 연관성이 있습니다. $$ V^{\pi}(s) = E_{a\sim \pi}{Q^{\pi}(s,a)}, $$

그리고

$$ V^\ast(s) = \max_a Q^\ast(s,a).$$

이렇게 주어진 정의에서 꽤 직접적으로 관계를 가지는데 증명할 수 있나요?

The Optimal Q-Function and the Optimal Action

최적의 행동 가치 함수 $Q^\ast(s,a)$와 최적의 정책에 의해 선택된 행동 간의 중요한 연관성이 있습니다. 정의에 의해 $Q^\ast(s,a)$는 주어진 상태 $s$에서 한 행동 $a$으로 부터 최적의 정책을 쭈욱 따를 때의 expected return 값을 줍니다.

$s$에서 최적의 정책은 $s$에서 시작하여 expected return이 최대가 되는 행동이 되도록 선택하는 것입니다. 결과적으로 $Q^\ast$를 가지고 있다고 하면, 최적의 행동 $a^\ast(s)$을 직접적으로 얻을 수 있는 겁니다. 다음과 같은 식을 통해서 말이죠.

$$ a^\ast(s) = \arg \max_a Q^\ast(s,a). $$

참고: $Q^*(s,a)$를 최대화 하는 행동이 여러 개 있을 수 있습니다. 이 경우 그 행동들 모두 최적이고 최적의 정책은 그것들 중 하나를 선택하는 것일 수 있습니다. 하지만 결정적으로(deterministically) 행동을 선택하는 최적의 정책은 항상 있습니다.

Bellman Equations

4가지 가치함수 모두 벨만 방정식(Bellman equation)이라는 특별한 self-consistency 방정식을 따릅니다. 벨만 방정식 속에 있는 아이디어는 다음과 같습니다.

시작 지점에서의 가치는 그 다음 도착할 곳에 대한 가치와 그곳에서 얻을 수 있는 보상의 합입니다.

on-policy 가치 함수를 위한 벨만방정식은

$$ V^{\pi}(s) = E_{a \sim \pi, \ s'\sim P}\left[r(s,a) + \gamma V^{\pi}(s')\right],$$ $$Q^{\pi}(s,a) = E_{s'\sim P}\left[r(s,a) + \gamma E_{a'\sim \pi}{Q^{\pi}(s',a')}\right],$$

여기서 $s' \sim P$는 $s' \sim P(\cdot |s,a)$의 축약형으로 다음 상태 $s'$가 환경 전이 규칙에 따라 샘플링된 것을 나타내고, $a \sim \pi$는 $a \sim \pi(\cdot|s)$의, $a' \sim \pi$는 $a' \sim \pi(\cdot|s')$의 축약형을 나타낸다.

최적의 가치 함수에 대한 벨만 방정식은

$$ V^\ast(s) = \max_a E_{s'\sim P}\left[r(s,a) + \gamma V^\ast(s')\right], $$

$$ Q^\ast(s,a) = E_{s'\sim P}\left[r(s,a) + \gamma \max_{a'} Q^\ast(s',a')\right]. $$

on-policy 가치 함수에 대한 벨만 방정식과 최적의 가치 함수에 대한 벨만 방정식의 결정적인 차이는 행동에 $\max$가 있냐 없냐입니다. 포함되면 에이전트가 행동을 선택을 할 때, 최적의 행동을 하기 위해 가장 높은 값이 나오도록 선택해야 한다는 점을 반영합니다.

알아두세요

용어 "벨만 backup"은 강화학습 문헌에서 자주 등장합니다. 상태나 상태행동 쌍의 벨만 backup은 벨만 방정식의 오른쪽 항의 (보상 + 다음 가치)입니다.

Advantage Functions

강화학습에서 가끔, 절대적으로 행동이 얼마나 좋은지 기술할 필요는 없지만, 평균에 비해 얼마나 좋은지는 기술할 필요가 있습니다. 즉, 말하자면 행동의 상대적인 advantage을 알고싶다는 얘기입니다. 이러한 advantage function의 개념을 정확히 다루어보겠습니다.

정책 $\pi$에 따른 advantage function $A^{\pi}(s,a)$는 상태 $s$에서 특정 행동 $a$를 취하는 것이 $\pi(\cdot|s)$에 따라 임의로 행동을 선택한 것보다 $\pi$를 무한히 행동할 때 얼마나 더 좋은지를 말합니다. 수학적으로, advantage function은 다음과 같이 정의됩니다.

$$ A^{\pi}(s,a) = Q^{\pi}(s,a) - V^{\pi}(s). $$

알아두세요

이에 대해선 나중에 다룰 예정이지만 advantage function은 policy gradient 방법에서 매우 중요합니다.

(Optional) Formalism

지금까지, 에이전트의 환경에 대해서 간단히(informal) 다루었지만 문헌을 통해 깊게 가고싶을 경우 표준 수학 공식을 따르고 싶을겁니다. Markov Decision Process (MDPs). MDP는 5개의 값을 가지고 있는 튜플 $\langle S, A, R, P, \rho_0 \rangle$ 입니다.

  • $S$는 모든 유효한 상태의 집합입니다.
  • $A$는 모든 유효한 행동의 집합입니다.
  • $R : S \times A \times S \to \mathbb{R}$는 보상 함수로 다음과 같습니다. $r_t = R(s_t, a_t, s_{t+1})$
  • $P : S \times A \to \mathcal{P}(S)$는 상태 전이 함수로 상태 $s$에서 행동 $a$를 취하면 상태 $s'$로 전이할 확률 $P(s'|s,a)$을 말합니다.
  • 그리고 $\rho_0$는 초기 상태 분포입니다.

Markov Decision Process라는 이름은 Markov property를 따르는 시스템을 참조합니다. Markov property는 전이할 때 오로지 가장 최근 상태와 행동만을 의존하고 그 이전의 과거는 영향을 받지 않는 것을 말합니다.

으아 번역 끝!

다음 번역은 Part 2: Kinds of RL Algorithms을 할 예정이다. 얼마나 걸릴지 후덜덜...