<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>아는 것과 모르는 것에 대한 구분</title>
    <link>https://neverparadise.tistory.com/</link>
    <description>후회없이 살고 싶습니다. </description>
    <language>ko</language>
    <pubDate>Mon, 1 Jun 2026 08:59:07 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>neverparadise</managingEditor>
    <item>
      <title>AndroidWorld 설치를 위한 환경설정</title>
      <link>https://neverparadise.tistory.com/48</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M3W9O/btsJfUui40p/JruebK5hkuXZfdmRG1g0rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M3W9O/btsJfUui40p/JruebK5hkuXZfdmRG1g0rK/img.png&quot; data-alt=&quot;그림 1: AndroidWorld&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M3W9O/btsJfUui40p/JruebK5hkuXZfdmRG1g0rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM3W9O%2FbtsJfUui40p%2FJruebK5hkuXZfdmRG1g0rK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;513&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 1: AndroidWorld&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;user-select: auto !important;&quot; data-ke-size=&quot;size16&quot;&gt;[Code repository]: &lt;a style=&quot;user-select: auto !important;&quot; href=&quot;https://github.com/google-research/android_world&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/google-research/android_world&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724490268452&quot; style=&quot;user-select: auto !important;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - google-research/android_world: AndroidWorld is an environment and benchmark for autonomous agents&quot; data-og-description=&quot;AndroidWorld is an environment and benchmark for autonomous agents - google-research/android_world&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/google-research/android_world&quot; data-og-url=&quot;https://github.com/google-research/android_world&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cqzcGv/hyWVXqsMNi/VU9XIlk3WzrCB17xK9Vu0k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a style=&quot;user-select: auto !important;&quot; href=&quot;https://github.com/google-research/android_world&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/google-research/android_world&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cqzcGv/hyWVXqsMNi/VU9XIlk3WzrCB17xK9Vu0k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600'); user-select: auto !important;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot; style=&quot;user-select: auto !important;&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;user-select: auto !important;&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - google-research/android_world: AndroidWorld is an environment and benchmark for autonomous agents&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;user-select: auto !important;&quot; data-ke-size=&quot;size16&quot;&gt;AndroidWorld is an environment and benchmark for autonomous agents - google-research/android_world&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;user-select: auto !important;&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;user-select: auto !important;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;user-select: auto !important;&quot; data-ke-size=&quot;size16&quot;&gt;안드로이드 월드는 컴퓨터를 제어하는 인공지능 연구를 위한 벤치마크입니다. 이 환경은 본래 리눅스 또는 macOS에서 동작하도록 개발되었습니다. 윈도우에서 이 환경을 실행시키려면 추가적인 설정들이 필요합니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;user-select: auto !important;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;user-select: auto !important;&quot; data-ke-size=&quot;size26&quot;&gt;1. WSL2 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/ko-kr/windows/wsl/install&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724492007637&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;WSL 설치&quot; data-og-description=&quot;wsl --install 명령을 사용하여 Linux용 Windows 하위 시스템을 설치합니다. Ubuntu, Debian, SUSE, Kali, Fedora, Pengwin, Alpine 등 원하는 Linux 배포판에서 실행되는 Windows 머신에서 Bash 터미널을 사용할 수 있습니&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/KeRaS/hyWV6VccqE/3BKfFXHlQsmk4EkhrBkKB0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/windows/wsl/install&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/KeRaS/hyWV6VccqE/3BKfFXHlQsmk4EkhrBkKB0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;WSL 설치&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;wsl --install 명령을 사용하여 Linux용 Windows 하위 시스템을 설치합니다. Ubuntu, Debian, SUSE, Kali, Fedora, Pengwin, Alpine 등 원하는 Linux 배포판에서 실행되는 Windows 머신에서 Bash 터미널을 사용할 수 있습니&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크 참고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. AndroidStudio 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/studio&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.android.com/studio&lt;/a&gt; 링크로 들어가서 화면 스크롤을 내리면 다음과 같이 운영체제별로 android studio를 다운받을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1753&quot; data-origin-height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/olSCw/btsJe7A9UqU/2XkfFRUtnSd8iXZ5NDzNI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/olSCw/btsJe7A9UqU/2XkfFRUtnSd8iXZ5NDzNI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/olSCw/btsJe7A9UqU/2XkfFRUtnSd8iXZ5NDzNI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FolSCw%2FbtsJe7A9UqU%2F2XkfFRUtnSd8iXZ5NDzNI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;329&quot; data-origin-width=&quot;1753&quot; data-origin-height=&quot;721&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Linux 버전을 눌러서 체크 표시를 하고 다운로드 버튼에 오른쪽 마우스를 클릭하면 주소를 복사할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1093&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/py7zb/btsJeQGqofq/TBcNTH4cJHs4fQqZ5iM0nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/py7zb/btsJeQGqofq/TBcNTH4cJHs4fQqZ5iM0nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/py7zb/btsJeQGqofq/TBcNTH4cJHs4fQqZ5iM0nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpy7zb%2FbtsJeQGqofq%2FTBcNTH4cJHs4fQqZ5iM0nK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1093&quot; height=&quot;506&quot; data-origin-width=&quot;1093&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;복사된 주소를 WSL의 터미널 상에서 wget을 통해 다운로드 받아줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/svK1k/btsJemMCTr0/7kGXNIQ8vVQkyGTyQrA4Wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/svK1k/btsJemMCTr0/7kGXNIQ8vVQkyGTyQrA4Wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/svK1k/btsJemMCTr0/7kGXNIQ8vVQkyGTyQrA4Wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsvK1k%2FbtsJemMCTr0%2F7kGXNIQ8vVQkyGTyQrA4Wk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1482&quot; height=&quot;125&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;125&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 Applications 라는 폴더를 만들어서 해당 폴더에 압축파일을 풉니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724491356692&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd
mkdir ~/Applications &amp;amp;&amp;amp; cd ~/Applications
tar xfv $(ls -1t ~/Downloads/android-studio-* | head -n1)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령어를 bashrc 파일에 등록해놓으면 편하게 터미널에서 android studio를 실행할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724491453037&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;alias android-studio=~/Applications/android-studio/bin/studio.sh&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Nested virtuialization 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 사용자를 kvm 그룹에 추가합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724491644656&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo usermod -a -G kvm ${USER}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) vim이나 nano 같은 텍스트 에디터를 열어서 wsl.conf 파일을 아래와 같이 수정합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724491701050&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vim /etc/wsl.conf&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1724491917574&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# wsl.conf
[boot] 
command = /bin/bash -c 'chown -v root:kvm /dev/kvm &amp;amp;&amp;amp; chmod 660 /dev/kvm'

[wsl2]
nestedVirtualization=true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 아래 명령어를 통해 wsl을 재부팅하거나 윈도우를 재부팅 해줍니다. 그리고 android studio를 실행합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724491941759&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;wsl.exe --shutdown&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. SDK 다운로드 및 &lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: left;&quot;&gt;Android Virtual Device 설정&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVzFHH/btsJfpO5Fh1/fkc2faCeqC7yhMKrRCX9Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVzFHH/btsJfpO5Fh1/fkc2faCeqC7yhMKrRCX9Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVzFHH/btsJfpO5Fh1/fkc2faCeqC7yhMKrRCX9Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVzFHH%2FbtsJfpO5Fh1%2Ffkc2faCeqC7yhMKrRCX9Kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;570&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;android studio 에서 상단 메뉴 중 Tools를 누르고 SDK Manager를 실행합니다. 그리고 Android 13.0 Tiramisu에 체크를 하고 OK를 눌러 설치를 진행합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1229&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qbN7R/btsJeUa0Whl/SieZsiHyQvUAfdflvSMLc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qbN7R/btsJeUa0Whl/SieZsiHyQvUAfdflvSMLc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qbN7R/btsJeUa0Whl/SieZsiHyQvUAfdflvSMLc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqbN7R%2FbtsJeUa0Whl%2FSieZsiHyQvUAfdflvSMLc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1229&quot; height=&quot;471&quot; data-origin-width=&quot;1229&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: left;&quot;&gt;이후, 다시 Tools에서 Device Manager를 실행합니다. 그리고 Create Virtual Device를 눌러서 새로운 디바이스를 생성합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pKgEb/btsJeUIOSa2/NjTjdGAp4k0O4i5jdskxw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pKgEb/btsJeUIOSa2/NjTjdGAp4k0O4i5jdskxw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pKgEb/btsJeUIOSa2/NjTjdGAp4k0O4i5jdskxw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpKgEb%2FbtsJeUIOSa2%2FNjTjdGAp4k0O4i5jdskxw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;648&quot; height=&quot;206&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, Pixel 6, Tiramisu를 선택해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A6yy8/btsJfp9mN1d/oKBHajudM84wskrLKYA2kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A6yy8/btsJfp9mN1d/oKBHajudM84wskrLKYA2kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A6yy8/btsJfp9mN1d/oKBHajudM84wskrLKYA2kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA6yy8%2FbtsJfp9mN1d%2FoKBHajudM84wskrLKYA2kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;502&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c48VrJ/btsJe63kzr5/bX6NJkBFkLVwHTuuKYwgik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c48VrJ/btsJe63kzr5/bX6NJkBFkLVwHTuuKYwgik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c48VrJ/btsJe63kzr5/bX6NJkBFkLVwHTuuKYwgik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc48VrJ%2FbtsJe63kzr5%2FbX6NJkBFkLVwHTuuKYwgik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;411&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqxo0M/btsJfNBZQfq/JKg7qPKbtLsJwE9RRdphI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqxo0M/btsJfNBZQfq/JKg7qPKbtLsJwE9RRdphI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqxo0M/btsJfNBZQfq/JKg7qPKbtLsJwE9RRdphI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcqxo0M%2FbtsJfNBZQfq%2FJKg7qPKbtLsJwE9RRdphI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;242&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AVD name은 AndroidWorldAvd로 설정합니다. Finish를 눌러 생성을 완료하고 bashrc 파일에서 AVD 경로와 실행 명령어를 아래와 같이 설정합니다. &lt;b&gt;Sdk 폴더의 경로가 사용자마다 다를 수 있으니 주의하세요.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724492694181&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vim ~/.bashrc

# .bashrc
EMULATOR_NAME=AndroidWorldAvd
alias avd='~/Android/Sdk/emulator/emulator -avd $EMULATOR_NAME -no-snapshot -grpc 8554'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 터미널에서 avd를 입력하면 emulator가 실행됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;489&quot; data-origin-height=&quot;995&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bexTak/btsJd908quU/V0QbTalHwXPWiUG3s0r5Y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bexTak/btsJd908quU/V0QbTalHwXPWiUG3s0r5Y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bexTak/btsJd908quU/V0QbTalHwXPWiUG3s0r5Y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbexTak%2FbtsJd908quU%2FV0QbTalHwXPWiUG3s0r5Y0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;773&quot; data-origin-width=&quot;489&quot; data-origin-height=&quot;995&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: left;&quot;&gt;5. 가상환경 생성, &lt;/span&gt;AndroidEnv 및 AndroidWorld 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 링크 참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/google-research/android_world?tab=readme-ov-file&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/google-research/android_world&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724492773519&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - google-research/android_world: AndroidWorld is an environment and benchmark for autonomous agents&quot; data-og-description=&quot;AndroidWorld is an environment and benchmark for autonomous agents - google-research/android_world&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/google-research/android_world?tab=readme-ov-file&quot; data-og-url=&quot;https://github.com/google-research/android_world&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b437ss/hyWSoiZlmi/9CKbHE1hd6pNkf31FeiAi1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/google-research/android_world?tab=readme-ov-file&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/google-research/android_world?tab=readme-ov-file&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b437ss/hyWSoiZlmi/9CKbHE1hd6pNkf31FeiAi1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - google-research/android_world: AndroidWorld is an environment and benchmark for autonomous agents&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;AndroidWorld is an environment and benchmark for autonomous agents - google-research/android_world&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. M&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: left;&quot;&gt;odel provider API 등록&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1724492058581&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Add to .bashrc.
export OPENAI_API_KEY=your-key
export GCP_API_KEY=your-key&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: left;&quot;&gt;[References]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: left;&quot;&gt;&lt;a href=&quot;https://serverfault.com/questions/1043441/how-to-run-kvm-nested-in-wsl2-or-vmware&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://serverfault.com/questions/1043441/how-to-run-kvm-nested-in-wsl2-or-vmware&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724491607888&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;How to run KVM nested in WSL2 (or vmware)?&quot; data-og-description=&quot;I'm trying to follow this tutorial to run KVM nested in WSL 2, but after following the directions through compiling the kernel and loading it, the test kvm-ok reports that KVM is not supported. I've&quot; data-og-host=&quot;serverfault.com&quot; data-og-source-url=&quot;https://serverfault.com/questions/1043441/how-to-run-kvm-nested-in-wsl2-or-vmware&quot; data-og-url=&quot;https://serverfault.com/questions/1043441/how-to-run-kvm-nested-in-wsl2-or-vmware&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/KBwJO/hyWShxmW3M/nTvfQ57SFwtm2QFQJrTyWK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/bwBAtF/hyWSiXkljx/R82QAvnnZjICcvttas6kW1/img.png?width=1114&amp;amp;height=1693&amp;amp;face=0_0_1114_1693,https://scrap.kakaocdn.net/dn/Qag1p/hyWVRX5RPL/MODMtCgEMHl1WP0dPABAb1/img.png?width=651&amp;amp;height=1250&amp;amp;face=0_0_651_1250&quot;&gt;&lt;a href=&quot;https://serverfault.com/questions/1043441/how-to-run-kvm-nested-in-wsl2-or-vmware&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://serverfault.com/questions/1043441/how-to-run-kvm-nested-in-wsl2-or-vmware&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/KBwJO/hyWShxmW3M/nTvfQ57SFwtm2QFQJrTyWK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/bwBAtF/hyWSiXkljx/R82QAvnnZjICcvttas6kW1/img.png?width=1114&amp;amp;height=1693&amp;amp;face=0_0_1114_1693,https://scrap.kakaocdn.net/dn/Qag1p/hyWVRX5RPL/MODMtCgEMHl1WP0dPABAb1/img.png?width=651&amp;amp;height=1250&amp;amp;face=0_0_651_1250');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;How to run KVM nested in WSL2 (or vmware)?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I'm trying to follow this tutorial to run KVM nested in WSL 2, but after following the directions through compiling the kernel and loading it, the test kvm-ok reports that KVM is not supported. I've&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;serverfault.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/48</guid>
      <comments>https://neverparadise.tistory.com/48#entry48comment</comments>
      <pubDate>Sat, 24 Aug 2024 18:48:30 +0900</pubDate>
    </item>
    <item>
      <title>벨만 최적방정식의 수렴성</title>
      <link>https://neverparadise.tistory.com/47</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;강화학습을 처음 공부하면 마르코프 의사결정 과정에서는 최소한 하나 이상의 최적 정책이 존재한다는 정리를 배우게 된다. 많은 RL 논문에서 이 정리와 비슷한 방식으로 개념을 증명한다. 본 글에서는 왜 하나의 최적 정책이 존재할 수 있는가? 에 대해 정리한 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 배경지식은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Background&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Markov Decision Process&lt;/li&gt;
