Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
5d69739
chore: add eslint, prettier (code formating)
Twince Jul 27, 2025
b30c92d
build: add vite
Twince Jul 27, 2025
1ddc1ce
chore: add pnpm
Twince Jul 27, 2025
a3b6bd7
chore: add tsconfig
Twince Jul 27, 2025
a27252a
chor: add path on jsconfig
Twince Jul 27, 2025
a9f0797
chore: add gitignore
Twince Jul 27, 2025
777e6b7
refactor: vite의 root 기준을 준수하기 위해 index.html 위치 변경
Twince Jul 27, 2025
75a0224
migratoin: `QueryProcessController`, `throttle`, `NueralNetworkBase`를…
Twince Jul 27, 2025
24f10ea
chore: 상수 및 캔버스의 type 지정
Twince Jul 27, 2025
cbdde7d
rename: vite의 entry 포인트를 위한 이름 변경
Twince Jul 27, 2025
c1bfc4f
chore: 코드 포맷팅 및 interface 공통화를 위한 clear 기능 추가(canvas)
Twince Jul 27, 2025
ccab050
refactor: migration to typescript(WIP)
Twince Aug 6, 2025
7e86c81
build: package, pnpm-lock 내용 추가
Twince Aug 6, 2025
54ccb9d
chore: tsconfig 'allowImportingTsExtensions' 옵션 추가
Twince Aug 6, 2025
1c7769e
migration: 캔버스 핸들링 코드 리팩토링(WIP)
Twince Aug 6, 2025
d7f0725
chore: 설명 주석 추가
Twince Aug 6, 2025
a5874df
refactor: DrawingEventHandler 리팩토링
Twince Aug 6, 2025
a88d829
refactor: migration activation ops
Twince Aug 7, 2025
7cc8338
refactor: canvas migration to Typescript
Twince Aug 7, 2025
54db197
chore: 오타 수정
Twince Aug 9, 2025
40fd0b9
fix: BoundingBox의 오브젝트 좌표를 외부에서 접근할 수 있도록 수정
Twince Aug 9, 2025
9cf8460
chore: drawingEvent 관련 네이밍 변경
Twince Aug 16, 2025
dd86942
refactor: BoundingBox의 캡슐화를 위한 getter 추가
Twince Aug 16, 2025
fcd057d
chore: js to ts
Twince Aug 16, 2025
9911f1d
refactor: entryPoint의 일관성을 위해 DrawingEventHandler의 선언 위치 변경
Twince Aug 16, 2025
ec63410
refactor: jsconfig path 변경
Twince Aug 16, 2025
848c866
feat: canvas clear 기능 추가
Twince Aug 16, 2025
75a8e5f
feat: type 오류 및 잘못된 type 수정
Twince Aug 16, 2025
43fae54
refactor: migration to Typescript
Twince Aug 16, 2025
22e7c40
chore: canvas 초기화 이벤트 추가
Twince Aug 16, 2025
c73fbc6
fix: 잘못된 type 수정
Twince Aug 16, 2025
c07e748
chore: path alias 지정 및 변경
Twince Aug 16, 2025
587ba48
chore: alias 수정에 따른 파일 변경
Twince Aug 29, 2025
680cc41
feat: perceptron 구현을 위한 아키텍처 적용(WIP)
Twince Aug 29, 2025
49c9834
fix: 잘못 정의된 이벤트 내용 수정
Twince Aug 29, 2025
2877545
feat: 용이한 시각화를 위한 input값 log scale 변환
Twince Aug 29, 2025
c8cdb7a
chore: id의 이름을 kebab-case로 변경
Twince Oct 1, 2025
cb7497d
refactor: 아키텍쳐 변경
Twince Oct 1, 2025
ae4360f
refactor: 아키텍쳐 구조 변경
Twince Oct 1, 2025
acf27fa
chore: kebab-case 네이밍 변경에 따른 getElementById 수정
Twince Oct 1, 2025
c1b4344
feat: node render를 위한 shapeVector 추가
Twince Oct 1, 2025
26ac970
chore: 아키텍쳐 변경에 따른 매개변수 수정
Twince Oct 1, 2025
a34ee4e
design: userInputCanvas의 화면 비율 변경
Twince Oct 1, 2025
3b6a181
feat: userInputCanvas의 curve 구현
Twince Oct 1, 2025
3f2d2f8
feat: 신경망 시각화 로직 구현
Twince Oct 7, 2025
d6b29e6
chore: 시각화 구현을 위한 이벤트 payload 설정
Twince Oct 7, 2025
ab37166
chore: 오타 수정 및 변수 위치 변경
Twince Oct 7, 2025
ffb1649
chore: perceptronCanvas의 회전 메서드를 BaseCanvas 클래스로 위임(책임분리 명확화)
Twince Oct 7, 2025
e847196
WIP: 테스트를 위한 테스트 로직
Twince Oct 9, 2025
352170b
WIP: 퍼셉트론 시각화 구현
Twince Oct 11, 2025
8c9ffa6
WIP:키텍처 변경에 따른 리팩토링
Twince Oct 16, 2025
51ec2e5
WIP: 아키텍처 변경에 따른 리팩토링
Twince Oct 16, 2025
448de71
Revert "WIP: 아키텍처 변경에 따른 리팩토"
Twince Oct 17, 2025
69316d4
WIP: 아키텍처 수정에 따른 퍼셉트론 구현
Twince Oct 18, 2025
e0ab6e4
WIP: 렌더 방식 변경
Twince Oct 19, 2025
2e06955
feat: 노드 렌더링 기능 구현
Twince Oct 25, 2025
fa4294e
feat: 노드 수에 따른 스크롤 한계값 구현
Twince Oct 25, 2025
bbaf877
feat: perceptron의 간선(edge) 렌더링 구현
Twince Oct 25, 2025
06015ba
refactor: 깔끔한 시각화를 위한 perceptron 렌더링 리팩토링
Twince Oct 25, 2025
81d22c1
test: 동작 테스트를 위한 user-input canvas 숨김
Twince Oct 26, 2025
cca64c9
chore: 폴더 구조 세분화
Twince Oct 26, 2025
a5a3df5
feat: grid 렌더링 기능 구현
Twince Oct 26, 2025
e453f13
chore: 설명 주석 추가
Twince Oct 26, 2025
cabde9b
feat: userInputCanvas cliping UI 구현
Twince Nov 1, 2025
719cec3
chore: BoundingBox 유틸 디렉토리 변경
Twince Nov 1, 2025
bf32cbe
design: UI layout 구현 및 아이콘 추가
Twince Nov 1, 2025
131a511
refactor: 퍼셉트론 기본 렌더링 옵션 변경
Twince Nov 1, 2025
812d0cd
refactor: 각 노드간 edge의 연결 수 변경
Twince Nov 1, 2025
b995c5b
feat: 그리드 레이아웃 렌더링 기능 구현
Twince Nov 1, 2025
5b8dbc6
refactor: 퍼셉트론 최대 스크롤 범위 수정
Twince Nov 1, 2025
5ab0a78
chore: 사용하지 않는 주석 삭제 및 preitter 적용, 디렉토리 이동
Twince Nov 1, 2025
e140df5
feat: 웹 폰트 추가 및 header title 추가
Twince Nov 1, 2025
2fc6162
refactor: DataStore를 싱글톤으로 변경 및 type 수정
Twince Nov 2, 2025
a16a31b
feat: perceptron 시각화 기능 구현
Twince Nov 2, 2025
833d95e
fix: 텍스트 렌더링 시 나타났던 인덱스 참조 오류 수정
Twince Nov 4, 2025
80b4bec
feat: perceptron 초기화 기능 구현
Twince Nov 4, 2025
0e8ded0
refactor/fix: perceptron 스크롤 방식 변경, 스크롤/터치 병행 불가 이슈 해결
Twince Nov 4, 2025
e99da7b
chore: 불필요한 주석 제거
Twince Nov 4, 2025
7cb7d25
chore: 불필요한 주석 제거
Twince Nov 4, 2025
dd5c2c2
chore/fix: 오타 및 오류 수정
Twince Nov 4, 2025
928668c
feat: 추론한 답 출력기능 구현
Twince Nov 5, 2025
2459204
feat/design: 반응형 지원을 위한 UI Adapter 구현
Twince Nov 8, 2025
06cf863
chore: 불필요한 주석 삭제
Twince Nov 8, 2025
cea3e69
chore: TODO 주석 삭제
Twince Nov 8, 2025
ce1f5ad
test: deploy action
Twince Nov 8, 2025
21308cf
fix: yaml env syntax
Twince Nov 8, 2025
a29fa37
fix: yaml env syntax
Twince Nov 8, 2025
04495d3
fix: vite config base
Twince Nov 8, 2025
12a5dc5
test: mobile viewport error test
Twince Nov 9, 2025
93b4852
fix: safari browser canvas clip-path rendering issue
Twince Nov 9, 2025
9d24355
fix: safari browser canvas clip-path rendering issue 2
Twince Nov 9, 2025
6c23021
fix: safari browser canvas clip-path rendering issue 3
Twince Nov 9, 2025
adbe68c
feat: 노드 swipe시 Y축 스크롤 방지기능 추가
Twince Nov 12, 2025
8b84476
feat: Partial responsive support
Twince Nov 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:prettier/recommended"
],
"plugins": ["prettier"],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"prettier/prettier": "error",
"no-unused-vars": "warn",
"no-console": "off"
}
}
39 changes: 39 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Deploy perceptron preview

