From 998677d9bad8a55ac1dbc2e050aec40e08a0bd8e Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 8 Jan 2021 17:20:24 -0800
Subject: [PATCH 01/35] Start of TensorScope
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/RawTensor.java | 59 ++++++++++----
.../src/main/java/org/tensorflow/Tensor.java | 19 +++++
.../main/java/org/tensorflow/TensorScope.java | 80 +++++++++++++++++++
3 files changed, 143 insertions(+), 15 deletions(-)
create mode 100644 tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
index c332fd7f1d1..84238144ef2 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
@@ -34,9 +34,9 @@
* A tensor which memory has not been mapped to a data space directly accessible from the JVM.
*
* A raw tensor is a minimalist representation of a tensor allocated in native memory by the
- * TensorFlow runtime library and it controls its lifetime within the current process. The data
- * is represented by a flat {@link ByteDataBuffer buffer of bytes}, until it is mapped in a
- * n-dimensional typed space by a {@link TType typed tensor}.
+ * TensorFlow runtime library and it controls its lifetime within the current process. The data is represented by a flat
+ * {@link ByteDataBuffer buffer of bytes}, until it is mapped in a n-dimensional typed space by a {@link TType typed
+ * tensor}.
*
* Instances of a RawTensor are not thread-safe and their resource must be released
* by calling {@link #close()} explicitly or implicitly via try-with-resources.
@@ -65,7 +65,30 @@ public RawTensor asRawTensor() {
@Override
public void close() {
- tensorScope.close();
+ if (!closed) {
+ tensorScope.close();
+ closed = true;
+ }
+ }
+
+ @Override
+ public boolean isClosed() {
+ return closed;
+ }
+
+ @Override
+ public void detach() {
+ TensorScope.detach(this);
+ }
+
+ @Override
+ public boolean attachToCurrentScope() {
+ TensorScope currentScope = TensorScope.getInnerScope();
+ if (currentScope != null) {
+ currentScope.attach(this);
+ return true;
+ }
+ return false;
}
/**
@@ -93,19 +116,19 @@ public String toString() {
* Allocates a new tensor in native memory of the given type, shape and size.
*
* The size of the tensor must be at least large enough to contain all scalars for the
- * given type and shape. More memory can also be allocated to store also metadata within the
- * tensor itself, e.g. a lookup table in a string tensor.
+ * given type and shape. More memory can also be allocated to store also metadata within the tensor itself, e.g. a
+ * lookup table in a string tensor.
*
* @param type tensor type class
* @param shape shape of the tensor
* @param size size in bytes of the tensor, or -1 to compute the size from the shape
* @return allocated tensor
- * @throws IllegalArgumentException if {@code size} is smaller than the minimum space required to
- * store the tensor data
- * @throws IllegalArgumentException if {@code size} is set to -1 but elements of the given
- * {@code type} are of variable length (e.g. strings)
- * @throws IllegalArgumentException if {@code shape} is totally or partially
- * {@link Shape#hasUnknownDimension() unknown}
+ * @throws IllegalArgumentException if {@code size} is smaller than the minimum space required to store the tensor
+ * data
+ * @throws IllegalArgumentException if {@code size} is set to -1 but elements of the given {@code type} are of
+ * variable length (e.g. strings)
+ * @throws IllegalArgumentException if {@code shape} is totally or partially {@link Shape#hasUnknownDimension()
+ * unknown}
* @throws IllegalStateException if tensor failed to be allocated
*/
static RawTensor allocate(Class extends TType> type, Shape shape, long size) {
@@ -147,9 +170,9 @@ static RawTensor fromHandle(TF_Tensor handle) {
TensorTypeInfo> typeInfo = TensorTypeRegistry.find(DataType.forNumber(dtype(handle)));
RawTensor t = new RawTensor(typeInfo, Shape.of(shape(handle)));
try (PointerScope scope = new PointerScope()) {
- scope.attach(handle);
- t.tensorHandle = handle;
- t.tensorScope = scope.extend();
+ scope.attach(handle);
+ t.tensorHandle = handle;
+ t.tensorScope = scope.extend();
}
return t;
}
@@ -168,6 +191,7 @@ static RawTensor fromHandle(TF_Tensor handle, EagerSession session) {
/**
* Returns the native handle to this tensor
+ *
* @throws IllegalStateException if tensor has been closed
*/
TF_Tensor nativeHandle() {
@@ -219,9 +243,14 @@ private static long[] shape(TF_Tensor handle) {
RawTensor(TensorTypeInfo extends TType> typeInfo, Shape shape) {
this.typeInfo = typeInfo;
this.shape = shape;
+ TensorScope currentScope = TensorScope.getInnerScope();
+ if (currentScope != null) {
+ currentScope.attach(this);
+ }
}
private PointerScope tensorScope;
+ private boolean closed;
private TF_Tensor tensorHandle;
private final TensorTypeInfo extends TType> typeInfo;
private final Shape shape;
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index fc1275229bf..7eaedb76dbf 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -212,4 +212,23 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
*/
@Override
void close();
+
+ /**
+ * Get whether this tensor has been closed.
+ */
+ boolean isClosed();
+
+ /**
+ * Detach this tensor from any scopes managing it. It must be manually closed or attached to another scope.
+ */
+ default void detach(){
+ asRawTensor().detach();
+ }
+
+ /**
+ * Attach this tensor to the current scope. No-ops and returns false if there is no current scope.
+ */
+ default boolean attachToCurrentScope(){
+ return asRawTensor().attachToCurrentScope();
+ }
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
new file mode 100644
index 00000000000..04898cdd1ef
--- /dev/null
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -0,0 +1,80 @@
+/*
+ Copyright 2021 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.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.bytedeco.javacpp.PointerScope;
+import org.tensorflow.ndarray.NdArray;
+
+public class TensorScope implements AutoCloseable{
+
+ static final ThreadLocal> scopeStack = ThreadLocal.withInitial(ArrayDeque::new);
+
+ /** Returns {@code scopeStack.get().peek()}, the last opened scope not yet closed. */
+ public static TensorScope getInnerScope() {
+ return scopeStack.get().peek();
+ }
+
+ /** Returns {@code scopeStack.get().iterator()}, all scopes not yet closed. */
+ public static Iterator getScopeIterator() {
+ return scopeStack.get().iterator();
+ }
+
+ /**
+ * Detaches the given tensor from any scopes managing it, requiring it to be manually closed.
+ */
+ public static void detach(Tensor t){
+ RawTensor raw = t.asRawTensor();
+ getScopeIterator().forEachRemaining(scope -> scope.detachTensor(raw));
+ }
+
+ public TensorScope(){
+ scopeStack.get().push(this);
+ }
+
+ /**
+ * Attach a tensor to this scope. This happens automatically to tensors that are created in the scope.
+ */
+ public void attach(Tensor t){
+ tensors.add(t.asRawTensor());
+ }
+
+
+ /**
+ * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ */
+ public void attach(Tensor... tensors){
+ for(Tensor t : tensors){
+ attach(t);
+ }
+ }
+
+ private void detachTensor(Tensor t){
+ tensors.remove(t.asRawTensor());
+ }
+
+ @Override
+ public void close() throws Exception {
+ tensors.forEach(Tensor::close);
+ }
+
+ private final Set tensors = new LinkedHashSet<>();
+}
From 591d44d39d52329268c5a190360ba66364114718 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Wed, 13 Jan 2021 16:00:06 -0800
Subject: [PATCH 02/35] Finish TensorScope, add test
Signed-off-by: Ryan Nett
---
.../java/org/tensorflow/EagerOperation.java | 2 +-
.../main/java/org/tensorflow/RawTensor.java | 26 ++--
.../src/main/java/org/tensorflow/Tensor.java | 13 +-
.../main/java/org/tensorflow/TensorScope.java | 124 ++++++++++++++----
.../org/tensorflow/types/family/TType.java | 20 +++
.../java/org/tensorflow/TensorScopeTest.java | 98 ++++++++++++++
6 files changed, 235 insertions(+), 48 deletions(-)
create mode 100644 tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
index 9f87fd8b95e..07691734db4 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
@@ -166,7 +166,7 @@ private static Tensor resolveTensorHandle(TFE_TensorHandle handle, EagerSession
TF_Status status = TF_Status.newStatus();
TF_Tensor tensor = TFE_TensorHandleResolve(handle, status).withDeallocator();
status.throwExceptionIfNotOK();
- return RawTensor.fromHandle(tensor, session).asTypedTensor();
+ return RawTensor.fromHandle(tensor).asTypedTensor();
}
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
index 84238144ef2..b864ccb64c1 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
@@ -81,9 +81,14 @@ public void detach() {
TensorScope.detach(this);
}
+ @Override
+ public boolean isAttached() {
+ return attached;
+ }
+
@Override
public boolean attachToCurrentScope() {
- TensorScope currentScope = TensorScope.getInnerScope();
+ TensorScope currentScope = TensorScope.getCurrentScope();
if (currentScope != null) {
currentScope.attach(this);
return true;
@@ -177,18 +182,6 @@ static RawTensor fromHandle(TF_Tensor handle) {
return t;
}
- /**
- * Create an eager Tensor object from a handle to the C TF_Tensor object.
- *
- * Takes ownership of the handle.
- */
- static RawTensor fromHandle(TF_Tensor handle, EagerSession session) {
- RawTensor t = fromHandle(handle);
- session.attach(handle);
- t.tensorScope.detach(handle);
- return t;
- }
-
/**
* Returns the native handle to this tensor
*
@@ -243,14 +236,15 @@ private static long[] shape(TF_Tensor handle) {
RawTensor(TensorTypeInfo extends TType> typeInfo, Shape shape) {
this.typeInfo = typeInfo;
this.shape = shape;
- TensorScope currentScope = TensorScope.getInnerScope();
- if (currentScope != null) {
- currentScope.attach(this);
+ TensorScope scope = TensorScope.getCurrentScope();
+ if (scope != null) {
+ scope.attach(this);
}
}
private PointerScope tensorScope;
private boolean closed;
+ boolean attached = false;
private TF_Tensor tensorHandle;
private final TensorTypeInfo extends TType> typeInfo;
private final Shape shape;
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index 7eaedb76dbf..c38a00626ad 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -221,14 +221,15 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
/**
* Detach this tensor from any scopes managing it. It must be manually closed or attached to another scope.
*/
- default void detach(){
- asRawTensor().detach();
- }
+ void detach();
+
+ /**
+ * Returns true if this tensor is attached to a {@link TensorScope}.
+ */
+ boolean isAttached();
/**
* Attach this tensor to the current scope. No-ops and returns false if there is no current scope.
*/
- default boolean attachToCurrentScope(){
- return asRawTensor().attachToCurrentScope();
- }
+ boolean attachToCurrentScope();
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index 04898cdd1ef..b56482af2fb 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -17,64 +17,138 @@
package org.tensorflow;
import java.util.ArrayDeque;
+import java.util.Collections;
import java.util.Deque;
-import java.util.Iterator;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
-import org.bytedeco.javacpp.PointerScope;
-import org.tensorflow.ndarray.NdArray;
+import java.util.WeakHashMap;
+
+
+/**
+ * A scope that can be used to manage tensor resources. Any tensors created between a scope's creation and calling
+ * {@code close()}, that haven't been detached, are guaranteed to be closed with the scope (even if they are created in
+ * a sub-scope). Tensors may be manually closed earlier without issue.
+ *
+ * Tensors are automatically tracked on creation. A tensor can me manually added to a scope with {@link
+ * TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}, or by passing them to {@link
+ * TensorScope#TensorScope(Tensor...)}. The tensor will then be closed when the first of it's managing scopes closes.
+ *
+ * {@link Tensor#detach()} detaches the tensor from all scopes, requiring the user to close it manually or attach it to
+ * another scope.
+ *
+ * Note that scope management is thread local, except for detach, which will detach even from scopes on other threads.
+ */
+public class TensorScope implements AutoCloseable {
-public class TensorScope implements AutoCloseable{
+ private static final Set allScopes = Collections.newSetFromMap(new WeakHashMap<>());
- static final ThreadLocal> scopeStack = ThreadLocal.withInitial(ArrayDeque::new);
+ private static final ThreadLocal> scopeStack = ThreadLocal.withInitial(ArrayDeque::new);
- /** Returns {@code scopeStack.get().peek()}, the last opened scope not yet closed. */
- public static TensorScope getInnerScope() {
+ /**
+ * Returns {@code scopeStack.get().peek()}, the last opened scope not yet closed on this thread.
+ */
+ static TensorScope getCurrentScope() {
return scopeStack.get().peek();
}
- /** Returns {@code scopeStack.get().iterator()}, all scopes not yet closed. */
- public static Iterator getScopeIterator() {
- return scopeStack.get().iterator();
- }
-
/**
* Detaches the given tensor from any scopes managing it, requiring it to be manually closed.
*/
- public static void detach(Tensor t){
+ public static void detach(Tensor t) {
RawTensor raw = t.asRawTensor();
- getScopeIterator().forEachRemaining(scope -> scope.detachTensor(raw));
+ synchronized (TensorScope.class) {
+ allScopes.forEach(x -> x.detachTensor(raw));
+ }
+ raw.attached = false;
+ }
+
+ /**
+ * Create a new tensor scope with the given thread locality.
+ */
+ public TensorScope() {
+ localScopeStack = scopeStack.get();
+
+ synchronized (TensorScope.class) {
+ allScopes.add(this);
+ }
+ localScopeStack.push(this);
}
- public TensorScope(){
- scopeStack.get().push(this);
+ /**
+ * Create a new tensor scope with the given thread locality, and attach the given tensors.
+ */
+ public TensorScope(Tensor... tensors) {
+ this();
+ attach(tensors);
}
/**
* Attach a tensor to this scope. This happens automatically to tensors that are created in the scope.
*/
- public void attach(Tensor t){
- tensors.add(t.asRawTensor());
+ public void attach(Tensor t) {
+ RawTensor rt = t.asRawTensor();
+ rt.attached = true;
+ tensors.add(rt);
}
/**
* Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
*/
- public void attach(Tensor... tensors){
- for(Tensor t : tensors){
- attach(t);
+ public void attach(Tensor... tensors) {
+ if (tensors != null) {
+ for (Tensor t : tensors) {
+ attach(t);
+ }
}
}
- private void detachTensor(Tensor t){
+ private void detachTensor(Tensor t) {
tensors.remove(t.asRawTensor());
}
- @Override
- public void close() throws Exception {
+ private void closeScope() {
tensors.forEach(Tensor::close);
+
+ synchronized (TensorScope.class) {
+ allScopes.remove(this);
+ }
+
+ closed = true;
+ }
+
+ /**
+ * Closes this scope and its tensors, and any inner scopes.
+ */
+ @Override
+ public void close() {
+ if (closed) {
+ return;
+ }
+
+ if (!localScopeStack.contains(this)) {
+ throw new IllegalStateException("This scope is not on the scope stack, but was not closed."
+ + " This should not be possible.");
+ }
+
+ while (true) {
+ TensorScope ts = localScopeStack.removeLast();
+ ts.closeScope();
+ if (ts == this) {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Gets whether the scope is closed.
+ */
+ public boolean isClosed() {
+ return closed;
}
- private final Set tensors = new LinkedHashSet<>();
+ private boolean closed = false;
+ private final Set tensors = new HashSet<>();
+ private final Deque localScopeStack;
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
index 2fc423b914e..a2bffe29575 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
@@ -80,4 +80,24 @@ default long numBytes() {
default void close() {
asRawTensor().close();
}
+
+ @Override
+ default boolean isClosed(){
+ return asRawTensor().isClosed();
+ }
+
+ @Override
+ default void detach(){
+ asRawTensor().detach();
+ }
+
+ @Override
+ default boolean isAttached(){
+ return asRawTensor().isAttached();
+ }
+
+ @Override
+ default boolean attachToCurrentScope(){
+ return asRawTensor().attachToCurrentScope();
+ }
}
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
new file mode 100644
index 00000000000..52cbb73564c
--- /dev/null
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -0,0 +1,98 @@
+/*
+ Copyright 2021 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 static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+import org.tensorflow.ndarray.Shape;
+import org.tensorflow.types.TFloat32;
+
+/**
+ * Unit tests for {@link TensorScope}
+ */
+public class TensorScopeTest {
+
+ private static TFloat32 makeTensor(long size) {
+ return TFloat32.tensorOf(Shape.of(size), x -> {
+ for (long i = 0; i < size; i++) {
+ x.setFloat(0, i);
+ }
+ });
+ }
+
+ @Test
+ public void testBasicScope() {
+ TensorScope scope = new TensorScope();
+
+ TFloat32 tensor = makeTensor(10);
+ TFloat32 detachTensor = makeTensor(10);
+ detachTensor.detach();
+
+ assertTrue(tensor.isAttached());
+ assertFalse(tensor.isClosed());
+
+ assertFalse(detachTensor.isAttached());
+ assertFalse(detachTensor.isClosed());
+
+ scope.close();
+
+ assertTrue(tensor.isClosed());
+ assertTrue(scope.isClosed());
+ assertFalse(detachTensor.isClosed());
+ }
+
+ @Test
+ public void testNestedScope() {
+ TensorScope outerScope = new TensorScope();
+ TensorScope scope = new TensorScope();
+
+ TFloat32 tensor = makeTensor(10);
+ TFloat32 detachTensor = makeTensor(10);
+ detachTensor.detach();
+
+ assertTrue(tensor.isAttached());
+ assertFalse(tensor.isClosed());
+
+ assertFalse(detachTensor.isAttached());
+ assertFalse(detachTensor.isClosed());
+
+ outerScope.close();
+
+ assertTrue(tensor.isClosed());
+ assertTrue(scope.isClosed());
+ assertTrue(outerScope.isClosed());
+ assertFalse(detachTensor.isClosed());
+ }
+
+ @Test
+ public void testAttach(){
+ TensorScope firstScope = new TensorScope();
+ TFloat32 tensor = makeTensor(10);
+ TensorScope secondScope = new TensorScope(tensor);
+
+ assertTrue(tensor.isAttached());
+ assertFalse(tensor.isClosed());
+
+ secondScope.close();
+
+ assertTrue(tensor.isClosed());
+ }
+
+
+}
From 34e1429893d6e876fd262ba5afbe4972b6d2c81d Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Wed, 13 Jan 2021 16:03:26 -0800
Subject: [PATCH 03/35] Javadoc updates
Signed-off-by: Ryan Nett
---
.../src/main/java/org/tensorflow/TensorScope.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index b56482af2fb..b98ca80c75d 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -65,6 +65,7 @@ public static void detach(Tensor t) {
/**
* Create a new tensor scope with the given thread locality.
+ * @see TensorScope
*/
public TensorScope() {
localScopeStack = scopeStack.get();
@@ -77,6 +78,7 @@ public TensorScope() {
/**
* Create a new tensor scope with the given thread locality, and attach the given tensors.
+ * @see TensorScope
*/
public TensorScope(Tensor... tensors) {
this();
From 700f0f8ce23cf74185428f2ad140cf188fb21e34 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Wed, 13 Jan 2021 16:07:00 -0800
Subject: [PATCH 04/35] Add a TensorScope to EagerSession to replicate pointer
attachment
Signed-off-by: Ryan Nett
---
.../src/main/java/org/tensorflow/EagerSession.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
index 8e7465388a8..192b1437a41 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
@@ -361,6 +361,7 @@ void detach(Pointer... resources) {
private final WeakPointerScope nativeResources;
private TFE_Context nativeHandle;
+ private final TensorScope tensorScope = new TensorScope();
private EagerSession(Options options) {
this.nativeResources = new WeakPointerScope();
@@ -374,6 +375,7 @@ private void checkSession() {
}
private synchronized void doClose() {
+ tensorScope.close();
if (nativeHandle != null && !nativeHandle.isNull()) {
nativeResources.close();
delete(nativeHandle);
From 8231407c1ae5ab64cd3b2ae4ebb15fd7a0598909 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Wed, 13 Jan 2021 16:18:41 -0800
Subject: [PATCH 05/35] Make auto-attach optional, use TensorScope in eager
session to close tensors.
Signed-off-by: Ryan Nett
---
.../java/org/tensorflow/EagerOperation.java | 5 +-
.../java/org/tensorflow/EagerSession.java | 6 ++-
.../main/java/org/tensorflow/RawTensor.java | 12 +----
.../src/main/java/org/tensorflow/Tensor.java | 3 +-
.../main/java/org/tensorflow/TensorScope.java | 54 +++++++++++++++----
5 files changed, 56 insertions(+), 24 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
index 07691734db4..7302ffaa4d9 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
@@ -30,6 +30,7 @@
import org.tensorflow.internal.c_api.TF_Tensor;
import org.tensorflow.ndarray.Shape;
import org.tensorflow.proto.framework.DataType;
+import org.tensorflow.types.family.TType;
/**
* Implementation of an {@link Operation} executed eagerly.
@@ -166,7 +167,9 @@ private static Tensor resolveTensorHandle(TFE_TensorHandle handle, EagerSession
TF_Status status = TF_Status.newStatus();
TF_Tensor tensor = TFE_TensorHandleResolve(handle, status).withDeallocator();
status.throwExceptionIfNotOK();
- return RawTensor.fromHandle(tensor).asTypedTensor();
+ TType typedTensor = RawTensor.fromHandle(tensor).asTypedTensor();
+ session.attachTensor(typedTensor);
+ return typedTensor;
}
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
index 192b1437a41..b363d40d94e 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
@@ -357,11 +357,15 @@ void detach(Pointer... resources) {
}
}
+ void attachTensor(Tensor tensor){
+ tensorScope.attach(tensor);
+ }
+
private static volatile EagerSession defaultSession = null;
private final WeakPointerScope nativeResources;
private TFE_Context nativeHandle;
- private final TensorScope tensorScope = new TensorScope();
+ private final TensorScope tensorScope = new TensorScope(false);
private EagerSession(Options options) {
this.nativeResources = new WeakPointerScope();
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
index b864ccb64c1..0dafad93581 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
@@ -88,12 +88,7 @@ public boolean isAttached() {
@Override
public boolean attachToCurrentScope() {
- TensorScope currentScope = TensorScope.getCurrentScope();
- if (currentScope != null) {
- currentScope.attach(this);
- return true;
- }
- return false;
+ return TensorScope.autoAttach(this);
}
/**
@@ -236,10 +231,7 @@ private static long[] shape(TF_Tensor handle) {
RawTensor(TensorTypeInfo extends TType> typeInfo, Shape shape) {
this.typeInfo = typeInfo;
this.shape = shape;
- TensorScope scope = TensorScope.getCurrentScope();
- if (scope != null) {
- scope.attach(this);
- }
+ TensorScope.autoAttach(this);
}
private PointerScope tensorScope;
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index c38a00626ad..3930e2cca91 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -229,7 +229,8 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
boolean isAttached();
/**
- * Attach this tensor to the current scope. No-ops and returns false if there is no current scope.
+ * Attach this tensor to the most recent scope that accepts automatic attachment.
+ * No-ops and returns false if there is no scope that does so.
*/
boolean attachToCurrentScope();
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index b98ca80c75d..2c3cd45050f 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -20,17 +20,18 @@
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.WeakHashMap;
/**
- * A scope that can be used to manage tensor resources. Any tensors created between a scope's creation and calling
+ * A scope that can be used to manage tensor resources. If auto-attach is used, any tensors created between a scope's creation and calling
* {@code close()}, that haven't been detached, are guaranteed to be closed with the scope (even if they are created in
* a sub-scope). Tensors may be manually closed earlier without issue.
*
- * Tensors are automatically tracked on creation. A tensor can me manually added to a scope with {@link
+ * When auto-attach is true, tensors are automatically tracked on creation. A tensor can me manually added to a scope with {@link
* TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}, or by passing them to {@link
* TensorScope#TensorScope(Tensor...)}. The tensor will then be closed when the first of it's managing scopes closes.
*
@@ -46,10 +47,19 @@ public class TensorScope implements AutoCloseable {
private static final ThreadLocal> scopeStack = ThreadLocal.withInitial(ArrayDeque::new);
/**
- * Returns {@code scopeStack.get().peek()}, the last opened scope not yet closed on this thread.
+ * Attach the tensor to the most recent scope that accepts automatic attachment.
+ * @return true if attached.
*/
- static TensorScope getCurrentScope() {
- return scopeStack.get().peek();
+ static boolean autoAttach(Tensor tensor) {
+ Iterator iterator = scopeStack.get().descendingIterator();
+ while (iterator.hasNext()) {
+ TensorScope scope = iterator.next();
+ if (scope.autoAttach) {
+ scope.attach(tensor);
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -64,27 +74,48 @@ public static void detach(Tensor t) {
}
/**
- * Create a new tensor scope with the given thread locality.
+ * Create a new tensor scope. If {@code autoAttach} is false, will not automatically manage tensors.
+ *
* @see TensorScope
*/
- public TensorScope() {
- localScopeStack = scopeStack.get();
+ public TensorScope(boolean autoAttach) {
+ this.autoAttach = autoAttach;
synchronized (TensorScope.class) {
allScopes.add(this);
}
+
+ localScopeStack = scopeStack.get();
localScopeStack.push(this);
}
/**
- * Create a new tensor scope with the given thread locality, and attach the given tensors.
+ * Create a new tensor scope that automatically manages tensors.
+ */
+ public TensorScope() {
+ this(true);
+ }
+
+ /**
+ * Create a new tensor, and attach the given tensors. If {@code autoAttach} is false, will not automatically manage
+ * tensors.
+ *
* @see TensorScope
*/
- public TensorScope(Tensor... tensors) {
- this();
+ public TensorScope(boolean autoAttach, Tensor... tensors) {
+ this(autoAttach);
attach(tensors);
}
+ /**
+ * Create a new tensor scope that automatically manages tensors, and attach the given tensors.
+ *
+ * @see TensorScope
+ */
+ public TensorScope(Tensor... tensors) {
+ this(true, tensors);
+ }
+
/**
* Attach a tensor to this scope. This happens automatically to tensors that are created in the scope.
*/
@@ -150,6 +181,7 @@ public boolean isClosed() {
return closed;
}
+ private final boolean autoAttach;
private boolean closed = false;
private final Set tensors = new HashSet<>();
private final Deque localScopeStack;
From a9982a491547f04096ad3bfb952c4ebfde7eefb3 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Wed, 13 Jan 2021 16:42:51 -0800
Subject: [PATCH 06/35] Test for non-auto-attach scope
Signed-off-by: Ryan Nett
---
.../java/org/tensorflow/TensorScopeTest.java | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
index 52cbb73564c..d9bb8dd3f43 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -55,6 +55,7 @@ public void testBasicScope() {
assertTrue(tensor.isClosed());
assertTrue(scope.isClosed());
assertFalse(detachTensor.isClosed());
+ detachTensor.close();
}
@Test
@@ -78,6 +79,7 @@ public void testNestedScope() {
assertTrue(scope.isClosed());
assertTrue(outerScope.isClosed());
assertFalse(detachTensor.isClosed());
+ detachTensor.close();
}
@Test
@@ -94,5 +96,24 @@ public void testAttach(){
assertTrue(tensor.isClosed());
}
+ @Test
+ public void testNoAutoAttach(){
+ TensorScope scope = new TensorScope(false);
+ TFloat32 tensor = makeTensor(10);
+ assertFalse(tensor.isAttached());
+
+ TFloat32 detachTensor = makeTensor(10);
+ assertFalse(detachTensor.isAttached());
+
+ scope.attach(detachTensor);
+ assertTrue(detachTensor.isAttached());
+
+ detachTensor.detach();
+ assertFalse(detachTensor.isAttached());
+
+ tensor.close();
+ detachTensor.close();
+ }
+
}
From d30d7b10ee7d4106fb3079a5cffc493dc09634b1 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Wed, 13 Jan 2021 16:43:58 -0800
Subject: [PATCH 07/35] cleanup scopes
Signed-off-by: Ryan Nett
---
.../src/test/java/org/tensorflow/TensorScopeTest.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
index d9bb8dd3f43..a60b5a1851f 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -94,6 +94,7 @@ public void testAttach(){
secondScope.close();
assertTrue(tensor.isClosed());
+ firstScope.close();
}
@Test
@@ -113,6 +114,7 @@ public void testNoAutoAttach(){
tensor.close();
detachTensor.close();
+ scope.close();
}
From 8a7e8be73a4d4aefce781a88625dbae3a121da20 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Wed, 13 Jan 2021 16:56:39 -0800
Subject: [PATCH 08/35] HasTensors abstraction for resource management of
multiple tensors
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/HasTensors.java | 63 +++++++++++++++
.../src/main/java/org/tensorflow/Tensor.java | 2 +-
.../main/java/org/tensorflow/TensorScope.java | 77 ++++++++++++-------
.../java/org/tensorflow/TensorScopeTest.java | 2 +-
4 files changed, 115 insertions(+), 29 deletions(-)
create mode 100644 tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
new file mode 100644
index 00000000000..f6cd0f199f1
--- /dev/null
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
@@ -0,0 +1,63 @@
+/*
+ Copyright 2021 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;
+
+/**
+ * An interface representing a collection or group of tensors. Provides methods for resource management.
+ */
+public interface HasTensors extends AutoCloseable {
+
+ /**
+ * Get the tensors held by this object.
+ */
+ Iterable tensors();
+
+ /**
+ * Detach these tensors from any scopes managing them. They must be manually closed or attached to another scope.
+ * @see Tensor#detach()
+ */
+ default void detach(){
+ tensors().forEach(Tensor::detach);
+ }
+
+ /**
+ * Attach all of these tensors to the most recent scope that accepts automatic attachment.
+ * No-ops and returns false if there is no scope that does so.
+ * @see Tensor#detach()
+ */
+ default boolean attachToCurrentScope(){
+ if(!TensorScope.hasAutoScope()){
+ return false;
+ }
+ tensors().forEach(Tensor::attachToCurrentScope);
+ return true;
+ }
+
+ /**
+ * Release resources associated with these tensors.
+ *
+ * WARNING:This must be invoked for all tensors that were not been produced by an eager
+ * operation or memory will be leaked. May be done automatically via {@link TensorScope}.
+ *
+ *
The Tensor objects are no longer usable after {@code close} returns.
+ * @see Tensor#close()
+ */
+ @Override
+ default void close(){
+ tensors().forEach(Tensor::close);
+ }
+}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index 3930e2cca91..834c0c819fd 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -206,7 +206,7 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
* Release resources associated with the Tensor.
*
* WARNING:This must be invoked for all tensors that were not been produced by an eager
- * operation or memory will be leaked.
+ * operation or memory will be leaked. May be done automatically via {@link TensorScope}.
*
*
The Tensor object is no longer usable after {@code close} returns.
*/
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index 2c3cd45050f..6fffe0600a9 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -27,13 +27,12 @@
/**
- * A scope that can be used to manage tensor resources. If auto-attach is used, any tensors created between a scope's creation and calling
- * {@code close()}, that haven't been detached, are guaranteed to be closed with the scope (even if they are created in
- * a sub-scope). Tensors may be manually closed earlier without issue.
+ * A scope that can be used to manage tensor resources. If auto-attach is used, any tensors created between a scope's
+ * creation and calling {@code close()}, that haven't been detached, are guaranteed to be closed with the scope (even if
+ * they are created in a sub-scope). Tensors may be manually closed earlier without issue.
*
- * When auto-attach is true, tensors are automatically tracked on creation. A tensor can me manually added to a scope with {@link
- * TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}, or by passing them to {@link
- * TensorScope#TensorScope(Tensor...)}. The tensor will then be closed when the first of it's managing scopes closes.
+ * When auto-attach is true, tensors are automatically tracked on creation. A tensor can me manually added to a scope
+ * with {@link TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. The tensor will then be closed when the first of it's managing scopes closes.
*
* {@link Tensor#detach()} detaches the tensor from all scopes, requiring the user to close it manually or attach it to
* another scope.
@@ -48,6 +47,7 @@ public class TensorScope implements AutoCloseable {
/**
* Attach the tensor to the most recent scope that accepts automatic attachment.
+ *
* @return true if attached.
*/
static boolean autoAttach(Tensor tensor) {
@@ -62,6 +62,20 @@ static boolean autoAttach(Tensor tensor) {
return false;
}
+ /**
+ * Return true if there is a scope that accepts auto attachment on the stack.
+ */
+ public static boolean hasAutoScope() {
+ Iterator iterator = scopeStack.get().descendingIterator();
+ while (iterator.hasNext()) {
+ TensorScope scope = iterator.next();
+ if (scope.autoAttach) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Detaches the given tensor from any scopes managing it, requiring it to be manually closed.
*/
@@ -97,44 +111,53 @@ public TensorScope() {
}
/**
- * Create a new tensor, and attach the given tensors. If {@code autoAttach} is false, will not automatically manage
- * tensors.
- *
- * @see TensorScope
+ * Attach a tensor to this scope. This happens automatically to tensors that are created in the scope.
+ * @return this
*/
- public TensorScope(boolean autoAttach, Tensor... tensors) {
- this(autoAttach);
- attach(tensors);
+ public TensorScope attach(Tensor t) {
+ RawTensor rt = t.asRawTensor();
+ rt.attached = true;
+ tensors.add(rt);
+
+ return this;
}
/**
- * Create a new tensor scope that automatically manages tensors, and attach the given tensors.
- *
- * @see TensorScope
+ * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ * @return this
*/
- public TensorScope(Tensor... tensors) {
- this(true, tensors);
+ public TensorScope attach(Tensor... tensors) {
+ if (tensors != null) {
+ for (Tensor t : tensors) {
+ attach(t);
+ }
+ }
+
+ return this;
}
/**
- * Attach a tensor to this scope. This happens automatically to tensors that are created in the scope.
+ * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ * @return this
*/
- public void attach(Tensor t) {
- RawTensor rt = t.asRawTensor();
- rt.attached = true;
- tensors.add(rt);
- }
+ public TensorScope attach(HasTensors tensors) {
+ tensors.tensors().forEach(this::attach);
+ return this;
+ }
/**
* Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ * @return this
*/
- public void attach(Tensor... tensors) {
+ public TensorScope attach(HasTensors... tensors) {
if (tensors != null) {
- for (Tensor t : tensors) {
- attach(t);
+ for (HasTensors ht : tensors) {
+ attach(ht);
}
}
+
+ return this;
}
private void detachTensor(Tensor t) {
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
index a60b5a1851f..74f4f6d19f7 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -86,7 +86,7 @@ public void testNestedScope() {
public void testAttach(){
TensorScope firstScope = new TensorScope();
TFloat32 tensor = makeTensor(10);
- TensorScope secondScope = new TensorScope(tensor);
+ TensorScope secondScope = new TensorScope().attach(tensor);
assertTrue(tensor.isAttached());
assertFalse(tensor.isClosed());
From 38b98f04cfc9e0fcd1240869eec4be805277ae6a Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Thu, 14 Jan 2021 22:39:32 -0800
Subject: [PATCH 09/35] Iterable attach methods
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/TensorScope.java | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index 6fffe0600a9..d6590a01f11 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -160,6 +160,30 @@ public TensorScope attach(HasTensors... tensors) {
return this;
}
+ /**
+ * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ * @return this
+ */
+ public TensorScope attach(Iterable tensors) {
+ tensors.forEach(this::attach);
+
+ return this;
+ }
+
+ /**
+ * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ * @return this
+ */
+ public TensorScope attach(Iterable... tensors) {
+ if (tensors != null) {
+ for (Iterable ht : tensors) {
+ attach(ht);
+ }
+ }
+
+ return this;
+ }
+
private void detachTensor(Tensor t) {
tensors.remove(t.asRawTensor());
}
From bfe6aa538d46fbd3bd2dea1e64f8113bc8789082 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 17:59:53 -0800
Subject: [PATCH 10/35] refactor hierarchy, add release to parent methods
Signed-off-by: Ryan Nett
---
.../java/org/tensorflow/EagerOperation.java | 4 +-
.../java/org/tensorflow/EagerSession.java | 6 -
.../main/java/org/tensorflow/HasTensors.java | 32 +++-
.../main/java/org/tensorflow/RawTensor.java | 30 ++-
.../src/main/java/org/tensorflow/Tensor.java | 13 +-
.../main/java/org/tensorflow/TensorScope.java | 174 ++++++++++--------
.../org/tensorflow/types/family/TType.java | 9 +-
.../java/org/tensorflow/TensorScopeTest.java | 38 ++--
8 files changed, 179 insertions(+), 127 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
index 7302ffaa4d9..4e9394b7df0 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerOperation.java
@@ -167,9 +167,7 @@ private static Tensor resolveTensorHandle(TFE_TensorHandle handle, EagerSession
TF_Status status = TF_Status.newStatus();
TF_Tensor tensor = TFE_TensorHandleResolve(handle, status).withDeallocator();
status.throwExceptionIfNotOK();
- TType typedTensor = RawTensor.fromHandle(tensor).asTypedTensor();
- session.attachTensor(typedTensor);
- return typedTensor;
+ return RawTensor.fromHandle(tensor).asTypedTensor();
}
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
index b363d40d94e..8e7465388a8 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/EagerSession.java
@@ -357,15 +357,10 @@ void detach(Pointer... resources) {
}
}
- void attachTensor(Tensor tensor){
- tensorScope.attach(tensor);
- }
-
private static volatile EagerSession defaultSession = null;
private final WeakPointerScope nativeResources;
private TFE_Context nativeHandle;
- private final TensorScope tensorScope = new TensorScope(false);
private EagerSession(Options options) {
this.nativeResources = new WeakPointerScope();
@@ -379,7 +374,6 @@ private void checkSession() {
}
private synchronized void doClose() {
- tensorScope.close();
if (nativeHandle != null && !nativeHandle.isNull()) {
nativeResources.close();
delete(nativeHandle);
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
index f6cd0f199f1..ae0661e0da7 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
@@ -28,23 +28,34 @@ public interface HasTensors extends AutoCloseable {
/**
* Detach these tensors from any scopes managing them. They must be manually closed or attached to another scope.
+ *
* @see Tensor#detach()
*/
- default void detach(){
+ default void detach() {
tensors().forEach(Tensor::detach);
}
/**
- * Attach all of these tensors to the most recent scope that accepts automatic attachment.
- * No-ops and returns false if there is no scope that does so.
- * @see Tensor#detach()
+ * Attach all of these tensors to the most recent scope.
+ *
+ * @throws IllegalStateException if there is no active scope.
+ * @see Tensor#attachToCurrentScope()
*/
- default boolean attachToCurrentScope(){
- if(!TensorScope.hasAutoScope()){
- return false;
+ default void attachToCurrentScope() {
+ TensorScope scope = TensorScope.currentScope();
+ if (scope == null) {
+ throw new IllegalStateException("Can't attach to current scope: no active tensor scopes.");
}
- tensors().forEach(Tensor::attachToCurrentScope);
- return true;
+
+ tensors().forEach(scope::attach);
+ }
+
+ /**
+ * Attach these tensors to the parent of their current scope, removing it from it's current scope.
+ * @throws IllegalStateException if any tensors do not have a scope, or their scope does not have a parent.
+ */
+ default void attachToParent(){
+ tensors().forEach(Tensor::attachToParent);
}
/**
@@ -54,10 +65,11 @@ default boolean attachToCurrentScope(){
* operation or memory will be leaked. May be done automatically via {@link TensorScope}.
*
* The Tensor objects are no longer usable after {@code close} returns.
+ *
* @see Tensor#close()
*/
@Override
- default void close(){
+ default void close() {
tensors().forEach(Tensor::close);
}
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
index 0dafad93581..f334a9d4369 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
@@ -83,12 +83,28 @@ public void detach() {
@Override
public boolean isAttached() {
- return attached;
+ return scope != null;
}
@Override
- public boolean attachToCurrentScope() {
- return TensorScope.autoAttach(this);
+ public synchronized void attachToParent() {
+ if(scope == null){
+ throw new IllegalStateException("Can't attach to parent: no scope.");
+ }
+ if(scope.parent == null){
+ throw new IllegalStateException("Can't attach to parent: scope does not have a parent.");
+ }
+
+ scope.parent.attach(this);
+ }
+
+ @Override
+ public void attachToCurrentScope() {
+ TensorScope scope = TensorScope.currentScope();
+ if(scope == null){
+ throw new IllegalStateException("Can't attach to current scope: no active tensor scopes.");
+ }
+ scope.attach(this);
}
/**
@@ -231,12 +247,16 @@ private static long[] shape(TF_Tensor handle) {
RawTensor(TensorTypeInfo extends TType> typeInfo, Shape shape) {
this.typeInfo = typeInfo;
this.shape = shape;
- TensorScope.autoAttach(this);
+
+ TensorScope currentScope = TensorScope.currentScope();
+ if(currentScope != null) {
+ this.scope = currentScope.attach(this);
+ }
}
private PointerScope tensorScope;
private boolean closed;
- boolean attached = false;
+ TensorScope scope;
private TF_Tensor tensorHandle;
private final TensorTypeInfo extends TType> typeInfo;
private final Shape shape;
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index 834c0c819fd..7009f03355b 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -223,14 +223,21 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
*/
void detach();
+ /**
+ * Attach this tensor to the parent of it's current scope, removing it from it's current scope.
+ * @throws IllegalStateException if it does not have a scope, or it's scope does not have a parent.
+ */
+ void attachToParent();
+
/**
* Returns true if this tensor is attached to a {@link TensorScope}.
*/
boolean isAttached();
/**
- * Attach this tensor to the most recent scope that accepts automatic attachment.
- * No-ops and returns false if there is no scope that does so.
+ * Attach this tensor to the most recent scope.
+ *
+ * @throws IllegalStateException if there are no active scopes
*/
- boolean attachToCurrentScope();
+ void attachToCurrentScope();
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index d6590a01f11..81a41097cb4 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -24,6 +24,7 @@
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
/**
@@ -32,7 +33,8 @@
* they are created in a sub-scope). Tensors may be manually closed earlier without issue.
*
* When auto-attach is true, tensors are automatically tracked on creation. A tensor can me manually added to a scope
- * with {@link TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. The tensor will then be closed when the first of it's managing scopes closes.
+ * with {@link TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. The tensor will then be closed
+ * when the first of it's managing scopes closes.
*
* {@link Tensor#detach()} detaches the tensor from all scopes, requiring the user to close it manually or attach it to
* another scope.
@@ -41,50 +43,32 @@
*/
public class TensorScope implements AutoCloseable {
- private static final Set allScopes = Collections.newSetFromMap(new WeakHashMap<>());
+ private static final InheritableThreadLocal currentScope = new InheritableThreadLocal<>();
- private static final ThreadLocal> scopeStack = ThreadLocal.withInitial(ArrayDeque::new);
+ public static TensorScope currentScope() {
+ TensorScope scope = currentScope.get();
- /**
- * Attach the tensor to the most recent scope that accepts automatic attachment.
- *
- * @return true if attached.
- */
- static boolean autoAttach(Tensor tensor) {
- Iterator iterator = scopeStack.get().descendingIterator();
- while (iterator.hasNext()) {
- TensorScope scope = iterator.next();
- if (scope.autoAttach) {
- scope.attach(tensor);
- return true;
- }
+ if (scope == null || !scope.closed) {
+ return scope;
}
- return false;
- }
- /**
- * Return true if there is a scope that accepts auto attachment on the stack.
- */
- public static boolean hasAutoScope() {
- Iterator iterator = scopeStack.get().descendingIterator();
- while (iterator.hasNext()) {
- TensorScope scope = iterator.next();
- if (scope.autoAttach) {
- return true;
- }
+ // scope could be closed in another thread, in which case this thread's currentScope wouldn't be updated
+ while (scope != null && scope.closed) {
+ scope = scope.parent;
}
- return false;
+ currentScope.set(scope);
+ return scope;
}
- /**
- * Detaches the given tensor from any scopes managing it, requiring it to be manually closed.
- */
- public static void detach(Tensor t) {
- RawTensor raw = t.asRawTensor();
- synchronized (TensorScope.class) {
- allScopes.forEach(x -> x.detachTensor(raw));
+ public static void detach(Tensor tensor) {
+ // ensure that I'm not attaching or detaching at the same time in different threads
+ RawTensor rt = tensor.asRawTensor();
+ synchronized (rt) {
+ if (rt.scope != null) {
+ rt.scope.tensors.remove(rt);
+ rt.scope = null;
+ }
}
- raw.attached = false;
}
/**
@@ -92,38 +76,41 @@ public static void detach(Tensor t) {
*
* @see TensorScope
*/
- public TensorScope(boolean autoAttach) {
- this.autoAttach = autoAttach;
+ public TensorScope() {
+ this.parent = currentScope();
+ currentScope.set(this);
- synchronized (TensorScope.class) {
- allScopes.add(this);
+ if (this.parent != null) {
+ synchronized (this.parent) {
+ this.parent.children.add(this);
+ }
}
-
- localScopeStack = scopeStack.get();
- localScopeStack.push(this);
- }
-
- /**
- * Create a new tensor scope that automatically manages tensors.
- */
- public TensorScope() {
- this(true);
}
/**
* Attach a tensor to this scope. This happens automatically to tensors that are created in the scope.
+ *
* @return this
*/
- public TensorScope attach(Tensor t) {
- RawTensor rt = t.asRawTensor();
- rt.attached = true;
- tensors.add(rt);
+ public synchronized TensorScope attach(Tensor tensor) {
+ if (this.closed) {
+ throw new IllegalStateException("Scope has been closed, can not attach new tensor.");
+ }
+
+ RawTensor rt = tensor.asRawTensor();
+ // ensure that I'm not attaching or detaching at the same time in different threads
+ synchronized (rt) {
+ detach(tensor);
+ rt.scope = this;
+ tensors.add(rt);
+ }
return this;
}
/**
* Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ *
* @return this
*/
public TensorScope attach(Tensor... tensors) {
@@ -138,6 +125,7 @@ public TensorScope attach(Tensor... tensors) {
/**
* Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ *
* @return this
*/
public TensorScope attach(HasTensors tensors) {
@@ -148,6 +136,7 @@ public TensorScope attach(HasTensors tensors) {
/**
* Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ *
* @return this
*/
public TensorScope attach(HasTensors... tensors) {
@@ -162,6 +151,7 @@ public TensorScope attach(HasTensors... tensors) {
/**
* Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ *
* @return this
*/
public TensorScope attach(Iterable tensors) {
@@ -172,9 +162,11 @@ public TensorScope attach(Iterable tensors) {
/**
* Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
+ *
* @return this
*/
- public TensorScope attach(Iterable... tensors) {
+ @SafeVarargs
+ public final TensorScope attach(Iterable... tensors) {
if (tensors != null) {
for (Iterable ht : tensors) {
attach(ht);
@@ -184,52 +176,76 @@ public TensorScope attach(Iterable... tensors) {
return this;
}
- private void detachTensor(Tensor t) {
- tensors.remove(t.asRawTensor());
- }
+ /**
+ * Closes this scope and its tensors, and any inner scopes.
+ */
+ @Override
+ public synchronized void close() {
+ if (closed) {
+ return;
+ }
- private void closeScope() {
+ children.forEach(TensorScope::close);
tensors.forEach(Tensor::close);
- synchronized (TensorScope.class) {
- allScopes.remove(this);
+ closed = true;
+
+ parent.children.remove(this);
+
+ if (currentScope() == this) {
+ currentScope.set(this.parent);
}
+ }
- closed = true;
+ /**
+ * Release the tensors and child scopes of this scope to it's parent, without closing them.
+ *
+ * @throws IllegalStateException if this scope has no parent.
+ */
+ public synchronized void releaseToParent() {
+ release(true);
}
/**
- * Closes this scope and its tensors, and any inner scopes.
+ * Release the tensors and child scopes of this scope without closing them, to it's parent if it has one.
+ *
+ * @param requireParent Whether to require a parent scope to release resources to.
+ * @throws IllegalStateException if this scope has no parent, but {@code requireParent} is true.
*/
- @Override
- public void close() {
+ public synchronized void release(boolean requireParent) {
if (closed) {
return;
}
- if (!localScopeStack.contains(this)) {
- throw new IllegalStateException("This scope is not on the scope stack, but was not closed."
- + " This should not be possible.");
+ if (this.parent == null && requireParent) {
+ throw new IllegalStateException("Can't release to parent: scope does not have parent.");
}
- while (true) {
- TensorScope ts = localScopeStack.removeLast();
- ts.closeScope();
- if (ts == this) {
- return;
- }
+ if (this.parent != null) {
+ TensorScope newParent = this.parent;
+ newParent.children.addAll(children);
+ children.forEach(x -> x.parent = newParent);
+ tensors.forEach(newParent::attach);
+ } else {
+ children.forEach(x -> x.parent = null);
+ tensors.forEach(TensorScope::detach);
}
+
+ children.clear();
+ tensors.clear();
+
+ close();
}
/**
* Gets whether the scope is closed.
*/
- public boolean isClosed() {
+ public synchronized boolean isClosed() {
return closed;
}
- private final boolean autoAttach;
private boolean closed = false;
- private final Set tensors = new HashSet<>();
- private final Deque localScopeStack;
+ private final Set tensors = ConcurrentHashMap.newKeySet();
+ TensorScope parent;
+ private final Set children = ConcurrentHashMap.newKeySet();
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
index a2bffe29575..b860a86be5a 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
@@ -91,13 +91,18 @@ default void detach(){
asRawTensor().detach();
}
+ @Override
+ default void attachToParent(){
+ asRawTensor().attachToParent();
+ }
+
@Override
default boolean isAttached(){
return asRawTensor().isAttached();
}
@Override
- default boolean attachToCurrentScope(){
- return asRawTensor().attachToCurrentScope();
+ default void attachToCurrentScope(){
+ asRawTensor().attachToCurrentScope();
}
}
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
index 74f4f6d19f7..76a83954d41 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -97,25 +97,25 @@ public void testAttach(){
firstScope.close();
}
- @Test
- public void testNoAutoAttach(){
- TensorScope scope = new TensorScope(false);
- TFloat32 tensor = makeTensor(10);
- assertFalse(tensor.isAttached());
-
- TFloat32 detachTensor = makeTensor(10);
- assertFalse(detachTensor.isAttached());
-
- scope.attach(detachTensor);
- assertTrue(detachTensor.isAttached());
-
- detachTensor.detach();
- assertFalse(detachTensor.isAttached());
-
- tensor.close();
- detachTensor.close();
- scope.close();
- }
+// @Test
+// public void testNoAutoAttach(){
+// TensorScope scope = new TensorScope(false);
+// TFloat32 tensor = makeTensor(10);
+// assertFalse(tensor.isAttached());
+//
+// TFloat32 detachTensor = makeTensor(10);
+// assertFalse(detachTensor.isAttached());
+//
+// scope.attach(detachTensor);
+// assertTrue(detachTensor.isAttached());
+//
+// detachTensor.detach();
+// assertFalse(detachTensor.isAttached());
+//
+// tensor.close();
+// detachTensor.close();
+// scope.close();
+// }
}
From 393b5dacbda3dcafd18bd5c919526cecaf7b8795 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 18:20:39 -0800
Subject: [PATCH 11/35] fix NPE
Signed-off-by: Ryan Nett
---
.../src/main/java/org/tensorflow/TensorScope.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index 81a41097cb4..ec521c39d72 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -190,7 +190,9 @@ public synchronized void close() {
closed = true;
- parent.children.remove(this);
+ if(parent != null) {
+ parent.children.remove(this);
+ }
if (currentScope() == this) {
currentScope.set(this.parent);
From 7a3f365842873f78ef49f1e07dbe0fd2737e8019 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 18:27:07 -0800
Subject: [PATCH 12/35] Javadoc updates
Signed-off-by: Ryan Nett
---
.../src/main/java/org/tensorflow/Tensor.java | 1 +
.../main/java/org/tensorflow/TensorScope.java | 22 ++++++++++++-------
2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index 7009f03355b..b6715a2e764 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -39,6 +39,7 @@
* doSomethingWith(t);
* }
* }
+ * This can be done automatically using {@link TensorScope}.
*
Instances of a Tensor are not thread-safe.
*/
public interface Tensor extends Shaped, AutoCloseable {
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index ec521c39d72..9d6f2acb5ed 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -28,18 +28,21 @@
/**
- * A scope that can be used to manage tensor resources. If auto-attach is used, any tensors created between a scope's
- * creation and calling {@code close()}, that haven't been detached, are guaranteed to be closed with the scope (even if
- * they are created in a sub-scope). Tensors may be manually closed earlier without issue.
+ * A scope that can be used to manage tensor resources. Any tensors created between a scope's
+ * creation and calling {@code close()} that haven't been detached or attached to a different scope are guaranteed to
+ * be closed with the scope (even if they are created in a sub-scope). Tensors may be manually closed earlier without
+ * issue.
*
- * When auto-attach is true, tensors are automatically tracked on creation. A tensor can me manually added to a scope
- * with {@link TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. The tensor will then be closed
- * when the first of it's managing scopes closes.
+ * Tensors are automatically tracked on creation. A tensor can me manually added to a scope
+ * with {@link TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. A tensor may only have one scope:
+ * if it currently has a scope when {@code attach} is called, it is removed from it's original scope.
*
- * {@link Tensor#detach()} detaches the tensor from all scopes, requiring the user to close it manually or attach it to
+ * {@link Tensor#detach()} detaches the tensor from it's scope, requiring the user to close it manually or attach it to
* another scope.
*
- * Note that scope management is thread local, except for detach, which will detach even from scopes on other threads.
+ * Note that scope management is mostly thread local. The current scope hierarchy will be inherited by new threads,
+ * and closing a scope will close it's children regardless of which threads they are on, but the active scope is
+ * thread local.
*/
public class TensorScope implements AutoCloseable {
@@ -211,6 +214,9 @@ public synchronized void releaseToParent() {
/**
* Release the tensors and child scopes of this scope without closing them, to it's parent if it has one.
*
+ *
WARNING: this method may release resources without assigning them to another scope if
+ * {@code requireParent} is false. {@link #releaseToParent()} should be used instead wherever possible.
+ *
* @param requireParent Whether to require a parent scope to release resources to.
* @throws IllegalStateException if this scope has no parent, but {@code requireParent} is true.
*/
From cd6f3d2e7d272baf20388bb8fca84d23d3dc66ed Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 18:40:22 -0800
Subject: [PATCH 13/35] New tests, remove eager session tensor closing test
Signed-off-by: Ryan Nett
---
.../java/org/tensorflow/TensorScopeTest.java | 80 ++++++++++++++-----
.../test/java/org/tensorflow/TensorTest.java | 17 ----
2 files changed, 61 insertions(+), 36 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
index 76a83954d41..b36f7f3e60e 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -97,25 +97,67 @@ public void testAttach(){
firstScope.close();
}
-// @Test
-// public void testNoAutoAttach(){
-// TensorScope scope = new TensorScope(false);
-// TFloat32 tensor = makeTensor(10);
-// assertFalse(tensor.isAttached());
-//
-// TFloat32 detachTensor = makeTensor(10);
-// assertFalse(detachTensor.isAttached());
-//
-// scope.attach(detachTensor);
-// assertTrue(detachTensor.isAttached());
-//
-// detachTensor.detach();
-// assertFalse(detachTensor.isAttached());
-//
-// tensor.close();
-// detachTensor.close();
-// scope.close();
-// }
+ @Test
+ public void testUpwardsAttach(){
+ TensorScope firstScope = new TensorScope();
+ TFloat32 tensor = makeTensor(10);
+ TensorScope secondScope = new TensorScope().attach(tensor);
+
+ firstScope.close();
+
+ assertTrue(tensor.isAttached());
+ assertFalse(tensor.isClosed());
+
+ secondScope.close();
+
+ assertTrue(tensor.isClosed());
+ }
+
+ @Test
+ public void testReleaseToParentScope() {
+ TensorScope outerScope = new TensorScope();
+ TensorScope scope = new TensorScope();
+
+ TFloat32 tensor = makeTensor(10);
+
+ assertTrue(tensor.isAttached());
+ assertFalse(tensor.isClosed());
+
+ scope.releaseToParent();
+
+ assertTrue(scope.isClosed());
+ assertTrue(tensor.isAttached());
+ assertFalse(tensor.isClosed());
+
+ outerScope.close();
+
+ assertTrue(tensor.isClosed());
+ assertTrue(outerScope.isClosed());
+ }
+
+ @Test
+ public void testAttachToParentScope() {
+ TensorScope outerScope = new TensorScope();
+ TensorScope scope = new TensorScope();
+
+ TFloat32 tensor = makeTensor(10);
+
+ assertTrue(tensor.isAttached());
+ assertFalse(tensor.isClosed());
+
+ tensor.attachToParent();
+
+ scope.close();
+
+ assertTrue(scope.isClosed());
+ assertTrue(tensor.isAttached());
+ assertFalse(tensor.isClosed());
+
+ outerScope.close();
+
+ assertTrue(tensor.isClosed());
+ assertTrue(outerScope.isClosed());
+ }
}
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorTest.java
index 9415a986222..6b9cb202b97 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorTest.java
@@ -487,23 +487,6 @@ public void useAfterClose() {
}
}
- @Test
- public void eagerTensorIsReleasedAfterSessionIsClosed() {
- TInt32 sum;
- try (EagerSession session = EagerSession.create()) {
- Ops tf = Ops.create(session);
- sum = tf.math.add(tf.constant(10), tf.constant(20)).asTensor();
- sum.asRawTensor().nativeHandle(); // does not throw
- assertEquals(30, sum.getInt());
- }
- try {
- sum.asRawTensor().nativeHandle();
- fail("Tensor native handle should have been closed by ending eager session");
- } catch (IllegalStateException e) {
- // as expected
- }
- }
-
@Test
public void fromHandle() {
// fromHandle is a package-visible method intended for use when the C TF_Tensor object has been
From 6bc6fceda01739217927216fddab65a0f3e26ce2 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 18:46:41 -0800
Subject: [PATCH 14/35] remove incorrect test
Signed-off-by: Ryan Nett
---
.../java/org/tensorflow/TensorScopeTest.java | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
index b36f7f3e60e..22ca77147a2 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -97,22 +97,6 @@ public void testAttach(){
firstScope.close();
}
- @Test
- public void testUpwardsAttach(){
- TensorScope firstScope = new TensorScope();
- TFloat32 tensor = makeTensor(10);
- TensorScope secondScope = new TensorScope().attach(tensor);
-
- firstScope.close();
-
- assertTrue(tensor.isAttached());
- assertFalse(tensor.isClosed());
-
- secondScope.close();
-
- assertTrue(tensor.isClosed());
- }
-
@Test
public void testReleaseToParentScope() {
TensorScope outerScope = new TensorScope();
From e2cd3665aa8171de8d1ba91022915d66ef7d8c50 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 18:48:53 -0800
Subject: [PATCH 15/35] clarify threading docs
Signed-off-by: Ryan Nett
---
.../src/main/java/org/tensorflow/TensorScope.java | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index 9d6f2acb5ed..ab3da511ceb 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -40,9 +40,8 @@
* {@link Tensor#detach()} detaches the tensor from it's scope, requiring the user to close it manually or attach it to
* another scope.
*
- * Note that scope management is mostly thread local. The current scope hierarchy will be inherited by new threads,
- * and closing a scope will close it's children regardless of which threads they are on, but the active scope is
- * thread local.
+ * Scopes will be inherited at thread creation, but further scope creation on different threads will be independent,
+ * other than having the same parent. Closing a scope will close it's children regardless of which threads they are on.
*/
public class TensorScope implements AutoCloseable {
From f3ff90abdc196468f5165ec9f55822a785f8d36f Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 18:50:29 -0800
Subject: [PATCH 16/35] grammar
Signed-off-by: Ryan Nett
---
.../src/main/java/org/tensorflow/HasTensors.java | 2 +-
.../src/main/java/org/tensorflow/Tensor.java | 4 ++--
.../src/main/java/org/tensorflow/TensorScope.java | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
index ae0661e0da7..ccb2f242fb2 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
@@ -51,7 +51,7 @@ default void attachToCurrentScope() {
}
/**
- * Attach these tensors to the parent of their current scope, removing it from it's current scope.
+ * Attach these tensors to the parent of their current scope, removing it from its current scope.
* @throws IllegalStateException if any tensors do not have a scope, or their scope does not have a parent.
*/
default void attachToParent(){
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index b6715a2e764..bd56146fa03 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -225,8 +225,8 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
void detach();
/**
- * Attach this tensor to the parent of it's current scope, removing it from it's current scope.
- * @throws IllegalStateException if it does not have a scope, or it's scope does not have a parent.
+ * Attach this tensor to the parent of it's current scope, removing it from its current scope.
+ * @throws IllegalStateException if it does not have a scope, or its scope does not have a parent.
*/
void attachToParent();
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index ab3da511ceb..cb8afe50af4 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -35,7 +35,7 @@
*
* Tensors are automatically tracked on creation. A tensor can me manually added to a scope
* with {@link TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. A tensor may only have one scope:
- * if it currently has a scope when {@code attach} is called, it is removed from it's original scope.
+ * if it currently has a scope when {@code attach} is called, it is removed from its original scope.
*
* {@link Tensor#detach()} detaches the tensor from it's scope, requiring the user to close it manually or attach it to
* another scope.
From 37e03746c7758b754e4e232a6b390337b61b7d51 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 18:51:06 -0800
Subject: [PATCH 17/35] formatting
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/HasTensors.java | 3 +-
.../main/java/org/tensorflow/RawTensor.java | 8 +--
.../src/main/java/org/tensorflow/Tensor.java | 70 +++++++++----------
.../main/java/org/tensorflow/TensorScope.java | 15 ++--
.../java/org/tensorflow/TensorScopeTest.java | 2 +-
5 files changed, 48 insertions(+), 50 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
index ccb2f242fb2..455afdcfb31 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
@@ -52,9 +52,10 @@ default void attachToCurrentScope() {
/**
* Attach these tensors to the parent of their current scope, removing it from its current scope.
+ *
* @throws IllegalStateException if any tensors do not have a scope, or their scope does not have a parent.
*/
- default void attachToParent(){
+ default void attachToParent() {
tensors().forEach(Tensor::attachToParent);
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
index f334a9d4369..f754349c715 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
@@ -88,10 +88,10 @@ public boolean isAttached() {
@Override
public synchronized void attachToParent() {
- if(scope == null){
+ if (scope == null) {
throw new IllegalStateException("Can't attach to parent: no scope.");
}
- if(scope.parent == null){
+ if (scope.parent == null) {
throw new IllegalStateException("Can't attach to parent: scope does not have a parent.");
}
@@ -101,7 +101,7 @@ public synchronized void attachToParent() {
@Override
public void attachToCurrentScope() {
TensorScope scope = TensorScope.currentScope();
- if(scope == null){
+ if (scope == null) {
throw new IllegalStateException("Can't attach to current scope: no active tensor scopes.");
}
scope.attach(this);
@@ -249,7 +249,7 @@ private static long[] shape(TF_Tensor handle) {
this.shape = shape;
TensorScope currentScope = TensorScope.currentScope();
- if(currentScope != null) {
+ if (currentScope != null) {
this.scope = currentScope.attach(this);
}
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index bd56146fa03..0eb35ec3614 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -26,13 +26,13 @@
* A statically typed multi-dimensional array.
*
* There are two categories of tensors in TensorFlow Java: {@link TType typed tensors} and
- * {@link RawTensor raw tensors}. The former maps the tensor native memory to an
- * n-dimensional typed data space, allowing direct I/O operations from the JVM, while the latter
- * is only a reference to a native tensor allowing basic operations and flat data access.
+ * {@link RawTensor raw tensors}. The former maps the tensor native memory to an n-dimensional typed data space,
+ * allowing direct I/O operations from the JVM, while the latter is only a reference to a native tensor allowing basic
+ * operations and flat data access.
*
* WARNING: Resources consumed by the Tensor object must be explicitly freed by
- * invoking the {@link #close()} method when the object is no longer needed. For example, using a
- * try-with-resources block:
+ * invoking the {@link #close()} method when the object is no longer needed. For example, using a try-with-resources
+ * block:
*
*
{@code
* try (Tensor t = Tensor.of(...)) {
@@ -54,10 +54,9 @@ public interface Tensor extends Shaped, AutoCloseable {
* @param type the tensor type class
* @param shape shape of the tensor
* @return an allocated but uninitialized tensor
- * @throws IllegalArgumentException if elements of the given {@code type} are of variable length
- * (e.g. strings)
- * @throws IllegalArgumentException if {@code shape} is totally or partially
- * {@link Shape#hasUnknownDimension() unknown}
+ * @throws IllegalArgumentException if elements of the given {@code type} are of variable length (e.g. strings)
+ * @throws IllegalArgumentException if {@code shape} is totally or partially {@link Shape#hasUnknownDimension()
+ * unknown}
* @throws IllegalStateException if tensor failed to be allocated
*/
static T of(Class type, Shape shape) {
@@ -68,27 +67,27 @@ static T of(Class type, Shape shape) {
* Allocates a tensor of a given datatype, shape and size.
*
* This method is identical to {@link #of(Class, Shape)}, except that the final size of the
- * tensor can be explicitly set instead of computing it from the datatype and shape, which could be
- * larger than the actual space required to store the data but not smaller.
+ * tensor can be explicitly set instead of computing it from the datatype and shape, which could be larger than the
+ * actual space required to store the data but not smaller.
*
* @param the tensor type
* @param type the tensor type class
* @param shape shape of the tensor
* @param size size in bytes of the tensor or -1 to compute the size from the shape
* @return an allocated but uninitialized tensor
- * @see #of(Class, Shape)
- * @throws IllegalArgumentException if {@code size} is smaller than the minimum space required to
- * store the tensor data
- * @throws IllegalArgumentException if {@code size} is set to -1 but elements of the given
- * {@code type} are of variable length (e.g. strings)
- * @throws IllegalArgumentException if {@code shape} is totally or partially
- * {@link Shape#hasUnknownDimension() unknown}
+ * @throws IllegalArgumentException if {@code size} is smaller than the minimum space required to store the tensor
+ * data
+ * @throws IllegalArgumentException if {@code size} is set to -1 but elements of the given {@code type} are of
+ * variable length (e.g. strings)
+ * @throws IllegalArgumentException if {@code shape} is totally or partially {@link Shape#hasUnknownDimension()
+ * unknown}
* @throws IllegalStateException if tensor failed to be allocated
+ * @see #of(Class, Shape)
*/
static T of(Class type, Shape shape, long size) {
RawTensor tensor = RawTensor.allocate(type, shape, size);
try {
- return (T)tensor.asTypedTensor();
+ return (T) tensor.asTypedTensor();
} catch (Exception e) {
tensor.close();
throw e;
@@ -99,8 +98,8 @@ static T of(Class type, Shape shape, long size) {
* Allocates and initialize a tensor of a given datatype and shape.
*
* The amount of memory to allocate is derived from the datatype and the shape of the tensor.
- * Tensor data is initialized by calling the {@code dataInitializer}, which receives in argument
- * the value returned by {@link #data()} on the allocated tensor. For example:
+ * Tensor data is initialized by calling the {@code dataInitializer}, which receives in argument the value returned by
+ * {@link #data()} on the allocated tensor. For example:
*
*
{@code
* FloatNdArray data = ...
@@ -117,10 +116,9 @@ static T of(Class type, Shape shape, long size) {
* @param shape shape of the tensor
* @param dataInitializer method receiving accessor to the allocated tensor data for initialization
* @return an allocated and initialized tensor
- * @throws IllegalArgumentException if elements of the given {@code type} are of variable length
- * (e.g. strings)
- * @throws IllegalArgumentException if {@code shape} is totally or partially
- * {@link Shape#hasUnknownDimension() unknown}
+ * @throws IllegalArgumentException if elements of the given {@code type} are of variable length (e.g. strings)
+ * @throws IllegalArgumentException if {@code shape} is totally or partially {@link Shape#hasUnknownDimension()
+ * unknown}
* @throws IllegalStateException if tensor failed to be allocated
*/
static T of(Class type, Shape shape, Consumer dataInitializer) {
@@ -142,14 +140,14 @@ static T of(Class type, Shape shape, Consumer dataInitia
* @param size size in bytes of the tensor or -1 to compute the size from the shape
* @param dataInitializer method receiving accessor to the allocated tensor data for initialization
* @return an allocated and initialized tensor
- * @see #of(Class, Shape, long, Consumer)
- * @throws IllegalArgumentException if {@code size} is smaller than the minimum space required to
- * store the tensor data
- * @throws IllegalArgumentException if {@code size} is set to -1 but elements of the given
- * {@code type} are of variable length (e.g. strings)
- * @throws IllegalArgumentException if {@code shape} is totally or partially
- * {@link Shape#hasUnknownDimension() unknown}
+ * @throws IllegalArgumentException if {@code size} is smaller than the minimum space required to store the tensor
+ * data
+ * @throws IllegalArgumentException if {@code size} is set to -1 but elements of the given {@code type} are of
+ * variable length (e.g. strings)
+ * @throws IllegalArgumentException if {@code shape} is totally or partially {@link Shape#hasUnknownDimension()
+ * unknown}
* @throws IllegalStateException if tensor failed to be allocated
+ * @see #of(Class, Shape, long, Consumer)
*/
static T of(Class type, Shape shape, long size, Consumer dataInitializer) {
T tensor = of(type, shape, size);
@@ -172,10 +170,9 @@ static T of(Class type, Shape shape, long size, Consumer
* @param type the tensor type class
* @param shape the tensor shape.
* @param rawData a buffer containing the tensor raw data.
- * @throws IllegalArgumentException if {@code rawData} is not large enough to contain the tensor
- * data
- * @throws IllegalArgumentException if {@code shape} is totally or partially
- * {@link Shape#hasUnknownDimension() unknown}
+ * @throws IllegalArgumentException if {@code rawData} is not large enough to contain the tensor data
+ * @throws IllegalArgumentException if {@code shape} is totally or partially {@link Shape#hasUnknownDimension()
+ * unknown}
* @throws IllegalStateException if tensor failed to be allocated with the given parameters
*/
static T of(Class type, Shape shape, ByteDataBuffer rawData) {
@@ -226,6 +223,7 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
/**
* Attach this tensor to the parent of it's current scope, removing it from its current scope.
+ *
* @throws IllegalStateException if it does not have a scope, or its scope does not have a parent.
*/
void attachToParent();
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index cb8afe50af4..b389b891c6e 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -28,14 +28,13 @@
/**
- * A scope that can be used to manage tensor resources. Any tensors created between a scope's
- * creation and calling {@code close()} that haven't been detached or attached to a different scope are guaranteed to
- * be closed with the scope (even if they are created in a sub-scope). Tensors may be manually closed earlier without
- * issue.
+ * A scope that can be used to manage tensor resources. Any tensors created between a scope's creation and calling
+ * {@code close()} that haven't been detached or attached to a different scope are guaranteed to be closed with the
+ * scope (even if they are created in a sub-scope). Tensors may be manually closed earlier without issue.
*
- * Tensors are automatically tracked on creation. A tensor can me manually added to a scope
- * with {@link TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. A tensor may only have one scope:
- * if it currently has a scope when {@code attach} is called, it is removed from its original scope.
+ * Tensors are automatically tracked on creation. A tensor can me manually added to a scope with {@link
+ * TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. A tensor may only have one scope: if it
+ * currently has a scope when {@code attach} is called, it is removed from its original scope.
*
* {@link Tensor#detach()} detaches the tensor from it's scope, requiring the user to close it manually or attach it to
* another scope.
@@ -192,7 +191,7 @@ public synchronized void close() {
closed = true;
- if(parent != null) {
+ if (parent != null) {
parent.children.remove(this);
}
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
index 22ca77147a2..f1652233730 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -83,7 +83,7 @@ public void testNestedScope() {
}
@Test
- public void testAttach(){
+ public void testAttach() {
TensorScope firstScope = new TensorScope();
TFloat32 tensor = makeTensor(10);
TensorScope secondScope = new TensorScope().attach(tensor);
From 08376347b9f2ace6aa5becd69810e5a7028a2b16 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Fri, 15 Jan 2021 18:52:41 -0800
Subject: [PATCH 18/35] Add note about different scopes
Signed-off-by: Ryan Nett
---
.../src/main/java/org/tensorflow/HasTensors.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
index 455afdcfb31..2c8fa17a6b4 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
@@ -53,6 +53,10 @@ default void attachToCurrentScope() {
/**
* Attach these tensors to the parent of their current scope, removing it from its current scope.
*
+ * Note that if tensors have different scopes, each tensor will be attached to its scope's parent.
+ * {@link TensorScope#attach(HasTensors)} or {@link #attachToCurrentScope()} can be used to ensure all tensors have
+ * the same scope.
+ *
* @throws IllegalStateException if any tensors do not have a scope, or their scope does not have a parent.
*/
default void attachToParent() {
From 555b13bc9f0f23e2edfbbccd59298cf884b963da Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Sat, 16 Jan 2021 15:17:15 -0800
Subject: [PATCH 19/35] Add option to not require parent to Tensor and
HasTensors
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/HasTensors.java | 20 +++++++++++++++-
.../main/java/org/tensorflow/RawTensor.java | 10 +++++---
.../src/main/java/org/tensorflow/Tensor.java | 21 +++++++++++++++--
.../org/tensorflow/types/family/TType.java | 23 +++++++++----------
4 files changed, 56 insertions(+), 18 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
index 2c8fa17a6b4..c24124cf757 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
@@ -50,6 +50,24 @@ default void attachToCurrentScope() {
tensors().forEach(scope::attach);
}
+
+ /**
+ * Attach these tensors to the parents of their current scopes, removing them from their current scopes.
+ *
+ * If {@code requireParent} is false, detaches each tensor if its scope does not have a parent. Otherwise, if
+ * {@code requireParent} is true and the scope does not have a parent, throws {@link IllegalStateException}.
+ *
+ *
WARNING: this method may release resources without assigning them to another scope if
+ * * {@code requireParent} is false. {@link #attachToParent()} should be used instead wherever possible.
+ *
+ * @param requireParent Whether to require a parent scope to release resources to.
+ * @throws IllegalStateException if the tensor does not have a scope, or if this scope has no parent, but {@code
+ * requireParent} is true
+ */
+ default void attachToParent(boolean requireParent) {
+ tensors().forEach(x -> x.attachToParent(requireParent));
+ }
+
/**
* Attach these tensors to the parent of their current scope, removing it from its current scope.
*
@@ -60,7 +78,7 @@ default void attachToCurrentScope() {
* @throws IllegalStateException if any tensors do not have a scope, or their scope does not have a parent.
*/
default void attachToParent() {
- tensors().forEach(Tensor::attachToParent);
+ attachToParent(true);
}
/**
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
index f754349c715..803207c548c 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
@@ -87,15 +87,19 @@ public boolean isAttached() {
}
@Override
- public synchronized void attachToParent() {
+ public synchronized void attachToParent(boolean requireParent) {
if (scope == null) {
throw new IllegalStateException("Can't attach to parent: no scope.");
}
- if (scope.parent == null) {
+ if (scope.parent == null && requireParent) {
throw new IllegalStateException("Can't attach to parent: scope does not have a parent.");
}
- scope.parent.attach(this);
+ if (scope.parent != null) {
+ scope.parent.attach(this);
+ } else {
+ this.detach();
+ }
}
@Override
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index 0eb35ec3614..7efc7d32d9f 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -224,9 +224,26 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
/**
* Attach this tensor to the parent of it's current scope, removing it from its current scope.
*
- * @throws IllegalStateException if it does not have a scope, or its scope does not have a parent.
+ * @throws IllegalStateException if the tensor does not have a scope, or its scope does not have a parent.
*/
- void attachToParent();
+ default void attachToParent() {
+ attachToParent(true);
+ }
+
+ /**
+ * Attach this tensor to the parent of it's current scope, removing it from its current scope.
+ *
+ * If {@code requireParent} is false, detaches the tensor if its scope does not have a parent. Otherwise, if
+ * {@code requireParent} is true and the scope does not have a parent, throws {@link IllegalStateException}.
+ *
+ *
WARNING: this method may release resources without assigning them to another scope if
+ * * {@code requireParent} is false. {@link #attachToParent()} should be used instead wherever possible.
+ *
+ * @param requireParent Whether to require a parent scope to release resources to.
+ * @throws IllegalStateException if the tensor does not have a scope, or if this scope has no parent, but {@code
+ * requireParent} is true
+ */
+ void attachToParent(boolean requireParent);
/**
* Returns true if this tensor is attached to a {@link TensorScope}.
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
index b860a86be5a..712ba660cc2 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
@@ -27,10 +27,9 @@
* to a n-dimensional data space allowing direct I/O access from the JVM.
*
* Subinterfaces of {@code TType} are propagated as a generic parameter to various entities of
- * TensorFlow to identify the type of the tensor they carry. For example, a
- * {@link org.tensorflow.Operand Operand} is an operand which outputs a 32-bit floating
- * point tensor. This parameter ensure type-compatibility between operands of a computation at
- * compile-time. For example:
+ * TensorFlow to identify the type of the tensor they carry. For example, a {@link org.tensorflow.Operand
+ * Operand} is an operand which outputs a 32-bit floating point tensor. This parameter ensure
+ * type-compatibility between operands of a computation at compile-time. For example:
*
* {@code
* Ops tf = Ops.create();
@@ -44,8 +43,8 @@
* }
*
* Even if all typed tensors implements somehow {@link org.tensorflow.ndarray.NdArray NdArray}
- * to provide access to their data, {@code TType} deliberately does not extend directly from this
- * interface, for the following reasons:
+ * to provide access to their data, {@code TType} deliberately does not extend directly from this interface, for the
+ * following reasons:
*
* - Implementing {@code NdArray} at this level could only expose boxed-type accessors, which
* are less performant than their primitive equivalent, only exposed by subinterfaces of
@@ -82,27 +81,27 @@ default void close() {
}
@Override
- default boolean isClosed(){
+ default boolean isClosed() {
return asRawTensor().isClosed();
}
@Override
- default void detach(){
+ default void detach() {
asRawTensor().detach();
}
@Override
- default void attachToParent(){
- asRawTensor().attachToParent();
+ default void attachToParent(boolean requireParent) {
+ asRawTensor().attachToParent(requireParent);
}
@Override
- default boolean isAttached(){
+ default boolean isAttached() {
return asRawTensor().isAttached();
}
@Override
- default void attachToCurrentScope(){
+ default void attachToCurrentScope() {
asRawTensor().attachToCurrentScope();
}
}
From 4319a650e4599d29b59e9e90de865b5f7efc9671 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Mon, 18 Jan 2021 21:01:39 -0800
Subject: [PATCH 20/35] Adjust API to be more explicit, add release
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/HasTensors.java | 45 ---
.../main/java/org/tensorflow/RawTensor.java | 32 +-
.../src/main/java/org/tensorflow/Tensor.java | 33 +-
.../main/java/org/tensorflow/TensorScope.java | 339 +++++++++++++-----
.../org/tensorflow/types/family/TType.java | 15 -
.../java/org/tensorflow/TensorScopeTest.java | 4 +-
6 files changed, 253 insertions(+), 215 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
index c24124cf757..5d8344d22a0 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
@@ -35,51 +35,6 @@ default void detach() {
tensors().forEach(Tensor::detach);
}
- /**
- * Attach all of these tensors to the most recent scope.
- *
- * @throws IllegalStateException if there is no active scope.
- * @see Tensor#attachToCurrentScope()
- */
- default void attachToCurrentScope() {
- TensorScope scope = TensorScope.currentScope();
- if (scope == null) {
- throw new IllegalStateException("Can't attach to current scope: no active tensor scopes.");
- }
-
- tensors().forEach(scope::attach);
- }
-
-
- /**
- * Attach these tensors to the parents of their current scopes, removing them from their current scopes.
- *
- *
If {@code requireParent} is false, detaches each tensor if its scope does not have a parent. Otherwise, if
- * {@code requireParent} is true and the scope does not have a parent, throws {@link IllegalStateException}.
- *
- *
WARNING: this method may release resources without assigning them to another scope if
- * * {@code requireParent} is false. {@link #attachToParent()} should be used instead wherever possible.
- *
- * @param requireParent Whether to require a parent scope to release resources to.
- * @throws IllegalStateException if the tensor does not have a scope, or if this scope has no parent, but {@code
- * requireParent} is true
- */
- default void attachToParent(boolean requireParent) {
- tensors().forEach(x -> x.attachToParent(requireParent));
- }
-
- /**
- * Attach these tensors to the parent of their current scope, removing it from its current scope.
- *
- *
Note that if tensors have different scopes, each tensor will be attached to its scope's parent.
- * {@link TensorScope#attach(HasTensors)} or {@link #attachToCurrentScope()} can be used to ensure all tensors have
- * the same scope.
- *
- * @throws IllegalStateException if any tensors do not have a scope, or their scope does not have a parent.
- */
- default void attachToParent() {
- attachToParent(true);
- }
/**
* Release resources associated with these tensors.
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
index 803207c548c..b5b21c8c46b 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
@@ -76,41 +76,11 @@ public boolean isClosed() {
return closed;
}
- @Override
- public void detach() {
- TensorScope.detach(this);
- }
-
@Override
public boolean isAttached() {
return scope != null;
}
- @Override
- public synchronized void attachToParent(boolean requireParent) {
- if (scope == null) {
- throw new IllegalStateException("Can't attach to parent: no scope.");
- }
- if (scope.parent == null && requireParent) {
- throw new IllegalStateException("Can't attach to parent: scope does not have a parent.");
- }
-
- if (scope.parent != null) {
- scope.parent.attach(this);
- } else {
- this.detach();
- }
- }
-
- @Override
- public void attachToCurrentScope() {
- TensorScope scope = TensorScope.currentScope();
- if (scope == null) {
- throw new IllegalStateException("Can't attach to current scope: no active tensor scopes.");
- }
- scope.attach(this);
- }
-
/**
* Returns the raw data of this tensor as a buffer of bytes.
*
@@ -254,7 +224,7 @@ private static long[] shape(TF_Tensor handle) {
TensorScope currentScope = TensorScope.currentScope();
if (currentScope != null) {
- this.scope = currentScope.attach(this);
+ this.scope = currentScope.withAttached(this);
}
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
index 7efc7d32d9f..2910349aa7a 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java
@@ -218,42 +218,15 @@ static T of(Class type, Shape shape, ByteDataBuffer rawData
/**
* Detach this tensor from any scopes managing it. It must be manually closed or attached to another scope.
- */
- void detach();
-
- /**
- * Attach this tensor to the parent of it's current scope, removing it from its current scope.
*
- * @throws IllegalStateException if the tensor does not have a scope, or its scope does not have a parent.
+ * Semantically, this makes the tensor everyone's responsibility: whoever uses it last needs to close it.
*/
- default void attachToParent() {
- attachToParent(true);
+ default void detach() {
+ TensorScope.detach(this);
}
- /**
- * Attach this tensor to the parent of it's current scope, removing it from its current scope.
- *
- *
If {@code requireParent} is false, detaches the tensor if its scope does not have a parent. Otherwise, if
- * {@code requireParent} is true and the scope does not have a parent, throws {@link IllegalStateException}.
- *
- *
WARNING: this method may release resources without assigning them to another scope if
- * * {@code requireParent} is false. {@link #attachToParent()} should be used instead wherever possible.
- *
- * @param requireParent Whether to require a parent scope to release resources to.
- * @throws IllegalStateException if the tensor does not have a scope, or if this scope has no parent, but {@code
- * requireParent} is true
- */
- void attachToParent(boolean requireParent);
-
/**
* Returns true if this tensor is attached to a {@link TensorScope}.
*/
boolean isAttached();
-
- /**
- * Attach this tensor to the most recent scope.
- *
- * @throws IllegalStateException if there are no active scopes
- */
- void attachToCurrentScope();
}
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index b389b891c6e..4218005307f 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -16,14 +16,7 @@
*/
package org.tensorflow;
-import java.util.ArrayDeque;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
import java.util.Set;
-import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
@@ -33,7 +26,7 @@
* scope (even if they are created in a sub-scope). Tensors may be manually closed earlier without issue.
*
* Tensors are automatically tracked on creation. A tensor can me manually added to a scope with {@link
- * TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrentScope()}. A tensor may only have one scope: if it
+ * TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrent()}. A tensor may only have one scope: if it
* currently has a scope when {@code attach} is called, it is removed from its original scope.
*
* {@link Tensor#detach()} detaches the tensor from it's scope, requiring the user to close it manually or attach it to
@@ -61,17 +54,6 @@ public static TensorScope currentScope() {
return scope;
}
- public static void detach(Tensor tensor) {
- // ensure that I'm not attaching or detaching at the same time in different threads
- RawTensor rt = tensor.asRawTensor();
- synchronized (rt) {
- if (rt.scope != null) {
- rt.scope.tensors.remove(rt);
- rt.scope = null;
- }
- }
- }
-
/**
* Create a new tensor scope. If {@code autoAttach} is false, will not automatically manage tensors.
*
@@ -88,12 +70,154 @@ public TensorScope() {
}
}
+ /**
+ * Closes this scope and its tensors, and any inner scopes.
+ */
+ @Override
+ public synchronized void close() {
+ if (closed) {
+ return;
+ }
+
+ children.forEach(TensorScope::close);
+ tensors.forEach(Tensor::close);
+
+ closed = true;
+
+ if (parent != null) {
+ parent.children.remove(this);
+ }
+
+ if (currentScope() == this) {
+ currentScope.set(this.parent);
+ }
+ }
+
+ /**
+ * Release the tensors and child scopes of this scope to it's parent, without closing them.
+ *
+ * Semantically, calling this method makes all of the resources in this scope the parent's responsibility, as if this
+ * scope had never existed.
+ *
+ * This will close this scope, but does not close any of it's resources.
+ *
+ * @throws IllegalStateException if this scope has no parent. If this happens,
+ * * the scope is not closed and no resources are released.
+ */
+ public synchronized void releaseToParent() {
+ release(true);
+ }
+
+ /**
+ * Release the tensors and child scopes of this scope to it's parent, or detach them if this scope has no parent.
+ *
+ * Semantically, calling this method makes all of the resources in this scope the parent's responsibility, as if this
+ * scope had never existed. It can be used in a method to transfer control to the caller, leaving how the resources
+ * are managed up to the caller.
+ *
+ * This will close this scope, but does not close any of it's resources.
+ */
+ public synchronized void release() {
+ release(false);
+ }
+
+ /**
+ * Release the tensors and child scopes of this scope without closing them, to it's parent if it has one.
+ *
+ *
WARNING: this method may release resources without assigning them to another scope if
+ * {@code requireParent} is false. {@link #releaseToParent()} should be used instead wherever possible.
+ *
+ * @param requireParent Whether to require a parent scope to release resources to.
+ * @throws IllegalStateException if this scope has no parent, but {@code requireParent} is true. If this happens,
+ * the scope is not closed and no resources are released.
+ */
+ public synchronized void release(boolean requireParent) {
+ if (closed) {
+ return;
+ }
+
+ if (this.parent == null && requireParent) {
+ throw new IllegalStateException("Can't release to parent: scope does not have parent.");
+ }
+
+ if (this.parent != null) {
+ TensorScope newParent = this.parent;
+ newParent.children.addAll(children);
+ children.forEach(x -> x.parent = newParent);
+ tensors.forEach(newParent::attach);
+ } else {
+ children.forEach(x -> x.parent = null);
+ tensors.forEach(TensorScope::detach);
+ }
+
+ children.clear();
+ tensors.clear();
+
+ close();
+ }
+
+ public static T detach(T tensor) {
+ // ensure that I'm not attaching or detaching at the same time in different threads
+ RawTensor rt = tensor.asRawTensor();
+ synchronized (rt) {
+ if (rt.scope != null) {
+ rt.scope.tensors.remove(rt);
+ rt.scope = null;
+ }
+ }
+ return tensor;
+ }
+
+ /**
+ * @see #detach(Tensor)
+ */
+ public static void detach(Tensor... tensors){
+ for(Tensor t : tensors){
+ detach(t);
+ }
+ }
+
+ /**
+ * @see #detach(Tensor)
+ */
+ public static T detach(T tensors){
+ detach(tensors.tensors());
+ return tensors;
+ }
+
+ /**
+ * @see #detach(Tensor)
+ */
+ public static void detach(HasTensors... tensors){
+ for(HasTensors ht : tensors){
+ detach(ht);
+ }
+ }
+
+ /**
+ * @see #detach(Tensor)
+ */
+ public static > T detach(T tensors){
+ tensors.forEach(TensorScope::detach);
+ return tensors;
+ }
+
+ /**
+ * @see #detach(Tensor)
+ */
+ @SafeVarargs
+ public static void detach(Iterable extends Tensor>... tensors){
+ for(Iterable extends Tensor> iterable : tensors){
+ detach(iterable);
+ }
+ }
+
/**
* Attach a tensor to this scope. This happens automatically to tensors that are created in the scope.
*
* @return this
*/
- public synchronized TensorScope attach(Tensor tensor) {
+ public synchronized T attach(T tensor) {
if (this.closed) {
throw new IllegalStateException("Scope has been closed, can not attach new tensor.");
}
@@ -106,141 +230,172 @@ public synchronized TensorScope attach(Tensor tensor) {
tensors.add(rt);
}
- return this;
+ return tensor;
}
/**
- * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
- *
- * @return this
+ * @see #attach(Tensor)
*/
- public TensorScope attach(Tensor... tensors) {
+ public void attach(Tensor... tensors) {
if (tensors != null) {
for (Tensor t : tensors) {
attach(t);
}
}
-
- return this;
}
/**
- * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
- *
- * @return this
+ * @see #attach(Tensor)
*/
- public TensorScope attach(HasTensors tensors) {
- tensors.tensors().forEach(this::attach);
-
- return this;
+ public T attach(T tensors) {
+ attach(tensors.tensors());
+ return tensors;
}
/**
- * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
- *
- * @return this
+ * @see #attach(Tensor)
*/
- public TensorScope attach(HasTensors... tensors) {
+ public void attach(HasTensors... tensors) {
if (tensors != null) {
for (HasTensors ht : tensors) {
attach(ht);
}
}
-
- return this;
}
/**
- * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
- *
- * @return this
+ * @see #attach(Tensor)
*/
- public TensorScope attach(Iterable tensors) {
+ public > T attach(T tensors) {
tensors.forEach(this::attach);
- return this;
+ return tensors;
}
/**
- * Attach tensors to this scope. This happens automatically to tensors that are created in the scope.
- *
- * @return this
+ * @see #attach(Tensor)
*/
@SafeVarargs
- public final TensorScope attach(Iterable... tensors) {
+ public final void attach(Iterable extends Tensor>... tensors) {
if (tensors != null) {
- for (Iterable ht : tensors) {
+ for (Iterable extends Tensor> ht : tensors) {
attach(ht);
}
}
+ }
+ /**
+ * @see #attach(Tensor)
+ */
+ public TensorScope withAttached(Tensor... tensors){
+ attach(tensors);
return this;
}
/**
- * Closes this scope and its tensors, and any inner scopes.
+ * @see #attach(Tensor)
*/
- @Override
- public synchronized void close() {
- if (closed) {
- return;
- }
-
- children.forEach(TensorScope::close);
- tensors.forEach(Tensor::close);
+ public TensorScope withAttached(HasTensors... tensors){
+ attach(tensors);
+ return this;
+ }
- closed = true;
+ /**
+ * @see #attach(Tensor)
+ */
+ public TensorScope withAttached(Iterable extends Tensor>... tensors){
+ attach(tensors);
+ return this;
+ }
- if (parent != null) {
- parent.children.remove(this);
+ /**
+ * Attach this tensor to the parent of this scope, removing it from its current scope, or detach it if there is
+ * no current scope or the current scope does not have a parent.
+ *
+ * Semantically, this makes the tensor's resources this scope's parent's responsibility.
+ *
+ * @param requireParent whether to require a parent scope to release resources to.
+ * @throws IllegalStateException if there is no current scope or the current scope does not have a parent, but {@code
+ * requireParent} is true. If this happens, the tensor's scope is not changed.
+ */
+ public T release(T tensor, boolean requireParent){
+ if (parent == null && requireParent) {
+ throw new IllegalStateException(
+ "Can't release to parent: not in a current scope, or the current scope does not have a parent.");
}
- if (currentScope() == this) {
- currentScope.set(this.parent);
+ detach(tensor);
+ if (parent != null) {
+ parent.attach(tensor);
}
+ return tensor;
}
+
/**
- * Release the tensors and child scopes of this scope to it's parent, without closing them.
+ * Attach this tensor to the parent of this scope, removing it from its current scope, or detach it if there is
+ * no current scope or the current scope does not have a parent.
*
- * @throws IllegalStateException if this scope has no parent.
+ * Semantically, this makes the tensor's resources this scope's parent's responsibility.
*/
- public synchronized void releaseToParent() {
- release(true);
+ public T release(T tensor){
+ return release(tensor, false);
}
/**
- * Release the tensors and child scopes of this scope without closing them, to it's parent if it has one.
- *
- * WARNING: this method may release resources without assigning them to another scope if
- * {@code requireParent} is false. {@link #releaseToParent()} should be used instead wherever possible.
- *
- * @param requireParent Whether to require a parent scope to release resources to.
- * @throws IllegalStateException if this scope has no parent, but {@code requireParent} is true.
+ * @see #release(Tensor)
*/
- public synchronized void release(boolean requireParent) {
- if (closed) {
- return;
+ public void release(Tensor... tensors){
+ for(Tensor t : tensors){
+ release(t);
}
+ }
- if (this.parent == null && requireParent) {
- throw new IllegalStateException("Can't release to parent: scope does not have parent.");
- }
+ /**
+ * @see #release(Tensor)
+ */
+ public T release(T tensors){
+ release(tensors.tensors());
+ return tensors;
+ }
- if (this.parent != null) {
- TensorScope newParent = this.parent;
- newParent.children.addAll(children);
- children.forEach(x -> x.parent = newParent);
- tensors.forEach(newParent::attach);
- } else {
- children.forEach(x -> x.parent = null);
- tensors.forEach(TensorScope::detach);
+ /**
+ * @see #release(Tensor)
+ */
+ public void release(HasTensors... tensors){
+ for(HasTensors ht : tensors){
+ release(ht);
}
+ }
- children.clear();
- tensors.clear();
+ /**
+ * @see #release(Tensor)
+ */
+ public > T release(T tensors){
+ tensors.forEach(this::release);
+ return tensors;
+ }
- close();
+ /**
+ * @see #release(Tensor)
+ */
+ @SafeVarargs
+ public final void release(Iterable extends Tensor>... tensors){
+ for(Iterable extends Tensor> iterable : tensors){
+ release(iterable);
+ }
+ }
+
+ /**
+ * Attach this tensor to the parent of this scope, removing it from its current scope.
+ *
+ * Semantically, this makes the tensor's resources this scope's parent's responsibility.
+ *
+ * @throws IllegalStateException if there is no current scope or the current scope does not have a parent, but {@code
+ * requireParent} is true. If this happens, the tensor's scope is not changed.
+ */
+ public T releaseToParent(T tensor){
+ return release(tensor, true);
}
/**
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
index 712ba660cc2..afe10f685a8 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java
@@ -85,23 +85,8 @@ default boolean isClosed() {
return asRawTensor().isClosed();
}
- @Override
- default void detach() {
- asRawTensor().detach();
- }
-
- @Override
- default void attachToParent(boolean requireParent) {
- asRawTensor().attachToParent(requireParent);
- }
-
@Override
default boolean isAttached() {
return asRawTensor().isAttached();
}
-
- @Override
- default void attachToCurrentScope() {
- asRawTensor().attachToCurrentScope();
- }
}
diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
index f1652233730..df63e16bc61 100644
--- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
+++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorScopeTest.java
@@ -86,7 +86,7 @@ public void testNestedScope() {
public void testAttach() {
TensorScope firstScope = new TensorScope();
TFloat32 tensor = makeTensor(10);
- TensorScope secondScope = new TensorScope().attach(tensor);
+ TensorScope secondScope = new TensorScope().withAttached(tensor);
assertTrue(tensor.isAttached());
assertFalse(tensor.isClosed());
@@ -129,7 +129,7 @@ public void testAttachToParentScope() {
assertTrue(tensor.isAttached());
assertFalse(tensor.isClosed());
- tensor.attachToParent();
+ scope.release(tensor);
scope.close();
From c13c8dbf94460a06e1a8e9ef8c0d35f91e3f9dd8 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Sat, 23 Jan 2021 14:29:15 -0800
Subject: [PATCH 21/35] Make constructor package private, use static methods.
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/TensorScope.java | 119 +++++++++++++++++-
1 file changed, 118 insertions(+), 1 deletion(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index 4218005307f..c45f108cc25 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -18,6 +18,9 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
/**
@@ -54,12 +57,126 @@ public static TensorScope currentScope() {
return scope;
}
+ /**
+ * Runs {@code block}, then closes any tensors created during its execution.
+ * To release tensors, use {@link #withCleanup(Consumer)} or one of the {@code produceWithCleanup} methods.
+ */
+ public static void withCleanup(Runnable block){
+ try(TensorScope scope = new TensorScope()){
+ block.run();
+ }
+ }
+
+ /**
+ * Runs {@code block}, then closes any tensors created during its execution (or attached to the scope).
+ *
Tensors can be released using the passed scope.
+ */
+ public static void withCleanup(Consumer block){
+ try(TensorScope scope = new TensorScope()){
+ block.accept(scope);
+ }
+ }
+
+ /**
+ * Runs {@code block} and returns the result, then closes any tensors created during its execution.
+ * To release tensors, use {@link #withCleanup(Function)} or one of the {@code produceWithCleanup} methods.
+ */
+ public static T withCleanup(Supplier block){
+ try(TensorScope scope = new TensorScope()){
+ return block.get();
+ }
+ }
+
+ /**
+ * Runs {@code block} and returns the result, then closes any tensors created during its execution (or attached to the scope).
+ * Tensors can be released using the passed scope.
+ */
+ public static T withCleanup(Function block){
+ try(TensorScope scope = new TensorScope()){
+ return block.apply(scope);
+ }
+ }
+
+ /**
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution.
+ * To release other tensors, use {@link #produceTensorWithCleanup(Function)}.
+ *
+ * @return the released result of {@code block}
+ */
+ public static T produceTensorWithCleanup(Supplier block){
+ try(TensorScope scope = new TensorScope()){
+ return scope.release(block.get());
+ }
+ }
+
+ /**
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution (or attached to the scope).
+ * Tensors can be released using the passed scope.
+ *
+ * @return the released result of {@code block}
+ */
+ public static T produceTensorWithCleanup(Function block){
+ try(TensorScope scope = new TensorScope()){
+ return scope.release(block.apply(scope));
+ }
+ }
+
+
+ /**
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution.
+ * To release other tensors, use {@link #produceTensorWithCleanup(Function)}.
+ *
+ * @return the released result of {@code block}
+ */
+ public static T produceHasTensorsWithCleanup(Supplier block){
+ try(TensorScope scope = new TensorScope()){
+ return scope.release(block.get());
+ }
+ }
+
+ /**
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution (or attached to the scope).
+ * Tensors can be released using the passed scope.
+ *
+ * @return the released result of {@code block}
+ */
+ public static T produceHasTensorsWithCleanup(Function block){
+ try(TensorScope scope = new TensorScope()){
+ return scope.release(block.apply(scope));
+ }
+ }
+
+
+ /**
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution.
+ * To release other tensors, use {@link #produceTensorWithCleanup(Function)}.
+ *
+ * @return the released result of {@code block}
+ */
+ public static > T produceTensorsWithCleanup(Supplier block){
+ try(TensorScope scope = new TensorScope()){
+ return scope.release(block.get());
+ }
+ }
+
+ /**
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution (or attached to the scope).
+ * Tensors can be released using the passed scope.
+ *
+ * @return the released result of {@code block}
+ */
+ public static > T produceTensorsWithCleanup(Function block){
+ try(TensorScope scope = new TensorScope()){
+ return scope.release(block.apply(scope));
+ }
+ }
+
/**
* Create a new tensor scope. If {@code autoAttach} is false, will not automatically manage tensors.
*
* @see TensorScope
*/
- public TensorScope() {
+ TensorScope() {
this.parent = currentScope();
currentScope.set(this);
From 7ebb44715795f0afe5650db7670ba2ff58816bdb Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Sat, 23 Jan 2021 14:29:52 -0800
Subject: [PATCH 22/35] format
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/TensorScope.java | 125 +++++++++---------
1 file changed, 66 insertions(+), 59 deletions(-)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index c45f108cc25..5a5f5922ee7 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -29,8 +29,8 @@
* scope (even if they are created in a sub-scope). Tensors may be manually closed earlier without issue.
*
* Tensors are automatically tracked on creation. A tensor can me manually added to a scope with {@link
- * TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrent()}. A tensor may only have one scope: if it
- * currently has a scope when {@code attach} is called, it is removed from its original scope.
+ * TensorScope#attach(Tensor)} or {@link Tensor#attachToCurrent()}. A tensor may only have one scope: if it currently
+ * has a scope when {@code attach} is called, it is removed from its original scope.
*
* {@link Tensor#detach()} detaches the tensor from it's scope, requiring the user to close it manually or attach it to
* another scope.
@@ -61,8 +61,8 @@ public static TensorScope currentScope() {
* Runs {@code block}, then closes any tensors created during its execution.
*
To release tensors, use {@link #withCleanup(Consumer)} or one of the {@code produceWithCleanup} methods.
*/
- public static void withCleanup(Runnable block){
- try(TensorScope scope = new TensorScope()){
+ public static void withCleanup(Runnable block) {
+ try (TensorScope scope = new TensorScope()) {
block.run();
}
}
@@ -71,8 +71,8 @@ public static void withCleanup(Runnable block){
* Runs {@code block}, then closes any tensors created during its execution (or attached to the scope).
*
Tensors can be released using the passed scope.
*/
- public static void withCleanup(Consumer block){
- try(TensorScope scope = new TensorScope()){
+ public static void withCleanup(Consumer block) {
+ try (TensorScope scope = new TensorScope()) {
block.accept(scope);
}
}
@@ -81,92 +81,99 @@ public static void withCleanup(Consumer block){
* Runs {@code block} and returns the result, then closes any tensors created during its execution.
* To release tensors, use {@link #withCleanup(Function)} or one of the {@code produceWithCleanup} methods.
*/
- public static T withCleanup(Supplier block){
- try(TensorScope scope = new TensorScope()){
+ public static T withCleanup(Supplier block) {
+ try (TensorScope scope = new TensorScope()) {
return block.get();
}
}
/**
- * Runs {@code block} and returns the result, then closes any tensors created during its execution (or attached to the scope).
+ * Runs {@code block} and returns the result, then closes any tensors created during its execution (or attached to the
+ * scope).
* Tensors can be released using the passed scope.
*/
- public static T withCleanup(Function block){
- try(TensorScope scope = new TensorScope()){
+ public static T withCleanup(Function block) {
+ try (TensorScope scope = new TensorScope()) {
return block.apply(scope);
}
}
/**
- * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution.
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its
+ * execution.
* To release other tensors, use {@link #produceTensorWithCleanup(Function)}.
*
* @return the released result of {@code block}
*/
- public static T produceTensorWithCleanup(Supplier block){
- try(TensorScope scope = new TensorScope()){
+ public static T produceTensorWithCleanup(Supplier block) {
+ try (TensorScope scope = new TensorScope()) {
return scope.release(block.get());
}
}
/**
- * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution (or attached to the scope).
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its
+ * execution (or attached to the scope).
* Tensors can be released using the passed scope.
*
* @return the released result of {@code block}
*/
- public static T produceTensorWithCleanup(Function block){
- try(TensorScope scope = new TensorScope()){
+ public static T produceTensorWithCleanup(Function block) {
+ try (TensorScope scope = new TensorScope()) {
return scope.release(block.apply(scope));
}
}
/**
- * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution.
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its
+ * execution.
* To release other tensors, use {@link #produceTensorWithCleanup(Function)}.
*
* @return the released result of {@code block}
*/
- public static T produceHasTensorsWithCleanup(Supplier block){
- try(TensorScope scope = new TensorScope()){
+ public static T produceHasTensorsWithCleanup(Supplier block) {
+ try (TensorScope scope = new TensorScope()) {
return scope.release(block.get());
}
}
/**
- * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution (or attached to the scope).
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its
+ * execution (or attached to the scope).
* Tensors can be released using the passed scope.
*
* @return the released result of {@code block}
*/
- public static T produceHasTensorsWithCleanup(Function block){
- try(TensorScope scope = new TensorScope()){
+ public static T produceHasTensorsWithCleanup(Function block) {
+ try (TensorScope scope = new TensorScope()) {
return scope.release(block.apply(scope));
}
}
/**
- * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution.
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its
+ * execution.
* To release other tensors, use {@link #produceTensorWithCleanup(Function)}.
*
* @return the released result of {@code block}
*/
- public static > T produceTensorsWithCleanup(Supplier block){
- try(TensorScope scope = new TensorScope()){
+ public static > T produceTensorsWithCleanup(Supplier block) {
+ try (TensorScope scope = new TensorScope()) {
return scope.release(block.get());
}
}
/**
- * Runs {@code block} and releases and returns the result, then closes any other tensors created during its execution (or attached to the scope).
+ * Runs {@code block} and releases and returns the result, then closes any other tensors created during its
+ * execution (or attached to the scope).
* Tensors can be released using the passed scope.
*
* @return the released result of {@code block}
*/
- public static > T produceTensorsWithCleanup(Function block){
- try(TensorScope scope = new TensorScope()){
+ public static > T produceTensorsWithCleanup(Function block) {
+ try (TensorScope scope = new TensorScope()) {
return scope.release(block.apply(scope));
}
}
@@ -218,8 +225,8 @@ public synchronized void close() {
*
* This will close this scope, but does not close any of it's resources.
*
- * @throws IllegalStateException if this scope has no parent. If this happens,
- * * the scope is not closed and no resources are released.
+ * @throws IllegalStateException if this scope has no parent. If this happens, * the scope is not closed and no
+ * resources are released.
*/
public synchronized void releaseToParent() {
release(true);
@@ -245,8 +252,8 @@ public synchronized void release() {
* {@code requireParent} is false. {@link #releaseToParent()} should be used instead wherever possible.
*
* @param requireParent Whether to require a parent scope to release resources to.
- * @throws IllegalStateException if this scope has no parent, but {@code requireParent} is true. If this happens,
- * the scope is not closed and no resources are released.
+ * @throws IllegalStateException if this scope has no parent, but {@code requireParent} is true. If this happens, the
+ * scope is not closed and no resources are released.
*/
public synchronized void release(boolean requireParent) {
if (closed) {
@@ -288,8 +295,8 @@ public static T detach(T tensor) {
/**
* @see #detach(Tensor)
*/
- public static void detach(Tensor... tensors){
- for(Tensor t : tensors){
+ public static void detach(Tensor... tensors) {
+ for (Tensor t : tensors) {
detach(t);
}
}
@@ -297,7 +304,7 @@ public static void detach(Tensor... tensors){
/**
* @see #detach(Tensor)
*/
- public static T detach(T tensors){
+ public static T detach(T tensors) {
detach(tensors.tensors());
return tensors;
}
@@ -305,8 +312,8 @@ public static T detach(T tensors){
/**
* @see #detach(Tensor)
*/
- public static void detach(HasTensors... tensors){
- for(HasTensors ht : tensors){
+ public static void detach(HasTensors... tensors) {
+ for (HasTensors ht : tensors) {
detach(ht);
}
}
@@ -314,7 +321,7 @@ public static void detach(HasTensors... tensors){
/**
* @see #detach(Tensor)
*/
- public static > T detach(T tensors){
+ public static > T detach(T tensors) {
tensors.forEach(TensorScope::detach);
return tensors;
}
@@ -323,8 +330,8 @@ public static > T detach(T tensors){
* @see #detach(Tensor)
*/
@SafeVarargs
- public static void detach(Iterable extends Tensor>... tensors){
- for(Iterable extends Tensor> iterable : tensors){
+ public static void detach(Iterable extends Tensor>... tensors) {
+ for (Iterable extends Tensor> iterable : tensors) {
detach(iterable);
}
}
@@ -404,7 +411,7 @@ public final void attach(Iterable extends Tensor>... tensors) {
/**
* @see #attach(Tensor)
*/
- public TensorScope withAttached(Tensor... tensors){
+ public TensorScope withAttached(Tensor... tensors) {
attach(tensors);
return this;
}
@@ -412,7 +419,7 @@ public TensorScope withAttached(Tensor... tensors){
/**
* @see #attach(Tensor)
*/
- public TensorScope withAttached(HasTensors... tensors){
+ public TensorScope withAttached(HasTensors... tensors) {
attach(tensors);
return this;
}
@@ -420,14 +427,14 @@ public TensorScope withAttached(HasTensors... tensors){
/**
* @see #attach(Tensor)
*/
- public TensorScope withAttached(Iterable extends Tensor>... tensors){
+ public TensorScope withAttached(Iterable extends Tensor>... tensors) {
attach(tensors);
return this;
}
/**
- * Attach this tensor to the parent of this scope, removing it from its current scope, or detach it if there is
- * no current scope or the current scope does not have a parent.
+ * Attach this tensor to the parent of this scope, removing it from its current scope, or detach it if there is no
+ * current scope or the current scope does not have a parent.
*
* Semantically, this makes the tensor's resources this scope's parent's responsibility.
*
@@ -435,7 +442,7 @@ public TensorScope withAttached(Iterable extends Tensor>... tensors){
* @throws IllegalStateException if there is no current scope or the current scope does not have a parent, but {@code
* requireParent} is true. If this happens, the tensor's scope is not changed.
*/
- public T release(T tensor, boolean requireParent){
+ public T release(T tensor, boolean requireParent) {
if (parent == null && requireParent) {
throw new IllegalStateException(
"Can't release to parent: not in a current scope, or the current scope does not have a parent.");
@@ -450,20 +457,20 @@ public T release(T tensor, boolean requireParent){
/**
- * Attach this tensor to the parent of this scope, removing it from its current scope, or detach it if there is
- * no current scope or the current scope does not have a parent.
+ * Attach this tensor to the parent of this scope, removing it from its current scope, or detach it if there is no
+ * current scope or the current scope does not have a parent.
*
* Semantically, this makes the tensor's resources this scope's parent's responsibility.
*/
- public T release(T tensor){
+ public T release(T tensor) {
return release(tensor, false);
}
/**
* @see #release(Tensor)
*/
- public void release(Tensor... tensors){
- for(Tensor t : tensors){
+ public void release(Tensor... tensors) {
+ for (Tensor t : tensors) {
release(t);
}
}
@@ -471,7 +478,7 @@ public void release(Tensor... tensors){
/**
* @see #release(Tensor)
*/
- public T release(T tensors){
+ public T release(T tensors) {
release(tensors.tensors());
return tensors;
}
@@ -479,8 +486,8 @@ public T release(T tensors){
/**
* @see #release(Tensor)
*/
- public void release(HasTensors... tensors){
- for(HasTensors ht : tensors){
+ public void release(HasTensors... tensors) {
+ for (HasTensors ht : tensors) {
release(ht);
}
}
@@ -488,7 +495,7 @@ public void release(HasTensors... tensors){
/**
* @see #release(Tensor)
*/
- public > T release(T tensors){
+ public > T release(T tensors) {
tensors.forEach(this::release);
return tensors;
}
@@ -497,8 +504,8 @@ public > T release(T tensors){
* @see #release(Tensor)
*/
@SafeVarargs
- public final void release(Iterable extends Tensor>... tensors){
- for(Iterable extends Tensor> iterable : tensors){
+ public final void release(Iterable extends Tensor>... tensors) {
+ for (Iterable extends Tensor> iterable : tensors) {
release(iterable);
}
}
@@ -511,7 +518,7 @@ public final void release(Iterable extends Tensor>... tensors){
* @throws IllegalStateException if there is no current scope or the current scope does not have a parent, but {@code
* requireParent} is true. If this happens, the tensor's scope is not changed.
*/
- public T releaseToParent(T tensor){
+ public T releaseToParent(T tensor) {
return release(tensor, true);
}
From 49ac26e1164a5298498d3d063700e1c478c497b3 Mon Sep 17 00:00:00 2001
From: Ryan Nett
Date: Sun, 24 Jan 2021 15:01:27 -0800
Subject: [PATCH 23/35] fixes
Signed-off-by: Ryan Nett
---
.../main/java/org/tensorflow/RawTensor.java | 14 +++---
.../{HasTensors.java => TensorContainer.java} | 2 +-
.../main/java/org/tensorflow/TensorScope.java | 48 +++++++++----------
.../java/org/tensorflow/TensorScopeTest.java | 4 +-
4 files changed, 34 insertions(+), 34 deletions(-)
rename tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/{HasTensors.java => TensorContainer.java} (96%)
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
index b5b21c8c46b..040bd6a91d4 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/RawTensor.java
@@ -66,7 +66,7 @@ public RawTensor asRawTensor() {
@Override
public void close() {
if (!closed) {
- tensorScope.close();
+ pointerScope.close();
closed = true;
}
}
@@ -78,7 +78,7 @@ public boolean isClosed() {
@Override
public boolean isAttached() {
- return scope != null;
+ return tensorScope != null;
}
/**
@@ -146,7 +146,7 @@ static RawTensor allocate(Class extends TType> type, Shape shape, long size) {
scope.attach(nativeHandle);
RawTensor t = new RawTensor(typeInfo, shape);
t.tensorHandle = nativeHandle;
- t.tensorScope = scope.extend();
+ t.pointerScope = scope.extend();
return t;
}
}
@@ -162,7 +162,7 @@ static RawTensor fromHandle(TF_Tensor handle) {
try (PointerScope scope = new PointerScope()) {
scope.attach(handle);
t.tensorHandle = handle;
- t.tensorScope = scope.extend();
+ t.pointerScope = scope.extend();
}
return t;
}
@@ -224,13 +224,13 @@ private static long[] shape(TF_Tensor handle) {
TensorScope currentScope = TensorScope.currentScope();
if (currentScope != null) {
- this.scope = currentScope.withAttached(this);
+ this.tensorScope = currentScope.withTensors(this);
}
}
- private PointerScope tensorScope;
+ private PointerScope pointerScope;
private boolean closed;
- TensorScope scope;
+ TensorScope tensorScope;
private TF_Tensor tensorHandle;
private final TensorTypeInfo extends TType> typeInfo;
private final Shape shape;
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorContainer.java
similarity index 96%
rename from tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
rename to tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorContainer.java
index 5d8344d22a0..248bf5a7e2a 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/HasTensors.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorContainer.java
@@ -19,7 +19,7 @@
/**
* An interface representing a collection or group of tensors. Provides methods for resource management.
*/
-public interface HasTensors extends AutoCloseable {
+public interface TensorContainer extends AutoCloseable {
/**
* Get the tensors held by this object.
diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
index 5a5f5922ee7..704b71a8ca4 100644
--- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
+++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/TensorScope.java
@@ -132,7 +132,7 @@ public static