package com.aelitis.azureus.core.neuronal; public class NeuralSpeedLimiter { //in bytes / sec long maxDlSpeed; long maxUlSpeed; long ulSpeed; long dlSpeed; //in ms long minLatency; long maxLatency; long latency; NeuralNetwork neuralNetwork; private boolean dirty; private double currentULTarget = 0.6; double trainingSet[][] = new double[][] { //dl speed, ul speed, latency, no_down_limit, down_limit, no_up_limit, up_limit //no latency => no limits {0.0, 0.0, 0.0, 0.9, 0.9, 0.9, 0.9}, {0.0, 1.0, 0.0, 0.9, 0.9, 0.9, 0.9}, {1.0, 0.0, 0.0, 0.9, 0.9, 0.9, 0.9}, {1.0, 1.0, 0.0, 0.9, 0.9, 0.9, 0.9}, //no download, high upload, mid-high latency => limit upload {0.0, 1.0, 1.0, 0.9, 0.9, 0.1, 0.1}, {0.0, 1.0, 0.3, 0.9, 0.9, 0.1, 0.1}, //no download, high upload, low-mid latency => some limit upload {0.0, 1.0, 0.1, 0.9, 0.9, 0.1, 0.8}, {0.0, 1.0, 0.2, 0.9, 0.9, 0.1, 0.6}, //no upload, high download, mid-high latency => limit download {1.0, 0.0, 1.0, 0.1, 0.5, 0.9, 0.9}, {1.0, 0.0, 0.3, 0.1, 0.6, 0.9, 0.9}, //no upload, high download, low-mid latency => some limit download {1.0, 0.0, 0.1, 0.1, 0.9, 0.9, 0.9}, {1.0, 0.0, 0.2, 0.1, 0.8, 0.9, 0.9}, }; public NeuralSpeedLimiter() { neuralNetwork = new NeuralNetwork(3,4,4); neuralNetwork.setLearningRate(0.05); neuralNetwork.setMomentum(true, 0.9); neuralNetwork.setActivationFunction(new LogisticActivationFunction()); train(); dirty = false; } private void train() { //System.out.println(neuralNetwork); double error = 1.0; int c = 0; while(error > 0.002 && c < 200000) { error = 0; for(int i = 0 ; i <trainingSet.length ; i++) { neuralNetwork.setInput(0, trainingSet[i][0]); neuralNetwork.setInput(1, trainingSet[i][1]); neuralNetwork.setInput(2, trainingSet[i][2]); neuralNetwork.setDesiredOutput(0, trainingSet[i][3]); neuralNetwork.setDesiredOutput(1, trainingSet[i][4]); neuralNetwork.setDesiredOutput(2, trainingSet[i][5]); neuralNetwork.setDesiredOutput(3, trainingSet[i][6]); neuralNetwork.feedForward(); error += neuralNetwork.calculateError(); neuralNetwork.backPropagate(); } error /= trainingSet.length; c++; } } private void resetInput() { try { if(ulSpeed > maxUlSpeed) maxUlSpeed = ulSpeed; if(dlSpeed > maxDlSpeed) maxDlSpeed = dlSpeed; if(latency > maxLatency) maxLatency = latency; if(latency < minLatency) minLatency = latency; double downloadFactor = (double)dlSpeed / maxDlSpeed; double uploadFactor = (double)ulSpeed / maxUlSpeed; double latencyFactor = ((double)latency - (double)minLatency) / maxLatency; neuralNetwork.setInput(0, downloadFactor); neuralNetwork.setInput(1, uploadFactor); neuralNetwork.setInput(2, latencyFactor); dirty = true; } catch(Throwable t) { //Ignore } } private void retrain(double ulTarget) { resetInput(); neuralNetwork.feedForward(); double shouldLimitDownload = neuralNetwork.getOutput(0); double downloadLimit = neuralNetwork.getOutput(1); double downloadFactor = (double)dlSpeed / maxDlSpeed; double uploadFactor = (double)ulSpeed / maxUlSpeed; double latencyFactor = ((double)latency - (double)minLatency) / maxLatency; double error = 1.0; int c = 0; //Only 100 loops at a time while(error > 0.002 && c < 400) { neuralNetwork.setInput(0, downloadFactor); neuralNetwork.setInput(1, uploadFactor); neuralNetwork.setInput(2, latencyFactor); neuralNetwork.setDesiredOutput(0, shouldLimitDownload); neuralNetwork.setDesiredOutput(1, downloadLimit); neuralNetwork.setDesiredOutput(2, 0.9); neuralNetwork.setDesiredOutput(3, ulTarget); neuralNetwork.feedForward(); error = neuralNetwork.calculateError(); neuralNetwork.backPropagate(); c++; } } private void feedForward() { neuralNetwork.feedForward(); dirty = false; double latencyFactor = ((double)latency - (double)minLatency) / maxLatency; if(latencyFactor >= 0.15) { //So, we have a high latency, let's re-train the neural network to lower upload speed in this case currentULTarget = currentULTarget * 0.97; retrain(currentULTarget); } else if(latencyFactor < 0.05) { //So, we have a low latency, let's re-train the neural network to increase upload speed in this case currentULTarget = currentULTarget * 1.02; retrain(currentULTarget); } /*System.out.println("input : " + (double)dlSpeed/maxDlSpeed + ", " + (double)ulSpeed/maxUlSpeed + ", " + ((double)latency-(double)minLatency)/maxLatency); System.out.println("output : " + neuralNetwork.getOutput(0) + ", " + neuralNetwork.getOutput(1) + ", " + neuralNetwork.getOutput(2) + ", " + neuralNetwork.getOutput(3));*/ } public void setMaxDlSpeed(long maxDlSpeed) { if(maxDlSpeed > 0) { this.maxDlSpeed = maxDlSpeed; } resetInput(); } public void setMaxUlSpeed(long maxUlSpeed) { if(maxUlSpeed > 0) { this.maxUlSpeed = maxUlSpeed; } resetInput(); } public void setMinLatency(long minLatency) { if(minLatency >= 0) { this.minLatency = minLatency; } resetInput(); } public void setUlSpeed(long ulSpeed) { if(ulSpeed >= 0) { this.ulSpeed = ulSpeed; } resetInput(); } public void setDlSpeed(long dlSpeed) { if(dlSpeed >= 0) { this.dlSpeed = dlSpeed; } resetInput(); } public void setLatency(long latency) { if(latency >= 0) { this.latency = latency; } resetInput(); } public void setMaxLatency(long maxLatency) { if(maxLatency > 0) { this.maxLatency = maxLatency; } resetInput(); } public boolean shouldLimitDownload() { if(dirty) feedForward(); return neuralNetwork.getOutput(0) < 0.5; } public long getDownloadLimit() { if(dirty) feedForward(); return (long) ( 1.2* maxDlSpeed * neuralNetwork.getOutput(1)); } public boolean shouldLimitUpload() { if(dirty) feedForward(); return neuralNetwork.getOutput(2) < 0.5; } public long getUploadLimit() { if(dirty) feedForward(); return (long) ( 1.2* maxUlSpeed * neuralNetwork.getOutput(3)); } public static void main(String args[]) { new NeuralSpeedLimiter(); } }