探索的大胜利——随机网络蒸馏(Random Network Distillation)

目录
写在前面
本项目是之前写过的一个项目项目——好奇心驱动的强化学习中鼓励探索机制(好奇心机制也是其中一种)的另一种形式,对好奇心还不是很熟悉的童鞋可以看看。
RND 有多强?
先来看一张 benchmark,环境为雅达利的游戏——蒙特祖马的复仇

可以看到一众经典算法包括 DQN、A3C、C51、ES 都考了零蛋,情况稍微好一点的算法一般是采用先进理论的算法(比如 UBE,不确定性贝尔曼方程及探索),又或者是一些分布式的训练框架(比如Ape-X,分布式优先级采样的 DQN 框架)
但是,我们的 RND 一骑绝尘,打通了所有关卡,还找到了所有隐藏房间(当然不知道训练了多久)。
RND 简介
我们的 RND 算法到底长啥样呢?这里先摆一张正经的伪代码(用于装杯)

简单来说,其实就是两个不同随机参数的网络,一个更新(称为 predictor)一个不更新(称为 target)。
target 满足的理论前提是对于不同的原始输入(比如图像),输出也要不同,也就是一对一的映射关系。
而 predictor 的目标,就是跟上 target 的脚步,如果 predictor 能跟上 target 的脚步(两个网络的输出很相似),说明 predictor 至少接受过与 target 一样的输入(也就是这个环境已经探索过了),此时内在的奖励就变少了。
举个例子,如果整张地图是一张被 target 盖住的刮刮乐,predictor 就会随着环境输入渐渐地把整个地图都刮开。

这里的内在奖励定义为 ∣ ∣ f ^ ( x ; θ ) − f ( x ) ∣ ∣ 2 ||\hat{f}(x;\theta)-f(x)||^2 ∣∣f^(x;θ)−f(x)∣∣2
我们一般称带小帽子的 f ^ \hat{f} f^为预测的值, θ \theta θ是参数,对应 predictor;剩下的 f f f自然就是 target 的输出。
举个例子,如果整张地图是一张被 target 盖住的刮刮乐,predictor 就会随着环境输入渐渐地把整个地图都刮开。

这里的内在奖励定义为 ∣ ∣ f ^ ( x ; θ ) − f ( x ) ∣ ∣ 2 ||\hat{f}(x;\theta)-f(x)||^2 ∣∣f^(x;θ)−f(x)∣∣2
我们一般称带小帽子的 f ^ \hat{f} f^为预测的值, θ \theta θ是参数,对应 predictor;剩下的 f f f自然就是 target 的输出。
RND 怎么用
了解好奇心机制的童鞋应该都知道,生成好奇心奖励的好奇心模块就是一个挂件,可以直接外接在强化学习的核心算法上。
所以,模型更新的时候记得收集一下 next state,做成一个列表。模型更新的时候按索引计算内在奖励,加在模型总损失里面就好了。
但是,一定要记得把 target 设置成 stop_gradient=True 噢!
真 · 完全体—— RND+PPO 玩马里奥
创建游戏环境
创建可供多线程的游戏环境
%%writefile MARIO/game_env.py
from __future__ import print_function
import gym_super_mario_bros
from gym.spaces import Box
from gym import Wrapper
from nes_py.wrappers import JoypadSpace
from gym_super_mario_bros.actions import SIMPLE_MOVEMENT, COMPLEX_MOVEMENT, RIGHT_ONLY
import cv2
import numpy as np
import subprocess as sp
import multiprocessing as mp
class Monitor:
def __init__(self, width, height, saved_path):
self.command = ["ffmpeg", "-y", "-f", "rawvideo", "-vcodec", "rawvideo", "-s", "{}X{}".format(width, height),
"-pix_fmt", "rgb24", "-r", "60", "-i", "-", "-an", "-vcodec", "mpeg4", saved_path]
try:
'''创建子进程
'''
self.pipe = sp.Popen(self.command, stdin=sp.PIPE, stderr=sp.PIPE)
except FileNotFoundError:
pass
'''记录
'''
def record(self, image_array):
self.pipe.stdin.write(image_array.tostring())
def process_frame(frame):
if frame is not None:
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
frame = cv2.resize(frame, (84, 84))[None, :, :] / 255.
return frame
else:
return np.zeros((1, 84, 84))
class CustomReward(Wrapper):
def __init__(self, env=None, monitor=None):
super(CustomReward, self).__init__(env)
self.observation_space = Box(low=0, high=255, shape=(1, 84, 84))
self.curr_score = 0
if monitor:
self.monitor = monitor
else:
self.monitor = None
def step(self, action):
state, reward, done, info = self.env.step(action)
if self.monitor:
self.monitor.record(state)
state = process_frame(state)
reward += (info["score"] - self.curr_score) / 40.
self.curr_score = info["score"]
if done:
if info["flag_get"]:
reward += 50
reward += info["time"]
else:
reward -= 50
return state, reward / 10., done, info
def reset(self):
self.curr_score = 0
return process_frame(self.env.reset())
class CustomSkipFrame(Wrapper):
def __init__(self, env, skip=4):
super(CustomSkipFrame, self).__init__(env)
self.observation_space = Box(low=0, high=255, shape=(skip, 84, 84))
self.skip = skip
self.states = np.zeros((skip, 84, 84), dtype=np.float32)
def step(self, action):
total_reward = 0
last_states = []
for i in range(self.skip):
state, reward, done, info = self.env.step(action)
total_reward += reward
if i >= self.s

本文介绍了一种增强强化学习探索能力的方法——随机网络蒸馏(RND)。通过两个网络的竞争,RND能够自动生成内在奖励,激励智能体探索未知环境。文章详细展示了RND的工作原理及其在经典游戏上的应用。
最低0.47元/天 解锁文章
1127





