-
โฑ ํธ์ฆ์จ ๋จธ์ ๋ฌ๋ 18์ฅ ๊ฐํ ํ์ต โฑ๐ฎ ์ด๊ฒ์ ๊ฒ ๊ณต๋ถ/โฉ ํธ์ฆ์จ ๋จธ์ ๋ฌ๋ 2026. 2. 6. 20:33
18.1 ๋ณด์์ ์ต์ ํํ๊ธฐ ์ํ ํ์ต
๊ฐํ ํ์ต์์ ์ํํธ์จ์ด ์์ด์ ํธ๋ ๊ด์ธก์ ํ๊ณ ์ฃผ์ด์ง ํ๊ฒฝ์์ ํ๋์ ํ๋ค.
๊ทธ๋ฆฌ๊ณ ๊ฒฐ๊ณผ์ ๋ฐ๋ผ ํ๊ฒฝ์ผ๋ก๋ถํฐ ๋ณด์์ ๋ฐ๋๋ค.
์์ด์ ํธ์ ๋ชฉ์ ์ ๋ณด์์ ์ฅ๊ธฐ๊ฐ ๊ธฐ๋์น๋ฅผ ์ต๋๋ก ๋ง๋๋ ํ๋์ ํ์ตํ๋ ๊ฒ์ด๋ค.
์์ ๋ณด์์ ๊ธฐ์จ์ผ๋ก, ์์ ๋ณด์์ ์ํ์ผ๋ก ์๊ฐํ ์ ์๋ค.
18.2 ์ ์ฑ ํ์
์ ์ฑ : ์ํํธ์จ์ด ์์ด์ ํธ๊ฐ ํ๋์ ๊ฒฐ์ ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ์๊ณ ๋ฆฌ์ฆ์ด๋ค.
์) ๊ด์ธก์ ์ ๋ ฅ์ผ๋ก ๋ฐ๊ณ ์ํํ ํ๋์ ์ถ๋ ฅํ๋ ์ ๊ฒฝ๋ง

์ ์ฑ ์ ๋ชจ๋ ์๊ณ ๋ฆฌ์ฆ์ด ๋ ์ ์์ผ๋ฉฐ ๊ฒฐ์ ์ ์ผ ํ์๋ ์๋ค. ์ด๋ค ๊ฒฝ์ฐ์๋ ํ๊ฒฝ์ ๊ด์ธกํ ํ์๋ ์๋ค.
๋ฌด์์์ฑ์ด ํฌํจ๋์ด ์๋ ์ ์ฑ ์ ํ๋ฅ ์ ์ ์ฑ ์ด๋ผ๊ณ ํ๋ค.
์) 30๋ถ ๋์ ์์งํ ๋จผ์ง์ ์์ ๋ณด์์ผ๋ก ๋ฐ๋ ๋ก๋ด ์ง๊ณต์ฒญ์๊ธฐ๊ฐ ์๋ค.
์ฌ๊ธฐ์๋ ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ ๋ ๊ฐ์ ์ ์ฑ ํ๋ผ๋ฏธํฐ์ธ ํ๋ฅ p์ ๊ฐ๋์ ๋ฒ์ r์ด ์๋ค.
์ด ํ๋ผ๋ฏธํฐ์ ๋ง์ ๋ค๋ฅธ ๊ฐ์ ์๋ํด๋ณด๊ณ ๊ฐ์ฅ ์ฑ๋ฅ์ด ์ข์ ์กฐํฉ์ ๊ณ ๋ฅด๋ ํ์ต ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ ์ ์๋ค.
ํ์ง๋ง ์ ์ฑ ๊ณต๊ฐ์ด ๋งค์ฐ ํฐ ๊ฒฝ์ฐ์ ์ข์ ํ๋ผ๋ฏธํฐ ์กฐํฉ์ ์ฐพ๋ ๋ฐ์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฐ๋ค.
๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์ ์ ์๊ณ ๋ฆฌ์ฆ์ด ์๋ค.
์) 1์ธ๋ ์ ์ฑ 100๊ฐ๋ฅผ ๋๋คํ๊ฒ ์์ฑํด์ ์๋ํด๋ณธ ๋ค, ์ฑ๋ฅ์ด ๋ฎ์ ์ ์ฑ 80๊ฐ๋ ๋ฒ๋ฆฌ๊ณ 20๊ฐ๋ฅผ ์ด๋ ค ๊ฐ๊ฐ ์์ ์ ์ฑ 4๊ฐ๋ฅผ ์์ฐํ๋ค.
์ด ์์ ์ ์ฑ ์ ๋ถ๋ชจ๋ฅผ ๋ณต์ฌํ ๊ฒ์ด ์ฝ๊ฐ์ ๋ฌด์์์ฑ์ ๋ํ ๊ฒ์ด๋ค.
์ด์๋จ์ ์ ์ฑ ๊ณผ ๊ทธ ์์์ 2์ธ๋๋ฅผ ๊ตฌ์ฑํ๋ฉฐ, ์ด๋ฐ ์์ผ๋ก ์ข์ ์ ์ฑ ์ ์ฐพ์ ๋๊น์ง ์ฌ๋ฌ ์ธ๋์ ๊ฑธ์ณ ๋ฐ๋ณตํ๋ค.

๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์ ์ฑ ํ๋ผ๋ฏธํฐ์ ๋ํ ๋ณด์์ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ํ๊ฐํด์ ๋์ ๋ณด์์ ๋ฐฉํฅ์ ๋ฐ๋ฅด๋ ๊ทธ๋ ์ด๋์ธํธ๋ก ํ๋ผ๋ฏธํฐ๋ฅผ ์์ ํ๋ ์ต์ ํ ๊ธฐ๋ฒ์ด ์๋ค. (์ ์ฑ ๊ทธ๋ ์ด๋์ธํธ(PG))
์) ๋ก๋ด์ฒญ์๊ธฐ์ ์์์ p๋ฅผ ์กฐ๊ธ ์ฆ๊ฐ์์ผ์ 30๋ถ ๋์ ๋ก๋ด์ด ์์งํ ๋จผ์ง ์์ด ์ฆ๊ฐํ๋์ง ํ๊ฐํ ์ ์๋ค.
๋จผ์ง ์์ด ๋ง์์ก๋ค๋ฉด P๋ฅผ ์กฐ๊ธ ์ฆ๊ฐ์ํค๊ณ ๊ทธ๋ ์ง ์๋ค๋ฉด p๋ฅผ ๊ฐ์์ํจ๋ค.
PG ์๊ณ ๋ฆฌ์ฆ์ ํ ์ํ๋ก๋ฅผ ์ฌ์ฉํด ๊ตฌํํ์ง๋ง ๊ทธ์ ์ ์์ด์ ํธ๊ฐ ํ๋ํ ํ๊ฒฝ์ ๋ง๋ค์ด์ผ ํ๋ค.
18.3 OpenAI Gym
๊ฐํ ํ์ต์์ ์ด๋ ค์ด ์ ์ ์์ด์ ํธ๋ฅผ ํ๋ จํ๊ธฐ ์ํด ๋จผ์ ์์ ํ๊ฒฝ์ ๋ง๋ จํด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
์ค์ ์ธ์์์ ํ๋ จํ๋ ๊ฒ์ ์ด๋ ต๊ณ ๋๋ฆฌ๊ธฐ์ ํ๋ จ์ ์ํ ์ต์ํ์ ์๋ฎฌ๋ ์ด์ ํ๊ฒฝ์ด ํ์ํ๋ค.
OpenAI Gym์ ๋ค์ํ ์ข ๋ฅ์ ์๋ฎฌ๋ ์ด์ ํ๊ฒฝ(์ํ๋ฆฌ ๊ฒ์, ๋ณด๋ ๊ฒ์, 2D์ 3D ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ๋ฑ)์ ์ ๊ณตํ๋ ํด๊น์ผ๋ก, ์ด๋ฅผ ์ฌ์ฉํ์ฌ ์์ด์ ํธ๋ฅผ ํ๋ จํ๊ณ ์ด๋ค์ ๋น๊ตํ๊ฑฐ๋ ์๋ก์ด RL ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ๋ฐํ ์ ์๋ค.
%pip install -q -U gymnasium %pip install swig %pip install -q -U gymnasium[classic_control, box2d, atari, accept-rom-license]์ฒซ ๋ฒ์งธ %pip ๋ช ๋ น์ Gym์ ์ต์ ๋ฒ์ ์ผ๋ก ์ ๊ทธ๋ ์ด๋ํ๋ค.
-q ์ต์ ์ ์กฐ์ฉํ ์ค์นํ๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ ์ฅํฉํ ์ถ๋ ฅ์ ๋ง๋ค์ง ์๊ณ , -U ์ต์ ์ ์ ๊ทธ๋ ์ด๋๋ฅผ ์๋ฏธํ๋ค.
๋ ๋ฒ์งธ %pip ๋ช ๋ น์ ๋ค์ํ ์ข ๋ฅ์ ํ๊ฒฝ์ ์คํํ๋ ๋ฐ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ๋ค. ์นดํธ์์ ๋ง๋์ ๊ท ํ์ ์ก์ ๊ฒ๊ณผ ๊ฐ์ ๊ณ ์ ์ ์ธ ์ ์ด ์ด๋ก ์ ํ๊ฒฝ์ด ํฌํจ๋๋ค.
import gymnasium as gym env = gym.make("CartPole-v1", render_mode="rgb_array")Gym์ ์ํฌํธํ๊ณ ํ๊ฒฝ์ ๋ง๋ ๋ค.
CartPole ํ๊ฒฝ์ ๋ง๋ ๋ค. ์นดํธ ์์ ๋์ธ ๋ง๋๊ฐ ๋์ด์ง์ง ์๋๋ก ์ผ์ชฝ์ด๋ ์ค๋ฅธ์ชฝ์ผ๋ก ๊ฐ์ํ ์ ์๋ 2D ์๋ฎฌ๋ ์ด์ ์ด๋ค.
obs, info = env.reset(seed=42) obs # array([ 0.0273956, -0.00611216, 0.03585979, 0.0197368 ], dtype=float32) info # {}ํ๊ฒฝ์ ๋ง๋ ํ reset() ๋ฉ์๋๋ก ์ด๊ธฐํํด์ผ ํ๋ค. ์ด ๋ฉ์๋๋ ์ฒซ ๋ฒ์งธ ๊ด์ธก์ ๋ฐํํ๋ค. ๊ด์ธก์ ํ๊ฒฝ์ ์ข ๋ฅ์ ๋ฐ๋ผ ๋ค๋ฅด๋ค.
CartPole ํ๊ฒฝ์ ๊ฒฝ์ฐ ๊ฐ ๊ด์ธก์ ๋ค ๊ฐ์ ์ค์๋ฅผ ๋ด์ 1D ๋ํ์ด ๋ฐฐ์ด์ด๋ค.
์ด ์ค์๋ ์นดํธ์ ์ํ ์์น(0.0 = ์ค์), ์นดํธ์ ์๋(์์๋ ์ฐ์ธก ๋ฐฉํฅ์ ์๋ฏธ), ๋ง๋์ ๊ฐ๋(0.0 = ์์ง), ๋ง๋์ ๊ฐ์๋(์์๋ ์๊ณ ๋ฐฉํฅ์ ์๋ฏธ)๋ฅผ ๋ํ๋ธ๋ค.
reset() ๋ฉ์๋๋ ์ถ๊ฐ์ ์ผ๋ก ํ๊ฒฝ์ ๊ด๋ จ๋ ์ ๋ณด๋ฅผ ๋ด์ ๋์ ๋๋ฆฌ๋ ๋ฐํํ๋ค.

