Initial commit

oops, should have committed before
This commit is contained in:
Starbeamrainbowlabs 2023-02-16 19:05:43 +00:00
commit 9e9942da19
Signed by: sbrl
GPG key ID: 1BE5172E637709C2
9 changed files with 835 additions and 0 deletions

159
.gitignore vendored Normal file
View file

@ -0,0 +1,159 @@
# Created by https://www.toptal.com/developers/gitignore/api/git,node
# Edit at https://www.toptal.com/developers/gitignore?templates=git,node
### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig
# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
# Optional stylelint cache
# SvelteKit build / generate output
.svelte-kit
# End of https://www.toptal.com/developers/gitignore/api/git,node

399
package-lock.json generated Normal file
View file

@ -0,0 +1,399 @@
{
"name": "tfsummaryvis",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "tfsummaryvis",
"version": "1.0.0",
"license": "MPL-2.0",
"dependencies": {
"esbuild": "^0.17.8",
"nomnoml": "^1.5.3"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.8.tgz",
"integrity": "sha512-0/rb91GYKhrtbeglJXOhAv9RuYimgI8h623TplY2X+vA4EXnk3Zj1fXZreJ0J3OJJu1bwmb0W7g+2cT/d8/l/w==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.8.tgz",
"integrity": "sha512-oa/N5j6v1svZQs7EIRPqR8f+Bf8g6HBDjD/xHC02radE/NjKHK7oQmtmLxPs1iVwYyvE+Kolo6lbpfEQ9xnhxQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.8.tgz",
"integrity": "sha512-bTliMLqD7pTOoPg4zZkXqCDuzIUguEWLpeqkNfC41ODBHwoUgZ2w5JBeYimv4oP6TDVocoYmEhZrCLQTrH89bg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.8.tgz",
"integrity": "sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.8.tgz",
"integrity": "sha512-n5WOpyvZ9TIdv2V1K3/iIkkJeKmUpKaCTdun9buhGRWfH//osmUjlv4Z5mmWdPWind/VGcVxTHtLfLCOohsOXw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.8.tgz",
"integrity": "sha512-a/SATTaOhPIPFWvHZDoZYgxaZRVHn0/LX1fHLGfZ6C13JqFUZ3K6SMD6/HCtwOQ8HnsNaEeokdiDSFLuizqv5A==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.8.tgz",
"integrity": "sha512-xpFJb08dfXr5+rZc4E+ooZmayBW6R3q59daCpKZ/cDU96/kvDM+vkYzNeTJCGd8rtO6fHWMq5Rcv/1cY6p6/0Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.8.tgz",
"integrity": "sha512-6Ij8gfuGszcEwZpi5jQIJCVIACLS8Tz2chnEBfYjlmMzVsfqBP1iGmHQPp7JSnZg5xxK9tjCc+pJ2WtAmPRFVA==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.8.tgz",
"integrity": "sha512-v3iwDQuDljLTxpsqQDl3fl/yihjPAyOguxuloON9kFHYwopeJEf1BkDXODzYyXEI19gisEsQlG1bM65YqKSIww==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.8.tgz",
"integrity": "sha512-8svILYKhE5XetuFk/B6raFYIyIqydQi+GngEXJgdPdI7OMKUbSd7uzR02wSY4kb53xBrClLkhH4Xs8P61Q2BaA==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.8.tgz",
"integrity": "sha512-B6FyMeRJeV0NpyEOYlm5qtQfxbdlgmiGdD+QsipzKfFky0K5HW5Td6dyK3L3ypu1eY4kOmo7wW0o94SBqlqBSA==",
"cpu": [
"loong64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.8.tgz",
"integrity": "sha512-CCb67RKahNobjm/eeEqeD/oJfJlrWyw29fgiyB6vcgyq97YAf3gCOuP6qMShYSPXgnlZe/i4a8WFHBw6N8bYAA==",
"cpu": [
"mips64el"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.8.tgz",
"integrity": "sha512-bytLJOi55y55+mGSdgwZ5qBm0K9WOCh0rx+vavVPx+gqLLhxtSFU0XbeYy/dsAAD6xECGEv4IQeFILaSS2auXw==",
"cpu": [
"ppc64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.8.tgz",
"integrity": "sha512-2YpRyQJmKVBEHSBLa8kBAtbhucaclb6ex4wchfY0Tj3Kg39kpjeJ9vhRU7x4mUpq8ISLXRXH1L0dBYjAeqzZAw==",
"cpu": [
"riscv64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.8.tgz",
"integrity": "sha512-QgbNY/V3IFXvNf11SS6exkpVcX0LJcob+0RWCgV9OiDAmVElnxciHIisoSix9uzYzScPmS6dJFbZULdSAEkQVw==",
"cpu": [
"s390x"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.8.tgz",
"integrity": "sha512-mM/9S0SbAFDBc4OPoyP6SEOo5324LpUxdpeIUUSrSTOfhHU9hEfqRngmKgqILqwx/0DVJBzeNW7HmLEWp9vcOA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.8.tgz",
"integrity": "sha512-eKUYcWaWTaYr9zbj8GertdVtlt1DTS1gNBWov+iQfWuWyuu59YN6gSEJvFzC5ESJ4kMcKR0uqWThKUn5o8We6Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.8.tgz",
"integrity": "sha512-Vc9J4dXOboDyMXKD0eCeW0SIeEzr8K9oTHJU+Ci1mZc5njPfhKAqkRt3B/fUNU7dP+mRyralPu8QUkiaQn7iIg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.8.tgz",
"integrity": "sha512-0xvOTNuPXI7ft1LYUgiaXtpCEjp90RuBBYovdd2lqAFxje4sEucurg30M1WIm03+3jxByd3mfo+VUmPtRSVuOw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.8.tgz",
"integrity": "sha512-G0JQwUI5WdEFEnYNKzklxtBheCPkuDdu1YrtRrjuQv30WsYbkkoixKxLLv8qhJmNI+ATEWquZe/N0d0rpr55Mg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.8.tgz",
"integrity": "sha512-Fqy63515xl20OHGFykjJsMnoIWS+38fqfg88ClvPXyDbLtgXal2DTlhb1TfTX34qWi3u4I7Cq563QcHpqgLx8w==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.8.tgz",
"integrity": "sha512-1iuezdyDNngPnz8rLRDO2C/ZZ/emJLb72OsZeqQ6gL6Avko/XCXZw+NuxBSNhBAP13Hie418V7VMt9et1FMvpg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.8.tgz",
"integrity": "sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==",
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.17.8",
"@esbuild/android-arm64": "0.17.8",
"@esbuild/android-x64": "0.17.8",
"@esbuild/darwin-arm64": "0.17.8",
"@esbuild/darwin-x64": "0.17.8",
"@esbuild/freebsd-arm64": "0.17.8",
"@esbuild/freebsd-x64": "0.17.8",
"@esbuild/linux-arm": "0.17.8",
"@esbuild/linux-arm64": "0.17.8",
"@esbuild/linux-ia32": "0.17.8",
"@esbuild/linux-loong64": "0.17.8",
"@esbuild/linux-mips64el": "0.17.8",
"@esbuild/linux-ppc64": "0.17.8",
"@esbuild/linux-riscv64": "0.17.8",
"@esbuild/linux-s390x": "0.17.8",
"@esbuild/linux-x64": "0.17.8",
"@esbuild/netbsd-x64": "0.17.8",
"@esbuild/openbsd-x64": "0.17.8",
"@esbuild/sunos-x64": "0.17.8",
"@esbuild/win32-arm64": "0.17.8",
"@esbuild/win32-ia32": "0.17.8",
"@esbuild/win32-x64": "0.17.8"
}
},
"node_modules/graphre": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/graphre/-/graphre-0.1.3.tgz",
"integrity": "sha512-F4OO/+BQj3R2UB3PQOGLgdAUy+SQuwy2A5cVGELAQDJlloSyyHqRe60ESFouRf8W0K+sm6gtWKotOwZoX3BL8w=="
},
"node_modules/nomnoml": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/nomnoml/-/nomnoml-1.5.3.tgz",
"integrity": "sha512-2LBKi3ygeYAC9l/wowgtBRxvQGuTryIczULVk2rFbWGUvs5aX68/sH+WgL95CschnSnxucTIv9L+3xScS71obQ==",
"dependencies": {
"graphre": "^0.1.3"
},
"bin": {
"nomnoml": "dist/nomnoml-cli.js"
}
}
}
}

32
package.json Normal file
View file

@ -0,0 +1,32 @@
{
"name": "tfsummaryvis",
"version": "1.0.0",
"description": "Visualise textual tensorflow summaries as a directed graph.",
"main": "src/index.mjs",
"scripts": {
"test": "echo \"No tests have been written yet.\"",
"build": "node ./src/esbuild.mjs"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sbrl/tfsummaryvis.git"
},
"keywords": [
"tensorflow",
"data",
"visualisation",
"directed",
"graph"
],
"author": "Starbeamrainbowlabs",
"license": "MPL-2.0",
"bugs": {
"url": "https://github.com/sbrl/tfsummaryvis/issues"
},
"homepage": "https://github.com/sbrl/tfsummaryvis#readme",
"private": true,
"dependencies": {
"esbuild": "^0.17.8",
"nomnoml": "^1.5.3"
}
}

34
src/app.css Normal file
View file

@ -0,0 +1,34 @@
html, body {
margin: 0; padding: 0;
font-size: 100%;
}
body {
min-height: 100vh;
font-family: Ubuntu, sans-serif;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas: "header header"
"left right"
"footer footer";
}
h1 {
grid-area: header;
margin: 0.5em;
text-align: center;
}
#input-summary {
grid-area: left;
}
#output-graph {
grid-area: right;
}
footer {
grid-area: footer;
margin: 0.5em;
}