&lt;li&gt;Policy, Return, Bellman Equation&lt;/li&gt;
&lt;li id=&quot;9a8e&quot;&gt;거리공간(Metric Spaces)&lt;/li&gt;
&lt;li&gt;코시수열(Cauchy Sequence)&lt;/li&gt;
&lt;li&gt;축약사상(Contraction mapping)&lt;/li&gt;
&lt;li&gt;바나흐고정점정리(Banach Fixed Point Theorem)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Markov Decision Process&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마르코프 의사결정 과정은 $&amp;lt;S, A, R, P, \gamma&amp;gt;$ 5개의 튜플로 구성된 이산시간 랜덤 프로세스다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태 $ S$: 풀고자 하는 의사결정 문제에서 에이전트가 존재할 수 있는 상태들의 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행동 $ A$: 상태에서 에이전트가 취할 수 있는 행동들의 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;보상 $ R$&lt;/span&gt;: 에이전트가 특정 상태에 도달하거나 행동을 취할 때 마다 받는 보상 신호 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;전이확률 $ P$&lt;/span&gt;: 특정 상태에서 어떤 행동을 했을 때 다른 상태로 전이할 확률&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;할인율$ \gamma $&lt;/span&gt;: 현재의 보상에 더 가중치를 주기 위한 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Policy, Return, Bellman Equation&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정책 $\pi(A_t = a|S_t = s)$: 에이전트가 특정 상태에서 어떤 행동을 취할 확률&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리턴 $G_t = \sum_{k=t+1}^T \gamma^{T-k-1}R_{k+1} &amp;nbsp;$: 누적 보상의 합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가치함수: $V(s) = \mathbb E [G_t|S_t = s]$. 누적 보상합의 기댓값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벨만기대방정식 &lt;span&gt;$V_\pi (s) = \mathbb E_\pi [R_{t+1} + \gamma V(S_{t+1})|S_t = s]$&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;: 가치함수를 보상과 다음 상태의 가치함수 합의 기댓값으로 재귀적으로 표현한 식. 다이나믹 프로그래밍을 통해 계산 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;벨만최적방정식&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;$V^*(s) = \max_{a\in \cal {A}} \mathbb E [R_{t+1} + \gamma V^*(S_{t+1})|S_t = s, A_t=a]$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Overview&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 다음을 증명하고자 한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Theorem:&amp;nbsp;For any finite MDP, there exists an optimal policy &amp;pi;* such that it is better than or equal to every other possible policy &amp;pi;.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최적의 정책을 찾으려면 우리는 정책들에 '순서'를 매길 수 있어야 한다. 그런데 정책은 위에서 확률분포라고 했다. 어떻게 정책들에 순서를 매길 수 있을까? 예를 들어 철수의 키가 180이고 영희의 키가 170이라고 하자 철수의 키는 영희보다 크므로 '철수 &amp;gt; 영희' 와 같은 방식으로 순서를 매길 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 값들의 크고 작음을 살펴봄으로써 순서를 매길 수 있다. 정책의 경우 정책을 통해 계산되는 가치함수의 값으로 비교를 수행할 수 있다. 두 정책 $\pi_1, \pi_2$의 순서를 매기는 문제는 곧 $V_{\pi_1},V_{\pi_2} $의 대소를 비교하여 나열하는 것과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&amp;nbsp;\pi_1&amp;nbsp;\ge&amp;nbsp;\pi_2&amp;nbsp;\&amp;nbsp;\text{if}&amp;nbsp;\&amp;nbsp;&amp;nbsp;&amp;nbsp;V_{\pi_1}&amp;nbsp;\ge&amp;nbsp;V_{\pi_2}&amp;nbsp;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위를 통해 정책의 좋고 나쁨을 비교하는 방법을 알았다. 우리는 어떤 정책이 다른 모든 정책보다&amp;nbsp; 같거나 더 좋다는 것을 보이면 된다. 이에 대한 증명은 바나흐 고정점 정리(Banach Fixed Point Theorem)를 이해해야한다. 바나흐 고정점 정리를 이해하려면 고정점 문제, 거리 공간, 코시 수열, 축약 사상에 대한 지식이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;고정점문제(Fixed point problem)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고정점 문제는 $f(x) = x$의 해를 구하는 문제이다. 문제의 이름처럼 $x$는 고정점이라고 부른다. 이 문제를 푸는 방법은 매우 간단하다. $x$의 어떤 무작위 시작점을 선택하고 반복적으로 함수값에 넣어서 함수값을 다시 입력으로 사용하면 된다.&amp;nbsp; 함수값이 수렴한다면 해를 찾은 것이 된다. $f^n (x)$를 함수를 $x$에 n번 적용한 함수라고 생각하자. 여기서 $f(x)$는 연속이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\begin{align}&amp;nbsp;\text{let},&amp;nbsp;x^*&amp;nbsp;&amp;amp;=&amp;nbsp;\lim_{n&amp;nbsp;\rightarrow&amp;nbsp;\infty}&amp;nbsp;f^n(x_0)&amp;nbsp;\\&amp;nbsp;f(x^*)&amp;nbsp;&amp;amp;=&amp;nbsp;f(\lim_{n&amp;nbsp;\rightarrow&amp;nbsp;\infty}&amp;nbsp;f^n(x_0))&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\lim_{n&amp;nbsp;\rightarrow&amp;nbsp;\infty}&amp;nbsp;f(f^n(x_0))&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\lim_{n&amp;nbsp;\rightarrow&amp;nbsp;\infty}&amp;nbsp;f^{n+1}(x_0))&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;x^*&amp;nbsp;\end{align}$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수가 연속이므로 sequential criterion for continuity [4] 에 의해 limit 연산을 밖으로 꺼낼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;거리공간(Metric space)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리공간은 거리라는 대수구조가 부여된 집합이다. 집합 내의 두 원소들 사이의 거리를 계산할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 집합 $X$에 대해서 거리를 다음과 같이 정의한다. 즉 거리는 $X$ 집합 내의 원소들의 순서쌍을 실수로 사상하는 함수다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ d :X \times X \rightarrow \mathbb R$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리 공간은 $(X, d)$와 같이 집합과 거리의 튜플로 표기한다. 거리 공간은 다음과 같은 성질을 지닌다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) $d(x, y) = 0 \leftrightarrow x= y$ &lt;b&gt;(Identify)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) $d(x, y) \ge 0$ &lt;b&gt;(&lt;span&gt;Non-Negativity)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) $d(x_a, x_b) = d(x_a, x_b)$ &lt;b&gt;(&lt;span&gt;Symmetry)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) $d(x_a, x_b) + d(x_b, x_c) \ge d(x_a, x_c)$ &lt;b&gt;(Triangular inequality)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코시수열(Cachy sequence)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코시 수열은 첨수가 커질수록, 수열이 진행될 수록 두 원소의 값(거리)이 점점 가까워지는 수열이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리 공간 $(X, d)$ 상에서 $X$의 임의의 두 원소 $x_a, x_b$를 선택했을 때, 모든 양수인 $\epsilon &amp;gt; 0$에 대해서 $a, b \ge N \rightarrow d(x_a, x_b) &amp;lt; \epsilon$ 을 만족시키는 정수 $N$이 존재하면 이를 코시수열이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;완비거리공간(Complete Metric space)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임의의 거리 공간 $(&lt;span data-reactroot=&quot;&quot;&gt;X, d)$ &lt;/span&gt;가 주어졌다고 하자, 만약 $&lt;span data-reactroot=&quot;&quot;&gt;X$ &lt;/span&gt;내의 임의의 코시수열이 어떤 값으로 수렴하고 그 값이 $X$에 속한다면, 그 거리공간은 완비성을 갖추었다고 말한다. 간단하게 거리 공간이 꽉 차있다고 생각하면 되겠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;축약사상(Contraction Mapping)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거리공간 상의 두 원소들에 대한 거리 $d(x_1, x_2)$가 있다. 두 원소들을 함수를 통과시켜 다시 거리를 계산한 것을 $d(f(x_1), f(x_2))$라고 하자. 원래의 거리 $d(x_1, x_2)$보다 함수를 통과시킨 원소들의 거리 $d(f(x_1), f(x_2))$가 같거나 작아지면 이를 축약사상이라고 한다. 수식으로는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ d(f(x_1), f(x_2)) \le \gamma d(x_1, x_2) $$&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;거리 함수 $d$를 가지는 거리공간 $(X, d)$에서 정의된 어떤 함수 $f$를 정의하자. 임의의 $x, y \in X$에 대하여 $d(f(x), f(y)) \le \gamma d(x, y)$를 만족하는 $\gamma &amp;lt; 1$이 존재하면 $f$를 축약사상이라고 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 축약사상은 두 원소들 사이의 거리를 감소시키게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;바나흐 고정점 정리(Banach fixed point theorem)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Theorem: Let $(X, d)$ be a complete metric space and a function $f: X \rightarrow X$ be a contractor then, f has a unique fixed point $x*&amp;isin; X (i.e. f(x*)=x*)$ such that the sequence $f(f(f(&amp;hellip;f(x))))$ converges to $x*$.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바나흐 고정점 정리는 완비거리공간 상에서 정의된 축약사상이 유일한 고정점을 갖는다는 정리이다. 이를 활용해서 MDP가 최적 정책을 가진다는 것을 보일 수 있다. 고정점 정리를 증명해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완비거리공간 &lt;span style=&quot;color: #666666;&quot;&gt;$(X, d)$&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;에서 &lt;span style=&quot;color: #666666;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;$X$의 임의의 점 $x_0$ 을 고려해보자. 우리는 이 점으로부터 반복해서 축약사상을 적용하고 수열을 만들어낼 것이다. $X$에 속하는 $n$번째 수열을 사상시켜서 $x_{n+1}$을 얻어낼 수 있다. 이를 0번째까지 반복하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$x_{n+1} = f(x_n) =&amp;nbsp; f(f(x_{n-1})) = \cdots =&amp;nbsp; f^n(x_0), \quad \text {for} \ n \ge 0.$$ $x_{m+1}, x_{n+1}$ 원소들은 m번째, n번째 원소들에 축약사상을 적용한 것이므로 다음과 같다. &lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;$(x_{n+1} = f(x_n))$&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$d(x_{m+1}, x_{n+1}) =&amp;nbsp;&amp;nbsp;d(f(x_m), f(x_{n}))$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;축약사상 $f$를 계속해서 적용해서 수열 $\{x_n \}_{n \in \mathbb N}$을 얻을 수 있었다 여기에 축약사상의 정의를 통해서 다음을 유도할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$d(x_{m+1}, x_{n+1}) = d(f(x_m), f(x_{n})) \le \gamma d(x_m, x_n)$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;증명&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 $x_n$이 코시 수열인지를 보이자. 만약 $ n \ge m \ge 1$이라면 축약사상의 정의와 삼각부등식을 활용해서 다음을 얻게 된다.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\begin{align}&amp;nbsp;d(x_n,&amp;nbsp;x_m)&amp;nbsp;&amp;amp;=&amp;nbsp;d(f^n(x_0),&amp;nbsp;f^m(x_0))&amp;nbsp;\\&amp;nbsp;&amp;amp;\le&amp;nbsp;\gamma^m&amp;nbsp;d(f^{n-m}x_0,&amp;nbsp;x_0)&amp;nbsp;\\&amp;nbsp;&amp;amp;\le&amp;nbsp;\gamma^m[d(f^{n-m}x_0,&amp;nbsp;f^{n-m-1}x_0)&amp;nbsp;+&amp;nbsp;d(f^{n-n-1}x_0,&amp;nbsp;f^{n-m-2}x_0)&amp;nbsp;\\&amp;nbsp;&amp;amp;&amp;nbsp;+&amp;nbsp;\cdots&amp;nbsp;+&amp;nbsp;d(f(x_0),&amp;nbsp;x_0)]&amp;nbsp;\quad&amp;nbsp;(\text{triangle&amp;nbsp;inequality})&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\gamma^m&amp;nbsp;[d(f^{n-m-1}x_1,&amp;nbsp;f^{n-m-1}x_0)&amp;nbsp;+&amp;nbsp;d(f^{n-m-2}x_1,&amp;nbsp;f^{n-m-2}x_0)&amp;nbsp;\\&amp;nbsp;&amp;amp;&amp;nbsp;+\cdots&amp;nbsp;+&amp;nbsp;d(x_1,&amp;nbsp;x_0)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\\&amp;nbsp;&amp;amp;\le&amp;nbsp;\gamma^m&amp;nbsp;\bigg&amp;nbsp;[&amp;nbsp;\sum_{k=0}^{n-m-1}\gamma^k&amp;nbsp;\bigg&amp;nbsp;]d(x_1,&amp;nbsp;x_0)&amp;nbsp;&amp;nbsp;\\&amp;nbsp;&amp;amp;\le&amp;nbsp;\gamma^m&amp;nbsp;\bigg&amp;nbsp;[&amp;nbsp;\sum_{k=0}^{\infty}\gamma^k&amp;nbsp;\bigg&amp;nbsp;]d(x_1,&amp;nbsp;x_0)&amp;nbsp;\\&amp;nbsp;&amp;amp;\le&amp;nbsp;\bigg(&amp;nbsp;{c^m&amp;nbsp;\over&amp;nbsp;1-c}\bigg&amp;nbsp;)d(x_1,&amp;nbsp;x_0)\end{align}$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 두 원소 사이의 거리는 m이 증가함에 따라 수렴하며, 이는 코시 수열의 정의와 일치한다. $X$가 완비이기 때문에 수열 $(x_n)$도 $X$ 내의 극한값 $x^*$ 로 수렴하게 된다. 극한값 &lt;span&gt;$x^*$&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;가 $f$의 고정점이라는 사실은 $f$의 연속성으로부터 유도된다.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;$$ f(x^*) = f (\lim_{n \rightarrow \infty}{x_n}) = \lim_{n \rightarrow \infty}f({x_n}) =&amp;nbsp;&amp;nbsp;\lim_{n \rightarrow \infty}x_{n+1} = x^*$$&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;벨만 최적방정식의 수렴&lt;/h2&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$B$라는 optimal bellman operator를 정의해보자. 가치함수를 입력 받아서 다시 가치함수를 출력하며, 이는 가치함수를 하나의 벡터로 보았을 때 벡터공간 상에서 벡터를 벡터로 보내는 사상으로 생각할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$BV(s) = \max_a R^a_s + \gamma \sum_{s^\prime\in S} P^a_{ss^\prime}V(s^\prime)$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;optimal bellman operator는 재귀적으로 동작하기에 가치함수의 수열을 만들게 된다. &lt;b&gt;만약 $B$가 어떤 거리 공간 상에서의 축약사상이라면,&lt;/b&gt; $B$를 반복적용했을 때 unique한 optimal value function을 얻을 수 있다. (바나흐 고정점정리) 그리고 이것은 최적 정책의 존재성을 유도하게 된다. 따라서 거리공간이 완비이고 $B$가 축약사상이라는 것을 증명하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;거리공간&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가치함수 $V(s)$는 특정 상태를 입력으로 받아 스칼라를 출력한다. 상태의 개수가 유한하다면 모든 상태에 대한 가치함수의 출력값들 $V$는 유한차원 벡터가 된다. 따라서 거리공간은 다음과 같이 정의된다. 지수 부분은 상태공간의 크기를 말한다. (집합의 원소개수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$X: V \in \mathbb R^{|\mathbb S|}$$&lt;/p&gt;
&lt;div&gt;Finite MDP에서는 보상값이 유한하므로 가치함수의 값은 항상 실수공간에 존재하게 된다. 따라서 거리공간은 완비가 된다.&lt;/div&gt;
&lt;div&gt;거리를 정의하기 위해서 L-infinity norm을 사용한다. 이는 다음과 같이 정의되며 X의 집합 중에서 최댓값을 거리로 사용하겠다는 의미이다.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;$$ ||X||_\infty = \max_{i \in [0, |X|]}|X_i|$$&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 정의들에 의해 다음의 정리가 유도된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Theorem: Bellman operator $B$&amp;nbsp;is a contraction mapping in the finite space&amp;nbsp;&lt;br /&gt;$(R, L-infinity)$&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;증명&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가치함수 $V_1, V_2$가 있다고 가정하자&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/epHqbg/btrT7FIjgfE/nGG0f9JQT7G6Meik3hPiU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/epHqbg/btrT7FIjgfE/nGG0f9JQT7G6Meik3hPiU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/epHqbg/btrT7FIjgfE/nGG0f9JQT7G6Meik3hPiU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FepHqbg%2FbtrT7FIjgfE%2FnGG0f9JQT7G6Meik3hPiU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1313&quot; height=&quot;541&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&amp;nbsp;&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;첫 번째 둘에서 두 번째 줄로 갈 때 $a^\prime$이 $a$로 대체하게 되는데 이것이 가치함수 값을 감소시켜서 부등식꼴이 된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;세 번째 줄에서 네 번째 줄로 갈 때는 거리를 infinity norm을 사용했기에 max에 $s^\prime$이 붙는다.&lt;/li&gt;
&lt;li&gt;다섯 번째 줄에서 확률을 다 더한 것은 1이므로 사라지고 축약사상의 꼴을 맞추기 위해 다시 norm을 씌운다.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 벨만 연산자는 축약사상이다. 벨반 연산자를 반복적용하면 바나흐 고정점 정리에 의해 최적의 가치함수로 수렴한다. 그리고 최적 가치함수로부터 최적 정책을 계산할 수 있게 된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1] &lt;a href=&quot;https://towardsdatascience.com/why-does-the-optimal-policy-exist-29f30fd51f8c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://towardsdatascience.com/why-does-the-optimal-policy-exist-29f30fd51f8c&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[2] &lt;a href=&quot;https://towardsdatascience.com/mathematical-analysis-of-reinforcement-learning-bellman-equation-ac9f0954e19f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://towardsdatascience.com/mathematical-analysis-of-reinforcement-learning-bellman-equation-ac9f0954e19f&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[3]&amp;nbsp;&lt;a href=&quot;https://stats.stackexchange.com/questions/468361/bellmans-equation-and-existence-of-optimal-policy-for-mdps&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stats.stackexchange.com/questions/468361/bellmans-equation-and-existence-of-optimal-policy-for-mdps&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[4] &lt;a href=&quot;https://www.geneseo.edu/~aguilar/public/notes/Real-Analysis-HTML/ch5-continuity.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.geneseo.edu/~aguilar/public/notes/Real-Analysis-HTML/ch5-continuity.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/47</guid>
      <comments>https://neverparadise.tistory.com/47#entry47comment</comments>
      <pubDate>Tue, 20 Dec 2022 15:27:10 +0900</pubDate>
    </item>
    <item>
      <title>RNN Policy 에 관하여 - (1)</title>
      <link>https://neverparadise.tistory.com/45</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;강화학습을 여러 문제에 적용하면서 보통은 Policy의 아키텍처를 FC layer나 CNN으로 설정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Partially Observable한 문제를 해결하기 위해 state를 쌓아서 policy input으로 많이 사용하는데 RNN을 사용해서 해결할 수도 있다. Policy에 단지 RNN을 추가했을 뿐인데 전체적인 학습 과정에서 꽤나 변화가 발생한다. 이번 포스팅에서는 RNN Policy의 전반적인 내용을 정리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. RNN&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2061&quot; data-origin-height=&quot;1664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGUgt1/btrOyCYbucj/KkHnDiSsC05K67ZSksE5l1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGUgt1/btrOyCYbucj/KkHnDiSsC05K67ZSksE5l1/img.png&quot; data-alt=&quot;그림 1: RNNCell&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGUgt1/btrOyCYbucj/KkHnDiSsC05K67ZSksE5l1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGUgt1%2FbtrOyCYbucj%2FKkHnDiSsC05K67ZSksE5l1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2061&quot; height=&quot;1664&quot; data-origin-width=&quot;2061&quot; data-origin-height=&quot;1664&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 1: RNNCell&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 보통 시퀀스를 처리하는 RNN의 구조는 위 그림과 같다. 원에 해당하는 것은 변수들이고 사각형은 뉴럴네트워크다. RNN은 이전시점의 은닉상태 $h_{t-1}$와 현재 시점의 입력 $x_{t}$을 받아서 $h_{t}$를 출력한다. RNN이 LSTM 인지, GRU 인지에 따라 $h_{t}$읙 구성이 바뀌게 된다. LSTM이면 output, (hidden state, cell state)를 리턴하고, Vanila RNN, GRU면 output, hidden state만을 리턴한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$output$의 경우 $(L, N, H_{out})$의 텐서가 출력되며, $h_t$의 경우 $(num\_ layers, N, H_{out})$ 형태의 텐서가 출력된다. &lt;b&gt;여기서 중요한 것은 RNNCell과 RNN의 차이이다. RNN은 RNNCell을 일반화한 것이다. 여러 개의 RNN Cell을 쌓아서 RNN을 만들 수 있다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2599&quot; data-origin-height=&quot;1040&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzFayX/btrOzeCWHd3/XVR4h3FC25khOGUXHOnWR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzFayX/btrOzeCWHd3/XVR4h3FC25khOGUXHOnWR0/img.png&quot; data-alt=&quot;그림 2: RNN&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzFayX/btrOzeCWHd3/XVR4h3FC25khOGUXHOnWR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzFayX%2FbtrOzeCWHd3%2FXVR4h3FC25khOGUXHOnWR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2599&quot; height=&quot;1040&quot; data-origin-width=&quot;2599&quot; data-origin-height=&quot;1040&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 2: RNN&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;1606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAiDUu/btrOBAZwxfy/yQxkCQu8vKnlDKRbzS1HN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAiDUu/btrOBAZwxfy/yQxkCQu8vKnlDKRbzS1HN0/img.png&quot; data-alt=&quot;그림 3: RNN Detail&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAiDUu/btrOBAZwxfy/yQxkCQu8vKnlDKRbzS1HN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAiDUu%2FbtrOBAZwxfy%2FyQxkCQu8vKnlDKRbzS1HN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1640&quot; height=&quot;1606&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;1606&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3: RNN Detail&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; RNN은 $(L, H_{in})$ 또는 &lt;b&gt;$(L,&amp;nbsp; N, H_{in})$ 형태의 텐서를 입력받는데 *시퀀스를 한 번에 입력받는다.* 만약 batched tensor를 처리하고 싶다면 각 모든 시퀀스들을 길이 $L$로 맞춰줘야 한다. &lt;b&gt;&lt;b&gt;RNNCell의 경우 시퀀스 텐서의 한 timestep 값인 $(N, H_{in})$ 텐서를 입력받는다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;의문을 가져볼만 한 것은, output의 경우 hidden state의 값을 순차적으로 시간에 따라 수집한 값들이다. hidden의 경우 마지막 스텝이 끝나고의 hidden state 값인데, 이미 output[-1]을 통해 hidden에 접근할 수 있는데 왜 굳이 리턴을 두 개로 만들었을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. RNN Value, Policy&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2935&quot; data-origin-height=&quot;1054&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/can3le/btrOBMesSNa/2FJ1O3w0LukMfRVoAHOVqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/can3le/btrOBMesSNa/2FJ1O3w0LukMfRVoAHOVqk/img.png&quot; data-alt=&quot;그림 4: RNN Value, Policy&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/can3le/btrOBMesSNa/2FJ1O3w0LukMfRVoAHOVqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcan3le%2FbtrOBMesSNa%2F2FJ1O3w0LukMfRVoAHOVqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2935&quot; height=&quot;1054&quot; data-origin-width=&quot;2935&quot; data-origin-height=&quot;1054&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4: RNN Value, Policy&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이제 RNN으로 Value와 Policy를 매개변수화하는 상황을 생각해보자. 환경을 초기화 한다음, 값이 0으로 채워진 init_hidden_state를 만들고 policy에 넣어주면서 rollout을 하면 될 것 같다. &lt;b&gt;아래 그림에서는 hidden이 드러나게 pesudo code를 작성했지만, 실제 구현할 때는 hidden을 멤버변수로 선언해서 rollout 과정에서 드러나지 않게 할 것이다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drqGSK/btrOB1bjWn4/kpjCcHP7DIb6Lx8LExj67k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drqGSK/btrOB1bjWn4/kpjCcHP7DIb6Lx8LExj67k/img.png&quot; data-alt=&quot;Figure: pseudo code&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drqGSK/btrOB1bjWn4/kpjCcHP7DIb6Lx8LExj67k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrqGSK%2FbtrOB1bjWn4%2FkpjCcHP7DIb6Lx8LExj67k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;660&quot; height=&quot;231&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure: pseudo code&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 문제가 되는 것은 우리는 그림 2처럼 RNNCell이 아닌 RNN을 사용할 것이라는 점이다. 위에서 설명한대로 RNN은 $(L, N, H_{in})$ 형태의 텐서를 입력받는다. 즉, &lt;b&gt;텐서에 시퀀스 차원이 포함되어야 한다!!&amp;nbsp;&lt;/b&gt;이 때문에 RNNPolicy Class 에서 forward 함수를 만들 때 여러 가지 경우를 고려해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, training 중과 training이 아닐 때를 구분한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;training 중에는 (L, N, state_dim)의 텐서가 네트워크의 입력으로 들어온다.&amp;nbsp;&lt;/li&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;evaluation 중에는 (state_dim) 하나의 텐서가 입력으로 들어온다. (state가 이미지일 수도 있어서 텐서라고 표현했다)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 if else 문을 활용해서 input의 shape에 따라 경우를 나누어서 처리하는 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;입력이 state 하나만 들어오는 경우 unsqueeze()나 reshape()를 활용해서 (1, 1, state_dim)의 텐서로 만들어준다.&amp;nbsp;&lt;/li&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;입력이 배치 단위의 시퀀스인 경우 그대로 네트워크를 통과시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) LSTM이 전체 네트워크에서 제일 앞단에 위치한 경우&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if else 문을 활용해서 input의 shape에 따라 경우를 나누어서 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;입력이 state 하나만 들어오는 경우 unsqueeze()나 reshape()를 활용해서 (1, 1, state_dim)의 텐서로 만들어준다.&amp;nbsp;&lt;/li&gt;
&lt;li data-ke-style=&quot;style1&quot;&gt;입력이 배치 단위의 시퀀스인 경우 그대로 네트워크를 통과시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 네트워크 앞단에 FC Layer나 Conv Layer가 있어서 중간에 LSTM이 위치한 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FC Layer나 통과 시킨 Conv Layer를 통과시킨 값들을 RNN의 input shape에 맞게 reshape해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;training 중에는 어떤 Linear layer의 입력으로 (L, N, state_dim)가 들어올 것이다. training 중과 evaluation 중인 경우를 나누어서 처리해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Code&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# rnn_policy.py&lt;/p&gt;
&lt;pre id=&quot;code_1665732116448&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.distributions import Categorical, Normal
from torch.utils.data.sampler import BatchSampler, SubsetRandomSampler

def get_init_lstm_state(num_rnn_layers, hidden_dim, batch_size, is_training, device):
    if is_training:
        hidden = torch.zeros(num_rnn_layers, batch_size, hidden_dim).to(device)
    else:
        hidden = torch.zeros(num_rnn_layers, 1, hidden_dim).to(device)
    return hidden        

class RNNPolicy(nn.Module):
    def __init__(self, args) -&amp;gt; None:
        super().__init__()
        # information        
        self.is_continuous = args.is_continuous
        self.state_dim = args.state_dim
        self.linear_dim = args.linear_dim
        self.hidden_dim = args.hidden_dim
        self.action_dim = args.action_dim
        self.batch_size = args.batch_size
        self.device = torch.device(args.device)
        self.num_rnn_layers = args.num_rnn_layers
        
        # network
        self.fc = nn.Linear(args.state_dim, args.linear_dim)
        self.gru = nn.GRU(args.linear_dim, args.hidden_dim, \
                            num_layers=self.num_rnn_layers, bias=True)
        if self.is_continuous:
            self.mean = nn.Linear(self.hidden_dim, self.action_dim)
            self.std =  nn.Linear(self.hidden_dim, self.action_dim)
        else:
            self.policy_logits = nn.Linear(args.hidden_dim, self.action_dim)
        
    def _format(self, state, device):
        x = state
        if not isinstance(x, torch.Tensor):
            x = torch.tensor(x, dtype=torch.float32)
            x = x.to(device=device)
        else:
            x = x.to(device=device)
        return x
    
    def forward(self, state):
        state = self._format(state, self.device)
        if len(state.shape) &amp;lt; 3:
            state = state.reshape(1, 1, -1)
            self.hidden = get_init_lstm_state(self.num_rnn_layers, self.hidden_dim, \
                                        batch_size=1, device=self.device, is_training=False)
        x = F.leaky_relu(self.fc(state))
        x, self.hidden = self.gru(x, self.hidden)
        x, self.hidden = torch.tanh(x), torch.tanh(self.hidden)
        if self.is_continuous:
            mu = torch.tanh(self.mean(x))
            std = F.softplus(self.std(x))
            dist = Normal(mu, std)
        else:
            logits = self.policy_logits(x)
            prob = F.softmax(logits, dim=-1)
            dist = Categorical(prob)
        return dist

    def choose_action(self, state, is_training=False):
        dist = self.forward(state)
        action = dist.sample()
        if is_training:
            return action, dist.log_prob(action)
        else:
            while len(action.shape) != 1:
                action = action.squeeze(0)
            return action.detach().to('cpu').numpy(), dist.log_prob(action).detach().to('cpu').numpy()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Policy execution&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이제 코드를 실행시켜보자 환경 코드는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# point_env.py&lt;/p&gt;
