gymnasium
gymnasium 소개
이번 시간에 할 것은 우리가 이제 gymnasium 또는 짐이라고 하는 팔선 패키지를 사용을 해서 우리가 강학습을 실제로 코딩으로 체험을 해보도록 하겠습니다
어려운 걸 하진 않으니까 적당히 하시면 되고 일단 이제 gymnasium이라는 게 뭐냐 하면은 원래 오픈 ai라고 책 gpt 만든 회사인데 여기에서 만든 짐이라는 라이브러리가 있어요.
라이브러리는 뭐냐면 우리가 프로그램을 짤 때 내가 모든 걸 프로그램으로 짠 게 아니라 남들이 만들어 놓은 어떤 기능 모음 기능 모음을 가져와서 그걸 바탕으로 깝니다.
기능을 모아 놓은 거니까 라이브러리는 책을 모아 놓은 거잖아요.
약간 비슷하다고 해서 보통 우리가 프로그래밍에서 기능 모음을 라이브러리라고 해요
강학습을 하는데 여러 가지 어떤 기능이 필요하니까 그걸 만든 거고 원래는 오픈 ai에서 만들었는데 2021년부터 오픈 ai가 손을 뗐습니다
그래서 우리가 이제 더 이상 만들기 귀찮으니까 아메 해주세요
그래서 이제 파라마 재단이라는 재단을 따로 만들어서 얘네가 이름을 바꿔서 김라지움이라는 형태로 관리를 하고 있습니다.
포크라고 되어있는데 포 크는 뭐냐면 짐이 이렇게 가고 있고 그래서 갈라져 나온 거예요
그래서 포크 모양이라고 해서 포크라고 합니다.
짐은 개발이 중단됐고 김라지움이라는 이름으로 계속 되는 거죠
주피터 노트북
그래서 이거를 실습을 하시려면 일단 우리 여기 사이트에 보시면 실습 및 Q&A에 보시면 일단 순서가 있는데 일단 줌피터 노트북 실행이라고 있어요
그래서 이거를 실행을 하시면 돼요
약간 주황색으로 눈 모양으로 생긴 아이콘이 있거든요
그거 누르시면 됩니다
이렇게 이렇게 생긴 아이콘 클릭 하셔가지고 실행하시면 되구요
그래서 이제 실행을 하시면 아 아 이거 캡처해 놓은 겁니다
아 뭐 이런 식의 화면이 아마 인터넷 창이 뜨실 거예요
안 뜨시는 분 있으시면 얘기해 주시구요
그 이게 뭐냐면 이제 주피터 노트북 설명을 좀 드리면 일단 우리가 주피 노트북을 쓰는데 주피터 노트북이 뭐냐
주피터라고 하겠습니다.
우리가 이제 파이썬이라는 프로그래밍 언어를 쓰는데 파이썬은 언어거든요
말입니다.
그러면은 컴퓨터한테 요 말을 하는데 뭔가 프로그램이 필요합니다.
여러분 친구한테 말을 하려면 카톡을 보내고 있어요.
앱을 써야 되잖아요
그러니까 우리가 친구한테 오늘 술 먹자 라고 한국말로 하려면 한국어도 언어죠
이거를 전달을 하려면 중간에 카톡이라든지 이런 앱이 필요하잖아요
마찬가지로 파이썬은 언어라서 이걸 컴퓨터한테 전달하려면 뭔가 전달해 주는 앱이 필요해요 그래서 이제 주피터라는 게 보통 데이터 분석이나 이럴 때 많이 사용하는 앱입니다.
우리가 한국 사람은 카톡으로 대화하듯이 파이썬을 쓸 때는 주피터라는 앱으로 많이 대화를 합니다.
이거를 일단 실행을 해주셔야 되구요
일단 제거를 좀 설치해놓고 그다음에 이제 이런 식으로 인터넷 창에 뜨는데 왜 인터넷 창에 뜨냐면 주피터 노트북은 이 컴퓨터가 내 컴퓨터가 아닌 경우에 대응해서 만들어져 있어요.
왜냐면 우리가 데이터 분석 같은거 할 때는 데이터가 되게 많으니까 내 컴퓨터에 그 데이터를 다 옮겨놓지 못하는 경우도 많고 회사 자료 이런거는 보안 문제가 있으니까 내 컴퓨터 옮겨놓으면 좀 문제란 말이에요
그래서 이제 원격에 서버가 있고 카톡하고 마찬가지입니다.
친구는 저쪽에 있고 친구한테 내가 말을 하는데 나는 내 스마트폰에서 말을 하지만 그 말은 친구한테 전달되잖아요.
주피터도 원래는 데이터가 있는 컴퓨터랑 내 컴퓨터가 별도인 경우를 상정하고 만들어져 있어요.
지금은 여러분 컴퓨터에서 하거든요.
그래서 어떻게 하냐면 혼자서 약간 이중 플레이를 합니다.
보시면 지금 약간 까만 창이 하나 떠있을 거에요.
그 까만 창이 뭐냐면 이쪽 원격 서버 역할을 흉내를 내는 겁니다.
그래서 마치 인터넷을 하는 것 같지만 사실 여러분 컴퓨터 한대에서 약간 북치고 장북치고 혼자 1인 2역을 하는 거에요.
그래서 그 까만 창은 닫으시면 안됩니다.
까만 창을 닫으면 1인 2역을 하고 한쪽이 없어지니까 대화가 안돼요.
그 다음에 이제 이런 화면이 뜨는데 여기 보시면 폴더들이 여러 개 있는데 이건 꼭 선택하셔야 되는 건 아니지만 그 중에 데스크탑이라고 있을 겁니다.
한 네 번째 쯤에 있을 거에요.
그래서 데스크탑을 눌러주세요.
여기 있는대로 여기 보시면 데스크탑을 선택을 하시면 되고 그 다음에 이제 퓨터 도둑 화면을 보면 이렇게 화면이 있고 데스크탑 선택하신다면 오른쪽에 보면 뉴라는 버튼이 이렇게 오른쪽 위에 있을 겁니다.
이거를 누르시면은 화면이 안나오면 써야죠.
노트북 눌러주세요.
네 그 다음에 선택하시면 됩니다.
그 다음에 이제 파이선 3를 고르시는데 아 제가 설치가 다 됐으니까 한번 보여드리면 모든 앱 누르고 아나콘다 3에서 주피턴을 두르고 그 다음에 이제 까만창이 뜨고 여기 이제 뭐라 뭐라 뭐라 해도 출력이 됩니다.
그러면은 크롬을 열어라 항상 누르면 인터넷 하는 것처럼 이렇게 나오지만 사실은 인터넷 하는게 아니고 약간 흉내만 해요.
그래서 여기서 여기서 데스크탑 누르시고 그러면은 뭐 강화학수 프로그래밍 뭐 이런게 나오죠.
안나올 수도 있겠군요.
일단 데스크탑이 어디냐면 바탕화면이 있다.
그래서 바탕화면에 실습한 파일들을 놓으려고 해요.
그 다음에 이제 뉴 누르고 노트북 그러면 이제 물어보죠.
파이선 3를 선택을 하시면 됩니다.
그래서 여러분들 바탕화면에 가시면 바탕화면에 가시면 아마 이제 Untitled 라고 여기 여기 보이시나요?
Untitled 라고 이런 파일이 하나 생겨있을 거에요.
여러분이 이제 이 파일은 뭐냐면 여러분이 이제 주피터를 통해서 컴퓨터랑 대화를 하면 그 대화가 이 파일에 다 자동으로 기록이 됩니다.
그래서 이제 내일도 다시 열어볼 수가 있어요.
그래서 우리가 아까 바탕화면을 고른 이유는 이 파일을 바탕화면에 저장하려고 그랬던 겁니다.
그래서 그래서 이제 이 Untitled 라는 이름이 싫다 그러면은 여기 상단의 메뉴에 보시면 View 라고 있거든요.
File Edit View. View를 누르시면은 Show Header 라고 있는데 상단 메뉴에서 View Show Header. 이거 누르시면은 이렇게 주피터 로고랑 Untitled 라는게 보이거든요.
접어드릴게요.
말로만 하면 헷갈릴거에요.
그래서 상단 메뉴에서 View 누르고 Show Header. 그 다음에 여기 Untitled 를 한번 눌러주시면 이름을 바꿀 수 있어요.
Rename File 나오는데 지금 현재 이름이 Untitled IPNB 인데 나중에 이게 헷갈리니까 Day 1 이렇게 바꾸시면 아 이게 1일차 한거구나.
알 수 있겠죠.
뭐 Day 1으로 하셔도 되고 뭐 다른 걸로 하셔도 되는데 일단은 Day 1으로 하겠습니다.
그래서 이제 바탕화면에 다시 보시면 파일 이름이 Day 1으로 바뀌어 있어요.
제가 그 저희 그 제 아내가 가끔 우리 대화 좀 하자
이러면은 제가 어 그래 그 소위 대화라는거 좀 해보시지
뭐 약간 이런식으로 갈테가 있는데 우리가 이제 그 컴퓨터랑 대화를 하면은 어떻게 되느냐
별건 없구요.
예를 들면 간단하게 1 더하기 1 얼마냐
이렇게 물어볼 수 있겠죠.
그냥 간단한데 여기다가 1 더하기 1 이렇게 쓰시면 돼요.
빈칸은 넣으셔도 되고 안 넣으셔도 되고 상관없습니다.
1 더하기를 하신 다음에 여기 상단에 보면 이렇게 재생버튼같이 생긴게 있거든요.
이거를 누르시면 이하고 컴퓨터가 대답을 합니다.
대화를 한다고 해서 뭐 진지하게 인생에 대해서 토론을 하는건 아니고 내가 어떤 코드를 넣으면 그거에 대한 실행결과를 이렇게 답변을 해줘요.
여기 재생버튼 같은거 누르시면은 그 말이 넘어갑니다.
gym 설치
그 다음에 이제 우리가 긴나지움을 설치를 해야 되는데 파이선에는 PIT라고 해서 여기 이제 PLP 있죠.
이거가 뭐냐면 이런 라이드러리 관리 프로그램입니다.
그래서 원래는 관리 프로그램을 켜가지고 이 긴나지움을 설치를 해야 되는데 이게 이제 귀찮기 때문에 그냥 느낌표를 하고 뒤에다 프로그램 이름을 쓰면 쥬피토 노트북이 알아서 대신 실행을 시켜줍니다.
그래서 느낌표 PIP 한 다음에 예약 PIP 프로그램 덜어 인스톨 하라고 좀 시켜라.
뭘 인스톨 하라고 시키냐면 긴나지움을 인스톨 하라고 시켜라 라고 하면 쥬피토 노트북이 대신 PLP한테 가서 이거를 실행을 시켜주는 거죠.
그래서 이건 이제 파이선 코드는 아니고 그냥 쥬피토 노트북의 기능입니다.
앞에 느낌표가 붙으면 어떤 외부 프로그램을 작동을 시킬 수가 있어요.
!pip install gymnasium
이것도 이제 재생을 누르면 지금은 여기 별표시가 뜨고 반응이 없거든요.
왜냐하면 지금은 PIP가 열심히 돌아가면서 긴나지움을 설치를 하고 있습니다.
다 끝나면 이제 Successfully Installed 이렇게 나오면서 끝나요.
그래서 보면 여기 주저리 주저리 뭐라고 나오는데 이거는 이제 뭐냐면 지금 보시면 Requirement Already Satisfied 이런 말 나오는데 이건 뭐냐면 긴나지움을 깔다가 넌파이도 깔아야 되네?
그럼 넌파이도 깔려있나 보니까 넌파이는 이미 여기 깔려있네?
그러면 얘는 패스 그 다음에 클라우드 피클이라는 것도 필요한데 얘도 여기 깔려있으니까 패스 이런 식으로 필요한 걸 찾아가지고 이미 깔려있으면 넘어가고 안 깔려있으면 추가로 설치도 해줍니다.
그래서 PIP라는 프로그램이 해주는 게 다운받고 설치하고 이런 걸 자동으로 다 해줘요.
긴나지움을 까는데 필요한 모든 작업을.
그래서 여러분이 일일이 설치할 필요가 없습니다.
내가 원하는 것만 말하면 나머지는 다 자동이에요.
임포트
import gymnasium as gym
그래서 여기 import라는 게 있는데 import가 설치된 걸 불러온 거예요.
그래서 우리가 오늘 설치를 했기 때문에 내일부터는 설치를 또 안 해도 됩니다.
내일은 PIP 안 해도 돼요.
내일 또 오셔가지고 또 설치하시는 분 있거든요.
또 설치해도 큰 문제는 없지만 집에 냉장고를 한번 설치했으면 이사갈 때까지 설치 안 해도 되는 거잖아요.
이 컴퓨터는 설치가 된 상태니까 계속 쓰면 되는데 문제는 여러분들이 오늘 아침에 냉장고 문을 여셨다고 오늘 저녁에 안 열어도 되는 건 아니죠.
냉장고에서 꺼내 먹으려면 냉장고 문을 열어야 되잖아요.
마찬가지로 여러분이 쥬피터 노트북에서 이런 식으로 노트를 만들어서 대화를 한번 시작하면 매번 대화를 할 때마다 긴나지움을 열어줘야 됩니다.
그래서 이제 열어놓고 거기서 기능을 꺼내다 쓰는 거예요.
그리고 대화가 끝나면 자동으로 닫히는데 다음 번 대화 때는 이미 다 닫혔으니까 다시 열어야 되죠.
그래서 매번 대화할 때마다 임포트라는 걸 이용해서 긴나지움을 불러옵니다.
임포트가 원래 직역하면 수입하다
이런 거죠.
외부에 있는 기능을 가져오는 겁니다.
근데 파이선은 어떤 기능이냐면 가져올 때 얘한테 다른 이름을 붙여줄 수 있어요.
우리가 외국에서 수입할 때 그 물건을 똑같은 이름으로 수입할 때도 있지만 가끔 이름을 좀 바꿔서 수입할 때도 있거든요.
예를 들면 우리나라에서도 아반떼가 외국에 수출할 때는 엘란트라 라는 이름으로 수출하거든요.
이름을 바꿀 수 있는데 이 as가 이름을 바꾸는 기능입니다.
그래서 뭐뭐로 써 이런 거죠.
그래서 긴나지움의 이름을 다른 걸로 바꿀 건데 원래 김에서 긴나지움이 파생이 됐으니까 긴나지움을 임포트할 때 김이라는 이름으로 임포트를 하면 우리가 옛날에 김으로 짜놓은 코드가 있으면 어차피 두 개가 호환되기 때문에 긴 나지움의 이름만 짐으로 바꿔주면 컴퓨터는 그게 두 개가 같은 건가 싶다
이렇게 넘어가게 됩니다.
실제로는 긴나지움이지만 임포트할 때는 짐으로 임포트를 해줍니다.
블랙잭
그래서 우리가 이제 짐 또는 긴나지움이 제공하는 중요한 기능은 뭐냐면 강화학습의 환경을 정의하는 것을 도와줘요.
그래서 여러분들이 다양한 강화학습 알고리즘을 만들 수가 있는데 대부분의 알고리즘이 환경이 일단 짐 또는 긴나지움 기준으로 만들어져 있다고 전제하고 알고리즘이 짜여져 있습니다.
그래서 여러분들이 환경을 직접 만드실 때도 이 짐 기준으로 만드셔야 다른 강화학습 알고리즘을 쓸 수가 있어요.
그리고 이제 약간 기본으로 몇 가지 환경은 내장이 되어 있는데 아주 간단한 예를 들면 블랙 잭 이런거가 환경이 내장이 되어 있습니다.
블랙 잭은 많이들 아시겠지만 카드 게임이죠.
그래가지고 카드를 해서 20일에 가까운 사람이 이기는 카드 게임입니다.
env = gym.make("Blackjack-v1")
그래서 이렇게 실행을 하면 짐한테 메이크 만들려고 하는 거예요.
여기 점은 뭐냐면 이 메이크 라는게 함수인데 명령이라고 생각하시면 돼요.
그 명령이 짐에 소속되어 있다
이렇게 생각하시면 됩니다.
점은 소속을 나타내고 그리고 이런 함수를 할 때는 이거 엑셀도 마찬가지인데 항상 과로를 쳐가지고 이 함수에 넘겨줄 값을 써주거든요.
그래서 여기다가 다운표에서 블랙 잭, 브이건 하면 이 이름을 메이크에 넘겨주면 메이크가 이미 내장되어 있는 환경 중에서 이 이름의 환경을 불러와가지고 이 ENV에다가 넣어줍니다.
여기 부원은 넣는 이렇게 써야 하는데 이게 두개가 같다라는 게 아니고 보통 프로그래밍에서는 오른쪽에 실행 결과를 왼쪽에다가 할당을 해라
이런 뜻이에요.
그럼 이 ENV에는 블랙 잭을 할 수 있는 환경이 들어가 있는 거죠.
그래서 이 환경을 쓰는 건데 이 환경에도 소속된 명령들이 있습니다.
그 중에 리셋이라는 명령이 있는데요.
이 리셋은 뭐냐면 시작, 시작, 에피소드를 시작하려면 리셋을 해줘야겠죠.
obs, info = env.reset(seed=42)
obs
(15, 2, 0)
그 다음에 여기 seed는 40이 이렇게 되어 있는데 이거는 뭐냐면 우리가 블랙 잭 같은 거는 뭡니까?
게임 자체가 랜덤이잖아요.
우리가 카드 게임하면 어떤 카드가 나올지 모른단 말이에요.
그래서 컴퓨터가 이제 난수를 생성을 하는데 컴퓨터는 그 순수한 의미에서 난수를 생성할 수가 없습니다.
난수라는 건 정말 말 그대로 무작위인데 컴퓨터는 1 더 1을 하면 2 가 나오는 계산기라서 무작위적인 숫자를 만들 수가 없어요.
그래서 어떻게 하냐면 유사한 난수라는 걸 생성을 합니다.
어떻게 하냐면 어떤 약간 이상하게 복잡한 공식을 해가지고 여기다 42를 넣으면 예를 들면 13,698 이렇게 나와요.
이 숫자를 또 이 공식에다 넣으면 그 다음에 716 이런 숫자가 나올까.
어떤 희한한 공식이 있어서 어떤 숫자를 넣으면 그 다음에 되게 뜬금없는 숫자가 튀어나오는 아주 희한하게 생긴 공식을 씁니다.
그러면 이렇게 놓고 보면 마치 랜덤한 숫자처럼 보이죠.
그래서 보통 첫 번째 값으로 시간을 보통 넣어요.
그래서 돌릴 때마다 결과가 달라지는데 그래서 우리가 보면 랜덤하네
이런 느낌이 들지만 실제로는 그냥 그때그때 다른 숫자가 나오는 것 뿐이에요.
그래서 여기다가 시즌은 42 이렇게 하면 첫 번째 값은 난수를 생성하는데 첫 번째 값은 42로 해라
이런 얘기인데 이건 왜 하냐면 별 이유는 없고 여러분들이랑 저랑 결과를 똑같게 만들기 위해서 그래요.
난수니까 그때그때마다 결과가 다르다는 거예요.
그러면 이게 내가 지금 제대로 돌린게 맞나 헷갈리잖아요.
그래서 그런 용도고 실제로는 안 쓰셔도 됩니다.
그냥 이거는 결과를 여러분이랑 똑같이 만들려고 한거니까 그 다음에 그럼 요 실행된 결과가 왼쪽에 obs랑 info 두 가지 변수에 들어가게 됩니다.
그래서 obs는 observation이란 뜻이에요.
관찰치.
그래서 뭔가
게임을 시작을 했으면 우리가 이제 그 게임에서 관찰하는 바가 있겠죠.
그래서 그냥 obs로 끝나면 obs의 변수 내용을 보여줍니다.
그래서 1520 3개 숫자가 나와요.
이게 우리가 현재 게임에서 관찰할 수 있는 내용입니다.
그래서 블랙잭을 하면 볼 수 있는 게 있고 없는 게 있잖아요.
뭘 볼 수 있습니다.
내 펜은 볼 수 있죠.
그 다음에 다음에 뭐가 나올지도 모르죠.
그거는 분명히 고정된 상태인데 나한테는 안보여요.
관찰할 수 있는 거는 내 눈에 보이는 것만 이렇게 나오는데
요 세 가지가 뭐냐 일단 플레이어에 합계.
내 지금 가지고 있는 카드가 다 더해서 얼마냐.
그러면 15고 그 다음에 딜러의 카드는 뭐냐.
1에서 10까지 나오는데 딜러의 카드는 2네요.
그 다음에 여기 영은 뭐냐면 블랙잭 게임에서는 트럼프 카드 중에 a가 들어가 있으면 내 편한 대로 계산할 수도 있거든요.
1로 계산할 수도 있고 11로 계산할 수도 있고.
그래서 지금은 이제 에이스는 없습니다.
15인데 블랙잭은 그래서 여러분 할 수 있는 행동이 두 개 밖에 없어요.
카드를 더 받을 거냐
말 거냐 그러면 21이 되면 최고 점수고 21을 넘기면 무조건 꼴등입니다.
여러분 같으면 지금 딜러는 2를 들고 있고 나는 지금 합쳐서 15점인데 카드를 한 장 더 받을까요
말까요
6이 나오면 베스트고 1 2 3 4 5는 괜찮고 7 8 9 10이 나오면 난 망해요.
여러분 이제 카지노 가서 앉아있으면 더 받을까요 말까요.
그래서 도박이죠.
행동 공간
그래서 여러분이 행동을 할 수가 있는데 여러분의 행동은 영은 멈춤
그만하겠다는 거고 1은 한 장 더 받겠다.
만약에 한 장 더 받아서 21 나오면 이기는 거고 만약에 한 장 더 받았는데 20 23 이렇게 되면 망하는 거고 19 18 이렇게 나오면 딜러도 한 장 더 받거든요.
그러면 딜러보다 점수가 높으면 이기고 낮으면 지고 도박이에요.
그래서 이게 여러분 행동 공간에 0하고 1이 있는데 여기 이제 여러분 액션 스페이스에 정의가 되어있습니다.
여기다가 점 샘플 이렇게 하면은 랜덤하게 행동을 하나 골라줍니다.
컴퓨터가.
난수로.
컴퓨터 보고 지금 하나 고르라고 한 거에요.
아유 쫄리네.
하나 골라봐
이렇게 하니까 컴퓨터가 뭘 골라줬냐면 더 받으세요.
action = env.action_space.sample()
action
1
그래서 여기 이제 코드가 좀 복잡한데 여러분이 한 스텝을 받는 겁니다.
한 스텝을 받는데 컴퓨터가 골라준 액션을 한 스텝으로 받을 거에요.
그래서 env.step, action 하면 여러분 행동이 환경으로 넘어갑니다.
obs, reward, terminated, truncated, info = env.step(action)
print(f'{obs=} {reward=} {terminated=} {truncated=}')
obs=(25, 2, 0) reward=-1.0 terminated=True truncated=False
그럼 환경에서 이제 결과가 여러 가지가 나오는데 제일 처음에 OBS를 이제 여러분이 뭔가 액션을 취했으니까 하나 더 받기로 했으니까 카드가 한 장 더 오겠죠.
그래도 OBS가 바뀔 거고.
그 다음 이제 리워드는 보상인데 이기면 플러스 1, 지면 마이너스 1, 무성도면 0점.
만약에 게임이 끝나면 점수가 있을 텐데 만약에 게임이 계속되면 블랙젝은 게임 중간에는 보상이 없잖아요.
그때는 0이 되겠죠.
그 다음에 이제 터미네이티드하고 트렁케이티드가 있는데 이거는 둘 다 끝났다는 얘기에요.
게임이 끝나면 터미네이티드랑 트렁케이티드가 나옵니다.
근데 이 터미네이티드하고 트렁케이티드가 좀 다른데 터미네이티드는 이거는 진짜 끝남이고 진짜 끝이고.
트렁케이티드는 뭐냐면 시간 관계상 중단 에피소드가 너무 길어져 가지고 아직 끝나는 조건에는 만족을 못했는데 시간 관계상 여기까지 하겠습니다.
요즘에도 그러다 야구중계 옛날에 하다가 경기가 너무 길어지면 정규 방송 관계로 이만 중단하고 스포츠 채널에서 이어서 하겠다고 하거든요.
이거는 여러분 로봇 재원을 하는데 1시간 동안 계속 보복보복되고 있으면 끝날 때까지 기다릴 수 없잖아요.
그럼 일단 시간 관계상 여기서는 중단 이렇게 할게 써요.
블랙젝에는 이거는 뭐 해당 사항이 없겠죠.
블랙젝은 금방 끝나니까.
그 다음에 이 인포에는 보조 정보가 들어갑니다.
그래서 밑에 있는 프린트 어쩌고 하는 거는 그거를 한꺼번에 출력을 해줘.
그래서 복사해서 붙여놓을 때 줄이 밀리는데 한 줄에 하나씩 써주시면 됩니다.
그러면 여러분이 카드를 한장 더 받았는데 25가 되어버렸죠.
아까 21을 넘으면 무조건 패라고 했죠.
리워드는 마이너스 1이 되고요.
그 다음에 터미네이티드는 게임이 끝났으니까 True.
이제 끝났다는 얘기입니다.
그리고 시간 관계상 중단된 것은 False.
시간 관계상 중단된 것은 아니다.
그냥 게임이 끝나버렸다.
버전 차이
그 다음에 이제 그 인터넷이나 책으로 이제 우리 요 수업만으로 강화학습을 다 공부하실 수 없을테니까 사점에 가서 책을 보시 거나 인터넷에서 자료를 찾아보시면 그게 짐이 버전이 구 버전하고 신 버전하고 호환이 안되거든요
구 버전하고 신 버전하고 좀 차이가 있는데 구 버전에서는 여기 OBS만 나오는데 신 버전에서는 OBS랑 인포가 다 나온다.
그래서 혹시 책을 사보셨는데 OBS는 이렇게 되있는 코드를 최신 버전 돌리시면 에러 나요
이렇게 바꿔주시면 되고 그 다음에 구 버전하고 신 버전하고 이것도 좀 다른데 구 버전에서 그냥 끝나면 끝인데 신 버전에서는 왜 끝났는지를 구별하게 되있습니다
그래서 요런 차이가 있으니까 주의를 하시면 될 것 같구요
우리는 어차피 신 버전 쓰니까 상관 없겠죠
반복
우리가 블랙제 게임을 하는데 100번 해가지고 내가 몇 판이나 이긴 한번 보자
이런 얘기에요
그 다음 while은 뭐냐면 뒤에 어떤 조건이 나와서 그 조건이 계속되는 동안 while이 영어로 하면 머모하는 동안이라도 있잖아요
직역하면 머모하는 동안인데 언제까지 반복을 할 거냐 하면은 not terminated 영어로 해석하시면 되죠
안 끝나면 반복 이런 얘기에요
결국에는 끝날 때까지 하라는 얘기죠
어쨌든 그래서 while not terminated은 안 끝났으면 그동안 여기 있는 것을 실행을 하고 다 끝나면 다음으로 넘어가라
이런 얘기에요
그리고 여기 보시면 else 라고 있는데 else는 뭐냐면 이제 우리가 끝났으면은 그 다음에 마무리를 해야 될 거 아니에요
마무리입니다
마무리 마무리를 해주는데 뭘 하냐면 여기 위에 보시면 returns 라고 있어요
그 다음에 이렇게 각 과로를 해놨는데 이 각 과로는 뭐냐면 list 라고 해서 파이썬에서 어떤 값들을 순차적으로 저장할 수 있는 구조입니다
어떤 자료를 순차적으로 저장을 할 수 있어요
그래서 여기 보시면 append 이렇게인데 append가 뒤에 붙여라
이런거에요
뒤에 추가해라
이런거에요
이번판에 받은 보상을 blackjack은 게임 특성상 마지막에 받는 보상을 제외하면 나머지는 다 0이에요
중간에 받는 보상은 어차피 0이라서 신경쓸거 없고 마지막에 딱 한번 받은 보상만 그게 그대로 return이 됩니다
그 리워드와 return이 똑같아요
이 경우에는 그래서 그거를 저장을 해줘라
이렇게 하면 되구요 그래서 100번을 다 하고 난 다음에 이렇게 들여쓰기 하는 부분은 우리가 반복할 100번 반복할 부분입니다
이렇게 들여쓰기 하는 부분이 100번 반복하는 부분이고 이렇게 들여쓰기 하는 부분은 y를 걸리는 부분이에요
그 다음에 mp.win 하면은 그래서 우리가 이제 이거를 평균을 내서 평균적으로 얼마나 받냐 보자 blackjack을 윈 딱 덮고 마부잡이로 그냥 랜덤하게 하면은 결과가 어떻게 되냐
이렇게 되죠
import tqdm.autonotebook as tqdm # 진행 막대 표시 라이브러리
import numpy as np # 수학계산 라이브러리
returns = [] # 수익 저장
for i in tqdm.trange(100): # 100번 게임
obs, info = env.reset()
terminated = False
while not terminated: # 끝날 때까지 반복
action = env.action_space.sample()
obs, reward, terminated, truncated, info = env.step(action)
else: # 끝나면
returns.append(reward) # 마지막 보상을 수익으로 저장
np.mean(returns) # 평균 수익
0%| | 0/100 [00:00<?, ?it/s]
0.45
객체지향 프로그래밍
그리고 이제 객체제한 프로그래밍이라는 개념이 있는데요
보통 줄여서 OOP라고 많이 합니다
오브젝트 오리엔티드 프로그램 그래서 OOP가 뭐다라고 간단하게 정의하기는 좀 힘든데 원래 OOP는 시뮬레이션을 하려고 만들었어요
왜냐하면 시뮬레이션을 하려면 뭔가 여러가지가 이렇게 있어가지고 얘네들끼리 서로 상호작용을 하거든요
예를 들면 입자 시뮬레이션을 한다
입자들끼리 돌아다니다가 서로 충돌하고 이렇게 되면 이걸 따로 한꺼번에 계산을 하려면 좀 복잡하단 말이에요
그래서 어떻게 하냐면 입자들 단위로 각자 자기 할 일은 자기가 대상하게 그러다가 입자들끼리 부딪히면 부딪힌 애들끼리 서로 운동량을 주고받거나 이런 다음에 또 각자 제갈필을 가면 되잖아요
그러니까 이 어떤 단위들마다 나눠서 계산을 하려고 OOP라는 것을 처음에 만들었습니다
그래서 지금은 이런 시뮬레이션 이외의 분야에서도 굉장히 많이 사용이 되는데 우리가 짐 같은 경우도 기본적으로 OOP 방식으로 어떤 환경을 설계를 하게 되어있어요
왜냐하면 환경에 구속요소가 되게 많은데 그것들이 각자 그냥 자기 할 복수를 하면 되잖아요
그래서 그렇게 되어있고 그래서 이제 클래스라는 개념을 좀 아셔야 됩니다
클래스는 뭐냐면 우리가 어떤 설계도 또는 템플릿이라고 할 수 있는데 여기서 클래스는 하급 이런 뜻이 아니라 유형 레지는 종류 이런 뜻이에요
그래서 예를 들면 우리가 어떤 풀밭에 양하고 늑대가 뛰어다 뛰어 놀고 있다.
그럼 늑대가 양을 잡아먹고 양은 도망 다니고 뭐 이러겠죠
양들은 다 똑같은 클래스고 늑대도 다 똑같은 클래스인데 그러면은 양은 어떻게 정의가 되고 늑대는 또 어떻게 정의가 되고 이런 거를 정의를 해줘야겠죠
그래서 그런 거를 정의하는 프로그래밍 방식입니다
그래서 파이선에서는 기본적으로 보시면 뭔가 정의를 할 때 들여쓰기를 하거든요
들여쓰기를 하면 그 얘기는 뭐냐면 지금 클래스 애니멀 이렇게 하면 지금부터 애니멀이라는 클래스를 정의할 거야
그런 얘기인데 그럼 그 세부사항은 이렇게 항상 들여쓰기가 된 상태로 정의를 합니다
그래서 여기까지가 애니멀의 정의에 해당이 돼요
그러면은 애니멀은 두 가지 세부사항을 가집니다
class Animal:
def __init__(self, name, age): # 생성자: self는 생성된 객체를 가리킴
self.name = name # 객체의 name 속성 값을 설정
self.age = age # 객체의 age 속성 값을 설정
def make_sound(self): # 객체의 메서드(함수) 정의
raise NotImplementedError # 사용시 구현되지 않았다는 에러 발생
그래서 이게 def라고 나오는데 이게 def는 뭐냐면 애니멀에 포함되는 함수 이걸 보통 메서드라고 부르는데 용어는 이렇게 중요한 게 아니고 어쨌든 애니멀에 해당되는 어떤 명령이라고 할 수 있어요
우리가 어떤 애니멀이라는 어떤 종류를 정의를 할 때 야
너는 이거는 이렇게 하고 저건 저렇게 해 라고 우리가 정의를 해주는 거예요
def는 define 정의하다 해야 되겠습니다
그래서 여기 보시면 긴 밑줄처럼 생겼는데 실제로 밑줄을 두 개 쓴 겁니다 밑줄 두 개 쓰고 이니트 밑줄 두 개 쓰고 이거는 약간 특수함수에요 특수한 함수인데 언제 하는 거냐면 처음에 initialize 할 때 initialize는 초기화 그러니까 우리가 어떤 동물을 처음 만들 우리가 컴퓨터 안에 동물에 해당되는 객체를 처음 만들 때 너는 처음에 이걸 해라
이렇게 시키는 거예요
뭘 시키냐면 self.name 이건 뭐냐면 너의 이름을 여기 넘겨준 여기 있는 name은 사용자가 넘겨준 이름입니다
너의 이름은 사용자가 넘겨준 그대로 설정하고 너의 나이도 사용자가 넘겨준 그대로 설정을 해라
이런 얘기예요
그래서 이름이랑 나이를 설정하라는 얘기고 그 다음에 DEF make sound 이렇게 되어있는데 이거는 내가 너한테 make sound 라고 하면 여기 정의된 행동을 해 이런 얘기예요
무슨 행동을 정의를 할 거냐면 여기 raise는 일으키다 해야 되는데 파이선에서 raise는 뭐냐면 error를 일으키라는 얘기입니다
error를 일으켜라 어떤 error를 일으키냐면 not implemented error를 일으켜라
이건 뭐냐면 아마 구현이 안 됐다 이런 거에요
그러니까 내가 너 보고 make sound 이러면은 저는 그런 거 구현이 안 돼 있어서 못 하겠는데 라고 error를 내가 정의를 해줘 그 다음에 이제 우리가 이걸 한번 써보면 일단 정의를 먼저 해보죠
a = Animal('똘똘이', 3)
그래서 우리가 이름은 똘똘이 나이는 3살 이렇게 하면 아까 우리가 이닛에서 뭐라고 정해였냐면 우리가 준 이름을 그대로 자기 이름으로 하고 우리가 준 나이를 그대로 자기 나이로 해라 라고 지정했어요
a.age
3
그래서 이 a라는 변수에 우리가 새로 정의한 animal이 들어가는데 그 animal의 age는 그대로 우리가 정해준 그대로 3일입니다
a.make_sound()
그 다음에 a한테 소리 좀 내봐 라고 하면은 우리가 error를 내라고 했기 때문에 error가 납니다
지금 이건 왜 배우냐면 우리가 환경을 정의하거나 행위자를 정의할 때 우리가 이런 식으로 정의를 할 거에요
환경한테는 너는 이거 할 때 이렇게 하고 저거 할 때 저거 해라 행위자 할 때는 이거 할 때는 이거 하고 저거 할 때는 저거 해라
class Dog(Animal): # Animal을 상속한 Dog를 정의
def __init__(self, name, age, breed):
super().__init__(name, age) # super() 함수로 객체의 부모 클래스에 접근
self.breed = breed # 자식 클래스의 속성을 설정
def make_sound(self): # make sound 메서드를 새로 정의
return f"{self.name} 멍멍"
d = Dog('바우', 5, '동네개')
d.make_sound()
'바우 멍멍'
밴딧 보행
환경의 공통적인 부분은 상속을 받고 우리 밴딕워크라는 환경의 특수한 부분만 따로 정의를 해주면 되는거에요
그게 이만큼 이만큼만 정의해주면 나머지는 다 공통적인 거니까 그거를 쓰면 된다
이런 얘기고 우리가 이 환경에 특수한게 뭐냐 이 환경의 action space랑 행동 공간이라 이 환경의 관찰 공간 두 가지를 정의를 해주셔야 합니다
class BanditWalk(gym.Env):
def __init__(self):
self.action_space = gym.spaces.Discrete(2) # 행동 공간
self.observation_space = gym.spaces.Discrete(3) # 관찰 공간
self.state = 1
def reset(self):
self.state = 1 # 시작하면 상태를 1로 설정
return self.state, {}
def step(self, action):
if action == 0: # 행동이 0이면
reward = 0 # 보상은 0
self.state = 0 # 상태는 0
else: # 행동이 1이면
reward = 1 # 보상은 +1
self.state = 2 # 상태는 2
return self.state, reward, True, False, {}
# 상태, 보상, 종료 여부, 잘림 여부, 추가 정보 반환
그래서 여기 discrete 2 이렇게 되어 있는데 이건 별 얘기는 아니고 discrete 2라고 하면 0하고 1을 두 가지를 포함하는 공간을 하나 정의를 해줍니다
그다음에 discrete 3 하면 0 1 2를 포함하는 공간을 또 하나 정의를 해줍니다
우리가 행동 공간은 이거 두 개에요
그래서 0은 왼쪽 오른쪽은 1 이렇게 되는거고 관찰 공간은 1이 출발점이고 0으로 가도 종료 2로 가도 종료 이렇게 되는거죠
env = BanditWalk() # 환경만 새로 정의
# 아래 코드는 블랙잭 것을 그대로 복사해서 사용
returns = [] # 수익 저장
for i in tqdm.trange(100): # 100번 게임
obs, info = env.reset()
terminated = False
while not terminated: # 끝날 때까지 반복
action = env.action_space.sample()
obs, reward, terminated, truncated, info = env.step(action)
else: # 끝나면
returns.append(reward) # 마지막 보상을 수익으로 저장
np.mean(returns) # 평균 수익
밴딧 미끄러운 보행
미끄럼이 왜 들어가냐면 앞에서는 내가 왼쪽으로 가고 싶으면 왼쪽으로 갈 수 있 고 오른쪽으로 가고 싶으면 오른쪽으로 갈 수 있잖아요.
문제가 너무 쉬웠거든요.
그래서 문제를 조금 더 어렵게 할 겁니다.
어떻게 어렵게 할 거냐면 내 뜻대로 안 돼요.
내가 가고 싶다고 왼쪽으로 갈 수 있는 게 아닙니다.
이제는 어떻게 바뀌냐면 미끄러워요.
미끄러웠다는 얘기는 왜 나오냐면 확률론적 전이함수가 있기 때문에 그렇습니다.
그래서 내가 왼쪽으로 가면 0번 행동을 하면 왼쪽으로 가는데 80%의 확률로만 왼쪽으로 가는데 성공하고 20%의 확률로는 미끄러져서 오른쪽으로 갑니다.
1번 행동을 하면 80%의 확률로 오른쪽으로 가는데 20%의 확률로 왼쪽으로 갑니다.
환장하겠죠?
내가 왼쪽으로 가려고 한다고 왼쪽으로 가지는 게 아니고 오른쪽으로 가려고 한다고 해서 오른쪽으로 가지는 게 아니에요.
그런 환경을 어떻게 구현을 하느냐
그러면 달라지는 건 뭐냐면 스탭만 달라져요.
class BanditSlipperyWalk(BanditWalk):
def step(self, action):
x = np.random.random() # 0~1 사이의 난수 발생
if action == 0: # 행동이 0이면
self.state = 0 if x < 0.8 else 2
# 80% 확률로 0, 20% 확률로 2
else: # 행동이 1이면
self.state = 2 if x < 0.8 else 0
# 80% 확률로 2, 20% 확률로 0
reward = 0 if self.state == 0 else 1
# 상태가 0이면 보상은 0, 아니면 1
return self.state, reward, True, False, {}
# 상태, 보상, 종료 여부, 잘림 여부, 추가 정보 반환
100번 무작위 정책 반복
env = BanditSlipperyWalk() # 환경만 새로 정의
# 아래 코드는 블랙잭 것을 그대로 복사해서 사용
returns = [] # 수익 저장
for i in tqdm.trange(100): # 100번 게임
obs, info = env.reset()
terminated = False
while not terminated: # 끝날 때까지 반복
action = env.action_space.sample()
obs, reward, terminated, truncated, info = env.step(action)
else: # 끝나면
returns.append(reward) # 마지막 보상을 수익으로 저장
np.mean(returns) # 평균 수익
유사 난수
x = 42
x = (2**31 - 1) * x % 7**5
x
2835
7**5
16807
프로즌 레이크
!pip install gymnasium[toy-text]
from PIL import Image
env = gym.make('FrozenLake-v1', render_mode="rgb_array") # new_step_api=True은 삭제
env.reset()
frame = env.render() # [0]은 삭제
Image.fromarray(frame)
<PIL.Image.Image image mode=RGB size=256x256>
env.reset()
frames = []
frames.append(env.render()) # += 을 append로
terminated = False
while not terminated:
action = env.action_space.sample()
obs, reward, terminated, truncated, info = env.step(action)
frames.append(env.render()) # += 을 append로
import imageio
filename = 'animation.gif'
imageio.mimsave(filename, frames, fps=2)
from IPython.display import Image
Image(filename)
<IPython.core.display.Image object>