diff --git a/package-lock.json b/package-lock.json
index 9a9a1e7..423084c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -74,9 +74,9 @@
       "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg=="
     },
     "ajv": {
-      "version": "5.5.1",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.1.tgz",
-      "integrity": "sha1-s4u4h22ehr7plJVqBOch6IskjrI=",
+      "version": "5.5.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
+      "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
       "requires": {
         "co": "4.6.0",
         "fast-deep-equal": "1.0.0",
@@ -330,7 +330,7 @@
       "integrity": "sha512-C9yv/UF3X+eJTi/zvfxuyfxmLibYrntpF3qoJYrMeQwgUJOZrZvpJiMG2FMQ3qnhWtF/be4pYONBBw95ZGe3vA==",
       "requires": {
         "browserslist": "2.10.0",
-        "caniuse-lite": "1.0.30000783",
+        "caniuse-lite": "1.0.30000784",
         "normalize-range": "0.1.2",
         "num2fraction": "1.2.2",
         "postcss": "6.0.14",
@@ -1399,8 +1399,8 @@
       "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.10.0.tgz",
       "integrity": "sha512-WyvzSLsuAVPOjbljXnyeWl14Ae+ukAT8MUuagKVzIDvwBxl4UAwD1xqtyQs2eWYPGUKMeC3Ol62goqYuKqTTcw==",
       "requires": {
-        "caniuse-lite": "1.0.30000783",
-        "electron-to-chromium": "1.3.28"
+        "caniuse-lite": "1.0.30000784",
+        "electron-to-chromium": "1.3.30"
       }
     },
     "bser": {
@@ -1495,7 +1495,7 @@
       "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
       "requires": {
         "browserslist": "1.7.7",
-        "caniuse-db": "1.0.30000783",
+        "caniuse-db": "1.0.30000784",
         "lodash.memoize": "4.1.2",
         "lodash.uniq": "4.5.0"
       },
@@ -1505,21 +1505,21 @@
           "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
           "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
           "requires": {
-            "caniuse-db": "1.0.30000783",
-            "electron-to-chromium": "1.3.28"
+            "caniuse-db": "1.0.30000784",
+            "electron-to-chromium": "1.3.30"
           }
         }
       }
     },
     "caniuse-db": {
-      "version": "1.0.30000783",
-      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000783.tgz",
-      "integrity": "sha1-FrMNRyZqT1FcxprgMWtnDJYDzb4="
+      "version": "1.0.30000784",
+      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000784.tgz",
+      "integrity": "sha1-G+lQEtlInHcZB0+BruV9vf/mNhs="
     },
     "caniuse-lite": {
-      "version": "1.0.30000783",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000783.tgz",
-      "integrity": "sha1-m1SZ+xtQPSNF0SqmuGEoUvQnb/0="
+      "version": "1.0.30000784",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000784.tgz",
+      "integrity": "sha1-EpztdOmhKApEGIC2zSvOMO9Z5sA="
     },
     "capture-stack-trace": {
       "version": "1.0.0",
@@ -2130,7 +2130,7 @@
           "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
           "requires": {
             "browserslist": "1.7.7",
-            "caniuse-db": "1.0.30000783",
+            "caniuse-db": "1.0.30000784",
             "normalize-range": "0.1.2",
             "num2fraction": "1.2.2",
             "postcss": "5.2.18",
@@ -2142,8 +2142,8 @@
           "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
           "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
           "requires": {
-            "caniuse-db": "1.0.30000783",
-            "electron-to-chromium": "1.3.28"
+            "caniuse-db": "1.0.30000784",
+            "electron-to-chromium": "1.3.30"
           }
         },
         "has-flag": {
@@ -2269,9 +2269,9 @@
       "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
     },
     "deeplearn": {
-      "version": "0.3.12",
-      "resolved": "https://registry.npmjs.org/deeplearn/-/deeplearn-0.3.12.tgz",
-      "integrity": "sha512-356ulx3zqxc4pz+v3ZzBRb4KxgtA46CH8vGSgpzEyXcZ6FM4D4l9mEfcMCRYToSsR149kUyasnD2V84oDKyjTg==",
+      "version": "0.3.15",
+      "resolved": "https://registry.npmjs.org/deeplearn/-/deeplearn-0.3.15.tgz",
+      "integrity": "sha512-pWqvolC8+t9g58XIz4GynBu6Aj1ZO2xSU4rZCpcxxeoE3BA0Cll5UeTZRHvO9lxn3ebEqOeB6ku9rZVDR4k6zQ==",
       "requires": {
         "seedrandom": "2.4.3"
       }
@@ -2509,10 +2509,18 @@
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
+    "electron-releases": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/electron-releases/-/electron-releases-2.1.0.tgz",
+      "integrity": "sha512-cyKFD1bTE/UgULXfaueIN1k5EPFzs+FRc/rvCY5tIynefAPqopQEgjr0EzY+U3Dqrk/G4m9tXSPuZ77v6dL/Rw=="
+    },
     "electron-to-chromium": {
-      "version": "1.3.28",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.28.tgz",
-      "integrity": "sha1-jdTmRYCGZE6fnwoc8y4qH53/2e4="
+      "version": "1.3.30",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.30.tgz",
+      "integrity": "sha512-zx1Prv7kYLfc4OA60FhxGbSo4qrEjgSzpo1/37i7l9ltXPYOoQBtjQxY9KmsgfHnBxHlBGXwLlsbt/gub1w5lw==",
+      "requires": {
+        "electron-releases": "2.1.0"
+      }
     },
     "elliptic": {
       "version": "6.4.0",
@@ -2638,9 +2646,9 @@
       }
     },
     "es6-promise": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz",
