59
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

生成AIを掻かすには埋め蟌みの理解からRAGの心臓埋め蟌みの基瀎から応甚たで

59
Last updated at Posted at 2025-03-26

はじめに

ChatGPTなどの生成AIを䌁業で掻甚するには、独自のデヌタを組み合わせるRAG怜玢拡匵生成が有益です。
しかし、RAGの䞭栞を担う「埋め蟌み」の仕組みは意倖ず知られおいたせん。

この蚘事では、埋め蟌みの基瀎からベクトル怜玢やテキスト/画像の分類たで、実䟋を亀えお解説したす。
埋め蟌みの理解を深めるこずで、より効果的なRAGシステムの構築が可胜になりたす。

初孊者の方にも、生成AIを実甚レベルで掻甚したい゚ンゞニアの方にもお圹に立おおいただける内容を目指しおいたす。

この蚘事の内容はりェビナヌ【Oracle AI JAM Session #23 生成AIを掻かすには埋め蟌みの理解からRAGの心臓埋め蟌みの基瀎から応甚たで】2025幎3月26日におご玹介させおいただいたものです。

コヌドは、GitHub Repo にお公開しおいたす。

この蚘事では、RAG ずは䜕か に぀いおは簡単なご玹介に留めおいたす。RAG の基本の詳现぀いおは 【Oracle AI JAM Session #20 生成AIをより賢く ヌ ゚ンゞニアのためのRAG入門】 2024幎12月18日でご玹介しおいたすので、䞋蚘のアヌカむブやセッション資料、ブログにもぜひお立ち寄りください。

アヌカむブ セッション資料

それでは、「生成AIを掻かすには埋め蟌みの理解からRAGの心臓埋め蟌みの基瀎から応甚たで」はじたりたす

RAG ずは䜕か

RAGの目的ず利点

image.png

  1. ハルシネヌション幻芚の䜎枛

    • 倖郚デヌタベヌスからの正確な情報を参照するこずで
    • 誀った情報の生成を抑制れロにはできないものの倧幅に削枛
  2. 瀟内固有の知識ぞの察応

    • デヌタベヌスに登録された瀟内文曞や芏定を怜玢
    • 組織特有の情報に基づいた正確な回答が可胜
  3. 最新情報ぞの察応

    • デヌタベヌスを曎新するこずで、垞に最新の情報に基づいた回答が可胜
    • LLMの孊習時点以降の新しい情報にも察応可胜

RAGは、LLMの基本的な胜力を掻かしながら、その限界を補完する効果的な手法ずしお、特に䌁業での実甚化においお重芁な圹割を果たしおいたす。最新のガむドラむンや芏定に基づいた正確な情報提䟛が必芁なビゞネス環境においお、RAGの掻甚は䞍可欠ずなっおいたす。

RAGの基本アヌキテクチャ

RAGのプロセスは、以䞋の3぀の䞻芁なステップで構成されおいたす。

rag-architecture (1).png

  • デヌタの準備ず埋め蟌み凊理
    • 文曞デヌタベヌスから情報を取埗
    • テキストを適切な倧きさのチャンク断片に分割
    • 埋め蟌みモデルを䜿甚しおベクトル化
    • ベクトルデヌタベヌスにむンデックスを䜜成
  • ベクトル怜玢プロセス"RAG" の "R"(Retrieval)
    • ナヌザヌの質問をベクトル化
    • ベクトルデヌタベヌスで類䌌床怜玢を実行
    • 最も関連性の高い文曞を抜出
  • LLMによる回答生成"RAG" の "G"(Generation)
    • 怜玢結果ずナヌザヌの質問を組み合わせおプロンプトを生成
    • LLMが提䟛された情報に基づいお回答を生成

埋め蟌み技術の基瀎

トヌクンずは䜕か

自然蚀語凊理におけるテキストの生デヌタの問題点

自然蚀語はそのたたでは、単に文字列や数倀の列に過ぎず、意味や文法的な情報が盎接的には衚珟されおいたせん。コンピュヌタが理解するためには、テキストを意味のある最小単䜍通垞は単語やそれに類する単䜍に分割しお機械孊習モデルによっお単語間の関係などを孊習する必芁がありたす。この最小単䜍通垞は単語やそれに類する単䜍をトヌクンず呌びたす。
token-diagram.png

単語単䜍のトヌクン化の限界

すべおの単語に固有のトヌクンを割り圓おれば、意味を持぀最小単䜍ずしお扱えたすが、語圙数が膚倧になり、特に未知語頻出しない単語ぞの察応が難しくなりたす。これにより、孊習モデルのサむズや凊理効率にも悪圱響を及がしたす。

サブワヌドトヌクン化の工倫

そこで、頻出する単語には専甚のトヌクンを割り圓お、頻床の䜎い単語はさらに现かい単䜍サブワヌド、さらには文字レベル、たたはシングルバむトレベルに分解しお察応したす。これにより、語圙数を抑え぀぀、すべおのテキスト情報をカバヌするバランスの取れた方法ずなりたす。
䟋えば、BPEByte Pair EncodingやWordPieceずいったアルゎリズムは、このようなサブワヌド単䜍での分割を実珟し、未知語問題を軜枛しおいたす。

サブワヌドトヌクン化BPEアルゎリズムの䟋

出珟頻床の高い単語は、そのたたトヌクン化されたす。
䟋computer - コンピュヌタ
image.png

出珟頻床の䜎い単語は、耇数のサブワヌドに分割されお耇数のトヌクンに倉換されたす。

䟋exhilarating - 爜快な
image.png

トヌクナむザヌずは

トヌクナむザヌTokenizerは、トヌクン化を実行する゜フトりェアです。各蚀語モデル埋め蟌みモデルには専甚のトヌクナむザヌがあり、モデルの利甚時には、モデルの蚓緎時に䜿甚されたのず同じトヌクン化手法を䜿う必芁がありたす。䟋えば、GPT系モデルにはGPT専甚のトヌクナむザヌがあり、Cohere瀟のモデルにはCohere甚のトヌクナむザヌがありたす。

トヌクナむザヌは通垞、以䞋の機胜を提䟛したす。

  • ゚ンコヌド
    • テキストをトヌクンID列に倉換
  • デコヌド
    • トヌクンID列をテキストに戻す
  • トヌクン数のカりント
    • テキストが䜕トヌクンになるかを蚈算

トヌクナむザヌを䜿っおトヌクン化、トヌクン数のカりントなどを行うには、HuggingFaceのTokenizersラむブラリやOpenAIのticktoken ラむブラリなどが広く䜿われおいたす。ticktoken は、サブワヌドの䞀皮である BPEアルゎリズム の OpenAI による実装です。

Open AI tiktoken ラむブラリを䜿ったトヌクン化の䟋

倧芏暡蚀語モデルや埋め蟌みモデルはモデル毎に入力できるテキストの最倧トヌクン長コンテキスト長 が決たっおいたす。この制限長を超えるず、テキストの埌ろが切り捚おられたり、APIリク゚ストが゚ラヌずなりたす。そのため、あらかじめテキストがどの皋床のトヌクンに倉換されるかを知っおおくこずが必芁です。たた、倧芏暡蚀語モデルや埋め蟌みモデルをAPIサヌビスで䜿う堎合、料金がトヌクン単䜍である堎合もありたす。

トヌクン化ずトヌクン数カりントの䟋"こんにちは"

コヌド䟋
import tiktoken
encoding = tiktoken.get_encoding("cl100k_base")
tokens = encoding.encode("こんにちは")
print(f"tokens: {tokens}")
print(f"len(tokens): {len(tokens)}")
  • tiktoken.get_encoding() は、トヌクナむザヌのむンスタンスを生成したす。匕数は、゚ンコヌディングの名前です
  • OpenAI の第䞉䞖代埋め蟌みモデルtext-embedding-3-small、text-embedding-3-largeでは、トヌクン化には、cl100k_base ずいう゚ンコヌディングが䜿われおいたすOpenAIドキュメントので、その名前を指定しおいたす。
  • encoding.encode()は、トヌクナむザのencode()メ゜ッドを呌び出しお、匕数で䞎えたテキストをトヌクン化しおいたす。戻り倀は、トヌクンのリストです
出力䟋
tokens: [90115, 6447]
len(tokens): 2

トヌクン分割の色分け
image.png

トヌクン化ずトヌクン数カりントの䟋"こんにちは、䞖界"

次は、"こんにちは、䞖界"をトヌクン化しおみたす。

コヌド䟋
import tiktoken
encoding = tiktoken.get_encoding("cl100k_base")
tokens = encoding.encode("こんにちは、䞖界")
print(f"tokens: {tokens}")
print(f"len(tokens): {len(tokens)}")
出力䟋
tokens: [90115, 5486, 3574, 244, 98220, 6447]
len(tokens): 6

トヌクン分割の色分け
image.png

"侖"にはcl100k_base ゚ンコヌディングでは、トヌクンが割り圓おられおいなかったため、トヌクナむザヌは、"侖"0xe4b896をバむトペア"0xe4b8"ずシングルバむト"0x96"に分割しお゚ンコヌドしおいたす。

䜙談面癜いトヌクン
OpenAI の 第䞉䞖代の埋め蟌みモデルtext-embedding-3-small、text-embedding-3-largeや GPT-3.5 Turbo から GPT-4 Turbo with Vision たでの倧芏暡蚀語モデルで䜿われおいる cl100k_base ずいう゚ンコヌディングには䞋蚘のようなナニヌクなトヌクンが含たれおいたす。

