darknet.js 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. const darknet = {};
  2. darknet.ModelFactory = class {
  3. async match(context) {
  4. const identifier = context.identifier;
  5. const extension = identifier.lastIndexOf('.') > 0 ? identifier.split('.').pop().toLowerCase() : '';
  6. if (extension === 'weights' && !identifier.toLowerCase().endsWith('.espresso.weights')) {
  7. const weights = await darknet.Weights.open(context);
  8. if (weights) {
  9. return context.set('darknet.weights', weights);
  10. }
  11. return null;
  12. }
  13. const reader = await context.read('text', 65536);
  14. if (reader) {
  15. try {
  16. for (let line = reader.read('\n'); line !== undefined; line = reader.read('\n')) {
  17. const content = line.trim();
  18. if (content.length > 0 && !content.startsWith('#')) {
  19. if (content.startsWith('[') && content.endsWith(']')) {
  20. return context.set('darknet.model');
  21. }
  22. return null;
  23. }
  24. }
  25. } catch {
  26. // continue regardless of error
  27. }
  28. }
  29. return null;
  30. }
  31. async open(context) {
  32. const metadata = await context.metadata('darknet-metadata.json');
  33. const identifier = context.identifier;
  34. const parts = identifier.split('.');
  35. parts.pop();
  36. const basename = parts.join('.');
  37. switch (context.type) {
  38. case 'darknet.weights': {
  39. const weights = context.value;
  40. const name = `${basename}.cfg`;
  41. const content = await context.fetch(name);
  42. const reader = await content.read('text');
  43. const configuration = new darknet.Configuration(reader, content.identifier);
  44. return new darknet.Model(metadata, configuration, weights);
  45. }
  46. case 'darknet.model': {
  47. try {
  48. const name = `${basename}.weights`;
  49. const content = await context.fetch(name);
  50. const weights = await darknet.Weights.open(content);
  51. const reader = await context.read('text');
  52. const configuration = new darknet.Configuration(reader, context.identifier);
  53. return new darknet.Model(metadata, configuration, weights);
  54. } catch {
  55. const reader = await context.read('text');
  56. const configuration = new darknet.Configuration(reader, context.identifier);
  57. return new darknet.Model(metadata, configuration, null);
  58. }
  59. }
  60. default: {
  61. throw new darknet.Error(`Unsupported Darknet format '${context.type}'.`);
  62. }
  63. }
  64. }
  65. };
  66. darknet.Model = class {
  67. constructor(metadata, configuration, weights) {
  68. this.format = 'Darknet';
  69. this.modules = [new darknet.Graph(metadata, configuration, weights)];
  70. }
  71. };
  72. darknet.Graph = class {
  73. constructor(metadata, configuration, weights) {
  74. this.inputs = [];
  75. this.outputs = [];
  76. this.nodes = [];
  77. const params = {};
  78. const sections = configuration.read();
  79. const globals = new Map();
  80. const net = sections.shift();
  81. const option_find_int = (options, key, defaultValue) => {
  82. let value = options[key];
  83. if (typeof value === 'string' && value.startsWith('$')) {
  84. const key = value.substring(1);
  85. value = globals.has(key) ? globals.get(key) : value;
  86. }
  87. if (value !== undefined) {
  88. const number = parseInt(value, 10);
  89. if (!Number.isInteger(number)) {
  90. throw new darknet.Error(`Invalid int option '${JSON.stringify(options[key])}'.`);
  91. }
  92. return number;
  93. }
  94. return defaultValue;
  95. };
  96. const option_find_str = (options, key, defaultValue) => {
  97. const value = options[key];
  98. return value === undefined ? defaultValue : value;
  99. };
  100. const make_shape = (dimensions, source) => {
  101. if (dimensions.some((dimension) => dimension === 0 || dimension === undefined || isNaN(dimension))) {
  102. throw new darknet.Error(`Invalid tensor shape '${JSON.stringify(dimensions)}' in '${source}'.`);
  103. }
  104. return new darknet.TensorShape(dimensions);
  105. };
  106. const load_weights = (name, shape, visible) => {
  107. const data = weights ? weights.read(4 * shape.reduce((a, b) => a * b, 1)) : null;
  108. const type = new darknet.TensorType('float32', make_shape(shape, 'load_weights'));
  109. const initializer = new darknet.Tensor(type, data);
  110. const value = new darknet.Value('', null, initializer);
  111. return new darknet.Argument(name, [value], null, visible !== false);
  112. };
  113. const load_batch_normalize_weights = (layer, prefix, size) => {
  114. layer.weights.push(load_weights(`${prefix}scale`, [size], prefix === ''));
  115. layer.weights.push(load_weights(`${prefix}mean`, [size], prefix === ''));
  116. layer.weights.push(load_weights(`${prefix}variance`, [size], prefix === ''));
  117. };
  118. const make_convolutional_layer = (layer, prefix, w, h, c, n, groups, size, stride_x, stride_y, padding, batch_normalize) => {
  119. layer.out_w = Math.floor((w + 2 * padding - size) / stride_x) + 1;
  120. layer.out_h = Math.floor((h + 2 * padding - size) / stride_y) + 1;
  121. layer.out_c = n;
  122. layer.out = layer.out_w * layer.out_h * layer.out_c;
  123. layer.weights.push(load_weights(`${prefix}biases`, [n], prefix === ''));
  124. if (batch_normalize) {
  125. if (prefix) {
  126. load_batch_normalize_weights(layer, prefix, n);
  127. } else {
  128. const batchnorm_layer = { weights: [] };
  129. load_batch_normalize_weights(batchnorm_layer, prefix, n);
  130. layer.chain.push({ type: 'batchnorm', layer: batchnorm_layer });
  131. }
  132. }
  133. layer.weights.push(load_weights(`${prefix}weights`, [Math.floor(c / groups), n, size, size], prefix === ''));
  134. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'make_convolutional_layer'));
  135. };
  136. const make_deconvolutional_layer = (l, batch, h, w, c, n, size, stride, padding, activation, batch_normalize) => {
  137. const pad = padding;
  138. l.out_w = Math.floor((w - 1) * stride + size - 2 * pad);
  139. l.out_h = Math.floor((h - 1) * stride + size - 2 * pad);
  140. l.out_c = n;
  141. l.out = l.out_w * l.out_h * l.out_c;
  142. l.weights.push(load_weights(`biases`, [n]));
  143. if (batch_normalize) {
  144. const batchnorm_layer = { weights: [] };
  145. load_batch_normalize_weights(batchnorm_layer, '', n);
  146. l.chain.push({ type: 'batchnorm', layer: batchnorm_layer });
  147. }
  148. l.weights.push(load_weights(`weights`, [c, n, size, size]));
  149. l.outputs[0].type = new darknet.TensorType('float32', make_shape([l.out_w, l.out_h, l.out_c], 'make_convolutional_layer'));
  150. };
  151. const make_connected_layer = (layer, prefix, inputs, outputs, batch_normalize) => {
  152. layer.out_h = 1;
  153. layer.out_w = 1;
  154. layer.out_c = outputs;
  155. layer.out = outputs;
  156. layer.weights.push(load_weights(`${prefix}biases`, [outputs], prefix === ''));
  157. if (batch_normalize) {
  158. if (prefix) {
  159. load_batch_normalize_weights(layer, prefix, outputs);
  160. } else {
  161. const batchnorm_layer = { weights: [] };
  162. load_batch_normalize_weights(batchnorm_layer, prefix, outputs);
  163. layer.chain.push({ type: 'batchnorm', layer: batchnorm_layer });
  164. }
  165. }
  166. layer.weights.push(load_weights(`${prefix}weights`, [inputs, outputs], prefix === ''));
  167. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([outputs], 'make_connected_layer'));
  168. };
  169. if (sections.length === 0) {
  170. throw new darknet.Error('Config file has no sections.');
  171. }
  172. switch (net.type) {
  173. case 'net':
  174. case 'network': {
  175. params.h = option_find_int(net.options, 'height', 0);
  176. params.w = option_find_int(net.options, 'width', 0);
  177. params.c = option_find_int(net.options, 'channels', 0);
  178. params.inputs = option_find_int(net.options, 'inputs', params.h * params.w * params.c);
  179. for (const key of Object.keys(net.options)) {
  180. globals.set(key, net.options[key]);
  181. }
  182. break;
  183. }
  184. default: {
  185. throw new darknet.Error(`Unexpected '[${net.type}]' section. First section must be [net] or [network].`);
  186. }
  187. }
  188. const inputType = params.w && params.h && params.c ?
  189. new darknet.TensorType('float32', make_shape([params.w, params.h, params.c], 'params-if')) :
  190. new darknet.TensorType('float32', make_shape([params.inputs], ''));
  191. const inputName = 'input';
  192. params.value = [new darknet.Value(inputName, inputType, null)];
  193. this.inputs.push(new darknet.Argument(inputName, params.value));
  194. for (let i = 0; i < sections.length; i++) {
  195. const section = sections[i];
  196. section.name = i.toString();
  197. section.layer = {
  198. inputs: [],
  199. weights: [],
  200. outputs: [new darknet.Value(section.name, null, null)],
  201. chain: []
  202. };
  203. }
  204. let infer = true;
  205. for (let i = 0; i < sections.length; i++) {
  206. const section = sections[i];
  207. const options = section.options;
  208. const layer = section.layer;
  209. layer.inputs.push(...params.value);
  210. switch (section.type) {
  211. case 'shortcut': {
  212. let remove = true;
  213. const from = options.from ? options.from.split(',').map((item) => Number.parseInt(item.trim(), 10)) : [];
  214. for (const route of from) {
  215. const index = route < 0 ? i + route : route;
  216. const exists = index >= 0 && index < sections.length;
  217. remove = exists && remove;
  218. if (exists) {
  219. const source = sections[index].layer;
  220. layer.inputs.push(source.outputs[0]);
  221. }
  222. }
  223. if (remove) {
  224. delete options.from;
  225. }
  226. break;
  227. }
  228. case 'sam':
  229. case 'scale_channels': {
  230. const from = option_find_int(options, 'from', 0);
  231. const index = from < 0 ? i + from : from;
  232. if (index >= 0 && index < sections.length) {
  233. const source = sections[index].layer;
  234. layer.from = source;
  235. layer.inputs.push(source.outputs[0]);
  236. delete options.from;
  237. }
  238. break;
  239. }
  240. case 'route': {
  241. layer.inputs = [];
  242. layer.layers = [];
  243. let remove = true;
  244. const routes = options.layers ? options.layers.split(',').map((route) => Number.parseInt(route.trim(), 10)) : [];
  245. for (const route of routes) {
  246. const index = route < 0 ? i + route : route;
  247. const exists = index >= 0 && index < sections.length;
  248. remove = exists && remove;
  249. if (exists) {
  250. const source = sections[index].layer;
  251. layer.inputs.push(source.outputs[0]);
  252. layer.layers.push(source);
  253. }
  254. }
  255. if (remove) {
  256. delete options.layers;
  257. }
  258. break;
  259. }
  260. default:
  261. break;
  262. }
  263. if (infer) {
  264. switch (section.type) {
  265. case 'conv':
  266. case 'convolutional': {
  267. const shape = layer.inputs[0].type.shape.dimensions;
  268. if (shape[0] !== params.w || shape[1] !== params.h || shape[2] !== params.c) {
  269. throw new darknet.Error('Layer before convolutional layer must output image.');
  270. }
  271. const size = option_find_int(options, 'size', 1);
  272. const n = option_find_int(options, 'filters', 1);
  273. const pad = option_find_int(options, 'pad', 0);
  274. const padding = pad ? (size >> 1) : option_find_int(options, 'padding', 0);
  275. let stride_x = option_find_int(options, 'stride_x', -1);
  276. let stride_y = option_find_int(options, 'stride_y', -1);
  277. if (stride_x < 1 || stride_y < 1) {
  278. const stride = option_find_int(options, 'stride', 1);
  279. stride_x = stride_x < 1 ? stride : stride_x;
  280. stride_y = stride_y < 1 ? stride : stride_y;
  281. }
  282. const groups = option_find_int(options, 'groups', 1);
  283. const batch_normalize = option_find_int(options, 'batch_normalize', 0);
  284. const activation = option_find_str(options, 'activation', 'logistic');
  285. make_convolutional_layer(layer, '', params.w, params.h, params.c, n, groups, size, stride_x, stride_y, padding, batch_normalize);
  286. if (activation !== 'logistic' && activation !== 'none') {
  287. layer.chain.push({ type: activation });
  288. }
  289. break;
  290. }
  291. case 'deconvolutional': {
  292. const shape = layer.inputs[0].type.shape.dimensions;
  293. if (shape[0] !== params.w || shape[1] !== params.h || shape[2] !== params.c) {
  294. throw new darknet.Error('Layer before convolutional layer must output image.');
  295. }
  296. const n = option_find_int(options, 'filters', 1);
  297. const size = option_find_int(options, 'size', 1);
  298. const stride = option_find_int(options, 'stride', 1);
  299. const activation = option_find_str(options, 'activation', 'logistic');
  300. const h = params.h;
  301. const w = params.w;
  302. const c = params.c;
  303. const batch = params.batch;
  304. let padding = option_find_int(options, 'padding', 0);
  305. const pad = option_find_int(options, 'pad', 0);
  306. if (pad) {
  307. padding = size / 2;
  308. }
  309. const batch_normalize = option_find_int(options, 'batch_normalize', 0);
  310. make_deconvolutional_layer(layer, batch, h, w, c, n, size, stride, padding, activation, batch_normalize);
  311. if (activation !== 'logistic' && activation !== 'none') {
  312. layer.chain.push({ type: activation });
  313. }
  314. break;
  315. }
  316. case 'connected': {
  317. const outputs = option_find_int(options, 'output', 1);
  318. const batch_normalize = option_find_int(options, 'batch_normalize', 0);
  319. const activation = option_find_str(options, 'activation', 'logistic');
  320. make_connected_layer(layer, '', params.inputs, outputs, batch_normalize);
  321. if (activation !== 'logistic' && activation !== 'none') {
  322. layer.chain.push({ type: activation });
  323. }
  324. break;
  325. }
  326. case 'local': {
  327. const shape = layer.inputs[0].type.shape.dimensions;
  328. if (shape[0] !== params.w || shape[1] !== params.h || shape[2] !== params.c) {
  329. throw new darknet.Error('Layer before avgpool layer must output image.');
  330. }
  331. const n = option_find_int(options, 'filters' , 1);
  332. const size = option_find_int(options, 'size', 1);
  333. const stride = option_find_int(options, 'stride', 1);
  334. const pad = option_find_int(options, 'pad', 0);
  335. const activation = option_find_str(options, 'activation', 'logistic');
  336. layer.out_h = Math.floor((params.h - (pad ? 1 : size)) / stride) + 1;
  337. layer.out_w = Math.floor((params.w - (pad ? 1 : size)) / stride) + 1;
  338. layer.out_c = n;
  339. layer.out = layer.out_w * layer.out_h * layer.out_c;
  340. layer.weights.push(load_weights('weights', [params.c, n, size, size, layer.out_h * layer.out_w]));
  341. layer.weights.push(load_weights('biases',[layer.out_w * layer.out_h * layer.out_c]));
  342. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'local'));
  343. if (activation !== 'logistic' && activation !== 'none') {
  344. layer.chain.push({ type: activation });
  345. }
  346. break;
  347. }
  348. case 'batchnorm': {
  349. layer.out_h = params.h;
  350. layer.out_w = params.w;
  351. layer.out_c = params.c;
  352. layer.out = layer.in;
  353. load_batch_normalize_weights(layer, '', layer.out_c);
  354. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'batchnorm'));
  355. break;
  356. }
  357. case 'activation': {
  358. layer.out_h = params.h;
  359. layer.out_w = params.w;
  360. layer.out_c = params.c;
  361. layer.out = layer.in;
  362. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'activation'));
  363. break;
  364. }
  365. case 'max':
  366. case 'maxpool': {
  367. const shape = layer.inputs[0].type.shape.dimensions;
  368. if (shape[0] !== params.w || shape[1] !== params.h || shape[2] !== params.c) {
  369. throw new darknet.Error('Layer before maxpool layer must output image.');
  370. }
  371. const antialiasing = option_find_int(options, 'antialiasing', 0);
  372. const stride = option_find_int(options, 'stride', 1);
  373. const blur_stride_x = option_find_int(options, 'stride_x', stride);
  374. const blur_stride_y = option_find_int(options, 'stride_y', stride);
  375. const stride_x = antialiasing ? 1 : blur_stride_x;
  376. const stride_y = antialiasing ? 1 : blur_stride_y;
  377. const size = option_find_int(options, 'size', stride);
  378. const padding = option_find_int(options, 'padding', size - 1);
  379. const out_channels = option_find_int(options, 'out_channels', 1);
  380. const maxpool_depth = option_find_int(options, 'maxpool_depth', 0);
  381. if (maxpool_depth) {
  382. layer.out_c = out_channels;
  383. layer.out_w = params.w;
  384. layer.out_h = params.h;
  385. } else {
  386. layer.out_w = Math.floor((params.w + padding - size) / stride_x) + 1;
  387. layer.out_h = Math.floor((params.h + padding - size) / stride_y) + 1;
  388. layer.out_c = params.c;
  389. }
  390. if (antialiasing) {
  391. const blur_size = antialiasing === 2 ? 2 : 3;
  392. const blur_pad = antialiasing === 2 ? 0 : Math.floor(blur_size / 3);
  393. layer.input_layer = { weights: [], outputs: layer.outputs, chain: [] };
  394. make_convolutional_layer(layer.input_layer, '', layer.out_h, layer.out_w, layer.out_c, layer.out_c, layer.out_c, blur_size, blur_stride_x, blur_stride_y, blur_pad, 0);
  395. layer.out_w = layer.input_layer.out_w;
  396. layer.out_h = layer.input_layer.out_h;
  397. layer.out_c = layer.input_layer.out_c;
  398. } else {
  399. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'maxpool'));
  400. }
  401. layer.out = layer.out_w * layer.out_h * layer.out_c;
  402. break;
  403. }
  404. case 'avgpool': {
  405. const shape = layer.inputs[0].type.shape.dimensions;
  406. if (shape[0] !== params.w || shape[1] !== params.h || shape[2] !== params.c) {
  407. throw new darknet.Error('Layer before avgpool layer must output image.');
  408. }
  409. layer.out_w = 1;
  410. layer.out_h = 1;
  411. layer.out_c = params.c;
  412. layer.out = layer.out_c;
  413. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'avgpool'));
  414. break;
  415. }
  416. case 'crnn': {
  417. const size = option_find_int(options, 'size', 3);
  418. const stride = option_find_int(options, 'stride', 1);
  419. const output_filters = option_find_int(options, 'output', 1);
  420. const hidden_filters = option_find_int(options, 'hidden', 1);
  421. const groups = option_find_int(options, 'groups', 1);
  422. const pad = option_find_int(options, 'pad', 0);
  423. const padding = pad ? (size >> 1) : option_find_int(options, 'padding', 0);
  424. const batch_normalize = option_find_int(options, 'batch_normalize', 0);
  425. layer.input_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  426. make_convolutional_layer(layer.input_layer, 'input_', params.h, params.w, params.c, hidden_filters, groups, size, stride, stride, padding, batch_normalize);
  427. layer.self_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  428. make_convolutional_layer(layer.self_layer, 'self_', params.h, params.w, hidden_filters, hidden_filters, groups, size, stride, stride, padding, batch_normalize);
  429. layer.output_layer = { weights: [], outputs: layer.outputs, chain: [] };
  430. make_convolutional_layer(layer.output_layer, 'output_', params.h, params.w, hidden_filters, output_filters, groups, size, stride, stride, padding, batch_normalize);
  431. layer.weights = layer.weights.concat(layer.input_layer.weights);
  432. layer.weights = layer.weights.concat(layer.self_layer.weights);
  433. layer.weights = layer.weights.concat(layer.output_layer.weights);
  434. layer.out_h = layer.output_layer.out_h;
  435. layer.out_w = layer.output_layer.out_w;
  436. layer.out_c = output_filters;
  437. layer.out = layer.output_layer.out;
  438. break;
  439. }
  440. case 'rnn': {
  441. const outputs = option_find_int(options, 'output', 1);
  442. const hidden = option_find_int(options, 'hidden', 1);
  443. const batch_normalize = option_find_int(options, 'batch_normalize', 0);
  444. const inputs = params.inputs;
  445. layer.input_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  446. make_connected_layer(layer.input_layer, 'input_', inputs, hidden, batch_normalize);
  447. layer.self_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  448. make_connected_layer(layer.self_layer, 'self_', hidden, hidden, batch_normalize);
  449. layer.output_layer = { weights: [], outputs: layer.outputs, chain: [] };
  450. make_connected_layer(layer.output_layer, 'output_', hidden, outputs, batch_normalize);
  451. layer.weights = layer.weights.concat(layer.input_layer.weights);
  452. layer.weights = layer.weights.concat(layer.self_layer.weights);
  453. layer.weights = layer.weights.concat(layer.output_layer.weights);
  454. layer.out_w = 1;
  455. layer.out_h = 1;
  456. layer.out_c = outputs;
  457. layer.out = outputs;
  458. break;
  459. }
  460. case 'gru': {
  461. const inputs = params.inputs;
  462. const outputs = option_find_int(options, 'output', 1);
  463. const batch_normalize = option_find_int(options, 'batch_normalize', 0);
  464. layer.input_z_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  465. make_connected_layer(layer.input_z_layer, 'input_z', inputs, outputs, batch_normalize);
  466. layer.state_z_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  467. make_connected_layer(layer.state_z_layer, 'state_z', outputs, outputs, batch_normalize);
  468. layer.input_r_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  469. make_connected_layer(layer.input_r_layer, 'input_r', inputs, outputs, batch_normalize);
  470. layer.state_r_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  471. make_connected_layer(layer.state_r_layer, 'state_r', outputs, outputs, batch_normalize);
  472. layer.input_h_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  473. make_connected_layer(layer.input_h_layer, 'input_h', inputs, outputs, batch_normalize);
  474. layer.state_h_layer = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  475. make_connected_layer(layer.state_h_layer, 'state_h', outputs, outputs, batch_normalize);
  476. layer.weights = layer.weights.concat(layer.input_z_layer.weights);
  477. layer.weights = layer.weights.concat(layer.state_z_layer.weights);
  478. layer.weights = layer.weights.concat(layer.input_r_layer.weights);
  479. layer.weights = layer.weights.concat(layer.state_r_layer.weights);
  480. layer.weights = layer.weights.concat(layer.input_h_layer.weights);
  481. layer.weights = layer.weights.concat(layer.state_h_layer.weights);
  482. layer.out = outputs;
  483. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([outputs], 'gru'));
  484. break;
  485. }
  486. case 'lstm': {
  487. const inputs = params.inputs;
  488. const outputs = option_find_int(options, 'output', 1);
  489. const batch_normalize = option_find_int(options, 'batch_normalize', 0);
  490. layer.uf = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  491. make_connected_layer(layer.uf, 'uf_', inputs, outputs, batch_normalize);
  492. layer.ui = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  493. make_connected_layer(layer.ui, 'ui_', inputs, outputs, batch_normalize);
  494. layer.ug = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  495. make_connected_layer(layer.ug, 'ug_', inputs, outputs, batch_normalize);
  496. layer.uo = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  497. make_connected_layer(layer.uo, 'uo_', inputs, outputs, batch_normalize);
  498. layer.wf = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  499. make_connected_layer(layer.wf, 'wf_', outputs, outputs, batch_normalize);
  500. layer.wi = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  501. make_connected_layer(layer.wi, 'wi_', outputs, outputs, batch_normalize);
  502. layer.wg = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  503. make_connected_layer(layer.wg, 'wg_', outputs, outputs, batch_normalize);
  504. layer.wo = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  505. make_connected_layer(layer.wo, 'wo_', outputs, outputs, batch_normalize);
  506. layer.weights = layer.weights.concat(layer.uf.weights);
  507. layer.weights = layer.weights.concat(layer.ui.weights);
  508. layer.weights = layer.weights.concat(layer.ug.weights);
  509. layer.weights = layer.weights.concat(layer.uo.weights);
  510. layer.weights = layer.weights.concat(layer.wf.weights);
  511. layer.weights = layer.weights.concat(layer.wi.weights);
  512. layer.weights = layer.weights.concat(layer.wg.weights);
  513. layer.weights = layer.weights.concat(layer.wo.weights);
  514. layer.out_w = 1;
  515. layer.out_h = 1;
  516. layer.out_c = outputs;
  517. layer.out = outputs;
  518. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([outputs], 'lstm'));
  519. weights = null;
  520. break;
  521. }
  522. case 'conv_lstm': {
  523. const size = option_find_int(options, "size", 3);
  524. const stride = option_find_int(options, "stride", 1);
  525. const output_filters = option_find_int(options, "output", 1);
  526. const groups = option_find_int(options, "groups", 1);
  527. const pad = option_find_int(options, "pad", 0);
  528. const padding = pad ? (size >> 1) : option_find_int(options, 'padding', 0);
  529. const batch_normalize = option_find_int(options, 'batch_normalize', 0);
  530. const bottleneck = option_find_int(options, "bottleneck", 0);
  531. const peephole = option_find_int(options, "peephole", 0);
  532. layer.uf = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  533. make_convolutional_layer(layer.uf, 'uf_', params.h, params.w, params.c, output_filters, groups, size, stride, stride, padding, batch_normalize);
  534. layer.ui = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  535. make_convolutional_layer(layer.ui, 'ui_', params.h, params.w, params.c, output_filters, groups, size, stride, stride, padding, batch_normalize);
  536. layer.ug = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  537. make_convolutional_layer(layer.ug, 'ug_', params.h, params.w, params.c, output_filters, groups, size, stride, stride, padding, batch_normalize);
  538. layer.uo = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  539. make_convolutional_layer(layer.uo, 'uo_', params.h, params.w, params.c, output_filters, groups, size, stride, stride, padding, batch_normalize);
  540. layer.weights = layer.weights.concat(layer.uf.weights);
  541. layer.weights = layer.weights.concat(layer.ui.weights);
  542. layer.weights = layer.weights.concat(layer.ug.weights);
  543. layer.weights = layer.weights.concat(layer.uo.weights);
  544. if (bottleneck) {
  545. layer.wf = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  546. make_convolutional_layer(layer.wf, 'wf_', params.h, params.w, output_filters * 2, output_filters, groups, size, stride, stride, padding, batch_normalize);
  547. layer.weights = layer.weights.concat(layer.wf.weights);
  548. } else {
  549. layer.wf = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  550. make_convolutional_layer(layer.wf, 'wf_', params.h, params.w, output_filters, output_filters, groups, size, stride, stride, padding, batch_normalize);
  551. layer.wi = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  552. make_convolutional_layer(layer.wi, 'wi_', params.h, params.w, output_filters, output_filters, groups, size, stride, stride, padding, batch_normalize);
  553. layer.wg = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  554. make_convolutional_layer(layer.wg, 'wg_', params.h, params.w, output_filters, output_filters, groups, size, stride, stride, padding, batch_normalize);
  555. layer.wo = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  556. make_convolutional_layer(layer.wo, 'wo_', params.h, params.w, output_filters, output_filters, groups, size, stride, stride, padding, batch_normalize);
  557. layer.weights = layer.weights.concat(layer.wf.weights);
  558. layer.weights = layer.weights.concat(layer.wi.weights);
  559. layer.weights = layer.weights.concat(layer.wg.weights);
  560. layer.weights = layer.weights.concat(layer.wo.weights);
  561. }
  562. if (peephole) {
  563. layer.vf = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  564. make_convolutional_layer(layer.vf, 'vf_', params.h, params.w, output_filters, output_filters, groups, size, stride, stride, padding, batch_normalize);
  565. layer.vi = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  566. make_convolutional_layer(layer.vi, 'vi_', params.h, params.w, output_filters, output_filters, groups, size, stride, stride, padding, batch_normalize);
  567. layer.vo = { weights: [], outputs: [new darknet.Value('', null, null)], chain: [] };
  568. make_convolutional_layer(layer.vo, 'vo_', params.h, params.w, output_filters, output_filters, groups, size, stride, stride, padding, batch_normalize);
  569. layer.weights = layer.weights.concat(layer.vf.weights);
  570. layer.weights = layer.weights.concat(layer.vi.weights);
  571. layer.weights = layer.weights.concat(layer.vo.weights);
  572. }
  573. layer.out_h = layer.uo.out_h;
  574. layer.out_w = layer.uo.out_w;
  575. layer.out_c = output_filters;
  576. layer.out = layer.out_h * layer.out_w * layer.out_c;
  577. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'conv_lstm'));
  578. break;
  579. }
  580. case 'softmax': {
  581. layer.out_w = params.w;
  582. layer.out_h = params.h;
  583. layer.out_c = params.c;
  584. layer.out = params.inputs;
  585. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out], 'softmax'));
  586. break;
  587. }
  588. case 'dropout': {
  589. layer.out_w = params.w;
  590. layer.out_h = params.h;
  591. layer.out_c = params.c;
  592. layer.out = params.inputs;
  593. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'dropout'));
  594. break;
  595. }
  596. case 'upsample': {
  597. const stride = option_find_int(options, 'stride', 2);
  598. layer.out_w = params.w * stride;
  599. layer.out_h = params.h * stride;
  600. layer.out_c = params.c;
  601. layer.out = layer.out_w * layer.out_h * layer.out_c;
  602. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'upsample'));
  603. break;
  604. }
  605. case 'crop': {
  606. const shape = layer.inputs[0].type.shape.dimensions;
  607. if (shape[0] !== params.w || shape[1] !== params.h || shape[2] !== params.c) {
  608. throw new darknet.Error('Layer before crop layer must output image.');
  609. }
  610. const crop_height = option_find_int(options, 'crop_height', 1);
  611. const crop_width = option_find_int(options, 'crop_width', 1);
  612. layer.out_w = crop_width;
  613. layer.out_h = crop_height;
  614. layer.out_c = params.c;
  615. layer.out = layer.out_w * layer.out_h * layer.out_c;
  616. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'crop'));
  617. break;
  618. }
  619. case 'yolo': {
  620. const classes = option_find_int(options, 'classes', 20);
  621. const n = option_find_int(options, 'num', 1);
  622. layer.out_h = params.h;
  623. layer.out_w = params.w;
  624. layer.out_c = n * (classes + 4 + 1);
  625. layer.out = layer.out_h * layer.out_w * layer.out_c;
  626. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'yolo'));
  627. break;
  628. }
  629. case 'Gaussian_yolo': {
  630. const classes = option_find_int(options, 'classes', 20);
  631. const n = option_find_int(options, 'num', 1);
  632. layer.out_h = params.h;
  633. layer.out_w = params.w;
  634. layer.out_c = n * (classes + 8 + 1);
  635. layer.out = layer.out_h * layer.out_w * layer.out_c;
  636. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'Gaussian_yolo'));
  637. break;
  638. }
  639. case 'region': {
  640. const coords = option_find_int(options, 'coords', 4);
  641. const classes = option_find_int(options, 'classes', 20);
  642. const num = option_find_int(options, 'num', 1);
  643. layer.out = params.h * params.w * num * (classes + coords + 1);
  644. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([params.h, params.w, num, (classes + coords + 1)], 'region'));
  645. break;
  646. }
  647. case 'cost': {
  648. layer.out = params.inputs;
  649. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out], 'cost'));
  650. break;
  651. }
  652. case 'reorg': {
  653. const stride = option_find_int(options, 'stride', 1);
  654. const reverse = option_find_int(options, 'reverse', 0);
  655. const extra = option_find_int(options, 'extra', 0);
  656. if (reverse) {
  657. layer.out_w = params.w * stride;
  658. layer.out_h = params.h * stride;
  659. layer.out_c = Math.floor(params.c / (stride * stride));
  660. layer.out = layer.out_h * layer.out_w * layer.out_c;
  661. } else {
  662. layer.out_w = Math.floor(params.w / stride);
  663. layer.out_h = Math.floor(params.h / stride);
  664. layer.out_c = params.c * (stride * stride);
  665. layer.out = layer.out_h * layer.out_w * layer.out_c;
  666. }
  667. if (extra) {
  668. layer.out_w = 0;
  669. layer.out_h = 0;
  670. layer.out_c = 0;
  671. layer.out = (params.h * params.w * params.c) + extra;
  672. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out], 'reorg'));
  673. } else {
  674. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'reorg'));
  675. }
  676. break;
  677. }
  678. case 'route': {
  679. const layers = [].concat(layer.layers);
  680. const groups = option_find_int(options, 'groups', 1);
  681. layer.out = 0;
  682. for (const next of layers) {
  683. layer.out += next.outputs / groups;
  684. }
  685. if (layers.length > 0) {
  686. const first = layers.shift();
  687. layer.out_w = first.out_w;
  688. layer.out_h = first.out_h;
  689. layer.out_c = first.out_c / groups;
  690. while (layers.length > 0) {
  691. const next = layers.shift();
  692. if (next.out_w === first.out_w && next.out_h === first.out_h) {
  693. layer.out_c += next.out_c;
  694. continue;
  695. }
  696. infer = false;
  697. break;
  698. }
  699. if (infer) {
  700. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'route'));
  701. }
  702. } else {
  703. infer = false;
  704. }
  705. if (!infer) {
  706. layer.out_h = 0;
  707. layer.out_w = 0;
  708. layer.out_c = 0;
  709. }
  710. break;
  711. }
  712. case 'sam':
  713. case 'scale_channels': {
  714. const activation = option_find_str(options, 'activation', 'linear');
  715. const from = layer.from;
  716. if (from) {
  717. layer.out_w = from.out_w;
  718. layer.out_h = from.out_h;
  719. layer.out_c = from.out_c;
  720. layer.out = layer.out_w * layer.out_h * layer.out_c;
  721. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out_w, layer.out_h, layer.out_c], 'shortcut|scale_channels|sam'));
  722. }
  723. if (activation !== 'linear' && activation !== 'none') {
  724. layer.chain.push({ type: activation });
  725. }
  726. break;
  727. }
  728. case 'shortcut': {
  729. const activation = option_find_str(options, 'activation', 'linear');
  730. layer.out_w = params.w;
  731. layer.out_h = params.h;
  732. layer.out_c = params.c;
  733. layer.out = params.w * params.h * params.c;
  734. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([params.w, params.h, params.c], 'shortcut|scale_channels|sam'));
  735. if (activation !== 'linear' && activation !== 'none') {
  736. layer.chain.push({ type: activation });
  737. }
  738. break;
  739. }
  740. case 'detection': {
  741. layer.out_w = params.w;
  742. layer.out_h = params.h;
  743. layer.out_c = params.c;
  744. layer.out = params.inputs;
  745. layer.outputs[0].type = new darknet.TensorType('float32', make_shape([layer.out], 'detection'));
  746. break;
  747. }
  748. default: {
  749. infer = false;
  750. break;
  751. }
  752. }
  753. params.h = layer.out_h;
  754. params.w = layer.out_w;
  755. params.c = layer.out_c;
  756. params.inputs = layer.out;
  757. params.last = section;
  758. }
  759. params.value = layer.outputs;
  760. }
  761. for (let i = 0; i < sections.length; i++) {
  762. this.nodes.push(new darknet.Node(metadata, net, sections[i]));
  763. }
  764. if (weights) {
  765. weights.validate();
  766. }
  767. }
  768. };
  769. darknet.Argument = class {
  770. constructor(name, value, type = null, visible = true) {
  771. this.name = name;
  772. this.value = value;
  773. this.type = type;
  774. this.visible = visible;
  775. }
  776. };
  777. darknet.Value = class {
  778. constructor(name, type, initializer) {
  779. if (typeof name !== 'string') {
  780. throw new darknet.Error(`Invalid value identifier '${JSON.stringify(name)}'.`);
  781. }
  782. this.name = name;
  783. this.type = initializer && initializer.type ? initializer.type : type;
  784. this.initializer = initializer;
  785. }
  786. };
  787. darknet.Node = class {
  788. constructor(metadata, net, section) {
  789. this.name = section.name || '';
  790. this.identifier = section.line === undefined ? undefined : section.line.toString();
  791. this.attributes = [];
  792. this.inputs = [];
  793. this.outputs = [];
  794. this.chain = [];
  795. const type = section.type;
  796. this.type = metadata.type(type) || { name: type };
  797. const layer = section.layer;
  798. if (layer && layer.inputs && layer.inputs.length > 0) {
  799. this.inputs.push(new darknet.Argument(layer.inputs.length <= 1 ? 'input' : 'inputs', layer.inputs));
  800. }
  801. if (layer && layer.weights && layer.weights.length > 0) {
  802. this.inputs = this.inputs.concat(layer.weights);
  803. }
  804. if (layer && layer.outputs && layer.outputs.length > 0) {
  805. this.outputs.push(new darknet.Argument(layer.outputs.length <= 1 ? 'output' : 'outputs', layer.outputs));
  806. }
  807. if (layer && layer.chain) {
  808. for (const chain of layer.chain) {
  809. this.chain.push(new darknet.Node(metadata, net, chain, ''));
  810. }
  811. }
  812. const options = section.options;
  813. if (options) {
  814. for (const [name, obj] of Object.entries(options)) {
  815. const schema = metadata.attribute(section.type, name);
  816. let type = null;
  817. let value = obj;
  818. let visible = true;
  819. if (schema) {
  820. type = schema.type || '';
  821. switch (type) {
  822. case '':
  823. case 'string': {
  824. break;
  825. }
  826. case 'int32': {
  827. const number = parseInt(value, 10);
  828. if (Number.isInteger(number)) {
  829. value = number;
  830. }
  831. break;
  832. }
  833. case 'float32': {
  834. const number = parseFloat(value);
  835. if (!isNaN(number)) {
  836. value = number;
  837. }
  838. break;
  839. }
  840. case 'int32[]': {
  841. const numbers = value.split(',').map((item) => parseInt(item.trim(), 10));
  842. if (numbers.every((number) => Number.isInteger(number))) {
  843. value = numbers;
  844. }
  845. break;
  846. }
  847. default: {
  848. throw new darknet.Error(`Unsupported attribute type '${type}'.`);
  849. }
  850. }
  851. visible = (schema.visible === false || value === schema.default);
  852. }
  853. const attribute = new darknet.Argument(name, value, type, visible);
  854. this.attributes.push(attribute);
  855. }
  856. }
  857. }
  858. };
  859. darknet.Tensor = class {
  860. constructor(type, data) {
  861. this.type = type;
  862. this.values = data;
  863. }
  864. };
  865. darknet.TensorType = class {
  866. constructor(dataType, shape) {
  867. this.dataType = dataType;
  868. this.shape = shape;
  869. }
  870. toString() {
  871. return (this.dataType || '?') + this.shape.toString();
  872. }
  873. };
  874. darknet.TensorShape = class {
  875. constructor(dimensions) {
  876. if (dimensions.some((dimension) => dimension === 0 || dimension === undefined || isNaN(dimension))) {
  877. throw new darknet.Error(`Invalid tensor shape '${JSON.stringify(dimensions)}'.`);
  878. }
  879. this.dimensions = dimensions;
  880. }
  881. toString() {
  882. if (this.dimensions) {
  883. if (this.dimensions.length === 0) {
  884. return '';
  885. }
  886. return `[${this.dimensions.map((dimension) => dimension.toString()).join(',')}]`;
  887. }
  888. return '';
  889. }
  890. };
  891. darknet.Configuration = class {
  892. constructor(reader, identifier) {
  893. this.reader = reader;
  894. this.identifier = identifier;
  895. }
  896. read() {
  897. // read_cfg
  898. const sections = [];
  899. let section = null;
  900. const reader = this.reader;
  901. let lineNumber = 0;
  902. const setup = /^setup.*\.cfg$/.test(this.identifier);
  903. for (let content = reader.read('\n'); content !== undefined; content = reader.read('\n')) {
  904. lineNumber++;
  905. const line = content.replace(/\s/g, '');
  906. if (line.length > 0) {
  907. switch (line[0]) {
  908. case '#':
  909. case ';':
  910. break;
  911. case '[': {
  912. const type = line[line.length - 1] === ']' ? line.substring(1, line.length - 1) : line.substring(1);
  913. if (setup) {
  914. if (type === 'metadata' || type === 'global' || type === 'wheel' ||
  915. type === 'isort' || type === 'flake8' || type === 'build_ext' ||
  916. type.startsWith('bdist_') || type.startsWith('tool:') || type.startsWith('coverage:')) {
  917. throw new darknet.Error('Invalid file content. File contains Python setup configuration data.');
  918. }
  919. }
  920. section = {
  921. line: lineNumber,
  922. type,
  923. options: {}
  924. };
  925. sections.push(section);
  926. break;
  927. }
  928. default: {
  929. if (!section || line[0] < 0x20 || line[0] > 0x7E) {
  930. throw new darknet.Error(`Invalid cfg '${content.replace(/[^\x20-\x7E]+/g, '?').trim()}' at line ${lineNumber}.`);
  931. }
  932. const index = line.indexOf('=');
  933. if (index < 0) {
  934. throw new darknet.Error(`Invalid cfg '${content.replace(/[^\x20-\x7E]+/g, '?').trim()}' at line ${lineNumber}.`);
  935. }
  936. const key = line.substring(0, index);
  937. const value = line.substring(index + 1);
  938. section.options[key] = value;
  939. break;
  940. }
  941. }
  942. }
  943. }
  944. return sections;
  945. }
  946. };
  947. darknet.Weights = class {
  948. static async open(context) {
  949. const reader = await context.read('binary');
  950. if (reader && reader.length >= 20) {
  951. const major = reader.int32();
  952. const minor = reader.int32();
  953. reader.int32(); // revision
  954. reader.seek(0);
  955. const transpose = (major > 1000) || (minor > 1000);
  956. if (!transpose) {
  957. const offset = 12 + ((major * 10 + minor) >= 2 ? 8 : 4);
  958. return new darknet.Weights(reader, offset);
  959. }
  960. }
  961. return null;
  962. }
  963. constructor(reader, offset) {
  964. this._reader = reader;
  965. this._offset = offset;
  966. }
  967. read(size) {
  968. this._reader.skip(this._offset);
  969. this._offset = 0;
  970. return this._reader.read(size);
  971. }
  972. validate() {
  973. if (this._reader.position !== this._reader.length) {
  974. throw new darknet.Error('Invalid weights size.');
  975. }
  976. }
  977. };
  978. darknet.Error = class extends Error {
  979. constructor(message) {
  980. super(message);
  981. this.name = 'Error loading Darknet model.';
  982. }
  983. };
  984. export const ModelFactory = darknet.ModelFactory;