chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

LLM本でミニマムなLLMを作る(その3)

課題:3.3章(P58):簡単なSelf-Attention機構を使って、コンテキストベクトルを作る章を理解する
取り組み:LLM本の説明を正しく理解しているか検証のため、ライブラリを使わず、素でn次元配列を演算して、コンテキストベクトルを生成する
結論:LLM本の実行例の通りには計算できた
詳細:

LLM本ではコンテキストベクトルを作るための演算が図解されている。理解があってるのかを確かめるため、ライブラリを使わず素でコンテキストベクトルを生成する。試作コードは以下

#!/usr/bin/python3

#
# self Attention functions (simple version)
# (LLM from Scratch ... Section 3.3; self attentino P.64 - P.67 )
#

import math

def get_context_vector(token, attention_vector):
    context_vector = [None] * len(token)
    for nth_context  in range(len(token)):
        context_vector[nth_context] = [0] * len(token[nth_context]) 
        for nth_token in range(len(token)):
           for nth_vector in range(len(token[nth_token])):
              context_vector[nth_context][nth_vector] += token[nth_token][nth_vector] * attention_vector[nth_context][nth_token]
    return context_vector

def get_attention_vector(vector):
    attention_vector = []
    for i in range(len(vector)):
        attention_vector.append(get_attention_score(vector, i))
    return attention_vector

def get_attention_score(vector, n):
    attention = []
    for i in range(len(vector)):
        attention.append(inner_product(vector[n], vector[i]))
    attention = soft_max(attention)
    return attention

def inner_product(x, y):
    value = 0
    if len(x) != len(y):
        print('Error! not same dimension')
        return None
    else:
       for i in range(len(x)):
           value += x[i] * y[i]
    return value

def soft_max(ary):
    exp_values = [math.exp(x) for x in ary]
    sum_value = sum(exp_values)
    smax_values = [x/sum_value for x in exp_values]
    return smax_values

上記を実行してみる

#!/usr/bin/python3

from lib.attention  import *  

token_vector = (
  (0.43, 0.15, 0.89),
  (0.55, 0.87, 0.66),
  (0.57, 0.85, 0.64),
  (0.22, 0.58, 0.33),
  (0.77, 0.25, 0.10),
  (0.05, 0.80, 0.55),
)

attention_v = get_attention_vector(token_vector)
context_v = get_context_vector(token_vector, attention_v)

print(context_v)

# 
# $ python3 test_att.py
# [[0.44205939860215243, 0.5930985621414954, 0.5789890706688827], 
#  [0.4418657478512921,  0.651481978030222,  0.5683088877257294], 
#  [0.4431275119837131,  0.6495945789684161, 0.56707305766733], 
#  [0.4303897327932225,  0.6298280620566503, 0.5510270600472974], 
#  [0.46710172950836115, 0.5909927255410325, 0.5265965239654562], 
#  [0.4177244739388295,  0.6503232057064708, 0.5645352170639022]
# ]

上記コンテキストベクトルは、LLM本のP66の結果と一致するのでまぁ計算方法は合っているだろうと判断
ただ、、やっつけ実装なので、、次元が変わった時でも正しく計算できるのかは不明。なお、これはSimpleな実装のため学習できないらしく、3.4章で学習可能なSelf-Attentionが説明される。例の、クエリ、キー、値で定義?されるAttentionの仕組み。正月休み中にはまとまった時間が取れるので、学習可能なSelf-AttentionとMulti-Headまでは終えたい。
■補足
バックプロパゲーションも手で書けるかとClaudeに相談したら、「基礎的な数学の知識で実装できます」と言ってきたので、ライブラリを使わず、できるところまで素で実装してみる。