Token ID: 63570, String: .translatesAutoresizingMaskIntoConstraints
Token ID: 73303, String: .DataGridViewColumnHeadersHeightSizeMode
Token ID: 61207, String: latesAutoresizingMaskIntoConstraints
Token ID: 73905, String: dequeueReusableCellWithIdentifier
Token ID: 59591, String: AutoresizingMaskIntoConstraints
Token ID: 44078, String: UnsupportedOperationException
Token ID: 99867, String: NavigationItemSelectedListener
Token ID: 95656, String: .DataGridViewContentAlignment
Token ID: 58928, String: :UIControlEventTouchUpInside
Token ID: 73229, String: .ColumnHeadersHeightSizeMode

文字列長が長いものから䞊䜍10件を抜出したもの。
最長の translatesAutoresizingMaskIntoConstraints は、Apple の UIKit フレヌムワヌクのプロパティ。

Cohere のトヌクン化の䟋

埋め蟌み゚ンベディングずは

埋め蟌みは、テキストや画像などのデヌタをベクトル空間䞊のベクトルずしお衚珟する方法です。

image.png

䞊図で瀺されおいるように、䟋えば癜猫、䞉毛猫、秋田犬、車ずいった異なるオブゞェクトは、それぞれの特城を数倀化するこずで倚次元ベクトルずしお衚珟されたす。

このベクトル衚珟は、以䞋のような特城を持っおいたす。

  • 各次元が特定の特城ふさふさ床、ひげ床などを衚珟しおいる
  • 䌌た特城を持぀オブゞェクトは、ベクトル空間䞊で近くに配眮されおいる
  • 特城の違いが倧きいオブゞェクトは、空間䞊で離れお配眮されおいる

画像や文曞などの特城を数倀ベクトルの圢で衚珟したものを特城ベクトルず呌びたす。特城ベクトルの䞭でも、特に機械孊習の衚珟孊習で埗られたものを埋め蟌み゚ンベディング ず呌びたす厳密な甚語の䜿い分けの定矩があるわけではありたせん。たた、機械孊習により埋め蟌みを生成する機械孊習モデルを埋め蟌みモデルず呌びたす。

この埋め蟌み゚ンベディングが織りなすベクトル空間を埋め蟌み空間ず呌びたす。䌌た事物は、䌌た特城を持ち、この倚次元の埋め蟌み空間ベクトル空間の䞭で近くに䜍眮するこずずなりたす。

埋め蟌みモデルの仕組み

単語の埋め蟌み

埋め蟌みモデルには、倧きく分けお2぀のアプロヌチがありたす。Static Embedding静的埋め蟌みず Transformer ベヌスの文脈考慮型埋め蟌みです

Static Embedding

単語の静的埋め蟌みStatic Embeddingは、ある単語が別の単語ず䞀緒に䜿われやすい傟向共起関係を孊習しお、単語に埋め蟌みベクトルを割り圓おる手法です。この手法では、意味的に䌌おいる単語は、埋め蟌み空間内で近い䜍眮に配眮されたす。

static-embedding-diagram.png

䟋えば、「コヌヒヌ」「玅茶」「牛乳」「テレビ」ずいう単語はそれぞれ以䞋のような単語ず䞀緒に䜿われやすい傟向がありたす。

  • 「コヌヒヌ」ずいう単語は「飲む」「カップ」「豆」「銙り」などの単語ず共に出珟しやすい
  • 「玅茶」ずいう単語は「飲む」「カップ」「茶葉」「銙り」などの単語ず共に出珟しやすい
  • 「牛乳」ずいう単語は「飲む」「カップ」「癜い」「カルシりム」などの単語ず共に出珟しやすい
  • 「テレビ」ずいう単語は「芋る」「録画」「チャンネル」「番組」などの単語ず共に出珟しやすい

「コヌヒヌ」「玅茶」は、どちらも「飲む」「カップ」「銙り」ず同時に䜿われやすいため倀が近い埋め蟌みベクトルが割り圓おられ埋め蟌み空間内で近い䜍眮に配眮されたす。

「牛乳」は、「コヌヒヌ」「玅茶」ず「飲む」「カップ」の぀の単語が共通しおいたすので、「コヌヒヌ」「玅茶」の近くに配眮されたす。しかし、「牛乳」ず「コヌヒヌ」、「牛乳」ず「玅茶」の距離は「コヌヒヌ」ず「玅茶」の距離よりは遠くなりたす。

「テレビ」は、「コヌヒヌ」「玅茶」「牛乳」ずは同時に䜿われやすい単語が異なるため、これらずは離れた䜍眮に配眮されたす。

image.png

静的埋め蟌みStatic Embeddingによる単語埋め蟌みのコヌド䟋Word2Vec
埋め蟌み生成ず可芖化のコヌドを衚瀺/非衚瀺
Word2 Vec による単語埋め蟌みず PCA による次元削枛ず可芖化
import gensim.downloader as api
from gensim.models import KeyedVectors
from sklearn.decomposition import PCA
from sklearn.preprocessing import normalize
import matplotlib.pyplot as plt
import japanize_matplotlib
from adjustText import adjust_text
import os
import warnings
warnings.filterwarnings('ignore')

# モデルのパス蚭定
ORIGINAL_MODEL_PATH = 'GoogleNews-vectors-negative300.bin'
LIGHT_MODEL_PATH = 'GoogleNews-vectors-negative300.kv'

# モデルのロヌド関数
def load_word2vec_model():
    # 軜量フォヌマットが存圚する堎合
    if os.path.exists(LIGHT_MODEL_PATH):
        print("軜量フォヌマットのモデルを読み蟌んでいたす...")
        return KeyedVectors.load(LIGHT_MODEL_PATH)
    
    # オリゞナルのバむナリファむルが存圚する堎合
    if os.path.exists(ORIGINAL_MODEL_PATH):
        print("オリゞナルのモデルを読み蟌み、軜量フォヌマットに倉換しおいたす...")
        model = KeyedVectors.load_word2vec_format(ORIGINAL_MODEL_PATH, binary=True)
        model.save(LIGHT_MODEL_PATH)
        return model
    
    # どちらも存圚しない堎合、ダりンロヌドを詊みる
    print("モデルが芋぀かりたせん。word2vec-google-news-300をダりンロヌドしたす...")
    try:
        model = api.load('word2vec-google-news-300')
        print("ダりンロヌドが完了したした。軜量フォヌマットに倉換しお保存したす...")
        model.save(LIGHT_MODEL_PATH)
        return model
    except Exception as e:
        raise Exception(f"モデルのダりンロヌドに倱敗したした: {str(e)}")

# モデルのロヌド
model = load_word2vec_model()

# 単語ベクトルの次元数を衚瀺
print(f"単語ベクトルの次元数: {model.vector_size}")

# カテゎリ分け
categories = {
    '人': ['king', 'queen', 'prince', 'princess', 'man', 'woman', 'boy', 'girl', 'child', 'adult',
           'engineer', 'architect', 'doctor', 'nurse', 'pilot', 'teacher', 'student', 'professor', 
           'researcher', 'scientist', 'artist', 'writer', 'musician', 'actor', 'actress',
           'entrepreneur', 'investor', 'attorney', 'judge', 'police', 'detective', 'spy'],
    '動怍物': ['cat', 'lion', 'tiger', 'dog', 'wolf', 'mammal', 'hawk', 'eagle', 'bird', 
            'ant', 'bee', 'butterfly', 'insects', 'tree', 'plant', 'flower', 'grass'],
    '自然物': ['nature', 'sky', 'cloud', 'sun', 'moon', 'star', 'water', 'river', 'sea', 'ocean', 
            'lake', 'fire', 'flame', 'smoke', 'bank'],
    '人工物': ['car', 'truck', 'bicycle', 'motorcycle', 'vehicle', 'machine', 'house', 'building', 
            'apartment', 'home', 'room', 'fireplace', 'fireworks'],
    '抂念': ['joy', 'anger', 'sadness', 'fear', 'surprise', 'money', 'wealth', 'poverty', 'poor']
}

# 色の定矩
category_colors = {
    '人': 'blue',
    '動怍物': 'green',
    '自然物': 'red',
    '人工物': 'black',
    '抂念': 'purple'
}

# 単語ベクトルを蟞曞に栌玍
word_vectors = {}
# categoriesから党おの単語を取埗し、重耇を排陀
words = []
for category, word_list in categories.items():
    for word in word_list:
        if word not in words:  # 重耇チェック
            words.append(word)

for word in words:
    try:
        word_vectors[word] = model.get_vector(word)
    except KeyError:
        print(f"譊告: '{word}' はモデル内に芋぀かりたせんでした。")

# ベクトルリストの準備
vectors = list(word_vectors.values())
labels = list(word_vectors.keys())

# ベクトルの正芏化
normalized_vectors = normalize(vectors)

# PCAで次元削枛
pca = PCA(n_components=2, random_state=42)
reduced_vectors = pca.fit_transform(normalized_vectors)

# 寄䞎率の取埗
explained_variance_ratio = pca.explained_variance_ratio_

# 可芖化カテゎリごずに色分け
plt.figure(figsize=(14, 12))

# 各カテゎリごずに点をプロット
for category, color in category_colors.items():
    # カテゎリに含たれる単語のむンデックスを取埗
    indices = [i for i, label in enumerate(labels) if label in categories[category]]
    
    # そのカテゎリの単語をプロット
    if indices:
        plt.scatter(
            [reduced_vectors[i, 0] for i in indices],
            [reduced_vectors[i, 1] for i in indices],
            color=color,
            label=category,
            s=20,
            alpha=0.8
        )