&lt;pre id=&quot;code_1665732266170&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;&quot;&quot;Simple 2D environment containing a point and a goal location.&quot;&quot;&quot;
import math
import numpy as np
import random
import seaborn as sns
import matplotlib.pyplot as plt
from gym import Env
from gym import spaces, spec
import torch
import pygame, sys
from pygame.locals import *
import time

def semi_circle_goal_sampler():
    r = 1.0
    angle = random.uniform(0, np.pi)
    goal = r * np.array((np.cos(angle), np.sin(angle)))
    return goal


def circle_goal_sampler():
    r = 1.0
    angle = random.uniform(0, 2*np.pi)
    goal = r * np.array((np.cos(angle), np.sin(angle)))
    return goal


GOAL_SAMPLERS = {
    'semi-circle': semi_circle_goal_sampler,
    'circle': circle_goal_sampler,
}

from gym import Env
from gym import spaces

device = torch.device(&quot;cuda:0&quot; if torch.cuda.is_available() else &quot;cpu&quot;)


def semi_circle_goal_sampler():
    r = 1.0
    angle = random.uniform(0, np.pi)
    goal = r * np.array((np.cos(angle), np.sin(angle)))
    return goal


def circle_goal_sampler():
    r = 1.0
    angle = random.uniform(0, 2*np.pi)
    goal = r * np.array((np.cos(angle), np.sin(angle)))
    return goal


GOAL_SAMPLERS = {
    'semi-circle': semi_circle_goal_sampler,
    'circle': circle_goal_sampler,
}


class PointEnv(Env):
    &quot;&quot;&quot;
    point robot on a 2-D plane with position control
    tasks (aka goals) are positions on the plane

     - tasks sampled from unit square
     - reward is L2 distance
    &quot;&quot;&quot;

    def __init__(self, max_episode_steps=100, goal_sampler=None, is_render=False):
        self.is_render = is_render
        if callable(goal_sampler):
            self.goal_sampler = goal_sampler
        elif isinstance(goal_sampler, str):
            self.goal_sampler = GOAL_SAMPLERS[goal_sampler]
        elif goal_sampler is None:
            self.goal_sampler = semi_circle_goal_sampler
        else:
            raise NotImplementedError(goal_sampler)

        self.reset_task()
        self.task_dim = 2
        self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(2,))
        # we convert the actions from [-1, 1] to [-0.1, 0.1] in the step() function
        self.action_space = spaces.Box(low=-1.0, high=1.0, shape=(2,))
        self._max_episode_steps = max_episode_steps
        if self.is_render == True:
            pygame.init()
            self.fpsClock = pygame.time.Clock()
            self.width = 600
            self.height = 600
            self.window = pygame.display.set_mode((self.width,self.height), 0, 32)
            pygame.display.set_caption('PointEnv')

    def sample_task(self):
        goal = self.goal_sampler()
        return goal

    def set_task(self, task):
        self._goal = task

    def get_task(self):
        return self._goal

    def reset_task(self, task=None):
        if task is None:
            task = self.sample_task()
        self.set_task(task)
        return task

    def reset_model(self):
        self._state = np.zeros(2)
        return self._get_obs()
    
    def scale(self, array):
        new_x = 2 * (array[0] - self.width / 2) / self.width
        new_y = 2 * (array[1] - self.height / 2) / self.height
        new_array = np.array([new_x, new_y])
        return new_array

    def upscale(self, array):
        new_x = array[0] * self.width / 2 + self.width / 2
        new_y = array[1] * self.height / 2 + self.height / 2
        new_array = np.array([new_x, new_y])
        return new_array
        
    def render(self, mode, tick):
        if mode=='text':
            print(f'State: {self._state}, Goal: {self._goal}')
        elif mode=='rgb':
            time.sleep(tick)
            #background_color=(255, 255, 255)
            #self.window.fill(background_color) 없으면 경로 남음
            goal_state = self.upscale(self._goal)
            agent_state = self.upscale(self._state)
            pygame.draw.circle(self.window, (0, 255, 0), goal_state, 4)
            pygame.draw.circle(self.window, (255, 0, 0) , agent_state, 4)
            pygame.display.update()
            
    def reset(self):
        obs = self.reset_model()
        if self.is_render==True:
            background_color=(255, 255, 255)
            self.window.fill(background_color)
            pygame.display.update()
            goal_state = self.upscale(self._goal)
            agent_state = self.upscale(obs)
            pygame.draw.circle(self.window, (0, 255, 0), goal_state, 4)
            pygame.draw.circle(self.window, (255, 0, 0) , agent_state, 4)
            pygame.display.update()
        return obs

    def _get_obs(self):
        return np.copy(self._state)

    def step(self, action):
        action = np.clip(action, self.action_space.low, self.action_space.high)
        assert self.action_space.contains(action), action

        self._state = self._state + 0.1 * action
        reward = - np.linalg.norm(self._state - self._goal, ord=2)
        done = False
        ob = self._get_obs()
        info = {'task': self.get_task()}
        return ob, reward, done, info

    def close(self):
        self.close()
        pygame.quit()


class SparsePointEnv(PointEnv):
    &quot;&quot;&quot; Reward is L2 distance given only within goal radius &quot;&quot;&quot;

    def __init__(self, goal_radius=0.2, max_episode_steps=100, goal_sampler='semi-circle', is_render=False):
        super().__init__(max_episode_steps=max_episode_steps, goal_sampler=goal_sampler, is_render=is_render)
        self.goal_radius = goal_radius
        self.reset_task()

    def sparsify_rewards(self, r):
        ''' zero out rewards when outside the goal radius '''
        mask = (r &amp;gt;= -self.goal_radius).astype(np.float32)
        r = r * mask
        return r

    def reset_model(self):
        self._state = np.array([0, 0])
        return self._get_obs()

    def step(self, action):
        ob, reward, done, d = super().step(action)
        sparse_reward = self.sparsify_rewards(reward)
        # make sparse rewards positive
        if reward &amp;gt;= -self.goal_radius:
            sparse_reward += 1
        d.update({'sparse_reward': sparse_reward})
        d.update({'dense_reward': reward})
        return ob, sparse_reward, done, d
    
    def render(self, mode, tick):
        if mode=='text':
            print(f'State: {self._state}, Goal: {self._goal}')
        elif mode=='rgb':
            time.sleep(tick)
            goal_state = self.upscale(self._goal)
            agent_state = self.upscale(self._state)
            pygame.draw.circle(self.window, (0, 255, 0), goal_state, 4)
            pygame.draw.circle(self.window, (255, 0, 0) , agent_state, 4)
            pygame.display.update()
            
    def reset(self):
        obs = self.reset_model()
        if self.is_render==True:
            background_color=(255, 255, 255)
            self.window.fill(background_color)
            pygame.display.update()
            goal_state = self.upscale(self._goal)
            agent_state = self.upscale(obs)
            pygame.draw.circle(self.window, (0, 255, 0), goal_state, 4)
            pygame.draw.circle(self.window, (0, 0, 128), goal_state, self.goal_radius*(self.width/2))
            pygame.draw.circle(self.window, (255, 0, 0) , agent_state, 4)
            pygame.display.update()
        return obs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# policy_execution.py&lt;/p&gt;
&lt;pre id=&quot;code_1665732283112&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
import pygame

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--state_dim', default=2)
parser.add_argument('--linear_dim', default=128)
parser.add_argument('--hidden_dim', default=64)
parser.add_argument('--num_rnn_layers', default=2)
parser.add_argument('--action_dim', default=2)
parser.add_argument('--batch_size', default=16)
parser.add_argument('--device', default='cpu')
parser.add_argument('--is_continuous', default=True)

args = parser.parse_args()

from point_env import *
from rnn_policy import RNNPolicy

goal = semi_circle_goal_sampler()
logger.debug(goal)
rnn_policy = RNNPolicy(args)

env = SparsePointEnv(goal_radius=0.5, max_episode_steps=100, 
                     goal_sampler='semi-circle', is_render=True)
                     
for e in range(10):
    done = False
    obs = env.reset()
    step = 0
    while not done and step &amp;lt; env._max_episode_steps:
        env.render(mode='rgb', tick=0.1)
        env.render(mode='text', tick=None)
        action, log_prob = rnn_policy.choose_action(obs)
        next_obs, reward, done, info = env.step(action)
        step += 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;1099&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wqEyM/btrOClul5O6/WhkjmeYcSpOK6k4B6ZSukk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wqEyM/btrOClul5O6/WhkjmeYcSpOK6k4B6ZSukk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wqEyM/btrOClul5O6/WhkjmeYcSpOK6k4B6ZSukk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwqEyM%2FbtrOClul5O6%2FWhkjmeYcSpOK6k4B6ZSukk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;669&quot; height=&quot;707&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;1099&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스팅에서는 RolloutBuffer와 Loss Function의 Update를 살펴볼 예정이다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;</description>
      <category>Reinforcement Learning</category>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/45</guid>
      <comments>https://neverparadise.tistory.com/45#entry45comment</comments>
      <pubDate>Fri, 14 Oct 2022 16:28:29 +0900</pubDate>
    </item>
    <item>
      <title>Variational Inference 관련 내용 정리</title>
      <link>https://neverparadise.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;Variational Inference는 확률을 추론하는 문제를 위한 알고리즘이다. 확률 계산이 불가능한 상황에서 임의의 확률분포를 도입하고 최적화 문제로 바꾸어서 근사적인 방법으로 문제를 푼다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Variational Inference를 알기 위해서는 다음과 같은 지식들을 알면 좋다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Probabilistic&lt;span&gt; &lt;/span&gt;&lt;/span&gt;Graphical Model&lt;/li&gt;