CartPole ํ๊ฒฝ img = env.render() img.shape # ๋์ด, ๋๋น, ์ฑ๋ # (400, 600, 3)render() ๋ฉ์๋๋ฅผ ํธ์ถํด ์ด ํ๊ฒฝ์ ์ด๋ฏธ์ง๋ก ๋ ๋๋งํ๋ค.
์ด ํ๊ฒฝ์ ๋ง๋ค ๋ render_mode="rgb_array"๋ก ์ง์ ํ๊ธฐ ๋๋ฌธ์ ์ด๋ฏธ์ง๋ ๋ํ์ด ๋ฐฐ์ด๋ก ๋ฐํ๋๋ค.
env.action_space # Discrete(2)๋งทํ๋กฏ๋ฆฝ์ imshow() ํจ์๋ฅผ ์ฌ์ฉํด ์ด๋ฏธ์ง๋ฅผ ํ๋ฉด์ ๊ทธ๋ฆด ์ ์๋ค.
Discrete(2)๋ ๊ฐ๋ฅํ ํ๋์ด ์ ์ 0๊ณผ 1์ด๋ผ๋ ๊ฒ์ ์๋ฏธํ๋ค. (์ผ์ชฝ ๊ฐ์, ์ค๋ฅธ์ชฝ ๊ฐ์)
๋ค๋ฅธ ํ๊ฒฝ์ ๋ ๋ง์ ๊ฐ๋ณ์ ์ธ ํ๋์ ๊ฐ์ง๊ฑฐ๋ ๋ค๋ฅธ ์ข ๋ฅ์ ํ๋(์. ์ฐ์์ ์ธ)์ ๊ฐ์ง ์ ์๋ค.
action = 1 # ์ค๋ฅธ์ชฝ์ผ๋ก ๊ฐ์ obs, reward, done, truncated, info = env.step(action) obs # array([ 0.02727336, 0.18847767, 0.03625453, -0.26141977], dtype=float32) reward # 1.0 done # False truncated # False info # {}๋ง๋๊ฐ ์ค๋ฅธ์ชฝ์ผ๋ก ๊ธฐ์ธ์ด์ ธ ์๊ธฐ ๋๋ฌธ์ ์นดํธ๋ฅผ ์ค๋ฅธ์ชฝ์ผ๋ก ๊ฐ์ํ ์ ์๋ค.
step() ๋ฉ์๋๋ ์ฃผ์ด์ง ํ๋์ ์คํํ๊ณ ๋ค ๊ฐ์ง ๊ฐ์ ๋ฐํํ๋ค.
obs : ์๋ก์ด ๊ด์ธก๊ฐ์ด๋ค. ์ด์ ์นดํธ๊ฐ ์ค๋ฅธ์ชฝ ๋ฐฉํฅ์ผ๋ก ์์ง์ธ๋ค. (obs[1] > 0). ๋ง๋๊ฐ ์ฌ์ ํ ์ค๋ฅธ์ชฝ ๋ฐฉํฅ์ผ๋ก ๊ธฐ์ธ์ด์ ธ ์์ง๋ง (obs[2] > 0) ๊ฐ์๋๊ฐ ์์๊ฐ ๋์์ผ๋ฏ๋ก (obs[3] < 0) ๋ค์ ์คํ ํ์๋ ์ผ์ชฝ์ผ๋ก ๊ธฐ์ธ์ด์ง ๊ฐ๋ฅ์ฑ์ด ํฌ๋ค.
reward : ์ด ํ๊ฒฝ์์๋ ์ด๋ค ํ๋์ ์คํํด๋ ๋งค ์คํ ๋ง๋ค 1.0์ ๋ณด์์ ๋ฐ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก ์์คํ ์ ๋ชฉ์ ์ ๊ฐ๋ฅํ ํ ์ค๋ซ๋์ ์คํํ๋ ๊ฒ์ด๋ค.
doen : ์ด ๊ฐ์ด True์ด๋ฉด ์ด ์ํผ์๋๊ฐ ๋๋ ๊ฒ์ด๋ค. ๋ง๋๊ฐ ๋๋ฌด ๊ธฐ์ธ์ด์ง๊ฑฐ๋ ํ๋ฉด ๋ฐ์ผ๋ก ๋๊ฐ๊ฑฐ๋ 200 ์คํ ์ ๋๊ธฐ๋ฉด ์ํผ์๋๊ฐ ๋๋๋ค. (๋ง์ง๋ง์ ๊ฒฝ์ฐ ์์ด์ ํธ๊ฐ ์ด๊ธด ๊ฒ์ด๋ค.). ์ํผ์๋๊ฐ ๋๋๋ฉด ํ๊ฒฝ์ ๋ค์ ์ฌ์ฉํ๊ธฐ ์ ์ ๊ผญ ์ด๊ธฐํํด์ผ ํ๋ค.
trundated : ์ด ๊ฐ์ ์ํผ์๋๊ฐ ์กฐ๊ธฐ์ ์ค๋จ๋๋ ๊ฒฝ์ฐ True๊ฐ ๋๋ค. ์ผ๋ถ RL ์๊ณ ๋ฆฌ์ฆ์ ์ค๋จ๋ ์ํผ์๋๋ฅผ ์ ์์ ์ผ๋ก ์๋ฃ๋ ์ํผ์๋์ ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํ์ง๋ง ์ด ์ฅ์์๋ ๋์ผํ๊ฒ ์ฒ๋ฆฌํ๋ค.
info : reset() ๋ฉ์๋๊ฐ ๋ฐํํ๋ ๊ฐ์ฒ๋ผ ํ๊ฒฝ์ ๊ด๋ จ๋ ์ถ๊ฐ ์ ๋ณด๋ฅผ ๋ด์ ๋์ ๋๋ฆฌ์ด๋ค.
def basic_policy(obs):: angle = obs[2] return 0 if angle < 0 else 1 totals = [] for episode in range(500): episode_rewards = 0 obs, info = env.reset(seed=episode) for step in range(200): action = basic_policy(obs) obs, reward, done, truncated, info = env.step(action) episode_rewards += reward if done or truncated: break totals.append(episode_rewards)์ด ์ ์ฑ ์ ๋ง๋๊ฐ ์ผ์ชฝ์ผ๋ก ๊ธฐ์ธ์ด์ง๋ฉด ์นดํธ๋ฅผ ์ผ์ชฝ์ผ๋ก ๊ฐ์ํ๊ณ ์ค๋ฅธ์ชฝ์ผ๋ก ๊ธฐ์ธ์ด์ง๋ฉด ์ค๋ฅธ์ชฝ์ผ๋ก ๊ฐ์ํ๋ค.
import numpy as np np.mean(totals), np.std(totals), min(totals), max(totals) # (41.698, 8.389445512070509, 24.0, 63.0)
18.4 ์ ๊ฒฝ๋ง ์ ์ฑ
์ ๊ฒฝ๋ง์ ๊ด์ธก์ ์ ๋ ฅ์ผ๋ก ๋ฐ๊ณ ์คํํ ํ๋์ ์ถ๋ ฅํ๋ค.
๊ฐ ํ๋์ ๋ํ ํ๋ฅ ์ ์ถ์ ํ๊ณ ์ถ์ ๋ ํ๋ฅ ์ ๋ฐ๋ผ ๋๋คํ๊ฒ ํ๋์ ์ ํํ๋ค.
๋๋คํ๊ฒ ํ๋์ ์ ํํ๋ฉด ์์ด์ ํธ๊ฐ ์๋ก์ด ํ๋์ ํํํ๋ ๊ฒ๊ณผ ์ ํ ์ ์๋ ํ๋์ ํ์ฉํ๋ ๊ฒ ์ฌ์ด์ ๊ท ํ์ ๋ง์ถ๊ฒ ๋๋ค.

์ด๋ฐ ํน๋ณํ ํ๊ฒฝ์์๋ ๊ณผ๊ฑฐ์ ํ๋๊ณผ ๊ด์ธก์ ๋ฌด์ํ ์ ์๋ค.
๊ฐ ๊ด์ธก์ด ํ๊ฒฝ์ ๋ํ ์์ ํ ์ํ๋ฅผ ๋ด๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ง์ฝ ์ด๋ค ์ํ๊ฐ ์จ๊ฒจ์ ธ ์์ ๋ ๊ณผ๊ฑฐ์ ํ๋๊ณผ ๊ด์ธก๋ ๊ณ ๋ คํด์ผ ํ๋ค.
๊ด์ธก์ ์ก์์ด ์์ ๋๋ ๊ฐ์ฅ ๊ฐ๋ฅ์ฑ ์๋ ํ์ฌ์ ์ํ๋ฅผ ์ถ์ ํ๊ธฐ ์ํด ์ง๋ ๊ด์ธก ๋ช ๊ฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
import tensorflow as tf model = tf.keras.Sequential([ tf.keras.layers.Dense(5, activation="relu"), tf.keras.layers.Dense(1, activation="sigmoid"), ])Sequential ๋ชจ๋ธ์ ์ฌ์ฉํด ์ ์ฑ ๋คํธ์ํฌ๋ฅผ ์ ์ํ๋ค.
์ ๋ ฅ์ ๊ฐ์๋ ๊ด์ธก ๊ณต๊ฐ์ ํฌ๊ธฐ์ด๋ค. ์ด ๊ฒฝ์ฐ๋ 4์ด๋ฉฐ, ๊ฐ๋จํ ๋ฌธ์ ์ด๋ฏ๋ก ์๋ ์ ๋ 5๊ฐ๋ฅผ ์ฌ์ฉํ๋ค.
๋ง์ง๋ง์ผ๋ก ํ๋์ ํ๋ฅ (์ผ์ชฝ ๋ฐฉํฅ์ผ ํ๋ฅ )์ด ํ์ํ๋ฏ๋ก ์๊ทธ๋ชจ์ด๋ ํ์ฑํ ํจ์๋ฅผ ์ฌ์ฉํ ํ๋์ ์ถ๋ ฅ ๋ด๋ฐ์ ๋๋ค.
๋ง์ฝ ๊ฐ๋ฅํ ํ๋์ด ๋ ๊ฐ๋ณด๋ค ๋ง์ผ๋ฉด ํ๋๋ง๋ค ํ๋์ ์ถ๋ ฅ ๋ด๋ฐ์ ๋๊ณ ์ํํธ๋งฅ์ค ํ์ฑํ ํจ์๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
18.5 ํ๋ ํ๊ฐ: ์ ์ฉ ํ ๋น ๋ฌธ์
๊ฐ ์คํ ์์ ๊ฐ์ฅ ์ข์ ํ๋์ด ๋ฌด์์ธ์ง ์๊ณ ์๋ค๋ฉด ํ์์ฒ๋ผ ์ถ์ ๋ ํ๋ฅ ๊ณผ ํ๊น ํ๋ฅ ์ฌ์ด์ ํฌ๋ก์ค ์ํธ๋กํผ๋ฅผ ์ต์ํํ๋๋ก ์ ๊ฒฝ๋ง์ ํ๋ จํ ์ ์๋ค.
์ผ๋ฐ์ ์ธ ์ง๋ ํ์ต๊ณผ ๊ฐ์ผ๋ ๊ฐํ ํ์ต์์ ์์ด์ ํธ๊ฐ ์ป์ ์ ์๋ ๊ฐ์ด๋๋ ๋ณด์๋ฟ์ด๋ค.
๋ณด์์ ์ผ๋ฐ์ ์ผ๋ก ๋๋ฌผ๊ณ ์ง์ฐ๋์ด ๋ํ๋๋ค.
์) ์์ด์ ํธ๊ฐ 100 ์คํ ๋์ ๋ง๋์ ๊ท ํ์ ์ ์งํ์ ๋ ์ฐ๋ฆฌ๊ฐ ์๋ ๊ฒ์ ๋ง์ง๋ง ํ๋ ๋ค์ ๋ง๋๊ฐ ์ฐ๋ ค์ก๋ค๋ ๊ฒ๋ฟ์ด๋ค.
์ด 100๋ฒ์ ํ๋ ์ค ์ด๋ ๊ฒ์ด ์ข๊ณ , ์ด๋ ๊ฒ์ด ๋์์ง ์ ์ ์๋ค.
์ ์ฉ ํ ๋น ๋ฌธ์ : ํ์ง๋ง ๋ชจ๋ ์ฑ ์์ด ๋ง์ง๋ง ํ๋์ ์๋ ๊ฒ์ ์๋๋ค.
์์ด์ ํธ๊ฐ ๋ณด์์ ๋ฐ์์ ๋ ์ด๋ค ํ๋ ๋๋ถ์ธ์ง ์๊ธฐ ์ด๋ ต๋ค.
→ ํ๋์ด ์ผ์ด๋ ํ ๊ฐ ๋จ๊ณ๋ง๋ค ํ ์ธ ๊ณ์ γ๋ฅผ ์ ์ฉํ ๋ณด์์ ๋ชจ๋ ํฉํ์ฌ ํ๋์ ํ๊ฐํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
ํ ์ธ๋ ๋ณด์์ ํฉ์ ํ๋์ ๋๊ฐ๋ผ๊ณ ํ๋ค.
ํ ์ธ ๊ณ์๊ฐ 0์ ๊ฐ๊น์ฐ๋ฉด ๋ฏธ๋์ ๋ณด์์ ํ์ฌ์ ๋ณด์๋งํผ ์ค์ํ๊ฒ ์ทจ๊ธ๋์ง ์์ ๊ฒ์ด๋ค.
๋ฐ๋๋ก ํ ์ธ ๊ณ์๊ฐ 1์ ๊ฐ๊น์ฐ๋ฉด ๋จผ ๋ฏธ๋์ ๋ณด์์ด ํ์ฌ์ ๋ณด์๋งํผ ์ค์ํ๊ฒ ๊ณ ๋ ค๋ ๊ฒ์ด๋ค.
์ ํ์ ์ธ ํ ์ธ ๊ณ์์ ๊ฐ์ 0.9์์ 0.99์ฌ์ด์ด๋ค.