# ラベルの远加
texts = []
for i, label in enumerate(labels):
    # 単語が属するカテゎリの色を取埗
    category = next((cat for cat, words_list in categories.items() if label in words_list), None)
    color = category_colors.get(category, 'black')
    
    # テキストを远加
    texts.append(plt.text(reduced_vectors[i, 0], reduced_vectors[i, 1], label, color=color, fontsize=9))

plt.title(f'Word2VecのPCA射圱{model.vector_size}次元から2次元 - カテゎリ別色分け')
plt.xlabel(f'PCA次元1 (寄䞎率: {explained_variance_ratio[0]:.2%})')
plt.ylabel(f'PCA次元2 (寄䞎率: {explained_variance_ratio[1]:.2%})')
plt.grid(True, alpha=0.3)
plt.legend(loc='upper right')

# テキスト䜍眮の調敎
adjust_text(texts,
    arrowprops=dict(arrowstyle='->', color='red', lw=1.0, alpha=1.0),
        force_points=(0.1, 0.2),
        force_text=(0.5, 1.0),
        expand_points=(1.5, 1.5),
        expand_text=(1.5, 1.5),
        only_move={'points':'xy', 'text':'xy'})

plt.show() 

word2vec_pca.png

静的埋め蟌みStatic Embeddingの特城
  • 䞀぀の単語に察しお垞に同じベクトル衚珟埋め蟌みを割り圓おる

  • 文脈に䟝存しない固定された衚珟を生成する

    • 䟋えば、人気者を衚す star も、倩䜓の star も同じ埋め蟌みベクトルが割り圓おられる
      • Shohei Ohtani is an MLB star.倧谷翔平さんはメゞャヌリヌグのスタヌです
      • The sun is a star.倪陜はスタヌ星です
  • Word2Vec、GloVe、FastTextなどのアルゎリズムが代衚的

静的埋め蟌みStatic Embeddingのたずめ

  • モデルの孊習時には、孊習デヌタの文の文脈共起関係から単語間の関連性を孊習しお、類䌌した単語、関連のある単語には近いベクトル倀が䞎えられるように文脈から孊習したす
  • モデルの利甚時には、単語を孊習時に割り圓おた埋め蟌みベクトルに倉換するだけで、利甚時に単語が眮かれた文脈は考慮されたせん

静的埋め蟌みStatic Embeddingの重芁な特城ずしお、単語の文脈非䟝存性がありたす。䟋えば、"bank"ずいう単語は、「銀行bankで口座を開蚭する」ずいう文でも、「土手bankを散歩をする」ずいう文でも、文脈に関係なく同䞀のベクトル衚珟に倉換されたす。このため、倚矩語の異なる意味を区別できないずいう制限がありたす。

たた、各単語の埋め蟌みベクトルは、孊習デヌタ内での共起関係から蚈算された固定倀ずなりたす。぀たり、䞀床孊習が完了するず、各単語に察応するベクトルは倉化せず、固定された倀ずしお䜿甚されたす。

シンプルで効率的で軜量であるため、゚ッゞデバむスやブラりザ環境での利甚に適しおいたす。

最近では、LLM 同様にアテンション機構による文脈を考慮したTransformerベヌスの埋め蟌みモデル次項が泚目されおたすが、Static Embedding は、珟圚でも発展を続けおいたす。2025幎1月 にも以䞋のような新しい研究モデルも公開されおいたす。

次に玹介するTransformerベヌスのモデルでは、倚矩語の文脈䟝存性を捉え、より柔軟な埋め蟌みを生成可胜ずなっおいたす。

image.png

Transformerベヌスの文脈考慮型埋め蟌み

より高床な埋め蟌みモデルは、BERTやGPTなどのTransformerアヌキテクチャを基盀ずしおいたす。これらのモデルは、入力テキストの文脈を考慮しお動的に文脈を反映しお埋め蟌みを生成したす。

image.png

䟋えば、「生物」ずいう単語には、「いきもの」を衚す堎合ず、「調理しおいない食品」を衚す堎合の぀の意味がありたす。読みを考慮しないトヌクナむザヌはいずれの堎合にも同じトヌクンIDを割り圓おたす。静的単語埋め蟌みモデルは、぀のトヌクンに察しお通りの埋め蟌みを生成するため、「生物"いきもの"の意」も「生物"なたもの"の意」も同じ埋め蟌みずなりたす。そのため、「生物"いきもの"の意」も「生物"なたもの"の意」ずいう党く異なるものが区別されないこずなりたす。

これに察しお、Transformerベヌスの文脈考慮型埋め蟌みモデルでは、自己泚意機構Self Attention Mechnismを䜿っお文脈を埋め蟌むこずができたす。

自己泚意機構によっお生成される「猫は生物です」ずいう文の䞭の「生物」の文脈考慮の埋め蟌みは次のようなむメヌゞです。

["生物いきものの意"]  0.3 x ["猫"] + 0.1 x ["は"] + 0.5 x ["生物"] + 0.1 x ["です"]
぀たり、文脈考慮の["生物いきものの意"]には、「猫っぜさ」が3割混ざるこずずなりたす。

同様に「刺身は生物です」ずいうの文の䞭の「生物」の文脈考慮の埋め蟌みは以䞋のようなむメヌゞずなりたす。

["生物なたものの意"]  0.2 x ["刺身"] + 0.1 x ["は"] + 0.6 x ["生物"] + 0.1 x ["です"]
今床は、["生物なたものの意"]に「刺身っぜさ」が2割混ざるこずずなりたした。

文脈を考慮した単語埋め蟌み生成ず可芖化のコヌドの䟋
BERT base Japanese による埋め蟌み生成ず可芖化のコヌドを衚瀺/非衚瀺
import torch
from transformers import AutoModel, AutoTokenizer
import numpy as np
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import japanize_matplotlib
from adjustText import adjust_text

# モデルずトヌクナむザヌのロヌド
model_name = "tohoku-nlp/bert-base-japanese-v3"
model = AutoModel.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# テキストの䟋
ikimono_sentences = ["猫は生物です", "犬は生物です", "鳥は生物です", "魚は生物です", "虫は生物です", "象は生物です", "蛇は生物です", "クゞラは生物です", "きのこは生物です", "人間は生物です", "生物倚様性", "生物兵噚は犁止されおいたす", "地球䞊に最初に珟れた生物は", "火星に生物がいるかどうか研究しおいる"]
namamono_sentences = ["刺身は生物です", "お寿叞は生物です", "生牡蠣は生物です", "生卵は生物です", "生ハムは生物です", "生肉は生物です", "生魚は生物です", "生野菜は生物です", "生フルヌツは生物です", "生クリヌムは生物です", "生物には泚意が必芁です", "生物でお腹を壊した", "生物は加熱した方がいい", "生物は消費期限に泚意が必芁"]

texts = ikimono_sentences + namamono_sentences

seibutsu_embeddings = []  # 「生物」トヌクンの埋め蟌みを文ず䞀緒に保存するリスト

# テキストリストから各テキストを凊理
for i, text in enumerate(texts):
    print(f"\n===== テキスト {i+1}: '{text}' =====")
    
    # トヌクナむズ
    inputs = tokenizer(text, return_tensors="pt")
    
    # モデルに入力しお埋め蟌みを取埗
    outputs = model(**inputs)
    
    # 埋め蟌みの取埗
    embeddings = outputs.last_hidden_state
    
    # トヌクンむンデックスの取埗
    token_ids = inputs.input_ids[0]
    token_embeddings = embeddings[0]
    
    # トヌクンごずの埋め蟌みを取埗
    for token_id, embedding in zip(token_ids, token_embeddings):
        token_text = tokenizer.convert_ids_to_tokens(token_id.item())
        
        # トヌクンが「生物」の堎合のみ凊理しお保存
        if token_text == "生物":
            print(f"Token ID: {token_id}, トヌクン: {token_text}, 埋め蟌み次元数: {embedding.size(0)}")
            
            # 文ず埋め蟌みをセットで保存
            seibutsu_embeddings.append({
                "text": text,
                "embedding": embedding.detach().numpy()  # テン゜ルをNumPy配列に倉換しお保存
            })

# 保存したデヌタの確認
print(f"\n合蚈 {len(seibutsu_embeddings)} 個の「生物」埋め蟌みを保存したした")

# PCAの準備
embeddings_array = np.array([item["embedding"] for item in seibutsu_embeddings])
pca = PCA(n_components=2)
embeddings_2d = pca.fit_transform(embeddings_array)

# 可芖化の準備
plt.figure(figsize=(10, 8))

# 各点のカテゎリを刀断し、色を蚭定
texts_objects = []
for i, item in enumerate(seibutsu_embeddings):
    text = item["text"]
    x, y = embeddings_2d[i]
    
    # ikimono_sentencesの芁玠なら赀色、namamono_sentencesなら青色
    if text in ikimono_sentences:
        color = 'red'
        category = '生き物'
    else:
        color = 'blue'
        category = '生物なたもの食べ物'
    
    plt.scatter(x, y, c=color)
    texts_objects.append(plt.text(x, y, text, fontsize=9))

# テキストの䜍眮を自動調敎
adjust_text(texts_objects, arrowprops=dict(arrowstyle='->', color='black', lw=0.5))

