Python Keras分类模型

Python Keras分类模型,python,keras,Python,Keras,我正在尝试创建一个Keras深度学习算法,从假彩色正射影像中识别针叶树和树叶树。我提取了大约4500张被认为是正确的培训/验证图像,如和。现实世界中的像素大小是0.5米,所以这些不是真正的高分辨率图像。所有图像都是固定大小的31x31像素。以下模型是谷歌的产品,尤其是Keras自己的文档网站 from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras

我正在尝试创建一个Keras深度学习算法,从假彩色正射影像中识别针叶树和树叶树。我提取了大约4500张被认为是正确的培训/验证图像,如和。现实世界中的像素大小是0.5米,所以这些不是真正的高分辨率图像。所有图像都是固定大小的31x31像素。以下模型是谷歌的产品,尤其是Keras自己的文档网站

from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K

# dimensions of our images.
img_width, img_height = 30, 30

train_data_dir = 'treedata/train'
validation_data_dir = 'treedata/validation'
nb_train_samples = 4000
nb_validation_samples = 533
epochs = 50
batch_size = 16

if K.image_data_format() == 'channels_first':
    input_shape = (3, img_width, img_height)
else:
    input_shape = (img_width, img_height, 3)

model = Sequential()

model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Dropout(0.5))

model.add(Activation('relu'))
model.add(Dense(2)) # number of classes
model.add(Activation('softmax'))

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

# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True)

# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1. / 255)

train_generator = train_datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode='categorical')

validation_generator = test_datagen.flow_from_directory(
    validation_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode='categorical')

model.fit_generator(
    train_generator,
    steps_per_epoch=nb_train_samples // batch_size,
    epochs=epochs,
    validation_data=validation_generator,
    validation_steps=nb_validation_samples // batch_size)

model.save('treetypes.h5')
从第二纪元开始,精度声称大于0.99,损耗小于0.02,我觉得这很奇怪。创建模型后,我尝试通过正射影像确定一个30x30像素的子图像是否包含给定类型的树

import numpy as np
import cv2
from keras.models import load_model
from keras.preprocessing import image

model = load_model('treetypes.h5') 
roi = cv2.imread('roi.jpg')
sy, sx = img.shape[:2]
px_apart = 10 # start sub-images 10 px apart
s = 30 # sub-image size

for starty in range(1, sy-img_height, px_apart):

    for startx in range(1, sx-img_width, px_apart):

        subimg = img[starty:starty+s, startx:startx+s]
        x = image.img_to_array(subimg)
        x = np.expand_dims(x, axis=0)
        is_tree = model.predict(x, batch_size=1, verbose=0) # predict classes
这就是我迷路的地方。首先也是最重要的一点是,似乎没有选择子图像既不是针叶树也不是叶子树(所有子图像都被预测为is_tree=[[0,1]]或is_tree=[[1,0]])。例如,没有预测[[0.1,0.02]],这表明此子图像根本不是树。因此,有两个主要问题:

1) 我是否正确理解了模型应该输出属于第1类(针叶)和第2类(叶状)的概率?为什么它只给出“二进制”结果?我在某个地方读到softmax将概率之和定为1

2) 我的模型几乎可用吗?或者,在给定粗采样分辨率的情况下,使用NN进行此操作是否可行?我怀疑我的模型有点太合适了


如果有人有时间,请提前感谢

如果使用softmax,两个类的总和将为1。这意味着你永远不会得到“没有树”的结果

但是如果您将激活更改为“sigmoid”,那么您可以同时拥有两个零(以及两个1)。如果您的模型或数据不太好,您可能会以“赞成针叶树”和“赞成叶树”结束

您也可以尝试创建三个类,然后返回softmax。类别1=针叶林;类别2=叶状;类别3=无


关于你的模型


嗯,这是一门艺术。只有通过大量测试和阅读成功案例,你才能找到适合这项任务的最佳模式

如果使用softmax,两个类的总和将为1。这意味着你永远不会得到“没有树”的结果

但是如果您将激活更改为“sigmoid”,那么您可以同时拥有两个零(以及两个1)。如果您的模型或数据不太好,您可能会以“赞成针叶树”和“赞成叶树”结束

您也可以尝试创建三个类,然后返回softmax。类别1=针叶林;类别2=叶状;类别3=无


关于你的模型


嗯,这是一门艺术。只有通过大量测试和阅读成功案例,你才能找到适合这项任务的最佳模式

我假设您的数据集中只有两个类。因此,我想向您推荐一种有趣的技术,称为channel inhibited softmax,以便有一个额外的类别,您可以阅读。为了使用此类别,您需要将额外的第三个输出从网络添加到始终等于
0
softmax
层。现在您有两个选择:

  • 您可以从您的模型中检索
    softmax
    的输入,并向其中添加一个人工
    0

    logits_model = Model(model.input, model.layers[-2].output)
    data = logits_model.predict(x)
    final_probs = numpy.exp(x) / (numpy.sum(numpy.exp(x), axis = 1) + 1)
    
    这种方法的优点是,您不需要训练新模型,而是使用现有模型

  • 你可以训练一个新的模型:

    def channel_inhibited_softmax(x):
        e = K.exp(x - K.max(x, axis=1, keepdims=True))
        s = K.sum(e, axis=1, keepdims=True) + K.exp(-K.max(x), axis=1)
        return e / s
    
    model.add(Activation('relu'))
    model.add(Dense(2)) # number of classes
    model.add(Lambda(channel_inhibited_softmax))
    
    现在,您可以使用附加的“不确定”类重新训练您的模型


  • 多亏了上述解决方案,您可以为模型添加不确定性,并检查给定图片是否可能不属于任何类别。

    我假设您的数据集中只有两个类别。因此,我想向您推荐一种有趣的技术,称为channel inhibited softmax,以便有一个额外的类别,您可以阅读。为了使用此类别,您需要将额外的第三个输出从网络添加到始终等于
    0
    softmax
    层。现在您有两个选择:

  • 您可以从您的模型中检索
    softmax
    的输入,并向其中添加一个人工
    0

    logits_model = Model(model.input, model.layers[-2].output)
    data = logits_model.predict(x)
    final_probs = numpy.exp(x) / (numpy.sum(numpy.exp(x), axis = 1) + 1)
    
    这种方法的优点是,您不需要训练新模型,而是使用现有模型

  • 你可以训练一个新的模型:

    def channel_inhibited_softmax(x):
        e = K.exp(x - K.max(x, axis=1, keepdims=True))
        s = K.sum(e, axis=1, keepdims=True) + K.exp(-K.max(x), axis=1)
        return e / s
    
    model.add(Activation('relu'))
    model.add(Dense(2)) # number of classes
    model.add(Lambda(channel_inhibited_softmax))
    
    现在,您可以使用附加的“不确定”类重新训练您的模型

  • 多亏了上面的解决方案,你可以给你的模型添加一个不确定性,并检查给定的图片是否可能不属于任何类别