如何使用Keras处理CNN中的可变大小输入?

Tho*_*rsp 16 python machine-learning neural-network deep-learning keras

我试图在MNIST数据库上执行通常的分类,但随机裁剪的数字.图像按以下方式裁剪:随机删除第一个/最后一个和/或行/列.

我想使用使用Keras(和Tensorflow后端)的卷积神经网络来执行卷积,然后进行通常的分类.

输入的大小可变,我无法让它工作.

这是我如何裁剪数字

import numpy as np
from keras.utils import to_categorical
from sklearn.datasets import load_digits

digits = load_digits()

X = digits.images
X = np.expand_dims(X, axis=3)

X_crop = list()
for index in range(len(X)):
    X_crop.append(X[index, np.random.randint(0,2):np.random.randint(7,9), np.random.randint(0,2):np.random.randint(7,9), :])
X_crop = np.array(X_crop)

y = to_categorical(digits.target)

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X_crop, y, train_size=0.8, test_size=0.2)
Run Code Online (Sandbox Code Playgroud)

这是我想要使用的模型的架构

from keras.layers import Dense, Dropout
from keras.layers.convolutional import Conv2D
from keras.models import Sequential

model = Sequential()

model.add(Conv2D(filters=10, 
                 kernel_size=(3,3), 
                 input_shape=(None, None, 1), 
                 data_format='channels_last'))

model.add(Dense(128, activation='relu'))
model.add(Dropout(0.2))

model.add(Dense(10, activation='softmax'))


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

model.summary()

model.fit(X_train, y_train, epochs=100, batch_size=16, validation_data=(X_test, y_test))
Run Code Online (Sandbox Code Playgroud)
  1. 有人知道如何在我的神经网络中处理可变大小的输入吗?

  2. 以及如何进行分类?

Mar*_*jko 25

TL/DR - 转到第4点

所以 - 在我们谈到这一点之前 - 让我们解决您网络的一些问题:

  1. 由于激活,您的网络将无法运行:categorical_crossentropy您需要softmax激活:

    model.add(Dense(10, activation='softmax'))
    
    Run Code Online (Sandbox Code Playgroud)
  2. 矢量化空间张量:正如丹尼尔所提到的 - 你需要在某个阶段将矢量从空间(图像)切换到矢量化(矢量).目前 - 应用于Densea的输出Conv2D等同于(1, 1)卷积.所以基本上 - 你的网络输出是空间的 - 没有矢量化导致维度不匹配的原因(你可以通过运行你的网络或检查它model.summary()来检查.为了改变它你需要使用GlobalMaxPooling2D或者GlobalAveragePooling2D.例如:

    model.add(Conv2D(filters=10, 
                 kernel_size=(3, 3), 
                 input_shape=(None, None, 1),
                 padding="same",
                 data_format='channels_last'))
    model.add(GlobalMaxPooling2D())
    model.add(Dense(128, activation='relu'))
    model.add(Dropout(0.2))
    
    model.add(Dense(10, activation='softmax'))
    
    Run Code Online (Sandbox Code Playgroud)
  3. 连锁numpy数组需要具有相同的形状:如果你检查形状,X_crop你会发现它不是空间矩阵.这是因为你连接了不同形状的矩阵.可悲的是 - 由于numpy.array需要有固定的形状,所以不可能克服这个问题.

  4. 如何使您的网络训练成为不同形状的例子:这样做最重要的是要理解两件事.首先 - 在一个批次中,每个图像应该具有相同的大小.第二 - fit多次调用是一个坏主意 - 当您重置内部模型状态时.所以这是需要做的事情:

    一个.编写一个单一批次的函数- 例如get_cropped_batches_generator,给定矩阵切割批次并随机裁剪的函数.

    湾 使用train_on_batch方法.这是一个示例代码:

    from six import next
    
    batches_generator = get_cropped_batches_generator(X, batch_size=16)
    losses = list()
    for epoch_nb in range(nb_of_epochs):
        epoch_losses = list()
        for batch_nb in range(nb_of_batches):
            # cropped_x has a different shape for different batches (in general)
            cropped_x, cropped_y = next(batches_generator) 
            current_loss = model.train_on_batch(cropped_x, cropped_y)
            epoch_losses.append(current_loss)
        losses.append(epoch_losses.sum() / (1.0 * len(epoch_losses))
    final_loss = losses.sum() / (1.0 * len(losses))
    
    Run Code Online (Sandbox Code Playgroud)

所以 - 上面代码的一些注释:首先,train_on_batch不使用很好的keras进度条.它返回一个损失值(对于给定的批处理) - 这就是我添加逻辑来计算损失的原因.您也可以使用Progbar回调.第二 - 你需要实现get_cropped_batches_generator- 我还没有编写代码来更清楚地回答我的问题.你可以问另一个关于如何实现它的问题.最后一件事 - 我six用来保持Python 2和之间的兼容性Python 3.