システムとcondaのC++標準ライブラリ(libstdc++)のバージョン違い問題による事象と対処法解説

システムとcondaのC++標準ライブラリ(libstdc++)のバージョン違い問題による事象と対処法解説

こんにちは!

先日、dlibをつかったPythonアプリケーション(conda環境で動作する)作っていたところ、以下のようなエラーに遭遇しました。

ImportError: /home/mlu/anaconda3/envs/example_env/bin/../lib/libstdc++.so.6: version `GLIBCXX_3.4.32' not found (required by /home/mlu/anaconda3/envs/example_env/lib/python3.10/site-packages/_dlib_pybind11.cpython-310-x86_64-linux-gnu.so)

「dlib_pybind11モジュールがGLIBCXX_3.4.32を要求してるけど、みつからない!」という感じのエラーですね。

本稿では、どうしたらこのエラーを直せるか、だけでなく、なぜこのエラーが発生してしまうのかを解説いたします。

まず、直し方から

まず直し方ですが、以下のコマンドでエラーを解消することができます。

conda install -c conda-forge libstdcxx-ng

GLIBCXX_x.x.x not found が発生するカラクリ

実際の環境構築、パッケージのビルド・インストールシーンでこの問題が発生するメカニズムを明らかにしたいとおもいます

STEP1. まずAnacondaのインストールからみていこう

Anacondaは以下のようにインストールしました。あえて少し古いAnacondaをつかっています。

# anaconda インストール
wget https://repo.anaconda.com/archive/Anaconda3-2024.02-1-Linux-x86_64.sh

bash Anaconda3-2024.02-1-Linux-x86_64.sh -b

echo "export PATH=~/anaconda3/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc


これでAnacondaはインストールできました。

STEP2.dlibのインストールに必要なcmakeを入れる

あとでdlibをインストールしますがdlibはPythonパッケージですが、インストール時にバイナリがビルドされますので、そのビルドができるようにシステムにcmakeを入れておきます

sudo apt-get update
sudo apt install -y build-essential
sudo apt-get install -y cmake

build-essential パッケージのインストールでは、

The following NEW packages will be installed:
  build-essential g++ g++-13 libstdc++-13-dev
  Setting up g++ (4:13.2.0-7ubuntu1) ...
update-alternatives: using /usr/bin/g++ to provide /usr/bin/c++ (c++) in auto mode

ということで、g++ がシステムのデフォルトC++コンパイラとして設定されました

次にcmakeのインストールログで重要な部分を抜粋します

The following NEW packages will be installed:
  cmake cmake-data cpp cpp-13 cpp-13-x86-64-linux-gnu cpp-x86-64-linux-gnu gcc gcc-13 gcc-13-base
  gcc-13-x86-64-linux-gnu gcc-x86-64-linux-gnu libaom3 libarchive13t64 libasan8 libatomic1 libc-dev-bin
  libc-devtools libc6-dev libcc1-0 libcrypt-dev libde265-0 libgcc-13-dev libgd3 libgomp1
  ...
3 upgraded, 44 newly installed, 0 to remove and 165 not upgraded.
Need to get 77.4 MB of archives.
After this operation, 232 MB of additional disk space will be used.

Setting up gcc-13-x86-64-linux-gnu (13.3.0-6ubuntu2~24.04) ...
Setting up gcc-13 (13.3.0-6ubuntu2~24.04) ...
Setting up gcc-x86-64-linux-gnu (4:13.2.0-7ubuntu1) ...
Setting up gcc (4:13.2.0-7ubuntu1) ...

はい、このログより、cmakeをインストールしただけで GCC 13.3.0 が丸ごと新規いストールされたことがわかります

STEP3. conda仮想環境を作る

さて、次にPythonアプリケーションの実行環境としてcondaで仮想環境を作りましょう

conda create -n example_env python=3.10.0
conda init bash
source ~/.bashrc
conda activate example_env

これで example_env というconda仮想環境ができました

さて、次はこの環境にはいって、 dlib を pip でインストールしましょう

STEP4. dlibをpipインストール(+ビルド)する

インストールはいたって簡単で、以下のようにします

conda activate example_env
pip install dlib

ただ、ここでは、何が起こってるか詳細に把握するため以下のようにして詳細なログを見られるように dlib をインストールしましょう。

conda activate example_env
# dlibのビルドログを詳細に見る
pip install dlib --verbose --force-reinstall --no-cache-dir

「CMake is not installed on your system!」みたいなのがでたらSTEP2を忘れてますので、cmakeをしっかりシステムにいれておきましょう

さて、dlibをビルドすると、ログに以下のような出力がみられます

-- The C compiler identification is GNU 13.3.0
-- The CXX compiler identification is GNU 13.3.0
-- Check for working C compiler: /usr/bin/cc - skipped
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Found PythonInterp: /home/mlu/anaconda3/envs/example_env/bin/python3.10
-- Found PythonLibs: /home/mlu/anaconda3/envs/example_env/lib/libpython3.10.so
/usr/include/c++/13/new:128:26: note: in a call to allocation function 'operator new []' declared here
128 | *GLIBCXX*NODISCARD void* operator new[](std::size_t) *GLIBCXX*THROW (std::bad_alloc)

つまりどういうことかというと、
conda環境でpip installしているにも関わらず

  • コンパイラ: システムの/usr/bin/cc/usr/bin/c++(GCC 13.3.0)を使用
  • C++標準ライブラリ: システムの/usr/include/c++/13/ヘッダーを使用
  • Python環境: conda環境内のPythonライブラリを使用

つまり、dlibは

  • ビルドツール(コンパイラ)→システムのコンパイラを使っている
  • 実行環境(Python)→conda環境をつかう

ということになります

まとめると「GLIBCXX_x.x.x not found が発生するカラクリ」とは

システムの新しいGLIBCXX_3.4.32に依存するバイナリが、conda環境の古いlibstdc++で実行される エラーとなっていた。

これって結構落とし穴ですよね。

ていうか、ビルドはシステムで実行がcondaで、それぞれまったく連携していないライブラリが参照されるっていう点がなんともですね。

そもそも conda 環境とは何なのか?

condaは「隔離された実行環境」を目指してつくられており、完全なOSではないが、独自のライブラリセットを持ち、実行時は環境内のライブラリを優先使用します。前述のとおりcondaの中には libstdc++ が含まれているが、これはシステムとは無関係で、conda-forgeで独自にビルドされたパッケージであるため、システム側のライブラリとはバージョン連携も全くしていません。

そもそもGLIBCXXとは何か?

libstdc++内のABI(Application Binary Interface)バージョンで、
GLIBCXX_3.4.32のような形式であらわされます。新しい機能が追加されるたびに番号が増えていきます。

たとえば以下はGCCのバージョンとの大まかな対応関係です

GCC 11 → GLIBCXX_3.4.29まで
GCC 12 → GLIBCXX_3.4.30まで
GCC 13 → GLIBCXX_3.4.32まで
GCC 14 → GLIBCXX_3.4.33まで

そもそもlibstdcxx-ngとは何か?

libstdcxx-ngはcondaパッケージ名で、conda版のGNU C++標準ライブラリ(libstdc++)の実体です

バージョン番号(例:13, 14, 15)はGCCのメジャーバージョンに対応します

GCCバージョンと libstdcxx-ng(conda版のC++標準ライブラリ) とGLIBCXX_ の対応は?

まとめるとバージョン対応は以下のようになります
GCC 9 → libstdcxx-ng 9 → GLIBCXX_3.4.26まで
GCC 11 → libstdcxx-ng 11 → GLIBCXX_3.4.29まで
GCC 12 → libstdcxx-ng 12 → GLIBCXX_3.4.30まで
GCC 13 → libstdcxx-ng 13 → GLIBCXX_3.4.32まで

実際にシステムとcondaの差分を確認する

さて、すれ違う原理がわかったところで実際に確認してみましょう

conda側のC++標準ライブラリについて調べる

まず、conda側のlibstdcxxのバージョンをみてみましょう。

$ conda list | grep -E "(gcc|libstdcxx)"

_libgcc_mutex             0.1                        main
libgcc-ng                 11.2.0               h1234567_1
libstdcxx-ng              11.2.0               h1234567_1

はい、ここからわかるとおりcondaにはlibstdcxx-ng 11.2.0 が入っていました。これは GCC 11.2.0のビルド済C++標準ライブラリですね。

さらにGLIBCXXのバージョンをみてみましょう

$ strings ~/anaconda3/lib/libstdc++.so.6 | grep GLIBCXX | tail -5

_ZNKSs15_M_check_lengthEmmPKc@@GLIBCXX_3.4.5
_ZNKSt14basic_ifstreamIwSt11char_traitsIwEE7is_openEv@GLIBCXX_3.4
_ZNSs4_Rep26_M_set_length_and_sharableEm@@GLIBCXX_3.4.5
GLIBCXX_3.4.26
_ZNKSs11_M_disjunctEPKc@GLIBCXX_3.4

GLIBCXX_3.4.26 ですね。

ここで最初のエラーメッセージを思い出しましょう、

ImportError: /home/mlu/anaconda3/envs/example_env/bin/../lib/libstdc++.so.6: version `GLIBCXX_3.4.32' not found (required by /home/mlu/anaconda3/envs/example_env/lib/python3.10/site-packages/_dlib_pybind11.cpython-310-x86_64-linux-gnu.so)

