demonstrates connecting an example simulator in Java using the swagger generated client
Перейти к файлу
Julian Ostrow 257ced7b76
Add files via upload
2024-02-09 15:34:24 -08:00
.settings initial push 2020-06-19 17:02:40 +00:00
.vscode readme update 2020-07-14 00:06:59 +00:00
bonsai updating namespaces 2020-08-17 18:09:51 +00:00
docker updating docker info 2020-09-03 18:52:48 +00:00
src/main/java/com/microsoft/bonsai/simulatorapi/samples/cartpole updating namespaces 2020-08-17 18:09:51 +00:00
target updating namespaces 2020-08-17 18:09:51 +00:00
.classpath initial push 2020-06-19 17:02:40 +00:00
.factorypath updating namespaces 2020-08-17 18:09:51 +00:00
.gitignore readme update 2020-07-14 00:06:59 +00:00
.project docker support 2020-07-13 01:13:26 +00:00
LICENSE Add files via upload 2024-02-09 15:34:24 -08:00
README.md updating namespaces 2020-08-17 18:09:51 +00:00
SECURITY.md Microsoft mandatory file 2023-06-02 17:05:25 +00:00
pom.xml updating namespaces 2020-08-17 18:09:51 +00:00

README.md

CartPole Java

This example demonstrates using the classic CartPole example in Java. It assumes the default inkling when the user creates a CartPole example in the Bonsai dashboard.

The focus of the example is the connection between a model in Java and the Bonsai platform.

Structure

The main entry point is App.java.

References

This example makes us of the Bonsai client SDK for Java, available .

Download the client SDK project, then run:

mvn install 

in the root directory where the pom.xml file exists. This installs in your local Maven repository and makes it available for the CartPole example to use.

References are managed in the pom.xml file:

<!-- bonsai reference -->
<dependency>
    <groupId>com.microsoft.bonsai.simulatorapi</groupId>
    <artifactId>bonsai-sdk</artifactId>
    <version>0.1.0</version>
    <scope>compile</scope>
</dependency>

App.java

The main interaction between the model and Bonsai happens in App.java.

Imports

The following imports need to be included:


import java.util.LinkedHashMap;

import com.microsoft.bonsai.client.*;
import com.microsoft.bonsai.generated.Sessions;
import com.microsoft.bonsai.generated.models.*;

import com.fasterxml.jackson.databind.*;

Client configuration

All initial sequence IDs are set to 1. Subsequent sequence IDs are generated by the service.

It should be noted that this example is using access keys to connect to the platform.

BonsaiClientConfig bcConfig = new BonsaiClientConfig(getWorkspace(),getAccessKey());
BonsaiClient client = new BonsaiClient(bcConfig);

Be sure to edit the getWorkspace and getAccessKey to put your respective workspace and access key.

Registering

The following steps are required for registering with Bonsai:

Sessions sessions = client.sessions();
                
SimulatorInterface sim_interface = new SimulatorInterface();
sim_interface.withName("Cartpole-Java");
sim_interface.withTimeout(60.0);
sim_interface.withCapabilities(null);

// minimum required
sim_interface.withSimulatorContext(bcConfig.simulatorContext);

//create only returns an object, so we need to check what type of object
Object registrationResponse = sessions.create(workspaceName, sim_interface);

// if we get an error during registration
if(registrationResponse.getClass() == ProblemDetails.class)
{
    ProblemDetails details = (ProblemDetails)registrationResponse;
    System.out.println(java.time.LocalDateTime.now() + " - ProblemDetails - " +  details.title());
}
// successful registration
else if(registrationResponse.getClass() == SimulatorSessionResponse.class)
{
    registered = registrationResponse;
    SimulatorSessionResponse sessionResponse = (SimulatorSessionResponse)registrationResponse;

    //this is required
    sessionId = sessionResponse.sessionId();
}

System.out.println(java.time.LocalDateTime.now() + " - registered session " + sessionId);

Control loop

After registering an receiving a session ID, the following can be used to check the events that are received from the service in the control loop:

// build the SimulatorState object
SimulatorState simState = new SimulatorState();
simState.withSequenceId(sequenceId); // required
simState.withState(model.getState()); // required
simState.withHalted(model.halted()); // required

// advance only returns an object, so we need to check what type of object
Object response = client.sessions().advance(workspaceName, sessionId, simState);

// if we get an error during advance
if (response.getClass() == ProblemDetails.class) {
    ProblemDetails details = (ProblemDetails) response;

    System.out.println(java.time.LocalDateTime.now() + " - ProblemDetails - " + details.title());
}
// succesful advance
else if (response.getClass() == Event.class) {

    Event event = (Event) response;
    System.out.println(java.time.LocalDateTime.now() + " - received event: " + event.type());
    sequenceId = event.sequenceId(); // get the sequence from the result

    // now check the type of event and handle accordingly

    if (event.type() == EventType.EPISODE_START) {
        // ignored event in Cartpole
        Config config = new Config();

        // If you have config values, pass them to the start event on your model:
        //event.episodeStart().config()
        model.start(config);

    } else if (event.type() == EventType.EPISODE_STEP) {
        Action action = new Action();

        // action() returns an Object with a class value of LinkedHashMap
        LinkedHashMap map = (LinkedHashMap) event.episodeStep().action();

        // get the value of the action
        Object theCommand = map.get("command");

        // sometimes that value is an integer -- somtimes its a double. in either case,
        // Action.command is a double
        if (theCommand.getClass() == Integer.class)
            action.command = ((Integer) theCommand).doubleValue();
        else if (theCommand.getClass() == Double.class)
            action.command = ((Double) theCommand).doubleValue();

        // move the model forward
        model.step(action);
    } else if (event.type() == EventType.EPISODE_FINISH) {
        System.out.println("Episode Finish");
    } else if (event.type() == EventType.IDLE) {
        Thread.sleep(event.idle().callbackTime().longValue() * 1000);
    } else if (event.type() == EventType.UNREGISTER) {
        client.sessions().delete(workspaceName, sessionId);
    }
}

Package

You can run mvn package from the command prompt in the directory where the pom.xml file exists. This will create the target\cartpole-1.0.jar and target\cartpole-1.0-jar-with-dependencies.jar files. The cartpole-1.0-jar-with-dependencies.jar file is a single jar file that contains all of the needed references to run.

Run Local

After packaging the app, run:

java -jar target\cartpole-1.0-jar-with-dependencies.jar

If you want to run in prediction, run:

java -jar target\cartpole-1.0-jar-with-dependencies.jar predict <URL>

where is your http endpoint for your exported brain.

Containerize

This example also includes steps to containerize and scale the training of the simulator.

From the command prompt in the docker folder, run:

build-docker.bat <docker_image_name> <azure_acr_name>

This will copy the JAR file over, build a docker container, prompt for a login to the Azure Container Registry, tag, and push your container to it.

You can now register the simulator with Bonsai.

Be sure to update the package statement in your inkling code.