Skip to main content

나는 로봇에게 The Witness를 플레이하도록 학습시켰다

“The Witness”에서 퍼즐 패턴을 인식하도록 신경망을 학습시키며 배운 것 이 글은 AI 번역본입니다. 오역이 의심되면 댓글로 알려 주세요
Created on September 15|Last edited on September 15
스포일러 경고: 이 글에서는 모델을 설명하는 과정에서 게임의 주요 줄거리를 다룹니다.
게임에서 The Witness에서, 플레이어는 원에서 시작해 끝점까지 연속된 선을 그려 패턴을 완성하며 퍼즐을 풉니다. 처음에는 이런 패턴이 패널 위에만 보이지만, 결국 섬 전체가 이러한 패턴으로 가득 차 있다는 사실을 깨닫게 되고, 진짜 목표는 주변 환경에서 이 패턴들을 알아보는 것임을 알게 됩니다. 그리고 게임을 마친 뒤에는, 저를 포함한 많은 플레이어가 일상 곳곳에서 이런 패턴이 보이기 시작했습니다. 현실 세계에서 또한
패널 속에서, 환경 속에서, 그리고 현실 세계에서도 보이는 The Witness의 퍼즐 패턴!
저는 The Witness 스크린샷에서 해당 퍼즐 패턴을 식별하고 라벨링하는 딥러닝 모델을 학습시켰습니다. 저는 경험 많은 웹 엔지니어이지만 머신러닝은 처음이며, 특히 예술적이고 창의적인 목적을 위한 머신러닝에 관심이 있습니다. 이 프로젝트는 딥러닝 기법을 조금씩 배우면서도 흥미로운 결과를 만들어 볼 수 있는 충분히 간단한 입문 과제로 보였습니다.
모델 작동 미리 보기.
꽤 고무적인 결과를 얻을 수 있었습니다! 이 글에서는 거기까지 가기 위해 제가 거친 과정을 차근차근 소개하겠습니다. 또한 저는 이미 a를 공개했습니다. 재현 가능한 저장소 이 프로젝트에 함께해 주시면 좋겠고, 다른 The Witness 팬들도 프로젝트를 개선하기 위해 협업해 주신다면 무척 기쁠 것입니다.

데이터 수집과 과제 정교화

먼저 게임을 플레이하며 환경 퍼즐마다 여러 장의 스크린샷을 찍었고, 총합은 약 300장이었습니다. 도움을 준 IGN에 감사드립니다. 이 종합 가이드 모든 퍼즐의 위치와, SaveGameWorld에 대한 저장 파일 그래서 모든 위치에 다시 접근할 필요가 없었죠! 다양한 각도에서 스크린샷을 확보했고, 퍼즐이 온전히 보이는 긍정 예시도 충분히 모았으며, 일부가 가려지거나 끊긴 부정 예시도 포함했습니다.

이 스크린샷 각각에 대한 학습 레이블은 Photoshop에서 수작업으로 만들었습니다. 작업을 빠르게 하기 위해 반복 절차를 자동화하는 액션을 만들었습니다. 퍼즐 영역이 있는 경우에는 “Select & Mask” 도구로 해당 영역을 수동 선택한 뒤, 선택 마스크를 흑백 이미지로 변환하고 “labels” 폴더에 PNG로 저장하는 액션을 실행했습니다.
소스 스크린샷 위에 겹쳐 표시한 학습 마스크
제 경험에서 머신러닝의 가장 흥미로운 측면 중 하나는 코드 개발 과정이 문제를 여러 차례 재정의하고 재구성하게 만든다는 점이었습니다. 처음에는 “The Witness의 규칙에 맞는 환경 퍼즐 패턴을 식별하고 라벨링한다”라고 문제를 규정했지만, 이는 충분히 정확하지 않았습니다. 학습용 데이터셋을 구축하는 과정에서 이미지의 어떤 부분을 퍼즐로 라벨링해야 하는지에 대한 정의를 더 정교하게 다듬도록 요구하는 다양한 상황이 나타났습니다.
모든 퍼즐 패턴이 시작되는 원형에 대해서는:
  • 전경의 물체에 가려진 원도 허용되나요?
  • 뷰포트 안에 완전히 보이지 않는 원도 허용되나요?
  • 원 둘레의 불규칙함이나 변형이 어느 정도까지 허용되나요?
  • 원의 관찰 각도는 어느 정도까지 허용되나요?
그리고 패턴의 나머지를 이루는 선에 대해서는:"
  • 끝나지 않은 채 뷰포트 밖으로 이어지는 선도 허용되나요?
  • 선의 두께가 넓어지거나 좁아지는 정도는 어느 수준까지 허용되나요?
  • 선이나 원 내부에서의 색상 변화 정도는 어느 수준까지 허용되나요?
  • 선 위에 투명한 재질(레이저나 그림자)이 겹쳐 있을 경우, 그것을 선의 단절로 간주해야 하나요? 선의 일부로 라벨링해야 하나요?

