diff --git a/assets/js/netscope.js b/assets/js/netscope.js index d5fae14..ed31c55 100644 --- a/assets/js/netscope.js +++ b/assets/js/netscope.js @@ -482,7 +482,7 @@ computeShapes = function(net) { return results; } catch (error) { e = error; - return Notify.warning("Can't infer network data shapes. " + e); + return Notify.warning("Can't infer network data shapes! " + e); } }; @@ -504,7 +504,7 @@ module.exports = CaffeParser = (function() { },{"./../network.coffee":8,"./../notify.coffee":9,"./../utils/utils.coffee":11,"./layers.coffee":3,"./parser":4}],3:[function(require,module,exports){ -var ConvolutionLayerBase, areShapesEqual, extractKernelSizes, extractPaddingSizes, extractStrideSizes, getLayerType, getParameterAsArray, getValueOrDefault, isDataLayer, isLossLayer, isUniformLayer, layers, shapesToString, utils, +var ConvolutionLayerBase, areShapesEqual, extractKernelSizes, extractPaddingSizes, extractStrideSizes, getLayerType, getParameterAsArray, getParameterLength, getValueOrDefault, isDataLayer, isLossLayer, isUniformLayer, layers, shapesToString, utils, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; @@ -574,6 +574,18 @@ getParameterAsArray = function(parameter, requiredLength, name) { })(); }; + getParameterLength = function(parameter) { + if (parameter != null) { + if (utils.typeIsArray(parameter)) { + return parameter.length; + } else { + return 1; + } + } else { + return 0; + } + }; + shapesToString = function(inputShapes) { var j, len, shape, text; text = '['; @@ -1011,6 +1023,265 @@ layers.Concat = this.ConcatLayer = (function() { })(); + layers.Slice = this.SliceLayer = (function() { + function SliceLayer(attribs) { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.slice_param : void 0; + this.slicePoint = params != null ? params.slice_point : void 0; + this.axis = getValueOrDefault(params.axis, 1); + } + + SliceLayer.prototype.inferShapes = function(bottoms, tops) { + var firstInputShape, i, j, ref; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.slicePoint = getParameterAsArray(this.slicePoint, tops.length - 1, 'slice_point'); + this.checkParameters(bottoms, tops); + firstInputShape = bottoms[0].shape; + for (i = j = 0, ref = tops.length - 1; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { + tops[i].shape = firstInputShape.slice(0); + tops[i].shape[this.axis] = this.slicePoint[i]; + } + tops[tops.length - 1].shape = firstInputShape.slice(0); + return tops[tops.length - 1].shape[this.axis] = firstInputShape[this.axis] - this.slicePoint[this.slicePoint.length - 1]; + }; + + SliceLayer.prototype.checkParameters = function(bottoms, tops) { + if ((bottoms != null ? bottoms[0] : void 0) == null) { + throw 'Slice layer must have at least one bottom blob.'; + } + if ((tops != null ? tops[1] : void 0) == null) { + throw 'Slice layer must have at least two top blob.'; + } + }; + + return SliceLayer; + + })(); + + layers.Permute = this.PermuteLayer = (function() { + function PermuteLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.permute_param : void 0; + this.order = params != null ? params.order : void 0; + } + + PermuteLayer.prototype.inferShapes = function(bottoms, tops) { + var bottom, firstInputShape, i, j, ref, results, top; + this.order = getParameterAsArray(this.order, bottoms[0].shape.length, 'order'); + firstInputShape = bottoms[0].shape; + top = tops[0]; + bottom = bottoms[0]; + top.shape = firstInputShape.slice(0); + results = []; + for (i = j = 0, ref = this.order.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { + results.push(top.shape[i] = bottom.shape[this.order[i]]); + } + return results; + }; + + return PermuteLayer; + + })(); + + layers.Flatten = this.FlattenLayer = (function() { + function FlattenLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.flatten_param : void 0; + this.axis = getValueOrDefault(params.axis, 1); + } + + FlattenLayer.prototype.inferShapes = function(bottoms, tops) { + var i, j, outputShape, ref, ref1, results, top; + outputShape = bottoms[0].shape; + top = tops[0]; + top.shape = outputShape.slice(0, this.axis + 1); + results = []; + for (i = j = ref = this.axis + 1, ref1 = outputShape.length; ref <= ref1 ? j < ref1 : j > ref1; i = ref <= ref1 ? ++j : --j) { + results.push(top.shape[this.axis] *= outputShape[i]); + } + return results; + }; + + return FlattenLayer; + + })(); + + layers.PriorBox = this.PriorBoxLayer = (function() { + function PriorBoxLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.prior_box_param : void 0; + this.min_size = params != null ? params.min_size : void 0; + this.max_size = params != null ? params.max_size : void 0; + this.aspect_ratio = params != null ? params.aspect_ratio : void 0; + this.flip = params != null ? params.flip : void 0; + } + + PriorBoxLayer.prototype.inferShapes = function(bottoms, tops) { + var already_exist, ar, aspect_ratio_length, aspect_ratio_param_length, aspect_ratios, height, i, j, k, l, len, len1, len2, m, max_size_length, min_size_length, num_priors, outputShape, ref, ref1, ref2, width; + min_size_length = getParameterLength(this.min_size); + max_size_length = getParameterLength(this.max_size); + aspect_ratio_param_length = getParameterLength(this.aspect_ratio); + aspect_ratios = [1.0]; + if (aspect_ratio_param_length === 1) { + ar = this.aspect_ratio; + already_exist = false; + ref = aspect_ratios.length; + for (k = 0, len = ref.length; k < len; k++) { + j = ref[k]; + if (Math.abs(ar - aspect_ratios[j]) < 1e-6) { + already_exist = true; + break; + } + } + if (already_exist !== true) { + aspect_ratios.push(ar); + if (this.flip) { + aspect_ratios.push(1.0 / ar); + } + } + } else { + ref1 = this.aspect_ratio; + for (l = 0, len1 = ref1.length; l < len1; l++) { + i = ref1[l]; + ar = i; + already_exist = false; + ref2 = aspect_ratios.length; + for (m = 0, len2 = ref2.length; m < len2; m++) { + j = ref2[m]; + if (Math.abs(ar - aspect_ratios[j]) < 1e-6) { + already_exist = true; + break; + } + } + if (already_exist !== true) { + aspect_ratios.push(ar); + if (this.flip) { + aspect_ratios.push(1.0 / ar); + } + } + } + } + aspect_ratio_length = aspect_ratios.length; + outputShape = bottoms[0].shape; + height = bottoms[0].shape[2]; + width = bottoms[0].shape[3]; + num_priors = aspect_ratio_length * min_size_length + max_size_length; + tops[0].shape = outputShape.slice(0, 3); + tops[0].shape[0] = 1; + tops[0].shape[1] = 2; + return tops[0].shape[2] = height * width * num_priors * 4; + }; + + return PriorBoxLayer; + + })(); + + layers.Reshape = this.ReshapeLayer = (function() { + function ReshapeLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.reshape_param : void 0; + this.shape = params != null ? params.shape : void 0; + } + + ReshapeLayer.prototype.inferShapes = function(bottoms, tops) { + var dim, dim_length, i, j, k, l, other_sum, outputShape, ref, ref1, ref2, results, sum; + dim_length = getParameterLength(this.shape.dim); + dim = getParameterAsArray(this.shape.dim, dim_length, 'dim'); + outputShape = bottoms[0].shape; + sum = 1; + for (i = j = 0, ref = bottoms[0].shape.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { + sum *= bottoms[0].shape[i]; + } + tops[0].shape = outputShape.slice(0, dim_length); + other_sum = 1; + for (i = k = 0, ref1 = dim_length; 0 <= ref1 ? k < ref1 : k > ref1; i = 0 <= ref1 ? ++k : --k) { + if (dim[i] !== 0 && dim[i] !== -1) { + tops[0].shape[i] = dim[i]; + } + if (dim[i] !== -1) { + other_sum *= tops[0].shape[i]; + } + } + results = []; + for (i = l = 0, ref2 = dim_length; 0 <= ref2 ? l < ref2 : l > ref2; i = 0 <= ref2 ? ++l : --l) { + if (dim[i] === -1) { + results.push(tops[0].shape[i] = sum / other_sum); + } else { + results.push(void 0); + } + } + return results; + }; + + return ReshapeLayer; + + })(); + + layers.Tiling = this.TilingLayer = (function() { + function TilingLayer(attribs) { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.tiling_param : void 0; + this.tile_dim = params != null ? params.tile_dim : void 0; + } + + TilingLayer.prototype.inferShapes = function(bottoms, tops) { + var channels, height, outputShape, width; + this.checkParameters(bottoms, tops); + outputShape = bottoms[0].shape; + channels = bottoms[0].shape[1]; + height = bottoms[0].shape[2]; + width = bottoms[0].shape[3]; + tops[0].shape = outputShape; + tops[0].shape[1] = channels / (this.tile_dim * this.tile_dim); + tops[0].shape[2] = height * this.tile_dim; + return tops[0].shape[3] = width * this.tile_dim; + }; + + TilingLayer.prototype.checkParameters = function(bottoms, tops) { + if (this.tile_dim == null) { + throw 'tile_dim must be specified.'; + } + if (!(this.tile_dim > 0)) { + throw 'tile_dim must be positive.'; + } + if (bottoms[0].shape[1] % (this.tile_dim * this.tile_dim) !== 0) { + throw 'The number of input channels for tiling layer must be multiples of the tile_dim.'; + } + }; + + return TilingLayer; + + })(); + + layers.Normalize = this.NormalizeLayer = (function() { + function NormalizeLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.norm_param : void 0; + this.across_spatial = params != null ? params.across_spatial : void 0; + this.channel_shared = params != null ? params.channel_shared : void 0; + } + + NormalizeLayer.prototype.inferShapes = function(bottoms, tops) { + var outputShape; + outputShape = bottoms[0].shape; + return tops[0].shape = outputShape; + }; + + return NormalizeLayer; + + })(); + layers.Eltwise = this.EltwiseLayer = (function() { function EltwiseLayer() { this.checkParameters = bind(this.checkParameters, this); @@ -1058,6 +1329,57 @@ layers.Eltwise = this.EltwiseLayer = (function() { })(); + layers.Axpy = this.AxpyLayer = (function() { + function AxpyLayer() { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + } + + AxpyLayer.prototype.inferShapes = function(bottoms, tops) { + var firstInputShape; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + firstInputShape = bottoms[1].shape; + return tops[0].shape = firstInputShape.slice(0); + }; + + AxpyLayer.prototype.checkParameters = function(bottoms, tops) { + var bottom, firstShape, inputShapes; + if ((bottoms != null ? bottoms.length : void 0) !== 3) { + throw 'Axpy layer must have three inputs.'; + } + inputShapes = (function() { + var k, len, results; + results = []; + for (k = 0, len = bottoms.length; k < len; k++) { + bottom = bottoms[k]; + results.push(bottom.shape); + } + return results; + })(); + firstShape = inputShapes[0]; + if (inputShapes[0][0] !== inputShapes[1][0]) { + throw "InputShapes 0 and 1 at 0 axe must have the same sizes."; + } + if (inputShapes[0][1] !== inputShapes[1][1]) { + throw "InputShapes 0 and 1 at 1 axe must have the same sizes."; + } + if (inputShapes[0].length === 4) { + if (inputShapes[0][2] !== 1 || inputShapes[0][3] !== 1) { + throw "InputShapes 0 at 2、3 axe must be 1."; + } + } + if (!areShapesEqual(inputShapes[1], inputShapes[2])) { + throw "Axpy layer received incorrect input shapes: " + ((shapesToString(inputShapes)) + ". ") + "InputShapes 1 and 2 at all axes must have the same sizes."; + } + }; + + return AxpyLayer; + + })(); + layers.Crop = this.CropLayer = (function() { function CropLayer(attribs) { this.checkParameters = bind(this.checkParameters, this); @@ -1090,6 +1412,77 @@ layers.Crop = this.CropLayer = (function() { })(); +layers.Interp = this.InterpLayer = (function() { + function InterpLayer(attribs) { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var ref, ref1, ref2, ref3, ref4, ref5; + this.params = attribs.interp_param; + this.height = getValueOrDefault((ref = this.params) != null ? ref.height : void 0, 0); + this.width = getValueOrDefault((ref1 = this.params) != null ? ref1.width : void 0, 0); + this.zoom_factor = getValueOrDefault((ref2 = this.params) != null ? ref2.zoom_factor : void 0, 1); + this.shrink_factor = getValueOrDefault((ref3 = this.params) != null ? ref3.shrink_factor : void 0, 1); + this.pad_beg = getValueOrDefault((ref4 = this.params) != null ? ref4.pad_beg : void 0, 0); + this.pad_end = getValueOrDefault((ref5 = this.params) != null ? ref5.pad_end : void 0, 0); + } + + InterpLayer.prototype.inferShapes = function(bottoms, tops) { + var height_in, height_in_eff, height_out, outputShape, width_in, width_in_eff, width_out; + this.checkParameters(bottoms, tops); + outputShape = bottoms[0].shape; + height_in = bottoms[0].shape[2]; + width_in = bottoms[0].shape[3]; + tops[0].shape = outputShape; + height_in_eff = height_in + this.pad_beg + this.pad_end; + width_in_eff = width_in + this.pad_beg + this.pad_end; + if ((this.params.shrink_factor != null) && (this.params.zoom_factor == null)) { + height_out = (height_in_eff - 1) / this.shrink_factor + 1; + width_out = (width_in_eff - 1) / this.shrink_factor + 1; + } else if ((this.params.shrink_factor == null) && (this.params.zoom_factor != null)) { + height_out = height_in_eff + (height_in_eff - 1) * (this.zoom_factor - 1); + width_out = width_in_eff + (width_in_eff - 1) * (this.zoom_factor - 1); + } else if ((this.params.height != null) && (this.params.width != null)) { + height_out = this.height; + width_out = this.width; + } else if ((this.params.shrink_factor != null) && (this.params.zoom_factor != null)) { + height_out = (height_in_eff - 1) / this.shrink_factor + 1; + width_out = (width_in_eff - 1) / this.shrink_factor + 1; + height_out = height_out + (height_out - 1) * (this.zoom_factor - 1); + width_out = width_out + (width_out - 1) * (this.zoom_factor - 1); + } + if (!(height_in_eff > 0)) { + throw 'height should be positive.'; + } + if (!(width_in_eff > 0)) { + throw 'width should be positive.'; + } + if (!(height_out > 0)) { + throw 'height should be positive.'; + } + if (!(width_out > 0)) { + throw 'width should be positive.'; + } + tops[0].shape[2] = height_out; + return tops[0].shape[3] = width_out; + }; + + InterpLayer.prototype.checkParameters = function(bottoms, tops) { + if (this.params.shrink_factor != null) { + if (!(this.shrink_factor >= 1)) { + throw 'shrink_factor must be positive.'; + } + } + if (this.params.zoom_factor != null) { + if (!(this.zoom_factor >= 1)) { + throw 'zoom_factor must be positive.'; + } + } + }; + + return InterpLayer; + +})(); + isLossLayer = function(layerType) { return /loss/i.test(layerType); }; @@ -1099,7 +1492,7 @@ isDataLayer = function(layerType) { }; isUniformLayer = function(lt) { - return (/relu/i.test(lt)) || (/prelu/i.test(lt)) || (/elu/i.test(lt)) || (/sigmoid/i.test(lt)) || (/tanh/i.test(lt)) || (/abs/i.test(lt)) || (/power/i.test(lt)) || (/exp/i.test(lt)) || (/log/i.test(lt)) || (/bnll/i.test(lt)) || (/threshold/i.test(lt)) || (/bias/i.test(lt)) || (/scale/i.test(lt)) || (/lrn/i.test(lt)) || (/dropout/i.test(lt)) || (/batchnorm/i.test(lt)) || (/mvn/i.test(lt)) || (/softmax/i.test(lt)); + return (/relu/i.test(lt)) || (/prelu/i.test(lt)) || (/elu/i.test(lt)) || (/sigmoid/i.test(lt)) || (/tanh/i.test(lt)) || (/abs/i.test(lt)) || (/power/i.test(lt)) || (/exp/i.test(lt)) || (/log/i.test(lt)) || (/bnll/i.test(lt)) || (/threshold/i.test(lt)) || (/bias/i.test(lt)) || (/scale/i.test(lt)) || (/lrn/i.test(lt)) || (/dropout/i.test(lt)) || (/batchnorm/i.test(lt)) || (/groupnorm/i.test(lt)) || (/bn/i.test(lt)) || (/mvn/i.test(lt)) || (/softmax/i.test(lt)); }; getLayerType = function(layerTypeName) { @@ -2841,7 +3234,7 @@ module.exports = Editor = (function() { $('#net-column').width((100 - editorWidthPercentage) + '%'); $('#master-container').prepend($editorBox); this.editor = CodeMirror($editorBox[0], { - value: '# Enter your network definition here.\n# Use Shift+Enter to update the visualization.', + value: '# Enter your network definition here!\n# Use Shift+Enter to update the visualization.', lineNumbers: true, lineWrapping: true }); diff --git a/lib/app.js b/lib/app.js new file mode 100644 index 0000000..92da83a --- /dev/null +++ b/lib/app.js @@ -0,0 +1,101 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var AppController, Editor, Notify, Renderer, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + slice = [].slice; + + Renderer = require('./renderer.coffee'); + + Editor = require('./editor.coffee'); + + Notify = require('./notify.coffee'); + + module.exports = AppController = (function() { + function AppController() { + this.handleWarning = bind(this.handleWarning, this); + this.handleError = bind(this.handleError, this); + this.inProgress = false; + this.$spinner = $('#net-spinner'); + this.$netBox = $('#net-container'); + this.$netError = $('#net-error'); + this.$netWarn = $('#net-warning'); + this.svg = '#net-svg'; + this.setupErrorHandler(); + } + + AppController.prototype.startLoading = function() { + var args, loader; + loader = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + if (this.inProgress) { + return; + } + this.$netError.hide(); + this.$netWarn.hide(); + this.$netBox.hide(); + this.$spinner.show(); + return loader.apply(null, slice.call(args).concat([(function(_this) { + return function(net) { + return _this.completeLoading(net); + }; + })(this)])); + }; + + AppController.prototype.completeLoading = function(net) { + var renderer; + this.$spinner.hide(); + $('#net-title').html(net.name.replace(/_/g, ' ')); + this.$netBox.show(); + $(this.svg).empty(); + $('.qtip').remove(); + renderer = new Renderer(net, this.svg); + return this.inProgress = false; + }; + + AppController.prototype.makeLoader = function(loader) { + return (function(_this) { + return function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return _this.startLoading.apply(_this, [loader].concat(slice.call(args))); + }; + })(this); + }; + + AppController.prototype.showEditor = function(loader) { + if (_.isUndefined(window.CodeMirror)) { + return $.getScript('assets/js/lib/codemirror.min.js', (function(_this) { + return function() { + return _this.netEditor = new Editor(_this.makeLoader(loader.load)); + }; + })(this)); + } + }; + + AppController.prototype.setupErrorHandler = function() { + window.onerror = this.handleError; + Notify.onerror(this.handleError); + return Notify.onwarning(this.handleWarning); + }; + + AppController.prototype.handleError = function(message, filename, lineno, colno, e) { + var msg; + msg = message; + if (((e != null ? e.line : void 0) != null) && ((e != null ? e.column : void 0) != null)) { + msg = "Line " + e.line + ", Column " + e.column + ": " + e.message; + } + this.$spinner.hide(); + $('.msg', this.$netError).html(msg); + this.$netError.show(); + return this.inProgress = false; + }; + + AppController.prototype.handleWarning = function(message) { + $('.msg', this.$netWarn).html(message); + return this.$netWarn.show(); + }; + + return AppController; + + })(); + +}).call(this); diff --git a/lib/caffe/caffe.js b/lib/caffe/caffe.js new file mode 100644 index 0000000..108e812 --- /dev/null +++ b/lib/caffe/caffe.js @@ -0,0 +1,406 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var Blob, BlobTable, CaffeParser, Layers, LayersGenerator, Network, NodesGenerator, Notify, Parser, Utils, computePrecedingShapes, computeShapes, generateLayers, generateNetwork, setNodeOutputShapesAttribute, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + hasProp = {}.hasOwnProperty; + + Parser = require('./parser'); + + Layers = require('./layers.coffee'); + + Network = require('./../network.coffee'); + + Utils = require('./../utils/utils.coffee'); + + Notify = require('./../notify.coffee'); + + Blob = (function() { + function Blob(name1) { + this.name = name1; + this.addReader = bind(this.addReader, this); + this.addWriter = bind(this.addWriter, this); + this.readers = []; + this.writers = []; + } + + Blob.prototype.addWriter = function(writerNode) { + this.writers.push(writerNode); + if (writerNode.tops == null) { + writerNode.tops = []; + } + return writerNode.tops.push(this); + }; + + Blob.prototype.addReader = function(readerNode) { + this.readers.push(readerNode); + if (readerNode.bottoms == null) { + readerNode.bottoms = []; + } + return readerNode.bottoms.push(this); + }; + + Blob.prototype.connectWithNodeAsTop = function(blob, writerNode) { + return blob.addWriter(writerNode); + }; + + Blob.prototype.connectWithNodeAsBottom = function(blob, readerNode) { + return blob.addReader(readerNode); + }; + + return Blob; + + })(); + + BlobTable = (function() { + function BlobTable(layers) { + this.generateBlobsByNames = bind(this.generateBlobsByNames, this); + this.getBlobByName = bind(this.getBlobByName, this); + this.fillInternalTable = bind(this.fillInternalTable, this); + this.table = {}; + this.fillInternalTable(layers); + } + + BlobTable.prototype.fillInternalTable = function(layers) { + var i, layer, len, results; + results = []; + for (i = 0, len = layers.length; i < len; i++) { + layer = layers[i]; + this.generateBlobsByNames(layer.top); + results.push(this.generateBlobsByNames(layer.bottom)); + } + return results; + }; + + BlobTable.prototype.getBlobByName = function(blobName) { + return this.table[blobName]; + }; + + BlobTable.prototype.generateBlobsByNames = function(blobNames) { + var blobName, blobNode, i, len, ref, results; + if (blobNames == null) { + return; + } + ref = Utils.asArray(blobNames); + results = []; + for (i = 0, len = ref.length; i < len; i++) { + blobName = ref[i]; + if (!(blobName in this.table)) { + blobNode = new Blob(blobName); + results.push(this.table[blobName] = blobNode); + } else { + results.push(void 0); + } + } + return results; + }; + + return BlobTable; + + })(); + + NodesGenerator = (function() { + function NodesGenerator(blobTable1) { + this.blobTable = blobTable1; + this.getFirstWriterNode = bind(this.getFirstWriterNode, this); + this.connectSingleNodeWithBlobs = bind(this.connectSingleNodeWithBlobs, this); + this.connectNodesWithBlobs = bind(this.connectNodesWithBlobs, this); + this.connectNonInplaceNodes = bind(this.connectNonInplaceNodes, this); + this.connectInplaceNodes = bind(this.connectInplaceNodes, this); + this.connectNodesWithEachOther = bind(this.connectNodesWithEachOther, this); + this.fillNetwork = bind(this.fillNetwork, this); + } + + NodesGenerator.prototype.fillNetwork = function(network, layers) { + this.connectNodesWithBlobs(network, layers); + this.connectNodesWithEachOther(); + return network; + }; + + NodesGenerator.prototype.connectNodesWithEachOther = function() { + var blob, inplaceNodes, k, lastInplaceNode, nonInplaceReaders, nonInplaceWriters, ref, results, writerNode; + ref = this.blobTable.table; + results = []; + for (k in ref) { + if (!hasProp.call(ref, k)) continue; + blob = ref[k]; + inplaceNodes = _.intersection(blob.writers, blob.readers); + nonInplaceWriters = _.difference(blob.writers, inplaceNodes); + nonInplaceReaders = _.difference(blob.readers, inplaceNodes); + writerNode = this.getFirstWriterNode(blob, nonInplaceWriters); + if (writerNode != null) { + lastInplaceNode = this.connectInplaceNodes(writerNode, inplaceNodes); + results.push(this.connectNonInplaceNodes(lastInplaceNode, nonInplaceReaders)); + } else { + results.push(void 0); + } + } + return results; + }; + + NodesGenerator.prototype.connectInplaceNodes = function(parentNode, inplaceNodes) { + var i, inplaceNode, lastParrentNode, len; + if (parentNode.coalesce == null) { + parentNode.coalesce = []; + } + lastParrentNode = parentNode; + for (i = 0, len = inplaceNodes.length; i < len; i++) { + inplaceNode = inplaceNodes[i]; + inplaceNode.annotation = 'InPlace'; + lastParrentNode.addChild(inplaceNode); + parentNode.coalesce.push(inplaceNode); + lastParrentNode = inplaceNode; + } + return lastParrentNode; + }; + + NodesGenerator.prototype.connectNonInplaceNodes = function(parentNode, nonInplaceNodes) { + var i, len, node, results; + results = []; + for (i = 0, len = nonInplaceNodes.length; i < len; i++) { + node = nonInplaceNodes[i]; + results.push(parentNode.addChild(node)); + } + return results; + }; + + NodesGenerator.prototype.connectNodesWithBlobs = function(network, layers) { + var i, layer, len, node; + for (i = 0, len = layers.length; i < len; i++) { + layer = layers[i]; + node = this.createNode(network, layer); + this.connectSingleNodeWithBlobs(node, Blob.prototype.connectWithNodeAsTop, layer.top); + this.connectSingleNodeWithBlobs(node, Blob.prototype.connectWithNodeAsBottom, layer.bottom); + } + return network; + }; + + NodesGenerator.prototype.connectSingleNodeWithBlobs = function(node, connectorFunction, blobNames) { + var blob, blobName, i, len, ref, results; + if (blobNames == null) { + return; + } + ref = Utils.asArray(blobNames); + results = []; + for (i = 0, len = ref.length; i < len; i++) { + blobName = ref[i]; + blob = this.blobTable.getBlobByName(blobName); + results.push(connectorFunction(blob, node)); + } + return results; + }; + + NodesGenerator.prototype.createNode = function(net, layer) { + var node; + node = net.createNode(layer.name, layer.type, layer.attribs); + node.bottoms = []; + node.tops = []; + return node; + }; + + NodesGenerator.prototype.getFirstWriterNode = function(blob, nonInplaceWriters) { + var n; + if (nonInplaceWriters.length > 1) { + throw ("Writers number for the '" + blob.name + "' Blob is greater than one.") + ("Non inplace layers with names " + ((function() { + var i, len, results; + results = []; + for (i = 0, len = nonInplaceWriters.length; i < len; i++) { + n = nonInplaceWriters[i]; + results.push(n.name); + } + return results; + })()) + " ") + "write to the same memory, Caffe topology is incorrect."; + } + return nonInplaceWriters[0]; + }; + + return NodesGenerator; + + })(); + + LayersGenerator = (function() { + function LayersGenerator(descriptors1, header1) { + this.descriptors = descriptors1; + this.header = header1; + this.tryConvertHeaderInputToDataLayer = bind(this.tryConvertHeaderInputToDataLayer, this); + this.tryConvertInputShapeEntryToDataLayer = bind(this.tryConvertInputShapeEntryToDataLayer, this); + this.tryExtractDescriptorsFromHeader = bind(this.tryExtractDescriptorsFromHeader, this); + this.generateRegularLayers = bind(this.generateRegularLayers, this); + this.generate = bind(this.generate, this); + } + + LayersGenerator.prototype.generate = function(phase) { + var layers; + this.tryExtractDescriptorsFromHeader(); + layers = this.generateRegularLayers(phase); + return layers; + }; + + LayersGenerator.prototype.generateRegularLayers = function(phase) { + var entry, headerKeys, i, layer, layerDesc, layers, len, ref; + if (phase == null) { + phase = 'train'; + } + layers = []; + headerKeys = ['name', 'type', 'top', 'bottom']; + ref = this.descriptors; + for (i = 0, len = ref.length; i < len; i++) { + entry = ref[i]; + layerDesc = entry.layer || entry.layers; + if (layerDesc != null) { + layer = {}; + _.extend(layer, _.pick(layerDesc, headerKeys)); + layer.attribs = _.omit(layerDesc, headerKeys); + layers.push(layer); + } else { + console.log('Unidentified entry ignored: ', entry); + } + } + layers = _.filter(layers, function(layer) { + var layerPhase, ref1; + layerPhase = (ref1 = layer.attribs.include) != null ? ref1.phase : void 0; + return !((layerPhase != null) && layerPhase !== phase); + }); + return layers; + }; + + LayersGenerator.prototype.tryExtractDescriptorsFromHeader = function() { + var dataLayer; + if (this.header.layer != null) { + this.descriptors.unshift(this.header); + return; + } + dataLayer = this.tryConvertHeaderInputToDataLayer(); + if (dataLayer == null) { + dataLayer = this.tryConvertInputShapeEntryToDataLayer(); + } + if (dataLayer != null) { + return this.descriptors.push(dataLayer); + } + }; + + LayersGenerator.prototype.tryConvertInputShapeEntryToDataLayer = function() { + var entry, i, inputName, inputShape, len, ref; + ref = this.descriptors; + for (i = 0, len = ref.length; i < len; i++) { + entry = ref[i]; + inputShape = entry.input_shape; + if (inputShape != null) { + break; + } + } + if (inputShape != null) { + inputName = this.header.input || 'data'; + return this.createDataLayerDescriptor(inputName, inputShape.dim); + } + }; + + LayersGenerator.prototype.tryConvertHeaderInputToDataLayer = function() { + var inputDim, layerName, ref, ref1; + layerName = (ref = this.header) != null ? ref.input : void 0; + inputDim = (ref1 = this.header) != null ? ref1.input_dim : void 0; + if ((layerName != null) && (inputDim != null)) { + return this.createDataLayerDescriptor(layerName, inputDim); + } + }; + + LayersGenerator.prototype.createDataLayerDescriptor = function(name, shape) { + var layer; + layer = { + name: name, + type: 'Data', + top: name, + input_param: { + shape: shape + } + }; + return { + layer: layer + }; + }; + + return LayersGenerator; + + })(); + + generateNetwork = function(layers, header) { + var blobTable, e, generator, network; + try { + network = new Network(header.name); + blobTable = new BlobTable(layers); + generator = new NodesGenerator(blobTable); + return generator.fillNetwork(network, layers); + } catch (error) { + e = error; + return Notify.error("Can't build network graph. " + e); + } + }; + + generateLayers = function(descriptors, header) { + var layersGenerator; + layersGenerator = new LayersGenerator(descriptors, header); + return layersGenerator.generate(); + }; + + setNodeOutputShapesAttribute = function(node) { + var blob, i, len, ref, ref1, results, shapeText; + if (!((node != null ? (ref = node.tops) != null ? ref.length : void 0 : void 0) > 0)) { + return; + } + node.attribs.blob_shapes = {}; + ref1 = node.tops; + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + blob = ref1[i]; + shapeText = '[ ' + blob.shape.join(', ') + ' ]'; + results.push(node.attribs.blob_shapes[blob.name] = shapeText); + } + return results; + }; + + computePrecedingShapes = function(node) { + var i, len, parent, ref; + ref = node.parents; + for (i = 0, len = ref.length; i < len; i++) { + parent = ref[i]; + if (!parent.areTopShapesInfered) { + computePrecedingShapes(parent); + parent.areTopShapesInfered = true; + } + } + Layers.inferTopShapes(node); + return setNodeOutputShapesAttribute(node); + }; + + computeShapes = function(net) { + var e, endNodes, i, len, node, results; + endNodes = net.findEndNodes(); + try { + results = []; + for (i = 0, len = endNodes.length; i < len; i++) { + node = endNodes[i]; + results.push(computePrecedingShapes(node)); + } + return results; + } catch (error) { + e = error; + return Notify.warning("Can't infer network data shapes. " + e); + } + }; + + module.exports = CaffeParser = (function() { + function CaffeParser() {} + + CaffeParser.parse = function(txt, phase) { + var descriptors, header, layers, network, ref; + ref = Parser.parse(txt), header = ref[0], descriptors = ref[1]; + layers = generateLayers(descriptors, header); + network = generateNetwork(layers, header); + computeShapes(network); + return network; + }; + + return CaffeParser; + + })(); + +}).call(this); diff --git a/lib/caffe/layers.js b/lib/caffe/layers.js new file mode 100644 index 0000000..b925bee --- /dev/null +++ b/lib/caffe/layers.js @@ -0,0 +1,1038 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var ConvolutionLayerBase, areShapesEqual, extractKernelSizes, extractPaddingSizes, extractStrideSizes, getLayerType, getParameterAsArray, getParameterLength, getValueOrDefault, isDataLayer, isLossLayer, isUniformLayer, layers, shapesToString, utils, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + utils = require('../utils/utils.coffee'); + + areShapesEqual = function(x, y) { + var i, k, ref; + if (x.length !== y.length) { + return false; + } + for (i = k = 0, ref = x.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + if (x[i] !== y[i]) { + return false; + } + } + return true; + }; + + getValueOrDefault = function(param, defaultValue) { + if (param != null) { + return param; + } else { + return defaultValue; + } + }; + + extractKernelSizes = function(params) { + return params.kernel_size || [params.kernel_h, params.kernel_w]; + }; + + extractPaddingSizes = function(params) { + if (params.pad != null) { + return params.pad; + } + if ((params.pad_h == null) && (params.pad_w == null)) { + return 0; + } + return [getValueOrDefault(params.pad_h, 0), getValueOrDefault(params.pad_w, 0)]; + }; + + extractStrideSizes = function(params) { + if (params.stride != null) { + return params.stride; + } + if ((params.stride_h == null) && (params.stride_w == null)) { + return 1; + } + return [getValueOrDefault(params.stride_h, 1), getValueOrDefault(params.stride_w, 1)]; + }; + + getParameterAsArray = function(parameter, requiredLength, name) { + var i; + if (utils.typeIsArray(parameter)) { + if (parameter.length !== requiredLength) { + throw ("Dimensions of the '" + name + "' parameter ") + ("must be equal to " + requiredLength + "."); + } + return parameter; + } + return (function() { + var k, ref, results; + results = []; + for (i = k = 0, ref = requiredLength; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + results.push(parameter); + } + return results; + })(); + }; + + getParameterLength = function(parameter) { + if (parameter != null) { + if (utils.typeIsArray(parameter)) { + return parameter.length; + } else { + return 1; + } + } else { + return 0; + } + }; + + shapesToString = function(inputShapes) { + var k, len, shape, text; + text = '['; + for (k = 0, len = inputShapes.length; k < len; k++) { + shape = inputShapes[k]; + text += " [ " + shape + " ]"; + } + text += ' ]'; + return text; + }; + + layers = {}; + + layers.Uniform = this.UniformLayer = (function() { + function UniformLayer() {} + + UniformLayer.prototype.inferShapes = function(bottoms, tops) { + var i, k, ref, results; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + results = []; + for (i = k = 0, ref = tops.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + results.push(tops[i].shape = bottoms[i].shape.slice(0)); + } + return results; + }; + + return UniformLayer; + + })(); + + layers.Loss = this.LossLayer = (function() { + function LossLayer() {} + + LossLayer.prototype.inferShapes = function(bottoms, tops) { + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + return tops[0].shape = [1]; + }; + + return LossLayer; + + })(); + + layers.Data = this.DataLayer = (function() { + function DataLayer(attribs) { + this.tryExtractShapeFromMemoryDataLayer = bind(this.tryExtractShapeFromMemoryDataLayer, this); + this.tryExtractShapeFromTransformParam = bind(this.tryExtractShapeFromTransformParam, this); + this.tryExtractShapes = bind(this.tryExtractShapes, this); + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + this.defaultBatchSize = 1; + this.defaultChannels = 3; + this.outputShape = this.tryExtractShapes(attribs); + } + + DataLayer.prototype.inferShapes = function(bottoms, tops) { + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + tops[0].shape = this.outputShape.slice(0); + if (tops[1]) { + return tops[1].shape = this.outputShape.slice(0, 1); + } + }; + + DataLayer.prototype.checkParameters = function(bottoms, tops) { + var ref; + if (this.outputShape == null) { + throw "Can't extract data shape from Data layer"; + } + if ((bottoms != null ? bottoms.length : void 0) > 0) { + throw "Data layer doesn't expect any input."; + } + if ((ref = tops != null ? tops.length : void 0) !== 1 && ref !== 2) { + throw 'Outputs number of Data layer must be equal to one or two.'; + } + }; + + DataLayer.prototype.tryExtractShapes = function(attribs) { + var ref, ref1, ref2, shape; + shape = attribs != null ? (ref = attribs.input_param) != null ? (ref1 = ref.shape) != null ? ref1.dim : void 0 : void 0 : void 0; + if (shape == null) { + shape = attribs != null ? (ref2 = attribs.input_param) != null ? ref2.shape : void 0 : void 0; + } + if (shape == null) { + shape = attribs != null ? attribs.shape : void 0; + } + if (shape == null) { + shape = this.tryExtractShapeFromTransformParam(attribs); + } + if (shape == null) { + shape = this.tryExtractShapeFromMemoryDataLayer(attribs); + } + return shape; + }; + + DataLayer.prototype.tryExtractShapeFromTransformParam = function(attribs) { + var channels, cropSize, ref; + cropSize = (ref = attribs.transform_param) != null ? ref.crop_size : void 0; + if (cropSize != null) { + channels = this.defaultChannels; + if (attribs.transform_param.force_gray) { + channels = 1; + } + return [this.defaultBatchSize, channels, cropSize, cropSize]; + } + }; + + DataLayer.prototype.tryExtractShapeFromMemoryDataLayer = function(attribs) { + var batch_size, channels, height, param, width; + param = attribs != null ? attribs.memory_data_param : void 0; + batch_size = param.batch_size || this.defaultBatchSize; + channels = param.channels || this.defaultChannels; + height = param.height; + width = param.width; + if ((height != null) && (width != null)) { + return [batch_size, channels, height, width]; + } + }; + + return DataLayer; + + })(); + + ConvolutionLayerBase = (function() { + function ConvolutionLayerBase(name1, attribs) { + var params; + this.name = name1; + this.checkParameters = bind(this.checkParameters, this); + this.inferShapesForOneBlobInternal = bind(this.inferShapesForOneBlobInternal, this); + this.inferShapesForOneBlob = bind(this.inferShapesForOneBlob, this); + this.inferShapes = bind(this.inferShapes, this); + params = attribs != null ? attribs.convolution_param : void 0; + if (params == null) { + throw this.name + " layer must have convolution_param."; + } + this.filters = params.num_output; + this.padding = extractPaddingSizes(params); + this.stride = extractStrideSizes(params); + this.kernel = extractKernelSizes(params); + this.dilation = getValueOrDefault(params.dilation, 1); + this.axis = getValueOrDefault(params.axis, 1); + } + + ConvolutionLayerBase.prototype.inferShapes = function(bottoms, tops) { + var i, k, ref, results; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + results = []; + for (i = k = 0, ref = tops.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + results.push(this.inferShapesForOneBlob(bottoms[i], tops[i])); + } + return results; + }; + + ConvolutionLayerBase.prototype.inferShapesForOneBlob = function(bottom, top) { + var dilation, inputShape, kernel, outputShape, padding, stride, sucDimLength, succeedingDimensions; + inputShape = bottom.shape; + outputShape = inputShape.slice(0); + succeedingDimensions = inputShape.slice(this.axis + 1); + sucDimLength = succeedingDimensions.length; + padding = getParameterAsArray(this.padding, sucDimLength, 'padding'); + kernel = getParameterAsArray(this.kernel, sucDimLength, 'kernel'); + stride = getParameterAsArray(this.stride, sucDimLength, 'stride'); + dilation = getParameterAsArray(this.dilation, sucDimLength, 'dilation'); + this.inferShapesForOneBlobInternal(inputShape, outputShape, padding, kernel, stride, dilation); + return top.shape = outputShape; + }; + + ConvolutionLayerBase.prototype.inferShapesForOneBlobInternal = function(input, output, padding, kernel, stride, dilation) { + return void 0; + }; + + ConvolutionLayerBase.prototype.checkParameters = function(bottoms, tops) { + if (this.filters == null) { + throw this.name + " layer must have num_output parameter."; + } + if ((this.kernel == null) && ((this.kernel[0] == null) || (this.kernel[1] == null))) { + console.log(this.kernel); + throw this.name + " kernel sizes must be set."; + } + if (bottoms == null) { + throw this.name + " layer received undefined bottom blobs."; + } + if (bottoms.length !== tops.length) { + throw (this.name + " layer can process number of top blobs which is equal to ") + ("the number of bottom blobs, but received " + tops.length + " top blobs and ") + (bottoms.length + " bottom blobs."); + } + }; + + return ConvolutionLayerBase; + + })(); + + layers.Convolution = this.ConvolutionLayer = (function(superClass) { + extend(ConvolutionLayer, superClass); + + function ConvolutionLayer(attribs) { + this.inferShapesForOneBlobInternal = bind(this.inferShapesForOneBlobInternal, this); + ConvolutionLayer.__super__.constructor.call(this, 'Convolution', attribs); + } + + ConvolutionLayer.prototype.inferShapesForOneBlobInternal = function(input, output, padding, kernel, stride, dilation) { + var i, ii, k, kernelExtent, outDim, ref, ref1, results; + output[this.axis] = this.filters; + results = []; + for (i = k = ref = this.axis + 1, ref1 = input.length; ref <= ref1 ? k < ref1 : k > ref1; i = ref <= ref1 ? ++k : --k) { + ii = i - this.axis - 1; + kernelExtent = dilation[ii] * (kernel[ii] - 1) + 1; + outDim = (input[i] + 2 * padding[ii] - kernelExtent) / stride[ii] + 1; + results.push(output[i] = Math.floor(outDim)); + } + return results; + }; + + return ConvolutionLayer; + + })(ConvolutionLayerBase); + + layers.Deconvolution = this.DeconvolutionLayer = (function(superClass) { + extend(DeconvolutionLayer, superClass); + + function DeconvolutionLayer(attribs) { + this.inferShapesForOneBlobInternal = bind(this.inferShapesForOneBlobInternal, this); + DeconvolutionLayer.__super__.constructor.call(this, 'Deconvolution', attribs); + } + + DeconvolutionLayer.prototype.inferShapesForOneBlobInternal = function(input, output, padding, kernel, stride, dilation) { + var i, ii, k, kernelExtent, outDim, ref, ref1, results; + output[this.axis] = this.filters; + results = []; + for (i = k = ref = this.axis + 1, ref1 = input.length; ref <= ref1 ? k < ref1 : k > ref1; i = ref <= ref1 ? ++k : --k) { + ii = i - this.axis - 1; + kernelExtent = dilation[ii] * (kernel[ii] - 1) + 1; + outDim = stride[ii] * (input[i] - 1) + kernelExtent - 2 * padding[ii]; + results.push(output[i] = Math.floor(outDim)); + } + return results; + }; + + return DeconvolutionLayer; + + })(ConvolutionLayerBase); + + layers.Pooling = this.PoolingLayer = (function() { + function PoolingLayer(attribs) { + this.getKernelSizes = bind(this.getKernelSizes, this); + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var params; + this.spatialDimSize = 2; + params = attribs != null ? attribs.pooling_param : void 0; + if (params == null) { + throw 'Pooling layer must have pooling_param.'; + } + this.padding = extractPaddingSizes(params); + this.stride = extractStrideSizes(params); + this.kernel = extractKernelSizes(params); + this.isGlobalPooling = getValueOrDefault(params.global_pooling, false); + } + + PoolingLayer.prototype.inferShapes = function(bottoms, tops) { + var i, ii, inputShape, k, kernel, outDim, outDimRounded, outputShape, padding, ref, stride; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + inputShape = bottoms[0].shape; + outputShape = inputShape.slice(0); + padding = getParameterAsArray(this.padding, this.spatialDimSize, 'padding'); + stride = getParameterAsArray(this.stride, this.spatialDimSize, 'stride'); + kernel = this.getKernelSizes(inputShape); + for (i = k = 0, ref = this.spatialDimSize; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + ii = inputShape.length - this.spatialDimSize + i; + outDim = (inputShape[ii] + 2 * padding[i] - kernel[i]) / stride[i]; + outDimRounded = (Math.floor(Math.ceil(outDim))) + 1; + if ((outDimRounded - 1) * stride[i] >= inputShape[ii] + padding[i]) { + outDimRounded--; + } + outputShape[ii] = outDimRounded; + } + tops[0].shape = outputShape; + if (tops[1]) { + return tops[1].shape = outputShape.slice(0); + } + }; + + PoolingLayer.prototype.checkParameters = function(bottoms, tops) { + var ref; + if ((this.kernel == null) && ((this.kernel[0] == null) || (this.kernel[1] == null))) { + throw 'Pooling layer must have kernel_size parameter.'; + } + if (bottoms == null) { + throw 'Pooling layer received undefined bottom blobs.'; + } + if (bottoms.length !== 1) { + throw "Pooling layer can process exactly one input, " + ("but received " + bottoms.length + " input shapes."); + } + if ((ref = tops.length) !== 1 && ref !== 2) { + throw "Pooling layer produces single output shape or two equal " + "shapes if the second top shape is specified."; + } + }; + + PoolingLayer.prototype.getKernelSizes = function(inputShape) { + var kernel; + if (this.isGlobalPooling) { + kernel = inputShape.slice(-this.spatialDimSize); + } else { + kernel = getParameterAsArray(this.kernel, this.spatialDimSize, 'kernel'); + } + return kernel; + }; + + return PoolingLayer; + + })(); + + layers.InnerProduct = this.InnerProductLayer = (function() { + function InnerProductLayer(attribs) { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.inner_product_param : void 0; + if (params == null) { + throw 'InnerProduct layer must have inner_product_param.'; + } + this.numOutput = params.num_output; + this.axis = getValueOrDefault(params.axis, 1); + } + + InnerProductLayer.prototype.inferShapes = function(bottoms, tops) { + var inputShape, outputShape; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + inputShape = bottoms[0].shape; + outputShape = inputShape.slice(0, this.axis); + outputShape[this.axis] = this.numOutput; + return tops[0].shape = outputShape; + }; + + InnerProductLayer.prototype.checkParameters = function(bottoms, tops) { + if (this.numOutput == null) { + throw 'InnerProduct layer must have num_output parameter.'; + } + if (bottoms == null) { + throw 'InnerProduct layer received undefined bottom blobs.'; + } + if (bottoms.length !== 1 || tops.length !== 1) { + throw "InnerProduct layer can accept and produce exactly one blob, but " + ("received " + bottoms.length + " bottoms blobs and " + tops.length + " top blobs."); + } + }; + + return InnerProductLayer; + + })(); + + layers.Concat = this.ConcatLayer = (function() { + function ConcatLayer(attribs) { + this.checkInputShapeAxes = bind(this.checkInputShapeAxes, this); + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var axis, params; + params = attribs != null ? attribs.concat_param : void 0; + axis = params != null ? params.concat_dim : void 0; + if (axis == null) { + axis = params != null ? params.axis : void 0; + } + this.axis = getValueOrDefault(axis, 1); + } + + ConcatLayer.prototype.inferShapes = function(bottoms, tops) { + var bottom, firstInputShape, k, len, outputShape; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + firstInputShape = bottoms[0].shape; + outputShape = firstInputShape.slice(0); + outputShape[this.axis] = 0; + for (k = 0, len = bottoms.length; k < len; k++) { + bottom = bottoms[k]; + outputShape[this.axis] += bottom.shape[this.axis]; + } + return tops[0].shape = outputShape; + }; + + ConcatLayer.prototype.checkParameters = function(bottoms, tops) { + var bottom, firstShape, inputShapes, k, len, results, shape; + if ((bottoms != null ? bottoms[0] : void 0) == null) { + throw 'Concat layer must have at least one bottom blob.'; + } + firstShape = bottoms[0].shape; + inputShapes = (function() { + var k, len, results; + results = []; + for (k = 0, len = bottoms.length; k < len; k++) { + bottom = bottoms[k]; + results.push(bottom.shape); + } + return results; + })(); + results = []; + for (k = 0, len = inputShapes.length; k < len; k++) { + shape = inputShapes[k]; + if (!this.checkInputShapeAxes(firstShape, shape)) { + throw "Concat layer received incorrect input shapes: " + ((shapesToString(inputShapes)) + ". ") + "All axes except axis along which concatenation " + "is performing must have the same sizes."; + } else { + results.push(void 0); + } + } + return results; + }; + + ConcatLayer.prototype.checkInputShapeAxes = function(firstShape, shape) { + var i, k, ref; + if (firstShape.length !== shape.length) { + return false; + } + for (i = k = 0, ref = shape.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + if (i !== this.axis && firstShape[i] !== shape[i]) { + return false; + } + } + return true; + }; + + return ConcatLayer; + + })(); + + layers.Slice = this.SliceLayer = (function() { + function SliceLayer(attribs) { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.slice_param : void 0; + this.slicePoint = params != null ? params.slice_point : void 0; + this.axis = getValueOrDefault(params.axis, 1); + } + + SliceLayer.prototype.inferShapes = function(bottoms, tops) { + var firstInputShape, i, k, ref; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.slicePoint = getParameterAsArray(this.slicePoint, tops.length - 1, 'slice_point'); + this.checkParameters(bottoms, tops); + firstInputShape = bottoms[0].shape; + for (i = k = 0, ref = tops.length - 1; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + tops[i].shape = firstInputShape.slice(0); + tops[i].shape[this.axis] = this.slicePoint[i]; + } + tops[tops.length - 1].shape = firstInputShape.slice(0); + return tops[tops.length - 1].shape[this.axis] = firstInputShape[this.axis] - this.slicePoint[this.slicePoint.length - 1]; + }; + + SliceLayer.prototype.checkParameters = function(bottoms, tops) { + if ((bottoms != null ? bottoms[0] : void 0) == null) { + throw 'Slice layer must have at least one bottom blob.'; + } + if ((tops != null ? tops[1] : void 0) == null) { + throw 'Slice layer must have at least two top blob.'; + } + }; + + return SliceLayer; + + })(); + + layers.Permute = this.PermuteLayer = (function() { + function PermuteLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.permute_param : void 0; + this.order = params != null ? params.order : void 0; + } + + PermuteLayer.prototype.inferShapes = function(bottoms, tops) { + var bottom, firstInputShape, i, k, ref, results, top; + this.order = getParameterAsArray(this.order, bottoms[0].shape.length, 'order'); + firstInputShape = bottoms[0].shape; + top = tops[0]; + bottom = bottoms[0]; + top.shape = firstInputShape.slice(0); + results = []; + for (i = k = 0, ref = this.order.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + results.push(top.shape[i] = bottom.shape[this.order[i]]); + } + return results; + }; + + return PermuteLayer; + + })(); + + layers.Flatten = this.FlattenLayer = (function() { + function FlattenLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.flatten_param : void 0; + this.axis = getValueOrDefault(params.axis, 1); + } + + FlattenLayer.prototype.inferShapes = function(bottoms, tops) { + var i, k, outputShape, ref, ref1, results, top; + outputShape = bottoms[0].shape; + top = tops[0]; + top.shape = outputShape.slice(0, this.axis + 1); + results = []; + for (i = k = ref = this.axis + 1, ref1 = outputShape.length; ref <= ref1 ? k < ref1 : k > ref1; i = ref <= ref1 ? ++k : --k) { + results.push(top.shape[this.axis] *= outputShape[i]); + } + return results; + }; + + return FlattenLayer; + + })(); + + layers.PriorBox = this.PriorBoxLayer = (function() { + function PriorBoxLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.prior_box_param : void 0; + this.min_size = params != null ? params.min_size : void 0; + this.max_size = params != null ? params.max_size : void 0; + this.aspect_ratio = params != null ? params.aspect_ratio : void 0; + this.flip = params != null ? params.flip : void 0; + } + + PriorBoxLayer.prototype.inferShapes = function(bottoms, tops) { + var already_exist, ar, aspect_ratio_length, aspect_ratio_param_length, aspect_ratios, height, i, j, k, l, len, len1, len2, m, max_size_length, min_size_length, num_priors, outputShape, ref, ref1, ref2, width; + min_size_length = getParameterLength(this.min_size); + max_size_length = getParameterLength(this.max_size); + aspect_ratio_param_length = getParameterLength(this.aspect_ratio); + aspect_ratios = [1.0]; + if (aspect_ratio_param_length === 1) { + ar = this.aspect_ratio; + already_exist = false; + ref = aspect_ratios.length; + for (k = 0, len = ref.length; k < len; k++) { + j = ref[k]; + if (Math.abs(ar - aspect_ratios[j]) < 1e-6) { + already_exist = true; + break; + } + } + if (already_exist !== true) { + aspect_ratios.push(ar); + if (this.flip) { + aspect_ratios.push(1.0 / ar); + } + } + } else { + ref1 = this.aspect_ratio; + for (l = 0, len1 = ref1.length; l < len1; l++) { + i = ref1[l]; + ar = i; + already_exist = false; + ref2 = aspect_ratios.length; + for (m = 0, len2 = ref2.length; m < len2; m++) { + j = ref2[m]; + if (Math.abs(ar - aspect_ratios[j]) < 1e-6) { + already_exist = true; + break; + } + } + if (already_exist !== true) { + aspect_ratios.push(ar); + if (this.flip) { + aspect_ratios.push(1.0 / ar); + } + } + } + } + aspect_ratio_length = aspect_ratios.length; + outputShape = bottoms[0].shape; + height = bottoms[0].shape[2]; + width = bottoms[0].shape[3]; + num_priors = aspect_ratio_length * min_size_length + max_size_length; + tops[0].shape = outputShape.slice(0, 3); + tops[0].shape[0] = 1; + tops[0].shape[1] = 2; + return tops[0].shape[2] = height * width * num_priors * 4; + }; + + return PriorBoxLayer; + + })(); + + layers.Reshape = this.ReshapeLayer = (function() { + function ReshapeLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.reshape_param : void 0; + this.shape = params != null ? params.shape : void 0; + } + + ReshapeLayer.prototype.inferShapes = function(bottoms, tops) { + var dim, dim_length, i, k, l, m, other_sum, outputShape, ref, ref1, ref2, results, sum; + dim_length = getParameterLength(this.shape.dim); + dim = getParameterAsArray(this.shape.dim, dim_length, 'dim'); + outputShape = bottoms[0].shape; + sum = 1; + for (i = k = 0, ref = bottoms[0].shape.length; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) { + sum *= bottoms[0].shape[i]; + } + tops[0].shape = outputShape.slice(0, dim_length); + other_sum = 1; + for (i = l = 0, ref1 = dim_length; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) { + if (dim[i] !== 0 && dim[i] !== -1) { + tops[0].shape[i] = dim[i]; + } + if (dim[i] !== -1) { + other_sum *= tops[0].shape[i]; + } + } + results = []; + for (i = m = 0, ref2 = dim_length; 0 <= ref2 ? m < ref2 : m > ref2; i = 0 <= ref2 ? ++m : --m) { + if (dim[i] === -1) { + results.push(tops[0].shape[i] = sum / other_sum); + } else { + results.push(void 0); + } + } + return results; + }; + + return ReshapeLayer; + + })(); + + layers.Tiling = this.TilingLayer = (function() { + function TilingLayer(attribs) { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.tiling_param : void 0; + this.tile_dim = params != null ? params.tile_dim : void 0; + } + + TilingLayer.prototype.inferShapes = function(bottoms, tops) { + var channels, height, outputShape, width; + this.checkParameters(bottoms, tops); + outputShape = bottoms[0].shape; + channels = bottoms[0].shape[1]; + height = bottoms[0].shape[2]; + width = bottoms[0].shape[3]; + tops[0].shape = outputShape; + tops[0].shape[1] = channels / (this.tile_dim * this.tile_dim); + tops[0].shape[2] = height * this.tile_dim; + return tops[0].shape[3] = width * this.tile_dim; + }; + + TilingLayer.prototype.checkParameters = function(bottoms, tops) { + if (this.tile_dim == null) { + throw 'tile_dim must be specified.'; + } + if (!(this.tile_dim > 0)) { + throw 'tile_dim must be positive.'; + } + if (bottoms[0].shape[1] % (this.tile_dim * this.tile_dim) !== 0) { + throw 'The number of input channels for tiling layer must be multiples of the tile_dim.'; + } + }; + + return TilingLayer; + + })(); + + layers.Normalize = this.NormalizeLayer = (function() { + function NormalizeLayer(attribs) { + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs != null ? attribs.norm_param : void 0; + this.across_spatial = params != null ? params.across_spatial : void 0; + this.channel_shared = params != null ? params.channel_shared : void 0; + } + + NormalizeLayer.prototype.inferShapes = function(bottoms, tops) { + var outputShape; + outputShape = bottoms[0].shape; + return tops[0].shape = outputShape; + }; + + return NormalizeLayer; + + })(); + + layers.Eltwise = this.EltwiseLayer = (function() { + function EltwiseLayer() { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + } + + EltwiseLayer.prototype.inferShapes = function(bottoms, tops) { + var firstInputShape; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + firstInputShape = bottoms[0].shape; + return tops[0].shape = firstInputShape.slice(0); + }; + + EltwiseLayer.prototype.checkParameters = function(bottoms, tops) { + var bottom, firstShape, inputShapes, k, len, results, shape; + if ((bottoms != null ? bottoms[0] : void 0) == null) { + throw 'Eltwise layer must have at least one input.'; + } + inputShapes = (function() { + var k, len, results; + results = []; + for (k = 0, len = bottoms.length; k < len; k++) { + bottom = bottoms[k]; + results.push(bottom.shape); + } + return results; + })(); + firstShape = inputShapes[0]; + results = []; + for (k = 0, len = inputShapes.length; k < len; k++) { + shape = inputShapes[k]; + if (!areShapesEqual(firstShape, shape)) { + throw "Eltwise layer received incorrect input shapes: " + ((shapesToString(inputShapes)) + ". ") + "All axes must have the same sizes."; + } else { + results.push(void 0); + } + } + return results; + }; + + return EltwiseLayer; + + })(); + + layers.Axpy = this.AxpyLayer = (function() { + function AxpyLayer() { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + } + + AxpyLayer.prototype.inferShapes = function(bottoms, tops) { + var firstInputShape; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + firstInputShape = bottoms[1].shape; + return tops[0].shape = firstInputShape.slice(0); + }; + + AxpyLayer.prototype.checkParameters = function(bottoms, tops) { + var bottom, firstShape, inputShapes; + if ((bottoms != null ? bottoms.length : void 0) !== 3) { + throw 'Axpy layer must have three inputs.'; + } + inputShapes = (function() { + var k, len, results; + results = []; + for (k = 0, len = bottoms.length; k < len; k++) { + bottom = bottoms[k]; + results.push(bottom.shape); + } + return results; + })(); + firstShape = inputShapes[0]; + if (inputShapes[0][0] !== inputShapes[1][0]) { + throw "InputShapes 0 and 1 at 0 axe must have the same sizes."; + } + if (inputShapes[0][1] !== inputShapes[1][1]) { + throw "InputShapes 0 and 1 at 1 axe must have the same sizes."; + } + if (inputShapes[0].length === 4) { + if (inputShapes[0][2] !== 1 || inputShapes[0][3] !== 1) { + throw "InputShapes 0 at 2、3 axe must be 1."; + } + } + if (!areShapesEqual(inputShapes[1], inputShapes[2])) { + throw "Axpy layer received incorrect input shapes: " + ((shapesToString(inputShapes)) + ". ") + "InputShapes 1 and 2 at all axes must have the same sizes."; + } + }; + + return AxpyLayer; + + })(); + + layers.Crop = this.CropLayer = (function() { + function CropLayer(attribs) { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var params; + params = attribs.crop_param; + this.axis = getValueOrDefault(params != null ? params.axis : void 0, 0); + } + + CropLayer.prototype.inferShapes = function(bottoms, tops) { + var i, k, outputShape, ref, ref1; + if ((tops != null ? tops[0] : void 0) == null) { + return; + } + this.checkParameters(bottoms, tops); + outputShape = bottoms[0].shape.slice(0); + for (i = k = ref = this.axis, ref1 = outputShape.length; ref <= ref1 ? k < ref1 : k > ref1; i = ref <= ref1 ? ++k : --k) { + outputShape[i] = bottoms[1].shape[i]; + } + return tops[0].shape = outputShape; + }; + + CropLayer.prototype.checkParameters = function(bottoms, tops) { + if ((bottoms != null ? bottoms.length : void 0) !== 2) { + throw 'Crop layer must have exactly two bottom blobs.'; + } + }; + + return CropLayer; + + })(); + + layers.Interp = this.InterpLayer = (function() { + function InterpLayer(attribs) { + this.checkParameters = bind(this.checkParameters, this); + this.inferShapes = bind(this.inferShapes, this); + var ref, ref1, ref2, ref3, ref4, ref5; + this.params = attribs.interp_param; + this.height = getValueOrDefault((ref = this.params) != null ? ref.height : void 0, 0); + this.width = getValueOrDefault((ref1 = this.params) != null ? ref1.width : void 0, 0); + this.zoom_factor = getValueOrDefault((ref2 = this.params) != null ? ref2.zoom_factor : void 0, 1); + this.shrink_factor = getValueOrDefault((ref3 = this.params) != null ? ref3.shrink_factor : void 0, 1); + this.pad_beg = getValueOrDefault((ref4 = this.params) != null ? ref4.pad_beg : void 0, 0); + this.pad_end = getValueOrDefault((ref5 = this.params) != null ? ref5.pad_end : void 0, 0); + } + + InterpLayer.prototype.inferShapes = function(bottoms, tops) { + var height_in, height_in_eff, height_out, outputShape, width_in, width_in_eff, width_out; + this.checkParameters(bottoms, tops); + outputShape = bottoms[0].shape; + height_in = bottoms[0].shape[2]; + width_in = bottoms[0].shape[3]; + tops[0].shape = outputShape; + height_in_eff = height_in + this.pad_beg + this.pad_end; + width_in_eff = width_in + this.pad_beg + this.pad_end; + if ((this.params.shrink_factor != null) && (this.params.zoom_factor == null)) { + height_out = (height_in_eff - 1) / this.shrink_factor + 1; + width_out = (width_in_eff - 1) / this.shrink_factor + 1; + } else if ((this.params.shrink_factor == null) && (this.params.zoom_factor != null)) { + height_out = height_in_eff + (height_in_eff - 1) * (this.zoom_factor - 1); + width_out = width_in_eff + (width_in_eff - 1) * (this.zoom_factor - 1); + } else if ((this.params.height != null) && (this.params.width != null)) { + height_out = this.height; + width_out = this.width; + } else if ((this.params.shrink_factor != null) && (this.params.zoom_factor != null)) { + height_out = (height_in_eff - 1) / this.shrink_factor + 1; + width_out = (width_in_eff - 1) / this.shrink_factor + 1; + height_out = height_out + (height_out - 1) * (this.zoom_factor - 1); + width_out = width_out + (width_out - 1) * (this.zoom_factor - 1); + } + if (!(height_in_eff > 0)) { + throw 'height should be positive.'; + } + if (!(width_in_eff > 0)) { + throw 'width should be positive.'; + } + if (!(height_out > 0)) { + throw 'height should be positive.'; + } + if (!(width_out > 0)) { + throw 'width should be positive.'; + } + tops[0].shape[2] = height_out; + return tops[0].shape[3] = width_out; + }; + + InterpLayer.prototype.checkParameters = function(bottoms, tops) { + if (this.params.shrink_factor != null) { + if (!(this.shrink_factor >= 1)) { + throw 'shrink_factor must be positive.'; + } + } + if (this.params.zoom_factor != null) { + if (!(this.zoom_factor >= 1)) { + throw 'zoom_factor must be positive.'; + } + } + }; + + return InterpLayer; + + })(); + + isLossLayer = function(layerType) { + return /loss/i.test(layerType); + }; + + isDataLayer = function(layerType) { + return (/input/i.test(layerType)) || (/data/i.test(layerType)); + }; + + isUniformLayer = function(lt) { + return (/relu/i.test(lt)) || (/prelu/i.test(lt)) || (/elu/i.test(lt)) || (/sigmoid/i.test(lt)) || (/tanh/i.test(lt)) || (/abs/i.test(lt)) || (/power/i.test(lt)) || (/exp/i.test(lt)) || (/log/i.test(lt)) || (/bnll/i.test(lt)) || (/threshold/i.test(lt)) || (/bias/i.test(lt)) || (/scale/i.test(lt)) || (/lrn/i.test(lt)) || (/dropout/i.test(lt)) || (/batchnorm/i.test(lt)) || (/groupnorm/i.test(lt)) || (/bn/i.test(lt)) || (/mvn/i.test(lt)) || (/softmax/i.test(lt)); + }; + + getLayerType = function(layerTypeName) { + var layerType, layerTypeNameTitle; + if (isUniformLayer(layerTypeName)) { + return layers.Uniform; + } + if (isDataLayer(layerTypeName)) { + return layers.Data; + } + if (isLossLayer(layerTypeName)) { + return layers.Loss; + } + layerType = layers[layerTypeName]; + if (layerType == null) { + layerTypeNameTitle = utils.toTitleCase(layerTypeName); + layerType = layers[layerTypeNameTitle]; + } + if (layerType == null) { + throw "Unsupported layer type: '" + layerTypeName + "'."; + } + return layerType; + }; + + exports.inferTopShapes = function(node) { + var LayerType, e, layer, top; + try { + LayerType = getLayerType(node.type); + layer = new LayerType(node.attribs); + layer.inferShapes(node.bottoms, node.tops); + return (function() { + var k, len, ref, results; + ref = node.tops; + results = []; + for (k = 0, len = ref.length; k < len; k++) { + top = ref[k]; + results.push(top.shape); + } + return results; + })(); + } catch (error) { + e = error; + throw ("Can't infer output shape of the '" + node.name + "' ") + ("layer of type '" + node.type + "'. ") + e; + } + }; + +}).call(this); diff --git a/lib/editor.js b/lib/editor.js new file mode 100644 index 0000000..5804c35 --- /dev/null +++ b/lib/editor.js @@ -0,0 +1,37 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var Editor; + + module.exports = Editor = (function() { + function Editor(loader) { + var $editorBox, editorWidthPercentage; + this.loader = loader; + editorWidthPercentage = 30; + $editorBox = $($.parseHTML('
')); + $editorBox.width(editorWidthPercentage + '%'); + $('#net-column').width((100 - editorWidthPercentage) + '%'); + $('#master-container').prepend($editorBox); + this.editor = CodeMirror($editorBox[0], { + value: '# Enter your network definition here.\n# Use Shift+Enter to update the visualization.', + lineNumbers: true, + lineWrapping: true + }); + this.editor.on('keydown', (function(_this) { + return function(cm, e) { + return _this.onKeyDown(e); + }; + })(this)); + } + + Editor.prototype.onKeyDown = function(e) { + if (e.shiftKey && e.keyCode === 13) { + e.preventDefault(); + return this.loader(this.editor.getValue()); + } + }; + + return Editor; + + })(); + +}).call(this); diff --git a/lib/loader.js b/lib/loader.js new file mode 100644 index 0000000..9b88cec --- /dev/null +++ b/lib/loader.js @@ -0,0 +1,70 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var Loader, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + module.exports = Loader = (function() { + function Loader(parser) { + this.parser = parser; + this.load = bind(this.load, this); + this.fromPreset = bind(this.fromPreset, this); + this.fromURL = bind(this.fromURL, this); + this.fromGist = bind(this.fromGist, this); + } + + Loader.prototype.fromGist = function(gistID, callback) { + var url; + url = 'https://api.github.com/gists/' + gistID; + return $.getJSON(url, (function(_this) { + return function(data) { + var fileInfo, fileKey, fileSet, filename, isProto, isSolitaryFile, isSolver; + fileSet = data['files']; + isSolitaryFile = Object.keys(fileSet).length === 1; + for (fileKey in fileSet) { + fileInfo = fileSet[fileKey]; + filename = fileInfo['filename'].toLowerCase(); + isProto = _.endsWith(filename, '.prototxt'); + isSolver = _.startsWith(filename, 'solver'); + if ((isProto && !isSolver) || isSolitaryFile) { + _this.load(fileInfo['content'], callback); + return; + } + } + return console.log('No prototxt found in the given GIST.'); + }; + })(this)); + }; + + Loader.prototype.fromURL = function(url, callback) { + return $.ajax({ + url: url, + success: (function(_this) { + return function() { + return _this.load(data, callback); + }; + })(this) + }); + }; + + Loader.prototype.fromPreset = function(name, callback) { + return $.get('./presets/' + name + '.prototxt', (function(_this) { + return function(data) { + return _this.load(data, callback); + }; + })(this)); + }; + + Loader.prototype.load = function(data, callback) { + var net; + net = this.parser.parse(data); + if (!_.isUndefined(callback)) { + callback(net); + } + return net; + }; + + return Loader; + + })(); + +}).call(this); diff --git a/lib/netscope.js b/lib/netscope.js new file mode 100644 index 0000000..d63d2b9 --- /dev/null +++ b/lib/netscope.js @@ -0,0 +1,46 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var AppController, CaffeNetwork, Loader, showDocumentation, + slice = [].slice; + + AppController = require('./app.coffee'); + + CaffeNetwork = require('./caffe/caffe.coffee'); + + Loader = require('./loader.coffee'); + + showDocumentation = function() { + return window.location.href = 'quickstart.html'; + }; + + $(document).ready(function() { + var app, loader, makeLoader, router, routes; + app = new AppController(); + loader = new Loader(CaffeNetwork); + makeLoader = function(loadingFunc) { + return function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return app.startLoading.apply(app, [loadingFunc].concat(slice.call(args))); + }; + }; + routes = { + '/gist/:gistID': makeLoader(loader.fromGist), + '/url/(.+)': makeLoader(loader.fromURL), + '/preset/:name': makeLoader(loader.fromPreset), + '/editor(/?)': (function(_this) { + return function() { + return app.showEditor(loader); + }; + })(this), + '/doc': (function(_this) { + return function() { + return showDocumentation(); + }; + })(this) + }; + router = Router(routes); + return router.init('/doc'); + }); + +}).call(this); diff --git a/lib/network.js b/lib/network.js new file mode 100644 index 0000000..6e82e51 --- /dev/null +++ b/lib/network.js @@ -0,0 +1,148 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var Network, Node, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Node = (function() { + function Node(name, type1, attribs1) { + this.name = name; + this.type = type1; + this.attribs = attribs1 != null ? attribs1 : {}; + this.detachChildren = bind(this.detachChildren, this); + this.detachChild = bind(this.detachChild, this); + this.addParents = bind(this.addParents, this); + this.addParent = bind(this.addParent, this); + this.addChildren = bind(this.addChildren, this); + this.addChild = bind(this.addChild, this); + this.hasChildren = bind(this.hasChildren, this); + this.parents = []; + this.children = []; + this.coalesce = []; + } + + Node.prototype.hasChildren = function() { + return this.children.length > 0; + }; + + Node.prototype.addChild = function(child) { + if (indexOf.call(this.children, child) < 0) { + this.children.push(child); + if (indexOf.call(child.parents, this) < 0) { + return child.parents.push(this); + } + } + }; + + Node.prototype.addChildren = function(children) { + return _.forEach(children, (function(_this) { + return function(c) { + return _this.addChild(c); + }; + })(this)); + }; + + Node.prototype.addParent = function(parent) { + return parent.addChild(this); + }; + + Node.prototype.addParents = function(parents) { + return _.forEach(parents, (function(_this) { + return function(p) { + return _this.addParent(p); + }; + })(this)); + }; + + Node.prototype.detachChild = function(child) { + _.pull(this.children, child); + return _.pull(child.parents, this); + }; + + Node.prototype.detachChildren = function() { + var children; + children = _.clone(this.children); + _.forEach(children, (function(_this) { + return function(c) { + return _this.detachChild(c); + }; + })(this)); + return children; + }; + + return Node; + + })(); + + module.exports = Network = (function() { + function Network(name) { + this.name = name != null ? name : 'Untitled Network'; + this.sortTopologically = bind(this.sortTopologically, this); + this.findEndNodes = bind(this.findEndNodes, this); + this.nodes = []; + } + + Network.prototype.createNode = function(label, type, attribs) { + var node; + node = new Node(label, type, attribs); + this.nodes.push(node); + return node; + }; + + Network.prototype.findEndNodes = function() { + var i, len, ref, results, x; + ref = this.nodes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + x = ref[i]; + if (!x.hasChildren()) { + results.push(x); + } + } + return results; + }; + + Network.prototype.sortTopologically = function() { + var i, j, len, len1, node, sortedNodes, unsortedNodes, visit; + sortedNodes = []; + unsortedNodes = _.clone(this.nodes); + for (i = 0, len = unsortedNodes.length; i < len; i++) { + node = unsortedNodes[i]; + node.sort_ = { + temp: false, + perm: false + }; + } + visit = function(node) { + var child, j, len1, ref; + if (node.sort_.temp === true) { + throw 'Graph is not a DAG. Complicit node: ' + node.name; + } + if (node.sort_.perm) { + return; + } + node.sort_.temp = true; + ref = node.children; + for (j = 0, len1 = ref.length; j < len1; j++) { + child = ref[j]; + visit(child); + } + node.sort_.perm = true; + node.sort_.temp = false; + return sortedNodes.unshift(node); + }; + while (unsortedNodes.length !== 0) { + visit(unsortedNodes.pop()); + } + for (j = 0, len1 = sortedNodes.length; j < len1; j++) { + node = sortedNodes[j]; + delete node.sort_; + } + return sortedNodes; + }; + + return Network; + + })(); + +}).call(this); diff --git a/lib/notify.js b/lib/notify.js new file mode 100644 index 0000000..bd0e3d9 --- /dev/null +++ b/lib/notify.js @@ -0,0 +1,48 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var Notifier; + + module.exports = Notifier = (function() { + function Notifier() {} + + Notifier._errorHandlers = []; + + Notifier._warningHandlers = []; + + Notifier.onerror = function(handler) { + return Notifier._errorHandlers.push(handler); + }; + + Notifier.onwarning = function(handler) { + return Notifier._warningHandlers.push(handler); + }; + + Notifier.error = function(object) { + var handler, i, len, ref, results; + console.log('Error: ' + object); + ref = Notifier._errorHandlers; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + handler = ref[i]; + results.push(handler(object)); + } + return results; + }; + + Notifier.warning = function(object) { + var handler, i, len, ref, results; + console.log('Warning: ' + object); + ref = Notifier._warningHandlers; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + handler = ref[i]; + results.push(handler(object)); + } + return results; + }; + + return Notifier; + + })(); + +}).call(this); diff --git a/lib/renderer.js b/lib/renderer.js new file mode 100644 index 0000000..2e41d72 --- /dev/null +++ b/lib/renderer.js @@ -0,0 +1,214 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var Renderer, + hasProp = {}.hasOwnProperty; + + module.exports = Renderer = (function() { + function Renderer(net, parent1) { + this.net = net; + this.parent = parent1; + this.iconify = false; + this.layoutDirection = 'tb'; + this.generateGraph(); + } + + Renderer.prototype.setupGraph = function() { + this.graph = new dagreD3.graphlib.Graph(); + this.graph.setDefaultEdgeLabel((function() { + return {}; + })); + return this.graph.setGraph({ + rankdir: this.layoutDirection, + ranksep: 30, + nodesep: 10, + edgesep: 20, + marginx: 0, + marginy: 0 + }); + }; + + Renderer.prototype.generateGraph = function() { + var child, i, j, k, l, lastCoalesed, layers, len, len1, len2, len3, len4, m, node, nodes, parent, ref, ref1, ref2, ref3, sink, source, uberParents; + this.setupGraph(); + nodes = this.net.sortTopologically(); + for (i = 0, len = nodes.length; i < len; i++) { + node = nodes[i]; + if (node.isInGraph) { + continue; + } + layers = [node].concat(node.coalesce); + if (layers.length > 1) { + lastCoalesed = layers[layers.length - 1]; + ref = lastCoalesed.children; + for (j = 0, len1 = ref.length; j < len1; j++) { + child = ref[j]; + uberParents = _.clone(child.parents); + uberParents[uberParents.indexOf(lastCoalesed)] = node; + child.parents = uberParents; + } + } + this.insertNode(layers); + ref1 = node.parents; + for (k = 0, len2 = ref1.length; k < len2; k++) { + parent = ref1[k]; + this.insertLink(parent, node); + } + } + ref2 = this.graph.sources(); + for (l = 0, len3 = ref2.length; l < len3; l++) { + source = ref2[l]; + (this.graph.node(source))["class"] = 'node-type-source'; + } + ref3 = this.graph.sinks(); + for (m = 0, len4 = ref3.length; m < len4; m++) { + sink = ref3[m]; + (this.graph.node(sink))["class"] = 'node-type-sink'; + } + return this.render(); + }; + + Renderer.prototype.insertNode = function(layers) { + var baseNode, i, layer, len, nodeClass, nodeDesc, nodeLabel; + baseNode = layers[0]; + nodeClass = 'node-type-' + baseNode.type.replace(/_/g, '-').toLowerCase(); + nodeLabel = ''; + for (i = 0, len = layers.length; i < len; i++) { + layer = layers[i]; + layer.isInGraph = true; + nodeLabel += this.generateLabel(layer); + } + nodeDesc = { + labelType: 'html', + label: nodeLabel, + "class": nodeClass, + layers: layers, + rx: 5, + ry: 5 + }; + if (this.iconify) { + _.extend(nodeDesc, { + shape: 'circle' + }); + } + return this.graph.setNode(baseNode.name, nodeDesc); + }; + + Renderer.prototype.generateLabel = function(layer) { + if (!this.iconify) { + return '
' + layer.name + '
'; + } else { + return ''; + } + }; + + Renderer.prototype.insertLink = function(src, dst) { + return this.graph.setEdge(src.name, dst.name, { + arrowhead: 'vee' + }); + }; + + Renderer.prototype.renderKey = function(key) { + return key.replace(/_/g, ' '); + }; + + Renderer.prototype.renderValue = function(value) { + if (Array.isArray(value)) { + return value.join(', '); + } + return value; + }; + + Renderer.prototype.renderSection = function(section) { + var i, isScalarArray, isSection, key, len, ref, s, subSection, val; + s = ''; + for (key in section) { + if (!hasProp.call(section, key)) continue; + val = section[key]; + isScalarArray = Array.isArray(val) && ((val.length === 0) || (typeof val[0] !== 'object')); + isSection = (typeof val === 'object') && !isScalarArray; + if (isSection) { + s += '
' + this.renderKey(key) + '
'; + s += '
'; + ref = [].concat(val); + for (i = 0, len = ref.length; i < len; i++) { + subSection = ref[i]; + s += this.renderSection(subSection); + } + } else { + s += '
'; + s += '' + this.renderKey(key) + ': '; + s += '' + this.renderValue(val) + ''; + } + s += '
'; + } + return s; + }; + + Renderer.prototype.tipForNode = function(nodeKey) { + var i, layer, len, node, ref, s; + node = this.graph.node(nodeKey); + s = ''; + ref = node.layers; + for (i = 0, len = ref.length; i < len; i++) { + layer = ref[i]; + s += '
'; + s += '
'; + s += '' + layer.name + ''; + s += ' · '; + s += '' + this.renderKey(layer.type) + ''; + if (layer.annotation != null) { + s += ' · ' + layer.annotation + ''; + } + s += '
'; + s += this.renderSection(layer.attribs); + } + return s; + }; + + Renderer.prototype.render = function() { + var bbox, graphRender, margin, svg, svgGroup, that, tipPositions; + svg = d3.select(this.parent); + svgGroup = svg.append('g'); + graphRender = new dagreD3.render(); + graphRender(svgGroup, this.graph); + bbox = svgGroup.node().getBBox(); + svgGroup.attr('transform', 'translate(' + Math.ceil(-bbox.x) + ')'); + margin = 5; + svg.attr('width', Math.ceil(bbox.width + 2 * margin)); + svg.attr('height', Math.ceil(bbox.height + 2 * margin)); + tipPositions = { + tb: { + my: 'left center', + at: 'right center' + }, + lr: { + my: 'top center', + at: 'bottom center' + } + }; + that = this; + return svgGroup.selectAll("g.node").each(function(nodeKey) { + var position; + position = tipPositions[that.layoutDirection]; + position.viewport = $(window); + return $(this).qtip({ + content: { + text: that.tipForNode(nodeKey) + }, + position: position, + show: { + delay: 0, + effect: false + }, + hide: { + effect: false + } + }); + }); + }; + + return Renderer; + + })(); + +}).call(this); diff --git a/lib/utils/utils.js b/lib/utils/utils.js new file mode 100644 index 0000000..dfa508e --- /dev/null +++ b/lib/utils/utils.js @@ -0,0 +1,41 @@ +// Generated by CoffeeScript 1.12.7 +(function() { + var toTitleCaseSaveSpaces, typeIsArray; + + exports.typeIsArray = typeIsArray = function(value) { + return value && typeof value === 'object' && value instanceof Array && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')); + }; + + exports.asArray = function(valueOrArray) { + if (typeIsArray(valueOrArray)) { + return valueOrArray; + } + return [valueOrArray]; + }; + + exports.asScalar = function(valueOrArray) { + if (!typeIsArray(valueOrArray)) { + return valueOrArray; + } + if (valueOrArray.length === 1) { + return valueOrArray[0]; + } + return valueOrArray; + }; + + exports.toTitleCaseSaveSpaces = toTitleCaseSaveSpaces = function(str) { + return str[0].toUpperCase() + str.slice(1, +(str.length - 1) + 1 || 9e9).toLowerCase(); + }; + + exports.toTitleCase = function(str) { + var i, len, part, partialNames, result; + partialNames = str.split(/[\ _]/); + result = ''; + for (i = 0, len = partialNames.length; i < len; i++) { + part = partialNames[i]; + result += toTitleCaseSaveSpaces(part); + } + return result; + }; + +}).call(this); diff --git a/src/caffe/layers.coffee b/src/caffe/layers.coffee index 2d1e837..4fdc703 100644 --- a/src/caffe/layers.coffee +++ b/src/caffe/layers.coffee @@ -42,6 +42,15 @@ getParameterAsArray = (parameter, requiredLength, name) -> return parameter return (parameter for i in [0...requiredLength]) +getParameterLength = (parameter) -> + if parameter? + if utils.typeIsArray parameter + return parameter.length + else + return 1 + else + return 0 + shapesToString = (inputShapes) -> text = '[' for shape in inputShapes @@ -311,6 +320,165 @@ class @ConcatLayer return false return true +layers.Slice = +class @SliceLayer + constructor: (attribs) -> + params = attribs?.slice_param + @slicePoint = params?.slice_point + @axis = getValueOrDefault params.axis, 1 + + inferShapes: (bottoms, tops) => + unless tops?[0]? then return + @slicePoint = getParameterAsArray @slicePoint, tops.length-1, 'slice_point' + @checkParameters bottoms, tops + firstInputShape = bottoms[0].shape + for i in [0...tops.length-1] + tops[i].shape = firstInputShape[..] + tops[i].shape[@axis] = @slicePoint[i] + tops[tops.length-1].shape = firstInputShape[..] + tops[tops.length-1].shape[@axis] = firstInputShape[@axis] - @slicePoint[@slicePoint.length-1] + + checkParameters: (bottoms, tops) => + unless bottoms?[0]? + throw 'Slice layer must have at least one bottom blob.' + unless tops?[1]? + throw 'Slice layer must have at least two top blob.' + +layers.Permute = +class @PermuteLayer + constructor: (attribs) -> + params = attribs?.permute_param + @order = params?.order + + inferShapes: (bottoms, tops) => + @order = getParameterAsArray @order, bottoms[0].shape.length, 'order' + firstInputShape = bottoms[0].shape + top = tops[0] + bottom = bottoms[0] + top.shape = firstInputShape[..] + for i in [0...@order.length] + top.shape[i] = bottom.shape[@order[i]] + +layers.Flatten = +class @FlattenLayer + constructor: (attribs) -> + params = attribs?.flatten_param + @axis = getValueOrDefault params.axis, 1 + + inferShapes: (bottoms, tops) => + outputShape = bottoms[0].shape + top = tops[0] + top.shape = outputShape[0...@axis+1] + for i in [@axis+1...outputShape.length] + top.shape[@axis] *= outputShape[i] + +layers.PriorBox = +class @PriorBoxLayer + constructor: (attribs) -> + params = attribs?.prior_box_param + @min_size = params?.min_size + @max_size = params?.max_size + @aspect_ratio = params?.aspect_ratio + @flip = params?.flip + + inferShapes: (bottoms, tops) => + min_size_length = getParameterLength @min_size + max_size_length = getParameterLength @max_size + aspect_ratio_param_length = getParameterLength @aspect_ratio + aspect_ratios = [1.0] + if aspect_ratio_param_length == 1 + ar = @aspect_ratio + already_exist = false + for j in aspect_ratios.length + if Math.abs(ar-aspect_ratios[j]) < 1e-6 + already_exist = true + break + if already_exist != true + aspect_ratios.push(ar) + if @flip + aspect_ratios.push(1.0/ar) + else + for i in @aspect_ratio + ar = i + already_exist = false + for j in aspect_ratios.length + if Math.abs(ar-aspect_ratios[j]) < 1e-6 + already_exist = true + break + if already_exist != true + aspect_ratios.push(ar) + if @flip + aspect_ratios.push(1.0/ar) + aspect_ratio_length = aspect_ratios.length + outputShape = bottoms[0].shape + height = bottoms[0].shape[2] + width = bottoms[0].shape[3] + num_priors = aspect_ratio_length * min_size_length + max_size_length + tops[0].shape = outputShape[0...3] + tops[0].shape[0] = 1 + tops[0].shape[1] = 2 + tops[0].shape[2] = height * width * num_priors * 4 + +layers.Reshape = +class @ReshapeLayer + constructor: (attribs) -> + params = attribs?.reshape_param + @shape = params?.shape + + inferShapes: (bottoms, tops) => + dim_length = getParameterLength @shape.dim + dim = getParameterAsArray @shape.dim, dim_length, 'dim' + outputShape = bottoms[0].shape + sum = 1 + for i in [0...bottoms[0].shape.length] + sum *= bottoms[0].shape[i] + tops[0].shape = outputShape[0...dim_length] + other_sum = 1 + for i in [0...dim_length] + if dim[i] != 0 and dim[i] != -1 + tops[0].shape[i] = dim[i] + if dim[i] != -1 + other_sum *= tops[0].shape[i] + for i in [0...dim_length] + if dim[i] == -1 + tops[0].shape[i] = sum / other_sum + +layers.Tiling = +class @TilingLayer + constructor: (attribs) -> + params = attribs?.tiling_param + @tile_dim = params?.tile_dim + + inferShapes: (bottoms, tops) => + @checkParameters bottoms, tops + outputShape = bottoms[0].shape + channels = bottoms[0].shape[1] + height = bottoms[0].shape[2] + width = bottoms[0].shape[3] + tops[0].shape = outputShape + tops[0].shape[1] = channels / (@tile_dim * @tile_dim) + tops[0].shape[2] = height * @tile_dim + tops[0].shape[3] = width * @tile_dim + + checkParameters: (bottoms, tops) => + unless @tile_dim? + throw 'tile_dim must be specified.' + unless @tile_dim > 0 + throw 'tile_dim must be positive.' + unless bottoms[0].shape[1] % (@tile_dim * @tile_dim) == 0 + throw 'The number of input channels for tiling layer must be multiples of the tile_dim.' + +layers.Normalize = +class @NormalizeLayer + constructor: (attribs) -> + params = attribs?.norm_param + @across_spatial = params?.across_spatial + @channel_shared = params?.channel_shared + + inferShapes: (bottoms, tops) => + outputShape = bottoms[0].shape + tops[0].shape = outputShape + layers.Eltwise = class @EltwiseLayer inferShapes: (bottoms, tops) => @@ -330,6 +498,31 @@ class @EltwiseLayer "#{shapesToString(inputShapes)}. " + "All axes must have the same sizes." +layers.Axpy = +class @AxpyLayer + inferShapes: (bottoms, tops) => + unless tops?[0]? then return + @checkParameters bottoms, tops + firstInputShape = bottoms[1].shape + tops[0].shape = firstInputShape[..] + + checkParameters: (bottoms, tops) => + if bottoms?.length != 3 + throw 'Axpy layer must have three inputs.' + inputShapes = (bottom.shape for bottom in bottoms) + firstShape = inputShapes[0] + if inputShapes[0][0] != inputShapes[1][0] + throw "InputShapes 0 and 1 at 0 axe must have the same sizes." + if inputShapes[0][1] != inputShapes[1][1] + throw "InputShapes 0 and 1 at 1 axe must have the same sizes." + if inputShapes[0].length == 4 + if inputShapes[0][2] != 1 or inputShapes[0][3] != 1 + throw "InputShapes 0 at 2、3 axe must be 1." + unless areShapesEqual inputShapes[1], inputShapes[2] + throw "Axpy layer received incorrect input shapes: " + + "#{shapesToString(inputShapes)}. " + + "InputShapes 1 and 2 at all axes must have the same sizes." + layers.Crop = class @CropLayer constructor: (attribs) -> @@ -348,6 +541,61 @@ class @CropLayer if bottoms?.length != 2 throw 'Crop layer must have exactly two bottom blobs.' +layers.Interp = +class @InterpLayer + constructor: (attribs) -> + @params = attribs.interp_param + @height = getValueOrDefault @params?.height, 0 + @width = getValueOrDefault @params?.width, 0 + @zoom_factor = getValueOrDefault @params?.zoom_factor, 1 + @shrink_factor = getValueOrDefault @params?.shrink_factor, 1 + @pad_beg = getValueOrDefault @params?.pad_beg, 0 + @pad_end = getValueOrDefault @params?.pad_end, 0 + + inferShapes: (bottoms, tops) => + @checkParameters bottoms, tops + outputShape = bottoms[0].shape + height_in = bottoms[0].shape[2] + width_in = bottoms[0].shape[3] + tops[0].shape = outputShape + height_in_eff = height_in + @pad_beg + @pad_end + width_in_eff = width_in + @pad_beg + @pad_end + if (@params.shrink_factor?) and (not @params.zoom_factor?) + height_out = (height_in_eff - 1) / @shrink_factor + 1; + width_out = (width_in_eff - 1) / @shrink_factor + 1; + else if (not @params.shrink_factor?) and (@params.zoom_factor?) + height_out = height_in_eff + (height_in_eff - 1) * (@zoom_factor - 1); + width_out = width_in_eff + (width_in_eff - 1) * (@zoom_factor - 1); + else if @params.height? and @params.width? + height_out = @height; + width_out = @width; + else if (@params.shrink_factor?) and (@params.zoom_factor?) + height_out = (height_in_eff - 1) / @shrink_factor + 1; + width_out = (width_in_eff - 1) / @shrink_factor + 1; + height_out = height_out + (height_out - 1) * (@zoom_factor - 1); + width_out = width_out + (width_out - 1) * (@zoom_factor - 1); + + unless height_in_eff > 0 + throw 'height should be positive.' + unless width_in_eff > 0 + throw 'width should be positive.' + unless height_out > 0 + throw 'height should be positive.' + unless width_out > 0 + throw 'width should be positive.' + + tops[0].shape[2] = height_out + tops[0].shape[3] = width_out + + checkParameters: (bottoms, tops) => + if @params.shrink_factor? + unless @shrink_factor >= 1 + throw 'shrink_factor must be positive.' + if @params.zoom_factor? + unless @zoom_factor >= 1 + throw 'zoom_factor must be positive.' + + isLossLayer = (layerType) -> /loss/i.test layerType @@ -372,6 +620,8 @@ isUniformLayer = (lt) -> (/lrn/i.test lt) or (/dropout/i.test lt) or (/batchnorm/i.test lt) or + (/groupnorm/i.test lt) or + (/bn/i.test lt) or (/mvn/i.test lt) or (/softmax/i.test lt) diff --git a/worklog.txt b/worklog.txt new file mode 100644 index 0000000..00b3329 --- /dev/null +++ b/worklog.txt @@ -0,0 +1,18 @@ +------------------netscope------------------ +netscope\src\caffe\layers.coffee +netscope\lib\caffe\layers.js +netscope\assets\js\netscope.js +【node.js command】coffee --compile --output lib/ src/ + +------------------apache-------------------- +Start apache in a DOS box: + +>httpd.exe + +Install as a service: + +>httpd.exe -k install + +ApacheMonitor: + +Double click ApacheMonitor.exe, or put it in your Startup folder. \ No newline at end of file