Closed drew-neely closed 6 years ago
Also, I am using the most recent version of Darknet.JS, with node v8.11.2. The machine I am using is an AWS EC2 instance running Ubuntu 16.04, if any of this is helpful.
It seems that each darknet.js detection can be run asynchronously, but not in parallel. I'm going to work on a fix for this, but in the meantime, you can get around this by creating a "detection pool" of all the images that you want to detect, and having darknet go through them one at a time. Here's an example that I've used in a web server that classified images:
import { Darknet, Detection } from 'darknet';
import { Subject, Observable, zip } from 'rxjs';
import { names } from './names';
const config = {
weights: 'bin/rubbish.weights',
config: "bin/rubbish.cfg",
};
export interface IDetectMe {
image: string;
id: string;
}
export interface IDetection {
id: string;
detections: Detection[];
}
export class Detector {
private darknet;
private images$ = new Subject<IDetectMe>();
private completion$ = new Subject();
private detection$ = new Subject<IDetection>();
constructor() {
this.darknet = new Darknet({
weights: config.weights,
config: config.config,
names: names
});
this.subscribeToDetections();
this.completion$.next();
}
private subscribeToDetections() {
zip(this.images$, this.completion$)
.subscribe(x => {
this.darknet.detectAsync(x[0].image)
.then(dets => {
this.completion$.next();
this.detection$.next({
id: x[0].id,
detections: dets
});
});
})
}
add(id: string, path: string) {
console.log(id+":", "detection started.");
this.images$.next({
id: id,
image: path
});
}
success$(): Observable<IDetection> {
return this.detection$.asObservable();
}
}
Then to start darknet:
const detector = new Detector();
detector.success$().subscribe(detection => console.log(detection);
detector.add('a', 'path/to/image.jpg');
detector.add('b', 'path/to/image.jpg');
detector.add('c', 'path/to/image.jpg');
This will go through the detections one at a time and output them from success$()
I hope this gives you some ideas.
I've incorporated that "Detector" logic in a version of darknet.js called DarknetExperimental
. If you swap out the Darknet
prototype for DarknetExperimental
, it should fix the issues that you're having. Let me know how it goes!
Just to let you know what's going on. At the moment, whenever detectAsync
is called, node-ffi executes the detection in a different thread. Now whenever detectAsync
is called, it will still execute those detections in a different thread, but it will do so sequentially and in order.
It works great! Thanks.
I'm just curious, is the Darknet model not able to run concurrent detections?
The Darknet C library isn't as far as I'm aware, and the darknet.js bindings definitely can't either.
If the machine you're running darknet.js on has multiple cores and a significant amount of memory, you can run concurrent async detections by creating multiple instances of Darknet
. Just note that it will use n
times as much memory as one instance.
My GTX1080Ti has enough memory to keep 3 models at the same time by using the following code, so that I attempt to create 3 instance of Darknet. However, the speed does not increase. What's wrong? ` const { Darknet } = require('darknet') //darknet.js const darknet0 = new Darknet({ weights: path.join(__dirname,'lpr_127000.weights'), config: path.join(dirname,'lpr.cfg'), namefile: path.join(dirname,'yolov3.names'), })
const darknet1 = new Darknet({ weights: path.join(__dirname,'lpr_127000.weights'), config: path.join(dirname,'lpr.cfg'), namefile: path.join(dirname,'yolov3.names'), })
const darknet2 = new Darknet({ weights: path.join(__dirname,'lpr_127000.weights'), config: path.join(dirname,'lpr.cfg'), namefile: path.join(dirname,'yolov3.names'), })
let round = 0
function detect(filepath){ if(fs.existsSync){ let result = { } let rnd = round++ % 3 if(rnd ===0){ console.log('dn0',filepath) result = (darknet0.detect(filepath, {thresh: 0.05})) } else if(rnd ===1){ console.log('dn1',filepath) result = (darknet1.detect(filepath, {thresh: 0.05})) } else { console.log('dn2',filepath) result = (darknet2.detect(filepath, {thresh: 0.05})) } return result } return {} } `
Hey @mochechan, I'm not currently able to test this, but I think the issue is that you're using darknet.detect
instead of darknet.detectAsync
.
Hi @bennetthardwick , is detectAsync
still available?
Unfortunately, I've not yet reimplemented it in the C++ v2 version. You can still use it in v1 however by installing the old version.
npm i --save darknet@1
Great thanks for your super quick reply mate, what'd be the main downside with that?
The only real difference between the two versions is that the C++ version works on ARM (#20) and is possibly a bit faster since there's no node-ffi overhead. You should have no problems using 1 (I think one of my projects still uses it :stuck_out_tongue_closed_eyes:)
When I make multiple calls to detectAsync consecutively with different images I get very different results than I do when I run the model with a single call.
For a particular image, a single call to detectAsync with no other consecutive calls gives the expected results that match what the darknet command line detect command gives for the same image.
But when I add a second call to detectAsync immediately after this call, the first and second calls return different and entirely incorrect JSON objects. Not surprisingly, this holds true for the third, fourth, and consecutive concurrent calls.
If there is some kind of workaround or fix for this that would be great. Otherwise I will just use the synchronous version.