【conda】既存環境のyml書き出しから新環境を構築するまでのメモ

以前の記事で論文の付属コードを動かそうとした際、setup.ymlでconda環境を構築しただけではうまく動作せず、結局ライブラリを入れ直したりして手こずりました(以下詳細)。

https://qiita.com/suzuki0430/items/89dd028996f7dc774796

1度の環境構築ならいいのですが、再度環境をつくりなおす場合はまたイチから苦しむことになるので、動作成功したconda環境をymlファイルに書き込む方法を調査し、もう一度同じ環境がつくれるかどうか確かめてみました。

ほぼ自分用のメモなのですが、以下のことが知りたい方には役立つと思います。

- conda環境を含んだymlファイルの生成
- ymlファイルによるconda環境の構築
- `libstdc++.so.6`のエラー解消

# ymlファイル生成
動作成功したconda仮想環境で、インストールされている全パッケージとバージョンを`environment.yml`ファイルに書き出します。

```
conda env export > environment.yml
```
対象のconda環境に入らずに書き出す場合は、以下のように書き出す仮想環境名を指定します。

```
conda env export  -n [仮想環境名] > environment.yml
```

私の環境(tabformer)を書き出したら以下のようになりました。

```yml:environment.yml
name: tabformer
channels:
  - anaconda
  - conda-forge
  - pytorch
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - _pytorch_select=0.1=cpu_0
  - asttokens=2.0.8=pyhd8ed1ab_0
  - attrs=22.1.0=pyh71513ae_1
  - backcall=0.2.0=pyh9f0ad1d_0
  - backports=1.0=py_2
  - backports.functools_lru_cache=1.6.4=pyhd8ed1ab_0
  - blas=1.0=mkl
  - bottleneck=1.3.5=py38h7deecbd_0
  - brotlipy=0.7.0=py38h27cfd23_1003
  - ca-certificates=2022.6.15=ha878542_0
  - certifi=2022.6.15=py38h578d9bd_0
  - cffi=1.15.1=py38h74dc2b5_0
  - charset-normalizer=2.0.4=pyhd3eb1b0_0
  - click=8.0.4=py38h06a4308_0
  - cryptography=37.0.1=py38h9ce1e76_0
  - cudatoolkit=11.0.221=h6bb024c_0
  - decorator=5.1.1=pyhd8ed1ab_0
  - entrypoints=0.4=pyhd8ed1ab_0
  - executing=0.10.0=pyhd8ed1ab_0
  - filelock=3.6.0=pyhd3eb1b0_0
  - freetype=2.11.0=h70c0345_0
  - giflib=5.2.1=h7b6447c_0
  - huggingface_hub=0.2.1=pyhd3eb1b0_0
  - idna=3.3=pyhd3eb1b0_0
  - importlib-metadata=4.11.3=py38h06a4308_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - importlib_resources=5.9.0=pyhd8ed1ab_0
  - intel-openmp=2021.4.0=h06a4308_3561
  - ipykernel=5.5.5=py38hd0cf306_0
  - ipython=8.4.0=py38h578d9bd_0
  - ipython_genutils=0.2.0=py_1
  - ipywidgets=8.0.1=pyhd8ed1ab_0
  - jedi=0.18.1=pyhd8ed1ab_2
  - joblib=1.1.0=pyhd3eb1b0_0
  - jpeg=9e=h7f8727e_0
  - jsonschema=4.14.0=pyhd8ed1ab_0
  - jupyter_client=7.0.6=pyhd8ed1ab_0
  - jupyter_core=4.11.1=py38h578d9bd_0
  - jupyterlab_widgets=3.0.2=pyhd8ed1ab_0
  - lcms2=2.12=h3be6417_0
  - ld_impl_linux-64=2.38=h1181459_1
  - libffi=3.3=he6710b0_2
  - libgcc=7.2.0=h69d50b8_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgfortran-ng=7.5.0=ha8ba4b0_17
  - libgfortran4=7.5.0=ha8ba4b0_17
  - libgomp=11.2.0=h1234567_1
  - libpng=1.6.37=hbc83047_0
  - libsodium=1.0.18=h36c2ea0_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - libtiff=4.2.0=h2818925_1
  - libuv=1.40.0=h7b6447c_0
  - libwebp=1.2.2=h55f646e_0
  - libwebp-base=1.2.2=h7f8727e_0
  - lz4-c=1.9.3=h295c915_1
  - matplotlib-inline=0.1.6=pyhd8ed1ab_0
  - mkl=2021.4.0=h06a4308_640
  - mkl-service=2.4.0=py38h7f8727e_0
  - mkl_fft=1.3.1=py38hd3c417c_0
  - mkl_random=1.2.2=py38h51133e4_0
  - nbformat=5.4.0=pyhd8ed1ab_0
  - ncurses=6.3=h5eee18b_3
  - nest-asyncio=1.5.5=pyhd8ed1ab_0
  - ninja=1.10.2=h06a4308_5
  - ninja-base=1.10.2=hd09550d_5
  - numexpr=2.8.3=py38h807cd23_0
  - numpy=1.23.1=py38h6c91a56_0
  - numpy-base=1.23.1=py38ha15fc14_0
  - openssl=1.1.1q=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pandas=1.4.3=py38h6a678d5_0
  - parso=0.8.3=pyhd8ed1ab_0
  - pexpect=4.8.0=pyh9f0ad1d_2
  - pickleshare=0.7.5=py_1003
  - pillow=9.2.0=py38hace64e9_1
  - pip=22.1.2=py38h06a4308_0
  - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_0
  - prompt-toolkit=3.0.30=pyha770c72_0
  - ptyprocess=0.7.0=pyhd3deb0d_0
  - pure_eval=0.2.2=pyhd8ed1ab_0
  - pycparser=2.21=pyhd3eb1b0_0
  - pygments=2.13.0=pyhd8ed1ab_0
  - pyopenssl=22.0.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pyrsistent=0.18.1=py38h0a891b7_1
  - pysocks=1.7.1=py38h06a4308_0
  - python=3.8.13=h12debd9_0
  - python-dateutil=2.8.2=pyhd3eb1b0_0
  - python-fastjsonschema=2.16.1=pyhd8ed1ab_0
  - python_abi=3.8=2_cp38
  - pytz=2022.1=py38h06a4308_0
  - pyyaml=6.0=py38h7f8727e_1
  - pyzmq=19.0.2=py38ha71036d_2
  - readline=8.1.2=h7f8727e_1
  - regex=2022.7.9=py38h5eee18b_0
  - requests=2.28.1=py38h06a4308_0
  - sacremoses=0.0.43=pyhd3eb1b0_0
  - scikit-learn=1.1.1=py38h6a678d5_0
  - scipy=1.7.3=py38hc147768_0
  - setuptools=61.2.0=py38h06a4308_0
  - six=1.16.0=pyhd3eb1b0_1
  - sqlite=3.39.2=h5082296_0
  - stack_data=0.4.0=pyhd8ed1ab_0
  - threadpoolctl=2.2.0=pyh0d69192_0
  - tk=8.6.12=h1ccaba5_0
  - tornado=6.1=py38h0a891b7_3
  - tqdm=4.64.0=py38h06a4308_0
  - traitlets=5.3.0=pyhd8ed1ab_0
  - typing-extensions=4.3.0=py38h06a4308_0
  - typing_extensions=4.3.0=py38h06a4308_0
  - urllib3=1.26.11=py38h06a4308_0
  - wcwidth=0.2.5=pyh9f0ad1d_2
  - wheel=0.37.1=pyhd3eb1b0_0
  - widgetsnbextension=4.0.2=pyhd8ed1ab_0
  - xz=5.2.5=h7f8727e_1
  - yaml=0.2.5=h7b6447c_0
  - zeromq=4.3.4=h9c3ff4c_1
  - zipp=3.8.0=py38h06a4308_0
  - zlib=1.2.12=h7f8727e_2
  - zstd=1.5.2=ha4553b6_0
  - pip:
      - sentencepiece==0.1.97
      - tokenizers==0.8.1rc2
      - torch==1.7.1
      - torchaudio==0.7.2
      - torchvision==0.8.2
      - transformers==3.2.0
```
論文の付属コードのymlファイルの中身が以下だったのですが、ほとんど別物でした。