32
src/app.mjs Normal file
View file

@ -0,0 +1,32 @@
"use strict";
import parse_summary from './lib/parse_summary.mjs';
import make_graph from './lib/make_graph.mjs';
function do_visualisation(el_in, el_out) {
console.log(el_in, el_out);
const source = el_in.value.trim();
if(source.length === 0) return;
const summary = parse_summary(source);
console.log(summary);
const svg = make_graph(summary);
console.log(svg);
const container = document.createElement("div");
container.innerHTML = svg;
el_out.replaceChildren(container);
}
window.addEventListener("load", () => {
const el_in = document.querySelector("#input-summary");
const el_out = document.querySelector("#output-graph");
el_in.addEventListener("changed", do_visualisation.bind(this, el_in, el_out));
el_in.addEventListener("keyup", do_visualisation.bind(this, el_in, el_out));
do_visualisation(el_in, el_out);
});

76
src/esbuild.mjs Normal file
View file

@ -0,0 +1,76 @@
"use strict";
import crypto from 'crypto';
import path from 'path';
import fs from 'fs';
import esbuild from 'esbuild';
const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf("/"));
const outdir = path.resolve(__dirname, "../dist");
/**
* Hashes the contents of a file.
* @ref https://stackoverflow.com/a/44643479/1460422
* @param {string} hashName The name of the hash algorithm to use.
* @param {string} path The path to the file to hash.
* @return {string} The resulting hash as a hexadecimal string.
*/
function hash_file(hashName, path) {
return new Promise((resolve, reject) => {
const hash = crypto.createHash(hashName);
const stream = fs.createReadStream(path);
stream.once("error", reject);
stream.on("data", chunk => hash.update(chunk));
stream.once("end", () => {
stream.off("error", reject);
resolve(hash.digest('base64'));
});
});
}
async function do_html() {
// We *would* use SHA3 here, but we need to use SHA2 for subresource integrity
let algorithm = "sha256";
let css_hash = await hash_file(algorithm, path.join(outdir, "app.css"));
let js_hash = await hash_file(algorithm, path.join(outdir, "app.js"));
let html = (await fs.promises.readFile(path.join(__dirname, "index.html"), "utf-8"))
.replace(/\{JS_HASH\}/g, js_hash)
.replace(/\{CSS_HASH\}/g, css_hash)
.replace(/\{JS_HASH_SHORT\}/g, js_hash.substring(0, 7).replace(/[+/=]/, ""))
.replace(/\{CSS_HASH_SHORT\}/g, css_hash.substring(0, 7).replace(/[+/=]/, ""))
.replace(/\{ALGO\}/g, algorithm);
await fs.promises.writeFile(path.join(outdir, "index.html"), html);
}
(async () => {
"use strict";
const result = await esbuild.build({
entryPoints: [
"./app.mjs",
"./app.css",
].map(filepath => path.resolve(__dirname, filepath)),
outdir,
bundle: true,
minify: typeof process.env.NO_MINIFY === "undefined",
sourcemap: true,
treeShaking: true,
loader: {
".html": "text",
".svg": "file",
".woff2": "file",
".woff": "file",
".eot": "file",
".ttf": "file",
},
external: ["fs", "path"],
});
if (result.errors.length > 0 || result.warnings.length > 0)
console.log(result);
await do_html();
// console.log(await esbuild.analyzeMetafile(result.metafile));
})();