「GLIBCXX_3.4.32 がみつからん」といっていますね。

そりゃそうです、conda側はGLIBCXX_3.4.26なのですから。

これが原因ですね。

システム側のC++標準ライブラリについて調べる

では件のdlib(つまり/home/mlu/anaconda3/envs/example_env/lib/python3.10/site-packages/_dlib_pybind11.cpython-310-x86_64-linux-gnu.so)にリンクしてるC++標準ライブラリを調べてみましょう

# ここでは $CONDA_PREFIXは/home/mlu/anaconda3/envs/example_env です
$ldd $CONDA_PREFIX/lib/python3.10/site-packages/_dlib_pybind11.cpython-310-x86_64-linux-gnu.so | grep libstdc++

        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9085cab000)

/lib/x86_64-linux-gnu/libstdc++.so.6って出ていますね。やはりdlibはシステムのlibstdc++にリンクされていましたね。conda環境の$CONDA_PREFIX/lib/libstdc++.so.6にリンクされているわけでは無いことがハッキリしました。

で、システム側のGLIBCXXを調べてみるとちゃんとシステム側には GLIBCXX_3.4.32 がありました。

strings /lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX_3.4.32

GLIBCXX_3.4.32

(または strings /lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX でシステムのlibstdc++のGLIBCXX一覧を表示させられます)