&lt;li&gt;Probabilistic Inference&lt;/li&gt;
&lt;li&gt;Bayesian Inference&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Probabilistic Graphical Model&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/efBG1X/btrMIdlP343/ZG7y9sxx53TIDFH3UPeycK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/efBG1X/btrMIdlP343/ZG7y9sxx53TIDFH3UPeycK/img.png&quot; data-alt=&quot;그림1: Probabilistic Graphical Model&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/efBG1X/btrMIdlP343/ZG7y9sxx53TIDFH3UPeycK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FefBG1X%2FbtrMIdlP343%2FZG7y9sxx53TIDFH3UPeycK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;271&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;355&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림1: Probabilistic Graphical Model&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 랜덤변수들의 집합이 있다고 할 때, 그 랜덤변수들 간의 의존성(dependency)를 보기 쉽게 그래프로 표현한 것을 확률적 그래프 모델(Probabilistic Graphical Model)이라고 한다. PGM의 종류로는 세 가지가 있다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Bayesian Network&lt;/li&gt;
&lt;li&gt;Markov Network&lt;/li&gt;
&lt;li&gt;Factor Graph&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 베이지안 네트워크의 경우 비순환 방향성 그래프로 표현되며 랜덤변수 간의 의존성이 (조건부) 그림 1의 왼쪽처럼 화살표로 표시된다. 만약 랜덤변수들의 결합분포를 구하고자 한다면 $p(X, Y, Z) = p(Z|X, Y)p(Y|X)p(X)$를 계산해야 하지만 조건부 독립을 이용하면 $p(X, Y, Z) = p(Z|X)p(Y|X)p(X)$를 계산하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;factor graph.png&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYP7Lb/btrMInWfB43/H2CUaVmJGE7rgejZtpPUIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYP7Lb/btrMInWfB43/H2CUaVmJGE7rgejZtpPUIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYP7Lb/btrMInWfB43/H2CUaVmJGE7rgejZtpPUIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYP7Lb%2FbtrMInWfB43%2FH2CUaVmJGE7rgejZtpPUIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;377&quot; data-filename=&quot;factor graph.png&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 마르코프 네트워크의 경우 방향성 그래프로 표현되며 변수들 간의 의존성이 일직선으로 표현된다. 팩터 그래프의 경우는 그래프에서 몇몇 변수의 함수들을 factorization을 통해 표현한 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Probabilistic Inference&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &lt;span style=&quot;background-color: #ffffff; color: #232629;&quot;&gt;통계학에서 배우는 통계적 추론(Statistical Inference)은 모집단에 대한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232629;&quot;&gt;어떤 양상을 알기 위해 모수추정&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #232629;&quot;&gt;(parameter estimation) 또는 가설검정(testing hypothesis)를 수행한다. 그러면 &lt;/span&gt;확률적인 추론(Probabilistic Inference)란 무엇일까? 위키피디아에서는 확률적 추론이 통계적 추론의 한 방법이라고 말하고 있다. Daphne Koller의 &lt;span style=&quot;background-color: #ffffff; color: #232629;&quot;&gt;Probabilistic Graphical Models&lt;span&gt; 책에서는 확률추론 문제를 다음과 같이 정의한다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&amp;nbsp;Probabilistic inference is a type of statistical inference. &quot;Probabilistic inference&quot; was introduced and roughly defined in the PGM context as any marginalisation task of a probability function, whether it is a marginal probability computation or finding the most probable outcome (for e.g. classification)&lt;br /&gt;&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnunFo/btrMHI5D92v/uf7FyY9SRszeCbK7moOZmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnunFo/btrMHI5D92v/uf7FyY9SRszeCbK7moOZmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnunFo/btrMHI5D92v/uf7FyY9SRszeCbK7moOZmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnunFo%2FbtrMHI5D92v%2Fuf7FyY9SRszeCbK7moOZmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;708&quot; height=&quot;280&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉, 설명하자면, 베이지안 네트워크나 마르코프 네트워크 같은 어떤 확률 그래프 모형(PGM)에서 확률함수의 주변화(marginalisation)를 수행하는 것으로, 이 과정에서 주변확률이나 조건부확률을 계산하는 문제를 푸는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Bayesian Inference&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 베이즈 추론은 추론해야 하는 대상의 사전확률(prior)과 데이터를 기반으로 계산한 가능도(liklihood)를 통해 대상의 사후확률(posterior)를 계산하는 방법이다. 베이즈룰은 다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ P(\theta | X) = {P(X|\theta)P(\theta) \over P(X)} $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ P(X) = \sum_{x \in X} p(x|\theta )P(\theta) \ \text {or} \ \int p(x|\theta )P(\theta)dx $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 머신러닝의 관점에서 회귀문제나 분류 문제를 푸는 모델을 생각해보자. 현재 대세적인 방법은 liklihood $P(X|\theta)$를 최대화하기 위해 고정된 데이터셋 $X$에 대한 예측값을 출력하고 손실함수를 계산하여 gradient descent로 최적의 파라미터를 향해 업데이트 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 위 식의 베이즈 룰을 사용하면 데이터가 추가로 들어올 때마다 베이지안 방식으로 모델 파라미터를 업데이트 할 수 있다. 베이지안 방식으로 파라미터를 업데이트 하면 오버피팅을 방지 할 수 있고 노이즈에 더욱 강건하다고 한다 (PRML ch4). 이렇게 &lt;b&gt;사전확률과 추가적인 관측 데이터로 베이즈 룰을 통해 사후확률을 계산하는 방법을&amp;nbsp; Bayesian Inference라고 한다.&lt;/b&gt; 하지만 단점으로는 사전확률을 어떻게 정할 것인지의 문제가 있다. 또한 베이즈룰의 오른쪽 우변의 분모를 Evidence라고 하는데 evidence를 계산하기 위해 고차원의 적분, 합 연산을 하는 것이 까다로우며 확률분포를 모르는 경우 이를 계산할 수가 없다! 그래서 근사적인 방법으로 계산하거나 샘플링을 하게 되는데 이 방법들이 &lt;a href=&quot;https://bookdown.org/rdpeng/advstatcomp/laplace-approximation.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;라플라스 근사&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Markov_chain_Monte_Carlo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;몬테카를로 마르코프 체인&lt;/a&gt;, &lt;u&gt;&lt;b&gt;변분추론(Variational Inference)&lt;/b&gt;&lt;/u&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. ELBO&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 베이지안 추론을 할 때, 라플라스 근사 경우 연속형 랜덤변수를 사용해야 하고 특정 위치의 확률밀도함수 값을 가우시안분포로 근사하기에 사용하기에 제약이 많다. [5] 몬테카를로 마르코프 체인 (MCMC) 방법으로 샘플링을 통해 분모를 계산해서 업데이트 하는 방식은 정말로 느리다. [4] 그래서 베이지안 추론 문제를 최적화를 통해서 해결하는 Variational Inference를 많이 사용한다. 변분추론을 이해하기 위해서는 evidence lower bound(ELBO)을 먼저 이해해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ELBO&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &lt;b&gt;evidence lower bound는 어떤 관측값으로 계산된 log-likelihood의 하한이다. &lt;/b&gt;여기서 evidence는 베이즈 룰에서 우변의 분모에 해당했었다&lt;b&gt;.&lt;/b&gt;&amp;nbsp; 확률적 추론을 위해 수행하는 알고리즘 (기댓값 최대화, 변분 추론)에서 계산에 매우 유용하다. 이제 &lt;b&gt;어떤 잠재변수를 가진 모델의 확률추론 문제를 풀고 싶다고 생각해보자.&lt;/b&gt; 데이터의 경우 랜덤변수 $X$의 관측값(realization)이고 잠재변수는 랜덤변수 $Z$의 확률 분포를 따른다고 하자. 그러면 latent variable model은 $P(X, Z;\theta)$ 라는 결합분포로 표현될 수 있다. 우리는 랜덤변수 $X$ 만 관측할 수 있고, $Z$는 관측할 수 없다. 보통 우리가 풀고 싶은 문제는 다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 주어진 파라미터 $\theta$에 대해서 사후확률분포 $P(Z|X;\theta)$를 계산하는 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 파라미터 $\theta$를 알 수 없을 때, 주어진 sample $x$에 대한 $\theta$의 최대우도추정치를 찾고 싶을 때&lt;br /&gt;$$ \arg \max_{\theta} l(\theta), \\ \text {where} l(\theta) := \log p(x;\theta) = \log \int_z p(x, z;\theta)dz$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1)번 문제를 해결하기 위해 Variational Inference를 사용하게 된다. (2)번 문제를 해결하기 위해서 maximization 사용한다. 둘 다 알고리즘에서 ELBO를 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ELBO 유도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; evidence는 다음과 같이 정의된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ \text {evidence} := \log p(x;\theta) $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; evidence라는 이름이 붙은 이유는 모델 $p$의 파라미터 $\theta$를 잘 선택했을 때, $x$에 대한 주변확률이 커지게 된다. 따라서, 높은 $\log p(x;\theta)$는 우리가 데이터에 대한 좋은 모델을 선택했다는 증거라는 말인 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이제 식을 유도해보자. 우리는 유도를 위해 전확률 법칙과 젠슨의 부등식을 사용할 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ \begin{align} \log p(x;\theta) &amp;amp;= \log \int p(x, z;\theta) dz \\ &amp;amp;= \log \int p(x, z;\theta) {q(z) \over q(z) } dz \\ &amp;amp;= \log \mathbb E_{Z \sim q(Z)} \bigg [ {p(x, Z) \over q(Z) }\bigg ]&amp;nbsp; \\ &amp;amp;\ge \mathbb E_{Z \sim q(Z)} \bigg [ \log {p(x, Z) \over q(Z) } \bigg ] \end{align} $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유도과정에서 $z$에 대한 임의의 확률분포 $q$를 도입해서 $Z$에 대한 기댓값으로 식을 바꾸었다. 이렇게 하는 이유는 &lt;u&gt;&lt;b&gt;첫 번째 줄의 적분값을 계산할 수 없어서 중요도 샘플링(importance sampling)을 통해 적분값을 계산하는 몬테카를로 적분을 하기 위함이다. &lt;/b&gt;&lt;/u&gt;&amp;nbsp; 이후 젠슨의 부등식을 통해 lower bound를 유도한다. 수식을 간략히 하기 위해 $\theta$는 생략했다. 따라서 ELBO는 evidence 하한으로써 다음과 같이 정의된다. $$ \text {ELBO} :=&amp;nbsp;&amp;nbsp;\mathbb E_{Z \sim q(Z)} \bigg [ \log {p(x, Z) \over q(Z) } \bigg ] $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ELBO와 Evidence 사이의 gap&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부등식을 보아하니 ELBO의 값은 Evidence보다 작다. 그렇다면 얼마만큼 작을까? 유도해보자. $\theta$는 생략한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$\begin {align} \text {evidence} - \text {ELBO} &amp;amp;= \log p(x) - \mathbb E_{Z \sim q(Z)} \bigg [ \log {p(x, Z) \over q(Z) } \bigg ] \\ &amp;amp;=&amp;nbsp;&amp;nbsp;\mathbb E_{Z \sim q(Z)} [\log p(x)] - \mathbb E_{Z \sim q(Z)} \bigg [ \log {p(x, Z) \over q(Z) } \bigg ] \\ &amp;amp;= \mathbb E_{Z \sim q(Z)} [\log p(x)] - \mathbb E_{Z \sim q(Z)} [\log p(x, Z)] + \mathbb E_{Z \sim q(Z)} [\log q(Z)]\\ &amp;amp;= \mathbb E_{Z \sim q(Z)} \bigg [- \log{ p(x, Z) \over p(x)} \bigg] + \mathbb E_{Z \sim q(Z)} [\log q(Z)] \\ &amp;amp;= \mathbb E_{Z \sim q(Z)} [-\log p(Z|x)] + \mathbb E_{Z \sim q(Z)} [\log q(Z)] \\ &amp;amp;= \mathbb E_{Z \sim q(Z)} \bigg [\log{ q( Z) \over p(Z|x)} \bigg] \\ &amp;amp;= KL( q(z) || p(z|x)) \end {align}$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;결과적으로 ELBO와 Evidence 값의 차이는 $q(z)$와 $p(z|x)$의 KL 다이버전스가 된다. 시각화하면 다음과 같다. [8]&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;635&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q5yUe/btrMS3Xdg5E/bock1ZKWIydYx74qi71f9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q5yUe/btrMS3Xdg5E/bock1ZKWIydYx74qi71f9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q5yUe/btrMS3Xdg5E/bock1ZKWIydYx74qi71f9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ5yUe%2FbtrMS3Xdg5E%2Fbock1ZKWIydYx74qi71f9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;333&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;635&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 만약 KL 다이버전스의 값이 0에 가까워 진다면 어떻게 될까? 우리는 임의의 분포 $q(z)$가 $p(z|x)$를 잘 근사했다고 생각할 수 있다! evidence의 lower bound를 찾는 과정에서 근사적인 방법에 대한 실마리를 얻은 것이다. Variational Inference에서는 KL 값을 줄이도록 모델을 최적화하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. Variational Inference&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Motivation&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Variational Inference는 사후확률을 추정하는 high-level 패러다임이다. 특히, 사후확률계산이 불가능할 때 사용된다. 모델에 잠재변수 $Z$가 포함되고, 관측 데이터 $X$가 포함된다면 모델을 확률분포 $P(Z, X)$로 표현할 수 있다. &lt;span&gt;&lt;span&gt;&amp;nbsp;목적이 사후확률분포 $P(Z|X)$를 계산해야할 때 VI를 사용한다. 만약 사전확률, 가능도, 증거를 모두 알고 있다면 사후확률은 다음과 같이 베이즈 룰을 통해 계산될 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;$$ p(z|x) = {p(x|z)p(z) \over p(x)} $$&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;그러나 실제 문제에서는 사전확률분포도 알려져 있지 않고 evidence를 계산하기 위해서는 $p(x) = \int p(x, z) dz$를 계산해야 한다. 이때, &lt;b&gt;&lt;u&gt;사후확률을 계산하기 위해서 문제를 최적화 문제로 바꾸어서 근사적으로 사용하는 방법이 Variational Inference다.&amp;nbsp;&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; $p(z | x)$를 베이즈 룰을 통해 정확히 계산하는 것 대신에, VI는 $p(z|x)$와 '가까운' 어떤 임의의 분포 $q(z)$를 찾는다.$q(z)$의 값이 $p(z|x)$와 비슷하다면 우리는 $q(z)$를 통해 사후확률을 계산하면 되는 것이다.&amp;nbsp; $q(z)$는 $\phi$라는 파라미터로 매개변수화 되고, 이를 variational paratemeter라고 한다. 따라서 VI의 목적은 $q(z|\phi)$가 $p(z|x)$와 가깝도록 하는 어떤 파라미터 $\hat \phi$를 찾는다. 그리고 실제 사후확률에 대한 근사값 $q(z|\hat \phi)$을 반환한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Variational Inference는 $q(z)$와 $p(z|x)$의 가까운 정도를 측정하기 위해 KL 다이버전스를 이용한다. 이는 위에서 살펴보았던 evidence와 ELBO 값의 차이로 정의된다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ KL( q(z) || p(z|x)) := \mathbb E_{Z \sim q(Z)} \bigg [\log{ q( Z) \over p(Z|x)} \bigg] $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;VI는 KL 다이버전스를 최소화하는 분포를 찾는다. 이는 아래와 같이 표현할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ \hat q := \arg \min_q KL(q_\phi (z) || p(z|x)) $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ \hat \phi = \arg \min_ \phi KL(q_\phi (z) || p(z|x)) $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 위 문제의 해는 $q(z)$와 $p(z|x)$에 대한 KL 다이버전스를 최소화하는 해이다. &lt;b&gt;그런데 문제는 여전히 KL 다이버전스 값을 우리는 계산할 수 없다는 것이다. &lt;/b&gt;$p(z|x)$를 계산하려면 $p(x, z) \over p(x)$를 계산해야하기 때문이다.&amp;nbsp; 대신에 우리는 우회해서 우변을 최소화한다. KL 다이버전스(좌변)는 evidence와 ELBO 값의 차이(우변)로 정의된다는 것이었다. 이는 곧 &lt;b&gt;KL 다이버전스를 최소화하는 문제는 evidence와 ELBO 값의 차이를 최소화하는 문제이며 evidence는&amp;nbsp; q에 의존하지 않기 때문에 ELBO를 최대화하는 것과 동일하다! 그래서 우리는 베이지안 추론을 근사하는 문제를 최적화 문제로 바꿀 수 있는 것이다. (evidence가 q에 의존하지 않는다는 것은 최적화 과정에서 미분에 의해 사라질 것이라는 것음 암시한다.)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;br /&gt;&lt;b&gt;Calculation&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;우변의 evidence 값을 최소화하면서 ELBO를 최대화하면 KL 다이버전스의 값을 0으로 만들 수 있을 것이다. 이제 이 계산을 어떻게 직접하는지 알아보자. KL 다이버전스의 값은 $p(z|x)$ 항을 계산할 수 없어서 여전히 KL 값을 얻기 어렵다. KL 다이버전스의 식을 다시 정리해보자. $p(z|x)$에 베이즈룰을 적용할 것이다. 아래 식에서 $q_\phi(z)$에 대한 파라미터 $\phi$는 생략 했다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;$$\begin{align}&amp;nbsp;KL(q&amp;nbsp;(z)&amp;nbsp;||&amp;nbsp;p(z|x))&amp;nbsp;&amp;amp;=&amp;nbsp;\int&amp;nbsp;q(z)\log&amp;nbsp;{q(z)&amp;nbsp;\over&amp;nbsp;p(z|x)}dz&amp;nbsp;&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\int&amp;nbsp;q(z)\log&amp;nbsp;{q(z)p(x)&amp;nbsp;\over&amp;nbsp;p(x|z)p(z)}dz&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\int&amp;nbsp;q(z)&amp;nbsp;\bigg&amp;nbsp;(&amp;nbsp;\log&amp;nbsp;q(z)&amp;nbsp;+&amp;nbsp;\log&amp;nbsp;p(x)&amp;nbsp;-&amp;nbsp;\log&amp;nbsp;p(x|z)&amp;nbsp;-&amp;nbsp;\log&amp;nbsp;p(z)&amp;nbsp;\bigg&amp;nbsp;)&amp;nbsp;dz&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\int&amp;nbsp;q(z)&amp;nbsp;\bigg&amp;nbsp;(&amp;nbsp;\log{q(z)\over&amp;nbsp;p(z)}&amp;nbsp;+&amp;nbsp;\log&amp;nbsp;p(x)&amp;nbsp;-&amp;nbsp;\log&amp;nbsp;p(x|z)&amp;nbsp;\bigg&amp;nbsp;)&amp;nbsp;dz&amp;nbsp;&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\mathbb&amp;nbsp;E_q&amp;nbsp;\bigg&amp;nbsp;[\log&amp;nbsp;{q(z)\over&amp;nbsp;p(z)}&amp;nbsp;\bigg&amp;nbsp;]&amp;nbsp;+&amp;nbsp;\mathbb&amp;nbsp;E_q&amp;nbsp;[\log&amp;nbsp;p(x)]&amp;nbsp;-&amp;nbsp;\mathbb&amp;nbsp;E_q[\log&amp;nbsp;p(x|Z)]&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;&amp;nbsp;\mathbb&amp;nbsp;E_q&amp;nbsp;[\log&amp;nbsp;p(x)]&amp;nbsp;&amp;nbsp;+&amp;nbsp;\mathbb&amp;nbsp;E_q&amp;nbsp;\bigg&amp;nbsp;[\log&amp;nbsp;{q(z)\over&amp;nbsp;p(z)}&amp;nbsp;\bigg&amp;nbsp;]&amp;nbsp;-&amp;nbsp;\mathbb&amp;nbsp;E_q[\log&amp;nbsp;p(x|Z)]&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;&amp;nbsp;\mathbb&amp;nbsp;E_q&amp;nbsp;[\log&amp;nbsp;p(x)]&amp;nbsp;&amp;nbsp;-&amp;nbsp;\bigg&amp;nbsp;(&amp;nbsp;\mathbb&amp;nbsp;E_q[\log&amp;nbsp;p(x|Z)]&amp;nbsp;-&amp;nbsp;\mathbb&amp;nbsp;E_q&amp;nbsp;\bigg&amp;nbsp;[\log&amp;nbsp;{q(z)\over&amp;nbsp;p(z)}&amp;nbsp;\bigg&amp;nbsp;]\bigg&amp;nbsp;)&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\mathbb&amp;nbsp;E_q&amp;nbsp;[\log&amp;nbsp;p(x)]&amp;nbsp;-&amp;nbsp;\mathbb&amp;nbsp;E_{Z&amp;nbsp;\sim&amp;nbsp;q(Z)}&amp;nbsp;\bigg&amp;nbsp;[&amp;nbsp;\log&amp;nbsp;{p(x,&amp;nbsp;Z)&amp;nbsp;\over&amp;nbsp;q(Z)&amp;nbsp;}&amp;nbsp;\bigg&amp;nbsp;]&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\text&amp;nbsp;{evidence}&amp;nbsp;-&amp;nbsp;\text&amp;nbsp;{ELBO}&amp;nbsp;&amp;nbsp;\end{align}$$ &lt;br /&gt;&lt;br /&gt;위에서&amp;nbsp;살펴보았던&amp;nbsp;evidence&amp;nbsp;-&amp;nbsp;ELBO&amp;nbsp;라는&amp;nbsp;식이&amp;nbsp;그대로&amp;nbsp;나온다.&amp;nbsp;gradient&amp;nbsp;descest&amp;nbsp;같은&amp;nbsp;최적화&amp;nbsp;방법을&amp;nbsp;이용해서&amp;nbsp;q를&amp;nbsp;학습시키면&amp;nbsp;evidence&amp;nbsp;값은&amp;nbsp;미분에&amp;nbsp;의해&amp;nbsp;사라진다.&amp;nbsp;결국&amp;nbsp;ELBO만을&amp;nbsp;최대화하면&amp;nbsp;되니까&amp;nbsp;우리는&amp;nbsp;다음의&amp;nbsp;식을&amp;nbsp;최대화하게&amp;nbsp;된다.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;$$\begin{align}&amp;nbsp;\text&amp;nbsp;{ELBO}&amp;nbsp;&amp;amp;=&amp;nbsp;\mathbb&amp;nbsp;E_{Z&amp;nbsp;\sim&amp;nbsp;q(Z)}&amp;nbsp;\bigg&amp;nbsp;[&amp;nbsp;\log&amp;nbsp;{p(x,&amp;nbsp;Z)&amp;nbsp;\over&amp;nbsp;q(Z)&amp;nbsp;}&amp;nbsp;\bigg&amp;nbsp;]&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\mathbb&amp;nbsp;E_{Z&amp;nbsp;\sim&amp;nbsp;q(Z)}&amp;nbsp;\bigg&amp;nbsp;[&amp;nbsp;\log&amp;nbsp;{p(x|Z)p(Z)&amp;nbsp;\over&amp;nbsp;q(Z)&amp;nbsp;}&amp;nbsp;\bigg&amp;nbsp;]&amp;nbsp;\\&amp;nbsp;&amp;amp;=&amp;nbsp;\mathbb&amp;nbsp;E_{Z&amp;nbsp;\sim&amp;nbsp;q(Z)}&amp;nbsp;\bigg&amp;nbsp;[&amp;nbsp;\log&amp;nbsp;{p(x|Z)&amp;nbsp;+&amp;nbsp;\log&amp;nbsp;p(Z)&amp;nbsp;-&amp;nbsp;\log&amp;nbsp;q(Z)&amp;nbsp;}&amp;nbsp;\bigg&amp;nbsp;]&amp;nbsp;\end{align}$$&lt;br /&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
뉴럴 네트워크 학습의 관점에서 봤을 때 위 식을 loss로 설정하고 위 식을 최소화하는 방향으로 파라미터 $\phi$를 학습시키면 최대화 문제를 풀 수 있게 된다.&amp;nbsp;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Monte Carlo ELBO&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 실제 사후확률에 대한 분포를 모르므로 $q_\phi (z)$로부터 데이터를 샘플링해서 기댓값을 구할 것이다. 그런데 문제가 있다. $z$를 샘플링해서 값을 사용하게 되면 계산 그래프 과정에서 연결이 끊어져서 역전파를 할 수 없게 된다. 즉, 샘플링 과정은 미분 불가능하다.&amp;nbsp;&lt;br /&gt;$$ z \sim q(\mu, \sigma^2)$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;Reparameterization&amp;nbsp;trick&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;위처럼 $z$를 $q(z)$로부터 직접 샘플링 하는 대신, reparameterization trick을 사용한다. $z$ 샘플을 $mu$와 noise의 합으로 표현하는 것이다.&amp;nbsp;&lt;br /&gt;$$z&amp;nbsp;=&amp;nbsp;\mu&amp;nbsp;+&amp;nbsp;\sigma&amp;nbsp;\circ&amp;nbsp;\epsilon,&amp;nbsp;\&amp;nbsp;\text&amp;nbsp;{where}&amp;nbsp;\&amp;nbsp;\epsilon&amp;nbsp;\sim&amp;nbsp;\cal&amp;nbsp;{N}(0,&amp;nbsp;1)$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 구현하면 아래와 같이 구현된다. negative elbo를 계산하는 함수를 보면 elbo 계산식이 그대로 사용되는 것을 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664173114484&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class VariationalDistribution(nn.Module):
    def __init__(self, input_dim, latent_dim, output_dim):
        super(VariationalDistribution, self).__init__()
        self.latent_dim = latent_dim
        self.fc1 = nn.Linear(input_dim, latent_dim)
        self.fc2 = nn.Linear(latent_dim, latent_dim)
        self.fc3 = nn.Linear(latent_dim, latent_dim)

        self.q_mean = nn.Linear(latent_dim, output_dim)
        self.q_log_var = nn.Linear(latent_dim, output_dim)

    def reparameterize(self, mu, log_var):
        sigma = torch.exp(0.5 * log_var) + 1e-5
        eps = torch.randn_like(sigma)
        return mu + sigma * eps
    
    def forward(self, x):
        x = F.leaky_relu(self.fc1(x))
        x = F.leaky_relu(self.fc2(x))
        x = F.leaky_relu(self.fc3(x))
        
        mu = self.q_mean(x)
        log_var = self.q_log_var(x)
        log_var = torch.clamp(log_var, min=1e-5)
        return self.reparameterize(mu, log_var), mu, log_var
        
 def log_liklihood_gaussian(y, mu, log_var):
    sigma = torch.exp(0.5 * log_var)
    return -0.5 * torch.log(2* np.pi * sigma**2) - (1 / (2 * sigma ** 2) * (y-mu)**2)

def calculate_negative_elbo(y_pred, y, mu, log_var):
    # liklihood 
    likelihood = log_liklihood_gaussian(y, mu, log_var)
    
    # prior
    log_prior = log_liklihood_gaussian(y_pred, 0, torch.log(torch.tensor(1.0)))

    # q_prob: variational dist of y_pred
    log_q_prob = log_liklihood_gaussian(y_pred, mu, log_var)
    
    elbo = (likelihood + log_prior - log_q_prob).mean()
    return -elbo&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1] &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%B2%A0%EC%9D%B4%EC%A6%88_%EC%B6%94%EB%A1%A0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko.wikipedia.org/wiki/%EB%B2%A0%EC%9D%B4%EC%A6%88_%EC%B6%94%EB%A1%A0&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[2] &lt;a href=&quot;https://stats.stackexchange.com/questions/243746/what-is-probabilistic-inference&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stats.stackexchange.com/questions/243746/what-is-probabilistic-inference&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[3]&lt;a href=&quot;https://datascienceschool.net/03%20machine%20learning/17.02%20%EA%B7%B8%EB%9E%98%ED%94%84%20%ED%99%95%EB%A5%A0%EB%AA%A8%ED%98%95.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; https://datascienceschool.net/03%20machine%20learning/17.02%20%EA%B7%B8%EB%9E%98%ED%94%84%20%ED%99%95%EB%A5%A0%EB%AA%A8%ED%98%95.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[4] &lt;a href=&quot;https://fabiandablander.com/r/Variational-Inference.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://fabiandablander.com/r/Variational-Inference.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[5] &lt;a href=&quot;http://norman3.github.io/prml/docs/chapter04/4.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://norman3.github.io/prml/docs/chapter04/4.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[6] &lt;a href=&quot;https://towardsdatascience.com/variational-bayes-4abdd9eb5c12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://towardsdatascience.com/variational-bayes-4abdd9eb5c12&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[7] &lt;a href=&quot;https://en.wikipedia.org/wiki/Variational_Bayesian_methods&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://en.wikipedia.org/wiki/Variational_Bayesian_methods&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[8] &lt;a href=&quot;https://mbernste.github.io/posts/elbo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mbernste.github.io/posts/elbo/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[9] &lt;a href=&quot;https://mbernste.github.io/posts/variational_inference/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mbernste.github.io/posts/variational_inference/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[10] &lt;a href=&quot;https://www.ritchievink.com/blog/2019/09/16/variational-inference-from-scratch/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.ritchievink.com/blog/2019/09/16/variational-inference-from-scratch/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Math</category>
      <category>변분추론 #Variational Inference #머신러닝 #딥러닝</category>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/44</guid>
      <comments>https://neverparadise.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 26 Sep 2022 15:18:45 +0900</pubDate>
    </item>
    <item>
      <title>[Paper Review] - Deep Reinforcement Learning at the Edge of the Statistical Precipice</title>
      <link>https://neverparadise.tistory.com/43</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;논문을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;읽은&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이유&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 강화학습 논문을 구현하고 실험을 재현할 때, 논문대로 잘나오지 않는 것들이 너무나도 많았다. 하이퍼파라미터, 네트워크를 똑같이 설정했는데도 그대로 나오지 않았다. 이 때문에 performance metric에 문제가 있거나 실험횟수가 너무 적어서 그런 것이 아닌가 생각을 했어서 관련 논문을 찾다가 이 논문을 발견했다. 논문에서는 구간추정에 기반한 metric을 사용해야 한다고 주장한다. 논문을 제대로 이해하려면 통계적 추론에 대한 배경지식(신뢰구간, 가설검정)이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TL;DR&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;강화학습에서 에이전트의 성능을 비교하기 위해 사분위수 평균(interquartile mean score)을 사용할 것을 제안한다.&lt;/li&gt;