23
src/index.html Normal file
View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Tensorflow Summary Visualisation</title>
</head>
<body>
<h1>Tensorflow Summary Visualisation</h1>
<textarea name="input-summary" id="input-summary"></textarea>
<div id="output-graph"></div>
<footer>
<p>Built with love by <a href="https://starbeamrainbowlabs.com/">Starbeamrainbowlabs</a></p>
</footer>
<!---------------->
<link rel="stylesheet" href="/app.css?hash={CSS_HASH_SHORT}" integrity="{ALGO}-{CSS_HASH}" />
<script src="/app.js?hash={JS_HASH_SHORT}" integrity="{ALGO}-{JS_HASH}" charset="utf-8"></script>
<!-- <link rel="stylesheet" href="/app.css" />
<script src="/app.js"></script> -->
</body>
</html>

20
src/lib/make_graph.mjs Normal file
View file

@ -0,0 +1,20 @@
"use strict";
import nomnoml from 'nomnoml';
export default function make_graph(summary) {
const result = [];
for(const layer of summary.layers) {
const output_shape = layer.output_shape.replace(/\[/, "\\[")
.replace(/\]/, "\\]");
result.push(`[${layer.name}|${layer.type}|Params: ${layer.params}|Output shape: ${output_shape}]`);
}
for(const edge of summary.edges) {
result.push(`[${edge.from}] --> [${edge.to}]`);
}
const nomnoml_source = result.join("\n");
const svg = nomnoml.renderSvg(nomnoml_source);
return svg;
}

