Python-使用tensorflow时精度低,损失小

Python-使用tensorflow时精度低,损失小,python,tensorflow,loss-function,cross-entropy,Python,Tensorflow,Loss Function,Cross Entropy,我正在建立一个简单的神经网络,它接受3个值,给出2个输出 我得到了67.5%的准确率和0.05的平均成本 我有1000个示例和500个测试示例的培训数据集。我计划在不久的将来制作一个更大的数据集 不久前,我设法获得了约82%的准确率,有时甚至更高,但成本相当高 我一直在尝试添加另一个层,该层当前在模型中,这就是我将损失降低到1.0以下的原因 我不确定到底出了什么问题,我对Tensorflow和NNs都是新手 这是我的密码: import tensorflow as tf import numpy

我正在建立一个简单的神经网络,它接受3个值,给出2个输出

我得到了67.5%的准确率和0.05的平均成本

我有1000个示例和500个测试示例的培训数据集。我计划在不久的将来制作一个更大的数据集

不久前,我设法获得了约82%的准确率,有时甚至更高,但成本相当高

我一直在尝试添加另一个层,该层当前在模型中,这就是我将损失降低到1.0以下的原因

我不确定到底出了什么问题,我对Tensorflow和NNs都是新手

这是我的密码:

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

我看到您在最后一层中使用了带S形激活函数的softmax loss。现在让我解释一下softmax激活和sigmoidal之间的区别

现在允许网络的输出为y=(0,1)、y=(1,0)、y=(0,0)和y=(1,1)。这是因为你的乙状结肠激活“挤压”y中0到1之间的每个元素。然而,损失函数假设y向量和为1

这里需要做的是惩罚S形交叉熵函数,如下所示:

-tf.reduce_sum(y*tf.log(a))-tf.reduce_sum((1-y)*tf.log(1-a))
或者,如果你想把a和变成一,你需要在你的最后一层中使用softmax激活(以获得a),而不是像这样实现的sigmoids

exp_out = tf.exp(y3)
a = exp_out/tf reduce_sum(exp_out)

另外,我正在火车上使用我的手机,所以请原谅我的打字错误。我看到您在最后一层使用带S形激活功能的softmax loss。现在让我解释一下softmax激活和sigmoidal之间的区别

现在允许网络的输出为y=(0,1)、y=(1,0)、y=(0,0)和y=(1,1)。这是因为你的乙状结肠激活“挤压”y中0到1之间的每个元素。然而,损失函数假设y向量和为1

这里需要做的是惩罚S形交叉熵函数,如下所示:

-tf.reduce_sum(y*tf.log(a))-tf.reduce_sum((1-y)*tf.log(1-a))
或者,如果你想把a和变成一,你需要在你的最后一层中使用softmax激活(以获得a),而不是像这样实现的sigmoids

exp_out = tf.exp(y3)
a = exp_out/tf reduce_sum(exp_out)
另外,我正在火车上使用手机,请原谅我的打字错误。请注意以下几点:

  • 层之间没有非线性。这意味着您正在训练一个网络,它相当于一个单层网络,只是浪费了大量的计算。通过在每个matmul/+偏置线之后添加一个简单的非线性,例如tf.nn.relu,例如,最后一层的所有棒的y2=tf.nn.relu(y2),可以很容易地解决这一问题
  • 您正在使用数值上不稳定的交叉熵实现。我鼓励您将tf.nn.sigmoid\u cross\u entropy\u与\u logits一起使用,并删除显式sigmoid调用(sigmoid函数的输入通常被称为logits或“logistic units”)
  • 看起来您并没有在移动数据集时对其进行洗牌。考虑到您选择的优化器,这可能会特别糟糕,这导致我们
  • 随机梯度下降不是很好。在不增加太多复杂度的情况下,可以考虑使用动量优化器。AdamOptimizer是我的目标,但要和他们一起玩
当编写清洁、可维护代码时,我也鼓励您考虑以下内容:

  • 使用更高级别的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
对于会话运行,您可以像以前一样使用它(我称之为“艰难之路”)

但我认为最好使用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)
注意:如果使用估计器,变量将在训练后保存,因此不需要每次重新训练。如果要重置,只需删除模型目录。

一些重要注意事项:

  • 层之间没有非线性。这意味着您正在训练一个网络,它相当于一个单层网络,只是浪费了大量的计算。通过在每个matmul/+偏置线之后添加一个简单的非线性,例如tf.nn.relu,例如,最后一层的所有棒的y2=tf.nn.relu(y2),可以很容易地解决这一问题
  • 您正在使用数值上不稳定的交叉熵实现。我鼓励您将tf.nn.sigmoid\u cross\u entropy\u与\u logits一起使用,并删除显式sigmoid调用(sigmoid函数的输入通常被称为logits或“logistic units”)
  • 看起来您并没有在移动数据集时对其进行洗牌。考虑到您选择的优化器,这可能会特别糟糕,这导致我们
  • 随机梯度下降不是很好。在不增加太多复杂度的情况下,可以考虑使用动量优化器。AdamOptimizer是我的目标,但要和他们一起玩
当编写清洁、可维护代码时,我也鼓励您考虑以下内容:

  • 使用更高级别的API,例如tf.layers。很好,您知道在可变级别上发生了什么,但是很容易在所有复制的代码中出错,并且层实现的默认值通常相当好
  • 考虑使用tf.data.Dataset API进行数据输入。一开始有点吓人,但这是徒手的