&lt;li&gt;점추정치 (normalized median, mean score)로만 결론을 내는 것은 점수의 가변성을 다루지 못하므로 잘못된 결론에 이를 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;평가 프로토콜 (evaluation protocol)의 선택이 성능 개선을 보이는데 영향을 미칠 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;생각해볼 것들&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IQM은 어떻게 측정하는가?&lt;br /&gt;-&amp;gt; 상위 25%, 하위 25% 의 실험 결과를 제거한 수치들을 사용한다.&lt;/li&gt;
&lt;li&gt;Optimality gap이란 무엇인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Abstract&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;대부분의&amp;nbsp; Deep RL 연구에서는 벤치마크에서 성능을 비교할 때 task들 간의 평균이나 중앙값 같은 점추정치(point estimate)를 비교한다.&lt;/li&gt;
&lt;li&gt;유한한 숫자의 학습을 시도할 때 내포되는 통계적인 불확실성을 무시한다. 계산을 많이 해야하는 벤치마크에서 연구가 전환되면서 task 당 실행횟수를 적게 평가하는 관행으로 인해 점추정만 하게 되면서 통계적 불확실성을 악화시킨 것이다.&lt;/li&gt;
&lt;li&gt;본 논문에서는 조금만 환경을 실행하는 상황에서 평가 방식을 신뢰하려면 결과의 불확실성을 무시할 수 없다고 주장한다.&lt;/li&gt;
&lt;li&gt;아타리 벤치마크에서 점추정을 통해서 얻은 결론과 철저히 통계적 분석을 한 결론 사이의 다름을 보인다.&lt;/li&gt;
&lt;li&gt;저자들은 성능을 집계한 구간 추정 (interval estimates) 방식이 좋다고 한다.&lt;/li&gt;
&lt;li&gt;결과의 가변성을 설명하고 더 강건하고 효율적은 metric 들을 표현하기 위해 performance profile 들을 제안한다. (interquartile mean scores). 필드에서 사용 가능한 오픈 소스 라이브러리 rliable 도 제안한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;1. Introductio&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tzufP/btrL7tWKMXT/bBmkpjAnI6zakK43l1BhY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tzufP/btrL7tWKMXT/bBmkpjAnI6zakK43l1BhY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tzufP/btrL7tWKMXT/bBmkpjAnI6zakK43l1BhY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtzufP%2FbtrL7tWKMXT%2FbBmkpjAnI6zakK43l1BhY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;214&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;강화학습의 성능 지표로 평균과 중앙값 같은 주로 point estimate 값을 사용한다.&lt;/li&gt;
&lt;li&gt;학습 실행을 적게 하는 것은 강화학습 알고리즘의 퍼포먼스에 상당한 가변성과 관련 있다.&lt;/li&gt;
&lt;li&gt;그림처럼 연구에서는 대부분 3번에서 10번 학습을 실행한다.&lt;/li&gt;
&lt;li&gt;더 많이 실행하면 불확실성을 줄일 수 있지만 계산비용 때문에 제한이 있다. 예를 들어, standard protocol을 이용해서 50개가 넘는 아타리 2600 게임들을 5번을 실행하려면 1000개의 GPU로 며칠을 학습시켜야 한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;통계적인 불확실성을 무시하는 것은 연구의 결론을 잘못된 방향으로 이끌 수 있다. 그리고 정확히 같은 무작위 조건에서도 연구의 내용을 재현하기 어렵게 만든다. 평균값의 경우 이상치에 영향을 받고 중앙값의 경우 0인 점수에 따라 많이 변하기 때문에 사분위수 평균(interquartile mean)을 사용할 것을 주장한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2. &lt;/span&gt;&lt;span&gt;Formalism&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$M$ 개의 task들을 평가하는 강화학습 환경을 고려해보자.&amp;nbsp;각 task에 대해서 $N$ 번의 독립적인 실험을 수행한다.&lt;/li&gt;
&lt;li&gt;이를 통해 normalized score를 얻을 수 있다. 표기는 $x_{m,n}$으로 하며, $m= 1, \dots, M, \quad&amp;nbsp; n= 1, \dots, N$ 이다. 이 스코어는 각 테스크마다 랜덤 policy의 경우 0점, 사람의 점수를 1점을 주는 방식으로 정규화해서 계산한다. normalized score set을 $x_{1:M, 1:N}$으로 표기한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;대부분의 실험에서 다른 실험들을 통해 얻은 점수에는 랜덤성이 내포되어 있다. 이는 1) 테스크의 stochasticity, 2) 학습 과정에서의 만들어진 탐험적 선택, 3) 랜덤으로 초기화된 파라미터, 4) 소프트웨어나 하드웨어의 non-determinism 들이 원인이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;그래서 저자들은 알고리즘의 m번째 작업에서 정규화된 점수를 랜덤변수 $X_m$으로 모델링한다. 그러면 점수 $x_{m,n}$은 랜덤변수 랜덤변수 $X_m$의 분포에서 뽑아진 $X_{m,n}$의 관측값(realization)이 된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;어떤 실수 $\tau \in \mathbb R$에 대해서 $X_m$의 tail distribution $F_m(\tau) = P(X_m &amp;gt; \tau)$ 로 정의한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;수집된 어떤 점수들을 $y_{1:K}$라고 하면, empricial tail distribution function은 다음처럼 주어진다. $\hat F(\tau; y_{1:K}) = {1\over K} \sum_{k=1}^K   [y_k &amp;gt; \tau].$&lt;/li&gt;
&lt;li&gt;특히 $\hat F_m (\tau) = \hat F(\tau ; x_{m, 1:N}) $으로 표기한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;알고리즘의 Aggregate performance 는 normalized scores의 집합 $x_{1:M, 1:N}$을 스칼라 값으로 mapping한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;두 개의 prevalent aggregate performance metric은 평균과 중앙값이다. 만약 특정 task $m$을 $N$번 실행한 평균 점수를 $\bar x_m = {1\over M} \sum_{n=1}^N x_{m,n}$ 라고 표기한다면, 전체 task에대한 평균과 중앙값은 $\text {Mean} (\bar x_{1:M})$과 $\text {Median} (\bar x_{1:M})$이 된다. 정확하게는 우리는 이를 task 평균에 대한 표본 평균과 표본 중앙값이라고 부른다. (sample mean, sample median으로 부르는 이유는 각 테스크를 N번 실행해서 계산했기 때문)&lt;/li&gt;
&lt;li&gt;$\bar x_m$은 랜덤변수 $\bar X_m = {1\over N} \sum_{n=1}^N X_{m,n}$의 관측값이기에 표본평균과 중앙값들은 랜덤변수 ${Mean} (\bar X_{1:M})$과 $\text {Median} (\bar X_{1:M})$의 점추정치들이다. 실험을 무한히 진행하면 평균과 중앙값에 대한 참값을 얻을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Confidence intervals&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신뢰구간 (Confidence intervals)은 true score에 대한 plausible value들의 추정치로써 해석될 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;$\alpha \times 100%$ CI는 어떤 구간을 계산하는데, 만약 실험을 다시 수행하고 다른 실험 집합을 사용해서 신뢰구간을 구성하는 경우, 실제 점수를 포함하는 계산된 신뢰구간의 비율이 $\alpha \times 100%$가 되도록 구간을 계산한다. 여기서 $\alpha \times [0,1]$은 norminal converage rate이다. 95%의 신뢰구간이 일반적으로 사용된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;만약 true score가 95%의 신뢰구간 밖에 있다면 sampling event는 5%의 확률로 우연히 발생한 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Remark&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저자들은 결과의 불확실성을 측정하기 위해 신뢰구간을 사용할 것은 추천한다. 그리고 주어진 데이터에 대해서 effect sizes (베이스라인에 대한 성능향상)을 보이라고 한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;또한 통계적 사고를 할 것을 강조하지만, 통계적 검정(p-value &amp;lt; 0.05) 같은 것은 피하라고 한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cycoBd/btrMjEbnrBQ/7LcnUfQzIosGTnZ8gK0Se0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cycoBd/btrMjEbnrBQ/7LcnUfQzIosGTnZ8gK0Se0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cycoBd/btrMjEbnrBQ/7LcnUfQzIosGTnZ8gK0Se0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcycoBd%2FbtrMjEbnrBQ%2F7LcnUfQzIosGTnZ8gK0Se0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;662&quot; height=&quot;428&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;그림 2를 살펴보자. median normalized score에 대한 확률분포를 그린 것이다. 100 번의 실험수행에서 균일하게 부분 표본추출하여 N번 실행의 10만 개의 다른 실험집합을 만들어서 계산했다. 즉 100개의 실험결과가 있으면, 5개씩 표본추출해서 이에 대한 표본중앙값들을 10000개를 만들어서 분포를 만들어낸 것이다. 표본추출된 분포는 다른 실험결과의 집합을 사용했을 때, 중앙값의 variation을 보여준다. 그동안 발표된 논문들에서 중앙값에 대해 보고된 점추정치들은 중앙값이 얼마나 변할 수 있는지 제공해주지 않는다. 그리고 평균 중앙값에 대해 과다하게 추정되거나 과소하게 추정되었을 수 있다. (overestimate, underestimate). 논문들에서 사용된 것처럼 $N=5$로 DER, OTR, DRQ에 대해 분포를 만들었고, $N=10$으로 SPR을 계산, $N=20$으로 CURL을 계산했다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; 오른쪽 그림은 중앙값에 대한 95%의 신뢰구간과 다양한 N에 대한 IQM의 점수들이다. &lt;b&gt;50번의 수행에서도 중앙값이 상당한 불확실성을 가진다!!!&lt;/b&gt; IQM은 중앙값보다 더 작은 신뢰구간을 가지고 있다. &lt;u&gt;신뢰구간이 중복될 때 불확실성을 적절히 설명하려면, 점수차이에 대한 신뢰구간을 계산해야 한다.&lt;/u&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;3. &lt;/span&gt;&lt;span&gt;Case Study: The Atari 100k benchmark&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실험을 적게 실행할 때, 단순히 점추정치를 사용하는 상황에서 발생할 수 있는 함정에 대해 케이스 스터디를 통해 설명한다. 케이스 스터디는 Atari 100k 벤치마크를 다루는데 이는 데이터 효율성을 평가하기 위한 ALE의 offshoot이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이 벤치마크에서는 알고리즘들이 26개의 게임에 대해서 100k 스텝들 (2~3 시간)에 대해서 평가된다. 이전의 논문에서 보고된 결과들은 3~5 번의 실험수행을 해서 결과를 냈었다. 드물게 10번, 20번 하는 경우도 있었다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;케이스 스터디는 최근 다섯 개의 deep RL 알고리즘에 대해 비교 한다. DER, OTR, DRQ, CURL, SPR를 선택했는데 이 벤치마크에서 representative, influential 한 알고리즘들이기 때문이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;하나의 게임에 대한 좋은 성능은 다른 게임에서의 성능에 대한 정보를 제공하지 않고도 높은 표본평균을 제공할 수 있기에, 전체 테스크에 대한 표본중앙값을 사용하여 성능을 측정하는 것이 일반적이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;각 알고리즘에 대해 &lt;b&gt;100개의 독립적인 실험(100 independent run)&lt;/b&gt;을 수행하고 평가해서 few-run regime에서의 statistical variation들을 조사한다. 하나의 실험에 대한 점수는 100개의 evaluation episoodes에 대한 average return이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각각의 실험수행&lt;/b&gt;은 하나의 알고리즘을 벤치마크에 있는 26개의 알고리즘에 대해 학습시키는 것에 해당한다. &lt;b&gt;(1 run = 1 algorithm training for 26 games)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;즉, 하나의 알고리즘 당 $26 \times 100$ 개의 점수들을 얻는다. 여기서 저자들은 3-100번의 실험들을 부분적으로 표본추출한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;subsampled score들은 점추정치의 집합을 생성하는데 사용된다. 이를 통해&amp;nbsp; statistical variability를 측정할 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;High variability in reported results&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실험에서 처음으로 관측된 것은 sample medians들이 상당한 변동성을 보인다는 것이다. (적은 수의 sample runs에 의존하는 무작위한 양들로 볼 때 확률분포가 상당히 넓다는 뜻인 것 같다)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이것은 점추정치만 사용했을 때, 오류가 있는 결론으로 이어질 수 있는 가능성이 상당하다는 것을 보인다! (논문에서 제안하는 알고리즘이 성능이 좋다는게 오류가 있을 수 있는 것이다)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;즉, 몇 번의 실험을 수행할 때 점추정치는 &quot;다른 실험 집합으로 알고리즘을 재평가하더라도 동일한 결론을 이끌어내는가?&quot;에 대한 답을 제공하지 못한다는 것이다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxcYs2/btrMhXjvOEr/61RG7ligEHgQY46tcnGFF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxcYs2/btrMhXjvOEr/61RG7ligEHgQY46tcnGFF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxcYs2/btrMhXjvOEr/61RG7ligEHgQY46tcnGFF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxcYs2%2FbtrMhXjvOEr%2F61RG7ligEHgQY46tcnGFF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;583&quot; height=&quot;220&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Substantial bias in sample medians&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;샘플 중앙값은 참인 중앙값에 대하여 편향된 추정량이다. (biased estimator of true median)&lt;/li&gt;
&lt;li&gt;즉, 일반적으로 $\mathbb E[\text {Median}(\bar X_{1:M})] \neq \text {Median} \mathbb E[X_{1:M}])$이다.&lt;/li&gt;
&lt;li&gt;few-run의 regime에서 bias가 알고리즘 간의 비교를 dominate할 수 있음을 그림 3에서 볼 수 있다. (실험횟수 N에 따라 알고리즘 간의 비교 결과가 달라질 수 있다)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Statistical concerns cannot be satisfactorily addressed with few runs.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vr4Gw/btrMjQpIiRK/4Qhq6x4fLwFkgwKVUSN970/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vr4Gw/btrMjQpIiRK/4Qhq6x4fLwFkgwKVUSN970/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vr4Gw/btrMjQpIiRK/4Qhq6x4fLwFkgwKVUSN970/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvr4Gw%2FbtrMjQpIiRK%2F4Qhq6x4fLwFkgwKVUSN970%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;455&quot; height=&quot;379&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3번 혹은 적은 횟수의 실험으로 성능이 개선되었다고 주장하는 것은 믿기 어려울 수 있다.&lt;/li&gt;
&lt;li&gt;실험적으로 강화학습에서의 folk wisdom에 따르면 20번 혹은 30번의 실험수행이면 충분하다고 한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;다양한 실행 횟수 (그림2 오른쪽)에 대한 샘플 중앙값에 대한 신뢰구간을 계산하면 이 수치가 아타리에서 50~100회의 실험 수행에 더 가까운 것을 볼 수 있다. 그러나 이는 대부분의 연구 프로젝트에서 실행하기에 너무 계산량이 많다.&lt;/li&gt;
&lt;li&gt;하나의 알고리즘이 더 낫다고 알려진 상황을 고려보자. 실행횟수를 다양하게 할 때, 성능 차이를 정확하게 평가하려면 Median과 IQM에 대한 신뢰도는 몇이 되어야할까?&amp;nbsp;&lt;/li&gt;
&lt;li&gt;구체적으로 저자들은 SPR을 포함하는 동일한 두 개의 N번의 실험을 고려한다. 이때, 실험 점수 중 하나를 고정된 비율로 인위적으로 부풀리눈 것을 제외한다.&lt;/li&gt;
&lt;li&gt;In particular, l = 0 corresponds to running the same experiment twice but with different runs. We find that statistically defensible improvements with median scores is only achieved for 25 runs (l = 25) and 100 runs &lt;br /&gt;(l = 10). With l = 0, even 100 runs are insufficient, with deviations of 20% possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Changes in evaluation protocols invalidates comparisons to prior work.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z33QS/btrMhDlknUS/fjNcJNaNb20ce2IKTZxqk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z33QS/btrMhDlknUS/fjNcJNaNb20ce2IKTZxqk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z33QS/btrMhDlknUS/fjNcJNaNb20ce2IKTZxqk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz33QS%2FbtrMhDlknUS%2FfjNcJNaNb20ce2IKTZxqk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;273&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;강화학습 알고리즘의 퍼포먼스를 측정하기 위해 전형적이고 비교적 안전한 접근은 마지막 트레이닝 에피소드들에서 받은 점수를 평균하는 것이다. 그러나, 이 field에서는 여러 개의 대안적인 프로토콜이 사용된 것을 볼 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;예를 들어, 여러 번의 실험 또는 학습 과정에서 달성된 최대평가점수를 사용하는 것이 있다. 비슷한 프로토콜이 CURL과 SUNRISE에서 사용되었다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;최댓값을 포함하는 대안적인 프로토콜에서 생성된 결과는 일반적으로 최종적인 성능으로 보고된 결과와 비교할 수 없다. Atari 100k에서 두 프로토콜이 실제 점수 차이보다 훨씬 더 큰 결과를 만들어내는 것을 그림 5에서 보이고 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;특히 CURL의 프로토콜로 DER을 평가하면 CURL에 대해서 보고된 점수보다 훨씬 높은 점수가 나온다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;즉, 평가 절차의 갭으로 인해, CURL이 DER보다 더 큰 true median score를 달성하는 것으로 평가되었다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;저자들의 실험으로 DER이 CURL보다 더 좋다는 어떤 근거를 제공한다. 마찬가지로 DER에 비해 SUCRISE의 수많은 개선이 평가 프로토콜의 변경으로 설명될 수 있음을 발견했다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;. Recommendations&amp;nbsp;and&amp;nbsp;Tools&amp;nbsp;for&amp;nbsp;Reliable&amp;nbsp;Evaluation&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 케이스&amp;nbsp; 스터디즌 통계적 불확실성 이슈를 해결하기 위해 필요한 실험횟수의 증가가 계산량이 너무 많아서 실행 불가능함을 보인다. 이 섹션에서는 few-run regime에서도 실험결과보고의 질을 향상시키기 위한 세 가지 툴을 확인한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.1&amp;nbsp;Stratified&amp;nbsp;Bootstrap&amp;nbsp;Confidence&amp;nbsp;Intervals&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;알고리즘의 aggregate performance가 존재할 것으로 추정되는 범위를 나타내기 위해 구간 추정을 보고하는 것의 중요성을 재차 확인해본다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;구체적으로는 stratified sampling으로 bootstrap CIs를 사용하는 것을 제안한다. 이 방법은 적은 샘플 사이즈에 적용될 수 있고, 샘플표준편차를 보고하는 것보다 더 정당화될 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이전의 논문들에서는 N번 실행된 단일 task average score의 uncertainty를 보고하기 위해 bootstrap CI를 사용할 것을 권장했었지만, 이는 N이 작을 때는 유용하지 않다. 왜냐하면 bootstrapping이 데이터로부터 re-sampling 하는 것이 true distribution으로부터 샘플링하는 것을 근사한다고 가정하기 때문이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;총 MxN 개의 랜덤한 샘플들을 전반적인 task에 걸쳐 집계하면 더 나은 것을 할 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;To compute the stratified bootstrap CIs, we re-ample runs with replacement independently for each task to construct an empirical bootstrap sample with N runs each for M tasks from which we calculate a statistic and repeat this process many times to approximate the sampling distribution of the&amp;nbsp;statistic.&lt;/li&gt;
&lt;li&gt;We measure the reliability of this technique in Atari 100k for variable N, by comparing the nominal coverage of 95% to the &amp;ldquo;true&amp;rdquo; coverage from the estimated CIs (Figure 6) for different bootstrap methods (see [30] and Appendix A.5). We find that percentile CIs provide good interval &lt;br /&gt;estimates&amp;nbsp;for&amp;nbsp;as&amp;nbsp;few&amp;nbsp;as&amp;nbsp;N&amp;nbsp;=&amp;nbsp;10&amp;nbsp;runs&amp;nbsp;for&amp;nbsp;both&amp;nbsp;median&amp;nbsp;and&amp;nbsp;IQM&amp;nbsp;scores&amp;nbsp;(Section&amp;nbsp;4.3).&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.2&amp;nbsp;Performance&amp;nbsp;Profiles&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 대부분의 강화학습 벤치마크에서는 테스크들 마다 다른 스코어를 산출한다. 그리고 스코어는 heavy-tailed, multimodal 일 수도 있고 이상치 값들을 가질 수도 있다. 평균이나 중앙값 값들을 사용하는 것 대신에 performance profile 들을 사용할 것을 추천한다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;run-score distributions 또는 score distribution이라 불리는 performance profile 제안한다. 특히 few-run regime에서 적합하다고 한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Score distribution 특정 정규화된 점수 상에서의 실행의 비율을 보여준다. 식은 다음과 같이 주어진다.&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ybNYH/btrMox4Yfou/VAHx7JU8BstxIp1d5koe2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ybNYH/btrMox4Yfou/VAHx7JU8BstxIp1d5koe2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ybNYH/btrMox4Yfou/VAHx7JU8BstxIp1d5koe2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FybNYH%2FbtrMox4Yfou%2FVAHx7JU8BstxIp1d5koe2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;803&quot; height=&quot;93&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 점수 분포를 사용하는 것의 장점은 underlying distribution $F(\tau) = {1\over N} \sum_{m=1}^M F_m(\tau)$&amp;nbsp;에 대한 불편추정량이라는 것이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;다른 장점으로는 극단적으로 높은 점수를 가진 outlier run이 어떤 $\tau$ 값에 대해서도 점수분포의 결과가 변할 수 있다는 것이다. (최댓값은 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.3&amp;nbsp;Robust&amp;nbsp;and&amp;nbsp;Efficient&amp;nbsp;Aggregate&amp;nbsp;Metrics&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) IQM, Optimality gap, Probability of improvement&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;median을 사용하는 대신에 사분위수 평균을 추천한다. 실험결과에서 하위 25%, 상위 25%를 제거하고 50%의 실험 결과만 사용하는 것이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;mean 대신에 optimality gap을 사용할 것은 추천한다. 이는 어떠한 양인데, 알고리즘이 최소 점수 $\gamma= 1.0$을 충족시키지 못하는 횟수이다. 예를 들어, 사람 수준의 성능을 얻는 것이 목표라고 하면, 1.0의 정규화된 점수는 그다지 중요하지 않은 목표라고 가정한다. 문제마다 threshold는 다르게 선택될 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;한 알고리즘 $X$가 $Y$보다 얼마나 강건하게 개선되는지에 관심 있다면 average probability of improvement를 고려하는 것이 좋다. 이 메트릭은 랜덤으로 선택된 테스크에 대해서 알고리즘 X가 알고리즘 Y보다 얼마나 더 좋은 성능을 내는지를 보여준다. 특히, $P(X &amp;gt; Y) = {1\over M}\sum_{m=1}^M P(X_m &amp;gt; Y_m)$ 값은 task m에 대해서 Y보다 X가 나을 확률이다. 주의할 것은 IQM 이나 optimality gap과는 달리 이 메트릭은 개선의 크기를 설명하지 않는다는 것이다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;. Re-evaluating&amp;nbsp;Evaluation&amp;nbsp;on&amp;nbsp;Deep&amp;nbsp;RL&amp;nbsp;Benchmarks&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 아타리 벤치마크에서 200M 개의 프레임에 대해 에이전트를 학습시킨 것은 가장 널리 알려진 벤치마크다. 몇 개의 인기 있는 메소드들을 결과의 uncertainty를 무시한 것과 고려한 것의 차이를 실험적으로 보인다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bemSTq/btrMlc8kWfQ/0ASaHoHqDKUHKIi47VOtqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bemSTq/btrMlc8kWfQ/0ASaHoHqDKUHKIi47VOtqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bemSTq/btrMlc8kWfQ/0ASaHoHqDKUHKIi47VOtqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbemSTq%2FbtrMlc8kWfQ%2F0ASaHoHqDKUHKIi47VOtqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;945&quot; height=&quot;444&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dreamer V2의 경우 집계된 점수에 상당한 불확실성을 보인다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;M-IQN은 Rainbow보다 더 좋은 성능을 보인다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;C51은 DQN보다 상당히 좋다고 여겨지지만 둘의 구간 추정치는 꽤나 겹쳐져 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;그림 9는 aggregate metric들에 대한 한계점들을 보여준다. metric의 선택에 따라 알고리즘의 순서가 변화할 수 있는 것이다. 순위를 매기는 것의 비일관성은 이러한 metric들이 task와 실험 수행들에서 전체 성능의 특정한 면만 포착한다고 볼 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;433&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yPHaV/btrMp15RmUB/4LtjKAkAmTbZurHxhJMje0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yPHaV/btrMp15RmUB/4LtjKAkAmTbZurHxhJMje0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yPHaV/btrMp15RmUB/4LtjKAkAmTbZurHxhJMje0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyPHaV%2FbtrMp15RmUB%2F4LtjKAkAmTbZurHxhJMje0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;724&quot; height=&quot;330&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;433&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;461&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DckcC/btrMt3vfY9A/g7pBSHZCyikdVriSDTkXhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DckcC/btrMt3vfY9A/g7pBSHZCyikdVriSDTkXhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DckcC/btrMt3vfY9A/g7pBSHZCyikdVriSDTkXhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDckcC%2FbtrMt3vfY9A%2Fg7pBSHZCyikdVriSDTkXhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;712&quot; height=&quot;351&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;461&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdaUQ6/btrMlVSOQqi/ieAQ2Hff0h9DYRTcqSv6Gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdaUQ6/btrMlVSOQqi/ieAQ2Hff0h9DYRTcqSv6Gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdaUQ6/btrMlVSOQqi/ieAQ2Hff0h9DYRTcqSv6Gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdaUQ6%2FbtrMlVSOQqi%2FieAQ2Hff0h9DYRTcqSv6Gk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;743&quot; height=&quot;312&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아타리와 여러 벤치마크 환경에서의 case study를 통해서 통계적인 이슈들이 보고된 결과들에 상당한 영향을 끼칠 수 있다는 것을 볼 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1] Deep Reinforcement Learning at the Edge of the Statistical Precipice, &lt;a href=&quot;https://arxiv.org/abs/2108.13264&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://arxiv.org/abs/2108.13264&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[2] &lt;a href=&quot;https://github.com/google-research/rliable&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/google-research/rliable&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[3] &lt;a href=&quot;https://www.youtube.com/watch?v=XSY9JwqD-bw&amp;amp;t=4s&amp;amp;ab_channel=RishabhAgarwal&quot;&gt;https://www.youtube.com/watch?v=XSY9JwqD-bw&amp;amp;t=4s&amp;amp;ab_channel=RishabhAgarwal&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Reinforcement Learning</category>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/43</guid>
      <comments>https://neverparadise.tistory.com/43#entry43comment</comments>
      <pubDate>Sun, 18 Sep 2022 20:47:07 +0900</pubDate>
    </item>
    <item>
      <title>[Paper Review] - Beyond Tabula-Rasa: a Modular Reinforcement Learning Approach for Physically Embedded 3D Sokoban</title>
      <link>https://neverparadise.tistory.com/42</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;논문을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;읽은&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이유&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; 우리의 뇌 중에서 브로카 영역이 언어를 담당한다고 알려진 것처럼, 뇌의 각 부위들이 특정 역할을 담당한다는 내용을 뇌과학책에서 보았다. 비슷한 원리로 강화학습의 에이전트의 정책 또는 정책을 근사하는 뉴럴 네트워크를 여러 모듈로 나누어서 각자의 역할을 담당하는 그런 연구가 없을까 하는 와중에 논문을 발견해서 읽게 되었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TL;DR&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 강화학습의 구성요소들을 여러 모듈로 나누어서 문제를 푸는 방식을 제안했다. Mujoco 기반의 Sokoban 문제에서 기존 10%도 안되던 테스크 성공률은 70퍼센트 넘게 개선했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;생각해볼 것들&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Tabula rasa의 의미?&amp;nbsp;&lt;br /&gt;-&amp;gt; 위키백과에 따르면 &lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;어떤 인간이 태어날 때에는 정신적인 어떠한 기제도 미리 갖추지 않고 마음이 '빈' 백지와도 같은 상태로 태어나며 출생 이후에 외부 세상의 감각적인 지각활동과 경험에 의해 서서히 마음이 형성되어 전체적인 지적 능력이 형성 된다는 개념이라고 한다. 현재 RL의 에이전트 정책이 랜덤으로 초기화된 뉴럴 네트워크에서 학습을 시작하는 것을 생각하면 된다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Modular의 의미?&lt;br /&gt;-&amp;gt; 전체는 여러 개의 나누어진 부분들로 구성되어 있고 이들이 결합하여 완전체를 형성한다는 의미. 레고블록이 그 예시&lt;/li&gt;
