gpt4 book ai didi

python - 如何使Keras网络不输出全1

转载 作者:行者123 更新时间:2023-11-30 09:06:33 25 4
gpt4 key购买 nike

我有一堆看起来像是玩电子游戏(我在Tkinter中创建的简单游戏)的人的图像:

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

游戏的想法是,用户控制屏幕底部的框以躲避掉落的球(他们只能左右躲避)。

我的目标是让神经网络在屏幕底部输出播放器的位置。如果它们完全位于左侧,则神经网络应该输出一个0,如果位于中间,则输出一个.5,一直到右边,一个1,并且所有值都在中间。

我的图片是300x400像素。我非常简单地存储了数据。我在50帧游戏中将每个图像和玩家位置记录为元组。因此,我的结果是以[(image, player position), ...]形式包含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


编辑:print(Y)给我:

<code>print(Y)</code>

因此绝对不是全零。

最佳答案

当然,更深的模型可能会为您提供更好的精度,但是考虑到图像很简单的事实,一个只有一个隐藏层的非常简单(浅)的模型应该具有中等到高精度的精度。因此,这是您需要进行的修改:


确保XY的类型为float32(当前,X的类型为uint8):

X = np.array(X, dtype=np.float32)
Y = np.array(Y, dtype=np.float32)

在训练神经网络时,最好将训练数据标准化。规范化有助于优化过程顺利进行,并加快解决方案的收敛速度。它进一步防止了大的值导致大的梯度更新,这将破坏性的。通常,输入数据中每个要素的值应落在较小的范围内,其中两个常见范围是 [-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(您永远不要从测试数据中减去其自身的均值或将其除以自己的标准差;而是使用训练数据的均值和标准差):

X_test -= X_mean
X_test /= X_std + 1e-8

如果在点1和点2上应用更改,则可能会注意到网络不再仅预测1或仅预测0。相反,它显示出一些模糊的学习迹象,并预测零和一的混合。这不错,但远非好事,我们抱有很高的期望!该预测应该比仅包含零和一的混合要好得多。在那里,您应该考虑(忘记!)学习速度。由于考虑到相对简单的问题,网络具有相对大量的参数(并且有一些训练数据样本),因此您应该选择较小的学习速率以平滑梯度更新和学习过程:

from keras import optimizers
model.compile(loss='mean_squared_error', optimizer=optimizers.Adam(lr=0.0001))


您会注意到其中的区别:10个周期后,损耗值达到 0.01左右。网络不再预测零和一的混合;而是预测更加准确,并且接近预期值(即 Y)。
别忘了!我们寄予厚望(合乎逻辑!)。因此,如何在不向网络添加任何新层的情况下做得更好(显然,我们假设 adding more layers可能会有所帮助!)?

4.1。收集更多的训练数据。

4.2。添加体重调整。常见的是L1和L2正则化(我强烈推荐Keras的作者FrançoisChollet撰写的《 notebooks》一书的Jupyter Deep Learning with Python。具体地说, here是讨论正则化的书。)





您应该始终以适当且公正的方式评估模型。根据训练数据(您曾经训练过的数据)对其进行评估并不能告诉您有关模型在看不见的(即新的或现实的)数据点上的性能的任何信息(例如,考虑一个存储或记忆所有训练的模型)数据。它可以在训练数据上完美地表现,但它是一个无用的模型,并且在新数据上的表现不佳。因此,我们应该具有测试和训练数据集:我们根据训练数据训练模型,并根据测试(即新的)数据评估模型。但是,在提出一个好的模型的过程中,您要进行大量的实验:例如,您首先更改层的类型和数量,训练模型,然后根据测试数据对其进行评估,以确保模型良好。然后,您改变另一种说法,即学习率,再次对其进行训练,然后在测试数据上再次对其进行评估……简而言之,这些调整和评估周期以某种方式导致对测试数据的过度拟合。因此,我们需要第三个数据集称为验证数据(更多信息: What is the difference between test set and validation set?):

# 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)


(实际上,当我们几乎没有可用的训练数据时,将验证和测试数据与全部可用数据分开是浪费的。在这种情况下,如果模型的计算成本不高,则不要分离一个称为交叉验证的验​​证集,如果数据样本很少,则可以进行 K-fold cross-validation或迭代K倍交叉验证。)




在编写此答案时,大约是凌晨4点,我感到困倦,但是我想提一件事,这与您的问题没有直接关系:通过使用Numpy库及其功能和方法,您可以编写更多内容简洁高效的代码,还可以节省很多时间。因此,请确保您更多地练习使用它,因为它在机器学习社区和图书馆中大量使用。为了证明这一点,这是您编写的相同代码,但更多地使用了Numpy(请注意,我没有应用上面在代码中提到的所有更改):

# 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

关于python - 如何使Keras网络不输出全1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50993978/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com