프로젝트 배경
기존에 Electron 기반 데스크톱 앱(OODE)으로 개발했던 머신러닝 분석 기능들이 있었습니다. K-Means 클러스터링, 로지스틱 회귀, PCA, 랜덤 포레스트 등 다양한 알고리즘을 제공했지만, 설치가 필요하다는 점이 진입 장벽이었습니다.
이 기능들을 브라우저만으로 실행 가능한 웹 앱으로 이식하면, 누구나 URL 접속만으로 데이터 분석을 할 수 있겠다는 생각에서 openML 프로젝트를 시작했습니다.
기술 스택
- React 18 + TypeScript + Vite 6: 빠른 개발 환경과 타입 안전성
- TensorFlow.js: 브라우저에서 WebGL/WebGPU 백엔드로 ML 연산
- Tailwind CSS: 다크/라이트 테마 지원 UI
- Chart.js + react-chartjs-2: 산점도, 바 차트 등 시각화
- PapaParse + XLSX: CSV/Excel 파일 파싱
- GitHub Pages: 정적 호스팅 + 커스텀 도메인
핵심 아키텍처
Web Worker 기반 비동기 연산
ML 연산은 무거운 작업이라 메인 스레드에서 실행하면 UI가 멈춥니다. 이를 해결하기 위해 각 알고리즘을 Web Worker로 분리했습니다.
// useWorker 훅 — Worker 통신을 추상화
const { run, progress, result, isRunning, cancel } =
useWorker<KMeansResult>('workers/kmeans.worker.js')
// 학습 시작
run({
type: 'RUN_KMEANS',
payload: { data: rawData, features, k: 3, normalize: true }
})
Worker 내부에서는 TensorFlow.js CDN을 importScripts로 로드하고, 진행률을 postMessage로 실시간 전달합니다. Vite 번들링과 TF.js WASM 에셋 로딩의 충돌을 피하기 위해 CDN 방식을 선택했습니다.
OODE에서 openML로 이식 패턴
Electron IPC 통신 패턴을 Web Worker 메시지 패턴으로 일관되게 변환했습니다.
| OODE (Electron) | openML (Web) |
|---|---|
window.electronAPI.runKMeans() | worker.postMessage({ type: 'RUN_KMEANS' }) |
require('./tf_singleton.cjs') | importScripts(tfjs CDN) |
updateProgress(percent) 콜백 | self.postMessage({ type: 'PROGRESS' }) |
| 파일 시스템 모델 저장 | Blob + URL.createObjectURL 다운로드 |
BrowserRouter + GitHub Pages
GitHub Pages는 서버 사이드 라우팅을 지원하지 않아서, /preprocessing 같은 경로에 직접 접속하면 404가 발생합니다. 이를 해결하기 위해 404.html 리다이렉트 트릭을 적용했습니다.
- GitHub Pages가 404를 만나면
404.html이 경로를 query parameter로 변환 index.html의 스크립트가 query parameter를 원래 경로로 복원- React Router의
BrowserRouter가 정상적으로 라우팅 처리
이 방식으로 /#/preprocessing 대신 /preprocessing이라는 깔끔한 URL을 사용할 수 있게 되었습니다.
구현한 알고리즘
1. K-Means 클러스터링
데이터를 k개의 그룹으로 자동 분류합니다. 클러스터별 산점도 시각화, 크기 비교 바 차트, 통계 테이블을 제공하며, 결과를 Excel로 내보낼 수 있습니다.
2. 로지스틱 회귀
이진 분류 모델을 학습하고 혼동행렬, 정밀도/재현율/F1 스코어를 시각화합니다. 학습된 모델을 JSON으로 저장하고 다시 불러와서 새 데이터를 예측할 수 있습니다.
3. PCA + 이상탐지
주성분 분석으로 고차원 데이터를 2D로 투영하고, T-squared 통계량을 이용해 이상치를 탐지합니다. Jacobi 고유분해 알고리즘을 순수 JavaScript로 구현했습니다.
4. 랜덤 포레스트
분류와 회귀 모드를 모두 지원합니다. 특성 중요도를 바 차트로 시각화하고, 개별 예측 결과를 테이블로 확인할 수 있습니다.
5. 상관분석
Pearson/Spearman 상관계수를 계산하고 히트맵으로 시각화합니다. 히트맵은 Canvas API로 렌더링하여 PNG 이미지로 내보내기가 가능하며, 오른쪽에 컬러 바로 상관관계 강도를 표시합니다.
i18n (국제화)
외부 라이브러리 없이 간단한 t(key, lang) 함수 패턴으로 EN/한국어 전환을 구현했습니다.
// strings.ts — 번역 키 정의
const strings = {
training: { en: 'Training...', ko: '학습 중...' },
complete: { en: 'Complete', ko: '완료' },
// ~190개 키
}
// 컴포넌트에서 사용
const { lang } = useLang()
<span>{t('training', lang)}</span>
LangContext로 언어 상태를 관리하고, localStorage에 저장하여 새로고침 후에도 선택이 유지됩니다.
마치며
Electron 앱을 웹으로 이식하면서, 브라우저 환경의 제약(Web Worker 통신, TF.js 에셋 로딩, SPA 라우팅)을 하나씩 해결해 나가는 과정이 흥미로웠습니다. 설치 없이 URL 하나로 머신러닝 분석을 할 수 있다는 점에서 접근성이 크게 향상되었습니다.
openML 바로가기: https://openml.dreamurl.biz