【发布时间】:2019-10-25 18:09:51
【问题描述】:
我一直在尝试使用卷积神经网络来实现 Actor Critic。有两个不同的图像作为强化学习代理的状态。对于(随机)初始化后的不同输入,CNN 的输出(Actor 的动作)是(几乎)相同的。因此,即使在训练之后,代理也永远不会学到任何有用的东西。
状态定义(2 个输入):
输入 1:[1,1,90,128] 图像,像素最大值为 45。
输入 2:[1,1,45,80] 图像,像素最大值为 45。
参与者的预期输出:[x,y]:根据状态的二维向量。这里 x 预计在 [0,160] 范围内,y 预计在 [0,112] 范围内
尝试使用输入进行不同类型的修改:
1:按原样输入两个图像。
2: 以(img/45) 的形式输入两个图像,以便像素值来自 [0,1]
3: 以2*((img/45)-0.5) 标准化输入两个图像,以便像素值来自 [-1,1]
4: 以(img-mean)/std 的形式提供两个图像的归一化@
结果:CNN 的输出几乎保持不变。
actor的定义代码如下。
import numpy as np
import pandas as pd
from tqdm import tqdm
import time
import cv2
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.nn.functional as F
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
class Actor(nn.Module):
def __init__(self, action_dim, max_action):
super(Actor,self).__init__()
# state image [1,1,90,128]
self.conv11 = nn.Conv2d(1,16,5)
self.conv11_bn = nn.BatchNorm2d(16)
self.conv12 = nn.Conv2d(16,16,5)
self.conv12_bn = nn.BatchNorm2d(16)
self.fc11 = nn.Linear(19*29*16,500)
# dim image [1,1,45,80]
self.conv21 = nn.Conv2d(1,16,5)
self.conv21_bn = nn.BatchNorm2d(16)
self.conv22 = nn.Conv2d(16,16,5)
self.conv2_bn = nn.BatchNorm2d(16)
self.fc21 = nn.Linear(8*17*16,250)
# common pool
self.pool = nn.MaxPool2d(2,2)
# after concatenation
self.fc2 = nn.Linear(750,100)
self.fc3 = nn.Linear(100,10)
self.fc4 = nn.Linear(10,action_dim)
self.max_action = max_action
def forward(self,x,y):
# state image
x = self.conv11_bn(self.pool(F.relu(self.conv11(x))))
x = self.conv11_bn(self.pool(F.relu(self.conv12(x))))
x = x.view(-1,19*29*16)
x = F.relu(self.fc11(x))
# state dim
y = self.conv11_bn(self.pool(F.relu(self.conv21(y))))
y = self.conv11_bn(self.pool(F.relu(self.conv22(y))))
y = y.view(-1,8*17*16)
y = F.relu(self.fc21(y))
# concatenate
z = torch.cat((x,y),dim=1)
z = F.relu(self.fc2(z))
z = F.relu(self.fc3(z))
z = self.max_action*torch.tanh(self.fc4(z))
return z
# to read different sample states for testing
obs = []
for i in range(200):
obs.append(np.load('eval_episodes/obs_'+str(i)+'.npy',allow_pickle=True))
obs = np.array(obs)
def tensor_from_numpy(state):
# to add dimensions to tensor to make it [batch_size,channels,height,width]
state_img = state
state_img = torch.from_numpy(state_img).float()
state_img = state_img[np.newaxis, :]
state_img = state_img[np.newaxis, :].to(device)
return state_img
actor = Actor(2,torch.FloatTensor([160,112]))
for i in range(20):
a = tensor_from_numpy(obs[i][0])
b = tensor_from_numpy(obs[i][2])
print(actor(a,b))
以上代码的输出:
tensor([[28.8616, 3.0934]], grad_fn=<MulBackward0>)
tensor([[27.4125, 3.2864]], grad_fn=<MulBackward0>)
tensor([[28.2210, 2.6859]], grad_fn=<MulBackward0>)
tensor([[27.6312, 3.9528]], grad_fn=<MulBackward0>)
tensor([[25.9290, 4.2942]], grad_fn=<MulBackward0>)
tensor([[26.9652, 4.5730]], grad_fn=<MulBackward0>)
tensor([[27.1342, 2.9612]], grad_fn=<MulBackward0>)
tensor([[27.6494, 4.2218]], grad_fn=<MulBackward0>)
tensor([[27.3122, 1.9945]], grad_fn=<MulBackward0>)
tensor([[29.6915, 1.9938]], grad_fn=<MulBackward0>)
tensor([[28.2001, 2.5967]], grad_fn=<MulBackward0>)
tensor([[26.8502, 4.4917]], grad_fn=<MulBackward0>)
tensor([[28.6489, 3.2022]], grad_fn=<MulBackward0>)
tensor([[28.1455, 2.7610]], grad_fn=<MulBackward0>)
tensor([[27.2369, 3.4243]], grad_fn=<MulBackward0>)
tensor([[25.9513, 5.3057]], grad_fn=<MulBackward0>)
tensor([[28.1400, 3.3242]], grad_fn=<MulBackward0>)
tensor([[28.2049, 2.6622]], grad_fn=<MulBackward0>)
tensor([[26.7446, 2.5966]], grad_fn=<MulBackward0>)
tensor([[25.3867, 5.0346]], grad_fn=<MulBackward0>)
states(.npy) 文件可以在here找到
对于不同的状态,动作应该从 [0-160,0-112] 变化,但这里的输出只是略有不同。
注意:输入图像最初是稀疏的(图像中有很多零)
状态像素值或网络定义有问题吗?
编辑:我认为问题与输入的规范化或稀疏性有关,因为我也尝试了与 tensorflow 相同的网络并且在那里面临同样的问题。
【问题讨论】:
-
评估 Actor 网络时,是否使用 actor.eval() 将网络置于评估模式(即关闭批归一化和 dropout,因为它们仅在训练期间使用)?
-
@akshayk07 即使在训练期间,对于不同的输入,网络的输出几乎(相同),并且不知何故它没有学到任何东西。我只是想让演员为不同的状态赋予不同的价值。即使是critic 也给出了相同的输出(因为actor 对所有状态都给出了相同的动作),因此agent 永远不会学到任何东西。
标签: python deep-learning conv-neural-network pytorch reinforcement-learning