numpy.where 缩小数组维度

numpy.where narrowing array dimensions

我想使用 cifar100 数据集中的一些 类 来训练模型。我使用 numpy where 来过滤数据集,但它缩小了图像数组的尺寸。

import numpy as np
from tensorflow.keras.datasets import cifar100

(x_train, y_train), (x_test, y_test) = cifar100.load_data()
index = np.where((y_train == 1) | (y_train == 2))
print('Images Shape: {}'.format(x_train.shape))
X_train = x_train[index]
Y_train = y_train[index]
print('Images Shape: {}'.format(X_train.shape))

打印:

Images Shape: (50000, 32, 32, 3)

Images Shape: (1000, 32, 3)

到目前为止我尝试了什么:

过滤后我尝试将结果转换为这样的图像形状:

index = np.asarray(index).reshape(x_train.shape[0])

但是我得到这个错误:

ValueError: cannot reshape array of size 2000 into shape (50000,)

我想仅使用来自 cifar100 数据集的 10 类 来训练模型。 这是我的模型:

import numpy as np
from tensorflow.keras.datasets import cifar100
from tensorflow.keras.layers import Conv2D, Flatten, Dense, MaxPool2D
from tensorflow.keras.models import Sequential

model = Sequential()
model.add(Conv2D(16, (3, 3),
                 # strides=(1, 1),
                 activation='relu',
                 padding='same',  # 'valid',
                 input_shape=(32, 32, 3)))
model.add(MaxPool2D((2, 2)))
model.add(Conv2D(32, (3, 3),
                 # strides=(1, 1),
                 activation='relu'))
model.add(MaxPool2D((2, 2)))
model.add(Conv2D(32, (3, 3),
                 # strides=(1, 1),
                 activation='relu'))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(10, activation='softmax'))
model.summary()

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

model.fit(X_train,
          Y_train,
          epochs=5,
          batch_size=64)

here 中的代码是您所需要的:

import tensorflow_datasets as tfds
import tensorflow as tf

def predicate(x, allowed_labels=tf.constant([0., 1., 2.])):
    label = x['label']
    isallowed = tf.equal(allowed_labels, tf.cast(label, tf.float32))
    reduced = tf.reduce_sum(tf.cast(isallowed, tf.float32))
    return tf.greater(reduced, tf.constant(0.))

cifar100_builder = tfds.builder("cifar100")
cifar100_builder.download_and_prepare()
ds_train = cifar100_builder.as_dataset(split="train")
ds_test = cifar100_builder.as_dataset(split="test")

filtered_ds_train=ds_train.filter(predicate)
filtered_ds_test=ds_test.filter(predicate)

我不确定对 y_train 个案例的子集进行培训是否正确。通常训练是在所有案例的 'random' 子集上完成的。 keras 等具有 split 将数据集(Xy 拆分为训练集和测试集的函数。

但是按照我的评论,解释您看到的行为。

有 (n,1) y_train:

In [203]: y = np.arange(10)[:,None]
In [204]: idx = np.nonzero((y<4)|(y>7))
In [205]: idx
Out[205]: (array([0, 1, 2, 3, 8, 9]), array([0, 0, 0, 0, 0, 0]))

nonzero/where returns 索引数组的元组,每个维度一个数组。由于2维为1,所以idx[1]全为0,没有提供任何有用的信息。

当用于索引 4d x_train 时,idx 在第一个维度上选择 6 个值,而在第二个维度上只选择第一个值:

In [206]: x = np.ones((10,2,3,4),int)
In [207]: x[idx].shape
Out[207]: (6, 3, 4)

仅使用第一个数组进行索引保留第二个维度:

In [208]: x[idx[0]].shape
Out[208]: (6, 2, 3, 4)

我不知道你想做什么:

index = np.asarray(index).reshape(x_train.shape[0])

在我的示例中 x.shape[0] 是 10,但 idx[0] 是 (6,)。重塑 idx[0] 没有意义,更不用说两个数组了。

In [209]: np.array(idx)
Out[209]: 
array([[0, 1, 2, 3, 8, 9],
       [0, 0, 0, 0, 0, 0]])