Python - 低精度,低损耗和张量流

时间:2018-03-17 05:59:55

标签: python tensorflow loss-function cross-entropy

我正在构建一个简单的神经网络,它需要3个值并提供2个输出。

我的准确率为67.5%,平均成本为0.05

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

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

我一直在尝试添加另一个当前在模型中的图层,这就是我在1.0以下获得损失的原因

我不确定出了什么问题,我是Tensorflow和NN的新手。

这是我的代码:

ndkBuild

2 个答案:

答案 0 :(得分:2)

一些重要的注意事项:

  • 您的图层之间没有非线性。这意味着您正在训练一个相当于单层网络的网络,只需要浪费大量的计算。这可以通过添加简单的非线性(例如,非线性)来轻松解决。在每个matmul / +偏置线之后的tf.nn.relu,例如, y2 = tf.nn.relu(y2)表示最后一层的所有条形。
  • 您正在使用数值不稳定的交叉熵实现。我鼓励你使用tf.nn.sigmoid_cross_entropy_with_logits,并删除你的显式sigmoid调用(你的sigmoid函数的输入通常被称为logits,或'logistic units')。
  • 您似乎没有随意移动数据集。如果您选择优化器,这可能会特别糟糕,这导致我们......
  • 随机梯度下降不是很好。为了在不增加太多复杂性的情况下进行提升,请考虑使用MomentumOptimizer。 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

对于会话运行,你可以像你一样使用它(我称之为'艰难的方式')......

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)

请注意,如果使用估算器,变量将在训练后保存,因此您不需要每次都重新训练。如果要重置,只需删除model_dir。

答案 1 :(得分:0)

我发现你在最后一层使用了带有S形激活函数的softmax损失。现在让我解释一下softmax激活和sigmoidal之间的区别。

您现在允许网络输出为y =(0,1),y =(1,0),y =(0,0)和y =(1,1)。这是因为你的S形活动"挤压" y中的每个元素在0和1之间。但是,您的损失函数假定您的y向量总和为1。

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

-tf.reduce_sum(y*tf.log(a))-tf.reduce_sum((1-y)*tf.log(1-a))

或者,如果你想要总和为1,你需要在最后一层使用softmax激活(以获得你的a)而不是sigmoids,这是以这样的方式实现的

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

聚苯乙烯。我在火车上使用手机,请原谅错别字