&lt;li&gt;왜 모듈화를 하면 문제를 잘 풀 수 있을까?&lt;br /&gt;-&amp;gt; 모듈화를 통해 state space와 action space의 크기를 줄이게 되어서 그런 것 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Abstract&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 지능이 있는 로봇은 추상적인 목표들을 달성하기 위해서 구체적이고 시공간적인 복잡한 감각정보를 활용하고, 모터를 제어하는 것이 필요하다. Tabula rasa deep RL은 시각적, 추상적, 물리적 추론이 요구되는 작업들을 다루어 왔는데, 이들을 같이 푸는 것은 매우 어렵다. 이 논문에서는 Mujoban이라는 3D 창고 환경에서 위의 도전과제들을 해결하는 내용을 다루었다. sense-plan-act라는 계층으로 RL 모듈을 구성해서 문제를 풀 수 있다고 한다. 각 모듈들은 classic 로봇 아키텍처와 비슷하게 잘 정의된 모듈인데, model-free 방식으로 동작한다. 그 결과 Mujoban에서 SOTA를 달성하였다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;1. Introductio&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kFcYQ/btrLadubYaS/kZLYRWUaEcOmFdLtPwTDhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kFcYQ/btrLadubYaS/kZLYRWUaEcOmFdLtPwTDhK/img.png&quot; data-alt=&quot;Figure 1: Mujoban environment&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kFcYQ/btrLadubYaS/kZLYRWUaEcOmFdLtPwTDhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkFcYQ%2FbtrLadubYaS%2FkZLYRWUaEcOmFdLtPwTDhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;409&quot; height=&quot;353&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;754&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 1: Mujoban environment&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; 기존의 RL 메소드들은 하나의 시스템에서 여러 문제를 jointly하게 풀려고 시도해왔다. &lt;i&gt;(하나의 정책으로 모든 의사결정을 해결하려고 함)&lt;/i&gt;. 이는 에이전트의 학습을 어렵게 해서 벤치마크에서 낮은 성능을 보였다. Mujoban이라는 환경에서 에이전트는&amp;nbsp; 1인칭 시점의 Observation을 입력으로 받아서 상자를 밀어서 옮기는 퍼즐을 풀어야 한다. 기존 Sota RL들은 TPU에서 몇 주의 학습을 해도 전체 시도 중에서 10%만 문제를 풀 수 있었다. 이때, 위 그림처럼 top-down view 같은 정보에 접근할 수 있었는데도 잘 풀 수가 없었다고 한다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2156&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/omLJE/btrLc6tIf81/xV4cyjZcO5IGncvl89gFI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/omLJE/btrLc6tIf81/xV4cyjZcO5IGncvl89gFI0/img.png&quot; data-alt=&quot;Figure 2: Modular RL architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/omLJE/btrLc6tIf81/xV4cyjZcO5IGncvl89gFI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FomLJE%2FbtrLc6tIf81%2FxV4cyjZcO5IGncvl89gFI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2156&quot; height=&quot;440&quot; data-origin-width=&quot;2156&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 2: Modular RL architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; 논문에서는 어려운 embodied task 들을 RL 모듈들을 구성해서 풀 수 있는지 조사한다. 이 모듈들은 sense-plan-act hierarchy로 동작하며 1) perception -&amp;gt; 2) abstract reasoning -&amp;gt; 3) motor contorl을 수행한다. 이렇게 모듈러 디자인을 하게 되면 효율적인 네트워크 구조와 학습 영역을 선택할 수 있고, 학습된 모듈을 재사용할 수 있다고 한다. 예를 들면 다른 테스크에서는 다른 모듈을 갈아 끼우는 식이다. 각 모듈들은 model-free 로 배타적으로 동작하고, 이전에 연구된 사례는 없었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; 모듈러 아키텍처는 그림 2와 같다. 각 모듈은 다른 목적함수를 최적화한다. 컨트롤러의경우 goal-oriented locomotion과 pushing에 대해 학습되고, 플래너는 고차원의 추상적 추론에 대해 학습된다. 인지 네트워크는 1인칭 시점의 RGB 시퀀스를 입력 받아서 2차원 상태를 추론한다. MPO 기반의 time-abstracted RL 알고리즘을 사용해서 성공률을 9.4%에서 78.7%로 개선했다. &lt;i&gt;(이때 1인칭 시점만 사용했다)&lt;/i&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; Contribution은 다음과 같다&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;model-free RL 모듈들이 sense-plan-act hierarchy로 구성되어 sota를 달성&lt;/li&gt;
&lt;li&gt;planning에 학습된 모듈이 다른 로봇 플랫폼에서 재사용 가능함을 보였다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;hierarchical policy를 학습시키는 modular RL 알고리즘을 제안한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Related Work&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 도메인 지식, 구조를 모델프리 강화학습에 통합하는 방법에 대한 연구가 최근에 수행되어 왔다. 도메인 지식은 다양한 형태로 나타날 수 있는데 1) reward shaping, 2) training curricula, 3) auxiliary tasks, 4) state representation, 5) algorithmic structure, 6) memory 에 대한 연구들이 있었다. 논문에서는 문제를 풀기 위해 계층적 강화학습 (Hierarchical RL) 형태로 접근한다. 추상화 수준, 시간 규모에 따라 다르게 행동하는 정책들의 hierarchy를 사용한다. &lt;i&gt;(이렇게 한 이유는 로보틱스에서 sense-plan-act 아키텍처가 널리 사용하기 때문인 것 같다). &lt;/i&gt;이러한 계층이&amp;nbsp; 큰 종류의 embodied 문제에 대해서 inductive bias의 형태를 가능하게 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Mujoban&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2306&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XDtiL/btrLfNgYeuV/lxsQp4khjcVDTKgKkK4W90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XDtiL/btrLfNgYeuV/lxsQp4khjcVDTKgKkK4W90/img.png&quot; data-alt=&quot;Figure 3: RL trajectory in Mujoban&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XDtiL/btrLfNgYeuV/lxsQp4khjcVDTKgKkK4W90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXDtiL%2FbtrLfNgYeuV%2FlxsQp4khjcVDTKgKkK4W90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2306&quot; height=&quot;541&quot; data-origin-width=&quot;2306&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 3: RL trajectory in Mujoban&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Mujoban 환경에서 시각 인지, 추상적 추론, 모터 제어를 해결한다. 이 환경은 2D sokoban 퍼즐로부터 3D 미로를 생성한다. 로봇은 미로를 탐험하고 박스를 목표 위치에 자신의 몸으로 밀어 넣는다. 기본 로봇은 2-DoF (Degree of freedom)을 가지는 공이다. (x축, y축으로 움직임) 그 다음 8-DoF 를 가지는 개미에 대해서도 실험한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 로봇이 받는 인풋은 1인칭 시점의 카메라 이미지 $o^{cam}$이고, proprioceptive 신호 $o^{pr}$이 있다. (터치, 위치, 속도, 가속 센서값). 그리고 global pos $o^{pos} = x, y, \phi $가 있다. 퍼즐을 풀면 +10의 보상을 받고, 박스를 타겟 위치로 옮기냐 마느냐에 따라 +1/-1 보상을 받는다. 그림에서 노란 색은 상자들이고 목표 위치는 빨간색이다. 에이전트는 박스를 빨간 상자로 밀어야 한다. 챌린지들은 다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Motor control&lt;/b&gt;. 에이전트는 목적지에 도달하기 위해 움직이는 법을 배워야 한다. 박스를 밀고 정렬해야 하며, grid peg에 막히면 안된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Abstract reasoning / Planning&lt;/b&gt;. 소코반 퍼즐은 long horizon planning을 필요로 한다. 박스들은 오직 밀기만 가능하고 당길 수 없다. 많은 움직임들이 되돌릴 수 없기에 미리 계획해서 움직이는 것이 중요하다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Perception.&amp;nbsp;&lt;/b&gt;Mujoban 환경은 겉으로 보기에 간단헤 보이지만 perception은 non-trivial한 visual mapping을 포함한다. 즉, 2D sokoban state 정보를 추론하기 위해 RGB 이미지들의 시퀀스들이 통합되어야 한다.&amp;nbsp;&lt;i&gt;(과거의 시각 정보들을 잘 기억해야 한다는 의미인 것 같다)&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 현실에서의 동작을 고려해서, 에이전트에게 1인칭 관측값만 제공하는 실험도 진행한다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Modular RL&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.1 Overview&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; embodied reasoning 레이어들을 구분되는 RL 모듈들로 나눈다. 1) perception module, 2) planner, 3) controller 세 가지고 있으며 각 모듈들의 목적함수는 다르다. (도메인 지식을 활용해서 만듬). 그림 2에 아키텍처를 살펴보면 1인칭 시점 이미지를 받아서 추상적인 2D 상태를 출력하는 역할을 perception module이 수행한다. 플래너는 추상적인 상태를 받아 지시사항을 내린다. (동, 서, 남, 북, 정지). 마지막으로 컨트롤러는 goal-oriented visuomotor policy인데 locomotion과 object manipulation을 수행한다. 시각정보와 instruction을 입력으로 받아서 모터의 토크 값 a와 완료 시그널 $\beta$를 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.2 Controller module&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&lt;/b&gt;컨트롤러의 역할은 locmotion과 object manipulation이다. control policy와 completion predictor에 대한 네트워크를 분리해서 사용했다. control policy는 $o^{cam}_t, A_t, o^{pr}_t, \beta_t $를 입력으로 받아서 토크 액션 $a_t$를 출력한다. 지시사항은 원 핫 인코딩되어 있고, ResNet과 LSTM을 연결해서 네트워크를 구성했다. 이후, actor critic MPO 알고리즘으로 학습시켰다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.3 Planner module&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 플래너의 역할은 퍼즐을 풀기 위해 abstract state estimates 값을 받아서 discrete instruction $A_t$를 출력한다. 여기서 instruction은 이런식이다. (앞으로 가기, 북쪽으로 가기, ...). 플래너는 abstract time에서 동작한다. 즉, 플래너의 각 스텝에서에 로봇은 지시사항을 완료할 때 까지 환경과 몇 번(가변)을 상호작용을 한다. 예를 들어 앞으로 가라는 한 번의 지시사항에 10번의 + 토크 행동을 취할 수 있다. Policy network와 비슷하게 ConvLSTM 구조를 사용하고, Q-value 값을 추정하는 critic head를 추가했다. 마찬가지로 플래너의 정책도 RL로 학습되지만 플래너의 관점에서 환경의 추상화된 버전과 상호작용한다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.4 Perception module&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAytxi/btrLhY27vrk/q9gjLetwKiU3u5b2g8OuN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAytxi/btrLhY27vrk/q9gjLetwKiU3u5b2g8OuN0/img.png&quot; data-alt=&quot;Figure 4: Geometry-aware perception network&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAytxi/btrLhY27vrk/q9gjLetwKiU3u5b2g8OuN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAytxi%2FbtrLhY27vrk%2Fq9gjLetwKiU3u5b2g8OuN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1538&quot; height=&quot;573&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 4: Geometry-aware perception network&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 인지 모듈의 경우 $o^{\text {cam}}_t$와 &lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;$o^{\text {pos}}_t$&lt;/span&gt;로부터 순차적으로 abstract state $S_t$를 예측한다. 이 테스크 mapping 문제인데 3D 장면으로부터 2D 지도로 만드는 문제와 동일하다. geometry-aware network 아키텍처를 그림 4와 같이 설계했는데, 강한 inductive bias가 포함된 것이다. (ConvLSTM 구조가 1인칭 시점으로부터 2D mapping을 잘 수행) 그리고 새로운 spatial attention mechanism을 사용했다. 원래의 어텐션과 달리 문제에 맞게 조금 변형 했다고 한다.&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; 네트워크는 2D 지도 $S_t$의 가능한 각 위치에 대해 시각 입력의 다른 요소에 주의를 기울임으로써 작동한다. 공간적 어텐션은 2D 그리드로 배열된 특징 벡터를 생성한다. 이 메커니즘은 abstract state에 대한 implicit belief를 만들고 ConvLSTM에 입력된다. LSTM의 출력은 5가지로 (None, Wall, Box, Target, Box-on-target)으로 구성되어 있다. 현재 추상적 상태의 공간적 위치를 예측하는 것이다. 네트워크의 학습은 크로스 엔트로피로 진행하고 레이블은 abstract state observation $S^* _t$이다. 이 네트워크는 현재 에이전트의 위치값에 의존하지만 시각정보와 고유감각 정보로부터 미래 위치를 예측할 수도 있다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.5 Training algorithm&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2229&quot; data-origin-height=&quot;1455&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzw8iR/btrLgeGAZoa/nCKZ6jCH0ePUUq1GbEs9Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzw8iR/btrLgeGAZoa/nCKZ6jCH0ePUUq1GbEs9Rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzw8iR/btrLgeGAZoa/nCKZ6jCH0ePUUq1GbEs9Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzw8iR%2FbtrLgeGAZoa%2FnCKZ6jCH0ePUUq1GbEs9Rk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;599&quot; height=&quot;391&quot; data-origin-width=&quot;2229&quot; data-origin-height=&quot;1455&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 알고리즘은 위와 같다. 17-19 라인을 보면 RL과 지도학습을 같이 활용한다는 것을 알 수 있다. task-specific한 구현 사항들은 생략되어 있어서 코드를 살펴봐야할 것 같다. side information $(o^{\text {box}}, S^*)$를 observation에 포함시켰는데, 학습에서 컨트롤러의 리워드와 지도학습의 loss를 계산할 때 사용한다. 샘플 수집과 모듈 업데이트를 분리된 노드에서 수행하도록 distributed RL을 적용했다. 하나의 V100 GPU로 learner 노드를 업데이트하고 actor 노드에는 CPU만 사용했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수렴하는데는 각각 7, 21, 5일이 걸렸다고 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Results&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.1 Modular RL results&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2100&quot; data-origin-height=&quot;531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxxFp1/btrLg8ekCey/oW7yINTbvyLcdv6nsfW4h0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxxFp1/btrLg8ekCey/oW7yINTbvyLcdv6nsfW4h0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxxFp1/btrLg8ekCey/oW7yINTbvyLcdv6nsfW4h0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxxFp1%2FbtrLg8ekCey%2FoW7yINTbvyLcdv6nsfW4h0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;634&quot; height=&quot;160&quot; data-origin-width=&quot;2100&quot; data-origin-height=&quot;531&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 먼저 세 가지 경우에 대한 실험이다. 1) oracle의 경우 2D 이미지만을 사용해서 수행한 경우, 2) 플래너와 컨트롤러가 perfect abstract state input을 받는 경우 3) 학습된 모듈들을 사용한 경우다. 성공률은 512개의 랜덤 에피소드에 대해서 다른 난이도로 실험했다. easy (5x5, 1 box), medium (8x8, 3 boxes), hard (10x10, 4 boxes). 만약 에이전트가 4800 스텝 (240초) 내에 퍼즐을 푼다면 성공한 것이다. 모든 모듈은 어려움 단계에서만 학습되었다. 보상의 경우 어려움 난이도에서 측정된 것이다. 최종적인 성공률은 78.7%로 아주 좋은 성능을 보이고 있다. 아래의 그림 5에서 학습 곡선을 보여준다. 이 결과는 Mujoban에서 가장 좋다고 알려진 RL 알고리즘의 성능보다 더 좋다는 것을 보여준다. (표 4를 보면 어려움 단계에서 50%도 안되는 성능을 보이고 있다.) 성능을 직접 비교할 수는 없다는 것에 유의해야 한다. (45초 동안 수행하고, top-down camera, abstract state, expert instruction을 포함하고 있다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.2 Comparison results&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2132&quot; data-origin-height=&quot;1445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r5UO8/btrLhuBxeQu/0wIAj7MfqcZryXK6utBEBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r5UO8/btrLhuBxeQu/0wIAj7MfqcZryXK6utBEBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r5UO8/btrLhuBxeQu/0wIAj7MfqcZryXK6utBEBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr5UO8%2FbtrLhuBxeQu%2F0wIAj7MfqcZryXK6utBEBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;664&quot; height=&quot;450&quot; data-origin-width=&quot;2132&quot; data-origin-height=&quot;1445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&lt;/b&gt;비교결과를 보면 Modular RL의 장점이 더욱 드러난다! Monolithic RL은 ResNet-LSTM 네트워크와 MPO로 학습했다. 동일하게 partially observable setting이고 동일한 actor critic setup을 사용했다. (critic에 privileged side information을 넣음). 커리큘럼 방식, critic network torso share, easy level에서만 학습한 것 등에 대해 비교했다.&amp;nbsp;&lt;br /&gt;&amp;nbsp; 표 3에서는 Structured RL에 대한 실험 결과를 보여준다. partial observability를 제거하고, top-down observation, abstract state를 추가한 것에 대한 실험이다. Monolithic RL의 경우 잘 동작하지 않지만, abstract state를 추가하고 structured exploration을 하도록 했다. 추가적인 유사 보상을 주었다고 한다. 성능이 꽤 잘나오는데 추후에 Option-Critic 같은 일반적인 HRL 메소드와의 비교를 future work로 남겨두고 있다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5.3 Module transfer&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2124&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlLidj/btrLg0gxQ7v/bop2sWeGJkzEmk9V5eut0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlLidj/btrLg0gxQ7v/bop2sWeGJkzEmk9V5eut0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlLidj/btrLg0gxQ7v/bop2sWeGJkzEmk9V5eut0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlLidj%2FbtrLg0gxQ7v%2Fbop2sWeGJkzEmk9V5eut0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2124&quot; height=&quot;413&quot; data-origin-width=&quot;2124&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&lt;/b&gt;Ball robot을 ant robot으로 대체한 실험이다. 환경의 물리적인 크기를 세 배 가까이 늘리고 상자들의 무게와 grid peg는 변하지 않았다. 복잡한 컨트롤에만 집중하기 위해 fully observable mujoban 세팅을 사용했다. 따라서 플래너와 컨트롤러 모듈만 필요하다. 평가 시간은 480초로 늘려서 실험한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 개미를 위한 컨트롤러를 학습시키고 이전의 ball robot에서 학습한 플래너를 가져와서 구성했다. 결과는 표 5에 나와 있는데 성능이 조금 떨어지긴 했지만 &lt;b&gt;학습한 모듈이 재사용 가능하다는 것을 보이고 있다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Discussion &amp;amp; Conclusions&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적절한 모듈화된 아키텍처를 사용하면 매우 어려운 도메인 (시각 입력을 사용하는)에서 개선을 이룰 수 있음을 보였다.&lt;/li&gt;
&lt;li&gt;기존의 End-to-end 방식은 충분한 계산 리소스와 시간이 있어야만 학습이 가능해서 현실문제에 적용하기 어려웠는데, 모듈 아키텍처를 적용하면 더 효율적으로 학습시킬 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;과도하게 모듈화된 구조는 불필요한 오버헤드를 발생시킬 수 있고, 에이전트가 로컬 옵티마에 빠지거나 솔루션을 찾지 못하게 할 수도 있다 이는 모듈들을 일반화해서 설계하고 joint refinement를 함으로써 피할 수 있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1] &lt;a href=&quot;https://sites.google.com/view/modular-rl/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sites.google.com/view/modular-rl/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1662108636867&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Modular RL&quot; data-og-description=&quot;Abstract Intelligent robots need to achieve abstract objectives using concrete, spatiotemporally complex sensory information and motor control. Tabula rasa deep reinforcement learning (RL) has tackled demanding tasks in terms of either visual, abstract, or&quot; data-og-host=&quot;sites.google.com&quot; data-og-source-url=&quot;https://sites.google.com/view/modular-rl/&quot; data-og-url=&quot;https://sites.google.com/view/modular-rl/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hKgjL/hyPF3xXFTB/Q8stKTr8unUYHucIBWIETK/img.png?width=1280&amp;amp;height=1059&amp;amp;face=0_0_1280_1059,https://scrap.kakaocdn.net/dn/GoHC3/hyPEJ8UTvV/ko3suewNkamQCakPQ3Eyb1/img.png?width=1280&amp;amp;height=252&amp;amp;face=0_0_1280_252&quot;&gt;&lt;a href=&quot;https://sites.google.com/view/modular-rl/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sites.google.com/view/modular-rl/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hKgjL/hyPF3xXFTB/Q8stKTr8unUYHucIBWIETK/img.png?width=1280&amp;amp;height=1059&amp;amp;face=0_0_1280_1059,https://scrap.kakaocdn.net/dn/GoHC3/hyPEJ8UTvV/ko3suewNkamQCakPQ3Eyb1/img.png?width=1280&amp;amp;height=252&amp;amp;face=0_0_1280_252');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Modular RL&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Abstract Intelligent robots need to achieve abstract objectives using concrete, spatiotemporally complex sensory information and motor control. Tabula rasa deep reinforcement learning (RL) has tackled demanding tasks in terms of either visual, abstract, or&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sites.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[2] &lt;a href=&quot;https://arxiv.org/abs/2010.01298&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://arxiv.org/abs/2010.01298&lt;/a&gt;&lt;/p&gt;</description>
      <category>Reinforcement Learning</category>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/42</guid>
      <comments>https://neverparadise.tistory.com/42#entry42comment</comments>
      <pubDate>Fri, 2 Sep 2022 19:48:21 +0900</pubDate>
    </item>
    <item>
      <title>최적화 관련 내용 정리</title>
      <link>https://neverparadise.tistory.com/41</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최적화: 주어진 제약조건 하에서 목적함수의 값을 최소 또는 최대로 하는 해를 구하는 문제.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실 속에서 문제를 푸는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 문제를 최적화 문제로 formulation&lt;br /&gt;&amp;nbsp; 상수, 변수, 제약조건, 목적함수를 통해 문제 구성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 알고리즘을 통한 해 구하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 계산 결과를 분석, 검증&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 최적화 문제와 알고리즘 재검토&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어려운 문제를 부분 문제(subproblem)으로 나누거나 완화 문제(relaxation problem)으로 풀 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minimizer (최소자): 특정 최적화 문제에서 목적함수를 최소로 만드는 값&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선형 계획 문제: 목적함수가 선형이고, 모든 제약조건이 선형 등식 혹은 부등식으로 나타낼 수 있는 최적화 문제&lt;/li&gt;
