<p>Everyone leans towards a binary classification approach. This may be a solution but removes the fundamental design objective which may be to solve it with a one class classifier.
Depending on what you want to achieve with a one-class classifier it can be an ill-conditioned problem.
In my experience, your last point often applies.</p>
<p>As mentioned in <a href="https://arxiv.org/pdf/1801.05365.pdf" rel="nofollow noreferrer">https://arxiv.org/pdf/1801.05365.pdf</a>:</p>
<blockquote>
<p>In  the  classical multiple-class   classification,   features   are   learned   with   the objective of maximizing inter-class distances between classes and minimizing intra-class variances within classes [2]. How-ever, in the absence of multiple classes such a discriminative approach is not possible.</p>
</blockquote>
<p>It yields a trivial solution. The reason why is explained a bit later:</p>
<blockquote>
<p>The reason  why  this  approach  ends  up  yielding  a  trivial  solution is  due  to  the  absence  of  a  regularizing  term  in  the  loss function  that  takes  into  account  the  discriminative  ability  of the network. For example, since all class labels are identical, a zero loss can be obtained by making all weights equal to zero. It is true that this is a valid solution in the closed world where onlynormal chairobjects exist. But such a network has zero discriminative ability whenabnormal chairobjects appear</p>
</blockquote>
<p>Note that the description here is made with regards to attempting to use one class classifiers to solve for different classes. One other useful objective of one class classifiers is to detect anomaly in e.g. factory operation signals. This is what I am currently working on. In such cases, having knowledge regarding the various damage states is very hard to obtain. It would be ridiculous to break a machine just to see how it operates when broken so that a decent multinomial classifier can be made. One solution to the problem is described in the following: <a href="https://arxiv.org/abs/1912.12502" rel="nofollow noreferrer">https://arxiv.org/abs/1912.12502</a>. Note that in this paper, because of the stochastic similarity of the classes, the descriminative capacity of classes is achieved as well.</p>
<p>I found that by following the guidelines described and specially, removing the last activation function, I got my one-class classifier working and the acuraccy did not give 0 values. Note that in your case you may also want to remove to binary-cross entropy since that requires binary inputs to make sense (use RMSE).</p>
<p>This method should also work for your case. In that case the network would be capable of determining which photos are numerically further away from the training photo class. In my experience however, it is likely still a hard problem to solve due to the variance contained in the pictures e.g. different background, angles, etc... To that end, the problem I am solving is much easier as there is much more similarity between operating conditions of the same condition stage. To put that into analogy, in my case the training class is more like the same picture with different noise levels and only slight movements of objects.</p>
One class classification using Keras and Python
<h2>Intro and questions:</h2>
<p>I'm trying to make a one-class classification convolutional neural network. By one-class I mean I have one image dataset containing about 200 images of Nicolas Cage. By one class classification I mean look at an image and predict 1 if Nicolas Cage is contained in this image and predict 0 Nicolas Cage is not contained in the image.</p>
<p>I’m a definitely a machine learning/deep learning beginner so I was hoping someone with some more knowledge and experience could help guide me in the right direction. Here are my issues and questions right now. My network is performing terribly. I’ve tried making a few predictions with images of Nicolas Cage and it predicts 0 every single time.</p>
<ul>
<li>Should I collect more data for this to work? I’m performing data augmentations with a small dataset of 207 images. I was hoping the data augmentations would help the network generalize but I think I was wrong</li>
<li>Should I try tweaking the amount of epochs, step per epoch, val steps, or the optimization algorithm I’m using for gradient descent? I’m using Adam but I was thinking maybe I should try stochastic gradient descent with different learning rates?</li>
<li>Should I add more convolution or dense layers to help my network better generalize and learn?</li>
<li>Should I just stop trying to do one class classification and go to normal binary classification because using a neural network with one class classification is not very feasible? I saw this post here <a href="https://stackoverflow.com/questions/51874969/one-class-classification-with-keras">one class classification with keras</a> and it seems like the OP ended up using an isolation forest. So I guess I could try using some convolutional layers and feed into an isolation forest or an SVM? I could not find a lot of info or tutorials about people using isolation forests with one-class image classification.</li>
</ul>
<hr />
<h2>Dataset:</h2>
<p>Here is a screenshot of what my dataset looks like that I’ve collected use a package called google-images-download. It contains about 200 images of Nicolas Cage. I did two searches to download 500 images. After manually cleaning the images I was down to 200 quality pictures of Nic Cage.
<a href="https://i.stack.imgur.com/c3KKo.png" rel="noreferrer">Dataset</a></p>
<hr />
<h2>The imports and model:</h2>
<pre><code>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'))
</code></pre>
<hr />
<h2>Compiling and image augmentation</h2>
<pre><code>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 = &quot;binary&quot;)

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 = &quot;binary&quot;)
</code></pre>
<hr />
<h3>Fitting the model</h3>
<pre><code>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
.
.
.
</code></pre>
<p>The model looks like it converges to a loss value of 1.0000e-07 as this doesn't change for the rest of the epochs</p>
<hr />
<h2>Training and Test accuracy plotted</h2>
<p><a href="https://i.stack.imgur.com/d5smF.png" rel="noreferrer">Training and Test accuracy</a></p>
<h2>Training and Test loss plotted</h2>
<p><a href="https://i.stack.imgur.com/LyotR.png" rel="noreferrer">Training and Test loss</a></p>
<hr />
<h2>Making the prediction</h2>
<pre><code>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)
</code></pre>
<p>We get 'This is not Nicolas Cage' every single time for the prediction.
I appreciate anyone that takes the time to even read through this and I appreciate any help on any part of this.</p>