on:
push:
branches:
- feat/perceptron

permissions:
contents: write

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v3
with:
version: 9

- uses: actions/setup-node@v4
with:
node-version: 18

- name: Install deps
run: pnpm install --frozen-lockfile

- name: Build
env:
GITHUB_REF_NAME: ${{ github.ref_name }}
run: pnpm build

- name: Deploy
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
publish_branch: gh-pages
destination_dir: feat/perceptron
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
dev/train/trainData/mnist/mnistTraindata_large.js
dev/train/trainData/mnist/mnist_train.csv
node_modules
dist
build
*.min.js
48 changes: 48 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/prettier.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"printWidth": 100,
"tabWidth": 4,
"trailingComma": "all",
"singleQuote": true,
"semi": true
}
Binary file added assets/eraser.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/left_arrow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/right_arrow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 19 additions & 15 deletions dev/train/Tester.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import {Trainer} from "./Trainer.js";
import { Trainer } from './Trainer.js';
// data sets
import {mnistTrainData} from "./trainData/mnist/mnistTrainData.js";
import {mnistTestData} from "./trainData/mnist/mnistTestData.js";
import {mnistTrainData_large} from "./trainData/mnist/mnistTraindata_large.js";

// train utils
import {normalizeInputs, oneHotEncodeLabels} from "./utils/trainDataHandler.js";
import {saveWeightsAsJson} from "./utils/saveWeightsAsJson.js";
import { mnistTrainData } from './trainData/mnist/mnistTrainData.js';
import { mnistTestData } from './trainData/mnist/mnistTestData.js';
import { mnistTrainData_large } from './trainData/mnist/mnistTraindata_large.js';

