다중 목적 강화학습 알고리즘의 일반화 및 정책 적응 복제 과정 기록

논문 링크: https://arxiv.org/pdf/1908.08342

논문 코드: https://github.com/RunzheYang/MORL

블로그: https://blog.csdn.net/weixin_56760882/article/details/145572826

이 문서는 심해 보물 환경(DST)을 예시로 들어 복제 결과를 설명한 것이지만, 본문에서는 FTN(과일 나무 탐사) 환경을 기반으로 복제 과정을 설명합니다.

복제 과정에서 원 논문 코드를 git으로 가져온 후, 노트북(RTX 4060)에서 환경을 구성하고 실행했습니다.

이 프로젝트는 다중 목적 강화학습 알고리즘의 일반화된 버전으로, 핵심은 envelope MOQ-learning이며, 4가지 환경에 적용됩니다(2개의 합성 환경 + 2개의 실제 환경).

합성 환경 두 개:

  • Deep Sea Treasure (DST): 심해 보물 찾기
  • Fruit Tree Navigation (FTN): 과일 나무 탐사

복잡한 실제 환경 두 개:

  • Task-Oriented Dialog Policy Learning (Dialog): 작업 중심 대화 정책 학습
  • SuperMario Game (SuperMario): 슈퍼마리오 게임

디렉토리 synthetic 내 파일 목록:

파일 경로 핵심 역할 필요한 이해 내용
synthetic/train.py 합성 환경 학습 진입점 명령줄 파라미터 분석(예: --env-name ft로 FTN 환경 지정, --method crl-envelope로 핵심 알고리즘 지정), 학습 루프 로직
synthetic/crl/envelope/meta.py 핵심 알고리즘 구현 envelope MOQ-learning의 핵심 로직(다중 목적 보상 가중, 정책 업데이트, 경험 재현)
synthetic/crl/envelope/models 네트워크 구조 선형/비선형 네트워크 구성(다양한 합성 환경의 상태/액션 공간 대응)
synthetic/envs 합성 환경 정의 DST/FTN 환경의 상태, 액션, 다중 목적 보상 함수 정의(환경 규칙 이해는 복제의 전제)

1. 환경 설정 - 기본 의존성 설치

원 코드가 의존하는 torch 0.4.0(2018년 버전)은 RTX40 시리즈 GPU의 CUDA 아키텍처 지원이 부족합니다(RTX4060은 Ada Lovelace 아키텍처, sm_89, 하지만 torch 0.4.0은 최대 sm_75/Turing 아키텍처까지 지원).

RTX4060 호환을 위해 pytorch 업그레이드:

# 1. 새로운 환경 생성(파이썬 3.6.15 지정)
conda create -n morl-synthetic python=3.6.15 -y

# 2. 환경 활성화
conda activate morl-synthetic

# 3. 파이썬 3.6 호환 핵심 의존성 설치
pip install numpy==1.19.5 scipy==1.5.4 -i https://pypi.tuna.tsinghua.edu.cn/simple

# 4. torch 1.10.2+cu113 설치(파이썬 3.6 유일한 고버전, RTX4060 호환)
pip install torch==1.10.2+cu113 torchvision==0.11.3+cu113 torchaudio==0.10.2+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable.html -i https://pypi.tuna.tsinghua.edu.cn/simple

PyTorch + CUDA가 RTX4060과 호환되는지 확인:

