How can I get my neural network to not output all 1s?

python

#1

Hello! I’m Jadiker, and this is my first post here :blush: It’s really nice to see a tech community built around kindness. I’m generally a regular on Stack Overflow, but was brought here by this post, and thought I’d try it out.

Not only am I brand new to this site, I’m also brand new to machine learning, so we’ll see how this goes.

I just discovered Keras, and I’m trying to make a very simple neural network.

I have a bunch of images that look like this of someone playing a videogame (a game I created in Tkinter).

Ball falling in videogame; player's box is at the bottom

The idea of the game is that the user controls the box at the bottom of the screen in order to dodge the falling balls. (They can only dodge left and right.)

My goal is to have the neural network output the position of the player’s square on the bottom of the screen. If the player is on the left, the neural network should output a 0, if they’re in the middle, a .5, all the way right, a 1, and all the values in-between.

My images are 300x400 pixels. During a 50-frame game, I recorded each of the images on the screen and the position of the player as a tuple. Thus my resulting data was a list in the form [(image, player position), ...] with 50 elements. I then used the python pickle module to pickle that list to a file called “position_data1.pkl”.

In my code, I try to create an extremely basic feed-forward nerual network that takes in the image and outputs a value between 0 and 1 representing where the box on the bottom of the image is. But my neural network is only outputting 1s :slightly_frowning_face:

What should I change in order to get it to train and output values close to what I want?

Of course, here is my code. Any help would be appreciated.

# machine learning code mostly from https://machinelearningmastery.com/tutorial-first-neural-network-python-keras/

from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import pickle

def pil_image_to_np_array(image):
    '''Takes an image and converts it to a numpy array'''
    # from https://stackoverflow.com/a/45208895
    # all my images are black and white, so I only need one channel
    return np.array(image)[:, :, 0:1]

def data_to_training_set(data):
    # split the list in the form [(frame 1 image, frame 1 player position), ...] into [[all images], [all player positions]]
    inputs, outputs = [list(val) for val in zip(*data)]
    for index, image in enumerate(inputs):
        # convert the PIL images into numpy arrays so Keras can process them
        inputs[index] = pil_image_to_np_array(image)
    return (inputs, outputs)

if __name__ == "__main__":
    # fix random seed for reproducibility
    np.random.seed(7)

    # load data
    # data will be in the form [(frame 1 image, frame 1 player position), (frame 2 image, frame 2 player position), ...]
    with open("position_data1.pkl", "rb") as pickled_data:
        data = pickle.load(pickled_data)
    X, Y = data_to_training_set(data)

    # get the width of the images
    width = X[0].shape[1] # == 400
    # convert the player position (a value between 0 and the width of the image) to values between 0 and 1
    for index, output in enumerate(Y):
        Y[index] = output / width

    # flatten the image inputs so they can be passed to a neural network
    for index, inpt in enumerate(X):
        X[index] = np.ndarray.flatten(inpt)

    # keras expects an array (not a list) of image-arrays for input to the neural network
    X = np.array(X)
    Y = np.array(Y)

    # create model
    model = Sequential()
    # my images are 300 x 400 pixels, so each input will be a flattened array of 120000 gray-scale pixel values
    # keep it super simple by not having any deep learning
    model.add(Dense(1, input_dim=120000, activation='sigmoid'))

    # Compile model
    model.compile(loss='mean_squared_error', optimizer='adam')

    # Fit the model
    model.fit(X, Y, epochs=15, batch_size=10)

    # see what the model is doing
    predictions = model.predict(X, batch_size=10)
    print(predictions) # this prints all 1s! # TODO fix

#2

So it turns out it was two issues:

  1. I didn’t have a small enough learning rate

  2. I didn’t normalize the data

The solution can be found as an answer to this question on stack overflow: https://stackoverflow.com/questions/50993978/how-to-get-keras-network-to-not-output-all-1s