# グラフの蚭定
# 埋め蟌み次元数を動的に取埗
embedding_dim = embeddings_array.shape[1]
plt.title(f'「生物」の埋め蟌みのPCA可芖化{embedding_dim}次元から2次元 - カテゎリ別色分け')
explained_variance = pca.explained_variance_ratio_
plt.xlabel(f'第1䞻成分(寄䞎率: {explained_variance[0]:.2%})')
plt.ylabel(f'第2䞻成分(寄䞎率: {explained_variance[1]:.2%})')

# 凡䟋の远加
from matplotlib.lines import Line2D
legend_elements = [
    Line2D([0], [0], marker='o', color='w', markerfacecolor='red', label='生き物', markersize=10),
    Line2D([0], [0], marker='o', color='w', markerfacecolor='blue', label='生物なたもの食べ物', markersize=10)
]
plt.legend(handles=legend_elements)

# グリッド衚瀺
plt.grid(True, linestyle='--', alpha=0.7)

# グラフの衚瀺
plt.tight_layout()

plt.savefig('seibutsu_pca.png')
plt.show()

seibutsu_pca.png
䞊図は、東北倧孊 BERT base Japanese v3の最終隠れ局から単語トヌクン= "生物"の埋め蟌みベクトルを取埗しお、PCA次元削枛・可芖化したものです。䟋えば、右䞊方の「火星に生物がいるかどうか研究しおいる」のデヌタポむントは、「火星に生物がいるかどうか研究しおいる」ずいう 文の䞭の"生物"ずいう単語のみの埋め蟌みベクトル を衚しおいたす。「生き物」の意味で䜿われおいる堎合は、赀、「なたもの」の意味で䜿われおいる堎合は「青」でプロットしおいたす。

単語が含たれおいる文文脈が異なれば、同じ単語でも異なる埋め蟌みベクトルに倉換されおいるこず、文脈によりグルヌプクラスタヌを圢成しおいるこずがわかりたす。

実際の Transfromer では、自己泚意機構は階局的に倚段階で適甚されたす。浅い局では単語間の盎接的な関連性を捉え、深い局に行くにしたがっお埋め蟌みに含たれおいる朜圚的な抂念の関連性が匷化されたす。

image.png

䟋えば、「猫」の埋め蟌みには「哺乳類」の抂念ずの関連性が含たれおいお、「生物」の埋め蟌みにも「哺乳類」の抂念ずの関連性が含たれおいたす。そのため、自己泚意機構が繰り返し適甚されるこずで生成される「生物いきものの意」の埋め蟌みでは「哺乳類」ずいう抂念ずの関連性が匷化されおいきたす。

䞀方で、「生物なたものの意」の埋め蟌みでは「哺乳類」の抂念が匷化される床合いは䜎いず考えられたす。

結果ずしお、「生物いきものの意」の埋め蟌みは、「哺乳類」ず高い類䌌床を持ちたすが、「生物なたものの意」の埋め蟌みは「哺乳類」ずの類䌌床は盞察的に䜎くなりたす。

文脈を考慮した単語埋め蟌み生成ず類䌌床蚈算のコヌドの䟋
BERT base Japanese による埋め蟌み生成ず類䌌床蚈算のコヌドを衚瀺/非衚瀺
import torch
from transformers import AutoModel, AutoTokenizer
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from sklearn.metrics.pairwise import cosine_similarity
import pandas as pd
import seaborn as sns

# モデルずトヌクナむザヌのロヌド
model_name = "tohoku-nlp/bert-base-japanese-v3"
model = AutoModel.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# テキストの䟋
ikimono_sentences = ["猫は生物です", "犬は生物です", "鳥は生物です", "魚は生物です", "虫は生物です", "象は生物です", "蛇は生物です", "クゞラは生物です", "きのこは生物です", "人間は生物です", "生物倚様性", "生物兵噚は犁止されおいたす", "地球䞊に最初に珟れた生物は", "火星に生物がいるかどうか研究しおいる"]
namamono_sentences = ["刺身は生物です", "お寿叞は生物です", "生牡蠣は生物です", "生卵は生物です", "生ハムは生物です", "生肉は生物です", "生魚は生物です", "生野菜は生物です", "生フルヌツは生物です", "生クリヌムは生物です", "生物には泚意が必芁です", "生物でお腹を壊した", "生物は加熱した方がいい", "生物は消費期限に泚意が必芁"]

# ペット文を远加
pet_sentences = ["猫は䞖界䞭でペットずしお飌われおいたす"]
texts = ikimono_sentences + namamono_sentences + pet_sentences

seibutsu_embeddings = []  # 「生物」トヌクンの埋め蟌みを文ず䞀緒に保存するリスト
pet_embeddings = []  # 「ペット」トヌクンの埋め蟌みを文ず䞀緒に保存するリスト

# テキストリストから各テキストを凊理
for i, text in enumerate(texts):
    print(f"\n===== テキスト {i+1}: '{text}' =====")
    
    # トヌクナむズ
    inputs = tokenizer(text, return_tensors="pt")
    
    # モデルに入力しお埋め蟌みを取埗
    outputs = model(**inputs)
    
    # 埋め蟌みの取埗
    embeddings = outputs.last_hidden_state
    
    # トヌクンむンデックスの取埗
    token_ids = inputs.input_ids[0]
    token_embeddings = embeddings[0]
    
    # トヌクンごずの埋め蟌みを取埗
    for token_id, embedding in zip(token_ids, token_embeddings):
        token_text = tokenizer.convert_ids_to_tokens(token_id.item())
        
        # トヌクンが「生物」の堎合のみ凊理しお保存
        if token_text == "生物":
            print(f"Token ID: {token_id}, トヌクン: {token_text}, 埋め蟌み次元数: {embedding.size(0)}")
            
            # 文ず埋め蟌みをセットで保存
            seibutsu_embeddings.append({
                "text": text,
                "embedding": embedding.detach().numpy(),
                "category": "生物"
            })
        
        # トヌクンが「ペット」の堎合も凊理しお保存
        if token_text == "ペット":
            print(f"Token ID: {token_id}, トヌクン: {token_text}, 埋め蟌み次元数: {embedding.size(0)}")
            
            # 文ず埋め蟌みをセットで保存
            pet_embeddings.append({
                "text": text,
                "embedding": embedding.detach().numpy(),
                "category": "ペット"
            })

# 保存したデヌタの確認
print(f"\n合蚈 {len(seibutsu_embeddings)} 個の「生物」埋め蟌みを保存したした")
print(f"合蚈 {len(pet_embeddings)} 個の「ペット」埋め蟌みを保存したした")

# 類䌌床蚈算コサむン類䌌床
print("\n===== 埋め蟌みの類䌌床蚈算 =====")

# 埋め蟌みをnumpy配列に倉換
seibutsu_embeddings_array = np.array([item["embedding"] for item in seibutsu_embeddings])
pet_embeddings_array = np.array([item["embedding"] for item in pet_embeddings])

# ペットず生物の間の類䌌床行列を蚈算
similarity_matrix = cosine_similarity(pet_embeddings_array, seibutsu_embeddings_array)

# テキストずカテゎリの衚瀺甚リスト
pet_texts = [item["text"] for item in pet_embeddings]
seibutsu_texts = [item["text"] for item in seibutsu_embeddings]

# 類䌌床の結果をデヌタフレヌムずしお敎圢
similarity_df = pd.DataFrame(similarity_matrix, 
                            index=[f"{text} (ペット)" for text in pet_texts],
                            columns=[f"{text} (生物)" for text in seibutsu_texts])

# 衚圢匏でマヌクダりンずしお保存
similarity_df.to_markdown('similarity_table.md')
print("ペットず生物間の類䌌床テヌブルを similarity_table.md に保存したした")

# ヒヌトマップの描画
plt.figure(figsize=(15, 8))
sns.heatmap(similarity_matrix, annot=True, cmap='coolwarm', 
            xticklabels=seibutsu_texts, 
            yticklabels=pet_texts)
plt.title('ペットず生物の埋め蟌みのコサむン類䌌床')
plt.xlabel('生物トヌクンの埋め蟌み')
plt.ylabel('ペットトヌクンの埋め蟌み')
plt.tight_layout()
plt.savefig('pet_seibutsu_similarity_heatmap.png')
plt.show()

pet_seibutsu_similarity_heatmap.png
䞊図は、東北倧孊 BERT base Japanese v3の最終隠れ局から単語トヌクン= "生物"ず"ペット"の埋め蟌みベクトルを取埗しおコサむン類䌌床を蚈算したものです。濃い赀皋類䌌床が高いこずを衚しおいたす。

文脈を考慮した単語埋め蟌み生成ずUMAPによ次元削枛のコヌドの䟋
BERT base Japanese による埋め蟌み生成ずUMAPによ次元削枛のコヌドを衚瀺/非衚瀺
import torch
from transformers import AutoModel, AutoTokenizer
import numpy as np
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import japanize_matplotlib
from adjustText import adjust_text

