Выход CNN не сильно меняется с входом - PullRequest
1 голос
/ 11 июня 2019

Я пытался реализовать 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 и сталкиваюсь там с той же проблемой.

1 Ответ

0 голосов
/ 04 июля 2019

Проблема с этим состояла в том, что инициализация веса не была подходящей. Я использовал гауссовскую инициализацию с двойным стандартным отклонением по умолчанию. Это помогло дать разные результаты для разных входов. Хотя после нескольких эпизодов обучения актер снова начинает давать ту же ценность, что объясняется насыщением критики.

...