最後にもう一度、直し方

本問題について、冒頭で直し方を書きました

conda install -c conda-forge libstdcxx-ng

これでconda内のC++標準ライブラリが最新になりますが、

GCC 12 → libstdcxx-ng 12 → GLIBCXX_3.4.30まで
GCC 13 → libstdcxx-ng 13 → GLIBCXX_3.4.32まで

ということで、conda内のC++標準ライブラリはまぁ GCC 13 の標準ライブラリがあればこと足りるということなので最新版というより以下のようにGCC13が入るようにすればOKということになります

conda install -c conda-forge libstdcxx-ng=13

まとめ

今回は、Pythonパッケージのdlibにおいて、「ビルド環境と実行環境でライブラリバージョンが異なる」というdependency hellの実例と原因と対策について解説しました。
すこし古いAnacondaをいれたせいで、そこに備わっていたC++標準ライブラリも古く、逆にシステム側は新しい標準ライブラリが入っており、システム側でビルドしてしまった(というか勝手にそうなる)がためにconda環境では動かないという問題に直面しました。

PythonパッケージはLinux,GCC のようなC++層のビルドを伴うものが多く、このような依存関係問題がよく発生します。Pure Pythonだけでも結構依存関係は面倒ですが、システム層(今回でいえばlibstdcppライブラリ)のビルドでの依存関係の問題がでると「あー面倒」となりがちですが、その発生原理やビルドやリンクのメカニズムを知っていると、地に足のついたトラブル対処ができるとおもいます。逆にこのあたりをウヤムヤにすると、さらなるdependency hell に陥ることがありますので、本稿がそういったお悩み解決のお役にたてれば幸いです!

では、また次回おあいしましょう!

Read more

発話音声からリアルなリップシンクを生成する技術 第3回:wav2vec特徴量から口形パラメータへの学習

発話音声からリアルなリップシンクを生成する技術 第3回:wav2vec特徴量から口形パラメータへの学習

こんにちは! 前回までの記事では、 * wav2vecを用いた音声特徴量抽出の仕組み(第1回)と、 * リップシンク制作における累積ドリフトの補正技術(第2回) について解説してきました。今回はいよいよ、これらの技術を統合して実際に音声から口の動きを生成する核心部分に踏み込みます。 本記事で扱うのは、wav2vecが抽出した768次元の音響特徴量を、26個の口形制御パラメータの時系列データに変換する学習プロセスです。これは単なる次元削減ではありません。音の物理的特性を表す高次元ベクトルから、人間の口の動きという全く異なるモダリティへの変換なのです。この変換を実現するには、音韻と視覚的な口形の間にある複雑な対応関係を、ニューラルネットワークに学習させる必要があります。 特に重要なのは、この対応関係が静的ではなく動的であるという点です。同じ音素でも前後の文脈によって口の形が変わり、さらに音が聞こえる前から口が動き始めるという時間的なズレも存在します。これらの複雑な現象をどのようにモデル化し、学習させるのか。本記事では、LSTMとTransformerという2つの強力なアプロー