&lt;li&gt;비선형 계획 문제: 목적함수나 제약 조건이 비선형함수로 나타난 문제 (2차함수 등)&lt;/li&gt;
&lt;li&gt;조합 최적화 문제: 결정변수가 정수값, 또는 {0, 1}이라는 이산적인 값을 갖는 최적화 문제. 해의 집합이 순열이나 네트워크 같은 조합된 구조를 가진다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;정수계획 문제: 모든 변수가 정수값을 갖는 선형 계획 문제&lt;/li&gt;
&lt;li&gt;혼잡 정수 계획 문제: 일부 변수가 정수값을 갖는 선형 계획 문제&lt;/li&gt;
&lt;li&gt;쌍대문제: 어떤 최적화 문제의 최적값에 대해서 좋은 상한을 구하는 문제. (dual problem)&lt;/li&gt;
&lt;li&gt;주 문제: 쌍대 문제의 본래 문제 (primal problem)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;쌍대정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목적함수를 최대화하는 상황해서, 선형 계획 문제의 최적값의 좋은 상한을 구하는 문제는 목적함수를 최소화하는 쌍대문제로 변형할 수 있었다. 선형 계획 문제에 최적해가 존재한다면 그 쌍대 문제에도 최적해가 존재하고 일치한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ball&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;open ball: 어떤 점을 중심으로 반지름이 $r$인 구의 내부를 의미. 반지름이 $r \ge 0$인 오픈볼의 표현은 다음과 같음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&amp;nbsp; B(x^*;r) = \{x \in \mathbb R^n: ||x-x^*|| &amp;lt; r \} $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;closed ball의 경우는 등호가 추가된 형태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&amp;nbsp; B(x^*;r) = \{x \in \mathbb R^n: ||x-x^*|| \le r \} $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Point&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;극점 극대점, 극소점 : 함숫값이 국소적으로 최대, 최소인 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임계점(critical point) : 모든 방향으로의 미분계수가 0인 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안장점 (saddle point) : 임계점이지만 극점이 아닌점 즉,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a&amp;nbsp;&lt;b&gt;stationary point(정태점)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;is a point on the surface of the graph where all its partial derivatives are zero&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Upper bound (상계)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수열 $\mathbf a = (a_1, a_2, a_3, \dots)$가 주어졌을 때, 모든 (자연수) $n$에 대하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ a_n \leq B $$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위를 만족시키는 실수 $B$가 존재하면 수열 $\mathbf a$를 위로 유계라 하고, $B$를 수열의 상계라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 위로 경계가 존재한다는 뜻이고 상계는 상한 경계라는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Supremum (the least upper bound)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상계 중에서 가장 작은 것을 최소상계 또는 상한이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Math</category>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/41</guid>
      <comments>https://neverparadise.tistory.com/41#entry41comment</comments>
      <pubDate>Fri, 2 Sep 2022 11:28:46 +0900</pubDate>
    </item>
    <item>
      <title>[Paper Review] - IMPALA: Scalable Distributed Deep-RL with Importance Weighted Actor-Learner Architectures</title>
      <link>https://neverparadise.tistory.com/40</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;TL;DR&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강화학습 에이전트를 더 빠르게 학습시키기위한 분산처리 아키텍처를 제안. 아키텍처는 비동기적으로 동작하는 Actor와 Learner로 구성되며, Off-policy 업데이트 방법인 V-trace를 제안하였음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;생각해봐야할 것&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왜 분산 강화학습 알고리즘의 개발동기는 무엇일까?&lt;/li&gt;
&lt;li&gt;알고리즘의 학습 루프에서 어떤 부분들이 병목현상을 일으키는가?&lt;/li&gt;
&lt;li&gt;IMPALA가 해결하고자 하는 것은 무엇인가? (contribution)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Ape-X, A3C, Batched A2C, IMPALA 간의 차이점은 무엇일까?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Retrace labmda 는 무엇인가?&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Abstract&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;본 논문에서는&amp;nbsp; 하나의 강화학습 에이전트에 단일 파라미터 셋을 사용해서 task 들의 large collection 을 풀고자 한다. 즉, &lt;b&gt;같은 환경을&lt;/b&gt; &lt;b&gt;여러 개를 시뮬레이션 해서 수집한 매우 많은 trajectory 들을 효율적으로 처리하는 것이 목적&lt;/b&gt;이다. 이를 위해 새로운 distributed agent인 IMPALA (Importance Weighted Actor-Learner Architecture)를 제안한다. 하나의 머신에서 리소스를 효율적으로 사용하고 &lt;u&gt;수천 개 규모의 머신들에서 데이터 효율성 감소, 리소스 활용도 감소 없이 학습이 가능하다&lt;/u&gt;. (CPU와 GPU를 놀게 하지 않고 잘 사용한다는 것인데 어떻게 하는 것일까?)&amp;nbsp; &lt;b&gt;에이전트의 acting과 learning을 분리하고 새로운 off-policy correction method인 V-trace를 사용&lt;/b&gt;해서 높은 throughput에서도 안정적인 학습을 가능하게 한다고 한다.&amp;nbsp;실험에서 DM-lab 30, Atari-57 환경에서 효율성을 입증했다. 그리고 multi task RL 에서 task 간의 positive transfer를 보였다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Introduction&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 그동안 강화학습은 하나의 환경에서 에이전트가 좋은 퍼포먼스를 보이게끔 학습되어왔다. 각 테스크마다 분리되어 학습을 진행한 것이다. 본 논문에서는 &lt;b&gt;다양한 테스크들의 집합을&lt;/b&gt; &lt;b&gt;동시에 학습시키고 평가&lt;/b&gt;하는 새로운 방법을 개발하는 것에 초점을 맞춘다. 기존의 SOTA 메소드인 A3C나 UNREAL 같은 경우 며칠에 걸쳐서 10억 개의 프레임들을 얻어야 하나의 도메인을 마스터할 수 있었다. 그런데 이 알고리즘들을 수십 개의 도메인에서 한 번에 학습시키는 것은 너무 느려서 비실용적이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dYH7fN/btrKz4K7HuX/9y1o5bPJTqKWRUcGIKCd31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYH7fN/btrKz4K7HuX/9y1o5bPJTqKWRUcGIKCd31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYH7fN/btrKz4K7HuX/9y1o5bPJTqKWRUcGIKCd31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYH7fN%2FbtrKz4K7HuX%2F9y1o5bPJTqKWRUcGIKCd31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;461&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1318&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A3C의 경우 환경에서 rollout을 수행하는 Worker와 네트워크를 학습시키는 부분이 존재한다. 정책의 파라미터에 대한 그래디언트를 중심에 있는 파라미터와 커뮤니케이션하여 비동기적으로 업데이트한다. &lt;b&gt;반면 IMPALA의 Actor (worker)들은 경험의 trajectory들을 중앙의 러너와 커뮤니케이션한다&lt;/b&gt;. trajectory들의 미니배치에서 업데이트 하기 위해 GPU를 사용하고 시간에 독립적인 연산들은 모두 적극적으로 병렬화 한다. (이 부분이 해석이 좀 안되었는데, actor와 learner 사이에서 trajectory를 전송할 때 시간적 비용이 발생하므로 이 부분을 제외하고 모두 병렬화하는 것 같다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 IMPALA를 활용하면 초당 25만 개의 프레임의 스루풋을 달성할 수 있다고 한다. (A3C 보다 30배나 빠르다!) 그리고 하이퍼파라미터와 네트워크 아키텍처에 더 강건하다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Related Work&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1048&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gs7YX/btrKE7mgZEf/Z91LeKFc98dlKRu0XJp4w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gs7YX/btrKE7mgZEf/Z91LeKFc98dlKRu0XJp4w1/img.png&quot; data-alt=&quot;그림: rollout을 위한 다양한 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gs7YX/btrKE7mgZEf/Z91LeKFc98dlKRu0XJp4w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGs7YX%2FbtrKE7mgZEf%2FZ91LeKFc98dlKRu0XJp4w1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;584&quot; height=&quot;269&quot; data-origin-width=&quot;1048&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림: rollout을 위한 다양한 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; A3C, Gorila, Ape-X, A2C 내용들이 나온다. 특히 batched A2C의 경우 여러 환경을 동시에 실행할 때, 가장 느린 환경이 전체 배치 단계의 수행 시간을 결정한다. 아타리 같은 환경에서는 렌더링 계산과정이 가벼워서 문제가 되지 않지만 물리 시뮬레이션 같은 복잡한 환경에서 돌릴 때, 에피소드의 길이가 다양한 상황일 때 문제가 된다고 한다. 그림에서 (a)의 경우 여러 개의 환경을 각 worker에 할당하여 병렬적으로 동작시켜서 batch &lt;span&gt;state&lt;span&gt; &lt;/span&gt;&lt;/span&gt;를 만들어 낸 후, 이를 gpu 상의 master network에 입력으로 넣어 batch action을 출력한 다음 다시 각 worker에 돌려주는 식으로 동작한다. 그리고 n step 마다 업데이트를 진행한다. (b)의 경우는 정확하지는 않지만 master network 가 각 actor의 환경에서 n step 만큼 순차적으로 forward 연산을 진행하는 것으로 보인다. (a)는 배치단위로 해서 forward 연산을 4번 진행하고 (b) 배치단위로 연산하지 않아서 forward를 16번 진행한다. backward pass는 동일하게 진행한다. 이렇게 하면 특히 (b)의 경우 환경에서 rollout을 하는 동안 GPU를 잘 활용하지 못하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;IMPALA&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lyuUW/btrKBrzR9p2/V7y64mpvyNo7h4elG19QWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lyuUW/btrKBrzR9p2/V7y64mpvyNo7h4elG19QWK/img.png&quot; data-alt=&quot;Figure: IMPALA&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lyuUW/btrKBrzR9p2/V7y64mpvyNo7h4elG19QWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlyuUW%2FbtrKBrzR9p2%2FV7y64mpvyNo7h4elG19QWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;393&quot; height=&quot;291&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure: IMPALA&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; IMPALA의 경우 Actor Critic 구조를 사용하고, baseline으로 Value Function을 사용한다. 환경에서 경험을 생성하는 부분과 정책과 가치함수의 파라미터를 학습하는 부분을 분리하는 것이 핵심이다. (Actor와 Learner의 분리). 그림처럼 아키텍처는 여러 개의 액터들과 여러 개의 러너로 구성할 수 있다. 파라미터는 러너들 사이에서 분산되고 액터가 보내온 경험들을 사용해 타깃 정책 $\pi$를 학습한다. 액터는 러너들로부터 파라미터를 받아오고 observation들을 러너로 보내기만 한다. 데이터 효율성을 위해 파라미터 업데이트는 동기화된 방식을 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 학습과정은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음으로 액터는 자기 자신의 local policy $\mu$를 가장 최근의 러너의 policy &amp;nbsp;$\pi$로 업데이트한다.&lt;/li&gt;
&lt;li&gt;환경에서 n번 스텝을 진행한다.&lt;/li&gt;
&lt;li&gt;n번 스텝을 진행하고, &lt;b&gt;(1)&lt;/b&gt; 상태, 행동, 보상에 대한 trajectory, &lt;b&gt;(2) &lt;/b&gt;initial LSTM hidden state, &lt;b&gt;(3)&lt;/b&gt; local policy distribution $\mu$ 들을 queue를 통해서 learner로 전송한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;learner 는 queue 에 모인 많은 trajectory들을 큰 배치 텐서로 만들어서 학습한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;위 과정을 반복한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 액터-러너 구조를 사용하면 커뮤니케이션 &lt;b&gt;오버헤드가 낮아진다!&lt;/b&gt; 왜냐하면 A3C와 같은 알고리즘에서는 local policy로 gradient를 계산해서 전송했는데 이와는 달리 그저 경험만을 전송하면 되기 때문이다. 그러나 위 과정을 반복할 때 문제점이 발생한다. &lt;b&gt;액터가 rollout을 수행할 때 사용하는 정책과 러너가 학습할 때 사용하는 정책이 달라져서 둘의 policy-lag이 발생한다.&lt;/b&gt; &lt;b&gt;즉, 액터는 러너에 비해 뒤쳐진 정책을 사용할 수 밖에 없으며, Off-policy 업데이트를 수행하게 된다.&lt;/b&gt; 이를 해결하기 위해 V-trace 가 제안되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Efficiency Optimisations&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; IMPALA에서 러너는 전체 trajectory 배치에 대해서 업데이트를 수행한다. 그래서 A3C 같은 온라인 에이전트보다 훨씬 더 많은 병렬화를 수행할 수 있다. (A3C에서는 local gradient 를 계산했었다) 러너는 모든 입력을 CNN으로 병렬처리해서 계산하는데, 시간축을 folding 해서 배치축으로 만든다. 그리고 output layer에 모든 time step들에 대해서 LSTM states가 병렬적으로 계산되도록 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;V-trace&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 정책 지연(policy-lag)으로 인해서 분산된 액터러너 구조는 off policy 학습을 수행하는 것이 중요하다. off policy는 환경에서 행동을 하는 정책 (behavior policy)와 학습 대상 정책 (target policy)가 다른 경우를 말한다. 이제 V-trace target을 살펴보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 행동 정책 $\mu$로부터 생성된 하나의 trajectory $(x_t, a_t, r_t)_{t=s} ^{t=s+n}$을 고려해보자. n-step V-trace target 을 다음과 같이 정의할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHJeKB/btrKFP65AFb/GEecfdwiZslgKkK3xkxvv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHJeKB/btrKFP65AFb/GEecfdwiZslgKkK3xkxvv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHJeKB/btrKFP65AFb/GEecfdwiZslgKkK3xkxvv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHJeKB%2FbtrKFP65AFb%2FGEecfdwiZslgKkK3xkxvv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;635&quot; height=&quot;82&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;125&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, $\delta_t V \overset{\rm def}= \rho _t (r_t + \gamma V(x_{t+1}) - V(x_t))$ 는 V에 대한 temporal difference이다. $\rho_t \overset{\rm def}= \min (\bar \rho, {\pi(a_t | x_t) \over \mu(a_t | x_t)})$, &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;$c_i&amp;nbsp;\overset{\rm def}= \min (\bar c, {\pi(a_t | x_t) \over&amp;nbsp;\mu(a_t | x_t)})$&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;는 truncated&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;importance sampling weight를 의미한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;$\bar c$가 1보다 크고, $c_i = 1, \rho_t = 1$이면 V-trace target은 on-policy의 n-steps 벨만 업데이트 식이 된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/danUF6/btrKFFjk9KK/4kMCSRPW8CnX3ZFatlVDsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/danUF6/btrKFFjk9KK/4kMCSRPW8CnX3ZFatlVDsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/danUF6/btrKFFjk9KK/4kMCSRPW8CnX3ZFatlVDsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdanUF6%2FbtrKFFjk9KK%2F4kMCSRPW8CnX3ZFatlVDsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;103&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;165&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 살펴보자면, $c_i$는 Retrace알고리즘의 trace cutting과 비슷하며, $c_s \dots c_{t-1}$은 TD 값 $\delta_t V$가 특정 시간 s에서 가치함수의 업데이트에 얼마나 영향을 미치는지를 측정한다. $\pi$ 와 $\mu$가 더 다를 수록, weight들의 product 값은 더욱 커지게 된다. 분산을 줄이기 위해 $\bar c$라는 하한을 두었다.$\bar c$는 가치함수의 수렴속도에 영향을 주고&amp;nbsp; $\bar \rho$의 경우 가치함수의 수렴성질에 직접적인 영향을 미친다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Experiments&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;489&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dMAtZI/btrKFwge7nc/dsypd1XZ4biDFAnXh58G21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dMAtZI/btrKFwge7nc/dsypd1XZ4biDFAnXh58G21/img.png&quot; data-alt=&quot;Figure: Model Architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dMAtZI/btrKFwge7nc/dsypd1XZ4biDFAnXh58G21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdMAtZI%2FbtrKFwge7nc%2Fdsypd1XZ4biDFAnXh58G21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;546&quot; height=&quot;328&quot; data-origin-width=&quot;813&quot; data-origin-height=&quot;489&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure: Model Architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 실험은 single task learning 상황과 multi-task learning 상황을 고려한다. 실험에 사용되는 아키텍처는 그림처럼 깊이가 얕은 모델, 깊은 모델 2 가지를 실험한다. 실험환경은 DM Lab 30, Atari 57에서 실험을 진행했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Computational Performance&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IMPALA 의 설계 목적은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rIXvE/btrKFemF8Fr/bexWlpblUSP5wAKoKMoCQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rIXvE/btrKFemF8Fr/bexWlpblUSP5wAKoKMoCQ1/img.png&quot; data-alt=&quot;Table 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rIXvE/btrKFemF8Fr/bexWlpblUSP5wAKoKMoCQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrIXvE%2FbtrKFemF8Fr%2FbexWlpblUSP5wAKoKMoCQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;357&quot; height=&quot;295&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Table 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;High throughput&lt;/li&gt;
&lt;li&gt;Computational Efficiency&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 다른 알고리즘보다 더 좋다는 것을 보이기 위해 A3C, Batched A2C와 비교실험을 수행했다. GPU를 사용하는 단일 머신 실험을 위해서 dynamic batching을 적용했다. (foward pass에서 배치 사이즈가 1이 되는 것을 막아준다) 표 1을 살펴보면 IMPALA가 두 테스크 모두에서 가장 좋은 성능을 보인다. 분산된 멀티 머신 실험에서는 scalability를 보여준다. 초당 25만 개의 프레임 throughput rate를 달성하고 하루에 210억 개의 프레임을 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Single-Task Learning&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Convergence and Stability&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IMPALA 의 learning dynamics를 조사하기 위해서 5개의 DM Lab 환경에서 에이전트를 학습시켰다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1645&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF8k0g/btrKHeecuIq/d2CmqxJBgK3M5AV5vFUkHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF8k0g/btrKHeecuIq/d2CmqxJBgK3M5AV5vFUkHK/img.png&quot; data-alt=&quot;Figure 4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF8k0g/btrKHeecuIq/d2CmqxJBgK3M5AV5vFUkHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF8k0g%2FbtrKHeecuIq%2Fd2CmqxJBgK3M5AV5vFUkHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1645&quot; height=&quot;516&quot; data-origin-width=&quot;1645&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 4&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림은 A3C, A2C와 비교 실험을 수행한 것이다. 대체적으로 좋은 성능을 보이는데, V-trace off policy correction이 더 좋은 성능을 내게 만든 것이라고 추측된다. 아래 행은 하이퍼파라미터 조합에 대한 성능 감소폭을 보인 것이다. 실험 결과, 하이퍼파라미터 값에 더 강건하다고 주장하고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) V-trace Analysis&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgOMhs/btrKErs8j1w/ta90wfvYHoMKTl49mIlzA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgOMhs/btrKErs8j1w/ta90wfvYHoMKTl49mIlzA0/img.png&quot; data-alt=&quot;Figure: Average Final return&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgOMhs/btrKErs8j1w/ta90wfvYHoMKTl49mIlzA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgOMhs%2FbtrKErs8j1w%2Fta90wfvYHoMKTl49mIlzA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;389&quot; height=&quot;301&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure: Average Final return&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;V-trace의 구성요소들에 대한 ablation study를 진행했다. 총 4가지로 V-trace를 구성하고 있는 수식을 변형한 실험이다. 1) No corretion, 2) epsilon correction, 3) 1-step importance sampling, 4) V-trace 에 대해 실험했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) Multi-Task Learning&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ASwtn/btrKOHOo3Vx/RKBAdrdrS68v2YoEK9ri40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ASwtn/btrKOHOo3Vx/RKBAdrdrS68v2YoEK9ri40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ASwtn/btrKOHOo3Vx/RKBAdrdrS68v2YoEK9ri40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FASwtn%2FbtrKOHOo3Vx%2FRKBAdrdrS68v2YoEK9ri40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;373&quot; height=&quot;208&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 실험에서는 모든 액터에서 같은 환경을 실행하는 것 대신, 고정된 숫자의 액터마다 다른 환경들을 할당했다. 예를 들어 48개의 액터가 있었다면 cartpole, pendulum, space invador, mountain car 등의 여러 환경들을 각각 할당하는 것이다. DMLAB-30 환경과 ATARI 57에서 실험을 진행했다. 아키텍처에 여러 가지 변형을 준 후, A3C와 비교한다. Mean capped human normalised score를 metric으로 사용했는데, 이는 하나의 테스크에서 사람을 능가하기보다는 여러 개의 테스크를 잘 푼다는 것을 강조하기 위함이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1] &lt;a href=&quot;https://medium.com/sciforce/reinforcement-learning-and-asynchronous-actor-critic-agent-a3c-algorithm-explained-f0f3146a14ab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/sciforce/reinforcement-learning-and-asynchronous-actor-critic-agent-a3c-algorithm-explained-f0f3146a14ab&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[2] &lt;a href=&quot;https://arxiv.org/abs/1802.01561&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://arxiv.org/abs/1802.01561&lt;/a&gt;&lt;/p&gt;</description>
      <category>Reinforcement Learning</category>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/40</guid>
      <comments>https://neverparadise.tistory.com/40#entry40comment</comments>
      <pubDate>Fri, 2 Sep 2022 11:09:35 +0900</pubDate>
    </item>
    <item>
      <title>리스트 컴프리헨션 사용시 주의점</title>
      <link>https://neverparadise.tistory.com/39</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;강화학습 코드를 작성하다가 정말 작은 실수 때문에 3시간을 날려서 기록으로 남겨둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 기반의 강화학습 코드를 작성할 때 주의해야할 것은 리스트의 얕은 복사와 깊은 복사 문제이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# 얕은 복사&lt;/p&gt;