ํ๋ ์ด์ต : ์ฐ๋ฆฌ๋ ํ๊ท ์ ์ผ๋ก ๋ค๋ฅธ ๊ฐ๋ฅํ ํ๋๊ณผ ๋น๊ตํด์ ๊ฐ ํ๋์ด ์ผ๋ง๋ ์ข์์ง ๋์์ง๋ฅผ ์ถ์ ํด์ผ ํ๋ค.
๋ง์ ์ํผ์๋๋ฅผ ์คํํ๊ณ ๋ชจ๋ ํ๋์ ๋๊ฐ๋ฅผ ์ ๊ทํํด์ผ ํ๋ค.
ํ๋ ์ด์ต์ด ์์์ธ ํ๋์ ๋์๊ณ , ์์์ธ ํ๋์ ์ข๋ค๊ณ ๊ฐ์ ํ ์ ์๋ค.
18.6 ์ ์ฑ ๊ทธ๋ ์ด๋์ธํธ
๋์ ๋ณด์์ ์ป๋ ๋ฐฉํฅ์ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ๋ฐ๋ฅด๋๋ก ์ ์ฑ ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ต์ ํํ๋ ์๊ณ ๋ฆฌ์ฆ์ด๋ค.
REINFORCEMENT ์๊ณ ๋ฆฌ์ฆ์ด ์ธ๊ธฐ ์๋ค.
1. ์ ๊ฒฝ๋ง ์ ์ฑ ์ด ์ฌ๋ฌ ๋ฒ์ ๊ฑธ์ณ ๊ฒ์์ ํ๋ ์ดํ๊ณ ๋งค ์คํ ๋ง๋ค ์ ํ๋ ํ๋์ด ๋ ๋์ ๊ฐ๋ฅ์ฑ์ ๊ฐ์ง๋๋ก ๋ง๋๋ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ๊ณ์ฐํ๋ค. ํ์ง๋ง ์์ง ์ด ๊ทธ๋ ์ด๋์ธํธ๋ฅด ์ ์ฉํ์ง๋ ์๋๋ค.
2. ์ํผ์๋๋ฅผ ๋ช ๋ฒ ์คํํ ๋ค์, ๊ฐ ํ๋์ ์ด์ต์ ๊ฒ์ฐํ๋ค.
3. ํ ํ๋์ ์ด์ต์ด ์์์ด๋ฉด ์ด ํ๋์ด ์ข์ ๊ฒ์์ ์๋ฏธํ๋ฏ๋ก ๋ฏธ๋์ ์ ํ๋ ๊ฐ๋ฅ์ฑ์ด ๋๋๋ก ์์ ๊ณ์ฐํ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ์ ์ฉํ๋ค. ๊ทธ๋ฌ๋ ํ๋ ์ด์ต์ด ์์์ด๋ฉด ์ด ํ๋์ด ๋์ ๊ฒ์์ ์๋ฏธํ๋ฏ๋ก ๋ฏธ๋์ ์ด ํ๋์ด ๋ ์ ํ๋๋๋ก ๋ฐ๋์ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ์ ์ฉํ๋ค. ์ด๋ ๊ฐ ๊ทธ๋ ์ด๋์ธํธ ๋ฒกํฐ์ ๊ทธ์ ์์ํ๋ ํ๋์ ์ด์ต์ ๊ณฑํ๋ฉด ๋๋ค.
4. ๋ง์ง๋ง์ผ๋ก ๋ชจ๋ ๊ฒฐ๊ณผ ๊ทธ๋ ์ด๋์ธํธ ๋ฒกํฐ๋ฅผ ํ๊ท ๋ด์ด ๊ฒฝ์ฌ ํ๊ฐ๋ฒ ์คํ ์ ์ํํ๋ค.
def play_one_step(env, obs, model, loss_fn): with tf.GradientTape() as tape: left_prova = model(obs[np.newaxis]) action = (tf.random.uniform([1, 1]) > left_proba) y_target = tf.constant([[1.]]) - tf.cast(action, tf.float32) loss = tf.reduce_mean(loss_fn(y_target, left_proba)) grads = tape.gradient(loss, model.trainable_variables) obs, reward, done, truncated, info = env.step(int(action)) return obs, reward, done, truncated, grads๋จผ์ ํ ์คํ ์ ์งํํ ํจ์๊ฐ ํ์ํ๋ค.
์ด๋ค ํ๋์ ์ ํํ๋๋ผ๋ ์์ค๊ณผ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด ์ณ์ ์ ํ์ด๋ผ๊ณ ๊ฐ์ ํ๋ค.
(์ด ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ์ ์ ๋์ ์ผ๋จ ์ ์ฅํ๋ค๊ฐ ์ด ํ๋์ด ์ข์์ง ๋์์ง ํ๋ช ๋ ํ์ ์กฐ์ ํ๋ค.)
GradientTape ๋ธ๋ก ์์์ ํ๋์ ๊ด์ธก๊ณผ ํจ๊ป ๋ชจ๋ธ์ ์ถ๋ ฅํ๋ค. ๋ชจ๋ธ์ ๋ฐฐ์น๋ฅผ ๊ธฐ๋ํ๋ฏ๋ก ํ๋์ ์ํ์ด ๋ค์ด ์๋ ๋ฐฐ์น๊ฐ ๋๋๋ก ๊ด์ธก์ ํฌ๊ธฐ๋ฅผ ๋ฐ๊พผ๋ค. ์ด ๋ชจ๋ธ์ ์ผ์ชฝ์ผ๋ก ์ด๋ํ ํ๋ฅ ์ ์ถ๋ ฅํ๋ค.
0์์ 1 ์ฌ์ด์ ๋๋คํ ์ค์๋ฅผ ์ํ๋งํ๊ณ ์ด ๊ฐ์ด left_proba๋ณด๋ค ํฐ์ง ํ์ธํ๋ค. action์ left_proba ํ๋ฅ ๋ก False๊ฐ ๋๊ณ 1 - left_proba ํ๋ฅ ๋ก True๊ฐ ๋๋ค. ์ด ๋ถ๋ฆฌ์ธ ๊ฐ์ ์ ์๋ก ๋ณํํ๋ฉด action์ ์ถ๋ ฅ๋ ํ๋ฅ ์ ๋ง๊ฒ 0(์ผ์ชฝ) ๋๋ 1(์ค๋ฅธ์ชฝ)์ด ๋๋ค.
์ผ์ชฝ์ผ๋ก ์ด๋ํ ํ๊น ํ๋ฅ ์ ์ ์ํ๋ค. ์ด ๊ฐ์ 1 - (์ค์๋ก ๋ณํ๋) ํ๋์ด๋ค. ํ๋์ด 0(์ผ์ชฝ)์ด๋ฉด ์ผ์ชฝ์ผ๋ก ์ด๋ํ ํ๊น ํ๋ฅ ์ 1์ด ๋๋ฉฐ, ํ๋์ด 1(์ค๋ฅธ์ชฝ)์ด๋ฉด ํ๊น ํ๋ฅ ์ด 0์ด ๋๋ค.
์ฃผ์ด์ง ์์ค ํจ์๋ฅผ ์ฌ์ฉํด ์์ค์ ๊ณ์ฐํ๊ณ ํ ์ดํ๋ฅผ ์ฌ์ฉํด ๋ชจ๋ธ์ ํ๋ จ ๊ฐ๋ฅํ ๋ณ์์ ๋ํ ์์ค์ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ๊ณ์ฐํ๋ค. ์ด ๊ทธ๋ ์ด๋์ธํธ๋ ๋์ค์ ์ ์ฉํ๊ธฐ ์ ์ ์ด ํ๋์ด ์ข์์ง ๋์์ง์ ๋ฐ๋ผ ์กฐ์ ๋ ๊ฒ์ด๋ค.
์ ํํ ํ๋์ ํ๋ ์ดํ๊ณ ์๋ก์ด ๊ด์ธก, ๋ณด์, ์ํผ์๋ ์ข ๋ฃ ์ฌ๋ถ, ์ํผ์๋ ์ค๋จ ์ฌ๋ถ, ๊ณ์ฐํ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ๋ฐํํ๋ค.
def play_multiple_episodes(env, n_episodes, n_max_steps, model, loss_fn): all_rewards = [] all_grads = [] for episode in range(n_episodes): current_rewards = [] current_grads = [] obs, info = env.reset() for step in range(n_max_steps): obs, reward, done, truncated, grads = play_one_step( env, obs, model, loss_fn) current_rewards.append(reward) current_grads.append(grads) if done or truncated: break all_rewards.append(current_rewards) all_grads.append(current_grads) return all_rewards, all_gradplay_one_step() ํจ์๋ฅผ ์ฌ์ฉํด ์ฌ๋ฌ ์ํผ์๋๋ฅผ ํ๋ ์ดํ๊ณ , ์ ์ฒด ๋ณด์ ๋ฐ ๊ฐ ์ํผ์๋์ ์คํ ์ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ๋ฐํํ๋ ํจ์์ด๋ค.
๋ณด์ ๋ฆฌ์คํธ์ ๋ฆฌ์คํธ(์ํผ์๋๋ง๋ค ๋ณด์ ๋ฆฌ์คํธ ํ๋, ์ด ๋ฆฌ์คํธ๋ ์คํ ๋ง๋ค ๋ณด์ ํ๋๋ฅผ ํฌํจํ๋ค.)์ ๊ทธ๋ ์ด๋์ธํธ ๋ฆฌ์คํธ์ ๋ฆฌ์คํธ(์ํผ์๋๋ง๋ค ๊ทธ๋ ์ด๋์ธํธ ๋ฆฌ์คํธ ํ๋, ์ด ๋ฆฌ์คํธ๋ ์คํ ๋ง๋ค ๊ทธ๋ ์ด๋์ธํธ ํํ์ ํ๋ ํฌํจํ๊ณ ๊ฐ ํํ์ ํ๋ จ ๊ฐ๋ฅํ ๋ณ์๋ง๋ค ๊ทธ๋ ์ด๋์ธํธ ํ ์ ํ๋๋ฅผ ํฌํจํ๋ค.)๋ฅผ ๋ฐํํ๋ค.
def discount_rewards(rewards, discount_factor): discounted = np.array(rewards) for step in range(len(rewards) -2, -1, -1): discounted[step] += discounted[step + 1] * discount_factor return discounted def discount_and_normalize_rewards(all_rewards, discount_factor): all_discounted_rewards = [discount_rewards(rewards, discount_factor) for rewards in all_rewards] flat_rewards = np.concatenate(all_discounted_rewards) reward_mean = flat_rewards.mean() reward_std = flat_rewards.std() return [(discounted_rewards - reward_nean) / reward_std for discounted_rewards in all_discounted_rewards]์ด ์๊ณ ๋ฆฌ์ฆ์ play_multiple_episodes() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ๋ฒ ๊ฒ์์ ํ๋ ์ดํ๋ค.
๊ทธ๋ค์ ์ฒ์๋ถํฐ ๋ชจ๋ ๋ณด์์ ์ดํด์ ๊ฐ ๋ณด์์ ํ ์ธํ๊ณ ์ ๊ทํํ๋ค.
์ฒซ ๋ฒ์งธ ํจ์๋ ๊ฐ ์คํ ์์ ํ ์ธ๋ ๋ฏธ๋ ๋ณด์์ ํฉ์ ๊ณ์ฐํ๋ค.
๋ ๋ฒ์งธ ํจ์๋ ์ฌ๋ฌ ์ํผ์๋์ ๊ฑธ์ณ ๊ณ์ฐ๋ ํ ์ธ๋ ๋ชจ๋ ๋ณด์(๋๊ฐ)์์ ํ๊ท ์ ๋นผ๊ณ ํ์ค ํธ์ฐจ๋ก ๋๋์ด ์ก๊ทํํ๋ค.
n_iterations = 150 n_episodes_per_update = 10 n_max_steps = 200 discount_factor = 0.95ํ์ดํผํ๋ผ๋ฏธํฐ๋ฅผ ์ ์ํ๋ค.
optimizer = tf.keras.optimizers.Nadam(learning_rate=0.01) loss_fn = tf.keras.losses.binary_crossentropy์ตํฐ๋ง์ด์ ์ ์์ค ํจ์๋ ํ์ํ๋ค.
for iteration in range(n_iterations): all_rewards, all_grads = play_multiple_episodes( env, n_episodes_per_update, n_max_steps, model, loss_fn) all_final_rewards = discount_and_normalize_rewards(all_rewards, discount_factor) all_mean_grads = [] for var_index in range(len(model, trainable_variables)): mean_grads = tf.reduce_mean( [final_reward * all_grads[episode_index][step][var_index] for episode_index, final_rewards in enumerate(all_final_rewards) for step, final_reward in enumerate(final_rewards)], axis=0) all_mean_grads.append(mean_grads) optimizer.apply_gradients(zip(all_mean_grads, model.trainable_variables))ํ๋ จ ๋ฐ๋ณต์ ๋ง๋ค์ด ์คํํ ์ค๋น๋ฅผ ํ๋ค.
๊ฐ ํ๋ จ ๋ฐ๋ณต์์ play_multiple_episodes() ํจ์๋ฅผ ํธ์ถํ๋ค.
discount_and_normalize_rewards() ํจ์๋ฅผ ํธ์ถํ์ฌ ๊ฐ ํ๋์ ์ ๊ทํ๋ ์ด์ต(final_reward)๋ฅผ ๊ณ์ฐํ๋ค. ์ด ๊ฐ์ ๊ฐ ํ๋์ด ์ค์ ๋ก ์ผ๋ง๋ ์ข์์ง ๋์์ง๋ฅผ ์๋ ค์ค๋ค.
ํ๋ จ ๊ฐ๋ฅํ ๋ณ์๋ฅผ ์ํํ๋ฉด์ ๋ชจ๋ ์ํผ์๋์ ๋ชจ๋ ์คํ ์ ๋ํ ๊ฐ ๋ณ์์ ๊ทธ๋ ์ด๋์ธํธ๋ฅผ final_reward๋ก ๊ฐ์ค์น๋ฅผ ๋์ด ํ๊ท ํ๋ค.
ํ๊ท ๊ทธ๋ ์ด๋์ธํธ๋ฅผ ์ตํฐ๋ง์ด์ ์ ์ ์ฉํ๋ค. ๋ชจ๋ธ์ ํ๋ จ ๊ฐ๋ฅํ ๋ณ์๊ฐ ๋ณ๊ฒฝ๋๊ณ ์๋ง ์ ์ฑ ์ด ์กฐ๊ธ ๋ ๋์์ง ๊ฒ์ด๋ค.
ํฌ๊ณ ๋ณต์กํ ๋ฌธ์ ์๋ ์ ์ ์ฉํ์ง ๋ชปํ๋ค.
์์ฃผ ๊ธด ์๊ฐ ๋์ ๊ฒ์์ ํ๋ ์ดํด์ผ ์ ์ฑ ์ ๋ง์ด ๊ฐ์ ํ ์ ์์ผ๋ฏ๋ก ์ํ ํจ์จ์ฑ์ด ๋งค์ฐ ์ข์ง ๋ชปํ๋ค.
๊ฐ ํ๋์ ์ด์ต์ ์ถ์ ํ๊ธฐ ์ํด ๋ง์ ์ํผ์๋๋ฅผ ์คํํด์ผ ํ๋ค.
์กํฐ-ํฌ๋ฆฌํฑ ์๊ณ ๋ฆฌ์ฆ ๊ฐ์ ๋ ๊ฐ๋ ฅํ ์๊ณ ๋ฆฌ์ฆ๋ ์๋ค.
18.7 ๋ง๋ฅด์ฝํ ๊ฒฐ์ ๊ณผ์
๋ง๋ฅด์ฝํ ์ฐ์ : ์ ํด์ง ๊ฐ์์ ์ํ๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ๊ฐ ์คํ ๋ง๋ค ํ ์ํ์์ ๋ค๋ฅธ ์ํ๋ก ๋๋คํ๊ฒ ์ ์ด๋๋ค.
์ํ s์์ ์ํ s'๋ก ์ ์ดํ๊ธฐ ์ํ ํ๋ฅ ์ ๊ณ ์ ๋์ด ์์ผ๋ฉฐ, ์์คํ ์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์์ผ๋ฏ๋ก ๊ณผ๊ฑฐ ์ํ์ ์๊ด์์ด (s, s') ์์๋ง ์์กดํ๋ค.
๋์ค๋ ๊ธธ์ด ์์ด์ ์์ํ ๊ทธ ์ํ์ ๋จ๊ฒ ๋๋ ์ํ๋ฅผ ์ข ๋ฃ ์ํ๋ผ๊ณ ํ๋ค.