By Qualiteg 研究部
AI時代のデータ漏洩防止の要諦とテクノロジー:第1回 AI DLPとPROXY

AI時代のデータ漏洩防止の要諦とテクノロジー:第1回 AI DLPとPROXY

こんにちは!本日はAI時代のデータ漏洩防止について、とくにその通信技術面に焦点をあてつつ、AIセキュリティにどのように取り組んでいくべきか、解説いたします。 1. はじめに 生成AIの急速な普及により、企業のデータガバナンスは新たな局面を迎えています。ChatGPTやClaudeといった大規模言語モデル(LLM)は、業務効率を飛躍的に向上させる一方で、意図しない機密情報の漏洩という深刻なリスクをもたらしています。 従業員が何気なく入力した顧客情報や営業秘密が、AIサービスの学習データとして使用される可能性があることを、多くの組織はまだ十分に認識していません。従来のDLP(Data Loss Prevention)ソリューションは、メールやファイル転送を監視することには長けていましたが、リアルタイムで行われるWebベースのAIチャットやAIエージェントとの対話で発生しうる新しい脅威には対応できていないのが現状です。 本記事では、AI時代のデータ漏洩防止において中核となる技術、特にHTTPS通信のインターセプトとその限界について、技術的な観点から詳しく解説します。プロキシサーバー

By Qualiteg プロダクト開発部, Qualiteg コンサルティング
LLM推論基盤プロビジョニング講座 第5回 GPUノード構成から負荷試験までの実践プロセス

LLM推論基盤プロビジョニング講座 第5回 GPUノード構成から負荷試験までの実践プロセス

こんにちは!これまでのLLM推論基盤プロビジョニング講座では、推論速度の定義、リクエスト数見積もり、メモリ消費量計算、推論エンジン選定について詳しく解説してきました。 今回は、残りのステップである「GPUノード構成見積もり」「負荷試験」「トレードオフ検討」について一気に解説し、最後に実際のサーバー構成例をご紹介します。 STEP5:GPUノード構成見積もり GPUメモリから考える同時リクエスト処理能力 LLMサービスを構築する際、どのGPUを何台選ぶかは非常に重要な決断です。今回はLlama 8Bモデルを例に、GPUメモリ容量と同時リクエスト処理能力の関係を見ていきましょう。 GPUメモリの使われ方を理解する ここは復習となりますが、 LLM推論においてGPUメモリは主に2つの用途で消費されます 1. モデル重みデータ: LLMモデル自体を格納するためのメモリ 2. KVキャッシュ: ユーザーとの対話コンテキストを保持するための一時メモリ Llama 8Bを16ビット精度で実行する場合、モデル重みデータは約16GBのメモリを占めます。これは固定的なメモリ消

By Qualiteg コンサルティング
発話音声からリアルなリップシンクを生成する技術 第2回:AIを使ったドリフト補正

発話音声からリアルなリップシンクを生成する技術 第2回:AIを使ったドリフト補正

こんにちは! 前回の記事では、当社のMotionVoxで使用している「リップシンク」技術について、wav2vecを用いた音声特徴量抽出の仕組みを解説しました。音声から正確な口の動きを予測するための基礎技術について理解いただけたかと思います。 今回は、その続編として、リップシンク制作における重要な技術的課題である「累積ドリフト」に焦点を当てます。wav2vecで高精度な音素認識ができても、実際の動画制作では複数の音声セグメントを時系列に配置する際、わずかなタイミング誤差が蓄積して最終的に大きなずれとなる現象が発生します。 本記事では、この累積ドリフトのメカニズムと、機械学習を活用した最新の補正技術について、実際の測定データを交えながら詳しく解説していきます。前回のwav2vecによる特徴抽出と今回のドリフト補正技術を組み合わせることで、MotionVoxがどのように高品質なリップシンクを実現しているのか、その全体像が見えてくるはずです。 累積ドリフトとは何か 基本概念 累積ドリフトとは、個々の音声セグメントが持つ微小なタイミング誤差が、時間の経過とともに蓄積していく現象で

By Qualiteg 研究部