不好意思。
我使用tensorflow-models / posenet(https://github.com/tensorflow/tfjs-models/tree/master/posenet),node.js(https://github.com/tensorflow/tfjs-node)和express(https://github.com/expressjs/express)实现了演示应用。
我按以下方式替换了示例代码,但是执行estimateMultiplePoses()(https://github.com/tensorflow/tfjs-models/blob/master/posenet/src/posenet_model.ts)时GPU可能无法工作。
你能告诉我如何在GPU上运行代码吗?
例如,当我将API发布到本地服务器时,响应非常低。
$curl -X POST -F thumbnail=@./picture.png localhost:3000/upload
[在服务器日志中]
我希望响应时间少于100毫秒。
当我不使用PoseNet API时,响应时间不到30毫秒,因此以为响应速度很慢是由于未在GPU上运行引起的。
POST /upload 200 2110.888 ms - 9372
但是,构建服务器时该过程可能仍然存在。
$ nvidia-smi
Tue Jul 31 10:27:38 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 396.37 Driver Version: 396.37 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 107... On | 00000000:01:00.0 On | N/A |
| 27% 40C P8 13W / 180W | 7732MiB / 8116MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 GeForce GTX 107... On | 00000000:02:00.0 Off | N/A |
| 27% 38C P8 12W / 180W | 7723MiB / 8119MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1252 G /usr/lib/xorg/Xorg 281MiB |
| 0 2068 G compiz 226MiB |
| 0 2435 G ...-token=... 61MiB |
| 0 2697 G unity-control-center 15MiB |
| 0 2945 G ...-token=... 92MiB |
| 0 14062 G ...-token=... 66MiB |
| 0 26892 C node 6983MiB |
| 1 26892 C node 7711MiB |
+-----------------------------------------------------------------------------+
致谢。
./ routes / index.js
var posenet = require('@tensorflow-models/posenet');
var tf = require('@tensorflow/tfjs');
require('@tensorflow/tfjs-node-gpu');
var express = require('express');
var router = express.Router();
var multer = require('multer');
var upload = multer({dest: "./uploads/"}).single('thumbnail');
var Canvas = require('canvas');
var Image = Canvas.Image;
const state = {
input: {
imageScaleFactor: 0.5,
flipHorizontal: false,
outputStride: 16,
},
detection: {
maxPoseDetections: 5,
minPoseConfidence: 0.15,
minPartConfidence: 0.1,
nmsRadius: 30.0,
},
};
function createHTMLCanvasElementFromRequest(req){
const img = new Image;
img.src = req.file.path;
const canvas = new Canvas(img.width,img.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, img.width, img.height);
return canvas;
}
function detectPoses(req, res){
const canvas = createHTMLCanvasElementFromRequest(req);
async function usePoseNet(req){
const net = await posenet.load();
const poses = await net.estimateMultiplePoses( canvas,
state.input.imageScaleFactor,
state.input.flipHorizontal,
state.input.outputStride,
state.detection.maxPoseDetections,
state.detection.minPartConfidence,
state.detection.nmsRadius);
return poses;
}
usePoseNet(req).then( json_res =>{
res.send({
"OriginalName": req.file.originalname,
"FileName": req.file.filename,
"Size": req.file.size,
"Width": canvas.width,
"Height": canvas.height,
"Context": json_res
})
}).catch(e => {
res.send({
"Error": e
});
});
}
function failedToGetImages(req,res, err){
res.send({
"Destination": req.file.destination,
"Error": err
});
}
router.post('/upload', function(req, res){
upload(req, res, function(err){
res.header('Content-Type', 'application/json; charset=utf-8');
err? failedToGetImages(req,res,err) : detectPoses(req, res);
});
});
module.exports = router;
./ app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(cookieParser());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Max-Age', '86400');
next();
});
app.options('*', function (req, res) {
res.sendStatus(200);
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
./ bin / www
#!/usr/bin/env node
var app = require('../app');
var debug = require('debug')('roboserver:server');
var http = require('http');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app);
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
}
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
内存:
存在SMBIOS 3.0.0。 句柄0x0043,DMI类型16,23字节 物理内存阵列 位置:系统板或主板 用途:系统内存 错误纠正类型:无 最大容量:32 GB 错误信息句柄:未提供 设备数量:2
句柄0x0044,DMI类型17,40字节 存储设备 数组句柄:0x0043 错误信息句柄:未提供 总宽度:未知 数据宽度:未知 大小:未安装模块 外形尺寸:未知 设置:无 定位器:ChannelA-DIMM1 银行定位器:BANK 0 类型:未知 类型详细信息:无 速度:未知 制造商:未指定 序列号:未指定 资产标签:未指定 零件编号:未指定 排名:未知 配置的时钟速度:未知 最低电压:未知 最大电压:未知 配置电压:未知
句柄0x0045,DMI类型17,40字节
存储设备
数组句柄:0x0043
错误信息句柄:未提供
总宽度:64位
资料宽度:64位
大小:16384 MB
规格:DIMM
设置:无
定位器:ChannelA-DIMM2
银行定位器:BANK 1
类型:DDR4
类型详细信息:同步未缓冲(未注册)
速度:2133 MHz
制造商:海盗船
序列号:00000000
资产标签:9876543210
零件编号:CMK32GX4M2B3000C15
等级:2
配置的时钟速度:2133 MHz
最低电压:未知
最大电压:未知
设定电压:1.2 V
句柄0x0046,DMI类型17,40字节 存储设备 数组句柄:0x0043 错误信息句柄:未提供 总宽度:未知 数据宽度:未知 大小:未安装模块 外形尺寸:未知 设置:无 定位器:ChannelB-DIMM1 银行定位器:BANK 2 类型:未知 类型详细信息:无 速度:未知 制造商:未指定 序列号:未指定 资产标签:未指定 零件编号:未指定 排名:未知 配置的时钟速度:未知 最低电压:未知 最大电压:未知 配置电压:未知
句柄0x0047,DMI类型17,40字节
存储设备
数组句柄:0x0043
错误信息句柄:未提供
总宽度:64位
资料宽度:64位
大小:16384 MB
规格:DIMM
设置:无
定位器:ChannelB-DIMM2
银行定位器:BANK 3
类型:DDR4
类型详细信息:同步未缓冲(未注册)
速度:2133 MHz
制造商:海盗船
序列号:00000000
资产标签:9876543210
零件编号:CMK32GX4M2B3000C15
等级:2
配置的时钟速度:2133 MHz
最低电压:未知
最大电压:未知
配置电压:1.2 V
要复制的精确命令:节点./bin/www