【问题标题】:Feeding a 2D image to a TensorFlow CNN for image classification将 2D 图像馈送到 TensorFlow CNN 以进行图像分类
【发布时间】:2021-12-28 15:27:13
【问题描述】:

感谢您提供帮助。我正在尝试使用 TensorFlow 训练卷积神经网络来预测我的系统的二进制方面。我有大约 1000 个 ndarray,大小为 400x400x3,持有浮动。这类似于(我认为)RGB 图像;我的图像的三个方面不是颜色,而是三个不同功能的输出,但这在这里不重要。这些 ndarray 中的每一个都与一个二进制标签相关联——0 或 1。我是 TensorFlow 的新手,虽然在机器学习原理上相当扎实,所以非常感谢有关解码错误的指导。我认为我排列图层的方式很奇怪,但我尝试非常密切地按照教程进行操作,所以我不知道为什么。

我的代码如下:

no_of_samples = 1035
train_batches = 30
BATCH_SIZE = 23
SHUFFLE_BUFFER_SIZE = 50

data, labels = np.load("total_image_data.npy", allow_pickle=True), np.load("labels.npy", allow_pickle=True)

#divide into test and train sets

train_indices = np.random.choice([i for i in range(no_of_samples)], size=train_batches*BATCH_SIZE)
test_indices = [i for i in range(no_of_samples) if i not in train_indices]

data_train, labels_train = [data[i] for i in train_indices], [labels[i] for i in train_indices]
data_test, labels_test = [data[i] for i in test_indices], [labels[i] for i in test_indices]

train_dataset = tf.data.Dataset.from_tensor_slices((data_train, labels_train))
test_dataset = tf.data.Dataset.from_tensor_slices((data_test, labels_test))

train_dataset = train_dataset.shuffle(SHUFFLE_BUFFER_SIZE).batch(BATCH_SIZE)
test_dataset = test_dataset.batch(BATCH_SIZE)



model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(200, 5, strides=3, activation='relu', input_shape=(BATCH_SIZE, 400, 400, 3)),
    tf.keras.layers.Conv2D(100, 5, strides=2, activation="relu"),
    tf.keras.layers.Conv2D(50, 5, activation="relu"),
    tf.keras.layers.Conv2D(25, 3, activation="relu"),
    tf.keras.layers.MaxPooling2D(3),
    tf.keras.layers.Conv2D(50, 3, activation="relu"),
    tf.keras.layers.Conv2D(25, 3, activation="relu"),
    tf.keras.layers.MaxPooling2D(3),
    tf.keras.layers.Conv2D(50, 2, activation="relu"),
    tf.keras.layers.Conv2D(25, 2, activation="relu"),
    
    tf.keras.layers.GlobalMaxPooling2D(),

    # Finally, we add a classification layer.
    tf.keras.layers.Dense(2)
])

model.compile(optimizer=tf.keras.optimizers.RMSprop(),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['sparse_categorical_accuracy'])

model.fit(labels_train, data_train, epochs=10, batch_size=BATCH_SIZE)

model.evaluate(labels_test, data_test)

我运行时遇到的错误如下:


Traceback (most recent call last):
  File "training.py", line 36, in <module>
    model = tf.keras.Sequential([
  File "/local/**/ac3/lib/python3.8/site-packages/tensorflow/python/training/tracking/base.py", line 530, in _method_wrapper
    result = method(self, *args, **kwargs)
  File "/local/**/ac3/lib/python3.8/site-packages/keras/utils/traceback_utils.py", line 67, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "/local/**/ac3/lib/python3.8/site-packages/keras/engine/input_spec.py", line 213, in assert_input_compatibility
    raise ValueError(f'Input {input_index} of layer "{layer_name}" '
ValueError: Input 0 of layer "max_pooling2d" is incompatible with the layer: expected ndim=4, found ndim=5. Full shape received: (None, 23, 58, 58, 25)

任何帮助解码此内容将不胜感激。

更新:新的令人兴奋的错误!在一些慷慨的社区成员的帮助下,我的代码现在看起来像这样:


import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

no_of_samples = 1035
BATCH_SIZE = 16
SHUFFLE_BUFFER_SIZE = 50

data, labels = np.load("total_image_data.npy", allow_pickle=True), np.load("labels.npy", allow_pickle=True)

print(np.shape(data)) ##this outputs (1035, 400, 400, 3)
print(np.shape(labels)) ##this outputs (1035, )



#divide into test and train sets


dataset = tf.data.Dataset.from_tensor_slices((data, labels)).shuffle(SHUFFLE_BUFFER_SIZE)
test_dataset = dataset.take(100).batch(BATCH_SIZE)
train_dataset = dataset.skip(100).batch(BATCH_SIZE)

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(200, 5, strides=3, activation='relu', input_shape=(400, 400, 3)),
    tf.keras.layers.Conv2D(100, 5, strides=2, activation="relu"),
    tf.keras.layers.Conv2D(50, 5, activation="relu"),
    tf.keras.layers.Conv2D(25, 3, activation="relu"),
    tf.keras.layers.MaxPooling2D(3),
    tf.keras.layers.Conv2D(50, 3, activation="relu"),
    tf.keras.layers.Conv2D(25, 3, activation="relu"),
    tf.keras.layers.MaxPooling2D(3),
    tf.keras.layers.Conv2D(50, 2, activation="relu"),
    tf.keras.layers.Conv2D(25, 2, activation="relu"),
    
    tf.keras.layers.GlobalMaxPooling2D(),

    # Finally, we add a classification layer.
    tf.keras.layers.Dense(1)
])

print('Labels shape -->',labels.shape)
print('Labels -->', labels)

model.compile(optimizer=tf.keras.optimizers.RMSprop(),
              loss=tf.keras.losses.BinaryCrossentropy(),
              metrics=['accuracy'])

model.fit(train_dataset, epochs=10)
model.evaluate(test_dataset)

这编译并运行良好,但报告了 nan 的损失和 58% 的跨时期的不变准确度(我正在寻找的东西的基线流行率为 38%)。再次,我投身于你的怜悯。

【问题讨论】:

  • 您不能将 BATCH_SIZE 放入您的输入定义中:tf.keras.layers.Conv2D(200, 5, strides=3, activation='relu', input_shape=( 400, 400, 3))

标签: python tensorflow keras deep-learning conv-neural-network


【解决方案1】:

我认为您需要更改一些内容:模型的输入形状不需要batch_size,它将在训练期间进行推断。将其更改为(400, 400, 3)。其次,如果您使用二进制标签,则需要将损失函数更改为tf.keras.losses.BinaryCrossentropy,将度量更改为tf.keras.metrics.BinaryAccuracy 或简单的accuracy。此外,您的输出层应该有一个输出节点而不是两个:tf.keras.layers.Dense(1)

这是一个基于您的代码的运行示例:

import numpy as np
import tensorflow as tf

no_of_samples = 250
BATCH_SIZE = 16
SHUFFLE_BUFFER_SIZE = 50

data, labels = np.random.random((no_of_samples, 400, 400, 3)), np.random.randint(2, size=no_of_samples)

dataset = tf.data.Dataset.from_tensor_slices((data, labels)).shuffle(SHUFFLE_BUFFER_SIZE)
test_dataset = dataset.take(50).batch(BATCH_SIZE)
train_dataset = dataset.skip(50).batch(BATCH_SIZE)

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(200, 5, strides=3, activation='relu', input_shape=(400, 400, 3)),
    tf.keras.layers.Conv2D(100, 5, strides=2, activation="relu"),
    tf.keras.layers.Conv2D(50, 5, activation="relu"),
    tf.keras.layers.Conv2D(25, 3, activation="relu"),
    tf.keras.layers.MaxPooling2D(3),
    tf.keras.layers.Conv2D(50, 3, activation="relu"),
    tf.keras.layers.Conv2D(25, 3, activation="relu"),
    tf.keras.layers.MaxPooling2D(3),
    tf.keras.layers.Conv2D(50, 2, activation="relu"),
    tf.keras.layers.Conv2D(25, 2, activation="relu"),
    
    tf.keras.layers.GlobalMaxPooling2D(),

    # Finally, we add a classification layer.
    tf.keras.layers.Dense(1)
])