python -c "import torch; 
print('PyTorch 버전:', torch.__version__);
print('CUDA 버전:', torch.version.cuda);
print('CUDA 사용 가능 여부:', torch.cuda.is_available());
print('GPU 이름:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else '인식되지 않음')"

기타 보조 의존성 설치:

# 기타 보조 의존성
pip install termcolor==1.1.0 torchfile==0.1.0 Pillow==8.4.0 six==1.16.0 -i https://pypi.tuna.tsinghua.edu.cn/simple

visdom 설치:

visdom은 외부 네트워크에서 정적 자원(js/css)을 다운로드하려고 시도하여 네트워크 초과 또는 접근 실패가 발생합니다. 최종적으로 오프라인 다운로드 및 컴파일을 선택했습니다.

1. visdom 오프라인 리소스 패키지 다운로드:

cd D:\ProgramData\논문 복제\FirRL
# visdom 저장소 클론
git clone https://github.com/fossasia/visdom.git【내가 직접 zip을 다운로드했습니다】
# 압축 해제된 visdom-master 디렉토리로 이동
cd D:\ProgramData\논문 복제\FirRL\visdom-master
# yarn 미러 소스 변경(국내 다운로드 속도 개선)
yarn config set registry https://registry.npmmirror.com
# electron 미러 소스 설정
yarn config set electron_mirror https://npmmirror.com/mirrors/electron/
# Visdom 프론트엔드 컴파일 의존성 설치(3-8분 소요, 오류 없으면 성공)
yarn install --ignore-optional
# static 폴더 컴파일(1-2분, 성공 시 "Compiled successfully" 출력)
yarn run build
# visdom 설치 디렉토리 찾기(출력 경로 복사)
python -c "import visdom; print(visdom.__path__[0])"
출력: D:\Anaconda\envs\morl-synthetic\lib\site-packages\visdom
# 컴파일된 파일 복사
xcopy /E /I /Y D:\ProgramData\논문 복제\FirRL\visdom-master\py\visdom\static D:\Anaconda\envs\morl-synthetic\lib\site-packages\visdom\static

참고: 【/E: 하위 디렉토리 및 파일 전체 복사;】 【/I: 대상이 존재하지 않을 경우 디렉토리 생성.】 주소를 자신의 주소로 변경하세요.

이 단계는 static을 생성합니다. 원래는 visdom-master에 static이 없었습니다.

2. static.zip을 visdom 설치 디렉토리의 static 폴더로 압축 해제:

경로: D:\Anaconda\envs\morl-synthetic\Lib\site-packages\visdom\static
(만약 static 폴더가 없으면 먼저 생성하세요)

3. visdom 시작 코드의 예외 처리 수정:

D:\Anaconda\envs\morl-synthetic\Lib\site-packages\visdom\server.py의 671-673줄 수정:
# 오류 코드
# logging.error('Error {} while downloading {}'.format(exc.code, key))
# 대체
if hasattr(exc, 'code'):
    logging.error('Error {} while downloading {}'.format(exc.code, key))
else:
    logging.error('Error while downloading {}: {}'.format(key, exc))

디렉토리 로그 문제 해결:
D:\ProgramData\논문 복제\FirRL\synthetic\utils\monitor.py에서 init_log 함수를 열고 1줄 디렉토리 생성 코드 추가:
def init_log(self, save_path, name):
    # 추가된 줄(파일 not found 예외 해결, 논문 원 로직 변경하지 않음)
    import os; os.makedirs(save_path, exist_ok=True)
    # 논문 원 코드 유지
    self.log_file = open("{}{}.log".format(save_path, name), 'w')

4. 자원 다운로드 건너뛰기로 visdom 시작:

D:\\Anaconda\\envs\\morl-synthetic\\lib\\site-packages\\visdom\\server.py에서 download_scripts() 함수를 교체:
def download_scripts():
    """
    함수 재작성: 모든 외부 리소스 다운로드 건너뛰기, 로컬 static 폴더 사용
    """
    import os
    # 로컬 static 폴더 경로 정의(복사한 경로와 일치해야 함)
    static_dir = os.path.join(os.path.dirname(__file__), 'static')
    # 로컬 static 파일 존재 여부 확인(복사한 파일이 유효한지 확인)
    if os.path.exists(os.path.join(static_dir, 'js', 'main.js')):
        print("로컬 static 폴더 감지, 외부 리소스 다운로드 건너뜀!")
        return
    # 로컬에 파일이 없는 경우 경고 메시지 출력(오류 발생하지 않음)
    print("로컬 static 폴더 누락, 복사 경로 확인 필요!")
    return

morl-synthetic 환경 활성화 상태에서 visdom 시작(새로운 PowerShell 창에서 실행)

python -m visdom.server
# 성공 시: It's Alive! 및 http://localhost:8097 접근 가능

성공 출력:

Checking for scripts.
It's Alive!
INFO:root:Application Started
You can navigate to http://localhost:8097

2. 모델 학습

FTN 도메인(과일 나무 탐사): 나무 형태의 탐사 게임입니다. 에이전트(스마트 엔티티)는 나무 뿌리에서 출발하여 각 단계에서 분기를 선택하고, 6가지 과일을 수집하는 것이 목표(다중 목적)이며, 잎으로 가면 라운드 종료. 로그에 있는 단계 수, 누적 단계 수, 액션, 보상 목록은 에이전트가 이 나무 장면에서 이동한 기록이며, True는 잎에 도달했음을 나타냅니다(이 라운드 종료).

morl-synthetic 환경 활성화 상태 유지

먼저 synthetic 디렉토리로 이동:

cd D:\ProgramData\논문 복제\FirRL\synthetic

코드 실행:

python train.py --env-name dst --method crl-envelope --model linear --gamma 0.99 `
>> --mem-size 4000 --batch-size 256 --lr 1e-3 --epsilon 0.5 --epsilon-decay `
>> --weight-num 32 --episode-num 2000 --optimizer Adam --save crl/envelope/saved/ `
>> --log crl/envelope/logs/ --update-freq 100 --beta 0.96 --name s3_r9 `
>> 2>&1 | Tee-Object -FilePath "crl/envelope/logs/training_s3_r9_$timestamp.log"

학습 과정 및 결과:

3. 평가

평가 코드:

$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"; python test/eval_dst.py --env-name dst --method crl-envelope --model linear --gamma 0.99 --save crl/envelope/saved/ --pltpareto --name s3_r9 2>&1 | Tee-Object -FilePath "crl/envelope/logs/eval_s3_r9_$timestamp.log"

결과:

  • policy-0.936: 정책 F1 점수(모델이 최적해에 얼마나 가까운지 측정), 정상 범위 0.85~0.98;
  • prediction-0.945: 예측 F1 점수(모델이 수익/비용 예측 정확도 측정); 이 두 지표는 임계값(일반적으로 F1>0.85가 합격)을 훨씬 초과하여, DST 환경에서 학습된 s3_r9 모델의 성능이 우수함을 보여줌.

심해 보물(DST) 환경에서의 다중 목적 강화학습(MORL) 파레토 전면 평가 그래프:

요소 의미
X축 `teasure value` 보물 가치, 높을수록 얻은 보물이 많음(목표 1).
Y축 `time penalty` 시간 페널티(음수), 더 음수일수록 시간이 더 많이 소요됨/페널티가 큼(목표 2).
검은 점선 + 검은 점 `Pareto` 이론적 최적 파레토 전면(실제 값), 알고리즘이 접근해야 할 목표.
주황색 점 `Recovered` 정책 실행으로 얻은 해(에이전트.act로 정책 샘플링).
초록색 점/선 `Predicted` 모델이 직접 예측한 해(에이전트.predict로 출력된 HQ 값).

녹색(Predicted)과 주황색(Recovered) 점이 검은 점선(이론적 파레토)에 거의 밀접하게 붙어 있는 것으로:

  • 모델 예측 파레토 해(녹색)는 이론적 최적과 거의 일치;
  • 정책 실행 해(주황색)도 이론적 전면과 높게 일치, 알고리즘으로 학습된 정책이 최적 균형을 효과적으로 복제함.

4. 고버전 PyTorch 호환 주의사항(오류 방지)

원 코드는 PyTorch 0.4.0 기반, 고버전에서는 미세 조정 필요:

1. Tensor 데이터 유형 호환

synthetic/train.py/roijers_train.py에서 다음 코드 찾기:

# 원 코드(0.4.0)
FloatTensor = torch.cuda.FloatTensor if use_cuda else torch.FloatTensor
LongTensor = torch.cuda.LongTensor if use_cuda else torch.LongTensor

PyTorch 1.10에 맞춤:

# PyTorch 1.10 호환
FloatTensor = torch.cuda.FloatTensor if use_cuda else torch.FloatTensor
LongTensor = torch.cuda.LongTensor if use_cuda else torch.LongTensor
# 고버전 Tensor 할당 경고 수정
torch.set_default_tensor_type(FloatTensor)

2. data.cpu()cpu().data로 변경(일부 파일)

act_1 = act_1.data.cpu()는 경고 발생 가능

PyTorch 0.4.0 기반 원 코드는 고버전에서 train.py의 Tensor 작업을 조정해야 합니다:

작업 파일: D:\ProgramData\논문 복제\FirRL\synthetic\train.py

다음 코드 찾기:

if args.method == "crl-naive":
    act_1 = act_1.data.cpu()
    act_2 = act_2.data.cpu()
elif args.method == "crl-envelope":
    act_1 = probe.dot(act_1.data)
    act_2 = probe.dot(act_2.data)
elif args.method == "crl-energy":
    act_1 = probe.dot(act_1.data)
    act_2 = probe.dot(act_2.data)

PyTorch 1.0+에 맞춤:

if args.method == "crl-naive":
    act_1 = act_1.cpu().data  # cpu()와 data 순서 변경
    act_2 = act_2.cpu().data
elif args.method == "crl-envelope":
    act_1 = probe.dot(act_1.cpu().data)  # CUDA Tensor 오류 방지 위해 cpu() 추가
    act_2 = probe.dot(act_2.cpu().data)
elif args.method == "crl-energy":
    act_1 = probe.dot(act_1.cpu().data)
    act_2 = probe.dot(act_2.cpu().data)

합성 환경에서 논문에서 권장하는 파라미터를 사용하여 학습했으며, 원 코드 수정은 거의 없었고 주로 환경 설정에 시간이 소요되었습니다. --episode-num 2000로 학습 시간은 약 3-4시간(5000회는 실행하지 않음).

참고: 정상 코드의 로그 파일은 터미널 출력을 저장하지 않아, 이러한 데이터를 사용하여 분석 및 그래프 작성해야 하며, 이는 더 직관적입니다.

태그: PyTorch Reinforcement Learning Multi-Objective Optimization Deep Learning Neural Networks

7월 8일 08:17에 게시됨