&lt;pre id=&quot;code_1660802771990&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;action_value = [0 for _ in range(5)]
value_table = [action_value for _ in range(5)]
value_table[0][0] = 1
print(value_table)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 코드를 작성하면 결과가 아래와 같이 출력된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[[1, 0, 0, 0, 0],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;[1, 0, 0, 0, 0],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;[1, 0, 0, 0, 0],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;[1, 0, 0, 0, 0],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1, 0, 0, 0, 0]]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 일까? value_table[0]의 원소들은 모두 action_value를 가리키고 있다. 따라서 하나의 원소를 바꾸면 모두 결과가 바뀌어 버리는 것이다. 이를 방지하려면 아래와 같이 리스트를 깊은 복사를 하도록 코드를 수정하거나 리스트 컴프리헨션을 이중으로 써야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# 깊은 복사&lt;/p&gt;
&lt;pre id=&quot;code_1660802928949&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;action_value = [0 for _ in range(5)]
value_table = [action_value[:] for _ in range(5)]
value_table[0][0] = 1
print(value_table)

value_table = [[0 for _ in range(5)] for _ in range(5)]
value_table[0][0] = 1
print(value_table)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[[1, 0, 0, 0, 0],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[0, 0, 0, 0, 0],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[0, 0, 0, 0, 0],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[0, 0, 0, 0, 0],&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[0, 0, 0, 0, 0]]&lt;/p&gt;</description>
      <category>Programming/Python</category>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/39</guid>
      <comments>https://neverparadise.tistory.com/39#entry39comment</comments>
      <pubDate>Thu, 18 Aug 2022 15:10:42 +0900</pubDate>
    </item>
    <item>
      <title>[Ray] - Introduction to Ray</title>
      <link>https://neverparadise.tistory.com/38</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;What is a Ray?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ray는 파이썬을 위한 분산 강화학습 프레임워크입니다. 오픈소스이며 저수준 API를 통해 파이썬으로 작성된 프로그램을 쉽게 병렬처리할 수 있다. 고수준 API에서는 머신러닝을 모델을 위한 분산학습, 하이퍼파라미터 튜닝, 강화학습 알고리즘등을 제공하고 있습니다. 먼저 Ray를 설치해보겠습니다. 리눅스나 맥 환경에서 사용하는 것을 추천드립니다. (window는 베타버전)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660624980430&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install -U &quot;ray[tune, rllib, serve]&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후, 주피터 노트북 파일을 만들어서 import하고 init 함수를 통해 ray를 실행시켜봅시다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660625318679&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import ray
ray.init()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2305&quot; data-origin-height=&quot;906&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uhg9s/btrJMzZd4aa/fUysyMcoe7l5knRiQgtbMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uhg9s/btrJMzZd4aa/fUysyMcoe7l5knRiQgtbMK/img.png&quot; data-alt=&quot;Figure: Ray Dashboard&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uhg9s/btrJMzZd4aa/fUysyMcoe7l5knRiQgtbMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuhg9s%2FbtrJMzZd4aa%2FfUysyMcoe7l5knRiQgtbMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2305&quot; height=&quot;906&quot; data-origin-width=&quot;2305&quot; data-origin-height=&quot;906&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure: Ray Dashboard&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 위와 같은 Dashboard를 띄울 수 있습니다. 현재 시스템에서 리소스를 얼마나 사용하고 있는지 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;What is a Ray cluster?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/78bgC/btrJQdnzK5o/6O9YDLE9beIitsniQNRHs0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/78bgC/btrJQdnzK5o/6O9YDLE9beIitsniQNRHs0/img.jpg&quot; data-alt=&quot;Figure: Ray Cluster&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/78bgC/btrJQdnzK5o/6O9YDLE9beIitsniQNRHs0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F78bgC%2FbtrJQdnzK5o%2F6O9YDLE9beIitsniQNRHs0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;698&quot; height=&quot;292&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure: Ray Cluster&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 본격적으로 Ray System의 구성요소들을 살펴보겠습니다. 우선 Ray cluster는 하나의 Head node와 여러 개의 Worker node 집합으로 구성됩니다. Head node 가 먼저 드라이버 프로세스와 함께 시작되고 클러스터 구성을 위해 주소값을 각 워커노드에 할당합니다. 각 Worker node은 할당된 작업을 수행하게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Ray cluster&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Head node&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Worker node&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Worker node components&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;Worker process&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; +-- process 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; +-- process 2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; +-- process n ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;Raylet&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; +-- Task Scheduler&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; +-- Object Store&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zpex4/btrJT7BgaRq/ULq6stDUrAOA3cPZCfWeFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zpex4/btrJT7BgaRq/ULq6stDUrAOA3cPZCfWeFK/img.png&quot; data-alt=&quot;Figure: Worker node&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zpex4/btrJT7BgaRq/ULq6stDUrAOA3cPZCfWeFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzpex4%2FbtrJT7BgaRq%2FULq6stDUrAOA3cPZCfWeFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;434&quot; height=&quot;218&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure: Worker node&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Worker process, Raylet&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Worker node는 그림처럼 여러 개의 Worker 프로세스들로 구성되어 있습니다. 각 worker unique한 ID와 IP 주소를 가집니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;worker 입력이 들어오면 판단하지 않고 실행합니다&lt;/u&gt;. 그렇다면 worker가 이미 많은 양의 작업을 처리하고 있거나 리소스가 부족하다는 것을 어떻게 알까요? Worker node 내부의 Raylet 컴포넌트가 이러한 정보들을 알려줍니다.&amp;nbsp;Raylet은 노드의 컴포넌트 중에서 worker 프로세스를 관리합니다. Raylet의 구성요소는 그림처럼 Task scheduler와 Object Store로 구성됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Object store&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 노드에는 object store가 존재합니다. 그리고 모든 object들은 분산된 object store에 집합적으로 저장됩니다. 이제 오브젝트 저장소라고 부르겠습니다. 오브젝트 저장소는 '공유 메모리'를 가지고 있는데 노드들 사이 또는 노드 내부에서 데이터를 공유하는 역할을 담당합니다. 그래서 worker 프로세스들이 필요한 데이터에 쉽게 접근할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Task scheduler&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 스케줄러는 리소스를 관리합니다. 예를 들어, 특정 작업이 4개의 CPU를 요구한다면, 스케줄러는 free worker process를 찾아내고 프로세스들이 리소스에 접근하게 해줍니다. 따라서 스케줄러는 CPU, RAM, GPU에 대한 정보를 알고 있어야 합니다. (Dashboard에 있는 정보들)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케줄러가 신경써야할 또 다른 것은 dependency resolution입니다. 즉, 각 worker들이 작업 수행에 필요한 모든 입력 데이터를 가지고 있는지 보장하는 것이 필요합니다. 처음에 스케줄러는 오브젝트 저장소에서 데이터를 검색해서 local dependency를 해결합니다. 만약 필요한 데이터가 현재 노드의 오브젝트 저장소에 없다면 스케줄러는 다른 노드들과 통신하고 remote dependency들을 받아옵니다. 스케줄러가 작업에 대한 충분한 리소스를 확보하고, 모든 의존성을 해결하고, 작업을 수행할 worker를 찾았다면 작업을 실행단계로 스케줄링합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Head node&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8z9vM/btrJRyGAodr/W9iGpjMKOgVgPgYH5pB71k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8z9vM/btrJRyGAodr/W9iGpjMKOgVgPgYH5pB71k/img.png&quot; data-alt=&quot;Figure: Head node&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8z9vM/btrJRyGAodr/W9iGpjMKOgVgPgYH5pB71k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8z9vM%2FbtrJRyGAodr%2FW9iGpjMKOgVgPgYH5pB71k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;153&quot; height=&quot;202&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure: Head node&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헤드 노드는 worker node의 모든 구성요소에 driver process와 global control store (GCS) 가 추가된 형태입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GCS는 키와 값의 쌍을 저장하고 redis로 구현되어 있습니다. 클러스터에 대한 global 정보를 담고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 아래와 같은 정보들을 저장합니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Raylet이 동작하고 있는지 여부&amp;nbsp;&lt;/li&gt;
&lt;li&gt;모든 actor들의 주소위치&lt;/li&gt;
&lt;li&gt;큰 오브젝트들이 속한 테이블&lt;/li&gt;
&lt;li&gt;오브젝트간의 의존성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ray Core API&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ray에서 핵심적으로 사용되는 API들을 정리해보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;API Call&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;ray.init()&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Ray Cluster를 초기화합니다. 주소를 인자로 주면 존재하는 클러스터에 연결합니다.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;@ray.remote&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;함수를 task로 만들고 클래스를 Actor로 만듭니다.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;ray.put()&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Object store에 데이터를 넣습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;ray.get()&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Object store에서 데이터를 가져옵니다. task나 actor에 의해 계산된 결과를 가져옵니다. 동기적으로 동작합니다.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;.remote()&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Ray cluster에 존재하는 actor 메소드를 실행하거나 task를 실행합니다. 비동기적으로 동작합니다.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;ray.wait()&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Object reference들의 리스트 2개를 반환합니다. 하나는 완료된 테스크들의 리스트이고 다른 하나는 끝나지 않은 테스크들에 대한 것입니다.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 예제를 통해 API를 사용해보겠습니다. 주피터 노트북에서 코드 작성을 권장드립니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# ex 2-1&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 ray를 사용하지 않고 데이터베이스에 있는 아이템을 검색하는 예제입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660782100348&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import time
import ray
ray.init()

database = [
    &quot;Learning&quot;, &quot;Ray&quot;, &quot;Flexible&quot;, &quot;Distributed&quot;, &quot;Python&quot;, 
    &quot;for&quot;, &quot;Data&quot;, &quot;Science&quot;
]

# ex 2-1
def retrieve(item):
    #time.sleep(item / 10.)
    time.sleep(len(database[item]) / 10.0)
    return item, database[item]

def print_runtime(input_data, start_time, decimals=2):
    print(f&quot;Runtime: {time.time() - start_time:.{decimals}f} seconds, data:&quot;)
    print(*input_data, sep=&quot;\n&quot;)

start = time.time()
data = [retrieve(item) for item in range(8)]
print_runtime(data, start)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 결과 시간이 대략 5초정도 걸렸습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660782148731&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Runtime: 5.01 seconds, data:
(0, 'Learning')
(1, 'Ray')
(2, 'Flexible')
(3, 'Distributed')
(4, 'Python')
(5, 'for')
(6, 'Data')
(7, 'Science')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# ex 2-2: ray.remote&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ray.remote 데코레이터를 통해 아주 간단하게 파이썬 함수를 Ray의 task로 만들 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 작성하고 제대로 동작하는지 확인한다음, 데코레이터를 코드에 추가하기만 하면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660782335683&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ray.remote # 데코레이터를 사용하면 파이썬 함수를 Ray task로 만들 수 있다. 
def retrieve_task(item):
    return retrieve(item)

start = time.time()
data_references = [retrieve_task.remote(item) for item in range(8)]
data = ray.get(data_references)
print_runtime(data, start, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660782382919&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Runtime: 1.22 seconds, data:
(0, 'Learning')
(1, 'Ray')
(2, 'Flexible')
(3, 'Distributed')
(4, 'Python')
(5, 'for')
(6, 'Data')
(7, 'Science')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;놀랍게도 시간이 약 4배 가까이 줄어들었습니다. 더 빠르게 작업을 처리할 수 있었던 이유는 함수의 실행을 비동기적으로, 병렬처리 했기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# ex 2-3: Object store with put and get&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 상황은 retrieve 함수가 database에 직접 접근할 수 있습니다. 그래서 remote function 또한 local Ray cluster에 접근하면서 동작하게 됩니다. 하지만 여러 개의 컴퓨터로 구성된 실제 cluster 환경에서는 이렇게 데이터베이스에 직접 접근해서 함수를 동작시킬 수 없습니다. 데이터베이스를 공유메모리에 올리는 것이 필요한 것이죠!&lt;br /&gt;ray에서는 driver나 여러 개의 worker 사이에서 데이터를 쉽게 공유할 수 있도록 put과 get이라는 메소드를 만들었습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ray.put(object): &lt;br /&gt;ray의 put함수를 통해서는 Head node나 Worker node의 Objectstore에 Object 데이터를 넣고 Store에 대한 레퍼런스 주소 값을 받아올 수 있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;ray.get(object_store_ref): &lt;br /&gt;ray의 get함수를 통해 레퍼런스 주소값을 넣어서 원래 데이터를 가져올 수 있습니다. 이렇게 오브젝트 스토어에 데이터를 공유하면 오버헤드가 줄어듭니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1660782703364&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;database_object_ref = ray.put(database)

@ray.remote
def retrieve_task(item):
    obj_store_data = ray.get(database_object_ref)
    time.sleep(len(obj_store_data[item]) / 10.0)
    return item, obj_store_data[item]

start = time.time()
data_references = [retrieve_task.remote(item) for item in range(8)]
data = ray.get(data_references)
print_runtime(data, start, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660782720330&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Runtime: 1.13 seconds, data:
(0, 'Learning')
(1, 'Ray')
(2, 'Flexible')
(3, 'Distributed')
(4, 'Python')
(5, 'for')
(6, 'Data')
(7, 'Science')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오버헤드 감소로 인해 걸린시간이 약간 줄어든 결과를 볼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# ex 2-4: ray.wait() &lt;/b&gt;Wait function for non-blocking calls&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;404&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XEwvH/btrJYxMMl49/wW2orvI4lRBW31DbhIvJc1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XEwvH/btrJYxMMl49/wW2orvI4lRBW31DbhIvJc1/img.jpg&quot; data-alt=&quot;ray.wait()의 동작&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XEwvH/btrJYxMMl49/wW2orvI4lRBW31DbhIvJc1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXEwvH%2FbtrJYxMMl49%2FwW2orvI4lRBW31DbhIvJc1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;308&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;404&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ray.wait()의 동작&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;예제 2-2처럼 ray.get(data_references)를 사용해서 결과에 접근하는 것을 blocking 이라고 부릅니다. 즉, 모든 결과가 끝날 때까지는 값을 출력하는 것이 막혀있는 것이죠. 이는 Head node의 driver process가 모든 결과들이 끝날 때 까지 기다린다는 의미입니다. 지금의 경우에는 큰 문제가 되지 않지만 각 데이터를 처리하는 시간이 몇 분씩 걸릴 수도 있습니다. 이 때, 저희는 driver process가 대기하기보다는 다른 task들에 대해서 자유롭게 동작하기를 바랍니다. 드라이버가 작업이나 데이터가 들어올 때마다 처리하는 것이죠!&amp;nbsp;&lt;br /&gt;또 한 가지 생각해봐야할 것은 데이터를 탐색하지 못한다면 데드락이 발생할 수 있습니다. 데이터베이스 연결에 데드락이 발생하면 드라이버 프로세스는 멈추게 되고 모든 아이템을 탐색할 수 없게 된다. 따라서 적절한 타임아웃을 추가해서 코드를 작성해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660783014802&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;start = time.time()
data_references = [retrieve_task.remote(item) for item in range(8)]
all_data = []

while len(data_references) &amp;gt; 0:
    finished, data_references = ray.wait(data_references, num_returns=2, timeout=7.0)
    data = ray.get(finished)
    print_runtime(data, start, 3)
    all_data.extend(data)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ray.wait() 함수는 task에 대한 레퍼런스 값을 받아서 끝난 task에 대한 레퍼런스 값과 완료되지 않은 레퍼런스 값을 리턴합니다. 그리고 timeout 인자를 통해 시간을 설정할 수 있습니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1660783409595&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;start = time.time()
data_references = [retrieve_task.remote(item) for item in range(8)]
all_data = []

while len(data_references) &amp;gt; 0:
    finished, data_references = ray.wait(data_references, num_returns=2, timeout=7.0)
    data = ray.get(finished)
    print_runtime(data, start, 3)
    all_data.extend(data)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660783471142&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Runtime: 0.311 seconds, data:
(1, 'Ray')
(5, 'for')
Runtime: 0.610 seconds, data:
(4, 'Python')
(6, 'Data')
Runtime: 0.806 seconds, data:
(0, 'Learning')
(7, 'Science')
Runtime: 1.110 seconds, data:
(2, 'Flexible')
(3, 'Distributed')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# ex2-5: Actor class&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ray.remote 데코레이터를 함수 말고 클래스에도 적용할 수 있습니다. 이때, remote가 적용된 class는 actor라고 부릅니다. 이렇게 하면 클러스터에서 현재 상태를 표현할 수 있는 코드를 구현할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660783587091&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ray.remote
class DataTracker:
    def __init__(self) -&amp;gt; None:
        self._counts = 0
    
    def increment(self):
        self._counts += 1
    
    def counts(self):
        return self._counts

# 이 클래스는 데이터 개수를 추적한다. 

@ray.remote
def retrieve_tracker_task(item, tracker):
    obj_store_data = ray.get(database_object_ref)
    time.sleep(item / 10.)
    tracker.increment.remote()
    return item, obj_store_data[item]

tracker = DataTracker.remote()
data_references = [retrieve_tracker_task.remote(item, tracker) for item in range(8)]
print(ray.get(data_references))
print(ray.get(tracker.counts.remote()))
print(ray.get(tracker._counts))&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660783610693&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[(0, 'Learning'), (1, 'Ray'), (2, 'Flexible'), (3, 'Distributed'), (4, 'Python'), (5, 'for'), (6, 'Data'), (7, 'Science')]
8&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 ray의 내용들을 살펴보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;a href=&quot;https://docs.ray.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.ray.io/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1660783729001&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Welcome to the Ray documentation &amp;mdash; Ray 1.13.0&quot; data-og-description=&quot;If you&amp;rsquo;re new to Ray, check out the getting started guide. You will learn how to install Ray, how to compute an example with the Ray Core API, and how to use each of Ray&amp;rsquo;s ML libraries. You will also understand where to go from there.&quot; data-og-host=&quot;docs.ray.io&quot; data-og-source-url=&quot;https://docs.ray.io/&quot; data-og-url=&quot;https://docs.ray.io/en/latest/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfC2Ey/hyPuADbvpQ/f7u3pygwjA7tcgnXbZSdeK/img.png?width=4726&amp;amp;height=1478&amp;amp;face=0_0_4726_1478,https://scrap.kakaocdn.net/dn/CL8Vb/hyPuFkbv4b/w1AhhJkQUa0HGzKevSAiU0/img.png?width=779&amp;amp;height=735&amp;amp;face=0_0_779_735,https://scrap.kakaocdn.net/dn/i6YST/hyPuLq9w7t/O2ABa0uUkJex5jpHwIv6fK/img.png?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500&quot;&gt;&lt;a href=&quot;https://docs.ray.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.ray.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfC2Ey/hyPuADbvpQ/f7u3pygwjA7tcgnXbZSdeK/img.png?width=4726&amp;amp;height=1478&amp;amp;face=0_0_4726_1478,https://scrap.kakaocdn.net/dn/CL8Vb/hyPuFkbv4b/w1AhhJkQUa0HGzKevSAiU0/img.png?width=779&amp;amp;height=735&amp;amp;face=0_0_779_735,https://scrap.kakaocdn.net/dn/i6YST/hyPuLq9w7t/O2ABa0uUkJex5jpHwIv6fK/img.png?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Welcome to the Ray documentation &amp;mdash; Ray 1.13.0&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;If you&amp;rsquo;re new to Ray, check out the getting started guide. You will learn how to install Ray, how to compute an example with the Ray Core API, and how to use each of Ray&amp;rsquo;s ML libraries. You will also understand where to go from there.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.ray.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Learning ray, 2022&lt;/p&gt;</description>
      <category>Programming</category>
      <author>neverparadise</author>
      <guid isPermaLink="true">https://neverparadise.tistory.com/38</guid>
      <comments>https://neverparadise.tistory.com/38#entry38comment</comments>
      <pubDate>Thu, 18 Aug 2022 09:49:33 +0900</pubDate>
    </item>
  </channel>
</rss>