feat: comprehensive documentation and demo updates
- Update READMEs and docs across multiple languages - Enhance interactive demos for Agent, LLM, VLM, Audio, Image Gen, Terminal, and Web Basics - Add new appendix sections for Database and IDE intros - Update VitePress config, theme, and utility scripts - Clean up unused assets and components
This commit is contained in:
+57
-31
@@ -21,11 +21,22 @@
|
||||
</template>
|
||||
|
||||
<div class="canvas-container">
|
||||
<canvas ref="canvasRef" width="300" height="300" class="noise-canvas"></canvas>
|
||||
<canvas
|
||||
ref="canvasRef"
|
||||
width="300"
|
||||
height="300"
|
||||
class="noise-canvas"
|
||||
></canvas>
|
||||
<div class="step-indicator">
|
||||
<span class="step-text">Step: {{ currentStep }} / {{ totalSteps }}</span>
|
||||
<el-progress
|
||||
:percentage="mode === 'forward' ? (currentStep / totalSteps * 100) : ((totalSteps - currentStep) / totalSteps * 100)"
|
||||
<span class="step-text"
|
||||
>Step: {{ currentStep }} / {{ totalSteps }}</span
|
||||
>
|
||||
<el-progress
|
||||
:percentage="
|
||||
mode === 'forward'
|
||||
? (currentStep / totalSteps) * 100
|
||||
: ((totalSteps - currentStep) / totalSteps) * 100
|
||||
"
|
||||
:status="mode === 'forward' ? 'exception' : 'success'"
|
||||
:show-text="false"
|
||||
:stroke-width="4"
|
||||
@@ -34,23 +45,33 @@
|
||||
</div>
|
||||
|
||||
<div class="slider-control">
|
||||
<el-slider
|
||||
v-model="currentStep"
|
||||
:min="0"
|
||||
:max="totalSteps"
|
||||
<el-slider
|
||||
v-model="currentStep"
|
||||
:min="0"
|
||||
:max="totalSteps"
|
||||
:format-tooltip="formatTooltip"
|
||||
@input="draw"
|
||||
/>
|
||||
<div class="slider-labels">
|
||||
<span>{{ mode === 'forward' ? '原图 (Original)' : '纯噪声 (Noise)' }}</span>
|
||||
<span>{{ mode === 'forward' ? '纯噪声 (Noise)' : '原图 (Original)' }}</span>
|
||||
<span>{{
|
||||
mode === 'forward' ? '原图 (Original)' : '纯噪声 (Noise)'
|
||||
}}</span>
|
||||
<span>{{
|
||||
mode === 'forward' ? '纯噪声 (Noise)' : '原图 (Original)'
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-alert
|
||||
:title="mode === 'forward' ? '训练阶段:破坏数据' : '生成阶段:创造数据'"
|
||||
:title="
|
||||
mode === 'forward' ? '训练阶段:破坏数据' : '生成阶段:创造数据'
|
||||
"
|
||||
:type="mode === 'forward' ? 'warning' : 'success'"
|
||||
:description="mode === 'forward' ? 'AI 通过学习如何「一点点加噪」,掌握了噪声的规律。这就像教它把积木推倒。' : 'AI 通过预测并减去噪声,从混沌中还原出图像。这就像它学会了把推倒的积木重新搭好。'"
|
||||
:description="
|
||||
mode === 'forward'
|
||||
? 'AI 通过学习如何「一点点加噪」,掌握了噪声的规律。这就像教它把积木推倒。'
|
||||
: 'AI 通过预测并减去噪声,从混沌中还原出图像。这就像它学会了把推倒的积木重新搭好。'
|
||||
"
|
||||
show-icon
|
||||
:closable="false"
|
||||
class="explanation-alert"
|
||||
@@ -61,7 +82,12 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, onUnmounted } from 'vue'
|
||||
import { VideoPlay, VideoPause, TopRight, BottomLeft } from '@element-plus/icons-vue'
|
||||
import {
|
||||
VideoPlay,
|
||||
VideoPause,
|
||||
TopRight,
|
||||
BottomLeft
|
||||
} from '@element-plus/icons-vue'
|
||||
|
||||
const canvasRef = ref(null)
|
||||
const mode = ref('reverse')
|
||||
@@ -77,7 +103,7 @@ const loadBaseImage = () => {
|
||||
canvas.width = 300
|
||||
canvas.height = 300
|
||||
const ctx = canvas.getContext('2d')
|
||||
|
||||
|
||||
// Draw a simple landscape
|
||||
// Sky
|
||||
const gradient = ctx.createLinearGradient(0, 0, 0, 300)
|
||||
@@ -85,13 +111,13 @@ const loadBaseImage = () => {
|
||||
gradient.addColorStop(1, '#E0F7FA')
|
||||
ctx.fillStyle = gradient
|
||||
ctx.fillRect(0, 0, 300, 300)
|
||||
|
||||
|
||||
// Sun
|
||||
ctx.beginPath()
|
||||
ctx.arc(240, 60, 30, 0, Math.PI * 2)
|
||||
ctx.fillStyle = '#FFD700'
|
||||
ctx.fill()
|
||||
|
||||
|
||||
// Mountains
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(0, 300)
|
||||
@@ -101,7 +127,7 @@ const loadBaseImage = () => {
|
||||
ctx.lineTo(300, 300)
|
||||
ctx.fillStyle = '#4CAF50'
|
||||
ctx.fill()
|
||||
|
||||
|
||||
// House
|
||||
ctx.fillStyle = '#795548'
|
||||
ctx.fillRect(50, 220, 60, 60)
|
||||
@@ -120,7 +146,7 @@ const generateNoise = (width, height) => {
|
||||
const data = new Uint8ClampedArray(size)
|
||||
for (let i = 0; i < size; i += 4) {
|
||||
const val = Math.random() * 255
|
||||
data[i] = val // R
|
||||
data[i] = val // R
|
||||
data[i + 1] = val // G
|
||||
data[i + 2] = val // B
|
||||
data[i + 3] = 255 // A
|
||||
@@ -149,7 +175,7 @@ const draw = () => {
|
||||
const canvas = canvasRef.value
|
||||
if (!canvas || !originalImage) return
|
||||
const ctx = canvas.getContext('2d')
|
||||
|
||||
|
||||
// Calculate noise ratio based on mode and step
|
||||
// Forward: 0 -> 100 (Clean -> Noisy)
|
||||
// Reverse: 100 -> 0 (Noisy -> Clean)
|
||||
@@ -158,18 +184,18 @@ const draw = () => {
|
||||
// but for UI, we want:
|
||||
// Forward Mode: Slider 0 (Clean) -> 100 (Noisy)
|
||||
// Reverse Mode: Slider 0 (Noisy) -> 100 (Clean)
|
||||
|
||||
|
||||
let noiseRatio = 0
|
||||
if (mode.value === 'forward') {
|
||||
noiseRatio = currentStep.value / totalSteps
|
||||
} else {
|
||||
// In reverse mode, slider 0 means start (Noisy), 100 means end (Clean)
|
||||
// So noise amount is 1 - slider
|
||||
noiseRatio = 1 - (currentStep.value / totalSteps)
|
||||
noiseRatio = 1 - currentStep.value / totalSteps
|
||||
}
|
||||
|
||||
|
||||
// Non-linear interpolation for better visual effect
|
||||
// noiseRatio = Math.pow(noiseRatio, 1.5)
|
||||
// noiseRatio = Math.pow(noiseRatio, 1.5)
|
||||
|
||||
const w = canvas.width
|
||||
const h = canvas.height
|
||||
@@ -177,20 +203,20 @@ const draw = () => {
|
||||
const d = output.data
|
||||
const o = originalImage.data
|
||||
const n = noiseImage.data
|
||||
|
||||
|
||||
for (let i = 0; i < d.length; i += 4) {
|
||||
// Simple linear interpolation
|
||||
// Pixel = (1 - alpha) * Original + alpha * Noise
|
||||
// Note: This is a simplified diffusion visualization.
|
||||
// Real diffusion adds noise: x_t = sqrt(alpha_bar) * x_0 + sqrt(1 - alpha_bar) * epsilon
|
||||
|
||||
|
||||
// Using simple blending for visualization
|
||||
d[i] = o[i] * (1 - noiseRatio) + n[i] * noiseRatio
|
||||
d[i+1] = o[i+1] * (1 - noiseRatio) + n[i+1] * noiseRatio
|
||||
d[i+2] = o[i+2] * (1 - noiseRatio) + n[i+2] * noiseRatio
|
||||
d[i+3] = 255
|
||||
d[i + 1] = o[i + 1] * (1 - noiseRatio) + n[i + 1] * noiseRatio
|
||||
d[i + 2] = o[i + 2] * (1 - noiseRatio) + n[i + 2] * noiseRatio
|
||||
d[i + 3] = 255
|
||||
}
|
||||
|
||||
|
||||
ctx.putImageData(output, 0, 0)
|
||||
}
|
||||
|
||||
@@ -208,7 +234,7 @@ const startAnimation = () => {
|
||||
if (currentStep.value >= totalSteps) {
|
||||
currentStep.value = 0
|
||||
}
|
||||
|
||||
|
||||
const animate = () => {
|
||||
if (currentStep.value < totalSteps) {
|
||||
currentStep.value += 1
|
||||
@@ -261,7 +287,7 @@ const formatTooltip = (val) => {
|
||||
|
||||
.noise-canvas {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@@ -57,9 +57,13 @@
|
||||
>
|
||||
<template #default>
|
||||
<p>
|
||||
<strong>Diffusion</strong> 就像在迷雾中摸索,路径充满了随机性,需要走很多弯路(步数多)才能到达终点。
|
||||
<br>
|
||||
<strong>Flow Matching</strong> 就像使用了 GPS 导航,直接找到了从噪声到图像的<strong>直线最优路径 (Optimal Transport)</strong>,因此只需要极少的步数。
|
||||
<strong>Diffusion</strong>
|
||||
就像在迷雾中摸索,路径充满了随机性,需要走很多弯路(步数多)才能到达终点。
|
||||
<br />
|
||||
<strong>Flow Matching</strong> 就像使用了 GPS
|
||||
导航,直接找到了从噪声到图像的<strong
|
||||
>直线最优路径 (Optimal Transport)</strong
|
||||
>,因此只需要极少的步数。
|
||||
</p>
|
||||
</template>
|
||||
</el-alert>
|
||||
@@ -83,7 +87,7 @@ let animationFrame = null
|
||||
let diffProgress = 0
|
||||
let flowProgress = 0
|
||||
const diffSpeed = 0.005 // Slow
|
||||
const flowSpeed = 0.02 // Fast
|
||||
const flowSpeed = 0.02 // Fast
|
||||
|
||||
// Particles
|
||||
const particles = []
|
||||
@@ -104,7 +108,7 @@ const startAnimation = () => {
|
||||
flowProgress = 0
|
||||
diffSteps.value = 0
|
||||
flowSteps.value = 0
|
||||
|
||||
|
||||
animate()
|
||||
}
|
||||
|
||||
@@ -118,7 +122,7 @@ const stopAnimation = () => {
|
||||
|
||||
const animate = () => {
|
||||
let finished = 0
|
||||
|
||||
|
||||
// Update Diffusion
|
||||
if (diffProgress < 1) {
|
||||
diffProgress += diffSpeed
|
||||
@@ -129,7 +133,7 @@ const animate = () => {
|
||||
drawFrame(diffCanvasRef.value, 1, 'curve')
|
||||
finished++
|
||||
}
|
||||
|
||||
|
||||
// Update Flow
|
||||
if (flowProgress < 1) {
|
||||
flowProgress += flowSpeed
|
||||
@@ -140,7 +144,7 @@ const animate = () => {
|
||||
drawFrame(flowCanvasRef.value, 1, 'line')
|
||||
finished++
|
||||
}
|
||||
|
||||
|
||||
if (finished < 2) {
|
||||
animationFrame = requestAnimationFrame(animate)
|
||||
} else {
|
||||
@@ -153,7 +157,7 @@ const drawStatic = (canvas, type) => {
|
||||
const ctx = canvas.getContext('2d')
|
||||
const w = canvas.width
|
||||
const h = canvas.height
|
||||
|
||||
|
||||
ctx.clearRect(0, 0, w, h)
|
||||
drawBackground(ctx, w, h)
|
||||
drawPath(ctx, w, h, type, false)
|
||||
@@ -165,21 +169,21 @@ const drawFrame = (canvas, progress, type) => {
|
||||
const ctx = canvas.getContext('2d')
|
||||
const w = canvas.width
|
||||
const h = canvas.height
|
||||
|
||||
|
||||
ctx.clearRect(0, 0, w, h)
|
||||
drawBackground(ctx, w, h)
|
||||
drawPath(ctx, w, h, type, true) // active path
|
||||
drawEndpoints(ctx, w, h)
|
||||
|
||||
|
||||
// Draw Particle
|
||||
const pos = getPosition(progress, type, w, h)
|
||||
|
||||
|
||||
// Draw Trail
|
||||
ctx.beginPath()
|
||||
if (type === 'curve') {
|
||||
ctx.moveTo(30, h - 30)
|
||||
// Re-calculate curve up to progress
|
||||
for(let t=0; t<=progress; t+=0.01) {
|
||||
for (let t = 0; t <= progress; t += 0.01) {
|
||||
const p = getPosition(t, type, w, h)
|
||||
ctx.lineTo(p.x, p.y)
|
||||
}
|
||||
@@ -190,7 +194,7 @@ const drawFrame = (canvas, progress, type) => {
|
||||
ctx.strokeStyle = type === 'curve' ? '#F56C6C' : '#67C23A'
|
||||
ctx.lineWidth = 3
|
||||
ctx.stroke()
|
||||
|
||||
|
||||
// Draw Head
|
||||
ctx.beginPath()
|
||||
ctx.arc(pos.x, pos.y, 6, 0, Math.PI * 2)
|
||||
@@ -207,8 +211,14 @@ const drawBackground = (ctx, w, h) => {
|
||||
ctx.strokeStyle = '#eee'
|
||||
ctx.lineWidth = 1
|
||||
ctx.beginPath()
|
||||
for(let x=0; x<=w; x+=20) { ctx.moveTo(x,0); ctx.lineTo(x,h); }
|
||||
for(let y=0; y<=h; y+=20) { ctx.moveTo(0,y); ctx.lineTo(w,y); }
|
||||
for (let x = 0; x <= w; x += 20) {
|
||||
ctx.moveTo(x, 0)
|
||||
ctx.lineTo(x, h)
|
||||
}
|
||||
for (let y = 0; y <= h; y += 20) {
|
||||
ctx.moveTo(0, y)
|
||||
ctx.lineTo(w, y)
|
||||
}
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
@@ -218,7 +228,7 @@ const drawEndpoints = (ctx, w, h) => {
|
||||
ctx.arc(30, h - 30, 8, 0, Math.PI * 2)
|
||||
ctx.fillStyle = '#909399'
|
||||
ctx.fill()
|
||||
|
||||
|
||||
// End (Image)
|
||||
ctx.beginPath()
|
||||
ctx.arc(w - 30, 30, 8, 0, Math.PI * 2)
|
||||
@@ -229,14 +239,14 @@ const drawEndpoints = (ctx, w, h) => {
|
||||
const drawPath = (ctx, w, h, type, isActive) => {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(30, h - 30)
|
||||
|
||||
|
||||
if (type === 'line') {
|
||||
ctx.lineTo(w - 30, 30)
|
||||
} else {
|
||||
// Bezier curve for diffusion
|
||||
ctx.quadraticCurveTo(w * 0.2, 30, w - 30, 30)
|
||||
}
|
||||
|
||||
|
||||
ctx.strokeStyle = isActive ? 'rgba(0,0,0,0.1)' : '#ddd'
|
||||
ctx.lineWidth = 2
|
||||
ctx.setLineDash([5, 5])
|
||||
@@ -249,7 +259,7 @@ const getPosition = (t, type, w, h) => {
|
||||
const startY = h - 30
|
||||
const endX = w - 30
|
||||
const endY = 30
|
||||
|
||||
|
||||
if (type === 'line') {
|
||||
return {
|
||||
x: startX + (endX - startX) * t,
|
||||
@@ -260,10 +270,16 @@ const getPosition = (t, type, w, h) => {
|
||||
// Control Point
|
||||
const cpX = w * 0.2
|
||||
const cpY = 30
|
||||
|
||||
const x = Math.pow(1-t, 2) * startX + 2 * (1-t) * t * cpX + Math.pow(t, 2) * endX
|
||||
const y = Math.pow(1-t, 2) * startY + 2 * (1-t) * t * cpY + Math.pow(t, 2) * endY
|
||||
|
||||
|
||||
const x =
|
||||
Math.pow(1 - t, 2) * startX +
|
||||
2 * (1 - t) * t * cpX +
|
||||
Math.pow(t, 2) * endX
|
||||
const y =
|
||||
Math.pow(1 - t, 2) * startY +
|
||||
2 * (1 - t) * t * cpY +
|
||||
Math.pow(t, 2) * endY
|
||||
|
||||
// Add some random jitter for diffusion look if t < 1
|
||||
// const jitter = t < 1 ? (Math.random() - 0.5) * 5 : 0
|
||||
// return { x: x + jitter, y: y + jitter }
|
||||
@@ -318,7 +334,7 @@ const getPosition = (t, type, w, h) => {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: inset 0 0 10px rgba(0,0,0,0.05);
|
||||
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
canvas {
|
||||
|
||||
@@ -53,7 +53,9 @@
|
||||
<div class="node-content">
|
||||
<div class="model-name">UNet / DiT</div>
|
||||
<div class="action-badge">
|
||||
<el-tag type="warning" size="small" effect="dark">去噪 (Denoise)</el-tag>
|
||||
<el-tag type="warning" size="small" effect="dark"
|
||||
>去噪 (Denoise)</el-tag
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
@@ -87,7 +89,9 @@
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<div class="explanation-item">
|
||||
<div class="exp-icon"><el-icon color="#409EFF"><Microphone /></el-icon></div>
|
||||
<div class="exp-icon">
|
||||
<el-icon color="#409EFF"><Microphone /></el-icon>
|
||||
</div>
|
||||
<div class="exp-text">
|
||||
<h4>耳朵 (Text Encoder)</h4>
|
||||
<p>负责"听懂"你的描述,把它翻译成计算机能理解的数学向量。</p>
|
||||
@@ -96,16 +100,22 @@
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="explanation-item">
|
||||
<div class="exp-icon"><el-icon color="#E6A23C"><Cpu /></el-icon></div>
|
||||
<div class="exp-icon">
|
||||
<el-icon color="#E6A23C"><Cpu /></el-icon>
|
||||
</div>
|
||||
<div class="exp-text">
|
||||
<h4>大脑 (UNet/DiT)</h4>
|
||||
<p>核心创造者。在潜空间(Latent Space)中通过预测噪声来构思画面。</p>
|
||||
<p>
|
||||
核心创造者。在潜空间(Latent Space)中通过预测噪声来构思画面。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="explanation-item">
|
||||
<div class="exp-icon"><el-icon color="#67C23A"><View /></el-icon></div>
|
||||
<div class="exp-icon">
|
||||
<el-icon color="#67C23A"><View /></el-icon>
|
||||
</div>
|
||||
<div class="exp-text">
|
||||
<h4>眼睛 (VAE)</h4>
|
||||
<p>负责"翻译"回图像。把大脑构思的模糊特征还原成高清像素图片。</p>
|
||||
@@ -118,7 +128,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { EditPen, Microphone, Right, Cpu, View, Picture } from '@element-plus/icons-vue'
|
||||
import {
|
||||
EditPen,
|
||||
Microphone,
|
||||
Right,
|
||||
Cpu,
|
||||
View,
|
||||
Picture
|
||||
} from '@element-plus/icons-vue'
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -217,12 +234,12 @@ import { EditPen, Microphone, Right, Cpu, View, Picture } from '@element-plus/ic
|
||||
.flow-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.arrow-connector {
|
||||
transform: rotate(90deg);
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
|
||||
.explanation-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
</div>
|
||||
<div class="grid-wrapper pixel-wrapper">
|
||||
<div class="pixel-grid">
|
||||
<div v-for="n in 256" :key="n" class="pixel-cell" :style="getPixelStyle(n)"></div>
|
||||
<div
|
||||
v-for="n in 256"
|
||||
:key="n"
|
||||
class="pixel-cell"
|
||||
:style="getPixelStyle(n)"
|
||||
></div>
|
||||
</div>
|
||||
<div class="grid-overlay">
|
||||
<span>HD Image</span>
|
||||
@@ -38,7 +43,9 @@
|
||||
</div>
|
||||
<el-icon :size="24" class="arrow-icon"><Right /></el-icon>
|
||||
</div>
|
||||
<el-tag type="danger" size="small" effect="dark" class="compress-tag">压缩 48x</el-tag>
|
||||
<el-tag type="danger" size="small" effect="dark" class="compress-tag"
|
||||
>压缩 48x</el-tag
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- Latent Space -->
|
||||
@@ -49,7 +56,12 @@
|
||||
</div>
|
||||
<div class="grid-wrapper latent-wrapper">
|
||||
<div class="latent-grid">
|
||||
<div v-for="n in 16" :key="n" class="latent-cell" :style="getLatentStyle(n)"></div>
|
||||
<div
|
||||
v-for="n in 16"
|
||||
:key="n"
|
||||
class="latent-cell"
|
||||
:style="getLatentStyle(n)"
|
||||
></div>
|
||||
</div>
|
||||
<div class="grid-overlay">
|
||||
<span>Latent Feature</span>
|
||||
@@ -207,7 +219,7 @@ const getLatentStyle = (n) => {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: rgba(0,0,0,0.6);
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
font-size: 0.75em;
|
||||
padding: 4px 8px;
|
||||
@@ -265,12 +277,12 @@ const getLatentStyle = (n) => {
|
||||
.viz-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.transform-process {
|
||||
transform: rotate(90deg);
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
|
||||
.compress-tag {
|
||||
display: none; /* Hide tag when rotated to avoid layout issues */
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
:style="{ opacity: token.weight }"
|
||||
>
|
||||
<div class="token-text">{{ token.text }}</div>
|
||||
<div class="token-weight">权重: {{ (token.weight * 100).toFixed(0) }}%</div>
|
||||
<div class="token-weight">
|
||||
权重: {{ (token.weight * 100).toFixed(0) }}%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,12 +27,21 @@
|
||||
<div class="attention-section">
|
||||
<div class="section-title">🎯 交叉注意力可视化</div>
|
||||
<div class="attention-grid">
|
||||
<div v-for="(item, index) in attentionMap" :key="index" class="attention-cell">
|
||||
<div
|
||||
v-for="(item, index) in attentionMap"
|
||||
:key="index"
|
||||
class="attention-cell"
|
||||
>
|
||||
<div class="cell-token">{{ item.token }}</div>
|
||||
<div class="cell-bar">
|
||||
<div class="bar-fill" :style="{ width: item.attention * 100 + '%' }"></div>
|
||||
<div
|
||||
class="bar-fill"
|
||||
:style="{ width: item.attention * 100 + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<div class="cell-value">
|
||||
{{ (item.attention * 100).toFixed(0) }}%
|
||||
</div>
|
||||
<div class="cell-value">{{ (item.attention * 100).toFixed(0) }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,9 +51,8 @@
|
||||
<p>
|
||||
<span class="icon">💡</span>
|
||||
<strong>交叉注意力机制</strong>让 AI 理解提示词的每个词。
|
||||
当生成图片时,AI 会"关注"不同的词:
|
||||
"cyberpunk" 影响整体风格,"cat" 决定主体,"neon lights" 控制灯光效果。
|
||||
词的顺序和权重都会影响最终画面!
|
||||
当生成图片时,AI 会"关注"不同的词: "cyberpunk" 影响整体风格,"cat"
|
||||
决定主体,"neon lights" 控制灯光效果。 词的顺序和权重都会影响最终画面!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user