60
src/lib/parse_summary.mjs Normal file
View file

@ -0,0 +1,60 @@
"use strict";
export default function parse_summary(text) {
const lines = text.trim().split(/\r?\n/);
const layers_raw = lines.slice(
lines.findIndex(line => line.startsWith("====")) + 1,
lines.findLastIndex(line => line.startsWith("===="))
);
const layers = [];
let acc = [];
for (const line of layers_raw) {
if(line.trim().length == 0) {
if(acc.length === 0) continue;
console.log(acc.map(layer_line => layer_line.substring(65).trim()).join(""));
// Handle parsed item
const result = {
name_raw: acc.map(layer_line => layer_line.substring(0, 32).trim()).join(""),
output_shape: acc.map(layer_line => layer_line.substring(32, 53).trim()).join(""),
params: parseInt(acc.map(layer_line => layer_line.substring(53, 65).trim()).join("")),
connected_to: JSON.parse(acc.map(layer_line => layer_line.substring(65).trim()).join("")
.replace(/'/g, '"'))
.map(connected_name => connected_name.replace(/(\[0\])+$/, ""))
};
result.type = result.name_raw.match(/ \(([^)]+)\)/)[1];
result.name = result.name_raw.split(/\s+/)[0];
layers.push(result);
acc.length = 0;
}
acc.push(line);
}
const edges = [];
for(const layer of layers) {
for(const connection of layer.connected_to) {
edges.push({
from: connection,
to: layer.name
});
}
}
return {
title: lines[0].match(/^Model: "([^"]+)"/)[1],
params: parseInt(lines.find(line => line.search(/^Total params:/) > -1).split(": ")[1].replace(/,/g, "")),
params_trainable: parseInt(lines.find(line => line.search(/^Trainable params:/) > -1).split(": ")[1].replace(/,/g, "")),
params_nontrainable: parseInt(lines.find(line => line.search(/^Non-trainable params:/) > -1).split(": ")[1].replace(/,/g, "")),
layers,
edges
}
}