NeuralTargetingBot

From Robowiki
Revision as of 11:12, 11 August 2017 by Dsekercioglu (talk | contribs) (Wrong copy paste fix)
Jump to navigation Jump to search

Neural Networks

Neural Networks are machine learning systems loosely based on brains. Also they are not very popular in roborumble.

Making a Simple Neural Targeting Bot Using Roboneural

Utilities

Roboneural(There is a link in it's page).

    public static class GunUtils {

        public static double absoluteBearing(Point2D.Double l1, Point2D.Double l2) {
            return Math.atan2(l2.x - l1.x, l2.y - l1.y);
        }

        public static int limit(int min, int val, int max) {
            return Math.max(min, Math.min(val, max));
        }
    }
AbsoluteBearing takes the angle to a point from the source.
Limit limits a number between two numbers.
Variables
    static final int BINS = 51;
    static final int MIDDLE_BIN = 25;
    static final double FIRE_POWER = 1.95;
    int[] splitNum = new int[]{9, 9};
    public static MultiLayerPerceptron mlp = new MultiLayerPerceptron(new int[]{18, BINS},
            new ActivationFunction[]{new Sigmoid()}, 0.2, 1);
    /*
        Creating a MultiLayerPerceptron is easy.
        First is how many cells for the nth layer.
        Second is the activation functions for hidden and output cells.
        Third is learning rate
        Fourth is batch size
     */

    Point2D.Double myLocation = new Point2D.Double();
    Point2D.Double enemyLocation = new Point2D.Double();

    ArrayList<Wave> gfWaves = new ArrayList<>();
    ArrayList<Wave> gfWavesToRemove = new ArrayList<>();

    public static ArrayList<double[]> neuralNetworkInput = new ArrayList<>();
    public static ArrayList<double[]> neuralNetworkOutput = new ArrayList<>();
    
    /*
    For saving past information to train our MLP.
    */

    public void run() { //Radar Stuff and Colors.
        setBodyColor(Color.ORANGE);
        setGunColor(Color.BLUE);
        setRadarColor(Color.CYAN);
        setScanColor(Color.CYAN);
        setAdjustGunForRobotTurn(true);
        setAdjustRadarForGunTurn(true);
        for (;;) {
            turnRadarRightRadians(Double.POSITIVE_INFINITY);
        }
    }


Wave Stuff
    public class Wave {

        double power;
        double velocity;
        double absoluteBearing;
        double distanceTraveled;
        int lateralDirection;
        double mea;
        double binWidth;
        Point2D.Double source;

        double[] input;

        public Wave(Point2D.Double source, double power, double absoluteBearing, int lateralDirection) {
            this.source = (Point2D.Double) source.clone();
            this.power = power;
            this.velocity = 20 - 3 * power;
            this.absoluteBearing = absoluteBearing;
            mea = 8 / velocity;
            binWidth = mea / BINS * 2;
            this.lateralDirection = lateralDirection;
        }

        public int update() {
            distanceTraveled += velocity;
            if (distanceTraveled > source.distance(enemyLocation)) {
                gfWavesToRemove.add(this);//These will be deleted.
                int bin = (int) Math.round(((Utils.normalRelativeAngle(GunUtils.absoluteBearing(source, enemyLocation) - absoluteBearing))
                        / (lateralDirection * binWidth)) + MIDDLE_BIN);
                return GunUtils.limit(0, bin, BINS - 1);//Hit guess factor
            }
            return -1;//If it didn't hit we will know that because of -1.
        }

        public double getFiringAngle(int firingBin) {
            return absoluteBearing + (lateralDirection * binWidth) * (firingBin - MIDDLE_BIN);//Producing a firing angle from a bin
        }
    }
Main code
    public void onScannedRobot(ScannedRobotEvent e) {
        myLocation.setLocation(getX(), getY());//Setting our location
        double absBearing = e.getBearingRadians() + getHeadingRadians();//For radar and targeting
        double distance = e.getDistance(); //For learning enemy location
        enemyLocation.setLocation(myLocation.x + Math.sin(absBearing) * distance,
                myLocation.y + Math.cos(absBearing) * distance);

        setTurnRadarRightRadians(Utils.normalRelativeAngle(absBearing - getRadarHeadingRadians()) * 2);//Locking the radar
        double enemyVelocity = e.getVelocity();
        double enemyLateralVelocity = (enemyVelocity * Math.sin(e.getHeadingRadians() - absBearing));//Some data
        double enemyAdvancingVelocity = (enemyVelocity * -Math.cos(e.getHeadingRadians() - absBearing));//Some data
        int enemyLateralDirection = enemyLateralVelocity >= 0 ? 1 : -1;

         //Don't forget to normalise the data between 0-1. FeatureSplitter works like that.
        double[] data = new double[]{Math.abs(enemyLateralVelocity), enemyAdvancingVelocity / 16 + 0.5};//Normal Data
        double[] preprocessedData = dsekercioglu.roboneural.format.FeatureSplitter.split(data, splitNum);
        //Preprocessing the data to make it more useful for small networks.

        Wave w = new Wave(myLocation, FIRE_POWER, absBearing, enemyLateralDirection);//Creating a wave
        w.input = preprocessedData;
        gfWaves.add(w);

        int firingBin = dsekercioglu.roboneural.format.Utils.getBin(mlp.getOutput(preprocessedData));//Getting the bestBin
        double firingAngle = w.getFiringAngle(firingBin);
        setTurnGunRightRadians(Utils.normalRelativeAngle(firingAngle - getGunHeadingRadians()));
        setFire(FIRE_POWER);
        train(); //For training the network
        updateWaves(); //For updating the waves
    }
Updating the Waves and Training Our MultiLayerPerceptron
    public void updateWaves() {
        for (Wave w : gfWaves) {
            int result = w.update();
            if (result != -1) { //Here we use the -1 to understand if the wave hit or didn't.
                neuralNetworkInput.add(0, w.input); //We add to the beginning to make training easier.
                double[] bins = new double[BINS];
                bins[result] = 1;//We set the correct gf. Others are zero initially.
                neuralNetworkOutput.add(0, bins); //Adding it.
            }
        }
        gfWaves.removeAll(gfWavesToRemove);//Removing the hit waves.
        gfWavesToRemove.clear();//Clearing the list.
    }

    public void train() {
        if (!neuralNetworkInput.isEmpty()) {
            for (int i = 0; i < 25; i++) {
                int index = (int) (Math.random() * Math.min(200, neuralNetworkInput.size())); //Training the last 200 waves 25 times.
                mlp.backPropogate(neuralNetworkInput.get(index), neuralNetworkOutput.get(index));
            }
        }
    }

Notes

To make it more powerful there is a lot more to do:
    • Changing the training policy.
    • Increasing the number of data.
    • Combining with another network.
    • Different activation functions(For example SoftPlus(SmoothMax))
    • Changing the output type.
    • Making an anti-surfer gun.(It can be really strong) NeuralTargetingBot gets about %61 against Shadow in Anti-Surfer Challenge. You can get %72 with a Neural Network.