Neural Network Minimize Function - java

I created a simple neural network; in order to actually train it, I would need to know in which direction the weights and biases need to be tweaked. I've read some articles on the topic, but I'm not exactly great at math and the only thing I understood was that the cost functions (which I managed to get working) need to be minimized. It would be great if someone could at least tell me in theory how this works. If required, I could also post more of the code. The minimize function should in the end replace evolve():
import java.util.Random;
public class Neuron {
Neuron[] input;
float[] weight;
float bias;
Float value = null;
public Neuron(Neuron[] input) {
this.input = input;
weight = new float[input.length];
setRandom();
}
public void setValue(float val) {
this.value = val;
}
public float getValue() {
if(this.value == null) {
return calculate();
}
else {
return this.value;
}
}
private float calculate() {
float res = 0;
for(int i = 0; i < input.length; i++) {
res += input[i].getValue() * weight[i];
}
res -= bias;
return sigmoid(res);
}
private void setRandom() {
Random rand = new Random();
float max = 0;
for(int i = 0; i < weight.length; i++) {
weight[i] = rand.nextFloat();
max += weight[i];
}
this.bias = max * 0.8f - rand.nextFloat();
}
public void evolve() {
Random rand = new Random();
for(int i = 0; i < weight.length; i++) {
weight[i] += rand.nextFloat() - 0.5f;
}
this.bias += rand.nextFloat() - 0.5f;
}
public static float sigmoid(float x) {
return (float)(1/( 1 + Math.pow(Math.E,(-1*(double)x))));
}
}

