Sentence Transformersのモデルを明示的にオフラインで使用する

Sentence Transformersのモデル読み込み含む処理をネット通信せずにオフラインで実行するために調べたので、備忘録として書き残しておきます。

結論

■ 事前準備

事前にPowershellなどで下記コマンドを実行して、モデルをローカルに保存しておきます。(この時点ではインターネット通信が必要)※本当はsnapshot_download()を使用した方が良いのですがその点については後述します。

python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2').save('./all-MiniLM-L6-v2-local')"

PS C:\Users\xxxxx\Desktop> python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2').save('./all-MiniLM-L6-v2-local')"

モデル名や保存場所は適宜書き換えて下さい。

■ コード

事前準備でローカルに保存したモデルを参照して動くコードです。

from sentence_transformers import SentenceTransformer

# sentence_transformersのモデルをキャッシュから取得する
import os
os.environ["HF_HUB_OFFLINE"] = "1"
os.environ["TRANSFORMERS_OFFLINE"] = "1"

model = SentenceTransformer(R".\all-MiniLM-L6-v2-local")
sentences = ["これはサンプル文です", "それぞれの文章が変換されます"]
embedding = model.encode(sentences)
print(embedding)

説明

以下の部分でローカルに保管したモデルファイルを指定して参照しています。

model = SentenceTransformer(R".\all-MiniLM-L6-v2-local")

下記の環境変数2つは公式サイトに載っている通りですが、端末がネットに接続されている場合でも明示的にオフライン環境で実行するように指定しています。単にオフラインで実行する場合には不要かもしれません。自分のケースはネット接続可能だけどわけあってこのコードはオフラインで実行する必要があった(後述)ので念のため書いています。

import os
os.environ["HF_HUB_OFFLINE"] = "1"
os.environ["TRANSFORMERS_OFFLINE"] = "1" 

公式サイト

状況補足

元々は下記の状況でもSentence Transformersがうまく動く方法を探していました。

  • プロキシ設定の関係で、Powershellで事前に「$env:http_proxy=”http://proxy.jp:xxxx”」とプロキシを通しておかないとHugging Faceのモデルがダウンロードできない
  • 上記のプロキシを通した状態でも、別の場所からファイルを呼び出してコードを実行するとHugging Faceのモデルを読み込めない(エラーは出ないが30分近く読み込み中のまま止まってしまう)
  • Hugging Faceのモデル読み込みを外部と通信せず、ローカルにあるファイルを参照したい
    • インターネットアクセスは可能

上記の場合には、下記の方法で解決可能でした。

  • 事前に下記コマンドでSentence Transformersのキャッシュを作成しておく(Powershellから直接ファイルorコマンドを実行すれば問題なく実行できるため、キャッシュ作成は可能)
    • python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')"
    • キャッシュファイルはWindowsの場合、デフォルトで「”C:\Users\~~~~\.cache\huggingface\hub”」に作成される。
  • 上記で作成したキャッシュを参照するように指定する
from sentence_transformers import SentenceTransformer

# sentence_transformersのモデルをキャッシュから取得する
import os
os.environ["HF_HUB_OFFLINE"] = "1"
os.environ["TRANSFORMERS_OFFLINE"] = "1"

cache_dir = R"C:\Users\<HostName>\.cache\huggingface\hub" 
model_name = "sentence-transformers/all-MiniLM-L6-v2" 
model = SentenceTransformer(model_name, cache_folder=cache_dir)
sentences = ["これはサンプル文です", "それぞれの文章が変換されます"]
embedding = model.encode(sentences)
print(embedding)

上記では環境変数 HF_HUB_OFFLINE TRANSFORMERS_OFFLINE を明示的に指定しているため、モデルの読み込みに際して、インターネット接続が可能であってもキャッシュを優先して利用します。(環境変数を指定しないとネットからモデルをダウンロードしようとするのか、止まってしまいます)

そういうわけで元々の悩み事は上記の通り「キャッシュを参照する」ことで解決したのですが……。

キャッシュを参照する方法の場合、完全にオフライン環境下では下記のようなエラーが出てしまいました。

‘(MaxRetryError(‘HTTPSConnectionPool(host=\’huggingface.co\’, port=443): Max retries exceeded with url: /sentence-transformers/all-MiniLM-L6-v2/resolve/main/modules.json (Caused by NameResolutionError(“: Failed to resolve \’huggingface.co\’ ([Errno 11001] getaddrinfo failed)”))’), ‘(Request ID: xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx)’)’ thrown while requesting HEAD https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/./modules.json

どうやらSentence Transformersはキャッシュファイルが存在する場合もHTTPリクエスト(HEAD)を投げてしまうようです。下記サイトの「ダウンロードできないときの挙動」によるとEtagを確認しようとする部分でインターネット通信が必要になるらしい。

参考:Huggingface Transformersのモデルをオフラインで利用する

元々の環境(プロキシ環境)ではこのHEAD自体は正常に通るもののモデルのダウンロード(GET?)はうまくいかないため、明示的にオフラインを指定してキャッシュを参照させれば解決しました。

ただしオフライン環境となるとHEAD自体も通らなくなるので、そもそもローカルにモデルをダウンロードしておき、そちらをモデルとして参照する必要があるようで、結論の部分で示した通りとなりました。

snapshot_download()(モデルの保存)について

今回はモデルをローカルに保存するために下記コマンドを使いました。

python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2').save('./all-MiniLM-L6-v2-local')"

ただSentenceTransformer(…)は本来、モデルを使うためのAPIであり、モデルを管理・ダウンロードするためのAPIではありません。

リポジトリの全ファイルを取得してモデルとして管理・利用する場合はHuggingFaceの snapshot_download() を用いるのが正当な方法のようです。

公式サイト

ただ今回はひとまず動けばいいという用途だったのでSentenceTransformer(…)の方を使いました。

以上、オフライン環境でSentence Transformersのモデルを使う方法についてでした。終わりです。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です