모델 아키텍처

핵심적으로 이 작업은 흔히 “시맨틱 세그멘테이션”이라고 부릅니다. 모델은 이미지에서 특정 종류의 객체에 속하는 픽셀이 어느 것인지 라벨링해야 합니다. 저는 이런 과제에 일반적으로 쓰이는 모델 아키텍처를 선택했는데, 바로 U-Net, 그리고 이는 원래 의료 영상 분할을 위해 개발된.
U-Net은 수축 경로(왼쪽의 인코더)와 확장 경로(오른쪽의 디코더)로 구성됩니다. 인코더는 여러 개의 계층적 합성곱 층을 통해 특징 감지 능력을 학습하고, 디코더는 U의 가장 아래에서 올라온 특징 정보와 수축 경로에서 전달된 위치 정보를 결합하여 전체 입력 이미지에 대한 시맨틱 맵을 생성합니다.

나는 사용했다 U-Net 예제 코드 시작하기 위해


코드 실행 방법

코딩 경험이 없어도 직접 코드를 실행해 볼 수 있습니다!
git clone git@github.com:wandb/witness.git
pip install -r requirements.txt

# Init on W&B to save your run results
wandb init

# Split data from /data/all into a training and validation sets
./process.py

# Train your model, and save the best one
./train.py

# Output the prediction for all examples in the validation set
./predict.py
훈련을 실행하기 위해 Amazon EC2의 p3.2xlarge 인스턴스를 사용했습니다. 이러한 인스턴스에는 모두 GPU가 탑재되어 훈련 속도가 훨씬 빠릅니다. 저는 Ubuntu Deep Learning AMI, 일반적으로 필요한 파이썬 라이브러리와 바이너리를 미리 설치해 둡니다.


초기 결과

첫 실행만으로도 유익하고 희망적인 결과가 나왔습니다. 저는 이를 정리해 두었습니다 내 결과를 탐구한 W&B 리포트.
성능이 가장 좋은 모델을 저장한 다음, 저는 predict.py 훈련 데이터가 잘못 라벨링되었거나 애매한 사례, 혹은 게임 자체가 특히 까다로운 예시가 된 경우를 찾아내는 스크립트입니다. 각 예시에서 좌상단은 스크린샷, 좌하단은 예측 결과, 우하단은 제가 직접 만든 라벨, 우상단은 라벨과 예측을 합성한 이미지입니다. 합성 이미지에서 흰색은 참양성, 빨간색은 거짓양성, 파란색은 거짓음성을 나타냅니다.

검증 세트의 이 예시에서 모델은 선의 일부는 찾아냈지만, 원이나 선의 끝은 식별하지 못했습니다. 원은 배경의 노란색이 비쳐 보이는 탓에 놓쳤을 수 있고, 선의 끝은 두께가 변하는 부분 때문에 놓쳤을 가능성이 있습니다.

이 경우 모델은 제가 초기 학습 데이터 구성에서 놓쳤던 퍼즐 두 개를 찾아냈습니다. 왼쪽에 있는 것은 원에서 이어진 선이 점점 넓어지다가 넓은 영역(바다)으로 확장되는 독특한 사례입니다. 저는 선의 너비가 허용 범위를 초과하는 지점까지의 영역을 규칙에 포함해야 함이 분명해 보일 때까지 이를 유효한 사례로 간주하지 않았습니다. 오른쪽에는 원에서 두 개의 잠재적인 선이 뻗어 나오는 퍼즐이 있으며, 이 역시 학습 데이터에서 라벨링하지 않았던 부분입니다.

검증 세트에서 발견한 한 사례입니다. 제가 훈련 세트에서는 실수로 퍼즐로 라벨링했지만, 실제로는 원과 선의 색상 차이가 너무 큽니다. 모델은 해당 영역을 퍼즐로 라벨링하지 않는 것이 맞습니다.

이 경우 원 영역이 부분적으로 가려져 있음에도 불구하고, 모델이 두 영역을 퍼즐로 잘못 라벨링했습니다. 퍼즐로 인정되려면 원은 항상 온전하고 가려지지 않은 상태여야 합니다.

이 사례는 원이 부분적으로 가려져 있는데도 모델이 거의 맞는 영역을 찾아낸 거짓 양성에 해당합니다.

이 예시는 훈련 세트에 포함되어 있음에도 모델이 퍼즐을 올바르게 라벨링하는 법을 끝내 학습하지 못한, 매우 까다로운 사례입니다.

