2026-01-18 10:24:35 +08:00
|
|
|
<template>
|
|
|
|
|
<div class="perceptron-demo">
|
|
|
|
|
<div class="neuron-viz">
|
|
|
|
|
<!-- Inputs -->
|
|
|
|
|
<div class="inputs-col">
|
|
|
|
|
<div class="input-node">
|
|
|
|
|
<span class="label">Input 1 (x₁)</span>
|
2026-01-18 12:21:49 +08:00
|
|
|
<input type="number" v-model="x1" class="val-input" />
|
2026-01-18 10:24:35 +08:00
|
|
|
</div>
|
|
|
|
|
<div class="input-node">
|
|
|
|
|
<span class="label">Input 2 (x₂)</span>
|
2026-01-18 12:21:49 +08:00
|
|
|
<input type="number" v-model="x2" class="val-input" />
|
2026-01-18 10:24:35 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Weights (Edges) -->
|
|
|
|
|
<div class="weights-col">
|
2026-01-18 12:21:49 +08:00
|
|
|
<div
|
|
|
|
|
class="weight-line"
|
|
|
|
|
:style="{
|
|
|
|
|
width: Math.abs(w1) * 2 + 2 + 'px',
|
|
|
|
|
opacity: Math.abs(w1) / 5 + 0.2
|
|
|
|
|
}"
|
|
|
|
|
></div>
|
2026-01-18 10:24:35 +08:00
|
|
|
<div class="weight-control top">
|
2026-01-18 12:21:49 +08:00
|
|
|
w₁: <input type="range" v-model="w1" min="-5" max="5" step="0.1" />
|
|
|
|
|
{{ w1 }}
|
2026-01-18 10:24:35 +08:00
|
|
|
</div>
|
2026-01-18 12:21:49 +08:00
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
class="weight-line"
|
|
|
|
|
:style="{
|
|
|
|
|
width: Math.abs(w2) * 2 + 2 + 'px',
|
|
|
|
|
opacity: Math.abs(w2) / 5 + 0.2
|
|
|
|
|
}"
|
|
|
|
|
></div>
|
2026-01-18 10:24:35 +08:00
|
|
|
<div class="weight-control bottom">
|
2026-01-18 12:21:49 +08:00
|
|
|
w₂: <input type="range" v-model="w2" min="-5" max="5" step="0.1" />
|
|
|
|
|
{{ w2 }}
|
2026-01-18 10:24:35 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Neuron (Sum & Activation) -->
|
|
|
|
|
<div class="neuron-body">
|
|
|
|
|
<div class="sum-part">
|
|
|
|
|
<div class="math">∑</div>
|
|
|
|
|
<div class="val">{{ weightedSum.toFixed(1) }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="bias-control">
|
2026-01-18 12:21:49 +08:00
|
|
|
Bias: <input type="number" v-model="bias" class="bias-input" />
|
2026-01-18 10:24:35 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Output -->
|
|
|
|
|
<div class="output-col">
|
|
|
|
|
<div class="arrow">➔</div>
|
|
|
|
|
<div class="output-node" :class="{ active: output > 0 }">
|
|
|
|
|
<span class="label">Output (y)</span>
|
|
|
|
|
<div class="val">{{ output }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="formula-bar">
|
2026-01-18 12:21:49 +08:00
|
|
|
Formula:
|
|
|
|
|
<code
|
|
|
|
|
>({{ x1 }} * {{ w1 }}) + ({{ x2 }} * {{ w2 }}) + {{ bias }} =
|
|
|
|
|
{{ weightedSum.toFixed(1) }}</code
|
|
|
|
|
>
|
|
|
|
|
<br />
|
|
|
|
|
Activation:
|
|
|
|
|
<code>Step( {{ weightedSum.toFixed(1) }} ) = {{ output }}</code>
|
2026-01-18 10:24:35 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, computed } from 'vue'
|
|
|
|
|
|
|
|
|
|
const x1 = ref(1)
|
|
|
|
|
const x2 = ref(0)
|
|
|
|
|
const w1 = ref(2.0)
|
|
|
|
|
const w2 = ref(-1.0)
|
|
|
|
|
const bias = ref(0)
|
|
|
|
|
|
|
|
|
|
const weightedSum = computed(() => {
|
2026-01-18 12:21:49 +08:00
|
|
|
return x1.value * w1.value + x2.value * w2.value + bias.value
|
2026-01-18 10:24:35 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const output = computed(() => {
|
|
|
|
|
return weightedSum.value > 0 ? 1 : 0
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.perceptron-demo {
|
|
|
|
|
border: 1px solid var(--vp-c-divider);
|
|
|
|
|
border-radius: 8px;
|
2026-01-19 11:25:10 +08:00
|
|
|
background: var(--vp-c-bg-soft);
|
2026-01-18 10:24:35 +08:00
|
|
|
padding: 1.5rem;
|
|
|
|
|
margin: 1rem 0;
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.neuron-viz {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
min-width: 500px;
|
|
|
|
|
gap: 1rem;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-18 12:21:49 +08:00
|
|
|
.inputs-col,
|
|
|
|
|
.output-col {
|
2026-01-18 10:24:35 +08:00
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 2rem;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-18 12:21:49 +08:00
|
|
|
.input-node,
|
|
|
|
|
.output-node {
|
2026-01-18 10:24:35 +08:00
|
|
|
width: 60px;
|
|
|
|
|
height: 60px;
|
|
|
|
|
border-radius: 50%;
|
2026-01-19 11:25:10 +08:00
|
|
|
border: 2px solid var(--vp-c-divider);
|
2026-01-18 10:24:35 +08:00
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
2026-01-19 11:25:10 +08:00
|
|
|
background: var(--vp-c-bg);
|
2026-01-18 10:24:35 +08:00
|
|
|
position: relative;
|
2026-01-19 11:25:10 +08:00
|
|
|
color: var(--vp-c-text-1);
|
2026-01-18 10:24:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.output-node.active {
|
2026-01-19 11:25:10 +08:00
|
|
|
background: var(--vp-c-brand);
|
|
|
|
|
border-color: var(--vp-c-brand);
|
|
|
|
|
color: var(--vp-c-bg);
|
2026-01-18 10:24:35 +08:00
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.label {
|
|
|
|
|
font-size: 0.6rem;
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: -15px;
|
|
|
|
|
width: 80px;
|
|
|
|
|
text-align: center;
|
2026-01-19 11:25:10 +08:00
|
|
|
color: var(--vp-c-text-2);
|
2026-01-18 10:24:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.val-input {
|
|
|
|
|
width: 40px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
border: none;
|
|
|
|
|
background: transparent;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
font-size: 1.1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.weights-col {
|
|
|
|
|
flex: 1;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
position: relative;
|
|
|
|
|
height: 120px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.weight-line {
|
|
|
|
|
height: 2px;
|
2026-01-19 11:25:10 +08:00
|
|
|
background: var(--vp-c-text-2);
|
2026-01-18 10:24:35 +08:00
|
|
|
position: absolute;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
top: 50%;
|
|
|
|
|
transform-origin: left center;
|
|
|
|
|
}
|
|
|
|
|
/* Simplified visual lines for CSS only demo - ideally SVG */
|
|
|
|
|
/* This is a simplified representation */
|
|
|
|
|
|
|
|
|
|
.weight-control {
|
|
|
|
|
font-size: 0.7rem;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 4px;
|
2026-01-19 11:25:10 +08:00
|
|
|
background: var(--vp-c-bg);
|
2026-01-18 10:24:35 +08:00
|
|
|
padding: 2px 4px;
|
2026-01-19 11:25:10 +08:00
|
|
|
border: 1px solid var(--vp-c-divider);
|
2026-01-18 10:24:35 +08:00
|
|
|
border-radius: 4px;
|
|
|
|
|
z-index: 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.neuron-body {
|
|
|
|
|
width: 100px;
|
|
|
|
|
height: 100px;
|
|
|
|
|
border-radius: 50%;
|
2026-01-19 11:25:10 +08:00
|
|
|
background: var(--vp-c-brand);
|
|
|
|
|
color: var(--vp-c-bg);
|
2026-01-18 10:24:35 +08:00
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
position: relative;
|
2026-01-19 11:25:10 +08:00
|
|
|
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.35);
|
2026-01-18 10:24:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.sum-part {
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
2026-01-18 12:21:49 +08:00
|
|
|
.math {
|
|
|
|
|
font-size: 1.5rem;
|
|
|
|
|
}
|
|
|
|
|
.val {
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
2026-01-18 10:24:35 +08:00
|
|
|
|
|
|
|
|
.bias-control {
|
|
|
|
|
position: absolute;
|
|
|
|
|
bottom: -30px;
|
2026-01-19 11:25:10 +08:00
|
|
|
background: var(--vp-c-bg);
|
|
|
|
|
color: var(--vp-c-text-1);
|
2026-01-18 10:24:35 +08:00
|
|
|
padding: 2px 8px;
|
|
|
|
|
border-radius: 10px;
|
2026-01-19 11:25:10 +08:00
|
|
|
border: 1px solid var(--vp-c-divider);
|
2026-01-18 10:24:35 +08:00
|
|
|
font-size: 0.7rem;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
}
|
|
|
|
|
.bias-input {
|
|
|
|
|
width: 30px;
|
2026-01-19 11:25:10 +08:00
|
|
|
border: 1px solid var(--vp-c-divider);
|
2026-01-18 10:24:35 +08:00
|
|
|
border-radius: 2px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.formula-bar {
|
|
|
|
|
margin-top: 2rem;
|
2026-01-19 11:25:10 +08:00
|
|
|
background: var(--vp-c-bg);
|
2026-01-18 10:24:35 +08:00
|
|
|
padding: 1rem;
|
|
|
|
|
border-radius: 6px;
|
2026-01-19 11:25:10 +08:00
|
|
|
font-family: var(--vp-font-family-mono);
|
2026-01-18 10:24:35 +08:00
|
|
|
font-size: 0.8rem;
|
2026-01-19 11:25:10 +08:00
|
|
|
color: var(--vp-c-text-1);
|
2026-01-18 10:24:35 +08:00
|
|
|
text-align: center;
|
2026-01-19 11:25:10 +08:00
|
|
|
border: 1px dashed var(--vp-c-divider);
|
2026-01-18 10:24:35 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-18 12:21:49 +08:00
|
|
|
input[type='range'] {
|
|
|
|
|
width: 60px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|