What input should I use for my Neural Network?

Viewed 77

I recently implemented a simple Deep Q-Learning agent in Processing for a game called Frozen Lake (game from OpenAI Gym). The agent basically has to find the shortest path between the starting and the ending points, avoiding obstacles (holes in the ice) and without going out of the map.

This is the code that generates the state passed to the Neural Network:

//Return an array of double containing all 0s except for the cell the Agent is on that is 1.
  private double[] getState()
  { 
    double[] state = new double[cellNum];
    for(Cell cell : lake.cells)
    {
      if((x - cellDim/2) == cell.x && (y - cellDim/2) == cell.y)
      {
        state[lake.cells.indexOf(cell)] = 1;
      }
      else
      {
        state[lake.cells.indexOf(cell)] = 0;
      }
    }
    return state;
  }

where lake is the environment object, cells is an ArrayList attribute of lake containing all the squares of the map, x and y are the agent's coordinates on the map.

And all of this works well, but the agent only learns the best path for a single game map and if the map changes the agent must be trained all over again.

I wanted the agent to learn how to play the game and not how to play a single map.

So, instead of setting all the map squares to 0 except the one the agent is on that is set to 1, I tried to associated some random numbers for every kind of square (Goal:1, Ice:8, Hole:0, Goal:3, Agent:7) and set the input like that, but it didn't work at all.

So I tried to convert all the colors of the squares into a grayscale value (from 0 to 255), so that now the different squares were mapped as (roughly): Goal:45, Ice:243.37, Hole:34.57, Goal:70.8, Agent:150.

But this didn't work either, so I mapped all the grayscale values to values between 0 and 1.

But no result with this either.

By the way, this is the code for the Neural Network to calculate the output:

public Layer[] estimateOutput(double[] input)
  {
    Layer[] neurons = new Layer[2]; //Hidden neurons [0] and Output neurons [1].
    
    neurons[0] = new Layer(input); //To be transformed into Hidden neurons.
    
    //Hidden neurons values calculation.
    neurons[0] = neurons[0].dotProduct(weightsHiddenNeurons).addition(biasesHiddenNeurons).sigmoid();
    
    //Output neurons values calculation.
    neurons[1] = neurons[0].dotProduct(weightsOutputNeurons).addition(biasesOutputNeurons);
    
    if(gameData.trainingGames == gameData.gamesThreshold)
    {
      //this.render(new Layer(input), neurons[0], neurons[1].sigmoid()); //Draw Agent's Neural Network.
    }
    
    return neurons;
  }

and to learn:

public void learn(Layer inputNeurons, Layer[] neurons, Layer desiredOutput)
  {
    Layer hiddenNeurons = neurons[0];
    Layer outputNeurons = neurons[1];
    
    Layer dBiasO = (outputNeurons.subtraction(desiredOutput)).valueMultiplication(2);
    Layer dBiasH = (dBiasO.dotProduct(weightsOutputNeurons.transpose())).layerMultiplication((inputNeurons.dotProduct(weightsHiddenNeurons).addition(biasesHiddenNeurons)).sigmoidDerivative());
    
    Layer dWeightO = (hiddenNeurons.transpose()).dotProduct(dBiasO);
    Layer dWeightH = (inputNeurons.transpose()).dotProduct(dBiasH);
    
    //Set new values for Weights and Biases
    weightsHiddenNeurons = weightsHiddenNeurons.subtraction(dWeightH.valueMultiplication(learningRate));
    biasesHiddenNeurons = biasesHiddenNeurons.subtraction(dBiasH.valueMultiplication(learningRate));
    weightsOutputNeurons = weightsOutputNeurons.subtraction(dWeightO.valueMultiplication(learningRate));
    biasesOutputNeurons = biasesOutputNeurons.subtraction(dBiasO.valueMultiplication(learningRate));
  }

Anyway, the whole project is available on GitHub, where the code is better commented: https://github.com/Nyphet/Frozen-Lake-DQL

What am I doing wrong on setting the input? How can I achieve "learning the game" instead of "learning the map"?

Thanks in advance.

0 Answers
Related