Я пытался реализовать Actor Critic с помощью сверточной нейронной сети. Существует два разных изображения в качестве состояния для агента обучения подкрепления. Выход (действия для актера) CNN является (почти) одинаковым для разных входов после (случайной) инициализации. Благодаря этому даже после обучения агент никогда не узнает ничего полезного.
Определения состояния (2 входа):
Ввод 1: [1,1,90,128] изображение с максимальным значением для пикселя 45.
Input 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 остается почти таким же.
Код для определения актера был приведен ниже.
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>)
Файлы состояний (.npy
) можно найти здесь
Для разных состояний действия должны отличаться от [0-160,0-112], но здесь выходы просто немного отличаются.
Примечание: входные изображения изначально разрежены (на изображении много нулей)
Есть ли проблема со значениями пикселей состояния или определением сети?
РЕДАКТИРОВАТЬ: Я думаю, что проблема связана с нормализацией или разреженностью входов, потому что я также пробовал ту же сеть с tenorflow и сталкиваюсь там с той же проблемой.