diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..47fa8d73 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,29 @@ +name: build + +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: "0 0 * * *" + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + node-version: [16] + os: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - name: Install dependencies + run: npm install + - name: Build + run: npm run build diff --git a/.gitignore b/.gitignore index 5e9d8d61..75f3ff7c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,11 @@ node_modules public/bundle.* package-lock.json public/assets/js/bundle.* +public/assets/js/ public/assets/css/bundle.* *.swp yarn.lock dist/ -deploy-gh-page.sh local-build/ tiny-vgg/data/ +pnpm-lock.yaml \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 63c5ac9c..00000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: node_js -node_js: - - lts/* -install: - - npm install -script: - - npm run build diff --git a/README.md b/README.md index 15986179..41e50693 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,17 @@ An interactive visualization system designed to help non-experts learn about Convolutional Neural Networks (CNNs) -[![Build Status](https://travis-ci.com/poloclub/cnn-explainer.svg?branch=master)](https://travis-ci.com/poloclub/cnn-explainer) +[![build](https://github.com/poloclub/cnn-explainer/workflows/build/badge.svg)](https://github.com/poloclub/cnn-explainer/actions) [![arxiv badge](https://img.shields.io/badge/arXiv-2004.15004-red)](http://arxiv.org/abs/2004.15004) +[![DOI:10.1109/TVCG.2020.3030418](https://img.shields.io/badge/DOI-10.1109/TVCG.2020.3030418-blue)](https://doi.org/10.1109/TVCG.2020.3030418) - + For more information, check out our manuscript: [**CNN Explainer: Learning Convolutional Neural Networks with Interactive Visualization**](https://arxiv.org/abs/2004.15004). Wang, Zijie J., Robert Turko, Omar Shaikh, Haekyu Park, Nilaksh Das, Fred Hohman, Minsuk Kahng, and Duen Horng Chau. -arXiv preprint 2020. arXiv:2004.15004. - +*IEEE Transactions on Visualization and Computer Graphics (TVCG), 2020.* ## Live Demo @@ -22,7 +22,7 @@ For a live demo, visit: http://poloclub.github.io/cnn-explainer/ Clone or download this repository: -``` +```bash git clone git@github.com:poloclub/cnn-explainer.git # use degit if you don't want to download commit histories @@ -31,32 +31,33 @@ degit poloclub/cnn-explainer Install the dependencies: -``` +```bash npm install ``` Then run CNN Explainer: -``` +```bash npm run dev ``` -Navigate to [localhost:5000](https://localhost:5000). You should see CNN Explainer running in your broswer :) +Navigate to [localhost:3000](https://localhost:3000). You should see CNN Explainer running in your broswer :) To see how we trained the CNN, visit the directory [`./tiny-vgg/`](tiny-vgg). +If you want to use CNN Explainer with your own CNN model or image classes, see [#8](/../../issues/8) and [#14](/../../issues/14). ## Credits -CNN Explainer was created by +CNN Explainer was created by Jay Wang, -Robert Turko, +Robert Turko, Omar Shaikh, Haekyu Park, Nilaksh Das, Fred Hohman, Minsuk Kahng, and Polo Chau, -which was the result of a research collaboration between +which was the result of a research collaboration between Georgia Tech and Oregon State. We thank @@ -65,27 +66,24 @@ We thank [Kantwon Rogers](https://www.kantwon.com), and the [Georgia Tech Visualization Lab](http://vis.gatech.edu) for their support and constructive feedback. - + ## Citation -``` + +```bibTeX @article{wangCNNExplainerLearning2020, title = {{{CNN Explainer}}: {{Learning Convolutional Neural Networks}} with {{Interactive Visualization}}}, shorttitle = {{{CNN Explainer}}}, author = {Wang, Zijie J. and Turko, Robert and Shaikh, Omar and Park, Haekyu and Das, Nilaksh and Hohman, Fred and Kahng, Minsuk and Chau, Duen Horng}, - year = {2020}, - month = apr, - archivePrefix = {arXiv}, - eprint = {2004.15004}, - eprinttype = {arxiv}, - journal = {arXiv:2004.15004 [cs]} + journal={IEEE Transactions on Visualization and Computer Graphics (TVCG)}, + year={2020}, + publisher={IEEE} } ``` ## License + The software is available under the [MIT License](https://github.com/poloclub/cnn-explainer/blob/master/LICENSE). ## Contact -If you have any questions, feel free to [open an issue](https://github.com/poloclub/cnn-explainer/issues/new/choose) or contact [Jay Wang](https://www.zijie.wang). - - +If you have any questions, feel free to [open an issue](https://github.com/poloclub/cnn-explainer/issues/new/choose) or contact [Jay Wang](https://zijie.wang). diff --git a/deploy-gh-page.sh b/deploy-gh-page.sh new file mode 100644 index 00000000..92f96295 --- /dev/null +++ b/deploy-gh-page.sh @@ -0,0 +1,5 @@ +npm run build +cp -r ./public/assets ./dist +cp -r ./public/bundle* ./dist +cp -r ./public/global.css ./dist +npx gh-pages -m "Deploy $(git log '--format=format:%H' master -1)" -d ./dist \ No newline at end of file diff --git a/package.json b/package.json index daa172c7..570e7251 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,14 @@ "version": "1.0.0", "devDependencies": { "@rollup/plugin-replace": "^2.3.2", + "gh-pages": "^6.0.0", "rollup": "^1.27.13", "rollup-plugin-commonjs": "^10.0.0", "rollup-plugin-livereload": "^1.0.0", "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-svelte": "^5.1.1", + "rollup-plugin-svelte": "~6.1.1", "rollup-plugin-terser": "^5.1.3", - "svelte": "^3.16.4" + "svelte": "^3.31.0" }, "dependencies": { "@tensorflow/tfjs": "^1.4.0", @@ -19,6 +20,7 @@ "build": "rollup -c", "dev": "rollup -c -w", "start": "sirv public --single", - "start:dev": "sirv public --single --dev" + "start:dev": "sirv public --single --dev --port 3000", + "deploy": "npx" } } diff --git a/public/assets/figures/preview.png b/public/assets/figures/preview.png new file mode 100644 index 00000000..0a63099a Binary files /dev/null and b/public/assets/figures/preview.png differ diff --git a/public/assets/figures/relu_graph.png b/public/assets/figures/relu_graph.png new file mode 100644 index 00000000..3db6ddbd Binary files /dev/null and b/public/assets/figures/relu_graph.png differ diff --git a/public/assets/figures/relu_graph.svg b/public/assets/figures/relu_graph.svg deleted file mode 100644 index 28b9d559..00000000 --- a/public/assets/figures/relu_graph.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - -10 - - - - - - -5 - - - - - 5 - - - - 10 - - - - - -10 - - - - - - -5 - - - - - 5 - - - - 10 - - - - - - - - - x - - - y - - - - diff --git a/public/assets/css/global.css b/public/global.css similarity index 100% rename from public/assets/css/global.css rename to public/global.css diff --git a/public/index.html b/public/index.html index 56cdf58c..ef28dbba 100644 --- a/public/index.html +++ b/public/index.html @@ -1,34 +1,91 @@ - + - - - + + + - CNN Explainer + + + - - - + + + + + + - - - - - - - - + + + + + + + + - + CNN Explainer + + + + + + + + + + + + + + + + + - + - - + diff --git a/rollup.config.js b/rollup.config.js index 185aa8bf..8be5c0a0 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -14,7 +14,7 @@ export default { sourcemap: true, format: 'iife', name: 'app', - file: 'public/assets/js/bundle.js' + file: 'public/bundle.js' }, plugins: [ svelte({ @@ -23,7 +23,7 @@ export default { // we'll extract any component CSS out into // a separate file — better for performance css: css => { - css.write('public/assets/css/bundle.css'); + css.write('bundle.css'); } }), diff --git a/src/App.svelte b/src/App.svelte index b2b41d9d..7817a8d1 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,12 +1,21 @@
-
- + +
+
diff --git a/src/Header.svelte b/src/Header.svelte index 87de69eb..24c46682 100644 --- a/src/Header.svelte +++ b/src/Header.svelte @@ -84,7 +84,7 @@
- + pdf icon
diff --git a/src/article/Article.svelte b/src/article/Article.svelte index f6581c76..e17aba47 100644 --- a/src/article/Article.svelte +++ b/src/article/Article.svelte @@ -168,7 +168,7 @@

    -
  1. Padding is often necessary when the kernel extends beyond the activation map. Padding conserves data at the borders of activation maps, which leads to better performance, and it can help preserve the input's spatial size, which allows an architecture designer to build depper, higher performing networks. There exist many padding techniques, but the most commonly used approach is zero-padding because of its performance, simplicity, and computational efficiency. The technique involves adding zeros symmetrically around the edges of an input. This approach is adopted by many high-performing CNNs such as AlexNet.
  2. +
  3. Padding is often necessary when the kernel extends beyond the activation map. Padding conserves data at the borders of activation maps, which leads to better performance, and it can help preserve the input's spatial size, which allows an architecture designer to build deeper, higher performing networks. There exist many padding techniques, but the most commonly used approach is zero-padding because of its performance, simplicity, and computational efficiency. The technique involves adding zeros symmetrically around the edges of an input. This approach is adopted by many high-performing CNNs such as AlexNet.
  4. Kernel size, often also referred to as filter size, refers to the dimensions of the sliding window over the input. Choosing this hyperparameter has a massive impact on the image classification task. For example, small kernel sizes are able to extract a much larger amount of information containing highly local features from the input. As you can see on the visualization above, a smaller kernel size also leads to a smaller reduction in layer dimensions, which allows for a deeper architecture. Conversely, a large kernel size extracts less information, which leads to a faster reduction in layer dimensions, often leading to worse performance. Large kernels are better suited to extract features that are larger. At the end of the day, choosing an appropriate kernel size will be dependent on your task and dataset, but generally, smaller kernel sizes lead to better performance for the image classification task because an architecture designer is able to stack more and more layers together to learn more and more complex features!
  5. Stride indicates how many pixels the kernel should be shifted over at a time. For example, as described in the convolutional layer example above, Tiny VGG uses a stride of 1 for its convolutional layers, which means that the dot product is performed on a 3x3 window of the input to yield an output value, then is shifted to the right by one pixel for every subsequent operation. The impact stride has on a CNN is similar to kernel size. As stride is decreased, more features are learned because more data is extracted, which also leads to larger output layers. On the contrary, as stride is increased, this leads to more limited feature extraction and smaller output layer dimensions. One responsibility of the architecture designer is to ensure that the kernel slides across the input symmetrically when implementing a CNN. Use the hyperparameter visualization above to alter stride on various input/kernel dimensions to understand this constraint!
@@ -178,10 +178,10 @@ Neural networks are extremely prevalent in modern technology—because they are so accurate! The highest performing CNNs today consist of an absurd amount of layers, which are able to learn more and more features. Part of the reason these groundbreaking CNNs are able to achieve such tremendous accuracies is because of their non-linearity. ReLU applies much-needed non-linearity into the model. Non-linearity is necessary to produce non-linear decision boundaries, so that the output cannot be written as a linear combination of the inputs. If a non-linear activation function was not present, deep CNN architectures would devolve into a single, equivalent convolutional layer, which would not perform nearly as well. The ReLU activation function is specifically used as a non-linear activation function, as opposed to other non-linear functions such as Sigmoid because it has been empirically observed that CNNs using ReLU are faster to train than their counterparts.

- The ReLU activation function is a one-to-one mathematical operation: {reluEquation} + The ReLU activation function is an elementwise mathematical operation: {reluEquation}

- relu graph + relu graph
Figure 3. The ReLU activation function graphed, which disregards all negative data.
@@ -286,4 +286,4 @@ Georgia Tech and Oregon State. We thank Anmol Chhabria, Kaan Sancak, Kantwon Rogers, and the Georgia Tech Visualization Lab for their support and constructive feedback. This work was supported in part by NSF grants IIS-1563816, CNS-1704701, NASA NSTRF, DARPA GARD, gifts from Intel, NVIDIA, Google, Amazon.

- \ No newline at end of file + diff --git a/src/detail-view/Dataview.svelte b/src/detail-view/Dataview.svelte index 0c9b7449..6e94b581 100644 --- a/src/detail-view/Dataview.svelte +++ b/src/detail-view/Dataview.svelte @@ -44,14 +44,14 @@ .attr("width", function(d) { return d.width; }) .attr("height", function(d) { return d.height; }) .style("opacity", 0.8) - .style("fill", function(d) { + .style("fill", function(d) { let normalizedValue = d.text; if (isInputLayer){ normalizedValue = 1 - d.text; } else { normalizedValue = (d.text + dataRange / 2) / dataRange; } - return colorScale(normalizedValue); + return colorScale(normalizedValue); }) .on('mouseover', function(d) { if (data.length != outputLength) { @@ -74,7 +74,7 @@ .style("font-size", Math.floor(constraint / textConstraintDivisor) + "px") .attr("x", function(d) { return d.x + d.width / 2; }) .attr("y", function(d) { return d.y + d.height / 2; }) - .style("fill", function(d) { + .style("fill", function(d) { let normalizedValue = d.text; if (isInputLayer){ normalizedValue = 1 - d.text; @@ -89,7 +89,9 @@ }) .style("text-anchor", "middle") .style("dominant-baseline", "middle") - .text(function(d) { return d.text; }) + .text(function(d) { + return d.text.toString().replace('-', '-'); + }) } } @@ -97,7 +99,7 @@ if (data != oldData) { redraw(); oldData = data; - } + } if (highlights != oldHighlight) { var grid = d3.select(grid_final).select('#grid').select("svg") diff --git a/src/overview/Modal.svelte b/src/overview/Modal.svelte index e3cce2a2..004182e1 100644 --- a/src/overview/Modal.svelte +++ b/src/overview/Modal.svelte @@ -178,8 +178,8 @@