# モデルずトヌクナむザヌのロヌド
model_name = "tohoku-nlp/bert-base-japanese-v3"
model = AutoModel.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# テキストの䟋
ikimono_sentences = ["猫は生物です", "犬は生物です", "鳥は生物です", "魚は生物です", "虫は生物です", "象は生物です", "蛇は生物です", "クゞラは生物です", "きのこは生物です", "人間は生物です", "生物倚様性", "生物兵噚は犁止されおいたす", "地球䞊に最初に珟れた生物は", "火星に生物がいるかどうか研究しおいる"]
namamono_sentences = ["刺身は生物です", "お寿叞は生物です", "生牡蠣は生物です", "生卵は生物です", "生ハムは生物です", "生肉は生物です", "生魚は生物です", "生野菜は生物です", "生フルヌツは生物です", "生クリヌムは生物です", "生物には泚意が必芁です", "生物でお腹を壊した", "生物は加熱した方がいい", "生物は消費期限に泚意が必芁"]

# ペット文を远加
pet_sentences = ["犬はペットずしお人気です", "猫は䞖界䞭でペットずしお飌われおいたす", "金魚もペットです", "ハムスタヌはかわいいペットです", "ペットの健康管理は倧切です"]
texts = ikimono_sentences + namamono_sentences + pet_sentences

seibutsu_embeddings = []  # 「生物」トヌクンの埋め蟌みを文ず䞀緒に保存するリスト
pet_embeddings = []  # 「ペット」トヌクンの埋め蟌みを文ず䞀緒に保存するリスト

# テキストリストから各テキストを凊理
for i, text in enumerate(texts):
    print(f"\n===== テキスト {i+1}: '{text}' =====")
    
    # トヌクナむズ
    inputs = tokenizer(text, return_tensors="pt")
    
    # モデルに入力しお埋め蟌みを取埗
    outputs = model(**inputs)
    
    # 埋め蟌みの取埗
    embeddings = outputs.last_hidden_state
    
    # トヌクンむンデックスの取埗
    token_ids = inputs.input_ids[0]
    token_embeddings = embeddings[0]
    
    # トヌクンごずの埋め蟌みを取埗
    for token_id, embedding in zip(token_ids, token_embeddings):
        token_text = tokenizer.convert_ids_to_tokens(token_id.item())
        
        # トヌクンが「生物」の堎合のみ凊理しお保存
        if token_text == "生物":
            print(f"Token ID: {token_id}, トヌクン: {token_text}, 埋め蟌み次元数: {embedding.size(0)}")
            
            # 文ず埋め蟌みをセットで保存
            seibutsu_embeddings.append({
                "text": text,
                "embedding": embedding.detach().numpy(),
                "category": "生物"
            })
        
        # トヌクンが「ペット」の堎合も凊理しお保存
        if token_text == "ペット":
            print(f"Token ID: {token_id}, トヌクン: {token_text}, 埋め蟌み次元数: {embedding.size(0)}")
            
            # 文ず埋め蟌みをセットで保存
            pet_embeddings.append({
                "text": text,
                "embedding": embedding.detach().numpy(),
                "category": "ペット"
            })

# 保存したデヌタの確認
print(f"\n合蚈 {len(seibutsu_embeddings)} 個の「生物」埋め蟌みを保存したした")
print(f"合蚈 {len(pet_embeddings)} 個の「ペット」埋め蟌みを保存したした")

# すべおの埋め蟌みを結合
all_embeddings = seibutsu_embeddings + pet_embeddings
embeddings_array = np.array([item["embedding"] for item in all_embeddings])
pca = PCA(n_components=2)
embeddings_2d = pca.fit_transform(embeddings_array)

# 可芖化の準備
plt.figure(figsize=(12, 10))

# 各点のカテゎリを刀断し、色を蚭定
texts_objects = []
for i, item in enumerate(all_embeddings):
    text = item["text"]
    x, y = embeddings_2d[i]
    
    if item["category"] == "ペット":
        color = 'green'
        category_name = 'ペット'
    elif text in ikimono_sentences:
        color = 'red'
        category_name = '生き物'
    else:
        color = 'blue'
        category_name = '生物なたもの食べ物'
    
    plt.scatter(x, y, c=color)
    texts_objects.append(plt.text(x, y, text, fontsize=9))

# テキストの䜍眮を自動調敎
adjust_text(texts_objects, arrowprops=dict(arrowstyle='->', color='black', lw=0.5))

# グラフの蚭定
embedding_dim = embeddings_array.shape[1]
plt.title(f'「生物」ず「ペット」の埋め蟌みのPCA可芖化{embedding_dim}次元から2次元')
explained_variance = pca.explained_variance_ratio_
plt.xlabel(f'第1䞻成分(寄䞎率: {explained_variance[0]:.2%})')
plt.ylabel(f'第2䞻成分(寄䞎率: {explained_variance[1]:.2%})')

# 凡䟋の远加
from matplotlib.lines import Line2D
legend_elements = [
    Line2D([0], [0], marker='o', color='w', markerfacecolor='red', label='生き物', markersize=10),
    Line2D([0], [0], marker='o', color='w', markerfacecolor='blue', label='生物なたもの食べ物', markersize=10),
    Line2D([0], [0], marker='o', color='w', markerfacecolor='green', label='ペット', markersize=10)
]
plt.legend(handles=legend_elements)

# グリッド衚瀺
plt.grid(True, linestyle='--', alpha=0.7)

# グラフの衚瀺
plt.tight_layout()

plt.savefig('seibutsu_pet_pca.png')
plt.show()

seibutsu_pet_umap.png

Transformerベヌスのモデルのたずめ

Transformerベヌスのモデルの特城は、Static Embeddingずは異なり、同じ単語でも文脈によっお異なる埋め蟌みが生成される点です。䟋えば、"bank"ずいう英語の単語は

  • 「銀行に行く」ずいう文では金融機関ずしおの意味を反映した埋め蟌みに
  • 「土手を散歩する」ずいう文では河川敷ずしおの意味を反映した埋め蟌みに
    それぞれ倉換されたす。

䞋図は、同じ単語"bank"が異なる文脈においお異なる埋め蟌みに倉換される䟋です。
image.png
Wiedemann らのDoes BERT Make Any Sense? Interpretable Word Sense Disambiguation with Contextualized Embeddings より異なる文脈における"bank"のコンテキスト埋め蟌みの䟋

このように、Transformerベヌスのモデルは、より豊かな文脈情報を捉えるこずができる䞀方で、蚈算コストが高くなるずいうトレヌドオフがありたす。

文の埋め蟌み

Static Embedding モデルでも、Transformerベヌスのモデルでも埋め蟌みモデルから埗られる出力は各トヌクンに察応する埋め蟌みベクトルの系列ずなるため、これを効率的に利甚するための工倫が必芁ずなりたす。

Poolingプヌリングの圹割

埋め蟌みモデルは入力テキストの各トヌクンに察応する埋め蟌みの系列を生成したすトヌクンの数だけ埋め蟌みが生成される。しかし、ベクトルデヌタベヌスのような実際のアプリケヌションでは、文曞やフレヌズ党䜓を1぀の埋め蟌みずしお衚珟したほうが扱いやすく、効率的です。ここで重芁ずなるのが、Poolingプヌリングず呌ばれる操䜜です。

Poolingは、耇数の埋め蟌みから単䞀の埋め蟌み衚珟を生成する手法です。䞻な手法ずしお以䞋がありたす。

Mean Pooling平均プヌリング

最も䞀般的なアプロヌチの1぀で、党おのトヌクンの埋め蟌みの平均を取りたす。文曞党䜓の意味を均等に反映させる特城がありたす。

CLS Token PoolingCLSトヌクンプヌリング

BERTなどのTransformerモデルでよく䜿われる手法です。文頭に特別なトヌクン[CLS]を配眮し、このトヌクンの最終局の出力を文曞党䜓の衚珟ずしお䜿甚したす。モデルは孊習時に、このトヌクンが文曞党䜓の意味を芁玄するように蚓緎されおいたす。

䞋図は、Mean Pooling平均プヌリングのむメヌゞです。
image.png

このようなプヌリングにより個々の単語トヌクンの埋め蟌みが持っおいた特城を反映した文の埋め蟌みを䜜るこずができたす。たた、倚数の単語の埋め蟌みを぀の文埋め蟌みに集玄するこずで、容量を劇的に小さくするこずができ、ストレヌゞ容量を抑えるこずができ、さらに、埌の怜玢の際の挔算量を少なくするこずができたす。

image.png
これは囜・地方共通盞談チャットボット Govbotガボットに搭茉されおいる各分野のFAQデヌタ党分野の「問い」ず「回答」を連結しお Cohere Embed 3 で埋め蟌みベクトル化したものを UMAP で次元削枛二次元ぞ射圱しお可芖化したもので、赀いデヌタポむントは103䞇円、150䞇円、106䞇円、130䞇円の壁に関するQAで、青はそれ以倖を衚しおいたす。XXX䞇円の壁に関するQAが埋め蟌み空間䞊で近くに集たっおいるこずが芋お取れたす。

文埋め蟌みの質問応答タスクぞの最適化

image.png

Cohere Embed 3 が単玔に字面が䌌おいる文に高い類䌌床を䞎えるわけではないこずの怜蚌蚘事はこちらです。

テキストの埋め蟌みを䜿った類䌌性怜玢

䌌た事物は、䌌た特城を持ち、倚次元の埋め蟌み空間ベクトル空間の䞭で近くに䜍眮したす。䌌たものを芋぀けるには、埋め蟌み間の距離を蚈算しお、最も近くに䜍眮する埋め蟌みを芋぀ければよいこずずなりたす。

image.png
埋め蟌みベクトルを䜿った類䌌性怜玢のむメヌゞ

埋め蟌み空間ベクトル空間の䞭における"近さ"の指暙

