<h1>Oscillations</h1>

<p>Those are most definitely connected to the size of your network; each batch coming through changes your neural network considerably as it does not have enough neurons to represent the relationships. </p>

<p>It works fine for one batch, updates the weights for another and changes previously learned connections effectively "unlearning". That's why the loss is also jumpy as the network tries to accommodate to the task you have given it.</p>

<p>Sigmoid activation and it's saturation may be causing you troubles as well (as the gradient is squashed into small region and most gradient updates are zero). Quick fix - use <code>ReLU</code> activation as described below.</p>

<p>Additionally, neural network <strong>does not</strong> care about accuracy, only about minimizing the loss value (which it tries to do most of the time). Say it predicts probabilities: <code>[0.55, 0.55, 0.55, 0.55, 0.45]</code> for classes <code>[1, 1, 1, 1, 0]</code> so it's accuracy is <code>100%</code> but it's pretty uncertain. Now, let's say the next update pushes the network into probabilities predictions: <code>[0.8, 0.8, 0.8, 0.8, 0.55]</code>. In such case, loss would drop, <strong>but so would accuracy</strong>, from <code>100%</code> to <code>80%</code>.</p>

<p><strong>BTW.</strong> You may want to check the scores for logistic regression and see how it performs on this task (so a single layer with output only).</p>

<h1>Some things to consider</h1>

<h2>1. Size of your neural network</h2>

<p>It's always good to start with simple model and grow it bigger if needed (wouldn't advise the other way around). You may want to check on a really small subsample of data (say two/three batches, 160 elements or so) whether your model can learn the relationship between input and output.</p>

<p>In your case I doubt the model will be able to learn those relationships with the size of layers you are providing. Try increasing the size, especially in the earlier layers (maybe <code>50</code>/<code>100</code> for starters) and see how it behaves.</p>

<h2>2. Activation function</h2>

<p>Sigmoid easily saturates (small region where changes occur, most of the values are almost 0 or 1). It is rarely used nowadays as activation before bottleneck (final layer). Most common nowadays is <a href="https://www.tensorflow.org/api_docs/python/tf/keras/activations/relu" rel="noreferrer"><code>ReLU</code></a> which is not prone to saturation (at least when the input is positive) or it's variations. This might help as well.</p>

<h2>3. Learning rate</h2>