๋ง๋ฅด์ฝํ ๊ฒฐ์ ๊ณผ์ : ๋ง๋ฅด์ฝํ ์ฐ์์ ๋น์ทํ์ง๋ง ์ฝ๊ฐ ๋ค๋ฅด๋ค.
๊ฐ ์คํ ์์ ์์ด์ ํธ๋ ์ฌ๋ฌ ๊ฐ๋ฅํ ํ๋ ์ค ํ๋๋ฅผ ์ ํํ ์ ์๊ณ , ์ ์ด ํ๋ฅ ์ ์ ํ๋ ํ๋์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค.
๋ํ ์ด๋ค ์ํ ์ ์ด๋ ๋ณด์(์์ ํน์ ์์)์ ๋ฐํํ๋ค.
์์ด์ ํธ์ ๋ชฉ์ ์ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ณด์์ ์ต๋ํํ๊ธฐ ์ํ ์ ์ฑ ์ ์ฐพ๋ ๊ฒ์ด๋ค.

์ต์ ์ ์ํ ๊ฐ์น V*(s) : ์์ด์ ํธ๊ฐ ์ํ s์ ๋๋ฌํ ํ ์ต์ ์ผ๋ก ํ๋ํ๋ค๊ณ ๊ฐ์ ํ๊ณ ํ๊ท ์ ์ผ๋ก ๊ธฐ๋ํ ์ ์๋ ํ ์ธ๋ ๋ฏธ๋ ๋ณด์์ ํฉ์ด๋ค.
์์ด์ ํธ๊ฐ ์ต์ ์ผ๋ก ํ๋ํ๋ฉด ๋ฒจ๋ง ์ต์ ๋ฐฉ์ ์์ด ์ ์ฉ๋๋ค๋ ๊ฒ์ ์ ์ฆํ๋ค.
์ด ์ฌ๊ท ์์ ์์ด์ ํธ๊ฐ ์ต์ ์ผ๋ก ํ๋ํ๋ฉด ํ์ฌ ์ํ์ ์ต์ ๊ฐ์น๋ ํ๋์ ์ต์ ํ๋์ผ๋ก ์ธํด ํ๊ท ์ ์ผ๋ก ๋ฐ๊ฒ ๋ ๋ณด์๊ณผ ์ด ํ๋์ด ์ ๋ฐํ ์ ์๋ ๊ฐ๋ฅํ ๋ชจ๋ ๋ค์ ์ํ์ ์ต์ ๊ฐ์น์ ๊ธฐ๋์น๋ฅผ ํฉํ ๊ฒ๊ณผ ๊ฐ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.

์๊ณ ๋ฆฌ์ฆ์ด ๊ฐ๋ฅํ ๋ชจ๋ ์ํ์ ๋ํ ์ต์ ์ ์ํ ๊ฐ์น๋ฅผ ์ ํํ ์ถ์ ํ ์ ์๋๋ก ๋์์ค๋ค.
๋จผ์ ๋ชจ๋ ์ํ ๊ฐ์น๋ฅผ 0์ผ๋ก ์ด๊ธฐํํ๋ค. ๊ทธ๋ฐ ๋ค์ ๊ฐ์น ๋ฐ๋ณต ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ ๋ฐ๋ณต์ ์ผ๋ก ์ ๋ฐ์ดํธํ๋ค.
[๊ฐ์น ๋ฐ๋ณต ์๊ณ ๋ฆฌ์ฆ]

