Skip to main content
 首页 » 编程设计

python之使用 Tensorflow 在二元分类中改变准确度值并且不改变损失值

2025年05月04日23findumars

我正在尝试使用深度神经网络架构对二进制标签值进行分类 - 0 和 +1。这是我在 tensorflow 中执行此操作的代码。这个问题也从 previous question 中的讨论中继承

import tensorflow as tf 
import numpy as np 
from preprocess import create_feature_sets_and_labels 
 
train_x,train_y,test_x,test_y = create_feature_sets_and_labels() 
 
x = tf.placeholder('float', [None, 5]) 
y = tf.placeholder('float') 
 
n_nodes_hl1 = 500 
n_nodes_hl2 = 500 
# n_nodes_hl3 = 500 
 
n_classes = 1 
batch_size = 100 
 
def neural_network_model(data): 
 
    hidden_1_layer = {'weights':tf.Variable(tf.random_normal([5, n_nodes_hl1])), 
                      'biases':tf.Variable(tf.random_normal([n_nodes_hl1]))} 
 
    hidden_2_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl1, n_nodes_hl2])), 
                      'biases':tf.Variable(tf.random_normal([n_nodes_hl2]))} 
 
    # hidden_3_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl2, n_nodes_hl3])), 
    #                   'biases':tf.Variable(tf.random_normal([n_nodes_hl3]))} 
 
    # output_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl3, n_classes])), 
    #                   'biases':tf.Variable(tf.random_normal([n_classes]))} 
 
    output_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl2, n_classes])), 
                    'biases':tf.Variable(tf.random_normal([n_classes]))} 
 
 
    l1 = tf.add(tf.matmul(data, hidden_1_layer['weights']), hidden_1_layer['biases']) 
    l1 = tf.nn.relu(l1) 
 
    l2 = tf.add(tf.matmul(l1, hidden_2_layer['weights']), hidden_2_layer['biases']) 
    l2 = tf.nn.relu(l2) 
 
    # l3 = tf.add(tf.matmul(l2, hidden_3_layer['weights']), hidden_3_layer['biases']) 
    # l3 = tf.nn.relu(l3) 
 
    # output = tf.transpose(tf.add(tf.matmul(l3, output_layer['weights']), output_layer['biases'])) 
    output = tf.add(tf.matmul(l2, output_layer['weights']), output_layer['biases']) 
    return output 
 
 
 
def train_neural_network(x): 
    prediction = tf.sigmoid(neural_network_model(x)) 
    cost = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(prediction, y)) 
    optimizer = tf.train.AdamOptimizer().minimize(cost) 
 
    hm_epochs = 10 
 
    with tf.Session() as sess: 
        sess.run(tf.initialize_all_variables()) 
 
        for epoch in range(hm_epochs): 
            epoch_loss = 0 
            i = 0 
            while i < len(train_x): 
                start = i 
                end = i + batch_size 
                batch_x = np.array(train_x[start:end]) 
        batch_y = np.array(train_y[start:end]) 
 
        _, c = sess.run([optimizer, cost], feed_dict={x: batch_x, 
                                              y: batch_y}) 
        epoch_loss += c 
        i+=batch_size 
 
            print('Epoch', epoch, 'completed out of', hm_epochs, 'loss:', epoch_loss) 
 
        # correct = tf.equal(tf.argmax(prediction, 1), tf.argmax(y, 1)) 
        # accuracy = tf.reduce_mean(tf.cast(correct, 'float')) 
        predicted_class = tf.greater(prediction,0.5) 
        correct = tf.equal(predicted_class, tf.equal(y,1.0)) 
        accuracy = tf.reduce_mean( tf.cast(correct, 'float') ) 
 
        # print (test_x.shape) 
        # accuracy = tf.nn.l2_loss(prediction-y,name="squared_error_test_cost")/test_x.shape[0] 
        print('Accuracy:', accuracy.eval({x: test_x, y: test_y})) 
 
train_neural_network(x)  

具体来说,(继承上一个问题的讨论)我删除了一层 - hidden_3_layer 。改变了

prediction = neural_network_model(x)



到

prediction = tf.sigmoid(neural_network_model(x)) 


