あれ
この方針をさらに推し進めたのがinstructor-embedding[8]で、色々なプロンプトを入れてタスクごとに埋め込みを最適化できるらしい
E5でTwo-Towerモデルっぽいことができる
Multilingual-E5でも実は入力文に"query:" "document:"というプロンプトを入れて、2つ(検索文と検索対象)を識別できる
JaColBERT
GLuCoSE
Sentence EmbeddingはBERTよりGloVeの方が良い
実験的にも、BERTの[CLS]トークン埋め込み や 平均プーリング埋め込み を使うぐらいだったら、GloVe等の(もっと古い時代の)単語埋め込みを使った方がましということが知られている
GloVe
intfloat/multilingual-e5-small
『日本語に対応した Embedding Model のベクトル検索での精度比較』
あれ
Web Prowlerの推薦性能を改善する方法が見えた。
ユーザーのベクトル化であるUser Embeddingを計算して、User EmbeddingとリンクのSentence Embeddingの類似度でクロールすれば良い。
推薦も今見ているページのSentence Embeddingを使って良きようにする。
User Embeddingは操作に応じて随時修正する。
User Embeddingの初期状態は、ブラウザに保存されたお気に入りや、履歴から計算すれば良い。ローカルで動作して情報が外には出ないので、こういった情報を安全に取り扱える。
あれ
500MBあるBERTをONNXに変換した後に量子化したら110MBほどになってLambdaで動かせるようになった。
Githubに乗せるファイルは100MB以下でないとだめなので、ダメ押しでgzipで圧縮したら75MBになった。
sonoisa/sentence-bert-base-ja-mean-tokens-v2
『local llmでsentence embeddingどれ使えば良いんだっけ』
Next.jsでサーバーレスSentence Embedding
『sentence transformersで日本語を扱えるモデルのまとめ』
sentence-transformers/all-MiniLM-L6-v2
『Sentence Transformers 2.2 : 事前訓練済みモデル』
『日本語Embeddingモデルのベンチマーク比較: OpenAIが圧倒的な精度でリード』
2023年11月14日日記
朝
特に記憶に無いです。
仕事
「Next.jsを使えば忌々しいAmplifyのDataStoreを無くせるんじゃね?」とか思って、社内システムの移植を開始した。もともとReactで動いていたので、3時間ほどでシステムがNext.jsの上で動くようになった。Next.jsの恩恵が受けられるのはこれからだ。
夜
「Next.jsを使えばBERTでSentence Embeddingを取るAPIをサーバーレスでつくれるんじゃね?」とかおもって実装した結果、比較的高性能な開発機であっても計算に3秒もかかることがわかり、検索には使えず無事死亡した。
デライトが落ちていた
「あれ」ってどんなんだったっけと思って、デライトで検索しようとしたところ、デライトが落ちていた(障害のお知らせ)。普段当たり前のようにデライトが使えているが、knownetの開発を通じてデライトが安定稼働していたことの異常さに気付きつつある。knownetの方はちゃんと動いている期間のほうが短い。
探そうとしていた情報については『t_wの輪郭』を参照して見つけられた。いざというときの保証として機能してくれた。
輪郭法によるSentence Embeddingを用いた検索の強化
検索結果の候補として、知名とトークンが一致した輪郭に加えて、そこから前景後景を2回まで辿った輪郭も、検索候補とする。これにより、類義語を考慮した検索となる。
ベクトル検索と比較して、実装が簡単。ベクトル検索がまだ簡単ではないので。
輪郭の順位づけに、輪郭本体のSentence Embeddingに加えて、前景後景のSentence Embeddingを用いる。輪郭単体のSentence Embeddingでは、意図せず順位が高くなる恐れがあるが、互助的に順位を出すことで、より安定した順位付けとなる。
輪郭本体のSentence Embeddingがまだ計算されていない間も、前景後景から補完されて順位付けができる利点もある。
knownetの2023年9月30日アップデート
- knownetの検索をアップデート
- Sentence EmbeddingをALBERTからAmazon BedrockのTitan Text Embeddings v2に変更
- 検索結果としてSentence Embeddingの類似順で100個だしていたのを、なんかいい感じに変更
- URLを変更
- 新URL: https://main.d3qyy5iftduw62.amplifyapp.com/
- 旧URL: https://stg.d3qyy5iftduw62.amplifyapp.com/
- バックエンドは同じなので投稿データはそのまま引き継がれている
- いい加減にドメインを割り当てたい
あれ
Amazon BedrockでSentence Embeddingを取得する
import boto3
import json
bedrock_runtime = boto3.client('bedrock-runtime', region_name="us-east-1")
def handler(event, context):
# プロンプトに設定する内容を取得
prompt = event.get('prompt')
# 各種パラメーターの指定
modelId = 'amazon.titan-embed-text-v1'
accept = 'application/json'
contentType = 'application/json'
# リクエストBODYの指定
body = json.dumps({
"inputText": prompt,
})
# Bedrock APIの呼び出し
response = bedrock_runtime.invoke_model(
modelId=modelId,
accept=accept,
contentType=contentType,
body=body
)
# APIレスポンスからBODYを取り出す
response_body = json.loads(response.get('body').read())
print(response_body)
# レスポンスBODYから応答テキストを取り出す
embedding = response_body.get('embedding')
return embedding
コードの改変元
https://dev.classmethod.jp/articles/invoke-bedrock-form-lambda-function/
Titan Text Embeddings v2
Amazon BedrockのSentence Embeddingの料金はOpenAIと同じ
Cartesian Genetic Programmingで文章の類似度を学習
あれ
いや、「ベクトル検索ぐらいマネージドサービスあるやろ」とはなるんだけど、たけーのよ。Azure Cognitive Searchとか、一番安いので月額1万円以上する。
DynamoDBとLambdaでやりくりすれば、維持費をほぼ0円、処理があっても月額100円ぐらいで何とかなるはずなんや。
で、そのために文章をベクトル化(Sentence Embedding)する処理が必要だったのだけどもですね、世のSentence Embeddingするライブラリやら言語モデル(BERTとか)やらはファイルサイズが巨大で、Lambda関数に乗り切らんかったわけです。
そこで、BERTを小型化したALBERTでSentence Embeddingが取れるように学習してたんですけども、やっとこさそれらしい結果が出せるようになってきた。
となると、次の課題はベクトル検索のDB部分なわけです。今はJavaScriptのライブラリを使ってるので速くないので、Go言語とかでやりたい。
というか、JavaScriptでのSentence Embeddingの計算は遅いはずなので、そこもGo言語に切り替えるうまみがあるはず。
あれ
あれ
昨日・今日とSentence Embeddingを吐くALBERTをSimCSEで学習させているが、少し前にちょいと試しで学習させたときの性能を上回ることができない。
機械学習はそんな淡い夢みたいなことが度々起こる。
SimCSE
『【論文要約】SimCSE: Simple Contrastive Learning of Sentence Embeddings』
llm-book/bert-base-japanese-v3-unsup-simcse-jawiki
あれ
「ONNXならGo言語で動くし、AWS LambdaでSentence Embeddingの計算イケんじゃね???」と思われたが、そもそも日本語のSentence Embeddingに対応した小さいモデルが市井になかった。終わり。
「自分で作れや」というあれがある。GPUがねぇ。いい加減にGoogle Colaboratoryの有償契約をすべきか。
あれ
遺伝的プログラミングで誤差逆伝播法行くぞ!!!
遺伝的プログラミング(Cartesian Genetic Programming)で得られたグラフ構造に内在するパラメーターを誤差逆伝播法で学習してやるのだぁ!!
遺伝的プログラミング単体ではどうにも学習が進まないのでやってやろうじゃねぇかよとなった。
『生成 AI に必要な「基盤モデル」のメモリ使用量 98%削減につながる技術を開発 ─ 自動運転車や工作用ロボット用組み込みシステムへの搭載を目指す』も背中を後押しした。良い構造の小さいモデルで良い性能が出せることが示された。
あれ
sentence embeddingの学習のために、コサイン類似度(cos(X,Y) - target_similarity)^2 の微分がしたいが、もはや微分は記憶の彼方。
あれ
あれ
JSTS
JSTSは、日本語の文ペアの意味がどのくらい近いかを測定するためのデータセット
E5
『OpenAIの埋め込みよりも高性能?多言語E5を日本語で評価してみる』
ajinkyaT/albert-japanese-v2-finetuned-nerからsentence embeddingっぽいものが取れたと思ったが、Word Embeddingだった
「本当にsentence embeddingにござるか~~~~?単なるWord Embeddingじゃないの~~~?」と思ったので、異なる文脈における同一単語のEmbeddingの差異を取った。
結論としては差異は無いため、単なるWord Embeddingと思われる。
東京は日本の首都です
と東京は関東に位置しており、埼玉や千葉が近隣にあります
の東京
のEmbedding結果を取った結果は以下の通りとなる。
tf.Tensor(
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0.], shape=(128,), dtype=float32)
ajinkyaT/albert-japanese-v2-finetuned-nerはEnergeticAI Embeddingsで動く可能性があるかと思われたが動かなかった
さらにさらにajinkyaT/albert-japanese-v2-finetuned-nerの良い所は、EnergeticAI Embeddingsで動かせる可能性がある。tensorflowjs_converterが出力したファイル形式に見覚えがあるので。
そう思って読み込ませてみたが動かなかった。model.jsonの中身を見ると、modelTopologyがnullになっており、そのためにエラーが発生する。
ajinkyaT/albert-japanese-v2-finetuned-nerからsentence embeddingっぽいものが取れた
何も分かってないけどajinkyaT/albert-japanese-v2-finetuned-nerでsentence embeddingっぽいものが取れて、大体良い感じの類似度が出る。
from transformers import (
TFAutoModelForMaskedLM, AutoTokenizer, TFAutoModel
)
import tensorflow as tf
import tensorflowjs as tfjs
from tensorflow import keras
import numpy as np
tokenizer = AutoTokenizer.from_pretrained("ajinkyaT/albert-japanese-v2-finetuned-ner")
model = TFAutoModel.from_pretrained("ajinkyaT/albert-japanese-v2-finetuned-ner")
print(model.summary())
def embedding_calc(text):
tokens = tokenizer(text, return_tensors="tf")
return model.layers[0].get_input_embeddings().call(tokens["input_ids"])[0]
def cos_sim(v1, v2):
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
embedding1 = tf.reduce_sum(embedding_calc("東京は日本の首都です"), 0)
embedding2 = tf.reduce_sum(embedding_calc("日本の首都は東京です"), 0)
embedding3 = tf.reduce_sum(embedding_calc("this is test sentence to test"), 0)
embedding4 = tf.reduce_sum(embedding_calc("japanese capital is Tokyo"), 0)
print(cos_sim(embedding1.numpy(), embedding2.numpy())) # 0.9314501
print(cos_sim(embedding2.numpy(), embedding4.numpy())) # 0.66796505
print(cos_sim(embedding2.numpy(), embedding3.numpy())) # 0.44220626
あれ
albert-japanese-tinysegmenter
qxencoder
Wrapper around tensorflowjs universal sentence encoder.