Python - tensorflow 的低准确度和低损失
Python - Low accuracy with low loss with tensorflow
我正在构建一个简单的神经网络,它采用 3 个值并提供 2 个输出。
我的准确率为 67.5%,平均成本为 0.05
我有一个包含 1000 个示例和 500 个测试示例的训练数据集。我计划在不久的将来制作更大的数据集。
不久前我设法得到了大约 82% 的准确率,有时甚至更高,但成本很高。
我一直在尝试添加模型中当前存在的另一层,这就是我的损失低于 1.0 的原因
我不确定出了什么问题,总的来说我是 Tensorflow 和 NN 的新手。
这是我的代码:
import tensorflow as tf
import numpy as np
import sys
sys.path.insert(0, '.../Dataset/Testing/')
sys.path.insert(0, '.../Dataset/Training/')
#other files
from TestDataNormaliser import *
from TrainDataNormaliser import *
learning_rate = 0.01
trainingIteration = 10
batchSize = 100
displayStep = 1
x = tf.placeholder("float", [None, 3])
y = tf.placeholder("float", [None, 2])
#layer 1
w1 = tf.Variable(tf.truncated_normal([3, 4], stddev=0.1))
b1 = tf.Variable(tf.zeros([4]))
y1 = tf.matmul(x, w1) + b1
#layer 2
w2 = tf.Variable(tf.truncated_normal([4, 4], stddev=0.1))
b2 = tf.Variable(tf.zeros([4]))
#y2 = tf.nn.sigmoid(tf.matmul(y1, w2) + b2)
y2 = tf.matmul(y1, w2) + b2
w3 = tf.Variable(tf.truncated_normal([4, 2], stddev=0.1))
b3 = tf.Variable(tf.zeros([2]))
y3 = tf.nn.sigmoid(tf.matmul(y2, w3) + b3) #sigmoid
#output
#wO = tf.Variable(tf.truncated_normal([2, 2], stddev=0.1))
#bO = tf.Variable(tf.zeros([2]))
a = y3 #tf.nn.softmax(tf.matmul(y2, wO) + bO) #y2
a_ = tf.placeholder("float", [None, 2])
#cost function
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y * tf.log(a)))
#cross_entropy = -tf.reduce_sum(y*tf.log(a))
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cross_entropy)
#training
init = tf.global_variables_initializer() #initialises tensorflow
with tf.Session() as sess:
sess.run(init) #runs the initialiser
writer = tf.summary.FileWriter(".../Logs")
writer.add_graph(sess.graph)
merged_summary = tf.summary.merge_all()
for iteration in range(trainingIteration):
avg_cost = 0
totalBatch = int(len(trainArrayValues)/batchSize) #1000/100
#totalBatch = 10
for i in range(batchSize):
start = i
end = i + batchSize #100
xBatch = trainArrayValues[start:end]
yBatch = trainArrayLabels[start:end]
#feeding training data
sess.run(optimizer, feed_dict={x: xBatch, y: yBatch})
i += batchSize
avg_cost += sess.run(cross_entropy, feed_dict={x: xBatch, y: yBatch})/totalBatch
if iteration % displayStep == 0:
print("Iteration:", '%04d' % (iteration + 1), "cost=", "{:.9f}".format(avg_cost))
#
print("Training complete")
predictions = tf.equal(tf.argmax(a, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(predictions, "float"))
print("Accuracy:", accuracy.eval({x: testArrayValues, y: testArrayLabels}))
我看到你在最后一层使用了带有 sigmoidal 激活函数的 softmax 损失。现在让我解释一下softmax激活和sigmoidal的区别。
您现在允许网络的输出为 y=(0, 1)、y=(1, 0)、y=(0, 0) 和 y=(1, 1)。这是因为您的 S 形激活 "squish" y 中的每个元素都在 0 和 1 之间。但是,您的损失函数假设您的 y 向量总和为 1。
这里你需要做的是惩罚sigmoidal交叉熵函数,它看起来像这样:
-tf.reduce_sum(y*tf.log(a))-tf.reduce_sum((1-y)*tf.log(1-a))
或者,如果你想将 a 求和为 1,你需要在最后一层使用 softmax 激活(以获得你的 a)而不是像这样实现的 sigmoids
exp_out = tf.exp(y3)
a = exp_out/tf reduce_sum(exp_out)
Ps。我在火车上使用我的 phone,所以请原谅打字错误
一些重要说明:
- 你的图层之间没有 non-linearities。这意味着您正在训练一个相当于 single-layer 网络的网络,只是浪费了大量的计算。这很容易通过添加一个简单的 non-linearity 来解决,例如tf.nn.relu 在每个 matmul/+ 偏置线之后,例如y2 = tf.nn.relu(y2) 对于最后一层的所有栏。
- 您正在使用数值不稳定的交叉熵实现。我鼓励您使用 tf.nn.sigmoid_cross_entropy_with_logits,并删除您的显式 sigmoid 调用(您的 sigmoid 函数的输入通常称为 logits,或 'logistic units')。
- 看来您并没有随意打乱数据集。考虑到您选择的优化器,这可能会特别糟糕,这会导致我们...
- 随机梯度下降不是很好。为了在不增加太多复杂性的情况下获得提升,请考虑改用 MomentumOptimizer。 AdamOptimizer 是我的 go-to,但请使用它们。
在编写干净、可维护的代码时,我还鼓励您考虑以下几点:
- 使用更高级别的 API,例如tf.layers。很高兴您知道在变量级别发生了什么,但是所有复制的代码很容易出错,并且层实现的默认值通常非常好
- 考虑使用 tf.data.Dataset API 作为数据输入。一开始有点吓人,但它处理了很多事情,比如批处理、洗牌、重复纪元等。非常好
- 考虑使用 tf.estimator.Estimator API 之类的东西来处理会话运行、摘要编写和评估。
通过所有这些更改,您可能会得到如下所示的内容(我已将您的代码留在其中,因此您可以大致看到等效的行)。
对于图形构建:
def get_logits(features):
"""tf.layers API is cleaner and has better default values."""
# #layer 1
# w1 = tf.Variable(tf.truncated_normal([3, 4], stddev=0.1))
# b1 = tf.Variable(tf.zeros([4]))
# y1 = tf.matmul(x, w1) + b1
x = tf.layers.dense(features, 4, activation=tf.nn.relu)
# #layer 2
# w2 = tf.Variable(tf.truncated_normal([4, 4], stddev=0.1))
# b2 = tf.Variable(tf.zeros([4]))
# y2 = tf.matmul(y1, w2) + b2
x = tf.layers.dense(x, 4, activation=tf.nn.relu)
# w3 = tf.Variable(tf.truncated_normal([4, 2], stddev=0.1))
# b3 = tf.Variable(tf.zeros([2]))
# y3 = tf.nn.sigmoid(tf.matmul(y2, w3) + b3) #sigmoid
# N.B Don't take a non-linearity here.
logits = tf.layers.dense(x, 1, actiation=None)
# remove unnecessary final dimension, batch_size * 1 -> batch_size
logits = tf.squeeze(logits, axis=-1)
return logits
def get_loss(logits, labels):
"""tf.nn.sigmoid_cross_entropy_with_logits is numerically stable."""
# #cost function
# cross_entropy = tf.reduce_mean(-tf.reduce_sum(y * tf.log(a)))
return tf.nn.sigmoid_cross_entropy_with_logits(
logits=logits, labels=labels)
def get_train_op(loss):
"""There are better options than standard SGD. Try the following."""
learning_rate = 1e-3
# optimizer = tf.train.GradientDescentOptimizer(learning_rate)
optimizer = tf.train.MomentumOptimizer(learning_rate)
# optimizer = tf.train.AdamOptimizer(learning_rate)
return optimizer.minimize(loss)
def get_inputs(feature_data, label_data, batch_size, n_epochs=None,
shuffle=True):
"""
Get features and labels for training/evaluation.
Args:
feature_data: numpy array of feature data.
label_data: numpy array of label data
batch_size: size of batch to be returned
n_epochs: number of epochs to train for. None will result in repeating
forever/until stopped
shuffle: bool flag indicating whether or not to shuffle.
"""
dataset = tf.data.Dataset.from_tensor_slices(
(feature_data, label_data))
dataset = dataset.repeat(n_epochs)
if shuffle:
dataset = dataset.shuffle(len(feature_data))
dataset = dataset.batch(batch_size)
features, labels = dataset.make_one_shot_iterator().get_next()
return features, labels
对于会话 运行,您可以像以前那样使用它(我称之为 'the hard way')...
features, labels = get_inputs(
trainArrayValues, trainArrayLabels, batchSize, n_epochs, shuffle=True)
logits = get_logits(features)
loss = get_loss(logits, labels)
train_op = get_train_op(loss)
init = tf.global_variables_initializer()
# monitored sessions have the `should_stop` method, which works with datasets
with tf.train.MonitoredSession() as sess:
sess.run(init)
while not sess.should_stop():
# get both loss and optimizer step in the same session run
loss_val, _ = sess.run([loss, train_op])
print(loss_val)
# save variables etc, do evaluation in another graph with different inputs?
但我认为您最好使用 tf.estimator.Estimator,尽管有些人更喜欢 tf.keras.Models。
def model_fn(features, labels, mode):
logits = get_logits(features)
loss = get_loss(logits, labels)
train_op = get_train_op(loss)
predictions = tf.greater(logits, 0)
accuracy = tf.metrics.accuracy(labels, predictions)
return tf.estimator.EstimatorSpec(
mode=mode, loss=loss, train_op=train_op,
eval_metric_ops={'accuracy': accuracy}, predictions=predictions)
def train_input_fn():
return get_inputs(trainArrayValues, trainArrayLabels, batchSize)
def eval_input_fn():
return get_inputs(
testArrayValues, testArrayLabels, batchSize, n_epochs=1, shuffle=False)
# Where variables and summaries will be saved to
model_dir = './model'
estimator = tf.estimator.Estimator(model_fn, model_dir)
estimator.train(train_input_fn, max_steps=max_steps)
estimator.evaluate(eval_input_fn)
请注意,如果您使用估算器,变量将在训练后保存,因此您不需要每次都 re-train。如果要重置,只需删除 model_dir.
我正在构建一个简单的神经网络,它采用 3 个值并提供 2 个输出。
我的准确率为 67.5%,平均成本为 0.05
我有一个包含 1000 个示例和 500 个测试示例的训练数据集。我计划在不久的将来制作更大的数据集。
不久前我设法得到了大约 82% 的准确率,有时甚至更高,但成本很高。
我一直在尝试添加模型中当前存在的另一层,这就是我的损失低于 1.0 的原因
我不确定出了什么问题,总的来说我是 Tensorflow 和 NN 的新手。
这是我的代码:
import tensorflow as tf
import numpy as np
import sys
sys.path.insert(0, '.../Dataset/Testing/')
sys.path.insert(0, '.../Dataset/Training/')
#other files
from TestDataNormaliser import *
from TrainDataNormaliser import *
learning_rate = 0.01
trainingIteration = 10
batchSize = 100
displayStep = 1
x = tf.placeholder("float", [None, 3])
y = tf.placeholder("float", [None, 2])
#layer 1
w1 = tf.Variable(tf.truncated_normal([3, 4], stddev=0.1))
b1 = tf.Variable(tf.zeros([4]))
y1 = tf.matmul(x, w1) + b1
#layer 2
w2 = tf.Variable(tf.truncated_normal([4, 4], stddev=0.1))
b2 = tf.Variable(tf.zeros([4]))
#y2 = tf.nn.sigmoid(tf.matmul(y1, w2) + b2)
y2 = tf.matmul(y1, w2) + b2
w3 = tf.Variable(tf.truncated_normal([4, 2], stddev=0.1))
b3 = tf.Variable(tf.zeros([2]))
y3 = tf.nn.sigmoid(tf.matmul(y2, w3) + b3) #sigmoid
#output
#wO = tf.Variable(tf.truncated_normal([2, 2], stddev=0.1))
#bO = tf.Variable(tf.zeros([2]))
a = y3 #tf.nn.softmax(tf.matmul(y2, wO) + bO) #y2
a_ = tf.placeholder("float", [None, 2])
#cost function
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y * tf.log(a)))
#cross_entropy = -tf.reduce_sum(y*tf.log(a))
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cross_entropy)
#training
init = tf.global_variables_initializer() #initialises tensorflow
with tf.Session() as sess:
sess.run(init) #runs the initialiser
writer = tf.summary.FileWriter(".../Logs")
writer.add_graph(sess.graph)
merged_summary = tf.summary.merge_all()
for iteration in range(trainingIteration):
avg_cost = 0
totalBatch = int(len(trainArrayValues)/batchSize) #1000/100
#totalBatch = 10
for i in range(batchSize):
start = i
end = i + batchSize #100
xBatch = trainArrayValues[start:end]
yBatch = trainArrayLabels[start:end]
#feeding training data
sess.run(optimizer, feed_dict={x: xBatch, y: yBatch})
i += batchSize
avg_cost += sess.run(cross_entropy, feed_dict={x: xBatch, y: yBatch})/totalBatch
if iteration % displayStep == 0:
print("Iteration:", '%04d' % (iteration + 1), "cost=", "{:.9f}".format(avg_cost))
#
print("Training complete")
predictions = tf.equal(tf.argmax(a, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(predictions, "float"))
print("Accuracy:", accuracy.eval({x: testArrayValues, y: testArrayLabels}))
我看到你在最后一层使用了带有 sigmoidal 激活函数的 softmax 损失。现在让我解释一下softmax激活和sigmoidal的区别。
您现在允许网络的输出为 y=(0, 1)、y=(1, 0)、y=(0, 0) 和 y=(1, 1)。这是因为您的 S 形激活 "squish" y 中的每个元素都在 0 和 1 之间。但是,您的损失函数假设您的 y 向量总和为 1。
这里你需要做的是惩罚sigmoidal交叉熵函数,它看起来像这样:
-tf.reduce_sum(y*tf.log(a))-tf.reduce_sum((1-y)*tf.log(1-a))
或者,如果你想将 a 求和为 1,你需要在最后一层使用 softmax 激活(以获得你的 a)而不是像这样实现的 sigmoids
exp_out = tf.exp(y3)
a = exp_out/tf reduce_sum(exp_out)
Ps。我在火车上使用我的 phone,所以请原谅打字错误
一些重要说明:
- 你的图层之间没有 non-linearities。这意味着您正在训练一个相当于 single-layer 网络的网络,只是浪费了大量的计算。这很容易通过添加一个简单的 non-linearity 来解决,例如tf.nn.relu 在每个 matmul/+ 偏置线之后,例如y2 = tf.nn.relu(y2) 对于最后一层的所有栏。
- 您正在使用数值不稳定的交叉熵实现。我鼓励您使用 tf.nn.sigmoid_cross_entropy_with_logits,并删除您的显式 sigmoid 调用(您的 sigmoid 函数的输入通常称为 logits,或 'logistic units')。
- 看来您并没有随意打乱数据集。考虑到您选择的优化器,这可能会特别糟糕,这会导致我们...
- 随机梯度下降不是很好。为了在不增加太多复杂性的情况下获得提升,请考虑改用 MomentumOptimizer。 AdamOptimizer 是我的 go-to,但请使用它们。
在编写干净、可维护的代码时,我还鼓励您考虑以下几点:
- 使用更高级别的 API,例如tf.layers。很高兴您知道在变量级别发生了什么,但是所有复制的代码很容易出错,并且层实现的默认值通常非常好
- 考虑使用 tf.data.Dataset API 作为数据输入。一开始有点吓人,但它处理了很多事情,比如批处理、洗牌、重复纪元等。非常好
- 考虑使用 tf.estimator.Estimator API 之类的东西来处理会话运行、摘要编写和评估。 通过所有这些更改,您可能会得到如下所示的内容(我已将您的代码留在其中,因此您可以大致看到等效的行)。
对于图形构建:
def get_logits(features):
"""tf.layers API is cleaner and has better default values."""
# #layer 1
# w1 = tf.Variable(tf.truncated_normal([3, 4], stddev=0.1))
# b1 = tf.Variable(tf.zeros([4]))
# y1 = tf.matmul(x, w1) + b1
x = tf.layers.dense(features, 4, activation=tf.nn.relu)
# #layer 2
# w2 = tf.Variable(tf.truncated_normal([4, 4], stddev=0.1))
# b2 = tf.Variable(tf.zeros([4]))
# y2 = tf.matmul(y1, w2) + b2
x = tf.layers.dense(x, 4, activation=tf.nn.relu)
# w3 = tf.Variable(tf.truncated_normal([4, 2], stddev=0.1))
# b3 = tf.Variable(tf.zeros([2]))
# y3 = tf.nn.sigmoid(tf.matmul(y2, w3) + b3) #sigmoid
# N.B Don't take a non-linearity here.
logits = tf.layers.dense(x, 1, actiation=None)
# remove unnecessary final dimension, batch_size * 1 -> batch_size
logits = tf.squeeze(logits, axis=-1)
return logits
def get_loss(logits, labels):
"""tf.nn.sigmoid_cross_entropy_with_logits is numerically stable."""
# #cost function
# cross_entropy = tf.reduce_mean(-tf.reduce_sum(y * tf.log(a)))
return tf.nn.sigmoid_cross_entropy_with_logits(
logits=logits, labels=labels)
def get_train_op(loss):
"""There are better options than standard SGD. Try the following."""
learning_rate = 1e-3
# optimizer = tf.train.GradientDescentOptimizer(learning_rate)
optimizer = tf.train.MomentumOptimizer(learning_rate)
# optimizer = tf.train.AdamOptimizer(learning_rate)
return optimizer.minimize(loss)
def get_inputs(feature_data, label_data, batch_size, n_epochs=None,
shuffle=True):
"""
Get features and labels for training/evaluation.
Args:
feature_data: numpy array of feature data.
label_data: numpy array of label data
batch_size: size of batch to be returned
n_epochs: number of epochs to train for. None will result in repeating
forever/until stopped
shuffle: bool flag indicating whether or not to shuffle.
"""
dataset = tf.data.Dataset.from_tensor_slices(
(feature_data, label_data))
dataset = dataset.repeat(n_epochs)
if shuffle:
dataset = dataset.shuffle(len(feature_data))
dataset = dataset.batch(batch_size)
features, labels = dataset.make_one_shot_iterator().get_next()
return features, labels
对于会话 运行,您可以像以前那样使用它(我称之为 'the hard way')...
features, labels = get_inputs(
trainArrayValues, trainArrayLabels, batchSize, n_epochs, shuffle=True)
logits = get_logits(features)
loss = get_loss(logits, labels)
train_op = get_train_op(loss)
init = tf.global_variables_initializer()
# monitored sessions have the `should_stop` method, which works with datasets
with tf.train.MonitoredSession() as sess:
sess.run(init)
while not sess.should_stop():
# get both loss and optimizer step in the same session run
loss_val, _ = sess.run([loss, train_op])
print(loss_val)
# save variables etc, do evaluation in another graph with different inputs?
但我认为您最好使用 tf.estimator.Estimator,尽管有些人更喜欢 tf.keras.Models。
def model_fn(features, labels, mode):
logits = get_logits(features)
loss = get_loss(logits, labels)
train_op = get_train_op(loss)
predictions = tf.greater(logits, 0)
accuracy = tf.metrics.accuracy(labels, predictions)
return tf.estimator.EstimatorSpec(
mode=mode, loss=loss, train_op=train_op,
eval_metric_ops={'accuracy': accuracy}, predictions=predictions)
def train_input_fn():
return get_inputs(trainArrayValues, trainArrayLabels, batchSize)
def eval_input_fn():
return get_inputs(
testArrayValues, testArrayLabels, batchSize, n_epochs=1, shuffle=False)
# Where variables and summaries will be saved to
model_dir = './model'
estimator = tf.estimator.Estimator(model_fn, model_dir)
estimator.train(train_input_fn, max_steps=max_steps)
estimator.evaluate(eval_input_fn)
请注意,如果您使用估算器,变量将在训练后保存,因此您不需要每次都 re-train。如果要重置,只需删除 model_dir.