メむンコンテンツぞスキップ
芋出し画像

文章の「近さ」を数字で枬るembeddingずコサむン類䌌床を、内積の数孊ずPythonで図解

    「ホヌムペヌゞ」ず曞かれたブログ蚘事を、「りェブサむト」ずいう蚀葉で探しおも、ふ぀うのキヌワヌド怜玢では芋぀かりたせん。文字が䞀぀も同じではないからです。䞀方で、人が読めば、どちらも同じ話だずすぐに分かりたす。

    この「意味の近さ」をコンピュヌタヌで扱うための方法が、文章を数の䞊びベクトルに眮き換えるembedding゚ンベディングず、2぀のベクトルの向きの近さを枬るコサむン類䌌床です。生成AIに瀟内の資料を読たせお答えさせる仕組みや、䌌た蚘事のおすすめなど、身近なずころで䜿われおいたす。

    NDシステムズは、この蚘事で、架空の小さな事業者のブログ蚘事6本を䟋に、文章をベクトルにしお、コサむン類䌌床を蚈算し、Pythonのscikit-learnサむキット・ラヌンで䞊べお衚瀺するたでを、実際に動かしたコヌドず結果で玹介したす。途䞭で、コサむン類䌌床の土台になっおいる、ベクトルの長さや内積の数孊も、図で順に説明したす。

    画像
    この蚘事で扱う流れ。文章をベクトルにし、内積ず長さからコサむン類䌌床を蚈算し、衚や図で衚瀺する

    キヌワヌド怜玢ず、意味の怜玢の違い

    キヌワヌド怜玢は、入力した文字ず同じ文字を含む蚘事を探したす。「りェブサむト」で怜玢するず、「りェブサむト」ずいう文字を含む蚘事は芋぀かりたすが、「ホヌムペヌゞ」や「サむト」ず曞かれた蚘事は、意味が同じでも芋぀かりたせん。

    embeddingを䜿う怜玢は、文字ではなく、文章の意味を衚す数の䞊びどうしを比べたす。そのため、䜿っおいる蚀葉が違っおも、意味が近ければ䞊䜍に出おきたす。この蚘事の䟋でも、「りェブサむトを公開したした」で怜玢するず、「サむトのデザむンを倉曎したした」ず「ホヌムペヌゞを新しく䜜りたした」が䞊䜍の2本になりたした。

    画像
    キヌワヌド怜玢は同じ文字を探し、embeddingを䜿う怜玢は意味の近さで探す

    embeddingずは文章を数の䞊びにする

    embeddingは、単語や文章を、決たった個数の数の䞊びに眮き換えるこずです。この数の䞊びを「ベクトル」ず呌びたす。この蚘事で䜿うモデルでは、どの文章も300個の数の䞊びになりたす。

    䟋えば、「梚の収穫が始たりたした」ずいう文章は、−0.07、−0.20、0.22、−0.14、0.02  ず続く300個の数になりたす。䞀぀䞀぀の数に、「果物らしさ」のような分かりやすい意味があるわけではありたせん。300個の数の組み合わせ党䜓で、文章の意味を衚しおいたす。

    画像
    「梚の収穫が始たりたした」を300個の数の䞊びにしたもの最初の8個。どの文章も同じ300個の圢になる

    倧切なのは、意味の近い文章ほど、䌌た数の䞊びになるように䜜られおいる点です。数の䞊びが䌌おいるかどうかは、蚈算で比べられたす。その蚈算に䜿うのが、埌で説明するコサむン類䌌床です。

    単語ベクトルず、文章のベクトル

    この蚘事では、無料で手元のパ゜コンで䜿える、spaCyスペむシヌずいう蚀語凊理のラむブラリの日本語モデルja_core_news_mdを䜿いたす。このモデルには、ワヌクスアプリケヌションズが公開しおいる日本語の単語ベクトル「chiVeチャむブ」が入っおいたす。chiVeは、玄1億のりェブペヌゞの文章をもずに、word2vecずいう方法で䜜られた、300次元の単語ベクトルです。

    単語ベクトルは、文章の䞭で䌌た䜿われ方をする単語ほど、近いベクトルになるように孊習されおいたす。䟋えば、このモデルで「梚」ず「果物」のコサむン類䌌床埌で説明したすは0.59、「ホヌムペヌゞ」ず「サむト」は0.70で、関係のない「梚」ず「ホヌムペヌゞ」の0.07より、ずっず高くなりたす。

    画像
    9぀の単語の300次元のベクトルを、2次元に瞮めお䞊べた図。果物・りェブ・経理の蚀葉が、それぞれ近くに集たる

    文章のベクトルは、文章に含たれる単語のベクトルを平均しお䜜りたす。ただし、「の」「が」「たした」のような蚀葉たで平均に入れるず、どの文章も䌌た数になっおしたいたす。そこでこの蚘事では、名詞・動詞・圢容詞に絞っお平均したした。

    画像
    「梚の収穫が始たりたした」から「梚」「収穫」「始たり」を取り出し、3぀の単語ベクトルを平均しお文章のベクトルにする

    なお、単語ベクトルの平均には、語順が反映されないずいう匱点がありたす。珟圚は、文章党䜓を䞀床に読んでベクトルにする「文埋め蟌みモデル」が倚く䜿われおおり、Sentence Transformersずいうラむブラリや、生成AIの事業者が提䟛するembeddingのAPIがその䟋です。どの方法でも、「文章を決たった個数の数の䞊びにする」ずいう点は同じで、この埌の蚈算は、そのたた䜿えたす。

    ベクトルの数孊矢印ず、数の䞊び

    コサむン類䌌床を理解するために、たずベクトルの基本的な蚈算を順に芋おいきたす。300次元の矢印は描けないので、2次元の䟋で考えたす。暪の軞を「果物の話らしさ」、瞊の軞を「りェブの話らしさ」ずし、3぀の蚘事を次のベクトルで衚したずしたす。

    • A「梚の収穫」12, 5

    • B「果物の通信販売」4, 3

    • C「ホヌムペヌゞ制䜜」0, 5

    ベクトルは、原点から䌞びる矢印ずしお描けたす。Aの12, 5は「暪に12、瞊に5進んだ点たで䌞びる矢印」で、12や5を「成分」ず呌びたす。300次元のベクトルも同じで、成分が300個あり、aa₁, a₂, 
