Skip to content

Commit

Permalink
Implement AutoCloseable with DnnModel
Browse files Browse the repository at this point in the history
Aims to provide a mechanism to address
* qupath#841
* qupath/qupath-extension-stardist#11
by ensuring that an OpenCV Net wrapped in a DnnModel can be closed without needing a reference to the Net itself.
The StarDist and TensorFlow extensions should be updated to make use of this.
  • Loading branch information
petebankhead committed Dec 22, 2021
1 parent 102e77b commit f7a16fa
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ List of bugs fixed:
* 'Automate -> Show workflow command history' displays empty workflow (https://github.com/qupath/qupath/pull/851)
* Extensions are sometimes loaded too late when running command line scripts (https://github.com/qupath/qupath/issues/852)
* ICC Profiles could not be set in the viewer (unused preview feature, https://github.com/qupath/qupath/pull/850)
* DnnModel implements AutoCloseable, so that calling DnnModel.close() can resolve
* GPU memory not freed when using OpenCV DNN (https://github.com/qupath/qupath/issues/841)
* QuPath with CUDA doesn’t release GPU memory after StarDist segmentation (https://github.com/qupath/qupath-extension-stardist/issues/11)
* Image writing fixes, including
* convert-ome command doesn't report when it is finished (https://github.com/qupath/qupath/issues/859)
* OMEPyramidWriter ignores file extension to always write ome.tif (https://github.com/qupath/qupath/issues/857)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

package qupath.opencv.dnn;

import java.io.Closeable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -71,5 +72,23 @@ public BlobFunction<T> getBlobFunction(String name) {
public PredictionFunction<T> getPredictionFunction() {
return predictFun;
}

/**
* Calls {@code close()} on the blob and prediction functions, if they are instances of
* {@link Closeable} or {@link AutoCloseable}.
*/
@Override
public void close() throws Exception {
logger.debug("Closing {}", this);
tryToClose(blobFun);
tryToClose(predictFun);
}

private void tryToClose(Object o) throws Exception {
if (o instanceof AutoCloseable)
((AutoCloseable)o).close();
else if (o instanceof Closeable)
((Closeable)o).close();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
* @see PredictionFunction
* @version 0.3.0
*/
public interface DnnModel<T> {
public interface DnnModel<T> extends AutoCloseable {

/**
* Default input layer name. This should be used when the input layer name is known or
Expand Down Expand Up @@ -137,4 +137,16 @@ public default List<Mat> batchConvertAndPredict(Mat... mats) {
return output;
}

/**
* Close this model if it will not be needed again.
* Subclasses that require cleanup may override this.
* A default, do-nothing implementation implementation is provided for backwards compatibility with v0.3.0.
*
* @since v0.3.1
* @implNote this was introduced to provide a mechanism to deal with a GPU memory leak when
* using OpenCV and CUDA. New code using any DnnModel should call this method if it can
* be known that the model will not be needed again in the future.
*/
public default void close() throws Exception {}

}
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ public OpenCVDnn build() {



class OpenCVNetFunction implements PredictionFunction<Mat> { //, UriResource {
class OpenCVNetFunction implements PredictionFunction<Mat>, AutoCloseable { //, UriResource {

private transient Net net;
private transient List<String> outputLayerNames;
Expand Down Expand Up @@ -797,6 +797,19 @@ public Map<String, DnnShape> getOutputs(DnnShape... inputShapes) {
return outputs;
return DnnTools.getOutputLayers(net, inputShapes);
}

@Override
public synchronized void close() throws Exception {
if (net != null) {
logger.debug("Closing {}", net);
net.close();
net.deallocate();
}
if (outputLayerNamesVector != null) {
outputLayerNamesVector.close();
outputLayerNamesVector.deallocate();
}
}

}

Expand Down Expand Up @@ -892,5 +905,12 @@ public PredictionFunction<Mat> getPredictionFunction() {
}
return predFun;
}

@Override
public void close() throws Exception {
if (predFun instanceof AutoCloseable) {
((AutoCloseable)predFun).close();
}
}

}

0 comments on commit f7a16fa

Please sign in to comment.