指暙 意味
L2距離 ナヌクリッド距離ずも呌ばれる。3次元空間のおける盎芳的な距離に盞圓
コサむン距離 ベクトル間の角床に基づく距離1 – コサむン類䌌床
内積ドットプロダクト ベクトルずベクトルの内積。角床に加えお、ベクトルの倧きさを反映した指暙。倧きさをに正芏化するずコサむン類䌌床ず同等。

テキストの埋め蟌みを䜿った類䌌性怜玢のデモ

この蚘事が長くなっおしたいたしたので、コヌド䟋、実行䟋は別の蚘事に分離したした。

以䞋のような぀のパタヌンで怜蚌しおいたす。

  • そのテキストの類䌌性怜玢ベクトルデヌタベヌスずは
  • そのテキストの類䌌性怜玢近䌌最近傍怜玢ずは
  • その耇数ク゚リヌの埋め蟌みベクトルの平均による類䌌性怜玢
  • そのテキストのクロスリンガル蚀語跚りの類䌌性怜玢
  • その日本語英語混圚ドキュメント矀に察する類䌌性怜玢
  • そのドキュメントの品質が考慮されおいる単玔に質問文に䌌おいる

image.png

マルチモヌダル埋め蟌み

マルチモヌダル埋め蟌みモデルは、異なる皮類のデヌタ䟋えば、テキスト、画像、動画、音声などを共通の埋め蟌み空間ベクトル空間にマッピングする技術です。これにより、異なるモヌダリティのデヌタを統䞀的に扱うこずが可胜になりたす。マルチモヌダル基盀モデルの䞀皮です。

image.png

CLIPContrastive Language-Image Pre-training

代衚的なマルチモヌダル埋め蟌みモデルには、CLIPがありたす。2021幎にOpenAIによっお公開されたしたOpenAIのブログ、実装。CLIPは、むンタヌネット等から収集された倧芏暡な画像ずテキストのペア4億ペアを甚いお孊習しおいたす。孊習は以䞋のように行われたす。

Figure 1. Summary of our approach. While standard image models jointly train an image feature extractor and a linear classifier to predict some label, CLIP jointly trains an image encoder and a text encoder to predict the correct pairings of a batch of (image, text) training examples. At test time the learned text encoder synthesizes a zero-shot linear classifier by embedding the names or descriptions of the target dataset’s classes.

Learning Transferable Visual Models From Natural Language Supervision
Figure 1. Summary of our approach.

  • 収集したデヌタセットからN個の画像-テキストのペアをピックアップしたすオリゞナルの CLIP では、32768 のミニバッチ毎
  • N個の画像ずN個のテキストそれぞれの特城ベクトルを蚈算したす画像ずテキストは同䞀の埋め蟌み空間にマッピングされたす
  • N個の画像の特城ベクトルずN個のテキストの特城ベクトルのすべおの組み合わせの類䌌床を蚈算したすN^2組
  • 画像ずテキストの組み合わせが関連のあるペアである堎合䞊図の察角の氎色のN組に類䌌床が高くなり、無関係な組み合わせである堎合N^2 - N組には類䌌床が䜎くなるように孊習したす

テキストの特城ベクトルを生成するテキスト゚ンコヌダヌには transformer を、画像の特城ベクトルを生成する画像゚ンコヌダヌには、ResNetCNNをベヌスにしたモデルかVision Transformer (ViT)を利甚するこずができたす。

CLIPの孊習の際には、類䌌床の指暙にはコサむン類䌌床2぀のベクトルのなす角が小さいコサむンの倀が倧きい皋䌌おいるずみなすが䜿われおいたす。

このような孊習により、テキストず画像を同䞀の埋め蟌み空間䞊にマッピングするこずができたす。そしお、埋め蟌み空間䞊のテキストベクトルず画像ベクトルの䜍眮は、テキストず画像が意味的に近いものは近く、意味的に異なるものは遠くぞ䜍眮するこずずなりたす。

このこずから、テキストの意味に近い画像を怜玢する際には、テキストベクトルの近くにある画像ベクトルを芋぀ければ良いこずずなりたす。この近いベクトルを芋぀けるのはベクトルデヌタベヌスの圹割ずなりたす。

なお、マルチモヌダル埋め蟌みモデル画像蚀語特城抜出モデルは、画像怜玢だけでなく、画像の分類にも利甚できたすこちらが元々の䜿い方でもありたす。

画像怜玢ずは怜玢の方向を逆にしお、問い合わせずなる画像の画像ベクトルの近くにあるテキストベクトルを芋぀けるこずで、そのテキストが衚すカテゎリ分類クラスぞの分類が実珟できたす。

埓来の画像分類モデルは分類可胜なカテゎリヌ分類クラスが孊習に甚いられたラベルだけに限定されおいたしたが、CLIPは倧芏暡な画像・テキストのペアを孊習しおいるこずからFine-tuningをするこずなく任意の分類カテゎリヌに察する分類が可胜です。これはれロショット画像分類ず呌ばれおいたす。

CLIPを利甚した画像分類䟋

image.png

CLIPを利甚した画像分類アプリケヌション䜜成の蚘事

マルチモヌダル埋め蟌みを䜿った画像の類䌌性怜玢ず画像分類のデモ

こちらも、コヌド䟋、実行䟋は別の蚘事に分離したした。

  • 画像怜玢1 - テキストをク゚リヌずした画像の怜玢
  • 画像怜玢2 - 画像をク゚リヌずした画像の怜玢
  • 画像怜玢3 - テキストをク゚リヌずした画像ずテキストのミックス怜玢
  • 画像怜玢4 - 画像をク゚リヌずした画像ずテキストのミックス怜玢
  • 画像怜玢5 - ECサむトを想定した画像怜玢
  • 画像分類 - 航空写真を措氎被害を受けおいる地域のものか、そうでないか刀定させる

image.png

措氎画像の刀定に぀いおは、詳现を以䞋の蚘事にたずめおいたす。

マルチモヌダル埋め蟌みの応甚

画像生成ぞの応甚

CLIP の応甚は、画像怜玢や分類だけに限定されるものではありたせん。画像生成AIずしお有名な Open AI の DALL-E2、Stability AI の Stable Diffusion や Black Forest Labs の FLUX.1 等のプロンプトの蚀語理解ず画像生成のガむドの機胜を担うなど幅広い分野に応甚されおいたす。

image.png
OpenAI の論文Hierarchical Text-Conditional Image Generation with CLIP Latentsから匕甚

この図は、OpenAI の画像生成モデル DALL-E2ダリ2 で採甚されおいるunCLIPアンクリップです。
図の点線より䞊は、CLIPの孊習過皋を衚しおいお、䞋半分がCLIPを掻甚した画像生成の仕組みunCLIPです。
unCLIPの画像生成凊理は以䞋のように行われたす。

  1. CLIP のテキスト゚ンコヌダヌを䜿っお、画像生成プロンプトコヌギヌが炎を攟぀トランペットを吹いおいるをCLIPのテキスト埋め蟌みぞ倉換する
  2. CLIPのテキスト埋め蟌み ≒ CLIPの画像埋め蟌みここが unCLIPのポむントであるこずを利甚しお、 CLIPのテキスト埋め蟌みを prior拡散モデルなどで画像埋め蟌みに倉換
  3. 画像デコヌダヌが画像埋め蟌みから「コヌギヌが炎を攟぀トランペットを吹いおいる」画像を生成する

2 の CLIP テキスト埋め蟌みから CLIP 画像埋め蟌みが unCLIP の肝ずなりたす。
unCLIP は、CLIP モデルの「テキストから画像ぞの察応関係」を掻甚しお画像生成を行う方匏です。

CLIP は、画像ずテキストをペアで孊習するこずで、それぞれを同じ特城空間埋め蟌み空間にマッピングできるマルチモヌダルモデルです。これにより、たずえば「a cat」ず入力するず、ネコの画像の特城ベクトルに近い䜍眮にマッピングされるようになっおいたす。

䞀芋するず、CLIP の「テキストの埋め蟌み」ず「画像の埋め蟌み」は同じ空間にあるので、テキスト埋め蟌みをそのたた䜿っお画像を再珟できそうに思えたす。

しかし、テキスト埋め蟌みはあくたでもテキストの特城を捉えた埋め蟌みであっお画像を生成するために十分な情報は持っおいたせん。たた、テキスト埋め蟌みず画像埋め蟌みは 同じ空間の䞭でも別の分垃領域 に偏っお存圚しおいるこずが知られおいたすAndi Marafioti さんの X 投皿。そのため、テキスト埋め蟌みをそのたた䜿うず、画像生成モデルが想定しおいる「画像的な特城」に合わず、うたく画像を生成できたせん。

そこで unCLIP では、CLIP のテキスト埋め蟌みを、画像埋め蟌みの圢匏に倉換する「priorプラむダ」ず呌ばれる倉換噚を䜿いたす。この prior は、通垞拡散モデルなどで構成され、テキストを画像的な衚珟ぞず倉換しおくれたす。

CLIP がもずもず画像ずテキストの意味的な察応関係を孊習しおいるため、この prior の孊習も効率よく行え、高い粟床で意味に合った画像生成が可胜になりたす。

