使用Keras和Python的一类分类 介绍和问题:

使用Keras和Python的一类分类 介绍和问题:,python,keras,deep-learning,classification,conv-neural-network,Python,Keras,Deep Learning,Classification,Conv Neural Network,我想做一个单类分类卷积神经网络。我说的一个类是指我有一个图像数据集,其中包含大约200张尼古拉斯·凯奇的图像。通过一类分类,我的意思是看一张图片,如果图片中包含尼古拉斯·凯奇,则预测1,如果图片中不包含尼古拉斯·凯奇,则预测0 我绝对是一个机器学习/深度学习的初学者,所以我希望有更多知识和经验的人能帮助我朝着正确的方向前进。这里是我现在的问题和议题。我的网络运行得很糟糕。我试着用尼古拉斯·凯奇的照片做了一些预测,每次预测都是0 我是否应该收集更多数据以使其发挥作用?我正在用一个由207幅图像组

我想做一个单类分类卷积神经网络。我说的一个类是指我有一个图像数据集,其中包含大约200张尼古拉斯·凯奇的图像。通过一类分类,我的意思是看一张图片,如果图片中包含尼古拉斯·凯奇,则预测1,如果图片中不包含尼古拉斯·凯奇,则预测0

我绝对是一个机器学习/深度学习的初学者,所以我希望有更多知识和经验的人能帮助我朝着正确的方向前进。这里是我现在的问题和议题。我的网络运行得很糟糕。我试着用尼古拉斯·凯奇的照片做了一些预测,每次预测都是0

  • 我是否应该收集更多数据以使其发挥作用?我正在用一个由207幅图像组成的小数据集进行数据扩充。我希望数据增强可以帮助网络的推广,但我认为我错了
  • 我应该尝试调整历元的数量、每历元的步长、val步长,还是我用于梯度下降的优化算法?我用的是Adam,但我想也许我应该尝试不同学习率的随机梯度下降法
  • 我应该添加更多的卷积或密集层来帮助我的网络更好地概括和学习吗
  • 我是否应该停止尝试进行单类分类,转而使用普通的二元分类,因为使用单类分类的神经网络不是很可行?我在这里看到了这篇文章,似乎OP最终使用了一个隔离林。所以我想我可以尝试使用一些卷积层,然后输入隔离林或SVM?我找不到很多关于人们使用带有一类图像分类的隔离林的信息或教程

数据集: 这是我使用一个名为google images download的软件包收集的数据集的屏幕截图。它包含了大约200张尼古拉斯·凯奇的照片。我做了两次搜索,下载了500张图片。在手动清理图像后,我将Nic Cage的质量降至200张。


进口和型号:
编译和图像增强
拟合模型 该模型似乎收敛到了1.0000e-07的损失值,因为这在余下的时间里不会改变


绘制训练和测试精度图

培训和测试损失


预测 我们每次预测都会听到“这不是尼古拉斯·凯奇”。
我感谢所有花时间通读这篇文章的人,也感谢对这篇文章的任何帮助。

将您的问题视为监督问题:

您正在解决人脸识别问题。如果您想区分“尼古拉斯·凯奇”或任何其他随机图像,您的问题是二值分类问题。对于二进制分类,您需要有一个标签为0或不是“Nicolas Cage”类的类

如果我举一个非常著名的例子,那就是热狗问题,而不是热狗问题(硅谷)。 这些链接可能会对您有所帮助


将您的问题视为无监督问题:

在这种情况下,您可以将图像表示为嵌入向量。将你的Nicolas Cage图像传递到预先训练过的facenet中,该facenet将为你提供面部嵌入,并绘制嵌入图,以查看每个图像之间的关系


如果有人从谷歌找到了这个,我就知道了。我做了几件事:

  • 我将随机图像数据集添加到我的训练和测试文件夹中。我基本上增加了一个“0”类。这些图片被标记为“not_nicolas”,我下载了与第一个数据集中相同数量的图片,大约200张。我有200张尼古拉斯·凯奇的照片和200张随机的照片。随机图片是在这个链接中生成的,我刚刚使用python脚本生成了200张图片。确保当您使用
    flow\u from\u directory
    时,它以字母数字顺序读取文件夹。因此,目录中的第一个文件夹将是类“0”。我花了太长时间才弄明白
  • 我将优化器改为随机梯度下降,而不是Adam
  • 我在flow\u from\u目录中添加了
    shuffle=True
    作为一个参数,以洗牌我们的图像,使我们的网络能够更好地概括

    我现在有99%的训练准确率和91%的测试准确率,我能够成功预测尼古拉斯·凯奇的图像


  • 每个人都倾向于采用二进制分类方法。这可能是一个解决方案,但删除了基本的设计目标,该目标可能是使用一类分类器来解决它。 根据您希望使用单类分类器实现什么,这可能是一个病态问题。 根据我的经验,你的最后一点经常适用

    如中所述:

    在经典的多类分类中,特征学习的目标是最大化类之间的类间距离和最小化类内方差[2]。然而,在没有多个类别的情况下,这种区别对待的方法是不可能的

    它产生了一个微不足道的解决方案。稍后将解释原因:

    这种方法最终产生一个平凡的解决方案的原因是,在考虑网络辨别能力的损失函数中没有正则化项。例如,由于所有类标签都是相同的,因此可以通过使所有权重等于零来获得零损失。的确,在只有正常对象存在的封闭世界中,这是一个有效的解决方案。但这样的网络在正常物体出现时没有辨别能力

    注意,这里的描述是关于尝试使用一个类分类器来解决不同类的问题。一类分类器的另一个有用目标
    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
    .
    .
    .
    
    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)
    
    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)