Jupyter上でkernel切り替えをしてもうまく機能しない場合の解決方法

# はじめに
Kaggleの過去の問題ではPython２を使ったりPython3でTensorFlowを使ったりとKernelを複数使い分けることがあります。そこでJupyter上でkernel切り替えを出来るようにしようとしたら以下のようなエラーが出て数日ハマりました。

```py3:error
ImportError: No module named tensorflow
```

調べた結果、**Jupyter上でのkernel切り替えが上手く機能していないのが原因**のようでした。

この記事では、まず**Anacondaを入れ終わった直後の状態からJupyter Notebook上でTensorFlowを使えるようになるまで**をまとめます。そして最後にハマった際のエラーについて少し触れようと思います。
`TensorFlowは必要ないからさっさとkernel切り替えについて教えろ`って人は*Jupyterのkernelを作成する*からお読みください。

# 実行環境
- n1-standard-1（vCPU x 1、メモリ 3.75 GB）
- Ubuntu 16.04.3
- Anaconda 3.4.0

# 解決方法
## Anacondaで仮想環境を構築する
まずはTensorFlowを入れるための仮想環境を作ります。

```bash:conda-create
$ conda create -n py35_tf python=3.5
```
`-n NAME`で名前を適当につけます。（今回はpy35_tf）

## TensorFlowをインストールする

まずは作成した環境に入りましょう。

```bash:conda-activate
$ source activate py35_tf
```

TensorFlowをインストールする方法はいくつかありますが、[公式ドキュメント](https://www.tensorflow.org/install/install_linux#InstallingAnaconda)に従ってインストールするとエラーを吐かずに済みました。

```bash:install-tf
(py35_tf)$ pip install --ignore-installed --upgrade tfBinaryURL
```
`tfBinaryURL`に自身の環境に対応するパッケージのURLをコピペします。
URL一覧は[こちら](https://www.tensorflow.org/install/install_linux#the_url_of_the_tensorflow_python_package)。
今回の場合はLinuxのPython3.5にCPU Onlyを入れたかったので、`https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.3.0-cp35-cp35m-linux_x86_64.whl`を`tfBinaryURL`として挿入しました。

## Jupyterのkernelを作成する
複数のフォーラムに複数の手段が紹介されており、混乱しました。
もっと効率の良い楽な方法があると思いますが、私は以下の手順で解決したのでとりあえずこちらを試してみてください。

```bash:create-kernel
(py35_tf)$ conda install notebook ipykernel
(py35_tf)$ ipython kernel install --user --name py35_tf --display-name Python3-TensorFlow   
```

`--name NAME`で名前を指定しないと、既存のPython3のkernelが上書きされるので要注意です。`--display-name DISPLAY-NAME`でJupyter上での表記を変更できます。

以上で無事Jupyter上でのkernel切り替え、TensorFlowが利用可能になりました。
こんな感じでJupyter上でkernelを選択できるようになっているはずです。
![スクリーンショット 2017-10-07 19.50.22.png](https://qiita-image-store.s3.amazonaws.com/0/204294/31a82aff-105f-e2ee-4bfd-e3f6af9c95be.png)


Jupyter上で今作ったkernelを選択し、TensorFlowが使えるかのテストを行います。

```py3:tf-test
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
```

`'Hello, TensorFlow!'`が出力されればめでたしめでたし。

# エラーについて
## エラーが起きた手順
[こちらの記事](https://qiita.com/tomochiii/items/8b937f15c79a0c3eae0e)を参考にTensorFlowが入ったAnacondaの仮想環境上でkernelをインストールしました。

```bash:error-kernel
$ source activate py35_tf
(py35_tf)$ ipython kernel install --user --name=py35_tf --display-name=Python3-TensorFlow
```

しかし、いざJupyter Notebook上でTensorFlowを使用すると冒頭にも示した`ImportError: No module named tensorflow`というエラーが発生しました。

TensorFlowを入れたAnacondaの仮想環境（py35_tf）上ではTensorFlowを使用しても何の問題もないので、どうやらJupyter Notebook側に問題がありそうです。

## エラーの原因
色々調べた結果、Anaconda上でのPythonパスとJupyter上でのPythonパスが一致していないことが原因だとわかりました。一番参考になったのが[こちらのスレッド](https://github.com/jupyter/notebook/issues/397)。

Anaconda上で作動しているPythonのパスを調べると

```bash:conda-path
source activate py35_tf
(py35_tf)$ python
>>> import sys
>>> sys.executable
'/home/user/anaconda3/envs/py35_tf/bin/python'
```

となりますが、Jupyter Notebookのkernelのパスを調べると

```bash:kernel-path
$ jupyter kernelspec list
python3		/home/user/anaconda3/lib/python3.5/site-packages/
py35_tf		/home/user/.local/share/jupyter/kernels/py35_tf
```
となり、py35_tfのkernelがAnaconda配下のディレクトリにないことがわかります。
次にkernelのjsonファイルを確認してみると

```bash:kernel-json
$ cd /home/user/.local/share/jupyter/kernels/py35_tf
$ vi kernel.json

{                                                                                             
 "display_name": "py35_tf_keras",                                                             
 "language": "python",                                                                        
 "argv": [                                                                                    
  "/home/user/anaconda3/bin/python",                                                
  "-m",                                                                                       
  "ipykernel",                                                                                
  "-f",                                                                                       
  "{connection_file}"                                                                         
 ]
}      
```
となり、Anacondaの仮想環境py35_tf内のPythonインタープリターで確認したパス`/home/user/anaconda3/envs/py35_tf/bin/python`ではないことがわかります。これはおそらく、**よくわかんないからとりあえずAnacondaの標準のPythonパスを通しておくね。作った仮想環境のPythonパスは通ってないよ。**という状態なのだと思います。

実際にJupyter Notebook上でpy35_tfのカーネルを選択し、`sys.executable`でPythonパスを見てみると、`/home/user/anaconda3/bin/python`が返ってきました。

じゃあjsonファイルを書き換えてAnacondaのpy35_tfと同じパス（`/home/user/anaconda3/envs/py35_tf/bin/python`）を通せばいいじゃないかと思い試してみても、Jupyter上での`sys.excecutable`は変わらずでした。

エラーの原因は以上のパスの不一致だとわかったのですが、結局解決法はわからず。GCEのインスタンスを作り直してあれこれ試行錯誤した結果、本記事で紹介する方法が唯一機能してくれました。

# 参照
- [Installing TensorFlow](https://www.tensorflow.org/install/)
- [Unable to import installed libraries #397](https://github.com/jupyter/notebook/issues/397)
- [Using both Python 2.x and Python 3.x in IPython Notebook](https://stackoverflow.com/questions/30492623/using-both-python-2-x-and-python-3-x-in-ipython-notebook)