{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 13wk-2: 강화학습 (1) – Bandit\n", "\n", "최규빈 \n", "2024-05-29\n", "\n", "\n", "\n", "# 1. 강의영상\n", "\n", "\n", "\n", "# 2. Imports" ], "id": "dfc29062-4442-473d-b2b1-aa17a57e3af3" }, { "cell_type": "code", "execution_count": 3, "metadata": { "tags": [] }, "outputs": [], "source": [ "import numpy as np" ], "id": "bf93dfa6-34a4-44ab-8bc5-61b02797dc0a" }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. 강화학습 Intro\n", "\n", "`-` 강화학습(대충설명): 어떠한 “(게임)환경”이 있을때 거기서 “뭘 할지”를\n", "학습하는 과업\n", "\n", "`-` 딥마인드: breakout $\\to$ 알파고\n", "\n", "- \n", "\n", "`-` 강화학습 미래? (이거 잘하면 먹고 살 수 있을까?)\n", "\n", "# 4. Game1: `Bandit` 게임\n", "\n", "## A. 게임설명 및 원시코드\n", "\n", "`-` 문제설명: 두 개의 버튼이 있다. `버튼0`을 누르면 1의 보상을,\n", "`버튼1`을 누르면 10의 보상을 준다고 가정\n", "\n", "`-` 처음에 어떤 행동을 해야 하는가?\n", "\n", "- 처음에는 아는게 없음\n", "- 일단 “아무거나” 눌러보자.\n", "\n", "`-` 버튼을 아무거나 누르는 코드를 작성해보자." ], "id": "00149303-5bc8-4b14-bf78-a69f0a41c852" }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "action_space = ['버튼0','버튼1']\n", "action = np.random.choice(action_space,p=[0.5,0.5])\n", "action" ], "id": "b59a9c17-68af-4172-b9a1-a57698c48064" }, { "cell_type": "markdown", "metadata": {}, "source": [ "> `action_space` 와 `action` 이라는 용어를 기억할 것\n", "\n", "`-` 버튼을 누른 행위에 따른 보상을 구현하자." ], "id": "42306d8d-8087-4e7a-9e4f-b45c0df17a59" }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "reward = 1 if action == \"버튼0\" else 10 \n", "reward" ], "id": "284085fb-fe92-420f-b1f1-e4e8f8bbe93c" }, { "cell_type": "markdown", "metadata": {}, "source": [ "> `reward`라는 용어를 기억할 것\n", "\n", "`-` 아무버튼이나 10번정도 눌러보면서 데이터를 쌓아보자." ], "id": "e075ba1f-d75e-4b26-b583-99c588fdad5d" }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "버튼1 10\n", "버튼1 10\n", "버튼1 10\n", "버튼0 1\n", "버튼1 10\n", "버튼1 10\n", "버튼0 1\n", "버튼0 1\n", "버튼1 10\n", "버튼0 1" ] } ], "source": [ "action_space = ['버튼0','버튼1']\n", "for _ in range(10):\n", " action = np.random.choice(action_space)\n", " reward = 1 if action == \"버튼0\" else 10\n", " print(action,reward)" ], "id": "047ed7c3-8764-4ddd-bf0d-d19f819579f4" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 깨달았음: `버튼0`을 누르면 1점을 받고, `버튼1`을 누르면 10점을 받는\n", "“환경(environment)”이구나? $\\to$ `버튼1`을 누르는 “동작(=action)”을\n", "해야하는 상황이구나?\n", "\n", "- 여기에서 $\\to$의 과정을 체계화 시킨 학문이 강화학습\n", "\n", "> `environment`라는 용어를 기억할 것" ], "id": "6cf2042d-c7f3-4135-ba02-98e953c77f8a" }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "버튼1 10\n", "버튼1 10\n", "버튼1 10\n", "버튼1 10\n", "버튼1 10\n", "버튼1 10\n", "버튼1 10\n", "버튼1 10\n", "버튼1 10\n", "버튼1 10" ] } ], "source": [ "action_space = ['버튼0','버튼1']\n", "for _ in range(10):\n", " action = '버튼1'\n", " reward = 1 if action == \"버튼0\" else 10\n", " print(action,reward)" ], "id": "7c411be6-725e-4437-861e-637a74d9d9e0" }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 게임 클리어\n", "\n", "`-` 강화학습: 환경(environment)을 이해 $\\to$ 에이전트(agent)가\n", "행동(action)을 결정\n", "\n", "> `agent`라는 용어를 기억할 것\n", "\n", "***위의 과정이 잘 되었다는 의미로 사용하는 문장들***\n", "\n", "- 강화학습이 성공적으로 잘 되었다.\n", "- 에이전트가 환경의 과제를 완료했다.\n", "- 에이전트가 환경에서 성공적으로 학습했다.\n", "- 에이전트가 올바른 행동을 학습했다.\n", "- 게임 클리어 (비공식)\n", "\n", "`-` 게임이 클리어 되었다는 것을 의미하는 지표를 정하고 싶다.\n", "\n", "- 첫 생각: `버튼1`을 누르는 순간 게임클리어로 보면 되지 않나?\n", "- 두번째 생각: 아니지? 우연히 누를수도 있잖아?\n", "- 게임클리어조건: (1) 20번은 그냥 진행 (2) 최근 20번의 보상의 평균이\n", " 9.5점 이상이면 게임이 클리어 되었다고 생각하자.[1]\n", "\n", "`-` 원시코드1: 환경을 이해하지 못한 에이전트 – 게임을 클리어할 수 없다.\n", "\n", "[1] `버튼1`을 눌러야 하는건 맞지만 몇번의 실수는 눈감아 주자는 의미" ], "id": "92489ae4-ee6e-4605-ad4d-0c96eef45b07" }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "시도:1 행동:0 보상:1 최근20번보상평균:1.0000 \n", "시도:2 행동:0 보상:1 최근20번보상평균:1.0000 \n", "시도:3 행동:0 보상:1 최근20번보상평균:1.0000 \n", "시도:4 행동:1 보상:10 최근20번보상평균:3.2500 \n", "시도:5 행동:0 보상:1 최근20번보상평균:2.8000 \n", "시도:6 행동:1 보상:10 최근20번보상평균:4.0000 \n", "시도:7 행동:0 보상:1 최근20번보상평균:3.5714 \n", "시도:8 행동:1 보상:10 최근20번보상평균:4.3750 \n", "시도:9 행동:0 보상:1 최근20번보상평균:4.0000 \n", "시도:10 행동:0 보상:1 최근20번보상평균:3.7000 \n", "시도:11 행동:1 보상:10 최근20번보상평균:4.2727 \n", "시도:12 행동:0 보상:1 최근20번보상평균:4.0000 \n", "시도:13 행동:1 보상:10 최근20번보상평균:4.4615 \n", "시도:14 행동:1 보상:10 최근20번보상평균:4.8571 \n", "시도:15 행동:1 보상:10 최근20번보상평균:5.2000 \n", "시도:16 행동:0 보상:1 최근20번보상평균:4.9375 \n", "시도:17 행동:0 보상:1 최근20번보상평균:4.7059 \n", "시도:18 행동:0 보상:1 최근20번보상평균:4.5000 \n", "시도:19 행동:1 보상:10 최근20번보상평균:4.7895 \n", "시도:20 행동:0 보상:1 최근20번보상평균:4.6000 \n", "--\n", "시도:21 행동:1 보상:10 최근20번보상평균:5.0500 \n", "시도:22 행동:0 보상:1 최근20번보상평균:5.0500 \n", "시도:23 행동:1 보상:10 최근20번보상평균:5.5000 \n", "시도:24 행동:1 보상:10 최근20번보상평균:5.5000 \n", "시도:25 행동:0 보상:1 최근20번보상평균:5.5000 \n", "시도:26 행동:0 보상:1 최근20번보상평균:5.0500 \n", "시도:27 행동:1 보상:10 최근20번보상평균:5.5000 \n", "시도:28 행동:1 보상:10 최근20번보상평균:5.5000 \n", "시도:29 행동:1 보상:10 최근20번보상평균:5.9500 \n", "시도:30 행동:1 보상:10 최근20번보상평균:6.4000 \n", "시도:31 행동:1 보상:10 최근20번보상평균:6.4000 \n", "시도:32 행동:1 보상:10 최근20번보상평균:6.8500 \n", "시도:33 행동:1 보상:10 최근20번보상평균:6.8500 \n", "시도:34 행동:1 보상:10 최근20번보상평균:6.8500 \n", "시도:35 행동:0 보상:1 최근20번보상평균:6.4000 \n", "시도:36 행동:0 보상:1 최근20번보상평균:6.4000 \n", "시도:37 행동:1 보상:10 최근20번보상평균:6.8500 \n", "시도:38 행동:1 보상:10 최근20번보상평균:7.3000 \n", "시도:39 행동:1 보상:10 최근20번보상평균:7.3000 \n", "시도:40 행동:1 보상:10 최근20번보상평균:7.7500 \n", "시도:41 행동:0 보상:1 최근20번보상평균:7.3000 \n", "시도:42 행동:1 보상:10 최근20번보상평균:7.7500 \n", "시도:43 행동:0 보상:1 최근20번보상평균:7.3000 \n", "시도:44 행동:0 보상:1 최근20번보상평균:6.8500 \n", "시도:45 행동:0 보상:1 최근20번보상평균:6.8500 \n", "시도:46 행동:1 보상:10 최근20번보상평균:7.3000 \n", "시도:47 행동:1 보상:10 최근20번보상평균:7.3000 \n", "시도:48 행동:0 보상:1 최근20번보상평균:6.8500 \n", "시도:49 행동:0 보상:1 최근20번보상평균:6.4000 \n", "시도:50 행동:1 보상:10 최근20번보상평균:6.4000 " ] } ], "source": [ "action_space = [0,1]\n", "actions = []\n", "rewards = []\n", "for t in range(1,51):\n", " action = np.random.choice(action_space)\n", " reward = 1 if action == 0 else 10\n", " actions.append(action)\n", " rewards.append(reward)\n", " #--#\n", " print(\n", " f\"시도:{t}\\t\"\n", " f\"행동:{action}\\t\"\n", " f\"보상:{reward}\\t\"\n", " f\"최근20번보상평균:{np.mean(rewards[-20:]):.4f}\\t\"\n", " )\n", " if t<20:\n", " pass \n", " elif t==20:\n", " print(\"--\")\n", " else: \n", " if np.mean(rewards[-20:]) > 9.5:\n", " print(\"Game Clear\")\n", " break" ], "id": "e4b8d98a-4bfa-492f-b91d-8c90776bd395" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 원시코드2: 환경을 깨달은 에이전트 – 게임클리어" ], "id": "7e923235-a35f-45f0-b9ef-beadbb4c2e76" }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "시도:1 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:2 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:3 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:4 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:5 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:6 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:7 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:8 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:9 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:10 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:11 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:12 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:13 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:14 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:15 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:16 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:17 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:18 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:19 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:20 행동:1 보상:10 최근20번보상평균:10.0000 \n", "--\n", "시도:21 행동:1 보상:10 최근20번보상평균:10.0000 \n", "Game Clear" ] } ], "source": [ "action_space = [0,1]\n", "actions = []\n", "rewards = []\n", "for t in range(1,51):\n", " action = 1\n", " reward = 1 if action == 0 else 10\n", " actions.append(action)\n", " rewards.append(reward)\n", " #--#\n", " print(\n", " f\"시도:{t}\\t\"\n", " f\"행동:{action}\\t\"\n", " f\"보상:{reward}\\t\"\n", " f\"최근20번보상평균:{np.mean(rewards[-20:]):.4f}\\t\"\n", " )\n", " if t<20:\n", " pass \n", " elif t==20:\n", " print(\"--\")\n", " else: \n", " if np.mean(rewards[-20:]) > 9.5:\n", " print(\"Game Clear\")\n", " break" ], "id": "19ce8841-5909-49d3-a43d-d361a2950d35" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## B. 수정1: `Env` 구현\n", "\n", "`-` `Bandit` 클래스 선언 + `.step()` 구현" ], "id": "6be0efa7-625e-48ef-86d1-a19ddef8580c" }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "class Bandit:\n", " def step(self,agent_action):\n", " reward = 1 if agent_action == 0 else 10\n", " return reward" ], "id": "9fbd588a-45c0-4842-aebe-8aec6b601f8a" }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "시도:1 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:2 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:3 행동:0 보상:1 최근20번보상평균:7.0000 \n", "시도:4 행동:0 보상:1 최근20번보상평균:5.5000 \n", "시도:5 행동:0 보상:1 최근20번보상평균:4.6000 \n", "시도:6 행동:1 보상:10 최근20번보상평균:5.5000 \n", "시도:7 행동:0 보상:1 최근20번보상평균:4.8571 \n", "시도:8 행동:1 보상:10 최근20번보상평균:5.5000 \n", "시도:9 행동:1 보상:10 최근20번보상평균:6.0000 \n", "시도:10 행동:1 보상:10 최근20번보상평균:6.4000 \n", "시도:11 행동:1 보상:10 최근20번보상평균:6.7273 \n", "시도:12 행동:0 보상:1 최근20번보상평균:6.2500 \n", "시도:13 행동:1 보상:10 최근20번보상평균:6.5385 \n", "시도:14 행동:1 보상:10 최근20번보상평균:6.7857 \n", "시도:15 행동:1 보상:10 최근20번보상평균:7.0000 \n", "시도:16 행동:1 보상:10 최근20번보상평균:7.1875 \n", "시도:17 행동:0 보상:1 최근20번보상평균:6.8235 \n", "시도:18 행동:1 보상:10 최근20번보상평균:7.0000 \n", "시도:19 행동:0 보상:1 최근20번보상평균:6.6842 \n", "시도:20 행동:1 보상:10 최근20번보상평균:6.8500 \n", "--\n", "시도:21 행동:0 보상:1 최근20번보상평균:6.4000 \n", "시도:22 행동:0 보상:1 최근20번보상평균:5.9500 \n", "시도:23 행동:1 보상:10 최근20번보상평균:6.4000 \n", "시도:24 행동:0 보상:1 최근20번보상평균:6.4000 \n", "시도:25 행동:0 보상:1 최근20번보상평균:6.4000 \n", "시도:26 행동:1 보상:10 최근20번보상평균:6.4000 \n", "시도:27 행동:0 보상:1 최근20번보상평균:6.4000 \n", "시도:28 행동:1 보상:10 최근20번보상평균:6.4000 \n", "시도:29 행동:1 보상:10 최근20번보상평균:6.4000 \n", "시도:30 행동:0 보상:1 최근20번보상평균:5.9500 \n", "시도:31 행동:1 보상:10 최근20번보상평균:5.9500 \n", "시도:32 행동:0 보상:1 최근20번보상평균:5.9500 \n", "시도:33 행동:0 보상:1 최근20번보상평균:5.5000 \n", "시도:34 행동:0 보상:1 최근20번보상평균:5.0500 \n", "시도:35 행동:0 보상:1 최근20번보상평균:4.6000 \n", "시도:36 행동:0 보상:1 최근20번보상평균:4.1500 \n", "시도:37 행동:1 보상:10 최근20번보상평균:4.6000 \n", "시도:38 행동:1 보상:10 최근20번보상평균:4.6000 \n", "시도:39 행동:1 보상:10 최근20번보상평균:5.0500 \n", "시도:40 행동:0 보상:1 최근20번보상평균:4.6000 \n", "시도:41 행동:1 보상:10 최근20번보상평균:5.0500 \n", "시도:42 행동:0 보상:1 최근20번보상평균:5.0500 \n", "시도:43 행동:1 보상:10 최근20번보상평균:5.0500 \n", "시도:44 행동:0 보상:1 최근20번보상평균:5.0500 \n", "시도:45 행동:0 보상:1 최근20번보상평균:5.0500 \n", "시도:46 행동:0 보상:1 최근20번보상평균:4.6000 \n", "시도:47 행동:1 보상:10 최근20번보상평균:5.0500 \n", "시도:48 행동:1 보상:10 최근20번보상평균:5.0500 \n", "시도:49 행동:0 보상:1 최근20번보상평균:4.6000 \n", "시도:50 행동:0 보상:1 최근20번보상평균:4.6000 " ] } ], "source": [ "env = Bandit()\n", "action_space = [0,1]\n", "actions = []\n", "rewards = []\n", "for t in range(1,51):\n", " action = np.random.choice(action_space)\n", " reward = env.step(action)\n", " actions.append(action)\n", " rewards.append(reward)\n", " #--#\n", " print(\n", " f\"시도:{t}\\t\"\n", " f\"행동:{action}\\t\"\n", " f\"보상:{reward}\\t\"\n", " f\"최근20번보상평균:{np.mean(rewards[-20:]):.4f}\\t\"\n", " )\n", " if t<20:\n", " pass \n", " elif t==20:\n", " print(\"--\")\n", " else: \n", " if np.mean(rewards[-20:]) > 9.5:\n", " print(\"Game Clear\")\n", " break" ], "id": "a5defbf3-27d4-4dc2-a007-f6f0a934e7a1" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## C. 수정2: `Agent` 구현 (인간지능)\n", "\n", "`-` Agent 클래스 설계\n", "\n", "- 액션을 하고, 본인의 행동과 환경에서 받은 reward를 기억\n", "- `.act()`함수와 `.save_experience()`함수 구현" ], "id": "89d9a5e8-b08a-4964-8139-bb38d7a35e07" }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [], "source": [ "class Agent:\n", " def __init__(self):\n", " self.action_space = [0,1]\n", " self.action = None \n", " self.reward = None\n", " self.actions = []\n", " self.rewards = [] \n", " def act(self):\n", " prob = [0.5, 0.5]\n", " self.action = 1 #np.random.choice(self.action_space,p=prob)\n", " def save_experience(self):\n", " self.actions.append(self.action)\n", " self.rewards.append(self.reward)" ], "id": "07b20e58-cf65-4dd3-8967-42f723f4d586" }, { "cell_type": "markdown", "metadata": {}, "source": [ "— 대충 아래와 같은 느낌으로 코드가 돌아가요 —\n", "\n", "**시점0**: init" ], "id": "245f7517-da1d-4b2b-abe9-3ecb2a0453b3" }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [], "source": [ "agent = Agent()\n", "env = Bandit()" ], "id": "f0381129-4060-4926-86e1-9241dc950f4f" }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "agent.action, agent.reward, agent.actions, agent.rewards" ], "id": "9228a4ef-6158-4339-9474-da5d804dc87f" }, { "cell_type": "markdown", "metadata": {}, "source": [ "**시점1**: agent 가 acition을 선택" ], "id": "b066e038-d9f9-49af-86e8-0bd00013d254" }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [], "source": [ "agent.act()" ], "id": "220c17f1-0fb2-445b-8c63-5c2ac5b98697" }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [], "source": [ "agent.action, agent.reward, agent.actions, agent.rewards" ], "id": "2aa0b490-0154-4ad4-94dd-43a378726659" }, { "cell_type": "markdown", "metadata": {}, "source": [ "**시점2**: env가 agent에게 보상을 줌" ], "id": "95daac19-e495-4be9-8a78-fc64a09ba587" }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [], "source": [ "agent.reward = env.step(agent.action)" ], "id": "8257dd32-6a78-4086-8785-33c00dd1fe61" }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [], "source": [ "agent.action, agent.reward, agent.actions, agent.rewards" ], "id": "174baf76-fad9-40b7-a7bb-177420c151cb" }, { "cell_type": "markdown", "metadata": {}, "source": [ "**시점3**: 경험을 저장" ], "id": "c254db63-b0bf-4bb1-84e7-547c870f76a7" }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [], "source": [ "agent.save_experience()" ], "id": "24ad0a83-2544-4263-9004-ade828924610" }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [], "source": [ "agent.action, agent.reward, agent.actions, agent.rewards" ], "id": "cdc18916-42ed-45bf-986e-3f0e53251037" }, { "cell_type": "markdown", "metadata": {}, "source": [ "– 전체코드 –" ], "id": "82fc2fc0-c4af-476a-8174-efc92f831063" }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "시도:1 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:2 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:3 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:4 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:5 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:6 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:7 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:8 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:9 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:10 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:11 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:12 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:13 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:14 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:15 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:16 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:17 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:18 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:19 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:20 행동:1 보상:10 최근20번보상평균:10.0000 \n", "--\n", "시도:21 행동:1 보상:10 최근20번보상평균:10.0000 \n", "Game Clear" ] } ], "source": [ "env = Bandit()\n", "agent = Agent()\n", "for t in range(1,51):\n", " agent.act()\n", " agent.reward = env.step(agent.action)\n", " agent.save_experience()\n", " #--#\n", " print(\n", " f\"시도:{t}\\t\"\n", " f\"행동:{agent.action}\\t\"\n", " f\"보상:{agent.reward}\\t\"\n", " f\"최근20번보상평균:{np.mean(agent.rewards[-20:]):.4f}\\t\"\n", " )\n", " if t<20:\n", " pass \n", " elif t==20:\n", " print(\"--\")\n", " else: \n", " if np.mean(agent.rewards[-20:]) > 9.5:\n", " print(\"Game Clear\")\n", " break " ], "id": "69629e5d-9f16-4a12-b5b4-c7b2d1de51d6" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## D. 수정3: `Agent` 구현 (인공지능)\n", "\n", "`-` 지금까지 풀이의 한계\n", "\n", "- 사실 강화학습은 “환경을 이해 $\\to$ 행동을 결정” 의 과정에서\n", " “$\\to$”의 과정을 수식화 한 것이다.\n", "- 그런데 지금까지 했던 코드는 환경(environment)를 이해하는 순간\n", " 에이전트(agent)가 최적의 행동(action)[1]을 **“직관적으로”**\n", " 결정하였으므로 기계가 스스로 학습을 했다고 볼 수 없다.\n", "\n", "`-` 에이전트가 데이터를 보고 스스로 학습할 수 있도록 설계 – 부제:\n", "`agent.learn()`을 설계하자.\n", "\n", "1. 데이터를 모아서 `q_table` 를 만든다. `q_table`은 아래와 같은 내용을\n", " 포함한다.\n", "\n", "| 행동 | 보상(추정값) |\n", "|:--------------:|:------------:|\n", "| 버튼0 ($=a_0$) | 1 ($=q_0$) |\n", "| 버튼1 ($=a_1$) | 10 ($=q_1$) |\n", "\n", "1. `q_table`을 바탕으로 적절한 정책(=`policy`)을 설정한다.\n", "\n", "- 이 예제에서는 버튼0과 버튼1을 각각\n", " $\\big(\\frac{q_0}{q_0+q_1},\\frac{q_1}{q_0+q_1}\\big)$ 의 확률로\n", " 선택하는 “정책”을 이용하면 충분할 듯\n", "- 처음부터 이러한 확률로 선택하기보다 처음 20번정도는 데이터를 쌓기\n", " 위해서 행동을 랜덤하게 선택하고, 그 이후에 위에서 제시한 확률값으로\n", " 행동을 선택하는게 합리적인듯.\n", "\n", "> 여기에서 `q_table`, `policy`라는 용어를 기억하세요.\n", "\n", "`-` `q_table`을 계산하는 코드 예시\n", "\n", "[1] `버튼1`을 누른다" ], "id": "1d54fab7-b5cb-4f93-b44c-a841e0a75051" }, { "cell_type": "code", "execution_count": 105, "metadata": { "tags": [] }, "outputs": [], "source": [ "agent.actions = [0, 1, 1, 0, 1, 0, 0] \n", "agent.rewards = [1, 9, 10, 1, 9.5, 1, 1.2] \n", "actions = np.array(agent.actions)\n", "rewards = np.array(agent.rewards)" ], "id": "cccaa9c0-d474-4f7e-9574-d8965ac2bfc1" }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [], "source": [ "q0,q1 = rewards[actions==0].mean(), rewards[actions==1].mean()" ], "id": "3a0cd0d3-3ee2-433c-ab85-ecf86aabdeb5" }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [], "source": [ "q_table = np.array([q0,q1])\n", "q_table" ], "id": "61b936fc-fe8f-4ca2-a690-7c8fc0025230" }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [], "source": [ "q_table/ q_table.sum()" ], "id": "b0dc5fd7-5aa8-4590-8ef4-dcecab25f8fa" }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [], "source": [ "prob = q_table/ q_table.sum()\n", "agent.action = np.random.choice(agent.action_space,p = prob )\n", "agent.action" ], "id": "49632925-f681-4b05-9adb-87a5c6d09286" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 최종코드정리" ], "id": "09060d0a-def4-49ee-ac09-ef4f9615430b" }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [], "source": [ "class Agent:\n", " def __init__(self):\n", " self.action_space = [0,1]\n", " self.action = None \n", " self.reward = None\n", " self.actions = []\n", " self.rewards = []\n", " self.q_table = np.array([0.001,0.001])\n", " self.n_experience = 0 \n", " def act(self):\n", " if self.n_experience <= 20:\n", " self.action = np.random.choice(self.action_space)\n", " else: \n", " prob = self.q_table/ self.q_table.sum() \n", " self.action = np.random.choice(self.action_space,p = prob )\n", " def save_experience(self):\n", " self.actions.append(self.action)\n", " self.rewards.append(self.reward)\n", " self.n_experience = self.n_experience + 1 \n", " def learn(self):\n", " if self.n_experience < 20:\n", " pass \n", " else: \n", " actions = np.array(self.actions)\n", " rewards = np.array(self.rewards) \n", " q0,q1 = rewards[actions==0].mean(), rewards[actions==1].mean()\n", " self.q_table = np.array([q0,q1])" ], "id": "03f53425-b31a-4f36-a540-566852a9b3b8" }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "시도:1 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:2 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:3 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:4 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:5 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:6 행동:1 보상:10 최근20번보상평균:10.0000 \n", "시도:7 행동:0 보상:1 최근20번보상평균:8.7143 \n", "시도:8 행동:1 보상:10 최근20번보상평균:8.8750 \n", "시도:9 행동:1 보상:10 최근20번보상평균:9.0000 \n", "시도:10 행동:1 보상:10 최근20번보상평균:9.1000 \n", "시도:11 행동:1 보상:10 최근20번보상평균:9.1818 \n", "시도:12 행동:1 보상:10 최근20번보상평균:9.2500 \n", "시도:13 행동:0 보상:1 최근20번보상평균:8.6154 \n", "시도:14 행동:1 보상:10 최근20번보상평균:8.7143 \n", "시도:15 행동:0 보상:1 최근20번보상평균:8.2000 \n", "시도:16 행동:1 보상:10 최근20번보상평균:8.3125 \n", "시도:17 행동:1 보상:10 최근20번보상평균:8.4118 \n", "시도:18 행동:1 보상:10 최근20번보상평균:8.5000 \n", "시도:19 행동:0 보상:1 최근20번보상평균:8.1053 \n", "시도:20 행동:1 보상:10 최근20번보상평균:8.2000 \n", "--\n", "시도:21 행동:1 보상:10 최근20번보상평균:8.2000 \n", "시도:22 행동:0 보상:1 최근20번보상평균:7.7500 \n", "시도:23 행동:1 보상:10 최근20번보상평균:7.7500 \n", "시도:24 행동:1 보상:10 최근20번보상평균:7.7500 \n", "시도:25 행동:1 보상:10 최근20번보상평균:7.7500 \n", "시도:26 행동:1 보상:10 최근20번보상평균:7.7500 \n", "시도:27 행동:1 보상:10 최근20번보상평균:8.2000 \n", "시도:28 행동:1 보상:10 최근20번보상평균:8.2000 \n", "시도:29 행동:1 보상:10 최근20번보상평균:8.2000 \n", "시도:30 행동:1 보상:10 최근20번보상평균:8.2000 \n", "시도:31 행동:1 보상:10 최근20번보상평균:8.2000 \n", "시도:32 행동:1 보상:10 최근20번보상평균:8.2000 \n", "시도:33 행동:1 보상:10 최근20번보상평균:8.6500 \n", "시도:34 행동:1 보상:10 최근20번보상평균:8.6500 \n", "시도:35 행동:1 보상:10 최근20번보상평균:9.1000 \n", "시도:36 행동:1 보상:10 최근20번보상평균:9.1000 \n", "시도:37 행동:1 보상:10 최근20번보상평균:9.1000 \n", "시도:38 행동:1 보상:10 최근20번보상평균:9.1000 \n", "시도:39 행동:1 보상:10 최근20번보상평균:9.5500 \n", "Game Clear" ] } ], "source": [ "env = Bandit()\n", "agent = Agent()\n", "for t in range(1,51):\n", " # step1: 행동\n", " agent.act()\n", " # step2: 보상\n", " agent.reward = env.step(agent.action)\n", " # step3: 저장 & 학습\n", " agent.save_experience()\n", " agent.learn() \n", " #--#\n", " print(\n", " f\"시도:{t}\\t\"\n", " f\"행동:{agent.action}\\t\"\n", " f\"보상:{agent.reward}\\t\"\n", " f\"최근20번보상평균:{np.mean(agent.rewards[-20:]):.4f}\\t\"\n", " )\n", " if t<20:\n", " pass \n", " elif t==20:\n", " print(\"--\")\n", " else: \n", " if np.mean(agent.rewards[-20:]) > 9.5:\n", " print(\"Game Clear\")\n", " break " ], "id": "e337fb3b-c6ac-470f-baa6-b871a8672b71" } ], "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernelspec": { "name": "python3", "display_name": "Python 3 (ipykernel)", "language": "python" }, "language_info": { "name": "python", "codemirror_mode": { "name": "ipython", "version": "3" }, "file_extension": ".py", "mimetype": "text/x-python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.8" } } }