V_k(s)๋ ์๊ณ ๋ฆฌ์ฆ์ k๋ฒ์งธ ๋ฐ๋ณต์์ ์ํ s์ ์ถ์ ๊ฐ์น์ด๋ค.
์ถฉ๋ถํ ์๊ฐ์ด ์ฃผ์ด์ง๋ฉด ์ด ์ถ์ ๊ฐ์ด ์ต์ ์ ์ ์ฑ ์ ๋์ํ๋ ์ต์ ์ ์ํ ๊ฐ์น์ ์๋ ดํ๋ ๊ฒ์ด ๋ณด์ฅ๋๋ค.
์ต์ ์ ์ํ ๊ฐ์น๋ฅผ ์๋ ๊ฒ์ ํนํ ์ ์ฑ ์ ํ๊ฐํ ๋ ์ ์ฉํ๋ค. ํ์ง๋ง ์์ด์ ํธ๋ฅผ ์ํ ์ต์ ์ ์ ์ฑ ์ ์๋ ค์ฃผ์ง๋ ์๋๋ค.
Q-๊ฐ์น๋ผ๊ณ ๋ถ๋ฅด๋ ์ต์ ์ ์ํ-ํ๋ ๊ฐ์น๋ฅผ ์ถ์ ํ ์ ์๋ ๋งค์ฐ ๋น์ทํ ์๊ณ ๋ฆฌ์ฆ์ด ๋ฐ๊ฒฌ๋์๋ค.
์ํ-ํ๋ (s, a) ์์ ๋ํ ์ต์ ์ Q-๊ฐ์น์ธ Q'(s, a)๋ ์์ด์ ํธ๊ฐ ์ํ s์ ๋๋ฌํด์ ํ๋ a๋ฅผ ์ ํํ ํ ์ด ํ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ ์ ์ ํ๊ท ์ ์ผ๋ก ๊ธฐ๋ํ ์ ์๋ ํ ์ธ๋ ๋ฏธ๋ ๋ณด์์ ํฉ์ด๋ค.
์์ด์ ํธ๋ ์ฌ๊ธฐ์ ์ด ํ๋ ์ดํ์ ์ต์ ์ผ๋ก ํ๋ํ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํ๋ค.
Q-๊ฐ์น์ ์ถ์ ์ ๋ชจ๋ 0์ผ๋ก ์ด๊ธฐํํ๋ค.
Q-๊ฐ์น ๋ฐ๋ณต ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํด ์ ๋ฐ์ดํธํ๋ค.
[Q-๊ฐ์น ๋ฐ๋ณต ์๊ณ ๋ฆฌ์ฆ]

์ต์ ์ Q-๊ฐ์น๋ฅผ ๊ตฌํ๊ณ ๋๋ฉด ์ต์ ์ ์ ์ฑ ์ธ π*(s)๋ฅผ ์ ์ํ๋ ๊ฒ์ ๊ฐ๋จํ๋ค.
์์ด์ ํธ๊ฐ ์ํ s์ ๋๋ฌํ์ ๋ ๊ฐ์ฅ ๋์ Q-๊ฐ์น๋ฅผ ๊ฐ์ง ํ๋์ ์ ํํ๋ฉด ๋๋ค.

