https://github.com/zfrenchee/NN-SVG
Tip revision: e65a5b1747d227857192f8c3e424660e489f6887 authored by Johan Pauwels on 12 February 2024, 01:27:00 UTC
Correct width and height label placement in AlexNet (#60)
Correct width and height label placement in AlexNet (#60)
Tip revision: e65a5b1
AlexNet.html
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-119008715-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-119008715-1');
</script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<style type="text/css">
* { font-weight: 100; }
h1 { font-weight: 100; }
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: fixed;
}
.nn-picker {
width: 410px;
margin: 30px;
z-index: 1000;
}
.github-corner {
z-index: 1000;
}
[data-toggle="collapse"] .fa:before {
font-size: 2rem;
color: black;
content: "\f106";
position: relative;
top: 5px;
}
.fa {
transition: 0.3s transform ease-in-out;
}
.collapsed .fa {
transform: rotate(-180deg);
}
.tab-content {
padding: 20px;
}
input[type="range"] {
margin-left: 10px;
}
#count {
position: fixed;
bottom: 0;
right: 1rem;
opacity: 0.4;
font-weight: 100;
}
a.disabled {
color: gray;
pointer-events: none;
}
</style>
<title>NN SVG</title>
</head>
<body>
<div id="graph-container"></div>
<div class="container-fluid">
<div class="row">
<div class="nn-picker">
<div class="card">
<div class="card-header">
<a class="pull-right" data-toggle="collapse" href="#collapsable" role="button"><i class="fa"></i></a>
<h1>NN-SVG</h1>
<p>Publication-ready NN-architecture schematics. <a id="download" class="disabled" href="#">Download SVG</a></p>
<nav>
<div class="nav nav-tabs card-header-tabs" role="tablist">
<a class="nav-item nav-link" href="index.html">FCNN style</a>
<a class="nav-item nav-link" href="LeNet.html">LeNet style</a>
<a class="nav-item nav-link active">AlexNet style</a>
</div>
</nav>
</div>
<div class="tab-content collapse show" id="collapsable">
<div class="tab-pane fade show active" id="AlexNet" role="tabpanel">
<h4>Style:</h4>
<div id="rendererType">
<label for="rendererType" style="margin-right:10px;">Renderer</label>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="radio" name="rendererType" id="webGL" value="webgl" checked> webGL
</label>
</div>
<div class="form-check form-check-inline">
<label class="form-check-label">
<input class="form-check-input" type="radio" name="rendererType" id="SVG" value="svg"> SVG
</label>
</div>
<small class="form-text text-muted">The SVG renderer is required to download SVG, however the WebGL renderer is required to show tensor dimensions.</small>
</div>
<br>
<div>
<input type="color" value="#eeeeee" id="color1">
<label for="color1">Color 1</label>
</div>
<div>
<input type="color" value="#99ddff" id="color2">
<label for="color2">Color 2</label>
</div>
<div>
<input type="color" value="#ffbbbb" id="color3">
<label for="color3">Color 3</label>
</div>
<div>
<label for="rectOpacity">Tensor Opacity</label>
<input type="range" id="rectOpacity" name="" min="0" max="1" step="0.01" value="0.4" style="position: relative; top: 3px;">
</div>
<div>
<div>
<label for="filterOpacity">Filter Opacity</label>
<input type="range" id="filterOpacity" name="" min="0" max="1" step="0.01" value="0.4" style="position: relative; top: 3px;">
</div>
<!-- <div>
<label for="borderWidth">Border Width</label>
<input type="range" id="borderWidth" name="" min="0.01" max="3" step="0.01" value="1" style="position: relative; top: 3px;">
</div> -->
<div>
<label for="betweenLayers">Spacing Between Layers</label>
<input type="range" id="betweenLayers" name="" min="10" max="100" step="1" value="20" style="position: relative; top: 3px;">
</div>
<hr>
<div>
<input type="checkbox" id="logDepth" name="logDepth" value="logDepth" checked>
<label for="logDepth">Log Feature-Map Depth Scaling</label>
</div>
<div>
<label for="depthScale">Depth Size Scaling</label>
<input type="range" id="depthScale" name="" min="1" max="100" step="1" value="10" style="position: relative; top: 3px;">
<span id="depthSpan">10</span>
</div>
<div>
<input type="checkbox" id="logWidth" name="logWidth" value="logWidth" checked>
<label for="logWidth">Log Feature-Map Width Scaling</label>
</div>
<div>
<label for="widthScale">Width Size Scaling</label>
<input type="range" id="widthScale" name="" min="1" max="100" step="1" value="10" style="position: relative; top: 3px;">
<span id="widthSpan">10</span>
</div>
<div>
<input type="checkbox" id="logConvSize" name="logConvSize" value="logConvSize">
<label for="logConvSize">Log Convolutional Filter Size Scaling</label>
</div>
<div>
<label for="convScale">Convolutional Filter Scaling</label>
<input type="range" id="convScale" name="" min="1" max="10" step="1" value="1" style="position: relative; top: 3px;">
<span id="convSpan">1</span>
</div>
<hr>
<div>
<input type="checkbox" id="showDims" name="showDims" value="showDims">
<label for="showDims">Show Tensor Dimensions</label>
</div>
<div>
<input type="checkbox" id="showConvDims" name="showConvDims" value="showConvDims">
<label for="showConvDims">Show Conv Dimensions</label>
</div>
<div>
<label for="fontScale">Font Size</label>
<input type="range" id="fontScale" name="" min="1" max="3" step="0.2" value="1" style="position: relative; top: 3px;">
</div>
<hr>
<h4>Architecture:</h4>
<div id="architecture">
<p>Height | Width | Depth | filter Height | filter Width</p>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-12">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="height" step="1" value="224" />
<input type="number" class="form-control" name="width" step="1" value="224" />
<input type="number" class="form-control" name="depth" step="1" value="3" />
<input type="number" class="form-control" name="filterHeight" step="1" value="11" />
<input type="number" class="form-control" name="filterWidth" step="1" value="11" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-12">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="height" step="1" value="55" />
<input type="number" class="form-control" name="width" step="1" value="55" />
<input type="number" class="form-control" name="depth" step="1" value="96" />
<input type="number" class="form-control" name="filterHeight" step="1" value="5" />
<input type="number" class="form-control" name="filterWidth" step="1" value="5" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-12">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="height" step="1" value="27" />
<input type="number" class="form-control" name="width" step="1" value="27" />
<input type="number" class="form-control" name="depth" step="1" value="256" />
<input type="number" class="form-control" name="filterHeight" step="1" value="3" />
<input type="number" class="form-control" name="filterWidth" step="1" value="3" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-12">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="height" step="1" value="13" />
<input type="number" class="form-control" name="width" step="1" value="13" />
<input type="number" class="form-control" name="depth" step="1" value="384" />
<input type="number" class="form-control" name="filterHeight" step="1" value="3" />
<input type="number" class="form-control" name="filterWidth" step="1" value="3" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-12">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="height" step="1" value="13" />
<input type="number" class="form-control" name="width" step="1" value="13" />
<input type="number" class="form-control" name="depth" step="1" value="384" />
<input type="number" class="form-control" name="filterHeight" step="1" value="3" />
<input type="number" class="form-control" name="filterWidth" step="1" value="3" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-12">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="height" step="1" value="13" />
<input type="number" class="form-control" name="width" step="1" value="13" />
<input type="number" class="form-control" name="depth" step="1" value="256" />
<input type="number" class="form-control" name="filterHeight" step="1" value="3" />
<input type="number" class="form-control" name="filterWidth" step="1" value="3" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-12">
<button class="btn btn-primary btn-add input-group-prepend"><span class="fa fa-plus"></span></button>
<input type="number" class="form-control" name="height" step="1"/>
<input type="number" class="form-control" name="width" step="1"/>
<input type="number" class="form-control" name="depth" step="1"/>
<input type="number" class="form-control" name="filterHeight" step="1"/>
<input type="number" class="form-control" name="filterWidth" step="1"/>
</div>
</div>
</div>
<hr>
<div id="architecture2">
<p>Vector Length</p>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-5">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="vectorLength" step="1" value="2048" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-5">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="vectorLength" step="1" value="2048" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-5">
<button class="btn btn-secondary btn-remove input-group-prepend"><span class="fa fa-minus"></span></button>
<input type="number" class="form-control" name="vectorLength" step="1" value="1000" />
</div>
</div>
<div class="row entry">
<div class="input-group mb-2 mr-sm-2 col-5">
<button class="btn btn-primary btn-add input-group-prepend"><span class="fa fa-plus"></span></button>
<input type="number" class="form-control" name="vectorLength" step="1"/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="count"><a style="font-size: 1rem" href="about.html">About</a></div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/underscore@1.13.0/underscore-umd-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
<script src="OrbitControls.js"></script>
<script src="SVGRenderer.js"></script>
<script src="Projector.js"></script>
<!-- We use locally cached copies of these in case the upstream versions change -->
<!-- <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script> -->
<!-- <script src="https://threejs.org/examples/js/renderers/Projector.js"></script> -->
<!-- <script src="https://threejs.org/examples/js/renderers/SVGRenderer.js"></script> -->
<!-- <script src="https://threejs.org/examples/js/renderers/CSS2DRenderer.js"></script> -->
<!-- <script src="https://threejs.org/examples/js/renderers/CSS3DRenderer.js"></script> -->
<script src="util.js"></script>
<script src="AlexNet.js"></script>
<script type="text/javascript">
alexnet = AlexNet();
function restart() {
architecture = $('#architecture').find('.entry').map((i,el) =>
_.object(['height','width','depth','filterHeight','filterWidth','rel_x','rel_y'],
$(el).find('input[type="number"]').map((j,input) => parseFloat($(input).val())).get().concat([rand(-0.4,0.4), rand(-0.4,0.4)]))
).get()
.filter(layer => Object.values(layer).every(val => !_.isNaN(val)));
architecture2 = $('#architecture2').find('input').map((i,el) => $(el).val()).get().filter(input => $.isNumeric(input)).map(s => parseInt(s));
alexnet.redraw({'architecture_':architecture, 'architecture2_':architecture2});
}
restart();
// /////////////////////////////////////////////////////////////////////////////
// /////// Select Styling ///////
// /////////////////////////////////////////////////////////////////////////////
$('#rendererType input:radio').change(function() {
rendererType = this.value;
if (rendererType == 'svg') {
showDims = false;
$("#showDims").prop('disabled', true).prop('checked', false);
$("#showConvDims").prop('disabled', true).prop('checked', false);
$("#download").removeClass('disabled');
}
else if (rendererType == 'webgl') {
$("#showDims").prop('disabled', false);
$("#showConvDims").prop('disabled', false);
$("#download").addClass('disabled');
}
$(this).blur();
alexnet.restartRenderer({'rendererType_':rendererType});
});
$("#color1").change( function () { alexnet.style({'color1_': this.value}); });
$("#color2").change( function () { alexnet.style({'color2_': this.value}); });
$("#color3").change( function () { alexnet.style({'color3_': this.value}); });
$("#fontScale").change( function () { alexnet.style({'fontScale_': this.value}); });
$("#rectOpacity").change( function () { alexnet.style({'rectOpacity_': parseFloat(this.value)}); $(this).blur(); });
$("#filterOpacity").change( function () { alexnet.style({'filterOpacity_': parseFloat(this.value)}); $(this).blur(); });
$("#betweenLayers").change( function () { alexnet.redraw({'betweenLayers_': parseFloat(this.value)}); $(this).blur(); });
$("#logDepth").change( function () { alexnet.redraw({'logDepth_': this.checked}); });
$("#depthScale").change( function () { alexnet.redraw({'depthScale_': parseFloat(this.value)}); $(this).blur(); $("#depthSpan").text(this.value); });
$("#logWidth").change( function () { alexnet.redraw({'logWidth_': this.checked}); });
$("#widthScale").change( function () { alexnet.redraw({'widthScale_': parseFloat(this.value)}); $(this).blur(); $("#widthSpan").text(this.value); });
$("#logConvSize").change( function () { alexnet.redraw({'logConvSize_': this.checked}); });
$("#convScale").change( function () { alexnet.redraw({'convScale_': parseFloat(this.value)}); $(this).blur(); $("#convSpan").text(this.value); });
$("#showDims").change( function () { alexnet.redraw({'showDims_': this.checked}); });
$("#showConvDims").change( function () { alexnet.redraw({'showConvDims_': this.checked}); });
// /////////////////////////////////////////////////////////////////////////////
// /////// Select Architecture ///////
// /////////////////////////////////////////////////////////////////////////////
$(document).on('click', '#architecture .btn-add', function(e) {
e.preventDefault();
var controlForm = $('#architecture');
var currentEntry = $(this).parents('.entry:first');
var newEntry = $(currentEntry.clone()).appendTo(controlForm);
newEntry.find('input').val('');
controlForm.find('.entry:not(:last) .btn-add')
.removeClass('btn-add').addClass('btn-remove')
.removeClass('btn-primary').addClass('btn-secondary')
.html('<span class="fa fa-minus"></span>');
restart();
});
$(document).on('click', '#architecture .btn-remove', function(e) {
e.preventDefault();
$(this).parents('.entry:first').remove();
restart();
return false;
});
$(document).on('click', '#architecture2 .btn-add', function(e) {
e.preventDefault();
var controlForm = $('#architecture2');
var currentEntry = $(this).parents('.entry:first');
var newEntry = $(currentEntry.clone()).appendTo(controlForm);
newEntry.find('input').val('');
controlForm.find('.entry:not(:last) .btn-add')
.removeClass('btn-add').addClass('btn-remove')
.removeClass('btn-primary').addClass('btn-secondary')
.html('<span class="fa fa-minus"></span>');
restart();
});
$(document).on('click', '#architecture2 .btn-remove', function(e) {
e.preventDefault();
$(this).parents('.entry:first').remove();
restart();
return false;
});
$(document).on('change', 'input', function(e) {
e.preventDefault();
restart();
});
$("#download").on("click", function() {
// ga('send', 'event', 'downloadSVG', 'AlexNet');
$(this).attr("href", 'data:application/octet-stream;base64,' + btoa(unescape(encodeURIComponent($('<div>').append($( $("#graph-container").html()).attr("xmlns", "http://www.w3.org/2000/svg") ).html()))))
.attr("download", "nn.svg")
});
</script>
</body>
</html>