我用python(v3.8.3)编写了一个简单的CNN。我试图优化网络,我想要更多关于它未能预测的信息。我试图添加一个混淆矩阵,我需要tensorflow.math.confusion_matrix()测试标签。
我的问题是,我无法弄清楚如何从tf.keras.preprocessing.image创建的数据集对象访问标签_dataset_from_directory()
我的图像被组织在具有标签作为名称的目录中。留档表示函数返回tf.data.Dataset对象。
If label_mode is None, it yields float32 tensors of shape (batch_size, image_size[0], image_size[1], num_channels), encoding
图像(有关num_channels的规则见下文)。否则,它会生成一个元组(图像、标签),其中图像具有形状(batch_size、image_size[0]、image_size[1]、num_channels),标签遵循下面描述的格式。
代码如下:
import tensorflow as tf
from tensorflow.keras import layers
#import matplotlib.pyplot as plt
import numpy as np
import random
import PIL
import PIL.Image
import os
import pathlib
#load the IMAGES
dataDirectory = '/p/home/username/tensorflow/newBirds'
dataDirectory = pathlib.Path(dataDirectory)
imageCount = len(list(dataDirectory.glob('*/*.jpg')))
print('Image count: {0}\n'.format(imageCount))
#test display an image
# osprey = list(dataDirectory.glob('OSPREY/*'))
# ospreyImage = PIL.Image.open(str(osprey[random.randint(1,100)]))
# ospreyImage.show()
# nFlicker = list(dataDirectory.glob('NORTHERN FLICKER/*'))
# nFlickerImage = PIL.Image.open(str(nFlicker[random.randint(1,100)]))
# nFlickerImage.show()
#set parameters
batchSize = 32
height=224
width=224
(trainData, trainLabels) = tf.keras.preprocessing.image_dataset_from_directory(
dataDirectory,
labels='inferred',
label_mode='categorical',
validation_split=0.2,
subset='training',
seed=324893,
image_size=(height,width),
batch_size=batchSize)
testData = tf.keras.preprocessing.image_dataset_from_directory(
dataDirectory,
labels='inferred',
label_mode='categorical',
validation_split=0.2,
subset='validation',
seed=324893,
image_size=(height,width),
batch_size=batchSize)
#class names and sampling a few images
classes = trainData.class_names
testClasses = testData.class_names
#plt.figure(figsize=(10,10))
# for images, labels in trainData.take(1):
# for i in range(9):
# ax = plt.subplot(3, 3, i+1)
# plt.imshow(images[i].numpy().astype("uint8"))
# plt.title(classes[labels[i]])
# plt.axis("off")
# plt.show()
#buffer to hold the data in memory for faster performance
autotune = tf.data.experimental.AUTOTUNE
trainData = trainData.cache().shuffle(1000).prefetch(buffer_size=autotune)
testData = testData.cache().prefetch(buffer_size=autotune)
#augment the dataset with zoomed and rotated images
#use convolutional layers to maintain spatial information about the images
#use max pool layers to reduce
#flatten and then apply a dense layer to predict classes
model = tf.keras.Sequential([
#layers.experimental.preprocessing.RandomFlip('horizontal', input_shape=(height, width, 3)),
#layers.experimental.preprocessing.RandomRotation(0.1),
#layers.experimental.preprocessing.RandomZoom(0.1),
layers.experimental.preprocessing.Rescaling(1./255, input_shape=(height, width, 3)),
layers.Conv2D(16, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(32, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(128, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(256, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
# layers.Conv2D(512, 3, padding='same', activation='relu'),
# layers.MaxPooling2D(),
#layers.Conv2D(1024, 3, padding='same', activation='relu'),
#layers.MaxPooling2D(),
#dropout prevents overtraining by not allowing each node to see each datapoint
#layers.Dropout(0.5),
layers.Flatten(),
layers.Dense(512, activation='relu'),
layers.Dense(len(classes))
])
model.compile(optimizer='adam',
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.summary()
epochs=2
history = model.fit(
trainData,
validation_data=testData,
epochs=epochs
)
#create confusion matrix
predictions = model.predict_classes(testData)
confusionMatrix = tf.math.confusion_matrix(labels=testClasses, predictions=predictions).numpy()
我试过使用(foo,foo1)=tf。克拉斯。预处理。图像\u数据集\u来自\u目录(dataDirectory等),但我得到(trainData,trainLabels)=tf。克拉斯。预处理。来自\u目录的图像\u数据集\u(值错误:要解压缩的值太多(应为2个)
如果我尝试作为一个变量返回,然后将其拆分为:
train = tf.keras.preprocessing.image_dataset_from_directory(
dataDirectory,
labels='inferred',
label_mode='categorical',
validation_split=0.2,
subset='training',
seed=324893,
image_size=(height,width),
batch_size=batchSize)
trainData = train[0]
trainLabels = train[1]
我得到TypeError:“BatchDataset”对象不可下标
我可以访问标签通过testClass=testData.class_names,但我得到:
2020-11-03 14:15:14.643300: W tenstorflow/core/框架/op_kernel.cc:1740]OP_REQUIRES在cast_op.cc:121失败:未实现:不支持将字符串转换为int64 Traceback(最近的调用最后): File"birdFake.py", line 115, inConfusionMatrix=tf.math.confusion_matrix(标签=测试类,预测=预测). Numpy()File"/p/home/username/minicon da3/lib/python3.8/site-包/tensorflow/python/util/dispatch.py",第201行,在包装器返回目标(*args,**kwargs)File"/p/home/username/minicon da3/lib/python3.8/site-packages/tensorflow/python/ops/confusion_matrix.py",第159行,在confusion_matrix标签=math_ops.cast(标签,dtypes.int64)File"/p/home/username/minicon da3/lib/python3.8/site-包/tenstorflow/python/util/dispatch.py",第201行,在包装器返回目标(*args,**kwargs)File"/p/home/username/minicon da3/lib/python3.8/site-pack/tenorflow/python/ops/math_ops.py",第966行,在铸x=gen_math_ops.cast(x,base_type,name=name)File"/p/home/username/miniconda3/lib/python3.8/site-packages/tensorflow/python/ops/gen_math_ops.py",第1827行,_ops.raise_from_not_ok_status(e,name)File"/p/home/username/minicon da3/lib/python3.8/site-包/tenstorflow/python/框架/ops.py",第6862行,raise_from_not_ok_statussix.raise_from(core._status_to_exception(e.code,消息),无)File",第3行,raise_fromtensorflow.python.framework.errors_impl。不支持将字符串转换为int64[Op: Cast]
我对任何将这些标签放入混淆矩阵的方法都持开放态度。任何关于为什么我所做的事情不起作用的想法也将受到赞赏。
更新:我尝试了Alexandre Catalano提出的方法,我得到了以下错误
Traceback(最近的调用最后): File"./birdFake.py",第118行,在标签=np.concatenate([标签,np.argmax(y.numpy(),轴=-1)])File"
我打印了标签数组的第一个元素,它是零
如果我是你,我将迭代整个测试数据,我将保存预测和标签,并在最后构建混淆矩阵。
testData = tf.keras.preprocessing.image_dataset_from_directory(
dataDirectory,
labels='inferred',
label_mode='categorical',
seed=324893,
image_size=(height,width),
batch_size=32)
predictions = np.array([])
labels = np.array([])
for x, y in testData:
predictions = np.concatenate([predictions, model.predict_classes(x)])
labels = np.concatenate([labels, np.argmax(y.numpy(), axis=-1)])
tf.math.confusion_matrix(labels=labels, predictions=predictions).numpy()
结果是
Found 4 files belonging to 2 classes.
array([[2, 0],
[2, 0]], dtype=int32)
修改自Alexandre Catalano的帖子:
predictions = np.array([])
labels = np.array([])
for x, y in test_ds:
predictions = np.concatenate([predictions, **np.argmax**(model.predict(x), axis = -1)])
labels = np.concatenate([labels, np.argmax(y.numpy(), axis=-1)])
您需要使用np。两组的argmax
这是2021的作品。
# Neah it does not, some debugging revealed:
# Credit: (with corrections and debugging)
# https://stackoverflow.com/questions/64687375/get-labels-from-dataset-when-using-tensorflow-image-dataset-from-directory
# predictions = np.array([])
test_labels = np.array([])
# counter = 0
for x, y in test_unshuffled:
# predictions = np.argmax(model.predict(x), axis = -1) #np.concatenate([predictions, np.argmax(model.predict(x), axis = -1)])
# print(f'prediction: {predictions}, size of {len(predictions)}')
# print(f'y label: {y.numpy()}, size of {len(y.numpy())}') #labels = np.concatenate([labels, np.argmax(y.numpy(), axis=-1)])
test_labels = np.concatenate([test_labels, y.numpy()])
# counter += 1
# if counter > 1:
# break
# with the final code:
test_predicted_labels = np.argmax(classes_predicted_unshuffled, axis=1)
test_predicted_labels.shape # sanity check
test_labels = np.array([])
for x, y in test_unshuffled:
test_labels = np.concatenate([test_labels, y.numpy()])
test_labels.shape # sanity check better match test_predicted_labels