transition_probabilities = [ # ํฌ๊ธฐ๋ [s, a, s'] [[0.7, 0.3, 0.0], [1.0, 0.0, 0.01, [0.8, 0.2, 0.0]], [[0.0, 1.0, 0.0], None, [0.0, 0.0, 1.0]], [None, [0.8, 0.1, 0.1], None] ] rewards = [ # ํฌ๊ธฐ๋ [s, a, s'] [[+10, 0, 0], [O, 0, 0], [0, 0, 0]], [[O, 0, 0], [0, 0, 0], [0, 0, -50]], [[O, 0, 01, [+40, 0, 0], [0, 0, 0]] ] possible_actions = [[O, 1, 2], [0, 2], [1]]์) ํ๋ a_1์ ํ๋ ์ดํ ํ s_2์์ s_0์ผ๋ก ์ ์ดํ ํ๋ฅ ์ ์๊ธฐ ์ํด์๋ transition_probabilities[2][1][0]์ ์ฐธ์กฐํ๋ค.
์ดํด ํด๋นํ๋ ๋ณด์์ ์ป์ผ๋ ค๋ฉด rewards[2][1][0]์ ์ฐธ์กฐํ๋ค.
s_2์์ ๊ฐ๋ฅํ ํ๋์ ๋ฆฌ์คํธ๋ฅผ ์ป์๋ฉด possible_actions[2]๋ฅผ ์ฐธ์กฐํ๋ค.
Q_values = np.full((3, 3), -np.inf) # ๋ถ๊ฐ๋ฅํ ํ๋์ ๋ํด์๋ -np.inf for state, actions in enumerate(possible_actions): Q_values[state, actions] = 0.0 # ๋ชจ๋ ๊ฐ๋ฅํ ํ๋์ ๋ํด์๊ทธ๋ค์ ๋ชจ๋ Q-๊ฐ์น๋ฅผ 0์ผ๋ก ์ด๊ธฐํํด์ผ ํ๋ค.
gamma = 0.90 # ํ ์ธ ๊ณ์ for iteration in range(50): Q_prev = Q_values.copy() for s in range(3): for a in possible_actions[s]: Q_values[s, a] = np.sum([ transition_probabilities[s][a][sp] * (rewards[s][a][sp] + gamma * Q_prev[sp].max()) for sp in range(3)])๋ชจ๋ ์ํ์ ๋ชจ๋ ๊ฐ๋ฅํ ํ๋์ ๋ํด ๋ชจ๋ Q-๊ฐ์น์ Q-๊ฐ์น ๋ฐ๋ณต ์๊ณ ๋ฆฌ์ฆ์ ๋ฐ๋ณต์ ์ผ๋ก ์ ์ฉํ๋ค.
Q_values # array ([[18.91891892, 17.02702702, 13.62162162], # [ 0. , -inf, -4.87971488], # [ -inf , 50.13365013, -inf]])์) ์์ด์ ํธ๊ฐ ์ํ s_0์ ์๊ณ ํ๋ a_1์ ์ ํํ์ ๋ ํ ์ธ๋ ๋ฏธ๋ ๋ณด์์ ๊ธฐ๋ ํฉ์ ์ฝ 17.0์ด๋ค.
np.argmax(Q_values, axis=1) # ๊ฐ ์ํ์ ๋ํด ์ต์ ์ ํ๋ # array([0, 0, 1])๊ฐ ์ํ์ ๋ํด ๊ฐ์ฅ ๋์ Q-๊ฐ์น๋ฅผ ๊ฐ๋ ํ๋์ด๋ค.
18.8 ์๊ฐ์ฐจ ํ์ต
๋ ๋ฆฝ์ ์ธ ํ๋์ผ๋ก ์ด๋ฃจ์ด์ง ๊ฐํ ํ์ต ๋ฌธ์ ๋ ๋ณดํต ๋ง๋ฅด์ฝํ ๊ฒฐ์ ๊ณผ์ ์ผ๋ก ๋ชจ๋ธ๋ง๋ ์ ์์ง๋ง ์ด๊ธฐ์ ์์ด์ ํธ๋ ์ ์ด ํ๋ฅ ์ ๋ํด ์์ง ๋ชปํ๋ฉฐ(T(s, a, s')๋ฅผ ๋ชจ๋ฅธ๋ค.), ๋ณด์์ด ์ผ๋ง๋ ๋๋์ง๋ ์์ง ๋ชปํ๋ค.(R(s, a, s')๋ฅผ ๋ชจ๋ฅธ๋ค.)
๋ณด์์ ๋ํด ์๊ธฐ ์ํด์๋ ์ ์ด๋ ํ ๋ฒ์ ๊ฐ ์ํ์ ์ ์ด๋ฅผ ๊ฒฝํํด์ผ ํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ ์ด ํ๋ฅ ์ ๋ํด ์ ๋ขฐํ ๋งํ ์ถ์ ์ ์ป์ผ๋ ค๋ฉด ์ฌ๋ฌ ๋ฒ ๊ฒฝํ์ ํด์ผ ํ๋ค.
์๊ฐ์ฐจ ํ์ต(TD ํ์ต) : Q-๊ฐ์น ๋ฐ๋ณต ์๊ณ ๋ฆฌ์ฆ๊ณผ ๋งค์ฐ ๋น์ทํ์ง๋ง ์์ด์ ํธ๊ฐ MDP์ ๋ํด ์ผ๋ถ ์ ๋ณด๋ง ์๊ณ ์์ ๋๋ฅผ ๋ค๋ฃฐ ์ ์๋๋ก ๋ณํํ ๊ฒ์ด๋ค.
์ผ๋ฐ์ ์ผ๋ก ์์ด์ ํธ๊ฐ ์ด๊ธฐ์ ๊ฐ๋ฅํ ์ํ์ ํ๋๋ง ์๊ณ ๋ค๋ฅธ ๊ฒ์ ๋ชจ๋ฅธ๋ค๊ณ ๊ฐ์ ํ๋ค.
์์ด์ ํธ๋ ํํ ์ ์ฑ ์ ์ฌ์ฉํด MDP๋ฅผ ํํํ๋ค.
ํํ์ด ์งํ๋ ์๋ก TD ํ์ต ์๊ณ ๋ฆฌ์ฆ์ด ์ค์ ๋ก ๊ด์ธก๋ ์ ์ด์ ๋ณด์์ ๊ทผ๊ฑฐํ์ฌ ์ํ ๊ฐ์น์ ์ถ์ ๊ฐ์ ์ ๋ฐ์ดํธํ๋ค.
[TD ํ์ต ์๊ณ ๋ฆฌ์ฆ]



์ด ์์ ์ฒซ ๋ฒ์งธ ํํ๋ฅผ ๋ ๊ฐ๋จํ ์ฐ๋ ๋ฐฉ๋ฒ์

ํ๊ธฐ๋ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.

๋ฅผ ์๋ฏธํ๋ค.
↓

๊ฐ ์ํ s์์ ์ด ์๊ณ ๋ฆฌ์ฆ์ ์์ด์ ํธ๊ฐ ํด๋น ์ํ๋ฅผ ๋ ๋ฌ์ ๋ ์ป์ ์ ์๋ ๋น์ฅ์ ๋ณด์๊ณผ(์ต์ ์ผ๋ก ํ๋ํ๋ค๊ณ ๊ฐ์ ํ์ฌ) ๋์ค์ ๊ธฐ๋ํ ์ ์๋ ๋ณด์์ ๋ํ ์ด๋ ํ๊ท ์ ์ ์ฅํ๋ค.
18.9 Q-๋ฌ๋
Q-๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ ์ด ํ๋ฅ ๊ณผ ๋ณด์์ ์ด๊ธฐ์ ์์ง ๋ชปํ ์ํฉ์์ Q-๊ฐ์น ๋ฐ๋ณต ์๊ณ ๋ฆฌ์ฆ์ ์ ์ฉํ ๊ฒ์ด๋ค.
Q-๋ฌ๋์ ์์ด์ ํธ๊ฐ ํ๋ ์ดํ๋ ๊ฒ์ ๋ณด๊ณ ์ ์ง์ ์ผ๋ก Q-๊ฐ์น ์ถ์ ์ ํฅ์ํ๋ ๋ฐฉ์์ผ๋ก ์๋ํ๋ค.
์ ํํ(์ถฉ๋ถํ ๊ทผ์ ํ) Q-๊ฐ์น ์ถ์ ์ ์ป๊ฒ ๋๋ฉด ์ต์ ์ ์ ์ฑ ์ ๊ฐ์ฅ ๋์ Q-๊ฐ์น๋ฅผ ๊ฐ์ง๋ ํ๋์ ์ ํํ๋ค. (ํ์์ ์ ์ฑ )
[Q-๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ]

๊ฐ ์ํ-ํ๋ (s, a) ์๋ง๋ค ์ด ์๊ณ ๋ฆฌ์ฆ์ด ํ๋ a๋ฅผ ์ ํํด ์ํ s๋ฅผ ๋ ๋ฌ์ ๋ ์์ด์ ํธ๊ฐ ๋ฐ์ ์ ์๋ ๋ณด์ r๊ณผ ๊ธฐ๋ํ ์ ์๋ ํ ์ธ๋ ๋ฏธ๋ ๋ณด์์ ํฉ์ ๋ํ ์ด๋ ํ๊ท ์ ์ ์ฅํ๋ค.
๋ฏธ๋ ๋ณด์์ ํฉ์ ์ถ์ ํ๊ธฐ ์ํด์๋ ํ๊น ์ ์ฑ ์ด ์ดํ๋ก ์ต์ ์ผ๋ก ํ๋ํ๋ค๊ณ ๊ฐ์ ํ๊ณ ๋ค์ ์ํ s'์ ๋ํ Q-๊ฐ์น ์ถ์ ์ ์ต๋๊ฐ์ ์ ํํ๋ค.
def step(state, action): probas = transition_probabilities[state][action] next_state = np.random.choice([0, 1, 2], p=probas) reward = rewards[state][action][next_state] return next_state, reward๋จผ์ ์์ด์ ํธ๊ฐ ํ๊ฒฝ์ ํ์ํ๊ฒ ๋ง๋ค์ด์ผ ํ๋ค.
์ด๋ฅผ ์ํด ์์ด์ ํธ๊ฐ ํ ํ๋์ ์คํํ๊ณ ๊ฒฐ๊ณผ ์ํ์ ๋ณด์์ ๋ฐ์ ์ ์๋ ์คํ ํจ์๊ฐ ํ์ํ๋ค.
def exploration_policy(state): return np.random.choice(possible_actions[state])์ด ์ํ ๊ณต๊ฐ์ ๋งค์ฐ ์๊ธฐ ๋๋ฌธ์ ๋จ์ํ ๋๋ค ์ ์ฑ ์ผ๋ก ์ถฉ๋ถํ๋ค.
์๊ณ ๋ฆฌ์ฆ์ ์ถฉ๋ถํ ์ค๋ซ๋์ ์คํํ๋ฉด ์์ด์ ํธ๊ฐ ๊ฐ ์ํ๋ฅผ ์ฌ๋ฌ ๋ฒ ๋ฐฉ๋ฌธํ๊ณ ๊ฐ๋ฅํ ๋ชจ๋ ํ๋์ ์ฌ๋ฌ ๋ฒ ์คํํ ์ ์๋ค.
alpha0 = 0.05 # ์ด๊ธฐ ํ์ต๋ฅ decay = 0.005 # ํ์ต๋ฅ ๊ฐ์ gamma = 0.90 # ํ ์ธ ๊ณ์ state = 0 # ์ด๊ธฐ ์ํ for iteration in range(10_000): action = exploration_policy(state) next_state, reward = step(state, action) next_value = Q_values[next_state].max() # ๋ค์ ์คํ ์์ ํ์์ ์ ์ฑ alpha = alpha0 / (1 + iteration * decay) Q_values[state, action] *= 1 - alpha Q_values[state, action] += alpha * (reward + gamma * next_value) state = next_stateQ-๊ฐ์น๋ฅผ ์ด๊ธฐํํ ํ ํ์ต๋ฅ ๊ฐ์ (๊ฑฐ๋ญ์ ๊ณฑ ๊ธฐ๋ฐ ์ค์ผ์ค๋ง)๋ฅผ ์ฌ์ฉํด Q-๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ์ ์คํํ๋ค.
์ต์ ์ Q-๊ฐ์น์ ์๋ ดํ๊ฒ ์ง๋ง ๋ง์ ๋ฐ๋ณต๊ณผ ํ์ดํผํ๋ผ๋ฏธํฐ ํ๋์ด ํ์ํ๋ค.

Q-๊ฐ์น ๋ฐ๋ณต ์๊ณ ๋ฆฌ์ฆ(์ผ์ชฝ)๊ณผ Q-๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ(์ค๋ฅธ์ชฝ) ํ๋ จ๋ ์ ์ฑ ์ ํ๋ จ ์ค์ ๋ฐ๋์ ์ฌ์ฉํ๋ ๊ฒ์ ์๋๋ค. (์คํ-ํด๋ฆฌ์ ์๊ณ ๋ฆฌ์ฆ)
์) ์์ ์ฝ๋์์ ์คํ๋ ์ ์ฑ (ํํ ์ ์ฑ )์ ์์ ํ ๋๋คํ ์ ์ฑ ์ด๋ฉฐ ํ๋ จ๋ ์ ์ฑ ์ ์ ํ ์ฌ์ฉ๋์ง ์๋๋ค.)
์ต์ ์ ์ ์ฑ ์ ํญ์ ๊ฐ์ฅ ๋์ Q-๊ฐ์น๋ฅผ ๊ฐ์ง ํ๋์ ์ ํํ๋ ๊ฒ์ด๋ค.
๋ฐ๋๋ก ์ ์ฑ ๊ทธ๋ ์ด๋์ธํธ ์๊ณ ๋ฆฌ์ฆ์ ์จ-ํด๋ฆฌ์ ์๊ณ ๋ฆฌ์ฆ์ด๋ค.
ํ๋ จ๋ ์ ์ฑ ์ ์ฌ์ฉํด ํ๊ฒฝ์ ํํํ๋ค.
18.9.1 ํํ ์ ์ฑ
Q-๋ฌ๋์ ํํ ์ ์ฑ ์ด MDP๋ฅผ ์ถฉ๋ถํ ํํํด์ผ ์๋ํ๋ค.
์์ ํ ๋๋ค ์ ์ฑ ์ด ๊ฒฐ๊ตญ์๋ ๋ชจ๋ ์ํ์ ์ ์ด๋ฅผ ์ฌ๋ฌ ๋ฒ ๊ฒฝํํ๋๋ก ๋ณด์ฅํ์ง๋ง ์ด๋ ๊ฒ ํ๋ ค๋ฉด ๊ทน๋จ์ ์ผ๋ก ์ค๋ ์๊ฐ์ด ๊ฑธ๋ฆด ์ ์๋ค.
๋ ๋์ ๋ฐฉ๋ฒ์ ε-๊ทธ๋ฆฌ๋ ์ ์ฑ ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
๊ฐ ์คํ ์์ ε ํ๋ฅ ๋ก ๋๋คํ๊ฒ ํ๋ํ๊ฑฐ๋ 1 - ε ํ๋ฅ ๋ก ๊ทธ ์๊ฐ ๊ฐ์ฅ ์ต์ ์ธ ๊ฒ์ผ๋ก(๊ฐ์ฅ ๋์ Q-๊ฐ์น๋ฅผ ์ ํํ์ฌ) ํ๋ํ๋ค.
์์ ํ ๋๋ค ์ ์ฑ ์ ๋นํด Q-๊ฐ์ ์ถ์ ์ด ์ ์ ๋ ํฅ์๋๊ธฐ ๋๋ฌธ์ ํ๊ฒฝ์์ ๊ด์ฌ ์๋ ๋ถ๋ถ์ ์ดํผ๋ ๋ฐ ์ ์ ๋ ๋ง์ ์๊ฐ์ ์ฌ์ฉํ ์ ์๋ค.
๊ทธ๋ผ์๋ ์ฌ์ ํ MDP์ ์๋ ค์ง์ง ์์ ์ง์ญ์ ๋ฐฉ๋ฌธํ๋ ๋ฐ ์ผ์ ์๊ฐ์ ์ฌ์ฉํ ๊ฒ์ด๋ค.
์ด ์ธ์๋ ํํ์ ๊ฐ๋ฅ์ฑ์ ์์กดํ๋ ๋์ ์ด์ ์ ๋ง์ด ํ์ง ์์๋ ํ๋์ ์๋ํ๋๋ก ํํ ์ ์ฑ ์ ๊ฐ์กฐํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
์ด๋ฐ ๋ฐฉ์์ Q-๊ฐ์น ์ถ์ ์ ๋ณด๋์ค๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํ๋๋ค.
[ํํ ํจ์๋ฅผ ์ฌ์ฉํ Q-๋ฌ๋

18.9.2 ๊ทผ์ฌ Q-๋ฌ๋๊ณผ ์ฌ์ธต Q-๋ฌ๋
Q-๋ฌ๋์ ์ฃผ์ ๋ฌธ์ ๋ ๋ง์ ์ํ์ ํ๋์ ๊ฐ์ง ๋๊ท๋ชจ์ MDP์ ์ ์ฉํ๊ธฐ ์ด๋ ต๋ค๋ ๊ฒ์ด๋ค.
→ ์ด๋ค ์ํ-ํ๋ (s, a) ์์ Q-๊ฐ์น๋ฅผ ๊ทผ์ฌํ๋ ํจ์ Q_θ(s, a)๋ฅผ ์ ์ ํ ๊ฐ์์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฐพ๋ ๊ฒ์ด๋ค. (๊ทผ์ฌ Q-๋ฌ๋)
์ฌ์ธต Q-๋คํธ์ํฌ(DQN) : Q-๊ฐ์น๋ฅผ ์ถ์ ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ DNN
์ฌ์ธต Q-๋ฌ๋ : ๊ทผ์ฌ Q-๋ฌ๋์ ์ํด DQN์ ์ฌ์ฉํ๋ ๊ฒ
์ฃผ์ด์ง ์ํ-ํ๋ ์ (s, a)์ ๋ํด DQN์ด ๊ณ์ฐํ ๊ทผ์ฌ Q-๊ฐ์น๋ฅผ ์๊ฐํด๋ณด๊ฒ ๋ค.
๋ฒจ๋ง ์ ๋๋ถ์ด ์ด ๊ทผ์ฌ Q-๊ฐ์น๋ ์ํ s์์ ํ๋ a๋ฅผ ์คํํ์ ๋ ๊ด์ธก๋ ๋ณด์ r๊ณผ ๊ทธ ์ดํ์ ์ต์ ์ผ๋ก ํ๋ํด์ ์ป์ ํ ์ธ๋ ๊ฐ์น๋ฅผ ๋ํ ๊ฐ์ ๊ฐ๋ฅํ ํ ๊ฐ๊น์์ผ ํ๋ค.
์ด ๋ฏธ๋์ ํ ์ธ๋ ๊ฐ์น๋ฅผ ์ถ์ ํ๊ธฐ ์ํด์๋ ๊ฐ๋จํ๊ฒ ๋ค์ ์ํ s'์ ๋ชจ๋ ๊ฐ๋ฅํ ํ๋ a'์ ๋ํด DQN์ ์คํํ๋ฉด ๋๋ค.
๊ทธ๋ผ ๋ชจ๋ ๊ฐ๋ฅํ ํ๋์ ๋ํ ๋ฏธ๋์ ๊ทผ์ฌ Q-๊ฐ์น๋ฅผ ์ป์ ์ ์๋ค.
๊ทธ๋ค์ ๊ทผ์ฌ Q-๊ฐ์น๊ฐ ๊ฐ์ฅ ๋์ ๊ฒ์ ๊ณ ๋ฅด๊ณ ํ ์ธ์ ์ ์ฉํ๋ฉด ํ ์ธ๋ ๋ฏธ๋ ๋ณด์์ ์ถ์ ์ ์ป์ ์ ์๋ค.
๋ณด์ r๊ณผ ๋ฏธ๋์ ํ ์ธ๋ ๊ฐ์น ์ถ์ ์ ๋ํ๋ฉด ์ํ-ํ๋ ์ (s, a)์ ๋ํ ํ๊น Q-๊ฐ์น y(s, a)๋ฅผ ์ป๊ฒ ๋๋ค.

์ด ํ๊น Q-๊ฐ์น๋ก ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ ์ฌ์ฉํด ํ๋ จ ๋จ๊ณ๋ฅผ ์ํํ ์ ์๋ค.
์ถ์ ๋ Q-๊ฐ์น Q(s, a)์ ํ๊น Q-๊ฐ์น y(s, a) ์ฌ์ด์ ์ ๊ณฑ ์ค์ฐจ๋ฅผ ์ต์ํํ๋ค.
๋๋ ์๊ณ ๋ฆฌ์ฆ์ด ํฐ ์ค์ฐจ์ ๋ฏผ๊ฐํ์ง ์๋๋ก ํ๋ฒ ์์ค์ ์ฌ์ฉํ๋ค.
18.10 ์ฌ์ธต Q-๋ฌ๋ ๊ตฌํ
์ฒซ ๋ฒ์งธ๋ก ํ์ํ ๊ฒ์ ์ฌ์ธต Q-๋คํธ์ํฌ์ด๋ค.
์ด๋ก ์ ์ผ๋ก๋ ์ํ-ํ๋ ์์ ์ ๋ ฅ์ผ๋ก ๋ฐ๊ณ ๊ทผ์ฌ Q-๊ฐ์น๋ฅผ ์ถ๋ ฅํ๋ ์ ๊ฒฝ๋ง์ด ํ์ํ๋ค.
ํ์ง๋ง ์ค์ ์์๋ ์ํ๋ง ์ ๋ ฅ์ผ๋ก ๋ฐ๊ณ ๊ฐ๋ฅํ ๋ชจ๋ ํ๋์ ๋ํ ๊ทผ์ฌ Q-๊ฐ์น๋ฅผ ๊ฐ๊ฐ ์ถ๋ ฅํ๋ ๊ฒ์ด ํจ์ฌ ํจ์จ์ ์ด๋ค.
input_shape = [4] # == env.observation_space.shape n_outputs = 2 # == env.action_space.n model = tf.keras.Sequential([ tf.keras.layers.Dense(32, activation="elu", input_shape=input_shape), tf.keras.layers.dense(32, activation="elu") tf.keras.layers.Dense(n_outputs) ])def epsilon_greedy_policy(state, epsilon=0): if np.random.rand() < epsilon: return np.random.randint(n_outputs) # ๋๋ค ํ๋ else: Q_values = model.predict(state[np.newaxis], verbose=0)[0] return Q_values.argmax() # DQN์ ๋ฐ๋ฅธ ์ต์ ์ ํ๋์ด DQN์ผ๋ก ํ๋์ ์ ํํ๋ ค๋ฉด ์์ธก Q-๊ฐ์น๊ฐ ๊ฐ์ฅ ํฐ ํ๋์ ์ ํํ๋ค.
์์ด์ ํธ๊ฐ ํ๊ฒฝ์ ํํํ๋๋ก ๋ง๋ค๊ธฐ ์ํด ε-๊ทธ๋ฆฌ๋ ์ ์ฑ ์ ์ฌ์ฉํ๋ค. (์ฆ, ํ๋ฅ ε๋งํผ ๋๋คํ ํ๋์ ์ ํํ๋ค.)
from collections import deque replay_buffer = deque(maxlen=2000)์ต๊ทผ์ ๊ฒฝํ์๋ง ์์งํ์ฌ DQN์ ํ๋ จํ๋ ๋์ ์ฌ์ ๋ฒํผ(์ฌ์ ๋ฉ๋ชจ๋ฆฌ)์ ๋ชจ๋ ๊ฒฝํ์ ์ ์ฅํ๊ณ ํ๋ จ ๋ฐ๋ณต๋ง๋ค ์ฌ๊ธฐ์์ ๋๋คํ ํ๋ จ ๋ฐฐ์น๋ฅผ ์ํ๋งํ ์ ์๋ค. ๊ฒฝํ๊ณผ ํ๋ จ ๋ฐฐ์น ์ฌ์ด์ ์๊ด๊ด๊ณ๊ฐ ์ค์ด๋ค์ด ํ๋ จ์ ๋์์ด ๋๋ค.
์ด๋ฅผ ์ํด ๋ฑ์ ์ฌ์ฉํ๋ค.
def sample_experiences(batch_size): indices = np.random.randint(len(replay_buffer), size=batch_size) batch = [replay_buffer[index] for index in indices] return [ np.array([experience[field_index] for experience in batch]) for field_index in range(6) ] # [states, actions, rewards, next_states, dones, truncateds]๊ฐ ๊ฒฝํ์ ์์ 6๊ฐ๋ก ๊ตฌ์ฑ๋๋ค.
์ํ s, ์์ด์ ํธ๊ฐ ์ ํํ ํ๋ a, ๊ฒฐ๊ณผ ๋ณด์ r, ๋๋ฌํ ๋ค์ ์ํ s', ์ํผ์๋๊ฐ ์ด๋ ์ข ๋ฃ๋์๋์ง ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ๋ถ๋ฆฌ์ธ ๊ฐ(done), ๋ง์ง๋ง์ผ๋ก ์ํผ์๋๊ฐ ์ค๋จ๋์๋์ง ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ๋ถ๋ฆฌ์ธ ๊ฐ(truncated)์ด๋ค.
์ฌ์ ๋ฒํผ์์ ๊ฒฝํ์ ๋๋คํ๊ฒ ์ํ๋งํ๊ธฐ ์ํด ์์ ํจ์๋ฅผ ๋ง๋ ๋ค.
์ด ํจ์๋ ๊ฒฝํ ์์ 6๊ฐ์ ์์ํ๋ ๋ํ์ด ๋ฐฐ์ด 6๊ฐ๋ฅผ ๋ฐํํ๋ค.
def play_one_step(env, state, epsilon): action = epsilon_greedy_policy(state, epsilon) next_state, reward, done, truncated, info = env.step(action) replay_buffer.append((state, action, reward, next_state, done, truncated)) return next_state, reward, done, truncated, infoε-๊ทธ๋ฆฌ๋ ์ ์ฑ ์ ์ฌ์ฉํด ํ๋์ ์คํ ์ ํ๋ ์ดํ๊ณ ๋ฐํ๋ ๊ฒฝํ์ ์ฌ์ ๋ฒํผ์ ์ ์ฅํ๋ค.
batch_size = 32 discount_factor = 0.95 optimizer = tf.keras.optimizers.Nadam(learning_rate=1e-2) loss_fn = tf.keras.losses.mean_squared_error def training_step(batch_size): experiences = sample_experiences(batch_size) states, actions, rewards, next_states, dones, truncateds = experiences next_Q_values = next_Q_values.max(axis=0) max_next_Q_values = next_Q_values.max(axis=1) runs = 1.0 - (dones | truncateds) # ์ํผ์๋๊ฐ ์ค์ง๋๊ฑฐ๋ ์ข ๋ฃ๋์ง ์์ target_Q_values = rewards + runs * discount_factor * max_next_Q_values target_Q_values = target_Q_values.reshape(-1, 1) nask = tf.one_hot(actions, n_outputs) with tf.GradientTape() as tape: all_Q_values = model(states) Q_values = tf.reduce_sum(all_Q_values * mask, axis=1, keepdims=True) loss = tf.reduce_mean(loss_fn(target_Q_values, Q_values)) grads = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables))์ฌ์ ๋ฒํผ์์ ๊ฒฝํ ๋ฐฐ์น๋ฅผ ์ํ๋งํ๊ณ ์ด ๋ฐฐ์น์์ ๊ฒฝ์ฌ ํ๊ฐ๋ฒ ํ ์คํ ์ ์ํํ์ฌ DQN์ ํ๋ จํ๋ ํจ์์ด๋ค.
ํ์ดํผํ๋ผ๋ฏธํฐ ๋ช ๊ฐ๋ฅผ ์ ์ํ๊ณ ์ตํฐ๋ง์ด์ ์ ์์ค ํจ์๋ฅผ ๋ง๋ ๋ค.
training_step() ํจ์๋ฅผ ๋ง๋ ๋ค. ์ด ํจ์๋ ๊ฒฝํ ๋ฐฐ์น๋ฅผ ์ํ๋งํ ๋ค์ DQN์ ์ฌ์ฉํ์ฌ ๊ฐ ๊ฒฝํ์ ๋ค์ ์ํ์์ ๊ฐ๋ฅํ ๋ชจ๋ ํ๋์ ๋ํ Q-๊ฐ์น๋ฅผ ์์ธกํ๋ค. ์์ด์ ํธ๊ฐ ์ต์ ์ผ๋ก ํ๋ ์ดํ๋ค๊ณ ๊ฐ์ ํ๋ฏ๋ก ๋ค์ ์ํ์ ๋ํ ์ต๋ Q-๊ฐ์น๋ง ์ ์ฅํ๋ค. ๊ทธ๋ค์ ํ๊น Q-๊ฐ์น ์์ ์ฌ์ฉํด ๊ฐ ๊ฒฝํ์ ์ํ-ํ๋ ์์ ๋ํ ํ๊น Q-๊ฐ์น๋ฅผ ๊ณ์ฐํ๋ค.
DQN์ด ๊ฒฝํํ ๊ฐ ์ํ-ํ๋ ์์ Q-๊ฐ์น๋ฅผ ๊ณ์ฐํ๊ธธ ์ํ๋ค. ํ์ง๋ง ์ด DQN์ ์์ด์ ํธ๊ฐ ์ค์ ๋ก ์ ํํ ํ๋๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ๊ฐ๋ฅํ ํ๋์ ๋ํ Q-๊ฐ์น๋ ์ถ๋ ฅํ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ํ์ํ์ง ์์ ๋ชจ๋ Q-๊ฐ์น๋ฅผ ๋ง์คํฌ ์ฒ๋ฆฌํด์ผ ํ๋ค. tf.one_hot() ํจ์๋ ํ๋ ์ธ๋ฑ์ค์ ๋ฐฐ์ด์ ๋ง์คํฌ๋ก ๋ณํํด์ค๋ค. ์) ์ฒ์ 3๊ฐ์ ๊ฒฝํ์ด ํ๋ 1, 1, 0์ ๊ฐ๊ฐ ๋ด๊ณ ์๋ค๋ฉด ๋ง์คํฌ๋ [[0, 1], [0, 1], [1, 0], ...]๊ณผ ๊ฐ๋ค. ์ด ๋ง์คํฌ๋ฅผ DQN์ ์ถ๋ ฅ๊ณผ ๊ณฑํ์ฌ ์ํ์ง ์์ Q-๊ฐ์น๋ฅผ 0์ผ๋ก ๋ง๋ค ์ ์๋ค. ๊ทธ๋ค์ 0์ ์์ ๊ธฐ ์ํด ์ด(axis=1) ๋ฐฉํฅ์ผ๋ก ๋ง์ ํ์ฌ ๊ฒฝํ๋ ์ํ-ํ๋ ์์ Q-๊ฐ์น๋ง ๋จ๊ธด๋ค. ๊ฒฐ๊ตญ ๋ฐฐ์น์ ์๋ ๊ฐ ๊ฒฝํ์ ๋ํด ์์ธก๋ Q-๊ฐ์น ํ๋๋ฅผ ๋ด์ ํ ์์ธ Q-values๋ฅผ ์ป๋๋ค.
์์ค์ ๊ณ์ฐํ๋ค. ์์ค์ ๊ฒฝํ๋ ์ํ-ํ๋ ์์ ๋ํ ํ๊น๊ณผ ์์ธก๋ Q-๊ฐ์น ์ฌ์ด์ ํ๊ท ์ ๊ณฑ ์ค์ฐจ์ด๋ค.
๋ชจ๋ธ์ ํ๋ จ ๊ฐ๋ฅํ ๋ณ์์ ๊ดํ ์์ค์ ์ต์ํํ๊ธฐ ์ํด ๊ฒฝ์ฌ ํ๊ฐ๋ฒ์ ์ํํ๋ค.
for episode in range(600): obs, info = env.reset)_ for step in range(200): epsilon = max(1 - episode / 500, 0.01) obs, reward, done, truncated, info = play_one_step(env, obs, epsilon) if done or truncated: break if episode > 50: training_step(batch_size)์ต๋ ์คํ 200๋ฒ์ผ๋ก ์ด๋ฃจ์ด์ง ์ํผ์๋ 600๊ฐ๋ฅผ ์คํํ๋ค.
๊ฐ ์คํ ์์ ๋จผ์ ε-๊ทธ๋ฆฌ๋ ์ ์ฑ ์ ๋ํ epsilon ๊ฐ์ ๊ณ์ฐํ๋ค.
์ด ๊ฐ์ 500 ์ํผ์๋ ์ง์ ๊น์ง 1์์ 0.01๋ก ์ ํ์ ์ผ๋ก ์ค์ด๋ ๋ค.
๊ทธ๋ค์ play_one_step() ํจ์๋ฅผ ํธ์ถํ๋ค. ์ด ํจ์๋ ε-๊ทธ๋ฆฌ๋ ์ ์ฑ ์ ์ฌ์ฉํด ํ๋์ ์ ํํ์ฌ ์คํํ๊ณ ๊ทธ ๊ฒฝํ์ ์ฌ์ ๋ฒํผ์ ๊ธฐ๋กํ๋ค.
์ํผ์๋๊ฐ ์ข ๋ฃ๋๊ฑฐ๋ ์ค๋จ๋๋ฉด ๋ฐ๋ณต์ ๋๋ธ๋ค.
๋ง์ง๋ง์ผ๋ก 50 ์ํผ์๋ ์ดํ์๋ training_step() ํจ์๋ฅผ ํธ์ถํด ์ฌ์ ๋ฒํผ์์ ์ํ๋งํ ๋ฐฐ์น๋ก ๋ชจ๋ธ์ ํ๋ จํ๋ค.
ํ๋ จ ์์ด ์ํผ์๋๋ฅผ 50๋ฒ ํ๋ ์ดํ๋ ์ด์ ๋ ์ฌ์ ๋ฒํผ๊ฐ ์ฑ์์ง ์๊ฐ์ ์ฃผ๊ธฐ ์ํด์์ด๋ค.