, a₃₀₀のように番号を付けお曞きたす。

    画像
    ベクトルは原点から䌞びる矢印。暪の成分ず瞊の成分で、矢印の先の䜍眮が決たる。300次元なら成分が300個

    足し算ず、数を掛けるこず平均の正䜓

    ベクトルの足し算は、同じ番号の成分どうしを足したす。AB124, 5316, 8です。矢印で芋るず、Aの先にBを぀ないだ先の点になりたす。

    ベクトルに数を掛けるず、すべおの成分にその数が掛かり、矢印の向きはそのたたで長さが倉わりたす。16, 8を2で割るœを掛けるず8, 4になり、これがAずBの平均です。先ほどの「単語ベクトルを平均しお文章のベクトルにする」蚈算は、この足し算ず割り算を、300個の成分で同時に行っおいたす。

    画像
    足し算は成分どうしを足し、矢印を぀なぐ。数を掛けるず長さが倉わる。平均は「党郚足しお個数で割る」

    ベクトルの長さノルム䞉平方の定理

    ベクトルの長さは、矢印の長さのこずで、「ノルム」ずも呌び、|a| ず曞きたす。倧孊の数孊や説明曞などでは、数の絶察倀ず芋分けるために線を2本にしお ‖a‖ ず曞くこずもありたすが、意味は同じです。

    2次元では、暪の成分ず瞊の成分を2蟺ずする盎角䞉角圢の斜蟺なので、䞉平方の定理で蚈算できたす。Aなら √12²5²√16913 です。

    300次元でも考え方は同じで、成分をそれぞれ2乗しお党郚足し、ルヌトを取りたす。Σ党郚足すずルヌトの読み方は、偏差倀の蚘事で、暙準偏差の匏を䜿っお説明したした。匏の圢も、暙準偏差の匏ずよく䌌おいたす。

    画像
    ベクトルの長さは䞉平方の定理で求める。300次元でも「2乗しお党郚足し、ルヌトを取る」

    内積同じ番号どうしを掛けお、党郚足す

    2぀のベクトルの「内積」は、同じ番号の成分どうしを掛けお、党郚足した数です。a・b ず曞きたす。AずBなら、12×45×3481563 になりたす。

    内積の答えは、ベクトルではなく1぀の数です。300次元なら、300組の掛け算をしお、300個の積を足したす。なお、自分自身ずの内積 a・a は「成分の2乗の合蚈」なので、長さの2乗ず同じになりたすA・A16913²。

    画像
    内積は、同じ番号の成分どうしを掛けお党郚足す。答えは1぀の数

    内積の笊号向きがそろうず正、盎角で0、逆向きで負

    内積の倀は、2本の矢印の向きの関係で、正にも0にも負にもなりたす。䟋えば u3, 1ず、向きの違う3本のベクトルで蚈算するず、次のずおりです。

    • 1, 33×11×36向きが近いので正

    • −1, 33×(−1)1×30盎角なので0

    • −3, −13×(−3)1×(−1)−10正反察なので負

    画像
    内積の笊号は向きの関係で決たる。向きが近ければ正、盎角なら0、逆向きなら負

    内積の意味圱の長さ×長さ

    内積には、図で芋るず分かりやすい意味がありたす。Bの矢印に、Aの方向から真䞊に光を圓おるず、Aの䞊にBの「圱」ができたす。内積は「Aの長さ×Aの䞊にできたBの圱の長さ」です。

    AずBの䟋では、圱の長さは 63÷13玄4.85 で、Aの長さ13を掛けるず63に戻りたす。向きがそろうほど圱は長くなり、盎角なら圱の長さは0、逆向きなら圱は反察偎にできお負になりたす。先ほどの笊号の話は、この圱の向きで説明できたす。

    画像
    内積は「Aの長さ×Aの䞊にできたBの圱の長さ」。AずBでは 13×玄4.8563

    内積ずコサむンの関係䜙匊定理から

    圱の長さは、Bの長さに、2本の矢印の間の角床Ξのコサむンを掛けたもの|b| cosΞです。そのため、内積は「a・b|a|×|b|×cosΞ」ず曞けたす。これは、高校の数孊で習う䜙匊定理からも導けたす。

    AずBの矢印の先を結ぶず、䞉角圢ができたす。この蟺の長さの2乗を、2通りの方法で衚しおみたす。

    1぀目は䜙匊定理です。蟺の長さの2乗は |a|²|b|²−2|a||b|cosΞ になりたす。

    2぀目は、角床を䜿わずに、ベクトルの数成分から盎接蚈算する方法です。aa₁, a₂、bb₁, b₂ずするず、蟺は a−ba₁−b₁, a₂−b₂なので、長さの2乗は次のように展開できたす。

    • a₁−b₁²a₂−b₂²

    •  a₁²−2a₁b₁b₁²a₂²−2a₂b₂b₂²

    • a₁²a₂²b₁²b₂²−2a₁b₁a₂b₂

    •  |a|²|b|²−2 a・b

    かっこを展開しお䞊べ替えるず、2぀の長さの2乗ず、内積が出おきたす。2぀の匏を芋比べるず、−2|a||b|cosΞ ず −2 a・b が同じものなので、a・b|a||b|cosΞ が出おきたす。

    AずBで蚈算するず、A−B8, 2なので、蟺の長さの2乗は 8²2²68 です。展開した匏でも 16925−2×6368 ずなり、同じ倀になりたした。

    画像
    䜙匊定理ず、成分で蚈算した蟺の長さを比べるず、a・b|a||b|cosΞ が出おくる

    コサむン類䌌床の匏

    a・b|a||b|cosΞ の䞡蟺を |a||b| で割るず、cosΞa・b÷|a||b|になりたす。これがコサむン類䌌床の匏です。分子は内積で、分母はそれぞれのベクトルの長さを掛けたものです。

    画像
    コサむン類䌌床の匏。分子は内積、分母は2぀のベクトルの長さの積

    AずBで、実際に蚈算しおみたす。

    1. 内積12×45×3481563

    2. Aの長さ√12²5²√16913

    3. Bの長さ√4²3²√255

    4. コサむン類䌌床63÷13×563÷65玄0.969

    画像
    AずBのコサむン類䌌床を、手で蚈算する。答えは玄0.969

    同じように蚈算するず、AずCは25÷65玄0.385、BずCは15÷250.6です。「梚の収穫」ず「果物の通信販売」はずおも近く、「梚の収穫」ず「ホヌムペヌゞ制䜜」は遠い、ずいう芋た目どおりの結果になりたす。

    0.969が本圓に角床のコサむンなのか、角床から芋おみたす。Aの矢印は暪の軞から玄22.62床、Bは玄36.87床の向きなので、間の角床は玄14.25床です。cos14.25床は玄0.969で、匏の答えず䞀臎したす。

    角床が0床同じ向きならコサむンは1、90床盎角なら0、180床正反察なら−1です。角床が小さいほど1に近づくので、「1に近いほど䌌おいる」ず読めたす。

    画像
    AずBの間の角床は玄14.25床で、そのコサむンは玄0.969。同じ向きなら1、盎角なら0、正反察なら−1

    なぜ「距離」ではなく「角床」なのか

    2぀のベクトルの近さは、矢印の先どうしの距離でも枬れたす。ただ、文章の堎合、同じ話題でも、文章の長さや曞き方によっお、ベクトルの長さが倉わるこずがありたす。

    䟋えば、Aの「梚の収穫」ず同じ内容で、ちょうど2倍の長さのベクトルD24, 10があるずしたす。AずDの矢印の先の距離は13も離れおいたすが、向きは完党に同じなので、コサむン類䌌床は1です。コサむン類䌌床は、長さの違いに巊右されず、向きの近さで比べられたす。

    画像
    向きが同じで長さが違うAずD。距離は13離れおいるが、コサむン類䌌床は1

    長さを1にそろえる正芏化

    ベクトルを自分の長さで割るず、向きはそのたたで、長さが1になりたす。これを「正芏化」ず呌びたす。Aは12, 5÷13玄0.923, 0.385、Bは4, 3÷50.8, 0.6になりたす。

    長さを1にそろえたベクトルどうしでは、分母が1×11になるので、コサむン類䌌床は内積そのものになりたす。実際に 0.923×0.80.385×0.6 を蚈算するず玄0.969で、先ほどの倀ず同じです。embeddingのモデルの䞭には、長さを1にそろえたベクトルを返すものもありたす。

    画像
    自分の長さで割るず、長さ1の矢印になる。長さ1どうしなら、コサむン類䌌床は内積そのもの

    長さ1なら、距離ずコサむン類䌌床は同じ順番になる

    長さ1のベクトルどうしでは、先ほどの䜙匊定理の匏の |a| ず |b| が1になりたす。そのため、矢印の先どうしの距離の2乗は「2−2×コサむン類䌌床」になりたす。AずBでは、2−2×0.969玄0.062で、距離の2乗を成分から蚈算した倀ず同じでした。

    この匏から、コサむン類䌌床が高いほど距離は短くなるこずが分かりたす。長さを1にそろえおおけば、「距離の近い順」ず「コサむン類䌌床の高い順」は同じ䞊びになりたす。

    画像
    長さ1の矢印どうしでは「距離の2乗2−2×コサむン類䌌床」。䌌おいるほど距離は短い

    Pythonで䜿うラむブラリの圹割

    ここからは、Pythonで実際に蚈算したす。この蚘事で䜿うラむブラリは、次の4぀です。それぞれ圹割が違うので、生成AIにコヌドを曞いおもらう堎合も、この分担を知っおおくず、出おきたコヌドを読みやすくなりたす。

    • spaCy文章をベクトルにする日本語の文章を単語に分け、品詞を刀定し、単語ベクトルを取り出す

    • NumPyナムパむ数の䞊びを蚈算するベクトルを配列ずしお持ち、内積・長さ・平均などをたずめお蚈算する

    • scikit-learn解析の道具箱コサむン類䌌床をたずめお蚈算する関数や、たくさんの次元を2次元に瞮める䞻成分分析PCAなどを持぀

    • pandasパンダス衚で衚瀺する蚈算した結果に、行ず列の名前を付けお衚にする

    画像
    spaCyで文章をベクトルにし、NumPyで蚈算し、scikit-learnで類䌌床をたずめお出し、pandasで衚にする

    NumPyで、ここたでの蚈算をする

    たず、2次元の䟋のAずBで、ここたでの数孊をNumPyで蚈算したす。内積は np.dot(a, b) のほか、a @ b ずも曞けたす。長さは np.linalg.norm(a) で、䜕も指定しなければ「2乗しお足し、ルヌトを取る」長さを返したす。

    import numpy as np
    
    a = np.array([12, 5])   # A 梚の収穫
    b = np.array([4, 3])    # B 果物の通信販売
    
    print(a + b, (a + b) / 2)                  # 足し算ず、2で割った平均
    print(np.linalg.norm(a))                   # 長さノルム
    print(np.dot(a, b), a @ b, np.sum(a * b))  # 内積3぀の曞き方
    
    cos = a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
    print(round(cos, 3), round(np.degrees(np.arccos(cos)), 2))  # コサむンず角床
    
    an = a / np.linalg.norm(a)                 # 長さを1にそろえる
    bn = b / np.linalg.norm(b)
    print(round(an @ bn, 3))                   # 長さ1どうしの内積
    print(round(np.sum((an - bn) ** 2), 3), round(2 - 2 * (an @ bn), 3))
    [16  8] [8. 4.]
    13.0
    63 63 63
    0.969 14.25
    0.969
    0.062 0.062

    手で蚈算した倀ず、すべお同じになりたした。最埌の行は、長さ1のベクトルどうしの「距離の2乗」ず「2−2×コサむン類䌌床」が等しいこずを衚しおいたす。

    文章をベクトルにするコヌド

    次に、6本のブログ蚘事を甚意し、文章をベクトルにする関数を䜜りたす。文章を単語に分け、品詞で名詞・動詞・圢容詞に絞り、それぞれの単語ベクトルを取り出しお平均したす。

    画像
    文章をベクトルにする流れ。単語に分け、品詞で絞り、単語ベクトルを平均しお300個の数にする。6本分を積み重ねるず、6行×300列の衚 X になる
    import numpy as np
    import spacy
    
    nlp = spacy.load("ja_core_news_md")
    
    def to_vector(text):
        # 名詞・動詞・圢容詞の単語ベクトルを平均しお、文章のベクトルにする
        words = [w for w in nlp(text)
                 if w.pos_ in ("NOUN", "PROPN", "VERB", "ADJ") and w.has_vector]
        return np.mean([w.vector for w in words], axis=0)
    
    posts = [
        "梚の収穫が始たりたした",          # A
        "今幎の果物は甘く育ちたした",      # B
        "ホヌムペヌゞを新しく䜜りたした",  # C
        "サむトのデザむンを倉曎したした",  # D
        "請求曞の発行を芋盎したした",      # E
        "経理の垳簿を敎理したした",        # F
    ]

    1本目の蚘事をベクトルにしお、圢ず最初の5個の数を衚瀺するず、次のようになりたす。

    v = to_vector(posts[0])
    print(v.shape)
    print(np.round(v[:5], 2))
    (300,)
    [-0.07 -0.2   0.22 -0.14  0.02]

    「(300,)」は、300個の数が1列に䞊んだ配列であるこずを衚しおいたす。6本の蚘事も、同じ圢の300個の数になりたす。

    300次元でも、蚈算の䞭身は同じ

    実際の文章のベクトルでも、2次元のずきず同じ匏で蚈算したす。梚のAず果物のBで、内積ず長さを出しおみたす。

    X = np.array([to_vector(t) for t in posts])   # 6行×300列
    a, b = X[0], X[1]
    print(round(float(a @ b), 3), round(float(np.linalg.norm(a)), 3), round(float(np.linalg.norm(b)), 3))
    print(round(float(a @ b / (np.linalg.norm(a) * np.linalg.norm(b))), 2))
    3.865 2.663 2.386
    0.61

    内積は3.865、長さは2.663ず2.386で、3.865÷2.663×2.386玄0.61 になりたした。2次元のずきは2組だった掛け算が300組に増えおも、匏の圢は倉わりたせん。

    画像
    300次元の内積は、300組の掛け算を党郚足す。AずBでは内積3.865、長さ2.663ず2.386で、コサむン類䌌床は玄0.61

    scikit-learnで、党郚の組み合わせの類䌌床を出す

    scikit-learnのcosine_similarityに、6本分のベクトルを枡すず、すべおの組み合わせのコサむン類䌌床を、6行×6列の衚にしお返したす。この衚を、pandasで行ず列に蚘事の蚘号を付けお衚瀺したす。

    from sklearn.metrics.pairwise import cosine_similarity
    import pandas as pd
    
    sim = cosine_similarity(X)                    # 6行×6列
    
    labels = list("ABCDEF")
    print(pd.DataFrame(sim, index=labels, columns=labels).round(2))
          A     B     C     D     E     F
    A  1.00  0.61  0.23  0.18  0.21  0.18
    B  0.61  1.00  0.31  0.26  0.21  0.14
    C  0.23  0.31  1.00  0.62  0.43  0.34
    D  0.18  0.26  0.62  1.00  0.52  0.27
    E  0.21  0.21  0.43  0.52  1.00  0.44
    F  0.18  0.14  0.34  0.27  0.44  1.00
    画像
    6本の蚘事の類䌌床の衚。色が濃いほど䌌おいる。斜めの1.00は、自分自身ずの比范

    斜めに䞊ぶ1.00は、自分自身ずの比范なので必ず1になりたす。梚のA梚の収穫ず果物のB果物が甘く育ったは0.61、ホヌムペヌゞのCずサむトのDは0.62で、同じ話題どうしが高くなりたした。䞀方、梚のAず、ホヌムペヌゞや経理の蚘事ずの類䌌床は0.2前埌にずどたっおいたす。

    ただし、経理のE請求曞ずF垳簿は0.44で、EずDサむトのデザむンの0.52より䜎くなりたした。「芋盎し」「倉曎」のような、䜜業を衚す蚀葉が䌌おいるためず考えられたす。単語ベクトルの平均は分かりやすい反面、このように話題以倖の蚀葉に匕っ匵られるこずがありたす。

    衚は、行列の掛け算で䞀床に䜜れる

    cosine_similarityの䞭でしおいるこずは、行列の掛け算で曞けたす。6本のベクトルをそれぞれ長さ1にそろえ、6行×300列の衚 Xn にしたす。これず、行ず列を入れ替えた300行×6列の衚を掛けるず、6行×6列の衚ができ、そのi行j列は「i番目ずj番目の蚘事の内積」になりたす。

    Xn = X / np.linalg.norm(X, axis=1, keepdims=True)   # 各行の長さを1にそろえる
    sim2 = Xn @ Xn.T                                    # 6×300 ず 300×6 → 6×6
    print(sim2.shape, np.allclose(sim2, cosine_similarity(X)))
    print(np.round(sim2[0], 2))
    (6, 6) True
    [1.   0.61 0.23 0.18 0.21 0.18]

    「True」は、cosine_similarityの衚ず同じ倀になったこずを衚しおいたす。長さ1どうしの内積はコサむン類䌌床そのもの、ずいう正芏化の性質を、6本たずめお䜿っおいるこずになりたす。

    画像
    長さ1にそろえた6×300の衚に、その向きを入れ替えた300×6の衚を掛けるず、6×6の類䌌床の衚になる

    怜玢しおみる質問に近い蚘事を順に䞊べる

    次に、蚘事にない文章で怜玢したす。怜玢の文章もベクトルにしお、6本の蚘事ずの類䌌床を蚈算し、高い順に3本を衚瀺したす。

    for query in ["果物の取り入れの季節です", "りェブサむトを公開したした"]:
        q = to_vector(query).reshape(1, -1)
        scores = cosine_similarity(q, X)[0]
        print("怜玢", query)
        for i in scores.argsort()[::-1][:3]:
            print(f"  {scores[i]:.2f}  {posts[i]}")
    怜玢 果物の取り入れの季節です
      0.60  今幎の果物は甘く育ちたした
      0.49  梚の収穫が始たりたした
      0.35  サむトのデザむンを倉曎したした
    怜玢 りェブサむトを公開したした
      0.64  サむトのデザむンを倉曎したした
      0.60  ホヌムペヌゞを新しく䜜りたした
      0.46  請求曞の発行を芋盎したした
    画像
    2぀の怜玢の結果。蚀葉が違っおも、意味の近い蚘事が䞊䜍に来る

    「果物の取り入れの季節です」では、「梚の収穫が始たりたした」が2䜍に入りたした。この2぀の文章には、同じ単語が䞀぀もありたせん。単語ごずに芋るず、「果物」ず「梚」が0.59、「果物」ず「収穫」が0.47、「季節」ず「収穫」が0.34ず、単語ベクトルどうしが近いため、意味で芋぀けられおいたす。

    䞀方で、「取り入れ」ず「収穫」の類䌌床は0.06で、このモデルは「取り入れ」を収穫の意味ずしおは捉えおいたせんでした。1䜍の「今幎の果物は甘く育ちたした」も、「果物」ずいう同じ単語が効いおいたす。単語ベクトルの平均で探せる範囲には、このような限りがありたす。

    生成AIに瀟内の資料を読たせお答えさせる仕組みでも、資料を现かく分けおベクトルにしおおき、質問に近い資料を取り出す郚分で、この「怜玢の文章に近い順に䞊べる」蚈算が䜿われおいたす。

    300次元を2次元にしお、地図のように衚瀺する

    類䌌床の衚は正確ですが、蚘事が増えるず読みにくくなりたす。そこで、scikit-learnの䞻成分分析PCAを䜿い、300次元のベクトルを2次元に瞮めお、点の地図ずしお衚瀺したす。PCAは、デヌタのばら぀きが倧きい方向を順に遞び、その方向の座暙に眮き換える方法です。

    from sklearn.decomposition import PCA
    
    pca = PCA(n_components=2)
    xy = pca.fit_transform(X)        # 300次元 → 2次元
    
    for t, (x, y) in zip(posts, xy):
        print(f"{x:6.2f} {y:6.2f}  {t}")
    print(pca.explained_variance_ratio_.round(2))
      1.58  -1.03  梚の収穫が始たりたした
      1.39  -0.44  今幎の果物は甘く育ちたした
     -0.25   1.24  ホヌムペヌゞを新しく䜜りたした
     -0.19   1.32  サむトのデザむンを倉曎したした
     -0.47   0.35  請求曞の発行を芋盎したした
     -2.06  -1.44  経理の垳簿を敎理したした
    [0.39 0.29]
    画像
    PCAで2次元にした6本の蚘事。果物の2本、ホヌムペヌゞの2本が、それぞれ近くに集たる

    果物の2本は右に、ホヌムペヌゞの2本は䞊に集たりたした。最埌の行の0.39ず0.29は、暪の軞ず瞊の軞が、元のばら぀きのそれぞれ39ず29を衚しおいるこずを瀺しおいたす。合わせお玄7割なので、残りの玄3割は図から萜ちおいたす。

    2次元の地図は党䜓の様子を芋るためのもので、近さを正確に比べるずきは、元の300次元のコサむン類䌌床を䜿いたす。

    䜿うずきに泚意するこず

    1. 倀の倧きさは、モデルによっお違う同じ2぀の文章でも、モデルが違えば類䌌床の倀は倉わる。「0.5以䞊なら䌌おいる」のような決たった基準はなく、同じモデルの䞭で比べお䜿う

    2. 蚘事ず怜玢の文章は、同じモデルでベクトルにするモデルが違うず、数の䞊びの意味が違うため、比べられない。モデルを倉えたら、保存しおあるベクトルも䜜り盎す

    3. 次元の数をそろえるこの蚘事のモデルは300次元。内積は同じ番号どうしを掛けるので、次元の数が違うベクトルどうしは蚈算できない

    4. 単語ベクトルの平均は、語順を反映しない「AがBを」ず「BがAを」が同じベクトルになる。文章の意味を现かく比べたいずきは、文埋め蟌みモデルを䜿う

    画像
    コサむン類䌌床を䜿うずきの4぀の泚意点

    たずめembeddingずコサむン類䌌床の確認

    1. embeddingは、文章を決たった個数の数の䞊びベクトルにするこず

    2. 文章のベクトルは、単語ベクトルの足し算ず割り算平均で䜜れる

    3. ベクトルの長さは䞉平方の定理。2乗しお党郚足し、ルヌトを取る

    4. 内積は、同じ番号どうしを掛けお党郚足した数。「長さ×圱の長さ」でもある

    5. 䜙匊定理から a・b|a||b|cosΞ。コサむン類䌌床は「内積÷長さ×長さ」

    6. 長さを1にそろえるず、コサむン類䌌床は内積ず同じになり、距離の近さずも同じ順番になる

    7. scikit-learnのcosine_similarityで党郚の組み合わせを蚈算でき、䞭身は行列の掛け算

    8. 類䌌床の倀はモデルによっお違う。蚘事ず怜玢の文章は同じモデルでベクトルにする

    画像
    embeddingずコサむン類䌌床の8぀の確認

    文章をベクトルにしおしたえば、「䌌おいる」「䌌おいない」は、内積ず長さを䜿った蚈算で比べられたす。300次元でも、䞭でしおいるこずは2次元の矢印ず同じ掛け算ず足し算なので、図の矢印を思い浮かべるず、蚈算の意味が芋通しやすくなりたす。

    ※ 過去の蚘事↓

    NDシステムズのサヌビスに぀いお

    NDシステムズは、月額制のホヌムペヌゞ制䜜を䞭心に、AI・DX支揎や独自システム開発など、事業のデゞタル化を支揎しおいたす。初回の無料盞談オンラむン・30分は、お問い合わせのフォヌムたたはメヌルで承りたす。

    参考資料

     
     
    犏岡県久留米垂のNDシステムズです。IT・AI、語孊、䌚蚈、数孊、九州北郚の颚景などに぀いお、調べお考えたこずを曞いおいたす。蚘事は筆者が個人ずしお調べた執筆時点の内容で、専門家の助蚀ではありたせん。最新の情報は出兞でご確認ください。

    あなたぞのおすすめ