Python 如何使Keras网络不输出所有1
我有一堆像这样的图片,有人在玩电子游戏(我在Tkinter中创建的一个简单游戏): 这个游戏的想法是,用户控制屏幕底部的盒子以躲避落下的球(他们只能躲避左右) 我的目标是让神经网络输出播放器在屏幕底部的位置。如果它们完全在左边,则神经网络应该输出一个<代码> 0代码/代码>,如果它们在中间,一个<代码> 5 ,并且始终是正确的,一个<代码> 1 <代码>,以及所有的值之间。 我的图像是300x400像素。我存储数据非常简单。在一个50帧的游戏中,我将每一帧的图像和玩家的位置记录为一个元组。因此,我的结果是一个包含50个元素的列表,格式为Python 如何使Keras网络不输出所有1,python,tensorflow,machine-learning,neural-network,keras,Python,Tensorflow,Machine Learning,Neural Network,Keras,我有一堆像这样的图片,有人在玩电子游戏(我在Tkinter中创建的一个简单游戏): 这个游戏的想法是,用户控制屏幕底部的盒子以躲避落下的球(他们只能躲避左右) 我的目标是让神经网络输出播放器在屏幕底部的位置。如果它们完全在左边,则神经网络应该输出一个 0代码/代码>,如果它们在中间,一个 5 ,并且始终是正确的,一个 1 ,以及所有的值之间。 我的图像是300x400像素。我存储数据非常简单。在一个50帧的游戏中,我将每一帧的图像和玩家的位置记录为一个元组。因此,我的结果是一个包含50个元素的
[(图像,玩家位置),…]
。然后我整理了那张单子
因此,在我的代码中,我尝试创建一个非常基本的前馈网络,它接收图像并输出一个介于0和1之间的值,表示图像底部框的位置。但我的神经网络只输出1s
我应该改变什么,以使其训练并输出接近我想要的值
当然,这是我的代码:
# 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
编辑:打印(Y)给了我:
所以它肯定不是全零。当然,更深层次的模型可能会提供更好的精度,但考虑到图像简单的事实,只有一个隐藏层的非常简单(浅)的模型应该提供中到高的精度。因此,以下是实现这一目标所需的修改:
X
和Y
类型为float32
(当前,X
类型为uint8
):
[-1,1]
和[0,1]
。因此,为了确保所有值都在[-1,1]
范围内,我们从每个特征中减去其平均值并除以其标准偏差:
X_mean = X.mean(axis=0)
X -= X_mean
X_std = X.std(axis=0)
X /= X_std + 1e-8 # add a very small constant to prevent division by zero
请注意,我们在这里规范化每个特征(即本例中的每个像素),而不是每个图像。当您想要预测新数据时,即在推理或测试模式下,您需要从测试数据中减去X_mean
,然后除以X_std
(您应该永远不要从测试数据中减去自己的平均值或除以自己的标准偏差;而是使用训练数据的平均值和标准差):
from keras import optimizers
model.compile(loss='mean_squared_error', optimizer=optimizers.Adam(lr=0.0001))
您会注意到差异:损失值在10个纪元后达到约0.01
。网络不再预测零和一的混合;相反,预测更准确,更接近它们应该达到的水平(即Y
)在写这个答案的时候大约是凌晨4点,我感到很困,但我想再提一件与你的问题没有直接关系的事情:通过使用Numpy库
X_test -= X_mean
X_test /= X_std + 1e-8
from keras import optimizers
model.compile(loss='mean_squared_error', optimizer=optimizers.Adam(lr=0.0001))
# first shuffle the data to make sure it isn't in any particular order
indices = np.arange(X.shape[0])
np.random.shuffle(indices)
X = X[indices]
Y = Y[indices]
# you have 200 images
# we select 100 images for training,
# 50 images for validation and 50 images for test data
X_train = X[:100]
X_val = X[100:150]
X_test = X[150:]
Y_train = Y[:100]
Y_val = Y[100:150]
Y_test = Y[150:]
# train and tune the model
# you can attempt train and tune the model multiple times,
# each time with different architecture, hyper-parameters, etc.
model.fit(X_train, Y_train, epochs=15, batch_size=10, validation_data=(X_val, Y_val))
# only and only after completing the tuning of your model
# you should evaluate it on the test data for just one time
model.evaluate(X_test, Y_test)
# after you are satisfied with the model performance
# and want to deploy your model for production use (i.e. real world)
# you can train your model once more on the whole data available
# with the best configurations you have found out in your tunings
model.fit(X, Y, epochs=15, batch_size=10)
# 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]
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 = zip(*data)
inputs = [pil_image_to_np_array(image) for image in inputs]
inputs = np.array(inputs, dtype=np.float32)
outputs = np.array(outputs, dtype=np.float32)
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.shape[2] # == 400
# convert the player position (a value between 0 and the width of the image) to values between 0 and 1
Y /= width
# flatten the image inputs so they can be passed to a neural network
X = np.reshape(X, (X.shape[0], -1))
# 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