ショートストーリー:「未来を紡ぐコード」
東京のプログラマ、加藤拓也は、夜の東京の喧騒から少し離れた静かな部屋で、一心不乱にキーボードを叩いていた。彼は次世代の動画生成AIモデルの研究に取り組んでおり、その最前線で活躍するプログラマだ。今日の彼の目標は、彼の開発した新しいアルゴリズムを使って、数学的な美しさを視覚化するアニメーションを作り上げることだった。
拓也の最新のプロジェクトは、3次元テンソルの計算を利用して、視覚的に魅力的なヒートマップを生成することだった。彼のコードは、正弦波と余弦波の複雑なパターンを組み合わせたもので、それぞれが異なるテンソルとして表現される。このテンソルたちは、未来の動画生成AIにおける「可能性の断片」だ。
ある晩、拓也は深夜のコード作成に没頭していた。彼のコンピュータの画面には、青い光が反射するテンソルデータが表示されている。テンソルAとテンソルB、それぞれが正弦波と余弦波のパターンを描き出しており、彼のプログラムはそれらのテンソルの積を計算し、3Dアニメーションとして可視化することを目指していた。
「このデータがどんなアニメーションになるのか、見てみたいな」と拓也は呟いた。
彼のコードが、テンソルの積を計算し、その結果を一つ一つスライスして3次元ヒートマップとしてプロットする準備が整った。拓也は深呼吸し、コードの実行ボタンを押した。画面に映し出されたのは、数十万のデータポイントが織りなす美しいパーティクルアニメーションだった。
アニメーションは、正弦波と余弦波が交錯する中で、色とりどりの点が優雅に舞う光景を描き出していた。それはまるで、宇宙の中で踊る星々のような、未来的で幻想的な光景だった。
その夜、拓也はコードの美しさと、数学の力によって創造されたビジュアルの力に感動し、深い満足感を覚えた。
未来の動画生成AIモデルの研究は、彼の手によって新たな次元を迎え、東京のプログラマとしての彼の探求は続く。夜が更ける中、拓也は静かに次のステップへと進むための準備を始めた。
TensorFlow.jsを使って3次元テンソルの計算を行い、GPUとCPUのパフォーマンスを比較しています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Tensor Performance Comparison</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
</head>
<body>
<h1>3D Tensor Performance Comparison</h1>
<button onclick="comparePerformance()">Run Performance Test</button>
<div id="results"></div>
<script>
async function runTensorCalculation(backend, size) {
// Set the backend and wait for it to be ready
await tf.setBackend(backend);
await tf.ready();
// Create 3D tensors
const tensor1 = tf.randomUniform([size, size, size]);
const tensor2 = tf.randomUniform([size, size, size]);
// Start performance measurement
const start = performance.now();
const result = tensor1.matMul(tensor2, true); // Example operation
await result.data(); // Execute computation
const end = performance.now();
return end - start; // Return elapsed time
}
async function comparePerformance() {
const sizes = [10, 50, 100, 200];
let resultsHtml = '<h2>Performance Results</h2>';
resultsHtml += '<table border="1"><tr><th>Size</th><th>GPU Time (ms)</th><th>CPU Time (ms)</th></tr>';
for (const size of sizes) {
// Measure GPU performance
const gpuTime = await runTensorCalculation('webgl', size);
// Measure CPU performance
const cpuTime = await runTensorCalculation('cpu', size);
resultsHtml += `<tr><td>${size}x${size}x${size}</td><td>${gpuTime.toFixed(2)}</td><td>${cpuTime.toFixed(2)}</td></tr>`;
}
resultsHtml += '</table>';
document.getElementById('results').innerHTML = resultsHtml;
}
</script>
</body>
</html>
異なるサイズの3次元テンソルの計算時間を測定し、プロットします。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GPU 3D Tensor Performance</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/plotly.js-dist/plotly.min.js"></script>
</head>
<body>
<div id="plot" style="width: 100%; height: 500px;"></div>
<script>
async function measureTensorCalculationTime(size) {
// ランダムな3次元テンソルを生成
const A = tf.randomUniform([size, size, size]);
const B = tf.randomUniform([size, size, size]);
// テンソル計算の時間を測定
const startTime = performance.now();
await tf.tidy(() => {
// テンソルの加算を計算(他の計算操作に変更可能)
const result = tf.add(A, B);
return result.data(); // 計算を強制的に実行
});
const endTime = performance.now();
// テンソルを解放してGPUメモリを確保
A.dispose();
B.dispose();
return endTime - startTime;
}
async function runPerformanceTest() {
const sizes = [10, 50, 100, 200, 300];
const times = [];
for (const size of sizes) {
console.log(`サイズ ${size}x${size}x${size} のテンソル計算を測定中`);
const time = await measureTensorCalculationTime(size);
times.push(time);
console.log(`${size}x${size}x${size} の計算時間: ${time} ms`);
}
// 測定結果をプロット
Plotly.newPlot('plot', [{
x: sizes.map(size => `${size}x${size}x${size}`),
y: times,
type: 'scatter',
mode: 'lines+markers',
marker: { color: 'blue' }
}], {
title: 'GPU 3D テンソル計算時間 vs サイズ',
xaxis: { title: 'テンソルサイズ (x x x)' },
yaxis: { title: '処理時間 (ms)' }
});
}
runPerformanceTest();
</script>
</body>
</html>
正弦波と余弦波に基づいたデータで生成されたテンソル積のスライスがパーティクルアニメーションとして表示されます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Tensor Particle Animation with Sinusoidal Data</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<!-- three.jsとTensorFlow.jsのCDNを読み込み -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script>
// シーン、カメラ、レンダラーの設定
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// グリッドサイズの設定
const gridSize = 50;
// パーティクルのジオメトリとマテリアルを設定
const particles = new THREE.BufferGeometry();
const particleCount = gridSize * gridSize * gridSize;
const positions = new Float32Array(particleCount * 3);
const colors = new Float32Array(particleCount * 3);
particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));
particles.setAttribute('color', new THREE.BufferAttribute(colors, 3));
const material = new THREE.PointsMaterial({
size: 0.5,
vertexColors: true
});
const particleSystem = new THREE.Points(particles, material);
scene.add(particleSystem);
camera.position.z = 75;
// 3次元テンソルAとBを生成
const x = tf.linspace(0, 2 * Math.PI, gridSize);
const y = tf.linspace(0, 2 * Math.PI, gridSize);
const z = tf.linspace(0, 2 * Math.PI, gridSize);
// Sin関数を使用してテンソルを生成
const tensorA = tf.tidy(() => {
const xMesh = tf.tile(x.reshape([gridSize, 1, 1]), [1, gridSize, gridSize]);
const yMesh = tf.tile(y.reshape([1, gridSize, 1]), [gridSize, 1, gridSize]);
const zMesh = tf.tile(z.reshape([1, 1, gridSize]), [gridSize, gridSize, 1]);
return tf.sin(xMesh).add(tf.sin(yMesh)).add(tf.sin(zMesh)).div(3);
});
const tensorB = tf.tidy(() => {
const xMesh = tf.tile(x.reshape([gridSize, 1, 1]), [1, gridSize, gridSize]);
const yMesh = tf.tile(y.reshape([1, gridSize, 1]), [gridSize, 1, gridSize]);
const zMesh = tf.tile(z.reshape([1, 1, gridSize]), [gridSize, gridSize, 1]);
return tf.cos(xMesh).add(tf.cos(yMesh)).add(tf.cos(zMesh)).div(3);
});
// テンソル積を計算
const tensorProduct = tf.tidy(() => tensorA.matMul(tensorB));
// テンソル積のスライスを保存
const slices = [];
for (let i = 0; i < gridSize; i++) {
const slice = tensorProduct.slice([0, 0, i], [gridSize, gridSize, 1]).reshape([gridSize, gridSize]);
slices.push(slice.arraySync());
}
let frame = 0;
const totalFrames = gridSize;
// パーティクルの位置と色を更新する関数
function updateParticles(frameIndex) {
const sliceValues = slices[frameIndex];
let index = 0;
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
const intensity = sliceValues[x][y];
const color = new THREE.Color().setHSL(intensity, 1, 0.5);
positions[index * 3] = x - gridSize / 2;
positions[index * 3 + 1] = y - gridSize / 2;
positions[index * 3 + 2] = frameIndex - gridSize / 2;
colors[index * 3] = color.r;
colors[index * 3 + 1] = color.g;
colors[index * 3 + 2] = color.b;
index++;
}
}
particles.attributes.position.needsUpdate = true;
particles.attributes.color.needsUpdate = true;
}
// アニメーションループ
function animate() {
updateParticles(frame);
frame = (frame + 1) % totalFrames;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
// ウィンドウサイズ変更時にレンダラーをリサイズ
window.addEventListener('resize', () => {
const width = window.innerWidth;
const height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
</script>
</body>
</html>
コードの説明
テンソルの生成:
x, y, z のテンソルを tf.linspace で生成し、それを使って sin 関数と cos 関数で tensorA と tensorB を生成します。テンソル tensorA と tensorB はそれぞれ正弦波と余弦波のパターンを持っています。
テンソル積の計算:
tensorA と tensorB のテンソル積を計算します。
スライスの保存:
テンソル積の各スライスを計算し、slices 配列に保存します。
パーティクルシステムの設定:
Three.js の BufferGeometry を使ってパーティクルシステムを作成します。各パーティクルの位置と色を設定します。
パーティクルの更新:
updateParticles 関数で、指定されたスライスのデータを使ってパーティクルの位置と色を更新します。
アニメーション:
animate 関数で、スライスを順次更新し、アニメーションをループさせます。