- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一台带有多个 GPU 的服务器,我想在 Java 应用程序内的模型推理期间充分利用它们。默认情况下,tensorflow 占用所有可用的 GPU,但仅使用第一个。
我可以想到三个选项来解决这个问题:
在进程级别限制设备可见性,即使用 CUDA_VISIBLE_DEVICES
环境变量。
这将需要我运行 java 应用程序的多个实例并在它们之间分配流量。不是那种诱人的想法。
在单个应用程序中启动多个 session ,并尝试通过 ConfigProto
为每个 session 分配一个设备:
public class DistributedPredictor {
private Predictor[] nested;
private int[] counters;
// ...
public DistributedPredictor(String modelPath, int numDevices, int numThreadsPerDevice) {
nested = new Predictor[numDevices];
counters = new int[numDevices];
for (int i = 0; i < nested.length; i++) {
nested[i] = new Predictor(modelPath, i, numDevices, numThreadsPerDevice);
}
}
public Prediction predict(Data data) {
int i = acquirePredictorIndex();
Prediction result = nested[i].predict(data);
releasePredictorIndex(i);
return result;
}
private synchronized int acquirePredictorIndex() {
int i = argmin(counters);
counters[i] += 1;
return i;
}
private synchronized void releasePredictorIndex(int i) {
counters[i] -= 1;
}
}
public class Predictor {
private Session session;
public Predictor(String modelPath, int deviceIdx, int numDevices, int numThreadsPerDevice) {
GPUOptions gpuOptions = GPUOptions.newBuilder()
.setVisibleDeviceList("" + deviceIdx)
.setAllowGrowth(true)
.build();
ConfigProto config = ConfigProto.newBuilder()
.setGpuOptions(gpuOptions)
.setInterOpParallelismThreads(numDevices * numThreadsPerDevice)
.build();
byte[] graphDef = Files.readAllBytes(Paths.get(modelPath));
Graph graph = new Graph();
graph.importGraphDef(graphDef);
this.session = new Session(graph, config.toByteArray());
}
public Prediction predict(Data data) {
// ...
}
}
乍一看,这种方法似乎工作正常。但是, session 偶尔会忽略 setVisibleDeviceList
选项,并且所有这些都会针对第一个导致内存不足崩溃的设备。
使用 tf.device()
规范在 python 中以多塔方式构建模型。在 Java 端,在共享 session 中为不同的 Predictor
提供不同的塔。
对我来说感觉很麻烦而且惯用错误。
更新:正如@ash 所建议的,还有另一种选择:
通过修改其定义 (graphDef
) 为现有图的每个操作分配适当的设备。
要完成它,可以修改方法 2 中的代码:
public class Predictor {
private Session session;
public Predictor(String modelPath, int deviceIdx, int numDevices, int numThreadsPerDevice) {
byte[] graphDef = Files.readAllBytes(Paths.get(modelPath));
graphDef = setGraphDefDevice(graphDef, deviceIdx)
Graph graph = new Graph();
graph.importGraphDef(graphDef);
ConfigProto config = ConfigProto.newBuilder()
.setAllowSoftPlacement(true)
.build();
this.session = new Session(graph, config.toByteArray());
}
private static byte[] setGraphDefDevice(byte[] graphDef, int deviceIdx) throws InvalidProtocolBufferException {
String deviceString = String.format("/gpu:%d", deviceIdx);
GraphDef.Builder builder = GraphDef.parseFrom(graphDef).toBuilder();
for (int i = 0; i < builder.getNodeCount(); i++) {
builder.getNodeBuilder(i).setDevice(deviceString);
}
return builder.build().toByteArray();
}
public Prediction predict(Data data) {
// ...
}
}
就像其他提到的方法一样,这个方法并没有让我从手动在设备之间分发数据中解脱出来。但至少它工作稳定并且比较容易实现。总的来说,这看起来像是一种(几乎)正常的技术。
有没有一种优雅的方法可以用 tensorflow java API 做这样的基本事情?任何想法,将不胜感激。
最佳答案
简而言之:有一种变通方法,您最终每个 GPU 有一个 session 。
详细信息:
一般流程是 TensorFlow 运行时尊重为图中的操作指定的设备。如果没有为操作指定设备,则它会根据一些试探法“放置”它。这些启发式方法目前导致“在 GPU 上进行操作:0 如果 GPU 可用并且有用于操作的 GPU 内核”(Placer::Run
如果您感兴趣的话)。
我认为你要求的是对 TensorFlow 的合理功能请求 - 能够将序列化图中的设备视为“虚拟”设备以在运行时映射到一组“物理”设备,或者设置“默认设备”。此功能当前不存在。将这样的选项添加到 ConfigProto
是您可能想要提交功能请求的内容。
我可以在此期间建议一个解决方法。首先,对您提出的解决方案进行一些评论。
您的第一个想法肯定会奏效,但正如您指出的那样,它很麻烦。
在 ConfigProto
中使用 visible_device_list
进行设置并不完全可行,因为这实际上是每个进程的设置,在创建第一个 session 后会被忽略进行中。这当然没有按应有的方式记录(并且有点不幸,这出现在每 session 配置中)。但是,这解释了为什么您在此处的建议不起作用以及为什么您仍然看到正在使用单个 GPU。
这可行。
另一种选择是最终得到不同的图形(操作明确地放置在不同的 GPU 上),从而导致每个 GPU 一个 session 。像这样的东西可以用来编辑图形并为每个操作明确分配一个设备:
public static byte[] modifyGraphDef(byte[] graphDef, String device) throws Exception {
GraphDef.Builder builder = GraphDef.parseFrom(graphDef).toBuilder();
for (int i = 0; i < builder.getNodeCount(); ++i) {
builder.getNodeBuilder(i).setDevice(device);
}
return builder.build().toByteArray();
}
之后,您可以使用类似以下内容为每个 GPU 创建一个 Graph
和 Session
:
final int NUM_GPUS = 8;
// setAllowSoftPlacement: Just in case our device modifications were too aggressive
// (e.g., setting a GPU device on an operation that only has CPU kernels)
// setLogDevicePlacment: So we can see what happens.
byte[] config =
ConfigProto.newBuilder()
.setLogDevicePlacement(true)
.setAllowSoftPlacement(true)
.build()
.toByteArray();
Graph graphs[] = new Graph[NUM_GPUS];
Session sessions[] = new Session[NUM_GPUS];
for (int i = 0; i < NUM_GPUS; ++i) {
graphs[i] = new Graph();
graphs[i].importGraphDef(modifyGraphDef(graphDef, String.format("/gpu:%d", i)));
sessions[i] = new Session(graphs[i], config);
}
然后使用sessions[i]
在 GPU #i 上执行图形。
希望对您有所帮助。
关于java - Tensorflow Java 多 GPU 推理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47799972/
现在,我正在使用 MALLET 包中的 LDA 主题建模工具对我的文档进行一些主题检测。最初一切都很好,我从中得到了 20 个主题。但是,当我尝试使用该模型推断新文档时,结果有点莫名其妙。 例如,我故
我正在使用 Jersey 在 Scala 中开发 REST web 服务JAX-RS 引用实现,我收到一个奇怪的错误。 我正在尝试创建一个 ContentDisposition对象使用 Content
以下两个用于计算斐波那契数列第 n 项的 Haskell 程序具有截然不同的性能特征: fib1 n = case n of 0 -> 1 1 -> 1 x -> (fib
所以在来自 another question 的评论中,我刚刚看到了这个计算字符串中 L 数量的例子: "hello".count('l'==) 而且够疯狂……它有效。 从完全扩展的版本开始,我们有:
我在 android 上运行训练有素的 yolov2 网络时遇到问题。我正在使用这个项目进行测试 https://github.com/szaza/android-yolo-v2 . 提供的网络工作正
我目前在我的 iOS 应用程序中使用 Tensorflow 的 Swift 版本。我的模型工作正常,但我无法将数据复制到第一个张量中,因此我可以使用神经网络来检测东西。 我咨询了the testsui
我有一个 SSD tflite 检测模型,正在台式计算机上使用 Python 运行。就目前而言,我的下面的脚本将单个图像作为推理的输入,并且运行良好: # Load TFLite model
我所拥有的:在 Tensorflow 中经过训练的递归神经网络。 我想要的:一个可以尽可能快地运行这个网络的移动应用程序(只有推理模式,没有训练)。 我相信有多种方法可以实现我的目标,但我希望您能提供
**我得到了一些让我的函数成为纯通用函数的建议,这可行,但我更愿意将函数限制为仅接受 Base 及其子项。 在创建可以接受可变模板类基类型参数的函数时遇到问题,而该函数实际上将使用从 Base 派生的
我想使用 TF 2.0 在我的 GPU 集群上运行分布式预测。我使用 MirroredStrategy 训练了一个用 Keras 制作的 CNN 并保存了它。我可以加载模型并在其上使用 .predic
实现一个 C++ 代码来加载一个已经训练好的模型然后获取它而不是使用 Python 真的值得吗? 我想知道这一点,因为据我所知,用于 python 的 Tensorflow 是幕后的 C++(对于 n
我将在网站上提供 pytorch 模型(resnet18)。 然而,在 cpu(amd3600) 中进行推理需要 70% 的 cpu 资源。 我不认为服务器(heroku)可以处理这个计算。 有什么方
为了充分利用 CPU/GPU,我运行了多个对不同数据集进行 DNN 推理(前馈)的进程。由于进程在前馈期间分配了 CUDA 内存,因此我收到了 CUDA 内存不足错误。为了缓解这种情况,我添加了 to
你知道用 1 个 GPU tensorflow 对 2 个 python 进程进行推理的优雅方法吗? 假设我有 2 个进程,第一个是分类猫/狗,第二个是分类鸟/飞机,每个进程运行不同的 tensorf
我是 Scala 的初学者,不明白这里发生了什么: 给定: val reverse:Option[MyObject] = ... 并且myObject.isNaire返回 bool 值。 如果我这样做
我正在尝试通过用我常用的语言 Clojure 实现算法 W 来自学 Hindley-Milner 类型推理。我遇到了 let 推理的问题,我不确定我是否做错了什么,或者我期望的结果是否需要算法之外的东
我正在尝试通过用我常用的语言 Clojure 实现算法 W 来自学 Hindley-Milner 类型推理。我遇到了 let 推理的问题,我不确定我是否做错了什么,或者我期望的结果是否需要算法之外的东
我做了一个项目,基本上使用带有 tensorflow 的 googles object detection api。 我所做的只是使用预训练模型进行推理:这意味着实时对象检测,其中输入是网络摄像头的视
我有一台带有多个 GPU 的服务器,我想在 Java 应用程序内的模型推理期间充分利用它们。默认情况下,tensorflow 占用所有可用的 GPU,但仅使用第一个。 我可以想到三个选项来解决这个问题
这个预测时间190ms,应该是cpu版本 昨天修改了个OpenCV DNN支持部署YOLOv5,6.1版本的Python代码,今天重新转换为C 代码了!貌似帧率比之前涨了点!说明C的确是比Python
我是一名优秀的程序员,十分优秀!