이 경우 모델은 왼쪽과 우상단의 완전한 퍼즐 세 개를 정확히 식별했지만, 원이 뷰포트 바깥으로 부분적으로 벗어난 우하단 예시는 어려워했습니다.

이 경우 모델은 햇빛이 비치는 영역의 퍼즐 부분은 정확히 인식했지만, 그림자에 있는 부분은 놓쳤습니다.

훈련 데이터 다듬기와 모델 재학습

위의 혼란스러운 사례들을 바탕으로 마스크 오류를 제거하고 학습 데이터 생성에 적용할 규칙을 명확히 하기 위해 학습 데이터를 다듬었습니다. 다음은 W&B Run 1에서 Run 2로의 개선을 보여 주는 보고서: 정확도가 명확히 상승했습니다!
학습이 전혀 진행되지 않은 채로 실행이 멈춰 버리는 이상한 문제가 비결정적으로 발생했습니다. 동료들의 도움으로, 무작위 시드에 따라 학습이 빈 예측이라는 국소 최소값 바깥을 탐색하지 못하는 경우가 있음을 확인했습니다. 양성 레이블 대부분이 틀린 것으로 간주되어 손실이 증가하기 때문입니다. 이를 해결하기 위해 가중 교차 엔트로피 손실 함수를 양성 예측에 더 가중치를 두도록 조정해 음성 예측보다 선호하게 만들자 문제가 해결되었습니다.
문제 규모에 비해 5단 U‑Net 예제가 너무 클 수 있다는 직관에 따라, U‑Net의 “티어” 수를 바꿔 가며 실험도 해 보았습니다. 다음에서 확인할 수 있습니다 보고서 여기에서 이러한 하이퍼파라미터를 비교했습니다. 한 가지 깨달음은 더 컴팩트한 모델들이 학습 세트에서는 더 느리게 학습했지만 검증 세트에서는 더 좋은 성능을 보였다는 점입니다. 이는 이들이 암기에는 덜 능하지만 일반화는 더 잘한다는 뜻입니다.

모델 되돌아보기

저에게 머신러닝에서 가장 흥미로운 부분 중 하나는 학습된 모델의 내부 구조를 들여다보며 의미 있는 발현 형태와 행동을 찾아내는 일입니다. 저는 스크립트를 하나 작성했고, visualize.py학습된 신경망의 중간 계층을 시각화하고, 간단한 3단 U‑Net 버전을 단계별로 설명하는 내용입니다.
대부분의 심층 합성곱 신경망에서 초기 계층은 미세한 패턴을 인코딩하는 데 주로 학습되고, 원하는 출력에 가까운 후반 계층일수록 더 의미론적인 정보를 인코딩하는 경향이 있습니다. 이 네트워크에서도 같은 양상을 확인할 수 있습니다.
여기에는 2번째 층의 각 셀 활성화를 시각화한 자료가 있습니다. 이 흑백 이미지는 단일 예시 이미지에 대해 각 셀의 원시 활성화를 보여 줍니다. 흰색은 이미지의 해당 부분이 그 셀을 활성화했음을 의미합니다.

소스 예시의 색조를 사용해 활성화된 영역을 색칠하면 해석하기가 더 쉬워집니다. 일부 셀은 대략적인 에지 검출기로 작동하고, 다른 셀은 하늘 같은 평탄한 영역에서 활성화되며, 또 다른 셀은 미세한 패턴에서 활성화되는 것을 볼 수 있습니다.

신경망의 깊은 부분(U의 하단에 있는 12번째 층)으로 들어갈수록 셀들이 매우 작은 지역적 정보를 포착하기 때문에 해석하기가 더 어려워집니다.

그리고 끝으로 갈수록, 이 이미지에서 의미 있는 부분을 많이 찾아냈다는 것을 볼 수 있습니다. 많은 셀이 퍼즐 패턴을 식별했습니다. 다른 셀들은 하늘, 울타리, 혹은 꽃무늬 영역을 가리켜 줍니다.

더 흥미로운 점은, 데이터셋의 모든 예시에 걸쳐 네트워크의 단일 셀 출력만 시각화해 보는 것입니다. 여기 U의 하단에 있는 12번째 층의 한 셀은 하늘 영역을 식별하도록 학습되었지만, 몇몇 경우에는 퍼즐도 함께 식별합니다.

다음은 19번째 층, 즉 끝에서 두 번째 층의 한 셀로, 대부분의 예시 이미지에서 퍼즐 패턴을 분명히 식별하도록 학습된 것을 볼 수 있습니다.

그리고 같은 층의 또 다른 셀은 대부분의 예시에서 퍼즐 주변의 에지 영역을 식별하는 것으로 보입니다.



다음 단계

