org.tensorflow.Session Maven / Gradle / Ivy
Show all versions of libtensorflow Show documentation
/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
package org.tensorflow;
import java.util.ArrayList;
import java.util.List;
/**
* Driver for {@link Graph} execution.
*
* A {@code Session} instance encapsulates the environment in which {@link Operation}s in a
* {@link Graph} are executed to compute {@link Tensor Tensors}. For example:
*
*
{@code
* // Let's say graph is an instance of the Graph class
* // for the computation y = 3 * x
*
* try (Session s = new Session(graph)) {
* try (Tensor x = Tensor.create(2.0f);
* Tensor y = s.runner().feed("x", x).fetch("y").run().get(0)) {
* System.out.println(y.floatValue()); // Will print 6.0f
* }
* try (Tensor x = Tensor.create(1.1f);
* Tensor y = s.runner().feed("x", x).fetch("y").run().get(0)) {
* System.out.println(y.floatValue()); // Will print 3.3f
* }
* }
* }
*
* WARNING:A {@code Session} owns resources that must be explicitly freed by
* invoking {@link #close()}.
*
*
Instances of a Session are thread-safe.
*/
public final class Session implements AutoCloseable {
/** Construct a new session with the associated {@link Graph}. */
public Session(Graph g) {
this(g, null);
}
/**
* Construct a new session with the associated {@link Graph} and configuration options.
*
* @param g The {@link Graph} the created Session will operate on.
* @param config Configuration parameters for the session specified as a serialized ConfigProto
* protocol buffer.
* @throws IllegalArgumentException if the config is not a valid serialization of the ConfigProto
* protocol buffer.
*/
public Session(Graph g, byte[] config) {
graph = g;
Graph.Reference r = g.ref();
try {
nativeHandle =
(config == null) ? allocate(r.nativeHandle()) : allocate2(r.nativeHandle(), null, config);
graphRef = g.ref();
} finally {
r.close();
}
}
/** Wrap an existing session with the associated {@link Graph}. */
Session(Graph g, long nativeHandle) {
graph = g;
this.nativeHandle = nativeHandle;
graphRef = g.ref();
}
/**
* Release resources associated with the Session.
*
*
Blocks until there are no active executions ({@link Session.Runner#run()} calls). A Session
* is not usable after close returns.
*/
@Override
public void close() {
graphRef.close();
synchronized (nativeHandleLock) {
if (nativeHandle == 0) {
return;
}
while (numActiveRuns > 0) {
try {
nativeHandleLock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// Possible leak of the Session and Graph in this case?
return;
}
}
delete(nativeHandle);
nativeHandle = 0;
}
}
/**
* Run {@link Operation}s and evaluate {@link Tensor Tensors}.
*
*
A Runner runs the necessary graph fragments to execute every {@link Operation} required to
* evaluate the {@link Tensor Tensors} to fetch. The {@link #feed(String,int,Tensor)} call allows
* callers to override the value of {@link Tensor Tensors} in the graph by substituting the
* provided {@link Tensor Tensors} for the outputs of the operations provided to {@link
* #feed(String,int,Tensor)}.
*/
public final class Runner {
/**
* Avoid evaluating {@code operation} and substitute {@code t} for the value it produces.
*
* @param operation Is either the string name of the operation, in which case this method is a
* shorthand for {@code feed(operation, 0)}, or it is a string of the form
* operation_name:output_index , in which case this method acts like {@code
* feed(operation_name, output_index)}. These colon-separated names are commonly used in the
* {@code SignatureDef} protocol buffer messages that are included in {@link
* SavedModelBundle#metaGraphDef()}.
*/
public Runner feed(String operation, Tensor> t) {
return feed(parseOutput(operation), t);
}
/**
* Avoid evaluating the {@code index}-th output of {@code operation} by substituting {@code t}
* for the value it produces.
*
*
Operations in a {@link Graph} can have multiple outputs, {@code index} identifies which
* one {@code t} is being provided for.
*/
public Runner feed(String operation, int index, Tensor> t) {
Operation op = operationByName(operation);
if (op != null) {
inputs.add(op.output(index));
inputTensors.add(t);
}
return this;
}
/**
* Use {@code t} instead of the Tensor referred to by executing the operation referred to by
* {@code operand}.
*/
public Runner feed(Operand> operand, Tensor> t) {
inputs.add(operand.asOutput());
inputTensors.add(t);
return this;
}
/**
* Make {@link #run()} return the output of {@code operation}.
*
* @param operation Is either the string name of the operation, in which case this method is a
* shorthand for {@code fetch(operation, 0)}, or it is a string of the form
* operation_name:output_index , in which case this method acts like {@code
* fetch(operation_name, output_index)}. These colon-separated names are commonly used in
* the {@code SignatureDef} protocol buffer messages that are included in {@link
* SavedModelBundle#metaGraphDef()}.
*/
public Runner fetch(String operation) {
return fetch(parseOutput(operation));
}
/**
* Make {@link #run()} return the {@code index}-th output of {@code operation}.
*
*
Operations in a {@link Graph} can have multiple outputs, {@code index} identifies which
* one to return.
*/
public Runner fetch(String operation, int index) {
Operation op = operationByName(operation);
if (op != null) {
outputs.add(op.output(index));
}
return this;
}
/**
* Makes {@link #run()} return the Tensor referred to by {@code output}.
*/
public Runner fetch(Output> output) {
outputs.add(output);
return this;
}
/**
* Makes {@link #run()} return the Tensor referred to by the output of {@code operand}.
*/
public Runner fetch(Operand> operand) {
return fetch(operand.asOutput());
}
/**
* Make {@link #run()} execute {@code operation}, but not return any evaluated {@link Tensor
* Tensors}.
*/
public Runner addTarget(String operation) {
GraphOperation op = operationByName(operation);
if (op != null) {
targets.add(op);
}
return this;
}
/**
* Make {@link #run()} execute {@code operation}, but not return any evaluated {@link Tensor
* Tensors}.
*
* @throws IllegalArgumentException if the operation is not a {@link GraphOperation}
*/
public Runner addTarget(Operation operation) {
if (!(operation instanceof GraphOperation)) {
throw new IllegalArgumentException(
"Operation of type "
+ operation.getClass().getName()
+ " is not supported in graph sessions");
}
targets.add((GraphOperation) operation);
return this;
}
/**
* Make {@link #run} execute {@code operand}, but not return any evaluated {@link Tensor
* Tensors}.
*/
public Runner addTarget(Operand> operand) {
return addTarget(operand.asOutput().op());
}
/**
* (Experimental method): set options (typically for debugging) for this run.
*
*
The options are presented as a serialized RunOptions
* protocol buffer.
*
*
The org.tensorflow package is free of any protocol buffer dependencies in order to remain
* friendly to resource constrained systems (where something like nanoproto may
* be more appropriate). A cost of that is this lack of type-safety in this API function. This
* choice is under review and this function may be replaced by more type-safe equivalents at any
* time.
*/
public Runner setOptions(byte[] options) {
this.runOptions = options;
return this;
}
/**
* Execute the graph fragments necessary to compute all requested fetches.
*
*
WARNING: The caller assumes ownership of all returned {@link Tensor Tensors}, i.e.,
* the caller must call {@link Tensor#close} on all elements of the returned list to free up
* resources.
*
*
TODO(ashankar): Reconsider the return type here. Two things in particular: (a) Make it
* easier for the caller to cleanup (perhaps returning something like AutoCloseableList in
* SessionTest.java), and (b) Evaluate whether the return value should be a list, or maybe a
* {@code Map