์ต๋ ๋ณด์ ๊ทผ์ฒ์์ ์์ ๋ ๊ฒ์ฒ๋ผ ๋ณด์์ผ๋ ์ ์๊ฐ ๊ธ๊ฒฉํ ๋จ์ด์ง๋ ๊ฑธ ์ต์ ์ ๋ง๊ฐ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์์ด์ ํธ๊ฐ ํ๊ฒฝ์ ํ์ํ๋ฉด ์ ์ฑ ์ ์ ๋ฐ์ดํธํ๋ค. ํ์ง๋ง ํ๊ฒฝ์ ํ ๋ถ๋ถ์์ ํ์ตํ ๊ฒ์ด ์์ ๋ค๋ฅธ ๋ถ๋ถ์์ ํ์ตํ ๊ฒ์ ๋ง๊ฐ๋จ๋ฆด ์ ์๋ค. ๊ฒฝํ์ ํฌ๊ฒ ์ฐ๊ด๋๋ฉฐ ํ์ต ํ๊ฒฝ์ ๊ณ์ ๋ฐ๋๋ค.
18.11 ์ฌ์ธต Q-๋ฌ๋์ ๋ณํ
18.11.1 ๊ณ ์ Q-๊ฐ์น ํ๊น
๊ธฐ๋ณธ ์ฌ์ธต Q-๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ์์ ๋ชจ๋ธ์ ์์ธก์ ๋ง๋ค๊ณ ํ๊น์ ์ค์ ํ๋ ๋ฐ ๋ชจ๋ ์ฌ์ฉ๋๋ค.
์ด๋ฐ ํผ๋๋ฐฑ ์ํ ๊ณผ์ ์ ๋คํธ์ํฌ๋ฅผ ๋ถ์์ ํ๊ฒ ๋ง๋ค์ด ๋ฐ์ฐ, ์ง๋, ๋๊ฒฐ ๋ฑ์ ๋ฌธ์ ๊ฐ ์๊ธด๋ค.
→ ํ ๊ฐ๊ฐ ์๋ ๋ ๊ฐ์ DQN์ ์ฌ์ฉํ๋ค.
์ฒซ ๋ฒ์งธ DQN์ ๊ฐ ์คํ ์์ ํ์ตํ๊ณ ์์ด์ ํธ๋ฅผ ์์ง์ด๋ ๋ฐ ์ฌ์ฉํ๋ ์จ๋ผ์ธ ๋ชจ๋ธ์ด๋ค.
๋ ๋ฒ์งธ DQN์ ํ๊น์ ์ ์ํ๊ธฐ ์ํด์๋ง ์ฌ์ฉํ๋ ํ๊น ๋ชจ๋ธ์ด๋ฉฐ, ์ด๋ ์จ๋ผ์ธ ๋ชจ๋ธ์ ๋จ์ํ ๋ณต์ฌ๋ณธ์ด๋ค.
target = tf.keras.models.clone_model(model) # ๋ชจ๋ธ ๊ตฌ์กฐ ๋ณต์ฌ target.set_weights(model.get_weights()) # ๊ฐ์ค์น ๋ณต์ฌnext_Q_values = target.predict(next_states, verbose=0)๊ทธ๋ค์ training_step() ํจ์์์ ๋ค์ ์ํ์ Q-๊ฐ์น๋ฅผ ๊ณ์ฐํ ๋ ์จ๋ผ์ธ ๋ชจ๋ธ ๋์ ํ๊น ๋ชจ๋ธ์ ์ฌ์ฉํ๋๋ก ํ ์ค์ ๋ฐ๊พธ์ด์ผ ํ๋ค.
if episode % 50 == 0: target.set_weights(model.get_weights())๋ง์ง๋ง์ผ๋ก ํ๋ จ ๋ฐ๋ณต์์ ์ผ์ ํ ๊ฐ๊ฒฉ์ผ๋ก ์จ๋ผ์ธ ๋ชจ๋ธ์ ๊ฐ์ค์น๋ฅผ ํ๊น ๋ชจ๋ธ๋ก ๋ณต์ฌํด์ผ ํ๋ค.
ํ๊น ๋ชจ๋ธ์ ์จ๋ผ์ธ ๋ชจ๋ธ๋ณด๋ค ์์ฃผ ์ ๋ฐ์ดํธ๋์ง ์์ผ๋ฏ๋ก Q-๊ฐ์น ํ๊น์ด ๋ ์์ ์ ์ด๋ฉฐ ํผ๋๋ฐฑ ๋ฐ๋ณต์ ์ํํ๊ณ ์ด์ ๋ํ ์ํฅ์ด ๊ฐ์๋๋ค.
18.11.2 ๋๋ธ DQN
ํ๊น ๋คํธ์ํฌ๊ฐ Q-๊ฐ์น๋ฅผ ๊ณผ๋ํ๊ฐํ๊ธฐ ์ฝ๋ค๋ ๊ด์ธก์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ค.
๋ชจ๋ ํ๋์ด ๋์ผํ๊ฒ ์ข๋ค๊ณ ๊ฐ์ ํ๋ค.
ํ๊น ๋ชจ๋ธ์ด ์ถ์ ํ Q-๊ฐ์น๊ฐ ๋์ผํด์ผ ํ์ง๋ง ๊ทผ์ฟ๊ฐ์ด๊ธฐ ๋๋ฌธ์ ์ฐ์ฐํ ๋ค๋ฅธ ๊ฒ๋ณด๋ค ์กฐ๊ธ ๋์ ๊ฐ์ด ์์ ๊ฒ์ด๋ค.
ํ๊น ๋ชจ๋ธ์ ํญ์ ๊ฐ์ฅ ํฐ Q-๊ฐ์น๋ฅผ ์ ํํ๋ฏ๋ก ํ๊ท Q-๊ฐ์น๋ณด๋ค ์กฐ๊ธ ๋ ์ปค์ง๊ณ ์ค์ Q-๊ฐ์น๋ฅผ ๊ณผ๋ํ๊ฐํ ๊ฐ๋ฅ์ฑ์ด ๋๋ค.
→ ๋ค์ ์ํ์์ ์ต์ ์ ํ๋์ ์ ํํ ๋ ํ๊น ๋ชจ๋ธ ๋์ ์จ๋ผ์ธ ๋ชจ๋ธ์ ์ฌ์ฉํ๋๋ก ์ ์๋์๋ค.
ํ๊น ๋ชจ๋ธ์ ์ต์ ์ ํ๋์ ๋ํ Q-๊ฐ์น๋ฅผ ์ถ์ ํ ๋๋ง ์ฌ์ฉํ๋ค.
def training_step(batch_size): experiences = sample_experiences(batch_size) states, actions, rewards, next_states, dones, truncateds = experiences next_Q_value = model.predict(next_states, vervose=0) best_next_actions = next_Q_values.argmax(axis=1) next_mask = tf.one_hot(best_next_actions, n_outputs).numpy() max_next_Q_values = (target.predict(next_states, verbose=0) * next_mask).sum(axis=1) [...]18.11.3 ์ฐ์ ์์ ๊ธฐ๋ฐ ๊ฒฝํ ์ฌ์
์ค์๋ ์ํ๋ง(IS), ์ฐ์ ์์ ๊ธฐ๋ฐ ๊ฒฝํ ์ฌ์(PER) : ์ฌ์ ๋ฒํผ์์ ๊ฒฝํ์ ๊ท ์ผํ๊ฒ ์ํ๋งํ๋ ๊ฒ์ด ์๋๋ผ ์ค์ํ ๊ฒฝํ์ ๋ ์์ฃผ ์ํ๋งํ๋ค.
18.11.4 ๋์ผ๋ง DQN
'๐ฎ ์ด๊ฒ์ ๊ฒ ๊ณต๋ถ > โฉ ํธ์ฆ์จ ๋จธ์ ๋ฌ๋' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