```yml:setup.yml
name: tabformer
channels:
  - anaconda
  - pytorch
  - huggingface
  - conda-forge
dependencies:
  - python>=3.8
  - pip>=21.0
  - pytorch=1.7.1=py3.8_cuda11.0.221_cudnn8.0.5_0
  - torchvision
  - pandas
  - scikit-learn
  - transformers
  - numpy
  - libgcc
  - pip:
      - transformers==3.2.0
```
# 環境構築
生成したymlファイルで環境構築を行います。
以下を実行すると、ymlファイルに記載したとおりにconda環境が生成されます。

```
conda env create -f environment.yml
```

`conda activate tabformer`で作成した環境に入り、学習を実行してみたのですが、以下のエラーがでました。

```
ImportError: /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by /opt/conda/envs/tabformer-opt/lib/python3.8/site-packages/pandas/_libs/window/aggregations.cpython-38-x86_64-linux-gnu.so)
```
論文のymlファイルで構築した際にも出たエラーなのですが、`libstdc++.so.6`のパスがconda環境に含まれるパスになっていないことによるものでした。
以前と同様に、適切なパスを通すことで解決しました。

```
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/conda/envs/tabformer/lib
```

こちらのエラー以外は特に発生せず、学習に移ることができました。


# さいごに
イチから作るより、はるかに早く環境を構築することができました。
`libstdc++.so.6`のエラーは結局手動で直すしかないのだろうか...

# 参考資料

https://qiita.com/junkor-1011/items/cd7c0e626aedc335011d