ショートストーリー: 「コードをトークンに分割し、それをベクトル化して行列に変換する方法」
東京の夜、ネオンに包まれた街を見下ろしながら、若きプログラマの凌介は静かにキーボードを叩いていた。彼は昼も夜も変わらず、ただ一つの目標に向かってプログラムを作り続けていた。その目標とは、「コード生成」をニューラルネットワークに完全に任せることだ。
その日のプロジェクトは特にチャレンジングだった。彼はある簡単なコード、数値の加算を行うシンプルなjavascriptコードを使って、コードをトークンに分割し、それをベクトル化して行列に変換する方法を試していた。
凌介はコンピュータに向かい、思索を巡らせた。「プログラムをトークンに分解し、それぞれにベクトルを与える。そうして、コードそのものを行列として表現する。これができれば、ニューラルネットワークが学習しやすくなる…」と彼はつぶやいた。まるで暗号を解くような感覚だが、彼にとっては未来への鍵だった。
コードをトークンにするプロセス
凌介はまず、簡単なjavascriptコードを手に取った。それは単純な数式で構成されたものだった。
今日の彼のサンプルコードはこうだった。
vec1 = [1, 2, 3];
vec2 = [4, 5, 6];
result = vec1.map((v, i) => v + vec2[i]);
console.log(result);
「このコードを一つ一つのトークンに分解して、それぞれをベクトルに変換していく…」彼は静かに考えながらコードをトークンに分割した。
コードの中の各要素、変数名、配列、そして関数をすべて細かく分解していった。vec1、vec2、result、そしてmap。これらのすべてが個別のトークンとして扱われ、まるで言語の単語のように扱われる。
トークン化されたコードが次々とベクトルに変換されていく様子を、彼は見守った。vec1には [0.34, 0.76, 0.12, ...] のような12次元のベクトルが、mapにはまた別のランダムなベクトルが割り当てられ、次第にコード全体が数値の行列として表現されていく。
トークンをベクトルに変換する
「これらのトークンに、ランダムな12次元ベクトルを割り当てる。そして、トークンが集合する行列を生成する…」
彼は計算機に命じ、トークンに対してランダムな12次元のベクトルを生成させた。1つ1つのトークンが、無機質な数列として変換されていく。その姿は、まるで言葉が目に見えないデジタルの言語に変換されていくかのようだった。
「これで準備は整った…」彼はコードが行列となって構造化される様子を眺め、次の段階に進む決意を固めた。
行列とニューラルネットワーク
凌介の目標は、この行列化されたコードを使ってニューラルネットワークを訓練し、次第にコード生成を自動化することだった。彼は次に、この行列をニューラルネットワークに流し込み、トレーニングを開始した。エポックごとに生成されるコードが少しずつ改善され、初期の混沌とした状態から、次第に正確で理にかなった構造を持つコードへと進化していく。
「コードが進化していく様子を見守るのは、まるでプログラムに命を吹き込んでいるかのようだ…」彼は目を輝かせ、コンピュータに表示される数字とコードの変化を注視した。
行列として表現されたコードは、ネットワークの中で計算され、最適化が進むたびに新しいコードを生み出していく。初めは簡単な加算しかできなかったプログラムが、徐々に複雑な関数や処理を生成できるようになっていく過程は、まるで機械が自ら考え、学習しているかのようだった。
新しい未来への第一歩
エポック100
vec1 = [1, 2, 3];
vec2 = [4, 5, 6];
result = vec1.map((v, i) => v + vec2[i]);
console.log(result);
最終的に凌介は、ニューラルネットワークを用いたコード生成がほぼ完成形に近づいていることを確信した。彼は椅子に深く腰を下ろし、夜の東京を眺めた。コンピュータの前で、無数のコードとベクトルが流れ、光が弾けるかのように計算が進行していく。
「これで、僕は自分の手で新しい時代を切り開いたのかもしれない…」
東京の夜は静かに続いていたが、凌介の心には新たな未来の輝きが広がっていた。彼は自らのプログラムを通じて、計算の世界に新しい生命を宿すことができたのだ。
そして、彼の物語はここから本当の意味で始まろうとしていた。
コードをメモ帳などのテキストエディタに貼り付け、ファイル名を「index.html」として保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。
実行結果。
Sample Code:
vec1 = [1, 2, 3];
vec2 = [4, 5, 6];
result = vec1.map((v, i) => v + vec2[i]);
console.log(result);
Epoch 10:
2, [4, [1, vec2[i]); 3]; vec2 [4, 6]; vec2[i]); [4, [1, [4, vec2[i]); i) console.log(result); vec2[i]); console.log(result);
Epoch 20:
[4, = [1, vec2[i]); 3]; vec2 = [4, 6]; vec2[i]); = [1, [4, [4, [4, console.log(result); vec2[i]); console.log(result);
Epoch 30:
[4, = [1, vec2[i]); 3]; vec2 = [4, 6]; vec2[i]); = vec1.map((v, i) [4, v console.log(result); vec2[i]); console.log(result);
Epoch 40:
[4, = [1, vec2[i]); 3]; vec2 = [4, 5, 6]; vec2[i]); = vec1.map((v, i) [4, v console.log(result); vec2[i]); console.log(result);
Epoch 50:
vec1 = [1, vec2[i]); 3]; vec2 = [4, 5, 6]; vec2[i]); = vec1.map((v, i) [4, v + vec2[i]); console.log(result);
Epoch 60:
vec1 = [1, 2, 3]; vec2 = [4, 5, 6]; vec2[i]); = vec1.map((v, i) => v + vec2[i]); console.log(result);
Epoch 70:
vec1 = [1, 2, 3]; vec2 = [4, 5, 6]; result = vec1.map((v, i) => v + vec2[i]); console.log(result);
Epoch 80:
vec1 = [1, 2, 3]; vec2 = [4, 5, 6]; result = vec1.map((v, i) => v + vec2[i]); console.log(result);
Epoch 90:
vec1 = [1, 2, 3]; vec2 = [4, 5, 6]; result = vec1.map((v, i) => v + vec2[i]); console.log(result);
Epoch 100:
vec1 = [1, 2, 3]; vec2 = [4, 5, 6]; result = vec1.map((v, i) => v + vec2[i]); console.log(result);
Sample Code:
vec1 = [1, 2, 3];
vec2 = [4, 5, 6];
result = vec1.map((v, i) => v + vec2[i]);
console.log(result);
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Token Vector Optimization with TensorFlow.js</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <!-- Chart.jsを読み込む -->
<style>
canvas {
max-width: 600px;
margin: 20px auto;
}
</style>
</head>
<body>
<h1>Token Vector Optimization using TensorFlow.js</h1>
<pre id="sampleCode"></pre>
<pre id="optimizedCode"></pre>
<canvas id="lossChart"></canvas> <!-- ロスをプロットするためのキャンバス -->
<script>
// サンプルコード(ベクトルの加算)
const sampleCode = `
vec1 = [1, 2, 3];
vec2 = [4, 5, 6];
result = vec1.map((v, i) => v + vec2[i]);
console.log(result);
`;
document.getElementById("sampleCode").textContent = `Sample Code:\n${sampleCode}`;
// トークンをリストに分割
const tokens = sampleCode.split(/\s+/);
// 各トークンに12次元のランダムベクトルを割り当てる
const tokenToVec = {};
tokens.forEach(token => {
tokenToVec[token] = tf.randomNormal([12]);
});
// 行列Aを生成(各トークンのベクトルを縦に並べた行列)
const A = tf.stack(tokens.map(token => tokenToVec[token]));
// シンプルなニューラルネットワークを定義
function createModel() {
const model = tf.sequential();
model.add(tf.layers.dense({ inputShape: [12], units: 12 }));
return model;
}
// モデルをインスタンス化
const model = createModel();
model.compile({
optimizer: tf.train.sgd(0.1), // 確率的勾配降下法を使用
loss: 'meanSquaredError' // 損失関数として平均二乗誤差を使用
});
// トレーニングの設定
const epochs = 100; // エポック数
const printInterval = 10; // ロスとコードを出力する間隔
const losses = []; // 各エポックのロスを記録する配列
async function trainModel() {
for (let epoch = 0; epoch < epochs; epoch++) {
// モデルにAを入力し、出力を得る
const output = model.predict(A);
// 損失を計算して最適化
const history = await model.fit(A, A, { epochs: 1, batchSize: tokens.length });
// 現在のエポックのロスを記録
losses.push(history.history.loss[0]);
// 一定のエポックごとに結果をプリント
if ((epoch + 1) % printInterval === 0) {
const outputData = output.arraySync();
const optimizedTokens = tokens.map((token, i) => {
// 各出力ベクトルに最も近いトークンを選ぶ
let closestToken = tokens[0];
let minDistance = tf.norm(tf.tensor(outputData[i]).sub(tokenToVec[tokens[0]])).arraySync();
tokens.forEach(t => {
const dist = tf.norm(tf.tensor(outputData[i]).sub(tokenToVec[t])).arraySync();
if (dist < minDistance) {
closestToken = t;
minDistance = dist;
}
});
return closestToken;
});
// 最適化されたコードをプリント
document.getElementById("optimizedCode").textContent += `Epoch ${epoch + 1}:\n${optimizedTokens.join(' ')}\n\n`;
}
}
// トレーニングが終了したらロスをプロットする
plotLoss(losses);
}
// ロスをプロットする関数
function plotLoss(losses) {
const ctx = document.getElementById('lossChart').getContext('2d');
const chart = new Chart(ctx, {
type: 'line', // 折れ線グラフ
data: {
labels: Array.from({ length: losses.length }, (_, i) => i + 1), // エポック数
datasets: [{
label: 'Loss',
data: losses, // 各エポックのロス
borderColor: 'rgba(75, 192, 192, 1)', // 線の色
borderWidth: 2,
fill: false // 塗りつぶしなし
}]
},
options: {
responsive: true,
scales: {
x: {
title: {
display: true,
text: 'Epoch'
}
},
y: {
title: {
display: true,
text: 'Loss'
}
}
}
}
});
}
// トレーニングを実行
trainModel();
</script>
</body>
</html>