-      "integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng=="
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.2.tgz",
+      "integrity": "sha512-LSas5vsuA6Q4nEdf9wokY5/AJYXry98i0IzXsv49rYsgDGDNDPbqAYR1Pe23iFxygfbGZNR/5VrHXBCh2BhvUQ=="
     },
     "es6-set": {
       "version": "0.1.5",
@@ -2725,7 +2733,7 @@
       "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.10.0.tgz",
       "integrity": "sha512-MMVl8P/dYUFZEvolL8PYt7qc5LNdS2lwheq9BYa5Y07FblhcZqFyaUqlS8TW5QITGex21tV4Lk0a3fK8lsJIkA==",
       "requires": {
-        "ajv": "5.5.1",
+        "ajv": "5.5.2",
         "babel-code-frame": "6.26.0",
         "chalk": "2.3.0",
         "concat-stream": "1.6.0",
@@ -4430,7 +4438,7 @@
       "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
       "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
       "requires": {
-        "ajv": "5.5.1",
+        "ajv": "5.5.2",
         "har-schema": "2.0.0"
       }
     },
@@ -4555,9 +4563,9 @@
       "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
     },
     "html-minifier": {
-      "version": "3.5.7",
-      "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.7.tgz",
-      "integrity": "sha512-GISXn6oKDo7+gVpKOgZJTbHMCUI2TSGfpg/8jgencWhWJsvEmsvp3M8emX7QocsXsYznWloLib3OeSfeyb/ewg==",
+      "version": "3.5.8",
+      "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.8.tgz",
+      "integrity": "sha512-WX7D6PB9PFq05fZ1/CyxPUuyqXed6vh2fGOM80+zJT5wAO93D/cUjLs0CcbBFjQmlwmCgRvl97RurtArIpOnkw==",
       "requires": {
         "camel-case": "3.0.0",
         "clean-css": "4.1.9",
@@ -4566,7 +4574,7 @@
         "ncname": "1.0.0",
         "param-case": "2.1.1",
         "relateurl": "0.2.7",
-        "uglify-js": "3.2.2"
+        "uglify-js": "3.3.2"
       }
     },
     "html-webpack-plugin": {
@@ -4575,7 +4583,7 @@
       "integrity": "sha1-6Yf0IYU9O2k4yMTIFxhC5f0XryM=",
       "requires": {
         "bluebird": "3.5.1",
-        "html-minifier": "3.5.7",
+        "html-minifier": "3.5.8",
         "loader-utils": "0.2.17",
         "lodash": "4.17.4",
         "pretty-error": "2.1.1",
@@ -7154,8 +7162,8 @@
           "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
           "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
           "requires": {
-            "caniuse-db": "1.0.30000783",
-            "electron-to-chromium": "1.3.28"
+            "caniuse-db": "1.0.30000784",
+            "electron-to-chromium": "1.3.30"
           }
         },
         "has-flag": {
@@ -8577,7 +8585,7 @@
       "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
       "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
       "requires": {
-        "ajv": "5.5.1"
+        "ajv": "5.5.2"
       }
     },
     "seedrandom": {
@@ -9039,7 +9047,7 @@
       "integrity": "sha512-sKctdX+5hUxkqJ/1DM88ubQ+QRvyw7CnxWdk909N2DgvxMqc1gcQFrwL7zpVc87wFmCA/OvRQd0iMC2XdFopYg==",
       "requires": {
         "dom-urls": "1.1.0",
-        "es6-promise": "4.1.1",
+        "es6-promise": "4.2.2",
         "glob": "7.1.2",
         "lodash.defaults": "4.2.0",
         "lodash.template": "4.4.0",
@@ -9057,7 +9065,7 @@
       "requires": {
         "del": "2.2.2",
         "sw-precache": "5.2.0",
-        "uglify-js": "3.2.2"
+        "uglify-js": "3.3.2"
       }
     },
     "sw-toolbox": {
@@ -9079,7 +9087,7 @@
       "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
       "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
       "requires": {
-        "ajv": "5.5.1",
+        "ajv": "5.5.2",
         "ajv-keywords": "2.1.1",
         "chalk": "2.3.0",
         "lodash": "4.17.4",
@@ -9252,9 +9260,9 @@
       "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g=="
     },
     "uglify-js": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.2.2.tgz",
-      "integrity": "sha512-++1NO/zZIEdWf6cDIGceSJQPX31SqIpbVAHwFG5+240MtZqPG/NIPoinj8zlXQtAfMBqEt1Jyv2FiLP3n9gVhQ==",
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.2.tgz",
+      "integrity": "sha512-uZp2gduFfZDDfx0iIAmfKgRTANCooWcFjnFmJ2n8x/+RpBNk97lac1HU5wvZxWZCBbwHmTFDpWAsEhKnQpsM2A==",
       "requires": {
         "commander": "2.12.2",
         "source-map": "0.6.1"
@@ -9527,7 +9535,7 @@
       "requires": {
         "acorn": "5.2.1",
         "acorn-dynamic-import": "2.0.2",
-        "ajv": "5.5.1",
+        "ajv": "5.5.2",
         "ajv-keywords": "2.1.1",
         "async": "2.6.0",
         "enhanced-resolve": "3.4.1",
diff --git a/package.json b/package.json
index 1077a0a..17129e9 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
-    "deeplearn": "0.3.12",
+    "deeplearn": "0.3.15",
     "react": "^16.1.1",
     "react-dom": "^16.1.1",
     "react-scripts": "1.0.17"
diff --git a/src/neuralNetwork.js b/src/neuralNetwork.js
index 857553a..9f02dc0 100644
--- a/src/neuralNetwork.js
+++ b/src/neuralNetwork.js
@@ -4,14 +4,15 @@ import {
   Graph,
   Session,
   SGDOptimizer,
-  NDArrayMathGPU,
+  ENV,
+  NDArrayMath,
   CostReduction,
 } from 'deeplearn';
 
-// Encapsulates math operations on the CPU and GPU.
-const math = new NDArrayMathGPU();
-
 class ColorAccessibilityModel {
+  // Encapsulates math operations on the CPU and GPU.
+  math = ENV.math;
+
   // Runs training.
   session;
 
@@ -47,27 +48,32 @@ class ColorAccessibilityModel {
     this.predictionTensor = this.createFullyConnectedLayer(graph, fullyConnectedLayer, 3, 2);
     this.costTensor = graph.meanSquaredCost(this.targetTensor, this.predictionTensor);
 
-    this.session = new Session(graph, math);
+    this.session = new Session(graph, this.math);
 
     this.prepareTrainingSet(trainingSet);
   }
 
   prepareTrainingSet(trainingSet) {
-    math.scope(() => {
-      const { rawInputs, rawTargets } = trainingSet;
+    const oldMath = ENV.math;
+    const safeMode = false;
+    const math = new NDArrayMath('cpu', safeMode);
+    ENV.setMath(math);
 
-      const inputArray = rawInputs.map(v => Array1D.new(this.normalizeColor(v)));
-      const targetArray = rawTargets.map(v => Array1D.new(v));
+    const { rawInputs, rawTargets } = trainingSet;
 
-      const shuffledInputProviderBuilder = new InCPUMemoryShuffledInputProviderBuilder([ inputArray, targetArray ]);
-      const [ inputProvider, targetProvider ] = shuffledInputProviderBuilder.getInputProviders();
+    const inputArray = rawInputs.map(v => Array1D.new(this.normalizeColor(v)));
+    const targetArray = rawTargets.map(v => Array1D.new(v));
 
-      // Maps tensors to InputProviders.
-      this.feedEntries = [
-        { tensor: this.inputTensor, data: inputProvider },
-        { tensor: this.targetTensor, data: targetProvider },
-      ];
-    });
+    const shuffledInputProviderBuilder = new InCPUMemoryShuffledInputProviderBuilder([ inputArray, targetArray ]);
+    const [ inputProvider, targetProvider ] = shuffledInputProviderBuilder.getInputProviders();
+
+    // Maps tensors to InputProviders.
+    this.feedEntries = [
+      { tensor: this.inputTensor, data: inputProvider },
+      { tensor: this.targetTensor, data: targetProvider },
+    ];
+
+    ENV.setMath(oldMath);
   }
 
   train(step, computeCost) {
@@ -77,7 +83,7 @@ class ColorAccessibilityModel {
 
     // Train one batch.
     let costValue;
-    math.scope(() => {
+    this.math.scope(() => {
       const cost = this.session.train(
         this.costTensor,
         this.feedEntries,
@@ -98,7 +104,7 @@ class ColorAccessibilityModel {
   predict(rgb) {
     let classifier = [];
 
-    math.scope(() => {
+    this.math.scope(() => {
       const mapping = [{
         tensor: this.inputTensor,
         data: Array1D.new(this.normalizeColor(rgb)),