> For the complete documentation index, see [llms.txt](https://deeplearning4j.konduit.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://deeplearning4j.konduit.ai/en-1.0.0-beta7/arbiter/visualization.md).

# Visualization

### Overview

Arbiter provides a web-based UI for monitoring hyperparameter optimization runs in real time. The UI shows:

* All candidate configurations evaluated so far and their scores
* Score history across candidates
* Hyperparameter value distributions for evaluated candidates
* Best candidate information
* Optimization run status (running, complete, failed)

The UI is served by the same `UIServer` used for DL4J training visualization (via `deeplearning4j-ui`). The Arbiter-specific content is served at:

```
http://localhost:9000/arbiter
```

***

### Dependencies

The UI requires the `arbiter-ui` artifact in addition to `arbiter-deeplearning4j`:

```xml
<dependency>
    <groupId>org.deeplearning4j</groupId>
    <artifactId>arbiter-deeplearning4j</artifactId>
    <version>1.0.0-M2.1</version>
</dependency>

<dependency>
    <groupId>org.deeplearning4j</groupId>
    <artifactId>arbiter-ui_2.11</artifactId>
    <version>1.0.0-M2.1</version>
</dependency>
```

The `arbiter-ui` artifact depends on `deeplearning4j-ui_2.11`. If you already have the DL4J UI dependency, you do not need to add it again.

***

### ArbiterStatusListener

`ArbiterStatusListener` is the bridge between the optimization runner and the UIServer. Attach it to the runner before calling `execute()`:

```java
// Start the UIServer (port 9000 by default)
UIServer uiServer = UIServer.getInstance();

// Create a StatsStorage backend
StatsStorage statsStorage = new InMemoryStatsStorage();

// Register the storage backend with the UI
uiServer.attach(statsStorage);

// Add the listener to the optimization runner
runner.addListeners(new ArbiterStatusListener(statsStorage));

// Run optimization — the UI will update as candidates are evaluated
runner.execute();
```

After calling `runner.execute()`, open a browser and navigate to `http://localhost:9000/arbiter` to see the live results.

***

### StatsStorage Backends

#### InMemoryStatsStorage

Stores stats in JVM memory. Fast and requires no external setup, but data is lost when the JVM exits. Suitable for interactive experimentation.

```java
StatsStorage statsStorage = new InMemoryStatsStorage();
```

#### FileStatsStorage

Persists stats to disk. Data survives JVM restarts, allowing you to resume monitoring or post-hoc analysis:

```java
StatsStorage statsStorage = new FileStatsStorage(new File("/tmp/arbiter_stats.dl4j"));
```

To restore and attach a previously saved stats file to the UI without re-running optimization:

```java
StatsStorage stored = new FileStatsStorage(new File("/tmp/arbiter_stats.dl4j"));
UIServer.getInstance().attach(stored);
// navigate to http://localhost:9000/arbiter to view historical results
```

***

### Full Example

```java
import org.deeplearning4j.api.storage.StatsStorage;
import org.deeplearning4j.arbiter.MultiLayerSpace;
import org.deeplearning4j.arbiter.conf.updater.AdamSpace;
import org.deeplearning4j.arbiter.layers.DenseLayerSpace;
import org.deeplearning4j.arbiter.layers.OutputLayerSpace;
import org.deeplearning4j.arbiter.optimize.api.CandidateGenerator;
import org.deeplearning4j.arbiter.optimize.api.OptimizationResult;
import org.deeplearning4j.arbiter.optimize.api.ParameterSpace;
import org.deeplearning4j.arbiter.optimize.api.score.ScoreFunction;
import org.deeplearning4j.arbiter.optimize.api.termination.MaxCandidatesCondition;
import org.deeplearning4j.arbiter.optimize.api.termination.MaxTimeCondition;
import org.deeplearning4j.arbiter.optimize.api.termination.TerminationCondition;
import org.deeplearning4j.arbiter.optimize.config.OptimizationConfiguration;
import org.deeplearning4j.arbiter.optimize.generator.RandomSearchGenerator;
import org.deeplearning4j.arbiter.optimize.parameter.continuous.ContinuousParameterSpace;
import org.deeplearning4j.arbiter.optimize.parameter.integer.IntegerParameterSpace;
import org.deeplearning4j.arbiter.optimize.runner.IOptimizationRunner;
import org.deeplearning4j.arbiter.optimize.runner.LocalOptimizationRunner;
import org.deeplearning4j.arbiter.saver.local.FileModelSaver;
import org.deeplearning4j.arbiter.scoring.impl.EvaluationScoreFunction;
import org.deeplearning4j.arbiter.task.MultiLayerNetworkTaskCreator;
import org.deeplearning4j.arbiter.ui.listener.ArbiterStatusListener;
import org.deeplearning4j.eval.Evaluation;
import org.deeplearning4j.ui.api.UIServer;
import org.deeplearning4j.ui.stats.StatsListener;
import org.deeplearning4j.ui.storage.InMemoryStatsStorage;
import org.nd4j.linalg.activations.Activation;
import org.nd4j.linalg.lossfunctions.LossFunctions;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

public class ArbiterUIExample {
    public static void main(String[] args) throws Exception {

        // 1. Define search space
        MultiLayerSpace searchSpace = new MultiLayerSpace.Builder()
            .seed(42)
            .updater(new AdamSpace(new ContinuousParameterSpace(1e-4, 1e-2)))
            .addLayer(new DenseLayerSpace.Builder()
                .nIn(784)
                .nOut(new IntegerParameterSpace(64, 256))
                .activation(Activation.RELU)
                .build())
            .addLayer(new OutputLayerSpace.Builder()
                .nOut(10)
                .activation(Activation.SOFTMAX)
                .lossFunction(LossFunctions.LossFunction.MCXENT)
                .build())
            .numEpochs(5)
            .build();

        // 2. Candidate generator
        CandidateGenerator candidateGenerator = new RandomSearchGenerator(searchSpace);

        // 3. Optimization configuration
        Properties dataProps = new Properties();
        dataProps.setProperty("batchSize", "64");

        OptimizationConfiguration configuration = new OptimizationConfiguration.Builder()
            .candidateGenerator(candidateGenerator)
            .dataSource(MnistDataSource.class, dataProps)
            .modelSaver(new FileModelSaver("/tmp/arbiter_models/"))
            .scoreFunction(new EvaluationScoreFunction(Evaluation.Metric.ACCURACY))
            .terminationConditions(
                new MaxTimeCondition(15, TimeUnit.MINUTES),
                new MaxCandidatesCondition(10)
            )
            .build();

        // 4. Set up UI
        UIServer uiServer = UIServer.getInstance();
        StatsStorage statsStorage = new InMemoryStatsStorage();
        uiServer.attach(statsStorage);

        // 5. Create and configure runner
        IOptimizationRunner runner = new LocalOptimizationRunner(
            configuration,
            new MultiLayerNetworkTaskCreator()
        );
        runner.addListeners(new ArbiterStatusListener(statsStorage));

        // 6. Run — open http://localhost:9000/arbiter to monitor
        System.out.println("UI: http://localhost:9000/arbiter");
        runner.execute();

        // 7. Print best result
        System.out.println(runner.toSummaryString());
    }
}
```

***

### What the Arbiter UI Shows

#### Candidates Table

A sortable table of all evaluated candidates showing:

* Candidate index
* Score (from the score function)
* Training duration
* Number of parameters
* Status (complete, running, failed)

Click a row to expand the hyperparameter details for that candidate.

#### Score vs. Candidate Index

A chart showing how the best score (and the current candidate's score) changes as more candidates are evaluated. An upward trend indicates the search is finding progressively better configurations.

#### Hyperparameter Distribution

For each hyperparameter in the search space, a visualization of the values that have been sampled and the corresponding scores. This makes it easy to see whether the search has found a concentration of good values in a particular region.

#### Best Candidate

A summary panel showing the hyperparameter configuration of the current best candidate, its score, and a link to download the model (when using `FileModelSaver`).

***

### Using Both Arbiter UI and DL4J Training UI Simultaneously

Both UIs are served by the same `UIServer` instance. If you also want per-candidate training curves (loss by iteration), add a `StatsListener` to each candidate model during training. This requires a custom `TaskCreator` that injects the listener:

```java
public class UIAwareTaskCreator extends MultiLayerNetworkTaskCreator {
    private final StatsStorage statsStorage;

    public UIAwareTaskCreator(StatsStorage statsStorage) {
        this.statsStorage = statsStorage;
    }

    @Override
    public OptimizationTask create(Candidate candidate, DataSource dataSource,
                                   ResultSaver saver, ScoreFunction score,
                                   List<Listener> listeners) {
        // Inject StatsListener into the candidate model before training
        MultiLayerNetworkOptimizationTask task = (MultiLayerNetworkOptimizationTask)
            super.create(candidate, dataSource, saver, score, listeners);
        task.addNetworkListener(new StatsListener(statsStorage));
        return task;
    }
}
```

Then use `UIAwareTaskCreator` instead of `MultiLayerNetworkTaskCreator`.

***

### Programmatic Access to Results (No UI)

If you do not need the web UI, you can inspect results programmatically after the run completes:

```java
runner.execute();

// List all results sorted by score (best first)
List<OptimizationResult> results = runner.getResults();
results.sort(Comparator.comparingDouble(r -> -r.getScore()));

for (int i = 0; i < Math.min(5, results.size()); i++) {
    OptimizationResult r = results.get(i);
    System.out.printf("Rank %d: score=%.4f, index=%d%n",
        i + 1, r.getScore(), r.getIndex());
}

// Get the best model
MultiLayerNetwork bestModel = (MultiLayerNetwork)
    runner.getBestResult().getResultReference().getResultModel();
```

***

### Related Pages

* [Arbiter Overview](/en-1.0.0-beta7/arbiter/overview.md) — full optimization configuration guide
* [Parameter Spaces](/en-1.0.0-beta7/arbiter/parameter-spaces.md) — search space primitives
* [Layer Spaces](/en-1.0.0-beta7/arbiter/layer-spaces.md) — layer-specific search spaces


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://deeplearning4j.konduit.ai/en-1.0.0-beta7/arbiter/visualization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