// train canvasUtils
import { normalizeInputs, oneHotEncodeLabels } from './utils/trainDataHandler.js';
import { saveWeightsAsJson } from './utils/saveWeightsAsJson.js';

// <entry point>
export const tester = () => {
const networkConfig = {inputNodes: 784, hiddenNodes: 200, outputNodes: 10, learningRate: 0.15};
const networkConfig = {
inputNodes: 784,
hiddenNodes: 200,
outputNodes: 10,
learningRate: 0.15,
};
const $NN = new Trainer({
inputNodes: networkConfig.inputNodes,
hiddenNodes: networkConfig.hiddenNodes,
outputNodes: networkConfig.outputNodes,
learningRate: networkConfig.learningRate
learningRate: networkConfig.learningRate,
});

const inputs = normalizeInputs(mnistTrainData);
Expand All @@ -25,16 +29,16 @@ export const tester = () => {
inputs.map((array, idx) => {
$NN.train(array, targets[idx]);
if (idx % 5000 === 0) console.log(`Training progress: ${idx}/60000`);
console.log("✅ training complete!");
console.log('✅ training complete!');
});

for (let i = 0; i<9; i++){
for (let i = 0; i < 9; i++) {
console.log('Query', mnistTestData[i][0]);
console.log($NN.query(normalizeInputs(mnistTestData)[i]));
}

saveWeightsAsJson($NN.W_inputToHidden, $NN.W_hiddenToOutput);
console.log("✅ Weight Downloaded!");
}
console.log('✅ Weight Downloaded!');
};

export default tester;
export default tester;
43 changes: 30 additions & 13 deletions dev/train/Trainer.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
import { NeuralNetworkBase } from "../../src/core/NeuralNetworkBase.js";
import { NeuralNetworkBase } from '../../src/core/NeuralNetworkBase.ts';

// matrix operations
import {matrixMultiply, transposeMatrix} from "../../src/core/ops/matrixOps.js";
import { matrixMultiply, transposeMatrix } from '../../src/core/ops/matrixOps.ts';

export class Trainer extends NeuralNetworkBase {
train(inputs, targets){
train(inputs, targets) {
// CNN operations
const { finalOutputs, hiddenOutputs } = this.feedForward(inputs);
// calculate errors
const output_errors = targets.map((v, idx) => v - finalOutputs[idx]).map(v => [v]); // 출력 계층의 오차를 목표값 - 출력값으로 지정
const output_errors = targets.map((v, idx) => v - finalOutputs[idx]).map((v) => [v]); // 출력 계층의 오차를 목표값 - 출력값으로 지정
const hidden_errors = matrixMultiply(transposeMatrix(this.W_hiddenToOutput), output_errors); // 은닉 계층의 오차를 은닉-> 출력 계층의 가중치값과(W_hiddenToOutput.T) 출력 계층의 오차들을 재조합하여 계산

// activation function derivative
const activationDerivative_HtO = finalOutputs.map(v => 1.0 - v).map((v, idx) => v * finalOutputs[idx]); // hidden to output derivative
const outputGradient = activationDerivative_HtO.map((v, idx) => v * output_errors[idx]).map(v => [v]);
const W_HtO_Update = matrixMultiply(outputGradient, transposeMatrix(hiddenOutputs)).map(array => array.map(v => v * this.learningRate)); // 오차값을 이용해 은닉 계층과 출력 계층간의 가중치 업데이트
const activationDerivative_HtO = finalOutputs
.map((v) => 1.0 - v)
.map((v, idx) => v * finalOutputs[idx]); // hidden to output derivative
const outputGradient = activationDerivative_HtO
.map((v, idx) => v * output_errors[idx])
.map((v) => [v]);
const W_HtO_Update = matrixMultiply(outputGradient, transposeMatrix(hiddenOutputs)).map(
(array) => array.map((v) => v * this.learningRate),
); // 오차값을 이용해 은닉 계층과 출력 계층간의 가중치 업데이트

const activationDerivative_ItH = hiddenOutputs.map(v => 1.0 - v).map((v, idx) => v * hiddenOutputs[idx]);
const hiddenGradient = activationDerivative_ItH.map((v, idx) => v * hidden_errors[idx]).map(v => [v]);
const W_ItH_update = matrixMultiply(hiddenGradient, transposeMatrix(inputs.map(v => [v]))).map(array => array.map(v => v * this.learningRate));
const activationDerivative_ItH = hiddenOutputs
.map((v) => 1.0 - v)
.map((v, idx) => v * hiddenOutputs[idx]);
const hiddenGradient = activationDerivative_ItH
.map((v, idx) => v * hidden_errors[idx])
.map((v) => [v]);
const W_ItH_update = matrixMultiply(
hiddenGradient,
transposeMatrix(inputs.map((v) => [v])),
).map((array) => array.map((v) => v * this.learningRate));

// update weights
this.W_hiddenToOutput = this.W_hiddenToOutput.map((row, i)=> row.map((v, j) => v + W_HtO_Update[i][j]));
this.W_inputToHidden = this.W_inputToHidden.map((row, i)=> row.map((v, j) => v + W_ItH_update[i][j]));
this.W_hiddenToOutput = this.W_hiddenToOutput.map((row, i) =>
row.map((v, j) => v + W_HtO_Update[i][j]),
);
this.W_inputToHidden = this.W_inputToHidden.map((row, i) =>
row.map((v, j) => v + W_ItH_update[i][j]),
);
}
}
}
57 changes: 57 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Neural Network Visualization</title>
<script type="module" src="src/main.ts"></script>
<script src="modernizr-custom.js"></script>
<link rel="stylesheet" href="/src/view/styles/settings.css">
<link rel="stylesheet" href="/src/view/styles/main.css">
</head>
<body>
<div id="app">
<header>
<h1 id="main-title">Neural Network</h1>
<h3 id="sub-title">visualization - Mobile Beta v1.0</h3>
</header>
<main id="wrapper">
<section id="query-result">
<div id="result"></div>
</section>
<div id="canvas-unit">
<div id="position-aligner">
<div id="left-indicator" class="indicator">
<div class="indicator-blur">
<img id="left-arrow" src="assets/left_arrow.png" alt="arrow_icon">
</div>
</div>
<div id="right-indicator" class="indicator">
<div class="indicator-blur">
<img id="right-arrow" src="assets/right_arrow.png" alt="arrow_icon">
</div>
</div>
<div id="perceptron-section">
<canvas id="perceptron"></canvas>
</div>
<button id="clear">
<img src="assets/eraser.png" alt="eraser_icon">
</button>
<div id="user-input-section">
<svg width="0" height="0">
<defs>
<clipPath id="arc-clip" clipPathUnits="userSpaceOnUse">
<path id="arc-path"/>
</clipPath>
</defs>
</svg>
<canvas class="user-input-canvas" id="user-input-canvas"></canvas>
</div>
</div>
</div>
</main>
</div>
</body>
</html>
5 changes: 2 additions & 3 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
{
"compilerOptions": {
"baseUrl": "src",
"baseUrl": "./src",
"paths": {
"@controller/*": ["controller/*"],
"@view/*": ["view/*"]
"@/*": ["*"]
}
},
"include": ["src"]
Expand Down
24 changes: 20 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,25 @@
"version": "1.0.0",
"type": "module",
"description": "",
"main": "public/index.html",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "vite",
"build": "vite build",
"deploy": "gh-pages -d dist",
"preview": "vite preview",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write ."
},
"private": true
}
"private": true,
"devDependencies": {
"@types/node": "^24.3.0",
"eslint": "^9.32.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.3",
"gh-pages": "^6.3.0",
"prettier": "3.6.2",
"vite": "^7.0.6"
}
}
Loading