テキストによる画像生成の誘導方匏には、unCLIP以倖にも様々な方法がありたす。

  • Classifier Guidance
    あらかじめ蚓緎した分類噚を䜿っお、生成途䞭の画像ずテキストプロンプトの䞀臎床を評䟡し、その情報から画像をテキストの意味に近づけるように調敎する方匏です。
  • Classifire-Free Guidance(CFG)
    分類噚を䜿わず、テキストあり・なしの䞡方の孊習を通しお埗た情報を䜿い、生成をテキストの内容に沿うよう誘導する方匏です。テキストず画像の関係は、亀差泚意機構Cross-Attentionによっお䌝達されたす。

たた、CFG の亀差泚意機構による誘導に加えお、プロンプト䞭の特定の単語たずえば「ball」や「dog」などが画像内にきちんず反映されるよう、泚意機構Attentionがその語に十分に「集䞭」するように誘導する方匏ずしお Attend-and-Excite があり、特定単語ぞの泚意重みが高たるように制埡するこずで、现かい芁玠の衚珟挏れプロンプト䞭に「ball」ず「dog」があるのにボヌルが描かれないずいったこずを防ぐこずができたす。
Attend-and-Excite: Attention-Based Semantic Guidance for Text-to-Image Diffusion Models

画像生成の蚘事

FLUX.1 を䜿った画像生成アプリケヌションや ComfyUI の䜿い方

画像生成ぞの応甚

375f132b-7541-4c3a-b0a1-ed572f03e2e9.gif

「テキストの埋め蟌みを䜿った類䌌性怜玢のデモ」の「その耇数ク゚リヌの埋め蟌みベクトルの平均による類䌌性怜玢」では、埋め蟌みベクトルに察しお算術挔算が可胜であるこずを、画像生成ぞの応甚では、CLIPなどの埋め蟌みベクトルが画像生成に応甚されおいるこずを芋お来たした。この぀を組み合わせるず䞊の猫からラむオンぞ倉身するような動画を䜜るこずができたす。

䞊の動画は、抂略以䞋のような手順で䜜られおいたす。

image.png

  • 「猫からラむオンぞ」方向埋め蟌みベクトルを䜜る
    • "Lion"ラむオン ずいう単語を含んだ文を぀くる
    • "Domestic cat"家猫ずいう単語を含んだ文を぀くる
    • 2぀の文の埋め蟌みベクトルを生成する
    • 2぀の埋め蟌みベクトルの差分を取るラむオン文 - 家猫文
    • ここたでの操䜜を数癟回繰り返しお平均を取り、これを「猫からラむオンぞ」方向ベクトルずする
  • 画像矀を生成する
    • 画像生成プロンプト"A cat in the park"の埋め蟌みベクトルに「猫からラむオンぞ」方向ベクトルの、䟋えば1/10を加算する
    • この加算された埋め蟌みベクトルで画像生成をガむドする
    • この凊理を繰り返す

䞋蚘のサむトで実際に詊しおみるこずができたす。Prompt に "A cat in the park" のような動画の出発点ずなるプロンプトを、1st direction to steer Starting state に、「Domestic cat」のような倉化の起点ずなるプロンプトを、2nd direction to steer Finishing state に「Lion」のような倉化の終点ずなるプロンプトを蚭定しお"Generate directions"をクリックするず動画が生成されたす。うたく行かないこずも倚いですがいろいろ詊しお楜しんでみおください。䞊の GIF 画像もこのアプリケヌションで䜜成したものです。

たた、この Lattent Navigation は䞋蚘の2぀を元にしおいたす。
Semantic Sliders
Traversing through CLIP Space, PCA and Latent Directions

プロンプト 1st direction to steer Starting state 2nd direction to steer Finishing state
a house urban USA style traditional Japanese style
生成画像

なお、Semantic Sliders のコヌドを読んでみるず生成される䟋文のテンプレヌトは、「Domestic cat」や「Lion」のような蚀葉が入力されるこずを意図しおいたせん。それでも、うたく行っおいるずころが面癜いですね。興味のある方は、clip_slider_pipeline.pyずconstants.py を読んでみおください。

超高解像床リモヌトむメヌゞセンシング画像の解析Image RAG

image.png
Enhancing Ultra High Resolution Remote Sensing Imagery Analysis with ImageRAG Figure 1 より

衛星画像などの超高解像床リモヌトセンシング画像や医療画像の䞭には、解像床が高すぎお珟圚利甚できるRemote Sensing Vision Language Models (RSVLMs)では解析できなものがありたす。このような甚途に画像に察する RAG が提案されおいたす。
通垞のテキスト情報に察する RAG では、ドキュメントをチャンクに分割しお、それを埋め蟌みベクトルぞ倉換しお、ベクトルデヌタベヌスぞ栌玍したすが、Image RAG では、超高解像床画像をパッチに分割しお、このパッチの埋め蟌みベクトルをベクトルデヌタベヌスぞ栌玍したす。たた、通垞のテキスト情報に察する RAG では、ベクトルデヌタベヌスから取埗したテキストチャンク矀は、LLM にコンテキストずしお入力されお、ナヌザヌの質問ぞの回答が生成されたすが、Image RAG では、LLM の代わりに VLM(マルチモヌダルLLM)が䜿われたす。
image.png

Enhancing Ultra High Resolution Remote Sensing Imagery Analysis with ImageRAG Figure 6 より

ショヌト動画投皿サむトの動画レコメンデヌション

image.png
image.png

A Multi-modal Modeling Framework for Cold-start Short-video Recommendation より

この論文のショヌト動画投皿サむトでは、ナヌザヌの行動履歎ず動画のマルチモヌダル埋め蟌みをク゚リヌずしお、動画の映像、音響、テキストタむトルや音声の曞き起こしの埋め蟌みベクトルに動画のクラスタヌごずの芖聎傟向を統合したマルチモヌダル埋め蟌みを怜玢察象ずするベクトル怜玢によっおサむト蚪問者ぞの掚奚動画の提瀺を行っおいたすこれは研究ではなくプロダクションで皌働しおいるものです。
このようなレコメンデヌションシステムでは、新芏に投皿された動画のような芖聎履歎の少ない動画のレコメンデヌションをどうするかずいうコヌルドスタヌト問題が課題でした。このサむトでは、1,000䞇を超える動画のマルチモヌダル埋め蟌みを k-means により玄1,000のらクラスタに分類し、新芏の動画をこの1,000のクラスタのいずれかに分類するこずにより、そのクラスタの芖聎傟向を䜿っお適切なナヌザヌぞ掚奚するこずを実珟しおいたす。

埋め蟌みを掻甚した RAG の粟床向䞊策

ナヌザヌの質問文のクラスタヌ分析によるドキュメントの改善

image.png
囜・地方共通盞談チャットボット Govbotガボットに搭茉されおいる各分野のFAQデヌタ党分野の「問い」を UMAP で次元削枛二次元ぞ射圱しお可芖化したもの

RAG を䜿っおいるかどうかに関わらず問い合わせ応答システムでは、開発者偎が想定した質問ず実際にナヌザヌが投入する質問を調べおみるず圓初想定しおいなかった質問矀が含たれおいるこずがありたす。開発偎は想定した質問に察する回答をLLMが生成できるようにドキュメントを甚意したすが、このような乖離があるず RAG システムは適切な回答を生成するこずができたせん。実際に投入された質問矀をクラスタヌ分析するこずでどのような質問が倚く投入されおいるのかを知るこずができ、ドキュメントの改善に関する掞察を埗るこずができたす。

たずめ

本蚘事では、生成AIを䌁業で実甚的に掻甚する䞊で重芁ずなる埋め蟌み技術に぀いお、基瀎から応甚たで幅広く解説したした。以䞋に䞻なポむントをたずめたす。

RAGず埋め蟌みの基瀎

  • RAG怜玢拡匵生成は、ハルシネヌション䜎枛、瀟内固有知識ぞの察応、最新情報ぞの察応などの利点を持぀
  • RAGのプロセスは「デヌタの準備ず埋め蟌み凊理」→「ベクトル怜玢」→「LLMによる回答生成」の3ステップ
  • 埋め蟌みはRAGの䞭栞技術であり、テキストや画像などのデヌタをベクトル空間䞊の点ずしお衚珟する

テキスト埋め蟌みの技術

  • トヌクン化はテキストを意味のある最小単䜍に分割する前凊理
  • 静的埋め蟌みWord2Vecなどは文脈に䟝存しない固定された衚珟を生成
  • Transformerベヌスの埋め蟌みは文脈を考慮した動的な衚珟を生成し、倚矩語の問題に察応
  • プヌリングMean Poolingなどにより、トヌクン単䜍の埋め蟌みから文曞党䜓の埋め蟌みを生成

マルチモヌダル埋め蟌み

  • CLIPなどのマルチモヌダル埋め蟌みモデルは、テキストず画像を同じベクトル空間にマッピング
  • これにより、テキストによる画像怜玢や画像による画像怜玢など倚様な怜玢が可胜に
  • 画像生成AIDALL-E2などでもCLIPの埋め蟌み技術が掻甚されおいる

埋め蟌みの応甚䟋

  • ベクトル怜玢による関連文曞の効率的な怜玢
  • 画像怜玢や画像分類
  • 画像生成の制埡や倉化を䞎える操䜜
  • 超高解像床画像の解析Image RAG
  • 動画掚薊システムにおけるコヌルドスタヌト問題の解決

埋め蟌み技術の理解を深めるこずで、より効果的なRAGシステムの構築が可胜になりたす。静的埋め蟌みからTransformerベヌスの文脈考慮型埋め蟌み、そしおマルチモヌダル埋め蟌みぞず進化しおきた技術は、今埌も生成AIの実甚化においお䞭心的な圹割を担っおいくでしょう。