이 모델의 성능을 높일 수 있는 방법은 매우 많으며, 크게 두 가지 범주로 나눌 수 있습니다. 학습 데이터를 개선하는 것과 모델 아키텍처를 개선하는 것입니다.
학습 데이터를 늘리고 개선하기 위해 선택할 수 있는 방법이 여러 가지 있습니다.
  • 더 많은 데이터게임을 다시 플레이하면서 스크린샷을 더 많이 찍고, 기존 프로세스를 그대로 사용해 수동으로 라벨링할 수 있습니다. 시간이 많이 들지만 기술적으로는 간단한 방법입니다.
  • 데이터 증강을 위한 시야각게임 렌더러의 카메라 시야각은 설정 페이지에서 구성할 수 있습니다. 서로 다른 시야각으로 학습 데이터를 많이 수집하면 모델의 견고성을 높이는 데 도움이 될 수 있습니다.
  • 데이터 증강 개선현재 모델은 데이터 증강에 기본 규칙 몇 가지를 사용합니다. 하지만 이를 개선할 여지가 있습니다. 예를 들어, 자르기 함수가 퍼즐의 원 일부를 잘라 내면, 이미 잘못된 퍼즐 라벨이 그대로 유지될 수 있습니다.
  • 합성 데이터이상적인 환경이라면, 스크린샷과 함께 퍼즐 영역의 내부 표현을 출력해 주는 커스텀 게임 빌드에 접근할 수 있을 것입니다. 그렇게만 된다면, 자동화를 통해 수만 장의 렌더링을 완벽한 라벨과 함께 생성할 수 있습니다.
  • 더 나은 학습/검증 분할. 학습 세트와 검증 세트는 스크린샷 모음에서 무작위로 분할되므로, 검증 세트의 각 항목이 모델에 대해 새로운 퍼즐이라는 보장이 없습니다. 모델이 실제로 일반화하고 있는지를 더 잘 검증하려면, 일부 퍼즐이 오직 검증 세트에만 등장하도록 보장하는 것이 좋습니다.
알고리즘과 모델을 개선할 수 있는 방법도 여러 가지가 있습니다:
  • 전이 학습. 수축 경로의 계층에는 ResNet 같은 사전 학습된 모델을 사용할 수 있으며, 이렇게 하면 훨씬 더 큰 학습 데이터셋에서 학습된 모든 특징을 모델이 활용할 수 있습니다.
  • 대체 아키텍처. 한 가지 대안으로는, 하나의 모델이 스크린샷을 입력으로 받아 가능한 퍼즐 후보들을 흑백 마스크 세트로 생성하고, 이어서 두 번째 모델이 그 후보들을 걸러 최종적으로 수용 가능한 퍼즐 집합을 얻는 방식을 상상할 수 있습니다. 이 접근법은 학습 데이터를 확장하는 일을 훨씬 쉽게 만들어 줄 수 있는데, 합성 RGB 게임 스크린샷을 생성하는 것보다 합성 1비트 마스크를 생성하는 편이 훨씬 간단하기 때문입니다.


현실 세계 이미지로 확장하기

이 프로젝트의 원래 의도는 현실 세계에서 The Witness의 패턴을 찾아보는 것이었고, 예를 들면 WitnessIRL 레딧 스레드. 결국 프로젝트 범위를 축소했습니다. 스크린샷에서 패턴을 식별하는 일만으로도 충분히 어려웠고, 해당 스레드의 약 100장 이미지는 의미 있는 성과를 내기엔 학습 데이터로 부족했기 때문입니다. 다만 게임 스크린샷으로 학습한 모델을 바탕으로 전이 학습을 적용하면, 현실 세계 사진에서 패턴을 감지하는 모델을 빠르게 출발시킬 수 있다고 믿습니다. 궁극적인 목표는 그 모델을 대규모 이미지 데이터셋에 적용하는 것입니다. 예를 들어, Flickr Creative Commons 100M 사진 데이터셋. 상상해 보세요, 우리가 얼마나 많은 퍼즐을 찾아낼 수 있을지!


기여하기!

이 프로젝트가 흥미롭게 느껴진다면, 함께 협업해 모델 성능을 높이고 학습 데이터를 개선하며, 나아가 현실 세계 이미지로까지 확장해 봅시다! 예시 레포는 여기 있습니다 프로세스를 재현하는 방법을 포함한 안내 사항과 함께
실행에 성공하고 성능을 개선하셨다면, 부탁드립니다 우리 벤치마크에 제출해 주세요 최고 점수를 기록하고 프로젝트를 진척시키기 위해 레포에 풀 리퀘스트로 제출해 주세요. 도움이 필요하시면 트위터나 이메일로 알려 주세요.



이 기사는 AI로 번역되었습니다. 오역이 의심되면 댓글로 알려 주세요. 원문 보고서는 아래 링크에서 확인하실 수 있습니다: 원문 보고서 보기