我正在尝试创建一个Keras深度学习算法来识别假彩色正射影像中的针叶树和叶子树。我已经提取了大约4 500个被认为是正确的训练/验证图像,例如here和here。现实世界中的像素大小为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')
从第2纪元开始,准确度声称为> 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是否可行?我怀疑我的模型有些过分......
如果有人有时间接受这个,请提前致谢!
答案 0 :(得分:0)
如果你使用softmax,两个类的总和将是1.这意味着你永远不会得到一个"没有树"结果。
但是如果你将激活更改为" sigmoid",那么你可以同时拥有两个零(以及两者都是1)。如果您的模型或数据不是那么好,最终可能会针对针对性的#34;并且"是的叶子"。
您也可以尝试创建三个类的方法,然后返回softmax。 Class1 =针叶树; Class2 = leafed; Class3 =无。
关于您的模特。
嗯,这是一门艺术。只测试很多并阅读成功案例,您将找到最适合该任务的模型。
答案 1 :(得分:0)
我假设您的数据集中只有两个类。因此,我想向您推荐一种名为 channel inhibit softmax 的有趣技术,以便有一个额外的可能类别,您可以阅读here。要使用此类别,您需要将网络中的其他第3个输出添加到softmax
图层,该图层始终等于0
。现在你有两个选择:
您可以从模型中检索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))
现在您可以使用其他不确定的课程重新训练您的模型。
感谢上述解决方案 - 您可以为模型添加不确定性,并检查给定图片是否可能不属于任何类别。