WindowsのPython embeddable版でTensorFlowを使う

## 【内容】
WindowsのPython embeddable版でTensorFlowを使おうとして少しハマったので、解決方法を共有します。


## 【前提条件】
WindowsのPython embeddable版 + pip がインストールされていることが前提です。
embeddable版のインストール方法は下記の記事を参照してください。
[【Windowsで環境を極力汚さずにPythonを動かす方法 (Python embeddable版)】](https://qiita.com/rhene/items/68941aced93ccc9c3071)

また、TensorFlowをWindowsで動かすためには「Microsoft Visual C++ 2015 再頒布可能パッケージ Update 3」が必要になります。
Python embeddable版を動かすためにも必要ですので、すでにインストールされているはずです。

最後に2019年07月28日現在、Windows環境でTensorFlowが対応しているのは**Python3.5/3.6/3.7の64bit版のみ**になります。

なお、本記事で検証したバージョンは以下になります。

- [Python 3.5.4 embeddable 64bit](https://www.python.org/ftp/python/3.5.4/python-3.5.4-embed-amd64.zip)
- [Python 3.6.7rc2 embeddable 64bit](https://www.python.org/ftp/python/3.6.7/python-3.6.7rc2-embed-amd64.zip)
- [Python 3.7.3 embeddable 64bit](https://www.python.org/ftp/python/3.7.3/python-3.7.3-embed-amd64.zip)
- [Python 3.7.4 embeddable 64bit](https://www.python.org/ftp/python/3.7.4/python-3.7.4-embed-amd64.zip)
- [TensorFlow](https://pypi.org/project/tensorflow/) 1.11.0, 1.13.0, 1.13.1, 1.14.0


## 【pipを用いたTensorFlowのインストール方法】
Python3.5/3.6/3.7の64bit版では下記のコマンドを実行することでTensorFlowをインストールすることが可能です。

```
(pythonのインストールフォルダ)\Scripts\pip install tensorflow
　または
(pythonのインストールフォルダ)\Scripts\pip install tensorflow-gpu
```

**ただし、embeddable版ではエラーが発生して失敗します。**
バージョンによって原因と解決方法が異なりますので、それぞれについて解説します。

先に投稿した[【Windowsで環境を極力汚さずにPythonを動かす方法 (Python embeddable版)】](https://qiita.com/rhene/items/68941aced93ccc9c3071)の手順を踏んでいる場合はエラーなくインストールできるはずですので、これ以降読む必要はありません。


## 【Python 3.5.4 embeddableの場合】
embeddable版はpython本体をzipファイルの中に収めていますが、ある特定モジュールのインストールスクリプトが、このzipファイルの中を参照できないようです。
よって、以下の手順でzipファイルを解凍して、その中身をzipファイルと同じ名前のフォルダに保存することで、問題を回避できます。

### 【対応方法】
1. pythonをインストールしたフォルダ内に「python35.zip」というZIPファイルが存在します。
　このファイルの名前を「__python35.zip」に変更します。
1. pythonをインストールしたフォルダ内に新規フォルダを作成し、名前を「python35.zip」とします。
1. 先ほど名前を変更したZIPファイル「__python35.zip」の中身を「python35.zip」フォルダ内に解凍します。
1. 最後に`(pythonのインストールフォルダ)\Scripts\pip`コマンドを実行して、TensorFlowをインストールします。



## 【Python 3.6.7rc2 embeddableの場合】(3.7.2、3.7.3、3.7.4でも確認済み)
通常Pythonはカレントディレクトリに存在するPythonファイルをimportできるのですが、embeddable版ではパスが通らずアクセスできない状態になっています。
このため、特定のモジュールのインストールスクリプトが自身のモジュールを参照できずにエラーになってしまいます。
そこで、下記の方法でカレントディレクトリにパスを通すことで、問題を回避します。

### 【対応方法】
1. pythonをインストールしたフォルダ内に「current.pth」というファイルを作成します。
　(ファイル名は何でも良いですが、拡張子を「.pth」としてください)
1. 「current.pth」をメモ帳などで開いて`import sys; sys.path.append('')`と記載して保存します。
1. 最後に`(pythonのインストールフォルダ)\Scripts\pip`コマンドを実行して、TensorFlowをインストールします。


## 【動作確認】
下記のコマンドを実行して、TensorFlowのバージョンが表示されるか確認します。

```
(pythonをインストールしたフォルダ)\python -c "import tensorflow as tf; print(tf.__version__)"
```
#### 【結果】
```
1.14.0
```

## 【動作確認2】
TensorFlowのチュートリアル(手書き数字識別)を実行します。

```mnist_test.py
import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
print(model.evaluate(x_test, y_test))
```
#### 【実行】
```
(pythonをインストールしたフォルダ)\python mnist_test.py
```

#### 【結果 TF_1.11.0 CPU版】
```
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 1s 0us/step
Epoch 1/5
2018-10-19 11:11:41.986927: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
60000/60000 [==============================] - 14s 228us/step - loss: 0.1996 - acc: 0.9413
Epoch 2/5
60000/60000 [==============================] - 13s 221us/step - loss: 0.0797 - acc: 0.9752
Epoch 3/5
60000/60000 [==============================] - 13s 219us/step - loss: 0.0524 - acc: 0.9834
Epoch 4/5
60000/60000 [==============================] - 13s 218us/step - loss: 0.0371 - acc: 0.9880
Epoch 5/5
60000/60000 [==============================] - 13s 219us/step - loss: 0.0266 - acc: 0.9915
10000/10000 [==============================] - 0s 46us/step
[0.08852570028939517, 0.9753]
```
#### 【結果 TF_1.14.0 GPU版】
```
2019-07-28 15:35:49.126687: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2019-07-28 15:35:49.135333: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library nvcuda.dll
2019-07-28 15:35:49.851931: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties:
name: GeForce MX150 major: 6 minor: 1 memoryClockRate(GHz): 1.5315
pciBusID: 0000:01:00.0
2019-07-28 15:35:49.860067: I tensorflow/stream_executor/platform/default/dlopen_checker_stub.cc:25] GPU libraries are statically linked, skip dlopen check.
2019-07-28 15:35:49.868413: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1763] Adding visible gpu devices: 0
2019-07-28 15:35:50.629424: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1181] Device interconnect StreamExecutor with strength 1 edge matrix:
2019-07-28 15:35:50.633160: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1187]      0
2019-07-28 15:35:50.635637: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1200] 0:   N
2019-07-28 15:35:50.639866: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1326] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 1360 MB memory) -> physical GPU (device: 0, name: GeForce MX150, pci bus id: 0000:01:00.0, compute capability: 6.1)
Epoch 1/5
60000/60000 [==============================] - 6s 98us/sample - loss: 0.2195 - acc: 0.9353
Epoch 2/5
60000/60000 [==============================] - 5s 82us/sample - loss: 0.0955 - acc: 0.9705
Epoch 3/5
60000/60000 [==============================] - 5s 81us/sample - loss: 0.0684 - acc: 0.9787
Epoch 4/5
60000/60000 [==============================] - 5s 82us/sample - loss: 0.0524 - acc: 0.9828
Epoch 5/5
60000/60000 [==============================] - 5s 82us/sample - loss: 0.0449 - acc: 0.9851
10000/10000 [==============================] - 0s 48us/sample - loss: 0.0768 - acc: 0.9751
[0.07682957069921541, 0.9751]
```