并根据尼尔的回答添加了 predicted_class, correct, accuracy 部分。我还在我的 csv 中将所有 -1 更改为 0。

这是我的踪迹:
('Epoch', 0, 'completed out of', 10, 'loss:', 37.312037646770477) 
('Epoch', 1, 'completed out of', 10, 'loss:', 37.073578298091888) 
('Epoch', 2, 'completed out of', 10, 'loss:', 37.035196363925934) 
('Epoch', 3, 'completed out of', 10, 'loss:', 37.035196363925934) 
('Epoch', 4, 'completed out of', 10, 'loss:', 37.035196363925934) 
('Epoch', 5, 'completed out of', 10, 'loss:', 37.035196363925934) 
('Epoch', 6, 'completed out of', 10, 'loss:', 37.035196363925934) 
('Epoch', 7, 'completed out of', 10, 'loss:', 37.035196363925934) 
('Epoch', 8, 'completed out of', 10, 'loss:', 37.035196363925934) 
('Epoch', 9, 'completed out of', 10, 'loss:', 37.035196363925934) 
('Accuracy:', 0.42608696) 

如您所见,损失并没有减少。因此我不知道它是否仍然正常工作。

这是多次重新运行的结果。结果摇摆不定:
('Epoch', 0, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 1, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 2, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 3, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 4, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 5, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 6, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 7, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 8, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Epoch', 9, 'completed out of', 10, 'loss:', 26.513012945652008) 
('Accuracy:', 0.60124224) 

其他:
('Epoch', 0, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 1, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 2, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 3, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 4, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 5, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 6, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 7, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 8, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 9, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Accuracy:', 1.0) 

另一个:
('Epoch', 0, 'completed out of', 10, 'loss:', 23.163824260234833) 
('Epoch', 1, 'completed out of', 10, 'loss:', 22.88000351190567) 
('Epoch', 2, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 3, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 4, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 5, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 6, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 7, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 8, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Epoch', 9, 'completed out of', 10, 'loss:', 22.873702049255371) 
('Accuracy:', 0.99627328) 

我还看到了 0.0 的准确度值 -_-

---------------编辑---------------

关于数据和数据处理的一些细节。我正在使用来自 Yahoo! 的 IBM 每日股票数据!融资 20 年(几乎)。这相当于大约 5200 行条目。

这是我处理它的方式:
import numpy as np 
import pandas as pd 
from sklearn.preprocessing import MinMaxScaler 
import csv 
import pickle 
 
def create_feature_sets_and_labels(test_size = 0.2): 
    df = pd.read_csv("ibm.csv") 
    df = df.iloc[::-1] 
    features = df.values 
    testing_size = int(test_size*len(features)) 
    train_x = list(features[1:,1:6][:-testing_size]) 
    train_y = list(features[1:,7][:-testing_size]) 
    test_x = list(features[1:,1:6][-testing_size:]) 
    test_y = list(features[1:,7][-testing_size:]) 
    scaler = MinMaxScaler(feature_range=(-5,5)) 
    train_x = scaler.fit_transform(train_x) 
    train_y = scaler.fit_transform(train_y) 
    test_x = scaler.fit_transform(test_x) 
    test_y = scaler.fit_transform(test_y) 
 
    return train_x, train_y, test_x, test_y 
 
if __name__ == "__main__": 
    train_x, train_y, test_x, test_y = create_feature_sets_and_labels() 
    with open('stockdata.pickle', 'wb') as f: 
        pickle.dump([train_x, train_y, test_x, test_y], f) 

第 0 列是日期。所以这不被用作特征。第 7 列也不是。我使用 sklearn 的 MinMaxScaler() 在 -5 到 5 的范围内对数据进行了标准化。

-------------编辑2-------

我注意到当数据以非标准化形式呈现时,系统不会改变其准确性。

请您参考如下方法:

一旦在 ML 训练任务中将数据预处理为错误的形状或范围,其余的数据流就会出错。您在问题的代码中以不同的方式多次执行此操作。

以事物的顺序进行处理。第一个问题是预处理。你的目标应该是:

  • 表格形式的 X 值(输入特征),每一行是一个示例,每一列是一个特征。值应该是数字并按比例缩放以用于神经网络。测试和训练数据需要以相同的比例缩放 - 这并不意味着使用相同的 .fit_transform因为这重新适合缩放器。
  • 表格形式的 Y 值(输出标签),每一行是匹配 X 的同一行的示例,每一列是输出的真实值。对于分类问题,值通常为 0 和 1,不应重新缩放,因为它们代表类成员。

  • 这重写了你的 create_feature_sets_and_labels函数正确地做事:
    def create_feature_sets_and_labels(test_size = 0.2): 
        df = pd.read_csv("ibm.csv") 
        df = df.iloc[::-1] 
        features = df.values 
        testing_size = int(test_size*len(features)) 
     
        train_x = np.array(features[1:,1:6][:-testing_size]).astype(np.float32) 
        train_y = np.array(features[1:,7][:-testing_size]).reshape(-1, 1).astype(np.float32) 
     
        test_x = np.array(features[1:,1:6][-testing_size:]).astype(np.float32) 
        test_y = np.array(features[1:,7][-testing_size:]).reshape(-1, 1).astype(np.float32) 
     
        scaler = MinMaxScaler(feature_range=(-5,5)) 
     
        scaler.fit(train_x) 
     
        train_x = scaler.transform(train_x) 
        test_x = scaler.transform(test_x) 
     
        return train_x, train_y, test_x, test_y 
    

    与您的版本的重要区别:
  • 使用类型转换 np.array ,而不是 list (细微差别)
  • y 值是表格 [n_examples, n_outputs] (主要区别,你的行向量形状是后来很多问题的原因)
  • Scaler 适合一次,然后应用于特征(主要区别,如果您分别缩放训练和测试数据,您不会预测任何有意义的东西)
  • Scaler 不适用于输出(分类器的主要区别,您希望训练和测试值是 0,1 以获得有意义的训练和报告准确性)

  • 您的此数据的训练代码也存在一些问题:
  • y = tf.placeholder('float')应该是 y = tf.placeholder('float', [None, 1]) .这对处理没有影响,但在 y 时会正确抛出错误。是错误的形状。那个错误会更早地成为事情出错的线索。
  • n_nodes_hl1 = 500和 n_nodes_hl2 = 500可以低得多,并且网络实际上会更好地工作,例如n_nodes_hl1 = 10和 n_nodes_hl2 = 10 - 这主要是因为您对权重使用了较大的初始值,您也可以缩小权重,而对于更复杂的数据,您可能想要这样做。在这种情况下,减少隐藏神经元的数量会更简单。
  • 正如我们在评论中所讨论的,你的 train_neural_network 函数的开始应该是这样的:
    output = neural_network_model(x) 
    prediction = tf.sigmoid(output) 
    cost = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(output, y)) 
    optimizer = tf.train.AdamOptimizer().minimize(cost) 
    

    . . .这是一个主要区别。通过使用 sigmoid_cross_entropy_with_logits您已 promise 使用输出层的预转换值进行训练。但是您仍然希望预测值能够测量准确性(或用于您想要读取预测值的网络的任何其他用途)。
  • 为了获得一致的损失度量,您希望每个示例都有平均损失,因此您需要将每批处理的平均总和除以批处理数:'loss:', epoch_loss/(len(train_x)/batch_size)

  • 如果我进行所有这些更正,然后再运行几个 epoch - 例如50,然后我得到 0.7 的典型损失和 0.5 的准确度度量- 这发生得相当可靠,但由于起始重量的变化确实会移动一点。准确性不是很稳定,并且可能会受到过度拟合的影响,这是您根本不允许的(并且您应该阅读有助于测量和管理过度拟合的技术,这是可靠地训练 NN 的重要部分)
    0.5 的值可能看起来很糟糕。可以通过修改网络架构或元参数来改进它。我可以下到 0.43训练损失和高达 0.83测试准确性,例如通过交换 tf.nn.relu对于 tf.tanh在隐藏层中运行 500 个 epoch。

    要了解有关神经网络的更多信息、训练时要测量的内容以及模型中可能值得更改的内容,您需要更深入地研究该主题。