aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--bower.BUILD326
-rw-r--r--gif.BUILD42
-rw-r--r--grpc.BUILD1
-rw-r--r--tensorflow/contrib/cmake/setup.py1
-rw-r--r--tensorflow/contrib/cmake/tf_python.cmake105
-rw-r--r--tensorflow/contrib/ios_examples/README.md55
-rw-r--r--tensorflow/contrib/ios_examples/camera/CameraExampleViewController.h2
-rw-r--r--tensorflow/contrib/ios_examples/camera/CameraExampleViewController.mm62
-rw-r--r--tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj12
-rw-r--r--tensorflow/contrib/ios_examples/camera/tensorflow_utils.h23
-rw-r--r--tensorflow/contrib/ios_examples/camera/tensorflow_utils.mm143
-rw-r--r--tensorflow/contrib/ios_examples/simple/RunModelViewController.mm2
-rw-r--r--tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj10
-rw-r--r--tensorflow/contrib/layers/python/layers/feature_column.py4
-rw-r--r--tensorflow/contrib/layers/python/layers/feature_column_ops.py2
-rw-r--r--tensorflow/contrib/layers/python/layers/initializers.py2
-rw-r--r--tensorflow/contrib/layers/python/layers/initializers_test.py27
-rw-r--r--tensorflow/contrib/layers/python/layers/layers.py73
-rw-r--r--tensorflow/contrib/learn/BUILD1
-rw-r--r--tensorflow/contrib/learn/python/learn/datasets/base.py20
-rw-r--r--tensorflow/contrib/learn/python/learn/models.py27
-rw-r--r--tensorflow/contrib/learn/python/learn/ops/__init__.py2
-rw-r--r--tensorflow/contrib/learn/python/learn/ops/autoencoder_ops.py58
-rw-r--r--tensorflow/contrib/makefile/Makefile6
-rwxr-xr-xtensorflow/contrib/makefile/compile_ios_protobuf.sh4
-rwxr-xr-xtensorflow/contrib/makefile/compile_ios_tensorflow.sh14
-rw-r--r--tensorflow/contrib/metrics/python/ops/histogram_ops.py5
-rw-r--r--tensorflow/contrib/quantization/tools/quantize_graph.py4
-rw-r--r--tensorflow/contrib/rnn/python/ops/rnn_cell.py8
-rw-r--r--tensorflow/core/BUILD3
-rw-r--r--tensorflow/core/kernels/conv_ops_using_gemm.cc10
-rw-r--r--tensorflow/core/kernels/cwise_op_gpu_logical_and.cu.cc2
-rw-r--r--tensorflow/core/kernels/cwise_op_gpu_logical_or.cu.cc2
-rw-r--r--tensorflow/core/kernels/cwise_ops_common.h14
-rw-r--r--tensorflow/core/kernels/cwise_ops_gpu_common.cu.h4
-rw-r--r--tensorflow/core/ops/image_ops.cc2
-rw-r--r--tensorflow/core/platform/default/logging.h17
-rw-r--r--tensorflow/core/protobuf/config.proto2
-rw-r--r--tensorflow/core/public/version.h2
-rw-r--r--tensorflow/examples/android/build.gradle2
-rw-r--r--tensorflow/examples/skflow/text_classification_character_cnn.py8
-rw-r--r--tensorflow/examples/tutorials/deepdream/README.md2
-rw-r--r--tensorflow/examples/tutorials/deepdream/deepdream.ipynb2
-rw-r--r--tensorflow/examples/tutorials/word2vec/word2vec_basic.py2
-rw-r--r--tensorflow/g3doc/api_docs/cc/ClassTensorShapeUtils.md6
-rw-r--r--tensorflow/g3doc/api_docs/cc/StructTF_Buffer.md25
-rw-r--r--tensorflow/g3doc/api_docs/cc/index.md1
-rw-r--r--tensorflow/g3doc/api_docs/python/client.md2
-rw-r--r--tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.nn.conv2d_transpose.md4
-rw-r--r--tensorflow/g3doc/get_started/os_setup.md255
-rw-r--r--tensorflow/g3doc/how_tos/adding_an_op/index.md5
-rw-r--r--tensorflow/g3doc/how_tos/reading_data/index.md4
-rw-r--r--tensorflow/models/rnn/ptb/ptb_word_lm.py3
-rw-r--r--tensorflow/models/rnn/translate/data_utils.py2
-rw-r--r--tensorflow/python/ops/array_ops.py7
-rw-r--r--tensorflow/python/ops/init_ops.py5
-rw-r--r--tensorflow/python/ops/math_ops.py2
-rw-r--r--tensorflow/python/ops/rnn_cell.py2
-rw-r--r--tensorflow/python/ops/special_math_ops.py74
-rw-r--r--tensorflow/python/ops/special_math_ops_test.py107
-rw-r--r--tensorflow/python/training/sync_replicas_optimizer.py5
-rw-r--r--tensorflow/tensorboard/components/tf-option-selector/tf-option-selector.html77
-rw-r--r--tensorflow/tensorboard/components/vz-projector/vz-projector-data-loader.html144
-rw-r--r--tensorflow/tensorboard/components/vz-projector/vz-projector-data-loader.ts500
-rw-r--r--tensorflow/tools/dist_test/Dockerfile2
-rw-r--r--tensorflow/tools/dist_test/Dockerfile.local2
-rwxr-xr-xtensorflow/tools/dist_test/scripts/dist_mnist_test.sh4
-rw-r--r--tensorflow/tools/dist_test/server/Dockerfile2
-rw-r--r--tensorflow/tools/dist_test/server/Dockerfile.test2
-rw-r--r--tensorflow/tools/docker/Dockerfile2
-rw-r--r--tensorflow/tools/docker/Dockerfile.devel2
-rw-r--r--tensorflow/tools/docker/Dockerfile.devel-gpu2
-rw-r--r--tensorflow/tools/docker/Dockerfile.gpu2
-rw-r--r--tensorflow/tools/docker/notebooks/1_hello_tensorflow.ipynb1432
-rw-r--r--tensorflow/tools/docker/notebooks/2_getting_started.ipynb1668
-rw-r--r--tensorflow/tools/docker/notebooks/3_mnist_from_scratch.ipynb3743
-rw-r--r--tensorflow/tools/docs/gen_cc_md.py1
-rw-r--r--tensorflow/tools/gcs_test/Dockerfile2
-rwxr-xr-xtensorflow/tools/git/gen_git_source.py15
-rw-r--r--tensorflow/tools/pip_package/setup.py2
-rw-r--r--tensorflow/workspace.bzl7
-rw-r--r--third_party/gpus/crosstool/CROSSTOOL.tpl4
-rwxr-xr-xthird_party/gpus/crosstool/clang/bin/crosstool_wrapper_driver_is_not_gcc.tpl3
-rw-r--r--third_party/gpus/cuda_configure.bzl42
-rwxr-xr-xutil/python/python_config.sh18
86 files changed, 5555 insertions, 3755 deletions
diff --git a/README.md b/README.md
index 2ea8aef02a..98e5e02a8d 100644
--- a/README.md
+++ b/README.md
@@ -33,10 +33,10 @@ and discussion.**
People who are a little more adventurous can also try our nightly binaries:
-* Linux CPU-only: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave)) / [Python 3.4](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/)) / [Python 3.5](https://ci.tensorflow.org/view/Nightly/job/nightly-python35-linux-cpu/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-python35-linux-cpu/))
-* Linux GPU: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/)) / [Python 3.4](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/)) / [Python 3.5](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/))
-* Mac CPU-only: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac1-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac1-slave/)) / [Python 3](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac1-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac1-slave/))
-* Mac GPU: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-mac/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-mac/)) / [Python 3](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-mac/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-mac/))
+* Linux CPU-only: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave)) / [Python 3.4](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/)) / [Python 3.5](https://ci.tensorflow.org/view/Nightly/job/nightly-python35-linux-cpu/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-python35-linux-cpu/))
+* Linux GPU: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/)) / [Python 3.4](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/)) / [Python 3.5](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-linux-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/))
+* Mac CPU-only: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac1-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac1-slave/)) / [Python 3](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac1-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac1-slave/))
+* Mac GPU: [Python 2](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-mac/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-mac/)) / [Python 3](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-mac/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-mac-gpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-mac/))
* [Android](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-android/TF_BUILD_CONTAINER_TYPE=ANDROID,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=NO_PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=android-slave/lastSuccessfulBuild/artifact/bazel-out/local_linux/bin/tensorflow/examples/android/tensorflow_demo.apk) ([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-android/TF_BUILD_CONTAINER_TYPE=ANDROID,TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=NO_PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=android-slave/))
#### *Try your first TensorFlow program*
diff --git a/bower.BUILD b/bower.BUILD
index 9d961529d1..5440d7b95b 100644
--- a/bower.BUILD
+++ b/bower.BUILD
@@ -321,6 +321,41 @@ filegroup(
)
filegroup(
+ name = "numericjs",
+ srcs = [
+ "benchmark.html",
+ "benchmark2.html",
+ "demo.html",
+ "documentation.html",
+ "myworker.js",
+ "resources/style.css",
+ "resources/style-ie.css",
+ "src/documentation.html",
+ "src/numeric.js",
+ "src/quadprog.js",
+ "src/seedrandom.js",
+ "src/sparse2.js",
+ "src/svd.js",
+ "tools/XMLHttpRequest.js",
+ "tools/closurelib.js",
+ "tools/excanvas.min.js",
+ "tools/goog-require.js",
+ "tools/jquery.flot.image.js",
+ "tools/jquery.flot.image.min.js",
+ "tools/jquery.flot.js",
+ "tools/jquery.flot.min.js",
+ "tools/jquery-1.7.1.js",
+ "tools/jquery-1.7.1.min.js",
+ "tools/json2.js",
+ "tools/megalib.js",
+ "tools/mytest.html",
+ "tools/sylvester.js",
+ "tools/unit2.js",
+ "tools/workshop.html",
+ ],
+)
+
+filegroup(
name = "paper_behaviors",
srcs = [
"index.html",
@@ -582,6 +617,275 @@ filegroup(
)
filegroup(
+ name = "three_js",
+ srcs = [
+ "three.js-r77/build/three.js",
+ "three.js-r77/build/three.min.js",
+ "three.js-r77/examples/js/AnimationClipCreator.js",
+ "three.js-r77/examples/js/BlendCharacter.js",
+ "three.js-r77/examples/js/BlendCharacterGui.js",
+ "three.js-r77/examples/js/BufferGeometryUtils.js",
+ "three.js-r77/examples/js/Car.js",
+ "three.js-r77/examples/js/Cloth.js",
+ "three.js-r77/examples/js/CurveExtras.js",
+ "three.js-r77/examples/js/Detector.js",
+ "three.js-r77/examples/js/Encodings.js",
+ "three.js-r77/examples/js/GPUParticleSystem.js",
+ "three.js-r77/examples/js/Gyroscope.js",
+ "three.js-r77/examples/js/Half.js",
+ "three.js-r77/examples/js/ImprovedNoise.js",
+ "three.js-r77/examples/js/MD2Character.js",
+ "three.js-r77/examples/js/MD2CharacterComplex.js",
+ "three.js-r77/examples/js/MarchingCubes.js",
+ "three.js-r77/examples/js/Mirror.js",
+ "three.js-r77/examples/js/MorphAnimMesh.js",
+ "three.js-r77/examples/js/MorphAnimation.js",
+ "three.js-r77/examples/js/Ocean.js",
+ "three.js-r77/examples/js/Octree.js",
+ "three.js-r77/examples/js/PRNG.js",
+ "three.js-r77/examples/js/ParametricGeometries.js",
+ "three.js-r77/examples/js/RollerCoaster.js",
+ "three.js-r77/examples/js/ShaderGodRays.js",
+ "three.js-r77/examples/js/ShaderSkin.js",
+ "three.js-r77/examples/js/ShaderTerrain.js",
+ "three.js-r77/examples/js/ShaderToon.js",
+ "three.js-r77/examples/js/SimplexNoise.js",
+ "three.js-r77/examples/js/SimulationRenderer.js",
+ "three.js-r77/examples/js/SkyShader.js",
+ "three.js-r77/examples/js/TimelinerController.js",
+ "three.js-r77/examples/js/TypedArrayUtils.js",
+ "three.js-r77/examples/js/UCSCharacter.js",
+ "three.js-r77/examples/js/Volume.js",
+ "three.js-r77/examples/js/VolumeSlice.js",
+ "three.js-r77/examples/js/WaterShader.js",
+ "three.js-r77/examples/js/WebVR.js",
+ "three.js-r77/examples/js/animation/CCDIKSolver.js",
+ "three.js-r77/examples/js/animation/MMDPhysics.js",
+ "three.js-r77/examples/js/cameras/CinematicCamera.js",
+ "three.js-r77/examples/js/cameras/CombinedCamera.js",
+ "three.js-r77/examples/js/controls/DeviceOrientationControls.js",
+ "three.js-r77/examples/js/controls/DragControls.js",
+ "three.js-r77/examples/js/controls/EditorControls.js",
+ "three.js-r77/examples/js/controls/FirstPersonControls.js",
+ "three.js-r77/examples/js/controls/FlyControls.js",
+ "three.js-r77/examples/js/controls/MouseControls.js",
+ "three.js-r77/examples/js/controls/OrbitControls.js",
+ "three.js-r77/examples/js/controls/OrthographicTrackballControls.js",
+ "three.js-r77/examples/js/controls/PointerLockControls.js",
+ "three.js-r77/examples/js/controls/TrackballControls.js",
+ "three.js-r77/examples/js/controls/TransformControls.js",
+ "three.js-r77/examples/js/controls/VRControls.js",
+ "three.js-r77/examples/js/crossfade/gui.js",
+ "three.js-r77/examples/js/crossfade/scenes.js",
+ "three.js-r77/examples/js/crossfade/transition.js",
+ "three.js-r77/examples/js/curves/NURBSCurve.js",
+ "three.js-r77/examples/js/curves/NURBSSurface.js",
+ "three.js-r77/examples/js/curves/NURBSUtils.js",
+ "three.js-r77/examples/js/effects/AnaglyphEffect.js",
+ "three.js-r77/examples/js/effects/AsciiEffect.js",
+ "three.js-r77/examples/js/effects/ParallaxBarrierEffect.js",
+ "three.js-r77/examples/js/effects/PeppersGhostEffect.js",
+ "three.js-r77/examples/js/effects/StereoEffect.js",
+ "three.js-r77/examples/js/effects/VREffect.js",
+ "three.js-r77/examples/js/exporters/OBJExporter.js",
+ "three.js-r77/examples/js/exporters/STLBinaryExporter.js",
+ "three.js-r77/examples/js/exporters/STLExporter.js",
+ "three.js-r77/examples/js/exporters/TypedGeometryExporter.js",
+ "three.js-r77/examples/js/geometries/ConvexGeometry.js",
+ "three.js-r77/examples/js/geometries/DecalGeometry.js",
+ "three.js-r77/examples/js/geometries/TeapotBufferGeometry.js",
+ "three.js-r77/examples/js/geometries/hilbert2D.js",
+ "three.js-r77/examples/js/geometries/hilbert3D.js",
+ "three.js-r77/examples/js/libs/ammo.js",
+ "three.js-r77/examples/js/libs/charsetencoder.min.js",
+ "three.js-r77/examples/js/libs/dat.gui.min.js",
+ "three.js-r77/examples/js/libs/earcut.js",
+ "three.js-r77/examples/js/libs/inflate.min.js",
+ "three.js-r77/examples/js/libs/jszip.min.js",
+ "three.js-r77/examples/js/libs/msgpack-js.js",
+ "three.js-r77/examples/js/libs/pnltri.min.js",
+ "three.js-r77/examples/js/libs/stats.min.js",
+ "three.js-r77/examples/js/libs/system.min.js",
+ "three.js-r77/examples/js/libs/timeliner_gui.min.js",
+ "three.js-r77/examples/js/libs/tween.min.js",
+ "three.js-r77/examples/js/libs/zlib_and_gzip.min.js",
+ "three.js-r77/examples/js/loaders/3MFLoader.js",
+ "three.js-r77/examples/js/loaders/AMFLoader.js",
+ "three.js-r77/examples/js/loaders/AWDLoader.js",
+ "three.js-r77/examples/js/loaders/AssimpJSONLoader.js",
+ "three.js-r77/examples/js/loaders/BabylonLoader.js",
+ "three.js-r77/examples/js/loaders/BinaryLoader.js",
+ "three.js-r77/examples/js/loaders/ColladaLoader.js",
+ "three.js-r77/examples/js/loaders/ColladaLoader2.js",
+ "three.js-r77/examples/js/loaders/DDSLoader.js",
+ "three.js-r77/examples/js/loaders/FBXLoader.js",
+ "three.js-r77/examples/js/loaders/HDRCubeTextureLoader.js",
+ "three.js-r77/examples/js/loaders/KMZLoader.js",
+ "three.js-r77/examples/js/loaders/MD2Loader.js",
+ "three.js-r77/examples/js/loaders/MMDLoader.js",
+ "three.js-r77/examples/js/loaders/MTLLoader.js",
+ "three.js-r77/examples/js/loaders/NRRDLoader.js",
+ "three.js-r77/examples/js/loaders/OBJLoader.js",
+ "three.js-r77/examples/js/loaders/PCDLoader.js",
+ "three.js-r77/examples/js/loaders/PDBLoader.js",
+ "three.js-r77/examples/js/loaders/PLYLoader.js",
+ "three.js-r77/examples/js/loaders/PVRLoader.js",
+ "three.js-r77/examples/js/loaders/PlayCanvasLoader.js",
+ "three.js-r77/examples/js/loaders/RGBELoader.js",
+ "three.js-r77/examples/js/loaders/STLLoader.js",
+ "three.js-r77/examples/js/loaders/SVGLoader.js",
+ "three.js-r77/examples/js/loaders/TGALoader.js",
+ "three.js-r77/examples/js/loaders/UTF8Loader.js",
+ "three.js-r77/examples/js/loaders/VRMLLoader.js",
+ "three.js-r77/examples/js/loaders/VTKLoader.js",
+ "three.js-r77/examples/js/loaders/collada/Animation.js",
+ "three.js-r77/examples/js/loaders/collada/AnimationHandler.js",
+ "three.js-r77/examples/js/loaders/collada/KeyFrameAnimation.js",
+ "three.js-r77/examples/js/loaders/ctm/CTMLoader.js",
+ "three.js-r77/examples/js/loaders/ctm/CTMWorker.js",
+ "three.js-r77/examples/js/loaders/ctm/ctm.js",
+ "three.js-r77/examples/js/loaders/ctm/lzma.js",
+ "three.js-r77/examples/js/loaders/deprecated/SceneLoader.js",
+ "three.js-r77/examples/js/loaders/gltf/glTF-parser.js",
+ "three.js-r77/examples/js/loaders/gltf/glTFAnimation.js",
+ "three.js-r77/examples/js/loaders/gltf/glTFLoader.js",
+ "three.js-r77/examples/js/loaders/gltf/glTFLoaderUtils.js",
+ "three.js-r77/examples/js/loaders/gltf/glTFShaders.js",
+ "three.js-r77/examples/js/loaders/gltf/gltfUtilities.js",
+ "three.js-r77/examples/js/loaders/sea3d/SEA3D.js",
+ "three.js-r77/examples/js/loaders/sea3d/SEA3DDeflate.js",
+ "three.js-r77/examples/js/loaders/sea3d/SEA3DLZMA.js",
+ "three.js-r77/examples/js/loaders/sea3d/SEA3DLegacy.js",
+ "three.js-r77/examples/js/loaders/sea3d/SEA3DLoader.js",
+ "three.js-r77/examples/js/math/ColorConverter.js",
+ "three.js-r77/examples/js/math/Lut.js",
+ "three.js-r77/examples/js/modifiers/BufferSubdivisionModifier.js",
+ "three.js-r77/examples/js/modifiers/ExplodeModifier.js",
+ "three.js-r77/examples/js/modifiers/SubdivisionModifier.js",
+ "three.js-r77/examples/js/modifiers/TessellateModifier.js",
+ "three.js-r77/examples/js/nodes/BuilderNode.js",
+ "three.js-r77/examples/js/nodes/ConstNode.js",
+ "three.js-r77/examples/js/nodes/FunctionCallNode.js",
+ "three.js-r77/examples/js/nodes/FunctionNode.js",
+ "three.js-r77/examples/js/nodes/GLNode.js",
+ "three.js-r77/examples/js/nodes/InputNode.js",
+ "three.js-r77/examples/js/nodes/NodeLib.js",
+ "three.js-r77/examples/js/nodes/NodeMaterial.js",
+ "three.js-r77/examples/js/nodes/RawNode.js",
+ "three.js-r77/examples/js/nodes/TempNode.js",
+ "three.js-r77/examples/js/nodes/accessors/CameraNode.js",
+ "three.js-r77/examples/js/nodes/accessors/ColorsNode.js",
+ "three.js-r77/examples/js/nodes/accessors/LightNode.js",
+ "three.js-r77/examples/js/nodes/accessors/NormalNode.js",
+ "three.js-r77/examples/js/nodes/accessors/PositionNode.js",
+ "three.js-r77/examples/js/nodes/accessors/ReflectNode.js",
+ "three.js-r77/examples/js/nodes/accessors/ScreenUVNode.js",
+ "three.js-r77/examples/js/nodes/accessors/UVNode.js",
+ "three.js-r77/examples/js/nodes/inputs/ColorNode.js",
+ "three.js-r77/examples/js/nodes/inputs/CubeTextureNode.js",
+ "three.js-r77/examples/js/nodes/inputs/FloatNode.js",
+ "three.js-r77/examples/js/nodes/inputs/IntNode.js",
+ "three.js-r77/examples/js/nodes/inputs/Matrix4Node.js",
+ "three.js-r77/examples/js/nodes/inputs/MirrorNode.js",
+ "three.js-r77/examples/js/nodes/inputs/ScreenNode.js",
+ "three.js-r77/examples/js/nodes/inputs/TextureNode.js",
+ "three.js-r77/examples/js/nodes/inputs/Vector2Node.js",
+ "three.js-r77/examples/js/nodes/inputs/Vector3Node.js",
+ "three.js-r77/examples/js/nodes/inputs/Vector4Node.js",
+ "three.js-r77/examples/js/nodes/materials/PhongNode.js",
+ "three.js-r77/examples/js/nodes/materials/PhongNodeMaterial.js",
+ "three.js-r77/examples/js/nodes/materials/StandardNode.js",
+ "three.js-r77/examples/js/nodes/materials/StandardNodeMaterial.js",
+ "three.js-r77/examples/js/nodes/math/Math1Node.js",
+ "three.js-r77/examples/js/nodes/math/Math2Node.js",
+ "three.js-r77/examples/js/nodes/math/Math3Node.js",
+ "three.js-r77/examples/js/nodes/math/OperatorNode.js",
+ "three.js-r77/examples/js/nodes/postprocessing/NodePass.js",
+ "three.js-r77/examples/js/nodes/utils/ColorAdjustmentNode.js",
+ "three.js-r77/examples/js/nodes/utils/JoinNode.js",
+ "three.js-r77/examples/js/nodes/utils/LuminanceNode.js",
+ "three.js-r77/examples/js/nodes/utils/NoiseNode.js",
+ "three.js-r77/examples/js/nodes/utils/NormalMapNode.js",
+ "three.js-r77/examples/js/nodes/utils/ResolutionNode.js",
+ "three.js-r77/examples/js/nodes/utils/RoughnessToBlinnExponentNode.js",
+ "three.js-r77/examples/js/nodes/utils/SwitchNode.js",
+ "three.js-r77/examples/js/nodes/utils/TimerNode.js",
+ "three.js-r77/examples/js/nodes/utils/VelocityNode.js",
+ "three.js-r77/examples/js/objects/ShadowMesh.js",
+ "three.js-r77/examples/js/pmrem/PMREMCubeUVPacker.js",
+ "three.js-r77/examples/js/pmrem/PMREMGenerator.js",
+ "three.js-r77/examples/js/postprocessing/AdaptiveToneMappingPass.js",
+ "three.js-r77/examples/js/postprocessing/BloomPass.js",
+ "three.js-r77/examples/js/postprocessing/BokehPass.js",
+ "three.js-r77/examples/js/postprocessing/ClearPass.js",
+ "three.js-r77/examples/js/postprocessing/DotScreenPass.js",
+ "three.js-r77/examples/js/postprocessing/EffectComposer.js",
+ "three.js-r77/examples/js/postprocessing/FilmPass.js",
+ "three.js-r77/examples/js/postprocessing/GlitchPass.js",
+ "three.js-r77/examples/js/postprocessing/ManualMSAARenderPass.js",
+ "three.js-r77/examples/js/postprocessing/MaskPass.js",
+ "three.js-r77/examples/js/postprocessing/RenderPass.js",
+ "three.js-r77/examples/js/postprocessing/SMAAPass.js",
+ "three.js-r77/examples/js/postprocessing/SavePass.js",
+ "three.js-r77/examples/js/postprocessing/ShaderPass.js",
+ "three.js-r77/examples/js/postprocessing/TAARenderPass.js",
+ "three.js-r77/examples/js/postprocessing/TexturePass.js",
+ "three.js-r77/examples/js/renderers/CSS2DRenderer.js",
+ "three.js-r77/examples/js/renderers/CSS3DRenderer.js",
+ "three.js-r77/examples/js/renderers/CanvasRenderer.js",
+ "three.js-r77/examples/js/renderers/Projector.js",
+ "three.js-r77/examples/js/renderers/RaytracingRenderer.js",
+ "three.js-r77/examples/js/renderers/RaytracingWorker.js",
+ "three.js-r77/examples/js/renderers/SVGRenderer.js",
+ "three.js-r77/examples/js/renderers/SoftwareRenderer.js",
+ "three.js-r77/examples/js/shaders/BasicShader.js",
+ "three.js-r77/examples/js/shaders/BleachBypassShader.js",
+ "three.js-r77/examples/js/shaders/BlendShader.js",
+ "three.js-r77/examples/js/shaders/BokehShader.js",
+ "three.js-r77/examples/js/shaders/BokehShader2.js",
+ "three.js-r77/examples/js/shaders/BrightnessContrastShader.js",
+ "three.js-r77/examples/js/shaders/ColorCorrectionShader.js",
+ "three.js-r77/examples/js/shaders/ColorifyShader.js",
+ "three.js-r77/examples/js/shaders/ConvolutionShader.js",
+ "three.js-r77/examples/js/shaders/CopyShader.js",
+ "three.js-r77/examples/js/shaders/DOFMipMapShader.js",
+ "three.js-r77/examples/js/shaders/DigitalGlitch.js",
+ "three.js-r77/examples/js/shaders/DotScreenShader.js",
+ "three.js-r77/examples/js/shaders/EdgeShader.js",
+ "three.js-r77/examples/js/shaders/EdgeShader2.js",
+ "three.js-r77/examples/js/shaders/FXAAShader.js",
+ "three.js-r77/examples/js/shaders/FilmShader.js",
+ "three.js-r77/examples/js/shaders/FocusShader.js",
+ "three.js-r77/examples/js/shaders/FresnelShader.js",
+ "three.js-r77/examples/js/shaders/GammaCorrectionShader.js",
+ "three.js-r77/examples/js/shaders/HorizontalBlurShader.js",
+ "three.js-r77/examples/js/shaders/HorizontalTiltShiftShader.js",
+ "three.js-r77/examples/js/shaders/HueSaturationShader.js",
+ "three.js-r77/examples/js/shaders/KaleidoShader.js",
+ "three.js-r77/examples/js/shaders/LuminosityShader.js",
+ "three.js-r77/examples/js/shaders/MirrorShader.js",
+ "three.js-r77/examples/js/shaders/NormalMapShader.js",
+ "three.js-r77/examples/js/shaders/OceanShaders.js",
+ "three.js-r77/examples/js/shaders/ParallaxShader.js",
+ "three.js-r77/examples/js/shaders/RGBShiftShader.js",
+ "three.js-r77/examples/js/shaders/SMAAShader.js",
+ "three.js-r77/examples/js/shaders/SSAOShader.js",
+ "three.js-r77/examples/js/shaders/SepiaShader.js",
+ "three.js-r77/examples/js/shaders/TechnicolorShader.js",
+ "three.js-r77/examples/js/shaders/ToneMapShader.js",
+ "three.js-r77/examples/js/shaders/TriangleBlurShader.js",
+ "three.js-r77/examples/js/shaders/UnpackDepthRGBAShader.js",
+ "three.js-r77/examples/js/shaders/VerticalBlurShader.js",
+ "three.js-r77/examples/js/shaders/VerticalTiltShiftShader.js",
+ "three.js-r77/examples/js/shaders/VignetteShader.js",
+ "three.js-r77/examples/js/utils/GeometryUtils.js",
+ "three.js-r77/examples/js/utils/ImageUtils.js",
+ "three.js-r77/examples/js/utils/ShadowMapViewer.js",
+ "three.js-r77/examples/js/utils/UVsDebug.js",
+ ],
+)
+
+filegroup(
name = "web_animations_js",
srcs = [
"web-animations.html",
@@ -608,3 +912,25 @@ filegroup(
"webcomponents-lite.min.js",
],
)
+
+filegroup(
+ name = "weblas",
+ srcs = [
+ "benchmark.html",
+ "benchmark/sgemm.js",
+ "dist/weblas.js",
+ "index.js",
+ "lib/globals.js",
+ "lib/pipeline.js",
+ "lib/saxpycalculator.js",
+ "lib/sclmpcalculator.js",
+ "lib/sdwnscalculator.js",
+ "lib/sgemmcalculator.js",
+ "lib/sscalcalculator.js",
+ "lib/tensor.js",
+ "lib/test.js",
+ "lib/webgl.js",
+ "test.html",
+ "test/data/generate.js",
+ ],
+)
diff --git a/gif.BUILD b/gif.BUILD
index cbdcc75f12..892e109e7d 100644
--- a/gif.BUILD
+++ b/gif.BUILD
@@ -15,13 +15,49 @@ HEADERS = [
"gif_lib_private.h",
]
+config_setting(
+ name = "windows",
+ values = {
+ "cpu": "x64_windows_msvc",
+ },
+ visibility = ["//visibility:public"],
+)
+
prefix_dir = "giflib-5.1.4/lib"
+prefix_dir_windows = "windows/giflib-5.1.4/lib"
+
+genrule(
+ name = "srcs_without_unistd",
+ srcs = [prefix_dir + "/" + source for source in SOURCES],
+ outs = [prefix_dir_windows + "/" + source for source in SOURCES],
+ cmd = "for f in $(SRCS); do " +
+ " sed 's/#include <unistd.h>//g' $$f > $(@D)/%s/$$(basename $$f);" % prefix_dir_windows +
+ "done",
+)
+
+genrule(
+ name = "hdrs_without_unistd",
+ srcs = [prefix_dir + "/" + hdrs for hdrs in HEADERS],
+ outs = [prefix_dir_windows + "/" + hdrs for hdrs in HEADERS],
+ cmd = "for f in $(SRCS); do " +
+ " sed 's/#include <unistd.h>//g' $$f > $(@D)/%s/$$(basename $$f);" % prefix_dir_windows +
+ "done",
+)
cc_library(
name = "gif",
- srcs = [prefix_dir + "/" + source for source in SOURCES],
- hdrs = [prefix_dir + "/" + hdrs for hdrs in HEADERS],
- includes = [prefix_dir],
+ srcs = select({
+ "//conditions:default" : [prefix_dir + "/" + source for source in SOURCES],
+ ":windows" : [":srcs_without_unistd"],
+ }),
+ hdrs = select({
+ "//conditions:default" : [prefix_dir + "/" + hdrs for hdrs in HEADERS],
+ ":windows" : [":hdrs_without_unistd"],
+ }),
+ includes = select({
+ "//conditions:default" : [prefix_dir],
+ ":windows" : [prefix_dir_windows],
+ }),
defines = [
"HAVE_CONFIG_H",
],
diff --git a/grpc.BUILD b/grpc.BUILD
index 624079a0c7..c1404b54fb 100644
--- a/grpc.BUILD
+++ b/grpc.BUILD
@@ -1224,6 +1224,7 @@ cc_library(
deps = [
":gpr",
"//external:nanopb",
+ "//external:zlib",
],
copts = [
"-std=gnu99",
diff --git a/tensorflow/contrib/cmake/setup.py b/tensorflow/contrib/cmake/setup.py
index 953c2aa97c..b8a30adc9d 100644
--- a/tensorflow/contrib/cmake/setup.py
+++ b/tensorflow/contrib/cmake/setup.py
@@ -177,7 +177,6 @@ setup(
include_package_data=True,
package_data={
'tensorflow': ['python/_pywrap_tensorflow.so',
- 'python/libpython_deps.so',
] + matches,
},
zip_safe=False,
diff --git a/tensorflow/contrib/cmake/tf_python.cmake b/tensorflow/contrib/cmake/tf_python.cmake
index fc3579aa90..67f45082f7 100644
--- a/tensorflow/contrib/cmake/tf_python.cmake
+++ b/tensorflow/contrib/cmake/tf_python.cmake
@@ -12,11 +12,7 @@
# Resolve installed dependencies
########################################################
-# 1. Resolve the installed version of SWIG.
-FIND_PACKAGE(SWIG REQUIRED)
-INCLUDE(${SWIG_USE_FILE})
-
-# 2. Resolve the installed version of Python (for Python.h and python).
+# 1. Resolve the installed version of Python (for Python.h and python).
# TODO(mrry): Parameterize the build script to enable Python 3 building.
include(FindPythonInterp)
if(NOT PYTHON_INCLUDE_DIR)
@@ -32,7 +28,7 @@ if(NOT PYTHON_INCLUDE_DIR)
endif(NOT PYTHON_INCLUDE_DIR)
FIND_PACKAGE(PythonLibs)
-# 3. Resolve the installed version of NumPy (for numpy/arrayobject.h).
+# 2. Resolve the installed version of NumPy (for numpy/arrayobject.h).
if(NOT NUMPY_INCLUDE_DIR)
set(NUMPY_NOT_FOUND false)
exec_program("${PYTHON_EXECUTABLE}"
@@ -45,7 +41,7 @@ if(NOT NUMPY_INCLUDE_DIR)
endif(${NUMPY_NOT_FOUND})
endif(NOT NUMPY_INCLUDE_DIR)
-# 4. Resolve the installed version of zlib (for libz.so).
+# 3. Resolve the installed version of zlib (for libz.so).
find_package(ZLIB REQUIRED)
@@ -292,12 +288,30 @@ add_dependencies(tf_python_ops tf_python_op_gen_main)
# Build the SWIG-wrapped library for the TensorFlow runtime.
############################################################
-# python_deps is a shared library containing all of the TensorFlow
+find_package(SWIG REQUIRED)
+# Generate the C++ and Python source code for the SWIG wrapper.
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/tf_python/tensorflow/python/pywrap_tensorflow.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/pywrap_tensorflow.cc"
+ DEPENDS tf_python_touchup_modules
+ COMMAND ${SWIG_EXECUTABLE}
+ ARGS -python -c++
+ -I${tensorflow_source_dir}
+ -I${CMAKE_CURRENT_BINARY_DIR}
+ -module pywrap_tensorflow
+ -outdir ${CMAKE_CURRENT_BINARY_DIR}/tf_python/tensorflow/python
+ -o ${CMAKE_CURRENT_BINARY_DIR}/pywrap_tensorflow.cc
+ -globals ''
+ ${tensorflow_source_dir}/tensorflow/python/tensorflow.i
+ COMMENT "Running SWIG to generate Python wrappers"
+ VERBATIM )
+
+# pywrap_tensorflow is a shared library containing all of the TensorFlow
# runtime and the standard ops and kernels. These are installed into
# tf_python/tensorflow/python/.
# TODO(mrry): Refactor this to expose a framework library that
# facilitates `tf.load_op_library()`.
-add_library(python_deps SHARED
+add_library(pywrap_tensorflow SHARED
"${tensorflow_source_dir}/tensorflow/python/client/tf_session_helper.h"
"${tensorflow_source_dir}/tensorflow/python/client/tf_session_helper.cc"
"${tensorflow_source_dir}/tensorflow/python/framework/cpp_shape_inference.h"
@@ -318,6 +332,7 @@ add_library(python_deps SHARED
"${tensorflow_source_dir}/tensorflow/c/checkpoint_reader.h"
"${tensorflow_source_dir}/tensorflow/c/tf_status_helper.cc"
"${tensorflow_source_dir}/tensorflow/c/tf_status_helper.h"
+ "${CMAKE_CURRENT_BINARY_DIR}/pywrap_tensorflow.cc"
$<TARGET_OBJECTS:tf_core_lib>
$<TARGET_OBJECTS:tf_core_cpu>
$<TARGET_OBJECTS:tf_core_framework>
@@ -326,7 +341,7 @@ add_library(python_deps SHARED
$<TARGET_OBJECTS:tf_core_distributed_runtime>
$<TARGET_OBJECTS:tf_core_kernels>
)
-target_link_libraries(python_deps
+target_link_libraries(pywrap_tensorflow
${CMAKE_THREAD_LIBS_INIT}
tf_protos_cc
${GRPC_LIBRARIES}
@@ -341,7 +356,7 @@ target_link_libraries(python_deps
${ZLIB_LIBRARIES}
${CMAKE_DL_LIBS}
)
-target_include_directories(python_deps PUBLIC
+target_include_directories(pywrap_tensorflow PUBLIC
${tensorflow_source_dir}
${CMAKE_CURRENT_BINARY_DIR}
${eigen_INCLUDE_DIRS}
@@ -349,62 +364,32 @@ target_include_directories(python_deps PUBLIC
${NUMPY_INCLUDE_DIR}
)
# C++11
-target_compile_features(python_deps PRIVATE
+target_compile_features(pywrap_tensorflow PRIVATE
cxx_rvalue_references
)
-set_target_properties(python_deps PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tf_python/tensorflow/python)
-
-# _pywrap_tensorflow is the target that generates the SWIG bindings
-# and compiles them as a shared library that depends on python_deps.
-set(CMAKE_SWIG_FLAGS "")
-set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/tf_python/tensorflow/python)
-SET_SOURCE_FILES_PROPERTIES("${tensorflow_source_dir}/tensorflow/python/tensorflow.i"
- PROPERTIES CPLUSPLUS ON
-)
-SET_PROPERTY(SOURCE "${tensorflow_source_dir}/tensorflow/python/tensorflow.i"
- PROPERTY SWIG_FLAGS "-I\"${tensorflow_source_dir}\"" "-module" "pywrap_tensorflow"
-)
-SWIG_ADD_MODULE(pywrap_tensorflow python
- "${tensorflow_source_dir}/tensorflow/python/tensorflow.i"
-)
-SWIG_LINK_LIBRARIES(pywrap_tensorflow
- python_deps
- ${PROTOBUF_LIBRARY}
- ${CMAKE_DL_LIBS}
-)
-target_include_directories(_pywrap_tensorflow PUBLIC
- ${tensorflow_source_dir}
- ${CMAKE_CURRENT_BINARY_DIR}
- ${eigen_INCLUDE_DIRS}
- ${PYTHON_INCLUDE_DIR}
- ${NUMPY_INCLUDE_DIR}
-)
-add_dependencies(_pywrap_tensorflow
- eigen
- tf_core_direct_session
- tf_core_distributed_runtime
- tf_core_framework
- python_deps
- tf_python_copy_scripts_to_destination
- tf_python_ops
- tf_python_touchup_modules
-)
-# C++11
-target_compile_features(_pywrap_tensorflow PRIVATE
- cxx_rvalue_references
-)
-set_target_properties(_pywrap_tensorflow PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tf_python/tensorflow/python)
+
+############################################################
+# Build a PIP package containing the TensorFlow runtime.
+############################################################
add_custom_target(tf_python_copy_pip_files)
-add_dependencies(tf_python_copy_pip_files _pywrap_tensorflow tf_python_copy_scripts_to_destination tf_python_touchup_modules)
+add_dependencies(tf_python_copy_pip_files
+ pywrap_tensorflow
+ tf_python_copy_scripts_to_destination
+ tf_python_touchup_modules
+ tf_python_ops)
+add_custom_command(TARGET tf_python_copy_pip_files POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy ${tensorflow_source_dir}/tensorflow/contrib/cmake/setup.py
+ ${CMAKE_CURRENT_BINARY_DIR}/tf_python/)
add_custom_command(TARGET tf_python_copy_pip_files POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${tensorflow_source_dir}/tensorflow/contrib/cmake/setup.py ${CMAKE_CURRENT_BINARY_DIR}/tf_python/)
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/libpywrap_tensorflow.so
+ ${CMAKE_CURRENT_BINARY_DIR}/tf_python/tensorflow/python/_pywrap_tensorflow.so)
add_custom_command(TARGET tf_python_copy_pip_files POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${tensorflow_source_dir}/tensorflow/tools/pip_package/README ${CMAKE_CURRENT_BINARY_DIR}/tf_python/)
+ COMMAND ${CMAKE_COMMAND} -E copy ${tensorflow_source_dir}/tensorflow/tools/pip_package/README
+ ${CMAKE_CURRENT_BINARY_DIR}/tf_python/)
add_custom_command(TARGET tf_python_copy_pip_files POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${tensorflow_source_dir}/tensorflow/tools/pip_package/MANIFEST.in ${CMAKE_CURRENT_BINARY_DIR}/tf_python/)
+ COMMAND ${CMAKE_COMMAND} -E copy ${tensorflow_source_dir}/tensorflow/tools/pip_package/MANIFEST.in
+ ${CMAKE_CURRENT_BINARY_DIR}/tf_python/)
add_custom_command(TARGET tf_python_copy_pip_files POST_BUILD
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/tf_python/setup.py bdist_wheel
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tf_python)
diff --git a/tensorflow/contrib/ios_examples/README.md b/tensorflow/contrib/ios_examples/README.md
index 83b1d7868a..873ae4c9db 100644
--- a/tensorflow/contrib/ios_examples/README.md
+++ b/tensorflow/contrib/ios_examples/README.md
@@ -13,7 +13,17 @@ This folder contains examples of how to build applications for iOS devices using
- Download
[Inception v1](https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip),
and extract the label and graph files into the data folders inside both the
- simple and camera examples.
+ simple and camera examples:
+
+```bash
+mkdir -p ~/graphs
+curl -o ~/graphs/inception5h.zip \
+ https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip \
+ && unzip ~/graphs/inception5h.zip -d ~/graphs/inception5h
+cp ~/graphs/inception5h/* tensorflow/contrib/ios_examples/benchmark/data/
+cp ~/graphs/inception5h/* tensorflow/contrib/ios_examples/camera/data/
+cp ~/graphs/inception5h/* tensorflow/contrib/ios_examples/simple/data/
+```
- Load the Xcode project inside the `simple` subfolder, and press Command-R to
build and run it on the simulator or your connected device.
@@ -86,3 +96,46 @@ rundown:
flag will cause these duplicates to become link errors. If you were using
`-all_load` to avoid issues with Objective-C categories in static libraries,
you may be able to replace it with the `-ObjC` flag.
+
+## Reducing the binary size
+
+TensorFlow is a comparatively large library for a mobile device, so it will
+increase the size of your app. Currently on iOS we see around a 11 MB binary
+footprint per CPU architecture, though we're actively working on reducing that.
+It can be tricky to set up the right configuration in your own app to keep the
+size minimized, so if you do run into this issue we recommend you start by
+looking at the simple example to examine its size. Here's how you do that:
+
+ - Open the Xcode project in tensorflow/contrib/ios_examples/simple.
+
+ - Make sure you've followed the steps above to get the data files.
+
+ - Choose "Generic iOS Device" as the build configuration.
+
+ - Select Product->Build.
+
+ - Once the build's complete, open the Report Navigator and select the logs.
+
+ - Near the bottom, you'll see a line saying "Touch tf_ios_makefile_example.app".
+
+ - Expand that line using the icon on the right, and copy the first argument to
+ the Touch command.
+
+ - Go to the terminal, type `ls -lah ` and then paste the path you copied.
+
+ - For example it might look like `ls -lah /Users/petewarden/Library/Developer/Xcode/DerivedData/tf_ios_makefile_example-etdbksqytcnzeyfgdwiihzkqpxwr/Build/Products/Debug-iphoneos/tf_ios_makefile_example.app`
+
+ - Running this command will show the size of the executable as the
+ `tf_ios_makefile_example` line.
+
+Right now you'll see a size of around 23 MB, since it's including two
+architectures (armv7 and arm64). As a first step, you should make sure the size
+increase you see in your own app is similar, and if it's larger, look at the
+"Other Linker Flags" used in the Simple Xcode project settings to strip the
+executable.
+
+After that, you can manually look at modifying the list of kernels
+included in tensorflow/contrib/makefile/tf_op_files.txt to reduce the number of
+implementations to the ones you're actually using in your own model. We're
+hoping to automate this step in the future, but for now manually removing them
+is the best approach. \ No newline at end of file
diff --git a/tensorflow/contrib/ios_examples/camera/CameraExampleViewController.h b/tensorflow/contrib/ios_examples/camera/CameraExampleViewController.h
index 1e730a456d..eb9d5aed68 100644
--- a/tensorflow/contrib/ios_examples/camera/CameraExampleViewController.h
+++ b/tensorflow/contrib/ios_examples/camera/CameraExampleViewController.h
@@ -17,6 +17,7 @@
#include <memory>
#include "tensorflow/core/public/session.h"
+#include "tensorflow/core/util/memmapped_file_system.h"
@interface CameraExampleViewController
: UIViewController<UIGestureRecognizerDelegate,
@@ -35,6 +36,7 @@
NSMutableArray *labelLayers;
AVCaptureSession *session;
std::unique_ptr<tensorflow::Session> tf_session;
+ std::unique_ptr<tensorflow::MemmappedEnv> tf_memmapped_env;
std::vector<std::string> labels;
}
@property(retain, nonatomic) CATextLayer *predictionTextLayer;
diff --git a/tensorflow/contrib/ios_examples/camera/CameraExampleViewController.mm b/tensorflow/contrib/ios_examples/camera/CameraExampleViewController.mm
index dc79e7a12a..86570b19d2 100644
--- a/tensorflow/contrib/ios_examples/camera/CameraExampleViewController.mm
+++ b/tensorflow/contrib/ios_examples/camera/CameraExampleViewController.mm
@@ -22,6 +22,27 @@
#include "tensorflow_utils.h"
+// If you have your own model, modify this to the file name, and make sure
+// you've added the file to your app resources too.
+static NSString* model_file_name = @"tensorflow_inception_graph";
+static NSString* model_file_type = @"pb";
+// This controls whether we'll be loading a plain GraphDef proto, or a
+// file created by the convert_graphdef_memmapped_format utility that wraps a
+// GraphDef and parameter file that can be mapped into memory from file to
+// reduce overall memory usage.
+const bool model_uses_memory_mapping = false;
+// If you have your own model, point this to the labels file.
+static NSString* labels_file_name = @"imagenet_comp_graph_label_strings";
+static NSString* labels_file_type = @"txt";
+// These dimensions need to match those the model was trained with.
+const int wanted_input_width = 224;
+const int wanted_input_height = 224;
+const int wanted_input_channels = 3;
+const float input_mean = 117.0f;
+const float input_std = 1.0f;
+const std::string input_layer_name = "input";
+const std::string output_layer_name = "softmax1";
+
static const NSString *AVCaptureStillImageIsCapturingStillImageContext =
@"AVCaptureStillImageIsCapturingStillImageContext";
@@ -269,39 +290,32 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
}
const int image_channels = 4;
- const int wanted_width = 224;
- const int wanted_height = 224;
- const int wanted_channels = 3;
- const float input_mean = 117.0f;
- const float input_std = 1.0f;
- assert(image_channels >= wanted_channels);
+ assert(image_channels >= wanted_input_channels);
tensorflow::Tensor image_tensor(
tensorflow::DT_FLOAT,
tensorflow::TensorShape(
- {1, wanted_height, wanted_width, wanted_channels}));
+ {1, wanted_input_height, wanted_input_width, wanted_input_channels}));
auto image_tensor_mapped = image_tensor.tensor<float, 4>();
tensorflow::uint8 *in = sourceStartAddr;
float *out = image_tensor_mapped.data();
- for (int y = 0; y < wanted_height; ++y) {
- float *out_row = out + (y * wanted_width * wanted_channels);
- for (int x = 0; x < wanted_width; ++x) {
- const int in_x = (y * image_width) / wanted_width;
- const int in_y = (x * image_height) / wanted_height;
+ for (int y = 0; y < wanted_input_height; ++y) {
+ float *out_row = out + (y * wanted_input_width * wanted_input_channels);
+ for (int x = 0; x < wanted_input_width; ++x) {
+ const int in_x = (y * image_width) / wanted_input_width;
+ const int in_y = (x * image_height) / wanted_input_height;
tensorflow::uint8 *in_pixel =
in + (in_y * image_width * image_channels) + (in_x * image_channels);
- float *out_pixel = out_row + (x * wanted_channels);
- for (int c = 0; c < wanted_channels; ++c) {
+ float *out_pixel = out_row + (x * wanted_input_channels);
+ for (int c = 0; c < wanted_input_channels; ++c) {
out_pixel[c] = (in_pixel[c] - input_mean) / input_std;
}
}
}
if (tf_session.get()) {
- std::string input_layer = "input";
- std::string output_layer = "output";
std::vector<tensorflow::Tensor> outputs;
tensorflow::Status run_status = tf_session->Run(
- {{input_layer, image_tensor}}, {output_layer}, {}, &outputs);
+ {{input_layer_name, image_tensor}}, {output_layer_name}, {}, &outputs);
if (!run_status.ok()) {
LOG(ERROR) << "Running model failed:" << run_status;
} else {
@@ -362,22 +376,28 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
- (void)viewDidLoad {
[super viewDidLoad];
- [self setupAVCapture];
square = [[UIImage imageNamed:@"squarePNG"] retain];
synth = [[AVSpeechSynthesizer alloc] init];
labelLayers = [[NSMutableArray alloc] init];
oldPredictionValues = [[NSMutableDictionary alloc] init];
- tensorflow::Status load_status =
- LoadModel(@"tensorflow_inception_graph", @"pb", &tf_session);
+
+ tensorflow::Status load_status;
+ if (model_uses_memory_mapping) {
+ load_status = LoadMemoryMappedModel(
+ model_file_name, model_file_type, &tf_session, &tf_memmapped_env);
+ } else {
+ load_status = LoadModel(model_file_name, model_file_type, &tf_session);
+ }
if (!load_status.ok()) {
LOG(FATAL) << "Couldn't load model: " << load_status;
}
tensorflow::Status labels_status =
- LoadLabels(@"imagenet_comp_graph_label_strings", @"txt", &labels);
+ LoadLabels(labels_file_name, labels_file_type, &labels);
if (!labels_status.ok()) {
LOG(FATAL) << "Couldn't load labels: " << labels_status;
}
+ [self setupAVCapture];
}
- (void)viewDidUnload {
diff --git a/tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj b/tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj
index 451f536a7c..c123df9586 100644
--- a/tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj
+++ b/tensorflow/contrib/ios_examples/camera/camera_example.xcodeproj/project.pbxproj
@@ -304,12 +304,6 @@
OTHER_LDFLAGS = (
"-force_load",
"$(SRCROOT)/../../makefile/gen/lib/libtensorflow-core.a",
- "-Xlinker",
- "-S",
- "-Xlinker",
- "-x",
- "-Xlinker",
- "-dead_strip",
);
PRODUCT_BUNDLE_IDENTIFIER = com.google.CameraExample;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -369,12 +363,6 @@
OTHER_LDFLAGS = (
"-force_load",
"$(SRCROOT)/../../makefile/gen/lib/libtensorflow-core.a",
- "-Xlinker",
- "-S",
- "-Xlinker",
- "-x",
- "-Xlinker",
- "-dead_strip",
);
PRODUCT_BUNDLE_IDENTIFIER = com.google.CameraExample;
PRODUCT_NAME = "$(TARGET_NAME)";
diff --git a/tensorflow/contrib/ios_examples/camera/tensorflow_utils.h b/tensorflow/contrib/ios_examples/camera/tensorflow_utils.h
index 9110a106fe..78bdb82aae 100644
--- a/tensorflow/contrib/ios_examples/camera/tensorflow_utils.h
+++ b/tensorflow/contrib/ios_examples/camera/tensorflow_utils.h
@@ -19,15 +19,34 @@
#include <vector>
#include "tensorflow/core/public/session.h"
+#include "tensorflow/core/util/memmapped_file_system.h"
#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
+// Reads a serialized GraphDef protobuf file from the bundle, typically
+// created with the freeze_graph script. Populates the session argument with a
+// Session object that has the model loaded.
tensorflow::Status LoadModel(NSString* file_name, NSString* file_type,
std::unique_ptr<tensorflow::Session>* session);
+
+// Loads a model from a file that has been created using the
+// convert_graphdef_memmapped_format tool. This bundles together a GraphDef
+// proto together with a file that can be memory-mapped, containing the weight
+// parameters for the model. This is useful because it reduces the overall
+// memory pressure, since the read-only parameter regions can be easily paged
+// out and don't count toward memory limits on iOS.
+tensorflow::Status LoadMemoryMappedModel(
+ NSString* file_name, NSString* file_type,
+ std::unique_ptr<tensorflow::Session>* session,
+ std::unique_ptr<tensorflow::MemmappedEnv>* memmapped_env);
+
+// Takes a text file with a single label on each line, and returns a list.
tensorflow::Status LoadLabels(NSString* file_name, NSString* file_type,
std::vector<std::string>* label_strings);
+
+// Sorts the results from a model execution, and returns the highest scoring.
void GetTopN(const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>,
- Eigen::Aligned>& prediction, const int num_results,
- const float threshold,
+ Eigen::Aligned>& prediction,
+ const int num_results, const float threshold,
std::vector<std::pair<float, int> >* top_results);
#endif // TENSORFLOW_CONTRIB_IOS_EXAMPLES_CAMERA_TENSORFLOW_UTILS_H_
diff --git a/tensorflow/contrib/ios_examples/camera/tensorflow_utils.mm b/tensorflow/contrib/ios_examples/camera/tensorflow_utils.mm
index 7a5dc31a22..43746882ee 100644
--- a/tensorflow/contrib/ios_examples/camera/tensorflow_utils.mm
+++ b/tensorflow/contrib/ios_examples/camera/tensorflow_utils.mm
@@ -16,9 +16,9 @@
#include "tensorflow_utils.h"
-#include <fstream>
#include <pthread.h>
#include <unistd.h>
+#include <fstream>
#include <queue>
#include <sstream>
#include <string>
@@ -35,56 +35,58 @@
#include "tensorflow/core/platform/types.h"
#include "tensorflow/core/public/session.h"
-
namespace {
- class IfstreamInputStream : public ::google::protobuf::io::CopyingInputStream {
- public:
- explicit IfstreamInputStream(const std::string& file_name)
- : ifs_(file_name.c_str(), std::ios::in | std::ios::binary) {}
- ~IfstreamInputStream() { ifs_.close(); }
-
- int Read(void* buffer, int size) {
- if (!ifs_) {
- return -1;
- }
- ifs_.read(static_cast<char*>(buffer), size);
- return ifs_.gcount();
+
+// Helper class used to load protobufs efficiently.
+class IfstreamInputStream : public ::google::protobuf::io::CopyingInputStream {
+ public:
+ explicit IfstreamInputStream(const std::string& file_name)
+ : ifs_(file_name.c_str(), std::ios::in | std::ios::binary) {}
+ ~IfstreamInputStream() { ifs_.close(); }
+
+ int Read(void* buffer, int size) {
+ if (!ifs_) {
+ return -1;
}
-
- private:
- std::ifstream ifs_;
- };
+ ifs_.read(static_cast<char*>(buffer), size);
+ return ifs_.gcount();
+ }
+
+ private:
+ std::ifstream ifs_;
+};
} // namespace
// Returns the top N confidence values over threshold in the provided vector,
// sorted by confidence in descending order.
void GetTopN(const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>,
- Eigen::Aligned>& prediction, const int num_results,
- const float threshold,
+ Eigen::Aligned>& prediction,
+ const int num_results, const float threshold,
std::vector<std::pair<float, int> >* top_results) {
// Will contain top N results in ascending order.
std::priority_queue<std::pair<float, int>,
- std::vector<std::pair<float, int> >,
- std::greater<std::pair<float, int> > > top_result_pq;
-
+ std::vector<std::pair<float, int> >,
+ std::greater<std::pair<float, int> > >
+ top_result_pq;
+
const int count = prediction.size();
for (int i = 0; i < count; ++i) {
const float value = prediction(i);
-
+
// Only add it if it beats the threshold and has a chance at being in
// the top N.
if (value < threshold) {
continue;
}
-
+
top_result_pq.push(std::pair<float, int>(value, i));
-
+
// If at capacity, kick the smallest value out.
if (top_result_pq.size() > num_results) {
top_result_pq.pop();
}
}
-
+
// Copy to output vector and reverse into descending order.
while (!top_result_pq.empty()) {
top_results->push_back(top_result_pq.top());
@@ -93,11 +95,10 @@ void GetTopN(const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>,
std::reverse(top_results->begin(), top_results->end());
}
-
bool PortableReadFileToProto(const std::string& file_name,
::google::protobuf::MessageLite* proto) {
::google::protobuf::io::CopyingInputStreamAdaptor stream(
- new IfstreamInputStream(file_name));
+ new IfstreamInputStream(file_name));
stream.SetOwnsCopyingStream(true);
::google::protobuf::io::CodedInputStream coded_stream(&stream);
// Total bytes hard limit / warning limit are set to 1GB and 512MB
@@ -107,10 +108,11 @@ bool PortableReadFileToProto(const std::string& file_name,
}
NSString* FilePathForResourceName(NSString* name, NSString* extension) {
- NSString* file_path = [[NSBundle mainBundle] pathForResource:name ofType:extension];
+ NSString* file_path =
+ [[NSBundle mainBundle] pathForResource:name ofType:extension];
if (file_path == NULL) {
LOG(FATAL) << "Couldn't find '" << [name UTF8String] << "."
- << [extension UTF8String] << "' in bundle.";
+ << [extension UTF8String] << "' in bundle.";
return nullptr;
}
return file_path;
@@ -119,19 +121,18 @@ NSString* FilePathForResourceName(NSString* name, NSString* extension) {
tensorflow::Status LoadModel(NSString* file_name, NSString* file_type,
std::unique_ptr<tensorflow::Session>* session) {
tensorflow::SessionOptions options;
-
+
tensorflow::Session* session_pointer = nullptr;
- tensorflow::Status session_status = tensorflow::NewSession(options, &session_pointer);
+ tensorflow::Status session_status =
+ tensorflow::NewSession(options, &session_pointer);
if (!session_status.ok()) {
LOG(ERROR) << "Could not create TensorFlow Session: " << session_status;
return session_status;
}
session->reset(session_pointer);
- LOG(INFO) << "Session created.";
-
+
tensorflow::GraphDef tensorflow_graph;
- LOG(INFO) << "Graph created.";
-
+
NSString* model_path = FilePathForResourceName(file_name, file_type);
if (!model_path) {
LOG(ERROR) << "Failed to find model proto at" << [file_name UTF8String]
@@ -139,37 +140,89 @@ tensorflow::Status LoadModel(NSString* file_name, NSString* file_type,
return tensorflow::errors::NotFound([file_name UTF8String],
[file_type UTF8String]);
}
- const bool read_proto_succeeded = PortableReadFileToProto(
- [model_path UTF8String], &tensorflow_graph);
+ const bool read_proto_succeeded =
+ PortableReadFileToProto([model_path UTF8String], &tensorflow_graph);
if (!read_proto_succeeded) {
LOG(ERROR) << "Failed to load model proto from" << [model_path UTF8String];
return tensorflow::errors::NotFound([model_path UTF8String]);
}
-
- LOG(INFO) << "Creating session.";
+
tensorflow::Status create_status = (*session)->Create(tensorflow_graph);
if (!create_status.ok()) {
LOG(ERROR) << "Could not create TensorFlow Graph: " << create_status;
return create_status;
}
-
+
+ return tensorflow::Status::OK();
+}
+
+tensorflow::Status LoadMemoryMappedModel(
+ NSString* file_name, NSString* file_type,
+ std::unique_ptr<tensorflow::Session>* session,
+ std::unique_ptr<tensorflow::MemmappedEnv>* memmapped_env) {
+ NSString* network_path = FilePathForResourceName(file_name, file_type);
+ memmapped_env->reset(
+ new tensorflow::MemmappedEnv(tensorflow::Env::Default()));
+ tensorflow::Status mmap_status =
+ (memmapped_env->get())->InitializeFromFile([network_path UTF8String]);
+ if (!mmap_status.ok()) {
+ LOG(ERROR) << "MMap failed with " << mmap_status.error_message();
+ return mmap_status;
+ }
+
+ tensorflow::GraphDef tensorflow_graph;
+ tensorflow::Status load_graph_status = ReadBinaryProto(
+ memmapped_env->get(),
+ tensorflow::MemmappedFileSystem::kMemmappedPackageDefaultGraphDef,
+ &tensorflow_graph);
+ if (!load_graph_status.ok()) {
+ LOG(ERROR) << "MMap load graph failed with "
+ << load_graph_status.error_message();
+ return load_graph_status;
+ }
+
+ tensorflow::SessionOptions options;
+ // Disable optimizations on this graph so that constant folding doesn't
+ // increase the memory footprint by creating new constant copies of the weight
+ // parameters.
+ options.config.mutable_graph_options()
+ ->mutable_optimizer_options()
+ ->set_opt_level(::tensorflow::OptimizerOptions::L0);
+ options.env = memmapped_env->get();
+
+ tensorflow::Session* session_pointer = nullptr;
+ tensorflow::Status session_status =
+ tensorflow::NewSession(options, &session_pointer);
+ if (!session_status.ok()) {
+ LOG(ERROR) << "Could not create TensorFlow Session: " << session_status;
+ return session_status;
+ }
+
+ tensorflow::Status create_status = session_pointer->Create(tensorflow_graph);
+ if (!create_status.ok()) {
+ LOG(ERROR) << "Could not create TensorFlow Graph: " << create_status;
+ return create_status;
+ }
+
+ session->reset(session_pointer);
+
return tensorflow::Status::OK();
}
tensorflow::Status LoadLabels(NSString* file_name, NSString* file_type,
- std::vector<std::string>* label_strings) {
+ std::vector<std::string>* label_strings) {
// Read the label list
NSString* labels_path = FilePathForResourceName(file_name, file_type);
if (!labels_path) {
LOG(ERROR) << "Failed to find model proto at" << [file_name UTF8String]
- << [file_type UTF8String];
+ << [file_type UTF8String];
return tensorflow::errors::NotFound([file_name UTF8String],
[file_type UTF8String]);
}
std::ifstream t;
t.open([labels_path UTF8String]);
std::string line;
- while(t){
+ while (t) {
std::getline(t, line);
label_strings->push_back(line);
}
diff --git a/tensorflow/contrib/ios_examples/simple/RunModelViewController.mm b/tensorflow/contrib/ios_examples/simple/RunModelViewController.mm
index 68e6bf8668..5c121962d9 100644
--- a/tensorflow/contrib/ios_examples/simple/RunModelViewController.mm
+++ b/tensorflow/contrib/ios_examples/simple/RunModelViewController.mm
@@ -239,7 +239,7 @@ NSString* RunInferenceOnImage() {
const float confidence = result.first;
const int index = result.second;
- ss << index << " " << confidence << " ";
+ ss << index << " " << confidence << " ";
// Write out the result as a string
if (index < label_strings.size()) {
diff --git a/tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj b/tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj
index 9e058be281..ae9f49dacd 100644
--- a/tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj
+++ b/tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj/project.pbxproj
@@ -274,8 +274,11 @@
591157B31CF4011D00C31E3A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_DEBUG_INFORMATION_LEVEL = default;
CODE_SIGN_IDENTITY = "iPhone Developer";
ENABLE_BITCODE = NO;
+ GCC_ENABLE_CPP_EXCEPTIONS = YES;
+ GCC_ENABLE_CPP_RTTI = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../../../..",
"$(SRCROOT)/../../makefile/downloads/protobuf/src/",
@@ -290,6 +293,7 @@
"$(SRCROOT)/../../makefile/gen/protobuf_ios/lib",
"$(SRCROOT)/../../makefile/gen/lib",
);
+ OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-force_load",
"$(SRCROOT)/../../makefile/gen/lib/libtensorflow-core.a",
@@ -302,14 +306,18 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "com.google.TF-Test";
PRODUCT_NAME = "$(TARGET_NAME)";
+ SEPARATE_STRIP = NO;
};
name = Debug;
};
591157B41CF4011D00C31E3A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_DEBUG_INFORMATION_LEVEL = default;
CODE_SIGN_IDENTITY = "iPhone Developer";
ENABLE_BITCODE = NO;
+ GCC_ENABLE_CPP_EXCEPTIONS = YES;
+ GCC_ENABLE_CPP_RTTI = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../../../..",
"$(SRCROOT)/../../makefile/downloads/protobuf/src/",
@@ -325,6 +333,7 @@
"$(SRCROOT)/../../makefile/gen/lib",
);
ONLY_ACTIVE_ARCH = YES;
+ OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-force_load",
"$(SRCROOT)/../../makefile/gen/lib/libtensorflow-core.a",
@@ -337,6 +346,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "com.google.TF-Test";
PRODUCT_NAME = "$(TARGET_NAME)";
+ SEPARATE_STRIP = NO;
};
name = Release;
};
diff --git a/tensorflow/contrib/layers/python/layers/feature_column.py b/tensorflow/contrib/layers/python/layers/feature_column.py
index 7b8df941f7..924d8c4e9e 100644
--- a/tensorflow/contrib/layers/python/layers/feature_column.py
+++ b/tensorflow/contrib/layers/python/layers/feature_column.py
@@ -1244,7 +1244,7 @@ class _RealValuedColumn(_FeatureColumn, collections.namedtuple(
return variable_scope.get_variable(
name,
shape=[self.dimension, num_outputs],
- initializer=array_ops.zeros_initializer,
+ initializer=init_ops.zeros_initializer,
collections=_add_variable_collection(weight_collections))
if self.name:
@@ -1834,7 +1834,7 @@ class DataFrameColumn(_FeatureColumn,
return variable_scope.get_variable(
name,
shape=[self.dimension, num_outputs],
- initializer=array_ops.zeros_initializer,
+ initializer=init_ops.zeros_initializer,
collections=_add_variable_collection(weight_collections))
if self.name:
diff --git a/tensorflow/contrib/layers/python/layers/feature_column_ops.py b/tensorflow/contrib/layers/python/layers/feature_column_ops.py
index 8da45f0be4..14b1d5eab3 100644
--- a/tensorflow/contrib/layers/python/layers/feature_column_ops.py
+++ b/tensorflow/contrib/layers/python/layers/feature_column_ops.py
@@ -375,7 +375,7 @@ def weighted_sum_from_feature_columns(columns_to_tensors,
variable = [contrib_variables.model_variable(
name='weight',
shape=[tensor.get_shape()[1], num_outputs],
- initializer=array_ops.zeros_initializer,
+ initializer=init_ops.zeros_initializer,
collections=weight_collections)]
predictions = math_ops.matmul(tensor, variable[0], name='matmul')
except ValueError as ee:
diff --git a/tensorflow/contrib/layers/python/layers/initializers.py b/tensorflow/contrib/layers/python/layers/initializers.py
index fef925ca7e..2d94c0b12c 100644
--- a/tensorflow/contrib/layers/python/layers/initializers.py
+++ b/tensorflow/contrib/layers/python/layers/initializers.py
@@ -112,7 +112,7 @@ def variance_scaling_initializer(factor=2.0, mode='FAN_IN', uniform=False,
raise TypeError('Cannot create initializer for non-floating point type.')
# Estimating fan_in and fan_out is not possible to do perfectly, but we try.
# This is the right thing for matrix multiply and convolutions.
- fan_in = float(shape[-2])
+ fan_in = float(shape[-2]) if len(shape) > 1 else float(shape[-1])
fan_out = float(shape[-1])
for dim in shape[:-2]:
fan_in *= float(dim)
diff --git a/tensorflow/contrib/layers/python/layers/initializers_test.py b/tensorflow/contrib/layers/python/layers/initializers_test.py
index d619dd8ee0..987454c789 100644
--- a/tensorflow/contrib/layers/python/layers/initializers_test.py
+++ b/tensorflow/contrib/layers/python/layers/initializers_test.py
@@ -168,5 +168,32 @@ class VarianceScalingInitializerTest(tf.test.TestCase):
mode='FAN_AVG',
uniform=True)
+ def test_1d_shape_fan_in(self):
+ for uniform in [False, True]:
+ self._test_variance(tf.contrib.layers.variance_scaling_initializer,
+ shape=[100],
+ variance=2. / 100.,
+ factor=2.0,
+ mode='FAN_IN',
+ uniform=uniform)
+
+ def test_1d_shape_fan_out(self):
+ for uniform in [False, True]:
+ self._test_variance(tf.contrib.layers.variance_scaling_initializer,
+ shape=[100],
+ variance=2. / 100.,
+ factor=2.0,
+ mode='FAN_OUT',
+ uniform=uniform)
+
+ def test_1d_shape_fan_avg(self):
+ for uniform in [False, True]:
+ self._test_variance(tf.contrib.layers.variance_scaling_initializer,
+ shape=[100],
+ variance=4. / (100. + 100.),
+ factor=2.0,
+ mode='FAN_AVG',
+ uniform=uniform)
+
if __name__ == '__main__':
tf.test.main()
diff --git a/tensorflow/contrib/layers/python/layers/layers.py b/tensorflow/contrib/layers/python/layers/layers.py
index 0947480d7c..08b40f77f5 100644
--- a/tensorflow/contrib/layers/python/layers/layers.py
+++ b/tensorflow/contrib/layers/python/layers/layers.py
@@ -135,7 +135,7 @@ def batch_norm(inputs,
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
if update_ops:
- updates = tf.group(update_ops)
+ updates = tf.group(*update_ops)
total_loss = control_flow_ops.with_dependencies([updates], total_loss)
One can set update_collections=None to force the updates in place, but that
@@ -150,7 +150,8 @@ def batch_norm(inputs,
not used. When the next layer is linear (also e.g. `nn.relu`), this can be
disabled since the scaling can be done by the next layer.
epsilon: small float added to variance to avoid dividing by zero.
- activation_fn: Optional activation function.
+ activation_fn: activation function, default set to None to skip it and
+ maintain a linear activation.
updates_collections: collections to collect the update ops for computation.
The updates_ops need to be excuted with the train_op.
If None, a control dependency would be added to make sure the updates are
@@ -275,7 +276,7 @@ def batch_norm(inputs,
outputs = nn.batch_normalization(
inputs, mean, variance, beta, gamma, epsilon)
outputs.set_shape(inputs_shape)
- if activation_fn:
+ if activation_fn is not None:
outputs = activation_fn(outputs)
return utils.collect_named_outputs(outputs_collections,
sc.original_name_scope, outputs)
@@ -298,7 +299,8 @@ def bias_add(inputs,
Args:
inputs: a tensor of with at least rank 2 and value for the last dimension,
e.g. `[batch_size, depth]`, `[None, None, None, depth]`.
- activation_fn: Optional activation function.
+ activation_fn: activation function, default set to None to skip it and
+ maintain a linear activation.
initializer: An initializer for the bias, defaults to 0.
regularizer: A regularizer like the result of
`l1_regularizer` or `l2_regularizer`.
@@ -328,7 +330,7 @@ def bias_add(inputs,
collections=biases_collections,
trainable=trainable)
outputs = nn.bias_add(inputs, biases)
- if activation_fn:
+ if activation_fn is not None:
outputs = activation_fn(outputs)
return utils.collect_named_outputs(outputs_collections,
sc.original_name_scope, outputs)
@@ -378,10 +380,12 @@ def convolution2d(inputs,
rate: integer. If less than or equal to 1, a standard convolution is used.
If greater than 1, than the a'trous convolution is applied and `stride`
must be set to 1.
- activation_fn: activation function.
+ activation_fn: activation function, set to None to skip it and maintain
+ a linear activation.
normalizer_fn: normalization function to use instead of `biases`. If
- `normalize_fn` is provided then `biases_initializer` and
+ `normalizer_fn` is provided then `biases_initializer` and
`biases_regularizer` are ignored and `biases` are not created nor added.
+ default set to None for no normalizer function
normalizer_params: normalization function parameters.
weights_initializer: An initializer for the weights.
weights_regularizer: Optional regularizer for the weights.
@@ -427,7 +431,7 @@ def convolution2d(inputs,
else:
outputs = nn.conv2d(inputs, weights, [1, stride_h, stride_w, 1],
padding=padding)
- if normalizer_fn:
+ if normalizer_fn is not None:
normalizer_params = normalizer_params or {}
outputs = normalizer_fn(outputs, **normalizer_params)
else:
@@ -442,7 +446,7 @@ def convolution2d(inputs,
collections=biases_collections,
trainable=trainable)
outputs = nn.bias_add(outputs, biases)
- if activation_fn:
+ if activation_fn is not None:
outputs = activation_fn(outputs)
return utils.collect_named_outputs(outputs_collections,
sc.original_name_scope, outputs)
@@ -487,10 +491,12 @@ def convolution2d_in_plane(
Can be an int if both strides are the same. Note that presently
both strides must have the same value.
padding: the padding type to use, either 'SAME' or 'VALID'.
- activation_fn: activation function.
+ activation_fn: activation function, set to None to skip it and maintain
+ a linear activation.
normalizer_fn: normalization function to use instead of `biases`. If
- `normalize_fn` is provided then `biases_initializer` and
+ `normalizer_fn` is provided then `biases_initializer` and
`biases_regularizer` are ignored and `biases` are not created nor added.
+ default set to None for no normalizer function
normalizer_params: normalization function parameters.
weights_initializer: An initializer for the weights.
weights_regularizer: Optional regularizer for the weights.
@@ -527,7 +533,7 @@ def convolution2d_in_plane(
depthwise_weights = array_ops.tile(weights, [1, 1, num_filters_in, 1])
outputs = nn.depthwise_conv2d(inputs, depthwise_weights,
[1, stride_h, stride_w, 1], padding)
- if normalizer_fn:
+ if normalizer_fn is not None:
normalizer_params = normalizer_params or {}
outputs = normalizer_fn(outputs, **normalizer_params)
else:
@@ -543,7 +549,7 @@ def convolution2d_in_plane(
trainable=trainable)
outputs = nn.bias_add(outputs, biases)
- if activation_fn:
+ if activation_fn is not None:
outputs = activation_fn(outputs)
return utils.collect_named_outputs(outputs_collections,
sc.original_name_scope, outputs)
@@ -583,10 +589,12 @@ def convolution2d_transpose(
Can be an int if both strides are the same. Note that presently
both strides must have the same value.
padding: one of 'VALID' or 'SAME'.
- activation_fn: activation function.
+ activation_fn: activation function, set to None to skip it and maintain
+ a linear activation.
normalizer_fn: normalization function to use instead of `biases`. If
- `normalize_fn` is provided then `biases_initializer` and
+ `normalizer_fn` is provided then `biases_initializer` and
`biases_regularizer` are ignored and `biases` are not created nor added.
+ default set to None for no normalizer function
normalizer_params: normalization function parameters.
weights_initializer: An initializer for the weights.
weights_regularizer: Optional regularizer for the weights.
@@ -656,7 +664,7 @@ def convolution2d_transpose(
out_shape[2] = get_deconv_dim(out_shape[2], stride_w, kernel_w, padding)
outputs.set_shape(out_shape)
- if normalizer_fn:
+ if normalizer_fn is not None:
normalizer_params = normalizer_params or {}
outputs = normalizer_fn(outputs, **normalizer_params)
else:
@@ -671,7 +679,7 @@ def convolution2d_transpose(
collections=biases_collections)
outputs = nn.bias_add(outputs, biases)
- if activation_fn:
+ if activation_fn is not None:
outputs = activation_fn(outputs)
return utils.collect_named_outputs(outputs_collections,
sc.original_name_scope, outputs)
@@ -777,10 +785,12 @@ def fully_connected(inputs,
inputs: A tensor of with at least rank 2 and value for the last dimension,
i.e. `[batch_size, depth]`, `[None, None, None, channels]`.
num_outputs: Integer or long, the number of output units in the layer.
- activation_fn: activation function.
+ activation_fn: activation function, set to None to skip it and maintain
+ a linear activation.
normalizer_fn: normalization function to use instead of `biases`. If
- `normalize_fn` is provided then `biases_initializer` and
+ `normalizer_fn` is provided then `biases_initializer` and
`biases_regularizer` are ignored and `biases` are not created nor added.
+ default set to None for no normalizer function
normalizer_params: normalization function parameters.
weights_initializer: An initializer for the weights.
weights_regularizer: Optional regularizer for the weights.
@@ -830,7 +840,7 @@ def fully_connected(inputs,
# Reshape inputs
inputs = array_ops.reshape(inputs, [-1, num_input_units])
outputs = standard_ops.matmul(inputs, weights)
- if normalizer_fn:
+ if normalizer_fn is not None:
normalizer_params = normalizer_params or {}
outputs = normalizer_fn(outputs, **normalizer_params)
else:
@@ -845,7 +855,7 @@ def fully_connected(inputs,
collections=biases_collections,
trainable=trainable)
outputs = nn.bias_add(outputs, biases)
- if activation_fn:
+ if activation_fn is not None:
outputs = activation_fn(outputs)
if len(static_shape) > 2:
# Reshape back outputs
@@ -880,7 +890,8 @@ def layer_norm(inputs,
scale: If True, multiply by `gamma`. If False, `gamma` is
not used. When the next layer is linear (also e.g. `nn.relu`), this can be
disabled since the scaling can be done by the next layer.
- activation_fn: Optional activation function.
+ activation_fn: activation function, default set to None to skip it and
+ maintain a linear activation.
reuse: whether or not the layer and its variables should be reused. To be
able to reuse the layer scope must be given.
variables_collections: optional collections for the variables.
@@ -935,7 +946,7 @@ def layer_norm(inputs,
outputs = nn.batch_normalization(
inputs, mean, variance, beta, gamma, variance_epsilon)
outputs.set_shape(inputs_shape)
- if activation_fn:
+ if activation_fn is not None:
outputs = activation_fn(outputs)
return utils.collect_named_outputs(outputs_collections,
sc.original_name_scope,
@@ -1014,7 +1025,7 @@ def one_hot_encoding(labels,
def _apply_activation(y, activation_fn, output_collections):
- if activation_fn:
+ if activation_fn is not None:
y = activation_fn(y)
ops.add_to_collections(list(output_collections or []) +
[ops.GraphKeys.ACTIVATIONS], y)
@@ -1109,10 +1120,12 @@ def separable_convolution2d(
stride: a list of length 2: [stride_height, stride_width], specifying the
depthwise convolution stride. Can be an int if both strides are the same.
padding: one of 'VALID' or 'SAME'.
- activation_fn: activation function.
+ activation_fn: activation function, set to None to skip it and maintain
+ a linear activation.
normalizer_fn: normalization function to use instead of `biases`. If
- `normalize_fn` is provided then `biases_initializer` and
+ `normalizer_fn` is provided then `biases_initializer` and
`biases_regularizer` are ignored and `biases` are not created nor added.
+ default set to None for no normalizer function
normalizer_params: normalization function parameters.
weights_initializer: An initializer for the weights.
weights_regularizer: Optional regularizer for the weights.
@@ -1171,7 +1184,7 @@ def separable_convolution2d(
outputs = nn.depthwise_conv2d(inputs, depthwise_weights, strides, padding)
num_outputs = depth_multiplier * num_filters_in
- if normalizer_fn:
+ if normalizer_fn is not None:
normalizer_params = normalizer_params or {}
outputs = normalizer_fn(outputs, **normalizer_params)
else:
@@ -1186,7 +1199,7 @@ def separable_convolution2d(
collections=biases_collections)
outputs = nn.bias_add(outputs, biases)
- if activation_fn:
+ if activation_fn is not None:
outputs = activation_fn(outputs)
return utils.collect_named_outputs(outputs_collections,
sc.original_name_scope, outputs)
@@ -1362,8 +1375,8 @@ def legacy_fully_connected(x,
Args:
x: The input `Tensor`.
num_output_units: The size of the output.
- activation_fn: A function that requires a single Tensor that is applied as a
- non-linearity. If None is used, do not apply any activation.
+ activation_fn: activation function, default set to None to skip it and
+ maintain a linear activation.
weight_init: An optional weight initialization, defaults to
`xavier_initializer`.
bias_init: An initializer for the bias, defaults to 0. Set to `None` in
diff --git a/tensorflow/contrib/learn/BUILD b/tensorflow/contrib/learn/BUILD
index cf9d4265f6..177936bead 100644
--- a/tensorflow/contrib/learn/BUILD
+++ b/tensorflow/contrib/learn/BUILD
@@ -408,6 +408,7 @@ py_test(
size = "small",
srcs = ["python/learn/estimators/classifier_test.py"],
srcs_version = "PY2AND3",
+ tags = ["manual"], # http://b/31032996
deps = [
":learn",
"//tensorflow:tensorflow_py",
diff --git a/tensorflow/contrib/learn/python/learn/datasets/base.py b/tensorflow/contrib/learn/python/learn/datasets/base.py
index feca15ac0e..2e1702a612 100644
--- a/tensorflow/contrib/learn/python/learn/datasets/base.py
+++ b/tensorflow/contrib/learn/python/learn/datasets/base.py
@@ -35,21 +35,6 @@ Dataset = collections.namedtuple('Dataset', ['data', 'target'])
Datasets = collections.namedtuple('Datasets', ['train', 'validation', 'test'])
-@deprecated('2016-09-15', 'Please use load_csv_{with|without}_header instead.')
-def load_csv(filename, target_dtype, target_column=-1, has_header=True):
- """Load dataset from CSV file."""
- if has_header:
- return load_csv_with_header(filename=filename,
- target_dtype=target_dtype,
- features_dtype=np.float64,
- target_column=target_column)
- else:
- return load_csv_without_header(filename=filename,
- target_dtype=target_dtype,
- features_dtype=np.float64,
- target_column=target_column)
-
-
def load_csv_with_header(filename,
target_dtype,
features_dtype,
@@ -60,7 +45,7 @@ def load_csv_with_header(filename,
header = next(data_file)
n_samples = int(header[0])
n_features = int(header[1])
- data = np.zeros((n_samples, n_features))
+ data = np.zeros((n_samples, n_features), dtype=features_dtype)
target = np.zeros((n_samples,), dtype=target_dtype)
for i, row in enumerate(data_file):
target[i] = np.asarray(row.pop(target_column), dtype=target_dtype)
@@ -83,8 +68,7 @@ def load_csv_without_header(filename,
target = np.array(target, dtype=target_dtype)
data = np.array(data)
- return Dataset(data=np.array(data),
- target=np.array(target).astype(target_dtype))
+ return Dataset(data=data, target=target)
def shrink_csv(filename, ratio):
diff --git a/tensorflow/contrib/learn/python/learn/models.py b/tensorflow/contrib/learn/python/learn/models.py
index 59e21986de..749eeadb1f 100644
--- a/tensorflow/contrib/learn/python/learn/models.py
+++ b/tensorflow/contrib/learn/python/learn/models.py
@@ -22,8 +22,6 @@ from __future__ import print_function
import functools
from tensorflow.contrib import rnn as contrib_rnn
-from tensorflow.contrib.learn.python.learn.ops import autoencoder_ops
-from tensorflow.contrib.learn.python.learn.ops import dnn_ops
from tensorflow.contrib.learn.python.learn.ops import losses_ops
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops
@@ -177,31 +175,6 @@ def logistic_regression(x,
class_weight=class_weight)
-def get_dnn_model(hidden_units, target_predictor_fn, dropout=None):
- """Returns a function that creates a DNN TensorFlow subgraph.
-
- Args:
- hidden_units: List of values of hidden units for layers.
- target_predictor_fn: Function that will predict target from input
- features. This can be logistic regression,
- linear regression or any other model,
- that takes x, y and returns predictions and loss
- tensors.
- dropout: When not none, causes dropout regularization to be used,
- with the specified probability of removing a given coordinate.
-
- Returns:
- A function that creates the subgraph.
- """
-
- def dnn_estimator(x, y):
- """DNN estimator with target predictor function on top."""
- layers = dnn_ops.dnn(x, hidden_units, dropout=dropout)
- return target_predictor_fn(layers, y)
-
- return dnn_estimator
-
-
## This will be in TensorFlow 0.7.
## TODO(ilblackdragon): Clean this up when it's released
def _reverse_seq(input_seq, lengths):
diff --git a/tensorflow/contrib/learn/python/learn/ops/__init__.py b/tensorflow/contrib/learn/python/learn/ops/__init__.py
index 7ef031fbeb..d9f8fb83b1 100644
--- a/tensorflow/contrib/learn/python/learn/ops/__init__.py
+++ b/tensorflow/contrib/learn/python/learn/ops/__init__.py
@@ -21,8 +21,6 @@ from __future__ import print_function
# pylint: disable=wildcard-import
from tensorflow.contrib.learn.python.learn.ops.array_ops import *
-from tensorflow.contrib.learn.python.learn.ops.autoencoder_ops import *
-from tensorflow.contrib.learn.python.learn.ops.dnn_ops import *
from tensorflow.contrib.learn.python.learn.ops.embeddings_ops import *
from tensorflow.contrib.learn.python.learn.ops.losses_ops import *
from tensorflow.contrib.learn.python.learn.ops.seq2seq_ops import *
diff --git a/tensorflow/contrib/learn/python/learn/ops/autoencoder_ops.py b/tensorflow/contrib/learn/python/learn/ops/autoencoder_ops.py
deleted file mode 100644
index 8a67e41319..0000000000
--- a/tensorflow/contrib/learn/python/learn/ops/autoencoder_ops.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ==============================================================================
-
-"""TensorFlow ops for autoencoder."""
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-
-from tensorflow.contrib.learn.python.learn.ops import dnn_ops
-from tensorflow.python.ops import nn
-from tensorflow.python.ops import variable_scope as vs
-
-
-def dnn_autoencoder(
- tensor_in, hidden_units, activation=nn.relu, add_noise=None, dropout=None,
- scope=None):
- """Creates fully connected autoencoder subgraph.
-
- Args:
- tensor_in: tensor or placeholder for input features.
- hidden_units: list of counts of hidden units in each layer.
- activation: activation function used to map inner latent layer onto
- reconstruction layer.
- add_noise: a function that adds noise to tensor_in,
- e.g. def add_noise(x):
- return(x + np.random.normal(0, 0.1, (len(x), len(x[0]))))
- dropout: if not None, will add a dropout layer with given
- probability.
- scope: the variable scope for this op.
-
- Returns:
- Tensors for encoder and decoder.
- """
- with vs.variable_scope(scope, "autoencoder", [tensor_in]):
- if add_noise is not None:
- tensor_in = add_noise(tensor_in)
- with vs.variable_scope("encoder"):
- # build DNN encoder
- encoder = dnn_ops.dnn(
- tensor_in, hidden_units, activation=activation, dropout=dropout)
- with vs.variable_scope("decoder"):
- # reverse hidden_units and built DNN decoder
- decoder = dnn_ops.dnn(
- encoder, hidden_units[::-1], activation=activation, dropout=dropout)
- return encoder, decoder
diff --git a/tensorflow/contrib/makefile/Makefile b/tensorflow/contrib/makefile/Makefile
index f1a0bd0897..a365a99004 100644
--- a/tensorflow/contrib/makefile/Makefile
+++ b/tensorflow/contrib/makefile/Makefile
@@ -140,7 +140,7 @@ $(shell mkdir -p $(DEPDIR) >/dev/null)
# Settings for the target compiler.
CXX := $(CC_PREFIX) gcc
OPTFLAGS := -O0
-CXXFLAGS := --std=c++11 -DIS_SLIM_BUILD $(OPTFLAGS)
+CXXFLAGS := --std=c++11 -DIS_SLIM_BUILD -fno-exceptions -DNDEBUG $(OPTFLAGS)
LDFLAGS := \
-L/usr/local/lib
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td
@@ -188,7 +188,9 @@ ifeq ($(HAS_GEN_HOST_PROTOC),true)
LIBFLAGS += -L$(MAKEFILE_DIR)/gen/protobuf-host/lib
export LD_LIBRARY_PATH=$(MAKEFILE_DIR)/gen/protobuf-host/lib
endif
+ CXXFLAGS += -fPIC
LIBFLAGS += -Wl,--allow-multiple-definition -Wl,--whole-archive
+ LDFLAGS := -Wl,--no-whole-archive
endif
# If we're on Linux, also link in the dl library.
ifeq ($(TARGET),LINUX)
@@ -282,7 +284,7 @@ ifeq ($(TARGET),IOS)
IPHONESIMULATOR_SYSROOT := $(shell xcrun --sdk iphonesimulator \
--show-sdk-path)
IOS_SDK_VERSION := $(shell xcrun --sdk iphoneos --show-sdk-version)
- MIN_SDK_VERSION := 9.2
+ MIN_SDK_VERSION := 8.2
# Override IOS_ARCH with ARMV7, ARMV7S, ARM64, or I386.
IOS_ARCH := X86_64
ifeq ($(IOS_ARCH),ARMV7)
diff --git a/tensorflow/contrib/makefile/compile_ios_protobuf.sh b/tensorflow/contrib/makefile/compile_ios_protobuf.sh
index d2b1d4e846..5ccb771e95 100755
--- a/tensorflow/contrib/makefile/compile_ios_protobuf.sh
+++ b/tensorflow/contrib/makefile/compile_ios_protobuf.sh
@@ -45,9 +45,9 @@ IPHONEOS_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path`
IPHONESIMULATOR_PLATFORM=`xcrun --sdk iphonesimulator --show-sdk-platform-path`
IPHONESIMULATOR_SYSROOT=`xcrun --sdk iphonesimulator --show-sdk-path`
IOS_SDK_VERSION=`xcrun --sdk iphoneos --show-sdk-version`
-MIN_SDK_VERSION=9.2
+MIN_SDK_VERSION=8.2
-CFLAGS="-DNDEBUG -g -O0 -pipe -fPIC -fcxx-exceptions"
+CFLAGS="-DNDEBUG -Os -pipe -fPIC -fno-exceptions"
CXXFLAGS="${CFLAGS} -std=c++11 -stdlib=libc++"
LDFLAGS="-stdlib=libc++"
LIBS="-lc++ -lc++abi"
diff --git a/tensorflow/contrib/makefile/compile_ios_tensorflow.sh b/tensorflow/contrib/makefile/compile_ios_tensorflow.sh
index 0c0edb7bd1..61ab844f18 100755
--- a/tensorflow/contrib/makefile/compile_ios_tensorflow.sh
+++ b/tensorflow/contrib/makefile/compile_ios_tensorflow.sh
@@ -16,9 +16,21 @@
# Builds the TensorFlow core library with ARM and x86 architectures for iOS, and
# packs them into a fat file.
+function less_than_required_version() {
+ echo $1 | (IFS=. read major minor micro
+ if [ $major -ne $2 ]; then
+ [ $major -lt $2 ]
+ elif [ $minor -ne $3 ]; then
+ [ $minor -lt $3 ]
+ else
+ [ ${micro:-0} -lt $4 ]
+ fi
+ )
+}
+
ACTUAL_XCODE_VERSION=`xcodebuild -version | head -n 1 | sed 's/Xcode //'`
REQUIRED_XCODE_VERSION=7.3.0
-if [ ${ACTUAL_XCODE_VERSION//.} -lt ${REQUIRED_XCODE_VERSION//.} ]
+if less_than_required_version $ACTUAL_XCODE_VERSION 7 3 0
then
echo "error: Xcode ${REQUIRED_XCODE_VERSION} or later is required."
exit 1
diff --git a/tensorflow/contrib/metrics/python/ops/histogram_ops.py b/tensorflow/contrib/metrics/python/ops/histogram_ops.py
index 77a4140180..56f4193a66 100644
--- a/tensorflow/contrib/metrics/python/ops/histogram_ops.py
+++ b/tensorflow/contrib/metrics/python/ops/histogram_ops.py
@@ -30,6 +30,7 @@ from tensorflow.python.framework import ops
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import control_flow_ops
from tensorflow.python.ops import histogram_ops
+from tensorflow.python.ops import init_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import nn_ops
from tensorflow.python.ops import variable_scope
@@ -152,7 +153,7 @@ def _auc_hist_accumulate(hist_true, hist_false, nbins, collections):
# Holds running total histogram of scores for records labeled True.
hist_true_acc = variable_scope.get_variable(
'hist_true_acc',
- initializer=array_ops.zeros_initializer(
+ initializer=init_ops.zeros_initializer(
[nbins],
dtype=hist_true.dtype),
collections=collections,
@@ -160,7 +161,7 @@ def _auc_hist_accumulate(hist_true, hist_false, nbins, collections):
# Holds running total histogram of scores for records labeled False.
hist_false_acc = variable_scope.get_variable(
'hist_false_acc',
- initializer=array_ops.zeros_initializer(
+ initializer=init_ops.zeros_initializer(
[nbins],
dtype=hist_false.dtype),
collections=collections,
diff --git a/tensorflow/contrib/quantization/tools/quantize_graph.py b/tensorflow/contrib/quantization/tools/quantize_graph.py
index 0a814dadae..5ded556691 100644
--- a/tensorflow/contrib/quantization/tools/quantize_graph.py
+++ b/tensorflow/contrib/quantization/tools/quantize_graph.py
@@ -981,7 +981,7 @@ def main(unused_args):
return -1
tf_graph = tf.GraphDef()
- with tf.gfile.Open(FLAGS.input, "r") as f:
+ with tf.gfile.Open(FLAGS.input, "rb") as f:
data = f.read()
tf_graph.ParseFromString(data)
@@ -993,7 +993,7 @@ def main(unused_args):
output_graph = rewriter.rewrite(FLAGS.output_node_names.split(","))
- f = tf.gfile.FastGFile(FLAGS.output, "w")
+ f = tf.gfile.FastGFile(FLAGS.output, "wb")
f.write(output_graph.SerializeToString())
return 0
diff --git a/tensorflow/contrib/rnn/python/ops/rnn_cell.py b/tensorflow/contrib/rnn/python/ops/rnn_cell.py
index 4307c50893..9e000a186f 100644
--- a/tensorflow/contrib/rnn/python/ops/rnn_cell.py
+++ b/tensorflow/contrib/rnn/python/ops/rnn_cell.py
@@ -207,7 +207,7 @@ class CoupledInputForgetGateLSTMCell(rnn_cell.RNNCell):
b = vs.get_variable(
"B", shape=[3 * self._num_units],
- initializer=array_ops.zeros_initializer, dtype=dtype)
+ initializer=init_ops.zeros_initializer, dtype=dtype)
# j = new_input, f = forget_gate, o = output_gate
cell_inputs = array_ops.concat(1, [inputs, m_prev])
@@ -334,7 +334,7 @@ class TimeFreqLSTMCell(rnn_cell.RNNCell):
dtype, self._num_unit_shards)
b = vs.get_variable(
"B", shape=[4 * self._num_units],
- initializer=array_ops.zeros_initializer, dtype=dtype)
+ initializer=init_ops.zeros_initializer, dtype=dtype)
# Diagonal connections
if self._use_peepholes:
@@ -537,7 +537,7 @@ class GridLSTMCell(rnn_cell.RNNCell):
dtype, self._num_unit_shards)
b_f = vs.get_variable(
"B_f", shape=[num_gates * self._num_units],
- initializer=array_ops.zeros_initializer, dtype=dtype)
+ initializer=init_ops.zeros_initializer, dtype=dtype)
if not self._share_time_frequency_weights:
concat_w_t = _get_concat_variable(
"W_t", [actual_input_size + 2 * self._num_units,
@@ -545,7 +545,7 @@ class GridLSTMCell(rnn_cell.RNNCell):
dtype, self._num_unit_shards)
b_t = vs.get_variable(
"B_t", shape=[num_gates * self._num_units],
- initializer=array_ops.zeros_initializer, dtype=dtype)
+ initializer=init_ops.zeros_initializer, dtype=dtype)
if self._use_peepholes:
# Diagonal connections
diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD
index 12fc04dace..6ea20c8e47 100644
--- a/tensorflow/core/BUILD
+++ b/tensorflow/core/BUILD
@@ -1099,6 +1099,7 @@ filegroup(
"lib/core/refcount.h",
"lib/core/status.h",
"lib/core/stringpiece.h",
+ "lib/core/threadpool.h",
"lib/gtl/array_slice.h",
"lib/gtl/array_slice_internal.h",
"lib/gtl/inlined_vector.h",
@@ -1513,7 +1514,7 @@ tf_cc_tests(
"framework/op_kernel_test.cc",
"framework/op_registration_test.cc",
"framework/partial_tensor_shape_test.cc",
- "framework/rendezvous_test.cc",
+ # "framework/rendezvous_test.cc", # flaky b/30476344
"framework/resource_mgr_test.cc",
"framework/shape_inference_test.cc",
"framework/shape_inference_testutil_test.cc",
diff --git a/tensorflow/core/kernels/conv_ops_using_gemm.cc b/tensorflow/core/kernels/conv_ops_using_gemm.cc
index 6da6da846b..2b00b6dbeb 100644
--- a/tensorflow/core/kernels/conv_ops_using_gemm.cc
+++ b/tensorflow/core/kernels/conv_ops_using_gemm.cc
@@ -262,14 +262,16 @@ class Im2ColConvFunctor {
errors::InvalidArgument("Im2Col patch too large for buffer"));
const size_t patches_per_chunk =
max_chunk_size / (filter_value_count * sizeof(T1));
+ const size_t chunk_value_count =
+ (max_chunk_size + (sizeof(T1) - 1)) / sizeof(T1);
// Because memory allocation is very expensive on mobile platforms, try to
// allocate a persistent buffer that will be kept around between calls. We
// use TensorFlow's resource management to ensure that the memory will be
// released when the session is over.
- Im2ColBufferResource<T1, max_chunk_size>* im2col_buffer_resource;
- std::function<Status(Im2ColBufferResource<T1, max_chunk_size>**)> creator =
- [](Im2ColBufferResource<T1, max_chunk_size>** resource) {
- *resource = new Im2ColBufferResource<T1, max_chunk_size>();
+ Im2ColBufferResource<T1, chunk_value_count>* im2col_buffer_resource;
+ std::function<Status(Im2ColBufferResource<T1, chunk_value_count>**)> creator =
+ [](Im2ColBufferResource<T1, chunk_value_count>** resource) {
+ *resource = new Im2ColBufferResource<T1, chunk_value_count>();
return Status::OK();
};
OP_REQUIRES_OK(context, context->resource_manager()->LookupOrCreate(
diff --git a/tensorflow/core/kernels/cwise_op_gpu_logical_and.cu.cc b/tensorflow/core/kernels/cwise_op_gpu_logical_and.cu.cc
index c62c377ded..1943779d21 100644
--- a/tensorflow/core/kernels/cwise_op_gpu_logical_and.cu.cc
+++ b/tensorflow/core/kernels/cwise_op_gpu_logical_and.cu.cc
@@ -22,6 +22,8 @@ namespace functor {
template struct BinaryFunctor<GPUDevice, logical_and, 1>;
template struct BinaryFunctor<GPUDevice, logical_and, 2>;
template struct BinaryFunctor<GPUDevice, logical_and, 3>;
+template struct BinaryFunctor<GPUDevice, logical_and, 4>;
+template struct BinaryFunctor<GPUDevice, logical_and, 5>;
} // namespace functor
} // namespace tensorflow
diff --git a/tensorflow/core/kernels/cwise_op_gpu_logical_or.cu.cc b/tensorflow/core/kernels/cwise_op_gpu_logical_or.cu.cc
index cccb2ebc36..8b39770652 100644
--- a/tensorflow/core/kernels/cwise_op_gpu_logical_or.cu.cc
+++ b/tensorflow/core/kernels/cwise_op_gpu_logical_or.cu.cc
@@ -22,6 +22,8 @@ namespace functor {
template struct BinaryFunctor<GPUDevice, logical_or, 1>;
template struct BinaryFunctor<GPUDevice, logical_or, 2>;
template struct BinaryFunctor<GPUDevice, logical_or, 3>;
+template struct BinaryFunctor<GPUDevice, logical_or, 4>;
+template struct BinaryFunctor<GPUDevice, logical_or, 5>;
} // namespace functor
} // namespace tensorflow
diff --git a/tensorflow/core/kernels/cwise_ops_common.h b/tensorflow/core/kernels/cwise_ops_common.h
index aa9c55a2ca..9e27ff9370 100644
--- a/tensorflow/core/kernels/cwise_ops_common.h
+++ b/tensorflow/core/kernels/cwise_ops_common.h
@@ -122,6 +122,20 @@ class BinaryOp : public BinaryOpShared {
BCast::ToIndexArray<3>(bcast->x_bcast()),
in1.shaped<Tin, 3>(bcast->y_reshape()),
BCast::ToIndexArray<3>(bcast->y_bcast()), error_ptr);
+ } else if (ndims == 4) {
+ functor::BinaryFunctor<Device, Functor, 4>().BCast(
+ eigen_device, out->shaped<Tout, 4>(bcast->result_shape()),
+ in0.shaped<Tin, 4>(bcast->x_reshape()),
+ BCast::ToIndexArray<4>(bcast->x_bcast()),
+ in1.shaped<Tin, 4>(bcast->y_reshape()),
+ BCast::ToIndexArray<4>(bcast->y_bcast()), error_ptr);
+ } else if (ndims == 5) {
+ functor::BinaryFunctor<Device, Functor, 5>().BCast(
+ eigen_device, out->shaped<Tout, 5>(bcast->result_shape()),
+ in0.shaped<Tin, 5>(bcast->x_reshape()),
+ BCast::ToIndexArray<5>(bcast->x_bcast()),
+ in1.shaped<Tin, 5>(bcast->y_reshape()),
+ BCast::ToIndexArray<5>(bcast->y_bcast()), error_ptr);
} else {
SetUnimplementedError(ctx);
}
diff --git a/tensorflow/core/kernels/cwise_ops_gpu_common.cu.h b/tensorflow/core/kernels/cwise_ops_gpu_common.cu.h
index 30d118466c..8eee18e648 100644
--- a/tensorflow/core/kernels/cwise_ops_gpu_common.cu.h
+++ b/tensorflow/core/kernels/cwise_ops_gpu_common.cu.h
@@ -128,7 +128,9 @@ struct BinaryFunctor<GPUDevice, Functor, NDIMS, has_errors> {
#define DEFINE_BINARY1(F, T) \
template struct BinaryFunctor<GPUDevice, F<T>, 1>; \
template struct BinaryFunctor<GPUDevice, F<T>, 2>; \
- template struct BinaryFunctor<GPUDevice, F<T>, 3>
+ template struct BinaryFunctor<GPUDevice, F<T>, 3>; \
+ template struct BinaryFunctor<GPUDevice, F<T>, 4>; \
+ template struct BinaryFunctor<GPUDevice, F<T>, 5>
#define DEFINE_BINARY2(F, T0, T1) \
DEFINE_BINARY1(F, T0); \
DEFINE_BINARY1(F, T1)
diff --git a/tensorflow/core/ops/image_ops.cc b/tensorflow/core/ops/image_ops.cc
index 85aab241f5..1449dfc74b 100644
--- a/tensorflow/core/ops/image_ops.cc
+++ b/tensorflow/core/ops/image_ops.cc
@@ -578,7 +578,7 @@ bounding box coordinates are floats in `[0.0, 1.0]` relative to the width and
height of the underlying image.
For example, if an image is 100 x 200 pixels and the bounding box is
-`[0.1, 0.5, 0.2, 0.9]`, the bottom-left and upper-right coordinates of the
+`[0.1, 0.2, 0.5, 0.9]`, the bottom-left and upper-right coordinates of the
bounding box will be `(10, 40)` to `(50, 180)`.
Parts of the bounding box may fall outside the image.
diff --git a/tensorflow/core/platform/default/logging.h b/tensorflow/core/platform/default/logging.h
index 1d7022bd45..dc4e6eb3fe 100644
--- a/tensorflow/core/platform/default/logging.h
+++ b/tensorflow/core/platform/default/logging.h
@@ -20,6 +20,7 @@ limitations under the License.
// IWYU pragma: friend third_party/tensorflow/core/platform/logging.h
#include <sstream>
+#include <limits>
#include "tensorflow/core/platform/macros.h"
#include "tensorflow/core/platform/types.h"
@@ -173,6 +174,8 @@ string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
// The (int, int) specialization works around the issue that the compiler
// will not instantiate the template version of the function on values of
// unnamed enum type - see comment below.
+// The (size_t, int) and (int, size_t) specialization are to handle unsigned
+// comparison errors while still being thorough with the comparison.
#define TF_DEFINE_CHECK_OP_IMPL(name, op) \
template <typename T1, typename T2> \
inline string* name##Impl(const T1& v1, const T2& v2, \
@@ -184,6 +187,20 @@ string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
} \
inline string* name##Impl(int v1, int v2, const char* exprtext) { \
return name##Impl<int, int>(v1, v2, exprtext); \
+ } \
+ inline string* name##Impl(const size_t v1, const int v2, const char* exprtext) { \
+ if (TF_PREDICT_FALSE(v2 < 0)) { \
+ return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext);\
+ } \
+ const size_t uval = (size_t)((unsigned)v1); \
+ return name##Impl<size_t, size_t>(uval, v2, exprtext); \
+ } \
+ inline string* name##Impl(const int v1, const size_t v2, const char* exprtext) { \
+ if (TF_PREDICT_FALSE(v2 >= std::numeric_limits<int>::max())) { \
+ return ::tensorflow::internal::MakeCheckOpString(v1, v2, exprtext);\
+ } \
+ const size_t uval = (size_t)((unsigned)v2); \
+ return name##Impl<size_t, size_t>(v1, uval, exprtext); \
}
// We use the full name Check_EQ, Check_NE, etc. in case the file including
diff --git a/tensorflow/core/protobuf/config.proto b/tensorflow/core/protobuf/config.proto
index 7cb93648cd..327710444e 100644
--- a/tensorflow/core/protobuf/config.proto
+++ b/tensorflow/core/protobuf/config.proto
@@ -123,7 +123,7 @@ message ThreadPoolOptionProto {
};
// Session configuration parameters.
-// The system picks an appropriate values for fields that are not set.
+// The system picks appropriate values for fields that are not set.
message ConfigProto {
// Map from device type name (e.g., "CPU" or "GPU" ) to maximum
// number of devices of that type to use. If a particular device
diff --git a/tensorflow/core/public/version.h b/tensorflow/core/public/version.h
index efdb6d0a65..50d86bff32 100644
--- a/tensorflow/core/public/version.h
+++ b/tensorflow/core/public/version.h
@@ -20,7 +20,7 @@ limitations under the License.
#define TF_MAJOR_VERSION 0
#define TF_MINOR_VERSION 10
-#define TF_PATCH_VERSION 0rc0
+#define TF_PATCH_VERSION 0
// TF_VERSION_SUFFIX is non-empty for pre-releases (e.g. "-alpha", "-alpha.1",
// "-beta", "-rc", "-rc.1")
diff --git a/tensorflow/examples/android/build.gradle b/tensorflow/examples/android/build.gradle
index 9dc5e5a6ff..8b0072e86b 100644
--- a/tensorflow/examples/android/build.gradle
+++ b/tensorflow/examples/android/build.gradle
@@ -31,7 +31,7 @@ android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
- lintOptions {t
+ lintOptions {
abortOnError false
}
diff --git a/tensorflow/examples/skflow/text_classification_character_cnn.py b/tensorflow/examples/skflow/text_classification_character_cnn.py
index d0406a52f4..599719564b 100644
--- a/tensorflow/examples/skflow/text_classification_character_cnn.py
+++ b/tensorflow/examples/skflow/text_classification_character_cnn.py
@@ -34,7 +34,6 @@ import pandas
import tensorflow as tf
from tensorflow.contrib import learn
-from tensorflow.contrib.layers import conv2d
FLAGS = tf.app.flags.FLAGS
tf.app.flags.DEFINE_bool('test_with_fake_data', False,
@@ -55,7 +54,8 @@ def char_cnn_model(x, y):
[-1, MAX_DOCUMENT_LENGTH, 256, 1])
with tf.variable_scope('CNN_Layer1'):
# Apply Convolution filtering on input sequence.
- conv1 = conv2d(byte_list, N_FILTERS, FILTER_SHAPE1, padding='VALID')
+ conv1 = tf.contrib.layers.convolution2d(byte_list, N_FILTERS,
+ FILTER_SHAPE1, padding='VALID')
# Add a RELU for non linearity.
conv1 = tf.nn.relu(conv1)
# Max pooling across output of Convolution+Relu.
@@ -65,7 +65,9 @@ def char_cnn_model(x, y):
pool1 = tf.transpose(pool1, [0, 1, 3, 2])
with tf.variable_scope('CNN_Layer2'):
# Second level of convolution filtering.
- conv2 = conv2d(pool1, N_FILTERS, FILTER_SHAPE2, padding='VALID')
+ conv2 = tf.contrib.layers.convolution2d(pool1, N_FILTERS,
+ FILTER_SHAPE2,
+ padding='VALID')
# Max across each filter to get useful features for classification.
pool2 = tf.squeeze(tf.reduce_max(conv2, 1), squeeze_dims=[1])
diff --git a/tensorflow/examples/tutorials/deepdream/README.md b/tensorflow/examples/tutorials/deepdream/README.md
index 3fbfea9684..3a715f6224 100644
--- a/tensorflow/examples/tutorials/deepdream/README.md
+++ b/tensorflow/examples/tutorials/deepdream/README.md
@@ -18,7 +18,7 @@ service.
In order to run the notebook locally, the following dependencies must be installed:
-- Python 2.7
+- Python 2.7 or 3.5
- TensorFlow (>=r0.7)
- NumPy
- Jupyter Notebook
diff --git a/tensorflow/examples/tutorials/deepdream/deepdream.ipynb b/tensorflow/examples/tutorials/deepdream/deepdream.ipynb
index d0dbd46313..bb6d70d5c6 100644
--- a/tensorflow/examples/tutorials/deepdream/deepdream.ipynb
+++ b/tensorflow/examples/tutorials/deepdream/deepdream.ipynb
@@ -278,7 +278,7 @@
" tensor = n.attr['value'].tensor\n",
" size = len(tensor.tensor_content)\n",
" if size > max_const_size:\n",
- " tensor.tensor_content = \"<stripped %d bytes>\"%size\n",
+ " tensor.tensor_content = bytes(\"<stripped %d bytes>\"%size, 'utf-8')\n",
" return strip_def\n",
" \n",
"def rename_nodes(graph_def, rename_func):\n",
diff --git a/tensorflow/examples/tutorials/word2vec/word2vec_basic.py b/tensorflow/examples/tutorials/word2vec/word2vec_basic.py
index b41e1bb8e7..628c6e2741 100644
--- a/tensorflow/examples/tutorials/word2vec/word2vec_basic.py
+++ b/tensorflow/examples/tutorials/word2vec/word2vec_basic.py
@@ -243,4 +243,4 @@ try:
plot_with_labels(low_dim_embs, labels)
except ImportError:
- print("Please install sklearn and matplotlib to visualize embeddings.")
+ print("Please install sklearn, matplotlib, and scipy to visualize embeddings.")
diff --git a/tensorflow/g3doc/api_docs/cc/ClassTensorShapeUtils.md b/tensorflow/g3doc/api_docs/cc/ClassTensorShapeUtils.md
index 761feccae2..96f20e856c 100644
--- a/tensorflow/g3doc/api_docs/cc/ClassTensorShapeUtils.md
+++ b/tensorflow/g3doc/api_docs/cc/ClassTensorShapeUtils.md
@@ -30,6 +30,12 @@ Static helper routines for ` TensorShape `. Includes a few common predicates on
+#### `static bool tensorflow::TensorShapeUtils::IsSquareMatrix(const TensorShape &shape)` {#static_bool_tensorflow_TensorShapeUtils_IsSquareMatrix}
+
+
+
+
+
#### `static bool tensorflow::TensorShapeUtils::IsMatrixOrHigher(const TensorShape &shape)` {#static_bool_tensorflow_TensorShapeUtils_IsMatrixOrHigher}
diff --git a/tensorflow/g3doc/api_docs/cc/StructTF_Buffer.md b/tensorflow/g3doc/api_docs/cc/StructTF_Buffer.md
deleted file mode 100644
index 084beffe66..0000000000
--- a/tensorflow/g3doc/api_docs/cc/StructTF_Buffer.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# `struct TF_Buffer`
-
-
-
-
-
-###Member Details
-
-#### `const void* TF_Buffer::data` {#const_void_TF_Buffer_data}
-
-
-
-
-
-#### `size_t TF_Buffer::length` {#size_t_TF_Buffer_length}
-
-
-
-
-
-#### `void(* TF_Buffer::data_deallocator)(void *data, size_t length))(void *data, size_t length)` {#void_TF_Buffer_data_deallocator_void_data_size_t_length_}
-
-
-
-
diff --git a/tensorflow/g3doc/api_docs/cc/index.md b/tensorflow/g3doc/api_docs/cc/index.md
index 6feb73d986..2fb0b1c1d2 100644
--- a/tensorflow/g3doc/api_docs/cc/index.md
+++ b/tensorflow/g3doc/api_docs/cc/index.md
@@ -48,7 +48,6 @@ write the graph to a file.
* [tensorflow::TensorShapeUtils](ClassTensorShapeUtils.md)
* [tensorflow::PartialTensorShape](ClassPartialTensorShape.md)
* [tensorflow::PartialTensorShapeUtils](ClassPartialTensorShapeUtils.md)
-* [TF_Buffer](StructTF_Buffer.md)
## Thread
diff --git a/tensorflow/g3doc/api_docs/python/client.md b/tensorflow/g3doc/api_docs/python/client.md
index 2d4c52a004..bd3252dfd5 100644
--- a/tensorflow/g3doc/api_docs/python/client.md
+++ b/tensorflow/g3doc/api_docs/python/client.md
@@ -134,7 +134,7 @@ Example:
# v is the numpy array [10, 20]
# 'fetches' can be a list.
v = session.run([a, b])
- # v a Python list with 2 numpy arrays: the numpy array [10, 20] and the
+ # v is a Python list with 2 numpy arrays: the numpy array [10, 20] and the
# 1-D array [1.0, 2.0]
# 'fetches' can be arbitrary lists, tuples, namedtuple, dicts:
MyData = collections.namedtuple('MyData', ['a', 'b'])
diff --git a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.nn.conv2d_transpose.md b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.nn.conv2d_transpose.md
index 5b2a0bb95b..e60a31ea5c 100644
--- a/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.nn.conv2d_transpose.md
+++ b/tensorflow/g3doc/api_docs/python/functions_and_classes/shard4/tf.nn.conv2d_transpose.md
@@ -11,9 +11,9 @@ deconvolution.
* <b>`value`</b>: A 4-D `Tensor` of type `float` and shape
- `[batch, height, width, in_channels]`.
+ `[batch, in_height, in_width, in_channels]`.
* <b>`filter`</b>: A 4-D `Tensor` with the same type as `value` and shape
- `[height, width, output_channels, in_channels]`. `filter`'s
+ `[filter_height, filter_width, output_channels, in_channels]`. `filter`'s
`in_channels` dimension must match that of `value`.
* <b>`output_shape`</b>: A 1-D `Tensor` representing the output shape of the
deconvolution op.
diff --git a/tensorflow/g3doc/get_started/os_setup.md b/tensorflow/g3doc/get_started/os_setup.md
index d172a413dc..14f27ed4dd 100644
--- a/tensorflow/g3doc/get_started/os_setup.md
+++ b/tensorflow/g3doc/get_started/os_setup.md
@@ -7,18 +7,19 @@ github source.
The TensorFlow Python API supports Python 2.7 and Python 3.3+.
-The GPU version (Linux & Mac OS X only) works best with Cuda Toolkit 7.5 and
-cuDNN v4. other versions are supported (Cuda toolkit >= 7.0 and
-cuDNN 6.5(v2), 7.0(v3), v5) only when installing from sources.
-Please see [Cuda installation](#optional-install-cuda-gpus-on-linux)
-for details.
+The GPU version works best with Cuda Toolkit 7.5 and
+cuDNN v5. Other versions are supported (Cuda toolkit >= 7.0 and
+cuDNN >= v3) only when installing from sources.
+Please see [Cuda installation](#optional-install-cuda-gpus-on-linux) for
+details. For Mac OS X, please see [Setup GPU for
+Mac](#optional-setup-gpu-for-mac).
## Overview
We support different ways to install TensorFlow:
-* [Pip install](#pip-installation): Install TensorFlow on your machine, possibly
- upgrading previously installed Python packages. May impact existing
+* [Pip install](#pip-installation): Install TensorFlow on your machine,
+ possibly upgrading previously installed Python packages. May impact existing
Python programs on your machine.
* [Virtualenv install](#virtualenv-installation): Install TensorFlow in its own
directory, not impacting any existing Python programs on your machine.
@@ -30,9 +31,9 @@ We support different ways to install TensorFlow:
* [Installing from sources](#installing-from-sources): Install TensorFlow by
building a pip wheel that you then install using pip.
-If you are familiar with Pip, Virtualenv, Anaconda, or Docker, please feel free to adapt
-the instructions to your particular needs. The names of the pip and Docker
-images are listed in the corresponding installation sections.
+If you are familiar with Pip, Virtualenv, Anaconda, or Docker, please feel free
+to adapt the instructions to your particular needs. The names of the pip and
+Docker images are listed in the corresponding installation sections.
If you encounter installation errors, see
[common problems](#common-problems) for some solutions.
@@ -43,8 +44,9 @@ If you encounter installation errors, see
management system used to install and manage software packages written in
Python.
-The packages that will be installed or upgraded during the pip install are listed in the
-[REQUIRED_PACKAGES section of setup.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/pip_package/setup.py).
+The packages that will be installed or upgraded during the pip install are
+listed in the [REQUIRED_PACKAGES section of
+setup.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/pip_package/setup.py).
Install pip (or pip3 for python3) if it is not already installed:
@@ -61,37 +63,37 @@ Then, select the correct binary to install:
```bash
# Ubuntu/Linux 64-bit, CPU only, Python 2.7
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 2.7
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Mac OS X, CPU only, Python 2.7:
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0rc0-py2-none-any.whl
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0-py2-none-any.whl
# Mac OS X, GPU enabled, Python 2.7:
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0rc0-py2-none-any.whl
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0-py2-none-any.whl
# Ubuntu/Linux 64-bit, CPU only, Python 3.4
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp34-cp34m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 3.4
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp34-cp34m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, CPU only, Python 3.5
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp35-cp35m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 3.5
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp35-cp35m-linux_x86_64.whl
# Mac OS X, CPU only, Python 3.4 or 3.5:
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0rc0-py3-none-any.whl
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0-py3-none-any.whl
# Mac OS X, GPU enabled, Python 3.4 or 3.5:
-$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0rc0-py3-none-any.whl
+$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0-py3-none-any.whl
```
Install TensorFlow:
@@ -157,37 +159,37 @@ Now, install TensorFlow just as you would for a regular Pip installation. First
```bash
# Ubuntu/Linux 64-bit, CPU only, Python 2.7
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 2.7
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Mac OS X, CPU only, Python 2.7:
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0rc0-py2-none-any.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0-py2-none-any.whl
# Mac OS X, GPU enabled, Python 2.7:
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0rc0-py2-none-any.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0-py2-none-any.whl
# Ubuntu/Linux 64-bit, CPU only, Python 3.4
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp34-cp34m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 3.4
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp34-cp34m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, CPU only, Python 3.5
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp35-cp35m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 3.5
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp35-cp35m-linux_x86_64.whl
# Mac OS X, CPU only, Python 3.4 or 3.5:
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0rc0-py3-none-any.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0-py3-none-any.whl
# Mac OS X, GPU enabled, Python 3.4 or 3.5:
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0rc0-py3-none-any.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0-py3-none-any.whl
```
Finally install TensorFlow:
@@ -211,7 +213,8 @@ When you are done using TensorFlow, deactivate the environment.
$ # Your prompt should change back
```
-To use TensorFlow later you will have to activate the Virtualenv environment again:
+To use TensorFlow later you will have to activate the Virtualenv environment
+again:
```bash
$ source ~/tensorflow/bin/activate # If using bash.
@@ -227,8 +230,9 @@ $ source ~/tensorflow/bin/activate.csh # If using csh.
[Anaconda](https://www.continuum.io/why-anaconda) is a Python distribution that
includes a large number of standard numeric and scientific computing packages.
-Anaconda uses a package manager called ["conda"](http://conda.pydata.org) that has its own
-[environment system](http://conda.pydata.org/docs/using/envs.html) similar to Virtualenv.
+Anaconda uses a package manager called ["conda"](http://conda.pydata.org) that
+has its own [environment system](http://conda.pydata.org/docs/using/envs.html)
+similar to Virtualenv.
As with Virtualenv, conda environments keep the dependencies required by
different Python projects in separate places. The Anaconda environment
@@ -244,7 +248,8 @@ packages needed by TensorFlow.
Install Anaconda:
-Follow the instructions on the [Anaconda download site](https://www.continuum.io/downloads).
+Follow the instructions on the [Anaconda download
+site](https://www.continuum.io/downloads).
Create a conda environment called `tensorflow`:
@@ -264,9 +269,11 @@ Activate the environment and use conda or pip to install TensorFlow inside it.
### Using conda
-A community maintained conda package is available [from conda-forge](https://github.com/conda-forge/tensorflow-feedstock).
+A community maintained conda package is available [from
+conda-forge](https://github.com/conda-forge/tensorflow-feedstock).
-Only the CPU version of TensorFlow is available at the moment and can be installed in the conda environment for Python 2 or Python 3.
+Only the CPU version of TensorFlow is available at the moment and can be
+installed in the conda environment for Python 2 or Python 3.
```bash
$ source activate tensorflow
@@ -278,48 +285,50 @@ $ source activate tensorflow
### Using pip
-If using pip make sure to use the `--ignore-installed` flag to prevent errors about `easy_install`.
+If using pip make sure to use the `--ignore-installed` flag to prevent errors
+about `easy_install`.
```bash
$ source activate tensorflow
(tensorflow)$ # Your prompt should change
```
-Now, install TensorFlow just as you would for a regular Pip installation. First select the correct binary to install:
+Now, install TensorFlow just as you would for a regular Pip installation. First
+select the correct binary to install:
```bash
# Ubuntu/Linux 64-bit, CPU only, Python 2.7
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 2.7
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Mac OS X, CPU only, Python 2.7:
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0rc0-py2-none-any.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0-py2-none-any.whl
# Mac OS X, GPU enabled, Python 2.7:
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0rc0-py2-none-any.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0-py2-none-any.whl
# Ubuntu/Linux 64-bit, CPU only, Python 3.4
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp34-cp34m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 3.4
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp34-cp34m-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp34-cp34m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, CPU only, Python 3.5
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp35-cp35m-linux_x86_64.whl
# Ubuntu/Linux 64-bit, GPU enabled, Python 3.5
-# Requires CUDA toolkit 7.5 and CuDNN v4. For other versions, see "Install from sources" below.
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0rc0-cp35-cp35m-linux_x86_64.whl
+# Requires CUDA toolkit 7.5 and CuDNN v5. For other versions, see "Install from sources" below.
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.10.0-cp35-cp35m-linux_x86_64.whl
# Mac OS X, CPU only, Python 3.4 or 3.5:
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0rc0-py3-none-any.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-0.10.0-py3-none-any.whl
# Mac OS X, GPU enabled, Python 3.4 or 3.5:
-(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0rc0-py3-none-any.whl
+(tensorflow)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow-0.10.0-py3-none-any.whl
```
Finally install TensorFlow:
@@ -358,15 +367,16 @@ $ source activate tensorflow
### Install IPython
-To use tensorflow with IPython it may be necessary to install IPython into the tensorflow environment:
+To use tensorflow with IPython it may be necessary to install IPython into the
+tensorflow environment:
```bash
$ source activate tensorflow
(tensorflow)$ conda install ipython
```
-Similarly, other Python packages like pandas may need to get installed into the tensorflow environment
-before they can be used together with tensorflow.
+Similarly, other Python packages like pandas may need to get installed into the
+tensorflow environment before they can be used together with tensorflow.
## Docker installation
@@ -385,7 +395,8 @@ code.
* `gcr.io/tensorflow/tensorflow:latest-devel-gpu`: GPU Binary image plus source
code.
-We also have tags with `latest` replaced by a released version (e.g., `0.10.0rc0-gpu`).
+We also have tags with `latest` replaced by a released version (e.g.,
+`0.10.0-gpu`).
With Docker the installation is as follows:
@@ -396,8 +407,8 @@ to allow launching containers without `sudo`.
* Launch a Docker container with the TensorFlow image. The image
gets downloaded automatically on first launch.
-See [installing Docker](http://docs.docker.com/engine/installation/) for instructions
-on installing Docker on your machine.
+See [installing Docker](http://docs.docker.com/engine/installation/) for
+instructions on installing Docker on your machine.
After Docker is installed, launch a Docker container with the TensorFlow binary
image as follows.
@@ -406,21 +417,25 @@ image as follows.
$ docker run -it -p 8888:8888 gcr.io/tensorflow/tensorflow
```
-The option `-p 8888:8888` is used to publish the Docker container᾿s internal port to the host machine, in this case to ensure Jupyter notebook connection.
+The option `-p 8888:8888` is used to publish the Docker container᾿s internal
+port to the host machine, in this case to ensure Jupyter notebook connection.
-The format of the port mapping is `hostPort:containerPort`. You can specify any valid port number for the host port but have to use `8888` for the container port portion.
+The format of the port mapping is `hostPort:containerPort`. You can specify any
+valid port number for the host port but have to use `8888` for the container
+port portion.
-If you're using a container with GPU support, some additional flags must be passed to expose the GPU device to the container.
+If you're using a container with GPU support, some additional flags must be
+passed to expose the GPU device to the container.
For NVidia GPU support install latest NVidia drivers and
-[nvidia-docker](https://github.com/NVIDIA/nvidia-docker).
-Run with
+[nvidia-docker](https://github.com/NVIDIA/nvidia-docker). Run with
```bash
$ nvidia-docker run -it -p 8888:8888 gcr.io/tensorflow/tensorflow:latest-gpu
```
-If you have a problem running `nvidia-docker`, then using the default config, we include a
+If you have a problem running `nvidia-docker`, then using the default config, we
+include a
[script](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/docker/docker_run_gpu.sh)
in the repo with these flags, so the command-line would look like
@@ -428,16 +443,19 @@ in the repo with these flags, so the command-line would look like
$ path/to/repo/tensorflow/tools/docker/docker_run_gpu.sh -p 8888:8888 gcr.io/tensorflow/tensorflow:latest-gpu
```
-For more details see [TensorFlow docker readme](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/docker).
+For more details see [TensorFlow docker
+readme](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/docker).
-You can now [test your installation](#test-the-tensorflow-installation) within the Docker container.
+You can now [test your installation](#test-the-tensorflow-installation) within
+the Docker container.
## Test the TensorFlow installation
### (Optional, Linux) Enable GPU Support
If you installed the GPU version of TensorFlow, you must also install the Cuda
-Toolkit 7.5 and cuDNN v4. Please see [Cuda installation](#optional-install-cuda-gpus-on-linux).
+Toolkit 7.5 and cuDNN v5. Please see [Cuda
+installation](#optional-install-cuda-gpus-on-linux).
You also need to set the `LD_LIBRARY_PATH` and `CUDA_HOME` environment
variables. Consider adding the commands below to your `~/.bash_profile`. These
@@ -471,23 +489,27 @@ Hello, TensorFlow!
### Run a TensorFlow demo model
-All TensorFlow packages, including the demo models, are installed in the Python library.
-The exact location of the Python library depends on your system, but is usually one of:
+All TensorFlow packages, including the demo models, are installed in the Python
+library. The exact location of the Python library depends on your system, but
+is usually one of:
```bash
/usr/local/lib/python2.7/dist-packages/tensorflow
/usr/local/lib/python2.7/site-packages/tensorflow
```
-You can find out the directory with the following command (make sure to use the Python you installed TensorFlow to, for example, use `python3` instead of `python` if you installed for Python 3):
+You can find out the directory with the following command (make sure to use the
+Python you installed TensorFlow to, for example, use `python3` instead of
+`python` if you installed for Python 3):
```bash
$ python -c 'import os; import inspect; import tensorflow; print(os.path.dirname(inspect.getfile(tensorflow)))'
```
The simple demo model for classifying handwritten digits from the MNIST dataset
-is in the sub-directory `models/image/mnist/convolutional.py`. You can run it from the command
-line as follows (make sure to use the Python you installed TensorFlow with):
+is in the sub-directory `models/image/mnist/convolutional.py`. You can run it
+from the command line as follows (make sure to use the Python you installed
+TensorFlow with):
```bash
# Using 'python -m' to find the program in the python search path:
@@ -517,8 +539,8 @@ using pip. You'll need pip for that, so install it as described
$ git clone https://github.com/tensorflow/tensorflow
```
-Note that these instructions will install the latest master branch
-of tensorflow. If you want to install a specific branch (such as a release branch),
+Note that these instructions will install the latest master branch of
+tensorflow. If you want to install a specific branch (such as a release branch),
pass `-b <branchname>` to the `git clone` command and `--recurse-submodules` for
r0.8 and earlier to fetch the protobuf library that TensorFlow depends on.
@@ -553,11 +575,11 @@ $ sudo apt-get install python3-numpy swig python3-dev python3-wheel
#### Optional: Install CUDA (GPUs on Linux)
-In order to build or run TensorFlow with GPU support, both NVIDIA's Cuda Toolkit (>= 7.0) and
-cuDNN (>= v2) need to be installed.
+In order to build or run TensorFlow with GPU support, both NVIDIA's Cuda Toolkit
+(>= 7.0) and cuDNN (>= v3) need to be installed.
-TensorFlow GPU support requires having a GPU card with NVidia Compute Capability >= 3.0.
-Supported cards include but are not limited to:
+TensorFlow GPU support requires having a GPU card with NVidia Compute Capability
+>= 3.0. Supported cards include but are not limited to:
* NVidia Titan
* NVidia Titan X
@@ -580,15 +602,14 @@ Install the toolkit into e.g. `/usr/local/cuda`
https://developer.nvidia.com/cudnn
-Download cuDNN v4 (v5 is currently a release candidate and is only supported when
-installing TensorFlow from sources).
+Download cuDNN v5.
-Uncompress and copy the cuDNN files into the toolkit directory. Assuming the
+Uncompress and copy the cuDNN files into the toolkit directory. Assuming the
toolkit is installed in `/usr/local/cuda`, run the following commands (edited
to reflect the cuDNN version you downloaded):
``` bash
-tar xvzf cudnn-7.5-linux-x64-v4.tgz
+tar xvzf cudnn-7.5-linux-x64-v5.1-ga.tgz
sudo cp cuda/include/cudnn.h /usr/local/cuda/include
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64
sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*
@@ -600,7 +621,8 @@ We recommend using [homebrew](http://brew.sh) to install the bazel and SWIG
dependencies, and installing python dependencies using easy_install or pip.
Of course you can also install Swig from source without using homebrew. In that
-case, be sure to install its dependency [PCRE](http://www.pcre.org) and not PCRE2.
+case, be sure to install its dependency [PCRE](http://www.pcre.org) and not
+PCRE2.
#### Dependencies
@@ -657,7 +679,7 @@ export PATH="$CUDA_HOME/bin:$PATH"
```
Finally, you will also want to install the [CUDA Deep Neural
-Network](https://developer.nvidia.com/cudnn) (cuDNN) library which currently
+Network](https://developer.nvidia.com/cudnn) (cuDNN v5) library which currently
requires an [Accelerated Computing Developer
Program](https://developer.nvidia.com/accelerated-computing-developer) account.
Once you have it downloaded locally, you can unzip and move the header and
@@ -729,10 +751,10 @@ Setting up CUPTI lib64
Configuration finished
```
-This creates a canonical set of symbolic links to the Cuda libraries on your system.
-Every time you change the Cuda library paths you need to run this step again before
-you invoke the bazel build command. For the cuDNN libraries, use '6.5' for R2, '7.0'
-for R3, and '4.0.4' for R4-RC.
+This creates a canonical set of symbolic links to the Cuda libraries on your
+system. Every time you change the Cuda library paths you need to run this step
+again before you invoke the bazel build command. For the cuDNN libraries, use
+'7.0' for R3, and '4.0.7' for R4.
#### Known issues
@@ -749,6 +771,10 @@ this more convenient by including the configure step in our build process.
When building from source, you will still build a pip package and install that.
+Please note that building from sources takes a lot of memory resources by
+default and if you want to limit RAM usage you can add `--local_resources
+2048,.5,1.0` while invoking bazel.
+
```bash
$ bazel build -c opt //tensorflow/tools/pip_package:build_pip_package
@@ -758,7 +784,7 @@ $ bazel build -c opt --config=cuda //tensorflow/tools/pip_package:build_pip_pack
$ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
# The name of the .whl file will depend on your platform.
-$ sudo pip install /tmp/tensorflow_pkg/tensorflow-0.10.0rc0-py2-none-any.whl
+$ sudo pip install /tmp/tensorflow_pkg/tensorflow-0.10.0-py2-none-any.whl
```
## Setting up TensorFlow for Development
@@ -826,22 +852,22 @@ If you encounter the following when trying to run a TensorFlow program:
ImportError: libcudart.so.7.0: cannot open shared object file: No such file or directory
```
-Make sure you followed the GPU installation [instructions](#optional-install-cuda-gpus-on-linux).
-If you built from source, and you left the Cuda or cuDNN version empty, try specifying them
-explicitly.
+Make sure you followed the GPU installation
+[instructions](#optional-install-cuda-gpus-on-linux). If you built from source,
+and you left the Cuda or cuDNN version empty, try specifying them explicitly.
### Protobuf library related issues
TensorFlow pip package depends on protobuf pip package version
3.0.0b2. Protobuf's pip package downloaded from [PyPI](https://pypi.python.org)
(when running `pip install protobuf`) is a Python only library, that has
-Python implementations of proto serialization/deserialization which can be 10x-50x
-slower than the C++ implementation. Protobuf also supports a binary extension
-for the Python package that contains fast C++ based proto parsing. This
-extension is not available in the standard Python only PIP package. We have
+Python implementations of proto serialization/deserialization which can be
+10x-50x slower than the C++ implementation. Protobuf also supports a binary
+extension for the Python package that contains fast C++ based proto parsing.
+This extension is not available in the standard Python only PIP package. We have
created a custom binary pip package for protobuf that contains the binary
extension. Follow these instructions to install the custom binary protobuf pip
-package :
+package:
```bash
# Ubuntu/Linux 64-bit:
@@ -851,7 +877,7 @@ $ pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/prot
$ pip install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/protobuf-3.0.0-cp27-cp27m-macosx_10_11_x86_64.whl
```
-and for Python 3 :
+And for Python 3:
```bash
# Ubuntu/Linux 64-bit:
@@ -1021,3 +1047,22 @@ installed, such as:
```bash
$ pip install --upgrade protobuf
```
+
+### Mac OS X: Segmentation Fault when import tensorflow
+
+On Mac OS X, you might get the following error when importing tensorflow in python:
+
+```
+>>> import tensorflow
+I tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcublas.dylib locally
+I tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcudnn.dylib locally
+I tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcufft.dylib locally
+"import tensorflow" terminated by signal SIGSEGV (Address boundary error)
+```
+
+This is due to the fact that by default, cuda creates libcuda.dylib, but tensorflow tries to load libcuda.1.dylib.
+This can be resolved by create a symbolic link:
+
+```bash
+ln -sf /usr/local/cuda/lib/libcuda.dylib /usr/local/cuda/lib/libcuda.1.dylib
+```
diff --git a/tensorflow/g3doc/how_tos/adding_an_op/index.md b/tensorflow/g3doc/how_tos/adding_an_op/index.md
index 99787ac95d..a9c29be5e7 100644
--- a/tensorflow/g3doc/how_tos/adding_an_op/index.md
+++ b/tensorflow/g3doc/how_tos/adding_an_op/index.md
@@ -1000,6 +1000,11 @@ cuda_op_kernel.cu.o -I $TF_INC -fPIC -lcudart
`cuda_op_kernel.so` produced above can be loaded as usual in Python, using the
`tf.load_op_library` function.
+Note that if your CUDA libraries are not installed in `/usr/local/lib64`,
+you'll need to specify the path explicitly in the second (g++) command above.
+For example, add `-L /usr/local/cuda-8.0/lib64/` if your CUDA is installed in
+`/usr/local/cuda-8.0`.
+
## Implement the gradient in Python
Given a graph of ops, TensorFlow uses automatic differentiation
diff --git a/tensorflow/g3doc/how_tos/reading_data/index.md b/tensorflow/g3doc/how_tos/reading_data/index.md
index b7ae72c916..9034b2f97d 100644
--- a/tensorflow/g3doc/how_tos/reading_data/index.md
+++ b/tensorflow/g3doc/how_tos/reading_data/index.md
@@ -172,7 +172,7 @@ You can then do any preprocessing of these examples you want. This would be any
processing that doesn't depend on trainable parameters. Examples include
normalization of your data, picking a random slice, adding noise or distortions,
etc. See
-[`tensorflow/models/image/cifar10/cifar10.py`](https://www.tensorflow.org/code/tensorflow/models/image/cifar10/cifar10.py)
+[`tensorflow/models/image/cifar10/cifar10_input.py`](https://www.tensorflow.org/code/tensorflow/models/image/cifar10/cifar10_input.py)
for an example.
### Batching
@@ -253,7 +253,7 @@ summary to the graph that indicates how full the example queue is. If you have
enough reading threads, that summary will stay above zero. You can
[view your summaries as training progresses using TensorBoard](../../how_tos/summaries_and_tensorboard/index.md).
-### Creating threads to prefetch using `QueueRunner` objects
+### Creating threads to prefetch using `QueueRunner` objects
The short version: many of the `tf.train` functions listed above add
[`QueueRunner`](../../api_docs/python/train.md#QueueRunner) objects to your
diff --git a/tensorflow/models/rnn/ptb/ptb_word_lm.py b/tensorflow/models/rnn/ptb/ptb_word_lm.py
index c94aa2336c..df36fe16f8 100644
--- a/tensorflow/models/rnn/ptb/ptb_word_lm.py
+++ b/tensorflow/models/rnn/ptb/ptb_word_lm.py
@@ -117,10 +117,9 @@ class PTBModel(object):
#
# The alternative version of the code below is:
#
- # from tensorflow.models.rnn import rnn
# inputs = [tf.squeeze(input_, [1])
# for input_ in tf.split(1, num_steps, inputs)]
- # outputs, state = rnn.rnn(cell, inputs, initial_state=self._initial_state)
+ # outputs, state = tf.nn.rnn(cell, inputs, initial_state=self._initial_state)
outputs = []
state = self._initial_state
with tf.variable_scope("RNN"):
diff --git a/tensorflow/models/rnn/translate/data_utils.py b/tensorflow/models/rnn/translate/data_utils.py
index 00d63103d2..551c49d532 100644
--- a/tensorflow/models/rnn/translate/data_utils.py
+++ b/tensorflow/models/rnn/translate/data_utils.py
@@ -73,7 +73,7 @@ def gunzip_file(gz_path, new_path):
def get_wmt_enfr_train_set(directory):
"""Download the WMT en-fr training corpus to directory unless it's there."""
- train_path = os.path.join(directory, "giga-fren.release2")
+ train_path = os.path.join(directory, "giga-fren.release2.fixed")
if not (gfile.Exists(train_path +".fr") and gfile.Exists(train_path +".en")):
corpus_file = maybe_download(directory, "training-giga-fren.tar",
_WMT_ENFR_TRAIN_URL)
diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py
index 4d39f7f796..1d1f54fec3 100644
--- a/tensorflow/python/ops/array_ops.py
+++ b/tensorflow/python/ops/array_ops.py
@@ -265,13 +265,6 @@ def rank_internal(input, name=None, optimize=True):
return gen_array_ops.rank(input, name=name)
-# DEPRECATED use init_ops.zeros_initializer
-# TODO(irving) Move it to init_ops.py
-def zeros_initializer(shape, dtype=dtypes.float32, partition_info=None):
- """An adaptor for zeros() to match the Initializer spec."""
- return zeros(shape, dtype)
-
-
def _SliceHelper(tensor, slice_spec, var=None):
"""Overload for Tensor.__getitem__.
diff --git a/tensorflow/python/ops/init_ops.py b/tensorflow/python/ops/init_ops.py
index 24699b868b..6cd89bf81e 100644
--- a/tensorflow/python/ops/init_ops.py
+++ b/tensorflow/python/ops/init_ops.py
@@ -61,8 +61,9 @@ def _assert_float_dtype(dtype):
return dtype
-# TODO(irving) Move array_ops.zeros_initializer here.
-zeros_initializer = array_ops.zeros_initializer
+def zeros_initializer(shape, dtype=dtypes.float32, partition_info=None):
+ """An adaptor for zeros() to match the Initializer spec."""
+ return array_ops.zeros(shape, dtype)
def ones_initializer(shape, dtype=dtypes.float32, partition_info=None):
diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py
index 3ee701c52a..444651a58a 100644
--- a/tensorflow/python/ops/math_ops.py
+++ b/tensorflow/python/ops/math_ops.py
@@ -138,6 +138,8 @@ common math computations that reduce various dimensions of a tensor.
@@accumulate_n
+@@einsum
+
## Scan
TensorFlow provides several operations that you can use to perform scans
diff --git a/tensorflow/python/ops/rnn_cell.py b/tensorflow/python/ops/rnn_cell.py
index abee823162..f0c6332655 100644
--- a/tensorflow/python/ops/rnn_cell.py
+++ b/tensorflow/python/ops/rnn_cell.py
@@ -495,7 +495,7 @@ class LSTMCell(RNNCell):
b = vs.get_variable(
"B", shape=[4 * self._num_units],
- initializer=array_ops.zeros_initializer, dtype=dtype)
+ initializer=init_ops.zeros_initializer, dtype=dtype)
# i = input_gate, j = new_input, f = forget_gate, o = output_gate
cell_inputs = array_ops.concat(1, [inputs, m_prev])
diff --git a/tensorflow/python/ops/special_math_ops.py b/tensorflow/python/ops/special_math_ops.py
index c16c76675d..905d6de61b 100644
--- a/tensorflow/python/ops/special_math_ops.py
+++ b/tensorflow/python/ops/special_math_ops.py
@@ -23,6 +23,8 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
+import re
+
from tensorflow.python.framework import ops
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import check_ops
@@ -86,3 +88,75 @@ def lbeta(x, name='lbeta'):
return empty_lbeta()
else:
return control_flow_ops.cond(is_empty, empty_lbeta, nonempty_lbeta)
+
+
+def einsum(axes, *inputs):
+ """
+ A generalized contraction between tensors of arbitrary dimension.
+
+ Like numpy.einsum.
+ """
+
+ match = re.match('([a-z,]+)->([a-z]+)', axes)
+ assert match, \
+ "Indices have incorrect format: %s" % axes
+
+ inputs = list(inputs)
+ idx_in = match.group(1).split(',')
+ idx_out = match.group(2)
+ idx_all = set(''.join(idx_in))
+
+
+ assert len(idx_in) == len(inputs), \
+ "Expected %d inputs but only got %d" % (len(idx_in), len(inputs))
+
+ # transpose inputs so axes are in alphabetical order
+ for i, (input_, axes_) in enumerate(zip(inputs, idx_in)):
+ assert input_.get_shape().ndims == len(axes_), \
+ "Input %d with axes %s has incorrect" \
+ " number of dimensions (expected %d, got %d)" % (
+ i, axes_, len(axes_), input_.get_shape().ndims
+ )
+
+ sorted_idx = sorted(axes_)
+
+ if list(axes_) != sorted_idx:
+ permuted = [axes_.find(ax) for ax in sorted_idx]
+ inputs[i] = array_ops.transpose(input_, permuted)
+ idx_in[i] = sorted_idx
+
+ missing_idx = set(idx_out).difference(idx_all)
+ assert not missing_idx, \
+ "Unknown ouput axes: %s" % missing_idx
+
+ reduction_idx = []
+ shapes = [[dim if dim else -1
+ for dim in tensor.get_shape().as_list()]
+ for tensor in inputs]
+
+ # validate shapes for broadcasting
+ for j, ax in enumerate(sorted(idx_all)):
+ dims = []
+ for i, idx in enumerate(idx_in):
+ if ax not in idx:
+ shapes[i].insert(j, 1)
+ else:
+ dim = shapes[i][j]
+ if isinstance(dim, int) and dim > 1:
+ dims.append(dim)
+
+ assert len(set(dims)) <= 1, \
+ "Dimension mismatch on axis: %s" % ax
+
+ if ax not in idx_out:
+ reduction_idx.append(j)
+
+ # reshape, multiply
+ expanded_inputs = [array_ops.reshape(input_, shape)
+ for input_, shape in zip(inputs, shapes)]
+ expanded_output = 1
+ for input_ in expanded_inputs:
+ expanded_output *= input_
+
+ # contract
+ return math_ops.reduce_sum(expanded_output, reduction_idx)
diff --git a/tensorflow/python/ops/special_math_ops_test.py b/tensorflow/python/ops/special_math_ops_test.py
index 883986f364..c190c589b7 100644
--- a/tensorflow/python/ops/special_math_ops_test.py
+++ b/tensorflow/python/ops/special_math_ops_test.py
@@ -111,5 +111,112 @@ class LBetaTestGpu(LBetaTest):
_use_gpu = True
+class EinsumTest(tf.test.TestCase):
+
+ # standard cases
+ simple_cases = [
+ 'ij,jk->ik',
+ 'ijk,jklm->il',
+ 'ij,jk,kl->il',
+ 'ijk->i',
+ ]
+
+ # where axes are not in order
+ misordered_cases = [
+ 'ji,kj->ik',
+ 'ikl,kji->kl',
+ 'klj,lki->ij',
+ ]
+
+ # more than two arguments
+ multiarg_cases = [
+ 'ijk,ijl,ikl->i',
+ 'i,ijk,j->k',
+ 'ij,ij,jk,kl->il',
+ ]
+
+ invalid_cases = [
+ # bad formats
+ 'ijk ijk',
+ 'ij,jk,kl'
+ 'ij->',
+
+ # axis in output that does not exist
+ 'ij,jk->im',
+
+ # incorrect number of dimensions
+ 'ij,jkl->kl',
+ ]
+
+ dim_mismatch_cases = [
+ ('ijk,jkl->il',
+ [(2,3,4), (3,5,6)]),
+
+ ]
+
+ def test_simple(self):
+ for case in self.simple_cases:
+ self.run_test(case)
+
+ def test_misordered(self):
+ for case in self.misordered_cases:
+ self.run_test(case)
+
+ def test_multiarg(self):
+ for case in self.multiarg_cases:
+ self.run_test(case)
+
+ def test_invalid(self):
+ for axes in self.invalid_cases:
+ result = None
+ inputs = [
+ tf.placeholder(tf.float32, shape=(3,4)),
+ tf.placeholder(tf.float32, shape=(3,4)),
+ ]
+
+ try:
+ result = tf.einsum(axes, *inputs)
+ except AssertionError as e:
+ print(e)
+ assert result is None, \
+ "An exception should have been thrown."
+
+ def test_dim_mismatch(self):
+ for axes, input_shapes in self.dim_mismatch_cases:
+ inputs = [
+ tf.placeholder(tf.float32, shape=shape)
+ for shape in input_shapes
+ ]
+ result = None
+ try:
+ result = tf.einsum(axes, *inputs)
+ except AssertionError:
+ pass
+ assert result is None, "An exception should have been thrown."
+
+ def run_test(self, axes):
+ all_axes = {ax: np.random.randint(4, 12)
+ for ax in axes if ax.isalpha()}
+
+ input_vals = []
+ input_axes, _, _ = axes.partition('->')
+
+ for idx in input_axes.split(','):
+ shape = [all_axes[ax] for ax in idx]
+ input_vals.append(np.random.random(shape))
+
+ input_tensors = [tf.constant(val) for val in input_vals]
+ output_tensor = tf.einsum(axes, *input_tensors)
+
+ with self.test_session():
+ output_value = output_tensor.eval()
+
+ correct_value = np.einsum(axes, *input_vals)
+
+ err = np.abs(correct_value - output_value).max()
+ print(axes, err)
+ assert err < 1e-8
+
+
if __name__ == '__main__':
tf.test.main()
diff --git a/tensorflow/python/training/sync_replicas_optimizer.py b/tensorflow/python/training/sync_replicas_optimizer.py
index 43e102d6da..ba07cd5908 100644
--- a/tensorflow/python/training/sync_replicas_optimizer.py
+++ b/tensorflow/python/training/sync_replicas_optimizer.py
@@ -335,7 +335,7 @@ class SyncReplicasOptimizer(optimizer.Optimizer):
local_step = array_ops.reshape(local_step, ())
is_stale = math_ops.less(local_step, global_step)
- with ops.name_scope(None, self._name, inputs):
+ with ops.name_scope(name, self._name, inputs) as name:
for grad, var in grads_and_vars:
var_list.append(var)
with ops.device(var.device):
@@ -411,7 +411,8 @@ class SyncReplicasOptimizer(optimizer.Optimizer):
with ops.control_dependencies([final_train_ops]):
token = sync_token_queue.dequeue()
train_op = state_ops.scatter_update(self._local_steps,
- self._replica_id, token)
+ self._replica_id,
+ token, name=name)
with ops.control_dependencies(clear_queue_ops):
# Sync_op needs to insert tokens to the token queue at the end of the
diff --git a/tensorflow/tensorboard/components/tf-option-selector/tf-option-selector.html b/tensorflow/tensorboard/components/tf-option-selector/tf-option-selector.html
new file mode 100644
index 0000000000..50b542ce69
--- /dev/null
+++ b/tensorflow/tensorboard/components/tf-option-selector/tf-option-selector.html
@@ -0,0 +1,77 @@
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../tf-dashboard-common/tensorboard-color.html">
+
+<!--
+tf-option-selector is a simple component that has buttons as content and
+provides a "selectedId" property that is one of the IDs of the buttons inside it.
+-->
+<dom-module id="tf-option-selector">
+ <template>
+ <div id="wrap">
+ <h3>[[name]]</h3>
+ <div class="content-wrapper"><content></content></div>
+ </div>
+ <style>
+ .content-wrapper ::content > * {
+ width: 30%;
+ font-size: 13px;
+ background: none;
+ margin-top: 10px;
+ color: var(--tb-ui-dark-accent);
+ }
+
+ .content-wrapper ::content :first-of-type {
+ margin-left: 0;
+ }
+
+ .content-wrapper ::content .selected {
+ background-color: var(--tb-ui-dark-accent);
+ color: white!important;
+ }
+
+ h3 {
+ color: var(--paper-grey-800);
+ margin: 0;
+ font-weight: normal;
+ font-size: 14px;
+ margin-bottom: 5px;
+ display: block;
+ pointer-events: none;
+ }
+ </style>
+ </template>
+ <script>
+ Polymer({
+ is: "tf-option-selector",
+ properties: {
+ name: String,
+ selectedId: {
+ type: String,
+ notify: true,
+ observer: '_selectedIdChanged'
+ }
+ },
+ attached: function() {
+ this.async(function() {
+ this.getEffectiveChildren().forEach(function(node) {
+ this.listen(node, 'tap', '_selectTarget');
+ }.bind(this));
+ });
+ },
+ _selectTarget: function(e) {
+ this.selectedId = e.currentTarget.id;
+ },
+ _selectedIdChanged: function() {
+ var selected = this.queryEffectiveChildren('#' + this.selectedId);
+ if (!selected) {
+ return;
+ }
+
+ this.getEffectiveChildren().forEach(function(node) {
+ node.classList.remove("selected");
+ });
+ selected.classList.add("selected");
+ }
+ });
+ </script>
+</dom-module>
diff --git a/tensorflow/tensorboard/components/vz-projector/vz-projector-data-loader.html b/tensorflow/tensorboard/components/vz-projector/vz-projector-data-loader.html
new file mode 100644
index 0000000000..e6beaa837e
--- /dev/null
+++ b/tensorflow/tensorboard/components/vz-projector/vz-projector-data-loader.html
@@ -0,0 +1,144 @@
+<!--
+@license
+Copyright 2016 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+<link rel="import" href="../paper-dropdown-menu/paper-dropdown-menu.html">
+<link rel="import" href="../paper-listbox/paper-listbox.html">
+<link rel="import" href="../paper-item/paper-item.html">
+
+<dom-module id='vz-projector-data-loader'>
+<template>
+<style>
+:host {
+}
+
+input[type=file] {
+ display: none;
+}
+
+.file-name {
+ margin-right: 10px;
+}
+
+.dirs {
+ display: flex;
+ flex-direction: column;
+ margin-right: 10px;
+ line-height: 20px;
+}
+
+.dir {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+paper-item {
+ --paper-item-disabled: {
+ border-bottom: 1px solid black;
+ justify-content: center;
+ font-size: 12px;
+ line-height: normal;
+ min-height: 0px;
+ };
+}
+</style>
+
+<!-- Server-mode UI -->
+<div class="server-controls" style="display:none;">
+ <div class="dirs">
+ <div class="dir">Checkpoint: <span id="checkpoint-file"></span></div>
+ <div class="dir">Metadata: <span id="metadata-file"></span></div>
+ </div>
+ <!-- List of tensors in checkpoint -->
+ <paper-dropdown-menu noink no-animations label="[[getNumTensorsLabel(tensorNames)]] found">
+ <paper-listbox attr-for-selected="value" class="dropdown-content" selected="{{selectedTensor}}">
+ <template is="dom-repeat" items="[[tensorNames]]">
+ <paper-item style="justify-content: space-between;" value="[[item.name]]" label="[[item.name]]">
+ [[item.name]]
+ <span style="margin-left: 5px; color:gray; font-size: 12px;">[[item.shape.0]]x[[item.shape.1]]</span>
+ </paper-item>
+ </template>
+ </paper-listbox>
+ </paper-dropdown-menu>
+</div>
+
+<!-- Standalone-mode UI -->
+<div class="standalone-controls" style="display:none;">
+
+ <!-- Upload buttons -->
+ <div style="display: flex; justify-content: space-between;">
+ <!-- Upload data -->
+ <div>
+ <button id="upload" title="Upload a TSV file" class="ink-button">Upload data</button>
+ <span id="file-name" class="file-name dir"></span>
+ <input type="file" id="file" name="file"/>
+ </div>
+
+ <!-- Upload metadata -->
+ <div>
+ <button id="upload-metadata" title="Upload a TSV metadata file" class="ink-button">Upload Metadata</button>
+ <span id="file-metadata-name" class="file-name dir"></span>
+ <input type="file" id="file-metadata" name="file-metadata"/>
+ </div>
+ </div>
+
+ <!-- Demo datasets -->
+ <paper-dropdown-menu style="width: 100%" noink no-animations label="Select a demo dataset">
+ <paper-listbox attr-for-selected="value" class="dropdown-content" selected="{{selectedDemo}}">
+ <paper-item value="smartreply_full">SmartReply All</paper-item>
+ <paper-item value="smartreply_5k">SmartReply 5K</paper-item>
+ <paper-item value="wiki_5k">Glove Wiki 5K</paper-item>
+ <paper-item value="wiki_10k">Glove Wiki 10K</paper-item>
+ <paper-item value="wiki_40k">Glove Wiki 40K</paper-item>
+ <paper-item value="mnist_10k">MNIST 10K</paper-item>
+ <paper-item value="iris">Iris</paper-item>
+ </paper-listbox>
+ </paper-dropdown-menu>
+
+</div>
+
+<!-- Label by -->
+<template is="dom-if" if="[[labelOptions.length]]">
+ <paper-dropdown-menu style="width: 100%" noink no-animations label="Label by">
+ <paper-listbox attr-for-selected="value" class="dropdown-content" selected="{{labelOption}}">
+ <template is="dom-repeat" items="[[labelOptions]]">
+ <paper-item style="justify-content: space-between;" value="[[item]]" label="[[item]]">
+ [[item]]
+ </paper-item>
+ </template>
+ </paper-listbox>
+ </paper-dropdown-menu>
+</template>
+
+<!-- Color by -->
+<template is="dom-if" if="[[colorOptions.length]]">
+ <paper-dropdown-menu id="colorby" style="width: 100%" noink no-animations label="Color by">
+ <paper-listbox attr-for-selected="value" class="dropdown-content" selected="{{colorOption}}">
+ <template is="dom-repeat" items="[[colorOptions]]">
+ <paper-item style="justify-content: space-between;" class$="[[getSeparatorClass(item.isSeparator)]]" value="[[item]]" label="[[item.name]]" disabled="[[item.isSeparator]]">
+ [[item.name]]
+ <span style="margin-left: 5px; color:gray; font-size: 12px;">[[item.desc]]</span>
+ </paper-item>
+ </template>
+ </paper-listbox>
+ </paper-dropdown-menu>
+</template>
+
+<!-- Closing global template -->
+</template>
+</dom-module>
diff --git a/tensorflow/tensorboard/components/vz-projector/vz-projector-data-loader.ts b/tensorflow/tensorboard/components/vz-projector/vz-projector-data-loader.ts
new file mode 100644
index 0000000000..f44bb6bbe9
--- /dev/null
+++ b/tensorflow/tensorboard/components/vz-projector/vz-projector-data-loader.ts
@@ -0,0 +1,500 @@
+/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+import {runAsyncTask, updateMessage} from './async';
+import {DataPoint, DataSet, DatasetMetadata, DataSource} from './data';
+import {PolymerElement} from './vz-projector-util';
+
+
+/** Prefix added to the http requests when asking the server for data. */
+const DATA_URL = 'data';
+
+type DemoDataset = {
+ fpath: string; metadata_path?: string; metadata?: DatasetMetadata;
+};
+
+type Metadata = {
+ [key: string]: (number|string);
+};
+
+/** List of compiled demo datasets for showing the capabilities of the tool. */
+const DEMO_DATASETS: {[name: string]: DemoDataset} = {
+ 'wiki_5k': {
+ fpath: 'wiki_5000_50d_tensors.ssv',
+ metadata_path: 'wiki_5000_50d_labels.ssv'
+ },
+ 'wiki_10k': {
+ fpath: 'wiki_10000_100d_tensors.ssv',
+ metadata_path: 'wiki_10000_100d_labels.ssv'
+ },
+ 'wiki_40k': {
+ fpath: 'wiki_40000_100d_tensors.ssv',
+ metadata_path: 'wiki_40000_100d_labels.ssv'
+ },
+ 'smartreply_5k': {
+ fpath: 'smartreply_5000_256d_tensors.tsv',
+ metadata_path: 'smartreply_5000_256d_labels.tsv'
+ },
+ 'smartreply_full': {
+ fpath: 'smartreply_full_256d_tensors.tsv',
+ metadata_path: 'smartreply_full_256d_labels.tsv'
+ },
+ 'mnist_10k': {
+ fpath: 'mnist_10k_784d_tensors.tsv',
+ metadata_path: 'mnist_10k_784d_labels.tsv',
+ metadata: {
+ image:
+ {sprite_fpath: 'mnist_10k_sprite.png', single_image_dim: [28, 28]}
+ },
+ },
+ 'iris': {fpath: 'iris_tensors.tsv', metadata_path: 'iris_labels.tsv'}
+};
+
+/** Maximum number of colors supported in the color map. */
+const NUM_COLORS_COLOR_MAP = 20;
+
+interface ServerInfo {
+ tensors: {[name: string]: [number, number]};
+ tensors_file: string;
+ checkpoint_file: string;
+ checkpoint_dir: string;
+ metadata_file: string;
+}
+
+let DataLoaderPolymer = PolymerElement({
+ is: 'vz-projector-data-loader',
+ properties: {
+ dataSource: {
+ type: Object, // DataSource
+ notify: true
+ },
+ selectedDemo: {type: String, value: 'wiki_5k', notify: true},
+ selectedTensor: {type: String, notify: true},
+ labelOption: {type: String, notify: true},
+ colorOption: {type: Object, notify: true},
+ // Private.
+ tensorNames: Array
+ }
+});
+
+export type ColorOption = {
+ name: string; desc?: string; map?: (value: string | number) => string;
+ isSeparator?: boolean;
+};
+
+class DataLoader extends DataLoaderPolymer {
+ dataSource: DataSource;
+ selectedDemo: string;
+ labelOption: string;
+ labelOptions: string[];
+ colorOption: ColorOption;
+ colorOptions: ColorOption[];
+ selectedTensor: string;
+ tensorNames: {name: string, shape: number[]}[];
+
+ private dom: d3.Selection<any>;
+
+ ready() {
+ this.dom = d3.select(this);
+ if (this.dataSource) {
+ // There is data already.
+ return;
+ }
+ // Check to see if there is a server.
+ d3.json(`${DATA_URL}/info`, (err, serverInfo) => {
+ if (err) {
+ // No server was found, thus operate in standalone mode.
+ this.setupStandaloneMode();
+ return;
+ }
+ // Server was found, thus show the checkpoint dir and the tensors.
+ this.setupServerMode(serverInfo);
+ });
+ }
+
+ getSeparatorClass(isSeparator: boolean): string {
+ return isSeparator ? 'separator' : null;
+ }
+
+ private setupServerMode(info: ServerInfo) {
+ // Display the server-mode controls.
+ this.dom.select('.server-controls').style('display', null);
+ this.dom.select('#checkpoint-file')
+ .text(info.checkpoint_file)
+ .attr('title', info.checkpoint_file);
+ this.dom.select('#metadata-file')
+ .text(info.metadata_file)
+ .attr('title', info.metadata_file);
+
+ // Handle the list of checkpoint tensors.
+ this.dom.on('selected-tensor-changed', () => {
+ this.selectedTensorChanged(this.selectedTensor);
+ });
+ let names = Object.keys(info.tensors)
+ .filter(name => {
+ let shape = info.tensors[name];
+ return shape.length == 2 && shape[0] > 1 && shape[1] > 1;
+ })
+ .sort((a, b) => info.tensors[b][0] - info.tensors[a][0]);
+ this.tensorNames =
+ names.map(name => { return {name, shape: info.tensors[name]}; });
+ }
+
+ private updateMetadataUI(columnStats: ColumnStats[]) {
+ // Label by options.
+ let labelIndex = -1;
+ this.labelOptions = columnStats.length > 1 ? columnStats.map((stats, i) => {
+ // Make the default label by the first non-numeric column.
+ if (!stats.isNumeric && labelIndex == -1) {
+ labelIndex = i;
+ }
+ return stats.name;
+ }) :
+ ['label'];
+ this.labelOption = this.labelOptions[Math.max(0, labelIndex)];
+
+ // Color by options.
+ let standardColorOption: ColorOption[] = [
+ {name: 'No color map'},
+ // TODO(smilkov): Implement this.
+ //{name: 'Distance of neighbors',
+ // desc: 'How far is each point from its neighbors'}
+ ];
+ let metadataColorOption: ColorOption[] =
+ columnStats
+ .filter(stats => {
+ return !stats.tooManyUniqueValues || stats.isNumeric;
+ })
+ .map(stats => {
+ let map: (v: string|number) => string;
+ if (!stats.tooManyUniqueValues) {
+ let scale = d3.scale.category20();
+ let range = scale.range();
+ // Re-order the range.
+ let newRange = range.map((color, i) => {
+ let index = (i * 2) % (range.length - 1);
+ if (index == 0) {
+ index = range.length - 1;
+ }
+ return range[index];
+ });
+ scale.range(newRange).domain(stats.uniqueValues);
+ map = scale;
+ } else {
+ map = d3.scale.linear<string>()
+ .domain([stats.min, stats.max])
+ .range(['white', 'black']);
+ }
+ let desc = stats.tooManyUniqueValues ?
+ 'gradient' :
+ stats.uniqueValues.length + ' colors';
+ return {name: stats.name, desc: desc, map: map};
+ });
+ if (metadataColorOption.length > 0) {
+ // Add a separator line between built-in color maps
+ // and those based on metadata columns.
+ standardColorOption.push({name: 'Metadata', isSeparator: true});
+ }
+ this.colorOptions = standardColorOption.concat(metadataColorOption);
+ this.colorOption = this.colorOptions[0];
+ }
+
+ private setupStandaloneMode() {
+ // Display the standalone UI controls.
+ this.dom.select('.standalone-controls').style('display', null);
+
+ // Demo dataset dropdown
+ let demoDatasetChanged = (demoDataSet: DemoDataset) => {
+ if (demoDataSet == null) {
+ return;
+ }
+
+ this.dom.selectAll('.file-name').style('display', 'none');
+ let separator = demoDataSet.fpath.substr(-3) == 'tsv' ? '\t' : ' ';
+ fetchDemoData(`${DATA_URL}/${demoDataSet.fpath}`, separator)
+ .then(points => {
+
+ let p1 = demoDataSet.metadata_path ?
+ new Promise<ColumnStats[]>((resolve, reject) => {
+ updateMessage('Fetching metadata...');
+ d3.text(
+ `${DATA_URL}/${demoDataSet.metadata_path}`,
+ (err: Error, rawMetadata: string) => {
+ if (err) {
+ console.error(err);
+ reject(err);
+ return;
+ }
+ resolve(parseAndMergeMetadata(rawMetadata, points));
+ });
+ }) :
+ null;
+
+ let p2 = demoDataSet.metadata && demoDataSet.metadata.image ?
+ fetchImage(
+ `${DATA_URL}/${demoDataSet.metadata.image.sprite_fpath}`) :
+ null;
+
+ Promise.all([p1, p2]).then(values => {
+ this.updateMetadataUI(values[0]);
+ let dataSource = new DataSource();
+ dataSource.originalDataSet = new DataSet(points);
+ dataSource.spriteImage = values[1];
+ dataSource.metadata = demoDataSet.metadata;
+ this.dataSource = dataSource;
+ });
+ });
+ };
+
+ this.dom.on('selected-demo-changed', () => {
+ demoDatasetChanged(DEMO_DATASETS[this.selectedDemo]);
+ });
+ demoDatasetChanged(DEMO_DATASETS[this.selectedDemo]);
+
+ // Show and setup the upload button.
+ let fileInput = this.dom.select('#file');
+ fileInput.on('change', () => {
+ let file: File = (<any>d3.event).target.files[0];
+ this.dom.select('#file-name')
+ .style('display', null)
+ .text(file.name)
+ .attr('title', file.name);
+ // Clear out the value of the file chooser. This ensures that if the user
+ // selects the same file, we'll re-read it.
+ (<any>d3.event).target.value = '';
+ // Clear the value of the datasets dropdown.
+ this.selectedDemo = null;
+ let fileReader = new FileReader();
+ fileReader.onload = evt => {
+ let str: string = (evt.target as any).result;
+ parseTensors(str).then(data => {
+ let dataSource = new DataSource();
+ dataSource.originalDataSet = new DataSet(data);
+ this.dataSource = dataSource;
+ });
+ };
+ fileReader.readAsText(file);
+ });
+
+ let uploadButton = this.dom.select('#upload');
+ uploadButton.on(
+ 'click', () => { (<HTMLInputElement>fileInput.node()).click(); });
+
+ // Show and setup the upload metadata button.
+ let fileMetadataInput = this.dom.select('#file-metadata');
+ fileMetadataInput.on('change', () => {
+ let file: File = (<any>d3.event).target.files[0];
+ this.dom.select('#file-metadata-name')
+ .style('display', null)
+ .text(file.name)
+ .attr('title', file.name);
+ // Clear out the value of the file chooser. This ensures that if the user
+ // selects the same file, we'll re-read it.
+ (<any>d3.event).target.value = '';
+ // Clear the value of the datasets dropdown.
+ this.selectedDemo = null;
+ let fileReader = new FileReader();
+ fileReader.onload = evt => {
+ let str: string = (evt.target as any).result;
+ parseAndMergeMetadata(str, this.dataSource.originalDataSet.points)
+ .then(columnStats => {
+ this.updateMetadataUI(columnStats);
+ // Must make a shallow copy, otherwise polymer will not
+ // fire the 'data-changed' event, even if we explicitly
+ // call this.fire().
+ this.dataSource = this.dataSource.makeShallowCopy();
+ });
+ };
+ fileReader.readAsText(file);
+ });
+
+ let uploadMetadataButton = this.dom.select('#upload-metadata');
+ uploadMetadataButton.on('click', () => {
+ (<HTMLInputElement>fileMetadataInput.node()).click();
+ });
+ }
+
+ private selectedTensorChanged(name: string) {
+ // Get the tensor.
+ updateMessage('Fetching tensor values...');
+ d3.text(`${DATA_URL}/tensor?name=${name}`, (err: Error, tsv: string) => {
+ if (err) {
+ console.error(err);
+ return;
+ }
+ parseTensors(tsv).then(dataPoints => {
+ updateMessage('Fetching metadata...');
+ d3.text(`${DATA_URL}/metadata`, (err: Error, rawMetadata: string) => {
+ if (err) {
+ console.error(err);
+ return;
+ }
+ parseAndMergeMetadata(rawMetadata, dataPoints).then(columnStats => {
+ this.updateMetadataUI(columnStats);
+ let dataSource = new DataSource();
+ dataSource.originalDataSet = new DataSet(dataPoints);
+ this.dataSource = dataSource;
+ });
+ });
+ });
+ });
+ }
+
+ private getNumTensorsLabel(tensorNames: string[]) {
+ return tensorNames.length === 1 ? '1 tensor' :
+ tensorNames.length + ' tensors';
+ }
+}
+
+function fetchImage(url: string): Promise<HTMLImageElement> {
+ return new Promise<HTMLImageElement>((resolve, reject) => {
+ let image = new Image();
+ image.onload = () => resolve(image);
+ image.onerror = (err) => reject(err);
+ image.src = url;
+ });
+}
+
+/** Makes a network request for a delimited text file. */
+function fetchDemoData(url: string, separator: string): Promise<DataPoint[]> {
+ return new Promise<DataPoint[]>((resolve, reject) => {
+ updateMessage('Fetching tensors...');
+ d3.text(url, (error: Error, dataString: string) => {
+ if (error) {
+ console.error(error);
+ updateMessage('Error loading data.');
+ reject(error);
+ } else {
+ parseTensors(dataString, separator).then(data => resolve(data));
+ }
+ });
+ });
+}
+
+/** Parses a tsv text file. */
+function parseTensors(content: string, delim = '\t'): Promise<DataPoint[]> {
+ let data: DataPoint[] = [];
+ let numDim: number;
+ return runAsyncTask('Parsing tensors...', () => {
+ let lines = content.split('\n');
+ lines.forEach(line => {
+ line = line.trim();
+ if (line == '') {
+ return;
+ }
+ let row = line.split(delim);
+ let dataPoint: DataPoint = {
+ metadata: {},
+ vector: null,
+ dataSourceIndex: data.length,
+ projections: null,
+ projectedPoint: null
+ };
+ // If the first label is not a number, take it as the label.
+ if (isNaN(row[0] as any) || numDim == row.length - 1) {
+ dataPoint.metadata['label'] = row[0];
+ dataPoint.vector = row.slice(1).map(Number);
+ } else {
+ dataPoint.vector = row.map(Number);
+ }
+ data.push(dataPoint);
+ if (numDim == null) {
+ numDim = dataPoint.vector.length;
+ }
+ if (numDim != dataPoint.vector.length) {
+ updateMessage('Parsing failed. Vector dimensions do not match');
+ throw Error('Parsing failed');
+ }
+ if (numDim <= 1) {
+ updateMessage(
+ 'Parsing failed. Found a vector with only one dimension?');
+ throw Error('Parsing failed');
+ }
+ });
+ return data;
+ });
+}
+
+/** Statistics for a metadata column. */
+type ColumnStats = {
+ name: string; isNumeric: boolean; tooManyUniqueValues: boolean;
+ uniqueValues?: string[];
+ min: number;
+ max: number;
+};
+
+function parseAndMergeMetadata(
+ content: string, data: DataPoint[]): Promise<ColumnStats[]> {
+ return runAsyncTask('Parsing metadata...', () => {
+ let lines = content.split('\n').filter(line => line.trim().length > 0);
+ let hasHeader = (lines.length - 1 == data.length);
+
+ // Dimension mismatch.
+ if (lines.length != data.length && !hasHeader) {
+ throw Error('Dimensions do not match');
+ }
+
+ // If the first row doesn't contain metadata keys, we assume that the values
+ // are labels.
+ let columnNames: string[] = ['label'];
+ if (hasHeader) {
+ columnNames = lines[0].split('\t');
+ lines = lines.slice(1);
+ }
+ let columnStats: ColumnStats[] = columnNames.map(name => {
+ return {
+ name: name,
+ isNumeric: true,
+ tooManyUniqueValues: false,
+ min: Number.POSITIVE_INFINITY,
+ max: Number.NEGATIVE_INFINITY
+ };
+ });
+ let setOfValues = columnNames.map(() => d3.set());
+ lines.forEach((line: string, i: number) => {
+ let rowValues = line.split('\t');
+ data[i].metadata = {};
+ columnNames.forEach((name: string, colIndex: number) => {
+ let value = rowValues[colIndex];
+ let set = setOfValues[colIndex];
+ let stats = columnStats[colIndex];
+ data[i].metadata[name] = value;
+
+ // Update stats.
+ if (!stats.tooManyUniqueValues) {
+ set.add(value);
+ if (set.size() > NUM_COLORS_COLOR_MAP) {
+ stats.tooManyUniqueValues = true;
+ }
+ }
+ if (isNaN(value as any)) {
+ stats.isNumeric = false;
+ } else {
+ stats.min = Math.min(stats.min, +value);
+ stats.max = Math.max(stats.max, +value);
+ }
+ });
+ });
+ columnStats.forEach((stats, colIndex) => {
+ let set = setOfValues[colIndex];
+ if (!stats.tooManyUniqueValues) {
+ stats.uniqueValues = set.values();
+ }
+ });
+ return columnStats;
+ });
+}
+
+document.registerElement(DataLoader.prototype.is, DataLoader);
diff --git a/tensorflow/tools/dist_test/Dockerfile b/tensorflow/tools/dist_test/Dockerfile
index b3e7489e07..3fc50de9d5 100644
--- a/tensorflow/tools/dist_test/Dockerfile
+++ b/tensorflow/tools/dist_test/Dockerfile
@@ -20,7 +20,7 @@ RUN /var/gcloud/google-cloud-sdk/bin/gcloud components install kubectl
# Install nightly TensorFlow pip
# TODO(cais): Should we build it locally instead?
RUN pip install \
- https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+ https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Copy test files
COPY scripts /var/tf-dist-test/scripts
diff --git a/tensorflow/tools/dist_test/Dockerfile.local b/tensorflow/tools/dist_test/Dockerfile.local
index 05da1e92d2..eb615be1fe 100644
--- a/tensorflow/tools/dist_test/Dockerfile.local
+++ b/tensorflow/tools/dist_test/Dockerfile.local
@@ -36,6 +36,6 @@ RUN curl -O https://bootstrap.pypa.io/get-pip.py && \
# Install TensorFlow CPU version from nightly build.
RUN pip --no-cache-dir install \
- https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+ https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
ADD . /var/tf_dist_test
diff --git a/tensorflow/tools/dist_test/scripts/dist_mnist_test.sh b/tensorflow/tools/dist_test/scripts/dist_mnist_test.sh
index 4f2cab22d9..7ebe80db1b 100755
--- a/tensorflow/tools/dist_test/scripts/dist_mnist_test.sh
+++ b/tensorflow/tools/dist_test/scripts/dist_mnist_test.sh
@@ -133,7 +133,7 @@ timeout ${TIMEOUT} python "${MNIST_REPLICA}" \
# Get N_PS by PS_HOSTS
N_PS=$(echo ${PS_HOSTS} | awk -F "," '{printf NF}')
# Replace the delimiter with " "
-PS_ARRAY=$(echo ${PS_HOSTS} | awk -F "," '{for(i=1;i<=NF;i++){printf $i" "}}')
+PS_ARRAY=($(echo ${PS_HOSTS} | awk -F "," '{for(i=1;i<=NF;i++){printf $i" "}}'))
# Run a number of ps in parallel. In general, we only set 1 ps.
echo "${N_PS} ps process(es) running in parallel..."
@@ -166,7 +166,7 @@ fi
# Get N_WORKERS by WORKER_HOSTS
N_WORKERS=$(echo ${WORKER_HOSTS} | awk -F "," '{printf NF}')
# Replace the delimiter with " "
-WORKER_ARRAY=$(echo ${WORKER_HOSTS} | awk -F "," '{for(i=1;i<=NF;i++){printf $i" "}}')
+WORKER_ARRAY=($(echo ${WORKER_HOSTS} | awk -F "," '{for(i=1;i<=NF;i++){printf $i" "}}'))
# Run a number of workers in parallel
echo "${N_WORKERS} worker process(es) running in parallel..."
diff --git a/tensorflow/tools/dist_test/server/Dockerfile b/tensorflow/tools/dist_test/server/Dockerfile
index 6876621299..d1d11e0524 100644
--- a/tensorflow/tools/dist_test/server/Dockerfile
+++ b/tensorflow/tools/dist_test/server/Dockerfile
@@ -36,7 +36,7 @@ RUN curl -O https://bootstrap.pypa.io/get-pip.py && \
# Install TensorFlow CPU version from nightly build
RUN pip --no-cache-dir install \
- https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+ https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Copy files, including the GRPC server binary at
# server/grpc_tensorflow_server.py
diff --git a/tensorflow/tools/dist_test/server/Dockerfile.test b/tensorflow/tools/dist_test/server/Dockerfile.test
index 1f7d2bdc05..298d1854a7 100644
--- a/tensorflow/tools/dist_test/server/Dockerfile.test
+++ b/tensorflow/tools/dist_test/server/Dockerfile.test
@@ -42,7 +42,7 @@ RUN pip install --upgrade pandas==0.18.1
# Install TensorFlow CPU version.
RUN pip --no-cache-dir install \
- https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+ https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Copy files, including the GRPC server binary at
# server/grpc_tensorflow_server.py
diff --git a/tensorflow/tools/docker/Dockerfile b/tensorflow/tools/docker/Dockerfile
index d8a7839542..68d71b0b2f 100644
--- a/tensorflow/tools/docker/Dockerfile
+++ b/tensorflow/tools/docker/Dockerfile
@@ -32,7 +32,7 @@ RUN pip --no-cache-dir install \
&& \
python -m ipykernel.kernelspec
-ENV TENSORFLOW_VERSION 0.10.0rc0
+ENV TENSORFLOW_VERSION 0.10.0
# --- DO NOT EDIT OR DELETE BETWEEN THE LINES --- #
# These lines will be edited automatically by parameterized_docker_build.sh. #
diff --git a/tensorflow/tools/docker/Dockerfile.devel b/tensorflow/tools/docker/Dockerfile.devel
index 69868b2e8b..794c18f196 100644
--- a/tensorflow/tools/docker/Dockerfile.devel
+++ b/tensorflow/tools/docker/Dockerfile.devel
@@ -65,7 +65,7 @@ RUN echo "build --spawn_strategy=standalone --genrule_strategy=standalone" \
>>/root/.bazelrc
ENV BAZELRC /root/.bazelrc
# Install the most recent bazel release.
-ENV BAZEL_VERSION 0.3.0
+ENV BAZEL_VERSION 0.3.1
WORKDIR /
RUN mkdir /bazel && \
cd /bazel && \
diff --git a/tensorflow/tools/docker/Dockerfile.devel-gpu b/tensorflow/tools/docker/Dockerfile.devel-gpu
index 304efc3a1d..9bd6129322 100644
--- a/tensorflow/tools/docker/Dockerfile.devel-gpu
+++ b/tensorflow/tools/docker/Dockerfile.devel-gpu
@@ -66,7 +66,7 @@ RUN echo "build --spawn_strategy=standalone --genrule_strategy=standalone" \
>>/root/.bazelrc
ENV BAZELRC /root/.bazelrc
# Install the most recent bazel release.
-ENV BAZEL_VERSION 0.3.0
+ENV BAZEL_VERSION 0.3.1
WORKDIR /
RUN mkdir /bazel && \
cd /bazel && \
diff --git a/tensorflow/tools/docker/Dockerfile.gpu b/tensorflow/tools/docker/Dockerfile.gpu
index 428f450d92..6cd4a57e25 100644
--- a/tensorflow/tools/docker/Dockerfile.gpu
+++ b/tensorflow/tools/docker/Dockerfile.gpu
@@ -32,7 +32,7 @@ RUN pip --no-cache-dir install \
&& \
python -m ipykernel.kernelspec
-ENV TENSORFLOW_VERSION 0.10.0rc0
+ENV TENSORFLOW_VERSION 0.10.0
# --- DO NOT EDIT OR DELETE BETWEEN THE LINES --- #
# These lines will be edited automatically by parameterized_docker_build.sh. #
diff --git a/tensorflow/tools/docker/notebooks/1_hello_tensorflow.ipynb b/tensorflow/tools/docker/notebooks/1_hello_tensorflow.ipynb
index 3854e33232..093f564c94 100644
--- a/tensorflow/tools/docker/notebooks/1_hello_tensorflow.ipynb
+++ b/tensorflow/tools/docker/notebooks/1_hello_tensorflow.ipynb
@@ -1,721 +1,781 @@
{
- "nbformat": 4,
- "nbformat_minor": 0,
- "metadata": {
- "colab": {
- "version": "0.3.2",
- "views": {},
- "default_view": {},
- "name": "Untitled",
- "provenance": []
- }
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "a3bskVXPvchm"
+ },
+ "source": [
+ "# Hello, TensorFlow\n",
+ "## A beginner-level, getting started, basic introduction to TensorFlow"
+ ]
},
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "a3bskVXPvchm",
- "colab_type": "text"
- },
- "source": [
- "# Hello, TensorFlow\n",
- "## A beginner-level, getting started, basic introduction to TensorFlow"
- ]
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "Rb5rSpcZvYbX"
+ },
+ "source": [
+ "TensorFlow is a general-purpose system for graph-based computation. A typical use is machine learning. In this notebook, we'll introduce the basic concepts of TensorFlow using some simple examples.\n",
+ "\n",
+ "TensorFlow gets its name from [tensors](https://en.wikipedia.org/wiki/Tensor), which are arrays of arbitrary dimensionality. A vector is a 1-d array and is known as a 1st-order tensor. A matrix is a 2-d array and a 2nd-order tensor. The \"flow\" part of the name refers to computation flowing through a graph. Training and inference in a neural network, for example, involves the propagation of matrix computations through many nodes in a computational graph.\n",
+ "\n",
+ "When you think of doing things in TensorFlow, you might want to think of creating tensors (like matrices), adding operations (that output other tensors), and then executing the computation (running the computational graph). In particular, it's important to realize that when you add an operation on tensors, it doesn't execute immediately. Rather, TensorFlow waits for you to define all the operations you want to perform. Then, TensorFlow optimizes the computation graph, deciding how to execute the computation, before generating the data. Because of this, a tensor in TensorFlow isn't so much holding the data as a placeholder for holding the data, waiting for the data to arrive when a computation is executed."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "E8FhiMivhcYB"
+ },
+ "source": [
+ "## Adding two vectors in TensorFlow\n",
+ "\n",
+ "Let's start with something that should be simple. Let's add two length four vectors (two 1st-order tensors):\n",
+ "\n",
+ "$\\begin{bmatrix} 1. & 1. & 1. & 1.\\end{bmatrix} + \\begin{bmatrix} 2. & 2. & 2. & 2.\\end{bmatrix} = \\begin{bmatrix} 3. & 3. & 3. & 3.\\end{bmatrix}$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:33:43.348840",
+ "start_time": "2016-09-16T14:33:41.278845"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "Rb5rSpcZvYbX",
- "colab_type": "text"
- },
- "source": [
- "TensorFlow is a general-purpose system for graph-based computation. A typical use is machine learning. In this notebook, we'll introduce the basic concepts of TensorFlow using some simple examples.\n",
- "\n",
- "TensorFlow gets its name from [tensors](https://en.wikipedia.org/wiki/Tensor), which are arrays of arbitrary dimensionality. A vector is a 1-d array and is known as a 1st-order tensor. A matrix is a 2-d array and a 2nd-order tensor. The \"flow\" part of the name refers to computation flowing through a graph. Training and inference in a neural network, for example, involves the propagation of matrix computations through many nodes in a computational graph.\n",
- "\n",
- "When you think of doing things in TensorFlow, you might want to think of creating tensors (like matrices), adding operations (that output other tensors), and then executing the computation (running the computational graph). In particular, it's important to realize that when you add an operation on tensors, it doesn't execute immediately. Rather, TensorFlow waits for you to define all the operations you want to perform. Then, TensorFlow optimizes the computation graph, deciding how to execute the computation, before generating the data. Because of this, a tensor in TensorFlow isn't so much holding the data as a placeholder for holding the data, waiting for the data to arrive when a computation is executed."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "E8FhiMivhcYB",
- "colab_type": "text"
- },
- "source": [
- "## Adding two vectors in TensorFlow\n",
- "\n",
- "Let's start with something that should be simple. Let's add two length four vectors (two 1st-order tensors):\n",
- "\n",
- "$\\begin{bmatrix} 1. & 1. & 1. & 1.\\end{bmatrix} + \\begin{bmatrix} 2. & 2. & 2. & 2.\\end{bmatrix} = \\begin{bmatrix} 3. & 3. & 3. & 3.\\end{bmatrix}$"
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 131,
+ "status": "ok",
+ "timestamp": 1446243605678,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "7391995727249e65",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 420
},
+ "id": "2iv3XQ6k3eF1",
+ "outputId": "e21e1144-736a-4b1f-df78-a9ceab9d4c61"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "2iv3XQ6k3eF1",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 131,
- "status": "ok",
- "timestamp": 1446243605678,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "7391995727249e65",
- "userId": "106975671469698476657"
- },
- "user_tz": 420
- },
- "outputId": "e21e1144-736a-4b1f-df78-a9ceab9d4c61"
- },
- "source": [
- "import tensorflow as tf\n",
- "\n",
- "with tf.Session():\n",
- " input1 = tf.constant([1.0, 1.0, 1.0, 1.0])\n",
- " input2 = tf.constant([2.0, 2.0, 2.0, 2.0])\n",
- " output = tf.add(input1, input2)\n",
- " result = output.eval()\n",
- " print result"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "[ 3. 3. 3. 3.]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "result: [ 3. 3. 3. 3.]\n"
+ ]
+ }
+ ],
+ "source": [
+ "from __future__ import print_function\n",
+ "\n",
+ "import tensorflow as tf\n",
+ "\n",
+ "with tf.Session():\n",
+ " input1 = tf.constant([1.0, 1.0, 1.0, 1.0])\n",
+ " input2 = tf.constant([2.0, 2.0, 2.0, 2.0])\n",
+ " output = tf.add(input1, input2)\n",
+ " result = output.eval()\n",
+ " print(\"result: \", result)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "dqLV5GXT3wLy"
+ },
+ "source": [
+ "What we're doing is creating two vectors, [1.0, 1.0, 1.0, 1.0] and [2.0, 2.0, 2.0, 2.0], and then adding them. Here's equivalent code in raw Python and using numpy:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:27:17.006000",
+ "start_time": "2016-09-16T14:27:17.000480"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "dqLV5GXT3wLy",
- "colab_type": "text"
- },
- "source": [
- "What we're doing is creating two vectors, [1.0, 1.0, 1.0, 1.0] and [2.0, 2.0, 2.0, 2.0], and then adding them. Here's equivalent code in raw Python and using numpy:"
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "7DzDJ7sW79ao",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 152,
- "status": "ok",
- "timestamp": 1446242020458,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "7391995727249e65",
- "userId": "106975671469698476657"
- },
- "user_tz": 420
- },
- "outputId": "cf89e613-06e5-4435-bea3-9f48a4eff943"
- },
- "source": [
- "print [x + y for x, y in zip([1.0] * 4, [2.0] * 4)]"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "[3.0, 3.0, 3.0, 3.0]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 152,
+ "status": "ok",
+ "timestamp": 1446242020458,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "7391995727249e65",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 420
},
+ "id": "7DzDJ7sW79ao",
+ "outputId": "cf89e613-06e5-4435-bea3-9f48a4eff943"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "MDWJf0lHAF4E",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 97,
- "status": "ok",
- "timestamp": 1446242021921,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "7391995727249e65",
- "userId": "106975671469698476657"
- },
- "user_tz": 420
- },
- "outputId": "66d8c4a2-92b7-4048-b365-39dc42dff2bc"
- },
- "source": [
- "import numpy as np\n",
- "x, y = np.full(4, 1.0), np.full(4, 2.0)\n",
- "print \"{} + {} = {}\".format(x, y, x + y)"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "[ 1. 1. 1. 1.] + [ 2. 2. 2. 2.] = [ 3. 3. 3. 3.]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[3.0, 3.0, 3.0, 3.0]\n"
+ ]
+ }
+ ],
+ "source": [
+ "print([x + y for x, y in zip([1.0] * 4, [2.0] * 4)])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:27:26.950716",
+ "start_time": "2016-09-16T14:27:26.940827"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "I52jQOyO8vAn",
- "colab_type": "text"
- },
- "source": [
- "## Details of adding two vectors in TensorFlow\n",
- "\n",
- "The example above of adding two vectors involves a lot more than it seems, so let's look at it in more depth.\n",
- "\n",
- ">`import tensorflow as tf`\n",
- "\n",
- "This import brings TensorFlow's public API into our IPython runtime environment.\n",
- "\n",
- ">`with tf.Session():`\n",
- "\n",
- "When you run an operation in TensorFlow, you need to do it in the context of a `Session`. A session holds the computation graph, which contains the tensors and the operations. When you create tensors and operations, they are not executed immediately, but wait for other operations and tensors to be added to the graph, only executing when finally requested to produce the results of the session. Deferring the execution like this provides additional opportunities for parallelism and optimization, as TensorFlow can decide how to combine operations and where to run them after TensorFlow knows about all the operations. \n",
- "\n",
- ">>`input1 = tf.constant([1.0, 1.0, 1.0, 1.0])`\n",
- "\n",
- ">>`input2 = tf.constant([2.0, 2.0, 2.0, 2.0])`\n",
- "\n",
- "The next two lines create tensors using a convenience function called `constant`, which is similar to numpy's `array` and numpy's `full`. If you look at the code for `constant`, you can see the details of what it is doing to create the tensor. In summary, it creates a tensor of the necessary shape and applies the constant operator to it to fill it with the provided values. The values to `constant` can be Python or numpy arrays. `constant` can take an optional shape parameter, which works similarly to numpy's `fill` if provided, and an optional name parameter, which can be used to put a more human-readable label on the operation in the TensorFlow operation graph.\n",
- "\n",
- ">>`output = tf.add(input1, input2)`\n",
- "\n",
- "You might think `add` just adds the two vectors now, but it doesn't quite do that. What it does is put the `add` operation into the computational graph. The results of the addition aren't available yet. They've been put in the computation graph, but the computation graph hasn't been executed yet.\n",
- "\n",
- ">>`result = output.eval()`\n",
- "\n",
- ">>`print result`\n",
- "\n",
- "`eval()` is also slightly more complicated than it looks. Yes, it does get the value of the vector (tensor) that results from the addition. It returns this as a numpy array, which can then be printed. But, it's important to realize it also runs the computation graph at this point, because we demanded the output from the operation node of the graph; to produce that, it had to run the computation graph. So, this is the point where the addition is actually performed, not when `add` was called, as `add` just put the addition operation into the TensorFlow computation graph."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "H_5_2YY3ySr2",
- "colab_type": "text"
- },
- "source": [
- "## Multiple operations\n",
- "\n",
- "To use TensorFlow, you add operations on tensors that produce tensors to the computation graph, then execute that graph to run all those operations and calculate the values of all the tensors in the graph.\n",
- "\n",
- "Here's a simple example with two operations:"
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 97,
+ "status": "ok",
+ "timestamp": 1446242021921,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "7391995727249e65",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 420
},
+ "id": "MDWJf0lHAF4E",
+ "outputId": "66d8c4a2-92b7-4048-b365-39dc42dff2bc"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "-kQmn3U_yXX8",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 101,
- "status": "ok",
- "timestamp": 1446242580297,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "7391995727249e65",
- "userId": "106975671469698476657"
- },
- "user_tz": 420
- },
- "outputId": "e96a6e27-665e-47d3-822e-47aeb66fc7f8"
- },
- "source": [
- "import tensorflow as tf\n",
- "\n",
- "with tf.Session():\n",
- " input1 = tf.constant(1.0, shape=[4])\n",
- " input2 = tf.constant(2.0, shape=[4])\n",
- " input3 = tf.constant(3.0, shape=[4])\n",
- " output = tf.add(tf.add(input1, input2), input3)\n",
- " result = output.eval()\n",
- " print result"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "[ 6. 6. 6. 6.]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[ 1. 1. 1. 1.] + [ 2. 2. 2. 2.] = [ 3. 3. 3. 3.]\n"
+ ]
+ }
+ ],
+ "source": [
+ "import numpy as np\n",
+ "x, y = np.full(4, 1.0), np.full(4, 2.0)\n",
+ "print(\"{} + {} = {}\".format(x, y, x + y))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "I52jQOyO8vAn"
+ },
+ "source": [
+ "## Details of adding two vectors in TensorFlow\n",
+ "\n",
+ "The example above of adding two vectors involves a lot more than it seems, so let's look at it in more depth.\n",
+ "\n",
+ ">`import tensorflow as tf`\n",
+ "\n",
+ "This import brings TensorFlow's public API into our IPython runtime environment.\n",
+ "\n",
+ ">`with tf.Session():`\n",
+ "\n",
+ "When you run an operation in TensorFlow, you need to do it in the context of a `Session`. A session holds the computation graph, which contains the tensors and the operations. When you create tensors and operations, they are not executed immediately, but wait for other operations and tensors to be added to the graph, only executing when finally requested to produce the results of the session. Deferring the execution like this provides additional opportunities for parallelism and optimization, as TensorFlow can decide how to combine operations and where to run them after TensorFlow knows about all the operations. \n",
+ "\n",
+ ">>`input1 = tf.constant([1.0, 1.0, 1.0, 1.0])`\n",
+ "\n",
+ ">>`input2 = tf.constant([2.0, 2.0, 2.0, 2.0])`\n",
+ "\n",
+ "The next two lines create tensors using a convenience function called `constant`, which is similar to numpy's `array` and numpy's `full`. If you look at the code for `constant`, you can see the details of what it is doing to create the tensor. In summary, it creates a tensor of the necessary shape and applies the constant operator to it to fill it with the provided values. The values to `constant` can be Python or numpy arrays. `constant` can take an optional shape parameter, which works similarly to numpy's `fill` if provided, and an optional name parameter, which can be used to put a more human-readable label on the operation in the TensorFlow operation graph.\n",
+ "\n",
+ ">>`output = tf.add(input1, input2)`\n",
+ "\n",
+ "You might think `add` just adds the two vectors now, but it doesn't quite do that. What it does is put the `add` operation into the computational graph. The results of the addition aren't available yet. They've been put in the computation graph, but the computation graph hasn't been executed yet.\n",
+ "\n",
+ ">>`result = output.eval()`\n",
+ "\n",
+ ">>`print result`\n",
+ "\n",
+ "`eval()` is also slightly more complicated than it looks. Yes, it does get the value of the vector (tensor) that results from the addition. It returns this as a numpy array, which can then be printed. But, it's important to realize it also runs the computation graph at this point, because we demanded the output from the operation node of the graph; to produce that, it had to run the computation graph. So, this is the point where the addition is actually performed, not when `add` was called, as `add` just put the addition operation into the TensorFlow computation graph."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "H_5_2YY3ySr2"
+ },
+ "source": [
+ "## Multiple operations\n",
+ "\n",
+ "To use TensorFlow, you add operations on tensors that produce tensors to the computation graph, then execute that graph to run all those operations and calculate the values of all the tensors in the graph.\n",
+ "\n",
+ "Here's a simple example with two operations:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:27:34.256654",
+ "start_time": "2016-09-16T14:27:34.237320"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "Hod0zvsly8YT",
- "colab_type": "text"
- },
- "source": [
- "This version uses `constant` in a way similar to numpy's `fill`, specifying the optional shape and having the values copied out across it.\n",
- "\n",
- "The `add` operator supports operator overloading, so you could try writing it inline as `input1 + input2` instead as well as experimenting with other operators."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "yS2WElRfxz53",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 156,
- "status": "ok",
- "timestamp": 1446242664353,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "7391995727249e65",
- "userId": "106975671469698476657"
- },
- "user_tz": 420
- },
- "outputId": "9818bf3c-5659-4a87-8b5d-40a28f1a2677"
- },
- "source": [
- "with tf.Session():\n",
- " input1 = tf.constant(1.0, shape=[4])\n",
- " input2 = tf.constant(2.0, shape=[4])\n",
- " output = input1 + input2\n",
- " print output.eval()"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "[ 3. 3. 3. 3.]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 101,
+ "status": "ok",
+ "timestamp": 1446242580297,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "7391995727249e65",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 420
},
+ "id": "-kQmn3U_yXX8",
+ "outputId": "e96a6e27-665e-47d3-822e-47aeb66fc7f8"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "zszjoYUjkUNU",
- "colab_type": "text"
- },
- "source": [
- "## Adding two matrices"
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[ 6. 6. 6. 6.]\n"
+ ]
+ }
+ ],
+ "source": [
+ "import tensorflow as tf\n",
+ "\n",
+ "with tf.Session():\n",
+ " input1 = tf.constant(1.0, shape=[4])\n",
+ " input2 = tf.constant(2.0, shape=[4])\n",
+ " input3 = tf.constant(3.0, shape=[4])\n",
+ " output = tf.add(tf.add(input1, input2), input3)\n",
+ " result = output.eval()\n",
+ " print(result)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "Hod0zvsly8YT"
+ },
+ "source": [
+ "This version uses `constant` in a way similar to numpy's `fill`, specifying the optional shape and having the values copied out across it.\n",
+ "\n",
+ "The `add` operator supports operator overloading, so you could try writing it inline as `input1 + input2` instead as well as experimenting with other operators."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:34:05.047883",
+ "start_time": "2016-09-16T14:34:05.032263"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "EWNYBCB6kbri",
- "colab_type": "text"
- },
- "source": [
- "Next, let's do something very similar, adding two matrices:\n",
- "\n",
- "$\\begin{bmatrix}\n",
- " 1. & 1. & 1. \\\\\n",
- " 1. & 1. & 1. \\\\\n",
- "\\end{bmatrix} + \n",
- "\\begin{bmatrix}\n",
- " 1. & 2. & 3. \\\\\n",
- " 4. & 5. & 6. \\\\\n",
- "\\end{bmatrix} = \n",
- "\\begin{bmatrix}\n",
- " 2. & 3. & 4. \\\\\n",
- " 5. & 6. & 7. \\\\\n",
- "\\end{bmatrix}$"
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "tmWcCxSilYkg",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 1540,
- "status": "ok",
- "timestamp": 1446242690334,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "7391995727249e65",
- "userId": "106975671469698476657"
- },
- "user_tz": 420
- },
- "outputId": "f3a2e904-790b-42e1-9ca4-2f3c54d7f4a8"
- },
- "source": [
- "import tensorflow as tf\n",
- "import numpy as np\n",
- "\n",
- "with tf.Session():\n",
- " input1 = tf.constant(1.0, shape=[2, 3])\n",
- " input2 = tf.constant(np.reshape(np.arange(1.0, 7.0, dtype=np.float32), (2, 3)))\n",
- " output = tf.add(input1, input2)\n",
- " print output.eval()"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "[[ 2. 3. 4.]\n",
- " [ 5. 6. 7.]]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 156,
+ "status": "ok",
+ "timestamp": 1446242664353,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "7391995727249e65",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 420
},
+ "id": "yS2WElRfxz53",
+ "outputId": "9818bf3c-5659-4a87-8b5d-40a28f1a2677"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "JuU3Bmglq1vd",
- "colab_type": "text"
- },
- "source": [
- "Recall that you can pass numpy or Python arrays into `constant`.\n",
- "\n",
- "In this example, the matrix with values from 1 to 6 is created in numpy and passed into `constant`, but TensorFlow also has `range`, `reshape`, and `tofloat` operators. Doing this entirely within TensorFlow could be more efficient if this was a very large matrix.\n",
- "\n",
- "Try experimenting with this code a bit -- maybe modifying some of the values, using the numpy version, doing this using, adding another operation, or doing this using TensorFlow's `range` function."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[ 3. 3. 3. 3.]\n"
+ ]
+ }
+ ],
+ "source": [
+ "with tf.Session():\n",
+ " input1 = tf.constant(1.0, shape=[4])\n",
+ " input2 = tf.constant(2.0, shape=[4])\n",
+ " output = input1 + input2\n",
+ " print(output.eval())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "zszjoYUjkUNU"
+ },
+ "source": [
+ "## Adding two matrices"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "EWNYBCB6kbri"
+ },
+ "source": [
+ "Next, let's do something very similar, adding two matrices:\n",
+ "\n",
+ "$\\begin{bmatrix}\n",
+ " 1. & 1. & 1. \\\\\n",
+ " 1. & 1. & 1. \\\\\n",
+ "\\end{bmatrix} + \n",
+ "\\begin{bmatrix}\n",
+ " 1. & 2. & 3. \\\\\n",
+ " 4. & 5. & 6. \\\\\n",
+ "\\end{bmatrix} = \n",
+ "\\begin{bmatrix}\n",
+ " 2. & 3. & 4. \\\\\n",
+ " 5. & 6. & 7. \\\\\n",
+ "\\end{bmatrix}$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:34:11.234151",
+ "start_time": "2016-09-16T14:34:11.214414"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "gnXnpnuLrflb",
- "colab_type": "text"
- },
- "source": [
- "## Multiplying matrices"
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "Ho-QNSOorj0y",
- "colab_type": "text"
- },
- "source": [
- "Let's move on to matrix multiplication. This time, let's use a bit vector and some random values, which is a good step toward some of what we'll need to do for regression and neural networks."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 1540,
+ "status": "ok",
+ "timestamp": 1446242690334,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "7391995727249e65",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 420
},
+ "id": "tmWcCxSilYkg",
+ "outputId": "f3a2e904-790b-42e1-9ca4-2f3c54d7f4a8"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "uNqMaFR8sIY5",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 132,
- "status": "ok",
- "timestamp": 1446242872027,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "7391995727249e65",
- "userId": "106975671469698476657"
- },
- "user_tz": 420
- },
- "outputId": "fc0e29a0-306c-4709-c181-1108d5a21d88"
- },
- "source": [
- "#@test {\"output\": \"ignore\"}\n",
- "import tensorflow as tf\n",
- "import numpy as np\n",
- "\n",
- "with tf.Session():\n",
- " input_features = tf.constant(np.reshape([1, 0, 0, 1], (1, 4)).astype(np.float32))\n",
- " weights = tf.constant(np.random.randn(4, 2).astype(np.float32))\n",
- " output = tf.matmul(input_features, weights)\n",
- " print \"Input:\"\n",
- " print input_features.eval()\n",
- " print \"Weights:\"\n",
- " print weights.eval()\n",
- " print \"Output:\"\n",
- " print output.eval()"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Input:\n",
- "[[ 1. 0. 0. 1.]]\n",
- "Weights:\n",
- "[[-0.8187139 -0.81037313]\n",
- " [-0.31439888 -2.36761999]\n",
- " [-1.3127892 -0.33629459]\n",
- " [-1.23475349 -1.19031894]]\n",
- "Output:\n",
- "[[-2.05346727 -2.00069213]]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[[ 2. 3. 4.]\n",
+ " [ 5. 6. 7.]]\n"
+ ]
+ }
+ ],
+ "source": [
+ "import tensorflow as tf\n",
+ "import numpy as np\n",
+ "\n",
+ "with tf.Session():\n",
+ " input1 = tf.constant(1.0, shape=[2, 3])\n",
+ " input2 = tf.constant(np.reshape(np.arange(1.0, 7.0, dtype=np.float32), (2, 3)))\n",
+ " output = tf.add(input1, input2)\n",
+ " print(output.eval())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "JuU3Bmglq1vd"
+ },
+ "source": [
+ "Recall that you can pass numpy or Python arrays into `constant`.\n",
+ "\n",
+ "In this example, the matrix with values from 1 to 6 is created in numpy and passed into `constant`, but TensorFlow also has `range`, `reshape`, and `tofloat` operators. Doing this entirely within TensorFlow could be more efficient if this was a very large matrix.\n",
+ "\n",
+ "Try experimenting with this code a bit -- maybe modifying some of the values, using the numpy version, doing this using, adding another operation, or doing this using TensorFlow's `range` function."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "gnXnpnuLrflb"
+ },
+ "source": [
+ "## Multiplying matrices"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "Ho-QNSOorj0y"
+ },
+ "source": [
+ "Let's move on to matrix multiplication. This time, let's use a bit vector and some random values, which is a good step toward some of what we'll need to do for regression and neural networks."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:34:21.587915",
+ "start_time": "2016-09-16T14:34:21.560728"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "JDAVTPhb22AP",
- "colab_type": "text"
- },
- "source": [
- "Above, we're taking a 1 x 4 vector [1 0 0 1] and multiplying it by a 4 by 2 matrix full of random values from a normal distribution (mean 0, stdev 1). The output is a 1 x 2 matrix.\n",
- "\n",
- "You might try modifying this example. Running the cell multiple times will generate new random weights and a new output. Or, change the input, e.g., to \\[0 0 0 1]), and run the cell again. Or, try initializing the weights using the TensorFlow op, e.g., `random_normal`, instead of using numpy to generate the random weights.\n",
- "\n",
- "What we have here is the basics of a simple neural network already. If we are reading in the input features, along with some expected output, and change the weights based on the error with the output each time, that's a neural network."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "XhnBjAUILuy8",
- "colab_type": "text"
- },
- "source": [
- "## Use of variables\n",
- "\n",
- "Let's look at adding two small matrices in a loop, not by creating new tensors every time, but by updating the existing values and then re-running the computation graph on the new data. This happens a lot with machine learning models, where we change some parameters each time such as gradient descent on some weights and then perform the same computations over and over again."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 132,
+ "status": "ok",
+ "timestamp": 1446242872027,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "7391995727249e65",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 420
},
+ "id": "uNqMaFR8sIY5",
+ "outputId": "fc0e29a0-306c-4709-c181-1108d5a21d88"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "vJ_AgZ8lLtRv",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 180,
- "status": "ok",
- "timestamp": 1446244201894,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "7391995727249e65",
- "userId": "106975671469698476657"
- },
- "user_tz": 420
- },
- "outputId": "8d3aadaa-2b34-4642-889b-e3daaf5ee693"
- },
- "source": [
- "#@test {\"output\": \"ignore\"}\n",
- "import tensorflow as tf\n",
- "import numpy as np\n",
- "\n",
- "with tf.Session() as sess:\n",
- " # Set up two variables, total and weights, that we'll change repeatedly.\n",
- " total = tf.Variable(tf.zeros([1, 2]))\n",
- " weights = tf.Variable(tf.random_uniform([1,2]))\n",
- " \n",
- " # Initialize the variables we defined above.\n",
- " tf.initialize_all_variables().run()\n",
- " \n",
- " # This only adds the operators to the graph right now. The assignment\n",
- " # and addition operations are not performed yet.\n",
- " update_weights = tf.assign(weights, tf.random_uniform([1, 2], -1.0, 1.0))\n",
- " update_total = tf.assign(total, tf.add(total, weights))\n",
- " \n",
- " for _ in range(5):\n",
- " # Actually run the operation graph, so randomly generate weights and then\n",
- " # add them into the total. Order does matter here. We need to update\n",
- " # the weights before updating the total.\n",
- " sess.run(update_weights)\n",
- " sess.run(update_total)\n",
- " \n",
- " print weights.eval(), total.eval()"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "[[-0.41494703 0.47648168]] [[-0.41494703 0.47648168]]\n",
- "[[ 0.35746408 0.99504066]] [[-0.05748296 1.47152233]]\n",
- "[[-0.46462393 -0.80201006]] [[-0.52210689 0.66951227]]\n",
- "[[-0.99513483 -0.42322445]] [[-1.51724172 0.24628782]]\n",
- "[[ 0.13371086 -0.85545826]] [[-1.38353086 -0.60917044]]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Input:\n",
+ "[[ 1. 0. 0. 1.]]\n",
+ "Weights:\n",
+ "[[ 1.31367278 -1.6877197 ]\n",
+ " [-0.66279149 -1.53286076]\n",
+ " [-0.82625914 -0.2789003 ]\n",
+ " [ 0.14008982 -1.76367188]]\n",
+ "Output:\n",
+ "[[ 1.45376265 -3.4513917 ]]\n"
+ ]
+ }
+ ],
+ "source": [
+ "#@test {\"output\": \"ignore\"}\n",
+ "import tensorflow as tf\n",
+ "import numpy as np\n",
+ "\n",
+ "with tf.Session():\n",
+ " input_features = tf.constant(np.reshape([1, 0, 0, 1], (1, 4)).astype(np.float32))\n",
+ " weights = tf.constant(np.random.randn(4, 2).astype(np.float32))\n",
+ " output = tf.matmul(input_features, weights)\n",
+ " print(\"Input:\")\n",
+ " print(input_features.eval())\n",
+ " print(\"Weights:\")\n",
+ " print(weights.eval())\n",
+ " print(\"Output:\")\n",
+ " print(output.eval())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "JDAVTPhb22AP"
+ },
+ "source": [
+ "Above, we're taking a 1 x 4 vector [1 0 0 1] and multiplying it by a 4 by 2 matrix full of random values from a normal distribution (mean 0, stdev 1). The output is a 1 x 2 matrix.\n",
+ "\n",
+ "You might try modifying this example. Running the cell multiple times will generate new random weights and a new output. Or, change the input, e.g., to \\[0 0 0 1]), and run the cell again. Or, try initializing the weights using the TensorFlow op, e.g., `random_normal`, instead of using numpy to generate the random weights.\n",
+ "\n",
+ "What we have here is the basics of a simple neural network already. If we are reading in the input features, along with some expected output, and change the weights based on the error with the output each time, that's a neural network."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "XhnBjAUILuy8"
+ },
+ "source": [
+ "## Use of variables\n",
+ "\n",
+ "Let's look at adding two small matrices in a loop, not by creating new tensors every time, but by updating the existing values and then re-running the computation graph on the new data. This happens a lot with machine learning models, where we change some parameters each time such as gradient descent on some weights and then perform the same computations over and over again."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:34:40.634269",
+ "start_time": "2016-09-16T14:34:40.568060"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "kSYJr89aM_n0",
- "colab_type": "text"
- },
- "source": [
- "This is more complicated. At a high level, we create two variables and add operations over them, then, in a loop, repeatedly execute those operations. Let's walk through it step by step.\n",
- "\n",
- "Starting off, the code creates two variables, `total` and `weights`. `total` is initialized to \\[0, 0\\] and `weights` is initialized to random values between -1 and 1.\n",
- "\n",
- "Next, two assignment operators are added to the graph, one that updates weights with random values from [-1, 1], the other that updates the total with the new weights. Again, the operators are not executed here. In fact, this isn't even inside the loop. We won't execute these operations until the `eval` call inside the loop.\n",
- "\n",
- "Finally, in the for loop, we run each of the operators. In each iteration of the loop, this executes the operators we added earlier, first putting random values into the weights, then updating the totals with the new weights. This call uses `eval` on the session; the code also could have called `eval` on the operators (e.g. `update_weights.eval`).\n",
- "\n",
- "It can be a little hard to wrap your head around exactly what computation is done when. The important thing to remember is that computation is only performed on demand.\n",
- "\n",
- "Variables can be useful in cases where you have a large amount of computation and data that you want to use over and over again with just a minor change to the input each time. That happens quite a bit with neural networks, for example, where you just want to update the weights each time you go through the batches of input data, then run the same operations over again."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 180,
+ "status": "ok",
+ "timestamp": 1446244201894,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "7391995727249e65",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 420
+ },
+ "id": "vJ_AgZ8lLtRv",
+ "outputId": "8d3aadaa-2b34-4642-889b-e3daaf5ee693"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "fL3WfAbKzqr5",
- "colab_type": "text"
- },
- "source": [
- "## What's next?\n",
- "\n",
- "This has been a gentle introduction to TensorFlow, focused on what TensorFlow is and the very basics of doing anything in TensorFlow. If you'd like more, the next tutorial in the series is Getting Started with TensorFlow, also available in the [notebooks directory](..)."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[[ 0.8507843 -0.5834744]] [[ 0.8507843 -0.5834744]]\n",
+ "[[ 0.43879151 0.56268287]] [[ 1.28957582 -0.02079153]]\n",
+ "[[-0.95309997 -0.57472134]] [[ 0.33647585 -0.59551287]]\n",
+ "[[-0.29628086 -0.89013624]] [[ 0.04019499 -1.48564911]]\n",
+ "[[ 0.02036881 0.07039046]] [[ 0.0605638 -1.41525865]]\n"
+ ]
}
- ]
+ ],
+ "source": [
+ "#@test {\"output\": \"ignore\"}\n",
+ "import tensorflow as tf\n",
+ "import numpy as np\n",
+ "\n",
+ "with tf.Session() as sess:\n",
+ " # Set up two variables, total and weights, that we'll change repeatedly.\n",
+ " total = tf.Variable(tf.zeros([1, 2]))\n",
+ " weights = tf.Variable(tf.random_uniform([1,2]))\n",
+ "\n",
+ " # Initialize the variables we defined above.\n",
+ " tf.initialize_all_variables().run()\n",
+ "\n",
+ " # This only adds the operators to the graph right now. The assignment\n",
+ " # and addition operations are not performed yet.\n",
+ " update_weights = tf.assign(weights, tf.random_uniform([1, 2], -1.0, 1.0))\n",
+ " update_total = tf.assign(total, tf.add(total, weights))\n",
+ " \n",
+ " for _ in range(5):\n",
+ " # Actually run the operation graph, so randomly generate weights and then\n",
+ " # add them into the total. Order does matter here. We need to update\n",
+ " # the weights before updating the total.\n",
+ " sess.run(update_weights)\n",
+ " sess.run(update_total)\n",
+ " \n",
+ " print(weights.eval(), total.eval())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "kSYJr89aM_n0"
+ },
+ "source": [
+ "This is more complicated. At a high level, we create two variables and add operations over them, then, in a loop, repeatedly execute those operations. Let's walk through it step by step.\n",
+ "\n",
+ "Starting off, the code creates two variables, `total` and `weights`. `total` is initialized to \\[0, 0\\] and `weights` is initialized to random values between -1 and 1.\n",
+ "\n",
+ "Next, two assignment operators are added to the graph, one that updates weights with random values from [-1, 1], the other that updates the total with the new weights. Again, the operators are not executed here. In fact, this isn't even inside the loop. We won't execute these operations until the `eval` call inside the loop.\n",
+ "\n",
+ "Finally, in the for loop, we run each of the operators. In each iteration of the loop, this executes the operators we added earlier, first putting random values into the weights, then updating the totals with the new weights. This call uses `eval` on the session; the code also could have called `eval` on the operators (e.g. `update_weights.eval`).\n",
+ "\n",
+ "It can be a little hard to wrap your head around exactly what computation is done when. The important thing to remember is that computation is only performed on demand.\n",
+ "\n",
+ "Variables can be useful in cases where you have a large amount of computation and data that you want to use over and over again with just a minor change to the input each time. That happens quite a bit with neural networks, for example, where you just want to update the weights each time you go through the batches of input data, then run the same operations over again."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "fL3WfAbKzqr5"
+ },
+ "source": [
+ "## What's next?\n",
+ "\n",
+ "This has been a gentle introduction to TensorFlow, focused on what TensorFlow is and the very basics of doing anything in TensorFlow. If you'd like more, the next tutorial in the series is Getting Started with TensorFlow, also available in the [notebooks directory](..)."
+ ]
+ }
+ ],
+ "metadata": {
+ "anaconda-cloud": {},
+ "colab": {
+ "default_view": {},
+ "name": "Untitled",
+ "provenance": [],
+ "version": "0.3.2",
+ "views": {}
+ },
+ "kernelspec": {
+ "display_name": "Python [default]",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.5.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
}
diff --git a/tensorflow/tools/docker/notebooks/2_getting_started.ipynb b/tensorflow/tools/docker/notebooks/2_getting_started.ipynb
index eb2569bc97..8db6bdd83c 100644
--- a/tensorflow/tools/docker/notebooks/2_getting_started.ipynb
+++ b/tensorflow/tools/docker/notebooks/2_getting_started.ipynb
@@ -1,835 +1,919 @@
{
- "nbformat": 4,
- "nbformat_minor": 0,
- "metadata": {
- "colab": {
- "version": "0.3.2",
- "views": {},
- "default_view": {},
- "name": "Untitled",
- "provenance": []
- }
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "6TuWv0Y0sY8n"
+ },
+ "source": [
+ "# Getting Started in TensorFlow\n",
+ "## A look at a very simple neural network in TensorFlow"
+ ]
},
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "6TuWv0Y0sY8n",
- "colab_type": "text"
- },
- "source": [
- "# Getting Started in TensorFlow\n",
- "## A look at a very simple neural network in TensorFlow"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "u9J5e2mQsYsQ",
- "colab_type": "text"
- },
- "source": [
- "This is an introduction to working with TensorFlow. It works through an example of a very simple neural network, walking through the steps of setting up the input, adding operators, setting up gradient descent, and running the computation graph. \n",
- "\n",
- "This tutorial presumes some familiarity with the TensorFlow computational model, which is introduced in the [Hello, TensorFlow](../notebooks/1_hello_tensorflow.ipynb) notebook, also available in this bundle."
- ]
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "u9J5e2mQsYsQ"
+ },
+ "source": [
+ "This is an introduction to working with TensorFlow. It works through an example of a very simple neural network, walking through the steps of setting up the input, adding operators, setting up gradient descent, and running the computation graph. \n",
+ "\n",
+ "This tutorial presumes some familiarity with the TensorFlow computational model, which is introduced in the [Hello, TensorFlow](../notebooks/1_hello_tensorflow.ipynb) notebook, also available in this bundle."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "Dr2Sv0vD8rT-"
+ },
+ "source": [
+ "## A simple neural network\n",
+ "\n",
+ "Let's start with code. We're going to construct a very simple neural network computing a linear regression between two variables, y and x. The function it tries to compute is the best $w_1$ and $w_2$ it can find for the function $y = w_2 x + w_1$ for the data. The data we're going to give it is toy data, linear perturbed with random noise.\n",
+ "\n",
+ "This is what the network looks like:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:30:56.880451",
+ "start_time": "2016-09-16T14:30:56.854405"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "Dr2Sv0vD8rT-",
- "colab_type": "text"
- },
- "source": [
- "## A simple neural network\n",
- "\n",
- "Let's start with code. We're going to construct a very simple neural network computing a linear regression between two variables, y and x. The function it tries to compute is the best $w_1$ and $w_2$ it can find for the function $y = w_2 x + w_1$ for the data. The data we're going to give it is toy data, linear perturbed with random noise.\n",
- "\n",
- "This is what the network looks like:"
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {}
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "id": "q09my4JYtKXw",
+ "outputId": "22b94683-437b-45ed-f6b8-4abf3b76ce38"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "q09my4JYtKXw",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {}
- ]
- },
- "cellView": "both",
- "outputId": "22b94683-437b-45ed-f6b8-4abf3b76ce38"
- },
- "source": [
- "from IPython.display import Image\n",
- "import base64\n",
- "Image(data=base64.decodestring(\"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\"), embed=True)"
- ],
- "outputs": [
- {
- "output_type": "execute_result",
- "execution_count": 1,
- "metadata": {},
- "data": {
- "image/png": "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\nAAAAAElFTkSuQmCC\n",
- "text/plain": [
- "<IPython.core.display.Image object>"
- ]
- }
- }
- ],
- "execution_count": 1
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/opt/anaconda3/lib/python3.5/site-packages/ipykernel/__main__.py:5: DeprecationWarning: decodestring() is a deprecated alias, use decodebytes()\n"
+ ]
},
{
- "cell_type": "markdown",
- "metadata": {
- "id": "fBQq_R8B8rRf",
- "colab_type": "text"
- },
- "source": [
- "Here is the TensorFlow code for this simple neural network and the results of running this code:"
+ "data": {
+ "image/png": "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\nAAAAAElFTkSuQmCC\n",
+ "text/plain": [
+ "<IPython.core.display.Image object>"
]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from __future__ import print_function\n",
+ "\n",
+ "from IPython.display import Image\n",
+ "import base64\n",
+ "Image(data=base64.decodestring(\"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\".encode('utf-8')), embed=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "fBQq_R8B8rRf"
+ },
+ "source": [
+ "Here is the TensorFlow code for this simple neural network and the results of running this code:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:31:31.203004",
+ "start_time": "2016-09-16T14:31:30.704391"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "Dy8pFefa_Ho_",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 665,
- "status": "ok",
- "timestamp": 1446658971218,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "4896c353dcc58d9f",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "5a95f8c8-0c32-411d-956d-bb81aeed8e50"
- },
- "source": [
- "#@test {\"output\": \"ignore\"}\n",
- "import tensorflow as tf\n",
- "import numpy as np\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "%matplotlib inline\n",
- "\n",
- "# Set up the data with a noisy linear relationship between X and Y.\n",
- "num_examples = 50\n",
- "X = np.array([np.linspace(-2, 4, num_examples), np.linspace(-6, 6, num_examples)])\n",
- "X += np.random.randn(2, num_examples)\n",
- "x, y = X\n",
- "x_with_bias = np.array([(1., a) for a in x]).astype(np.float32)\n",
- "\n",
- "losses = []\n",
- "training_steps = 50\n",
- "learning_rate = 0.002\n",
- "\n",
- "with tf.Session() as sess:\n",
- " # Set up all the tensors, variables, and operations.\n",
- " input = tf.constant(x_with_bias)\n",
- " target = tf.constant(np.transpose([y]).astype(np.float32))\n",
- " weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))\n",
- " \n",
- " tf.initialize_all_variables().run()\n",
- " \n",
- " yhat = tf.matmul(input, weights)\n",
- " yerror = tf.sub(yhat, target)\n",
- " loss = tf.nn.l2_loss(yerror)\n",
- " \n",
- " update_weights = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)\n",
- " \n",
- " for _ in range(training_steps):\n",
- " # Repeatedly run the operations, updating the TensorFlow variable.\n",
- " update_weights.run()\n",
- " losses.append(loss.eval())\n",
- "\n",
- " # Training is done, get the final values for the graphs\n",
- " betas = weights.eval()\n",
- " yhat = yhat.eval()\n",
- "\n",
- "# Show the fit and the loss over time.\n",
- "fig, (ax1, ax2) = plt.subplots(1, 2)\n",
- "plt.subplots_adjust(wspace=.3)\n",
- "fig.set_size_inches(10, 4)\n",
- "ax1.scatter(x, y, alpha=.7)\n",
- "ax1.scatter(x, np.transpose(yhat)[0], c=\"g\", alpha=.6)\n",
- "line_x_range = (-4, 6)\n",
- "ax1.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], \"g\", alpha=0.6)\n",
- "ax2.plot(range(0, training_steps), losses)\n",
- "ax2.set_ylabel(\"Loss\")\n",
- "ax2.set_xlabel(\"Training steps\")\n",
- "plt.show()"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f804039d090>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "vNtkU8h18rOv",
- "colab_type": "text"
- },
- "source": [
- "In the remainder of this notebook, we'll go through this example in more detail."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 665,
+ "status": "ok",
+ "timestamp": 1446658971218,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "4896c353dcc58d9f",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "Dy8pFefa_Ho_",
+ "outputId": "5a95f8c8-0c32-411d-956d-bb81aeed8e50"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "r6rsv-q5gnn-",
- "colab_type": "text"
- },
- "source": [
- "## From the beginning\n",
- "\n",
- "Let's walk through exactly what this is doing from the beginning. We'll start with what the data looks like, then we'll look at this neural network, what is executed when, what gradient descent is doing, and how it all works together."
+ "data": {
+ "image/png": "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\nAAAASUVORK5CYII=\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f9a7c017a20>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "#@test {\"output\": \"ignore\"}\n",
+ "import tensorflow as tf\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "%matplotlib inline\n",
+ "\n",
+ "# Set up the data with a noisy linear relationship between X and Y.\n",
+ "num_examples = 50\n",
+ "X = np.array([np.linspace(-2, 4, num_examples), np.linspace(-6, 6, num_examples)])\n",
+ "X += np.random.randn(2, num_examples)\n",
+ "x, y = X\n",
+ "x_with_bias = np.array([(1., a) for a in x]).astype(np.float32)\n",
+ "\n",
+ "losses = []\n",
+ "training_steps = 50\n",
+ "learning_rate = 0.002\n",
+ "\n",
+ "with tf.Session() as sess:\n",
+ " # Set up all the tensors, variables, and operations.\n",
+ " input = tf.constant(x_with_bias)\n",
+ " target = tf.constant(np.transpose([y]).astype(np.float32))\n",
+ " weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))\n",
+ "\n",
+ " tf.initialize_all_variables().run()\n",
+ "\n",
+ " yhat = tf.matmul(input, weights)\n",
+ " yerror = tf.sub(yhat, target)\n",
+ " loss = tf.nn.l2_loss(yerror)\n",
+ " \n",
+ " update_weights = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)\n",
+ " \n",
+ " for _ in range(training_steps):\n",
+ " # Repeatedly run the operations, updating the TensorFlow variable.\n",
+ " update_weights.run()\n",
+ " losses.append(loss.eval())\n",
+ "\n",
+ " # Training is done, get the final values for the graphs\n",
+ " betas = weights.eval()\n",
+ " yhat = yhat.eval()\n",
+ "\n",
+ "# Show the fit and the loss over time.\n",
+ "fig, (ax1, ax2) = plt.subplots(1, 2)\n",
+ "plt.subplots_adjust(wspace=.3)\n",
+ "fig.set_size_inches(10, 4)\n",
+ "ax1.scatter(x, y, alpha=.7)\n",
+ "ax1.scatter(x, np.transpose(yhat)[0], c=\"g\", alpha=.6)\n",
+ "line_x_range = (-4, 6)\n",
+ "ax1.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], \"g\", alpha=0.6)\n",
+ "ax2.plot(range(0, training_steps), losses)\n",
+ "ax2.set_ylabel(\"Loss\")\n",
+ "ax2.set_xlabel(\"Training steps\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "vNtkU8h18rOv"
+ },
+ "source": [
+ "In the remainder of this notebook, we'll go through this example in more detail."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "r6rsv-q5gnn-"
+ },
+ "source": [
+ "## From the beginning\n",
+ "\n",
+ "Let's walk through exactly what this is doing from the beginning. We'll start with what the data looks like, then we'll look at this neural network, what is executed when, what gradient descent is doing, and how it all works together."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "UgtkJKqAjuDj"
+ },
+ "source": [
+ "## The data\n",
+ "\n",
+ "This is a toy data set here. We have 50 (x,y) data points. At first, the data is perfectly linear."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:31:33.923639",
+ "start_time": "2016-09-16T14:31:33.724554"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "UgtkJKqAjuDj",
- "colab_type": "text"
- },
- "source": [
- "## The data\n",
- "\n",
- "This is a toy data set here. We have 50 (x,y) data points. At first, the data is perfectly linear."
- ]
+ "cellView": "form",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "-uoBWol3klhA",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "form",
- "executionInfo": {
- "elapsed": 398,
- "status": "ok",
- "timestamp": 1446659128547,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "4896c353dcc58d9f",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "efef4adf-42de-4e6f-e0c3-07ddd3083d85"
- },
- "source": [
- "#@test {\"output\": \"ignore\"}\n",
- "num_examples = 50\n",
- "X = np.array([np.linspace(-2, 4, num_examples), np.linspace(-6, 6, num_examples)])\n",
- "plt.figure(figsize=(4,4))\n",
- "plt.scatter(X[0], X[1])\n",
- "plt.show()"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\nDzcvNav5fpAxAAAAAElFTkSuQmCC\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f8030785b10>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 398,
+ "status": "ok",
+ "timestamp": 1446659128547,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "4896c353dcc58d9f",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "-uoBWol3klhA",
+ "outputId": "efef4adf-42de-4e6f-e0c3-07ddd3083d85"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "AId3xHBNlcnk",
- "colab_type": "text"
- },
- "source": [
- "Then we perturb it with noise:"
+ "data": {
+ "image/png": "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\n1ZAcyT0AAAAASUVORK5CYII=\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f9a67fb4fd0>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "#@test {\"output\": \"ignore\"}\n",
+ "num_examples = 50\n",
+ "X = np.array([np.linspace(-2, 4, num_examples), np.linspace(-6, 6, num_examples)])\n",
+ "plt.figure(figsize=(4,4))\n",
+ "plt.scatter(X[0], X[1])\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "AId3xHBNlcnk"
+ },
+ "source": [
+ "Then we perturb it with noise:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:31:35.755403",
+ "start_time": "2016-09-16T14:31:35.572825"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "fXcGNNtjlX63",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "form",
- "executionInfo": {
- "elapsed": 327,
- "status": "ok",
- "timestamp": 1446659134929,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "4896c353dcc58d9f",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "231c945e-e4a4-409e-b75b-8a8fe1fdfc30"
- },
- "source": [
- "#@test {\"output\": \"ignore\"}\n",
- "X += np.random.randn(2, num_examples)\n",
- "plt.figure(figsize=(4,4))\n",
- "plt.scatter(X[0], X[1])\n",
- "plt.show()"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\nAAAAAElFTkSuQmCC\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f8040158790>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "cellView": "form",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 327,
+ "status": "ok",
+ "timestamp": 1446659134929,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "4896c353dcc58d9f",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "fXcGNNtjlX63",
+ "outputId": "231c945e-e4a4-409e-b75b-8a8fe1fdfc30"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "3dc1cl5imNLM",
- "colab_type": "text"
- },
- "source": [
- "## What we want to do\n",
- "\n",
- "What we're trying to do is calculate the green line below:"
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAWgAAAFkCAYAAAANJ6GuAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzt3X2QXFd55/Hv48ZgWMh4LIKDEzYUaCREsay3xwQ7LPJi\nxm5ptIEi1IJbL9TCmmAWI62ABVwOlV0SYuOwGDvg8FaLwQPNOlUbCKuRxgzC0gIRsnvASYFRj2Qb\n2zFlQK1MUryt0372j+6WpqWZ6Zfpc+/pvr9PVReeO919TkvoN2fOOfc55u6IiEh8zkq7AyIisjQF\ntIhIpBTQIiKRUkCLiERKAS0iEikFtIhIpBTQIiKRUkCLiERKAS0iEikFtIhIpIIGtJmdZWZ/bGb3\nm9nPzeyomf1hyDZFRIbFkwK//3uBtwBvAL4PXATcZmb/4O4fDdy2iMhACx3QlwBfdvd9ja8fMrOt\nwO8EbldEZOCFnoP+FvBKMxsDMLN/DbwMmA7crojIwAs9gr4B+DXgB2ZWo/4D4Tp3/+JSTzazNUAB\neBD4ZeC+iYgk4RzgucCMux/v5oWhA/r1wFbgSupz0BcCN5vZo+5++xLPLwCfD9wnEZE0bAO+0M0L\nQgf0jcCfuvtfNr7+npk9F7gWWCqgHwSYmppiw4YNgbsWl927d3PTTTel3Y3E6XNnSxY/93333cf2\n7duhkW/dCB3QTwNOP7LlCZaf+/4lwIYNG8jn8yH7FZ2RkZHMfWbQ586arH7uhq6nbUMH9FeA68zs\nYeB7QB7YDXw6cLsiIgMvdEBfA/wx8DHgWcCjwF80romIyAqCBrS7/wx4R+MhIiJdUC2OSBSLxbS7\nkAp97mzJ6ufulbmfvoaXHjPLA+VyuZzlhQQRGSJzc3OMj48DjLv7XDev1QhaRCRSCmgRkUgpoEVE\nIqWAFhGJlAJaRCRSCmgRkUgpoEVEIqWAFhGJlAJaRCRSCmgRkUgpoEVEIqWAFhGJlAJaRCRSCmgR\nkUgpoEVEIqWAFhGJlAJaRCRSCmgRkUgpoEVEIqWAFhGJlAJaRCRSCmgRkUgpoEVEIvWktDsgIvGp\nVCocO3aMtWvXMjY2lnZ3MksjaBE5qVqtsmnTFtavX8/k5CTr1q1j06YtnDhxIu2uZZICWkRO2rp1\nB7Ozh4Ap4CFgitnZQxSL21PuWTYFD2gzu8DMbjezn5rZz83sXjPLh25XRLpTqVSYmZmmVrsF2AY8\nB9hGrXYzMzPTzM/Pp9zD7Aka0GZ2LvBN4FdAAdgAvBPQ70sikTl27Fjjvzae9p1LATh69Gii/ZHw\ni4TvBR5y96sWXfth4DZFpAfPf/7zG/91kPoIuukAAGvXrk26S5kXeorj94B7zOwOM3vMzObM7Kq2\nrxKRxK1bt45CYZJcbif1OeiHgSlyuV0UCpPazZGC0AH9POCtwBHgCuDjwC1mphUHkQiVSlNMTFwM\n7AD+JbCDiYmLKZWmUu5ZNpm7h3tzs18Bh9395Yuu3Qxc5O4vW+L5eaC8ceNGRkZGWr5XLBYpFovB\n+ioip8zPz3P06FHtg+5SqVSiVCq1XFtYWODgwYMA4+4+1837hQ7oB4E73f0PFl27GrjO3Z+zxPPz\nQLlcLpPPa6OHiAy+ubk5xsfHoYeADj3F8U1g/WnX1qOFQhGRtkIH9E3AxWZ2rZk938y2AlcBHw3c\nrojIwAsa0O5+D/AaoAj8HXAdsMvdvxiyXRHJjkqlwt69e4fyRprgxZLcfRqYDt2OiGRLtVpl69Yd\nzMycipdCYZJSaYrR0dEUe9Y/qsUhIgMpC3VDVG5URAZOs25IPZybdz1uo1ZzZmZ2MD8/PxTbAzWC\nFpGBk5W6IQpoERk4rXVDFhuuuiEKaJEhM8y7GpqyUjdEAS0yJLJ2GkoW6oZokVAksKTO92vd1bAR\nOMjs7E6Kxe3s27cnWLtpGR0dZd++PUNdN0QBLRJIkvt0s7KrYSljY2ND+9k0xSESSJL7dLOyqyFr\nFNAiASR9vl9WdjVkjQJaJICkR7RZ2dWQNQpokQDSGNFmYVdD1miRUCSA5oh2dnYntZpTHzkfIJfb\nxcREmBFtFnY1ZI0CWiSQUmmKYnE7MzM7Tl6bmJgMPqId5l0NWaOAFglEI1pZLQW0SGAa0UqvtEgo\nIhIpBbSISKQ0xSEiQHI1Q6RzGkGLZFzWquANEgW0SMZl4Wy/QaUpDpEMy3IVvEGgEbRIhqkKXtwU\n0CIZpip4cVNAi2SYquDFTQEtknGqghcvLRKKZNzo6Ci33HITBw++BoBLL71UI+dIJBbQZnYt8AHg\nI+7+jqTaFZHlJXluonQvkSkOM3sJ8Gbg3iTaE5HOaA903IIHtJk9nfrf/lXAP4RuT0Q6s/S5iS+h\nVntTkHMTpXtJjKA/BnzF3fcn0JaIdKh1D3QV2AKsBz4EwJVXbtPt3ikLGtBmdiVwIXBtyHZEpHut\ne6B3AK1THffee0xTHSkLFtBm9lvAR4Dt7v54qHZEpDfNPdBnnfU2YBpYPNWxjVrt5iWnOiqVCnv3\n7k1sCiTp9mISchfHOPDrQNnMrHEtB2w0s2uAp7i7L/XC3bt3MzIy0nKtWCxSLBYDdldkeC1XSrS+\nB/oK5ubuYaXbvcfGxhLf8TGIO0xKpRKlUqnl2sLCQu9v6O5BHsC/AF542uMw8FlgwzKvyQNeLpdd\nRFbv+PHjXihMOnDyUShMerVaPfmcI0eONL435eCLHrc74JVKxd3dC4VJz+XOazzvIYcpz+XO80Jh\nMkjfk24vlHK53Pyzz3u3OdrtC1bzAL4OfHiF7yugRfqo05A79bzbG8+7veV5nYZ4vyTdXkirCeik\nb/VeckpDRPpv6W10S88tt7vdO+mqd6qyV5ford7uflmS7YlkWSch15yPHh0dZd++PczPz3P06NEz\n5qpbd3xsW/ReYareJd1erFSLQ2RI9RJyY2NjS9bhaO74mJ3dSa3m1EP+ALncLiYm+l/1Lun2YqVq\ndiJDqt+lRJOueqcqexpBiwy1UmmKYnE7MzM7Tl6bmJjsKeTaTYP0W9LtxUgBLTLEQoTcctMgoSTd\nXkwU0CIZkOWQG2QKaJEeLHdnnkg/aZFQpAvVapVNm7awfv16JicnWbduHZs2bVHVNwlCAS3SBRW4\nlyRpikOkQ8078+rh3NxXvI1azZmZ2cH8/LymO6SvNIIW6ZBuP47PsJciVUCLdKj1zrzFsnX7cQyy\nshaggBbpUL/vzJPeZWUtQAEt0gXdfpy+bqr0DTotEop0Qbcfp6+bKn2DTgEt0gPdmZeeLJUi1RSH\niAyULK0FKKBFZOBkZS1AUxwiMnCyshaggBYJRAWVwhv2tQBNcYj0WVZuopDwFNAifZaVmygkPE1x\niPRRFgoqaeomORpBi/RRNwWVBq3Qj6ZukqeAFumjTgoqDWrQaeomeQpokT7q5CaKQQy6LNW/iIkC\nWqTPVrqJYlCDTrWw06FFQpE+W+kmikOHDjWeNViFfrJU/yImCmiRQJa6iWJQg645dTM7u5Nazan/\nQDlALreLiYnhqn8Rk6BTHGZ2rZkdNrN/NLPHzOyvzGxdyDZFYjbIhX6yUv8iJqFH0C8H/hy4p9HW\n9cCdZrbB3X8RuG2Rvuj3vt9SaYpicTszMztOXpuYmIw+6LJS/yImQQPa3ScXf21m/xH4MTAOfCNk\n2yKrVa1W2bp1R+PGk7pCoR6ko6OjPb/voAfdsNe/iEnSuzjOBRyoJtyuSNdCb4cbGxtj8+bNCjtZ\nVmKLhGZmwEeAb7j795NqV6QXWbhlW+KX5Aj6VuCFwJUJtinSE+37lRgkMoI2s48Ck8DL3f1H7Z6/\ne/duRkZGWq4Vi0WKxWKgHoq0GtTtcJKuUqlEqVRqubawsNDz+5m7r7ZPKzdQD+dXA5e6+/1tnpsH\nyuVymXw+H7RfIu1s2rSF2dlD1Go307rv92L27dvT1XupAlx2zc3NMT4+DjDu7nPdvDb0PuhbqQ8/\ntgI/M7PzG49zQrYr0g/92Pc7qIWRJA6h56CvBn4NuAt4dNHjdYHbFVm15na4SqXC9PQ0lUqFffv2\ndLXFbhALI0k8Qu+DVjEmGXi97vvVThBZLQWoSCDaCSKrpYAWCaST4v0iK1FAiwQSa2GkQTtqK8sU\n0CIBxVQBTjtKBo/qQYsEFFNhpNYdJRuBg8zO7qRY3N71vm5JhgJaJAFpV4DTjpLBpCkOkQzQjpLB\npIAWyQDtKBlMCmiRDIh1R4msTAEtkhEx7SiRzmiRUCQjYtpRIp1RQItkTNo7SqRzmuIQEYmUAlpE\nJFIKaBGRSCmgRUQipYAWEYmUdnGIJCjk4bE6mHb4aAQtkoCQpT5VRnR4KaBFEhDy8FgdTDu8NMUh\n0qNOpxRClvpUGdHhphG09EWWjlHqdkohZKlPlREdbgpoWZUY5j+T/uHQ7ZRCyFKfKiM65Nw9mgeQ\nB7xcLrsMhkJh0nO58xymHB5ymPJc7jwvFCaDt338+HEvFCYdOPkoFCa9Wq0Ga/PIkSONtqYcfNHj\ndge8Uqks+bpTf063N/6cbu/bn1PI95bVK5fLzf9/5r3bTOz2BSEfCuh4HDlyxKenp5cNnOZzegmr\nfknjh8P09HTjMz902md+yAGfnp5e8nXVajXYD5OQ7y2rt5qA1iJhxrRb2KpWq2zduqOx8FRXKExS\nKk0xOjra8txO5j9DLVCltTjWOqWwbdF3Vp5SCFnqU2VEh1i3iR7ygUbQwXQ6HdDNqDTNEXSvI9l+\n6MeUQie/ochw0BSHtNVJ8PYSuGnNf6b5w2E1UwppzJtLuqIPaOBtwAPAL4BDwEuWeZ4COoBOw6yX\nUWma859pL45VKpWuR8FpLqpKOqIOaOD1wC+BNwAvAD4BVIFnLvFcBXQAnQbvakalvYTVag3a4lja\ni6qSjtgXCXcDn3D3zwGY2dXAFuBNwI0JtJ95nS5sNU9+np3dSa3m1Bf7DpDL7WJiYuWTn9M4RmnQ\nFsfSXFSVwRT0RhUzOxsYB77WvObuDswCl4RsW05pBm8ut5P6roeHgSlyuV0UCq3BO4gnP4+NjbF5\n8+bEw63bG2R0U4l0rdshdzcP4NnAE8BLT7v+QeBvlni+pjgC6XY6II0pi0GxmoW+tOfNJXmrmeIw\nrwdjEGb2bODvgUvc/duLrt8I/Ft3/93Tnp8Hyhs3bmRkZKTlvYrFIsViMVhfs2JQpgNitmnTFmZn\nD1Gr3UJ9uuIgudxOJiYuZt++PSu+9sSJExSL2zvaZy6Dp1QqUSqVWq4tLCxw8OBBgHF3n+vm/UIH\n9NnAz4HXuvtfL7p+GzDi7q857fl5oFwul8nn88H6JdKrSqXC+vXrab1BhsbXO6hUKh394NMPyuyY\nm5tjfHwcegjooHPQ7v44UAZe2bxmZtb4+lsh2xYJoV/V49KaN5fBkkQ1uw8Df2BmbzCzFwAfB54G\n3JZA2yJ9pYU+SVLwbXbufoeZPRN4P3A+8F2g4O4/Cd32oNMZc/FZzVZEkW4lUg/a3W919+e6+1Pd\n/RJ3vyeJdgdVDDWWZXmDuBVRBpOq2UWotSB8fZfA7OxOisXtbXcJSHiDdoOMDC4FdGR0xtzgSOPu\nSckWHXkVGZ0xJyJNCujIaJeAiDQpoCPTTd0MERluCugIaZeAiIAWCaOkXQIiAgroqGmXgEi2aYpD\nRCRSCmgRkUgpoEVEIqWAFhGJlAJaRCRSCmgRkUgpoEVEIqWAFhGJlG5UkWXpRBeRdGkELWfo14ku\nlUqFvXv3Mj8/H6inIsNNAS1n2Lp1B1/96jeB/0q9zOkUs7OHKBa3d/R6Hdkl0h8KaGlx+PBhZmb2\n8cQTC8CfUT8o4AvUan/KzMx0R6Ph1iO7HqLbgBeROgW0tHjrW68BnsHicIVDwB1A+xNdmkd21Wq3\nUD+y6znUj+y6ueOAj5GmayQNCmg5qVKpMDd3N/AxFocr3AzsB9qf6DJsR3ZpukbSpICWk9qFaz5/\nUdvdHMN2ZJemayRNCmg5qV24fuITf9H2PYbpyK5hna6RwaGAlpPahetFF13U0fv0+8iutOZ/h226\nRgaPAlpa9CNcm0d2VSoVpqenqVQq7Nu3h9HR0a76kvb877BN18jg0Z2E0qKf5yGu9siu1vnfjcBB\nZmd3UixuZ9++PT2/b6eav1HMzu6kVnPqI+cD5HK7mJgYrOkaGUwKaFlS2uchNud/6+G8rXF1G7Wa\nMzOzg/n5+UT6VypNUSxuZ2Zmx8lrExOTOmFdEhEsoM3st4H3AZcBvwH8PfB54APu/niodmU4dDL/\nm0RA64R1SVPIEfQLAAPeDBwDXgR8Gnga8O6A7coQaJ3/3bboO+nM/6b9G4VkU7BFQnefcff/5O5f\nc/cH3f3/AB8Cfj9UmzI8hmm7nkivkt7FcS5QTbhNGVD93q4nMmgSWyQ0s7XANcA7kmpTBpvmfyXr\nzN27e4HZ9cB7VniKAxvcvbLoNb8J3AXsd/e3rPDeeaC8ceNGRkZGWr5XLBYpFotd9VVEJEmlUolS\nqdRybWFhgYMHDwKMu/tcN+/XS0CvAda0edr97v7PjedfAHwd+Ja7v7HNe+eBcrlcJp/Pd9UvEZEY\nzc3NMT4+Dj0EdNdTHO5+HDjeyXMbI+f9wN3Am7ptS0Qky0Lug3429WmNB6lvq3uWmQHg7o+FaldE\nZFiEXCS8Anhe4/Fw45pRn6POBWxXRGQohNwH/Vl3z532OMvdFc5DRCeNiISjanbSk7QrzYlkgQJa\neqKTRkTCUzU76VosleZEhp1G0NI1nTQikgwFtHRNJ42IJEMBLV1rV2nO3Vfc2aGdHyKdUUBLT5aq\nNLdxY57HH3982Z0d2vkh0h0FtPRkqYNhn/zkJ3PgQJnldnZo54dId7SLQ1aledJIu50dd955p3Z+\niHRJI2jpi3Y7Ow4dOrTo+xVgLzCPdn6ILE8jaOmLdmcIXnzxxY2vXwV8d9H3LwS080NkKRpBS1+0\n29lxxRVXsGbN+cADLJ6DhgdYs+Z8TW+ILEEBLX2z0hmClUqF48cfAz5GfYT9nMb/fpTjxx/TljuR\nJWiKQ/pmpTMEW+egFzs1B61RtEgrBbT0XXNnx2Lt5qg1By1yJk1xSCLazVFr9CxyJgW0JGalOWoR\nOZOmOCQxK81Ri8iZFNCSuKXmqEXkTApoWbVKpcKxY8daRsRLXROR7iigpWfVapWtW3c0amzUXXbZ\n5QDs3//Vk9cKhUlKpSlGR0cT76PIINMiofRsqep0X//63ezffxBVrBNZPY2gpSfLVa9zd+q7NH6H\n5t2Cqlgn0huNoKUn7arXwdEzrqlinUh3FNDSk3bnEsLaM67pbkGR7miKQ3rSvDNwdnYntZpTHyUf\nwOztuD8F+DZwDnCAXG4XExO6W1CkWwpo6VmpNEWxuJ2ZmR0nr73iFc1dHKeuTUxM6m5BkR4ooKVn\nK90ZOD8/z1133YWZcemll2qLnUgPEgloM3sycBh4MXChu/9tEu1KMk6/M7BarfL2t/+Xlv3R2gst\n0r2kFglvBB4BPKH2JEX9OL27Uqmwd+9eFfKXTAse0Ga2GbgceBdgoduTdDX3R9dqt7D45JRa7WZm\nZqbbBm61WmXTpi2sX7+eyclJ1q1bx6ZNWzhx4kQS3ReJStCANrPzgU8C24FfhGxL4tBuf3S7vdD9\nGH2LDIvQI+jPALe6+3cCtyORaLc/eqW90KsdfYsMm64XCc3seuA9KzzFgQ3AJuAZwAebL+20jd27\ndzMyMtJyrVgsUiwWu+usJG65/dGd7IXuZPStvdQSs1KpRKlUarm2sLDQ8/tZvXZCFy8wWwOsafO0\nB4A7gH9/2vUc8M/A5939jUu8dx4ol8tl8vl8V/2SVmmW+zxx4kRjf3R3uzgqlQrr16+ntb4Hja93\nUKlUFNAycObm5hgfHwcYd/e5bl7b9Qja3Y8Dx9s9z8zeDly36NIFwAzwOupb7iSApUqAJr3FrdeT\nU1Yz+hYZRsHmoN39EXf/fvMBzFOf5rjf3R8N1W7WxbTINjY2xubNm7sKVp1bKHJK0ncSah90QMuV\nAB2kcp86t1DklMQC2t1/SH0OWgIZpkU2nVsoonKjQ2U1W9xEJD4K6CHSXGTL5XZSn+Z4GJgil9tF\noaBFNpFBo4AeMlpkExkeKjcaodXsYdYim8jwUEBHpJ97mLXIJjL4NMURkZj2MItI+jSCjsQw7GEW\nkf7SCLoLIYvIr7ZMp4gMHwV0B5IoIp/mHmadXiISJwV0B5KYG05jD7NOLxGJnLtH8wDygJfLZY/F\nkSNHHHCYcvBFj9sd8Eql0re2qtWqFwqTjfbqj0Jh0qvVat/aWKxQmPRc7rzGZ3vIYcpzufO8UJjs\n+r2OHDni09PTff3zEBkG5XK5+e85711mohYJ20iyvkWSe5j7tSgZQ3lTkWGlKY420pgb7qVMZ7f6\ntSiprYEi4Sig2xi0+hadLvj14wePzhAUCUsB3YFBqG/R7YJfP37waGugSFgK6A4054YrlQrT09NU\nKhX27dsT1RxrL1MNq/3Bo/KmImFpkbALsda36HXBb7WLkjpDUCQsjaCHwGqnGlazKDkI0z8ig0oj\n6CHQOtWwbdF3wk81qLypSDgK6CEQw1RDrNM/IoNMUxxDQlMNIsNHI+ghoakGkeGjgB4ymmoQGR4K\n6ASs5oxBEckuzUEHdPjwYcbHX6JyniLSEwV0AM3brl/60pcyN3dP4+plwCdUSEhEOqaADmCp267h\nu8CXVUhIRDoWNKDNbIuZHTKzn5tZ1cz+d8j2YrBchTe4GZimvgVOhYREpL1gi4Rm9lrgk8B7gf3A\n2cCLQrUXi3a3XcNXABUSEpH2ggS0meWAjwDvdPfbFn3rByHai0m7267POutTXH65CgmJSHuhpjjy\nwAUAZjZnZo+a2bSZvTBQe9FYrs4yXAOcxeWXv0x394lIR0IF9PMAA/4IeD+wBTgBHDCzcwO1GY2l\nbrvO59dx993fjq6OtIjEq6spDjO7HnjPCk9xYAOngv9P3P1Ljde+EXgE+A/Ap7rv6uDQbdci0g/d\nzkF/CPhMm+fcT2N6A7ivedHd/5+Z3U9zG8MKdu/ezcjISMu1YrFIsVjsrrcp023XItlSKpUolUot\n1xYWFnp+P3P31fbpzDc1ewbwY+A/u/tnGtfOpj4h+4fu/ullXpcHyuVymXw+3/d+iYgkbW5ujvHx\ncYBxd5/r5rVBdnG4+z+Z2ceB/25mjwA/BN5NfQrkL0O0KSIybEIWS3oX8DjwOeCpwLeBy9y99/G+\niEiGBAtod69RHzW/O1QbIiLDTLU4REQipXrQEVL9aBEBjaCj0ixTqvrRIgIK6KgsVaZU9aNFsktT\nHJFolimth3OzyNI2ajVnZmYH8/Pzmu4QyRiNoCPRrkyp6keLZI8COhKtZUoXq5cpVf1okexRQEdi\nuTKludwuCgXVjxbJIgV0RJYqUzoxcbHqR4tklBYJI6IypSKymAI6QipTKiKgKQ4RkWgpoEVEIqWA\nFhGJlAJaRCRSCmgRkUgpoEVEIqWAFhGJlAJaRCRSCmgRkUgpoEVEIqWAFhGJlAJaRCRSCmgRkUgp\noEVEIqWAFhGJlAJaRCRSCuhIlEqltLuQCn3ubMnq5+5VsIA2szEz+5KZ/cTMFszs/5rZpaHaG3RZ\n/T+uPne2ZPVz9yrkCHoPkAP+HZAH7gX2mNmzArYpIjI0ggS0ma0B1gI3uPv33P0Y8F7gacCLQrQp\nIjJsggS0ux8HfgC8wcyeZmZPAq4GHgPKIdoUERk2IU/1vhz4EvBPwBPUw3mTuy+s8JpzAO67776A\n3YrTwsICc3NzaXcjcfrc2ZLFz70oz87p9rXm7p0/2ex64D0rPMWBDe5eMbMvU5+D/hPgl8BVwKuB\ni9z9sWXefyvw+Y47JCIyOLa5+xe6eUG3Ab0GWNPmafcDlwL7gHPd/WeLXl8BPu3uN67w/gXgQeqh\nLiIy6M4BngvMNKZ/O9bVFEfjzds2YGZPbb7ktG89wQrz3o337+onjIjIAPhWLy8Ktc3ub4ATwGfN\n7MWNPdF/Rv2nyJ5AbYqIDJWQuzg2AU8HvgbcDfwu8Cp3/7sQbYqIDJuu5qBFRCQ5qsUhIhIpBbSI\nSKSiD2gze7KZfdfMnjCzF6fdn5DM7LfN7NNmdr+Z/dzM5s3sv5nZ2Wn3LQQze5uZPWBmvzCzQ2b2\nkrT7FJKZXWtmh83sH83sMTP7KzNbl3a/ktT4M3jCzD6cdl+SYGYXmNntZvbTxr/pe80s3+nrow9o\n4EbgEc7csjeMXgAY8GbghcBu6rfIfyDNToVgZq8H/gfwR8C/oV5Ma8bMnplqx8J6OfDnwEuBCeBs\n4M5F21KHWuMH8Jup/10PPTM7F/gm8Cvq93dsAN5JfYdbZ+8R8yKhmW0GPgS8Fvg+cKG7/226vUqW\nmb0LuNrd16bdl34ys0PAt919V+NrAx4GblnuRqZh0/hh9GNgo7t/I+3+hGRmT6deh+etwPuA77j7\nO9LtVVhmdgNwibv3XGY52hG0mZ0PfBLYDvwi5e6k6VygmnYn+qkxZTNOfQsmAF4fKcwCl6TVrxSc\nS/03w6H6+13Gx4CvuPv+tDuSoN8D7jGzOxpTWnNmdlU3bxBtQAOfAW519++k3ZG0mNla4Brg42n3\npc+eSb1Oy+k1WR4DfiP57iSv8RvDR4BvuPv30+5PSGZ2JXAhcG3afUnY86j/xnAEuIL6v+NbzGx7\np2+QaECb2fWNBYLlHjUzW2dmO4FnAB9svjTJfvZbp5/7tNf8JrAX+F/u/j/T6XnijGysNQDcSn2d\n4cq0OxKSmf0W9R9E29398bT7k7CzgLK7v8/d73X3TwKfoh7aHQlZbnQpH6I+Ml7JA8ArgIuBX9UH\nGifdY2afd/c3BupfKJ187vub/2FmFwD7qY+u3hKyYyn5KVADzj/t+rM4c1Q9dMzso8Ak8HJ3/1Ha\n/QlsHPh1oGyn/jHngI1mdg3wFI95IWx1fgScXjv5PuD3O32DRAO6i2JLbweuW3TpAmAGeB1wOEzv\nwun0c8PJkfN+6rfHvylkv9Li7o+bWRl4JfDXcPJX/lcCt6TZt9Aa4fxq4FJ3fyjt/iRgFvhXp127\njXpQ3TAuITBJAAABHklEQVTE4Qz1HRzrT7u2Hvhhp2+Q9Ai6I+7+yOKvzexn1H/9vd/dH02nV+GZ\n2bOBu6iXW3038KzmoGO5GtoD7MPUi2mVqf/Q3U39SLTb0uxUSGZ2K1AEXgX8rLEQDrDg7kNZXrdR\nbrhljr3x7/m4uw/7yRw3Ad80s2uBO6hvr7yK+lbDjkQZ0MsY5p+0TVdQX1h4HvUtZ3BqXjaXVqdC\ncPc7GtvM3k99quO7QMHdf5Juz4K6mvrf5V2nXX8j8LnEe5OeLPxbxt3vMbPXADdQ31r4ALDL3b/Y\n6XtEvQ9aRCTLYt5mJyKSaQpoEZFIKaBFRCKlgBYRiZQCWkQkUgpoEZFIKaBFRCKlgBYRiZQCWkQk\nUgpoEZFIKaBFRCL1/wFWkBDIhYzcuAAAAABJRU5ErkJggg==\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f9a67fb4e10>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "#@test {\"output\": \"ignore\"}\n",
+ "X += np.random.randn(2, num_examples)\n",
+ "plt.figure(figsize=(4,4))\n",
+ "plt.scatter(X[0], X[1])\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "3dc1cl5imNLM"
+ },
+ "source": [
+ "## What we want to do\n",
+ "\n",
+ "What we're trying to do is calculate the green line below:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:31:37.772603",
+ "start_time": "2016-09-16T14:31:37.508209"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "P0m-3Mf8sQaA",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "form",
- "executionInfo": {
- "elapsed": 414,
- "status": "ok",
- "timestamp": 1446659137254,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "4896c353dcc58d9f",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "74e74f19-6ff8-4a8c-81c7-9021a08b78b5"
- },
- "source": [
- "#@test {\"output\": \"ignore\"}\n",
- "weights = np.polyfit(X[0], X[1], 1)\n",
- "plt.figure(figsize=(4,4))\n",
- "plt.scatter(X[0], X[1])\n",
- "line_x_range = (-3, 5)\n",
- "plt.plot(line_x_range, [weights[1] + a * weights[0] for a in line_x_range], \"g\", alpha=0.8)\n",
- "plt.show()"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f80640172d0>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "cellView": "form",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 414,
+ "status": "ok",
+ "timestamp": 1446659137254,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "4896c353dcc58d9f",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "P0m-3Mf8sQaA",
+ "outputId": "74e74f19-6ff8-4a8c-81c7-9021a08b78b5"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "VYUr2uPA9ah8",
- "colab_type": "text"
- },
- "source": [
- "Remember that our simple network looks like this:"
+ "data": {
+ "image/png": "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\nTkSuQmCC\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f9a387871d0>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "#@test {\"output\": \"ignore\"}\n",
+ "weights = np.polyfit(X[0], X[1], 1)\n",
+ "plt.figure(figsize=(4,4))\n",
+ "plt.scatter(X[0], X[1])\n",
+ "line_x_range = (-3, 5)\n",
+ "plt.plot(line_x_range, [weights[1] + a * weights[0] for a in line_x_range], \"g\", alpha=0.8)\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "VYUr2uPA9ah8"
+ },
+ "source": [
+ "Remember that our simple network looks like this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:32:02.494004",
+ "start_time": "2016-09-16T14:32:02.472050"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "gt8UuSQA9frA",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "form",
- "executionInfo": {
- "elapsed": 170,
- "status": "ok",
- "timestamp": 1446659140755,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "4896c353dcc58d9f",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "080025d5-d110-4975-e105-7635afaa3ce9"
- },
- "source": [
- "from IPython.display import Image\n",
- "import base64\n",
- "Image(data=base64.decodestring(\"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\"), embed=True)"
- ],
- "outputs": [
- {
- "output_type": "execute_result",
- "execution_count": 6,
- "metadata": {},
- "data": {
- "image/png": "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\nAAAAAElFTkSuQmCC\n",
- "text/plain": [
- "<IPython.core.display.Image object>"
- ]
- }
- }
- ],
- "execution_count": 6
+ "cellView": "form",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "Ft95NDUZy4Rr",
- "colab_type": "text"
- },
- "source": [
- "That's equivalent to the function $\\hat{y} = w_2 x + w_1$. What we're trying to do is find the \"best\" weights $w_1$ and $w_2$. That will give us that green regression line above.\n",
- "\n",
- "What are the best weights? They're the weights that minimize the difference between our estimate $\\hat{y}$ and the actual y. Specifically, we want to minimize the sum of the squared errors, so minimize $\\sum{(\\hat{y} - y)^2}$, which is known as the *L2 loss*. So, the best weights are the weights that minimize the L2 loss."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 170,
+ "status": "ok",
+ "timestamp": 1446659140755,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "4896c353dcc58d9f",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "gt8UuSQA9frA",
+ "outputId": "080025d5-d110-4975-e105-7635afaa3ce9"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "RHDGz_14vGNg",
- "colab_type": "text"
- },
- "source": [
- "## Gradient descent\n",
- "\n",
- "What gradient descent does is start with random weights for $\\hat{y} = w_2 x + w_1$ and gradually moves those weights toward better values.\n",
- "\n",
- "It does that by following the downward slope of the error curves. Imagine that the possible errors we could get with different weights as a landscape. From whatever weights we have, moving in some directions will increase the error, like going uphill, and some directions will decrease the error, like going downhill. We want to roll downhill, always moving the weights toward lower error.\n",
- "\n",
- "How does gradient descent know which way is downhill? It follows the partial derivatives of the L2 loss. The partial derivative is like a velocity, saying which way the error will change if we change the weight. We want to move in the direction of lower error. The partial derivative points the way.\n",
- "\n",
- "So, what gradient descent does is start with random weights and gradually walk those weights toward lower error, using the partial derivatives to know which direction to go."
- ]
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/opt/anaconda3/lib/python3.5/site-packages/ipykernel/__main__.py:3: DeprecationWarning: decodestring() is a deprecated alias, use decodebytes()\n",
+ " app.launch_new_instance()\n"
+ ]
},
{
- "cell_type": "markdown",
- "metadata": {
- "id": "W7SgnPAWBX2M",
- "colab_type": "text"
- },
- "source": [
- "## The code again\n",
- "\n",
- "Let's go back to the code now, walking through it with many more comments in the code this time:"
+ "data": {
+ "image/png": "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\nAAAAAElFTkSuQmCC\n",
+ "text/plain": [
+ "<IPython.core.display.Image object>"
]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from IPython.display import Image\n",
+ "import base64\n",
+ "Image(data=base64.decodestring(\"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\".encode('utf-8')), embed=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "Ft95NDUZy4Rr"
+ },
+ "source": [
+ "That's equivalent to the function $\\hat{y} = w_2 x + w_1$. What we're trying to do is find the \"best\" weights $w_1$ and $w_2$. That will give us that green regression line above.\n",
+ "\n",
+ "What are the best weights? They're the weights that minimize the difference between our estimate $\\hat{y}$ and the actual y. Specifically, we want to minimize the sum of the squared errors, so minimize $\\sum{(\\hat{y} - y)^2}$, which is known as the *L2 loss*. So, the best weights are the weights that minimize the L2 loss."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "RHDGz_14vGNg"
+ },
+ "source": [
+ "## Gradient descent\n",
+ "\n",
+ "What gradient descent does is start with random weights for $\\hat{y} = w_2 x + w_1$ and gradually moves those weights toward better values.\n",
+ "\n",
+ "It does that by following the downward slope of the error curves. Imagine that the possible errors we could get with different weights as a landscape. From whatever weights we have, moving in some directions will increase the error, like going uphill, and some directions will decrease the error, like going downhill. We want to roll downhill, always moving the weights toward lower error.\n",
+ "\n",
+ "How does gradient descent know which way is downhill? It follows the partial derivatives of the L2 loss. The partial derivative is like a velocity, saying which way the error will change if we change the weight. We want to move in the direction of lower error. The partial derivative points the way.\n",
+ "\n",
+ "So, what gradient descent does is start with random weights and gradually walk those weights toward lower error, using the partial derivatives to know which direction to go."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "W7SgnPAWBX2M"
+ },
+ "source": [
+ "## The code again\n",
+ "\n",
+ "Let's go back to the code now, walking through it with many more comments in the code this time:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:32:55.672248",
+ "start_time": "2016-09-16T14:32:55.024600"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "4qtXAPGmBWUW",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 718,
- "status": "ok",
- "timestamp": 1446659172854,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "4896c353dcc58d9f",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "0664707f-ea8a-453b-fc3f-48d5ca0f76dc"
- },
- "source": [
- "#@test {\"output\": \"ignore\"}\n",
- "import tensorflow as tf\n",
- "import numpy as np\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "# Set up the data with a noisy linear relationship between X and Y.\n",
- "num_examples = 50\n",
- "X = np.array([np.linspace(-2, 4, num_examples), np.linspace(-6, 6, num_examples)])\n",
- "# Add random noise (gaussian, mean 0, stdev 1)\n",
- "X += np.random.randn(2, num_examples)\n",
- "# Split into x and y\n",
- "x, y = X\n",
- "# Add the bias node which always has a value of 1\n",
- "x_with_bias = np.array([(1., a) for a in x]).astype(np.float32)\n",
- "\n",
- "# Keep track of the loss at each iteration so we can chart it later\n",
- "losses = []\n",
- "# How many iterations to run our training\n",
- "training_steps = 50\n",
- "# The learning rate. Also known has the step size. This changes how far\n",
- "# we move down the gradient toward lower error at each step. Too large\n",
- "# jumps risk inaccuracy, too small slow the learning.\n",
- "learning_rate = 0.002\n",
- "\n",
- "# In TensorFlow, we need to run everything in the context of a session.\n",
- "with tf.Session() as sess:\n",
- " # Set up all the tensors.\n",
- " # Our input layer is the x value and the bias node.\n",
- " input = tf.constant(x_with_bias)\n",
- " # Our target is the y values. They need to be massaged to the right shape.\n",
- " target = tf.constant(np.transpose([y]).astype(np.float32))\n",
- " # Weights are a variable. They change every time through the loop.\n",
- " # Weights are initialized to random values (gaussian, mean 0, stdev 0.1)\n",
- " weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))\n",
- "\n",
- " # Initialize all the variables defined above.\n",
- " tf.initialize_all_variables().run()\n",
- " \n",
- " # Set up all operations that will run in the loop.\n",
- " # For all x values, generate our estimate on all y given our current\n",
- " # weights. So, this is computing y = w2 * x + w1 * bias\n",
- " yhat = tf.matmul(input, weights)\n",
- " # Compute the error, which is just the difference between our \n",
- " # estimate of y and what y actually is.\n",
- " yerror = tf.sub(yhat, target)\n",
- " # We are going to minimize the L2 loss. The L2 loss is the sum of the\n",
- " # squared error for all our estimates of y. This penalizes large errors\n",
- " # a lot, but small errors only a little.\n",
- " loss = tf.nn.l2_loss(yerror)\n",
- "\n",
- " # Perform gradient descent. \n",
- " # This essentially just updates weights, like weights += grads * learning_rate\n",
- " # using the partial derivative of the loss with respect to the\n",
- " # weights. It's the direction we want to go to move toward lower error.\n",
- " update_weights = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)\n",
- " \n",
- " # At this point, we've defined all our tensors and run our initialization\n",
- " # operations. We've also set up the operations that will repeatedly be run\n",
- " # inside the training loop. All the training loop is going to do is \n",
- " # repeatedly call run, inducing the gradient descent operation, which has the effect of\n",
- " # repeatedly changing weights by a small amount in the direction (the\n",
- " # partial derivative or gradient) that will reduce the error (the L2 loss).\n",
- " for _ in range(training_steps):\n",
- " # Repeatedly run the operations, updating the TensorFlow variable.\n",
- " sess.run(update_weights)\n",
- " \n",
- " # Here, we're keeping a history of the losses to plot later\n",
- " # so we can see the change in loss as training progresses.\n",
- " losses.append(loss.eval())\n",
- "\n",
- " # Training is done, get the final values for the charts\n",
- " betas = weights.eval()\n",
- " yhat = yhat.eval()\n",
- "\n",
- "# Show the results.\n",
- "fig, (ax1, ax2) = plt.subplots(1, 2)\n",
- "plt.subplots_adjust(wspace=.3)\n",
- "fig.set_size_inches(10, 4)\n",
- "ax1.scatter(x, y, alpha=.7)\n",
- "ax1.scatter(x, np.transpose(yhat)[0], c=\"g\", alpha=.6)\n",
- "line_x_range = (-4, 6)\n",
- "ax1.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], \"g\", alpha=0.6)\n",
- "ax2.plot(range(0, training_steps), losses)\n",
- "ax2.set_ylabel(\"Loss\")\n",
- "ax2.set_xlabel(\"Training steps\")\n",
- "plt.show()"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlUAAAEPCAYAAABr+zG+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xl8VPW9//HXJwtLIKwBQVAEEdlETBUXLM2VKlZR22uv\n2NpatNdb6lqtGm17L1j7uwgu1KU+qPe617Vqi3LdEIm4VFHjggNaXNjXsIU1ZPn8/pgJjiEJSWY5\nk5n38/GYR2bOnDnnM0K+fviez/l8zd0RERERkdhkBR2AiIiISDpQUiUiIiISB0qqREREROJASZWI\niIhIHCipEhEREYkDJVUiIiIicRCXpMrMrjezkJl9bGaPmFmbeBxXRCRRzKyvmb0aGbsWmtnlke1d\nzexlM/vMzF4ys85Rn7nezJaY2WIzOyW46EUkFcWcVJlZP+Ai4Ch3HwHkAOfGelwRkQSrAq5y92HA\n8cAlZjYYuA54xd0PB14Frgcws6HAOcAQ4HvA3WZmgUQuIikpHjNV5cAeoIOZ5QB5wOo4HFdEJGHc\nfa27fxh5vh1YDPQFzgIejOz2IPD9yPMzgcfdvcrdlwJLgFFJDVpEUlrMSZW7bwZuBZYDq4At7v5K\nrMcVEUkWMzsEGAm8DRzg7usgnHgBPSO79QFWRH1sVWSbiAgQn8t/A4ArgX7AgUBHM/txrMcVEUkG\nM+sIPAVcEZmxqrt2l9byEpEmyYnDMY4G3nT3TQBm9gxwAvBo9E5mpoFJJE24e1rUEkVKFp4CHnb3\nWZHN68zsAHdfZ2a9gPWR7auAg6I+3jeyre4xNdaJpInmjnXxqKn6DDjOzNpFijbHEq5NqC+4lHhM\nnjw58BhSKQ7FktpxpFosaeY+YJG73x617VlgYuT5z4BZUdvPNbM2ZtYfGAgsqO+gQf8ZpdPft0yM\nPx2+Q2uP371lY13MM1Xu/pGZPQS8D1QDHwD3xHpcEZFEMrPRwHnAQjP7gPBlvt8A04AnzexCYBnh\nO/5w90Vm9iSwCKgELvaWjrwikpbicfkPd78ZuDkexxIRSQZ3fxPIbuDt7zbwmanA1IQFJSKtWkZ2\nVC8qKgo6BCB14gDFUp9UiQNSKxZJf63971trjx9a/3do7fG3lCVr9trMNFMukgbMDE+TQvVE0Fgn\nkh5aMtZl5EyViIiISLwpqRIRERGJAyVVIimuoqqixbf3iohI8iipEklhVTVV3LXgLhasqrcdkoiI\npBAlVSIpyt154MMH6NCmA8f0OSbocEREZD+UVImkqGcWP8OmXZv4+VE/J8v0qyoikuo0UoukoHlf\nzeOjdR9xyTGXkJudG3Q4IiLSBEqqRFLMB2s+4MXPX+TyYy+nQ5sOQYcjIiJNpKRKJIV8sekL/vLx\nX7j4mIspyCsIOhwREWkGJVUiKWLd9nXMfG8mFxx1Af269As6HBERaSYlVSIpoLyinDveuYPvD/4+\nw3sODzocERFpASVVIgGrqKrgrgV3cVzf4xh98OigwxERkRZSUiUSoBqv4Z7376Fvp76MHzQ+6HBE\nRCQGSqpEAuLuPPLxIzjOeUech1mzFkMXEZEUo6RKJCDPL3me5VuX84tv/YLsrOygwxERkRgpqRIJ\nwFsr3uLNFW9y2bGX0TanbdDhiIhIHCipEkmy0PoQzyx+hsuPvZxObTsFHY6IiMRJXJIqM+tsZn81\ns8VmFjKzY+NxXJF0s3zrcu774D4mHT2JXh17BR1ORjOze81snZl9HLVthJm9ZWYfmdksM+sY9d71\nZrYkMs6d0tix3RMZuYikKvM4/Pab2QPAa+5+v5nlAHnuXl5nH4/HuURKS0t54omXAJgwYRyFhYUB\nR9Q0G3duZPqb05kwfAKFvVtHzPUxM9y91VfVm9mJwHbgIXcfEdm2ALjK3d8ws4nAAHf/LzMbCjwC\nHAP0BV4BDqtvUDMz377d6aAVhkRatZaMdTHPVJlZJ+Db7n4/gLtX1U2oROKltLSUSZNmMH/+KObP\nH8WkSTMoLS0NOqz92rFnB3e8cwfjBo5r1QlVOnH3N4DNdTYfFtkO4cTp7MjzM4HHI+PbUmAJMKqh\nY2/bFudgRaRViMflv/5AmZndb2alZnaPmbWPw3FF9vHEEy+RnT2RgoKxFBSMJTt74t5Zq1RVWV3J\n3e/ezREHHMFJ/U8KOhxpXMjMzow8P4fwrBRAH2BF1H6rItvqpaRKJDPlxOkYhcAl7v6emf0RuA6Y\nHIdji7Rq7s59H9xHl3ZdOHvI2fv/gATtQuBOM/tP4FlgT0sOcsstU+jdO/y8qKiIoqKieMUnIglS\nUlJCSUlJTMeIR1K1Eljh7u9FXj8FFNe345QpU/Y+10AjLTFhwjjmzZtBWVn4dXX1A0yYcGWwQdUR\nCoWYPWc2ALlDcqnJr+GKY69otc094zHQtBbu/k9gHICZHQacHnlrFXBQ1K59I9vq9eMfT+E730lU\nlCKSCHXzkhtuuKHZx4hXofprwEXu/k8zm0y4UL24zj4qVJe4eOSRR7jjjicAuPzyCZx33nlxPX4s\nhfChUIhrb76W3GG5rK9ez4a1G3jsgsc4+sij4xpjkNKlUB3AzA4BnnP3IyKve7j7BjPLAu4H5rn7\nA1GF6scSvuw3h0YK1Z97zhmvVYdEWrWWjHXxmKkCuBx4xMxygS+BC+J0XJFvKC0t5fbbXyQ7+woA\nbr/9AYYMGbI38Yn1zsDaQvjs7IkAzJs3g5kzr2zycWbPmU3usFyyDspi55adHJZ1GHPnzU2rpCpd\nmNmjQBHQ3cyWEy5ZyDezSwAHnnH3BwDcfZGZPQksAiqBixv7V6JqqkQyU1ySKnf/iPCtxiIJFV2o\nDlBWFt5WWFgYc0K0v+M31faa7WzYvIHhPYezY9uOJn9Oksvdf9zAW3c0sP9UYGpTjq2kSiQzqaO6\npI1UuDPw2BOP5ct1X1JQXsCOL3dQGapk/Mm6DpRplFSJZKZ4Xf4TSYpEF6rHcvwtu7fw8taX+cP3\n/8CK0vDd9+OvGc+wYcPiFp+0DkqqRDJTXArVm3QiFapLnDRUN1X38l919QPNvvzX2PEbs7tqN7e8\ndQuFvQs57bDTmnW+1iadCtUTwcz8qqucW28NOhIRiUVLxjolVZJWgljCprqmmrsW3EX3vO6cd8R5\nrbZ1QlMpqWqcmflFFzn33BN0JCISiyDv/hNJCYWFhQlLpOpL2Nydhz9+mOysbH58xI8xs1a7NqHE\njy7/iWQmJVUiTdDQnYUrO6xkzbY1XHX8VWRZVlzuQJTWr1yrn4pkJCVVIk1QX6uFW/46kwEn96R4\ndDFtc9o2uF9zWzJI66eZKpHMpJYKIi2ws+OXfJ79KZcfezn5bfODDkdSjJIqkcykmSqRJpgwYRzP\nPz+ZVRsfp6rDNvYMfZf7xs2gZ4ee++yX6msTSuIpqRLJTEqqROoRXWx+9NED+cd7/2Bb3kJqRi5k\nV8E2Dll7MId2O3SfzxUWFjJz5pVRheqqp8pESqpEMpNaKojUEV1svnPnUpbt/C+6DWzLjn472N1t\nN0f1O4ou5V04Pvd4in9VvN/jpRu1VGicmXn79s7OnUFHIiKxaMlYp5oqkTqii833ZJWRNfgQdloF\ne7ruoW37tuzatCvoECXFVVRAVVXQUYhIsimpEtkPx/HDHVtlZK3MYtvybVrTTxrVsSNs3x50FCKS\nbEqqROqYMGEcZWU38nrpKFasepid2z8mv2MeI3qMoMsnXTi1y6lMv2a61vSTBuXnq65KJBOpUF2a\nJRO6hb/55pus3PMO1X2q4VDDKmDUulEcOfRIxl+oBZJl/5RUiWQmJVXSZJnQLTwUCvH7//k9NSfW\nkNM9h6rtVXSo6cjmTZszsihdWkZJlUhmUlIlTZYJ3cJnz5mNHW5YX6Mmv4bcmlwqP6+Envv/rEgt\nJVUimUk1VSJ19OnXh6rKKtgGVZurqFpWRfuaAoqLp1JaWhp0eNIKKKkSyUxKqqTJJkwYR3X1A5SV\nzaWsbG6kW/i4oMOKq29/59uUV5dzePbhdPqyE3kf5NHDh7NmzUTmzx/FpEkzlFjJfimpEslMcbv8\nZ2ZZwHvASnc/M17HldSRrt3CQ6EQs+fMptIrWdt3LcXji9m8cDP0gX92WsOiRWek9SXPTGVm9wLj\ngXXuPiKy7RjgT0AuUAlc7O7vRd67HrgQqAKucPeXGzq2kiqRzBTPmqorgEVApzgeU1JMYWFhWiUU\noVCIa2++luyh2XxV9RU5JTlM+uUkho8dDkBx8dSAI5QEuh+4E3goatt04Hfu/rKZfQ+4GfgXMxsK\nnAMMAfoCr5jZYQ0tE5GfD+XliQ1eRFJPXJIqM+sLnAb8P+CqeBxTJFGi20LsqllDztActvTYQmfv\nTPec7vzfK//H8OHhpEoLJKcvd3/DzPrV2bwG6Bx53gVYFXl+JvC4u1cBS81sCTAKeKe+Y2umSiQz\nxWumagZwDV8PRiIpqW5biBUbrqbLuZV06NqBI3oeQdnGsm/sn66XPKVB1wFvmtmtgAEnRLb3Af4R\ntd+qyLZ65efDunUJi1FEUlTMSZWZnU64JuFDMysiPBDVa8qUKXufFxUVUVRUFOvpRZrliSdeoqKi\niD1Z7wFgvY9i1bJnGd3pOMq2lIWXn7nmm8vPpNslz+YqKSmhpKQk6DCS5V7gMnf/u5n9ELgPOLm5\nB3n11SksWwZTpmisE2kt4jHWWQMlAU0/gNl/Az8hXLzZHsgHnnH38+vs11D5gUjS/Pznv+KZ+W/T\n9sheVLbbyo49nzHWRzNm9NEAjD9ZHdP3pyUrt6eqyOW/56IK1cvdvVPU+1vcvYuZXQe4u0+LbH8R\nmOzu+1z+MzN/8knn8cfh6aeT9EVEJO5aMtbFPFPl7r8BfhMJ4DvAr+smVCK1YlnmJh5L5HToVgOH\nr6Sqex678pfR5ssaDj20t7qlZy7jm7PrS8zsO+7+mpmNBZZEtj8LPGJmMwhf9hsILGjooJ06qaZK\nJBOpo7okTSzL3MRjiZxQKMSSr5bQqWc22woWcpAdQO8hB8Oer+/yS9f1DGVfZvYoUAR0N7PlwGTg\nP4C7zawNsDvyGndfZGZPEr7DubbVQoNT7ypUF8lMcU2q3P014LV4HlPSRyzL3MS6RE5t64Qd/XZQ\ntrGMNmva0LfvAVQsrGDe51/RseNZQHquZyj1c/cfN/DWsQ3sPxVoUo8NJVUimUkzVZIRZs+ZTdbQ\nLHZ33c3IbSPZ8sYW2pS34ZBuR7Coo5p7SnwpqRLJTEqqJGla2vOptLSUtWtXsXTpf7N9+w46duzQ\n7H5RNV7DsqpldMvtxqCBg1hfvZ7jc49n05qaln4dkQYpqRLJTEqqJGla0vMpupaqR4/hbNhwE9/6\n1jFcfnnTL9G5O1mDs6h6oYpOOZ1Yv2H93tYJFRUVau4pcVebVLmDpcV9kiLSFDG3VGjyidRSQVqg\nuHgq8+ePiro8N5cxYxYwbdr1TT7GC0te4P0173Nal9OY8+oc4JutE+JxV2EmSaeWColQO9a1bQtb\nt0K7dkFHJCItEUhLBZFU9vbKt3l9+etcO/paurTrQuGIfROmTG/uKYlRO1ulpEokc2QFHYBIYyZM\nGEd19QOUlc2lrGxu5PLcuCZ9dvGGxTy16CkuG3UZXdp1SXCkIt+kuiqRzKOZKklpza3DCoVCzJ4z\nm601W1ndazW/Hfdbeuf3Tla4InspqRLJPEqqJOU19fJcbS8qH+osqVxCz5Ke7DlyD3RPQpAideTn\nQ3l50FGISDLp8p+kjdlzZmNDjXWd1zHokEH0OKwHs+fMDjosyVCaqRLJPEqqJG1UezVLq5bStX1X\n+uT3CTocyXBKqkQyj5IqSQvuTuXASmyN0WFtB9Z/FulFdfL4oEOTDKWkSiTzqKZK0sIzi58hr1se\nD//Hw7w0N1zUPv6ar3tRiSRbp05KqkQyjZKqNJVJDS1f/epVPl73MdeOvpYObTow8oiRQYckopkq\nkQykpCoNRS/tAjBv3gxmzmz6si6pbtasWcx8eCYAp5x9CmsL1u5NqERSRX4+bNgQdBQikkxKqtLQ\nE0+8RHb2xKilXcLbmpJUpfoM16xZs7hoykVkj8qmKruK155/jTvOvIPueeqbIKklPx++/DLoKEQk\nmVSoLnvVznDNnz+K+fNHMWnSDEpLS4MOa69QKMQ1N17DrvxdtOnRhppDasjrlMfTTzwddGgi+9Dl\nP5HMo5mqNDRhwjjmzZtBWVn4dXhplyv3+7lYZrgSrbax55b+W6hoV8GaVWsosAK8Sot0S2pSUiWS\neZRUpaHmLu2Saupegmzbti1XT76aZT2Wcejhh/Le2vdgF2x7bRvtt7Vn0pRJAUcssi8lVSKZR0lV\nmmrq0i7RWjrDFU91i+yff34ynQduZrNtZlPNJtaUr+GQnoew5cMtdN3ZlZun3MxZZ52V1BhFmkJJ\nlUjmibmmysz6mtmrZhYys4Vmdnk8ApPkq53hGjNmAWPGLAjkjsHoS5AFBWPZWtGLdZ03MeSkIVTu\nrKS6opqclTmM6jCKvz34NyVU0mJmdq+ZrTOzj6O2PW5mpZHHV2ZWGvXe9Wa2xMwWm9kp+zu+kiqR\nzBOPmaoq4Cp3/9DMOgLvm9nL7v5pHI4tSdaSGa5k2N5lO71H9Kb67WoOsUOYfsN0NfaUWN0P3Ak8\nVLvB3c+tfW5mtwBbIs+HAOcAQ4C+wCtmdpi7N1jUp6RKJPPEnFS5+1pgbeT5djNbDPQBlFRJs9Ve\ngvznP99k3fbZVFV+RcGmDny57EsOyz0M8mH6NUqoJHbu/oaZ9Wtkl3OAosjzs4DH3b0KWGpmS4BR\nwDsNfVhJlUjmiWtNlZkdAoykkYFGWqdk9a8qLCykqKg3M578A1ZotC1ow9pd2zhjxRkcPfhoLT0j\nSWFm3wbWunttp6k+wD+idlkV2dagjh1h506oqYEsNa8RyQhxS6oil/6eAq5w9+317TNlypS9z4uK\niigqKorX6SWBktmhPRQKcf9z95M12sg5JIfdlbvJ35jP9rLtFP+qOO7nk/0rKSmhpKQk6DCS7UfA\nYy39cO1Yl50NL7xQxOmnF8UnKhFJmHiMddZISUDTD2KWA8wGXnD32xvYp7HyA0lhxcVTmT9/VFT/\nqrmMGbOAadOub9HxGpv1mvbHadz6t1vZNngbfpCTtTuL7M+yOdFP5IWnXoj9y0jMzAx3t6DjiIfI\n5b/n3H1E1LZswjNRhe6+OrLtOsDdfVrk9YvAZHffZ1Y+eqzr3Rveew/6NDqnJSKpqCVjXbwmpe8D\nFjWUUInUakrX9oOHHkzljkp8rVP9VTX+kTPpp+pFJQlhkUe0k4HFtQlVxLPAuWbWxsz6AwOBBfs7\neKdOqqsSySTxaKkwGjgPOMnMPojcinxq7KFJqpgwYRzV1Q9QVjaXsrK5kf5V41p0rLotE7KzJ+6d\ntQIYN3Yc29tsp39Bfzov7Eyn0k5MvWyqWidI3JnZo8BbwCAzW25mF0TemkCdS3/uvgh4ElgEPA9c\n3JSpdxWri2SWeNz99yaQHYdYJEUlq0O7u/NOxTv86Ls/ou3nbbFDjPEnB1OYnuoLS0vs3P3HDWy/\noIHtU4GpzTmHkiqRzKKO6tIk8epf1VDXdnfnr4v+yvY92/nt6b8lJyu4v5rJLMyX9KakSiSzKKmS\npGpo1uuVL19h8YbFXDP6mkATKkjthaWldVFSJZJZlFRJ0tWd9Xpv9Xu88uUrXDv6WvJy8wKMTCS+\nlFSJZBYlVZJ0oVCI2XNmA3DEcUfwavmr/Oq4X9GtfbeAIwtLhYWlJT0oqRLJLEqqJKlmzZpF8W3F\nZA3NoluPbvz5yT/zx3/7I3079Q06tL2SVZgv6U9JlUhmUVIlSRMKhSieXszW4VvJ7ZPLyp0rGdRx\nEIvfWcyZx58ZdHjfkKoLS0vrkp8Py5YFHYWIJItWpJKkmT1nNtkHZNOmYxt2td1F+/bt2blhZ9Bh\niSSMZqpEMouSKkmqHv17UL6pHC9zbKVRs6iG8SePDzoskYRQUiWSWZRUSdKc/t3T2VSxiR4H9KDn\nkp50+aQL066aFkhzT5FkUFIlkllUUyVx1Vgn8i9yvuCkfzmJHst7kNMrJ7Bu6SLJoqRKJLMoqZK4\naawT+evLXufd1e9y4/gbyW+bH2icIsmSnw/l5UFHISLJoqRK4qahTuQ5fXJ49rNnuWb0NUqoJKN0\n6qSZKpFMoqRK4m7bthDrts5mx47P+WpzNQ9++CCXjrqUnh16Bh2aSFLp8p9IZlFSJd/QWE3U/kyY\nMI5nnrmKlTu/hJ5G9sE7eSunLbd3vJ3+XfsnKmSRlKWkSiSzKKlKA7EkQnWP01BNVFO0bduWym5L\nyTp6M1l52ThV9OjYl8/f/RxGtygkkVatbVuoqYE9e6BNm6CjEZFEU0uFVq42EZo/fxTz549i0qQZ\nlJaWtuhY0TVRBQVjyc6euDdZa4rZc2aTV5hHwbButB/chryCPPZ8vqdFsYg0lZkdamZtI8+LzOxy\nM+sSdFwAZpqtEskkSqpauVgToXjr1aMX5dvLqdldQ9aWLKrXVau5pyTa00C1mQ0E7gEOAh4NNqSv\n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\nTkSuQmCC\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f8047207c10>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "lSWT9YsLP1de",
- "colab_type": "text"
- },
- "source": [
- "This version of the code has a lot more comments at each step. Read through the code and the comments.\n",
- "\n",
- "The core piece is the loop, which contains a single `run` call. `run` executes the operations necessary for the `GradientDescentOptimizer` operation. That includes several other operations, all of which are also executed each time through the loop. The `GradientDescentOptimizer` execution has a side effect of assigning to weights, so the variable weights changes each time in the loop.\n",
- "\n",
- "The result is that, in each iteration of the loop, the code processes the entire input data set, generates all the estimates $\\hat{y}$ for each $x$ given the current weights $w_i$, finds all the errors and L2 losses $(\\hat{y} - y)^2$, and then changes the weights $w_i$ by a small amount in the direction of that will reduce the L2 loss.\n",
- "\n",
- "After many iterations of the loop, the amount we are changing the weights gets smaller and smaller, and the loss gets smaller and smaller, as we narrow in on near optimal values for the weights. By the end of the loop, we should be near the lowest possible values for the L2 loss, and near the best possible weights we could have."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 718,
+ "status": "ok",
+ "timestamp": 1446659172854,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "4896c353dcc58d9f",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "4qtXAPGmBWUW",
+ "outputId": "0664707f-ea8a-453b-fc3f-48d5ca0f76dc"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "dFOk7ERATLk2",
- "colab_type": "text"
- },
- "source": [
- "## The details\n",
- "\n",
- "This code works, but there are still a few black boxes that are worth diving into here. `l2_loss`? `GradientDescentOptimizer`? What exactly are those doing?\n",
- "\n",
- "One way to understand exactly what those are doing is to do the same thing without using those functions. Here is equivalent code that calculates the gradients (derivatives), L2 loss (sum squared error), and `GradientDescentOptimizer` from scratch without using those functions."
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0YAAAF5CAYAAAC7lzpJAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3Xl81OW99//XZ7IvTMIQAgygKG6Y4MIiWqpFbbGtiv1Z\nTjxUu9DWhVrbQ+kpt3fbY3uwv1bODbZqbY1o1SpYbs7xtLVWc9rGWpeCgAsBxLpBzDJJCNkTJst1\n/zETDREhITP5Znk/H488Jny/M9/5TB4P+PLOdV2fy5xziIiIiIiIjGY+rwsQERERERHxmoKRiIiI\niIiMegpGIiIiIiIy6ikYiYiIiIjIqKdgJCIiIiIio56CkYiIiIiIjHoKRiIiIiIiMuopGImIiIiI\nyKinYCQiIiIiIqOegpGIiIiIiIx6cQ1GZna+mf3OzMrMrMvMFh3mOf9uZuVm1mJm/2NmJ8WzJhER\nkcMxs5vNbIuZNZhZyMweM7NTDvO888zsz2bWZGb1Zva0maX0OD/WzB6JnjtgZuvMLGNwP42IiPRX\nvEeMMoCXgRsB1/ukma0Evg5cD5wDNANPmVlynOsSERHp7XzgTmAe8HEgCSgys7TuJ5jZecAfgSeB\nOdGvu4CuHtdZD8wALgYuBS4A7hmE+kVEZADMuQ/klfi8kVkX8Bnn3O96HCsH/sM5d3v0z34gBHzR\nObdxUAoTERE5DDPLAaqAC5xzz0aPvQA85Zz7wYe85jRgFzDbOfdS9NglwB+AKc65ysGoXURE+s+z\nNUZmdgIwEfhz9zHnXAOwGTjPq7pERESisonMdqgFMLPxREaTaszsOTOrjE6jm9/jNecBB7pDUdSf\noteZN0h1i4jIMfCy+cJEIjeKUK/joeg5ERERT5iZAT8FnnXO7YoePjH6eAuRqXGXANuBP5vZ9Oi5\niURGmd7jnOskEq50bxMRGcISvS7gMIzDrEd676TZOCI3o3eAtkGqSURkpEgFphGZDrbf41qGsruB\n04Geo0Hdv0z8pXPuoej33zKzi4EvA989wvU+9N6m+5qIyIDE7L7mZTCqJHKjmMCho0a5wEuHfUXE\nJcAjcaxLRGQ0uJpIkwDpxczuAj4NnO+cq+hxqvv73b1eshs4Lvp9JZH7WM/rJQBj+eAMiW66r4mI\nDNyA72ueBSPn3NtmVkmka8+r8F7zhXnAz4/w0ncAHn74YWbMmBHvMuNi+fLl3H777V6XccxUv7dU\nv/eG82fYvXs311xzDUT/LZVDRUPRFcDHnHP7ep5zzr0TbRp0aq+XnQI8Ef3+BSDbzM7usc7oYiK/\nCNz8IW/7Dgzv+1osDee/X/Ggn8f79LN4n34W74vlfS2uwSi6b8NJRG4IACea2ZlArXOulMj87e+Z\n2RtEPswq4F3gt0e4bBvAjBkzmDVrVrxKj6usrKxhWzuofq+pfu+NhM+Apmx9gJndDSwBFgHNZjYh\neqreOdf98/oP4Adm9iqR7Si+RCQofRbAOfeamT0F3Gtmy4BkIi3ANxyhI92wv6/F0gj5+xUz+nm8\nTz+L9+lncVgDvq/Fe8RoDlBMZF61A9ZEjz8IfNk5t9rM0oksYs0G/gZ8yjkXjnNdIiIivd1A5F71\ndK/jS4GHAJxzP4tu5roWCACvAB93zr3d4/mfI7K30Z+I7G+0CfhmXCsXEZEBi2swcs79laN0vovu\nBfGDeNYhIiJyNM65PnVqdc6tBlYf4XwdcE2s6hIRkcHhZbtuERERERGRIUHByANLlizxuoQBUf3e\nUv3eGwmfQWSo0t+vQ+nn8T79LN6nn0V8mHMfumXQkGRms4Bt27Zt06IzEZF+2r59O7NnzwaY7Zzb\n7nU9ovuaiMhAxPK+phEjEREREREZ9RSMRERERERk1FMwEhERERGRUU/BSERERERERj0FIxERERER\nGfUUjEREREREZNRTMBIRERERkVFPwUhEREREREY9BSMRERERERn1FIxERERERGTUUzASEREREZFR\nT8FIRERERERGPQUjEREREREZ9RSMRERERERk1FMwEhHph6rmKq9LEBERkThQMBIR6aPX97/OD5/+\nIS+Wveh1KSIiIhJjCkYiIn1Q1lDG3S/ezUmBkzh70tlelyMiIiIxpmAkInIUta213LH5DnLSc1g2\ndxmJvkSvSxIREZEYUzASETmC5nAzP/v7z0j0JfKNed8gNTHV65JEREQkDhSMREQ+RLgzzF1b7qIp\n3MQ3z/0m/hS/1yWJiIhInCgYiYgcRpfr4t5t9/Juw7vcNO8mcjNyvS5JRERE4kjBSESkF+ccj7z6\nCCVVJdww5wamZU/zuiQRERGJMwUjEZFeHn/9cZ7d9yxfPOuL5OXmeV2OiIiIDAIFIxGRHp7Z+wyP\nv/44V864knOnnOt1OSIiIjJIFIxERKJeqniJ9TvWc9EJF7Fw+kKvyxEREZFBpGAkIgK8UfsG67av\nY/ak2RTkFWBmXpckg8zMbjazLWbWYGYhM3vMzE45wvP/aGZdZrao1/GpZvYHM2s2s0ozW21mut+K\niAxx2qVQREalUChEdXU1ubm5dKR18PMtP2d6YDpLz16qUDR6nQ/cCWwlcn/8MVBkZjOcc609n2hm\ny4FOwPU67gOeAMqBc4Eg8GsgDHwv3h9ARESOnYKRiIwqzc3NFK4rpHhzMU3hJpJTkwnnh/nonI+y\nbM4yEn36Z3G0cs59uuefzexLQBUwG3i2x/EzgX8B5gKVvS5zCXAacKFzrgbYYWbfB35iZj9wznXE\n7xOIiMhAaGhfREaVwnWFbHpuEwmzEpj0/03indPf4fV3Xye1JJW0pDSvy5OhJZvIiFBt9wEzSwPW\nAzc656oO85pzgR3RUNTtKSALUItDEZEhTMFIREaNUChE8eZics/JJeeUHN5oeYPkscnMPH4mf9/y\nd6qqDvf/XBmNLDKf8qfAs865XT1O3R499viHvHQiEOp1LNTjnIiIDFGaMyIio0Z1dTVN4SamBqey\nu2Y3ze3NzMydSUp2CqVbSqmqqiI3N9frMmVouBs4HZjffSDaZOEi4KxjvKY70snly5eTlZV1yLEl\nS5awZMmSY3w7EZGRZcOGDWzYsOGQY/X19TG7voKRiIwa48ePJyM5g537dtIypoW88Xn4U/xUvVNF\nRlKGQpEAYGZ3AZ8GznfOVfQ4dSFwIlDfq0HHf5nZM865i4isOZrb65IToo+9R5IO8eMf385HPjJr\nQLWLiIxkh/tl0fbt25k9e3ZMrq+pdCIyakyYMIEJsybwbsW75DTlkNGZQdWeKqq2VHHhvAsVjKQ7\nFF1BpHnCvl6nfwycAZzZ4wvgm8DS6PcvADPNLKfH6xYC9UDPKXkf0Ng4sNpFRGRgNGIkIqPG3/b+\nDTfdsYhFVG6vpHRrKRlJGSyev5jrr73e6/LEY2Z2N7AEWAQ0m1n3SE+9c64t2myhqtdrAEqdc3uj\nh4qIBKBfm9lKYBKwCrjLOdd+pPeP4WwQERE5BgpGIjIqvFL5Co/seIRPnPwJrvrMVVRXV7+3pkgj\nRRJ1A5F1QE/3Or4UeOhDXnPIuiHnXJeZXQb8AngeaAYeAG452ps3NPSvWBERiS0FIxEZ8d6sfZN7\nt9/L2RPPpiCvADNTIJIPcM71e3q5cy7hMMdKgcv6ey0FIxERb2mNkYiMaBWNFdy15S5OyD6BL5/9\nZXymf/ZkaFIwEhHxlv6HICIj1oHWA/xs888YmzaWZXOXkZSQ5HVJIh9Ka4xERLylYCQiI1JLewt3\nbL4Dw/jGvG+QnpTudUkiR6QRIxERbykYiciI097Zzt0v3k39wXq+Me8bZKdme12SyFEpGImIeEvB\nSERGlC7XxX0v3cc7de/w9XO+zqQxk7wuSaRPNJVORMRbCkYiMmI459iwYwOvVL7CdbOv48SxJ3pd\nkkifacRIRMRbCkYiMmL88Y0/8szeZ7jmjGs4Y8IZXpcj0i8KRiIi3tI+RiKjVFlZGZWVlUyaNIlg\nMOh1OQP27L5n+e1rv+WK065g/nHzj/r8kfb5ZfhTMBIR8ZaCkcgo09jYyOrVaykq2kpLC6Snw8KF\nc1i5cgWZmZlel3dMXg29ysOvPszHpn2MT530qSM+dyR+fhkZtMZIRMRbmkonMsqsXr2WjRv34POt\nIBj8FT7fCjZu3MNtt63xurRj8taBtyjcVshZE8/in/P/GTM74vNH2ueXkaOpCTo7va5CRGT0UjAS\nGUXKysooKtpKIHAdOTkLSE7OISdnAYHAtRQVbaW8vNzrEvulorGCu7bcxbTsaXzl7K/gsyP/kzbS\nPr+MPBo1EhHxjoKRyChSWVlJSwv4/fmHHPf7Z9LSAhUVFR5V1n91bXXcsfkOslKy+Nrcr5GUkHTU\n14ykzy8jU22t1xWIiIxeCkYio8jEiRNJT4eGhpJDjjc07CA9HSZNGh57/rS0t3DH5jtwOL4x7xuk\nJ6X36XUj5fPLyKVgJCLiHQUjkVFk8uTJLFw4h9raQmpqigmHa6ipKaa29l4WLpwzLLqztXe284sX\nf8GB1gN8c943GZs2ts+vHQmfX0Y2BSMREe+oK53IKLNy5QpgDUVFaykvj3RlKyiYEz0+tHW5Lu5/\n6X7ernub5ecuZ9KY/o/wDOfPLyPfgQNeVyAiMnopGImMMpmZmaxadQvLlpVTUVER1318YrlXkHOO\n35T8hpcqX2LZnGVMD0w/pusM5ucX6Y/ERI0YiYh4ScFIZJQKBoNxCwTx2CvoyTee5Ol3nuaaM67h\nzIlnDrjGeH5+kWORlaVgJCLiJa0xEpGYO9xeQevX7+Rf/uXbx9QS+/nS5/nv1/6by0+9nPOPPz8O\nFYt4b8wYBSMRES8pGIlITPXeK8jny2b//kmEQgtYv/4vXHrpF/n+939IU1NTn663I7SDX7/ya84/\n/nwuPfnSOFcv4p2sLK0xEhHxkoKRiMRU772C3nzzTcrLm0lIuJiEhOl0dCxm48Y93HbbmqNe6+0D\nb3PPtns4Y8IZfG7m5zCzeJcv4hm/XyNGIiJeUjASkZjquVdQW1sr1dX1JCUdh89XTmJiIhMnXk4g\ncC1FRVs/MK0uFApRUlJCVVUVoaYQd265k+OyjuOrs76Kz/TPlYxsWmMkIuItNV8QkZjq3ito48ZC\nmpsbaW9PISFhO52dDzBp0hxSU4P4fMmUl0NFRQXBYJDm5mYK1xVSvLmYpnATKakptOe3M2/2PG6c\neyNJCUlefyyRuPP74c03va5CRGT0UjASkZjr3ivo8cfvoqurHOfGMm7cfKZMuRGAhoYdpKfDpEmR\nfYgK1xWy6blN5J6TS3BSkG17t9FQ1sCFKReS8YkMDz+JyODRVDoREW9pboqIxFz3XkG/+c2dnHpq\nKp2dB6mpmcr27dt56aUH2b//HhYunEMwGCQUClG8uZjcc3LJOSWHN1vfJHFsIjOnzmTzi5upqqry\n+uOIDIru5gvOeV2JiMjopBEjEYmbX/96A01N08jJyaSx8Xe0t4fZv7+CE06YxMqV6wCorq6mKdzE\n1OBU9uzfQ8PBBmbmziQ1O5XSF0upqqoiNzfX408iEn9+P4TD0NICGRooFREZdApGIhIX3W27c3JW\nkJOzgLa2ctraKmhpeYtw+CEaGhrIzMxk/PjxZCRnsGvfLprHNDMjZwZZqVlU7akiIylDoUhGDb8/\n8lhbq2AkIuIFTaUTkbjo3bY7NTVIdvZscnIupKUl0ngBYMKECQRnBSmtKGVc0zjGdI2hak8VVVuq\nuHDehQpGMmr0DEYiIjL4PA9GZnaLmXX1+trldV0iMjA923b31LvxwgulL9AxvYPLpl7G2FfGUvpf\npXRu72Tx/MVcf+31XpQuo5SZ3WxmW8yswcxCZvaYmZ3S4/xYM7vDzF4zs2Yz22tmPzMzf6/rTDWz\nP0SfU2lmq82O3m8+KyvyqE1eRUS8MVSm0pUAFwPduzd2eFiLiMRAz7bd4PD7Z9LQsIPa2nspKIg0\nXiipKuGhVx5iwYkLuOYz11BdXf3emiKNFIkHzgfuBLYSuT/+GCgysxnOuVYgCEwCvgXsBo4H7oke\nKwCIBqAngHLg3Ohrfg2Ege8d6c01YiQi4q2hEow6nHPVXhchIrHV3ba7qGgt5eWQng4FBXNYuXIF\n79S9wz1b7yE/N5+rz7gaM1MgEk855z7d889m9iWgCpgNPOuc2wn8U4+nvG1m3wV+bWY+51wXcAlw\nGnChc64G2GFm3wd+YmY/cM596C/+MjMjjwpGIiLeGCrB6GQzKwPagBeAm51zpR7XJCID1N22e9my\nckpKSkhMTCQ/P58Wa+HOzXcyxT+Fa2dfi+/os4xEvJANOOBIUSUbaIiGIoiMEu2IhqJuTwG/APKA\nVz7sQgkJkJ2tYCQi4pWhEIz+DnwJ2ENkOsIPgGfMLN851+xhXSISA83Nzfzm//6G4s3FNIWbSElN\noSO/g7mz5vL1c75OckKy1yWKfICZGfBTIiNFh133amY5RKbH3dPj8EQg1OupoR7nPjQYAQQCWmMk\nIuIVz4ORc+6pHn8sMbMtwF4i87V/5U1VIhIrhesK2fD0BjLPyCRwfIBdlbuoL6vnYykfI2OhehLL\nkHU3cDow/3AnzWwM8Acia2R/2MdrHnXr1kBAI0YiIl7xPBj15pyrN7PXgZOO9Lzly5eT1d3CJ2rJ\nkiUsWbIknuWJDIqysjIqKyuZNGkSwWDQ63KO2VtvvcW6R9ex//j9+A74aD3YSmpGKnmT89jy4hZt\n3hpnGzZsYMOGDYccq6+v96ia4cPM7gI+DZzvnKs4zPlMItPj6oArnXOdPU5XAnN7vWRC9LH3SNIh\nli9fzt69WZSVQbSbve5rIiI9xPu+Zs4d9RdYgyp6w9kL3OKcu+sw52cB27Zt28asWbMGvT6ReGps\nbGT16rUUFW2lpSXSrGDhwkizgszuldnDyI033ciDf3gQ/xV+uiZ10dLWQvKBZE4YcwL+3X5+dsvP\nyM/P97rMUWX79u3Mnj0bYLZzbrvX9Qw10VB0BfAx59xbhzk/hkgoagU+7Zw72Ov8J4HfA5O61xmZ\n2XXAbUCuc679MNd87762evUsqqvhz3+O9ScTERmZYnlf83zFs5n9h5ldYGbHm9lHgMeItOvecJSX\niow4q1evZePGPfh8KwgGf4XPt4KNG/dw221rvC6tX5qbm/n3W/+djU9uJOzC1LxeQ31ZPWPTxzIm\nZwylr5eS5JI0WiRDipndDVwNfA5oNrMJ0a/U6PlM4H+AdOCrQHaP53TfT4uAXUQ61Z1hZpcAq4C7\nDheKetMaIxER73gejIApwHrgNeBRoBo41zm339OqRAZZWVkZRUVbCQSuIydnAcnJOeTkLCAQuJai\noq2Ul5d7XWKfFa4r5LG/PwZnQ+pnUuk8sZPOPZ20/K2FzppO2na3ceZJZyoYyVBzA+AHniayD1H3\nV0H0/Gwi0+RmAm9Ez1VEH6cARLvTXQZ0As8DDwEPALf0pQCtMRIR8Y7na4ycc5o8LQJUVlbS0gLB\n4KFTy/z+mZSXQ0VFxbBYbxQKhSjeXMzE8yZScaACN8YxpnUM4bQwjS81YqXG5KTJLLthmdelihzC\nOXfEXxY65/4KJPThOqVEwlG/KRiJiHhnKIwYiQgwceJE0tOhoaHkkOMNDTtIT4dJkyZ5VFn/VFdX\n0xRuInlyMi7L4WvykZ2ZTe6ZuaRlp5Hrz+Wrn/8q06ZN87pUkSFn7FhobIT2o066ExGRWPN8xEhE\nIiZPnszChXPYuLEQcPj9M2lo2EFt7b0UFMwZ8qNFZWVl7Ny5k4aGBjqSOigpK+HEiSfiEhwV1RW0\nlLeQ0pZCwccLuP7a670uV2RICgQij3V1MH68t7WIiIw2CkYiQ8jKlSuANRQVraW8PNKVrqBgTvT4\n0NTY2Mitt/6Eh9dvoq6tBsZ24maGSdmVwmkJpzH+hPGMZSyV/6jkymuu5Pvf+77XJYsMWd3BqLZW\nwUhEZLApGIkMIZmZmaxadQvLlpVTUVExLPYxuvXWn/DzXzxAW0YDlptEV14Y5zpJ/Hsne9/aS9uU\nNjKSMvjCJ76gkSKRo+gZjEREZHApGIkMQcFgcMgHIohMn3t4/SbachpImJuJO6EdX1sS7oVk2tM7\nyQnk8G9f/zdmzJihDnQifTB2bORRwUhEZPCp+YKIHLOdO3dS116DnZIE0zshqYvk1PEkneKnI9xB\nXUsd48aNUygS6aPuYKS9jEREBp+CkUiMlJWVsW3btmG139BAJSQkYClduCntdLo2kjqy8ZGEy3bg\nOklPSFcoEumHtLTIl0aMREQGn6bSiQxQY2Mjq1evpahoKy0tkYYJCxdGGiZkZmZ6XV5c5efnMyY/\njdaEGqw6la70DroS2+koryapNYFPLvikgpFIP2kvIxERb2jESGSAVq9ey8aNe/D5VhAM/gqfbwUb\nN+7httvWeF1a3L3a9CrHnTeVwL4skvY5OkqraC8JkVRiXHz2xXz7W9/2ukSRYWfsWAUjEREvaMRI\nZADKysooKtpKILCCnJwFANFHR1HRWpYtKz+mJgplZWVUVlYO6a50W8q2sGnXJpZftpyKMRX88a9/\npLq+mrSEND71+U+x4lsrSE9P97pMkWFHI0YiIt5QMBIZgMrKSlpaIBjMP+S43z+T8nKoqKjoV7AZ\n6tPyQqEQ1dXV1CXVsf6N9Zw39TyuOvMq7Czj6iVXU1VVRW5urqbPiQxAIKDmCyIiXlAwEhmAiRMn\nkp4ODQ0l740YATQ07CA9HSZNmtSv63VPywsEVhAM5tPQUMLGjYXAGlatuiW2xfdDc3MzhesKKd5c\nTI2roXJCJWcFz+KzH/ssZgagQCQSI4EA7NrldRUiIqOP1hiJDMDkyZNZuHAOtbWF1NQUEw7XUFNT\nTG3tvSxcOKdfo0XvT8u7jpycBSQn55CTs4BA4FqKirZ62u2ucF0hm57bRMfZHdSfV09abhoV2ypY\nd986z2oSGam0xkhExBsKRiIDtHLlCgoKTqWray3l5Uvp6lpLQcGprFy5ol/X6Z6W5/d/cFpeS0tk\nWp4XQqEQxZuLGTt3LJX+SlJSUjjn9HOYOHcixZuLqaqq8qQukZFKa4xERLyhqXQiA5SZmcmqVbew\nbFk5FRUVx9wwIdbT8mKlurqahvYGGtIa6Ozq5KyJZ5GckEzW5CxKN5e+t65IRGKje42RcxCdqSoi\nIoNAwUgkRoLB4IA6yHVPy4usKXL4/TNpaNhBbe29FBT0b1peLI0dN5aa8TW01rdy7mnnkpqYCkB9\nWT0ZSRkKRSIxFghAZyc0NoLf73U1IiKjh4KRyBASmX63hqKitZSXR7rSFRTM6fe0vIEoKytj586d\nJCYmkpeXx1OVT5E1NYuknUm0pLSQNDmJ+rJ6qrZUsXj+YgUjkRgbOzbyWFurYCQiMpgUjESGkMzM\nTG644avMnz8PgDPOOGPQRooaGxu59daf8PD6TRxorYaUTsackca0+cfzoyt/xI70HRRvLqZ0cykZ\nSRksnr+Y66+9flBqExlNAoHIY20tTJvmaSkiIqOKgpHIEOH1Hka33voT7vrFA7Sm1eGyEmFiJ62B\nGhqKGtiavJX/9Z3/xdVV2qtIJN66g5H2MhIRGVzqSicyRHTvYeTzrSAY/BU+3wo2btzDbbetift7\nl5WV8fD6TbQG6nDnpcEnM2Guwf4U2so7KXzk3vcCUX5+vkKRSBz1HDESEZHBo2AkMgR4vYfRzp07\nORCuxk1PxI5Pw/wtWFImlhUAB5XV1ZSUlMS1BhGJGDMGfD4FIxGRwaZgJDIEeL2HUUJCApbcCVng\nkuugMxkLZ0EWgINwAp2dnXGtQUQifD5t8ioi4gUFI5EhoOceRgCtrWXU1W2jpqZ4UPYwys/PJ2fi\nWMhugdZ2qE+GzmZcVTXWZIxNyyUvLy+uNYjI+7r3MhIRkcGj5gsig6SsrIzKysrDbgDbvYfRo4/+\nnNLSB2lsrKC9/SDOVTJnziT8ce7Zm56dzvTPnEjFKxW0v92Fy6zCtTjsTSOtdRyfX7p4ULrjHeln\nJDKaBAIaMRIRGWwKRiJx1tducytXruDppxexdWsIsyUkJU1nzJhKQqEnuO22NaxadUtM6wqFQlRX\nV5M1LouH33iYmWfNZH7ifB5Zv57QG9W4gwmMTcnl819bzPe+d3NM37s3rzvyiQw1mkonIjL4FIxE\n4qy721wgsIJgMJ+GhhI2biwEDg079fX1hMMZnH76TWRknENKSiqpqanU1EylqGgty5aVx2QUpbm5\nmcJ1hRRvLqYx3EhNbg3ZU7NZt3Qdp156KjctvYmSkhI6OzvJy8sblJGbvv6MREaLQADKyryuQkRk\ndNEaI5E46k+3ue4GDDk5s8jKyiY1NRWIfQOGwnWFbHpuE76zfbR/vJ3myc007Wziid88AUBubi4X\nXXQRn/jEJwZt+pyXHflEhiKtMRIRGXwKRiJx1J9uc70bMHRraNgRswYMoVCI4s3F5J6TS+vEVvZ3\n7ufM6Wcy7axpFG8upqqqasDv0V9ed+QTGYq0xkhEZPApGInEUX/CTncDhtraQmpqigmHa6ipKaa2\n9l4WLpwTk9Gb6upqmsJNtIxtYV/DPk7MPpHcjFyyJmfR3N7sSTAajEAo0hdmdrOZbTGzBjMLmdlj\nZnZKr+ekmNnPzazGzBrNbJOZ5fZ6zlQz+4OZNZtZpZmtNrN+3W+1xkhEZPApGInEUX/DzsqVKygo\nOJWurrWUly+lq2stBQWnsnLlipjUM378eDrGdPB65etMGTOFKf4pANSX1ZORlEFubu5RrhB7gxEI\nRfrofOBOYB7wcSAJKDKztB7P+SlwKfBZ4AIgCPxn98loAHqCyBrec4EvAl8C/r0/hQQC0NICBw8e\n60cREZH+UvMFkTiLhJo1FBWtpbw80nGtoGDOYcNOZmYmq1bdwrJl5VRUVPS7bfXR2l3XJdTRdUoX\nCW8nkJGcwcGkg9SX1VO1pYrF8xd7Eoygfz8jkXhxzn2655/N7EtAFTAbeNbM/MCXgX92zv01+pyl\nwG4zO8c5twW4BDgNuNA5VwPsMLPvAz8xsx845zr6UksgEHk8cAAmTozFpxMRkaNRMBKJs2MJO8Fg\nsF+BqC/MLD2pAAAgAElEQVTtrt9teJe7X7ybRfMX4Uvz8cyWZyjdUkpGUgaL5y/m+muvH9DnHIiB\nBkKROMkGHNA9qW02kfvmn7uf4JzbY2b7gPOALURGiXZEQ1G3p4BfAHnAK3154+5gVFurYCQiMlgU\njEQGSX/DTn98WLvrpqYf8pWvfJFEfyL377mf3IxcvvGRb5B6QSpfqPoCVVVV5ObmejZS1Fs8f0Yi\n/WFmRmTa3LPOuV3RwxOBsHOuodfTQ9Fz3c8JHeZ897l+ByMRERkcCkYiHjnatLf+XCfS7noFOTkL\nAMjOnkt55f/lgU0P8fe3n2X/1P0cP/l4fn39r0lNjLQBH0qBSGQIuhs4HfhoH55rREaWjqYvzwEi\nzRdAwUhEZDApGIkMsr5Me+uP7nbXweD77a73vVtIfcaLdB4PB+YfwIUdda/UseGhDSz/5vJYfhyR\nEcfM7gI+DZzvnOu5kVYlkGxm/l6jRrm8PypUCcztdckJ0cfeI0mHWL58OVlZWQB0dUWOPfHEEhYt\nWnIMn0JEZOTZsGEDGzZsOORYfX19zK6vYCQyyD5s2husYdWqW/p9vZ7trnNyFnDwYIia1mLs9CQ4\noR1SYO4Jc2lNaaV4czFXV12tkSKRDxENRVcAH3PO7et1ehvQAVwMPBZ9/inAccDz0ee8APxvM8vp\nsc5oIVAP7OIIbr/9dmbNmvXen8eMgVNPHdjnEREZSZYsWcKSJYf+smj79u3Mnj07JtdXu26RQfT+\ntLfryMlZQHJyDjk5CwgErqWoaCvl5eVHv0gvPdtd7917H3v3rqOxdQ9tE14ndWwCMyfOZEzKGE/3\nKhIZDszsbuBq4HNAs5lNiH6lAkRHie4D1prZAjObDfwKeM4592L0MkVEAtCvzewMM7sEWAXc5Zxr\n70892uRVRGRwKRiJDKLuaW9+f/4hx/3+mbS0QEVFxTFdd+nSz0PCdnZXfI03Gn9Aa/B1OprrmDF2\nBp3NnTS3NHu6V5HIMHED4AeeBsp7fBX0eM5y4HFgU4/nfbb7pHOuC7gM6CQyivQQ8ADQ7+FgbfIq\nIjK4NJVOZBD1nvbWraFhB+npMGnSpGO67tdu+hrvJpSSvcgPU6CuoY6OrR288PRmMi7IxZrbyaxO\n5sYrv6ZgJPIhnHNH/WWhc+4gcFP068OeU0okHA2IRoxERAaXRoxEBlHPaW81NcWEwzXU1BRTW3sv\nCxfO6Xd3uubmZr7zv75D8bZiwjPCNE1oosnXROqYVMjx0XmwC/d8LrwynYNv51BX2xinTyYisRYI\nRDZ4FRGRwaERI5FBtnLlCmANRUVrKS+PdKUrKJgTPd4/d/78Tu7/r/sJJ7ZD0OhIOIivzWhv7SRl\n0kQ6U5uZMubzTJ78ORobd1JcvJby8nLtFSQyDAQCsK93+wcREYkbBSORQZaZmcmqVbewbFk5FRUV\nx7yPUSgU4v5Hf0XLeB+EEsF1YZZIV1cndHXgqw7j60hl/PhPkJKSi5mP8vLIOiYFI5GhT2uMREQG\nl4KRiEeCweCAAkpJSQmVB/aTNnMm4eA2Ot9thmofNj4BV9pKx45GchM+yZgxecDA1zGJyODSGiMR\nkcGlYCQyTHV2duI6fbSlv0vauGm0//EA7fU1OF87tBjJBzOZfNoXCYdraGjYQW3tvRQU9H8dk4h4\nIxCAurrIZq8+rQgWEYk7BSOROCkrK6OysvKYp8odzcmnnUzCmcbBugNkHTiJ7PmzaN1bStOu18lK\nSWTJF67khRfup7z8/gGtYxIRbwQC4BzU10em1YmISHwpGInEWGNjI6tXr6WoaCstLZHmCgsXRkJJ\nZmZmTN6jy3XxROUTTD9rKu9saKUjXE9LSjNdBzvwd4xn6dJP8ZOf/Ijy8oGtYxIR73SHodpaBSMR\nkcGgYCQSY6tXr2Xjxj0EAisIBvNpaChh48ZCYA2rVvV7j8cPcM7xyKuPUFJVwi+/8gt+xxP84Q/P\n0dh4kDE5mVx66SXvjQwNdB2TiHgnEIg81tbC9One1iIiMhooGInEUFlZGUVFWwkEVry3gWvk0VFU\ntJZlywbeKvvx1x/n2X3PsvTspcydMpe5q+YOuMOdiAw948ZFHqurva1DRGS00HJOkRiqrKykpQX8\n/vxDjvv9M2lpibTKHohn9j7D468/zpUzruTcKee+dzwYDDJ79myFIpERZPJkSEuD117zuhIRkdFB\nwUgkhiZOnEh6OjQ0lBxyPBatsl+qeIn1O9Zz0QkXsXD6woGWKiJDnM8Hp58OO3d6XYmIyOigYCQS\nQ5MnT2bhwjnU1hZSU1NMOFxDTU0xtbX3snDhsbfK/sf+f7Bu+zpmT5pNQV4BZhbjykVkKMrPh5KS\noz9PREQGTmuMRGIs0vhgDUVFaykv55haZYdCIaqrq8nNzaUjrYO7X7yb6YHpLD176RFDUbxbhIvI\n4MrPh02btJeRiMhgUDASibHMzExWrbrlmBoiNDc3U7iukN/+6bfsb9xPVnYWyecm89E5H2XZnGUk\n+g7/V3YwWoSLyODLy4PmZti3D6ZN87oaEZGRTcFIJE6OpVX22tvXsubRNbRMbqErtwuyIOmVJD7S\n8RHSPp72oa+Ld4twEfFGfrSPS0mJgpGISLxpYF5kiHjrrbe47ee3UT+lno7TOnCnONx4R7glzH0P\n3kdVVdVhX/d+i/DryMlZQHJyDjk5CwgErqWoaCvl5eWD/ElEJFamTAG/X+uMREQGg4KRyBDQ3NzM\nVUuuotk1wzRw2Y6uhC5IAN9kH/vb9vP8888f9rXxbhEuIt4xi0ynU2c6EZH4UzASGQLW3L6GXe/s\ngi4iE1y7/2YauGaHa3ccOHDgsK+NZ4twEfGeOtOJiAwOBSMRj4VCIf7y/F9Izk2GqUATUA0chK6y\nLjpf7iS5K5lzzjnnsK+PV4twERka8vNh927o7PS6EhGRkU3NF0Q8Vl1dTYevg6QTkkjwJ9C5qxMa\ngVSgBazOmD9rPnl5eR96jVi0CI8FtQsXib28PDh4EN58E045xetqRERGLgUjEY9071UEkDA+gY7M\nDtIr02mvbyfcGKbrQBe0w6kTT2X9w+uPeK2BtAiPBbULF4mfnp3pFIxEROJHwUhkkHXvVVS8uZim\ncBOWYZT6S/E3+8lsz6R+Yj1NyU2072/nnLPP4fHfPU56enqfrn0sLcJjQe3CReInNxfGjYs0YLjy\nSq+rEREZubTGSGSQFa4rZNNzm0iYlUDOFTnsPWUvne2dnFF3Biemn8g0/zTOnHom3/nad/oViryi\nduHiJTP7pJl9tMefbzSzl81svZmN9bK2WDFTAwYRkcGgESORGOjr2ppQKETx5mJyz8kla3oWL4de\nJnt8NpOSJ0ED/Pi7P8Y5R25uLrm5uYP4CY5dd7vwYPCD7cLLyyPtwrXeSOLoP4CVAGY2E1gDrAUu\njD4u9a602MnPh+Jir6sQERnZFIxEBqC/a2uqq6tpCjcRnBSkpLoEw8gfnw9joHRLKc458vPzD/NO\nQ1fPduE5OQveO6524TJITgB2Rb//LPC4c+5/m9ks4AnvyoqtvDy45x4IhyE52etqRERGJk2lExmA\n7rU1Pt8KgsFf4fOtYOPGPdx225oPPDcUClFTU0NCVwIv73uZcGeY/Nx8UhJTqC+rJyMpY9iMEvWk\nduHisTDQPd/040BR9PtawO9JRXGQnw8dHfD6615XIiIycmnESOQYvb+2ZsV7IyWRR0dR0VqWLSsn\nGAwe0myhMdzIa4mv0fxaM3NOmUNCdgJVb1VRtaWKxfMXD8tgBEOnXbiMSs8Ca83sOeAc4Kro8VOA\ndz2rKsa6u/Xv3Pl+lzoREYktBSORY9TXtTXdzRbGzx1Pp7+TlOoUfM/5CO0MYScYGUkZLJ6/mOuv\nvd6jTzJwXrcLl1Ht68DdwGJgmXOuLHr8U8CTnlUVY4EATJoUacBw1VVHf76IiPTfkAhGZnYj8G1g\nIvAKcJNz7kVvqxI5sr6srenZbKFtYhvV9dWcOf1MfKk+Wv/eys1fv5kZM2YM25Gi3rxqFy6jl3Nu\nH3DZYY4v7++1zOx84F+B2cAk4DPOud/1OJ8B3AZcAYwD3gbucM7d0+M5KUSaPlwFpABPAV9zzlX1\nt57e1JlORCS+PF9jZGZXEekidAtwNpFg9JSZ5XhamIwoZWVlbNu2Laato4+2tiYhIYHnn3+e2uZa\n2gJtvFP/DtOypjExcyJZk7Not3bGjRs3YkKRiBfMbFa0G133n68ws/82s//fzPrbpiADeBm4EXCH\nOX87sBD4HHAa8FPgLjPrGcx+ClxKpBHEBUAQ+M9+1nFY+fmRqXQiIhIfQ2HEaDlwj3PuIQAzu4HI\nTeXLwGovC5Phr79d4/rrcGtrPvOZM3C0c9VXr6Il3MKb9W/i9jjOOPUMpvqnAgzrZgsiQ8w9wE+A\nHWZ2IvAo8BjwT0SaMvxLXy/knHuS6PQ7M7PDPOU84EHn3N+if77XzK4nsrbpcTPzE7l3/bNz7q/R\n6ywFdpvZOc65LcfyAbvl5cFPfwqtrZCWNpAriYjI4Xg6YmRmSUSmLPy5+5hzzgF/InIDEhmQ/nSN\nOxbda2see+weHnjgBzzyyO3s+cdO7v793exM20npyaW05rfSsqeF6q3VhJvDVO2JNFu4cN6FCkYi\nA3cKkVEeiIShZ5xznwO+RGTUJpaeBxaZWRDAzC4ETiYyXQ4i97NEDr2n7QH2EYN7Wn4+OAe7dw/0\nSiIicjheT6XLARKAUK/jISLrjUSO2ftd464jJ2cByck55OQsIBC4lqKirTGdVhcMBpk9ezbrH13P\nMzufIfXcVPzn+mnJbSEhO4Gs2iz2/2U/bz76Jp3bO4d9swWRIcR4/172cd7fu6iUyD0mlm4CdgPv\nmlk4+l43Oueei56fCISdcw29XheTe9rpp0ceNZ1ORCQ+hsJUusMxDj+/W6TP+to1LlZKSkr4/VO/\nxzKMtBPTqOuoIzktmXRfOl15XQTTg3zrS99i/vz5GikSiZ2twPfM7E/Ax4Bl0eMn8MFfug3UN4B5\nRJo97COyhuhuMyt3zv3lCK+LyT1tzBg4/ng1YBARiRevg1EN0AlM6HU8l6Pc0JYvX05WVtYhx5Ys\nWcKSJUtiWqAMX33pGhcL3fsU/fZPv+X10Osc7DxIy+4W0k5JY2zmWCzJqK2tJT0pfdiHorKyMior\nK9WOe5jYsGEDGzZsOORYfX29R9XEzb8AjwCfAX7knHsjenwxkalvMWFmqcCPgCuia5EASszsbCJd\nVf8CVALJZubvNWp01Hsa9O2+pgYMIjKaxfu+5mkwcs61m9k24GLgd/DegteLgTuO9Nrbb7+dWbNm\nxb9IGba6u8Zt3FgIOPz+mTQ07KC29l4KCubE7D/2hesK2fD0BpLzk8mYlMFB30EONh4k5ZkUuAga\n32ykc08nFy2+aNiGong3sZD4ONwvi7Zv387s2bM9qij2nHOvAjMPc+pfifziLVaSol+9R346eX8q\n3zagg8g97DEAMzsFOA544Whv0Jf7Wn4+PPpov+oWERkx4n1f83rECCL7PTwYDUhbiHSpSwce8LIo\nGRkO1zWuoGBO9PjAvfXWW6x7dB37j9+Pr9lHXVodXYldpDWkcXDXQfaH9uOaHRfkXcCKb8XmPb3Q\n3cQiEFhBMJhPQ0NJNHCuYdWqW7wuTwQzmw3MIBJcdjvnth/DNTKAk4hMfQM40czOBGqdc6Vm9lfg\nP8ysDdgLLAC+QLTznXOuwczuA9aa2QGgkcgv+Z4baEe6bnl5sHcvNDZGptaJiEjseB6MnHMbo3sW\n/TuRKXUvA5c456q9rUxGgu6uccuWlVNRURHzKWC/LPwl79a9i/9iPx3+DhLaEqASEi0RSzFOzDiR\ny6+8nG9/69ukp6fH7H0H0/tNLFa8NyUx8ugoKlrLsmXlmlYnnjGzXOA3RNYX1REJNVlmVkykbXZ/\n7iVzgGIi4coR2WMP4EEibbivAn4MPAwEiISjm51zhT2usZzIKNImIhu8PklkX6SYyI8umdy1C+bN\ni9VVRUQEhkAwAnDO3Q3c7XUdMnIFg8GY/+c9FArxyp5XSPenE+4IE3ZhAv4AvgQfzTXNnHzCyRSu\nLSQvL6/P1xyKa3gGu4mFSD/dCYwB8pxzuwHM7HQiYeYOoM8LT6N7D31ot1bnXBXwlaNc4yCR7nU3\n9fV9++O008DnizRgUDASEYmtIRGMRIaj6upq2hPayT4zm711e8kkk5RxKbTVtBHeE+ajn/pon0PR\nUF7DM1hNLESO0SeBj3eHIgDn3C4zuxEo8q6s+EhLg+nT1ZlORCQevN7HSGTYKSsrY9u2bXR2dtKV\n2UXr1FaCKUFSX0yl+Ylm2p9vZ3LSZJbdsOzoF4uK90a0A9HdxKK2tpCammLC4Rpqaoqprb2XhQtj\n18RC5Bj5gPbDHG9nhN7j1JlORCQ+NGIk0kfdozqbNj3JgQMNZExJoX1uDQmlCeSfnE/KjBRq3qih\n4fUGPnfx55g2bVqfrjsc1vDEu4mFyAD8BfiZmS1xzpUDmNlk4PbouREnLw/uu8/rKkRERh4FI5E+\nuvnm71F43wN0pLfgsrpgisO3K4lz7Ry6mrqoaa8hIymDyy6+jOuvvb7P1x0Oa3ji3cRCZAC+DvwW\neMfMSok0TTgOeBW4xsvC4iU/HyoqoLYWAgGvqxERGTkUjET6oKysjPseuJ/2yc0wNwk73odr6qTr\ntTDb332Zzc8/h8/nIzc3t997FQ2nNTzxaGIhMhDOuVJglpl9AjiNSFe6XcBrwL8B13lYXlx0d6bb\nuRPOP9/bWkRERpIROf9aJNYef/xx2lKaYU4ivpMNkiEhOwM7M5m2lGY2b95Mfn7+MW3gqjU8IgPn\nnPsf59ydzrk7nHN/AsZxlA5yw9XJJ0NiohowiIjEmkaMRPqgsrISUhwc10WXAzqS6KQLJhgkOyoq\nKgZ0fa3hEZG+Sk6GU09VAwYRkVhTMBLpgwsuuAD+DLR1QmIykb86nVARxsLGggULBnR9reERkf7I\nz9eIkYhIrCkYiaeG4oam3UKhENXV1YwfP57dCbtJGJdI5wsdMK0NJoQh1AUvOVLaMjnppJNi8p5a\nwyMifZGXB3/6EzgHZl5XIyIyMigYiSeG8oamzc3NFK4rpHhzMU3hJlqyW2iZ0MLEqnzqXm+j5a23\ncMmdWDiJ9I4TmTxl8pDoHCcympjZfx3lKdmDUohH5syB/fvhtddgxgyvqxERGRkUjMQT3RuaBgIr\nCAbzaWgoYePGQmANq1bd4mlthesK2fTcJnLPySU1kMrbFW+TuCcRX1kyM0//BWY+6uu3k5U1C+c6\n6epaO6Q6x4mMEvV9OP/QYBTihQULIr9Q+v3vFYxERGJFwUgG3VDe0DQUClG8uZjcc3JJPC6RPdV7\nmDZ5GlnJWewq2U1V1R3k5t7ElCnX0NCwg9raeykoUOc4kcHmnFvqdQ1eSkuDT3wCfvc7+M53vK5G\nRGRkULtuGXTdG5r6/R/c0LSlhQF3eBuI6upqmsJNJOQmsLtmN4G0ACcHTiZ7SjbBaZP4+Mcn0tW1\nlvLypXR1raWg4FR1jhMRTyxaBC+8ANXVXlciIjIyaMRIBt1Q3dA0FApRU1NDl6+Ll0tfZlzuOE4b\ndxpmRn1ZPf5UP6tW/YCOjo6jdo4byk0lRGRkuPTSSPOFJ56AL37R62pERIY/BSMZdN0bmkbWFDn8\n/pmeTkt76623+GXhL3nl9VdoTWxlV+ouOko6ODn/ZDoyO9hftp+qLVUsnr/4vQ1cP6zGodxUQkRG\nlgkTYN68yDojBSMRkYFTMBJPDIUNTbu7z617dB3v1r1LWnYaCeck4A/46fhrB/v+sY/wCWEykjJY\nPH8x1197/VGvOZSbSojIyHP55fDjH8PBg5CS4nU1IiLDm4KReGIobGhauK6QDU9vYP/x+/Ff7Ke5\nq5mDNQc5rfw0jvv0cbT+vZWbv34zM2bMeG+k6EiGclMJERmZFi2C734Xnn4aLrnE62pERIY3NV8Q\nTwWDQWbPnj3ogaG7+1zmGZn4cn20+9txWY7s7Gxq3qghOTOZdmtn3LhxfQpFMLSbSojIyJSXB9Om\nRbrTiYjIwCgYyajU3X0u57gcwqlhmtuayU7NJmN8Bh1dHdS8UUNGUkafQxEc2lSiJ6+bSojIyGUW\nGTX6/e8jjRhEROTYKRjJqDR+/HgykzMpqy4jYUwCSfVJdNR30PB2A+1N7TS83sCF8y7sVzDqbipR\nW1tITU0x4XANNTXF1Nbey8KF2utIROLj8suhtBReecXrSkREhjetMZJRacKECZww+wS27NvC5JzJ\nVNaFqHy1iq43O0muS2PsuHFcveTqfl93KDSVEJHR5YILwO+PjBqddZbX1YiIDF8KRjIq7azaScv0\nFi7quogXN2ylrqqDDM4gO/lcAtPms/ft33Hnnb/odye5odBUQkRGl+Rk+OQnI+uMvv99r6sRERm+\nFIxkVAiFQlRXV5Obm0trciv3bLuHM4NncsWcK7hiw1c4edwSJky4lJSUyNS5mpoJA+okFwwGFYhE\nZNAsWgTXXAPl5aB/ekREjo2CkYxo3XsVPfnMk9S11JHmT8PONi6cdyHXzrqWkldKaG9PIRi8nOTk\nnPde5/fPpLw80klOAUdEhrpPfQoSEuDxx+G667yuRkRkeFLzBRnRfvTjH/F/Hvk/bLWt/CP4D14c\n/yIv7X4Je9FISUxRJzkRGRECAfjoRyPrjERE5NgoGMmI1NjYyPLl/8rae35Gub+S2uw66sbV05Zx\nkLb6NtZvWk9VVZU6yYnIiHH55fCnP0FLi9eViIgMTwpGMiLdeutPuP+B/+ag7yCMNUj14ToMDqbR\nMc7H3tBedu/eDUQ6yRUUnEpX11rKy5fS1bWWgoJT1UlORIaVRYugrS0SjkREpP+0xkhGnLKyMh5e\nv4k2f3Mk+o/3wRigxuhqD5PUNoZwawM1NTWAOsmJyMhw8slw6qmR7nSLFnldjYjI8KMRIxlRmpub\nWXXrKkJt79B5aguc7qC1A2oSICEJKjvoKmkjIZyC3+8/5LXBYJDZs2crFImMUmZ2vpn9zszKzKzL\nzD4QL8xshpn91szqzKzJzDab2ZQe51PM7OdmVmNmjWa2ycz6vlP0AC1aFGnA0NU1WO8oIjJyKBjJ\niFK4rpBn9zyLjXXYjAQ42QflDp7vgGc74CWHVSQz3j+FvLw8r8sVkaElA3gZuBFwvU+a2XTgb8Au\n4AJgJrAKaOvxtJ8ClwKfjT4nCPxnXKvu4fLLIRSCF18crHcUERk5NJVORoxQKETx5mKmnj+Vd559\nhxZrwJeYSdf4Dkg6CFVdWDiZrMTJXPO5RRoZEpFDOOeeBJ4EMDM7zFNuBf7gnLu5x7G3u78xMz/w\nZeCfnXN/jR5bCuw2s3Occ1viVnzUeefBuHGR7nTz5sX73URERhaNGMmwU1ZWxrZt2ygvLz/keHV1\nNU3hJlJOSCH97HSSSn0kVLRiaWFo6SQh5GNi+lSW3bCY733v5g+5uojIB0WD0qXAP8zsSTMLmdnf\nzeyKHk+bTeQXjn/uPuCc2wPsA84bjDoTE+Gyy+DRRzWdTkSkvzRiJMNGY2Mjq1evpahoKy0tkJ4O\nCxfOYeXKFWRmZjJ+/Hh86T52lO1g+snTcfWOd//xLs0NzfjqffzTpf/Ev674V6ZPn+71RxGR4ScX\nyARWAt8FvgN8CvgvM1vgnPsbMBEIO+caer02FD03KK67Dh58EIqK4JOfHKx3FREZ/hSMZNhYvXot\nGzfuIRBYQTCYT0NDCRs3FtLU9EO+8pUv4hvjo/P0Tjr2dTA+eTyBiwIEJgcof6GcK6+8kn/73r/F\npI6ysjIqKyvVvU5kdOmeYfHfzrk7ot+/amYfAW4gsvbowxiHWbPU2/Lly8nKyjrk2JIlS1iyZEm/\nCj3vPDjrLPj5zxWMRGRk2bBhAxs2bDjkWH19fcyur2Akw0JZWRmPP/43kpP/iczMU0hOziE7ey6l\nZQ9y34b7eea1v9B4ciNTJ0zlq9O+yov/r707j6+iuv8//vpklSQECCEkARdwQVZlcakr1hZb/Wm1\nKhW17qgoaikq1bpja6UVF1QU91rFora21n41WrFaFxACCoorqJBAAgYSkhhCkvP749zIJWQly9zk\nvp+PxzzuvTNn5n7ucJnJ554zn1nyPqsXriY5Ppmzjz2biyZe1OoYmuqxEpEubQNQBayoM38FcGjo\n+TogwcxS6/QaZeB7jRp15513MmrUqFYHagaTJ8PEibByJQwc2OpNiohEhPp+LMrNzWX06NFtsn0l\nRhLxNm/ezJVX/oYVKz4jJuYZ1qz5F2lpIygt/4Aie5uaHqV8mvYp3aq60X1pd1IOS+Hhux6msLCQ\njIwMMjIar5Tb3B6ghnqs4A6mT7+xjT+1iEQS59xWM3sfGFRn0T7A16Hni/HJ09HA3wHMbB9gN+Dd\nDgoVgAkT4KqrYPZs+OMfO/KdRUQ6LyVGEtE2b97Mscf+jPffz6eysj9msdTUpPPNmheoyV6Jje6G\nDYjB4g2WQmVCJfMXzOeMCWcwbNiwJrfd3B6gvLw8cnIWkZY2lfT0sQChR0dOzkwmTcrXsDqRTs7M\nkoG98EPfAAaa2X5AkXNuNfBH4BkzewuYj7/G6P8BRwI450rM7BFgppltBDYD9wBvd0RFunBJSXD+\n+fDII3Dzzf61iIg0TlXpJKJdf/1NLFpURVzc7XTr9jTwK7ZsyacqcR01AypxA8qIS46hT98+JA9N\nZtPGTWzcvJHCwsImt13bAxQTM5Xs7MeIiZnKvHmfcvvtd+zQdt26dZSXQ2rq9slWaupwysth7dq1\nbfWRRSQ4Y4Al+J4fB9wB5AI3AzjnXsBfT3Q18CG+NPfPnXPhvUFTgH8BzwFvAPn4exp1uEmTYNMm\nX6FORESapsRIAtVQ6e3aZa+9tgSzCXTr9lOSknoTG78cuuVBt2LoXwOuioyUPiTGJZKQkUBFRQWx\n1SZpCIQAACAASURBVLHNGj7ne4AuJD19LAkJ6aSnjyUtbSI5OYt2iCczM5OkJCgpWb7d/JKSZSQl\nQVZWVut3hogEyjn3X+dcjHMuts50Xlibx51z+zjnkp1zo5xz/6qzjS3Oucucc+nOue7OuVOdc03/\nUtMOBg6EY4+FWbPANVn6QURENJROAtGcYWzr1q2jqiqB+Pg9qaoqoar6SVzWi8T1y6DKfQo9gM1Q\nuqWUbnt2o/TLUqo3VfPD43/YZGJU2wOUnb1jD1B+vu8BCh8a169fP8aNGxO6psiRmjqckpJlFBU9\nxPjxYzSMTkQi0uTJ8NOfwrvvwiGHBB2NiEhkU4+RBKI5w9gyMzPp0SOe7t3XUVm5hO/sOVyfSmqy\nNsBejoSvE0guT+a7gu/Y8L8NVLxXwRFDj+DKX1/Z5PvvTA/QtGlTGT9+EDU1M8nPP5eampmMHz+I\nadOmtn6HiIi0g3HjYK+94N57g45ERCTyqcdIOlxzCxnU9tI89dTfqKz+iOq4VbC1BhIcscWxDOkx\nhA3fbGDzus0M7DeQE045gam/nkpSM64y3pkeoJSUFKZPv5FJk/JZu3at7mMkIhEvJgYuuQSmTYOZ\nMyGzw24zKyLS+ajHSDpcSwoZTJ58MaXfvUNVjy9gj2oY6mAruG8cRZuKGH7UcPbfc38en/U41193\nfbOSolo72wOUnZ3N6NGjlRSJSKdwzjkQHw8PPRR0JCIikU09RtLhwoex1fYYQf3D2GbeOZONyRuJ\nPySe6n7VuFIHiyEmMYZ1n60jrTqNs445i6FDh7Y4jqZ6gJp7fyMRkUjWqxeceSY88AD85jc+SRIR\nkR0pMZIO19xhbAUFBby+8HXcIEfMnjHEx8RDLFQNrKJmcQ2uxDEyayQXTbyoVfFkZ2dvl/i05P5G\nIiKdwaWXwpw58MILcOqpQUcjIhKZNJROAtGcYWzr16+HXcB2N2q21pAYn0i37t1IGpBETEwMqfGp\nzb6mqCVacn8jEZHOYMQIOOIIFWEQEWmMeowkEM0pZJDWO42KPSpIiEugcm0lVb2riOseR+WqStwm\nx0H7H7RTQ+ga09zCECIinc2ll8IvfgHLlsHw4UFHIyISedRjJIFqqJCBc46cghxSd01l4PqBpG9O\np+arGsrfKaf6vWoG9xnMk0882ebxtKQwhIhIZ3LSSdCvH8yYEXQkIiKRSYmRRKQXPnmBd1e/y23j\nb+O8g8/jgLgDGFE6gv237M+vT/01C95ZQHp6epu/787c30hEpDOIj4drr4WnnoKPPgo6GhGRyKOh\ndBJxXl/1Oi9/8TKnDj2VIwYewRFXHMEZhWdQWFhIRkYGGRkZ37dt68pxO3N/IxGRzuKCC+CPf4Qb\nboDnnw86GhGRyKLESCLKovxFzPtoHj/e88f8aOCPvp9fNyFqz8pxvgDEHeTkzCQ/3297/PgxTd7f\nSEQk0iUkwE03+XsbLVoEY8YEHZGISORQYiQR49MNn/LYksc4IPsATh58cqNtayvHpaVNJTt7GCUl\ny0O9PHcwffqNrYqjOYUhREQ6qzPPhD/8Aa67Dl5+OehoREQihxIjCdQbb7zB0qVL6T+kP29Vv8Xe\nvffm7P3PxswaXKejKsfVvb+RiEhXEBsLt9wC48fDW2/B4YcHHZGISGRQYiSBWLVqFSecdAKfFXxG\ndXI1brgjPT6dt/7wFnExjX8tayvHZWfvWDkuP99XjlNCIyLSsJNPhpEjfTGGN9+ERn6LEhGJGqpK\nJ4E44aQT+Lj8Y/gRxE6IxXYz1i9fz8k/b3wIHahynIhIa8XEwK23wv/+B6+8EnQ0IiKRQYmRdLg3\n3niDzwo+I+6gOGL2jcESjeSsZBJGJfBZwWe8+eabja5fWzmuqGgOGzbMp7JyAxs2zKeo6CHGjVPl\nOBGR5vjpT+GQQ/y1Rs4FHY2ISPCUGEmHW7p0KdXx1djuRo2rITEukRiLIWG3BGriasjNzW1yG9Om\nTWX8+EHU1MwkP/9campmMn78IFWOExFpJjP4/e9h8WL4+9+DjkZEJHi6xkg6TEFBAevXr2fXXXeF\nAbC1bCvJycnEmM/PK7+pJKYqhlGjRjW5LVWOExFpvSOPhB//2Pca/exnvjCDiEi0UmIk7a6srIw5\nD8/h5TdeZmPpRrb220pCVgIV71VQuWclCbslUPlNJVsXbmVI3yEcccQRzd62KseJiLTOrbfCQQfB\n00/DL38ZdDQiIsFRYiTtbtZ9s3jwmQepiK9gS98tVMRW0G19N7p/3Z1NX23iu7jviKmKYUjfIbz0\nz5eCDldEJKoceCCceKK/8etpp0F8fNARiYgEQ4mRtKuCggKenPckJUklJByaQHVqNcmbk6n+tJr0\n7HTmXD+HVatWMWrUqBb1FImISNuZPh322w/uvhuuvDLoaEREgqHiC9KuVqxYQUFJAQkHJVCRVkHS\nLkn07t+blANSKCwppGfPnvzqV79SUiQiEqBhw+Cyy+DGG+Gbb4KORkQkGEqMpN1Vp1RTmlxKQmwC\nPRJ7YGaQDC5W9WFFRCLFLbdAz55w+eVBRyIiEgwlRtKu+g7oS+zwWKq/rWaXil1wVY6KTRWUfV5G\nZs9MBg8eHHSIIiICpKb6oXT/+IefRESijRIjaTdllWU8s/IZRuwzgj4f9aF0aSnrctdRsqSE1PxU\nzvr5WWRkZAQdpoiIhJx8sr/x62WXQWlp0NGIiHQsJUbSYnl5eSxevJj8/PwG21RWV3LvwnsprSzl\ntp/dRuzqBDa9VsHmf29l02sVWH4cp5x8SgdGLSIiTTGDe++F9ev90DoRkWiiqnTSbJs3b2bGjJnk\n5CyivBySkmDcuDFMmzaVlJSU79vVuBoeWvwQa0rWMPWQqfzy+PNYs7ofu8RfR5zblaqq1axZ/Rhn\nn30Bb731eoCfSERE6ho4EK6/Hm64wd/XaPjwoCMSEekYgfYYmdlXZlYTNlWb2dVBxiQNmzFjJvPm\nfUpMzFSysx8jJmYq8+Z9yu2330FBQQHLly+noKCApz58iuWFy7l4zMVs+GIDS5asISFhCikpZ7PL\nLj8kJeVsEhJ+xZIla8jNzQ36Y4mIAGBmh5vZP80sL3ROOqGRtg+G2lxeZ34vM3vKzIrNbKOZPWxm\nye0ffdu68krYZx+4+GKoqQk6GhGRjhF0j5EDrgMeAiw0b3Nw4UhD8vLyyMlZRFraVNLTxwKQnj6W\n6upynnjyKhZ89DZVMVWU9ioldmAst516G0MzhvKXnL9QVZVIcvIB220vMfFAysoS+fjjjxk1alQA\nn0hEZAfJwFLgUeD5hhqZ2YnAgUBePYufBvoCRwMJwOPAg8CZbRxru0pIgNmzYexYePRRuOCCoCMS\nEWl/kXCNUalzbr1zrjA0fRd0QLKjdevWUV4OqanDtptfvDmXDQlrqRxSScJPE1i/x3qKPytmyUtL\nANh3332Ji9vCli3vb7feli0LiYvbQnp6epPXK4mIdATn3MvOuRuccy+w7ce67ZhZP+Ae4HSgqs6y\nfYFjgPOdc4ucc+8AlwGnmVlm+0bf9o48Es4+G66+GgoLg45GRKT9RUJi9Bsz22BmuWZ2pZnFBh1Q\nNGlOIQWAzMxMkpKgpGT59/O2bCmgsOzfJA5KIGnvJL6p+IY9++/JPkP2Yf6C+RQWFjJmzBhGjuxP\nZeWdlJW9QFVVPmVlL1BZeRdpaTXceON9nHPOTZx00kVcf/3NlKoMkohEKDMz4M/ADOfcinqa/ADY\n6JxbEjbvNfzoiIM6IMQ298c/+scrrww2DhGRjhD0ULq7gVygCDgE+AOQCegQ3M6aW0ihVr9+/Rg3\nbgzz5s0BHKmpwykoeIkt7kt2HZLG16Vfk56UzsBeA6lMqGT1wtUUFhaSkZHBs88+zamnns6SJVdT\nVpZIXNwWMjNrSEjYj5iYy8jOHkZJyfLQtu9g+vQbO3x/iIg0w2+ASufcvQ0szwS261txzlWbWVFo\nWafTpw/86U9w/vlw0kl+EhHpqto8MTKz24BpjTRxwGDn3GfOubvC5i83s63AA2Z2jXNua2PvM2XK\nFHr06LHdvAkTJjBhwoSdDT2q1BZSSEub2uzEZNq0qcAd5OTMJD8f4uO3kLlrClu7byEtsS+Deg/C\nzCjOKyY5Pvn7exRlZmby1luvk5uby8cff0x6ejo33ngfMTGXbXe9EjhycmYyaVI+2dnZHbEbRLq0\nuXPnMnfu3O3mFRcXBxRN52Zmo4HLgZE7szr+3NeoSD2vnXsuvPiiv87ogAOgf/9AwxGRKNbe5zVz\nrsljdcs2aNYb6N1Es5XOuaq6M81sCLAM2Nc593kD2x8FLF68eLEu2t9JeXl5/PznFxMTs62QAsCG\nDfOpqZnJ3//+YKOJyQcffMAnn3xCvz37ccNrN/DF6i/Yf4/9SeufRnFeMYULCznl0FOYcsWUetdf\nvHgx55xzE9nZj5GQkP79/MrKDeTnn8vjj9/E6NGj2+zzisg2ubm5tf+/RjvnVBayAWZWA5zonPtn\n6PUVwB1sn+DEAjXAN865gWZ2LvAn51zvsO3EAhXAKc65fzTwXhF/Xvv2W9hvP9h7b3jtNYjVoHcR\niRBteV5r8x4j59y3wLc7ufpI/ElGl3m2o9pCCtnZ2xdSSE0dTn4+rF27tt7EqKysjDkPz2H+gvkU\nby1mXeY6+mX24/zdz2fxksWsXria5PhkTjn0FC6aeFGD7x9+vVJ4YlZSsoykJMjKymqzzyoi0kb+\nDLxaZ15OaP5jodfvAj3NbGTYdUZH43uMFnRIlO2kd2948kk4+mi4/Xa49tqgIxIRaXuBXWNkZgfj\nL0adjy/RfQgwE3jSOaexHu1oZxOTOQ/P4bm3nyP9gHTKksqo3lTN5uWbST04lYfvevj7a4pqh9A1\npL7rlUpKllFU9BDjx4/RMDoRCUTofkN7sa0i3UAz2w8ocs6tBjbWab8VWFc7wsE594mZvQI8ZGaT\n8OW6ZwFznXPrOupztJejjoJrrvE3fj36aDioU5aTEBFpWJBV6bYApwFvAMuBa/DDFBruapA2UZuY\nFBXNYcOG+VRWbmDDhvkUFT3EuHH1JyYFBQXMXzCfPgf04dve31JhFRww6AD6j+7P/AXzARg2bFiT\nSVGtadOmMn78IGpqZpKffy41NTMZP35Q6Dqm1mtutT0RkTBjgCXAYvyQuTvwBYJubqB9fWPRTwc+\nwVej+xfwJl3ovHbTTTBmDEyYACUlQUcjItK2AusxCg0z+EFQ7x/t6hZSSEqC8ePHNJiYrF+/ns2V\nm6lKraLouyKG9hlKamIqif0SWb1gNcuWLaNnz55kZWU1q8cnJSWF6dNvZNKkfNauXdvs9ZrS0mp7\nIiK1nHP/pQU/GDrnBtYzbxOd7GauLREfD08/DfvvD5dcAn/5S9ARiYi0naDLdUtAWpqY9OnTh/Je\n5RRuKGTEwBGkdUsD4Nuvv2X1l2u46qrb2bo1scWJSHZ2dpsOnduZansiItJ8AwfC7Nlw5pnwk5/4\nRxGRriASbvAqAcrOzmb06NFNJiefVXxGzMAYun3ZjZi8GLaUbqHw00KWvvABm/KSSUy8luzsx4iJ\nmcq8eZ9y++13dNAn2CYvL4+cnEWkpV1IevpYEhLSSU8fS1raRHJyFmlYnYhIGznjDPjlL2HSJPjy\ny6CjERFpG0qMpEkfrPuAp5Y9xUXjLuKCERdQnVvN6r+tpuydMmxdd/bY/fcRkYjUVttLTd2x2l55\nua+2JyIibeO++6BvXzj1VCgrCzoaEZHW01A6adSXRV/yUO5DjMwcyVmjziJmdAxnFp5JYWEha9eu\n5de/vodevcZst05TZb/bi8qAi4h0nO7d4W9/g0MOgbPOgmefhRj93CoinZgOYdKg/M353LvwXgb0\nHMB5I88jxvzXJSMjg2HDhjFkyJDvE5FwQSUiO1NtT0REdt6IETB3Lvz973DddUFHIyLSOkqMpF4b\nv9vIPQvuoVe3Xkw6YBLxsfE7tInERKS9y4CLiMj2jj8eZsyA226DP/856GhERHaehtLJDsq3lnPP\ngnswjMsPupyk+KQG27a07Hd7a68y4CIi0rCpU2HFCpg40VetO+ywoCMSEWk5JUayna3VW7n//fsp\n3lLMVYdcRc9dejbaPlITkbYuAy4iIg0z8yW8v/wSTjoJFi6EAQOCjkpEpGU0lE6+V+NqeGTJI3y1\n6SsmHziZrO7Nv0aouWW/RUSka0pIgOefhx49/PC6kpKgIxIRaRklRlGuoKCA5cuXU1BQwNxlc/lg\n3QdcOPpCBvba4YbuIiIijerdG158EdasgdNOg6qqoCMSEWk+DaWLUmVlZcx5eA7zF8yntLKUsl5l\nxAyM4daTb2VE3xFBhyciIp3U4MEwbx4ce6y/AeyDD6qMt4h0DjpURak5D8/hubefI3ZULInHJlK4\nRyHFnxfz4f99GHRoIiLSyY0bB48+Co88ApMng3NBRyQi0jT1GEWhgoIC5i+YT8aBGcTuGsvXG75m\nYP+BdE/ozvwF8zmj8AwyMjKCDlNERDqxs86CykpfqS4hAe680xdpEBGJVEqMotD69esprSylZ5+e\nrPh2Bb279WbPXntSmVDJ6oWrKSwsVGIkIiKtdsEFsHUrXHIJxMf7+x0pORKRSKXEKAr16dOHuG5x\nfLjmQ9L7prNv+r6YGcV5xSTHJyspEhGRNjNpku85+tWvfM/RrbcqORKRyKTEKAol9kikemg1lasr\n6ZPQh63JWynOK6ZwYSGnHHqKEiMREWlTV1zhe46uugoSE+GGG4KOSERkR0qMokz51nLuWXAP+++3\nPz9M/CEL3l/A6oWrSY5P5pRDT+GiiRcFHaKIiHRBV17pk6Nrr/XD6q65JuiIRES2p8Qoimyt3srs\n92ez8buNXH3Y1WT9NIvCwsLvrylST5GIiLSna67xw+quvRZKSzWsTkQiixKjKFHjanh0yaOs2rSK\nKQdPIat7FoASIhER6VA33ADJyX5Y3erV8PDD/tojEZGgKTGKAs45/rr8ryxZt4RJYyaxZ9qeQYck\nIiJRyswPq+vfH84+G/Lz4fnnoUePoCMTkWinG7xGgZe/eJk3vnqDM4afwX6Z+wUdjoiICKedBjk5\nsHgxHHEE5OUFHZGIRDslRl3cO6vf4YVPXuD4Qcdz+O6HBx2OiIjI9448Ev73P9i4EQ4+GJYvDzoi\nEYlmSoy6sGUFy3jygyc5fPfDOW7v44IOR0REZAdDh8J770Hv3nDYYTB/ftARiUi0UmLURa3auIoH\nFz/I8L7DOX346ZjK/oiISITKzoY334QDD4Rx42DmTHAu6KhEJNooMeqCCkoLmLVwFrv12I2JoyYS\nY/pnFhGRyJaaCi+9BFOmwNSp8POfw6ZNQUclItFEfzF3MZsqNnH3grtJTUzl0gMuJT42PuiQRERE\nmiU+HmbMgH/8A954A0aN8sUZREQ6ghKjLuS7rd8xa8EsqmuqueKgK0hOSA46JBERkRY74QTIzfXX\nHR1yCMyeraF1ItL+lBh1EVU1Vdz//v0UfVfEFQdfQa9uvYIOSUSkUzGzw83sn2aWZ2Y1ZnZC2LI4\nM7vdzD40s9JQmyfMLKvONnqZ2VNmVmxmG83sYTPTr1Q7YcAAX7Huwgvhkkvg9NNh8+agoxKRrkyJ\nURfgnOPRJY+ycuNKLjngErK7ZwcdkohIZ5QMLAUuBer2TyQB+wM3AyOBk4BBwD/qtHsaGAwcDRwH\nHAE82H4hd22JiTBrFjzzDPzrX7DffvD660FHJSJdlRKjTs45x18/+iu5a3O5YNQF7N1776BDEhHp\nlJxzLzvnbnDOvQBYnWUlzrljnHPPO+c+d84tBCYDo82sP4CZDQaOAc53zi1yzr0DXAacZmaZHfxx\nupRf/AKWLIHddoOjj/a9SMXFQUclIl2NEqNOLufLHOavms/pw09nZNbIoMMREYkmPfE9S7W10w4G\nNjrnloS1eS3U5qAOjq3L2Wsv31s0ezbMnevvf/TSS0FHJSJdiRKjTuzd1e/ytxV/47h9juOI3Y8I\nOhwRkahhZonAH4CnnXOlodmZQGF4O+dcNVAUWiatFBMDF18MH30Ew4fD//t/cOaZ8O23QUcmIl2B\nEqNOannhcv78wZ85bLfDOH6f44MOJ1B5eXksXryY/Pz8oEMRkShgZnHAs/ieoEuaswo7XrMkrbDb\nbvDvf8MTT/jHwYP985qaoCMTkc4sLugApOW+2vQVDy56kGEZwzhjxBmYWdMrdUGbN29mxoyZ5OQs\norwckpJg3LgxTJs2lZSUlKDDE5EuKCwp2hX4YVhvEcA6IKNO+1igF1DQ1LanTJlCjx49tps3YcIE\nJkyY0NqwuyQzOOssGDcOfvUrOOccuOcemDkTjjwy6OhEpD3MnTuXuXPnbjevuA0vOFRi1MkUlBYw\na8Es+qf2Z+LoicRY9Hb6zZgxk3nzPiUtbSrZ2cMoKVnOvHlzgDuYPv3GoMMTkS4mLCkaCBzlnNtY\np8m7QE8zGxl2ndHR+B6jBU1t/84772TUqFFtGXJUyMz0VesuvxymTIGxY+HEE/2NYvdWPSKRLqW+\nH4tyc3MZPXp0m2w/ev+q7oRKtpRw94K7SUlIYfKBk0mITQg6pMDk5eWRk7OItLQLSU8fS0JCOunp\nY0lLm0hOziINqxORFjOzZDPbz8z2D80aGHq9a6jn53lgFHAmEG9mfUNTPIBz7hPgFeAhMzvAzA4F\nZgFznXPrAvhIUeWQQ+Ddd+Hpp/3NYYcM8YlSUVHQkYlIZ6HEqJOoqKrgngX3UF1TzeUHXU5yQnTf\nL3DdunWUl0Nq6rDt5qemDqe8HNauXRtQZCLSiY0BlgCL8dcE3QHk4u9d1B84PvS4FMgH1oYefxC2\njdOBT/DV6P4FvAlc1DHhS0wMTJgAn3wCt9wCDz/sq9lNnw6bNjW9vohENyVGnUBVTRWz35/NhvIN\nXH7Q5fRO6h10SIHLzMwkKQlKSpZvN7+kZBlJSZCVldXAmiIi9XPO/dc5F+Oci60zneec+7qeZbWv\n3wzbxibn3JnOuR7OuV7OuYnOufIgP1c06tYNrrkGvvjCV637/e9h993ht7+F9euDjk5EIpUSowjn\nnOPxpY/zRdEXXHLAJfRL7Rd0SBGhX79+jBs3hqKiOWzYMJ/Kyg1s2DCfoqKHGDduDNnZ2UGHKCIi\nAevb1xdkWLUKLroI7r4b9tgDpk4FDSwQkbqUGEUw5xzPfvwsi/IXcf6o89mn9z5BhxRRpk2byvjx\ng6ipmUl+/rnU1Mxk/PhBTJs2NejQREQkgmRm+mIMX3/tk6JHHoEBA7bdE0lEBFSVLqK9uvJV/rPy\nP0wYPoFRWapUVFdKSgrTp9/IpEn5rF27lqysLPUUiYhIg3r39tceTZ0K990Hs2bBgw/68t6XXAIn\nnQTx8UFHKSJBUY9RhHpvzXs8//HzHLv3sYzdY2zQ4US07OxsRo8eraRIRESapUcPuPZa34P0zDPg\nHPziF/46pBtvhLy8oCMUkSAoMYpAHxV+xBNLn+DQ3Q7lhEEnBB2OiIhIl5SQ4BOi//4XPvwQfvYz\nuOMOnyCdeCI89xxUVAQdpYh0FCVGEebrTV/z4OIHGZoxlDNHnImZBR2SiIhIlzd8OMye7XuL7rrL\nP556qr8+6YIL4I03oKYm6ChFpD0pMYoghWWFzFo4i+zu2UwcNZEY0z9PuLy8PBYvXqybt4qISLvp\n0QMmT4b33/f3Q7r8cnj9dTjqKF/R7je/gUWL/PA7EelaVHwhQpRsKeHu9+4mKT6JyQdOJjEuMeiQ\nIsbmzZuZMWMmOTmLKC+HpCQYN24M06ZNJSUlJejwRESkixo0yBdruPlmePdd+Mtf4KGH4PbboV8/\nOOEEP+Ru7Fg/LE9EOjd1SUSAiqoKZi2YxdaarVxx0BWkJOiP/XAzZsxk3rxPiYmZSnb2Y8TETGXe\nvE+5/fY7gg5NRESigBkccgjcfz8UFPgepFNOgf/7PzjmGOjTB047DZ5+WjeQFenMlBgFrKqmigcW\nPUBhWSGXH3Q5vZN6Bx1SRMnLyyMnZxFpaReSnj6WhIR00tPHkpY2kZycRRpWJyIiHSouzg+ru+su\nWLkSPvjAl//+/HM44wzIyICRI+Gqq+CVV6C8POiIRaS5lBgFyDnHE0uf4PNvP+eSAy6hf2r/oEOK\nOOvWraO8HFJTh203PzV1OOXlsFa3LhcRkYCYwYgRcMMNsHixL9jw5JOw336+9+gnP4FevXwidcst\n8J//QGlp0FGLSEOUGAXo+RXP837++5w78lwGpQ8KOpyIlJmZSVISlJQs325+SckykpIgKysroMhE\nRES2l50NZ54Jjz8Oa9bAihW+/HdqKtx5J/zoR9CzJ4weDZdd5u+htHp10FGLSC0VXwjIq1++yqtf\nvsppw05jTPaYoMOJWP369WPcuDHMmzcHcKSmDqekZBlFRQ8xfvwY3dRVREQikhnsu6+fJk/2pb5X\nrIB33oG334aXX4Z77/Vts7Jg1Cg/jR7tH/v399sQkY6jxCgAC/MW8tzHz/GTvX7CUQOOCjqciDdt\n2lTgDnJyZpKf76vSjR8/JjRfREQk8sXEwNChfpo40c8rKPCJ0qJFkJsLDzywrXhDnz4+QRoxYtt6\ngwdDcnJwn0Gkq1Ni1MFWrF/B40sf5we7/oAT9z0x6HA6hZSUFKZPv5FJk/JZu3YtWVlZ6ikSEZFO\nr29fOOkkP4G/N1Jenk+SFi/2j88+C3/8o19uBgMGwLBhMGQI7LOPn/be2ydS6mESaR0lRh3IOceL\nn73I4PTB/HLELzEdwVokOztbCZGIiHRZZn4IXf/+/h5JtUpL4eOPYfly+Ogj//iXv/jrmGr16OET\npH32gb328jej3WMPn0j17++r6YlI4/TfpAOZGZcdeBkxFkNsTGzQ4YiIiEgnkJICBx7op3Dl5fDl\nl/DZZ75c+Oef++fz50N40dbYWJ8cDRgAu+7qn/frty0J69fPlxmPUUkuiXJKjDpYt/huQYcgzJRO\ngQAAE39JREFUIiIiXUBSEgwf7qe6Kirgm2/gq6/8tGqVn1auhDffhPx82Lp1W/u4OMjM9FPfvtue\n177u08dP6enQu7d6oKRr0tdaREREpIvZZZdt1yDVp6bGF3pYs8Zf17RmDaxbt2368EN49VX/vLJy\nx/V79fKJUu/ekJbmX6elbf+8Z08/xK/2sUcP6N5dPVMSuZQYiYiIiESZmBjfE9S3ry8R3hDnYNMm\n2LDBJ1K1j7XPN2yAjRt9r9SSJVBU5KctW+rfnpm/r1P37g1PKSm++l7tFP46KQm6dfOPtVO3bn6K\n1VUK0kpKjERERESkXma+B6hXL1/cobnKy6G42E+bNm17Xvt68+ZtU0mJf1y/3j+WlW2bSkt9ctYc\n8fG+p2yXXXyiVPs8MXHbY+1U+zohwU/hz2un+Phtj3Wfx8Xt+DwuruEpNnbbY/jzuDifpKoeV2RQ\nYiQiIiIibaq2Nycrq3Xbcc5fL1Va6pOt777b/rF2qqjw88Ifa59v2bJtqqjwCVdtr1Zl5Y5T7fyt\nW/1UVdU2+6QxMTHbkqbaKXxe7fP6Hmunuq9rE66GXtc+rzuv7vy68xqaGloODa9Td1n467rP99zT\n3yy5PSkxEhEREZGIZLZtqFxQnNuWJFVW+kQpPGmq+9jQVF3d8GNDU02Nn2qf132sb6qu9jE3ND98\nWd3n9S2rnV/f66aW1e6/+qa6y8Jf1/e8sSGfbUWJkYiIiIhIA8y2Da9LTg46GmlPqgsiIiIiIiJR\nT4mRiIiIiIhEPSVGIiIiIiIS9ZQYiYiIiIhI1Gu3xMjMrjWzt82szMyKGmizq5m9FGqzzsxmmFmX\nT9bmzp0bdAitoviDpfiD1xU+g+zIzA43s3+aWZ6Z1ZjZCfW0ucXM8s2s3MxeNbO96izvZWZPmVmx\nmW00s4fNTJdrt4D+f21P+2Mb7YtttC/aR3smIfHAPGB2fQtDCdC/8ZXxDgbOBs4BbmnHmCJCZ/8y\nK/5gKf7gdYXPIPVKBpYClwI73FLSzKYBk4GLgAOBMuAVM0sIa/Y0MBg4GjgOOAJ4sH3D7lr0/2t7\n2h/baF9so33RPtqtXLdz7mYAMzu7gSbHAPsCRznnNgDLzOx64A9mdpNzrgNupyUiIuI5514GXgYw\nq/c+9FcA051zL4banAUUACcC88xsMP7cNto5tyTU5jLgJTO70jm3rgM+hoiI7KQgh60dDCwLJUW1\nXgF6AEODCUlERGRHZjYAyAT+UzvPOVcCLAB+EJp1MLCxNikKeQ3f+3RQB4UqIiI7KcjEKBP/S1u4\ngrBlIiIikSITn+DUd97KDGtTGL7QOVcNFKHzmohIxGvRUDozuw2Y1kgTBwx2zn3WqqjqGdsdZheA\nFStWtPItglNcXExubm7QYew0xR8sxR+8zvwZwo6duwQZRxdiNH7Oak6bTn9ea0ud+f9Xe9D+2Eb7\nYhvti23a8rxmzjV1PA9rbNYb6N1Es5Xh1weFrjG60zmXVmdbNwPHO+dGhc3bA1gJjHTOfdBADKcD\nTzU7aBERqc8Zzrmngw4iUplZDXCic+6fodcDgC+B/Z1zH4a1ewNY4pybYmbnAn9yzvUOWx4LVACn\nOOf+0cB76bwmItJ6rT6vtajHyDn3LfBta94wzLvAtWaWHnad0TigGPi4kfVeAc4AvsKfbEREpPl2\nAfbAH0ulmZxzq8xsHb7a3IcAZpaKv3bovlCzd4GeZjYy7Dqjo/E9Rgsa2bzOayIiO6/Nzmst6jFq\n0YbNdgXSgJ8BU/ElSwG+cM6Vhcp1LwHy8cPzsoA/A3Occ9e3S1AiIiINCN1vaC98IpML/BqYDxQ5\n51ab2dX489U5+CRmOr5Y0FDnXGVoG/8GMoBJQALwKLDQOffLDv0wIiLSYu2ZGD0GnFXPoqOcc2+G\n2uyKv8/RWPz9IB4HrnHO1bRLUCIiIg0wsyPxiVDdE+MTzrnzQm1uAi4EegJvAZc6574I20ZP4F7g\neKAGeA64wjlX3u4fQEREWqXdEiMREREREZHOIshy3SIiIiIiIhFBiZGIiIiIiES9Tp8YmdlxZvae\nmZWbWZGZ/S3omFrKzBLMbKmZ1ZjZiKDjaQ4z293MHjazlaF9/7mZ3WRm8UHH1hgzu9TMVpnZd6Hv\nzQFBx9QcZnaNmS00sxIzKzCzv5vZPkHHtbNCn6fGzGYGHUtzmVm2mT1pZhtC3/kPzGxU02sGz8xi\nzGx62P/XL8zsuqDjks57TGotMzvczP5pZnmhY8EJ9bS5xczyQ9/ZV81sryBibW/NOb6bWaKZ3Rc6\n/mw2s+fMLCOomNuLmV0cOrYWh6Z3zOwnYcujYj/Up77zZjTtDzO7MfT5w6ePw5a3yb7o1ImRmZ2M\nr2T3CDAcOATojPflmAGsoembBEaSffGVmyYCQ4ApwMXA74IMqjFm9gvgDuBGYCTwAfCKmaUHGljz\nHA7MwpcG/hEQD+SYWbdAo9oJoT/8JuL3f6cQuqD+bWALcAwwGF9tc2OQcbXAb4CLgEvw/3evBq42\ns8mBRhXlOvkxqbWSgaXApdRz7jOzacBk/Pf2QHyBplfMLKEjg+wgzTm+3wUcB5yMr/KbDTzfwXF2\nhNX4yo+jQ9PrwD/MbHBoebTsh+00ct6Mtv2xHOgLZIamw8KWtc2+cM51ygmIxf8HOifoWFr5OX4K\nfIT/Y6UGGBF0TK34LFfiy7EHHksD8b0H3B322vAJ6dVBx7YTnyU99H05LOhYWhh3CvAp8EN89a+Z\nQcfUzLj/APw36DhaEf+LwEN15j0H/Dno2KJ56krHpFbuhxrghDrz8oEpYa9Tge+A8UHH2wH7Y7vj\ne+izbwFOCmszKNTmwKDj7YD98S1wbrTuh4bOm9G2P/A/IOU2sKzN9kVn7jEahc8GMbPcUHf7v81s\nSMBxNZuZ9QXmAGfiD/idXU+gKOgg6hMa4jca+E/tPOf/57wG/CCouFqhJ/5X1ojc3424D3jROfd6\n0IG00PHAIjObFxrqkmtmFwQdVAu8AxxtZnsDmNl+wKHAvwONKop1wWNSmzGzAfhfg8P3TQn+JrnR\nsG/qHt9HA3Fsvz8+Bb6hC++P0BDg04Ak/M2To3I/0PB5cwzRtz/2Dg2//dLM/mL+tj/Qht+NuDYL\nteMNxP+6diN+GNfX+B6L/5rZ3s65TUEG10yPAfc755aY2e5BB9MaobHfk/E3RIxE6fhexoI68wvw\nvyp0GmZm+C7j/znnPm6qfaQIneD2xx/MO5uB+Bt23oEfLnoQcI+ZVTjn/hJoZM3zB/wvap+YWTV+\nGPVvnXPPBBtWVOsyx6R2kIlPDOrbN5kdH07HaeD4nglUhpLDcF1yf5jZMHwitAuwGd8L8ImZjSSK\n9gM0ed7sS3Ttj/fwN9f+FMgCbgLeDH1f2uz/SMQlRmZ2G358aUMcfnx/bW/Xrc65F0LrnosfhnAq\n8FB7xtmQFsT/E6A7cHvtqu0cWrM0N37n3Gdh6/QD/g/4q3Pu0XYOsa0ZnevaLoD78dd1HRp0IM1l\nZv3xJ/sfO+e2Bh3PTogBFjrnrg+9/sDMhuKTpc6QGP0COB04DfgYf6K928zynXNPBhqZ1NUZj0kd\nJRr2Te3x/bCmGtJ198cnwH74nrOTgT+b2RGNtO+S+6EV580uuT+cc6+EvVxuZgvxnSLjgYoGVmvx\nvoi4xAj4E74npTErCQ2jA1bUznTOVZrZSmC3doqtOZoT/yrgKOBgYIv/geh7i8zsKefcue0UX1Oa\nu/8BX6kLf3Hk/5xzF7VnYK20AajG/8ISLoMdf5WMWGZ2L3AscLhzbm3Q8bTAaKAPsNi2feFjgSNC\nBQASQ8OIItVawo41ISuAnwcQy86YAfzeOfds6PVHZrYHcA2gxCgYXeKY1E7W4f+g6cv2+yIDWBJI\nRB2gzvE9P2zROiDBzFLr/CLeJb8rzrkqtv2dkWtmBwJXAPOIov1A0+fNnwCJUbQ/tuOcKzazz4C9\n8EOQ2+S7EXGJkXPuW/yFdo0ys8X4C60G4cfP147Z3gOfQQaiBfFfBvw2bFY28Ao+813YPtE1rbnx\nw/c9Ra8D7wPntWdcreWc2xr6zhwN/BO+H7JwNHBPkLE1V+ik+TPgSOfcN0HH00Kv4StHhnscn1z8\nIcKTIvAV6eoObxpEgMeaFkpix1/NaujklUk7s65wTGovzrlVZrYOvy8+BDCzVPwQ1vuCjK29NHF8\nXwxU4ffH30Pt98H/CPxuR8YZkBggkejbD42eN4E8YCvRsz+2Y2YpwJ7AE7ThdyPiEqPmcs5tNrMH\ngJvNbA3+D5Sr8Sf/ZxtdOQI459aEvzazMvwvZCvr/FIUkcwsC3gD+Aq/3zNqf9BwzkXqLxUzgSdC\nf4wsxF+bloQ/0EQ0M7sfmACcAJSFCncAFDvnGupCjhjOuTL8EK7vhb7z3zrn6vbERKI7gbfN7Br8\nr5YHARfgy6d2Bi8CvzWz1fgqmKPw3/+HA41KOu0xqbXMLBn/S2/tL+EDQ0VBipxzq/FDiK4zsy/w\n55np+KHy/wgg3HbV1PHdOVdiZo8AM81sI/66m3uAt51zgf2Q2h7M7Hf4ofmr8ZcbnAEcCYyLpv0A\nzTtvRtP+MLM/4s9lXwP9gJvxydAzbfnd6LSJUciV+Gz5z0A3fMWaHzrnigONaudF+q/m4cbhL0gf\niD+AwbaxnLFBBdUY59y80P1BbsEP0VgKHOOcWx9sZM1yMX7fvlFn/rn4739n1Gm+7865RWZ2Ev5X\nuuvxw2Gv6ETFCybj/7C8Dz+0IB+YHZonAenkx6TWGoMvPexC0x2h+U8A5znnZphZEvAg/lqTt4Cf\nOucqgwi2nTXn+D4FP/TyOXzvycv4e0B1NX3xnzkLKMb3GI4Lq8gWLfuhIXXPm9G0P/rj71XaG1gP\n/A84ODTSCdpoX1jkj2ARERERERFpXxpfLiIiIiIiUU+JkYiIiIiIRD0lRiIiIiIiEvWUGImIiIiI\nSNRTYiQiIiIiIlFPiZGIiIiIiEQ9JUYiIiIiIhL1lBiJiIiIiEjUU2IkIiIiIiJRT4mRiIiISCdl\nZmvN7MIWtD/GzKrNLKE94xLpjJQYiYiIiLQTM6sJJSI19UzVZnZDK99iGPBEC9r/B8hyzlW28n13\nWig5q1FyJpEmLugARERERLqwzLDnpwE3A/sAFppXWt9KZhbrnKtuauPOuW9bEoxzrgoobMk67cAA\nx7Z9IBIR1GMkIiIi0k6cc4W1E1DsZ7n1YfPLw3pQfmxmS8xsCzDazAaZ2T/NrMDMSszsXTM7Mnz7\n4UPpzCwxtJ2zzOxFMyszs0/M7Cdh7bfrrTGzi0LbOC7UtiS0bu+wdeLNbLaZFZtZoZndYmZzzezp\nhj63mQ00s5fMbKOZlZrZUjP7oZkNAv4davZdqNfs/tA6MWZ2g5mtCsW+2MxOqCf2Y8xsmZl9Z2b/\nC22z0fdtxT+hRBElRiIiIiKR4ffAr4DBwCdACvACMBYYBfwXeNHM+jaxnZuAx4DhwHzgaTNLCVvu\n6rTvCVwK/CL0XoOAP4QtvwE4CZgAHA5kAz9tIoY5QDVwSCiO64DvgM+A00NtdgOygKtDr28GTgbO\nA4YC9wN/NbMD62z7dmAycACwGfinmdX2PjX0viJN0lA6ERERkeA54Brn3H/D5i0OTbV+Y2YnA8cB\njzayrTnOub8BmNm1wEX4xOrNBtonAOc759aG1pkNXBa2/FLgt865f4eWX0zTidGuwMPOuRWh16tq\nF5jZxtDTwtprncwsGZgK/MA590Fo+SNmNha4EFgYtu3raveTmZ0FrMbvk3819r4iTVGPkYiIiEhk\nCE+CMLNUM7vLzFaEhoZtBvbA97Q0ZlntE+fcRqASyGikfVFtUhSytra9mWXge5TeD9tmFbC0iRju\nAn5nZm+GhscNaaL9IGAX4C0z21w7AacCe4a1c8B7YbGsB1bie9l25n1FvqfESERERCQylNV5fQ9w\nDH6o2WHAfsDn+B6exmyt89rR+N98jbW3sHnhGi2c4JybjU9onsb3Vi0xswsaWSUl9B5H4z9n7TQE\nOKOx9wqPr573zW3ifUW+p8RIREREJDIdgh8W9qJz7iOgCD9UrMM45wqATcD31/mYWRw+aWlq3dXO\nuQeccycC9wG1CUptqfDYsObLgCpgN+fcyjpTflg7Aw4OiyUDGIi/Jqu+970/7H1FGqVrjEREREQi\n0+fAqWaWg/+b7VZ8YYGOdi9wo5l9DXyJvxYoiR17kb5nZrOAfwBfAOnAEcCHocVfhR6PN7PXgXLn\n3EYzuwe418x2Ad7FD+E7DH8t0jNhm78lNMyuCJgR2l7t9U+Nva9Io5QYiYiIiESmy4GH8UlCIfA7\noFedNnWTk/qSlQYTmGaajk8ynsb39szGV8iraGSdeOABfAW7YuAl4NcAzrlVZvY7/FDBdHwluUvw\nQwbz8ZXkBgAb8ddd3Vrns1wTimEAsAg40TlX09T7ijTFnGvt/xURERERiRZmFoPvkXnIOXdbB77v\nMfieoW611exE2pJ6jERERESkQWY2EDgSeAs/hG4KkAk809h6Ip2Nii+IiIiISGMcMBE/bO2/+GIH\nRznndI8g6VI0lE5ERERERKKeeoxERERERCTqKTESEREREZGop8RIRERERESinhIjERERERGJekqM\nREREREQk6ikxEhERERGRqKfESEREREREop4SIxERERERiXr/H/4yLmZJbS/SAAAAAElFTkSuQmCC\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f9a3844c9b0>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "#@test {\"output\": \"ignore\"}\n",
+ "import tensorflow as tf\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "# Set up the data with a noisy linear relationship between X and Y.\n",
+ "num_examples = 50\n",
+ "X = np.array([np.linspace(-2, 4, num_examples), np.linspace(-6, 6, num_examples)])\n",
+ "# Add random noise (gaussian, mean 0, stdev 1)\n",
+ "X += np.random.randn(2, num_examples)\n",
+ "# Split into x and y\n",
+ "x, y = X\n",
+ "# Add the bias node which always has a value of 1\n",
+ "x_with_bias = np.array([(1., a) for a in x]).astype(np.float32)\n",
+ "\n",
+ "# Keep track of the loss at each iteration so we can chart it later\n",
+ "losses = []\n",
+ "# How many iterations to run our training\n",
+ "training_steps = 50\n",
+ "# The learning rate. Also known has the step size. This changes how far\n",
+ "# we move down the gradient toward lower error at each step. Too large\n",
+ "# jumps risk inaccuracy, too small slow the learning.\n",
+ "learning_rate = 0.002\n",
+ "\n",
+ "# In TensorFlow, we need to run everything in the context of a session.\n",
+ "with tf.Session() as sess:\n",
+ " # Set up all the tensors.\n",
+ " # Our input layer is the x value and the bias node.\n",
+ " input = tf.constant(x_with_bias)\n",
+ " # Our target is the y values. They need to be massaged to the right shape.\n",
+ " target = tf.constant(np.transpose([y]).astype(np.float32))\n",
+ " # Weights are a variable. They change every time through the loop.\n",
+ " # Weights are initialized to random values (gaussian, mean 0, stdev 0.1)\n",
+ " weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))\n",
+ "\n",
+ " # Initialize all the variables defined above.\n",
+ " tf.initialize_all_variables().run()\n",
+ "\n",
+ " # Set up all operations that will run in the loop.\n",
+ " # For all x values, generate our estimate on all y given our current\n",
+ " # weights. So, this is computing y = w2 * x + w1 * bias\n",
+ " yhat = tf.matmul(input, weights)\n",
+ " # Compute the error, which is just the difference between our \n",
+ " # estimate of y and what y actually is.\n",
+ " yerror = tf.sub(yhat, target)\n",
+ " # We are going to minimize the L2 loss. The L2 loss is the sum of the\n",
+ " # squared error for all our estimates of y. This penalizes large errors\n",
+ " # a lot, but small errors only a little.\n",
+ " loss = tf.nn.l2_loss(yerror)\n",
+ "\n",
+ " # Perform gradient descent. \n",
+ " # This essentially just updates weights, like weights += grads * learning_rate\n",
+ " # using the partial derivative of the loss with respect to the\n",
+ " # weights. It's the direction we want to go to move toward lower error.\n",
+ " update_weights = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)\n",
+ "\n",
+ " # At this point, we've defined all our tensors and run our initialization\n",
+ " # operations. We've also set up the operations that will repeatedly be run\n",
+ " # inside the training loop. All the training loop is going to do is \n",
+ " # repeatedly call run, inducing the gradient descent operation, which has the effect of\n",
+ " # repeatedly changing weights by a small amount in the direction (the\n",
+ " # partial derivative or gradient) that will reduce the error (the L2 loss).\n",
+ " for _ in range(training_steps):\n",
+ " # Repeatedly run the operations, updating the TensorFlow variable.\n",
+ " sess.run(update_weights)\n",
+ "\n",
+ " # Here, we're keeping a history of the losses to plot later\n",
+ " # so we can see the change in loss as training progresses.\n",
+ " losses.append(loss.eval())\n",
+ "\n",
+ " # Training is done, get the final values for the charts\n",
+ " betas = weights.eval()\n",
+ " yhat = yhat.eval()\n",
+ "\n",
+ "# Show the results.\n",
+ "fig, (ax1, ax2) = plt.subplots(1, 2)\n",
+ "plt.subplots_adjust(wspace=.3)\n",
+ "fig.set_size_inches(10, 4)\n",
+ "ax1.scatter(x, y, alpha=.7)\n",
+ "ax1.scatter(x, np.transpose(yhat)[0], c=\"g\", alpha=.6)\n",
+ "line_x_range = (-4, 6)\n",
+ "ax1.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], \"g\", alpha=0.6)\n",
+ "ax2.plot(range(0, training_steps), losses)\n",
+ "ax2.set_ylabel(\"Loss\")\n",
+ "ax2.set_xlabel(\"Training steps\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "lSWT9YsLP1de"
+ },
+ "source": [
+ "This version of the code has a lot more comments at each step. Read through the code and the comments.\n",
+ "\n",
+ "The core piece is the loop, which contains a single `run` call. `run` executes the operations necessary for the `GradientDescentOptimizer` operation. That includes several other operations, all of which are also executed each time through the loop. The `GradientDescentOptimizer` execution has a side effect of assigning to weights, so the variable weights changes each time in the loop.\n",
+ "\n",
+ "The result is that, in each iteration of the loop, the code processes the entire input data set, generates all the estimates $\\hat{y}$ for each $x$ given the current weights $w_i$, finds all the errors and L2 losses $(\\hat{y} - y)^2$, and then changes the weights $w_i$ by a small amount in the direction of that will reduce the L2 loss.\n",
+ "\n",
+ "After many iterations of the loop, the amount we are changing the weights gets smaller and smaller, and the loss gets smaller and smaller, as we narrow in on near optimal values for the weights. By the end of the loop, we should be near the lowest possible values for the L2 loss, and near the best possible weights we could have."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "dFOk7ERATLk2"
+ },
+ "source": [
+ "## The details\n",
+ "\n",
+ "This code works, but there are still a few black boxes that are worth diving into here. `l2_loss`? `GradientDescentOptimizer`? What exactly are those doing?\n",
+ "\n",
+ "One way to understand exactly what those are doing is to do the same thing without using those functions. Here is equivalent code that calculates the gradients (derivatives), L2 loss (sum squared error), and `GradientDescentOptimizer` from scratch without using those functions."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:33:24.839102",
+ "start_time": "2016-09-16T14:33:24.328170"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "_geHN4sPTeRk",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 657,
- "status": "ok",
- "timestamp": 1446499870301,
- "user": {
- "color": "",
- "displayName": "",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "",
- "photoUrl": "",
- "sessionId": "0",
- "userId": ""
- },
- "user_tz": 480
- },
- "outputId": "85c49bf6-8d07-401a-ae08-79c6933adff5"
- },
- "source": [
- "#@test {\"output\": \"ignore\"}\n",
- "\n",
- "# Use the same input data and parameters as the examples above.\n",
- "# We're going to build up a list of the errors over time as we train to display later.\n",
- "losses = []\n",
- "\n",
- "with tf.Session() as sess:\n",
- " # Set up all the tensors.\n",
- " # The input is the x values with the bias appended on to each x.\n",
- " input = tf.constant(x_with_bias)\n",
- " # We're trying to find the best fit for the target y values.\n",
- " target = tf.constant(np.transpose([y]).astype(np.float32))\n",
- " # Let's set up the weights randomly\n",
- " weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))\n",
- "\n",
- " tf.initialize_all_variables().run()\n",
- " \n",
- " # learning_rate is the step size, so how much we jump from the current spot\n",
- " learning_rate = 0.002\n",
- " \n",
- " # The operations in the operation graph.\n",
- " # Compute the predicted y values given our current weights\n",
- " yhat = tf.matmul(input, weights)\n",
- " # How much does this differ from the actual y?\n",
- " yerror = tf.sub(yhat, target)\n",
- " # Change the weights by subtracting derivative with respect to that weight\n",
- " loss = 0.5 * tf.reduce_sum(tf.mul(yerror, yerror))\n",
- " gradient = tf.reduce_sum(tf.transpose(tf.mul(input, yerror)), 1, keep_dims=True)\n",
- " update_weights = tf.assign_sub(weights, learning_rate * gradient)\n",
- " \n",
- " # Repeatedly run the operation graph over the training data and weights.\n",
- " for _ in range(training_steps):\n",
- " sess.run(update_weights)\n",
- "\n",
- " # Here, we're keeping a history of the losses to plot later\n",
- " # so we can see the change in loss as training progresses.\n",
- " losses.append(loss.eval())\n",
- "\n",
- " # Training is done, compute final values for the graph.\n",
- " betas = weights.eval()\n",
- " yhat = yhat.eval()\n",
- "\n",
- "# Show the results.\n",
- "fig, (ax1, ax2) = plt.subplots(1, 2)\n",
- "plt.subplots_adjust(wspace=.3)\n",
- "fig.set_size_inches(10, 4)\n",
- "ax1.scatter(x, y, alpha=.7)\n",
- "ax1.scatter(x, np.transpose(yhat)[0], c=\"g\", alpha=.6)\n",
- "line_x_range = (-4, 6)\n",
- "ax1.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], \"g\", alpha=0.6)\n",
- "ax2.plot(range(0, training_steps), losses)\n",
- "ax2.set_ylabel(\"Loss\")\n",
- "ax2.set_xlabel(\"Training steps\")\n",
- "plt.show()"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\nRK5CYII=\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f8040158550>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 657,
+ "status": "ok",
+ "timestamp": 1446499870301,
+ "user": {
+ "color": "",
+ "displayName": "",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "",
+ "photoUrl": "",
+ "sessionId": "0",
+ "userId": ""
+ },
+ "user_tz": 480
},
+ "id": "_geHN4sPTeRk",
+ "outputId": "85c49bf6-8d07-401a-ae08-79c6933adff5"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "TzIETgHwTexL",
- "colab_type": "text"
- },
- "source": [
- "This code looks very similar to the code above, but without using `l2_loss` or `GradientDescentOptimizer`. Let's look at exactly what it is doing instead.\n",
- "\n",
- "This code is the key difference:\n",
- "\n",
- ">`loss = 0.5 * tf.reduce_sum(tf.mul(yerror, yerror))`\n",
- "\n",
- ">`gradient = tf.reduce_sum(tf.transpose(tf.mul(input, yerror)), 1, keep_dims=True)`\n",
- "\n",
- ">`update_weights = tf.assign_sub(weights, learning_rate * gradient)`\n",
- "\n",
- "The first line calculates the L2 loss manually. It's the same as `l2_loss(yerror)`, which is half of the sum of the squared error, so $\\frac{1}{2} \\sum (\\hat{y} - y)^2$. With this code, you can see exactly what the `l2_loss` operation does. It's the total of all the squared differences between the target and our estimates. And minimizing the L2 loss will minimize how much our estimates of $y$ differ from the true values of $y$.\n",
- "\n",
- "The second line calculates $\\begin{bmatrix}\\sum{(\\hat{y} - y)*1} \\\\ \\sum{(\\hat{y} - y)*x_i}\\end{bmatrix}$. What is that? It's the partial derivatives of the L2 loss with respect to $w_1$ and $w_2$, the same thing as what `gradients(loss, weights)` does in the earlier code. Not sure about that? Let's look at it in more detail. The gradient calculation is going to get the partial derivatives of loss with respect to each of the weights so we can change those weights in the direction that will reduce the loss. L2 loss is $\\frac{1}{2} \\sum (\\hat{y} - y)^2$, where $\\hat{y} = w_2 x + w_1$. So, using the chain rule and substituting in for $\\hat{y}$ in the derivative, $\\frac{\\partial}{\\partial w_2} = \\sum{(\\hat{y} - y)\\, *x_i}$ and $\\frac{\\partial}{\\partial w_1} = \\sum{(\\hat{y} - y)\\, *1}$. `GradientDescentOptimizer` does these calculations automatically for you based on the graph structure.\n",
- "\n",
- "The third line is equivalent to `weights -= learning_rate * gradient`, so it subtracts a constant the gradient after scaling by the learning rate (to avoid jumping too far each time, which risks moving in the wrong direction). It's also the same thing that `GradientDescentOptimizer(learning_rate).minimize(loss)` does in the earlier code. Gradient descent updates its first parameter based on the values in the second after scaling by the third, so it's equivalent to the `assign_sub(weights, learning_rate * gradient)`.\n",
- "\n",
- "Hopefully, this other code gives you a better understanding of what the operations we used previously are actually doing. In practice, you'll want to use those high level operators most of the time rather than calculating things yourself. For this toy example and simple network, it's not too bad to compute and apply the gradients yourself from scratch, but things get more complicated with larger networks."
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f9a3844c978>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
}
- ]
-} \ No newline at end of file
+ ],
+ "source": [
+ "#@test {\"output\": \"ignore\"}\n",
+ "\n",
+ "# Use the same input data and parameters as the examples above.\n",
+ "# We're going to build up a list of the errors over time as we train to display later.\n",
+ "losses = []\n",
+ "\n",
+ "with tf.Session() as sess:\n",
+ " # Set up all the tensors.\n",
+ " # The input is the x values with the bias appended on to each x.\n",
+ " input = tf.constant(x_with_bias)\n",
+ " # We're trying to find the best fit for the target y values.\n",
+ " target = tf.constant(np.transpose([y]).astype(np.float32))\n",
+ " # Let's set up the weights randomly\n",
+ " weights = tf.Variable(tf.random_normal([2, 1], 0, 0.1))\n",
+ "\n",
+ " tf.initialize_all_variables().run()\n",
+ "\n",
+ " # learning_rate is the step size, so how much we jump from the current spot\n",
+ " learning_rate = 0.002\n",
+ "\n",
+ " # The operations in the operation graph.\n",
+ " # Compute the predicted y values given our current weights\n",
+ " yhat = tf.matmul(input, weights)\n",
+ " # How much does this differ from the actual y?\n",
+ " yerror = tf.sub(yhat, target)\n",
+ " # Change the weights by subtracting derivative with respect to that weight\n",
+ " loss = 0.5 * tf.reduce_sum(tf.mul(yerror, yerror))\n",
+ " gradient = tf.reduce_sum(tf.transpose(tf.mul(input, yerror)), 1, keep_dims=True)\n",
+ " update_weights = tf.assign_sub(weights, learning_rate * gradient)\n",
+ " \n",
+ " # Repeatedly run the operation graph over the training data and weights.\n",
+ " for _ in range(training_steps):\n",
+ " sess.run(update_weights)\n",
+ " \n",
+ " # Here, we're keeping a history of the losses to plot later\n",
+ " # so we can see the change in loss as training progresses.\n",
+ " losses.append(loss.eval())\n",
+ "\n",
+ " # Training is done, compute final values for the graph.\n",
+ " betas = weights.eval()\n",
+ " yhat = yhat.eval()\n",
+ "\n",
+ "# Show the results.\n",
+ "fig, (ax1, ax2) = plt.subplots(1, 2)\n",
+ "plt.subplots_adjust(wspace=.3)\n",
+ "fig.set_size_inches(10, 4)\n",
+ "ax1.scatter(x, y, alpha=.7)\n",
+ "ax1.scatter(x, np.transpose(yhat)[0], c=\"g\", alpha=.6)\n",
+ "line_x_range = (-4, 6)\n",
+ "ax1.plot(line_x_range, [betas[0] + a * betas[1] for a in line_x_range], \"g\", alpha=0.6)\n",
+ "ax2.plot(range(0, training_steps), losses)\n",
+ "ax2.set_ylabel(\"Loss\")\n",
+ "ax2.set_xlabel(\"Training steps\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "TzIETgHwTexL"
+ },
+ "source": [
+ "This code looks very similar to the code above, but without using `l2_loss` or `GradientDescentOptimizer`. Let's look at exactly what it is doing instead.\n",
+ "\n",
+ "This code is the key difference:\n",
+ "\n",
+ ">`loss = 0.5 * tf.reduce_sum(tf.mul(yerror, yerror))`\n",
+ "\n",
+ ">`gradient = tf.reduce_sum(tf.transpose(tf.mul(input, yerror)), 1, keep_dims=True)`\n",
+ "\n",
+ ">`update_weights = tf.assign_sub(weights, learning_rate * gradient)`\n",
+ "\n",
+ "The first line calculates the L2 loss manually. It's the same as `l2_loss(yerror)`, which is half of the sum of the squared error, so $\\frac{1}{2} \\sum (\\hat{y} - y)^2$. With this code, you can see exactly what the `l2_loss` operation does. It's the total of all the squared differences between the target and our estimates. And minimizing the L2 loss will minimize how much our estimates of $y$ differ from the true values of $y$.\n",
+ "\n",
+ "The second line calculates $\\begin{bmatrix}\\sum{(\\hat{y} - y)*1} \\\\ \\sum{(\\hat{y} - y)*x_i}\\end{bmatrix}$. What is that? It's the partial derivatives of the L2 loss with respect to $w_1$ and $w_2$, the same thing as what `gradients(loss, weights)` does in the earlier code. Not sure about that? Let's look at it in more detail. The gradient calculation is going to get the partial derivatives of loss with respect to each of the weights so we can change those weights in the direction that will reduce the loss. L2 loss is $\\frac{1}{2} \\sum (\\hat{y} - y)^2$, where $\\hat{y} = w_2 x + w_1$. So, using the chain rule and substituting in for $\\hat{y}$ in the derivative, $\\frac{\\partial}{\\partial w_2} = \\sum{(\\hat{y} - y)\\, *x_i}$ and $\\frac{\\partial}{\\partial w_1} = \\sum{(\\hat{y} - y)\\, *1}$. `GradientDescentOptimizer` does these calculations automatically for you based on the graph structure.\n",
+ "\n",
+ "The third line is equivalent to `weights -= learning_rate * gradient`, so it subtracts a constant the gradient after scaling by the learning rate (to avoid jumping too far each time, which risks moving in the wrong direction). It's also the same thing that `GradientDescentOptimizer(learning_rate).minimize(loss)` does in the earlier code. Gradient descent updates its first parameter based on the values in the second after scaling by the third, so it's equivalent to the `assign_sub(weights, learning_rate * gradient)`.\n",
+ "\n",
+ "Hopefully, this other code gives you a better understanding of what the operations we used previously are actually doing. In practice, you'll want to use those high level operators most of the time rather than calculating things yourself. For this toy example and simple network, it's not too bad to compute and apply the gradients yourself from scratch, but things get more complicated with larger networks."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "anaconda-cloud": {},
+ "colab": {
+ "default_view": {},
+ "name": "Untitled",
+ "provenance": [],
+ "version": "0.3.2",
+ "views": {}
+ },
+ "kernelspec": {
+ "display_name": "Python [default]",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.5.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/tensorflow/tools/docker/notebooks/3_mnist_from_scratch.ipynb b/tensorflow/tools/docker/notebooks/3_mnist_from_scratch.ipynb
index 8f8bedbdfe..79852a3521 100644
--- a/tensorflow/tools/docker/notebooks/3_mnist_from_scratch.ipynb
+++ b/tensorflow/tools/docker/notebooks/3_mnist_from_scratch.ipynb
@@ -1,1868 +1,2051 @@
{
- "nbformat": 4,
- "nbformat_minor": 0,
- "metadata": {
- "colab": {
- "version": "0.3.2",
- "views": {},
- "default_view": {},
- "name": "Untitled",
- "provenance": []
- }
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "9yupXUk1DKOe"
+ },
+ "source": [
+ "# MNIST from scratch\n",
+ "\n",
+ "This notebook walks through an example of training a TensorFlow model to do digit classification using the [MNIST data set](http://yann.lecun.com/exdb/mnist/). MNIST is a labeled set of images of handwritten digits.\n",
+ "\n",
+ "An example follows."
+ ]
},
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "9yupXUk1DKOe",
- "colab_type": "text"
- },
- "source": [
- "# MNIST from scratch\n",
- "\n",
- "This notebook walks through an example of training a TensorFlow model to do digit classification using the [MNIST data set](http://yann.lecun.com/exdb/mnist/). MNIST is a labeled set of images of handwritten digits.\n",
- "\n",
- "An example follows."
- ]
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:20.863031",
+ "start_time": "2016-09-16T14:49:20.818734"
+ },
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {}
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "id": "sbUKaF8_uDI_",
+ "outputId": "67a51332-3aea-4c29-8c3d-4752db08ccb3"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "sbUKaF8_uDI_",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {}
- ]
- },
- "cellView": "both",
- "outputId": "67a51332-3aea-4c29-8c3d-4752db08ccb3"
- },
- "source": [
- "from IPython.display import Image\n",
- "import base64\n",
- "Image(data=base64.decodestring(\"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\"), embed=True)"
- ],
- "outputs": [
- {
- "output_type": "execute_result",
- "execution_count": 1,
- "metadata": {},
- "data": {
- "image/png": "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\ngUDg/wHX+3lgThDIegAAAABJRU5ErkJggg==\n",
- "text/plain": [
- "<IPython.core.display.Image object>"
- ]
- }
- }
- ],
- "execution_count": 1
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/opt/anaconda3/lib/python3.5/site-packages/ipykernel/__main__.py:5: DeprecationWarning: decodestring() is a deprecated alias, use decodebytes()\n"
+ ]
},
{
- "cell_type": "markdown",
- "metadata": {
- "id": "J0QZYD_HuDJF",
- "colab_type": "text"
- },
- "source": [
- "We're going to be building a model that recognizes these digits as 5, 0, and 4.\n",
- "\n",
- "# Imports and input data\n",
- "\n",
- "We'll proceed in steps, beginning with importing and inspecting the MNIST data. This doesn't have anything to do with TensorFlow in particular -- we're just downloading the data archive."
+ "data": {
+ "image/png": "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\ngUDg/wHX+3lgThDIegAAAABJRU5ErkJggg==\n",
+ "text/plain": [
+ "<IPython.core.display.Image object>"
]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from __future__ import print_function\n",
+ "\n",
+ "from IPython.display import Image\n",
+ "import base64\n",
+ "Image(data=base64.decodestring(\"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\".encode('utf-8')), embed=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "J0QZYD_HuDJF"
+ },
+ "source": [
+ "We're going to be building a model that recognizes these digits as 5, 0, and 4.\n",
+ "\n",
+ "# Imports and input data\n",
+ "\n",
+ "We'll proceed in steps, beginning with importing and inspecting the MNIST data. This doesn't have anything to do with TensorFlow in particular -- we're just downloading the data archive."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:20.958307",
+ "start_time": "2016-09-16T14:49:20.864840"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "w5vKZqr6CDz9",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {}
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 110,
- "status": "ok",
- "timestamp": 1446749124399,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "794eac6d-a918-4888-e8cf-a8628474d7f1"
- },
- "source": [
- "import os\n",
- "import urllib\n",
- "\n",
- "SOURCE_URL = 'http://yann.lecun.com/exdb/mnist/'\n",
- "WORK_DIRECTORY = \"/tmp/mnist-data\"\n",
- "\n",
- "def maybe_download(filename):\n",
- " \"\"\"A helper to download the data files if not present.\"\"\"\n",
- " if not os.path.exists(WORK_DIRECTORY):\n",
- " os.mkdir(WORK_DIRECTORY)\n",
- " filepath = os.path.join(WORK_DIRECTORY, filename)\n",
- " if not os.path.exists(filepath):\n",
- " filepath, _ = urllib.urlretrieve(SOURCE_URL + filename, filepath)\n",
- " statinfo = os.stat(filepath)\n",
- " print 'Succesfully downloaded', filename, statinfo.st_size, 'bytes.'\n",
- " else:\n",
- " print 'Already downloaded', filename\n",
- " return filepath\n",
- "\n",
- "train_data_filename = maybe_download('train-images-idx3-ubyte.gz')\n",
- "train_labels_filename = maybe_download('train-labels-idx1-ubyte.gz')\n",
- "test_data_filename = maybe_download('t10k-images-idx3-ubyte.gz')\n",
- "test_labels_filename = maybe_download('t10k-labels-idx1-ubyte.gz')"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Already downloaded train-images-idx3-ubyte.gz\n",
- "Already downloaded train-labels-idx1-ubyte.gz\n",
- "Already downloaded t10k-images-idx3-ubyte.gz\n",
- "Already downloaded t10k-labels-idx1-ubyte.gz\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {}
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "gCtMhpIoC84F",
- "colab_type": "text"
- },
- "source": [
- "## Working with the images\n",
- "\n",
- "Now we have the files, but the format requires a bit of pre-processing before we can work with it. The data is gzipped, requiring us to decompress it. And, each of the images are grayscale-encoded with values from [0, 255]; we'll normalize these to [-0.5, 0.5].\n",
- "\n",
- "Let's try to unpack the data using the documented format:\n",
- "\n",
- " [offset] [type] [value] [description] \n",
- " 0000 32 bit integer 0x00000803(2051) magic number \n",
- " 0004 32 bit integer 60000 number of images \n",
- " 0008 32 bit integer 28 number of rows \n",
- " 0012 32 bit integer 28 number of columns \n",
- " 0016 unsigned byte ?? pixel \n",
- " 0017 unsigned byte ?? pixel \n",
- " ........ \n",
- " xxxx unsigned byte ?? pixel\n",
- " \n",
- "Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).\n",
- "\n",
- "We'll start by reading the first image from the test data as a sanity check."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 110,
+ "status": "ok",
+ "timestamp": 1446749124399,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "w5vKZqr6CDz9",
+ "outputId": "794eac6d-a918-4888-e8cf-a8628474d7f1"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "P_3Fm5BpFMDF",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {}
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 57,
- "status": "ok",
- "timestamp": 1446749125010,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "c8e777e0-d891-4eb1-a178-9809f293cc28"
- },
- "source": [
- "import gzip, binascii, struct, numpy\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "with gzip.open(test_data_filename) as f:\n",
- " # Print the header fields.\n",
- " for field in ['magic number', 'image count', 'rows', 'columns']:\n",
- " # struct.unpack reads the binary data provided by f.read.\n",
- " # The format string '>i' decodes a big-endian integer, which\n",
- " # is the encoding of the data.\n",
- " print field, struct.unpack('>i', f.read(4))[0]\n",
- " \n",
- " # Read the first 28x28 set of pixel values. \n",
- " # Each pixel is one byte, [0, 255], a uint8.\n",
- " buf = f.read(28 * 28)\n",
- " image = numpy.frombuffer(buf, dtype=numpy.uint8)\n",
- " \n",
- " # Print the first few values of image.\n",
- " print 'First 10 pixels:', image[:10]"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "magic number 2051\n",
- "image count 10000\n",
- "rows 28\n",
- "columns 28\n",
- "First 10 pixels: [0 0 0 0 0 0 0 0 0 0]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Already downloaded train-images-idx3-ubyte.gz\n",
+ "Already downloaded train-labels-idx1-ubyte.gz\n",
+ "Already downloaded t10k-images-idx3-ubyte.gz\n",
+ "Already downloaded t10k-labels-idx1-ubyte.gz\n"
+ ]
+ }
+ ],
+ "source": [
+ "import os\n",
+ "from six.moves.urllib.request import urlretrieve\n",
+ "\n",
+ "SOURCE_URL = 'http://yann.lecun.com/exdb/mnist/'\n",
+ "WORK_DIRECTORY = \"/tmp/mnist-data\"\n",
+ "\n",
+ "def maybe_download(filename):\n",
+ " \"\"\"A helper to download the data files if not present.\"\"\"\n",
+ " if not os.path.exists(WORK_DIRECTORY):\n",
+ " os.mkdir(WORK_DIRECTORY)\n",
+ " filepath = os.path.join(WORK_DIRECTORY, filename)\n",
+ " if not os.path.exists(filepath):\n",
+ " filepath, _ = urlretrieve(SOURCE_URL + filename, filepath)\n",
+ " statinfo = os.stat(filepath)\n",
+ " print('Succesfully downloaded', filename, statinfo.st_size, 'bytes.')\n",
+ " else:\n",
+ " print('Already downloaded', filename)\n",
+ " return filepath\n",
+ "\n",
+ "train_data_filename = maybe_download('train-images-idx3-ubyte.gz')\n",
+ "train_labels_filename = maybe_download('train-labels-idx1-ubyte.gz')\n",
+ "test_data_filename = maybe_download('t10k-images-idx3-ubyte.gz')\n",
+ "test_labels_filename = maybe_download('t10k-labels-idx1-ubyte.gz')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "gCtMhpIoC84F"
+ },
+ "source": [
+ "## Working with the images\n",
+ "\n",
+ "Now we have the files, but the format requires a bit of pre-processing before we can work with it. The data is gzipped, requiring us to decompress it. And, each of the images are grayscale-encoded with values from [0, 255]; we'll normalize these to [-0.5, 0.5].\n",
+ "\n",
+ "Let's try to unpack the data using the documented format:\n",
+ "\n",
+ " [offset] [type] [value] [description] \n",
+ " 0000 32 bit integer 0x00000803(2051) magic number \n",
+ " 0004 32 bit integer 60000 number of images \n",
+ " 0008 32 bit integer 28 number of rows \n",
+ " 0012 32 bit integer 28 number of columns \n",
+ " 0016 unsigned byte ?? pixel \n",
+ " 0017 unsigned byte ?? pixel \n",
+ " ........ \n",
+ " xxxx unsigned byte ?? pixel\n",
+ " \n",
+ "Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black).\n",
+ "\n",
+ "We'll start by reading the first image from the test data as a sanity check."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:22.112407",
+ "start_time": "2016-09-16T14:49:20.960204"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "7NXKCQENNRQT",
- "colab_type": "text"
- },
- "source": [
- "The first 10 pixels are all 0 values. Not very interesting, but also unsurprising. We'd expect most of the pixel values to be the background color, 0.\n",
- "\n",
- "We could print all 28 * 28 values, but what we really need to do to make sure we're reading our data properly is look at an image."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {}
+ ]
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "F_5w-cOoNLaG",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {}
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 887,
- "status": "ok",
- "timestamp": 1446749126640,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "77dabc81-e3ee-4fcf-ac72-88038494fb6c"
- },
- "source": [
- "%matplotlib inline\n",
- "\n",
- "# We'll show the image and its pixel value histogram side-by-side.\n",
- "_, (ax1, ax2) = plt.subplots(1, 2)\n",
- "\n",
- "# To interpret the values as a 28x28 image, we need to reshape\n",
- "# the numpy array, which is one dimensional.\n",
- "ax1.imshow(image.reshape(28, 28), cmap=plt.cm.Greys);\n",
- "\n",
- "ax2.hist(image, bins=20, range=[0,255]);"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f22841b4d50>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 57,
+ "status": "ok",
+ "timestamp": 1446749125010,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "P_3Fm5BpFMDF",
+ "outputId": "c8e777e0-d891-4eb1-a178-9809f293cc28"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "weVoVR-nN0cN",
- "colab_type": "text"
- },
- "source": [
- "The large number of 0 values correspond to the background of the image, another large mass of value 255 is black, and a mix of grayscale transition values in between.\n",
- "\n",
- "Both the image and histogram look sensible. But, it's good practice when training image models to normalize values to be centered around 0.\n",
- "\n",
- "We'll do that next. The normalization code is fairly short, and it may be tempting to assume we haven't made mistakes, but we'll double-check by looking at the rendered input and histogram again. Malformed inputs are a surprisingly common source of errors when developing new models."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "magic number 2051\n",
+ "image count 10000\n",
+ "rows 28\n",
+ "columns 28\n",
+ "First 10 pixels: [0 0 0 0 0 0 0 0 0 0]\n"
+ ]
+ }
+ ],
+ "source": [
+ "import gzip, binascii, struct, numpy\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "with gzip.open(test_data_filename) as f:\n",
+ " # Print the header fields.\n",
+ " for field in ['magic number', 'image count', 'rows', 'columns']:\n",
+ " # struct.unpack reads the binary data provided by f.read.\n",
+ " # The format string '>i' decodes a big-endian integer, which\n",
+ " # is the encoding of the data.\n",
+ " print(field, struct.unpack('>i', f.read(4))[0])\n",
+ " \n",
+ " # Read the first 28x28 set of pixel values. \n",
+ " # Each pixel is one byte, [0, 255], a uint8.\n",
+ " buf = f.read(28 * 28)\n",
+ " image = numpy.frombuffer(buf, dtype=numpy.uint8)\n",
+ " \n",
+ " # Print the first few values of image.\n",
+ " print('First 10 pixels:', image[:10])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "7NXKCQENNRQT"
+ },
+ "source": [
+ "The first 10 pixels are all 0 values. Not very interesting, but also unsurprising. We'd expect most of the pixel values to be the background color, 0.\n",
+ "\n",
+ "We could print all 28 * 28 values, but what we really need to do to make sure we're reading our data properly is look at an image."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:22.525418",
+ "start_time": "2016-09-16T14:49:22.114324"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "jc1xCZXHNKVp",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {}
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 531,
- "status": "ok",
- "timestamp": 1446749126656,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "bd45b3dd-438b-41db-ea8f-d202d4a09e63"
- },
- "source": [
- "# Let's convert the uint8 image to 32 bit floats and rescale \n",
- "# the values to be centered around 0, between [-0.5, 0.5]. \n",
- "# \n",
- "# We again plot the image and histogram to check that we \n",
- "# haven't mangled the data.\n",
- "scaled = image.astype(numpy.float32)\n",
- "scaled = (scaled - (255 / 2.0)) / 255\n",
- "_, (ax1, ax2) = plt.subplots(1, 2)\n",
- "ax1.imshow(scaled.reshape(28, 28), cmap=plt.cm.Greys);\n",
- "ax2.hist(scaled, bins=20, range=[-0.5, 0.5]);"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f22841b4550>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {}
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 887,
+ "status": "ok",
+ "timestamp": 1446749126640,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "F_5w-cOoNLaG",
+ "outputId": "77dabc81-e3ee-4fcf-ac72-88038494fb6c"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "PlqlwkX-O0Hd",
- "colab_type": "text"
- },
- "source": [
- "Great -- we've retained the correct image data while properly rescaling to the range [-0.5, 0.5].\n",
- "\n",
- "## Reading the labels\n",
- "\n",
- "Let's next unpack the test label data. The format here is similar: a magic number followed by a count followed by the labels as `uint8` values. In more detail:\n",
- "\n",
- " [offset] [type] [value] [description] \n",
- " 0000 32 bit integer 0x00000801(2049) magic number (MSB first) \n",
- " 0004 32 bit integer 10000 number of items \n",
- " 0008 unsigned byte ?? label \n",
- " 0009 unsigned byte ?? label \n",
- " ........ \n",
- " xxxx unsigned byte ?? label\n",
- "\n",
- "As with the image data, let's read the first test set value to sanity check our input path. We'll expect a 7."
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f84680e3fd0>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "%matplotlib inline\n",
+ "\n",
+ "# We'll show the image and its pixel value histogram side-by-side.\n",
+ "_, (ax1, ax2) = plt.subplots(1, 2)\n",
+ "\n",
+ "# To interpret the values as a 28x28 image, we need to reshape\n",
+ "# the numpy array, which is one dimensional.\n",
+ "ax1.imshow(image.reshape(28, 28), cmap=plt.cm.Greys);\n",
+ "\n",
+ "ax2.hist(image, bins=20, range=[0,255]);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "weVoVR-nN0cN"
+ },
+ "source": [
+ "The large number of 0 values correspond to the background of the image, another large mass of value 255 is black, and a mix of grayscale transition values in between.\n",
+ "\n",
+ "Both the image and histogram look sensible. But, it's good practice when training image models to normalize values to be centered around 0.\n",
+ "\n",
+ "We'll do that next. The normalization code is fairly short, and it may be tempting to assume we haven't made mistakes, but we'll double-check by looking at the rendered input and histogram again. Malformed inputs are a surprisingly common source of errors when developing new models."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:22.895369",
+ "start_time": "2016-09-16T14:49:22.527595"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "d8zv9yZzQOnV",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {}
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 90,
- "status": "ok",
- "timestamp": 1446749126903,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "ad203b2c-f095-4035-e0cd-7869c078da3d"
- },
- "source": [
- "with gzip.open(test_labels_filename) as f:\n",
- " # Print the header fields.\n",
- " for field in ['magic number', 'label count']:\n",
- " print field, struct.unpack('>i', f.read(4))[0]\n",
- "\n",
- " print 'First label:', struct.unpack('B', f.read(1))[0]"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "magic number 2049\n",
- "label count 10000\n",
- "First label: 7\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {}
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 531,
+ "status": "ok",
+ "timestamp": 1446749126656,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "jc1xCZXHNKVp",
+ "outputId": "bd45b3dd-438b-41db-ea8f-d202d4a09e63"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "zAGrQSXCQtIm",
- "colab_type": "text"
- },
- "source": [
- "Indeed, the first label of the test set is 7.\n",
- "\n",
- "## Forming the training, testing, and validation data sets\n",
- "\n",
- "Now that we understand how to read a single element, we can read a much larger set that we'll use for training, testing, and validation.\n",
- "\n",
- "### Image data\n",
- "\n",
- "The code below is a generalization of our prototyping above that reads the entire test and training data set."
+ "data": {
+ "image/png": "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\nR6FQKPn86OjoilWXjdw4aGZmpmx7nrogl1+VsNyF+8iRI6tY9vhLLC39vysGvc1M4UBE1ms30Awc\nyzx+DHhmide0w/q+Xf3Hf/xHfG8I2FXirEfi28fKvNPXALj88svLfl5ra4H3vOfP2b17d+7zjz3m\nP+NOoiCQdd+GtWV4eJg/+IM/ZGFhtuz7RGPSl8qesVLVZaW2QPQte2mp/OesdM7w8DD33PNPK7Yn\nUurv4GuArfj7jZT7e3o0vv2/gVJdRI8A/1imLU99xnr+Pwhe277mN8lhzrlqvp+IbDNmdhrwfeBC\n59wDwePXAT/pnPu/cl7z68BHNq6VIlvea5xzH63Wm6lyICLrNUxUu9+XeXwvy6sJ3t3Aa4DvACt9\nvRWR0tqBc4j+n6oaVQ5EZN3M7CvAA865N8c/G/A4cKNz7j11bZyIVEyVAxGphuuBD5vZQzw1lbET\n+FA9GyUia6NwICLr5py73cx2A+8i6l74OnCJc+5EfVsmImuhbgURERFJ0d4KIiIikqJwICIiIikK\nByJSc2bWb2YfMbOimY2a2d+aWdcqXnehmd1jZpPxaz9vZqWX9Ktxe4LXf9rMlszsso1uS3z+jWb2\nLTObMrPvmtlfmlnPGj77KjN7zMxmzOwrZvb8Fc7/L2Z2JD7/YTN7eaWfWa32mNnrzeyLZjYSH59d\nqf21akvmda+O/9v4h3q1xcx6zewmM3syfs23zOxllXymwoGIbISPEq1FezHRngsvBt5f7gVmdiHw\naeAu4Hnx8T5WWtKvRu0J2nWQaF2Hag3YqrQtpxMty/d7wI8CvwG8DPjbSj402CzrauC5RDtp3h0P\nLM07/8K4rX8D/ATwv4D/ZWbPquRzq9Ue4Kfi9rwEuAB4AvhMvCjXRrfFv+5s4D3AF9fbhrW2JV7O\n/HPAWcAvE61S+ptEC5WtnnNOhw4dOmp2AD9CdEF/bvDYJcAisL/M6+4HrmmU9sTnPQf4LtECT0vA\nZfVqS+Z9fgWYAZoqeM1XgL8Mfjbge8BbSpz/98Ancv6Obq7S30tF7cl5fRNQBC6vR1viz/8ScAXw\nQeAf6vF7Ad4A/AfQvJ7PVeVARGrtQmDUOfe14LHPEX3zfmHeC8xsT/zcsJndZ2ZH4y6FF9WjPXGb\nOoi+qV7lnDtehXasuS05+oBx59yqqirBZln3+MdcdGUpt1nWhfHzobvLnL9qa2xPVhfQCozUqS1X\nA8edcx9cz+dXoS2/QBza4v9vHjGzt5lZRdd7hQMRqbX9QOpi6pw7RfSP+P4Srzk3vr2aqMR+CXAY\nuMfMfqgO7QE4BNzrnPvf6/z8arQlEZeX38Equ0Vi5TbLKvW5+ys8vxJraU/WnxOVzrMBpuZtiUPr\nFcDr1/nZ624L0f87/4Xo+v5y4FrgvwJvr+SDFQ5EZE3M7E/jgVeljlNmdl65t6B0v73/t+mvnXO3\nOOceds79HtF2eFdudHvigYc/Q7Ty44pq/LsJP6cb+BTwDeCPV9O2ld5yNZ+7jvMrtdrfwx8Cvwq8\n0jk3v5FtMbMdwK3AbzrnRmv02atqS6yJKDz8lnPua86524F3A2+s5AO0QqKIrNV/J+pbLef/AEeJ\n+ugTZtYM9FN6Y6YfxLfZvWyPEA202uj2/DTRN7KimYWP/4OZfdE59zMb2BZ/3g6isv4Y8MtxxWG1\n1rJZ1tEKz6/EWtoDgJn9PvAW4GLn3L/VoS0/BJwNfNKe+o+jKW7bPPBM51y5/Z+r2RaI/t+Zj7sf\nvCPAfjNrcc4truaDFQ5EZE2ccyeBkyudZ2b3A31m9tygb/1iom8/D+S9xjn3HTN7kmikdeg84M6N\nbg/wp0Sj9EPfAN4MLOtmqHFbfMXgbqJBiJdV+m3ZObdg0T4YFwOfiN/T4p9vLPGy+3Oe/7n48XVZ\nY3swsz8gKpe/NDNuYyPbcgT4scxj7wZ2AP8P0SyKjWoLwH3AYOaxZwI/WG0w8B+uQ4cOHTU9iC7o\n/wI8H3gRUffArcHzpxP9I/u84LE3A6PAq4i+nV0LTAFPr0d7ct5j3bMV1tIWoovOV4j2r3g60bdK\nf1QyW+FXicLFa4lmTbyfKNDsiZ+/BfiT4PwLgXmiKZTPBK4h2m77WVX6b6TS9rwl/vxfyvwOuja6\nLTmvr+ZshUp/L2cQzdr4S+CHiabHHgX+sKLPrUbjdejQoaPcQTSa/rb4H61Rom/hncHzZxOVT1+c\ned1biKYOTgD3AhfWsz2Z9zhVpXBQUVuI5vefyhxL8e1ZFX727wDfiS8+95MOZ/8E/F3m/FcB34rP\n/1eizbWq+d/JqtsDPJbzezgF/NFGtyXntVULB2v8e3oh8GVgmmha41uJ91Ja7aGNl0RERCRFsxVE\nREQkReFAREREUhQOREREJEXhQERERFIUDkRERCRF4UBERERSFA5EREQkReFA5P9vt44FAAAAAAb5\nW++eQ1EEwMgBADByAACMHAAAE5OOiZtgWJb5AAAAAElFTkSuQmCC\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f8444471358>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Let's convert the uint8 image to 32 bit floats and rescale \n",
+ "# the values to be centered around 0, between [-0.5, 0.5]. \n",
+ "# \n",
+ "# We again plot the image and histogram to check that we \n",
+ "# haven't mangled the data.\n",
+ "scaled = image.astype(numpy.float32)\n",
+ "scaled = (scaled - (255 / 2.0)) / 255\n",
+ "_, (ax1, ax2) = plt.subplots(1, 2)\n",
+ "ax1.imshow(scaled.reshape(28, 28), cmap=plt.cm.Greys);\n",
+ "ax2.hist(scaled, bins=20, range=[-0.5, 0.5]);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "PlqlwkX-O0Hd"
+ },
+ "source": [
+ "Great -- we've retained the correct image data while properly rescaling to the range [-0.5, 0.5].\n",
+ "\n",
+ "## Reading the labels\n",
+ "\n",
+ "Let's next unpack the test label data. The format here is similar: a magic number followed by a count followed by the labels as `uint8` values. In more detail:\n",
+ "\n",
+ " [offset] [type] [value] [description] \n",
+ " 0000 32 bit integer 0x00000801(2049) magic number (MSB first) \n",
+ " 0004 32 bit integer 10000 number of items \n",
+ " 0008 unsigned byte ?? label \n",
+ " 0009 unsigned byte ?? label \n",
+ " ........ \n",
+ " xxxx unsigned byte ?? label\n",
+ "\n",
+ "As with the image data, let's read the first test set value to sanity check our input path. We'll expect a 7."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:22.925176",
+ "start_time": "2016-09-16T14:49:22.897739"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "ofFZ5oJeRMDA",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {}
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 734,
- "status": "ok",
- "timestamp": 1446749128718,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "ff2de90b-aed9-4ce5-db8c-9123496186b1"
- },
- "source": [
- "IMAGE_SIZE = 28\n",
- "PIXEL_DEPTH = 255\n",
- "\n",
- "def extract_data(filename, num_images):\n",
- " \"\"\"Extract the images into a 4D tensor [image index, y, x, channels].\n",
- " \n",
- " For MNIST data, the number of channels is always 1.\n",
- "\n",
- " Values are rescaled from [0, 255] down to [-0.5, 0.5].\n",
- " \"\"\"\n",
- " print 'Extracting', filename\n",
- " with gzip.open(filename) as bytestream:\n",
- " # Skip the magic number and dimensions; we know these values.\n",
- " bytestream.read(16)\n",
- " \n",
- " buf = bytestream.read(IMAGE_SIZE * IMAGE_SIZE * num_images)\n",
- " data = numpy.frombuffer(buf, dtype=numpy.uint8).astype(numpy.float32)\n",
- " data = (data - (PIXEL_DEPTH / 2.0)) / PIXEL_DEPTH\n",
- " data = data.reshape(num_images, IMAGE_SIZE, IMAGE_SIZE, 1)\n",
- " return data\n",
- "\n",
- "train_data = extract_data(train_data_filename, 60000)\n",
- "test_data = extract_data(test_data_filename, 10000)"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Extracting /tmp/mnist-data/train-images-idx3-ubyte.gz\n",
- "Extracting /tmp/mnist-data/t10k-images-idx3-ubyte.gz\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {}
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "0x4rwXxUR96O",
- "colab_type": "text"
- },
- "source": [
- "A crucial difference here is how we `reshape` the array of pixel values. Instead of one image that's 28x28, we now have a set of 60,000 images, each one being 28x28. We also include a number of channels, which for grayscale images as we have here is 1.\n",
- "\n",
- "Let's make sure we've got the reshaping parameters right by inspecting the dimensions and the first two images. (Again, mangled input is a very common source of errors.)"
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 90,
+ "status": "ok",
+ "timestamp": 1446749126903,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "d8zv9yZzQOnV",
+ "outputId": "ad203b2c-f095-4035-e0cd-7869c078da3d"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "0AwSo8mlSja_",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {},
- {}
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 400,
- "status": "ok",
- "timestamp": 1446749129657,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "11490c39-7c67-4fe5-982c-ca8278294d96"
- },
- "source": [
- "print 'Training data shape', train_data.shape\n",
- "_, (ax1, ax2) = plt.subplots(1, 2)\n",
- "ax1.imshow(train_data[0].reshape(28, 28), cmap=plt.cm.Greys);\n",
- "ax2.imshow(train_data[1].reshape(28, 28), cmap=plt.cm.Greys);"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Training data shape (60000, 28, 28, 1)\n"
- ],
- "name": "stdout"
- },
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\nbj/C7XFdaAAAAABJRU5ErkJggg==\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f22684f2890>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "magic number 2049\n",
+ "label count 10000\n",
+ "First label: 7\n"
+ ]
+ }
+ ],
+ "source": [
+ "with gzip.open(test_labels_filename) as f:\n",
+ " # Print the header fields.\n",
+ " for field in ['magic number', 'label count']:\n",
+ " print(field, struct.unpack('>i', f.read(4))[0])\n",
+ "\n",
+ " print('First label:', struct.unpack('B', f.read(1))[0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "zAGrQSXCQtIm"
+ },
+ "source": [
+ "Indeed, the first label of the test set is 7.\n",
+ "\n",
+ "## Forming the training, testing, and validation data sets\n",
+ "\n",
+ "Now that we understand how to read a single element, we can read a much larger set that we'll use for training, testing, and validation.\n",
+ "\n",
+ "### Image data\n",
+ "\n",
+ "The code below is a generalization of our prototyping above that reads the entire test and training data set."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:23.525119",
+ "start_time": "2016-09-16T14:49:22.928289"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "cwBhQ3ouTQcW",
- "colab_type": "text"
- },
- "source": [
- "Looks good. Now we know how to index our full set of training and test images."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {}
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "PBCB9aYxRvBi",
- "colab_type": "text"
- },
- "source": [
- "### Label data\n",
- "\n",
- "Let's move on to loading the full set of labels. As is typical in classification problems, we'll convert our input labels into a [1-hot](https://en.wikipedia.org/wiki/One-hot) encoding over a length 10 vector corresponding to 10 digits. The vector [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], for example, would correspond to the digit 1."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 734,
+ "status": "ok",
+ "timestamp": 1446749128718,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "ofFZ5oJeRMDA",
+ "outputId": "ff2de90b-aed9-4ce5-db8c-9123496186b1"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "9pK1j2WlRwY9",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 191,
- "status": "ok",
- "timestamp": 1446749131421,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "1ca31655-e14f-405a-b266-6a6c78827af5"
- },
- "source": [
- "NUM_LABELS = 10\n",
- "\n",
- "def extract_labels(filename, num_images):\n",
- " \"\"\"Extract the labels into a 1-hot matrix [image index, label index].\"\"\"\n",
- " print 'Extracting', filename\n",
- " with gzip.open(filename) as bytestream:\n",
- " # Skip the magic number and count; we know these values.\n",
- " bytestream.read(8)\n",
- " \n",
- " buf = bytestream.read(1 * num_images)\n",
- " labels = numpy.frombuffer(buf, dtype=numpy.uint8)\n",
- " # Convert to dense 1-hot representation.\n",
- " return (numpy.arange(NUM_LABELS) == labels[:, None]).astype(numpy.float32)\n",
- "\n",
- "train_labels = extract_labels(train_labels_filename, 60000)\n",
- "test_labels = extract_labels(test_labels_filename, 10000)"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Extracting /tmp/mnist-data/train-labels-idx1-ubyte.gz\n",
- "Extracting /tmp/mnist-data/t10k-labels-idx1-ubyte.gz\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Extracting /tmp/mnist-data/train-images-idx3-ubyte.gz\n",
+ "Extracting /tmp/mnist-data/t10k-images-idx3-ubyte.gz\n"
+ ]
+ }
+ ],
+ "source": [
+ "IMAGE_SIZE = 28\n",
+ "PIXEL_DEPTH = 255\n",
+ "\n",
+ "def extract_data(filename, num_images):\n",
+ " \"\"\"Extract the images into a 4D tensor [image index, y, x, channels].\n",
+ " \n",
+ " For MNIST data, the number of channels is always 1.\n",
+ "\n",
+ " Values are rescaled from [0, 255] down to [-0.5, 0.5].\n",
+ " \"\"\"\n",
+ " print('Extracting', filename)\n",
+ " with gzip.open(filename) as bytestream:\n",
+ " # Skip the magic number and dimensions; we know these values.\n",
+ " bytestream.read(16)\n",
+ "\n",
+ " buf = bytestream.read(IMAGE_SIZE * IMAGE_SIZE * num_images)\n",
+ " data = numpy.frombuffer(buf, dtype=numpy.uint8).astype(numpy.float32)\n",
+ " data = (data - (PIXEL_DEPTH / 2.0)) / PIXEL_DEPTH\n",
+ " data = data.reshape(num_images, IMAGE_SIZE, IMAGE_SIZE, 1)\n",
+ " return data\n",
+ "\n",
+ "train_data = extract_data(train_data_filename, 60000)\n",
+ "test_data = extract_data(test_data_filename, 10000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "0x4rwXxUR96O"
+ },
+ "source": [
+ "A crucial difference here is how we `reshape` the array of pixel values. Instead of one image that's 28x28, we now have a set of 60,000 images, each one being 28x28. We also include a number of channels, which for grayscale images as we have here is 1.\n",
+ "\n",
+ "Let's make sure we've got the reshaping parameters right by inspecting the dimensions and the first two images. (Again, mangled input is a very common source of errors.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:23.829853",
+ "start_time": "2016-09-16T14:49:23.527283"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "hb3Vaq72UUxW",
- "colab_type": "text"
- },
- "source": [
- "As with our image data, we'll double-check that our 1-hot encoding of the first few values matches our expectations."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {},
+ {}
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 400,
+ "status": "ok",
+ "timestamp": 1446749129657,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "0AwSo8mlSja_",
+ "outputId": "11490c39-7c67-4fe5-982c-ca8278294d96"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "uEBID71nUVj1",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 127,
- "status": "ok",
- "timestamp": 1446749132853,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "3f318310-18dd-49ed-9943-47b4aae7ee69"
- },
- "source": [
- "print 'Training labels shape', train_labels.shape\n",
- "print 'First label vector', train_labels[0]\n",
- "print 'Second label vector', train_labels[1]"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Training labels shape (60000, 10)\n",
- "First label vector [ 0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]\n",
- "Second label vector [ 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Training data shape (60000, 28, 28, 1)\n"
+ ]
},
{
- "cell_type": "markdown",
- "metadata": {
- "id": "5EwtEhxRUneF",
- "colab_type": "text"
- },
- "source": [
- "The 1-hot encoding looks reasonable.\n",
- "\n",
- "### Segmenting data into training, test, and validation\n",
- "\n",
- "The final step in preparing our data is to split it into three sets: training, test, and validation. This isn't the format of the original data set, so we'll take a small slice of the training data and treat that as our validation set."
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f8444461630>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "print('Training data shape', train_data.shape)\n",
+ "_, (ax1, ax2) = plt.subplots(1, 2)\n",
+ "ax1.imshow(train_data[0].reshape(28, 28), cmap=plt.cm.Greys);\n",
+ "ax2.imshow(train_data[1].reshape(28, 28), cmap=plt.cm.Greys);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "cwBhQ3ouTQcW"
+ },
+ "source": [
+ "Looks good. Now we know how to index our full set of training and test images."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "PBCB9aYxRvBi"
+ },
+ "source": [
+ "### Label data\n",
+ "\n",
+ "Let's move on to loading the full set of labels. As is typical in classification problems, we'll convert our input labels into a [1-hot](https://en.wikipedia.org/wiki/One-hot) encoding over a length 10 vector corresponding to 10 digits. The vector [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], for example, would correspond to the digit 1."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:23.854577",
+ "start_time": "2016-09-16T14:49:23.831545"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "e7aBYBtIVxHE",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 176,
- "status": "ok",
- "timestamp": 1446749134110,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "bdeae1a8-daff-4743-e594-f1d2229c0f4e"
- },
- "source": [
- "VALIDATION_SIZE = 5000\n",
- "\n",
- "validation_data = train_data[:VALIDATION_SIZE, :, :, :]\n",
- "validation_labels = train_labels[:VALIDATION_SIZE]\n",
- "train_data = train_data[VALIDATION_SIZE:, :, :, :]\n",
- "train_labels = train_labels[VALIDATION_SIZE:]\n",
- "\n",
- "train_size = train_labels.shape[0]\n",
- "\n",
- "print 'Validation shape', validation_data.shape\n",
- "print 'Train size', train_size"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Validation shape (5000, 28, 28, 1)\n",
- "Train size 55000\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "1JFhEH8EVj4O",
- "colab_type": "text"
- },
- "source": [
- "# Defining the model\n",
- "\n",
- "Now that we've prepared our data, we're ready to define our model.\n",
- "\n",
- "The comments describe the architecture, which fairly typical of models that process image data. The raw input passes through several [convolution](https://en.wikipedia.org/wiki/Convolutional_neural_network#Convolutional_layer) and [max pooling](https://en.wikipedia.org/wiki/Convolutional_neural_network#Pooling_layer) layers with [rectified linear](https://en.wikipedia.org/wiki/Convolutional_neural_network#ReLU_layer) activations before several fully connected layers and a [softmax](https://en.wikipedia.org/wiki/Convolutional_neural_network#Loss_layer) loss for predicting the output class. During training, we use [dropout](https://en.wikipedia.org/wiki/Convolutional_neural_network#Dropout_method).\n",
- "\n",
- "We'll separate our model definition into three steps:\n",
- "\n",
- "1. Defining the variables that will hold the trainable weights.\n",
- "1. Defining the basic model graph structure described above. And,\n",
- "1. Stamping out several copies of the model graph for training, testing, and validation.\n",
- "\n",
- "We'll start with the variables."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 191,
+ "status": "ok",
+ "timestamp": 1446749131421,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "9pK1j2WlRwY9",
+ "outputId": "1ca31655-e14f-405a-b266-6a6c78827af5"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "Q1VfiAzjzuK8",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 2081,
- "status": "ok",
- "timestamp": 1446749138298,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "f53a39c9-3a52-47ca-d7a3-9f9d84eccf63"
- },
- "source": [
- "import tensorflow as tf\n",
- "\n",
- "# We'll bundle groups of examples during training for efficiency.\n",
- "# This defines the size of the batch.\n",
- "BATCH_SIZE = 60\n",
- "# We have only one channel in our grayscale images.\n",
- "NUM_CHANNELS = 1\n",
- "# The random seed that defines initialization.\n",
- "SEED = 42\n",
- "\n",
- "# This is where training samples and labels are fed to the graph.\n",
- "# These placeholder nodes will be fed a batch of training data at each\n",
- "# training step, which we'll write once we define the graph structure.\n",
- "train_data_node = tf.placeholder(\n",
- " tf.float32,\n",
- " shape=(BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, NUM_CHANNELS))\n",
- "train_labels_node = tf.placeholder(tf.float32,\n",
- " shape=(BATCH_SIZE, NUM_LABELS))\n",
- "\n",
- "# For the validation and test data, we'll just hold the entire dataset in\n",
- "# one constant node.\n",
- "validation_data_node = tf.constant(validation_data)\n",
- "test_data_node = tf.constant(test_data)\n",
- "\n",
- "# The variables below hold all the trainable weights. For each, the\n",
- "# parameter defines how the variables will be initialized.\n",
- "conv1_weights = tf.Variable(\n",
- " tf.truncated_normal([5, 5, NUM_CHANNELS, 32], # 5x5 filter, depth 32.\n",
- " stddev=0.1,\n",
- " seed=SEED))\n",
- "conv1_biases = tf.Variable(tf.zeros([32]))\n",
- "conv2_weights = tf.Variable(\n",
- " tf.truncated_normal([5, 5, 32, 64],\n",
- " stddev=0.1,\n",
- " seed=SEED))\n",
- "conv2_biases = tf.Variable(tf.constant(0.1, shape=[64]))\n",
- "fc1_weights = tf.Variable( # fully connected, depth 512.\n",
- " tf.truncated_normal([IMAGE_SIZE / 4 * IMAGE_SIZE / 4 * 64, 512],\n",
- " stddev=0.1,\n",
- " seed=SEED))\n",
- "fc1_biases = tf.Variable(tf.constant(0.1, shape=[512]))\n",
- "fc2_weights = tf.Variable(\n",
- " tf.truncated_normal([512, NUM_LABELS],\n",
- " stddev=0.1,\n",
- " seed=SEED))\n",
- "fc2_biases = tf.Variable(tf.constant(0.1, shape=[NUM_LABELS]))\n",
- "\n",
- "print 'Done'"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Done\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Extracting /tmp/mnist-data/train-labels-idx1-ubyte.gz\n",
+ "Extracting /tmp/mnist-data/t10k-labels-idx1-ubyte.gz\n"
+ ]
+ }
+ ],
+ "source": [
+ "NUM_LABELS = 10\n",
+ "\n",
+ "def extract_labels(filename, num_images):\n",
+ " \"\"\"Extract the labels into a 1-hot matrix [image index, label index].\"\"\"\n",
+ " print('Extracting', filename)\n",
+ " with gzip.open(filename) as bytestream:\n",
+ " # Skip the magic number and count; we know these values.\n",
+ " bytestream.read(8)\n",
+ " buf = bytestream.read(1 * num_images)\n",
+ " labels = numpy.frombuffer(buf, dtype=numpy.uint8)\n",
+ " # Convert to dense 1-hot representation.\n",
+ " return (numpy.arange(NUM_LABELS) == labels[:, None]).astype(numpy.float32)\n",
+ "\n",
+ "train_labels = extract_labels(train_labels_filename, 60000)\n",
+ "test_labels = extract_labels(test_labels_filename, 10000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "hb3Vaq72UUxW"
+ },
+ "source": [
+ "As with our image data, we'll double-check that our 1-hot encoding of the first few values matches our expectations."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:23.864350",
+ "start_time": "2016-09-16T14:49:23.857177"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "QHB_u04Z4HO6",
- "colab_type": "text"
- },
- "source": [
- "Now that we've defined the variables to be trained, we're ready to wire them together into a TensorFlow graph.\n",
- "\n",
- "We'll define a helper to do this, `model`, which will return copies of the graph suitable for training and testing. Note the `train` argument, which controls whether or not dropout is used in the hidden layer. (We want to use dropout only during training.)"
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "V85_B9QF3uBp",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 772,
- "status": "ok",
- "timestamp": 1446749138306,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "457d3e49-73ad-4451-c196-421dd4681efc"
- },
- "source": [
- "def model(data, train=False):\n",
- " \"\"\"The Model definition.\"\"\"\n",
- " # 2D convolution, with 'SAME' padding (i.e. the output feature map has\n",
- " # the same size as the input). Note that {strides} is a 4D array whose\n",
- " # shape matches the data layout: [image index, y, x, depth].\n",
- " conv = tf.nn.conv2d(data,\n",
- " conv1_weights,\n",
- " strides=[1, 1, 1, 1],\n",
- " padding='SAME')\n",
- "\n",
- " # Bias and rectified linear non-linearity.\n",
- " relu = tf.nn.relu(tf.nn.bias_add(conv, conv1_biases))\n",
- " \n",
- " # Max pooling. The kernel size spec ksize also follows the layout of\n",
- " # the data. Here we have a pooling window of 2, and a stride of 2.\n",
- " pool = tf.nn.max_pool(relu,\n",
- " ksize=[1, 2, 2, 1],\n",
- " strides=[1, 2, 2, 1],\n",
- " padding='SAME')\n",
- " conv = tf.nn.conv2d(pool,\n",
- " conv2_weights,\n",
- " strides=[1, 1, 1, 1],\n",
- " padding='SAME')\n",
- " relu = tf.nn.relu(tf.nn.bias_add(conv, conv2_biases))\n",
- " pool = tf.nn.max_pool(relu,\n",
- " ksize=[1, 2, 2, 1],\n",
- " strides=[1, 2, 2, 1],\n",
- " padding='SAME')\n",
- " \n",
- " # Reshape the feature map cuboid into a 2D matrix to feed it to the\n",
- " # fully connected layers.\n",
- " pool_shape = pool.get_shape().as_list()\n",
- " reshape = tf.reshape(\n",
- " pool,\n",
- " [pool_shape[0], pool_shape[1] * pool_shape[2] * pool_shape[3]])\n",
- " \n",
- " # Fully connected layer. Note that the '+' operation automatically\n",
- " # broadcasts the biases.\n",
- " hidden = tf.nn.relu(tf.matmul(reshape, fc1_weights) + fc1_biases)\n",
- " \n",
- " # Add a 50% dropout during training only. Dropout also scales\n",
- " # activations such that no rescaling is needed at evaluation time.\n",
- " if train:\n",
- " hidden = tf.nn.dropout(hidden, 0.5, seed=SEED)\n",
- " return tf.matmul(hidden, fc2_weights) + fc2_biases\n",
- "\n",
- "print 'Done'"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Done\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 127,
+ "status": "ok",
+ "timestamp": 1446749132853,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "uEBID71nUVj1",
+ "outputId": "3f318310-18dd-49ed-9943-47b4aae7ee69"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "7bvEtt8C4fLC",
- "colab_type": "text"
- },
- "source": [
- "Having defined the basic structure of the graph, we're ready to stamp out multiple copies for training, testing, and validation.\n",
- "\n",
- "Here, we'll do some customizations depending on which graph we're constructing. `train_prediction` holds the training graph, for which we use cross-entropy loss and weight regularization. We'll adjust the learning rate during training -- that's handled by the `exponential_decay` operation, which is itself an argument to the `MomentumOptimizer` that performs the actual training.\n",
- "\n",
- "The vaildation and prediction graphs are much simpler the generate -- we need only create copies of the model with the validation and test inputs and a softmax classifier as the output."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Training labels shape (60000, 10)\n",
+ "First label vector [ 0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]\n",
+ "Second label vector [ 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n"
+ ]
+ }
+ ],
+ "source": [
+ "print('Training labels shape', train_labels.shape)\n",
+ "print('First label vector', train_labels[0])\n",
+ "print('Second label vector', train_labels[1])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "5EwtEhxRUneF"
+ },
+ "source": [
+ "The 1-hot encoding looks reasonable.\n",
+ "\n",
+ "### Segmenting data into training, test, and validation\n",
+ "\n",
+ "The final step in preparing our data is to split it into three sets: training, test, and validation. This isn't the format of the original data set, so we'll take a small slice of the training data and treat that as our validation set."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:23.874014",
+ "start_time": "2016-09-16T14:49:23.866161"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "9pR1EBNT3sCv",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 269,
- "status": "ok",
- "timestamp": 1446749139596,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "570681b1-f33e-4618-b742-48e12aa58132"
- },
- "source": [
- "# Training computation: logits + cross-entropy loss.\n",
- "logits = model(train_data_node, True)\n",
- "loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(\n",
- " logits, train_labels_node))\n",
- "\n",
- "# L2 regularization for the fully connected parameters.\n",
- "regularizers = (tf.nn.l2_loss(fc1_weights) + tf.nn.l2_loss(fc1_biases) +\n",
- " tf.nn.l2_loss(fc2_weights) + tf.nn.l2_loss(fc2_biases))\n",
- "# Add the regularization term to the loss.\n",
- "loss += 5e-4 * regularizers\n",
- "\n",
- "# Optimizer: set up a variable that's incremented once per batch and\n",
- "# controls the learning rate decay.\n",
- "batch = tf.Variable(0)\n",
- "# Decay once per epoch, using an exponential schedule starting at 0.01.\n",
- "learning_rate = tf.train.exponential_decay(\n",
- " 0.01, # Base learning rate.\n",
- " batch * BATCH_SIZE, # Current index into the dataset.\n",
- " train_size, # Decay step.\n",
- " 0.95, # Decay rate.\n",
- " staircase=True)\n",
- "# Use simple momentum for the optimization.\n",
- "optimizer = tf.train.MomentumOptimizer(learning_rate,\n",
- " 0.9).minimize(loss,\n",
- " global_step=batch)\n",
- "\n",
- "# Predictions for the minibatch, validation set and test set.\n",
- "train_prediction = tf.nn.softmax(logits)\n",
- "# We'll compute them only once in a while by calling their {eval()} method.\n",
- "validation_prediction = tf.nn.softmax(model(validation_data_node))\n",
- "test_prediction = tf.nn.softmax(model(test_data_node))\n",
- "\n",
- "print 'Done'"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Done\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "4T21uZJq5UfH",
- "colab_type": "text"
- },
- "source": [
- "# Training and visualizing results\n",
- "\n",
- "Now that we have the training, test, and validation graphs, we're ready to actually go through the training loop and periodically evaluate loss and error.\n",
- "\n",
- "All of these operations take place in the context of a session. In Python, we'd write something like:\n",
- "\n",
- " with tf.Session() as s:\n",
- " ...training / test / evaluation loop...\n",
- " \n",
- "But, here, we'll want to keep the session open so we can poke at values as we work out the details of training. The TensorFlow API includes a function for this, `InteractiveSession`.\n",
- "\n",
- "We'll start by creating a session and initializing the varibles we defined above."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 176,
+ "status": "ok",
+ "timestamp": 1446749134110,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "e7aBYBtIVxHE",
+ "outputId": "bdeae1a8-daff-4743-e594-f1d2229c0f4e"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "z6Kc5iql6qxV",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- }
- },
- "cellView": "both"
- },
- "source": [
- "# Create a new interactive session that we'll use in\n",
- "# subsequent code cells.\n",
- "s = tf.InteractiveSession()\n",
- "\n",
- "# Use our newly created session as the default for \n",
- "# subsequent operations.\n",
- "s.as_default()\n",
- "\n",
- "# Initialize all the variables we defined above.\n",
- "tf.initialize_all_variables().run()"
- ],
- "outputs": [],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Validation shape (5000, 28, 28, 1)\n",
+ "Train size 55000\n"
+ ]
+ }
+ ],
+ "source": [
+ "VALIDATION_SIZE = 5000\n",
+ "\n",
+ "validation_data = train_data[:VALIDATION_SIZE, :, :, :]\n",
+ "validation_labels = train_labels[:VALIDATION_SIZE]\n",
+ "train_data = train_data[VALIDATION_SIZE:, :, :, :]\n",
+ "train_labels = train_labels[VALIDATION_SIZE:]\n",
+ "\n",
+ "train_size = train_labels.shape[0]\n",
+ "\n",
+ "print('Validation shape', validation_data.shape)\n",
+ "print('Train size', train_size)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "1JFhEH8EVj4O"
+ },
+ "source": [
+ "# Defining the model\n",
+ "\n",
+ "Now that we've prepared our data, we're ready to define our model.\n",
+ "\n",
+ "The comments describe the architecture, which fairly typical of models that process image data. The raw input passes through several [convolution](https://en.wikipedia.org/wiki/Convolutional_neural_network#Convolutional_layer) and [max pooling](https://en.wikipedia.org/wiki/Convolutional_neural_network#Pooling_layer) layers with [rectified linear](https://en.wikipedia.org/wiki/Convolutional_neural_network#ReLU_layer) activations before several fully connected layers and a [softmax](https://en.wikipedia.org/wiki/Convolutional_neural_network#Loss_layer) loss for predicting the output class. During training, we use [dropout](https://en.wikipedia.org/wiki/Convolutional_neural_network#Dropout_method).\n",
+ "\n",
+ "We'll separate our model definition into three steps:\n",
+ "\n",
+ "1. Defining the variables that will hold the trainable weights.\n",
+ "1. Defining the basic model graph structure described above. And,\n",
+ "1. Stamping out several copies of the model graph for training, testing, and validation.\n",
+ "\n",
+ "We'll start with the variables."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:28.803525",
+ "start_time": "2016-09-16T14:49:23.875999"
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "hcG8H-Ka6_mw",
- "colab_type": "text"
- },
- "source": [
- "Now we're ready to perform operations on the graph. Let's start with one round of training. We're going to organize our training steps into batches for efficiency; i.e., training using a small set of examples at each step rather than a single example."
- ]
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "LYVxeEox71Pg",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 386,
- "status": "ok",
- "timestamp": 1446749389138,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "9184b5df-009a-4b1b-e312-5be94351351f"
- },
- "source": [
- "BATCH_SIZE = 60\n",
- "\n",
- "# Grab the first BATCH_SIZE examples and labels.\n",
- "batch_data = train_data[:BATCH_SIZE, :, :, :]\n",
- "batch_labels = train_labels[:BATCH_SIZE]\n",
- "\n",
- "# This dictionary maps the batch data (as a numpy array) to the\n",
- "# node in the graph it should be fed to.\n",
- "feed_dict = {train_data_node: batch_data,\n",
- " train_labels_node: batch_labels}\n",
- "\n",
- "# Run the graph and fetch some of the nodes.\n",
- "_, l, lr, predictions = s.run(\n",
- " [optimizer, loss, learning_rate, train_prediction],\n",
- " feed_dict=feed_dict)\n",
- "\n",
- "print 'Done'"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Done\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 2081,
+ "status": "ok",
+ "timestamp": 1446749138298,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "Q1VfiAzjzuK8",
+ "outputId": "f53a39c9-3a52-47ca-d7a3-9f9d84eccf63"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "7bL4-RNm_K-B",
- "colab_type": "text"
- },
- "source": [
- "Let's take a look at the predictions. How did we do? Recall that the output will be probabilities over the possible classes, so let's look at those probabilities."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Done\n"
+ ]
+ }
+ ],
+ "source": [
+ "import tensorflow as tf\n",
+ "\n",
+ "# We'll bundle groups of examples during training for efficiency.\n",
+ "# This defines the size of the batch.\n",
+ "BATCH_SIZE = 60\n",
+ "# We have only one channel in our grayscale images.\n",
+ "NUM_CHANNELS = 1\n",
+ "# The random seed that defines initialization.\n",
+ "SEED = 42\n",
+ "\n",
+ "# This is where training samples and labels are fed to the graph.\n",
+ "# These placeholder nodes will be fed a batch of training data at each\n",
+ "# training step, which we'll write once we define the graph structure.\n",
+ "train_data_node = tf.placeholder(\n",
+ " tf.float32,\n",
+ " shape=(BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, NUM_CHANNELS))\n",
+ "train_labels_node = tf.placeholder(tf.float32,\n",
+ " shape=(BATCH_SIZE, NUM_LABELS))\n",
+ "\n",
+ "# For the validation and test data, we'll just hold the entire dataset in\n",
+ "# one constant node.\n",
+ "validation_data_node = tf.constant(validation_data)\n",
+ "test_data_node = tf.constant(test_data)\n",
+ "\n",
+ "# The variables below hold all the trainable weights. For each, the\n",
+ "# parameter defines how the variables will be initialized.\n",
+ "conv1_weights = tf.Variable(\n",
+ " tf.truncated_normal([5, 5, NUM_CHANNELS, 32], # 5x5 filter, depth 32.\n",
+ " stddev=0.1,\n",
+ " seed=SEED))\n",
+ "conv1_biases = tf.Variable(tf.zeros([32]))\n",
+ "conv2_weights = tf.Variable(\n",
+ " tf.truncated_normal([5, 5, 32, 64],\n",
+ " stddev=0.1,\n",
+ " seed=SEED))\n",
+ "conv2_biases = tf.Variable(tf.constant(0.1, shape=[64]))\n",
+ "fc1_weights = tf.Variable( # fully connected, depth 512.\n",
+ " tf.truncated_normal([IMAGE_SIZE // 4 * IMAGE_SIZE // 4 * 64, 512],\n",
+ " stddev=0.1,\n",
+ " seed=SEED))\n",
+ "fc1_biases = tf.Variable(tf.constant(0.1, shape=[512]))\n",
+ "fc2_weights = tf.Variable(\n",
+ " tf.truncated_normal([512, NUM_LABELS],\n",
+ " stddev=0.1,\n",
+ " seed=SEED))\n",
+ "fc2_biases = tf.Variable(tf.constant(0.1, shape=[NUM_LABELS]))\n",
+ "\n",
+ "print('Done')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "QHB_u04Z4HO6"
+ },
+ "source": [
+ "Now that we've defined the variables to be trained, we're ready to wire them together into a TensorFlow graph.\n",
+ "\n",
+ "We'll define a helper to do this, `model`, which will return copies of the graph suitable for training and testing. Note the `train` argument, which controls whether or not dropout is used in the hidden layer. (We want to use dropout only during training.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:28.834326",
+ "start_time": "2016-09-16T14:49:28.805723"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "2eNitV_4_ZUL",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 160,
- "status": "ok",
- "timestamp": 1446749519023,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "f1340dd1-255b-4523-bf62-7e3ebb361333"
- },
- "source": [
- "print predictions[0]"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "[ 2.25393465e-04 4.76219648e-05 1.66868104e-03 5.67830284e-05\n",
- " 6.03432834e-01 4.34970111e-02 2.19316153e-05 1.41285171e-04\n",
- " 1.54902827e-05 3.50893021e-01]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "X5MgraJb_eQZ",
- "colab_type": "text"
- },
- "source": [
- "As expected without training, the predictions are all noise. Let's write a scoring function that picks the class with the maximum probability and compares with the example's label. We'll start by converting the probability vectors returned by the softmax into predictions we can match against the labels."
- ]
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 772,
+ "status": "ok",
+ "timestamp": 1446749138306,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "V85_B9QF3uBp",
+ "outputId": "457d3e49-73ad-4451-c196-421dd4681efc"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "wMMlUf5rCKgT",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 220,
- "status": "ok",
- "timestamp": 1446750411574,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "2c10e96d-52b6-47b0-b6eb-969ad462d46b"
- },
- "source": [
- "# The highest probability in the first entry.\n",
- "print 'First prediction', numpy.argmax(predictions[0])\n",
- "\n",
- "# But, predictions is actually a list of BATCH_SIZE probability vectors.\n",
- "print predictions.shape\n",
- "\n",
- "# So, we'll take the highest probability for each vector.\n",
- "print 'All predictions', numpy.argmax(predictions, 1)"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "First prediction 4\n",
- "(60, 10)\n",
- "All predictions [4 4 2 7 7 7 7 7 7 7 7 7 0 8 9 0 7 7 0 7 4 0 5 0 9 9 7 0 7 4 7 7 7 0 7 7 9\n",
- " 7 9 9 0 7 7 7 2 7 0 7 2 9 9 9 9 9 0 7 9 4 8 7]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Done\n"
+ ]
+ }
+ ],
+ "source": [
+ "def model(data, train=False):\n",
+ " \"\"\"The Model definition.\"\"\"\n",
+ " # 2D convolution, with 'SAME' padding (i.e. the output feature map has\n",
+ " # the same size as the input). Note that {strides} is a 4D array whose\n",
+ " # shape matches the data layout: [image index, y, x, depth].\n",
+ " conv = tf.nn.conv2d(data,\n",
+ " conv1_weights,\n",
+ " strides=[1, 1, 1, 1],\n",
+ " padding='SAME')\n",
+ "\n",
+ " # Bias and rectified linear non-linearity.\n",
+ " relu = tf.nn.relu(tf.nn.bias_add(conv, conv1_biases))\n",
+ "\n",
+ " # Max pooling. The kernel size spec ksize also follows the layout of\n",
+ " # the data. Here we have a pooling window of 2, and a stride of 2.\n",
+ " pool = tf.nn.max_pool(relu,\n",
+ " ksize=[1, 2, 2, 1],\n",
+ " strides=[1, 2, 2, 1],\n",
+ " padding='SAME')\n",
+ " conv = tf.nn.conv2d(pool,\n",
+ " conv2_weights,\n",
+ " strides=[1, 1, 1, 1],\n",
+ " padding='SAME')\n",
+ " relu = tf.nn.relu(tf.nn.bias_add(conv, conv2_biases))\n",
+ " pool = tf.nn.max_pool(relu,\n",
+ " ksize=[1, 2, 2, 1],\n",
+ " strides=[1, 2, 2, 1],\n",
+ " padding='SAME')\n",
+ "\n",
+ " # Reshape the feature map cuboid into a 2D matrix to feed it to the\n",
+ " # fully connected layers.\n",
+ " pool_shape = pool.get_shape().as_list()\n",
+ " reshape = tf.reshape(\n",
+ " pool,\n",
+ " [pool_shape[0], pool_shape[1] * pool_shape[2] * pool_shape[3]])\n",
+ " \n",
+ " # Fully connected layer. Note that the '+' operation automatically\n",
+ " # broadcasts the biases.\n",
+ " hidden = tf.nn.relu(tf.matmul(reshape, fc1_weights) + fc1_biases)\n",
+ "\n",
+ " # Add a 50% dropout during training only. Dropout also scales\n",
+ " # activations such that no rescaling is needed at evaluation time.\n",
+ " if train:\n",
+ " hidden = tf.nn.dropout(hidden, 0.5, seed=SEED)\n",
+ " return tf.matmul(hidden, fc2_weights) + fc2_biases\n",
+ "\n",
+ "print('Done')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "7bvEtt8C4fLC"
+ },
+ "source": [
+ "Having defined the basic structure of the graph, we're ready to stamp out multiple copies for training, testing, and validation.\n",
+ "\n",
+ "Here, we'll do some customizations depending on which graph we're constructing. `train_prediction` holds the training graph, for which we use cross-entropy loss and weight regularization. We'll adjust the learning rate during training -- that's handled by the `exponential_decay` operation, which is itself an argument to the `MomentumOptimizer` that performs the actual training.\n",
+ "\n",
+ "The vaildation and prediction graphs are much simpler the generate -- we need only create copies of the model with the validation and test inputs and a softmax classifier as the output."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:29.058141",
+ "start_time": "2016-09-16T14:49:28.836169"
},
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 269,
+ "status": "ok",
+ "timestamp": 1446749139596,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "9pR1EBNT3sCv",
+ "outputId": "570681b1-f33e-4618-b742-48e12aa58132"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "8pMCIZ3_C2ni",
- "colab_type": "text"
- },
- "source": [
- "Next, we can do the same thing for our labels -- using `argmax` to convert our 1-hot encoding into a digit class."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Done\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Training computation: logits + cross-entropy loss.\n",
+ "logits = model(train_data_node, True)\n",
+ "loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(\n",
+ " logits, train_labels_node))\n",
+ "\n",
+ "# L2 regularization for the fully connected parameters.\n",
+ "regularizers = (tf.nn.l2_loss(fc1_weights) + tf.nn.l2_loss(fc1_biases) +\n",
+ " tf.nn.l2_loss(fc2_weights) + tf.nn.l2_loss(fc2_biases))\n",
+ "# Add the regularization term to the loss.\n",
+ "loss += 5e-4 * regularizers\n",
+ "\n",
+ "# Optimizer: set up a variable that's incremented once per batch and\n",
+ "# controls the learning rate decay.\n",
+ "batch = tf.Variable(0)\n",
+ "# Decay once per epoch, using an exponential schedule starting at 0.01.\n",
+ "learning_rate = tf.train.exponential_decay(\n",
+ " 0.01, # Base learning rate.\n",
+ " batch * BATCH_SIZE, # Current index into the dataset.\n",
+ " train_size, # Decay step.\n",
+ " 0.95, # Decay rate.\n",
+ " staircase=True)\n",
+ "# Use simple momentum for the optimization.\n",
+ "optimizer = tf.train.MomentumOptimizer(learning_rate,\n",
+ " 0.9).minimize(loss,\n",
+ " global_step=batch)\n",
+ "\n",
+ "# Predictions for the minibatch, validation set and test set.\n",
+ "train_prediction = tf.nn.softmax(logits)\n",
+ "# We'll compute them only once in a while by calling their {eval()} method.\n",
+ "validation_prediction = tf.nn.softmax(model(validation_data_node))\n",
+ "test_prediction = tf.nn.softmax(model(test_data_node))\n",
+ "\n",
+ "print('Done')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "4T21uZJq5UfH"
+ },
+ "source": [
+ "# Training and visualizing results\n",
+ "\n",
+ "Now that we have the training, test, and validation graphs, we're ready to actually go through the training loop and periodically evaluate loss and error.\n",
+ "\n",
+ "All of these operations take place in the context of a session. In Python, we'd write something like:\n",
+ "\n",
+ " with tf.Session() as s:\n",
+ " ...training / test / evaluation loop...\n",
+ " \n",
+ "But, here, we'll want to keep the session open so we can poke at values as we work out the details of training. The TensorFlow API includes a function for this, `InteractiveSession`.\n",
+ "\n",
+ "We'll start by creating a session and initializing the varibles we defined above."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:29.357483",
+ "start_time": "2016-09-16T14:49:29.059952"
+ },
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ }
+ },
+ "colab_type": "code",
+ "collapsed": true,
+ "id": "z6Kc5iql6qxV"
+ },
+ "outputs": [],
+ "source": [
+ "# Create a new interactive session that we'll use in\n",
+ "# subsequent code cells.\n",
+ "s = tf.InteractiveSession()\n",
+ "\n",
+ "# Use our newly created session as the default for \n",
+ "# subsequent operations.\n",
+ "s.as_default()\n",
+ "\n",
+ "# Initialize all the variables we defined above.\n",
+ "tf.initialize_all_variables().run()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "hcG8H-Ka6_mw"
+ },
+ "source": [
+ "Now we're ready to perform operations on the graph. Let's start with one round of training. We're going to organize our training steps into batches for efficiency; i.e., training using a small set of examples at each step rather than a single example."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:29.584699",
+ "start_time": "2016-09-16T14:49:29.359107"
},
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 386,
+ "status": "ok",
+ "timestamp": 1446749389138,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "LYVxeEox71Pg",
+ "outputId": "9184b5df-009a-4b1b-e312-5be94351351f"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "kZWp4T0JDDUe",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 232,
- "status": "ok",
- "timestamp": 1446750498351,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "47b588cd-bc82-45c3-a5d0-8d84dc27a3be"
- },
- "source": [
- "print 'Batch labels', numpy.argmax(batch_labels, 1)"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Batch labels [7 3 4 6 1 8 1 0 9 8 0 3 1 2 7 0 2 9 6 0 1 6 7 1 9 7 6 5 5 8 8 3 4 4 8 7 3\n",
- " 6 4 6 6 3 8 8 9 9 4 4 0 7 8 1 0 0 1 8 5 7 1 7]\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Done\n"
+ ]
+ }
+ ],
+ "source": [
+ "BATCH_SIZE = 60\n",
+ "\n",
+ "# Grab the first BATCH_SIZE examples and labels.\n",
+ "batch_data = train_data[:BATCH_SIZE, :, :, :]\n",
+ "batch_labels = train_labels[:BATCH_SIZE]\n",
+ "\n",
+ "# This dictionary maps the batch data (as a numpy array) to the\n",
+ "# node in the graph it should be fed to.\n",
+ "feed_dict = {train_data_node: batch_data,\n",
+ " train_labels_node: batch_labels}\n",
+ "\n",
+ "# Run the graph and fetch some of the nodes.\n",
+ "_, l, lr, predictions = s.run(\n",
+ " [optimizer, loss, learning_rate, train_prediction],\n",
+ " feed_dict=feed_dict)\n",
+ "\n",
+ "print('Done')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "7bL4-RNm_K-B"
+ },
+ "source": [
+ "Let's take a look at the predictions. How did we do? Recall that the output will be probabilities over the possible classes, so let's look at those probabilities."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:29.593985",
+ "start_time": "2016-09-16T14:49:29.586233"
},
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 160,
+ "status": "ok",
+ "timestamp": 1446749519023,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "2eNitV_4_ZUL",
+ "outputId": "f1340dd1-255b-4523-bf62-7e3ebb361333"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "bi5Z6whtDiht",
- "colab_type": "text"
- },
- "source": [
- "Now we can compare the predicted and label classes to compute the error rate and confusion matrix for this batch."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[ 2.25393116e-04 4.76219611e-05 1.66867452e-03 5.67827519e-05\n",
+ " 6.03432178e-01 4.34969068e-02 2.19316553e-05 1.41286102e-04\n",
+ " 1.54903100e-05 3.50893795e-01]\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(predictions[0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "X5MgraJb_eQZ"
+ },
+ "source": [
+ "As expected without training, the predictions are all noise. Let's write a scoring function that picks the class with the maximum probability and compares with the example's label. We'll start by converting the probability vectors returned by the softmax into predictions we can match against the labels."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:29.606284",
+ "start_time": "2016-09-16T14:49:29.597095"
+ },
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 220,
+ "status": "ok",
+ "timestamp": 1446750411574,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "wMMlUf5rCKgT",
+ "outputId": "2c10e96d-52b6-47b0-b6eb-969ad462d46b"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "U4hrLW4CDtQB",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- },
- {
- "item_id": 2
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 330,
- "status": "ok",
- "timestamp": 1446751307304,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "720494a3-cbf9-4687-9d94-e64a33fdd78f"
- },
- "source": [
- "correct = numpy.sum(numpy.argmax(predictions, 1) == numpy.argmax(batch_labels, 1))\n",
- "total = predictions.shape[0]\n",
- "\n",
- "print float(correct) / float(total)\n",
- "\n",
- "confusions = numpy.zeros([10, 10], numpy.float32)\n",
- "bundled = zip(numpy.argmax(predictions, 1), numpy.argmax(batch_labels, 1))\n",
- "for predicted, actual in bundled:\n",
- " confusions[predicted, actual] += 1\n",
- "\n",
- "plt.grid(False)\n",
- "plt.xticks(numpy.arange(NUM_LABELS))\n",
- "plt.yticks(numpy.arange(NUM_LABELS))\n",
- "plt.imshow(confusions, cmap=plt.cm.jet, interpolation='nearest');"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "0.0666666666667\n"
- ],
- "name": "stdout"
- },
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\nTkSuQmCC\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f226836c350>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "First prediction 4\n",
+ "(60, 10)\n",
+ "All predictions [4 4 2 7 7 7 7 7 7 7 7 7 0 8 9 0 7 7 0 7 4 0 5 0 9 9 7 0 7 4 7 7 7 0 7 7 9\n",
+ " 7 9 9 0 7 7 7 2 7 0 7 2 9 9 9 9 9 0 7 9 4 8 7]\n"
+ ]
+ }
+ ],
+ "source": [
+ "# The highest probability in the first entry.\n",
+ "print('First prediction', numpy.argmax(predictions[0]))\n",
+ "\n",
+ "# But, predictions is actually a list of BATCH_SIZE probability vectors.\n",
+ "print(predictions.shape)\n",
+ "\n",
+ "# So, we'll take the highest probability for each vector.\n",
+ "print('All predictions', numpy.argmax(predictions, 1))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "8pMCIZ3_C2ni"
+ },
+ "source": [
+ "Next, we can do the same thing for our labels -- using `argmax` to convert our 1-hot encoding into a digit class."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:29.615484",
+ "start_time": "2016-09-16T14:49:29.609168"
+ },
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 232,
+ "status": "ok",
+ "timestamp": 1446750498351,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "kZWp4T0JDDUe",
+ "outputId": "47b588cd-bc82-45c3-a5d0-8d84dc27a3be"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "iZmx_9DiDXQ3",
- "colab_type": "text"
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Batch labels [7 3 4 6 1 8 1 0 9 8 0 3 1 2 7 0 2 9 6 0 1 6 7 1 9 7 6 5 5 8 8 3 4 4 8 7 3\n",
+ " 6 4 6 6 3 8 8 9 9 4 4 0 7 8 1 0 0 1 8 5 7 1 7]\n"
+ ]
+ }
+ ],
+ "source": [
+ "print('Batch labels', numpy.argmax(batch_labels, 1))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "bi5Z6whtDiht"
+ },
+ "source": [
+ "Now we can compare the predicted and label classes to compute the error rate and confusion matrix for this batch."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:29.841313",
+ "start_time": "2016-09-16T14:49:29.618274"
+ },
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
},
- "source": [
- "Now let's wrap this up into our scoring function."
- ]
+ {
+ "item_id": 2
+ }
+ ]
},
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 330,
+ "status": "ok",
+ "timestamp": 1446751307304,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
+ },
+ "id": "U4hrLW4CDtQB",
+ "outputId": "720494a3-cbf9-4687-9d94-e64a33fdd78f"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "DPJie7bPDaLa",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 178,
- "status": "ok",
- "timestamp": 1446751995007,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "a06c64ed-f95f-416f-a621-44cccdaba0f8"
- },
- "source": [
- "def error_rate(predictions, labels):\n",
- " \"\"\"Return the error rate and confusions.\"\"\"\n",
- " correct = numpy.sum(numpy.argmax(predictions, 1) == numpy.argmax(labels, 1))\n",
- " total = predictions.shape[0]\n",
- "\n",
- " error = 100.0 - (100 * float(correct) / float(total))\n",
- "\n",
- " confusions = numpy.zeros([10, 10], numpy.float32)\n",
- " bundled = zip(numpy.argmax(predictions, 1), numpy.argmax(labels, 1))\n",
- " for predicted, actual in bundled:\n",
- " confusions[predicted, actual] += 1\n",
- " \n",
- " return error, confusions\n",
- "\n",
- "print 'Done'"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Done\n"
- ],
- "name": "stdout"
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "0.06666666666666667\n"
+ ]
},
{
- "cell_type": "markdown",
- "metadata": {
- "id": "sLv22cjeB5Rd",
- "colab_type": "text"
- },
- "source": [
- "We'll need to train for some time to actually see useful predicted values. Let's define a loop that will go through our data. We'll print the loss and error periodically.\n",
- "\n",
- "Here, we want to iterate over the entire data set rather than just the first batch, so we'll need to slice the data to that end.\n",
- "\n",
- "(One pass through our training set will take some time on a CPU, so be patient if you are executing this notebook.)"
+ "data": {
+ "image/png": "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\n9OY6UgAAAABJRU5ErkJggg==\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f841ece8128>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "correct = numpy.sum(numpy.argmax(predictions, 1) == numpy.argmax(batch_labels, 1))\n",
+ "total = predictions.shape[0]\n",
+ "\n",
+ "print(float(correct) / float(total))\n",
+ "\n",
+ "confusions = numpy.zeros([10, 10], numpy.float32)\n",
+ "bundled = zip(numpy.argmax(predictions, 1), numpy.argmax(batch_labels, 1))\n",
+ "for predicted, actual in bundled:\n",
+ " confusions[predicted, actual] += 1\n",
+ "\n",
+ "plt.grid(False)\n",
+ "plt.xticks(numpy.arange(NUM_LABELS))\n",
+ "plt.yticks(numpy.arange(NUM_LABELS))\n",
+ "plt.imshow(confusions, cmap=plt.cm.jet, interpolation='nearest');"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "iZmx_9DiDXQ3"
+ },
+ "source": [
+ "Now let's wrap this up into our scoring function."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:49:29.857607",
+ "start_time": "2016-09-16T14:49:29.843904"
+ },
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 178,
+ "status": "ok",
+ "timestamp": 1446751995007,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "DPJie7bPDaLa",
+ "outputId": "a06c64ed-f95f-416f-a621-44cccdaba0f8"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "4cgKJrS1_vej",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- }
- },
- "cellView": "both"
- },
- "source": [
- "# Train over the first 1/4th of our training set.\n",
- "steps = int(train_size / BATCH_SIZE)\n",
- "for step in xrange(steps):\n",
- " # Compute the offset of the current minibatch in the data.\n",
- " # Note that we could use better randomization across epochs.\n",
- " offset = (step * BATCH_SIZE) % (train_size - BATCH_SIZE)\n",
- " batch_data = train_data[offset:(offset + BATCH_SIZE), :, :, :]\n",
- " batch_labels = train_labels[offset:(offset + BATCH_SIZE)]\n",
- " # This dictionary maps the batch data (as a numpy array) to the\n",
- " # node in the graph it should be fed to.\n",
- " feed_dict = {train_data_node: batch_data,\n",
- " train_labels_node: batch_labels}\n",
- " # Run the graph and fetch some of the nodes.\n",
- " _, l, lr, predictions = s.run(\n",
- " [optimizer, loss, learning_rate, train_prediction],\n",
- " feed_dict=feed_dict)\n",
- " \n",
- " # Print out the loss periodically.\n",
- " if step % 100 == 0:\n",
- " error, _ = error_rate(predictions, batch_labels)\n",
- " print 'Step %d of %d' % (step, steps)\n",
- " print 'Mini-batch loss: %.5f Error: %.5f Learning rate: %.5f' % (l, error, lr)\n",
- " print 'Validation error: %.1f%%' % error_rate(\n",
- " validation_prediction.eval(), validation_labels)[0]\n"
- ],
- "outputs": [],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Done\n"
+ ]
+ }
+ ],
+ "source": [
+ "def error_rate(predictions, labels):\n",
+ " \"\"\"Return the error rate and confusions.\"\"\"\n",
+ " correct = numpy.sum(numpy.argmax(predictions, 1) == numpy.argmax(labels, 1))\n",
+ " total = predictions.shape[0]\n",
+ "\n",
+ " error = 100.0 - (100 * float(correct) / float(total))\n",
+ "\n",
+ " confusions = numpy.zeros([10, 10], numpy.float32)\n",
+ " bundled = zip(numpy.argmax(predictions, 1), numpy.argmax(labels, 1))\n",
+ " for predicted, actual in bundled:\n",
+ " confusions[predicted, actual] += 1\n",
+ " \n",
+ " return error, confusions\n",
+ "\n",
+ "print('Done')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "sLv22cjeB5Rd"
+ },
+ "source": [
+ "We'll need to train for some time to actually see useful predicted values. Let's define a loop that will go through our data. We'll print the loss and error periodically.\n",
+ "\n",
+ "Here, we want to iterate over the entire data set rather than just the first batch, so we'll need to slice the data to that end.\n",
+ "\n",
+ "(One pass through our training set will take some time on a CPU, so be patient if you are executing this notebook.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:53:26.998313",
+ "start_time": "2016-09-16T14:49:29.860079"
},
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ }
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "id": "4cgKJrS1_vej"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "J4LskgGXIDAm",
- "colab_type": "text"
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Step 0 of 916\n",
+ "Mini-batch loss: 7.71249 Error: 91.66667 Learning rate: 0.01000\n",
+ "Validation error: 88.9%\n",
+ "Step 100 of 916\n",
+ "Mini-batch loss: 3.28715 Error: 8.33333 Learning rate: 0.01000\n",
+ "Validation error: 5.8%\n",
+ "Step 200 of 916\n",
+ "Mini-batch loss: 3.30949 Error: 8.33333 Learning rate: 0.01000\n",
+ "Validation error: 3.6%\n",
+ "Step 300 of 916\n",
+ "Mini-batch loss: 3.15385 Error: 3.33333 Learning rate: 0.01000\n",
+ "Validation error: 3.1%\n",
+ "Step 400 of 916\n",
+ "Mini-batch loss: 3.08212 Error: 1.66667 Learning rate: 0.01000\n",
+ "Validation error: 2.7%\n",
+ "Step 500 of 916\n",
+ "Mini-batch loss: 3.02827 Error: 1.66667 Learning rate: 0.01000\n",
+ "Validation error: 2.2%\n",
+ "Step 600 of 916\n",
+ "Mini-batch loss: 3.03260 Error: 5.00000 Learning rate: 0.01000\n",
+ "Validation error: 1.9%\n",
+ "Step 700 of 916\n",
+ "Mini-batch loss: 3.16032 Error: 6.66667 Learning rate: 0.01000\n",
+ "Validation error: 2.2%\n",
+ "Step 800 of 916\n",
+ "Mini-batch loss: 3.06246 Error: 3.33333 Learning rate: 0.01000\n",
+ "Validation error: 2.0%\n",
+ "Step 900 of 916\n",
+ "Mini-batch loss: 2.85098 Error: 0.00000 Learning rate: 0.01000\n",
+ "Validation error: 1.9%\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Train over the first 1/4th of our training set.\n",
+ "steps = train_size // BATCH_SIZE\n",
+ "for step in range(steps):\n",
+ " # Compute the offset of the current minibatch in the data.\n",
+ " # Note that we could use better randomization across epochs.\n",
+ " offset = (step * BATCH_SIZE) % (train_size - BATCH_SIZE)\n",
+ " batch_data = train_data[offset:(offset + BATCH_SIZE), :, :, :]\n",
+ " batch_labels = train_labels[offset:(offset + BATCH_SIZE)]\n",
+ " # This dictionary maps the batch data (as a numpy array) to the\n",
+ " # node in the graph it should be fed to.\n",
+ " feed_dict = {train_data_node: batch_data,\n",
+ " train_labels_node: batch_labels}\n",
+ " # Run the graph and fetch some of the nodes.\n",
+ " _, l, lr, predictions = s.run(\n",
+ " [optimizer, loss, learning_rate, train_prediction],\n",
+ " feed_dict=feed_dict)\n",
+ " \n",
+ " # Print out the loss periodically.\n",
+ " if step % 100 == 0:\n",
+ " error, _ = error_rate(predictions, batch_labels)\n",
+ " print('Step %d of %d' % (step, steps))\n",
+ " print('Mini-batch loss: %.5f Error: %.5f Learning rate: %.5f' % (l, error, lr))\n",
+ " print('Validation error: %.1f%%' % error_rate(\n",
+ " validation_prediction.eval(), validation_labels)[0])\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "J4LskgGXIDAm"
+ },
+ "source": [
+ "The error seems to have gone down. Let's evaluate the results using the test set.\n",
+ "\n",
+ "To help identify rare mispredictions, we'll include the raw count of each (prediction, label) pair in the confusion matrix."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:55:10.942063",
+ "start_time": "2016-09-16T14:53:26.999971"
+ },
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
},
- "source": [
- "The error seems to have gone down. Let's evaluate the results using the test set.\n",
- "\n",
- "To help identify rare mispredictions, we'll include the raw count of each (prediction, label) pair in the confusion matrix."
- ]
+ {
+ "item_id": 2
+ }
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 436,
+ "status": "ok",
+ "timestamp": 1446752934104,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "6Yh1jGFuIKc_",
+ "outputId": "4e411de4-0fe2-451b-e4ca-8a4854f0db89"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "6Yh1jGFuIKc_",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- },
- {
- "item_id": 2
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 436,
- "status": "ok",
- "timestamp": 1446752934104,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "4e411de4-0fe2-451b-e4ca-8a4854f0db89"
- },
- "source": [
- "test_error, confusions = error_rate(test_prediction.eval(), test_labels)\n",
- "print 'Test error: %.1f%%' % test_error\n",
- "\n",
- "plt.xlabel('Actual')\n",
- "plt.ylabel('Predicted')\n",
- "plt.grid(False)\n",
- "plt.xticks(numpy.arange(NUM_LABELS))\n",
- "plt.yticks(numpy.arange(NUM_LABELS))\n",
- "plt.imshow(confusions, cmap=plt.cm.jet, interpolation='nearest');\n",
- "\n",
- "for i, cas in enumerate(confusions):\n",
- " for j, count in enumerate(cas):\n",
- " if count > 0:\n",
- " xoff = .07 * len(str(count))\n",
- " plt.text(j-xoff, i+.2, int(count), fontsize=9, color='white')"
- ],
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Test error: 1.4%\n"
- ],
- "name": "stdout"
- },
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f22684b17d0>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Test error: 2.0%\n"
+ ]
},
{
- "cell_type": "markdown",
- "metadata": {
- "id": "yLnS4dGiMwI1",
- "colab_type": "text"
- },
- "source": [
- "We can see here that we're mostly accurate, with some errors you might expect, e.g., '9' is often confused as '4'.\n",
- "\n",
- "Let's do another sanity check to make sure this matches roughly the distribution of our test set, e.g., it seems like we have fewer '5' values."
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAW0AAAFyCAYAAAA+gYtsAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3XucTfX++PHXZ1/mwlxQidwODVLjfinRzSRKkk4hdVxy\nyS0Shn4cE75FSuUwHUaF6MitTEqKcknOOXNcGkUMYmhoMIyZMRfGfH5/rGHGEHv27L3X3jPv5+Ox\nH7P3+uy13u+199rvWfuzPnstpbVGCCGEb7CYnYAQQgjHSdEWQggfIkVbCCF8iBRtIYTwIVK0hRDC\nh0jRFkIIHyJFWwghfIgUbSGE8CE2sxMoLqXUTUAH4DCQbW42QgjhEgHAX4BvtNYp13uizxVtjIL9\nidlJCCGEGzwH/Ot6T/DFon0YYHFNaBDg3AJGJsG71Zybt3nCQOdmvGwt0LGEy5DYZSd2ST6ia4DH\nSjB/bgnm9eXX3IzYp4DPIL++XY8vFu1sMAp2s3LOLSDU6vy8UNXZGfMFuGAZErvsxLaXMPZtJZj/\nQglj++prbmrsG3b5yoFIIYTwIVK0hRDCh0jRFkIIH1Imi/azFc2MHi6xJbaHNDQxdll9zd0fW4q2\nx5n5QZLYZSt2YxNjl9XX3P2xy2TRFkIIXyVFWwghfIjXFG2l1FCl1CGlVJZS6j9KqZZm5ySEEN7G\nK4q2Uqo7MAOIApoC8cA3SqmbTU1MCCG8jFcUbWAkMFdr/bHWei8wCMgEXjA3LSGE8C6mF22llB1o\nDnx3aZrWWgPrgdbFXmC12jDrK9iYAl8fgV6jr2zv2g8++xV+TIfVB+H+xwvamrSBhVth8xlj3mGv\nO7VOZrPbrcyd25mDB0eQmjqO3buH0qdPE7PTKvWGDGlJXNwAsrImsHJld4/H79y5Ljt29CM9fQxH\nj77EgAFNPZ6Dp5n5ms+c+SiJiSNJTR3HkSMjmTGjA1ar+0uqN5x75GbACiQXmZ4M1C/WkpSC976A\n7z+D4Y9DjTCYsw6Sj8I3S+GpAfDscBjbDfb/DBVvhoDyBfO+swoWToeF90LVmhCzAZIOwecfuGA1\nPcdms3DsWDrt2i0kMTGVVq2q8fXXz3P0aBrfffeb2emVWklJ6UyZspmHH65D9eohHo3doUMdZs/u\nwHPPxbJly1FCQvy59dbyHs3BDGa+5tHRcYwdu47s7FwqVQpk+fJuREa2YerUH9wa1xuK9p9RgP6z\nxpFJxomfCnuxRX061aoHcyeB1nBkP6z6EJ4aCN8ug0GTYMLzRsEGOHMK4+xaQFAohFSELz82Hh8/\nAv9dD3XNHPPpnKysC0yatPHy47i4JDZsOETbtjWlaLtRbOxeAJo2reLxAjJ58gNMnryFLVuOApCW\nlkNaWo5HczCDma95QkLBaa8tFkVenqZu3UoOzPkz8EuRaY5fGsAbivYp4CJwa5Hplbl67/uyd6td\n40x9FfK/mlgskJeXf98KdRvBX+rDTbfCnS1g4gfG9K1r4Z1RkJkB6akQ+xF07Q/zp0HVWnD3w/D6\nIBetpnn8/W20alWNxYt3mZ2KcIPAQBvNm1ehevVg9u4dRHCwHz/8cJQRI74lOfmc2emVapGRbRg/\n/n6Cgvw4dSqTyMh1DszVkKt/hHMciHEopul92lrrC8B2IOLSNKWUyn+8tVgLS9wHxw7D4Mlgs0Od\nO+GJvhAUAiH5/wFbRcCzzaBHE6P/e9Q7BfOvW27slf87C1YlwObV8B9H3gTv9sEHT7BvXwqrVu01\nOxXhBhUrBqKUokuXekREfEJY2PucP3+RxYu7mJ1aqTd9+o+Ehk6lQYPZzJmzjeTkDLfHNL1o53sH\nGKiU6qWUugOYA5QDFhRrKRcvwsgucEcz+DYJ/m+RsfecmgJZ+S/mh28Ye9VpZ+CjqXB/Z2N6rXrw\nbiy8NQLu9odHbjOK/vCprltLE0RHd6Ju3Up07fqp2akIN8nIOA/AzJn/IykpnaysXKKiNvPQQ7UI\nCPCGL9OlX0JCCrt2JbNgwZNuj+UVRVtrvQwYBUwGdgKNgA5a65PFXtihvTC0I7SrDD2bg38A7NgE\nh/dBTpF+I6UK7oeFGwcsN6wy+sNPn4DVC6FNSa78Ya7o6E60alWN9u0XXf5gi9InLS2HI0fOXjFN\nKWMzLryJC/fy87MSFuZIn3bJeEXRBtBav6+1/ovWOlBr3Vprvc2pBYWFQ0Ag2GzQrqvRPRIzBc7n\nwJrF0HeccdAxKBR6R8LGVcZ8e7bDLbfBA/l73hVvhk5/g707XLSGnjV79mO0bl2d9u0/Jj299B+Q\n8gYWi8Lf34bdbsViUfj5WbHZPPMRi4nZyfDhLalaNYiAABsTJ97H+vWHyMoqySXDvJ9Zr3m5cnZ6\n925CSIg/AOHhlRk//j7Wrj3g9tjKGBLtO5RSzYDt2+v9ySXDhkyGZ4aA3Q8S4uHd0fDzf422gEAY\nO9so5jnZsCkWZoyC7Eyj/b5OxgiT6nWM9v98C2+PNLpSLsX/Kcrt61hSNWqEcvjwy2Rn55Kbm3d5\nr2vx4l0MHfqV2emVWhMnPkBU1IMU/kxt2pRIRMTCEizVscuNKQVvvtmOPn0aoTVs2JDISy99w8mT\nmSWIXZLLjXmGe17zGwsMtLNqVQ+aNq2Cv7+NEyfOsWLFHl57bSM5Oc78o7x8ILK51vq6e4qlr2i7\nO74PFG1RmpTkGpEl5f1Fu/RwvGh7TfeIEEKIG5OiLYQQPkSKthBC+BAp2kII4UOkaAshhA+Roi2E\nED7EZ3/j2jxhIFDV43GjmOTxmJdMQoYblj0y7M7zzBhm6Xgplj1tIYTwIVK0hRDCh0jRFkIIHyJF\nWwghfIgUbSGE8CFStIUQwodI0RZCCB8iRVsIIXyIFG0hhPAhUrSFEMKHeEXRVkrdp5T6QimVpJTK\nU0o9YXZOQgjhjbyiaAPlgZ+AoYBvXf9MCCE8yCtOGKW1XgusBVBKKZPTEUIIr+Ute9pCCCEcIEW7\nhFoOGcKAuDgmZGXRfeXKK9oemjSJwfHx/P38eTrMmHFFW6WwMLqvXMmoY8cYm5JC382bqdG69RXP\nCe/Rg6G7d/Pq2bP0/89/aN78tmLn5+9vY//+4aSkjC3+yvmgIUNaEhc3gKysCaxc2d3sdDzOzPe7\nLG1raWmjOXu24JaTM46dO/t7JLYU7RJKT0pi85QpbI+JuaotZf9+vh0zhn2xsVe1BVSowP41a3g/\nPJw3b7qJ+IULeW7NGgIrVgSgxr338vg//8nnvXoxNTSUnR9+yJo1zxEU5Fes/CZPfohDh844t3I+\nKCkpnSlTNhMTs93sVExh5vtdlra1kJC3CQ0tuP366ymWLNntkdg+XLTXAkuK3H72eBZ7Y2PZt3o1\nmSkpV7XtWryYg99+S056+lVtx7ZtY8eHH5J1+jQAOz78kLyLF7m1USMA6j/xBHtXreLYdqP4bJ83\nj4yM83Tt2sDh3Jo1q0rHjmG8+eaPzqyaT4qN3cvq1ftISck0OxWPM/P9Lovb2iUtW95GgwY3s3Dh\nLgfniAcWF7mtcTieVxyIdE5HzLhyjbtUDg/HLyiIk3v2AKAsFihyTFYpaNToVoeWZ7EoYmI6M3jw\nl9hsPvy/WTjEzPe7rG9rL7zQmK+/Pkhy8jkH52icfyvsGPC+Q3N7xSuslCqvlGqslGqSP6lO/uMa\npibmIQGhoTy9ZAk/vP46506eBGD/mjU06NqV6vfcg8VqpeWQIdSsGUpIiL9Dyxwzpg3btx9n69aj\n7kxdeAkz3++yvK0FBNjo0eNO5s3b6bGY3rKn3QLYgDFGWwOXjtotBF4wKylP8A8J4bmvvyZx82Y2\nTZlyefrhjRtZ+/LLPPHBB5SvXJmE1atZt+43h77216lTkUGDWtCkyRwAZBRl6Wbm+13Wt7Xu3e/k\n3LkLrFlzwGMxvaJoa6034SV7/Z7kFxTE82vXcuKXX/hq6NCr2nfOn8/O+fMBsFit9D2Uwnvv/eeG\ny23btiaVK5cnIeEllAK73UpwsB/JyWPo1OkTtm075vJ1EeYx8/0u69tav36NWbBgF9qDPwn0iqLt\ny5TFgtVux2q3G/f9/NB5eeTl5mKxWrHYbFisVpTVarRdvEjexYv4BQXxt2+/JWXfPlYPHHjVci1W\nK7fcdRfJu3YRWKkSEW+8wW+/neGbb278H33p0t2sW/fb5cf33luDefM607jxPzl5snQfoLNYFHa7\nFbvdisWi8POzkpenyc3NMzs1tzHz/S7L21q9epW4997q9O37pUfjStEuofsnTODBqCh0/r/a8ZmZ\nJG7axMKICDrPm0eT3r0vt7UaNoz4hQuJ7dePBl27Uq1VKyqHh9Pgr381FqY1q198kV8+/RSL3c6T\n8+dTKSyM3Jwc9q5aRefOSxzKKScnl+PHC0asnDx5Dq3hjz8yXLvyXmjChPuJinrw8muemTmeTZsS\niYhYaHJm7mPm+12Wt7UXXmjMpk1HOHjQs8Mclfbkfr0LKKWaAdthIGaMHoliksdjXjKJKNNiC1F2\n2E2IeXn0SHOt9Y7rPbPM9SMLIYQvk6IthBA+RIq2EEL4ECnaQgjhQ6RoCyGED5GiLYQQPkTGaReT\nmcPuzvqbN9wwNEeGG5Y9gSbGzjIx9gUTYuY6/EzZ0xZCCB8iRVsIIXyIFG0hhPAhUrSFEMKHSNEW\nQggfIkVbCCF8iBRtIYTwIVK0hRDCh0jRFkIIHyJFWwghfIgUbSGE8CGmF22l1KtKqTilVJpSKlkp\n9blSqp7ZeQkhhDcyvWgD9wGzgLuBhzEu0PatUsrMs9UIIYRXMv0sf1rrxwo/Vkr1AU4AzYEtZuQk\nhBDeyhv2tIuqAGjgtCsWNmRIS+LiBpCVNYGVK7u7YpFeE9v+4hDKb4kjODWLwE9XXtkYFETgwk8I\nTk4l6NAx/MaNv6LZf+Ikyv8vnuD08/i/OeOKNuu9bQg+mUbwibPG7WQaubkTeffdjg7lZeZrPnPm\noyQmjiQ1dRxHjoxkxowOWK3euJn7viFDmhIX14usrFGsXPnkFW2TJrUlPr4v58+PZsaMdm7Pxd/f\nxv79w0lJGev2WJeYtZ171daslFLAe8AWrfUeVywzKSmdKVM2ExOz3RWL86rY+lgSOVOncP7DmKva\nAt6bDaEVSL+9OpkP34/fCwOwP/vc5fa8A/vJfnUMuatjr5r34tYfSb8lhPTKoaRXDiXjztvJzc1j\nyZKfHcrLzNc8OjqO+vVnUaHCNJo0mUOTJlWIjGzj8TzKgqSkDKZM2UpMzE9Xte3ff4YxYzYSG3vA\nI7lMnvwQhw6d8UisS8zazk3vHinifeBOwIFP2VogoMi0cKDhFVNiY/cC0LRpFapXD3FBio5zd+xL\nBdfSpClUq17QEBCA/enunHugNWRkkJdxgPPvz8Lepx8XlnwCwIV/LQZAd+txwzj2v/Vh//7TxMUl\nOZSXma95QkLK5fsWiyIvT1O3biWP5lBWxMbuB6Bp01upXj34irbFi3cD0KNHA7fn0axZVTp2DOOV\nV75h2bJn3B7vEue385+BX4pMy3Z4bq8p2kqp2cBjwH1a6+M3nqMjUNXNWfkmS736YLeTtyv+8rSL\nu37Cb8yrTi3P3qsvH8zZ4ar03C4ysg3jx99PUJAfp05lEhm5zuyUhJtYLIqYmM4MHvwlNptXdRxc\nR0OK7lzCceDqb8zX4hVrmV+wuwAPaa2PmJ2Pr1NBQXDuHGh9eZpOTUUFB19nrmuztmmL5S+1WbQo\n/sZP9hLTp/9IaOhUGjSYzZw520hOzjA7JeEmY8a0Yfv242zdetTsVDzG9KKtlHofeA7oCZxTSt2a\nfyva9yEcpDMyoFw5UOryNBUaik5PL/ay7L1fIPfLLzh92sxr9jknISGFXbuSWbDgyRs/WficOnUq\nMmhQi8vfpFSh7b0084bukUEYo0U2FpneF/jY49mUAnkJ++DCBSyNGpMXbxwksjZuSt5uxw4kXhYU\nhP2pZ8js3hWHDjN4IT8/K2Fh0qddGrVtW5PKlcuTkPASSoHdbiU42I/k5DF06vQJ27YdMztFtzC9\naGut3bq3b7Eo7HYrdrsVi0Xh52clL0+Tm5vnzrCeiW2xgN2OstuN+35+kJcH2dlcWLEU/6gpZPXu\niaXyrfgNHkZ2VKFhf1Yr2GzGX6vVmPfiReOWz96jJzrlFBe/W09xirZZr3m5cnaeeeYuPv/8V9LS\ncggPr8z48fexdq1nRjCUNcb7bMFut1z1PlutCpvNgtWqsFqNtosX87h4Ud94wQ5aunQ369b9dvnx\nvffWYN68zjRu/E9Onsx0WZw/Y9Z2rrR23YvoCUqpZsB2GIgjByInTnyAqKgHKbyemzYlEhGx0H1J\nuin2Wf9JVzz2Gz8R//FRV/RdX/xhE5kdI4xx2tFzsT36ODozk/P/nMX5N9+4/LyAmI+wP9/7inkv\nLF5I9ov9Lj8uv/k/XFj7FeffmEJoTpTDeZr1mgcG2lm1qgdNm1bB39/GiRPnWLFiD6+9tpGcnFy3\nxi6drv+j5IkT2xAV1abI+3yUiIhP+eijx+jdO/yKtoULf6Ffv68djF387rj776/F55/34Kab3iz2\nvM5w7XZ++UBkc631dY/6l/qiXZoULdqeVJyiLUoLM88k4XvHUErG8aJt+oFIIYQQjpOiLYQQPkSK\nthBC+BAp2kII4UOkaAshhA+Roi2EED7E9B/XCMeZOexO1zZvuKE6JMMNzWHmsDu7ibEvmBj7xmRP\nWwghfIgUbSGE8CFStIUQwodI0RZCCB8iRVsIIXyIFG0hhPAhUrSFEMKHSNEWQggfIkVbCCF8iBRt\nIYTwIaYXbaXUIKVUvFLqbP5tq1Kqo9l5CSGENzK9aANHgbFA8/zb90CsUqqBqVkJIYQXMv2EUVrr\nr4pMmqCUGgzcA/xqQkpCCOG1TC/ahSmlLEA3oBzwb5PTEUIIr+MN3SMopcKVUulADvA+0FVrvdfk\ntErEbrcyd25nDh4cQWrqOHbvHkqfPk08Fn/mzEdJTBxJauo4jhwZyYwZHbBa3fR216gNH30FO1Jg\nyxEYMLqg7fY7YNE6o+3fSfB/c8DP32irWh12pUH82YLbvvMw53P35OlGZr/fZjFzvdPSRnP2bMEt\nJ2ccO3f290hs8PBnrBBv2dPeCzQGKgB/BT5WSt3vy4XbZrNw7Fg67dotJDExlVatqvH1189z9Gga\n3333m9vjR0fHMXbsOrKzc6lUKZDly7sRGdmGqVN/cG0gpSDmC/jmM+j3OPwlDD5eB8ePwpdLYeYS\n+N8P0LsDhFSAD7+Cl/4OMybA8d+hUUjBsmw22JoEq5e4NkcPMPv9NouZ6x0S8vYVj3/6qT9Llux2\na8zCPPYZK8IrirbWOhe49A7vUEq1AkYAg/98rrVAQJFp4UBDN2RYfFlZF5g0aePlx3FxSWzYcIi2\nbWt65EOckJBy+b7FosjL09StW8n1gerUh9r14B+TQGs4tB+WfQg9BhpFu0ZtmDAI8vIg9TR89wU0\nuefay3qkK1gs8K3v7Wmb/X6bxVvWu2XL22jQ4GYWLtzlsZjOf8Z+Bn4pMi3b4bheUbSvwQL4X/8p\nHYGqnsjFJfz9bbRqVY3Fiz23UUVGtmH8+PsJCvLj1KlMIiPXuT6IxVLwNy/PuG+1wh2NjPsxb8Ff\ne8Oen4w97Ue6wr/mXntZz7wAsZ/ABe++cogjzHi/vYFZ6/3CC435+uuDJCef82hc5z5jDbl65/I4\nEONQTNP7tJVSryul2iqlauX3bU8FHgAWm52bK33wwRPs25fCqlWe6/GZPv1HQkOn0qDBbObM2UZy\ncobrg/y2D5IOw8jJYLdD3Tvh6b4QlN/tsXkttGgLP6cbfdrHjsCK+Vcv57aa0OZhWDrP9TmawIz3\n2xuYsd4BATZ69LiTefN2eizmJR75jBVhetEGbgU+xujXXo8xVvsRrfX3pmblQtHRnahbtxJdu35q\nSvyEhBR27UpmwYInXb/wixdhYBe4q5nRHz1jESz/CFJTIDgUFq039qzvDIRmlSArE9795OrlPNMX\ndu+ABM/1SbqL2e+3Wcxa7+7d7+TcuQusWXPAo3ELc+tnrAjTu0e01p473GuC6OhOtGpVjXbtFpKR\ncd60PPz8rISFuaFPG+DgXuhT6EeskVPhv5ug1u3gHwiLoo3p6WmwZC58uObqZfy1D0S/7p78PMhb\n3m9PM3O9+/VrzIIFu9Dao2Gv4tbPWCHesKddas2e/RitW1enffuPSU/P8VjccuXs9O7dhJAQ47BA\neHhlxo+/j7Vr3bQnUj8cAgKN0R8duhrdI7OnGMX8XDo8N8jo8y4fZByg3L3jyvnvewQq3ARf+vae\nqVnvt9nMXO969Spx773VmT8/3qNxPf4ZK8T0Pe3SqkaNUAYPbkl2di6JiSNRyhhcsXjxLoYOLfoj\nUNfSGnr2bMhbb7XH39/GiRPnWLFiD6+9ttE9AR/rBs8PAbsf7I03ukv27zHaBnSGcdNh9BuQmwvb\nf4Qxfa6c/5kX4OvlcM79/YHuYub7bSaz1/uFFxqzadMRDh484/ZYhXn8M1aI0mZ/pygmpVQzYDsM\nxJdGj/g6XXuSabHVoSjTYguz2E2MbcbopcujR5prrXdc75nSPSKEED5EirYQQvgQKdpCCOFDpGgL\nIYQPkaIthBA+RIq2EEL4EBmnLRxi5rA7fbeJww3/K8MNzWHmScPMGG7oeCmWPW0hhPAhUrSFEMKH\nSNEWQggf4nBHilLqHUefq7V+xbl0hBBCXE9xDkQ2LfK4OWAF9uU/rgdcBLa7IC8hhBDX4HDR1lo/\ndOm+UuoVIB3orbU+kz+tIjAfcO9VLYUQogxztk97FPDqpYINkH9/Qn6bEEIIN3C2aIcAt1xj+i1A\nsPPpCCGEuB5ni/bnwHyl1FNKqepKqWpKqb8CHwKfuS49IYQQhTn7i8hBwNvAvyj4+VAuRtEe44K8\nhBBCXINTRVtrnQkMUUqNAW4HFHBAa33OlckJIYS4Ukl/XFM1/5agtT6nlFIlTUgp9apSKq8448KF\nEKKscKpoK6VuUkp9ByQAayi4WOOHSqkZziajlGoJDAA8e2llIYTwEc7uab+LcRqumkBmoelLgY7O\nLFApFQQsBvoDqU7mJYQQpZqzRfsRYKzW+vci0/cDtZxcZjSwWmv9vZPzi7LottrwzlfwTQrEHoHn\nRhe0vb8BNmXBd2fhuzTjb6VbC9r/cgfMWmfMuzoJxs4BP3/Pr4MLDBnSkri4AWRlTWDlyu5mp+Mx\nZq33Rx89Tnb2WM6eHU1a2mjOnh1Nq1a3eSS2s6NHynPlHvYllYCc4i5MKdUDaAK0cDIfURYpBW99\nARs/g1GPQ/Uw+Mc6SD4K65eC1jB7DCyffe35J/0Ldm2BER0gqIJR/F/4O8yZ4Nn1cIGkpHSmTNnM\nww/XoXr1ELPT8Rgz1zs6ejujRq33aExwvmj/APQC/p7/WCulLEAksKE4C1JKVQfeA9prrYtx5vO1\nQECRaeFAw+KEF76sVn2oWQ8+nGQU6KP7YfWH8ORAo2iDUdj/zG21YfpgyMuDtNPwwxcQfo9ncnex\n2Ni9ADRtWqVMFW3fXO944Oci07IdntvZoh0JfKeUagH4AdOBuzD2tNsUc1nNMX5Jub3Q6BMrcL9S\nahjgr7XWV8/WkYLjn6JMUpZCf/OM+xYrhDUqeE6fCfDCRPgjET59D9YuLmj719vQqTfs/8nY036g\nK6ya67H0hW/r1ashvXo15PjxDObPj+fdd+McnLNx/q2wY8D7Ds3t7DjtX5RS9YBhGCeOCsL4JWS0\n1vp4MRe3nqt3jxcAvwLTrl2whQCO7IPjh2HgZJgXBTXqwuN9oXz+Htf74+DQHsjOhBYR8PoyOJdm\n7FED/HstTJgP36cbhX/zKvhyvllrI3zIzJn/Y/To7zh9OotWrW5j2bKnuHhR849//M/tsZ0d8lcT\nSNNav6617qa1fkxrPUFrfTy/zWFa63Na6z2Fb8A5IEVr/asz+Yky4uJFiOwC9ZsZBxJfWwRffgRn\nU4z23XGQmWF0f8StM/aiH84/WBUUCrPWG9MeCIRHKhnFfdIn5q2P8Bnx8cmcPp0FQFzcMaZN20r3\n7nd6JLazo0cOcY0TRimlbspvKynZuxaOObwXXu4Ij1aG3s3BLwB2brr2c/PyCu5Xux38A2FFtFH8\nz6UZBfzexzyTtyhVPNkf4GzRVly7sAZRnB71P6G1bidXvxEOuT3cKL5WGzzY1ege+WiK0UXSuiP4\nBxgHI1u0gydfhA0rjPkS90JmOjw1CCwWKBcEXQbCvh3mro+TLBaFv78Nu92KxaLw87Nis5X+qwma\ntd5PP30HQUF+ADRvXpWxY1uzYoVnOgaK1add6KflGpiilCo87M8K3A385KLchLixiG7w1yFg84MD\n8TCmi9GPHXoT9IuCyUuM5x0/DDNHwsbPjcfZmTC6MwybDoPegIu5sOtHmNLHnPUooQkT7icq6kEu\nHQLKzBzPpk2JREQsNDkz9zJrvYcNa8HcuY9hs1lISkpn9uxtxTgQWTKqOMf5lFKXhvM9APwbOF+o\n+TxwGHhba73fVQleI4dmwHYYiIweKRv03ZNMi63+G2VabGEW+42f4nKXR48011pf9+tesfa0L11y\nTCk1HxihtU5zNkUhhBDF52znz8tco+ArpSoppXxlhLsQQvgcZ4v2p0CPa0zvlt8mhBDCDZwt2ndz\n7Z+rb8xvE0II4QbOFm1/rt0fbgcCnU9HCCHE9ThbtOMwhm8UNQjY7nw6QgghrsfZE0ZNANYrpRoD\n3+VPiwBaYpxrWwghhBs4e8KoH5VSrTGuvN4NyAJ2Af3cOUZbmMm8Xi8zx0rrUeaNEQdQM5y+ep8L\nmDmi14yx0pcU4wzRLpPr8DOd3dNGa/0T8Jyz8wshhCg+h4u2Uirk0o9pbjQWW350I4QQ7lGcPe0z\nSqmqWusTGBfevdbv3y+dSMrqiuSEEEJcqThFux1wOv/+Q27IRQghxA04XLS11puudV8IIYTnFKdP\nu9GNn2XQWu9yLh0hhBDXU5zukZ8w+qv/7AIIhUmfthBCuEFxfhFZG6iT//evGJcVGwI0zb8NAQ7m\ntwkhhHCZors7AAAgAElEQVSD4vRpJ166r5RaDgzXWq8p9JRdSqmjwBRgletSFEIIcYmz5x5pyLUv\n4HsIKNYliZVSUUqpvCK3PU7mJYQQpZqzRftX4FWllN+lCfn3X81vK65fgFuBKvm3tk7mJYQQpZqz\nP2MfBKwGfldK7cI4MNk4/29nJ5aXq7U+6WQuQghRZjh7wqg4pVRt4HngDowRJcuAf2mtzzmxyLpK\nqSQgG+OCwa9qrY86k5sQQpRmznaPoLXO1FrHaK1f0VqP1FrPc7Jg/wfoA3TA2IOvDWxWSpV3NrfC\nhgxpSVzcALKyJrByZXdXLNIhdruVuXM7c/DgCFJTx7F791D69GnisfhmGDKkKXFxvcjKGsXKlU9e\n0bZsWReSkoaQmvoyBw4M5NVX7zEpSxcKqQq9P4NJJ+G1ZHhuCZS76cZtjrQ7aMiQxsTF9SQrazgr\nV179Jbdfv3B+/bUP6enDOHjwBR5/vI6za3udHMz5jAFUrRrEZ589zcmTI0lOfpklS57kpps8c0bK\nmTMfJTFxJKmp4zhyZCQzZnTAanW6pDrM6QhKqb8ppbYopY4ppWrlTxuplOpSnOVorb/RWq/UWv+i\ntV4HPAZUxDjla4klJaUzZcpmYmI8e20Gm83CsWPptGu3kAoVptG37ypmzOhARITrPzTeIikpgylT\nthIT89NVba+99iO1as2hQoX3eOCBJTz33F08+2wDE7J0oafeBzRMqQFv1AZ7IDw588ZtjrQ7yHjN\n/0NMzM9XtQ0Y0JCXX25Gt25fEhw8m7vvXsLPP59yalWvn4M5nzGA99/viNaaGjVmUbt2NIGBdmbO\n9Mwp/aOj46hffxYVKkyjSZM5NGlShcjINm6P61TRVkoNBt4BvsYosJd+THMG40rtTtNanwUSgLDr\nP3MtsKTI7eoNNzZ2L6tX7yMlJbMkaRVbVtYFJk3aSGJiKgBxcUls2HCItm1rejQPT4qN3c/q1QdI\nScm+qm3PnlPk5uYBoBTk5Wnq1q3k6RRdq1JtiF8GudlwPhPil0KVhjduc6TdQbGxB1m9+jdSUrKu\nmK4UTJrUmhEjNlwu1KdOZZGY6PoTcJr1GQOoXbsCy5b9SnZ2LpmZF1i6dA8NG97ikdgJCSlkZxvn\nwbZYVDG26Z+5unatdTius3vaLwEDtNavc+XZu7dhDAd0mlIqCLgdOH79Z3YEni1yK1Fot/L3t9Gq\nVTXi4/8wOxXTzJ7dnoyMkSQmDqZ8eTsLFlz9T9anbJoBjbuBfzAEhELTZ2HPF0bb5nf+vO1G87pA\n/fqVuPXW8rRoUYXffutHYmJ/5s59mKAgMy8u4HozZvyXbt0aEBzsR2ioP88+exdffOG567BERrbh\n7NlXSU4eQ6NGtzJrVpwDczXk6trV0eGYzhbt2sDOa0zPAYrVF62Uekspdb9SqpZS6l7gc4x/BEuc\nzM0rffDBE+zbl8KqVXvNTsU0w4atIyjoXVq0WMiiRbs5c+bqPXKfcngrBFWGKWdg0ikIqADfTzPa\nDv345203mtcFKlUKACAiogbNmi2mSZPF1K4dyjvvPOiyGN5g69bfqVy5PGfOjOLUqVeoUMGfadO2\neiz+9Ok/Eho6lQYNZjNnzjaSkzPcHtPZon0IuNZRtY4Uf5x2deBfwF7gU+AkcI/WOsXJ3LxOdHQn\n6tatRNeun5qdilfYuTOZ9PTzzJjRzuxUSubFdfDbD/BqORgfBIlbYeC6/Lb1f952o3ldICPjPABv\nvBFHamoOZ85kM3VqHJ07l65jKuvW9eSHH45Qrtx0goKms3Xr76xb19PjeSQkpLBrVzILFjx54yeX\nkLNF+x0gWinVHWO4Xyul1HhgKjC9OAvSWj+rta6utQ7UWtfUWvfUWl/r15Y+KTq6E61aVaN9+0WX\nP0gC7HYLYWEVzE7DeeUqQYVa8OMsuHgecnNgyyyo2Sq/reY12u6GwIrXmTe/3QX27TtDVtaV1x1U\nyiWL9hqVKgVSq1Yos2Zt4/z5i+TkXGTWrG3cfXc1KlYM8Hg+fn5WwsLcf5zGqaKttf4AGAv8H1AO\nY095EDBCa+1Vu5MWi8Lf34bdbsViUfj5WbHZ3D8sB2D27Mdo3bo67dt/THp6jkdimsl4ra3Y7ZYr\nXusaNYLp2rUe5coZ/amtW1dj+PDmrF3rw/+bM0/Dqf1w71Cw+oHNH9oMg9Sjf9529ihknblxezH8\n2Wuek3ORxYt/Zdy4VoSG+hMa6k9kZEtWrTrg8pfCrM/Y6dNZ7N9/mqFDW+DnZ8Xf38qwYS04ejTN\n7V1v5crZ6d27CSEh/gCEh1dm/Pj7WLvW9a9vUUrrG51ltcgMSimgBnBCa52tlCoHBOVfhsztlFLN\ngO0wEKh6w+dPnPgAUVEPUng9N21KJCJiofuSBGrUCOXw4ZfJzs4lNzcPpUBrWLx4F0OHfuXW2O5x\n47GvEye2ISqqTZHX+ii9e3/FJ590Jjz8ZiwWxbFjGXz88S+8+eZ/HYyddeOnuMl1r8Z+S33o8h7U\naAEoSNoJq0fB8V3Xb7vRvIXc6GrsEyfeQ1RU6yKv+e9ERKwgMNDG7Nnt6No1jOzsXGJjDzJq1CYy\nMx298rdjI03c8xlz7IBp/fo38d577WnRoipKGV1vo0atZ9eukpSjG1+NPTDQzqpVPWjatAr+/jZO\nnDjHihV7eO21jeTkOH5l9QLHgRiA5lrrHdd7pjNF24Lxy8W7tNaeO0xbEL9YRVu4imd+sHBtXlq0\nPeBGRdu9zLw+t5mjXG5ctF3P8aJd7O8wWus8YD9Q/J9vCSGEKBFnO57GAW8ppcJdmYwQQojrc/Ys\nfx9jHICMV0qdp8j3V621j//UTQghvJOzRbtEP1UXQgjhnGIV7fyDkGOAJwA/4DtgktbavCNFQghR\nhhS3T/v/Aa8DGUASMAJ439VJCSGEuLbiFu3ewBCtdQet9ZMYV6npmb8HLoQQws2K26ddE+N0rABo\nrdcrpTRwG/C7KxMT3qZs9oCpGVGmxtfPjDIttlpu5rqbMVbaNxR3D9mG8cOawi5g7kh4IYQoM4q7\np62ABUqpwifSCADmKKUuX2pMa/2UK5ITQghxpeIW7WudTGCxKxIRQghxY8Uq2lrrvu5KRAghxI3J\nqA8hhPAhUrSFEMKHSNEWQggfIkVbCCF8iBRtIYTwIVK0hRDCh3hF0VZK3aaUWqSUOqWUylRKxedf\nVkwIIUQhzp5P22WUUhWAHzFO89oBOAXUBYp3WWohhCgDTC/aGJcuO6K17l9oWqJZyQghhDfzhu6R\nzsA2pdQypVSyUmqHUqr/Dedy0MyZj5KYOJLU1HEcOTKSGTM6YLV6w2oLd/L3t7F//3BSUsaanYp7\nVK4N476Cj1Lg/SPQebQxPfhmeGmRMW3+GZi2DZo/XjCf1Q4Tv4eYP4z2d3ZDhMs+bsIDvKF61QEG\nA/uAR4A5wD+UUs+7YuHR0XHUrz+LChWm0aTJHJo0qUJkZBtXLFp4scmTH+LQoVLaw6YURH4Bv22D\nfjfDlAjoOAzu7Q4BQfDbDvh/raBvRVgWBSOWwG31jXnzcuGjYfBiVaP97aeg+xSof6+56yQc5g3d\nIxYgTmv99/zH8UqpuzAK+XVORrUW4wSDhYUDDa+YkpCQUhDIosjL09StK9cdLs2aNatKx45hvPLK\nNyxb9ozZ6bjebfXhtnqwfBJoDcf3w/cfwsMDYetS+Ordgufu+AqO7YO69xh/tYbf9xS0K2VMqxIG\n+7Z6fl3KpJ+BX4pMK3rG6z/nDUX7OPBrkWm/Ajc4vWtHoKpDASIj2zB+/P0EBflx6lQmkZHrnEhT\n+AKLRRET05nBg7/EZvOGL5JucOlCURYLXMzLv2+Fmo2ufm7ILVCtARzZdeX0sV9Aw4fB5g+J8RD3\nuXtzFoU0pOjOpVEGYxya2xu26h+B+kWm1ceFByOnT/+R0NCpNGgwmzlztpGcnOGqRQsvM2ZMG7Zv\nP87WrUfNTsV9ju2DE4eh22Sjj7r6nfBQXygXcuXzrDaja2Trp3Bo55Vtbz4Bz5eD1x6A/66E82Xz\nykS+yBuK9rvAPUqpV5VStyulegL9gdmuDpSQkMKuXcksWPCkqxctvECdOhUZNKjF5W9SSimTM3KT\nvIvwVheo3QzmJsGwRbDhI0gv6ArEaoNXVkB2Bswd+OfL2rsFKlSBJ8a4P2/hEqZ3j2ittymlugLT\ngL8Dh4ARWutP3RHPz89KWJj0aZdGbdvWpHLl8iQkvIRSYLdbCQ72Izl5DJ06fcK2bcfMTtF1kvbC\nGx0LHvecCns2GfetNnhlufF3ehejyF+P1Q5V6rovV+FSphdtAK31GmCNq5dbrpydZ565i88//5W0\ntBzCwyszfvx9rF17wNWhhBdYunQ369b9dvnxvffWYN68zjRu/E9Onsw0MTM3qBEOyQfh4gVo3hke\n7AuT2xl9268sB79yMO3xqwt2rUZGP/feLZB7AZp0hLY9YY4M+/MVXlG03UVr6NmzIW+91R5/fxsn\nTpxjxYo9vPbaRrNTE26Qk5PL8ePplx+fPHkOreGPP0rhMYx7u8EjQ8DmZxxIfKuLMSqkwX1GET+f\nbYzhBuOD8PkbEPsmWGzw7BtQtZ4x/eRhWDgS/r3M1NURjlNaa7NzKJb8c5Jsh4E4OnpECF+ln5lk\nWmy1PMq02GXP5dEjzbXWO673TG84ECmEEMJBUrSFEMKHSNEWQggfIkVbCCF8iBRtIYTwIVK0hRDC\nh0jRFkIIH1Kqf1xT+tjNTsAkF8xOwDRmjpXOq2TeGHHLaTPHiJvxOXO8FMuethBC+BAp2kII4UOk\naAshhA+Roi2EED5EirYQQvgQKdpCCOFDpGgLIYQPkaIthBA+RIq2EEL4ENOLtlLqkFIq7xq3WWbn\nJoQQ3sYbfsbeArAWetwQ+BaQi9YJIUQRphdtrXVK4cdKqc7AQa31DyalJIQQXsv07pHClFJ24Dng\nQ7NzEUIIb+RVRRvoCoQCC12xMLvdyty5nTl4cASpqePYvXsoffo0ccWivdpHHz1OdvZYzp4dTVra\naM6eHU2rVrd5NIfOneuyY0c/0tPHcPToSwwY0NQjcYcMaUlc3ACysiawcmV3j8T0hthu128IrI+D\npCxYuPLKtqAgmPsJHEqF3cdg1PjitX+0DHYnGe3bDsDIVx1Oa+bMR0lMHElq6jiOHBnJjBkdsFo9\nV9bM2M5N7x4p4gXga631H65YmM1m4dixdNq1W0hiYiqtWlXj66+f5+jRNL777jdXhPBa0dHbGTVq\nvSmxO3Sow+zZHXjuuVi2bDlKSIg/t95a3iOxk5LSmTJlMw8/XIfq1UM8EtMbYrvd8SR4ewo88DDc\nVv3KtjdnQ2gFaFgdKleBz9bDkcOw/BMH21+DgwmQmwu3VYPl3/Dsnr0sWfLzDdOKjo5j7Nh1ZGfn\nUqlSIMuXdyMysg1Tp7q/d9Ws7dxrirZSqibwMPCkY3OsBQKKTAvHOI5pyMq6wKRJGy8/jotLYsOG\nQ7RtW7PUF20zTZ78AJMnb2HLlqMApKXlkJaW45HYsbF7AWjatIrHC6eZsd1uTazxt2HTK4t2QAA8\n2R06toaMDMg4APNmwXP9jKJ8o3aAfXsKBVKQl0fdupUcSishoeCQmMWiyMvTDs9bUs5v5/FA0X9I\n2Q7H9abukReAZGCNY0/vCDxb5NbwunP4+9to1aoa8fEu2ZH3ar16NeTkyZHs2jWAkSNbeSxuYKCN\n5s2rUL16MHv3DiIpaTifftrVY3vawsPC6oPdDr/EF0z75Se4q5Fxv+4d12+/ZPpsOJIB8YlQrjwL\nFvzkcAqRkW04e/ZVkpPH0KjRrcyaFVeCFXJMybbzxsDzRW6PORzbK4q2UkoBfYAFWus8d8X54IMn\n2LcvhVWr9rorhFeYOfN/1K8/h1tueZf+/b9ixIhWDB/e0iOxK1YMRClFly71iIj4hLCw9zl//iKL\nF3fxSHzhYeWDIPMcaF0w7WwqBAUb98uVv377JZHDoGYQRLSAZYs4c8bxPc/p038kNHQqDRrMZs6c\nbSQnZ5RghRxj5nbuFUUbo1ukBjDfXQGioztRt24lunb91F0hvEZ8fDKnT2cBEBd3jGnTttK9+50e\niZ2RcR4w/nEkJaWTlZVLVNRmHnqoFgEBXtMbJ1zlXAYElgOlCqaFhEJGumPtRe3aCRnpzJjxSLFT\nSUhIYdeuZBYscLCHtQTM3M69omhrrddpra1a6wPuWH50dCdatapG+/aLLr/YZUnhnRx3S0vL4ciR\ns1dMU8rIofDnVpQSB/bBhQsQ3rhgWsOmsOdnx9qvxW4nLMy5fmk/P6vT8xaHmdu5VxRtd5o9+zFa\nt65O+/Yfk57umYNhZnv66TsICvIDoHnzqowd25oVK371WPyYmJ0MH96SqlWDCAiwMXHifaxff4is\nrFy3x7ZYFP7+Nux2KxaLws/Pis3mmc3czNhuZ7GAv7/RP22xgJ8f2GyQnQ2rlsKrUyA4GOqEQf9h\nsGieMd+N2qvVgMe7QrlyxuOWrWHAcNauvfH+W7lydnr3bkJIiD8A4eGVGT/+PofmdQWztnOlPbkb\n5gJKqWbAdhgIVL3uc2vUCOXw4ZfJzs4lNzfv8n/CxYt3MXToVx7J17Ucu0r0xo3P07BhZWw2C0lJ\n6XzwwU+8885/3ZxbAaXgzTfb0adPI7SGDRsSeemlbzh5MtPJJTp+NfaJEx8gKupBCm/XmzYlEhHh\nkqH/XhvbHa64GvuYiRAZdeXXtq2b4MkIYxz2jLnQ4XHIzIQPZsE7bxQ873rt1WrAnMXQINz4Z/DH\nMVj6MZaooiPDrhYYaGfVqh40bVoFf38bJ06cY8WKPbz22kZyckpSOB37nLl2Oz8GvA/QXGu947px\nS3PRLn0c25hKH8eLtnCdK4q2h1lOR5kW25zPmeNFu5R8dxNCiLJBirYQQvgQKdpCCOFDpGgLIYQP\nkaIthBA+RIq2EEL4ECnaQgjhQ3z4ZBA2zBlPaeaYYRmvXPaYNzbfzLHSup15Y8TV92ast+M/BpI9\nbSGE8CFStIUQwodI0RZCCB8iRVsIIXyIFG0hhPAhUrSFEMKHSNEWQggfIkVbCCF8iBRtIYTwIVK0\nhRDCh5hetJVSFqXUFKXUb0qpTKXUAaXUBLPzEkIIb+QN5x4ZB7wI9AL2AC2ABUqpVK31bFMzE0II\nL+MNRbs1EKu1Xpv/+IhSqifQysSchBDCK5nePQJsBSKUUnUBlFKNgTbAmpIu+KOPHic7eyxnz44m\nLW00Z8+OplWr20q6WIcNGdKSuLgBZGVNYOXK7h6La3bsmTMfJTFxJKmp4zhyZCQzZnTAavXspubv\nb2P//uGkpIz1aFyzVK0axGefPc3JkyNJTn6ZJUue5KabAj0S26PbWtXa8MZX8HkKLDkC3UZf/ZwK\ntxjtc7Zf3fbsOFj8G3yZDvN/hfotnE7FrM+YNxTtacBSYK9S6jywHXhPa/2pKxYeHb2d0NC3CQl5\nm9DQt4mLO+aKxTokKSmdKVM2ExNzjY2nFMeOjo6jfv1ZVKgwjSZN5tCkSRUiI9t4NIfJkx/i0KEz\nHo1ppvff74jWmho1ZlG7djSBgXZmznzEI7E9tq0pBVO+gIRt8NTNMCYCnhwGDxUpmC/Nhv3XyKXf\n69DqURjdDh4Phsj2cOKI0+mY9Rnzhu6R7kBPoAdGn3YTYKZS6pjWetGfz7YGCCgyrSHQ2D1ZOiE2\ndi8ATZtWoXr1kDITOyEh5fJ9i0WRl6epW7eSx+I3a1aVjh3DeOWVb1i27BmPxTVT7doVmDp1K9nZ\nxnmZly7dw7hxrT0S22PbWo36UL0efDwJtIbf98PXH0KngbBhqfGce5+A4IqwbhH89eWCeYMqwF9H\nQv+G8MdhY9rJ30uUjvPr/TPwS5Fp2Q7P7Q1FezrwhtZ6ef7j3UqpvwCvAtcp2o8BN+7q6NWrIb16\nNeT48Qzmz4/n3XfjSpqvcEBkZBvGj7+foCA/Tp3KJDJynUfiWiyKmJjODB78JTabN3yR9IwZM/5L\nt24NWLPmABaL4tln7+KLL/abnZZrKUuhv3nGfYsV6jQy7pcPgUEzYGwHaNj2ynnvvAfOZ0NET3j8\nRTifA5uWwUcTIO+ix1bB0DD/VthxIMahub1hqy4H6CLT8nBBbjNn/o/69edwyy3v0r//V4wY0Yrh\nw1uWdLHCAdOn/0ho6FQaNJjNnDnbSE7O8EjcMWPasH37cbZuPeqReN5i69bfqVy5PGfOjOLUqVeo\nUMGfadO2mp2Wax3dB8mHoc9ksNmh1p3QoS+Uy9/LHfAmrP0Ijv929bzBlaB8KNwWBn8Lg5H3G10l\nPXzvmIc3FO3VwHil1GNKqVpKqa7ASOCzki44Pj6Z06ezAIiLO8a0aVvp3v3Oki5WFENCQgq7diWz\nYMGTbo9Vp05FBg1qcXmvXinl9pjeYt26nvzwwxHKlZtOUNB0tm79nXXrepqdlmvlXYS/d4G6zWBp\nEry6yCjSaSkQ3gbuagOfTjeeW/S9z8owulQWTDT2uE8lwWczoXVnz69HCXlD98gwYAoQDVQGjgH/\nzJ/mUrro/rzwCD8/K2Fh7u/Tbtu2JpUrlych4SWUArvdSnCwH8nJY+jU6RO2bfPcQWhPqlQpkFq1\nQpk1axvnzxtf9WfN2saYMa2pWDGAM2cc7y/1ekf2wriOBY/7T4Vdm6BphDGyZPlxY7rdH/wDYUUy\nDGgIB+PNydcNTN/T1lqf01q/orWurbUur7Wuq7WO0lo7fqXLP/H003cQFOQHQPPmVRk7tjUrVvxa\n4pwdZbEo/P1t2O1WLBaFn5/VY/2sZsUuV85O795NCAnxByA8vDLjx9/H2rUH3B576dLdhIX9gyZN\n5tC48Rz69/+CtLQcGjf+Jzt3/uH2+GY5fTqL/ftPM3RoC/z8rPj7Wxk2rAVHj6Z5pGB7dFurHW4U\nY6sN2naFjn1h8f/B8hnQux4MbGzcFkw0CvzAxnDmBCQnwo710CsK/ALgpqrw5Evw4yqnUzHrM+YN\ne9puM2xYC+bOfQybzUJSUjqzZ2/z6IHICRPuJyrqQXT+Ln5m5ng2bUokImJhqY2tNfTs2ZC33mqP\nv7+NEyfOsWLFHl57baNb4wLk5ORy/Hj65ccnT55Da/jjD8/0p5upS5flvPdee5KShqMU7NyZzBNP\nLPNIbI9uaw90gy5DwOZn7D3/vQsc3m20ZZ8reF7GGbh4AU4X+mf9xnMwap6x933uLKxfBMvecjoV\nsz5jSvtYn4FSqhmwHYbgyOgR17tgQkxRdtlNjG3etq7bTTIttvo+yoSol0ePNNda77jeM03vHhFC\nCOE4KdpCCOFDpGgLIYQPkaIthBA+RIq2EEL4ECnaQgjhQ6RoCyGED/HhH9fkImOmywrPnMz/2rJM\njA3mbuPmjRE3Z6y0Qdf1/BjxHdnQ3MFznMmethBC+BAp2kII4UOkaAshhA+Roi2EED5EirYQQvgQ\nKdpCCOFDpGgLIYQPkaIthBA+RIq2EEL4EK8o2kqpIKXUe0qpw0qpTKXUFqVUC7PzEkIIb+MVRRv4\nEIgAngPCgXXAeqVUVVOzEkIIL2N60VZKBQBPAWO01j9qrX/TWk8CDgCDzc1OCCG8i+lFG+OkVVYg\np8j0LKCt59MRQgjvZXrR1lpnAP8G/q6UqqqUsiilngdaA9I9IhwyZEhT4uJ6kZU1ipUrn7yibdKk\ntsTH9+X8+dHMmNHOpAxLt86d67JjRz/S08dw9OhLDBjQ1KPx/f1t7N8/nJSUse4LUqM2zPsK4lJg\n0xHoN7qg7fY7YME6o+2HJJg8B/z8C9rLB8GMT2B7Kmw5BoPHO52G6UU73/OAApKAbGAY8C/goplJ\nCd+RlJTBlClbiYn56aq2/fvPMGbMRmJjD5iQWenXoUMdZs/uwPDh3xIc/BZ33RXDxo2JHs1h8uSH\nOHTojPsCKAX//AJ+3gZ33wy9I+D5YdCpu9H+zhI4+Cvccwt0bgh3NIahfy+Yf+JsCKkA91eH5+6H\nbgPgieecSsUrzqettT4EPKSUCgRCtNbJSqlPgUN/PtdaIKDItHCgobvSFF4sNnY/AE2b3kr16sFX\ntC1evBuAHj0aeDyvsmDy5AeYPHkLW7YYJ4ROS8shLa1ob6f7NGtWlY4dw3jllW9YtuwZ9wSpUx/+\nUg9mTwKt4fB+WPEhdBsIXy2F6rVh4iDIy4PU0/D9F9D4HmNe/wB4rDt0aw3nMljyxwGyomfR4ol+\nTJjzCQBni7F76hVF+xKtdRaQpZSqCHQARv/5szsivSdCmCsw0Ebz5lWoXj2YvXsHERzsxw8/HGXE\niG9JTj7n9vgWiyImpjODB3+JzebGjgNluRTQKMwAVivc0ci4/8Fb0LU3/PqTsUfdvit8Otdoq1Mf\nbHbYGw/As8HAsZ+g4at8cZvxFJ+7CIJS6hGlVAel1F+UUu2B74FfgQXmZiaEuJ6KFQNRStGlSz0i\nIj4hLOx9zp+/yOLFXTwSf8yYNmzffpytWx2seM46tA+SDsOIyWC3Q9id8FRfKB9itP+wFpq3hZ3p\nRp/2sSOwcr7RVi4Iss4Ze+iXpKVC+eCrwjjCK4o2EApEU1CoNwMdtNbSpy2EF8vIOA/AzJn/Iykp\nnaysXKKiNvPQQ7UICHDvF/k6dSoyaFALIiPXAaCUcl+wixdhSBe4s5lRlN9aBCs/gtQUCA6FBeth\n6VxoFAgtK0F2pnHgESAzAwLKGf3ilwSHwrl0p1Lxiu4RrfVyYLnZeQghiictLYcjR85eMU0pY6fS\nnTUUoG3bmlSuXJ6EhJdQCux2K8HBfiQnj6FTp0/Ytu2YawMe3Av9OhY8Hj0V/rcJat4OAYGwONqY\nnpFmdI3MW2M8/m0f5F4wDk7+mn+gvEFTSPjZqTS8ZU9biBKxWBT+/lbsdgsWi8LPz3q5j9NqNdqs\nVoXVarRZrW6uKGVITMxOhg9vSdWqQQQE2Jg48T7Wrz9EVlauW+MuXbqbsLB/0KTJHBo3nkP//l+Q\nlmPDHrMAAAntSURBVJZD48b/ZOfOP1wfsF64UZxtNnikq9E9Ej0Ffttr7DU/O8jo8y4fBN0Hwp6d\nxnw52bBmKbw8xegSqRVmjDxZNs+pNLxiT1uIkpow4V6iotqg8/sNMzNfYdOmo0REfMq8eY/Su3f4\n5bZhw5qxcOEv9Ov3tZkplxrTpm2lYsUA4uP7ozVs2JBIr15fuD1uTk4ux48XdDGcPHkOreGPPzLc\nE/DRbtBzCNj9YF88DO4CB/YYbS92hsjp8Mob/P/27j3YqrIO4/j3AS/kBS2t1IpRExW1SEEdTSA0\nHLNRs6ZEJTW0q1pDTRhjDl6ycXTyiKSNo3lFUCtvTCpomBfUITgzOAioJCjeSLHQ8GRy+PXHu05s\nNqjD4ax3u/Z+PjPrj73O2udZa+1zfvvd73r3eulcBe0z4ayT1zz3gjPh/KvgkReh4224aSJMndyt\n3VDUdo5XgKT9gDnwPTx6pFV8pIHZHQ3MbrRNG5j9bsOSo/952TNrRo8Mioj299vW3SNmZhXiom1m\nViEtWrS7d9XW2VXNXver7fm06jmf28Dsxh33lO6N4tsgLVq05zm7pbIbWUBa9Zw38g2jccftom1m\nZmtx0TYzqxAXbTOzCqnil2v6AEyaNJQBA7p3q80xYx6kre3oHt0pZ3+Ys++hrW1Eg7Jb9ZxPp63t\nKw3K3rjjbqf7z10xZgztbW0b/LwFCxbAqFGw7v2m11HFL9ecANzc6P0wMyvBiRHxvl+VrGLR3o50\nr+0lpFluzMyqrg+wMzAtIpa/34aVK9pmZq3MFyLNzCrERdvMrEJctM3MKsRF28ysQlqqaEs6XdJi\nSR2SnpC0f6bcIZLulvSSpNWSsgyelTRO0ixJb0paJukOSbvnyC7yfyBprqQVxfKYpCM++Jk9vh/j\nivN+aaa88UVe7TI/U/ZOkm6S9Lqkt4vzv1+m7MXrOe7VkiaWnNtL0gWSniuOeZGkX5aZWZe/laTL\nJC0p8h+VNLisvJYp2pKOA34DjAf2Jd1FaJqk7TPEb0m61dzpQM7hOkOAicCBwJdJd7WfLinXrAJL\ngbOAQcUyA7hLUve+FdUNxRvzd8l/16h5wCeBHYrlkLIDJW0LzATeIQ2LHQD8DPhn2dmFwaw53h2A\nEaS/99tKzv0F8H3gR8CewFhgrKQzSs7t8nvgMOBEYB/gfuABSeXM0hIRLbEATwATah4LeBEYm3k/\nVgNHN+gcbF/kH9LA12E58J1MWVsBTwOHAg8Cl2bKHQ+0N+DcXgQ81KjXdj37cxnwTIacqcDVdev+\nCNyYIbsPaZqdI+rWzwbOLyOzJVrakjYltfT+0rUu0pl9ADioUfvVANuSWj5v5A4uPsKOBLYAHs8U\newUwNSJmZMqr1b/oDvu7pEmSPpMh8yhgtqTbiu6wdkmnZchdR/E/dyKpFVq2x4DDJPUvsgcCXwTu\nyZC9CdCb9OmmVgclfbqq4r1HumN70oldVrd+GbBH/t3JT5JILZ9HIyJL/2qRuw+pSPcB3gKOjYiF\nGXJHAl8gfWTP7QngFFIrf0fgXOBhSftExMoSc3cFfkjqBryQ1C12uaT/RMSkEnPX51hgG+CGDFkX\nAX2BhZI6Sd2+Z0fELWUHR8S/JT0OnCNpIammnEBqDD5bRmarFO33IvL2MTfSlcBepBZITguBgaRW\n/jeAGyUNLbNwS/o06Q1qRERknyE2IqbVPJwnaRbwPPAt4LoSo3sBsyLinOLxXEl7kwp57qI9Grg3\nIl7NkHUcqVCOBOaT3qwnSHo5Im7KkD8KuBZ4CVgFtAOTgVIuALdK0X4d6CRdGKr1CdZtfTcdSb8F\njgSGRMQrObMjYhXwXPGwXdIBwE9IhaQsg4CPA3OKTxiQPmkNLS5ObV50j2URESskPQPsVnLUK8CC\nunULgK+XnLsWSf1IF76/linyYuDXEfGH4vFTknYGxgGlF+2IWAwMLy7w942IZZJuARaXkdcSfdpF\na2sO6Qov8P/ugsNI/WFNqyjYxwDDI+KFRu8P6W9u85IzHgA+R2pxDSyW2aTW5sCcBRvSkDDgs6Si\nWqaZrNvdtweplZ/TaFJjKEefMqTrJPWv6Woy17eI6CgK9kdJo3fuLCOnVVraAJcCN0iaA8wCxpBe\n7OvLDpa0JamV1dXq27W4WPJGRCwtMfdK4HjgaGClpK5PGisiovQ7JEq6ELiXNPRva9KFqWHA4WXm\nFv3Ga/XbS1oJLI+I+pZoj5N0CWlEw/PAp4DzSB+bp5Qc3QbMlDSONMzuQOA00pDHLIrG0CnA9RGx\nOlPsVOBsSUuBp0jdEmOAa3KESzqc9L/9NNCf1PJfQFm1pewhMR+mhTSOcwnpyu7jwOBMucNI7/yd\ndcu1JeeuL7MTOCnTcV9D6hrpAF4FpgOHNui1n0G+IX9TSMNJO4AXSP2bu2TKPhJ4EnibVMBGZz7P\nI4q/sd0yZm5JapQtBlaSLgCeB2ySKf+bwKLi9X4JmABsXVaeb81qZlYhLdGnbWbWLFy0zcwqxEXb\nzKxCXLTNzCrERdvMrEJctM3MKsRF28ysQly0zcwqxEXbzKxCXLTNMpH0YK55Kq15uWhbU5J0kKRV\nku7ewOddJ+n2svbLbGO5aFuzGg1cDgwrbYJVswZw0bamI2kL0iwxvwP+DJxc9/O9JE2VtELSm5Ie\nkrSLpPHFtsdIWi2pU9JQScOKx31rfsfAYl2/4vHHJE2WtFTSSklPFlOemfUoF21rRiOBhRHxLHAz\ncGrXDyTtBDxMuo3ml0j3Xr6WdG/5S0j3ob6PNMvRjqyZJGN9t8OsXdeHNNHCkcDewFWkqdX276mD\nMoPWmgTBWsdo1kwzdR/Qt5iX8mHgDOBfwPER0Vlss6jriZI6gM0i4rWadR8YGBEvk+7p3OUKSUeQ\n7rX8t404FrO1uKVtTUXSHsABwK0ARWG+jVTIIU099khNwe6p3F6Szim6RZZLeos0Q0+/nswxc0vb\nms2ppEl8X65rIb8j6cekbpEN1TVtVu0v3LRum7HAmaRJi+eRZlCZAGzWjTyz9+SibU1DUm/g28BP\ngfvrfnwnqa/7SeAkSb3fo7X9X1LRr/UaqWDvCKwo1u1bt83BwF0RMaXYF5HmC5yPWQ9y94g1k6OA\nbUlzb86vXYDbSa3wicA2wK2SBknaTdIoSf2L37EE+Lyk3SVtJ2kTUp/3UuDcYvuvkt4Yaj0LjCjG\nhw8gXYjcoewDttbjom3NZDRwf0S8tZ6f/QkYTJodfThpMti/kkZ8nAa8W2x3NWlW7dnAP4CDI2IV\nqZW+JzAX+Dlwdt3v/xXQTrrwOQN4BbijbhtPyGobzRP7mplViFvaZmYV4qJtZlYhLtpmZhXiom1m\nViEu2mZmFeKibWZWIS7aZmYV4qJtZlYhLtpmZhXiom1mViEu2mZmFfI/1HOp484XZnwAAAAASUVO\nRK5CYII=\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f841eb30f98>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "test_error, confusions = error_rate(test_prediction.eval(), test_labels)\n",
+ "print('Test error: %.1f%%' % test_error)\n",
+ "\n",
+ "plt.xlabel('Actual')\n",
+ "plt.ylabel('Predicted')\n",
+ "plt.grid(False)\n",
+ "plt.xticks(numpy.arange(NUM_LABELS))\n",
+ "plt.yticks(numpy.arange(NUM_LABELS))\n",
+ "plt.imshow(confusions, cmap=plt.cm.jet, interpolation='nearest');\n",
+ "\n",
+ "for i, cas in enumerate(confusions):\n",
+ " for j, count in enumerate(cas):\n",
+ " if count > 0:\n",
+ " xoff = .07 * len(str(count))\n",
+ " plt.text(j-xoff, i+.2, int(count), fontsize=9, color='white')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "yLnS4dGiMwI1"
+ },
+ "source": [
+ "We can see here that we're mostly accurate, with some errors you might expect, e.g., '9' is often confused as '4'.\n",
+ "\n",
+ "Let's do another sanity check to make sure this matches roughly the distribution of our test set, e.g., it seems like we have fewer '5' values."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2016-09-16T14:55:18.083458",
+ "start_time": "2016-09-16T14:55:17.830485"
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "x5KOv1AJMgzV",
- "colab_type": "code",
- "colab": {
- "autoexec": {
- "startup": false,
- "wait_interval": 0
- },
- "output_extras": [
- {
- "item_id": 1
- }
- ]
- },
- "cellView": "both",
- "executionInfo": {
- "elapsed": 352,
- "status": "ok",
- "timestamp": 1446753006584,
- "user": {
- "color": "#1FA15D",
- "displayName": "Michael Piatek",
- "isAnonymous": false,
- "isMe": true,
- "permissionId": "00327059602783983041",
- "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
- "sessionId": "716a6ad5e180d821",
- "userId": "106975671469698476657"
- },
- "user_tz": 480
- },
- "outputId": "2acdf737-bab6-408f-8b3c-05fa66d04fe6"
- },
- "source": [
- "plt.xticks(numpy.arange(NUM_LABELS))\n",
- "plt.hist(numpy.argmax(test_labels, 1));"
- ],
- "outputs": [
- {
- "output_type": "display_data",
- "metadata": {},
- "data": {
- "image/png": "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\nqSGWviQ15H8Bc9sQZEMpbW0AAAAASUVORK5CYII=\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f2265a72d50>"
- ]
- }
- }
- ],
- "execution_count": 0
+ "cellView": "both",
+ "colab": {
+ "autoexec": {
+ "startup": false,
+ "wait_interval": 0
+ },
+ "output_extras": [
+ {
+ "item_id": 1
+ }
+ ]
+ },
+ "colab_type": "code",
+ "collapsed": false,
+ "executionInfo": {
+ "elapsed": 352,
+ "status": "ok",
+ "timestamp": 1446753006584,
+ "user": {
+ "color": "#1FA15D",
+ "displayName": "Michael Piatek",
+ "isAnonymous": false,
+ "isMe": true,
+ "permissionId": "00327059602783983041",
+ "photoUrl": "//lh6.googleusercontent.com/-wKJwK_OPl34/AAAAAAAAAAI/AAAAAAAAAlk/Rh3u6O2Z7ns/s50-c-k-no/photo.jpg",
+ "sessionId": "716a6ad5e180d821",
+ "userId": "106975671469698476657"
+ },
+ "user_tz": 480
},
+ "id": "x5KOv1AJMgzV",
+ "outputId": "2acdf737-bab6-408f-8b3c-05fa66d04fe6"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "E6DzLSK5M1ju",
- "colab_type": "text"
- },
- "source": [
- "Indeed, we appear to have fewer 5 labels in the test set. So, on the whole, it seems like our model is learning and our early results are sensible.\n",
- "\n",
- "But, we've only done one round of training. We can greatly improve accuracy by training for longer. To try this out, just re-execute the training cell above."
+ "data": {
+ "image/png": "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\nG1beKa9dAAAAAElFTkSuQmCC\n",
+ "text/plain": [
+ "<matplotlib.figure.Figure at 0x7f841c174f60>"
]
+ },
+ "metadata": {},
+ "output_type": "display_data"
}
- ]
-} \ No newline at end of file
+ ],
+ "source": [
+ "plt.xticks(numpy.arange(NUM_LABELS))\n",
+ "plt.hist(numpy.argmax(test_labels, 1));"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "E6DzLSK5M1ju"
+ },
+ "source": [
+ "Indeed, we appear to have fewer 5 labels in the test set. So, on the whole, it seems like our model is learning and our early results are sensible.\n",
+ "\n",
+ "But, we've only done one round of training. We can greatly improve accuracy by training for longer. To try this out, just re-execute the training cell above."
+ ]
+ }
+ ],
+ "metadata": {
+ "anaconda-cloud": {},
+ "colab": {
+ "default_view": {},
+ "name": "Untitled",
+ "provenance": [],
+ "version": "0.3.2",
+ "views": {}
+ },
+ "kernelspec": {
+ "display_name": "Python [default]",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.5.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/tensorflow/tools/docs/gen_cc_md.py b/tensorflow/tools/docs/gen_cc_md.py
index d6818cc295..81ec71185e 100644
--- a/tensorflow/tools/docs/gen_cc_md.py
+++ b/tensorflow/tools/docs/gen_cc_md.py
@@ -85,7 +85,6 @@ write the graph to a file.
@@TensorShapeUtils
@@PartialTensorShape
@@PartialTensorShapeUtils
-@@TF_Buffer
## Thread
diff --git a/tensorflow/tools/gcs_test/Dockerfile b/tensorflow/tools/gcs_test/Dockerfile
index a9d2e8a3ae..aebad1c5a7 100644
--- a/tensorflow/tools/gcs_test/Dockerfile
+++ b/tensorflow/tools/gcs_test/Dockerfile
@@ -16,7 +16,7 @@ RUN ./install_google_cloud_sdk.bash --disable-prompts --install-dir=/var/gcloud
# Install nightly TensorFlow pip
RUN pip install \
- https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0rc0-cp27-none-linux_x86_64.whl
+ https://ci.tensorflow.org/view/Nightly/job/nightly-matrix-cpu/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
# Copy test files
RUN mkdir -p /gcs-smoke/python
diff --git a/tensorflow/tools/git/gen_git_source.py b/tensorflow/tools/git/gen_git_source.py
index 6c0770b1ff..ffd228ed7e 100755
--- a/tensorflow/tools/git/gen_git_source.py
+++ b/tensorflow/tools/git/gen_git_source.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,6 +30,7 @@ from __future__ import print_function
import argparse
import json
import os
+import subprocess
import shutil
@@ -111,7 +112,10 @@ def configure(src_base_path, debug=False):
if src is None:
open(os.path.join(gen_path, target), "w").write("")
else:
- os.symlink(src, os.path.join(gen_path, target))
+ if hasattr(os, 'symlink'):
+ os.symlink(src, os.path.join(gen_path, target))
+ else:
+ shutil.copy2(src, os.path.join(gen_path, target))
json.dump(spec, open(os.path.join(gen_path, "spec.json"), "w"), indent=2)
if debug:
@@ -157,9 +161,8 @@ def generate(arglist):
raise RuntimeError(
"Run ./configure again, branch was '%s' but is now '%s'" %
(old_branch, new_branch))
- strs["tf_git_version"] = os.popen(
- "git -C \"%s\" describe --long --dirty --tags" %
- (data["path"],)).read().strip()
+ strs["tf_git_version"] = subprocess.check_output(
+ ["git", "-C", data["path"], "describe", "--long", "--dirty", "--tags"]).strip()
# TODO(aselle): Check for escaping
cpp_file = "\n".join("const char* %s() {return \"%s\";}" % (x, y)
for x, y in strs.items())
@@ -177,7 +180,7 @@ def raw_generate(output_file):
"""
strs = {"tf_compiler_version": "__VERSION__"}
- version = os.popen("git describe --long --dirty --tags").read().strip()
+ version = subprocess.check_output(["git", "describe", "--long", "--dirty", "--tags"]).strip()
version = version if version else "unknown"
strs["tf_git_version"] = version
cpp_file = "\n".join("const char* %s() {return \"%s\";}" % (x, y)
diff --git a/tensorflow/tools/pip_package/setup.py b/tensorflow/tools/pip_package/setup.py
index 1fda9fd49f..a8a8193c8e 100644
--- a/tensorflow/tools/pip_package/setup.py
+++ b/tensorflow/tools/pip_package/setup.py
@@ -27,7 +27,7 @@ from setuptools import find_packages, setup, Command, Extension
from setuptools.command.install import install as InstallCommandBase
from setuptools.dist import Distribution
-_VERSION = '0.10.0rc0'
+_VERSION = '0.10.0'
numpy_version = "1.8.2"
if platform.system() == "Darwin":
diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl
index dd3c7b257f..ac92050fe0 100644
--- a/tensorflow/workspace.bzl
+++ b/tensorflow/workspace.bzl
@@ -26,7 +26,7 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""):
native.git_repository(
name = "com_googlesource_code_re2",
remote = "https://github.com/google/re2.git",
- commit = "fc6337a382bfd4f7c861abea08f872d3c85b31da",
+ commit = "7bab3dc83df6a838cc004cc7a7f51d5fe1a427d5",
)
native.git_repository(
@@ -204,3 +204,8 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""):
sha256 = "36658cb768a54c1d4dec43c3116c27ed893e88b02ecfcb44f2166f9c0b7f2a0d",
build_file = str(Label("//:zlib.BUILD")),
)
+
+ native.bind(
+ name = "zlib",
+ actual = "@zlib_archive//:zlib",
+ )
diff --git a/third_party/gpus/crosstool/CROSSTOOL.tpl b/third_party/gpus/crosstool/CROSSTOOL.tpl
index 18aab5b3d8..3ce6b74a52 100644
--- a/third_party/gpus/crosstool/CROSSTOOL.tpl
+++ b/third_party/gpus/crosstool/CROSSTOOL.tpl
@@ -120,7 +120,7 @@ toolchain {
# linker_flag: "-Wl,--detect-odr-violations"
# Include directory for cuda headers.
- cxx_builtin_include_directory: "/usr/local/cuda%{cuda_version}/include"
+ cxx_builtin_include_directory: "%{cuda_include_path}"
compilation_mode_flags {
mode: DBG
@@ -219,7 +219,7 @@ toolchain {
linker_flag: "-no-canonical-prefixes"
# Include directory for cuda headers.
- cxx_builtin_include_directory: "/usr/local/cuda%{cuda_version}/include"
+ cxx_builtin_include_directory: "%{cuda_include_path}"
compilation_mode_flags {
mode: DBG
diff --git a/third_party/gpus/crosstool/clang/bin/crosstool_wrapper_driver_is_not_gcc.tpl b/third_party/gpus/crosstool/clang/bin/crosstool_wrapper_driver_is_not_gcc.tpl
index b32bb966cf..d3bb93c036 100755
--- a/third_party/gpus/crosstool/clang/bin/crosstool_wrapper_driver_is_not_gcc.tpl
+++ b/third_party/gpus/crosstool/clang/bin/crosstool_wrapper_driver_is_not_gcc.tpl
@@ -95,6 +95,7 @@ def GetHostCompilerOptions(argv):
parser.add_argument('-iquote', nargs='*', action='append')
parser.add_argument('--sysroot', nargs=1)
parser.add_argument('-g', nargs='*', action='append')
+ parser.add_argument('-fno-canonical-system-headers', action='store_true')
args, _ = parser.parse_known_args(argv)
@@ -106,6 +107,8 @@ def GetHostCompilerOptions(argv):
opts += ' -iquote ' + ' -iquote '.join(sum(args.iquote, []))
if args.g:
opts += ' -g' + ' -g'.join(sum(args.g, []))
+ if args.fno_canonical_system_headers:
+ opts += ' -fno-canonical-system-headers'
if args.sysroot:
opts += ' --sysroot ' + args.sysroot[0]
diff --git a/third_party/gpus/cuda_configure.bzl b/third_party/gpus/cuda_configure.bzl
index ddd376cddb..06ae39e8b9 100644
--- a/third_party/gpus/cuda_configure.bzl
+++ b/third_party/gpus/cuda_configure.bzl
@@ -120,13 +120,31 @@ def _enable_cuda(repository_ctx):
return False
-def _cuda_toolkit_path(repository_ctx):
- """Finds the cuda toolkit directory."""
+def _cuda_toolkit_path(repository_ctx, cuda_version):
+ """Finds the cuda toolkit directory.
+
+ Args:
+ repository_ctx: The repository context.
+ cuda_version: The cuda toolkit version.
+
+ Returns:
+ A speculative real path of the cuda toolkit install directory.
+ """
cuda_toolkit_path = _DEFAULT_CUDA_TOOLKIT_PATH
if _CUDA_TOOLKIT_PATH in repository_ctx.os.environ:
cuda_toolkit_path = repository_ctx.os.environ[_CUDA_TOOLKIT_PATH].strip()
if not repository_ctx.path(cuda_toolkit_path).exists:
auto_configure_fail("Cannot find cuda toolkit path.")
+
+ if cuda_version:
+ # Handle typical configuration where the real path is
+ # <basedir>/cuda-<version> and the provided path is <basedir>/cuda.
+ version_suffixed = "%s-%s" % (cuda_toolkit_path, cuda_version)
+ if repository_ctx.path(version_suffixed).exists:
+ return version_suffixed
+ # Returns the non-versioned path if cuda version is not provided or if the
+ # installation does not use a cuda- directory, such as on ArchLinux where
+ # CUDA installs directly to /opt/cuda.
return cuda_toolkit_path
@@ -173,6 +191,11 @@ def _compute_capabilities(repository_ctx):
def _cpu_value(repository_ctx):
+ os_name = repository_ctx.os.name.lower()
+ if os_name.startswith("mac os"):
+ return "Darwin"
+ if os_name.find("windows") != -1:
+ return "Windows"
result = repository_ctx.execute(["uname", "-s"])
return result.stdout.strip()
@@ -209,6 +232,17 @@ def _cuda_symlink_files(cpu_value, cuda_version, cudnn_version):
cuda_rand_lib = "lib/libcurand%s.dylib" % cuda_ext,
cuda_fft_lib = "lib/libcufft%s.dylib" % cuda_ext,
cuda_cupti_lib = "extras/CUPTI/lib/libcupti%s.dylib" % cuda_ext)
+ elif cpu_value == "Windows":
+ return struct(
+ cuda_lib_path = "lib",
+ cuda_rt_lib = "lib/cudart%s.dll" % cuda_ext,
+ cuda_rt_lib_static = "lib/cudart_static.lib",
+ cuda_blas_lib = "lib/cublas%s.dll" % cuda_ext,
+ cuda_dnn_lib = "lib/cudnn%s.dll" % cudnn_ext,
+ cuda_dnn_lib_alt = "cudnn%s.dll" % cudnn_ext,
+ cuda_rand_lib = "lib/curand%s.dll" % cuda_ext,
+ cuda_fft_lib = "lib/cufft%s.dll" % cuda_ext,
+ cuda_cupti_lib = "extras/CUPTI/lib/cupti%s.dll" % cuda_ext)
else:
auto_configure_fail("Not supported CPU value %s" % cpu_value)
@@ -353,8 +387,8 @@ def _symlink_dir(repository_ctx, src_dir, dest_dir):
def _create_cuda_repository(repository_ctx):
"""Creates the repository containing files set up to build with CUDA."""
- cuda_toolkit_path = _cuda_toolkit_path(repository_ctx)
cuda_version = _cuda_version(repository_ctx)
+ cuda_toolkit_path = _cuda_toolkit_path(repository_ctx, cuda_version)
cudnn_install_basedir = _cudnn_install_basedir(repository_ctx)
cudnn_version = _cudnn_version(repository_ctx)
compute_capabilities = _compute_capabilities(repository_ctx)
@@ -408,7 +442,7 @@ def _create_cuda_repository(repository_ctx):
gcc_host_compiler_includes = _gcc_host_compiler_includes(repository_ctx, cc)
_tpl(repository_ctx, "crosstool:CROSSTOOL",
{
- "%{cuda_version}": ("-%s" % cuda_version) if cuda_version else "",
+ "%{cuda_include_path}": cuda_toolkit_path + '/include',
"%{gcc_host_compiler_includes}": gcc_host_compiler_includes,
})
_tpl(repository_ctx,
diff --git a/util/python/python_config.sh b/util/python/python_config.sh
index d7090a4450..c32603315f 100755
--- a/util/python/python_config.sh
+++ b/util/python/python_config.sh
@@ -142,10 +142,13 @@ function setup_python {
for x in $EXPECTED_PATHS; do
if [ -e "$x" ]; then
- rm "$x"
+ # This makes ./configure slow on Windows, but it works.
+ rm -rf "$x"
fi
done
+# ln -sf is acutally implemented as copying in msys since creating symbolic links is privileged on Windows
+# So we need -rf to remove them above.
ln -sf "${python_include}" util/python/python_include
ln -sf "${python_lib}" util/python/python_lib
ln -sf "${numpy_include}" third_party/py/numpy/numpy_include
@@ -159,13 +162,24 @@ function setup_python {
echo "export PYTHON_BIN_PATH=$PYTHON_BIN_PATH" > tools/python_bin_path.sh
}
+PLATFORM="$(uname -s | tr 'A-Z' 'a-z')"
+function is_windows() {
+ # On windows, the shell script is actually running in msys
+ if [[ "${PLATFORM}" =~ msys_nt* ]]; then
+ true
+ else
+ false
+ fi
+}
+
function check_python {
for x in $EXPECTED_PATHS; do
if [ ! -e "$x" ]; then
echo -e "\n\nERROR: Cannot find '${x}'. Did you run configure?\n\n" 1>&2
exit 1
fi
- if [ ! -L "${x}" ]; then
+ # Don't check symbolic link on Windows
+ if ! is_windows && [ ! -L "${x}" ]; then
echo -e "\n\nERROR: '${x}' is not a symbolic link. Internal error.\n\n" 1>&2
exit 1
fi