<p>For each dataset and each neural network model optimal choice of learning rate is different. Defaults usually work so-so, but when the learning rate is too small it might get stuck in the local minima (and it's generalization will be worse), while the value being too big will make your network unstable (loss will highly oscillate).</p>

<p>You may want to read up on <a href="https://www.datacamp.com/community/tutorials/cyclical-learning-neural-nets" rel="noreferrer">Cyclical Learning Rate</a> (or in the original <a href="https://arxiv.org/abs/1506.01186" rel="noreferrer">research paper by Leslie N. Smith</a>. In there you can find info on how to choose a good learning rate heuristically and setup some simple learning rate schedulers. Those techniques were used by <a href="https://www.fast.ai/" rel="noreferrer">fast.ai</a> teams in CIFAR10 competitions with really good results. On their site <a href="https://docs.fast.ai/callbacks.one_cycle.html" rel="noreferrer">or in documentation of their library</a> you can find <code>One Cycle Policy</code> and learning rate finder (based on the work of aforementioned researcher). This should get you started in this realm I think.</p>

<h2>4. Normalization</h2>

<p>Not sure, but this normalization looks pretty non-standard to me (never seen it done like that). Good normalization is the basis for neural network convergence (unless the data is already pretty close to normal distribution). Usually one subtracts the mean and divides by standard deviation for each feature. You can check some schemes in <a href="https://scikit-learn.org/stable/modules/preprocessing.html" rel="noreferrer"><code>scikit-learn</code> library</a> for example.</p>

<h2>5. Depth</h2>

<p>This shouldn't be an issue but if your input is complicated you should consider adding more layers to your neural network (right now it's almost definitely too thin). This would allow it to learn more abstract features and transform the input space more.</p>

<h1>Overfitting</h1>

<p>When the network overfits to the data you may employ some regularization techniques (hard to tell what might help, you should test it on your own), some of those include:</p>

<ul>
<li>Higher learning rate with batch normalization smoothing out learning space.</li>
<li>Smaller number of neurons (relationships learned by the network would intuitively have to be more data distribution representative).</li>
<li>Smaller batch size have regularization effect as well.</li>
<li>Dropout, though it's hard to pin-point good dropout rate. Would resort to it as the last one. Furthermore it is known to collide with batch normalization techniques (though there are techniques to combine them, see <a href="https://arxiv.org/abs/1801.05134" rel="noreferrer">here</a> or <a href="https://stackoverflow.com/questions/39691902/ordering-of-batch-normalization-and-dropout">here</a>, you may find more over the web).</li>
<li>L1/L2 regularization with the second being much more widely applied (unless you have specific knowledge indicating L1 might perform better)</li>
<li>Data augmentation - I would try this one first, mostly because of curiosity. As your features are continuous you may want to add some random noise on batch-to-batch basis generated from gaussian distribution. Noise would have to be small, standard deviation around <code>1e-2</code> or <code>1e-3</code>, you would have to test those values experimentally.</li>
<li>Early stopping - after <code>N</code> epochs without improvement on the validation set you end your training. Pretty common technique, should be used almost every time. Remember to save the best model on validation set and set <code>patience</code> (<code>N</code> mentioned above) to some moderately sized value (do not set patience to 1 epoch or so, neural network may easily improve after 5 or so).</li>
</ul>

<p>Plus there are tons of other techniques you may find. Check what makes intuitive sense and which one you like the most and test how it performs.</p>
How to correct unstable loss and accuracy during training? (binary classification)
<p>I am currently working on a small binary classification project using the new keras API in tensorflow. The problem is a simplified version of the Higgs Boson challenge posted on Kaggle.com a few years back. The dataset shape is 2000x14, where the first 13 elements of each row form the input vector, and the 14th element is the corresponding label. Here is a sample of said dataset:</p>

<pre><code>86.043,52.881,61.231,95.475,0.273,77.169,-0.015,1.856,32.636,202.068, 2.432,-0.419,0.0,0
138.149,69.197,58.607,129.848,0.941,120.276,3.811,1.886,71.435,384.916,2.447,1.408,0.0,1
137.457,3.018,74.670,81.705,5.954,775.772,-8.854,2.625,1.942,157.231,1.193,0.873,0.824,1
</code></pre>

<p>I am relatively new to machine learning and tensorflow, but I am familiar with the higher level concepts such as loss functions, optimizers and activation functions. I have tried building various models inspired by examples of binary classification problems found online, but I am having difficulties with training the model. During training, the loss somethimes increases within the same epoch, leading to unstable learning. The accuracy hits a plateau around 70%. I have tried changing the learning rate and other hyperparameters but to no avail. In comparison, I have hardcoded a fully-connected feed forward neural net that reaches around 80-85% accuracy on the same problem.</p>

<p>Here is my current model:</p>

<pre><code>import tensorflow as tf
from tensorflow.python.keras.layers.core import Dense
import numpy as np
import pandas as pd

def normalize(array):
    return array/np.linalg.norm(array, ord=2, axis=1, keepdims=True)

x_train = pd.read_csv('data/labeled.csv', sep='\s+').iloc[:1800, :-1].values
y_train = pd.read_csv('data/labeled.csv', sep='\s+').iloc[:1800, -1:].values

x_test = pd.read_csv('data/labeled.csv', sep='\s+').iloc[1800:, :-1].values
y_test = pd.read_csv('data/labeled.csv', sep='\s+').iloc[1800:, -1:].values

x_train = normalize(x_train)
x_test = normalize(x_test)

model = tf.keras.Sequential()
model.add(Dense(9, input_dim=13, activation=tf.nn.sigmoid)
model.add(Dense(6, activation=tf.nn.sigmoid))
model.add(Dense(1, activation=tf.nn.sigmoid))

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=50)
model.evaluate(x_test, y_test)
</code></pre>

<p>As mentionned, some of the epochs start with a higher accuracy than they finish with, leading to unstable learning. </p>

<pre><code>  32/1800 [..............................] - ETA: 0s - loss: 0.6830 - acc: 0.5938
1152/1800 [==================&gt;...........] - ETA: 0s - loss: 0.6175 - acc: 0.6727
1800/1800 [==============================] - 0s 52us/step - loss: 0.6098 - acc: 0.6861
Epoch 54/250

  32/1800 [..............................] - ETA: 0s - loss: 0.5195 - acc: 0.8125
1376/1800 [=====================&gt;........] - ETA: 0s - loss: 0.6224 - acc: 0.6672
1800/1800 [==============================] - 0s 43us/step - loss: 0.6091 - acc: 0.6850
Epoch 55/250
</code></pre>

<p>What could be the cause of these oscillations in learning in such a simple model? 
Thanks</p>

<hr>

<p>EDIT:</p>

<p>I have followed some suggestions from the comments and have modified the model accordingly. It now looks more like this:</p>

<pre><code>model = tf.keras.Sequential()
model.add(Dense(250, input_dim=13, activation=tf.nn.relu))
model.add(Dropout(0.4))
model.add(Dense(200, activation=tf.nn.relu))
model.add(Dropout(0.4))
model.add(Dense(100, activation=tf.nn.relu))
model.add(Dropout(0.3))
model.add(Dense(50, activation=tf.nn.relu))
model.add(Dense(1, activation=tf.nn.sigmoid))

model.compile(optimizer='adadelta',
              loss='binary_crossentropy',
              metrics=['accuracy'])
</code></pre>