model.compile(optimizer=tf.keras.optimizers.RMSprop(),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

model.fit(train_dataset, epochs=10, validation_data=test_dataset)
print('Labels shape -->',labels.shape)
print('Labels -->', labels)
Labels shape --> (250,)
Labels --> [1 0 0 0 0 1 0 1 0 1 1 1 0 1 1 0 0 1 0 0 1 0 0 1 0 1 1 0 0 1 1 1 0 1 1 0 0
 0 1 0 1 1 1 0 1 1 1 1 0 0 0 0 0 1 1 1 0 1 1 0 0 0 1 1 0 1 1 0 0 1 1 1 0 0
 1 0 1 1 1 1 1 1 1 1 0 0 1 1 0 1 1 1 1 0 1 1 0 0 0 1 0 1 1 1 0 1 0 1 1 0 1
 1 1 1 1 0 0 0 1 0 0 0 1 1 1 0 1 1 1 0 0 0 1 1 1 0 1 0 1 0 1 1 0 1 0 0 1 0
 1 1 1 1 0 0 1 0 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 0 1 1 0 0 1 1 1 0 0 0 0 1
 0 0 0 0 1 1 0 1 1 1 0 0 0 0 1 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1
 0 0 1 1 1 1 1 0 0 0 1 0 0 1 0 1 1 1 1 1 0 1 1 1 0 1 1 0]

【讨论】:

  • 非常感谢您。我尝试在我的数据上运行您的代码,它产生了以下错误TypeError: Failed to convert elements of &lt;keras.losses.BinaryCrossentropy object at 0x7f819052d3a0&gt; to Tensor. Consider casting elements to a supported type. See https://www.tensorflow.org/api_docs/python/tf/dtypes for supported TF dtypes. 我只能想到两件事:我的标签是整数(?)或与我的输入数据有关的事实你的也是相同形状的ndarrays。这对你来说很明显吗?再次,非常感谢。
  • 检查您的标签是否与我的答案中的标签相似。我把它们贴在了底部。
  • 他们做到了!现在我已经修复了指标,它似乎正在运行——我无法告诉你我有多感激。我唯一有点担心的是我正在看着它运行并且它说'loss = nan'-我应该担心吗?准确性正在改变......
  • 对,损失不应该是nan。如果您复制了我发布的整个代码并且只是调整了数据预处理部分以适合您的数据,那么您的数据一定有问题,因为模型在虚拟数据上运行得非常好。没有看到一切,很难说是什么原因。也许用您当前使用的代码更新您的问题
  • 我不这么认为——我只是在让它运行时返回并检查输出,并且每个时期的损失仍然是 nan。我会再看看我的输入数据并用代码更新我的问题——非常感谢。
【解决方案2】:

当损失达到 nan 时,最简单的解释是你的梯度要么爆炸,要么消失。尝试在优化器上使用梯度裁剪(按值或按范数),这基本上不允许梯度超过或超过某个值。

这也会影响网络的性能,但总比损失 nan 好。

使用您当前的代码,实现将如下所示:

model.compile(optimizer=tf.keras.optimizers.RMSprop(clipvalue=0.5),
              loss=tf.keras.losses.BinaryCrossentropy(),
              metrics=['accuracy'])

该值只是一个示例,如果有效,请尝试稍微调整一下。

【讨论】:

  • 有趣的是,这不起作用。还有其他可能正在做的事情吗?我的输入很奇怪吗?再次非常感谢。
  • 我刚刚意识到,您的输出层没有明确声明的激活函数,因此它默认为线性。对于二元分类,推荐使用 Sigmoid。 tf.keras.layers.Dense(1, activation="sigmoid")我在我的机器上运行它,损失和准确性都没有得到解决
  • 或者..就像已经建议的那样...使用损失函数的from_logits=True 并让损失函数保持线性。
猜你喜欢
  • 2016-04-19
  • 1970-01-01
  • 2017-07-18
  • 1970-01-01
  • 2020-02-09
  • 2021-09-16
  • 2021-05-24
  • 2018-07-23
  • 2020-04-01
相关资源
最近更新 更多