Cost function is basically a function of the difference between the real datapoints and your predictions (i.e. it's your penalty). Say for argument's sake, your neural network is f(x) = 2x + 1. Now, say your observed real datapoint is x = 1, y = 4. Therefore your prediction (f(1)) is 3.
If your cost function is the absolute difference between actual observed value and prediction i.e. |f(x) - y| the value of your cost function is 1 (for x = 1) and you would need to minimize this cost function. However, if your cost function is 100 - |f(x) - y| you would want to maximize it. In this cost function your maximum reward is 100.
So your weights and bias need to move in the direction that would get you closer to minimizing your penalty and maximizing your reward. The closer your prediction is to the observed dataset value, the higher the reward and smaller the penalty.
Notes:
This is a gross oversimplification of the math involved but it should help you get started. Also read about overfitting in machine learning.
For understanding machine learning theory Cross Validated would be better forum.

Related

How do you introduce probability in your Java methods – in a flexible and concise fashion?

I've been learning Java for only about a week and a half. At this point, the only way I could think of to include an element of randomness in my code is to use the Random class's nextInt method. Below is a portion of my method:
Random random = new Random();
int randomInt = random.nextInt(10)+1;
[...]
if(randomInt <= 3){
System.out.println("Magnificent!");
} else if (randomInt >= 7){
System.out.println("Marvelous!");
} else {
System.out.println("Delectable!");
}
However, it's wordy and lacks flexibility. I would like to be able to distribute pieces of total probability of 1 to different scenarios in a concise way: thing A happens with a probability of 0.3, thing B happens with a probability of, say, 0.5, thing С happens with a probability of 0.2. How could I achieve that?
In a general case, you have a set of weighted values, which can produce a random value based on a probability which is its weight as fraction of the total weights. The weights can be normalized (meaning their sum is 1), or non-normalized, which is the easier assumption.
When rolling a random value out of that set, it's most efficient to check for the values with the highest probability first. Roll a random number between 0 and the total weight, then go through the values in order of their weight (descending), and check if the random number is lower than the cumulative weight -> if so, return that value.
Code:
public class WeightedRandom<T> {
private final Comparator<WeightedValue<T>> byWeight =
Comparator.comparing(wv -> wv.weight);
private final Set<WeightedValue<T>> weightedValues =
new TreeSet<>(byWeight.reversed());
private double totalWeight;
void put(double weight, T value) {
if (weight <= 0) {
return;
}
totalWeight += weight;
weightedValues.add(new WeightedValue<>(weight, value));
}
public T next() {
if (weightedValues.isEmpty()) {
throw new NoSuchElementException();
}
double rnd = ThreadLocalRandom.current().nextDouble(totalWeight);
double sum = 0;
Iterator<WeightedValue<T>> iterator = weightedValues.iterator();
WeightedValue<T> result;
do {
result = iterator.next();
sum += result.weight;
} while (rnd > sum && iterator.hasNext());
return result.value;
}
private static class WeightedValue<T> {
final double weight;
final T value;
public WeightedValue(double weight, T value) {
this.weight = weight;
this.value = value;
}
}
}
Example:
public static void main(String[] args) {
WeightedRandom<String> random = new WeightedRandom<>();
random.put(3, "AAA");
random.put(2, "BBB");
random.put(5, "CCC");
for (int i = 0; i < 1000; i++) {
String value = random.next();
System.out.println(value);
}
}
Usually, you're going to use Random.nextDouble(), and test e.g. random.nextDouble() < 0.3 to have a probability of 0.3.
To test more than one possibility, you will need to sum some things, e.g
double r = random.nextDouble();
if (r < 0.3) {
...0.3 probability
} else if (r < 0.8) {
...0.5 probability
} else {
...0.2 probability
}

Optimisation in Java Using Apache Commons Math

I'm trying to minimise a value in Java usingcommons-math. I've had a look at their documentation but I don't really get how to implement it.
Basically, in my code below, I have a Double which has the expected goals in a soccer match and I'd like to optimise the probability value of under 3 goals occurring in a game to 0.5.
import org.apache.commons.math3.distribution.PoissonDistribution;
public class Solver {
public static void main(String[] args) {
final Double expectedGoals = 2.9d;
final PoissonDistribution poissonGoals = new PoissonDistribution(expectedGoals);
Double probabilityUnderThreeGoals = 0d;
for (int score = 0; score < 15; score++) {
final Double probability =
poissonGoals.probability(score);
if (score < 3) {
probabilityUnderThreeGoals = probabilityUnderThreeGoals + probability;
}
}
System.out.println(probabilityUnderThreeGoals); //prints 0.44596319855718064, I want to optimise this to 0.5
}
}
The cumulative probability (<= x) of a Poisson random variable can be calculated by:
In your case, x is 2 and you want to find lambda (the mean) such that this is 0.5. You can type this into WolframAlpha and have it solve it for you. So rather than an optimisation problem, this is just a root-finding problem (though one could argue that optimisation problems are just finding roots.)
You can also do this with Apache Commons Maths, with one of the root finders.
int maximumGoals = 2;
double expectedProbability = 0.5;
UnivariateFunction f = x -> {
double sum = 0;
for (int i = 0; i <= maximumGoals; i++) {
sum += Math.pow(x, i) / CombinatoricsUtils.factorialDouble(i);
}
return sum * Math.exp(-x) - expectedProbability;
};
// the four parameters that "solve" takes are:
// the number of iterations, the function to solve, min and max of the root
// I've put some somewhat sensible values as an example. Feel free to change them
double answer = new BisectionSolver().solve(Integer.MAX_VALUE, f, 0, maximumGoals / expectedProbability);
System.out.println("Solved: " + answer);
System.out.println("Cumulative Probability: " + new PoissonDistribution(answer).cumulativeProbability(maximumGoals));
This prints:
Solved: 2.674060344696045
Cumulative Probability: 0.4999999923623868

Belt Collision Time Calculation

Mr. Dis and Mr. Aster are mechanical engineers at Fiasco Iron Works.
They were assigned to design roadways for automated trolleys to carry
the iron ores across the smelting plants. They were supposed to make
two circular roadways for the automated trolleys. However, by mistake
Mr Dis and Mr Aster made the circular roadways tangential to each
other (i.e. the two circular paths touch each other at a point).
Every morning at 0800 hrs the trolleys start at the point of tangency
and move clockwise in their respective tracks. It is quite obvious
that at some point the trolleys would collide at the point from where
they started. In a desperate attempt to save the trolleys and the
damage caused to the operations of the plant, the Chief Engineer of
the plant has requested you to write a program that will sound a
hooter 10 seconds before the collision such that the foreman can stop
the trolleys in order to avoid the collision. Write a program to
find out the time lapsed (in seconds) before the hooter should go off.
public static int timeLapsed(int perimeter1, int speed1, int perimeter2, int speed2) {
int greater,smaller;
int result = 0;
if(perimeter1 > perimeter2) {
greater = perimeter1;
smaller = perimeter2;
} else {
greater = perimeter2;
smaller = perimeter1;
}
for(int i=1;i<=smaller;i++) {
if(((greater*i)%smaller)==0) {
result = greater*i;
break;
}
}
return result/speed1-10;
}
Here, I am trying to calculate the distance before collision which is basically am LCM operation and then division by speed. But this is failing for some of the cases.Please help me understand why.
The belt having greater perimeter is considered for calculating the distance it covers before collision. So the speed can not be chosen arbitrarily, it should be of the belt having greater perimeter.
Changes
public static int timeLapsed(int perimeter1, int speed1, int perimeter2, int speed2) {
int greater,smaller;
int speed, result = 0;
if(perimeter1 > perimeter2) {
greater = perimeter1;
smaller = perimeter2;
speed = speed1;
} else {
greater = perimeter2;
smaller = perimeter1;
speed = speed2;
}
for(int i=1;i<=smaller;i++) {
if(((greater*i)%smaller)==0) {
result = greater*i;
break;
}
}
return result/speed-10;
}
Another alternative approach, calculate the LCM of time taken by both belts which would be the time of collision.
public static int timeLapsed(int perimeter1, int speed1, int perimeter2, int speed2) {
int timeForTrolley1 = perimeter1/speed1,timeForTrolley2 = perimeter2/speed2;
int greater,smaller;
int result = 0;
if(timeForTrolley1 > timeForTrolley2) {
greater = timeForTrolley1;
smaller = timeForTrolley2;
} else {
greater = timeForTrolley2;
smaller = timeForTrolley1;
}
for(int i=1;i<=smaller;i++) {
if(((greater*i)%smaller)==0) {
result = greater*i;
break;
}
}
return result-10;
}

Getting different results each time I run FFT with Processing and Beads

I am using Processing 3 with the Beads library in order to analyse a number of samples but each time I run the analysis on the same data, I get very different results. Here's the sample and analysis setup:
import beads.*;
import org.jaudiolibs.beads.*;
AudioContext ac;
GranularSamplePlayer sample;
Gain gain;
ShortFrameSegmenter sfs;
FFT fft;
PowerSpectrum ps;
Frequency f;
SpectralPeaks sp;
float[][] meanHarmonics;
int numPeaks = 6;
void setup() {
size(1600, 900);
ac = new AudioContext();
ac.start();
println(dataPath("") + "1.wav");
sample = new GranularSamplePlayer(ac, SampleManager.sample(dataPath("") + "\\1.wav"));
gain = new Gain(ac, 1, 1);
// input chaining
gain.addInput(sample);
ac.out.addInput(gain);
// setup analysis
// break audio into more manageable chunks
sfs = new ShortFrameSegmenter(ac);
sfs.addInput(sample);
// fast fourier transform to analyse the harmonic spectrum
fft = new FFT();
sfs.addListener(fft);
// PowerSpectrum turns the raw FFT output into proper audio data.
ps = new PowerSpectrum();
fft.addListener(ps);
// Frequency tries to determine the strongest frequency in the wave
// which is the fundamental that determines the pitch of the sound
f = new Frequency(44100.0f);
ps.addListener(f);
// Listens for harmonics
sp = new SpectralPeaks(ac, numPeaks);
ps.addListener(sp);
meanHarmonics = new float[numPeaks][2];
// initialise meanHarmonics
for(int i = 0; i < numPeaks; i++) {
for(int j = 0; j < 2; j++) {
meanHarmonics[i][j] = 0;
}
}
ac.out.addDependent(sfs);
int startTime = millis();
int loops = 0;
float meanFrequency = 0.0;
while(millis() - startTime < 1500) {
loops++;
if(loops == 1) {
sample.start(0);
}
Float inputFrequency = f.getFeatures();
if(inputFrequency != null) {
meanFrequency += inputFrequency;
}
float[][] harmonics = sp.getFeatures();
if(harmonics != null) {
for(int feature = 0; feature < numPeaks; feature++) {
// harmonic must be in human audible range
// and its amplitude must be large enough to be audible
if(harmonics[feature][0] < 20000.0 && harmonics[feature][1] > 0.01) {
// average out the frequencies
meanHarmonics[feature][0] += harmonics[feature][0];
// average out the amplitudes
meanHarmonics[feature][1] += harmonics[feature][1];
}
}
}
}
float maxAmp = 0.0;
float freq = 0.0;
sample.pause(true);
meanFrequency /= loops;
println(meanFrequency);
for(int feature = 0; feature < numPeaks; feature++) {
meanHarmonics[feature][0] /= loops;
meanHarmonics[feature][1] /= loops;
if(meanHarmonics[feature][1] > maxAmp) {
freq = meanHarmonics[feature][0];
maxAmp = meanHarmonics[feature][1];
}
println(meanHarmonics[feature][0] + " " + meanHarmonics[feature][1]);
}
println(freq + " " + meanFrequency);
println();
}
I run FFT for a set amount of time during which I sum the frequency returned by the Frequency object and the SpectralPeaks features.
At the end I divide accumulated frequencies and amplitudes to obtain the means. I also try to find the fundamental frequency in the SpectralPeaks array by finding the frequency with the largest amplitude.
But every time I run my program I get a different result, both from SpectralPeaks and Frequency(and their values also differ from each other).
Here are some example values:
1st run:
Spectral Peaks features:
914.84863 0.040409338
844.96295 0.033234257
816.0808 0.027509697
664.9141 0.022158746
633.3232 0.019597264
501.93716 0.01606628
Spectral Peaks fundamental: 914.84863
Frequency: 1028.1572
2nd run, same sample:
Spectral Peaks features:
1023.4123 0.03913592
1109.2562 0.031178929
967.0786 0.026673868
721.2698 0.021666735
629.9294 0.018046249
480.82416 0.014858524
Spectral Peaks fundamental: 1023.4123
Frequency: 1069.3387
Also, the value returned by Frequency is often NaN, I don't understand why that is.
The reason why your code returns different values is because it is sampling and analyzing the audio at different moments. Once you start playing the audio, you have no control when Float inputFrequency = f.getFeatures(); gets executed.
A better approach is not to use millis() and replace the while loop with a for loop, and use ac.runForMillisecondsNonRealTime(). This way you get know exactly that you performing the analysis for a 1500 milliseconds.
//while(millis() - startTime < 1500) {
for(int i = 0; i < numPeaks; i++) {
ac.runForNMillisecondsNonRealTime(1500/numPeaks);
Float inputFrequency = f.getFeatures();
if(inputFrequency != null) {
meanFrequency += inputFrequency;
}
float[][] harmonics = sp.getFeatures();
if(harmonics != null) {
for(int feature = 0; feature < numPeaks; feature++) {
// harmonic must be in human audible range
// and its amplitude must be large enough to be audible
if(harmonics[feature][0] < 20000.0 && harmonics[feature][1] > 0.01) {
// average out the frequencies
meanHarmonics[feature][0] += harmonics[feature][0];
// average out the amplitudes
meanHarmonics[feature][1] += harmonics[feature][1];
}
}
}
}

Implementing exponential moving average in Java

I essentially have an array of values like this:
0.25, 0.24, 0.27, 0.26, 0.29, 0.34, 0.32, 0.36, 0.32, 0.28, 0.25, 0.24, 0.25
The above array is oversimplified, I'm collecting 1 value per millisecond in my real code and I need to process the output on an algorithm I wrote to find the closest peak before a point in time. My logic fails because in my example above, 0.36 is the real peak, but my algorithm would look backwards and see the very last number 0.25 as the peak, as there's a decrease to 0.24 before it.
The goal is to take these values and apply an algorithm to them which will "smooth" them out a bit so that I have more linear values. (ie: I'd like my results to be curvy, not jaggedy)
I've been told to apply an exponential moving average filter to my values. How can I do this? It's really hard for me to read mathematical equations, I deal much better with code.
How do I process values in my array, applying an exponential moving average calculation to even them out?
float[] mydata = ...
mySmoothedData = exponentialMovingAverage(mydata, 0.5);
float[] exponentialMovingAverage(float[] input, float alpha) {
// what do I do here?
return result;
}
To compute an exponential moving average, you need to keep some state around and you need a tuning parameter. This calls for a little class (assuming you're using Java 5 or later):
class ExponentialMovingAverage {
private double alpha;
private Double oldValue;
public ExponentialMovingAverage(double alpha) {
this.alpha = alpha;
}
public double average(double value) {
if (oldValue == null) {
oldValue = value;
return value;
}
double newValue = oldValue + alpha * (value - oldValue);
oldValue = newValue;
return newValue;
}
}
Instantiate with the decay parameter you want (may take tuning; should be between 0 and 1) and then use average(…) to filter.
When reading a page on some mathmatical recurrence, all you really need to know when turning it into code is that mathematicians like to write indexes into arrays and sequences with subscripts. (They've a few other notations as well, which doesn't help.) However, the EMA is pretty simple as you only need to remember one old value; no complicated state arrays required.
I am having a hard time understanding your questions, but I will try to answer anyway.
1) If your algorithm found 0.25 instead of 0.36, then it is wrong. It is wrong because it assumes a monotonic increase or decrease (that is "always going up" or "always going down"). Unless you average ALL your data, your data points---as you present them---are nonlinear. If you really want to find the maximum value between two points in time, then slice your array from t_min to t_max and find the max of that subarray.
2) Now, the concept of "moving averages" is very simple: imagine that I have the following list: [1.4, 1.5, 1.4, 1.5, 1.5]. I can "smooth it out" by taking the average of two numbers: [1.45, 1.45, 1.45, 1.5]. Notice that the first number is the average of 1.5 and 1.4 (second and first numbers); the second (new list) is the average of 1.4 and 1.5 (third and second old list); the third (new list) the average of 1.5 and 1.4 (fourth and third), and so on. I could have made it "period three" or "four", or "n". Notice how the data is much smoother. A good way to "see moving averages at work" is to go to Google Finance, select a stock (try Tesla Motors; pretty volatile (TSLA)) and click on "technicals" at the bottom of the chart. Select "Moving Average" with a given period, and "Exponential moving average" to compare their differences.
Exponential moving average is just another elaboration of this, but weights the "older" data less than the "new" data; this is a way to "bias" the smoothing toward the back. Please read the Wikipedia entry.
So, this is more a comment than an answer, but the little comment box was just to tiny. Good luck.
Take a look at this.
If your noise has zero average, consider also the use of a Kalman filter.
In a rolling manner.... i also use commons.apache math library
public LinkedList EMA(int dperiods, double alpha)
throws IOException {
String line;
int i = 0;
DescriptiveStatistics stats = new SynchronizedDescriptiveStatistics();
stats.setWindowSize(dperiods);
File f = new File("");
BufferedReader in = new BufferedReader(new FileReader(f));
LinkedList<Double> ema1 = new LinkedList<Double>();
// Compute some statistics
while ((line = in.readLine()) != null) {
double sum = 0;
double den = 0;
System.out.println("line: " + " " + line);
stats.addValue(Double.parseDouble(line.trim()));
i++;
if (i > dperiods)
for (int j = 0; j < dperiods; j++) {
double var = Math.pow((1 - alpha), j);
den += var;
sum += stats.getElement(j) * var;
System.out.println("elements:"+stats.getElement(j));
System.out.println("sum:"+sum);
}
else
for (int j = 0; j < i; j++) {
double var = Math.pow((1 - alpha), j);
den += var;
sum += stats.getElement(j) * var;
}
ema1.add(sum / den);
System.out.println("EMA: " + sum / den);
}
return ema1;
}
public class MovingAvarage {
public static void main(String[] args) {
double[] array = {1.2, 3.4, 4.5, 4.5, 4.5};
double St = 0D;
for(int i=0; i<array.length; i++) {
St = movingAvarage(St, array[i]);
}
System.out.println(St);
}
private static double movingAvarage(double St, double Yt) {
double alpha = 0.01, oneMinusAlpha = 0.99;
if(St <= 0D) {
St = Yt;
} else {
St = alpha*Yt + oneMinusAlpha*St;
}
return St;
}
}
If you're having trouble with the math, you could go with a simple moving average instead of exponential. So the output you get would be the last x terms divided by x. Untested pseudocode:
int data[] = getFilled();
int outdata[] = initializeme()
for (int y = 0; y < data.length; y++)
int sum = 0;
for (int x = y; x < y-5; x++)
sum+=data[x];
outdata[y] = sum / 5;
Note that you will need to handle the start and end parts of the data since clearly you can't average the last 5 terms when you are on your 2nd data point. Also, there are more efficient ways of calculating this moving average(sum = sum - oldest + newest), but this is to get the concept of what's happening across.

Categories