ぜひ、この蚘事で玹介した抂念や技術を実際の業務に応甚し、生成AIの可胜性を最倧限に匕き出しおください。

甚語の敎理

甚語英語 日本語 意味
BPE バむトペア゚ンコヌディング トヌクン化アルゎリズムの䞀皮で、頻出する文字列のペアを繰り返し結合しおいくこずで効率的な語圙を構築する手法Byte Pair Encoding。未知語や皀な単語に察応しながらも語圙サむズを抑えるこずができる。
CLIP クリップ OpenAIによっお開発されたマルチモヌダル埋め蟌みモデルで、テキストず画像を同じ埋め蟌み空間にマッピングするContrastive Language-Image Pre-training。倧芏暡な画像-テキストペアを甚いお孊習され、画像怜玢や分類、画像生成のガむドなど幅広い甚途に応甚されおいる。
Contrastive Learning 察照孊習 類䌌したデヌタポむントを近づけ、異なるデヌタポむントを遠ざけるように衚珟を孊習する手法。マルチモヌダル埋め蟌みモデルであるCLIPなどで䜿甚され、異なるモダリティ間の察応関係を効果的に孊習できる。関連するデヌタペア正䟋ずそうでないペア負䟋の察比を通じお埋め蟌み空間の構造を圢成する。
Cosine Similarity コサむン類䌌床 2぀のベクトル間の類䌌床を枬る指暙で、ベクトル間のなす角のコサむン倀を蚈算する。倀が1に近いほど類䌌床が高く、-1に近いほど類䌌床が䜎いこずを瀺す。埋め蟌みベクトル間の意味的類䌌性を評䟡するのによく䜿われる。
Cross-Attention 亀差泚意機構 異なる入力シヌケンス間の関連性を蚈算する泚意機構。䟋えば、テキスト-画像モデルにおいお、テキストの特城が画像の特定郚分にどの皋床泚目すべきかを決定する。画像生成モデルではテキストプロンプトず生成䞭の画像間の関連付けに䜿われる。自己泚意機構が単䞀シヌケンス内の関係性を捉えるのに察し、亀差泚意機構は異なるモダリティ間の関係性を捉える。
Cross-lingual クロスリンガル 耇数の蚀語にたたがるずいう意味。クロスリンガル埋め蟌みは、異なる蚀語のテキストを同じ埋め蟌み空間に倉換し、蚀語間の意味的察応関係を捉えるこずができる技術。
Embedding 埋め蟌み 1. 手法ずしおの埋め蟌み
高次元デヌタテキスト、画像などを䜎次元の密なベクトル空間に倉換したもの。意味的・抂念的な関係性を保ちながら、デヌタを効率的に衚珟する手法。
2. 衚珟ずしおの埋め蟌み
䞊蚘の手法によっお生成された䜎次元ベクトル自䜓も「埋め蟌み」ず呌ばれる。深局孊習によっお埗られた特城ベクトルを特に「埋め蟌み」ず呌ぶ。デヌタの意味的・抂念的関係性を保持しおいる。たた、わかりやすく埋め蟌みベクトル、もしくは、単にベクトルず衚珟されるこずも倚い。
Embedding Model 埋め蟌みモデル デヌタを特定の次元の埋め蟌みベクトルに倉換するために蚓緎された機械孊習モデル。デヌタの意味的関係を数孊的空間に衚珟できるよう蚭蚈されおいる。画像、動画、音声などのテキスト以倖のモヌダルのデヌタを埋め蟌みベクトルぞ倉換するモデルもある。
Embedding Space 埋め蟌み空間 埋め蟌みベクトルが存圚する数孊的な空間。各デヌタポむントが意味的な関係性を保ちながらマッピングされる倚次元空間であり、類䌌したデヌタは空間内で近い䜍眮に配眮され、異なるデヌタは遠い䜍眮に配眮される。この空間内での距離や方向が意味を持ち、ベクトル挔算加算、枛算、類䌌床蚈算などを通じおデヌタの関係性を探玢できる。
Feature Vector 特城ベクトル デヌタの特城を数倀のベクトル圢匏で衚珟したもの。機械孊習アルゎリズムが凊理しやすいように、生デヌタから抜出された特城を数倀化したベクトル。
Hallucination ハルシネヌション 倧芏暡蚀語モデルLLMが事実に基づかない情報や存圚しない情報を生成しおしたう珟象。RAGを掻甚するこずで、倖郚デヌタベヌスからの正確な情報参照により、このような幻芚を䜎枛するこずができる。
Image RAG むメヌゞRAG 超高解像床画像の解析に察応するため、画像をパッチに分割しお埋め蟌みベクトル化し、ベクトルデヌタベヌスで怜玢しおマルチモヌダルLLMVLMに提䟛するRAGの画像版Image Retrieval-Augmented Generation。衛星画像や医療画像などの分析に掻甚される。
Multimodal Embedding Model マルチモヌダル埋め蟌みモデル 耇数の皮類のデヌタモダリティテキスト、画像、音声、動画などを同䞀の埋め蟌み空間に倉換できるモデル。異なるモダリティのデヌタ間の関係性を捉え、クロスモヌダル怜玢や異皮デヌタ間の類䌌性蚈算などを可胜にする。䟋えばテキストず画像を同じ埋め蟌み空間にマッピングするこずで、テキストから関連画像を怜玢したり、画像の内容をテキストで説明したりするこずができる。
PCA 䞻成分分析 高次元デヌタの分散を最倧化する方向䞻成分を特定し、重芁な情報を保持しながらデヌタの次元を削枛する手法Principal Component Analysis。埋め蟌みベクトルの可芖化やノむズ陀去などに䜿甚される。UMAPなどず比范しお線圢倉換であるため解釈がしやすいが、非線圢な関係の保持は難しい。
Pooling プヌリング 耇数の埋め蟌みから単䞀の埋め蟌み衚珟を生成する手法。Mean Pooling平均プヌリングやCLS Token PoolingCLSトヌクンプヌリングなどがある。
RAG 怜玢拡匵生成 倖郚知識源から関連情報を怜玢しお蚀語モデルの生成プロセスを拡匵する手法Retrieval-Augmented Generation。LLMの基本的な知識を掻かしながら、倖郚デヌタベヌスから怜玢した最新たたは特定領域の情報を組み合わせるこずで、より正確で具䜓的な回答を生成できる。ハルシネヌション幻芚の䜎枛や組織固有の知識ぞの察応、最新情報ぞの察応などの利点がある。
Self-Attention Mechanism 自己泚意機構 シヌケンスの各芁玠が他のすべおの芁玠ずの関連性を考慮できるようにする機構。入力シヌケンス内の任意の䜍眮の単語間の䟝存関係をモデル化するこずができ、文脈を考慮した衚珟の生成を可胜にする。
Static Embedding 静的埋め蟌み 文脈に䟝存せず、単語に垞に同じベクトル衚珟を割り圓おる埋め蟌み手法。Word2Vec、GloVe、FastTextなどの手法が該圓する。蚈算効率が良く軜量だが、倚矩語の異なる意味を区別できないずいう制限がある。
Token トヌクン テキストを凊理する際の基本単䜍。蚀語モデルやNLPタスクにおいお、テキストはトヌクンの列ずしお扱われる。トヌクンは単語、郚分単語、文字、蚘号などの圢態で衚され、モデルやタスクによっお定矩が異なる。䟋えば、「富士山」は1トヌクンの堎合もあれば、「富/士/山」のように耇数のトヌクンに分割される堎合もある。各トヌクンは通垞、数倀ID敎数に倉換されおモデルに入力される。
Tokenizer トヌクナむザヌ テキスト文字列をトヌクンのシヌケンスに倉換するツヌルやアルゎリズム。トヌクナむザヌはテキストを分割し、各トヌクンに䞀意のIDを割り圓おる機胜を持぀。たた、特殊トヌクン文の開始/終了、䞍明単語などの远加や、トヌクン列の長さの調敎パディング、切り詰めなども行う。蚀語モデルごずに専甚のトヌクナむザヌが蚭蚈されおおり、モデルの蚓緎ず掚論で同じトヌクナむザヌを䜿甚する必芁がある。
Transformer トランスフォヌマヌ 自己泚意機構Self-Attention Mechanismを䞭心ずしたニュヌラルネットワヌクアヌキテクチャ。文脈を考慮した埋め蟌みを生成でき、BERTやGPTなどの基盀ずなっおいる。
UMAP ナヌマップ 高次元デヌタを䜎次元通垞2次元か3次元に瞮玄する次元削枛アルゎリズムUniform Manifold Approximation and Projection。デヌタの局所的および倧域的構造を保持しながら可芖化するのに適しおいる。埋め蟌みベクトルの可芖化やクラスタヌ分析などに䜿甚される。
unCLIP アンクリップ OpenAIのDALL-E2で採甚されおいる画像生成方匏で、CLIPの埋め蟌み空間における「テキストから画像ぞの察応関係」を掻甚しお画像生成を行う。CLIPのテキスト埋め蟌みをprior拡散モデルなどで画像埋め蟌みに倉換し、その埌画像デコヌダヌで実際の画像を生成する。
Vector Database ベクトルデヌタベヌス 埋め蟌みベクトルを効率的に栌玍し、類䌌床に基づいた怜玢を可胜にするデヌタベヌス。RAGシステムにおいお、ク゚リに関連する文曞を高速に怜玢するために䜿甚される。
59
42
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?