[英]One class classification using Keras and Python
我正在尝试制作一个一类分类卷积神经网络。 一类是指我有一个图像数据集,其中包含大约 200 张 Nicolas Cage 的图像。 通过一类分类,我的意思是查看图像并预测 1 如果此图像中包含 Nicolas Cage 并预测 0 Nicolas Cage 不包含在图像中。
我绝对是一个机器学习/深度学习初学者,所以我希望有更多知识和经验的人可以帮助指导我朝着正确的方向前进。 这是我现在的问题和问题。 我的网络表现非常糟糕。 我试过用 Nicolas Cage 的图像进行一些预测,每次都预测为 0。
这是我使用名为 google-images-download 的包收集的数据集外观的屏幕截图。 它包含大约 200 张尼古拉斯凯奇的图像。 我做了两次搜索以下载 500 张图片。 手动清理图像后,我只剩下 200 张 Nic Cage 质量的图片。 数据集
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Activation
classifier = Sequential()
classifier.add(Conv2D(32, (3, 3), input_shape = (200, 200, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size=(2, 2)))
classifier.add(Conv2D(64, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size=(2, 2)))
classifier.add(Flatten())
classifier.add(Dense(units = 64, activation = 'relu'))
classifier.add(Dropout(0.5))
# output layer
classifier.add(Dense(1))
classifier.add(Activation('sigmoid'))
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory('/Users/ginja/Desktop/Code/Nic_Cage/Small_Dataset/train/',
target_size = (200, 200),
batch_size = 32,
class_mode = "binary")
test_set = test_datagen.flow_from_directory('/Users/ginja/Desktop/Code/Nic_Cage/Small_Dataset/test/',
target_size = (200, 200),
batch_size = 32,
class_mode = "binary")
history = classifier.fit_generator(training_set,
steps_per_epoch = 1000,
epochs = 25,
validation_data = test_set,
validation_steps = 500)
Epoch 1/25
1000/1000 [==============================] - 1395s 1s/step - loss: 0.0012 - acc: 0.9994 - val_loss: 1.0000e-07 - val_acc: 1.0000
Epoch 2/25
1000/1000 [==============================] - 1350s 1s/step - loss: 1.0000e-07 - acc: 1.0000 - val_loss: 1.0000e-07 - val_acc: 1.0000
Epoch 3/25
1000/1000 [==============================] - 1398s 1s/step - loss: 1.0000e-07 - acc: 1.0000 - val_loss: 1.0000e-07 - val_acc: 1.0000
Epoch 4/25
1000/1000 [==============================] - 1342s 1s/step - loss: 1.0000e-07 - acc: 1.0000 - val_loss: 1.0000e-07 - val_acc: 1.0000
Epoch 5/25
1000/1000 [==============================] - 1327s 1s/step - loss: 1.0000e-07 - acc: 1.0000 - val_loss: 1.0000e-07 - val_acc: 1.0000
Epoch 6/25
1000/1000 [==============================] - 1329s 1s/step - loss: 1.0000e-07 - acc: 1.0000 - val_loss: 1.0000e-07 - val_acc: 1.0000
.
.
.
该模型看起来像收敛到 1.0000e-07 的损失值,因为这在其余的 epoch 中不会改变
from keras.preprocessing import image
import numpy as np
test_image = image.load_img('/Users/ginja/Desktop/Code/Nic_Cage/nic_cage_predict_1.png', target_size = (200, 200))
#test_image.show()
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
result = classifier.predict(test_image)
training_set.class_indices
if result[0][0] == 1:
prediction = 'This is Nicolas Cage'
else:
prediction = 'This is not Nicolas Cage'
print(prediction)
我们每次都得到“这不是尼古拉斯凯奇”的预测。 我感谢任何花时间阅读本文的人,我感谢在这方面的任何帮助。
如果有人从谷歌找到这个,我想通了。 我做了几件事:
flow_from_directory
它按字母数字顺序读取文件夹。 所以目录中的第一个文件夹将是“0”类。 我花了太长时间才弄明白。path = "/Users/ginja/Desktop/Code/Nic_Cage/Random_images"
for i in range(200):
url = "https://picsum.photos/200/200/?random"
response = requests.get(url)
if response.status_code == 200:
file_name = 'not_nicolas_{}.jpg'.format(i)
file_path = path + "/" + file_name
with open(file_path, 'wb') as f:
print("saving: " + file_name)
f.write(response.content)
我在 flow_from_directory 中添加了shuffle = True
作为参数来洗牌我们的图像,让我们的网络更好地泛化
我现在的训练准确度为 99%,测试准确度为 91%,我能够成功预测 Nicolas Cage 的图像!
每个人都倾向于二元分类方法。 这可能是一个解决方案,但消除了可能是用一类分类器解决它的基本设计目标。 根据您想用一类分类器实现的目标,它可能是一个病态问题。 根据我的经验,你的最后一点经常适用。
如https://arxiv.org/pdf/1801.05365.pdf 中所述:
在经典的多类分类中,学习特征的目的是最大化类之间的类间距离并最小化类内的类内方差 [2]。 然而,在没有多个类的情况下,这种区分方法是不可能的。
它产生了一个简单的解决方案。 原因稍后解释:
这种方法最终产生一个简单解决方案的原因是由于损失函数中没有考虑到网络判别能力的正则化项。 例如,由于所有类别标签都相同,因此可以通过使所有权重为零来获得零损失。 确实,在只有普通椅子对象存在的封闭世界中,这是一个有效的解决方案。 但是这样的网络在出现异常椅子物体时的判别能力为零
请注意,这里的描述是关于尝试使用一类分类器来解决不同的类。 一类分类器的另一个有用目标是检测例如工厂操作信号中的异常。 这就是我目前正在做的工作。 在这种情况下,很难获得有关各种损坏状态的知识。 破坏机器只是为了看看它在损坏时如何运行以便可以制作一个体面的多项式分类器是荒谬的。 以下描述了该问题的一种解决方案: https : //arxiv.org/abs/1912.12502 。 请注意,在本文中,由于类的随机相似性,也实现了类的判别能力。
我发现通过遵循所描述的指南,特别是删除最后一个激活函数,我的一类分类器可以工作,并且准确度没有给出 0 值。 请注意,在您的情况下,您可能还想删除二进制交叉熵,因为这需要二进制输入才能有意义(使用 RMSE)。
这种方法也适用于您的情况。 在这种情况下,网络将能够确定哪些照片在数值上远离训练照片类。 然而,根据我的经验,由于图片中包含的差异,例如不同的背景、角度等,这可能仍然是一个难以解决的问题......为此,我解决的问题要容易得多,因为有更多的相似性同一工况阶段的工况之间。 打个比方,在我的例子中,训练班更像是同一张图片,但噪音水平不同,物体只有轻微的运动。
将您的问题视为监督问题:
您正在解决人脸识别问题。 如果您想区分“尼古拉斯凯奇”或任何其他随机图像,您的问题是二元分类问题。 对于二元分类,您需要有一个标签为 0 的类或不是“尼古拉斯凯奇”类。
如果我举一个非常著名的例子,那就是 Hotdog-Not-Hotdog 问题(硅谷)。 这些链接可能对您有所帮助。
https://github.com/J-Yash/Hotdog-Not-Hotdog/blob/master/Hotdog_classifier_transfer_learning.ipynb
将您的问题视为无监督问题:
在这里,您可以将图像表示为嵌入向量。 将您的 Nicolas Cage 图像传递到一个预训练的 facenet 中,该 facenet 将为您提供面部嵌入并绘制该嵌入以查看每个图像之间的关系。
https://paperswithcode.com/paper/facenet-a-unified-embedding-for-face
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.